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