| 426 | } |
| 427 | |
| 428 | func (b *binrep) openELF(name string, start, limit, offset uint64, relocationSymbol string) (plugin.ObjFile, error) { |
| 429 | ef, err := elfOpen(name) |
| 430 | if err != nil { |
| 431 | return nil, fmt.Errorf("error parsing %s: %v", name, err) |
| 432 | } |
| 433 | defer ef.Close() |
| 434 | |
| 435 | buildID := "" |
| 436 | if id, err := elfexec.GetBuildID(ef); err == nil { |
| 437 | buildID = fmt.Sprintf("%x", id) |
| 438 | } |
| 439 | |
| 440 | var ( |
| 441 | kernelOffset *uint64 |
| 442 | pageAligned = func(addr uint64) bool { return addr%4096 == 0 } |
| 443 | ) |
| 444 | if strings.Contains(name, "vmlinux") || !pageAligned(start) || !pageAligned(limit) || !pageAligned(offset) { |
| 445 | // Reading all Symbols is expensive, and we only rarely need it so |
| 446 | // we don't want to do it every time. But if _stext happens to be |
| 447 | // page-aligned but isn't the same as Vaddr, we would symbolize |
| 448 | // wrong. So if the name the addresses aren't page aligned, or if |
| 449 | // the name is "vmlinux" we read _stext. We can be wrong if: (1) |
| 450 | // someone passes a kernel path that doesn't contain "vmlinux" AND |
| 451 | // (2) _stext is page-aligned AND (3) _stext is not at Vaddr |
| 452 | symbols, err := ef.Symbols() |
| 453 | if err != nil && err != elf.ErrNoSymbols { |
| 454 | return nil, err |
| 455 | } |
| 456 | |
| 457 | // The kernel relocation symbol (the mapping start address) can be either |
| 458 | // _text or _stext. When profiles are generated by `perf`, which one was used is |
| 459 | // distinguished by the mapping name for the kernel image: |
| 460 | // '[kernel.kallsyms]_text' or '[kernel.kallsyms]_stext', respectively. If we haven't |
| 461 | // been able to parse it from the mapping, we default to _stext. |
| 462 | if relocationSymbol == "" { |
| 463 | relocationSymbol = "_stext" |
| 464 | } |
| 465 | for _, s := range symbols { |
| 466 | if s.Name == relocationSymbol { |
| 467 | kernelOffset = &s.Value |
| 468 | break |
| 469 | } |
| 470 | } |
| 471 | } |
| 472 | |
| 473 | // Check that we can compute a base for the binary. This may not be the |
| 474 | // correct base value, so we don't save it. We delay computing the actual base |
| 475 | // value until we have a sample address for this mapping, so that we can |
| 476 | // correctly identify the associated program segment that is needed to compute |
| 477 | // the base. |
| 478 | if _, err := elfexec.GetBase(&ef.FileHeader, elfexec.FindTextProgHeader(ef), kernelOffset, start, limit, offset); err != nil { |
| 479 | return nil, fmt.Errorf("could not identify base for %s: %v", name, err) |
| 480 | } |
| 481 | |
| 482 | if b.fast || (!b.addr2lineFound && !b.llvmSymbolizerFound) { |
| 483 | return &fileNM{file: file{ |
| 484 | b: b, |
| 485 | name: name, |