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, ...@@ -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); path, callback, (struct bcc_symbol_option*)option, payload, 0);
} }
static int loadaddr(Elf *e, uint64_t *addr) { int bcc_elf_foreach_load_section(const char *path,
size_t phnum, i; 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) if (openelf(path, &e, &fd) < 0)
return -1; goto exit;
for (i = 0; i < phnum; ++i) { if (elf_getphdrnum(e, &nhdrs) != 0)
GElf_Phdr header; goto exit;
GElf_Phdr header;
for (i = 0; i < nhdrs; i++) {
if (!gelf_getphdr(e, (int)i, &header)) if (!gelf_getphdr(e, (int)i, &header))
continue; continue;
if (header.p_type != PT_LOAD || !(header.p_flags & PF_X))
if (header.p_type != PT_LOAD)
continue; continue;
res = callback(header.p_vaddr, header.p_memsz, header.p_offset, payload);
*addr = (uint64_t)header.p_vaddr; if (res < 0) {
return 0; err = 1;
goto exit;
}
} }
err = 0;
return -1; exit:
} if (e)
elf_end(e);
int bcc_elf_loadaddr(const char *path, uint64_t *address) { if (fd >= 0)
Elf *e; close(fd);
int fd, res; return err;
if (openelf(path, &e, &fd) < 0)
return -1;
res = loadaddr(e, address);
elf_end(e);
close(fd);
return res;
} }
int bcc_elf_get_type(const char *path) { int bcc_elf_get_type(const char *path) {
......
...@@ -32,17 +32,31 @@ struct bcc_elf_usdt { ...@@ -32,17 +32,31 @@ struct bcc_elf_usdt {
const char *arg_fmt; const char *arg_fmt;
}; };
// Binary module path, bcc_elf_usdt struct, payload
typedef void (*bcc_elf_probecb)(const char *, const struct bcc_elf_usdt *, typedef void (*bcc_elf_probecb)(const char *, const struct bcc_elf_usdt *,
void *); void *);
// Symbol name, start address, length, payload // 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 *); 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, int bcc_elf_foreach_usdt(const char *path, bcc_elf_probecb callback,
void *payload); void *payload);
int bcc_elf_loadaddr(const char *path, uint64_t *address); // Iterate over all executable load sections of an ELF
int bcc_elf_foreach_sym(const char *path, bcc_elf_symcb callback, // Returns -1 on error, 1 if stopped by callback, and 0 on success
void *option, void *payload); 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_get_type(const char *path);
int bcc_elf_is_shared_obj(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, ...@@ -416,11 +416,24 @@ static int _find_sym(const char *symname, uint64_t addr, uint64_t,
return 0; 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, int bcc_resolve_symname(const char *module, const char *symname,
const uint64_t addr, int pid, const uint64_t addr, int pid,
struct bcc_symbol_option *option, struct bcc_symbol_option *option,
struct bcc_symbol *sym) { struct bcc_symbol *sym) {
uint64_t load_addr;
static struct bcc_symbol_option default_option = { static struct bcc_symbol_option default_option = {
.use_debug_file = 1, .use_debug_file = 1,
.check_debug_file_crc = 1, .check_debug_file_crc = 1,
...@@ -437,29 +450,37 @@ int bcc_resolve_symname(const char *module, const char *symname, ...@@ -437,29 +450,37 @@ int bcc_resolve_symname(const char *module, const char *symname,
} else { } else {
sym->module = bcc_procutils_which_so(module, pid); sym->module = bcc_procutils_which_so(module, pid);
} }
if (sym->module == NULL) if (sym->module == NULL)
return -1; return -1;
ProcMountNSGuard g(pid); ProcMountNSGuard g(pid);
if (bcc_elf_loadaddr(sym->module, &load_addr) < 0)
goto invalid_module;
sym->name = symname; sym->name = symname;
sym->offset = addr; sym->offset = addr;
if (option == NULL) if (option == NULL)
option = &default_option; option = &default_option;
if (sym->name && sym->offset == 0x0) if (sym->name && sym->offset == 0x0)
if (bcc_elf_foreach_sym(sym->module, _find_sym, option, sym) < 0) if (bcc_elf_foreach_sym(sym->module, _find_sym, option, sym) < 0)
goto invalid_module; goto invalid_module;
if (sym->offset == 0x0) if (sym->offset == 0x0)
goto invalid_module; 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; return 0;
invalid_module: 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