[ktap] [PATCH 1/3] symbol: replace find_symbol() by get_dso_symbols()

  • From: Azat Khuzhin <a3at.mail@xxxxxxxxx>
  • To: ktap@xxxxxxxxxxxxx
  • Date: Wed, 13 Nov 2013 23:13:35 +0400

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


Other related posts: