Home | History | Annotate | Download | only in obj
      1 // Do not edit. Bootstrap copy of /Volumes/Android/buildbot/src/android/build-tools/out/obj/go/src/cmd/internal/obj/util.go
      2 
      3 //line /Volumes/Android/buildbot/src/android/build-tools/out/obj/go/src/cmd/internal/obj/util.go:1
      4 // Copyright 2015 The Go Authors.  All rights reserved.
      5 // Use of this source code is governed by a BSD-style
      6 // license that can be found in the LICENSE file.
      7 
      8 package obj
      9 
     10 import (
     11 	"bufio"
     12 	"bytes"
     13 	"fmt"
     14 	"io"
     15 	"log"
     16 	"os"
     17 	"strconv"
     18 	"strings"
     19 	"time"
     20 )
     21 
     22 const REG_NONE = 0
     23 
     24 var start time.Time
     25 
     26 func Cputime() float64 {
     27 	if start.IsZero() {
     28 		start = time.Now()
     29 	}
     30 	return time.Since(start).Seconds()
     31 }
     32 
     33 type Biobuf struct {
     34 	f       *os.File
     35 	r       *bufio.Reader
     36 	w       *bufio.Writer
     37 	linelen int
     38 }
     39 
     40 func Bopenw(name string) (*Biobuf, error) {
     41 	f, err := os.Create(name)
     42 	if err != nil {
     43 		return nil, err
     44 	}
     45 	return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
     46 }
     47 
     48 func Bopenr(name string) (*Biobuf, error) {
     49 	f, err := os.Open(name)
     50 	if err != nil {
     51 		return nil, err
     52 	}
     53 	return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
     54 }
     55 
     56 func Binitw(w io.Writer) *Biobuf {
     57 	return &Biobuf{w: bufio.NewWriter(w)}
     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 Access(name string, mode int) int {
    173 	if mode != 0 {
    174 		panic("bad access")
    175 	}
    176 	_, err := os.Stat(name)
    177 	if err != nil {
    178 		return -1
    179 	}
    180 	return 0
    181 }
    182 
    183 func Blinelen(b *Biobuf) int {
    184 	return b.linelen
    185 }
    186 
    187 func Bterm(b *Biobuf) error {
    188 	var err error
    189 	if b.w != nil {
    190 		err = b.w.Flush()
    191 	}
    192 	err1 := b.f.Close()
    193 	if err == nil {
    194 		err = err1
    195 	}
    196 	return err
    197 }
    198 
    199 func envOr(key, value string) string {
    200 	if x := os.Getenv(key); x != "" {
    201 		return x
    202 	}
    203 	return value
    204 }
    205 
    206 func Getgoroot() string {
    207 	return envOr("GOROOT", defaultGOROOT)
    208 }
    209 
    210 func Getgoarch() string {
    211 	return envOr("GOARCH", defaultGOARCH)
    212 }
    213 
    214 func Getgoos() string {
    215 	return envOr("GOOS", defaultGOOS)
    216 }
    217 
    218 func Getgoarm() string {
    219 	switch v := envOr("GOARM", defaultGOARM); v {
    220 	case "5", "6", "7":
    221 		return v
    222 	}
    223 	// Fail here, rather than validate at multiple call sites.
    224 	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
    225 	panic("unreachable")
    226 }
    227 
    228 func Getgo386() string {
    229 	// Validated by cmd/compile.
    230 	return envOr("GO386", defaultGO386)
    231 }
    232 
    233 func Getgoextlinkenabled() string {
    234 	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
    235 }
    236 
    237 func Getgoversion() string {
    238 	return version
    239 }
    240 
    241 func Atoi(s string) int {
    242 	i, _ := strconv.Atoi(s)
    243 	return i
    244 }
    245 
    246 func (p *Prog) Line() string {
    247 	return p.Ctxt.LineHist.LineString(int(p.Lineno))
    248 }
    249 
    250 var armCondCode = []string{
    251 	".EQ",
    252 	".NE",
    253 	".CS",
    254 	".CC",
    255 	".MI",
    256 	".PL",
    257 	".VS",
    258 	".VC",
    259 	".HI",
    260 	".LS",
    261 	".GE",
    262 	".LT",
    263 	".GT",
    264 	".LE",
    265 	"",
    266 	".NV",
    267 }
    268 
    269 /* ARM scond byte */
    270 const (
    271 	C_SCOND     = (1 << 4) - 1
    272 	C_SBIT      = 1 << 4
    273 	C_PBIT      = 1 << 5
    274 	C_WBIT      = 1 << 6
    275 	C_FBIT      = 1 << 7
    276 	C_UBIT      = 1 << 7
    277 	C_SCOND_XOR = 14
    278 )
    279 
    280 // CConv formats ARM condition codes.
    281 func CConv(s uint8) string {
    282 	if s == 0 {
    283 		return ""
    284 	}
    285 	sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
    286 	if s&C_SBIT != 0 {
    287 		sc += ".S"
    288 	}
    289 	if s&C_PBIT != 0 {
    290 		sc += ".P"
    291 	}
    292 	if s&C_WBIT != 0 {
    293 		sc += ".W"
    294 	}
    295 	if s&C_UBIT != 0 { /* ambiguous with FBIT */
    296 		sc += ".U"
    297 	}
    298 	return sc
    299 }
    300 
    301 func (p *Prog) String() string {
    302 	if p.Ctxt == nil {
    303 		return "<Prog without ctxt>"
    304 	}
    305 
    306 	sc := CConv(p.Scond)
    307 
    308 	var buf bytes.Buffer
    309 
    310 	fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
    311 	sep := "\t"
    312 	if p.From.Type != TYPE_NONE {
    313 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
    314 		sep = ", "
    315 	}
    316 	if p.Reg != REG_NONE {
    317 		// Should not happen but might as well show it if it does.
    318 		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg)))
    319 		sep = ", "
    320 	}
    321 	if p.From3Type() != TYPE_NONE {
    322 		if p.From3.Type == TYPE_CONST && (p.As == ADATA || p.As == ATEXT || p.As == AGLOBL) {
    323 			// Special case - omit $.
    324 			fmt.Fprintf(&buf, "%s%d", sep, p.From3.Offset)
    325 		} else {
    326 			fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
    327 		}
    328 		sep = ", "
    329 	}
    330 	if p.To.Type != TYPE_NONE {
    331 		fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
    332 	}
    333 	if p.RegTo2 != REG_NONE {
    334 		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
    335 	}
    336 	return buf.String()
    337 }
    338 
    339 func (ctxt *Link) NewProg() *Prog {
    340 	p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
    341 	p.Ctxt = ctxt
    342 	return p
    343 }
    344 
    345 func (ctxt *Link) Line(n int) string {
    346 	return ctxt.LineHist.LineString(n)
    347 }
    348 
    349 func Getcallerpc(interface{}) uintptr {
    350 	return 1
    351 }
    352 
    353 func (ctxt *Link) Dconv(a *Addr) string {
    354 	return Dconv(nil, a)
    355 }
    356 
    357 func Dconv(p *Prog, a *Addr) string {
    358 	var str string
    359 
    360 	switch a.Type {
    361 	default:
    362 		str = fmt.Sprintf("type=%d", a.Type)
    363 
    364 	case TYPE_NONE:
    365 		str = ""
    366 		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
    367 			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
    368 		}
    369 
    370 	case TYPE_REG:
    371 		// TODO(rsc): This special case is for x86 instructions like
    372 		//	PINSRQ	CX,$1,X6
    373 		// where the $1 is included in the p->to Addr.
    374 		// Move into a new field.
    375 		if a.Offset != 0 {
    376 			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
    377 			break
    378 		}
    379 
    380 		str = Rconv(int(a.Reg))
    381 		if a.Name != TYPE_NONE || a.Sym != nil {
    382 			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
    383 		}
    384 
    385 	case TYPE_BRANCH:
    386 		if a.Sym != nil {
    387 			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
    388 		} else if p != nil && p.Pcond != nil {
    389 			str = fmt.Sprint(p.Pcond.Pc)
    390 		} else if a.Val != nil {
    391 			str = fmt.Sprint(a.Val.(*Prog).Pc)
    392 		} else {
    393 			str = fmt.Sprintf("%d(PC)", a.Offset)
    394 		}
    395 
    396 	case TYPE_INDIR:
    397 		str = fmt.Sprintf("*%s", Mconv(a))
    398 
    399 	case TYPE_MEM:
    400 		str = Mconv(a)
    401 		if a.Index != REG_NONE {
    402 			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
    403 		}
    404 
    405 	case TYPE_CONST:
    406 		if a.Reg != 0 {
    407 			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
    408 		} else {
    409 			str = fmt.Sprintf("$%v", Mconv(a))
    410 		}
    411 
    412 	case TYPE_TEXTSIZE:
    413 		if a.Val.(int32) == ArgsSizeUnknown {
    414 			str = fmt.Sprintf("$%d", a.Offset)
    415 		} else {
    416 			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
    417 		}
    418 
    419 	case TYPE_FCONST:
    420 		str = fmt.Sprintf("%.17g", a.Val.(float64))
    421 		// Make sure 1 prints as 1.0
    422 		if !strings.ContainsAny(str, ".e") {
    423 			str += ".0"
    424 		}
    425 		str = fmt.Sprintf("$(%s)", str)
    426 
    427 	case TYPE_SCONST:
    428 		str = fmt.Sprintf("$%q", a.Val.(string))
    429 
    430 	case TYPE_ADDR:
    431 		str = fmt.Sprintf("$%s", Mconv(a))
    432 
    433 	case TYPE_SHIFT:
    434 		v := int(a.Offset)
    435 		op := string("<<>>->@>"[((v>>5)&3)<<1:])
    436 		if v&(1<<4) != 0 {
    437 			str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
    438 		} else {
    439 			str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
    440 		}
    441 		if a.Reg != 0 {
    442 			str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
    443 		}
    444 
    445 	case TYPE_REGREG:
    446 		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
    447 
    448 	case TYPE_REGREG2:
    449 		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
    450 
    451 	case TYPE_REGLIST:
    452 		str = regListConv(int(a.Offset))
    453 	}
    454 
    455 	return str
    456 }
    457 
    458 func Mconv(a *Addr) string {
    459 	var str string
    460 
    461 	switch a.Name {
    462 	default:
    463 		str = fmt.Sprintf("name=%d", a.Name)
    464 
    465 	case NAME_NONE:
    466 		switch {
    467 		case a.Reg == REG_NONE:
    468 			str = fmt.Sprint(a.Offset)
    469 		case a.Offset == 0:
    470 			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
    471 		case a.Offset != 0:
    472 			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
    473 		}
    474 
    475 	case NAME_EXTERN:
    476 		str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
    477 
    478 	case NAME_GOTREF:
    479 		str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
    480 
    481 	case NAME_STATIC:
    482 		str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
    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, 12k)
    532 )
    533 
    534 // RegisterRegister binds a pretty-printer (Rconv) for register
    535 // numbers to a given register number range.  Lo is inclusive,
    536 // hi exclusive (valid registers are lo through hi-1).
    537 func RegisterRegister(lo, hi int, Rconv func(int) string) {
    538 	regSpace = append(regSpace, regSet{lo, hi, Rconv})
    539 }
    540 
    541 func Rconv(reg int) string {
    542 	if reg == REG_NONE {
    543 		return "NONE"
    544 	}
    545 	for i := range regSpace {
    546 		rs := &regSpace[i]
    547 		if rs.lo <= reg && reg < rs.hi {
    548 			return rs.Rconv(reg)
    549 		}
    550 	}
    551 	return fmt.Sprintf("R???%d", reg)
    552 }
    553 
    554 func regListConv(list int) string {
    555 	str := ""
    556 
    557 	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
    558 		if list&(1<<uint(i)) != 0 {
    559 			if str == "" {
    560 				str += "["
    561 			} else {
    562 				str += ","
    563 			}
    564 			// This is ARM-specific; R10 is g.
    565 			if i == 10 {
    566 				str += "g"
    567 			} else {
    568 				str += fmt.Sprintf("R%d", i)
    569 			}
    570 		}
    571 	}
    572 
    573 	str += "]"
    574 	return str
    575 }
    576 
    577 /*
    578 	Each architecture defines an instruction (A*) space as a unique
    579 	integer range.
    580 	Global opcodes like CALL start at 0; the architecture-specific ones
    581 	start at a distinct, big-maskable offsets.
    582 	Here is the list of architectures and the base of their opcode spaces.
    583 */
    584 
    585 const (
    586 	ABase386 = (1 + iota) << 12
    587 	ABaseARM
    588 	ABaseAMD64
    589 	ABasePPC64
    590 	ABaseARM64
    591 	AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
    592 )
    593 
    594 type opSet struct {
    595 	lo    int
    596 	names []string
    597 }
    598 
    599 // Not even worth sorting
    600 var aSpace []opSet
    601 
    602 // RegisterOpcode binds a list of instruction names
    603 // to a given instruction number range.
    604 func RegisterOpcode(lo int, Anames []string) {
    605 	aSpace = append(aSpace, opSet{lo, Anames})
    606 }
    607 
    608 func Aconv(a int) string {
    609 	if a < A_ARCHSPECIFIC {
    610 		return Anames[a]
    611 	}
    612 	for i := range aSpace {
    613 		as := &aSpace[i]
    614 		if as.lo <= a && a < as.lo+len(as.names) {
    615 			return as.names[a-as.lo]
    616 		}
    617 	}
    618 	return fmt.Sprintf("A???%d", a)
    619 }
    620 
    621 var Anames = []string{
    622 	"XXX",
    623 	"CALL",
    624 	"CHECKNIL",
    625 	"DATA",
    626 	"DUFFCOPY",
    627 	"DUFFZERO",
    628 	"END",
    629 	"FUNCDATA",
    630 	"GLOBL",
    631 	"JMP",
    632 	"NOP",
    633 	"PCDATA",
    634 	"RET",
    635 	"TEXT",
    636 	"TYPE",
    637 	"UNDEF",
    638 	"USEFIELD",
    639 	"VARDEF",
    640 	"VARKILL",
    641 }
    642 
    643 func Bool2int(b bool) int {
    644 	if b {
    645 		return 1
    646 	}
    647 	return 0
    648 }
    649