github.com/undoio/delve@v1.9.0/pkg/proc/bininfo.go (about) 1 package proc 2 3 import ( 4 "bytes" 5 "debug/dwarf" 6 "debug/elf" 7 "debug/macho" 8 "debug/pe" 9 "encoding/binary" 10 "encoding/hex" 11 "errors" 12 "fmt" 13 "go/ast" 14 "go/token" 15 "io" 16 "os" 17 "path/filepath" 18 "sort" 19 "strconv" 20 "strings" 21 "sync" 22 "time" 23 24 "github.com/undoio/delve/pkg/dwarf/frame" 25 "github.com/undoio/delve/pkg/dwarf/godwarf" 26 "github.com/undoio/delve/pkg/dwarf/line" 27 "github.com/undoio/delve/pkg/dwarf/loclist" 28 "github.com/undoio/delve/pkg/dwarf/op" 29 "github.com/undoio/delve/pkg/dwarf/reader" 30 "github.com/undoio/delve/pkg/dwarf/util" 31 "github.com/undoio/delve/pkg/goversion" 32 "github.com/undoio/delve/pkg/logflags" 33 "github.com/undoio/delve/pkg/proc/debuginfod" 34 "github.com/hashicorp/golang-lru/simplelru" 35 "github.com/sirupsen/logrus" 36 ) 37 38 const ( 39 dwarfGoLanguage = 22 // DW_LANG_Go (from DWARF v5, section 7.12, page 231) 40 dwarfAttrAddrBase = 0x74 // debug/dwarf.AttrAddrBase in Go 1.14, defined here for compatibility with Go < 1.14 41 dwarfTreeCacheSize = 512 // size of the dwarfTree cache of each image 42 ) 43 44 // BinaryInfo holds information on the binaries being executed (this 45 // includes both the executable and also any loaded libraries). 46 type BinaryInfo struct { 47 // Architecture of this binary. 48 Arch *Arch 49 50 // GOOS operating system this binary is executing on. 51 GOOS string 52 53 debugInfoDirectories []string 54 55 // BuildID of this binary. 56 BuildID string 57 58 // Functions is a list of all DW_TAG_subprogram entries in debug_info, sorted by entry point 59 Functions []Function 60 // Sources is a list of all source files found in debug_line. 61 Sources []string 62 // LookupFunc maps function names to a description of the function. 63 LookupFunc map[string]*Function 64 // lookupGenericFunc maps function names, with their type parameters removed, to functions. 65 // Functions that are not generic are not added to this map. 66 lookupGenericFunc map[string][]*Function 67 68 // SymNames maps addr to a description *elf.Symbol of this addr. 69 SymNames map[uint64]*elf.Symbol 70 71 // Images is a list of loaded shared libraries (also known as 72 // shared objects on linux or DLLs on windows). 73 Images []*Image 74 75 ElfDynamicSection ElfDynamicSection 76 77 lastModified time.Time // Time the executable of this process was last modified 78 79 // PackageMap maps package names to package paths, needed to lookup types inside DWARF info. 80 // On Go1.12 this mapping is determined by using the last element of a package path, for example: 81 // github.com/undoio/delve 82 // will map to 'delve' because it ends in '/delve'. 83 // Starting with Go1.13 debug_info will contain a special attribute 84 // (godwarf.AttrGoPackageName) containing the canonical package name for 85 // each package. 86 // If multiple packages have the same name the map entry will have more 87 // than one item in the slice. 88 PackageMap map[string][]string 89 90 frameEntries frame.FrameDescriptionEntries 91 92 types map[string]dwarfRef 93 packageVars []packageVar // packageVars is a list of all global/package variables in debug_info, sorted by address 94 95 gStructOffset uint64 96 97 // nameOfRuntimeType maps an address of a runtime._type struct to its 98 // decoded name. Used with versions of Go <= 1.10 to figure out the DIE of 99 // the concrete type of interfaces. 100 nameOfRuntimeType map[uint64]nameOfRuntimeTypeEntry 101 102 // consts[off] lists all the constants with the type defined at offset off. 103 consts constantsMap 104 105 // inlinedCallLines maps a file:line pair, corresponding to the header line 106 // of a function to a list of PC addresses where an inlined call to that 107 // function starts. 108 inlinedCallLines map[fileLine][]uint64 109 110 // dwrapUnwrapCache caches unwrapping of defer wrapper functions (dwrap) 111 dwrapUnwrapCache map[uint64]*Function 112 113 // Go 1.17 register ABI is enabled. 114 regabi bool 115 116 logger *logrus.Entry 117 } 118 119 var ( 120 // ErrCouldNotDetermineRelocation is an error returned when Delve could not determine the base address of a 121 // position independent executable. 122 ErrCouldNotDetermineRelocation = errors.New("could not determine the base address of a PIE") 123 124 // ErrNoDebugInfoFound is returned when Delve cannot open the debug_info 125 // section or find an external debug info file. 126 ErrNoDebugInfoFound = errors.New("could not open debug info") 127 ) 128 129 var ( 130 supportedLinuxArch = map[elf.Machine]bool{ 131 elf.EM_X86_64: true, 132 elf.EM_AARCH64: true, 133 elf.EM_386: true, 134 } 135 136 supportedWindowsArch = map[_PEMachine]bool{ 137 _IMAGE_FILE_MACHINE_AMD64: true, 138 } 139 140 supportedDarwinArch = map[macho.Cpu]bool{ 141 macho.CpuAmd64: true, 142 macho.CpuArm64: true, 143 } 144 ) 145 146 // ErrFunctionNotFound is returned when failing to find the 147 // function named 'FuncName' within the binary. 148 type ErrFunctionNotFound struct { 149 FuncName string 150 } 151 152 func (err *ErrFunctionNotFound) Error() string { 153 return fmt.Sprintf("could not find function %s\n", err.FuncName) 154 } 155 156 // FindFileLocation returns the PC for a given file:line. 157 // Assumes that `file` is normalized to lower case and '/' on Windows. 158 func FindFileLocation(p Process, filename string, lineno int) ([]uint64, error) { 159 // A single file:line can appear in multiple concrete functions, because of 160 // generics instantiation as well as multiple inlined calls into other 161 // concrete functions. 162 163 // 1. Find all instructions assigned in debug_line to filename:lineno. 164 165 bi := p.BinInfo() 166 167 fileFound := false 168 pcs := []line.PCStmt{} 169 for _, image := range bi.Images { 170 for _, cu := range image.compileUnits { 171 if cu.lineInfo == nil || cu.lineInfo.Lookup[filename] == nil { 172 continue 173 } 174 175 fileFound = true 176 pcs = append(pcs, cu.lineInfo.LineToPCs(filename, lineno)...) 177 } 178 } 179 180 if len(pcs) == 0 { 181 // Check if the line contained a call to a function that was inlined, in 182 // that case it's possible for the line itself to not appear in debug_line 183 // at all, but it will still be in debug_info as the call site for an 184 // inlined subroutine entry. 185 for _, pc := range bi.inlinedCallLines[fileLine{filename, lineno}] { 186 pcs = append(pcs, line.PCStmt{PC: pc, Stmt: true}) 187 } 188 } 189 190 if len(pcs) == 0 { 191 return nil, &ErrCouldNotFindLine{fileFound, filename, lineno} 192 } 193 194 // 2. assign all occurrences of filename:lineno to their containing function 195 196 pcByFunc := map[*Function][]line.PCStmt{} 197 sort.Slice(pcs, func(i, j int) bool { return pcs[i].PC < pcs[j].PC }) 198 var fn *Function 199 for _, pcstmt := range pcs { 200 if fn == nil || (pcstmt.PC < fn.Entry) || (pcstmt.PC >= fn.End) { 201 fn = p.BinInfo().PCToFunc(pcstmt.PC) 202 } 203 if fn != nil { 204 pcByFunc[fn] = append(pcByFunc[fn], pcstmt) 205 } 206 } 207 208 selectedPCs := []uint64{} 209 210 for fn, pcs := range pcByFunc { 211 212 // 3. for each concrete function split instruction between the inlined functions it contains 213 214 if strings.Contains(fn.Name, "·dwrap·") || fn.trampoline { 215 // skip autogenerated functions 216 continue 217 } 218 219 dwtree, err := fn.cu.image.getDwarfTree(fn.offset) 220 if err != nil { 221 return nil, fmt.Errorf("loading DWARF for %s@%#x: %v", fn.Name, fn.offset, err) 222 } 223 inlrngs := allInlineCallRanges(dwtree) 224 225 // findInlRng returns the DWARF offset of the inlined call containing pc. 226 // If multiple nested inlined calls contain pc the deepest one is returned 227 // (since allInlineCallRanges returns inlined call by decreasing depth 228 // this is the first matching entry of the slice). 229 findInlRng := func(pc uint64) dwarf.Offset { 230 for _, inlrng := range inlrngs { 231 if inlrng.rng[0] <= pc && pc < inlrng.rng[1] { 232 return inlrng.off 233 } 234 } 235 return fn.offset 236 } 237 238 pcsByOff := map[dwarf.Offset][]line.PCStmt{} 239 240 for _, pc := range pcs { 241 off := findInlRng(pc.PC) 242 pcsByOff[off] = append(pcsByOff[off], pc) 243 } 244 245 // 4. pick the first instruction with stmt set for each inlined call as 246 // well as the main body of the concrete function. If nothing has 247 // is_stmt set pick the first instruction instead. 248 249 for off, pcs := range pcsByOff { 250 sort.Slice(pcs, func(i, j int) bool { return pcs[i].PC < pcs[j].PC }) 251 252 var selectedPC uint64 253 for _, pc := range pcs { 254 if pc.Stmt { 255 selectedPC = pc.PC 256 break 257 } 258 } 259 260 if selectedPC == 0 && len(pcs) > 0 { 261 selectedPC = pcs[0].PC 262 } 263 264 if selectedPC == 0 { 265 continue 266 } 267 268 // 5. if we picked the entry point of the function, skip it 269 270 if off == fn.offset && fn.Entry == selectedPC { 271 selectedPC, _ = FirstPCAfterPrologue(p, fn, true) 272 } 273 274 selectedPCs = append(selectedPCs, selectedPC) 275 } 276 } 277 278 sort.Slice(selectedPCs, func(i, j int) bool { return selectedPCs[i] < selectedPCs[j] }) 279 280 return selectedPCs, nil 281 } 282 283 // inlRnage is the range of an inlined call 284 type inlRange struct { 285 off dwarf.Offset 286 depth uint32 287 rng [2]uint64 288 } 289 290 // allInlineCallRanges returns all inlined calls contained inside 'tree' in 291 // reverse nesting order (i.e. the most nested calls are returned first). 292 // Note that a single inlined call might not have a continuous range of 293 // addresses and therefore appear multiple times in the returned slice. 294 func allInlineCallRanges(tree *godwarf.Tree) []inlRange { 295 r := []inlRange{} 296 297 var visit func(*godwarf.Tree, uint32) 298 visit = func(n *godwarf.Tree, depth uint32) { 299 if n.Tag == dwarf.TagInlinedSubroutine { 300 for _, rng := range n.Ranges { 301 r = append(r, inlRange{off: n.Offset, depth: depth, rng: rng}) 302 } 303 } 304 for _, child := range n.Children { 305 visit(child, depth+1) 306 } 307 } 308 visit(tree, 0) 309 310 sort.SliceStable(r, func(i, j int) bool { return r[i].depth > r[j].depth }) 311 return r 312 } 313 314 // FindFunction returns the functions with name funcName. 315 func (bi *BinaryInfo) FindFunction(funcName string) ([]*Function, error) { 316 if fn := bi.LookupFunc[funcName]; fn != nil { 317 return []*Function{fn}, nil 318 } 319 fns := bi.LookupGenericFunc()[funcName] 320 if len(fns) == 0 { 321 return nil, &ErrFunctionNotFound{funcName} 322 } 323 return fns, nil 324 } 325 326 // FindFunctionLocation finds address of a function's line 327 // If lineOffset is passed FindFunctionLocation will return the address of that line 328 func FindFunctionLocation(p Process, funcName string, lineOffset int) ([]uint64, error) { 329 bi := p.BinInfo() 330 origfns, err := bi.FindFunction(funcName) 331 if err != nil { 332 return nil, err 333 } 334 335 if lineOffset > 0 { 336 fn := origfns[0] 337 filename, lineno := fn.cu.lineInfo.PCToLine(fn.Entry, fn.Entry) 338 return FindFileLocation(p, filename, lineno+lineOffset) 339 } 340 341 r := make([]uint64, 0, len(origfns[0].InlinedCalls)+len(origfns)) 342 343 for _, origfn := range origfns { 344 if origfn.Entry > 0 { 345 // add concrete implementation of the function 346 pc, err := FirstPCAfterPrologue(p, origfn, false) 347 if err != nil { 348 return nil, err 349 } 350 r = append(r, pc) 351 } 352 // add inlined calls to the function 353 for _, call := range origfn.InlinedCalls { 354 r = append(r, call.LowPC) 355 } 356 if len(r) == 0 { 357 return nil, &ErrFunctionNotFound{funcName} 358 } 359 } 360 sort.Slice(r, func(i, j int) bool { return r[i] < r[j] }) 361 return r, nil 362 } 363 364 // FirstPCAfterPrologue returns the address of the first 365 // instruction after the prologue for function fn. 366 // If sameline is set FirstPCAfterPrologue will always return an 367 // address associated with the same line as fn.Entry. 368 func FirstPCAfterPrologue(p Process, fn *Function, sameline bool) (uint64, error) { 369 pc, _, line, ok := fn.cu.lineInfo.PrologueEndPC(fn.Entry, fn.End) 370 if ok { 371 if !sameline { 372 return pc, nil 373 } 374 _, entryLine := fn.cu.lineInfo.PCToLine(fn.Entry, fn.Entry) 375 if entryLine == line { 376 return pc, nil 377 } 378 } 379 380 pc, err := firstPCAfterPrologueDisassembly(p, fn, sameline) 381 if err != nil { 382 return fn.Entry, err 383 } 384 385 if pc == fn.Entry { 386 // Look for the first instruction with the stmt flag set, so that setting a 387 // breakpoint with file:line and with the function name always result on 388 // the same instruction being selected. 389 if pc2, _, _, ok := fn.cu.lineInfo.FirstStmtForLine(fn.Entry, fn.End); ok { 390 return pc2, nil 391 } 392 } 393 394 return pc, nil 395 } 396 397 // cpuArch is a stringer interface representing CPU architectures. 398 type cpuArch interface { 399 String() string 400 } 401 402 // ErrUnsupportedArch is returned when attempting to debug a binary compiled for an unsupported architecture. 403 type ErrUnsupportedArch struct { 404 os string 405 cpuArch cpuArch 406 } 407 408 func (e *ErrUnsupportedArch) Error() string { 409 var supportArchs []cpuArch 410 switch e.os { 411 case "linux": 412 for linuxArch := range supportedLinuxArch { 413 supportArchs = append(supportArchs, linuxArch) 414 } 415 case "windows": 416 for windowArch := range supportedWindowsArch { 417 supportArchs = append(supportArchs, windowArch) 418 } 419 case "darwin": 420 for darwinArch := range supportedDarwinArch { 421 supportArchs = append(supportArchs, darwinArch) 422 } 423 } 424 425 errStr := "unsupported architecture of " + e.os + "/" + e.cpuArch.String() 426 errStr += " - only" 427 for _, arch := range supportArchs { 428 errStr += " " + e.os + "/" + arch.String() + " " 429 } 430 if len(supportArchs) == 1 { 431 errStr += "is supported" 432 } else { 433 errStr += "are supported" 434 } 435 436 return errStr 437 } 438 439 type compileUnit struct { 440 name string // univocal name for non-go compile units 441 Version uint8 // DWARF version of this compile unit 442 lowPC uint64 443 ranges [][2]uint64 444 445 entry *dwarf.Entry // debug_info entry describing this compile unit 446 isgo bool // true if this is the go compile unit 447 lineInfo *line.DebugLineInfo // debug_line segment associated with this compile unit 448 optimized bool // this compile unit is optimized 449 producer string // producer attribute 450 451 offset dwarf.Offset // offset of the entry describing the compile unit 452 453 image *Image // parent image of this compilation unit. 454 } 455 456 type fileLine struct { 457 file string 458 line int 459 } 460 461 // dwarfRef is a reference to a Debug Info Entry inside a shared object. 462 type dwarfRef struct { 463 imageIndex int 464 offset dwarf.Offset 465 } 466 467 // InlinedCall represents a concrete inlined call to a function. 468 type InlinedCall struct { 469 cu *compileUnit 470 LowPC, HighPC uint64 // Address range of the generated inlined instructions 471 } 472 473 // Function describes a function in the target program. 474 type Function struct { 475 Name string 476 Entry, End uint64 // same as DW_AT_lowpc and DW_AT_highpc 477 offset dwarf.Offset 478 cu *compileUnit 479 480 trampoline bool // DW_AT_trampoline attribute set to true 481 482 // InlinedCalls lists all inlined calls to this function 483 InlinedCalls []InlinedCall 484 } 485 486 // instRange returns the indexes in fn.Name of the type parameter 487 // instantiation, which is the position of the outermost '[' and ']'. 488 // If fn is not an instantiated function both returned values will be len(fn.Name) 489 func (fn *Function) instRange() [2]int { 490 d := len(fn.Name) 491 inst := [2]int{d, d} 492 if strings.HasPrefix(fn.Name, "type..") { 493 return inst 494 } 495 inst[0] = strings.Index(fn.Name, "[") 496 if inst[0] < 0 { 497 inst[0] = d 498 return inst 499 } 500 inst[1] = strings.LastIndex(fn.Name, "]") 501 if inst[1] < 0 { 502 inst[0] = d 503 inst[1] = d 504 return inst 505 } 506 return inst 507 } 508 509 // PackageName returns the package part of the symbol name, 510 // or the empty string if there is none. 511 // Borrowed from $GOROOT/debug/gosym/symtab.go 512 func (fn *Function) PackageName() string { 513 inst := fn.instRange() 514 return packageName(fn.Name[:inst[0]]) 515 } 516 517 func packageName(name string) string { 518 pathend := strings.LastIndex(name, "/") 519 if pathend < 0 { 520 pathend = 0 521 } 522 523 if i := strings.Index(name[pathend:], "."); i != -1 { 524 return name[:pathend+i] 525 } 526 return "" 527 } 528 529 // ReceiverName returns the receiver type name of this symbol, 530 // or the empty string if there is none. 531 // Borrowed from $GOROOT/debug/gosym/symtab.go 532 func (fn *Function) ReceiverName() string { 533 inst := fn.instRange() 534 pathend := strings.LastIndex(fn.Name[:inst[0]], "/") 535 if pathend < 0 { 536 pathend = 0 537 } 538 l := strings.Index(fn.Name[pathend:], ".") 539 if l == -1 { 540 return "" 541 } 542 if r := strings.LastIndex(fn.Name[inst[1]:], "."); r != -1 && pathend+l != inst[1]+r { 543 return fn.Name[pathend+l+1 : inst[1]+r] 544 } else if r := strings.LastIndex(fn.Name[pathend:inst[0]], "."); r != -1 && l != r { 545 return fn.Name[pathend+l+1 : pathend+r] 546 } 547 return "" 548 } 549 550 // BaseName returns the symbol name without the package or receiver name. 551 // Borrowed from $GOROOT/debug/gosym/symtab.go 552 func (fn *Function) BaseName() string { 553 inst := fn.instRange() 554 if i := strings.LastIndex(fn.Name[inst[1]:], "."); i != -1 { 555 return fn.Name[inst[1]+i+1:] 556 } else if i := strings.LastIndex(fn.Name[:inst[0]], "."); i != -1 { 557 return fn.Name[i+1:] 558 } 559 return fn.Name 560 } 561 562 // NameWithoutTypeParams returns the function name without instantiation parameters 563 func (fn *Function) NameWithoutTypeParams() string { 564 inst := fn.instRange() 565 if inst[0] == inst[1] { 566 return fn.Name 567 } 568 return fn.Name[:inst[0]] + fn.Name[inst[1]+1:] 569 } 570 571 // Optimized returns true if the function was optimized by the compiler. 572 func (fn *Function) Optimized() bool { 573 return fn.cu.optimized 574 } 575 576 // PrologueEndPC returns the PC just after the function prologue 577 func (fn *Function) PrologueEndPC() uint64 { 578 pc, _, _, ok := fn.cu.lineInfo.PrologueEndPC(fn.Entry, fn.End) 579 if !ok { 580 return fn.Entry 581 } 582 return pc 583 } 584 585 // From $GOROOT/src/runtime/traceback.go:597 586 // exportedRuntime reports whether the function is an exported runtime function. 587 // It is only for runtime functions, so ASCII A-Z is fine. 588 func (fn *Function) exportedRuntime() bool { 589 name := fn.Name 590 const n = len("runtime.") 591 return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' 592 } 593 594 // unexportedRuntime reports whether the function is a private runtime function. 595 func (fn *Function) privateRuntime() bool { 596 name := fn.Name 597 const n = len("runtime.") 598 return len(name) > n && name[:n] == "runtime." && !('A' <= name[n] && name[n] <= 'Z') 599 } 600 601 type constantsMap map[dwarfRef]*constantType 602 603 type constantType struct { 604 initialized bool 605 values []constantValue 606 } 607 608 type constantValue struct { 609 name string 610 fullName string 611 value int64 612 singleBit bool 613 } 614 615 // packageVar represents a package-level variable (or a C global variable). 616 // If a global variable does not have an address (for example it's stored in 617 // a register, or non-contiguously) addr will be 0. 618 type packageVar struct { 619 name string 620 cu *compileUnit 621 offset dwarf.Offset 622 addr uint64 623 } 624 625 type buildIDHeader struct { 626 Namesz uint32 627 Descsz uint32 628 Type uint32 629 } 630 631 // ElfDynamicSection describes the .dynamic section of an ELF executable. 632 type ElfDynamicSection struct { 633 Addr uint64 // relocated address of where the .dynamic section is mapped in memory 634 Size uint64 // size of the .dynamic section of the executable 635 } 636 637 // NewBinaryInfo returns an initialized but unloaded BinaryInfo struct. 638 func NewBinaryInfo(goos, goarch string) *BinaryInfo { 639 r := &BinaryInfo{GOOS: goos, nameOfRuntimeType: make(map[uint64]nameOfRuntimeTypeEntry), logger: logflags.DebuggerLogger()} 640 641 // TODO: find better way to determine proc arch (perhaps use executable file info). 642 switch goarch { 643 case "386": 644 r.Arch = I386Arch(goos) 645 case "amd64": 646 r.Arch = AMD64Arch(goos) 647 case "arm64": 648 r.Arch = ARM64Arch(goos) 649 } 650 return r 651 } 652 653 // LoadBinaryInfo will load and store the information from the binary at 'path'. 654 func (bi *BinaryInfo) LoadBinaryInfo(path string, entryPoint uint64, debugInfoDirs []string) error { 655 fi, err := os.Stat(path) 656 if err == nil { 657 bi.lastModified = fi.ModTime() 658 } 659 660 bi.debugInfoDirectories = debugInfoDirs 661 662 return bi.AddImage(path, entryPoint) 663 } 664 665 func loadBinaryInfo(bi *BinaryInfo, image *Image, path string, entryPoint uint64) error { 666 var wg sync.WaitGroup 667 defer wg.Wait() 668 669 switch bi.GOOS { 670 case "linux", "freebsd": 671 return loadBinaryInfoElf(bi, image, path, entryPoint, &wg) 672 case "windows": 673 return loadBinaryInfoPE(bi, image, path, entryPoint, &wg) 674 case "darwin": 675 return loadBinaryInfoMacho(bi, image, path, entryPoint, &wg) 676 } 677 return errors.New("unsupported operating system") 678 } 679 680 // GStructOffset returns the offset of the G 681 // struct in thread local storage. 682 func (bi *BinaryInfo) GStructOffset() uint64 { 683 return bi.gStructOffset 684 } 685 686 // LastModified returns the last modified time of the binary. 687 func (bi *BinaryInfo) LastModified() time.Time { 688 return bi.lastModified 689 } 690 691 // DwarfReader returns a reader for the dwarf data 692 func (so *Image) DwarfReader() *reader.Reader { 693 return reader.New(so.dwarf) 694 } 695 696 // Types returns list of types present in the debugged program. 697 func (bi *BinaryInfo) Types() ([]string, error) { 698 types := make([]string, 0, len(bi.types)) 699 for k := range bi.types { 700 types = append(types, k) 701 } 702 return types, nil 703 } 704 705 // PCToLine converts an instruction address to a file/line/function. 706 func (bi *BinaryInfo) PCToLine(pc uint64) (string, int, *Function) { 707 fn := bi.PCToFunc(pc) 708 if fn == nil { 709 return "", 0, nil 710 } 711 f, ln := fn.cu.lineInfo.PCToLine(fn.Entry, pc) 712 return f, ln, fn 713 } 714 715 type ErrCouldNotFindLine struct { 716 fileFound bool 717 filename string 718 lineno int 719 } 720 721 func (err *ErrCouldNotFindLine) Error() string { 722 if err.fileFound { 723 return fmt.Sprintf("could not find statement at %s:%d, please use a line with a statement", err.filename, err.lineno) 724 } 725 return fmt.Sprintf("could not find file %s", err.filename) 726 } 727 728 // AllPCsForFileLines returns a map providing all PC addresses for filename and each line in linenos 729 func (bi *BinaryInfo) AllPCsForFileLines(filename string, linenos []int) map[int][]uint64 { 730 r := make(map[int][]uint64) 731 for _, line := range linenos { 732 r[line] = make([]uint64, 0, 1) 733 } 734 for _, image := range bi.Images { 735 for _, cu := range image.compileUnits { 736 if cu.lineInfo != nil && cu.lineInfo.Lookup[filename] != nil { 737 cu.lineInfo.AllPCsForFileLines(filename, r) 738 } 739 } 740 } 741 return r 742 } 743 744 // PCToFunc returns the concrete function containing the given PC address. 745 // If the PC address belongs to an inlined call it will return the containing function. 746 func (bi *BinaryInfo) PCToFunc(pc uint64) *Function { 747 i := sort.Search(len(bi.Functions), func(i int) bool { 748 fn := bi.Functions[i] 749 return pc <= fn.Entry || (fn.Entry <= pc && pc < fn.End) 750 }) 751 if i != len(bi.Functions) { 752 fn := &bi.Functions[i] 753 if fn.Entry <= pc && pc < fn.End { 754 return fn 755 } 756 } 757 return nil 758 } 759 760 // PCToImage returns the image containing the given PC address. 761 func (bi *BinaryInfo) PCToImage(pc uint64) *Image { 762 fn := bi.PCToFunc(pc) 763 return bi.funcToImage(fn) 764 } 765 766 // Image represents a loaded library file (shared object on linux, DLL on windows). 767 type Image struct { 768 Path string 769 StaticBase uint64 770 addr uint64 771 772 index int // index of this object in BinaryInfo.SharedObjects 773 774 closer io.Closer 775 sepDebugCloser io.Closer 776 777 dwarf *dwarf.Data 778 dwarfReader *dwarf.Reader 779 loclist2 *loclist.Dwarf2Reader 780 loclist5 *loclist.Dwarf5Reader 781 debugAddr *godwarf.DebugAddrSection 782 debugLineStr []byte 783 784 typeCache map[dwarf.Offset]godwarf.Type 785 786 compileUnits []*compileUnit // compileUnits is sorted by increasing DWARF offset 787 788 dwarfTreeCache *simplelru.LRU 789 runtimeMallocgcTree *godwarf.Tree // patched version of runtime.mallocgc's DIE 790 791 // runtimeTypeToDIE maps between the offset of a runtime._type in 792 // runtime.moduledata.types and the offset of the DIE in debug_info. This 793 // map is filled by using the extended attribute godwarf.AttrGoRuntimeType 794 // which was added in go 1.11. 795 runtimeTypeToDIE map[uint64]runtimeTypeDIE 796 797 loadErrMu sync.Mutex 798 loadErr error 799 } 800 801 func (image *Image) registerRuntimeTypeToDIE(entry *dwarf.Entry, ardr *reader.Reader) { 802 if off, ok := entry.Val(godwarf.AttrGoRuntimeType).(uint64); ok { 803 if _, ok := image.runtimeTypeToDIE[off]; !ok { 804 image.runtimeTypeToDIE[off] = runtimeTypeDIE{entry.Offset, -1} 805 } 806 } 807 } 808 809 // AddImage adds the specified image to bi, loading data asynchronously. 810 // Addr is the relocated entry point for the executable and staticBase (i.e. 811 // the relocation offset) for all other images. 812 // The first image added must be the executable file. 813 func (bi *BinaryInfo) AddImage(path string, addr uint64) error { 814 // Check if the image is already present. 815 if len(bi.Images) > 0 && !strings.HasPrefix(path, "/") { 816 return nil 817 } 818 for _, image := range bi.Images { 819 if image.Path == path && image.addr == addr { 820 return nil 821 } 822 } 823 824 // Actually add the image. 825 image := &Image{Path: path, addr: addr, typeCache: make(map[dwarf.Offset]godwarf.Type)} 826 image.dwarfTreeCache, _ = simplelru.NewLRU(dwarfTreeCacheSize, nil) 827 828 // add Image regardless of error so that we don't attempt to re-add it every time we stop 829 image.index = len(bi.Images) 830 bi.Images = append(bi.Images, image) 831 err := loadBinaryInfo(bi, image, path, addr) 832 if err != nil { 833 bi.Images[len(bi.Images)-1].loadErr = err 834 } 835 bi.macOSDebugFrameBugWorkaround() 836 return err 837 } 838 839 // moduleDataToImage finds the image corresponding to the given module data object. 840 func (bi *BinaryInfo) moduleDataToImage(md *moduleData) *Image { 841 fn := bi.PCToFunc(uint64(md.text)) 842 if fn != nil { 843 return bi.funcToImage(fn) 844 } 845 // Try searching for the image with the closest address preceding md.text 846 var so *Image 847 for i := range bi.Images { 848 if int64(bi.Images[i].StaticBase) > int64(md.text) { 849 continue 850 } 851 if so == nil || int64(bi.Images[i].StaticBase) > int64(so.StaticBase) { 852 so = bi.Images[i] 853 } 854 } 855 return so 856 } 857 858 // imageToModuleData finds the module data in mds corresponding to the given image. 859 func (bi *BinaryInfo) imageToModuleData(image *Image, mds []moduleData) *moduleData { 860 for _, md := range mds { 861 im2 := bi.moduleDataToImage(&md) 862 if im2 != nil && im2.index == image.index { 863 return &md 864 } 865 } 866 return nil 867 } 868 869 // typeToImage returns the image containing the give type. 870 func (bi *BinaryInfo) typeToImage(typ godwarf.Type) *Image { 871 return bi.Images[typ.Common().Index] 872 } 873 874 var errBinaryInfoClose = errors.New("multiple errors closing executable files") 875 876 // Close closes all internal readers. 877 func (bi *BinaryInfo) Close() error { 878 var errs []error 879 for _, image := range bi.Images { 880 if err := image.Close(); err != nil { 881 errs = append(errs, err) 882 } 883 } 884 switch len(errs) { 885 case 0: 886 return nil 887 case 1: 888 return errs[0] 889 default: 890 return errBinaryInfoClose 891 } 892 } 893 894 func (image *Image) Close() error { 895 var err1, err2 error 896 if image.sepDebugCloser != nil { 897 err := image.sepDebugCloser.Close() 898 if err != nil { 899 err1 = fmt.Errorf("closing shared object %q (split dwarf): %v", image.Path, err) 900 } 901 } 902 if image.closer != nil { 903 err := image.closer.Close() 904 if err != nil { 905 err2 = fmt.Errorf("closing shared object %q: %v", image.Path, err) 906 } 907 } 908 if err1 != nil && err2 != nil { 909 return errBinaryInfoClose 910 } 911 if err1 != nil { 912 return err1 913 } 914 return err2 915 } 916 917 func (image *Image) setLoadError(logger *logrus.Entry, fmtstr string, args ...interface{}) { 918 image.loadErrMu.Lock() 919 image.loadErr = fmt.Errorf(fmtstr, args...) 920 image.loadErrMu.Unlock() 921 if logger != nil { 922 logger.Errorf("error loading binary %q: %v", image.Path, image.loadErr) 923 } 924 } 925 926 // LoadError returns any error incurred while loading this image. 927 func (image *Image) LoadError() error { 928 return image.loadErr 929 } 930 931 func (image *Image) getDwarfTree(off dwarf.Offset) (*godwarf.Tree, error) { 932 if image.runtimeMallocgcTree != nil && off == image.runtimeMallocgcTree.Offset { 933 return image.runtimeMallocgcTree, nil 934 } 935 if r, ok := image.dwarfTreeCache.Get(off); ok { 936 return r.(*godwarf.Tree), nil 937 } 938 r, err := godwarf.LoadTree(off, image.dwarf, image.StaticBase) 939 if err != nil { 940 return nil, err 941 } 942 image.dwarfTreeCache.Add(off, r) 943 return r, nil 944 } 945 946 type nilCloser struct{} 947 948 func (c *nilCloser) Close() error { return nil } 949 950 // LoadImageFromData creates a new Image, using the specified data, and adds it to bi. 951 // This is used for debugging BinaryInfo, you should use LoadBinary instead. 952 func (bi *BinaryInfo) LoadImageFromData(dwdata *dwarf.Data, debugFrameBytes, debugLineBytes, debugLocBytes []byte) { 953 image := &Image{} 954 image.closer = (*nilCloser)(nil) 955 image.sepDebugCloser = (*nilCloser)(nil) 956 image.dwarf = dwdata 957 image.typeCache = make(map[dwarf.Offset]godwarf.Type) 958 image.dwarfTreeCache, _ = simplelru.NewLRU(dwarfTreeCacheSize, nil) 959 960 if debugFrameBytes != nil { 961 bi.frameEntries, _ = frame.Parse(debugFrameBytes, frame.DwarfEndian(debugFrameBytes), 0, bi.Arch.PtrSize(), 0) 962 } 963 964 image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize()) 965 966 bi.loadDebugInfoMaps(image, nil, debugLineBytes, nil, nil) 967 968 bi.Images = append(bi.Images, image) 969 } 970 971 func (bi *BinaryInfo) locationExpr(entry godwarf.Entry, attr dwarf.Attr, pc uint64) ([]byte, *locationExpr, error) { 972 //TODO(aarzilli): handle DW_FORM_loclistx attribute form new in DWARFv5 973 a := entry.Val(attr) 974 if a == nil { 975 return nil, nil, fmt.Errorf("no location attribute %s", attr) 976 } 977 if instr, ok := a.([]byte); ok { 978 return instr, &locationExpr{isBlock: true, instr: instr}, nil 979 } 980 off, ok := a.(int64) 981 if !ok { 982 return nil, nil, fmt.Errorf("could not interpret location attribute %s", attr) 983 } 984 instr := bi.loclistEntry(off, pc) 985 if instr == nil { 986 return nil, nil, fmt.Errorf("could not find loclist entry at %#x for address %#x", off, pc) 987 } 988 return instr, &locationExpr{pc: pc, off: off, instr: instr}, nil 989 } 990 991 type locationExpr struct { 992 isBlock bool 993 isEscaped bool 994 off int64 995 pc uint64 996 instr []byte 997 } 998 999 func (le *locationExpr) String() string { 1000 if le == nil { 1001 return "" 1002 } 1003 var descr bytes.Buffer 1004 1005 if le.isBlock { 1006 fmt.Fprintf(&descr, "[block] ") 1007 op.PrettyPrint(&descr, le.instr) 1008 } else { 1009 fmt.Fprintf(&descr, "[%#x:%#x] ", le.off, le.pc) 1010 op.PrettyPrint(&descr, le.instr) 1011 } 1012 1013 if le.isEscaped { 1014 fmt.Fprintf(&descr, " (escaped)") 1015 } 1016 return descr.String() 1017 } 1018 1019 // LocationCovers returns the list of PC addresses that is covered by the 1020 // location attribute 'attr' of entry 'entry'. 1021 func (bi *BinaryInfo) LocationCovers(entry *dwarf.Entry, attr dwarf.Attr) ([][2]uint64, error) { 1022 a := entry.Val(attr) 1023 if a == nil { 1024 return nil, fmt.Errorf("attribute %s not found", attr) 1025 } 1026 if _, isblock := a.([]byte); isblock { 1027 return [][2]uint64{[2]uint64{0, ^uint64(0)}}, nil 1028 } 1029 1030 off, ok := a.(int64) 1031 if !ok { 1032 return nil, fmt.Errorf("attribute %s of unsupported type %T", attr, a) 1033 } 1034 cu := bi.Images[0].findCompileUnitForOffset(entry.Offset) 1035 if cu == nil { 1036 return nil, errors.New("could not find compile unit") 1037 } 1038 if cu.Version >= 5 && cu.image.loclist5 != nil { 1039 return nil, errors.New("LocationCovers does not support DWARFv5") 1040 } 1041 1042 image := cu.image 1043 base := cu.lowPC 1044 if image == nil || image.loclist2.Empty() { 1045 return nil, errors.New("malformed executable") 1046 } 1047 1048 r := [][2]uint64{} 1049 var e loclist.Entry 1050 image.loclist2.Seek(int(off)) 1051 for image.loclist2.Next(&e) { 1052 if e.BaseAddressSelection() { 1053 base = e.HighPC 1054 continue 1055 } 1056 r = append(r, [2]uint64{e.LowPC + base, e.HighPC + base}) 1057 } 1058 return r, nil 1059 } 1060 1061 // Location returns the location described by attribute attr of entry. 1062 // This will either be an int64 address or a slice of Pieces for locations 1063 // that don't correspond to a single memory address (registers, composite 1064 // locations). 1065 func (bi *BinaryInfo) Location(entry godwarf.Entry, attr dwarf.Attr, pc uint64, regs op.DwarfRegisters, mem MemoryReadWriter) (int64, []op.Piece, *locationExpr, error) { 1066 instr, descr, err := bi.locationExpr(entry, attr, pc) 1067 if err != nil { 1068 return 0, nil, nil, err 1069 } 1070 readMemory := op.ReadMemoryFunc(nil) 1071 if mem != nil { 1072 readMemory = mem.ReadMemory 1073 } 1074 addr, pieces, err := op.ExecuteStackProgram(regs, instr, bi.Arch.PtrSize(), readMemory) 1075 return addr, pieces, descr, err 1076 } 1077 1078 // loclistEntry returns the loclist entry in the loclist starting at off, 1079 // for address pc. 1080 func (bi *BinaryInfo) loclistEntry(off int64, pc uint64) []byte { 1081 var base uint64 1082 image := bi.Images[0] 1083 cu := bi.findCompileUnit(pc) 1084 if cu != nil { 1085 base = cu.lowPC 1086 image = cu.image 1087 } 1088 if image == nil { 1089 return nil 1090 } 1091 1092 var loclist loclist.Reader = image.loclist2 1093 var debugAddr *godwarf.DebugAddr 1094 if cu != nil && cu.Version >= 5 && image.loclist5 != nil { 1095 loclist = image.loclist5 1096 if addrBase, ok := cu.entry.Val(dwarfAttrAddrBase).(int64); ok { 1097 debugAddr = image.debugAddr.GetSubsection(uint64(addrBase)) 1098 } 1099 } 1100 1101 if loclist.Empty() { 1102 return nil 1103 } 1104 1105 e, err := loclist.Find(int(off), image.StaticBase, base, pc, debugAddr) 1106 if err != nil { 1107 bi.logger.Errorf("error reading loclist section: %v", err) 1108 return nil 1109 } 1110 if e != nil { 1111 return e.Instr 1112 } 1113 1114 return nil 1115 } 1116 1117 // findCompileUnit returns the compile unit containing address pc. 1118 func (bi *BinaryInfo) findCompileUnit(pc uint64) *compileUnit { 1119 for _, image := range bi.Images { 1120 for _, cu := range image.compileUnits { 1121 for _, rng := range cu.ranges { 1122 if pc >= rng[0] && pc < rng[1] { 1123 return cu 1124 } 1125 } 1126 } 1127 } 1128 return nil 1129 } 1130 1131 func (bi *Image) findCompileUnitForOffset(off dwarf.Offset) *compileUnit { 1132 i := sort.Search(len(bi.compileUnits), func(i int) bool { 1133 return bi.compileUnits[i].offset >= off 1134 }) 1135 if i > 0 { 1136 i-- 1137 } 1138 return bi.compileUnits[i] 1139 } 1140 1141 // Producer returns the value of DW_AT_producer. 1142 func (bi *BinaryInfo) Producer() string { 1143 for _, cu := range bi.Images[0].compileUnits { 1144 if cu.isgo && cu.producer != "" { 1145 return cu.producer 1146 } 1147 } 1148 return "" 1149 } 1150 1151 // Type returns the Dwarf type entry at `offset`. 1152 func (image *Image) Type(offset dwarf.Offset) (godwarf.Type, error) { 1153 return godwarf.ReadType(image.dwarf, image.index, offset, image.typeCache) 1154 } 1155 1156 // funcToImage returns the Image containing function fn, or the 1157 // executable file as a fallback. 1158 func (bi *BinaryInfo) funcToImage(fn *Function) *Image { 1159 if fn == nil { 1160 return bi.Images[0] 1161 } 1162 return fn.cu.image 1163 } 1164 1165 // parseDebugFrameGeneral parses a debug_frame and a eh_frame section. 1166 // At least one of the two must be present and parsed correctly, if 1167 // debug_frame is present it must be parsable correctly. 1168 func (bi *BinaryInfo) parseDebugFrameGeneral(image *Image, debugFrameBytes []byte, debugFrameName string, debugFrameErr error, ehFrameBytes []byte, ehFrameAddr uint64, ehFrameName string, byteOrder binary.ByteOrder) { 1169 if debugFrameBytes == nil && ehFrameBytes == nil { 1170 image.setLoadError(bi.logger, "could not get %s section: %v", debugFrameName, debugFrameErr) 1171 return 1172 } 1173 1174 if debugFrameBytes != nil { 1175 fe, err := frame.Parse(debugFrameBytes, byteOrder, image.StaticBase, bi.Arch.PtrSize(), 0) 1176 if err != nil { 1177 image.setLoadError(bi.logger, "could not parse %s section: %v", debugFrameName, err) 1178 return 1179 } 1180 bi.frameEntries = bi.frameEntries.Append(fe) 1181 } 1182 1183 if ehFrameBytes != nil && ehFrameAddr > 0 { 1184 fe, err := frame.Parse(ehFrameBytes, byteOrder, image.StaticBase, bi.Arch.PtrSize(), ehFrameAddr) 1185 if err != nil { 1186 if debugFrameBytes == nil { 1187 image.setLoadError(bi.logger, "could not parse %s section: %v", ehFrameName, err) 1188 return 1189 } 1190 bi.logger.Warnf("could not parse %s section: %v", ehFrameName, err) 1191 return 1192 } 1193 bi.frameEntries = bi.frameEntries.Append(fe) 1194 } 1195 } 1196 1197 // ELF /////////////////////////////////////////////////////////////// 1198 1199 // openSeparateDebugInfo searches for a file containing the separate 1200 // debug info for the binary using the "build ID" method as described 1201 // in GDB's documentation [1], and if found returns two handles, one 1202 // for the bare file, and another for its corresponding elf.File. 1203 // [1] https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html 1204 // 1205 // Alternatively, if the debug file cannot be found be the build-id, Delve 1206 // will look in directories specified by the debug-info-directories config value. 1207 func (bi *BinaryInfo) openSeparateDebugInfo(image *Image, exe *elf.File, debugInfoDirectories []string) (*os.File, *elf.File, error) { 1208 var debugFilePath string 1209 var err error 1210 for _, dir := range debugInfoDirectories { 1211 var potentialDebugFilePath string 1212 if strings.Contains(dir, "build-id") && len(bi.BuildID) > 2 { 1213 potentialDebugFilePath = fmt.Sprintf("%s/%s/%s.debug", dir, bi.BuildID[:2], bi.BuildID[2:]) 1214 } else if strings.HasPrefix(image.Path, "/proc") { 1215 path, err := filepath.EvalSymlinks(image.Path) 1216 if err == nil { 1217 potentialDebugFilePath = fmt.Sprintf("%s/%s.debug", dir, filepath.Base(path)) 1218 } 1219 } else { 1220 potentialDebugFilePath = fmt.Sprintf("%s/%s.debug", dir, filepath.Base(image.Path)) 1221 } 1222 _, err := os.Stat(potentialDebugFilePath) 1223 if err == nil { 1224 debugFilePath = potentialDebugFilePath 1225 break 1226 } 1227 } 1228 // We cannot find the debug information locally on the system. Try and see if we're on a system that 1229 // has debuginfod so that we can use that in order to find any relevant debug information. 1230 if debugFilePath == "" { 1231 debugFilePath, err = debuginfod.GetDebuginfo(bi.BuildID) 1232 if err != nil { 1233 return nil, nil, ErrNoDebugInfoFound 1234 } 1235 } 1236 sepFile, err := os.OpenFile(debugFilePath, 0, os.ModePerm) 1237 if err != nil { 1238 return nil, nil, errors.New("can't open separate debug file: " + err.Error()) 1239 } 1240 1241 elfFile, err := elf.NewFile(sepFile) 1242 if err != nil { 1243 sepFile.Close() 1244 return nil, nil, fmt.Errorf("can't open separate debug file %q: %v", debugFilePath, err.Error()) 1245 } 1246 1247 if !supportedLinuxArch[elfFile.Machine] { 1248 sepFile.Close() 1249 return nil, nil, fmt.Errorf("can't open separate debug file %q: %v", debugFilePath, &ErrUnsupportedArch{os: "linux", cpuArch: elfFile.Machine}) 1250 } 1251 1252 return sepFile, elfFile, nil 1253 } 1254 1255 // loadBinaryInfoElf specifically loads information from an ELF binary. 1256 func loadBinaryInfoElf(bi *BinaryInfo, image *Image, path string, addr uint64, wg *sync.WaitGroup) error { 1257 exe, err := os.OpenFile(path, 0, os.ModePerm) 1258 if err != nil { 1259 return err 1260 } 1261 image.closer = exe 1262 elfFile, err := elf.NewFile(exe) 1263 if err != nil { 1264 return err 1265 } 1266 if !supportedLinuxArch[elfFile.Machine] { 1267 return &ErrUnsupportedArch{os: "linux", cpuArch: elfFile.Machine} 1268 } 1269 1270 if image.index == 0 { 1271 // adding executable file: 1272 // - addr is entryPoint therefore staticBase needs to be calculated by 1273 // subtracting the entry point specified in the executable file from addr. 1274 // - memory address of the .dynamic section needs to be recorded in 1275 // BinaryInfo so that we can find loaded libraries. 1276 if addr != 0 { 1277 image.StaticBase = addr - elfFile.Entry 1278 } else if elfFile.Type == elf.ET_DYN { 1279 return ErrCouldNotDetermineRelocation 1280 } 1281 if dynsec := elfFile.Section(".dynamic"); dynsec != nil { 1282 bi.ElfDynamicSection.Addr = dynsec.Addr + image.StaticBase 1283 bi.ElfDynamicSection.Size = dynsec.Size 1284 } 1285 } else { 1286 image.StaticBase = addr 1287 } 1288 1289 dwarfFile := elfFile 1290 1291 bi.loadBuildID(image, elfFile) 1292 var debugInfoBytes []byte 1293 image.dwarf, err = elfFile.DWARF() 1294 if err != nil { 1295 var sepFile *os.File 1296 var serr error 1297 sepFile, dwarfFile, serr = bi.openSeparateDebugInfo(image, elfFile, bi.debugInfoDirectories) 1298 if serr != nil { 1299 return serr 1300 } 1301 image.sepDebugCloser = sepFile 1302 image.dwarf, err = dwarfFile.DWARF() 1303 if err != nil { 1304 return err 1305 } 1306 } 1307 1308 debugInfoBytes, err = godwarf.GetDebugSectionElf(dwarfFile, "info") 1309 if err != nil { 1310 return err 1311 } 1312 1313 image.dwarfReader = image.dwarf.Reader() 1314 1315 debugLineBytes, err := godwarf.GetDebugSectionElf(dwarfFile, "line") 1316 if err != nil { 1317 return err 1318 } 1319 debugLocBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "loc") 1320 image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize()) 1321 debugLoclistBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "loclists") 1322 image.loclist5 = loclist.NewDwarf5Reader(debugLoclistBytes) 1323 debugAddrBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "addr") 1324 image.debugAddr = godwarf.ParseAddr(debugAddrBytes) 1325 debugLineStrBytes, _ := godwarf.GetDebugSectionElf(dwarfFile, "line_str") 1326 image.debugLineStr = debugLineStrBytes 1327 1328 wg.Add(3) 1329 go bi.parseDebugFrameElf(image, dwarfFile, elfFile, debugInfoBytes, wg) 1330 go bi.loadDebugInfoMaps(image, debugInfoBytes, debugLineBytes, wg, nil) 1331 go bi.loadSymbolName(image, elfFile, wg) 1332 if image.index == 0 { 1333 // determine g struct offset only when loading the executable file 1334 wg.Add(1) 1335 go bi.setGStructOffsetElf(image, dwarfFile, wg) 1336 } 1337 return nil 1338 } 1339 1340 // _STT_FUNC is a code object, see /usr/include/elf.h for a full definition. 1341 const _STT_FUNC = 2 1342 1343 func (bi *BinaryInfo) loadSymbolName(image *Image, file *elf.File, wg *sync.WaitGroup) { 1344 defer wg.Done() 1345 if bi.SymNames == nil { 1346 bi.SymNames = make(map[uint64]*elf.Symbol) 1347 } 1348 symSecs, _ := file.Symbols() 1349 for _, symSec := range symSecs { 1350 if symSec.Info == _STT_FUNC { // TODO(chainhelen), need to parse others types. 1351 s := symSec 1352 bi.SymNames[symSec.Value+image.StaticBase] = &s 1353 } 1354 } 1355 } 1356 1357 func (bi *BinaryInfo) loadBuildID(image *Image, file *elf.File) { 1358 buildid := file.Section(".note.gnu.build-id") 1359 if buildid == nil { 1360 bi.logger.Warn("can't find build-id note on binary") 1361 return 1362 } 1363 1364 br := buildid.Open() 1365 bh := new(buildIDHeader) 1366 if err := binary.Read(br, binary.LittleEndian, bh); err != nil { 1367 bi.logger.Warnf("can't read build-id header: %v", err) 1368 return 1369 } 1370 1371 name := make([]byte, bh.Namesz) 1372 if err := binary.Read(br, binary.LittleEndian, name); err != nil { 1373 bi.logger.Warnf("can't read build-id name: %v", err) 1374 return 1375 } 1376 1377 if strings.TrimSpace(string(name)) != "GNU\x00" { 1378 bi.logger.Warn("invalid build-id signature") 1379 return 1380 } 1381 1382 descBinary := make([]byte, bh.Descsz) 1383 if err := binary.Read(br, binary.LittleEndian, descBinary); err != nil { 1384 bi.logger.Warnf("can't read build-id desc: %v", err) 1385 return 1386 } 1387 bi.BuildID = hex.EncodeToString(descBinary) 1388 } 1389 1390 func (bi *BinaryInfo) parseDebugFrameElf(image *Image, dwarfFile, exeFile *elf.File, debugInfoBytes []byte, wg *sync.WaitGroup) { 1391 defer wg.Done() 1392 1393 debugFrameData, debugFrameErr := godwarf.GetDebugSectionElf(dwarfFile, "frame") 1394 ehFrameSection := exeFile.Section(".eh_frame") 1395 var ehFrameData []byte 1396 var ehFrameAddr uint64 1397 if ehFrameSection != nil { 1398 ehFrameAddr = ehFrameSection.Addr 1399 ehFrameData, _ = ehFrameSection.Data() 1400 } 1401 1402 bi.parseDebugFrameGeneral(image, debugFrameData, ".debug_frame", debugFrameErr, ehFrameData, ehFrameAddr, ".eh_frame", frame.DwarfEndian(debugInfoBytes)) 1403 } 1404 1405 func (bi *BinaryInfo) setGStructOffsetElf(image *Image, exe *elf.File, wg *sync.WaitGroup) { 1406 defer wg.Done() 1407 1408 // This is a bit arcane. Essentially: 1409 // - If the program is pure Go, it can do whatever it wants, and puts the G 1410 // pointer at %fs-8 on 64 bit. 1411 // - %Gs is the index of private storage in GDT on 32 bit, and puts the G 1412 // pointer at -4(tls). 1413 // - Otherwise, Go asks the external linker to place the G pointer by 1414 // emitting runtime.tlsg, a TLS symbol, which is relocated to the chosen 1415 // offset in libc's TLS block. 1416 // - On ARM64 (but really, any architecture other than i386 and 86x64) the 1417 // offset is calculate using runtime.tls_g and the formula is different. 1418 1419 var tls *elf.Prog 1420 for _, prog := range exe.Progs { 1421 if prog.Type == elf.PT_TLS { 1422 tls = prog 1423 break 1424 } 1425 } 1426 1427 switch exe.Machine { 1428 case elf.EM_X86_64, elf.EM_386: 1429 tlsg := getSymbol(image, bi.logger, exe, "runtime.tlsg") 1430 if tlsg == nil || tls == nil { 1431 bi.gStructOffset = ^uint64(bi.Arch.PtrSize()) + 1 //-ptrSize 1432 return 1433 } 1434 1435 // According to https://reviews.llvm.org/D61824, linkers must pad the actual 1436 // size of the TLS segment to ensure that (tlsoffset%align) == (vaddr%align). 1437 // This formula, copied from the lld code, matches that. 1438 // https://github.com/llvm-mirror/lld/blob/9aef969544981d76bea8e4d1961d3a6980980ef9/ELF/InputSection.cpp#L643 1439 memsz := tls.Memsz + (-tls.Vaddr-tls.Memsz)&(tls.Align-1) 1440 1441 // The TLS register points to the end of the TLS block, which is 1442 // tls.Memsz long. runtime.tlsg is an offset from the beginning of that block. 1443 bi.gStructOffset = ^(memsz) + 1 + tlsg.Value // -tls.Memsz + tlsg.Value 1444 1445 case elf.EM_AARCH64: 1446 tlsg := getSymbol(image, bi.logger, exe, "runtime.tls_g") 1447 if tlsg == nil || tls == nil { 1448 bi.gStructOffset = 2 * uint64(bi.Arch.PtrSize()) 1449 return 1450 } 1451 1452 bi.gStructOffset = tlsg.Value + uint64(bi.Arch.PtrSize()*2) + ((tls.Vaddr - uint64(bi.Arch.PtrSize()*2)) & (tls.Align - 1)) 1453 1454 default: 1455 // we should never get here 1456 panic("architecture not supported") 1457 } 1458 } 1459 1460 func getSymbol(image *Image, logger *logrus.Entry, exe *elf.File, name string) *elf.Symbol { 1461 symbols, err := exe.Symbols() 1462 if err != nil { 1463 image.setLoadError(logger, "could not parse ELF symbols: %v", err) 1464 return nil 1465 } 1466 1467 for _, symbol := range symbols { 1468 if symbol.Name == name { 1469 s := symbol 1470 return &s 1471 } 1472 } 1473 return nil 1474 } 1475 1476 // PE //////////////////////////////////////////////////////////////// 1477 1478 const _IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 0x0040 1479 1480 // loadBinaryInfoPE specifically loads information from a PE binary. 1481 func loadBinaryInfoPE(bi *BinaryInfo, image *Image, path string, entryPoint uint64, wg *sync.WaitGroup) error { 1482 peFile, closer, err := openExecutablePathPE(path) 1483 if err != nil { 1484 return err 1485 } 1486 image.closer = closer 1487 cpuArch := _PEMachine(peFile.Machine) 1488 if !supportedWindowsArch[cpuArch] { 1489 return &ErrUnsupportedArch{os: "windows", cpuArch: cpuArch} 1490 } 1491 image.dwarf, err = peFile.DWARF() 1492 if err != nil { 1493 return err 1494 } 1495 debugInfoBytes, err := godwarf.GetDebugSectionPE(peFile, "info") 1496 if err != nil { 1497 return err 1498 } 1499 1500 //TODO(aarzilli): actually test this when Go supports PIE buildmode on Windows. 1501 opth := peFile.OptionalHeader.(*pe.OptionalHeader64) 1502 if entryPoint != 0 { 1503 image.StaticBase = entryPoint - opth.ImageBase 1504 } else { 1505 if opth.DllCharacteristics&_IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE != 0 { 1506 return ErrCouldNotDetermineRelocation 1507 } 1508 } 1509 1510 image.dwarfReader = image.dwarf.Reader() 1511 1512 debugLineBytes, err := godwarf.GetDebugSectionPE(peFile, "line") 1513 if err != nil { 1514 return err 1515 } 1516 debugLocBytes, _ := godwarf.GetDebugSectionPE(peFile, "loc") 1517 image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize()) 1518 debugLoclistBytes, _ := godwarf.GetDebugSectionPE(peFile, "loclists") 1519 image.loclist5 = loclist.NewDwarf5Reader(debugLoclistBytes) 1520 debugAddrBytes, _ := godwarf.GetDebugSectionPE(peFile, "addr") 1521 image.debugAddr = godwarf.ParseAddr(debugAddrBytes) 1522 debugLineStrBytes, _ := godwarf.GetDebugSectionPE(peFile, "line_str") 1523 image.debugLineStr = debugLineStrBytes 1524 1525 wg.Add(2) 1526 go bi.parseDebugFramePE(image, peFile, debugInfoBytes, wg) 1527 go bi.loadDebugInfoMaps(image, debugInfoBytes, debugLineBytes, wg, nil) 1528 1529 // Use ArbitraryUserPointer (0x28) as pointer to pointer 1530 // to G struct per: 1531 // https://golang.org/src/runtime/cgo/gcc_windows_amd64.c 1532 1533 bi.gStructOffset = 0x28 1534 return nil 1535 } 1536 1537 func openExecutablePathPE(path string) (*pe.File, io.Closer, error) { 1538 f, err := os.OpenFile(path, 0, os.ModePerm) 1539 if err != nil { 1540 return nil, nil, err 1541 } 1542 peFile, err := pe.NewFile(f) 1543 if err != nil { 1544 f.Close() 1545 return nil, nil, err 1546 } 1547 return peFile, f, nil 1548 } 1549 1550 func (bi *BinaryInfo) parseDebugFramePE(image *Image, exe *pe.File, debugInfoBytes []byte, wg *sync.WaitGroup) { 1551 defer wg.Done() 1552 1553 debugFrameBytes, err := godwarf.GetDebugSectionPE(exe, "frame") 1554 bi.parseDebugFrameGeneral(image, debugFrameBytes, ".debug_frame", err, nil, 0, "", frame.DwarfEndian(debugInfoBytes)) 1555 } 1556 1557 // MACH-O //////////////////////////////////////////////////////////// 1558 1559 // loadBinaryInfoMacho specifically loads information from a Mach-O binary. 1560 func loadBinaryInfoMacho(bi *BinaryInfo, image *Image, path string, entryPoint uint64, wg *sync.WaitGroup) error { 1561 exe, err := macho.Open(path) 1562 1563 if err != nil { 1564 return err 1565 } 1566 1567 if entryPoint != 0 { 1568 // This is a little bit hacky. We use the entryPoint variable, but it 1569 // actually holds the address of the mach-o header. We can use this 1570 // to calculate the offset to the non-aslr location of the mach-o header 1571 // (which is 0x100000000) 1572 image.StaticBase = entryPoint - 0x100000000 1573 } 1574 1575 image.closer = exe 1576 if !supportedDarwinArch[exe.Cpu] { 1577 return &ErrUnsupportedArch{os: "darwin", cpuArch: exe.Cpu} 1578 } 1579 image.dwarf, err = exe.DWARF() 1580 if err != nil { 1581 return err 1582 } 1583 debugInfoBytes, err := godwarf.GetDebugSectionMacho(exe, "info") 1584 if err != nil { 1585 return err 1586 } 1587 1588 image.dwarfReader = image.dwarf.Reader() 1589 1590 debugLineBytes, err := godwarf.GetDebugSectionMacho(exe, "line") 1591 if err != nil { 1592 return err 1593 } 1594 debugLocBytes, _ := godwarf.GetDebugSectionMacho(exe, "loc") 1595 image.loclist2 = loclist.NewDwarf2Reader(debugLocBytes, bi.Arch.PtrSize()) 1596 debugLoclistBytes, _ := godwarf.GetDebugSectionMacho(exe, "loclists") 1597 image.loclist5 = loclist.NewDwarf5Reader(debugLoclistBytes) 1598 debugAddrBytes, _ := godwarf.GetDebugSectionMacho(exe, "addr") 1599 image.debugAddr = godwarf.ParseAddr(debugAddrBytes) 1600 debugLineStrBytes, _ := godwarf.GetDebugSectionMacho(exe, "line_str") 1601 image.debugLineStr = debugLineStrBytes 1602 1603 wg.Add(2) 1604 go bi.parseDebugFrameMacho(image, exe, debugInfoBytes, wg) 1605 go bi.loadDebugInfoMaps(image, debugInfoBytes, debugLineBytes, wg, bi.setGStructOffsetMacho) 1606 return nil 1607 } 1608 1609 func (bi *BinaryInfo) setGStructOffsetMacho() { 1610 // In go1.11 it's 0x30, before 0x8a0, see: 1611 // https://github.com/golang/go/issues/23617 1612 // and go commit b3a854c733257c5249c3435ffcee194f8439676a 1613 producer := bi.Producer() 1614 if producer != "" && goversion.ProducerAfterOrEqual(producer, 1, 11) { 1615 bi.gStructOffset = 0x30 1616 return 1617 } 1618 bi.gStructOffset = 0x8a0 1619 } 1620 1621 func (bi *BinaryInfo) parseDebugFrameMacho(image *Image, exe *macho.File, debugInfoBytes []byte, wg *sync.WaitGroup) { 1622 defer wg.Done() 1623 1624 debugFrameBytes, debugFrameErr := godwarf.GetDebugSectionMacho(exe, "frame") 1625 ehFrameSection := exe.Section("__eh_frame") 1626 var ehFrameBytes []byte 1627 var ehFrameAddr uint64 1628 if ehFrameSection != nil { 1629 ehFrameAddr = ehFrameSection.Addr 1630 ehFrameBytes, _ = ehFrameSection.Data() 1631 } 1632 1633 bi.parseDebugFrameGeneral(image, debugFrameBytes, "__debug_frame", debugFrameErr, ehFrameBytes, ehFrameAddr, "__eh_frame", frame.DwarfEndian(debugInfoBytes)) 1634 } 1635 1636 // macOSDebugFrameBugWorkaround applies a workaround for [golang/go#25841] 1637 // 1638 // It finds the Go function with the lowest entry point and the first 1639 // debug_frame FDE, calculates the difference between the start of the 1640 // function and the start of the FDE and sums it to all debug_frame FDEs. 1641 // A number of additional checks are performed to make sure we don't ruin 1642 // executables unaffected by this bug. 1643 // 1644 // [golang/go#25841]: https://github.com/golang/go/issues/25841 1645 func (bi *BinaryInfo) macOSDebugFrameBugWorkaround() { 1646 //TODO: log extensively because of bugs in the field 1647 if bi.GOOS != "darwin" || bi.Arch.Name != "arm64" { 1648 return 1649 } 1650 if len(bi.Images) > 1 { 1651 // Only do this for the first executable, but it might work for plugins as 1652 // well if we had a way to distinguish where entries in bi.frameEntries 1653 // come from 1654 return 1655 } 1656 exe, ok := bi.Images[0].closer.(*macho.File) 1657 if !ok { 1658 return 1659 } 1660 if exe.Flags&macho.FlagPIE == 0 { 1661 bi.logger.Infof("debug_frame workaround not needed: not a PIE (%#x)", exe.Flags) 1662 return 1663 } 1664 1665 // Find first Go function (first = lowest entry point) 1666 var fn *Function 1667 for i := range bi.Functions { 1668 if bi.Functions[i].cu.isgo && bi.Functions[i].Entry > 0 { 1669 fn = &bi.Functions[i] 1670 break 1671 } 1672 } 1673 if fn == nil { 1674 bi.logger.Warn("debug_frame workaround not applied: could not find a Go function") 1675 return 1676 } 1677 1678 if fde, _ := bi.frameEntries.FDEForPC(fn.Entry); fde != nil { 1679 // Function is covered, no need to apply workaround 1680 bi.logger.Warnf("debug_frame workaround not applied: function %s (at %#x) covered by %#x-%#x", fn.Name, fn.Entry, fde.Begin(), fde.End()) 1681 return 1682 } 1683 1684 // Find lowest FDE in debug_frame 1685 var fde *frame.FrameDescriptionEntry 1686 for i := range bi.frameEntries { 1687 if bi.frameEntries[i].CIE.CIE_id == ^uint32(0) { 1688 fde = bi.frameEntries[i] 1689 break 1690 } 1691 } 1692 1693 if fde == nil { 1694 bi.logger.Warnf("debug_frame workaround not applied because there are no debug_frame entries (%d)", len(bi.frameEntries)) 1695 return 1696 } 1697 1698 fnsize := fn.End - fn.Entry 1699 1700 if fde.End()-fde.Begin() != fnsize || fde.Begin() > fn.Entry { 1701 bi.logger.Warnf("debug_frame workaround not applied: function %s (at %#x-%#x) has a different size than the first FDE (%#x-%#x) (or the FDE starts after the function)", fn.Name, fn.Entry, fn.End, fde.Begin(), fde.End()) 1702 return 1703 } 1704 1705 delta := fn.Entry - fde.Begin() 1706 1707 bi.logger.Infof("applying debug_frame workaround +%#x: function %s (at %#x-%#x) and FDE %#x-%#x", delta, fn.Name, fn.Entry, fn.End, fde.Begin(), fde.End()) 1708 1709 for i := range bi.frameEntries { 1710 if bi.frameEntries[i].CIE.CIE_id == ^uint32(0) { 1711 bi.frameEntries[i].Translate(delta) 1712 } 1713 } 1714 } 1715 1716 // Do not call this function directly it isn't able to deal correctly with package paths 1717 func (bi *BinaryInfo) findType(name string) (godwarf.Type, error) { 1718 ref, found := bi.types[name] 1719 if !found { 1720 return nil, reader.ErrTypeNotFound 1721 } 1722 image := bi.Images[ref.imageIndex] 1723 return godwarf.ReadType(image.dwarf, ref.imageIndex, ref.offset, image.typeCache) 1724 } 1725 1726 func (bi *BinaryInfo) findTypeExpr(expr ast.Expr) (godwarf.Type, error) { 1727 if lit, islit := expr.(*ast.BasicLit); islit && lit.Kind == token.STRING { 1728 // Allow users to specify type names verbatim as quoted 1729 // string. Useful as a catch-all workaround for cases where we don't 1730 // parse/serialize types correctly or can not resolve package paths. 1731 typn, _ := strconv.Unquote(lit.Value) 1732 1733 // Check if the type in question is an array type, in which case we try to 1734 // fake it. 1735 if len(typn) > 0 && typn[0] == '[' { 1736 closedBrace := strings.Index(typn, "]") 1737 if closedBrace > 1 { 1738 n, err := strconv.Atoi(typn[1:closedBrace]) 1739 if err == nil { 1740 return bi.findArrayType(n, typn[closedBrace+1:]) 1741 } 1742 } 1743 } 1744 return bi.findType(typn) 1745 } 1746 bi.expandPackagesInType(expr) 1747 if snode, ok := expr.(*ast.StarExpr); ok { 1748 // Pointer types only appear in the dwarf informations when 1749 // a pointer to the type is used in the target program, here 1750 // we create a pointer type on the fly so that the user can 1751 // specify a pointer to any variable used in the target program 1752 ptyp, err := bi.findTypeExpr(snode.X) 1753 if err != nil { 1754 return nil, err 1755 } 1756 return pointerTo(ptyp, bi.Arch), nil 1757 } 1758 if anode, ok := expr.(*ast.ArrayType); ok { 1759 // Array types (for example [N]byte) are only present in DWARF if they are 1760 // used by the program, but it's convenient to make all of them available 1761 // to the user for two reasons: 1762 // 1. to allow reading arbitrary memory byte-by-byte (by casting an 1763 // address to an array of bytes). 1764 // 2. to read the contents of a channel's buffer (we create fake array 1765 // types for them) 1766 1767 alen, litlen := anode.Len.(*ast.BasicLit) 1768 if litlen && alen.Kind == token.INT { 1769 n, _ := strconv.Atoi(alen.Value) 1770 return bi.findArrayType(n, exprToString(anode.Elt)) 1771 } 1772 } 1773 return bi.findType(exprToString(expr)) 1774 } 1775 1776 func (bi *BinaryInfo) findArrayType(n int, etyp string) (godwarf.Type, error) { 1777 switch etyp { 1778 case "byte", "uint8": 1779 etyp = "uint8" 1780 fallthrough 1781 default: 1782 btyp, err := bi.findType(etyp) 1783 if err != nil { 1784 return nil, err 1785 } 1786 return fakeArrayType(uint64(n), btyp), nil 1787 } 1788 } 1789 1790 func complexType(typename string) bool { 1791 for _, ch := range typename { 1792 switch ch { 1793 case '*', '[', '<', '{', '(', ' ': 1794 return true 1795 } 1796 } 1797 return false 1798 } 1799 1800 func (bi *BinaryInfo) registerTypeToPackageMap(entry *dwarf.Entry) { 1801 if entry.Tag != dwarf.TagTypedef && entry.Tag != dwarf.TagBaseType && entry.Tag != dwarf.TagClassType && entry.Tag != dwarf.TagStructType { 1802 return 1803 } 1804 1805 typename, ok := entry.Val(dwarf.AttrName).(string) 1806 if !ok || complexType(typename) { 1807 return 1808 } 1809 1810 dot := strings.LastIndex(typename, ".") 1811 if dot < 0 { 1812 return 1813 } 1814 path := typename[:dot] 1815 slash := strings.LastIndex(path, "/") 1816 if slash < 0 || slash+1 >= len(path) { 1817 return 1818 } 1819 name := path[slash+1:] 1820 bi.PackageMap[name] = []string{path} 1821 } 1822 1823 func (bi *BinaryInfo) loadDebugInfoMaps(image *Image, debugInfoBytes, debugLineBytes []byte, wg *sync.WaitGroup, cont func()) { 1824 if wg != nil { 1825 defer wg.Done() 1826 } 1827 1828 if bi.types == nil { 1829 bi.types = make(map[string]dwarfRef) 1830 } 1831 if bi.consts == nil { 1832 bi.consts = make(map[dwarfRef]*constantType) 1833 } 1834 if bi.PackageMap == nil { 1835 bi.PackageMap = make(map[string][]string) 1836 } 1837 if bi.inlinedCallLines == nil { 1838 bi.inlinedCallLines = make(map[fileLine][]uint64) 1839 } 1840 if bi.dwrapUnwrapCache == nil { 1841 bi.dwrapUnwrapCache = make(map[uint64]*Function) 1842 } 1843 1844 image.runtimeTypeToDIE = make(map[uint64]runtimeTypeDIE) 1845 1846 ctxt := newLoadDebugInfoMapsContext(bi, image, util.ReadUnitVersions(debugInfoBytes)) 1847 1848 reader := image.DwarfReader() 1849 1850 for { 1851 entry, err := reader.Next() 1852 if err != nil { 1853 image.setLoadError(bi.logger, "error reading debug_info: %v", err) 1854 break 1855 } 1856 if entry == nil { 1857 break 1858 } 1859 switch entry.Tag { 1860 case dwarf.TagCompileUnit: 1861 cu := &compileUnit{} 1862 cu.image = image 1863 cu.entry = entry 1864 cu.offset = entry.Offset 1865 cu.Version = ctxt.offsetToVersion[cu.offset] 1866 if lang, _ := entry.Val(dwarf.AttrLanguage).(int64); lang == dwarfGoLanguage { 1867 cu.isgo = true 1868 } 1869 cu.name, _ = entry.Val(dwarf.AttrName).(string) 1870 compdir, _ := entry.Val(dwarf.AttrCompDir).(string) 1871 if compdir != "" { 1872 cu.name = filepath.Join(compdir, cu.name) 1873 } 1874 cu.ranges, _ = image.dwarf.Ranges(entry) 1875 for i := range cu.ranges { 1876 cu.ranges[i][0] += image.StaticBase 1877 cu.ranges[i][1] += image.StaticBase 1878 } 1879 if len(cu.ranges) >= 1 { 1880 cu.lowPC = cu.ranges[0][0] 1881 } 1882 lineInfoOffset, hasLineInfo := entry.Val(dwarf.AttrStmtList).(int64) 1883 if hasLineInfo && lineInfoOffset >= 0 && lineInfoOffset < int64(len(debugLineBytes)) { 1884 var logfn func(string, ...interface{}) 1885 if logflags.DebugLineErrors() { 1886 logger := logrus.New().WithFields(logrus.Fields{"layer": "dwarf-line"}) 1887 logger.Logger.Level = logrus.DebugLevel 1888 logfn = func(fmt string, args ...interface{}) { 1889 logger.Printf(fmt, args) 1890 } 1891 } 1892 cu.lineInfo = line.Parse(compdir, bytes.NewBuffer(debugLineBytes[lineInfoOffset:]), image.debugLineStr, logfn, image.StaticBase, bi.GOOS == "windows", bi.Arch.PtrSize()) 1893 } 1894 cu.producer, _ = entry.Val(dwarf.AttrProducer).(string) 1895 if cu.isgo && cu.producer != "" { 1896 semicolon := strings.Index(cu.producer, ";") 1897 if semicolon < 0 { 1898 cu.optimized = goversion.ProducerAfterOrEqual(cu.producer, 1, 10) 1899 } else { 1900 cu.optimized = !strings.Contains(cu.producer[semicolon:], "-N") || !strings.Contains(cu.producer[semicolon:], "-l") 1901 const regabi = " regabi" 1902 if i := strings.Index(cu.producer[semicolon:], regabi); i > 0 { 1903 i += semicolon 1904 if i+len(regabi) >= len(cu.producer) || cu.producer[i+len(regabi)] == ' ' { 1905 bi.regabi = true 1906 } 1907 } 1908 cu.producer = cu.producer[:semicolon] 1909 } 1910 } 1911 gopkg, _ := entry.Val(godwarf.AttrGoPackageName).(string) 1912 if cu.isgo && gopkg != "" { 1913 bi.PackageMap[gopkg] = append(bi.PackageMap[gopkg], escapePackagePath(strings.Replace(cu.name, "\\", "/", -1))) 1914 } 1915 image.compileUnits = append(image.compileUnits, cu) 1916 if entry.Children { 1917 bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu) 1918 } 1919 1920 case dwarf.TagPartialUnit: 1921 reader.SkipChildren() 1922 1923 default: 1924 // ignore unknown tags 1925 reader.SkipChildren() 1926 } 1927 } 1928 1929 sort.Sort(compileUnitsByOffset(image.compileUnits)) 1930 sort.Sort(functionsDebugInfoByEntry(bi.Functions)) 1931 sort.Sort(packageVarsByAddr(bi.packageVars)) 1932 1933 bi.LookupFunc = make(map[string]*Function) 1934 bi.lookupGenericFunc = nil 1935 for i := range bi.Functions { 1936 bi.LookupFunc[bi.Functions[i].Name] = &bi.Functions[i] 1937 } 1938 1939 for _, cu := range image.compileUnits { 1940 if cu.lineInfo != nil { 1941 for _, fileEntry := range cu.lineInfo.FileNames { 1942 bi.Sources = append(bi.Sources, fileEntry.Path) 1943 } 1944 } 1945 } 1946 sort.Strings(bi.Sources) 1947 bi.Sources = uniq(bi.Sources) 1948 1949 if bi.regabi { 1950 // prepare patch for runtime.mallocgc's DIE 1951 fn := bi.LookupFunc["runtime.mallocgc"] 1952 if fn != nil && fn.cu.image == image { 1953 tree, err := image.getDwarfTree(fn.offset) 1954 if err == nil { 1955 tree.Children, err = regabiMallocgcWorkaround(bi) 1956 if err != nil { 1957 bi.logger.Errorf("could not patch runtime.mallogc: %v", err) 1958 } else { 1959 image.runtimeMallocgcTree = tree 1960 } 1961 } 1962 } 1963 } 1964 1965 if cont != nil { 1966 cont() 1967 } 1968 } 1969 1970 // LookupGenericFunc returns a map that allows searching for instantiations of generic function by specificying a function name without type parameters. 1971 // For example the key "pkg.(*Receiver).Amethod" will find all instantiations of Amethod: 1972 // - pkg.(*Receiver[.shape.int]).Amethod 1973 // - pkg.(*Receiver[.shape.*uint8]).Amethod 1974 // - etc. 1975 func (bi *BinaryInfo) LookupGenericFunc() map[string][]*Function { 1976 if bi.lookupGenericFunc == nil { 1977 bi.lookupGenericFunc = make(map[string][]*Function) 1978 for i := range bi.Functions { 1979 dn := bi.Functions[i].NameWithoutTypeParams() 1980 if dn != bi.Functions[i].Name { 1981 bi.lookupGenericFunc[dn] = append(bi.lookupGenericFunc[dn], &bi.Functions[i]) 1982 } 1983 } 1984 } 1985 return bi.lookupGenericFunc 1986 } 1987 1988 // loadDebugInfoMapsCompileUnit loads entry from a single compile unit. 1989 func (bi *BinaryInfo) loadDebugInfoMapsCompileUnit(ctxt *loadDebugInfoMapsContext, image *Image, reader *reader.Reader, cu *compileUnit) { 1990 hasAttrGoPkgName := goversion.ProducerAfterOrEqual(cu.producer, 1, 13) 1991 1992 depth := 0 1993 1994 for { 1995 entry, err := reader.Next() 1996 if err != nil { 1997 image.setLoadError(bi.logger, "error reading debug_info: %v", err) 1998 return 1999 } 2000 if entry == nil { 2001 break 2002 } 2003 switch entry.Tag { 2004 case 0: 2005 if depth == 0 { 2006 return 2007 } else { 2008 depth-- 2009 } 2010 case dwarf.TagImportedUnit: 2011 bi.loadDebugInfoMapsImportedUnit(entry, ctxt, image, cu) 2012 reader.SkipChildren() 2013 2014 case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType: 2015 if name, ok := entry.Val(dwarf.AttrName).(string); ok { 2016 if !cu.isgo { 2017 name = "C." + name 2018 } 2019 if _, exists := bi.types[name]; !exists { 2020 bi.types[name] = dwarfRef{image.index, entry.Offset} 2021 } 2022 } 2023 if cu != nil && cu.isgo && !hasAttrGoPkgName { 2024 bi.registerTypeToPackageMap(entry) 2025 } 2026 image.registerRuntimeTypeToDIE(entry, ctxt.ardr) 2027 reader.SkipChildren() 2028 2029 case dwarf.TagVariable: 2030 if n, ok := entry.Val(dwarf.AttrName).(string); ok { 2031 var addr uint64 2032 if loc, ok := entry.Val(dwarf.AttrLocation).([]byte); ok { 2033 if len(loc) == bi.Arch.PtrSize()+1 && op.Opcode(loc[0]) == op.DW_OP_addr { 2034 addr, _ = util.ReadUintRaw(bytes.NewReader(loc[1:]), binary.LittleEndian, bi.Arch.PtrSize()) 2035 } 2036 } 2037 if !cu.isgo { 2038 n = "C." + n 2039 } 2040 if _, known := ctxt.knownPackageVars[n]; !known { 2041 bi.packageVars = append(bi.packageVars, packageVar{n, cu, entry.Offset, addr + image.StaticBase}) 2042 } 2043 } 2044 reader.SkipChildren() 2045 2046 case dwarf.TagConstant: 2047 name, okName := entry.Val(dwarf.AttrName).(string) 2048 typ, okType := entry.Val(dwarf.AttrType).(dwarf.Offset) 2049 val, okVal := entry.Val(dwarf.AttrConstValue).(int64) 2050 if okName && okType && okVal { 2051 if !cu.isgo { 2052 name = "C." + name 2053 } 2054 ct := bi.consts[dwarfRef{image.index, typ}] 2055 if ct == nil { 2056 ct = &constantType{} 2057 bi.consts[dwarfRef{image.index, typ}] = ct 2058 } 2059 ct.values = append(ct.values, constantValue{name: name, fullName: name, value: val}) 2060 } 2061 reader.SkipChildren() 2062 2063 case dwarf.TagSubprogram: 2064 inlined := false 2065 if inval, ok := entry.Val(dwarf.AttrInline).(int64); ok { 2066 inlined = inval >= 1 2067 } 2068 2069 if inlined { 2070 bi.addAbstractSubprogram(entry, ctxt, reader, image, cu) 2071 } else { 2072 originOffset, hasAbstractOrigin := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 2073 if hasAbstractOrigin { 2074 bi.addConcreteInlinedSubprogram(entry, originOffset, ctxt, reader, cu) 2075 } else { 2076 bi.addConcreteSubprogram(entry, ctxt, reader, cu) 2077 } 2078 } 2079 2080 default: 2081 if entry.Children { 2082 depth++ 2083 } 2084 } 2085 } 2086 } 2087 2088 // loadDebugInfoMapsImportedUnit loads entries into cu from the partial unit 2089 // referenced in a DW_TAG_imported_unit entry. 2090 func (bi *BinaryInfo) loadDebugInfoMapsImportedUnit(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, image *Image, cu *compileUnit) { 2091 off, ok := entry.Val(dwarf.AttrImport).(dwarf.Offset) 2092 if !ok { 2093 return 2094 } 2095 reader := image.DwarfReader() 2096 reader.Seek(off) 2097 imentry, err := reader.Next() 2098 if err != nil { 2099 return 2100 } 2101 if imentry.Tag != dwarf.TagPartialUnit { 2102 return 2103 } 2104 bi.loadDebugInfoMapsCompileUnit(ctxt, image, reader, cu) 2105 } 2106 2107 // addAbstractSubprogram adds the abstract entry for an inlined function. 2108 func (bi *BinaryInfo) addAbstractSubprogram(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, reader *reader.Reader, image *Image, cu *compileUnit) { 2109 name, ok := subprogramEntryName(entry, cu) 2110 if !ok { 2111 bi.logger.Warnf("reading debug_info: abstract subprogram without name at %#x", entry.Offset) 2112 // In some cases clang produces abstract subprograms that do not have a 2113 // name, but we should process them anyway. 2114 } 2115 2116 if entry.Children { 2117 bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu) 2118 } 2119 2120 originIdx := ctxt.lookupAbstractOrigin(bi, entry.Offset) 2121 fn := &bi.Functions[originIdx] 2122 fn.Name = name 2123 fn.offset = entry.Offset 2124 fn.cu = cu 2125 } 2126 2127 // addConcreteInlinedSubprogram adds the concrete entry of a subprogram that was also inlined. 2128 func (bi *BinaryInfo) addConcreteInlinedSubprogram(entry *dwarf.Entry, originOffset dwarf.Offset, ctxt *loadDebugInfoMapsContext, reader *reader.Reader, cu *compileUnit) { 2129 lowpc, highpc, ok := subprogramEntryRange(entry, cu.image) 2130 if !ok { 2131 bi.logger.Warnf("reading debug_info: concrete inlined subprogram without address range at %#x", entry.Offset) 2132 if entry.Children { 2133 reader.SkipChildren() 2134 } 2135 return 2136 } 2137 2138 originIdx := ctxt.lookupAbstractOrigin(bi, originOffset) 2139 fn := &bi.Functions[originIdx] 2140 fn.offset = entry.Offset 2141 fn.Entry = lowpc 2142 fn.End = highpc 2143 fn.cu = cu 2144 2145 if entry.Children { 2146 bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu) 2147 } 2148 } 2149 2150 // addConcreteSubprogram adds a concrete subprogram (a normal subprogram 2151 // that doesn't have abstract or inlined entries) 2152 func (bi *BinaryInfo) addConcreteSubprogram(entry *dwarf.Entry, ctxt *loadDebugInfoMapsContext, reader *reader.Reader, cu *compileUnit) { 2153 lowpc, highpc, ok := subprogramEntryRange(entry, cu.image) 2154 if !ok { 2155 bi.logger.Warnf("reading debug_info: concrete subprogram without address range at %#x", entry.Offset) 2156 // When clang inlines a function, in some cases, it produces a concrete 2157 // subprogram without address range and then inlined calls that reference 2158 // it, instead of producing an abstract subprogram. 2159 // It is unclear if this behavior is standard. 2160 } 2161 2162 name, ok := subprogramEntryName(entry, cu) 2163 if !ok { 2164 bi.logger.Warnf("reading debug_info: concrete subprogram without name at %#x", entry.Offset) 2165 } 2166 2167 trampoline, _ := entry.Val(dwarf.AttrTrampoline).(bool) 2168 2169 originIdx := ctxt.lookupAbstractOrigin(bi, entry.Offset) 2170 fn := &bi.Functions[originIdx] 2171 2172 fn.Name = name 2173 fn.Entry = lowpc 2174 fn.End = highpc 2175 fn.offset = entry.Offset 2176 fn.cu = cu 2177 fn.trampoline = trampoline 2178 2179 if entry.Children { 2180 bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu) 2181 } 2182 } 2183 2184 func subprogramEntryName(entry *dwarf.Entry, cu *compileUnit) (string, bool) { 2185 name, ok := entry.Val(dwarf.AttrName).(string) 2186 if !ok { 2187 return "", false 2188 } 2189 if !cu.isgo { 2190 name = "C." + name 2191 } 2192 return name, true 2193 } 2194 2195 func subprogramEntryRange(entry *dwarf.Entry, image *Image) (lowpc, highpc uint64, ok bool) { 2196 ok = false 2197 if ranges, _ := image.dwarf.Ranges(entry); len(ranges) >= 1 { 2198 ok = true 2199 lowpc = ranges[0][0] + image.StaticBase 2200 highpc = ranges[0][1] + image.StaticBase 2201 } 2202 return lowpc, highpc, ok 2203 } 2204 2205 func (bi *BinaryInfo) loadDebugInfoMapsInlinedCalls(ctxt *loadDebugInfoMapsContext, reader *reader.Reader, cu *compileUnit) { 2206 for { 2207 entry, err := reader.Next() 2208 if err != nil { 2209 cu.image.setLoadError(bi.logger, "error reading debug_info: %v", err) 2210 return 2211 } 2212 switch entry.Tag { 2213 case 0: 2214 return 2215 case dwarf.TagInlinedSubroutine: 2216 originOffset, ok := entry.Val(dwarf.AttrAbstractOrigin).(dwarf.Offset) 2217 if !ok { 2218 bi.logger.Warnf("reading debug_info: inlined call without origin offset at %#x", entry.Offset) 2219 reader.SkipChildren() 2220 continue 2221 } 2222 2223 lowpc, highpc, ok := subprogramEntryRange(entry, cu.image) 2224 if !ok { 2225 bi.logger.Warnf("reading debug_info: inlined call without address range at %#x", entry.Offset) 2226 reader.SkipChildren() 2227 continue 2228 } 2229 2230 callfileidx, ok1 := entry.Val(dwarf.AttrCallFile).(int64) 2231 callline, ok2 := entry.Val(dwarf.AttrCallLine).(int64) 2232 if !ok1 || !ok2 { 2233 bi.logger.Warnf("reading debug_info: inlined call without CallFile/CallLine at %#x", entry.Offset) 2234 reader.SkipChildren() 2235 continue 2236 } 2237 callfile, cferr := cu.filePath(int(callfileidx), entry) 2238 if cferr != nil { 2239 bi.logger.Warnf("%v", cferr) 2240 reader.SkipChildren() 2241 continue 2242 } 2243 2244 originIdx := ctxt.lookupAbstractOrigin(bi, originOffset) 2245 fn := &bi.Functions[originIdx] 2246 2247 fn.InlinedCalls = append(fn.InlinedCalls, InlinedCall{ 2248 cu: cu, 2249 LowPC: lowpc, 2250 HighPC: highpc, 2251 }) 2252 2253 if fn.cu == nil { 2254 fn.cu = cu 2255 } 2256 2257 fl := fileLine{callfile, int(callline)} 2258 bi.inlinedCallLines[fl] = append(bi.inlinedCallLines[fl], lowpc) 2259 2260 if entry.Children { 2261 bi.loadDebugInfoMapsInlinedCalls(ctxt, reader, cu) 2262 } 2263 } 2264 reader.SkipChildren() 2265 } 2266 } 2267 2268 func uniq(s []string) []string { 2269 if len(s) <= 0 { 2270 return s 2271 } 2272 src, dst := 1, 1 2273 for src < len(s) { 2274 if s[src] != s[dst-1] { 2275 s[dst] = s[src] 2276 dst++ 2277 } 2278 src++ 2279 } 2280 return s[:dst] 2281 } 2282 2283 func (bi *BinaryInfo) expandPackagesInType(expr ast.Expr) { 2284 switch e := expr.(type) { 2285 case *ast.ArrayType: 2286 bi.expandPackagesInType(e.Elt) 2287 case *ast.ChanType: 2288 bi.expandPackagesInType(e.Value) 2289 case *ast.FuncType: 2290 for i := range e.Params.List { 2291 bi.expandPackagesInType(e.Params.List[i].Type) 2292 } 2293 if e.Results != nil { 2294 for i := range e.Results.List { 2295 bi.expandPackagesInType(e.Results.List[i].Type) 2296 } 2297 } 2298 case *ast.MapType: 2299 bi.expandPackagesInType(e.Key) 2300 bi.expandPackagesInType(e.Value) 2301 case *ast.ParenExpr: 2302 bi.expandPackagesInType(e.X) 2303 case *ast.SelectorExpr: 2304 switch x := e.X.(type) { 2305 case *ast.Ident: 2306 if len(bi.PackageMap[x.Name]) > 0 { 2307 // There's no particular reason to expect the first entry to be the 2308 // correct one if the package name is ambiguous, but trying all possible 2309 // expansions of all types mentioned in the expression is complicated 2310 // and, besides type assertions, users can always specify the type they 2311 // want exactly, using a string. 2312 x.Name = bi.PackageMap[x.Name][0] 2313 } 2314 default: 2315 bi.expandPackagesInType(e.X) 2316 } 2317 case *ast.StarExpr: 2318 bi.expandPackagesInType(e.X) 2319 default: 2320 // nothing to do 2321 } 2322 } 2323 2324 // escapePackagePath returns pkg with '.' replaced with '%2e' (in all 2325 // elements of the path except the first one) like Go does in variable and 2326 // type names. 2327 func escapePackagePath(pkg string) string { 2328 slash := strings.Index(pkg, "/") 2329 if slash < 0 { 2330 slash = 0 2331 } 2332 return pkg[:slash] + strings.Replace(pkg[slash:], ".", "%2e", -1) 2333 } 2334 2335 // Looks up symbol (either functions or global variables) at address addr. 2336 // Used by disassembly formatter. 2337 func (bi *BinaryInfo) symLookup(addr uint64) (string, uint64) { 2338 fn := bi.PCToFunc(addr) 2339 if fn != nil { 2340 if fn.Entry == addr { 2341 // only report the function name if it's the exact address because it's 2342 // easier to read the absolute address than function_name+offset. 2343 return fn.Name, fn.Entry 2344 } 2345 return "", 0 2346 } 2347 if sym, ok := bi.SymNames[addr]; ok { 2348 return sym.Name, addr 2349 } 2350 i := sort.Search(len(bi.packageVars), func(i int) bool { 2351 return bi.packageVars[i].addr >= addr 2352 }) 2353 if i >= len(bi.packageVars) { 2354 return "", 0 2355 } 2356 if bi.packageVars[i].addr > addr { 2357 // report previous variable + offset if i-th variable starts after addr 2358 i-- 2359 } 2360 if i >= 0 && bi.packageVars[i].addr != 0 { 2361 return bi.packageVars[i].name, bi.packageVars[i].addr 2362 } 2363 return "", 0 2364 } 2365 2366 type PackageBuildInfo struct { 2367 ImportPath string 2368 DirectoryPath string 2369 Files map[string]struct{} 2370 } 2371 2372 // ListPackagesBuildInfo returns the list of packages used by the program along with 2373 // the directory where each package was compiled and optionally the list of 2374 // files constituting the package. 2375 func (bi *BinaryInfo) ListPackagesBuildInfo(includeFiles bool) []*PackageBuildInfo { 2376 m := make(map[string]*PackageBuildInfo) 2377 for _, cu := range bi.Images[0].compileUnits { 2378 if cu.image != bi.Images[0] || !cu.isgo || cu.lineInfo == nil { 2379 //TODO(aarzilli): what's the correct thing to do for plugins? 2380 continue 2381 } 2382 2383 ip := strings.Replace(cu.name, "\\", "/", -1) 2384 if _, ok := m[ip]; !ok { 2385 path := cu.lineInfo.FirstFile() 2386 if ext := filepath.Ext(path); ext != ".go" && ext != ".s" { 2387 continue 2388 } 2389 dp := filepath.Dir(path) 2390 m[ip] = &PackageBuildInfo{ 2391 ImportPath: ip, 2392 DirectoryPath: dp, 2393 Files: make(map[string]struct{}), 2394 } 2395 } 2396 2397 if includeFiles { 2398 pbi := m[ip] 2399 2400 for _, file := range cu.lineInfo.FileNames { 2401 pbi.Files[file.Path] = struct{}{} 2402 } 2403 } 2404 } 2405 2406 r := make([]*PackageBuildInfo, 0, len(m)) 2407 for _, pbi := range m { 2408 r = append(r, pbi) 2409 } 2410 2411 sort.Slice(r, func(i, j int) bool { return r[i].ImportPath < r[j].ImportPath }) 2412 return r 2413 } 2414 2415 // cuFilePath takes a compilation unit "cu" and a file index reference 2416 // "fileidx" and returns the corresponding file name entry from the 2417 // DWARF line table associated with the unit; "entry" is the offset of 2418 // the attribute where the file reference originated, for logging 2419 // purposes. Return value is the file string and an error value; error 2420 // will be non-nil if the file could not be recovered, perhaps due to 2421 // malformed DWARF. 2422 func (cu *compileUnit) filePath(fileidx int, entry *dwarf.Entry) (string, error) { 2423 if cu.lineInfo == nil { 2424 return "", fmt.Errorf("reading debug_info: file reference within a compilation unit without debug_line section at %#x", entry.Offset) 2425 } 2426 // File numbering is slightly different before and after DWARF 5; 2427 // account for this here. See section 6.2.4 of the DWARF 5 spec. 2428 if cu.Version < 5 { 2429 fileidx-- 2430 } 2431 if fileidx < 0 || fileidx >= len(cu.lineInfo.FileNames) { 2432 return "", fmt.Errorf("reading debug_info: file index (%d) out of range in compile unit file table at %#x", fileidx, entry.Offset) 2433 } 2434 return cu.lineInfo.FileNames[fileidx].Path, nil 2435 }