github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/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 "bytes" 9 "cmd/internal/objabi" 10 "fmt" 11 "strings" 12 ) 13 14 const REG_NONE = 0 15 16 // Line returns a string containing the filename and line number for p 17 func (p *Prog) Line() string { 18 return p.Ctxt.OutermostPos(p.Pos).Format(false, true) 19 } 20 21 // InnermostLineNumber returns a string containing the line number for the 22 // innermost inlined function (if any inlining) at p's position 23 func (p *Prog) InnermostLineNumber() string { 24 pos := p.Ctxt.InnermostPos(p.Pos) 25 if !pos.IsKnown() { 26 return "?" 27 } 28 return fmt.Sprintf("%d", pos.Line()) 29 } 30 31 // InnermostFilename returns a string containing the innermost 32 // (in inlining) filename at p's position 33 func (p *Prog) InnermostFilename() string { 34 // TODO For now, this is only used for debugging output, and if we need more/better information, it might change. 35 // An example of what we might want to see is the full stack of positions for inlined code, so we get some visibility into what is recorded there. 36 pos := p.Ctxt.InnermostPos(p.Pos) 37 if !pos.IsKnown() { 38 return "<unknown file name>" 39 } 40 return pos.Filename() 41 } 42 43 var armCondCode = []string{ 44 ".EQ", 45 ".NE", 46 ".CS", 47 ".CC", 48 ".MI", 49 ".PL", 50 ".VS", 51 ".VC", 52 ".HI", 53 ".LS", 54 ".GE", 55 ".LT", 56 ".GT", 57 ".LE", 58 "", 59 ".NV", 60 } 61 62 /* ARM scond byte */ 63 const ( 64 C_SCOND = (1 << 4) - 1 65 C_SBIT = 1 << 4 66 C_PBIT = 1 << 5 67 C_WBIT = 1 << 6 68 C_FBIT = 1 << 7 69 C_UBIT = 1 << 7 70 C_SCOND_XOR = 14 71 ) 72 73 // CConv formats ARM condition codes. 74 func CConv(s uint8) string { 75 if s == 0 { 76 return "" 77 } 78 sc := armCondCode[(s&C_SCOND)^C_SCOND_XOR] 79 if s&C_SBIT != 0 { 80 sc += ".S" 81 } 82 if s&C_PBIT != 0 { 83 sc += ".P" 84 } 85 if s&C_WBIT != 0 { 86 sc += ".W" 87 } 88 if s&C_UBIT != 0 { /* ambiguous with FBIT */ 89 sc += ".U" 90 } 91 return sc 92 } 93 94 func (p *Prog) String() string { 95 if p == nil { 96 return "<nil Prog>" 97 } 98 if p.Ctxt == nil { 99 return "<Prog without ctxt>" 100 } 101 return fmt.Sprintf("%.5d (%v)\t%s", p.Pc, p.Line(), p.InstructionString()) 102 } 103 104 // InstructionString returns a string representation of the instruction without preceding 105 // program counter or file and line number. 106 func (p *Prog) InstructionString() string { 107 if p == nil { 108 return "<nil Prog>" 109 } 110 111 if p.Ctxt == nil { 112 return "<Prog without ctxt>" 113 } 114 115 sc := CConv(p.Scond) 116 117 var buf bytes.Buffer 118 119 fmt.Fprintf(&buf, "%v%s", p.As, sc) 120 sep := "\t" 121 122 if p.From.Type != TYPE_NONE { 123 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.From)) 124 sep = ", " 125 } 126 if p.Reg != REG_NONE { 127 // Should not happen but might as well show it if it does. 128 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.Reg))) 129 sep = ", " 130 } 131 for i := range p.RestArgs { 132 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.RestArgs[i])) 133 sep = ", " 134 } 135 136 if p.As == ATEXT { 137 // If there are attributes, print them. Otherwise, skip the comma. 138 // In short, print one of these two: 139 // TEXT foo(SB), DUPOK|NOSPLIT, $0 140 // TEXT foo(SB), $0 141 s := p.From.Sym.Attribute.TextAttrString() 142 if s != "" { 143 fmt.Fprintf(&buf, "%s%s", sep, s) 144 sep = ", " 145 } 146 } 147 if p.To.Type != TYPE_NONE { 148 fmt.Fprintf(&buf, "%s%v", sep, Dconv(p, &p.To)) 149 } 150 if p.RegTo2 != REG_NONE { 151 fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2))) 152 } 153 return buf.String() 154 } 155 156 func (ctxt *Link) NewProg() *Prog { 157 p := new(Prog) 158 p.Ctxt = ctxt 159 return p 160 } 161 162 func (ctxt *Link) CanReuseProgs() bool { 163 return !ctxt.Debugasm 164 } 165 166 func (ctxt *Link) Dconv(a *Addr) string { 167 return Dconv(nil, a) 168 } 169 170 func Dconv(p *Prog, a *Addr) string { 171 var str string 172 173 switch a.Type { 174 default: 175 str = fmt.Sprintf("type=%d", a.Type) 176 177 case TYPE_NONE: 178 str = "" 179 if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil { 180 str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg))) 181 } 182 183 case TYPE_REG: 184 // TODO(rsc): This special case is for x86 instructions like 185 // PINSRQ CX,$1,X6 186 // where the $1 is included in the p->to Addr. 187 // Move into a new field. 188 if a.Offset != 0 && (a.Reg < RBaseARM64 || a.Reg >= RBaseMIPS) { 189 str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg))) 190 break 191 } 192 193 str = Rconv(int(a.Reg)) 194 if a.Name != NAME_NONE || a.Sym != nil { 195 str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg))) 196 } 197 if (RBaseARM64+1<<10+1<<9) /* arm64.REG_ELEM */ <= a.Reg && 198 a.Reg < (RBaseARM64+1<<11) /* arm64.REG_ELEM_END */ { 199 str += fmt.Sprintf("[%d]", a.Index) 200 } 201 202 case TYPE_BRANCH: 203 if a.Sym != nil { 204 str = fmt.Sprintf("%s(SB)", a.Sym.Name) 205 } else if p != nil && p.Pcond != nil { 206 str = fmt.Sprint(p.Pcond.Pc) 207 } else if a.Val != nil { 208 str = fmt.Sprint(a.Val.(*Prog).Pc) 209 } else { 210 str = fmt.Sprintf("%d(PC)", a.Offset) 211 } 212 213 case TYPE_INDIR: 214 str = fmt.Sprintf("*%s", Mconv(a)) 215 216 case TYPE_MEM: 217 str = Mconv(a) 218 if a.Index != REG_NONE { 219 str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale)) 220 } 221 222 case TYPE_CONST: 223 if a.Reg != 0 { 224 str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg))) 225 } else { 226 str = fmt.Sprintf("$%v", Mconv(a)) 227 } 228 229 case TYPE_TEXTSIZE: 230 if a.Val.(int32) == objabi.ArgsSizeUnknown { 231 str = fmt.Sprintf("$%d", a.Offset) 232 } else { 233 str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32)) 234 } 235 236 case TYPE_FCONST: 237 str = fmt.Sprintf("%.17g", a.Val.(float64)) 238 // Make sure 1 prints as 1.0 239 if !strings.ContainsAny(str, ".e") { 240 str += ".0" 241 } 242 str = fmt.Sprintf("$(%s)", str) 243 244 case TYPE_SCONST: 245 str = fmt.Sprintf("$%q", a.Val.(string)) 246 247 case TYPE_ADDR: 248 str = fmt.Sprintf("$%s", Mconv(a)) 249 250 case TYPE_SHIFT: 251 v := int(a.Offset) 252 ops := "<<>>->@>" 253 switch objabi.GOARCH { 254 case "arm": 255 op := ops[((v>>5)&3)<<1:] 256 if v&(1<<4) != 0 { 257 str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15) 258 } else { 259 str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31) 260 } 261 if a.Reg != 0 { 262 str += fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 263 } 264 case "arm64": 265 op := ops[((v>>22)&3)<<1:] 266 str = fmt.Sprintf("R%d%c%c%d", (v>>16)&31, op[0], op[1], (v>>10)&63) 267 default: 268 panic("TYPE_SHIFT is not supported on " + objabi.GOARCH) 269 } 270 271 case TYPE_REGREG: 272 str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset))) 273 274 case TYPE_REGREG2: 275 str = fmt.Sprintf("%v, %v", Rconv(int(a.Offset)), Rconv(int(a.Reg))) 276 277 case TYPE_REGLIST: 278 str = RLconv(a.Offset) 279 } 280 281 return str 282 } 283 284 func Mconv(a *Addr) string { 285 var str string 286 287 switch a.Name { 288 default: 289 str = fmt.Sprintf("name=%d", a.Name) 290 291 case NAME_NONE: 292 switch { 293 case a.Reg == REG_NONE: 294 str = fmt.Sprint(a.Offset) 295 case a.Offset == 0: 296 str = fmt.Sprintf("(%v)", Rconv(int(a.Reg))) 297 case a.Offset != 0: 298 str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg))) 299 } 300 301 // Note: a.Reg == REG_NONE encodes the default base register for the NAME_ type. 302 case NAME_EXTERN: 303 reg := "SB" 304 if a.Reg != REG_NONE { 305 reg = Rconv(int(a.Reg)) 306 } 307 if a.Sym != nil { 308 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 309 } else { 310 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 311 } 312 313 case NAME_GOTREF: 314 reg := "SB" 315 if a.Reg != REG_NONE { 316 reg = Rconv(int(a.Reg)) 317 } 318 if a.Sym != nil { 319 str = fmt.Sprintf("%s%s@GOT(%s)", a.Sym.Name, offConv(a.Offset), reg) 320 } else { 321 str = fmt.Sprintf("%s@GOT(%s)", offConv(a.Offset), reg) 322 } 323 324 case NAME_STATIC: 325 reg := "SB" 326 if a.Reg != REG_NONE { 327 reg = Rconv(int(a.Reg)) 328 } 329 if a.Sym != nil { 330 str = fmt.Sprintf("%s<>%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 331 } else { 332 str = fmt.Sprintf("<>%s(%s)", offConv(a.Offset), reg) 333 } 334 335 case NAME_AUTO: 336 reg := "SP" 337 if a.Reg != REG_NONE { 338 reg = Rconv(int(a.Reg)) 339 } 340 if a.Sym != nil { 341 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 342 } else { 343 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 344 } 345 346 case NAME_PARAM: 347 reg := "FP" 348 if a.Reg != REG_NONE { 349 reg = Rconv(int(a.Reg)) 350 } 351 if a.Sym != nil { 352 str = fmt.Sprintf("%s%s(%s)", a.Sym.Name, offConv(a.Offset), reg) 353 } else { 354 str = fmt.Sprintf("%s(%s)", offConv(a.Offset), reg) 355 } 356 } 357 return str 358 } 359 360 func offConv(off int64) string { 361 if off == 0 { 362 return "" 363 } 364 return fmt.Sprintf("%+d", off) 365 } 366 367 type regSet struct { 368 lo int 369 hi int 370 Rconv func(int) string 371 } 372 373 // Few enough architectures that a linear scan is fastest. 374 // Not even worth sorting. 375 var regSpace []regSet 376 377 /* 378 Each architecture defines a register space as a unique 379 integer range. 380 Here is the list of architectures and the base of their register spaces. 381 */ 382 383 const ( 384 // Because of masking operations in the encodings, each register 385 // space should start at 0 modulo some power of 2. 386 RBase386 = 1 * 1024 387 RBaseAMD64 = 2 * 1024 388 RBaseARM = 3 * 1024 389 RBasePPC64 = 4 * 1024 // range [4k, 8k) 390 RBaseARM64 = 8 * 1024 // range [8k, 13k) 391 RBaseMIPS = 13 * 1024 // range [13k, 14k) 392 RBaseS390X = 14 * 1024 // range [14k, 15k) 393 ) 394 395 // RegisterRegister binds a pretty-printer (Rconv) for register 396 // numbers to a given register number range. Lo is inclusive, 397 // hi exclusive (valid registers are lo through hi-1). 398 func RegisterRegister(lo, hi int, Rconv func(int) string) { 399 regSpace = append(regSpace, regSet{lo, hi, Rconv}) 400 } 401 402 func Rconv(reg int) string { 403 if reg == REG_NONE { 404 return "NONE" 405 } 406 for i := range regSpace { 407 rs := ®Space[i] 408 if rs.lo <= reg && reg < rs.hi { 409 return rs.Rconv(reg) 410 } 411 } 412 return fmt.Sprintf("R???%d", reg) 413 } 414 415 type regListSet struct { 416 lo int64 417 hi int64 418 RLconv func(int64) string 419 } 420 421 var regListSpace []regListSet 422 423 // Each architecture is allotted a distinct subspace: [Lo, Hi) for declaring its 424 // arch-specific register list numbers. 425 const ( 426 RegListARMLo = 0 427 RegListARMHi = 1 << 16 428 429 // arm64 uses the 60th bit to differentiate from other archs 430 RegListARM64Lo = 1 << 60 431 RegListARM64Hi = 1<<61 - 1 432 ) 433 434 // RegisterRegisterList binds a pretty-printer (RLconv) for register list 435 // numbers to a given register list number range. Lo is inclusive, 436 // hi exclusive (valid register list are lo through hi-1). 437 func RegisterRegisterList(lo, hi int64, rlconv func(int64) string) { 438 regListSpace = append(regListSpace, regListSet{lo, hi, rlconv}) 439 } 440 441 func RLconv(list int64) string { 442 for i := range regListSpace { 443 rls := ®ListSpace[i] 444 if rls.lo <= list && list < rls.hi { 445 return rls.RLconv(list) 446 } 447 } 448 return fmt.Sprintf("RL???%d", list) 449 } 450 451 type opSet struct { 452 lo As 453 names []string 454 } 455 456 // Not even worth sorting 457 var aSpace []opSet 458 459 // RegisterOpcode binds a list of instruction names 460 // to a given instruction number range. 461 func RegisterOpcode(lo As, Anames []string) { 462 if len(Anames) > AllowedOpCodes { 463 panic(fmt.Sprintf("too many instructions, have %d max %d", len(Anames), AllowedOpCodes)) 464 } 465 aSpace = append(aSpace, opSet{lo, Anames}) 466 } 467 468 func (a As) String() string { 469 if 0 <= a && int(a) < len(Anames) { 470 return Anames[a] 471 } 472 for i := range aSpace { 473 as := &aSpace[i] 474 if as.lo <= a && int(a-as.lo) < len(as.names) { 475 return as.names[a-as.lo] 476 } 477 } 478 return fmt.Sprintf("A???%d", a) 479 } 480 481 var Anames = []string{ 482 "XXX", 483 "CALL", 484 "DUFFCOPY", 485 "DUFFZERO", 486 "END", 487 "FUNCDATA", 488 "JMP", 489 "NOP", 490 "PCDATA", 491 "RET", 492 "TEXT", 493 "UNDEF", 494 } 495 496 func Bool2int(b bool) int { 497 // The compiler currently only optimizes this form. 498 // See issue 6011. 499 var i int 500 if b { 501 i = 1 502 } else { 503 i = 0 504 } 505 return i 506 }