summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/google/gops/internal/obj/util.go
diff options
context:
space:
mode:
authorWim <wim@42.be>2017-03-23 23:28:55 +0100
committerWim <wim@42.be>2017-03-23 23:28:55 +0100
commit2f68519b3c6b5a70028882c99afeb76f291b7725 (patch)
tree2555d0b8b81491f136a176a58e2618a25edc8edc /vendor/github.com/google/gops/internal/obj/util.go
parentefe641f202653dfd3bc7bde221188e098db3def7 (diff)
downloadmatterbridge-msglm-0.10.2-dev.tar.gz
matterbridge-msglm-0.10.2-dev.tar.bz2
matterbridge-msglm-0.10.2-dev.zip
Add gops agentv0.10.2-dev
Diffstat (limited to 'vendor/github.com/google/gops/internal/obj/util.go')
-rw-r--r--vendor/github.com/google/gops/internal/obj/util.go499
1 files changed, 499 insertions, 0 deletions
diff --git a/vendor/github.com/google/gops/internal/obj/util.go b/vendor/github.com/google/gops/internal/obj/util.go
new file mode 100644
index 00000000..9f1c6f08
--- /dev/null
+++ b/vendor/github.com/google/gops/internal/obj/util.go
@@ -0,0 +1,499 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package obj
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "os"
+ "strings"
+ "time"
+)
+
+const REG_NONE = 0
+
+var start time.Time
+
+func Cputime() float64 {
+ if start.IsZero() {
+ start = time.Now()
+ }
+ return time.Since(start).Seconds()
+}
+
+func envOr(key, value string) string {
+ if x := os.Getenv(key); x != "" {
+ return x
+ }
+ return value
+}
+
+var (
+ GOROOT = envOr("GOROOT", defaultGOROOT)
+ GOARCH = envOr("GOARCH", defaultGOARCH)
+ GOOS = envOr("GOOS", defaultGOOS)
+ GO386 = envOr("GO386", defaultGO386)
+ GOARM = goarm()
+ Version = version
+)
+
+func goarm() int {
+ switch v := envOr("GOARM", defaultGOARM); v {
+ case "5":
+ return 5
+ case "6":
+ return 6
+ case "7":
+ return 7
+ }
+ // Fail here, rather than validate at multiple call sites.
+ log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
+ panic("unreachable")
+}
+
+func Getgoextlinkenabled() string {
+ return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
+}
+
+func (p *Prog) Line() string {
+ return p.Ctxt.LineHist.LineString(int(p.Lineno))
+}
+
+var armCondCode = []string{
+ ".EQ",
+ ".NE",
+ ".CS",
+ ".CC",
+ ".MI",
+ ".PL",
+ ".VS",
+ ".VC",
+ ".HI",
+ ".LS",
+ ".GE",
+ ".LT",
+ ".GT",
+ ".LE",
+ "",
+ ".NV",
+}
+
+/* ARM scond byte */
+const (
+ C_SCOND = (1 << 4) - 1
+ C_SBIT = 1 << 4
+ C_PBIT = 1 << 5
+ C_WBIT = 1 << 6
+ C_FBIT = 1 << 7
+ C_UBIT = 1 << 7
+ C_SCOND_XOR = 14
+)
+
+// CConv formats ARM condition codes.
+func CConv(s uint8) string {
+ if s == 0 {
+ return ""
+ }
+ sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
+ if s&C_SBIT != 0 {
+ sc += ".S"
+ }
+ if s&C_PBIT != 0 {
+ sc += ".P"
+ }
+ if s&C_WBIT != 0 {
+ sc += ".W"
+ }
+ if s&C_UBIT != 0 { /* ambiguous with FBIT */
+ sc += ".U"
+ }
+ return sc
+}
+
+func (p *Prog) String() string {
+ if p == nil {
+ return "<nil Prog>"
+ }
+
+ if p.Ctxt == nil {
+ return "<Prog without ctxt>"
+ }
+
+ sc := CConv(p.Scond)
+
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), p.As, sc)
+ sep := "\t"
+ quadOpAmd64 := p.RegTo2 == -1
+ if quadOpAmd64 {
+ fmt.Fprintf(&buf, "%s$%d", sep, p.From3.Offset)
+ sep = ", "
+ }
+ if p.From.Type != TYPE_NONE {
+ fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
+ sep = ", "
+ }
+ if p.Reg != REG_NONE {
+ // Should not happen but might as well show it if it does.
+ fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
+ sep = ", "
+ }
+ if p.From3Type() != TYPE_NONE {
+ if p.From3.Type == TYPE_CONST && p.As == ATEXT {
+ // Special case - omit $.
+ fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
+ } else if quadOpAmd64 {
+ fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.From3.Reg)))
+ } else {
+ fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
+ }
+ sep = ", "
+ }
+ if p.To.Type != TYPE_NONE {
+ fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
+ }
+ if p.RegTo2 != REG_NONE && !quadOpAmd64 {
+ fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
+ }
+ return buf.String()
+}
+
+func (ctxt *Link) NewProg() *Prog {
+ var p *Prog
+ if i := ctxt.allocIdx; i < len(ctxt.progs) {
+ p = &ctxt.progs[i]
+ ctxt.allocIdx = i + 1
+ } else {
+ p = new(Prog) // should be the only call to this; all others should use ctxt.NewProg
+ }
+ p.Ctxt = ctxt
+ return p
+}
+func (ctxt *Link) freeProgs() {
+ s := ctxt.progs[:ctxt.allocIdx]
+ for i := range s {
+ s[i] = Prog{}
+ }
+ ctxt.allocIdx = 0
+}
+
+func (ctxt *Link) Line(n int) string {
+ return ctxt.LineHist.LineString(n)
+}
+
+func Getcallerpc(interface{}) uintptr {
+ return 1
+}
+
+func (ctxt *Link) Dconv(a *Addr) string {
+ return Dconv(nil, a)
+}
+
+func Dconv(p *Prog, a *Addr) string {
+ var str string
+
+ switch a.Type {
+ default:
+ str = fmt.Sprintf("type=%d", a.Type)
+
+ case TYPE_NONE:
+ str = ""
+ if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
+ str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
+ }
+
+ case TYPE_REG:
+ // TODO(rsc): This special case is for x86 instructions like
+ // PINSRQ CX,$1,X6
+ // where the $1 is included in the p->to Addr.
+ // Move into a new field.
+ if a.Offset != 0 {
+ str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
+ break
+ }
+
+ str = Rconv(int(a.Reg))
+ if a.Name != NAME_NONE || a.Sym != nil {
+ str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
+ }
+
+ case TYPE_BRANCH:
+ if a.Sym != nil {
+ str = fmt.Sprintf("%s(SB)", a.Sym.Name)
+ } else if p != nil && p.Pcond != nil {
+ str = fmt.Sprint(p.Pcond.Pc)
+ } else if a.Val != nil {
+ str = fmt.Sprint(a.Val.(*Prog).Pc)
+ } else {
+ str = fmt.Sprintf("%d(PC)", a.Offset)
+ }
+
+ case TYPE_INDIR:
+ str = fmt.Sprintf("*%s", Mconv(a))
+
+ case TYPE_MEM:
+ str = Mconv(a)
+ if a.Index != REG_NONE {
+ str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
+ }
+
+ case TYPE_CONST:
+ if a.Reg != 0 {
+ str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
+ } else {
+ str = fmt.Sprintf("$%v", Mconv(a))
+ }
+
+ case TYPE_TEXTSIZE:
+ if a.Val.(int32) == ArgsSizeUnknown {
+ str = fmt.Sprintf("$%d", a.Offset)
+ } else {
+ str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
+ }
+
+ case TYPE_FCONST:
+ str = fmt.Sprintf("%.17g", a.Val.(float64))
+ // Make sure 1 prints as 1.0
+ if !strings.ContainsAny(str, ".e") {
+ str += ".0"
+ }
+ str = fmt.Sprintf("$(%s)", str)
+
+ case TYPE_SCONST:
+ str = fmt.Sprintf("$%q", a.Val.(string))
+
+ case TYPE_ADDR:
+ str = fmt.Sprintf("$%s", Mconv(a))
+
+ case TYPE_SHIFT:
+ v := int(a.Offset)
+ ops := "<<>>->@>"
+ switch GOARCH {
+ case "arm":
+ op := ops[((v>>5)&3)<<1:]
+ if v&(1<<4) != 0 {
+ str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
+ } else {
+ str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
+ }
+ if a.Reg != 0 {
+ str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
+ }
+ case "arm64":
+ op := ops[((v>>22)&3)<<1:]
+ str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63)
+ default:
+ panic("TYPE_SHIFT is not supported on " + GOARCH)
+ }
+
+ case TYPE_REGREG:
+ str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
+
+ case TYPE_REGREG2:
+ str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
+
+ case TYPE_REGLIST:
+ str = regListConv(int(a.Offset))
+ }
+
+ return str
+}
+
+func Mconv(a *Addr) string {
+ var str string
+
+ switch a.Name {
+ default:
+ str = fmt.Sprintf("name=%d", a.Name)
+
+ case NAME_NONE:
+ switch {
+ case a.Reg == REG_NONE:
+ str = fmt.Sprint(a.Offset)
+ case a.Offset == 0:
+ str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
+ case a.Offset != 0:
+ str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
+ }
+
+ case NAME_EXTERN:
+ if a.Sym != nil {
+ str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
+ } else {
+ str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
+ }
+
+ case NAME_GOTREF:
+ if a.Sym != nil {
+ str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
+ } else {
+ str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset))
+ }
+
+ case NAME_STATIC:
+ if a.Sym != nil {
+ str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
+ } else {
+ str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
+ }
+
+ case NAME_AUTO:
+ if a.Sym != nil {
+ str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
+ } else {
+ str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
+ }
+
+ case NAME_PARAM:
+ if a.Sym != nil {
+ str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
+ } else {
+ str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
+ }
+ }
+ return str
+}
+
+func offConv(off int64) string {
+ if off == 0 {
+ return ""
+ }
+ return fmt.Sprintf("%+d", off)
+}
+
+type regSet struct {
+ lo int
+ hi int
+ Rconv func(int) string
+}
+
+// Few enough architectures that a linear scan is fastest.
+// Not even worth sorting.
+var regSpace []regSet
+
+/*
+ Each architecture defines a register space as a unique
+ integer range.
+ Here is the list of architectures and the base of their register spaces.
+*/
+
+const (
+ // Because of masking operations in the encodings, each register
+ // space should start at 0 modulo some power of 2.
+ RBase386 = 1 * 1024
+ RBaseAMD64 = 2 * 1024
+ RBaseARM = 3 * 1024
+ RBasePPC64 = 4 * 1024 // range [4k, 8k)
+ RBaseARM64 = 8 * 1024 // range [8k, 13k)
+ RBaseMIPS64 = 13 * 1024 // range [13k, 14k)
+ RBaseS390X = 14 * 1024 // range [14k, 15k)
+)
+
+// RegisterRegister binds a pretty-printer (Rconv) for register
+// numbers to a given register number range. Lo is inclusive,
+// hi exclusive (valid registers are lo through hi-1).
+func RegisterRegister(lo, hi int, Rconv func(int) string) {
+ regSpace = append(regSpace, regSet{lo, hi, Rconv})
+}
+
+func Rconv(reg int) string {
+ if reg == REG_NONE {
+ return "NONE"
+ }
+ for i := range regSpace {
+ rs := &regSpace[i]
+ if rs.lo <= reg && reg < rs.hi {
+ return rs.Rconv(reg)
+ }
+ }
+ return fmt.Sprintf("R???%d", reg)
+}
+
+func regListConv(list int) string {
+ str := ""
+
+ for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
+ if list&(1<<uint(i)) != 0 {
+ if str == "" {
+ str += "["
+ } else {
+ str += ","
+ }
+ // This is ARM-specific; R10 is g.
+ if i == 10 {
+ str += "g"
+ } else {
+ str += fmt.Sprintf("R%d", i)
+ }
+ }
+ }
+
+ str += "]"
+ return str
+}
+
+type opSet struct {
+ lo As
+ names []string
+}
+
+// Not even worth sorting
+var aSpace []opSet
+
+// RegisterOpcode binds a list of instruction names
+// to a given instruction number range.
+func RegisterOpcode(lo As, Anames []string) {
+ if len(Anames) > AllowedOpCodes {
+ panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes))
+ }
+ aSpace = append(aSpace, opSet{lo, Anames})
+}
+
+func (a As) String() string {
+ if 0 <= a && int(a) < len(Anames) {
+ return Anames[a]
+ }
+ for i := range aSpace {
+ as := &aSpace[i]
+ if as.lo <= a && int(a-as.lo) < len(as.names) {
+ return as.names[a-as.lo]
+ }
+ }
+ return fmt.Sprintf("A???%d", a)
+}
+
+var Anames = []string{
+ "XXX",
+ "CALL",
+ "DUFFCOPY",
+ "DUFFZERO",
+ "END",
+ "FUNCDATA",
+ "JMP",
+ "NOP",
+ "PCDATA",
+ "RET",
+ "TEXT",
+ "TYPE",
+ "UNDEF",
+ "USEFIELD",
+ "VARDEF",
+ "VARKILL",
+ "VARLIVE",
+}
+
+func Bool2int(b bool) int {
+ // The compiler currently only optimizes this form.
+ // See issue 6011.
+ var i int
+ if b {
+ i = 1
+ } else {
+ i = 0
+ }
+ return i
+}