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