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.
22 func Cputime() float64 {
26 return time.Since(start).Seconds()
36 func Bopenw(name string) (*Biobuf, error) {
37 f, err := os.Create(name)
41 return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
44 func Bopenr(name string) (*Biobuf, error) {
45 f, err := os.Open(name)
49 return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
52 func Binitw(w io.Writer) *Biobuf {
53 return &Biobuf{w: bufio.NewWriter(w)}
56 func Binitr(r io.Reader) *Biobuf {
57 return &Biobuf{r: bufio.NewReader(r)}
60 func (b *Biobuf) Write(p []byte) (int, error) {
64 func Bwritestring(b *Biobuf, p string) (int, error) {
65 return b.w.WriteString(p)
68 func Bseek(b *Biobuf, offset int64, whence int) int64 {
70 if err := b.w.Flush(); err != nil {
71 log.Fatalf("writing output: %v", err)
73 } else if b.r != nil {
75 offset -= int64(b.r.Buffered())
78 off, err := b.f.Seek(offset, whence)
80 log.Fatalf("seeking in output: %v", err)
88 func Boffset(b *Biobuf) int64 {
90 if err := b.w.Flush(); err != nil {
91 log.Fatalf("writing output: %v", err)
94 off, err := b.f.Seek(0, 1)
96 log.Fatalf("seeking in output [0, 1]: %v", err)
99 off -= int64(b.r.Buffered())
104 func (b *Biobuf) Flush() error {
108 func Bputc(b *Biobuf, c byte) {
114 func Bread(b *Biobuf, p []byte) int {
115 n, err := io.ReadFull(b.r, p)
117 if err != nil && err != io.EOF {
124 func Bgetc(b *Biobuf) int {
125 c, err := b.r.ReadByte()
132 func Bgetrune(b *Biobuf) int {
133 r, _, err := b.r.ReadRune()
140 func Bungetrune(b *Biobuf) {
144 func (b *Biobuf) Read(p []byte) (int, error) {
148 func (b *Biobuf) Peek(n int) ([]byte, error) {
152 func Brdline(b *Biobuf, delim int) string {
153 s, err := b.r.ReadBytes(byte(delim))
155 log.Fatalf("reading input: %v", err)
161 func Brdstr(b *Biobuf, delim int, cut int) string {
162 s, err := b.r.ReadString(byte(delim))
164 log.Fatalf("reading input: %v", err)
166 if len(s) > 0 && cut > 0 {
172 func Blinelen(b *Biobuf) int {
176 func Bterm(b *Biobuf) error {
188 func envOr(key, value string) string {
189 if x := os.Getenv(key); x != "" {
195 func Getgoroot() string {
196 return envOr("GOROOT", defaultGOROOT)
199 func Getgoarch() string {
200 return envOr("GOARCH", defaultGOARCH)
203 func Getgoos() string {
204 return envOr("GOOS", defaultGOOS)
207 func Getgoarm() int32 {
208 switch v := envOr("GOARM", defaultGOARM); v {
216 // Fail here, rather than validate at multiple call sites.
217 log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
221 func Getgo386() string {
222 // Validated by cmd/compile.
223 return envOr("GO386", defaultGO386)
226 func Getgoextlinkenabled() string {
227 return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
230 func Getgoversion() string {
234 func (p *Prog) Line() string {
235 return p.Ctxt.LineHist.LineString(int(p.Lineno))
238 var armCondCode = []string{
259 C_SCOND = (1 << 4) - 1
268 // CConv formats ARM condition codes.
269 func CConv(s uint8) string {
273 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR]
283 if s&C_UBIT != 0 { /* ambiguous with FBIT */
289 func (p *Prog) String() string {
291 return "<Prog without ctxt>"
298 fmt.Fprintf(&buf, "%.5d (%v)\t%v%s", p.Pc, p.Line(), Aconv(int(p.As)), sc)
300 if p.From.Type != TYPE_NONE {
301 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From))
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)))
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)
314 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, p.From3))
318 if p.To.Type != TYPE_NONE {
319 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To))
321 if p.RegTo2 != REG_NONE {
322 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
327 func (ctxt *Link) NewProg() *Prog {
328 p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
333 func (ctxt *Link) Line(n int) string {
334 return ctxt.LineHist.LineString(n)
337 func Getcallerpc(interface{}) uintptr {
341 func (ctxt *Link) Dconv(a *Addr) string {
345 func Dconv(p *Prog, a *Addr) string {
350 str = fmt.Sprintf("type=%d", a.Type)
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)))
359 // TODO(rsc): This special case is for x86 instructions like
361 // where the $1 is included in the p->to Addr.
362 // Move into a new field.
364 str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
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)))
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)
381 str = fmt.Sprintf("%d(PC)", a.Offset)
385 str = fmt.Sprintf("*%s", Mconv(a))
389 if a.Index != REG_NONE {
390 str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
392 if p.As == ATYPE && a.Gotype != nil {
393 str += fmt.Sprintf("%s", a.Gotype.Name)
398 str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
400 str = fmt.Sprintf("$%v", Mconv(a))
404 if a.Val.(int32) == ArgsSizeUnknown {
405 str = fmt.Sprintf("$%d", a.Offset)
407 str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
411 str = fmt.Sprintf("%.17g", a.Val.(float64))
412 // Make sure 1 prints as 1.0
413 if !strings.ContainsAny(str, ".e") {
416 str = fmt.Sprintf("$(%s)", str)
419 str = fmt.Sprintf("$%q", a.Val.(string))
422 str = fmt.Sprintf("$%s", Mconv(a))
426 op := string("<<>>->@>"[((v>>5)&3)<<1:])
428 str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
430 str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
433 str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
437 str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
440 str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
443 str = regListConv(int(a.Offset))
449 func Mconv(a *Addr) string {
454 str = fmt.Sprintf("name=%d", a.Name)
458 case a.Reg == REG_NONE:
459 str = fmt.Sprint(a.Offset)
461 str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
463 str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
468 str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
470 str = fmt.Sprintf("%s(SB)", offConv(a.Offset))
475 str = fmt.Sprintf("%s%s@GOT(SB)", a.Sym.Name, offConv(a.Offset))
477 str = fmt.Sprintf("%s@GOT(SB)", offConv(a.Offset))
482 str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
484 str = fmt.Sprintf("<>%s(SB)", offConv(a.Offset))
489 str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
491 str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
496 str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
498 str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
504 func offConv(off int64) string {
508 return fmt.Sprintf("%+d", off)
514 Rconv func(int) string
517 // Few enough architectures that a linear scan is fastest.
518 // Not even worth sorting.
519 var regSpace []regSet
522 Each architecture defines a register space as a unique
524 Here is the list of architectures and the base of their register spaces.
528 // Because of masking operations in the encodings, each register
529 // space should start at 0 modulo some power of 2.
531 RBaseAMD64 = 2 * 1024
533 RBasePPC64 = 4 * 1024 // range [4k, 8k)
534 RBaseARM64 = 8 * 1024 // range [8k, 13k)
535 RBaseMIPS64 = 13 * 1024 // range [13k, 14k)
538 // RegisterRegister binds a pretty-printer (Rconv) for register
539 // numbers to a given register number range. Lo is inclusive,
540 // hi exclusive (valid registers are lo through hi-1).
541 func RegisterRegister(lo, hi int, Rconv func(int) string) {
542 regSpace = append(regSpace, regSet{lo, hi, Rconv})
545 func Rconv(reg int) string {
549 for i := range regSpace {
551 if rs.lo <= reg && reg < rs.hi {
555 return fmt.Sprintf("R???%d", reg)
558 func regListConv(list int) string {
561 for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
562 if list&(1<<uint(i)) != 0 {
568 // This is ARM-specific; R10 is g.
572 str += fmt.Sprintf("R%d", i)
582 Each architecture defines an instruction (A*) space as a unique
584 Global opcodes like CALL start at 0; the architecture-specific ones
585 start at a distinct, big-maskable offsets.
586 Here is the list of architectures and the base of their opcode spaces.
590 ABase386 = (1 + iota) << 12
596 AMask = 1<<12 - 1 // AND with this to use the opcode as an array index.
604 // Not even worth sorting
607 // RegisterOpcode binds a list of instruction names
608 // to a given instruction number range.
609 func RegisterOpcode(lo int, Anames []string) {
610 aSpace = append(aSpace, opSet{lo, Anames})
613 func Aconv(a int) string {
614 if 0 <= a && a < len(Anames) {
617 for i := range aSpace {
619 if as.lo <= a && a < as.lo+len(as.names) {
620 return as.names[a-as.lo]
623 return fmt.Sprintf("A???%d", a)
626 var Anames = []string{
649 func Bool2int(b bool) int {