Commit 899d3e92 authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #1357 from palmtenor/load_section

Fix edge case when doing symbol name -> address resolution
parents ac5c03ce b09e43b4
......@@ -470,40 +470,39 @@ int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback,
path, callback, (struct bcc_symbol_option*)option, payload, 0);
}
static int loadaddr(Elf *e, uint64_t *addr) {
size_t phnum, i;
int bcc_elf_foreach_load_section(const char *path,
bcc_elf_load_sectioncb callback,
void *payload) {
Elf *e = NULL;
int fd = -1, err = -1, res;
size_t nhdrs, i;
if (elf_getphdrnum(e, &phnum) != 0)
return -1;
if (openelf(path, &e, &fd) < 0)
goto exit;
for (i = 0; i < phnum; ++i) {
GElf_Phdr header;
if (elf_getphdrnum(e, &nhdrs) != 0)
goto exit;
GElf_Phdr header;
for (i = 0; i < nhdrs; i++) {
if (!gelf_getphdr(e, (int)i, &header))
continue;
if (header.p_type != PT_LOAD)
if (header.p_type != PT_LOAD || !(header.p_flags & PF_X))
continue;
*addr = (uint64_t)header.p_vaddr;
return 0;
res = callback(header.p_vaddr, header.p_memsz, header.p_offset, payload);
if (res < 0) {
err = 1;
goto exit;
}
}
err = 0;
return -1;
}
int bcc_elf_loadaddr(const char *path, uint64_t *address) {
Elf *e;
int fd, res;
if (openelf(path, &e, &fd) < 0)
return -1;
res = loadaddr(e, address);
exit:
if (e)
elf_end(e);
if (fd >= 0)
close(fd);
return res;
return err;
}
int bcc_elf_get_type(const char *path) {
......
......@@ -32,17 +32,31 @@ struct bcc_elf_usdt {
const char *arg_fmt;
};
// Binary module path, bcc_elf_usdt struct, payload
typedef void (*bcc_elf_probecb)(const char *, const struct bcc_elf_usdt *,
void *);
// Symbol name, start address, length, payload
// Callback returning a negative value indicates to stop the iteration
typedef int (*bcc_elf_symcb)(const char *, uint64_t, uint64_t, void *);
// Segment virtual address, memory size, file offset, payload
// Callback returning a negative value indicates to stop the iteration
typedef int (*bcc_elf_load_sectioncb)(uint64_t, uint64_t, uint64_t, void *);
// Iterate over all USDT probes noted in a binary module
// Returns -1 on error, and 0 on success
int bcc_elf_foreach_usdt(const char *path, bcc_elf_probecb callback,
void *payload);
int bcc_elf_loadaddr(const char *path, uint64_t *address);
int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback,
void *option, void *payload);
// Iterate over all executable load sections of an ELF
// Returns -1 on error, 1 if stopped by callback, and 0 on success
int bcc_elf_foreach_load_section(const char *path,
bcc_elf_load_sectioncb callback,
void *payload);
// Iterate over symbol table of a binary module
// Parameter "option" points to a bcc_symbol_option struct to indicate wheather
// and how to use debuginfo file, and what types of symbols to load.
// Returns -1 on error, and 0 on success or stopped by callback
int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback, void *option,
void *payload);
int bcc_elf_get_type(const char *path);
int bcc_elf_is_shared_obj(const char *path);
......
......@@ -416,11 +416,24 @@ static int _find_sym(const char *symname, uint64_t addr, uint64_t,
return 0;
}
struct load_addr_t {
uint64_t target_addr;
uint64_t binary_addr;
};
int _find_load(uint64_t v_addr, uint64_t mem_sz, uint64_t file_offset,
void *payload) {
struct load_addr_t *addr = static_cast<load_addr_t *>(payload);
if (addr->target_addr >= v_addr && addr->target_addr < (v_addr + mem_sz)) {
addr->binary_addr = addr->target_addr - v_addr + file_offset;
return -1;
}
return 0;
}
int bcc_resolve_symname(const char *module, const char *symname,
const uint64_t addr, int pid,
struct bcc_symbol_option *option,
struct bcc_symbol *sym) {
uint64_t load_addr;
static struct bcc_symbol_option default_option = {
.use_debug_file = 1,
.check_debug_file_crc = 1,
......@@ -437,29 +450,37 @@ int bcc_resolve_symname(const char *module, const char *symname,
} else {
sym->module = bcc_procutils_which_so(module, pid);
}
if (sym->module == NULL)
return -1;
ProcMountNSGuard g(pid);
if (bcc_elf_loadaddr(sym->module, &load_addr) < 0)
goto invalid_module;
sym->name = symname;
sym->offset = addr;
if (option == NULL)
option = &default_option;
if (sym->name && sym->offset == 0x0)
if (bcc_elf_foreach_sym(sym->module, _find_sym, option, sym) < 0)
goto invalid_module;
if (sym->offset == 0x0)
goto invalid_module;
sym->offset = (sym->offset - load_addr);
// For executable (ET_EXEC) binaries, translate the virtual address
// to physical address in the binary file.
// For shared object binaries (ET_DYN), the address from symbol table should
// already be physical address in the binary file.
if (bcc_elf_get_type(sym->module) == ET_EXEC) {
struct load_addr_t addr = {
.target_addr = sym->offset,
.binary_addr = 0x0,
};
if (bcc_elf_foreach_load_section(sym->module, &_find_load, &addr) < 0)
goto invalid_module;
if (!addr.binary_addr)
goto invalid_module;
sym->offset = addr.binary_addr;
}
return 0;
invalid_module:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment