Skip to content

Commit

Permalink
Merge pull request iovisor#1357 from palmtenor/load_section
Browse files Browse the repository at this point in the history
Fix edge case when doing symbol name -> address resolution
  • Loading branch information
yonghong-song committed Sep 25, 2017
2 parents ac5c03c + b09e43b commit 899d3e9
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 38 deletions.
51 changes: 25 additions & 26 deletions src/cc/bcc_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
elf_end(e);
close(fd);

return res;
exit:
if (e)
elf_end(e);
if (fd >= 0)
close(fd);
return err;
}

int bcc_elf_get_type(const char *path) {
Expand Down
22 changes: 18 additions & 4 deletions src/cc/bcc_elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
37 changes: 29 additions & 8 deletions src/cc/bcc_syms.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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:
Expand Down

0 comments on commit 899d3e9

Please sign in to comment.