github.com/mdempsky/go@v0.0.0-20151201204031-5dd372bd1e70/src/cmd/internal/obj/util.go (about)

     1  // Copyright 2015 The Go Authors.  All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package obj
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"os"
    14  	"strings"
    15  	"time"
    16  )
    17  
    18  const REG_NONE = 0
    19  
    20  var start time.Time
    21  
    22  func Cputime() float64 {
    23  	if start.IsZero() {
    24  		start = time.Now()
    25  	}
    26  	return time.Since(start).Seconds()
    27  }
    28  
    29  type Biobuf struct {
    30  	f       *os.File
    31  	r       *bufio.Reader
    32  	w       *bufio.Writer
    33  	linelen int
    34  }
    35  
    36  func Bopenw(name string) (*Biobuf, error) {
    37  	f, err := os.Create(name)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  	return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
    42  }
    43  
    44  func Bopenr(name string) (*Biobuf, error) {
    45  	f, err := os.Open(name)
    46  	if err != nil {
    47  		return nil, err
    48  	}
    49  	return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
    50  }
    51  
    52  func Binitw(w io.Writer) *Biobuf {
    53  	return &Biobuf{w: bufio.NewWriter(w)}
    54  }
    55  
    56  func Binitr(r io.Reader) *Biobuf {
    57  	return &Biobuf{r: bufio.NewReader(r)}
    58  }
    59  
    60  func (b *Biobuf) Write(p []byte) (int, error) {
    61  	return b.w.Write(p)
    62  }
    63  
    64  func Bwritestring(b *Biobuf, p string) (int, error) {
    65  	return b.w.WriteString(p)
    66  }
    67  
    68  func Bseek(b *Biobuf, offset int64, whence int) int64 {
    69  	if b.w != nil {
    70  		if err := b.w.Flush(); err != nil {
    71  			log.Fatalf("writing output: %v", err)
    72  		}
    73  	} else if b.r != nil {
    74  		if whence == 1 {
    75  			offset -= int64(b.r.Buffered())
    76  		}
    77  	}
    78  	off, err := b.f.Seek(offset, whence)
    79  	if err != nil {
    80  		log.Fatalf("seeking in output: %v", err)
    81  	}
    82  	if b.r != nil {
    83  		b.r.Reset(b.f)
    84  	}
    85  	return off
    86  }
    87  
    88  func Boffset(b *Biobuf) int64 {
    89  	if b.w != nil {
    90  		if err := b.w.Flush(); err != nil {
    91  			log.Fatalf("writing output: %v", err)
    92  		}
    93  	}
    94  	off, err := b.f.Seek(0, 1)
    95  	if err != nil {
    96  		log.Fatalf("seeking in output [0, 1]: %v", err)
    97  	}
    98  	if b.r != nil {
    99  		off -= int64(b.r.Buffered())
   100  	}
   101  	return off
   102  }
   103  
   104  func (b *Biobuf) Flush() error {
   105  	return b.w.Flush()
   106  }
   107  
   108  func Bputc(b *Biobuf, c byte) {
   109  	b.w.WriteByte(c)
   110  }
   111  
   112  const Beof = -1
   113  
   114  func Bread(b *Biobuf, p []byte) int {
   115  	n, err := io.ReadFull(b.r, p)
   116  	if n == 0 {
   117  		if err != nil && err != io.EOF {
   118  			n = -1
   119  		}
   120  	}
   121  	return n
   122  }
   123  
   124  func Bgetc(b *Biobuf) int {
   125  	c, err := b.r.ReadByte()
   126  	if err != nil {
   127  		return -1
   128  	}
   129  	return int(c)
   130  }
   131  
   132  func Bgetrune(b *Biobuf) int {
   133  	r, _, err := b.r.ReadRune()
   134  	if err != nil {
   135  		return -1
   136  	}
   137  	return int(r)
   138  }
   139  
   140  func Bungetrune(b *Biobuf) {
   141  	b.r.UnreadRune()
   142  }
   143  
   144  func (b *Biobuf) Read(p []byte) (int, error) {
   145  	return b.r.Read(p)
   146  }
   147  
   148  func (b *Biobuf) Peek(n int) ([]byte, error) {
   149  	return b.r.Peek(n)
   150  }
   151  
   152  func Brdline(b *Biobuf, delim int) string {
   153  	s, err := b.r.ReadBytes(byte(delim))
   154  	if err != nil {
   155  		log.Fatalf("reading input: %v", err)
   156  	}
   157  	b.linelen = len(s)
   158  	return string(s)
   159  }
   160  
   161  func Brdstr(b *Biobuf, delim int, cut int) string {
   162  	s, err := b.r.ReadString(byte(delim))
   163  	if err != nil {
   164  		log.Fatalf("reading input: %v", err)
   165  	}
   166  	if len(s) > 0 && cut > 0 {
   167  		s = s[:len(s)-1]
   168  	}
   169  	return s
   170  }
   171  
   172  func Blinelen(b *Biobuf) int {
   173  	return b.linelen
   174  }
   175  
   176  func Bterm(b *Biobuf) error {
   177  	var err error
   178  	if b.w != nil {
   179  		err = b.w.Flush()
   180  	}
   181  	err1 := b.f.Close()
   182  	if err == nil {
   183  		err = err1
   184  	}
   185  	return err
   186  }
   187  
   188  func envOr(key, value string) string {
   189  	if x := os.Getenv(key); x != "" {
   190  		return x
   191  	}
   192  	return value
   193  }
   194  
   195  func Getgoroot() string {
   196  	return envOr("GOROOT", defaultGOROOT)
   197  }
   198  
   199  func Getgoarch() string {
   200  	return envOr("GOARCH", defaultGOARCH)
   201  }
   202  
   203  func Getgoos() string {
   204  	return envOr("GOOS", defaultGOOS)
   205  }
   206  
   207  func Getgoarm() int32 {
   208  	switch v := envOr("GOARM", defaultGOARM); v {
   209  	case "5":
   210  		return 5
   211  	case "6":
   212  		return 6
   213  	case "7":
   214  		return 7
   215  	}
   216  	// Fail here, rather than validate at multiple call sites.
   217  	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
   218  	panic("unreachable")
   219  }
   220  
   221  func Getgo386() string {
   222  	// Validated by cmd/compile.
   223  	return envOr("GO386", defaultGO386)
   224  }
   225  
   226  func Getgoextlinkenabled() string {
   227  	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
   228  }
   229  
   230  func Getgoversion() string {
   231  	return version
   232  }
   233  
   234  func (p *Prog) Line() string {
   235  	return p.Ctxt.LineHist.LineString(int(p.Lineno))
   236  }
   237  
   238  var armCondCode = []string{
   239  	".EQ",
   240  	".NE",
   241  	".CS",
   242  	".CC",
   243  	".MI",
   244  	".PL",
   245  	".VS",
   246  	".VC",
   247  	".HI",
   248  	".LS",
   249  	".GE",
   250  	".LT",
   251  	".GT",
   252  	".LE",
   253  	"",
   254  	".NV",
   255  }
   256  
   257  /* ARM scond byte */
   258  const (
   259  	C_SCOND     = (1 << 4) - 1
   260  	C_SBIT      = 1 << 4
   261  	C_PBIT      = 1 << 5
   262  	C_WBIT      = 1 << 6
   263  	C_FBIT      = 1 << 7
   264  	C_UBIT      = 1 << 7
   265  	C_SCOND_XOR = 14
   266  )
   267  
   268  // CConv formats ARM condition codes.
   269  func CConv(s uint8) string {
   270  	if s == 0 {
   271  		return ""
   272  	}
   273  	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
   274  	if s&C_SBIT != 0 {
   275  		sc += ".S"
   276  	}
   277  	if s&C_PBIT != 0 {
   278  		sc += ".P"
   279  	}
   280  	if s&C_WBIT != 0 {
   281  		sc += ".W"
   282  	}
   283  	if s&C_UBIT != 0 { /* ambiguous with FBIT */
   284  		sc += ".U"
   285  	}
   286  	return sc
   287  }
   288  
   289  func (p *Prog) String() string {
   290  	if p.Ctxt == nil {
   291  		return "<Prog without ctxt>"
   292  	}
   293  
   294  	sc := CConv(p.Scond)
   295  
   296  	var buf bytes.Buffer
   297  
   298  	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
   299  	sep := "\t"
   300  	if p.From.Type != TYPE_NONE {
   301  		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
   302  		sep = ", "
   303  	}
   304  	if p.Reg != REG_NONE {
   305  		// Should not happen but might as well show it if it does.
   306  		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
   307  		sep = ", "
   308  	}
   309  	if p.From3Type() != TYPE_NONE {
   310  		if p.From3.Type == TYPE_CONST && (p.As == ADATA || p.As == ATEXT || p.As == AGLOBL) {
   311  			// Special case - omit $.
   312  			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
   313  		} else {
   314  			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
   315  		}
   316  		sep = ", "
   317  	}
   318  	if p.To.Type != TYPE_NONE {
   319  		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
   320  	}
   321  	if p.RegTo2 != REG_NONE {
   322  		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
   323  	}
   324  	return buf.String()
   325  }
   326  
   327  func (ctxt *Link) NewProg() *Prog {
   328  	p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
   329  	p.Ctxt = ctxt
   330  	return p
   331  }
   332  
   333  func (ctxt *Link) Line(n int) string {
   334  	return ctxt.LineHist.LineString(n)
   335  }
   336  
   337  func Getcallerpc(interface{}) uintptr {
   338  	return 1
   339  }
   340  
   341  func (ctxt *Link) Dconv(a *Addr) string {
   342  	return Dconv(nil, a)
   343  }
   344  
   345  func Dconv(p *Prog, a *Addr) string {
   346  	var str string
   347  
   348  	switch a.Type {
   349  	default:
   350  		str = fmt.Sprintf("type=%d", a.Type)
   351  
   352  	case TYPE_NONE:
   353  		str = ""
   354  		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
   355  			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
   356  		}
   357  
   358  	case TYPE_REG:
   359  		// TODO(rsc): This special case is for x86 instructions like
   360  		//	PINSRQ	CX,$1,X6
   361  		// where the $1 is included in the p->to Addr.
   362  		// Move into a new field.
   363  		if a.Offset != 0 {
   364  			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
   365  			break
   366  		}
   367  
   368  		str = Rconv(int(a.Reg))
   369  		if a.Name != TYPE_NONE || a.Sym != nil {
   370  			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
   371  		}
   372  
   373  	case TYPE_BRANCH:
   374  		if a.Sym != nil {
   375  			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
   376  		} else if p != nil && p.Pcond != nil {
   377  			str = fmt.Sprint(p.Pcond.Pc)
   378  		} else if a.Val != nil {
   379  			str = fmt.Sprint(a.Val.(*Prog).Pc)
   380  		} else {
   381  			str = fmt.Sprintf("%d(PC)", a.Offset)
   382  		}
   383  
   384  	case TYPE_INDIR:
   385  		str = fmt.Sprintf("*%s", Mconv(a))
   386  
   387  	case TYPE_MEM:
   388  		str = Mconv(a)
   389  		if a.Index != REG_NONE {
   390  			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
   391  		}
   392  
   393  	case TYPE_CONST:
   394  		if a.Reg != 0 {
   395  			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
   396  		} else {
   397  			str = fmt.Sprintf("$%v", Mconv(a))
   398  		}
   399  
   400  	case TYPE_TEXTSIZE:
   401  		if a.Val.(int32) == ArgsSizeUnknown {
   402  			str = fmt.Sprintf("$%d", a.Offset)
   403  		} else {
   404  			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
   405  		}
   406  
   407  	case TYPE_FCONST:
   408  		str = fmt.Sprintf("%.17g", a.Val.(float64))
   409  		// Make sure 1 prints as 1.0
   410  		if !strings.ContainsAny(str, ".e") {
   411  			str += ".0"
   412  		}
   413  		str = fmt.Sprintf("$(%s)", str)
   414  
   415  	case TYPE_SCONST:
   416  		str = fmt.Sprintf("$%q", a.Val.(string))
   417  
   418  	case TYPE_ADDR:
   419  		str = fmt.Sprintf("$%s", Mconv(a))
   420  
   421  	case TYPE_SHIFT:
   422  		v := int(a.Offset)
   423  		op := string("<<>>->@>"[((v>>5)&3)<<1:])
   424  		if v&(1<<4) != 0 {
   425  			str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
   426  		} else {
   427  			str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
   428  		}
   429  		if a.Reg != 0 {
   430  			str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   431  		}
   432  
   433  	case TYPE_REGREG:
   434  		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   435  
   436  	case TYPE_REGREG2:
   437  		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
   438  
   439  	case TYPE_REGLIST:
   440  		str = regListConv(int(a.Offset))
   441  	}
   442  
   443  	return str
   444  }
   445  
   446  func Mconv(a *Addr) string {
   447  	var str string
   448  
   449  	switch a.Name {
   450  	default:
   451  		str = fmt.Sprintf("name=%d", a.Name)
   452  
   453  	case NAME_NONE:
   454  		switch {
   455  		case a.Reg == REG_NONE:
   456  			str = fmt.Sprint(a.Offset)
   457  		case a.Offset == 0:
   458  			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
   459  		case a.Offset != 0:
   460  			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
   461  		}
   462  
   463  	case NAME_EXTERN:
   464  		if a.Sym != nil {
   465  			str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
   466  		} else {
   467  			str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
   468  		}
   469  
   470  	case NAME_GOTREF:
   471  		if a.Sym != nil {
   472  			str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
   473  		} else {
   474  			str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset))
   475  		}
   476  
   477  	case NAME_STATIC:
   478  		if a.Sym != nil {
   479  			str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
   480  		} else {
   481  			str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
   482  		}
   483  
   484  	case NAME_AUTO:
   485  		if a.Sym != nil {
   486  			str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
   487  		} else {
   488  			str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
   489  		}
   490  
   491  	case NAME_PARAM:
   492  		if a.Sym != nil {
   493  			str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
   494  		} else {
   495  			str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
   496  		}
   497  	}
   498  	return str
   499  }
   500  
   501  func offConv(off int64) string {
   502  	if off == 0 {
   503  		return ""
   504  	}
   505  	return fmt.Sprintf("%+d", off)
   506  }
   507  
   508  type regSet struct {
   509  	lo    int
   510  	hi    int
   511  	Rconv func(int) string
   512  }
   513  
   514  // Few enough architectures that a linear scan is fastest.
   515  // Not even worth sorting.
   516  var regSpace []regSet
   517  
   518  /*
   519  	Each architecture defines a register space as a unique
   520  	integer range.
   521  	Here is the list of architectures and the base of their register spaces.
   522  */
   523  
   524  const (
   525  	// Because of masking operations in the encodings, each register
   526  	// space should start at 0 modulo some power of 2.
   527  	RBase386    = 1 * 1024
   528  	RBaseAMD64  = 2 * 1024
   529  	RBaseARM    = 3 * 1024
   530  	RBasePPC64  = 4 * 1024  // range [4k, 8k)
   531  	RBaseARM64  = 8 * 1024  // range [8k, 13k)
   532  	RBaseMIPS64 = 13 * 1024 // range [13k, 16k)
   533  )
   534  
   535  // RegisterRegister binds a pretty-printer (Rconv) for register
   536  // numbers to a given register number range.  Lo is inclusive,
   537  // hi exclusive (valid registers are lo through hi-1).
   538  func RegisterRegister(lo, hi int, Rconv func(int) string) {
   539  	regSpace = append(regSpace, regSet{lo, hi, Rconv})
   540  }
   541  
   542  func Rconv(reg int) string {
   543  	if reg == REG_NONE {
   544  		return "NONE"
   545  	}
   546  	for i := range regSpace {
   547  		rs := &regSpace[i]
   548  		if rs.lo <= reg && reg < rs.hi {
   549  			return rs.Rconv(reg)
   550  		}
   551  	}
   552  	return fmt.Sprintf("R???%d", reg)
   553  }
   554  
   555  func regListConv(list int) string {
   556  	str := ""
   557  
   558  	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
   559  		if list&(1<<uint(i)) != 0 {
   560  			if str == "" {
   561  				str += "["
   562  			} else {
   563  				str += ","
   564  			}
   565  			// This is ARM-specific; R10 is g.
   566  			if i == 10 {
   567  				str += "g"
   568  			} else {
   569  				str += fmt.Sprintf("R%d", i)
   570  			}
   571  		}
   572  	}
   573  
   574  	str += "]"
   575  	return str
   576  }
   577  
   578  /*
   579  	Each architecture defines an instruction (A*) space as a unique
   580  	integer range.
   581  	Global opcodes like CALL start at 0; the architecture-specific ones
   582  	start at a distinct, big-maskable offsets.
   583  	Here is the list of architectures and the base of their opcode spaces.
   584  */
   585  
   586  const (
   587  	ABase386 = (1 + iota) << 12
   588  	ABaseARM
   589  	ABaseAMD64
   590  	ABasePPC64
   591  	ABaseARM64
   592  	ABaseMIPS64
   593  	AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
   594  )
   595  
   596  type opSet struct {
   597  	lo    int
   598  	names []string
   599  }
   600  
   601  // Not even worth sorting
   602  var aSpace []opSet
   603  
   604  // RegisterOpcode binds a list of instruction names
   605  // to a given instruction number range.
   606  func RegisterOpcode(lo int, Anames []string) {
   607  	aSpace = append(aSpace, opSet{lo, Anames})
   608  }
   609  
   610  func Aconv(a int) string {
   611  	if a < A_ARCHSPECIFIC {
   612  		return Anames[a]
   613  	}
   614  	for i := range aSpace {
   615  		as := &aSpace[i]
   616  		if as.lo <= a && a < as.lo+len(as.names) {
   617  			return as.names[a-as.lo]
   618  		}
   619  	}
   620  	return fmt.Sprintf("A???%d", a)
   621  }
   622  
   623  var Anames = []string{
   624  	"XXX",
   625  	"CALL",
   626  	"CHECKNIL",
   627  	"DATA",
   628  	"DUFFCOPY",
   629  	"DUFFZERO",
   630  	"END",
   631  	"FUNCDATA",
   632  	"GLOBL",
   633  	"JMP",
   634  	"NOP",
   635  	"PCDATA",
   636  	"RET",
   637  	"TEXT",
   638  	"TYPE",
   639  	"UNDEF",
   640  	"USEFIELD",
   641  	"VARDEF",
   642  	"VARKILL",
   643  }
   644  
   645  func Bool2int(b bool) int {
   646  	if b {
   647  		return 1
   648  	}
   649  	return 0
   650  }