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