Old find_symbol() just find symbol by name, the new one get_dso_symbols() will return all symbols/notes. And user of this functions, will match name/pattern by itself. For now get_dso_symbols() used like find_symbol(), this behaviour will be changed in next patches. Signed-off-by: Azat Khuzhin <a3at.mail@xxxxxxxxx> --- userspace/eventdef.c | 13 ++++++- userspace/symbol.c | 105 +++++++++++++++++++++++++++++++++++++++++---------- userspace/symbol.h | 25 +++++++++--- 3 files changed, 117 insertions(+), 26 deletions(-) diff --git a/userspace/eventdef.c b/userspace/eventdef.c index 748ca10..13703c6 100644 --- a/userspace/eventdef.c +++ b/userspace/eventdef.c @@ -333,6 +333,8 @@ static char *parse_events_resolve_symbol(char *event, int type) { char *colon, *end, *tail, *binary, *symbol; vaddr_t symbol_address; + struct dso_symbol *symbols = NULL; + size_t symbols_count, i; colon = strchr(event, ':'); if (!colon) @@ -357,7 +359,16 @@ static char *parse_events_resolve_symbol(char *event, int type) symbol = strdup(colon + 1 /* skip ":" */); } - symbol_address = find_symbol(binary, symbol, type); + symbols_count = get_dso_symbols(&symbols, binary, type); + for (i = 0; i < symbols_count; ++i) { + if (strcmp(symbols[i].name, symbol)) + continue; + + symbol_address = symbols[i].addr; + break; + } + free_dso_symbols(symbols, symbols_count); + if (symbol_address) { verbose_printf("symbol %s resolved to 0x%lx\n", event, symbol_address); diff --git a/userspace/symbol.c b/userspace/symbol.c index 1df20f9..f3d5fc6 100644 --- a/userspace/symbol.c +++ b/userspace/symbol.c @@ -75,21 +75,59 @@ static vaddr_t find_load_address(Elf *elf) return address; } -static vaddr_t search_symbol(Elf *elf, const char *symbol) +void free_dso_symbols(struct dso_symbol *symbols, size_t symbols_count) +{ + size_t i; + for (i = 0; i < symbols_count; ++i) { + free(symbols[i].name); + } + + free(symbols); +} + +/** + * libc have about ~2000 symbols. + */ +#define SYMBOLS_COUNT 3000 + +/** + * realloc() and free() on failure + * + * TODO: allocation by chunks + */ +static struct dso_symbol * +realloc_symbols(struct dso_symbol *symbols, size_t symbols_count) +{ + struct dso_symbol *new; + + new = realloc(symbols, sizeof(*symbols) * symbols_count); + + if (!new && symbols) + free_dso_symbols(symbols, symbols_count); + + return new; +} + +static size_t elf_symbols(GElf_Shdr shdr) +{ + return shdr.sh_size / shdr.sh_entsize; +} + +static size_t dso_symbols(struct dso_symbol **symbols, Elf *elf) { Elf_Data *elf_data = NULL; Elf_Scn *scn = NULL; GElf_Sym sym; GElf_Shdr shdr; + size_t symbols_count = 0; vaddr_t load_address = find_load_address(elf); if (!load_address) - return 0; + return symbols_count; while ((scn = elf_nextscn(elf, scn))) { - int i, symbols; - char *current_symbol; + int i; gelf_getshdr(scn, &shdr); @@ -97,21 +135,31 @@ static vaddr_t search_symbol(Elf *elf, const char *symbol) continue; elf_data = elf_getdata(scn, elf_data); - symbols = shdr.sh_size / shdr.sh_entsize; - for (i = 0; i < symbols; i++) { + for (i = 0; i < elf_symbols(shdr); i++) { + char *name; + struct dso_symbol symbol; + gelf_getsym(elf_data, i, &sym); if (GELF_ST_TYPE(sym.st_info) != STT_FUNC) continue; - current_symbol = elf_strptr(elf, shdr.sh_link, sym.st_name); - if (!strcmp(current_symbol, symbol)) - return sym.st_value - load_address; + ++symbols_count; + *symbols = realloc_symbols(*symbols, symbols_count); + if (!*symbols) { + symbols_count = 0; + break; + } + + name = elf_strptr(elf, shdr.sh_link, sym.st_name); + symbol.name = strdup(name); + symbol.addr = sym.st_value - load_address; + memcpy(&(*symbols)[symbols_count - 1], &symbol, sizeof(symbol)); } } - return 0; + return symbols_count; } #define SDT_NOTE_TYPE 3 @@ -172,7 +220,7 @@ static const char *sdt_note_data(const Elf_Data *data, size_t off) return ((data->d_buf) + off); } -static vaddr_t search_stapsdt_note(Elf *elf, const char *note) +static size_t dso_sdt_notes(struct dso_symbol **symbols, Elf *elf) { GElf_Ehdr ehdr; Elf_Scn *scn = NULL; @@ -182,7 +230,9 @@ static vaddr_t search_stapsdt_note(Elf *elf, const char *note) size_t next; GElf_Nhdr nhdr; size_t name_off, desc_off, offset; + vaddr_t vaddr = 0; + size_t symbols_count = 0; if (gelf_getehdr(elf, &ehdr) == NULL) return 0; @@ -205,6 +255,7 @@ static vaddr_t search_stapsdt_note(Elf *elf, const char *note) (next = gelf_getnote(data, offset, &nhdr, &name_off, &desc_off)) > 0; offset = next) { const char *name; + struct dso_symbol symbol; if (nhdr.n_namesz != sizeof(SDT_NOTE_NAME) || memcmp(data->d_buf + name_off, SDT_NOTE_NAME, @@ -212,37 +263,51 @@ static vaddr_t search_stapsdt_note(Elf *elf, const char *note) continue; name = sdt_note_name(elf, &nhdr, sdt_note_data(data, desc_off)); - if (!name || strcmp(name, note)) + if (!name) continue; vaddr = sdt_note_addr(elf, sdt_note_data(data, desc_off), nhdr.n_descsz, nhdr.n_type); + if (!vaddr) + continue; + + ++symbols_count; + *symbols = realloc_symbols(*symbols, symbols_count); + if (!*symbols) { + symbols_count = 0; + break; + } + + symbol.name = strdup(name); + symbol.addr = vaddr; + memcpy(&(*symbols)[symbols_count - 1], &symbol, sizeof(symbol)); } - return vaddr; + return symbols_count; } -vaddr_t find_symbol(const char *exec, const char *symbol, int type) +size_t get_dso_symbols(struct dso_symbol **symbols, const char *exec, int type) { - vaddr_t vaddr = 0; + size_t symbols_count = 0; + Elf *elf; int fd; if (elf_version(EV_CURRENT) == EV_NONE) - return vaddr; + return symbols_count; fd = open(exec, O_RDONLY); if (fd < 0) - return vaddr; + return symbols_count; elf = elf_begin(fd, ELF_C_READ, NULL); if (elf) { switch (type) { case FIND_SYMBOL: - vaddr = search_symbol(elf, symbol); + symbols_count = dso_symbols(symbols, elf); break; case FIND_STAPSDT_NOTE: - vaddr = search_stapsdt_note(elf, symbol); + symbols_count = dso_sdt_notes(symbols, elf); break; } @@ -250,5 +315,5 @@ vaddr_t find_symbol(const char *exec, const char *symbol, int type) } close(fd); - return vaddr; + return symbols_count; } diff --git a/userspace/symbol.h b/userspace/symbol.h index 558d5fe..e4ac8a7 100644 --- a/userspace/symbol.h +++ b/userspace/symbol.h @@ -1,5 +1,5 @@ /* - * symbol.h + * symbol.h - extract symbols from DSO. * * This file is part of ktap by Jovi Zhangwei. * @@ -23,14 +23,29 @@ #define FIND_SYMBOL 1 #define FIND_STAPSDT_NOTE 2 +struct dso_symbol; + #ifndef NO_LIBELF + #include <gelf.h> +#include <sys/queue.h> + typedef GElf_Addr vaddr_t; +struct dso_symbol +{ + char *name; + vaddr_t addr; +}; + /** - * Find symbol in DSO - * - * @return 0 on failure, otherwise address of symbol. + * free() symbols and it's names + */ +void free_dso_symbols(struct dso_symbol *symbols, size_t symbols_count); +/** + * @return all symbols and notes in DSO. + * (You must call free_dso_symbols() at end.) */ -vaddr_t find_symbol(const char *exec, const char *symbol, int type); +size_t get_dso_symbols(struct dso_symbol **symbols, const char *exec, int type); + #endif -- 1.8.4.rc3