diff --git a/src/cc/bcc_elf.c b/src/cc/bcc_elf.c index 521ee9777e96..ce17de578f03 100644 --- a/src/cc/bcc_elf.c +++ b/src/cc/bcc_elf.c @@ -929,37 +929,59 @@ int bcc_elf_foreach_sym_lazy(const char *path, bcc_elf_symcb_lazy callback, return foreach_sym_core(path, NULL, callback, o, payload); } -int bcc_elf_get_text_scn_info(const char *path, uint64_t *addr, - uint64_t *offset) { - int err; - Elf_Scn *section = NULL; - GElf_Shdr header; - size_t stridx; - char *name; +int bcc_elf_get_scn_info(const char *path, uint64_t segment_offset, + uint64_t *addr, uint64_t *offset) { + int ret; struct bcc_elf_file elf_file; + Elf_Scn *section = NULL; + GElf_Shdr shdr; + uint64_t segment_vaddr = 0, segment_memsz = 0; + int found_segment = 0; + bcc_elf_file_init(&elf_file); - if ((err = bcc_elf_file_open(path, &elf_file)) < 0 || - (err = elf_getshdrstrndx(elf_file.elf, &stridx)) < 0) + if ((ret = bcc_elf_file_open(path, &elf_file)) < 0) + goto exit; + + ret = -1; + + size_t phdr_num, i; + if (elf_getphdrnum(elf_file.elf, &phdr_num) != 0) + goto exit; + + GElf_Phdr phdr; + for (i = 0; i < phdr_num; ++i) { + if (!gelf_getphdr(elf_file.elf, i, &phdr)) + continue; + if (phdr.p_type != PT_LOAD || !(phdr.p_flags & PF_X)) + continue; + + if (phdr.p_offset == segment_offset) { + segment_vaddr = phdr.p_vaddr; + segment_memsz = phdr.p_memsz; + found_segment = 1; + break; + } + } + if (!found_segment) goto exit; - err = -1; while ((section = elf_nextscn(elf_file.elf, section)) != 0) { - if (!gelf_getshdr(section, &header)) + if (!gelf_getshdr(section, &shdr)) continue; - name = elf_strptr(elf_file.elf, stridx, header.sh_name); - if (name && !strcmp(name, ".text")) { - *addr = (uint64_t)header.sh_addr; - *offset = (uint64_t)header.sh_offset; - err = 0; + if (shdr.sh_addr >= segment_vaddr && + shdr.sh_addr < segment_vaddr + segment_memsz) { + *addr = (uint64_t)shdr.sh_addr; + *offset = (uint64_t)shdr.sh_offset; + ret = 0; break; } } exit: bcc_elf_file_close(&elf_file); - return err; + return ret; } int bcc_elf_foreach_load_section(const char *path, diff --git a/src/cc/bcc_elf.h b/src/cc/bcc_elf.h index ba1805682ff3..5972b34f1c00 100644 --- a/src/cc/bcc_elf.h +++ b/src/cc/bcc_elf.h @@ -73,8 +73,8 @@ int bcc_elf_foreach_sym_lazy(const char *path, bcc_elf_symcb_lazy callback, // Returns -1 on error, and 0 on success or stopped by callback int bcc_elf_foreach_vdso_sym(bcc_elf_symcb callback, void *payload); -int bcc_elf_get_text_scn_info(const char *path, uint64_t *addr, - uint64_t *offset); +int bcc_elf_get_scn_info(const char *path, uint64_t segment_offset, + uint64_t *addr, uint64_t *offset); int bcc_elf_get_type(const char *path); int bcc_elf_is_pie(const char *path); diff --git a/src/cc/bcc_syms.cc b/src/cc/bcc_syms.cc index a015850c9dce..341bcf035a1d 100644 --- a/src/cc/bcc_syms.cc +++ b/src/cc/bcc_syms.cc @@ -204,19 +204,6 @@ int ProcSyms::_add_module(mod_info *mod, int enter_ns, void *payload) { auto module = Module( mod->name, modpath, &ps->symbol_option_); - // pid/maps doesn't account for file_offset of text within the ELF. - // It only gives the mmap offset. We need the real offset for symbol - // lookup. - if (module.type_ == ModuleType::SO) { - if (bcc_elf_get_text_scn_info(modpath->path(), &module.elf_so_addr_, - &module.elf_so_offset_) < 0) { - fprintf(stderr, "WARNING: Couldn't find .text section in %s\n", - modpath->alt_path()); - fprintf(stderr, "WARNING: BCC can't handle sym look ups for %s", - modpath->alt_path()); - } - } - if (!bcc_is_perf_map(modpath->path()) || module.type_ != ModuleType::UNKNOWN) // Always add the module even if we can't read it, so that we could @@ -226,7 +213,24 @@ int ProcSyms::_add_module(mod_info *mod, int enter_ns, void *payload) { else return 0; } - it->ranges_.emplace_back(mod->start_addr, mod->end_addr, mod->file_offset); + // pid/maps doesn't account for file_offset of text within the ELF. + // It only gives the mmap offset. We need the real offset for symbol + // lookup. + // since there will be different real offset, so we must calculate each time. + uint64_t elf_so_offset; + uint64_t elf_so_addr; + if (it->type_ == ModuleType::SO) { + if (bcc_elf_get_scn_info(modpath->path(), static_cast(mod->file_offset), + &elf_so_addr, &elf_so_offset) < 0) { + fprintf(stderr, "WARNING: Couldn't find .text section in %s\n", + modpath->alt_path()); + fprintf(stderr, "WARNING: BCC can't handle sym look ups for %s", + modpath->alt_path()); + } + } + + it->ranges_.emplace_back(mod->start_addr, mod->end_addr, mod->file_offset, + elf_so_addr, elf_so_offset); // perf-PID map is added last. We try both inside the Process's mount // namespace + chroot, and in global /tmp. Make sure we only add one. if (it->type_ == ModuleType::PERF_MAP) @@ -310,10 +314,6 @@ ProcSyms::Module::Module(const char *name, std::shared_ptr path, type_ = ModuleType::PERF_MAP; else if (bcc_elf_is_vdso(path_->path()) == 1) type_ = ModuleType::VDSO; - - // Will be stored later - elf_so_offset_ = 0; - elf_so_addr_ = 0; } int ProcSyms::Module::_add_symbol(const char *symname, uint64_t start, @@ -361,7 +361,7 @@ bool ProcSyms::Module::contains(uint64_t addr, uint64_t &offset) const { if (addr >= range.start && addr < range.end) { if (type_ == ModuleType::SO || type_ == ModuleType::VDSO) { offset = __so_calc_mod_offset(range.start, range.file_offset, - elf_so_addr_, elf_so_offset_, addr); + range.elf_so_addr, range.elf_so_offset, addr); } else { offset = addr; } @@ -721,7 +721,7 @@ int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address, mod.start == 0x0) return -1; - if (bcc_elf_get_text_scn_info(module, &elf_so_addr, &elf_so_offset) < 0) + if (bcc_elf_get_scn_info(module, mod.file_offset, &elf_so_addr, &elf_so_offset) < 0) return -1; *global = __so_calc_global_addr(mod.start, mod.file_offset, elf_so_addr, diff --git a/src/cc/syms.h b/src/cc/syms.h index 94ed7ac8a73d..b1cae27d736f 100644 --- a/src/cc/syms.h +++ b/src/cc/syms.h @@ -154,8 +154,10 @@ class ProcSyms : SymbolCache { uint64_t start; uint64_t end; uint64_t file_offset; - Range(uint64_t s, uint64_t e, uint64_t f) - : start(s), end(e), file_offset(f) {} + uint64_t elf_so_addr; + uint64_t elf_so_offset; + Range(uint64_t s, uint64_t e, uint64_t f, uint64_t elf_so_addr, uint64_t elf_so_offset) + : start(s), end(e), file_offset(f), elf_so_addr(elf_so_addr), elf_so_offset(elf_so_offset) {} }; Module(const char *name, std::shared_ptr path, @@ -168,10 +170,6 @@ class ProcSyms : SymbolCache { bcc_symbol_option *symbol_option_; ModuleType type_; - // The file offset within the ELF of the SO's first text section. - uint64_t elf_so_offset_; - uint64_t elf_so_addr_; - std::unordered_set symnames_; std::vector syms_;