github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/cmd/link/internal/ld/pcln.go (about) 1 // Copyright 2013 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 ld 6 7 import ( 8 "cmd/internal/objabi" 9 "cmd/internal/src" 10 "cmd/internal/sys" 11 "cmd/link/internal/sym" 12 "log" 13 "os" 14 "path/filepath" 15 "strings" 16 ) 17 18 // iteration over encoded pcdata tables. 19 20 func getvarint(pp *[]byte) uint32 { 21 v := uint32(0) 22 p := *pp 23 for shift := 0; ; shift += 7 { 24 v |= uint32(p[0]&0x7F) << uint(shift) 25 tmp4 := p 26 p = p[1:] 27 if tmp4[0]&0x80 == 0 { 28 break 29 } 30 } 31 32 *pp = p 33 return v 34 } 35 36 func pciternext(it *Pciter) { 37 it.pc = it.nextpc 38 if it.done != 0 { 39 return 40 } 41 if -cap(it.p) >= -cap(it.d.P[len(it.d.P):]) { 42 it.done = 1 43 return 44 } 45 46 // value delta 47 v := getvarint(&it.p) 48 49 if v == 0 && it.start == 0 { 50 it.done = 1 51 return 52 } 53 54 it.start = 0 55 dv := int32(v>>1) ^ (int32(v<<31) >> 31) 56 it.value += dv 57 58 // pc delta 59 v = getvarint(&it.p) 60 61 it.nextpc = it.pc + v*it.pcscale 62 } 63 64 func pciterinit(ctxt *Link, it *Pciter, d *sym.Pcdata) { 65 it.d = *d 66 it.p = it.d.P 67 it.pc = 0 68 it.nextpc = 0 69 it.value = -1 70 it.start = 1 71 it.done = 0 72 it.pcscale = uint32(ctxt.Arch.MinLC) 73 pciternext(it) 74 } 75 76 func addvarint(d *sym.Pcdata, val uint32) { 77 n := int32(0) 78 for v := val; v >= 0x80; v >>= 7 { 79 n++ 80 } 81 n++ 82 83 old := len(d.P) 84 for cap(d.P) < len(d.P)+int(n) { 85 d.P = append(d.P[:cap(d.P)], 0) 86 } 87 d.P = d.P[:old+int(n)] 88 89 p := d.P[old:] 90 var v uint32 91 for v = val; v >= 0x80; v >>= 7 { 92 p[0] = byte(v | 0x80) 93 p = p[1:] 94 } 95 p[0] = byte(v) 96 } 97 98 func addpctab(ctxt *Link, ftab *sym.Symbol, off int32, d *sym.Pcdata) int32 { 99 var start int32 100 if len(d.P) > 0 { 101 start = int32(len(ftab.P)) 102 ftab.AddBytes(d.P) 103 } 104 return int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(start))) 105 } 106 107 func ftabaddstring(ctxt *Link, ftab *sym.Symbol, s string) int32 { 108 n := int32(len(s)) + 1 109 start := int32(len(ftab.P)) 110 ftab.Grow(int64(start) + int64(n) + 1) 111 copy(ftab.P[start:], s) 112 return start 113 } 114 115 // numberfile assigns a file number to the file if it hasn't been assigned already. 116 func numberfile(ctxt *Link, file *sym.Symbol) { 117 if file.Type != sym.SFILEPATH { 118 ctxt.Filesyms = append(ctxt.Filesyms, file) 119 file.Value = int64(len(ctxt.Filesyms)) 120 file.Type = sym.SFILEPATH 121 path := file.Name[len(src.FileSymPrefix):] 122 file.Name = expandGoroot(path) 123 } 124 } 125 126 func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) { 127 // Give files numbers. 128 for _, f := range files { 129 numberfile(ctxt, f) 130 } 131 132 newval := int32(-1) 133 var out sym.Pcdata 134 var it Pciter 135 for pciterinit(ctxt, &it, d); it.done == 0; pciternext(&it) { 136 // value delta 137 oldval := it.value 138 139 var val int32 140 if oldval == -1 { 141 val = -1 142 } else { 143 if oldval < 0 || oldval >= int32(len(files)) { 144 log.Fatalf("bad pcdata %d", oldval) 145 } 146 val = int32(files[oldval].Value) 147 } 148 149 dv := val - newval 150 newval = val 151 v := (uint32(dv) << 1) ^ uint32(dv>>31) 152 addvarint(&out, v) 153 154 // pc delta 155 addvarint(&out, (it.nextpc-it.pc)/it.pcscale) 156 } 157 158 // terminating value delta 159 addvarint(&out, 0) 160 161 *d = out 162 } 163 164 // onlycsymbol reports whether this is a symbol that is referenced by C code. 165 func onlycsymbol(s *sym.Symbol) bool { 166 switch s.Name { 167 case "_cgo_topofstack", "_cgo_panic", "crosscall2": 168 return true 169 } 170 if strings.HasPrefix(s.Name, "_cgoexp_") { 171 return true 172 } 173 return false 174 } 175 176 func emitPcln(ctxt *Link, s *sym.Symbol) bool { 177 if s == nil { 178 return true 179 } 180 if ctxt.BuildMode == BuildModePlugin && ctxt.HeadType == objabi.Hdarwin && onlycsymbol(s) { 181 return false 182 } 183 // We want to generate func table entries only for the "lowest level" symbols, 184 // not containers of subsymbols. 185 if s.Attr.Container() { 186 return true 187 } 188 return true 189 } 190 191 // pclntab initializes the pclntab symbol with 192 // runtime function and file name information. 193 194 var pclntabZpcln sym.FuncInfo 195 196 // These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab. 197 var pclntabNfunc int32 198 var pclntabFiletabOffset int32 199 var pclntabPclntabOffset int32 200 var pclntabFirstFunc *sym.Symbol 201 var pclntabLastFunc *sym.Symbol 202 203 func (ctxt *Link) pclntab() { 204 funcdataBytes := int64(0) 205 ftab := ctxt.Syms.Lookup("runtime.pclntab", 0) 206 ftab.Type = sym.SPCLNTAB 207 ftab.Attr |= sym.AttrReachable 208 209 // See golang.org/s/go12symtab for the format. Briefly: 210 // 8-byte header 211 // nfunc [thearch.ptrsize bytes] 212 // function table, alternating PC and offset to func struct [each entry thearch.ptrsize bytes] 213 // end PC [thearch.ptrsize bytes] 214 // offset to file table [4 bytes] 215 nfunc := int32(0) 216 217 // Find container symbols and mark them as such. 218 for _, s := range ctxt.Textp { 219 if s.Outer != nil { 220 s.Outer.Attr |= sym.AttrContainer 221 } 222 } 223 224 for _, s := range ctxt.Textp { 225 if emitPcln(ctxt, s) { 226 nfunc++ 227 } 228 } 229 230 pclntabNfunc = nfunc 231 ftab.Grow(8 + int64(ctxt.Arch.PtrSize) + int64(nfunc)*2*int64(ctxt.Arch.PtrSize) + int64(ctxt.Arch.PtrSize) + 4) 232 ftab.SetUint32(ctxt.Arch, 0, 0xfffffffb) 233 ftab.SetUint8(ctxt.Arch, 6, uint8(ctxt.Arch.MinLC)) 234 ftab.SetUint8(ctxt.Arch, 7, uint8(ctxt.Arch.PtrSize)) 235 ftab.SetUint(ctxt.Arch, 8, uint64(nfunc)) 236 pclntabPclntabOffset = int32(8 + ctxt.Arch.PtrSize) 237 238 funcnameoff := make(map[string]int32) 239 nameToOffset := func(name string) int32 { 240 nameoff, ok := funcnameoff[name] 241 if !ok { 242 nameoff = ftabaddstring(ctxt, ftab, name) 243 funcnameoff[name] = nameoff 244 } 245 return nameoff 246 } 247 248 nfunc = 0 249 var last *sym.Symbol 250 for _, s := range ctxt.Textp { 251 last = s 252 if !emitPcln(ctxt, s) { 253 continue 254 } 255 pcln := s.FuncInfo 256 if pcln == nil { 257 pcln = &pclntabZpcln 258 } 259 260 if pclntabFirstFunc == nil { 261 pclntabFirstFunc = s 262 } 263 264 if len(pcln.InlTree) > 0 { 265 if len(pcln.Pcdata) <= objabi.PCDATA_InlTreeIndex { 266 // Create inlining pcdata table. 267 pcdata := make([]sym.Pcdata, objabi.PCDATA_InlTreeIndex+1) 268 copy(pcdata, pcln.Pcdata) 269 pcln.Pcdata = pcdata 270 } 271 272 if len(pcln.Funcdataoff) <= objabi.FUNCDATA_InlTree { 273 // Create inline tree funcdata. 274 funcdata := make([]*sym.Symbol, objabi.FUNCDATA_InlTree+1) 275 funcdataoff := make([]int64, objabi.FUNCDATA_InlTree+1) 276 copy(funcdata, pcln.Funcdata) 277 copy(funcdataoff, pcln.Funcdataoff) 278 pcln.Funcdata = funcdata 279 pcln.Funcdataoff = funcdataoff 280 } 281 } 282 283 funcstart := int32(len(ftab.P)) 284 funcstart += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1) 285 286 ftab.SetAddr(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), s) 287 ftab.SetUint(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint64(funcstart)) 288 289 // Write runtime._func. Keep in sync with ../../../../runtime/runtime2.go:/_func 290 // and package debug/gosym. 291 292 // fixed size of struct, checked below 293 off := funcstart 294 295 end := funcstart + int32(ctxt.Arch.PtrSize) + 3*4 + 5*4 + int32(len(pcln.Pcdata))*4 + int32(len(pcln.Funcdata))*int32(ctxt.Arch.PtrSize) 296 if len(pcln.Funcdata) > 0 && (end&int32(ctxt.Arch.PtrSize-1) != 0) { 297 end += 4 298 } 299 ftab.Grow(int64(end)) 300 301 // entry uintptr 302 off = int32(ftab.SetAddr(ctxt.Arch, int64(off), s)) 303 304 // name int32 305 nameoff := nameToOffset(s.Name) 306 off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(nameoff))) 307 308 // args int32 309 // TODO: Move into funcinfo. 310 args := uint32(0) 311 if s.FuncInfo != nil { 312 args = uint32(s.FuncInfo.Args) 313 } 314 off = int32(ftab.SetUint32(ctxt.Arch, int64(off), args)) 315 316 // deferreturn 317 deferreturn := uint32(0) 318 lastWasmAddr := uint32(0) 319 for _, r := range s.R { 320 if ctxt.Arch.Family == sys.Wasm && r.Type == objabi.R_ADDR { 321 // Wasm does not have a live variable set at the deferreturn 322 // call itself. Instead it has one identified by the 323 // resumption point immediately preceding the deferreturn. 324 // The wasm code has a R_ADDR relocation which is used to 325 // set the resumption point to PC_B. 326 lastWasmAddr = uint32(r.Add) 327 } 328 if r.Sym != nil && r.Sym.Name == "runtime.deferreturn" && r.Add == 0 { 329 if ctxt.Arch.Family == sys.Wasm { 330 deferreturn = lastWasmAddr 331 } else { 332 // Note: the relocation target is in the call instruction, but 333 // is not necessarily the whole instruction (for instance, on 334 // x86 the relocation applies to bytes [1:5] of the 5 byte call 335 // instruction). 336 deferreturn = uint32(r.Off) 337 } 338 break // only need one 339 } 340 } 341 off = int32(ftab.SetUint32(ctxt.Arch, int64(off), deferreturn)) 342 343 if pcln != &pclntabZpcln { 344 renumberfiles(ctxt, pcln.File, &pcln.Pcfile) 345 if false { 346 // Sanity check the new numbering 347 var it Pciter 348 for pciterinit(ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) { 349 if it.value < 1 || it.value > int32(len(ctxt.Filesyms)) { 350 Errorf(s, "bad file number in pcfile: %d not in range [1, %d]\n", it.value, len(ctxt.Filesyms)) 351 errorexit() 352 } 353 } 354 } 355 } 356 357 if len(pcln.InlTree) > 0 { 358 inlTreeSym := ctxt.Syms.Lookup("inltree."+s.Name, 0) 359 inlTreeSym.Type = sym.SRODATA 360 inlTreeSym.Attr |= sym.AttrReachable | sym.AttrDuplicateOK 361 362 for i, call := range pcln.InlTree { 363 // Usually, call.File is already numbered since the file 364 // shows up in the Pcfile table. However, two inlined calls 365 // might overlap exactly so that only the innermost file 366 // appears in the Pcfile table. In that case, this assigns 367 // the outer file a number. 368 numberfile(ctxt, call.File) 369 nameoff := nameToOffset(call.Func.Name) 370 371 inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+0), uint32(call.Parent)) 372 inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+4), uint32(call.File.Value)) 373 inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+8), uint32(call.Line)) 374 inlTreeSym.SetUint32(ctxt.Arch, int64(i*16+12), uint32(nameoff)) 375 } 376 377 pcln.Funcdata[objabi.FUNCDATA_InlTree] = inlTreeSym 378 pcln.Pcdata[objabi.PCDATA_InlTreeIndex] = pcln.Pcinline 379 } 380 381 // pcdata 382 off = addpctab(ctxt, ftab, off, &pcln.Pcsp) 383 384 off = addpctab(ctxt, ftab, off, &pcln.Pcfile) 385 off = addpctab(ctxt, ftab, off, &pcln.Pcline) 386 off = int32(ftab.SetUint32(ctxt.Arch, int64(off), uint32(len(pcln.Pcdata)))) 387 388 // funcID uint8 389 funcID := objabi.FuncID_normal 390 switch s.Name { 391 case "runtime.main": 392 funcID = objabi.FuncID_runtime_main 393 case "runtime.goexit": 394 funcID = objabi.FuncID_goexit 395 case "runtime.jmpdefer": 396 funcID = objabi.FuncID_jmpdefer 397 case "runtime.mcall": 398 funcID = objabi.FuncID_mcall 399 case "runtime.morestack": 400 funcID = objabi.FuncID_morestack 401 case "runtime.mstart": 402 funcID = objabi.FuncID_mstart 403 case "runtime.rt0_go": 404 funcID = objabi.FuncID_rt0_go 405 case "runtime.asmcgocall": 406 funcID = objabi.FuncID_asmcgocall 407 case "runtime.sigpanic": 408 funcID = objabi.FuncID_sigpanic 409 case "runtime.runfinq": 410 funcID = objabi.FuncID_runfinq 411 case "runtime.gcBgMarkWorker": 412 funcID = objabi.FuncID_gcBgMarkWorker 413 case "runtime.systemstack_switch": 414 funcID = objabi.FuncID_systemstack_switch 415 case "runtime.systemstack": 416 funcID = objabi.FuncID_systemstack 417 case "runtime.cgocallback_gofunc": 418 funcID = objabi.FuncID_cgocallback_gofunc 419 case "runtime.gogo": 420 funcID = objabi.FuncID_gogo 421 case "runtime.externalthreadhandler": 422 funcID = objabi.FuncID_externalthreadhandler 423 case "runtime.debugCallV1": 424 funcID = objabi.FuncID_debugCallV1 425 } 426 off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(funcID))) 427 428 // unused 429 off += 2 430 431 // nfuncdata must be the final entry. 432 off = int32(ftab.SetUint8(ctxt.Arch, int64(off), uint8(len(pcln.Funcdata)))) 433 for i := range pcln.Pcdata { 434 off = addpctab(ctxt, ftab, off, &pcln.Pcdata[i]) 435 } 436 437 // funcdata, must be pointer-aligned and we're only int32-aligned. 438 // Missing funcdata will be 0 (nil pointer). 439 if len(pcln.Funcdata) > 0 { 440 if off&int32(ctxt.Arch.PtrSize-1) != 0 { 441 off += 4 442 } 443 for i := range pcln.Funcdata { 444 if pcln.Funcdata[i] == nil { 445 ftab.SetUint(ctxt.Arch, int64(off)+int64(ctxt.Arch.PtrSize)*int64(i), uint64(pcln.Funcdataoff[i])) 446 } else { 447 // TODO: Dedup. 448 funcdataBytes += pcln.Funcdata[i].Size 449 450 ftab.SetAddrPlus(ctxt.Arch, int64(off)+int64(ctxt.Arch.PtrSize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i]) 451 } 452 } 453 454 off += int32(len(pcln.Funcdata)) * int32(ctxt.Arch.PtrSize) 455 } 456 457 if off != end { 458 Errorf(s, "bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, len(pcln.Pcdata), len(pcln.Funcdata), ctxt.Arch.PtrSize) 459 errorexit() 460 } 461 462 nfunc++ 463 } 464 465 pclntabLastFunc = last 466 // Final entry of table is just end pc. 467 ftab.SetAddrPlus(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize), last, last.Size) 468 469 // Start file table. 470 start := int32(len(ftab.P)) 471 472 start += int32(-len(ftab.P)) & (int32(ctxt.Arch.PtrSize) - 1) 473 pclntabFiletabOffset = start 474 ftab.SetUint32(ctxt.Arch, 8+int64(ctxt.Arch.PtrSize)+int64(nfunc)*2*int64(ctxt.Arch.PtrSize)+int64(ctxt.Arch.PtrSize), uint32(start)) 475 476 ftab.Grow(int64(start) + (int64(len(ctxt.Filesyms))+1)*4) 477 ftab.SetUint32(ctxt.Arch, int64(start), uint32(len(ctxt.Filesyms)+1)) 478 for i := len(ctxt.Filesyms) - 1; i >= 0; i-- { 479 s := ctxt.Filesyms[i] 480 ftab.SetUint32(ctxt.Arch, int64(start)+s.Value*4, uint32(ftabaddstring(ctxt, ftab, s.Name))) 481 } 482 483 ftab.Size = int64(len(ftab.P)) 484 485 if ctxt.Debugvlog != 0 { 486 ctxt.Logf("%5.2f pclntab=%d bytes, funcdata total %d bytes\n", Cputime(), ftab.Size, funcdataBytes) 487 } 488 } 489 490 func gorootFinal() string { 491 root := objabi.GOROOT 492 if final := os.Getenv("GOROOT_FINAL"); final != "" { 493 root = final 494 } 495 return root 496 } 497 498 func expandGoroot(s string) string { 499 const n = len("$GOROOT") 500 if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') { 501 return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:])) 502 } 503 return s 504 } 505 506 const ( 507 BUCKETSIZE = 256 * MINFUNC 508 SUBBUCKETS = 16 509 SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS 510 NOIDX = 0x7fffffff 511 ) 512 513 // findfunctab generates a lookup table to quickly find the containing 514 // function for a pc. See src/runtime/symtab.go:findfunc for details. 515 func (ctxt *Link) findfunctab() { 516 t := ctxt.Syms.Lookup("runtime.findfunctab", 0) 517 t.Type = sym.SRODATA 518 t.Attr |= sym.AttrReachable 519 t.Attr |= sym.AttrLocal 520 521 // find min and max address 522 min := ctxt.Textp[0].Value 523 max := int64(0) 524 for _, s := range ctxt.Textp { 525 max = s.Value + s.Size 526 } 527 528 // for each subbucket, compute the minimum of all symbol indexes 529 // that map to that subbucket. 530 n := int32((max - min + SUBBUCKETSIZE - 1) / SUBBUCKETSIZE) 531 532 indexes := make([]int32, n) 533 for i := int32(0); i < n; i++ { 534 indexes[i] = NOIDX 535 } 536 idx := int32(0) 537 for i, s := range ctxt.Textp { 538 if !emitPcln(ctxt, s) { 539 continue 540 } 541 p := s.Value 542 var e *sym.Symbol 543 i++ 544 if i < len(ctxt.Textp) { 545 e = ctxt.Textp[i] 546 } 547 for !emitPcln(ctxt, e) && i < len(ctxt.Textp) { 548 e = ctxt.Textp[i] 549 i++ 550 } 551 q := max 552 if e != nil { 553 q = e.Value 554 } 555 556 //print("%d: [%lld %lld] %s\n", idx, p, q, s->name); 557 for ; p < q; p += SUBBUCKETSIZE { 558 i = int((p - min) / SUBBUCKETSIZE) 559 if indexes[i] > idx { 560 indexes[i] = idx 561 } 562 } 563 564 i = int((q - 1 - min) / SUBBUCKETSIZE) 565 if indexes[i] > idx { 566 indexes[i] = idx 567 } 568 idx++ 569 } 570 571 // allocate table 572 nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE) 573 574 t.Grow(4*int64(nbuckets) + int64(n)) 575 576 // fill in table 577 for i := int32(0); i < nbuckets; i++ { 578 base := indexes[i*SUBBUCKETS] 579 if base == NOIDX { 580 Errorf(nil, "hole in findfunctab") 581 } 582 t.SetUint32(ctxt.Arch, int64(i)*(4+SUBBUCKETS), uint32(base)) 583 for j := int32(0); j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ { 584 idx = indexes[i*SUBBUCKETS+j] 585 if idx == NOIDX { 586 Errorf(nil, "hole in findfunctab") 587 } 588 if idx-base >= 256 { 589 Errorf(nil, "too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base) 590 } 591 592 t.SetUint8(ctxt.Arch, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base)) 593 } 594 } 595 }