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