[ktap] [PATCH] add new symbol module to search symbols in DSO (for uprobes)

  • From: Azat Khuzhin <a3at.mail@xxxxxxxxx>
  • To: ktap@xxxxxxxxxxxxx
  • Date: Tue, 5 Nov 2013 08:16:21 +0400

This will allow to don't hardcoding addresses of functions in ktap
scripts, that use uprobes, but instead, use normal function names.

Before this patch:
$ ktap -e 'trace probe:/path/to/bin:0xDEADBEAF' # instead some real address

After this path:
$ ktap -e 'trace probe:/path/to/bin:foo'

Works also for ret probes (%return)
Requires libelf.

Signed-off-by: Azat Khuzhin <a3at.mail@xxxxxxxxx>
---
v2: make it more pretty
v3: make it faster (thanks to Yicheng)

 Makefile             |   5 ++-
 include/ktap_types.h |   2 +
 userspace/eventdef.c |  43 ++++++++++++++++++-
 userspace/symbol.c   | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++
 userspace/symbol.h   |  32 +++++++++++++++
 5 files changed, 194 insertions(+), 2 deletions(-)
 create mode 100644 userspace/symbol.c
 create mode 100644 userspace/symbol.h

diff --git a/Makefile b/Makefile
index 372b41a..344c82a 100644
--- a/Makefile
+++ b/Makefile
@@ -59,6 +59,8 @@ $(UDIR)/tstring.o: $(INTP)/tstring.c $(INC)/*
        $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $<
 $(UDIR)/object.o: $(INTP)/object.c $(INC)/*
        $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $<
+$(UDIR)/symbol.o: $(UDIR)/symbol.c $(INC)/*
+       $(QUIET_CC)$(CC) $(DEBUGINFO_FLAG) $(KTAPC_CFLAGS) -o $@ -c $<
 
 KTAPOBJS =
 KTAPOBJS += $(UDIR)/lex.o
@@ -73,9 +75,10 @@ KTAPOBJS += $(UDIR)/opcode.o
 KTAPOBJS += $(UDIR)/table.o
 KTAPOBJS += $(UDIR)/tstring.o
 KTAPOBJS += $(UDIR)/object.o
+KTAPOBJS += $(UDIR)/symbol.o
 
 ktap: $(KTAPOBJS)
-       $(QUIET_LINK)$(CC) $(KTAPC_CFLAGS) -o $@ $(KTAPOBJS) -lpthread
+       $(QUIET_LINK)$(CC) $(KTAPC_CFLAGS) -o $@ $(KTAPOBJS) -lpthread -lelf
 
 KMISC := /lib/modules/$(KVERSION)/ktapvm/
 
diff --git a/include/ktap_types.h b/include/ktap_types.h
index 1dae9d8..4e19f0b 100644
--- a/include/ktap_types.h
+++ b/include/ktap_types.h
@@ -600,5 +600,7 @@ extern ktap_global_state dummy_global_state;
 #define KTAP_QL(x)      "'" x "'"
 #define KTAP_QS         KTAP_QL("%s")
 
+#define STRINGIFY(type) #type
+
 #endif /* __KTAP_TYPES_H__ */
 
diff --git a/userspace/eventdef.c b/userspace/eventdef.c
index 76a68ac..280202d 100644
--- a/userspace/eventdef.c
+++ b/userspace/eventdef.c
@@ -29,6 +29,7 @@
 #include "../include/ktap_types.h"
 #include "../include/ktap_opcodes.h"
 #include "ktapc.h"
+#include "symbol.h"
 
 static char tracing_events_path[] = "/sys/kernel/debug/tracing/events";
 
@@ -305,6 +306,42 @@ static int parse_events_add_kprobe(char *old_event)
 
 #define UPROBE_EVENTS_PATH "/sys/kernel/debug/tracing/uprobe_events"
 
+static char* parse_events_resolve_symbol(char *event, char *r)
+{
+       char *colon = strchr(event, ':');
+       vaddr_t symbol_address = strtol(colon + 1 /* skip ":" */, NULL, 0);
+
+       char *binary, *symbol;
+
+       /**
+        * We already have address, no need in resolving.
+        */
+       if (symbol_address) {
+               return event;
+       }
+
+       binary = strndup(event, colon - event);
+       if (r) {
+               symbol = strndup(colon + 1 /* skip ":" */,
+                       r - 1 /* skip "%" */ - colon);
+       } else {
+               symbol = strdup(colon + 1);
+       }
+
+       if ((symbol_address = find_symbol(binary, symbol))) {
+               verbose_printf("symbol %s resolved to 0x%lx\n",
+                       event, symbol_address);
+
+               event = realloc(event, strlen(event) + 
(strlen(STRINGIFY(ULONG_MAX))));
+               sprintf(event, "%s:0x%lx", binary, symbol_address);
+       }
+
+       free(binary);
+       free(symbol);
+
+       return event;
+}
+
 static int parse_events_add_uprobe(char *old_event)
 {
        static int event_seq = 0;
@@ -326,6 +363,10 @@ static int parse_events_add_uprobe(char *old_event)
        r = strstr(event, "%return");
        if (r) {
                memset(r, ' ', 7);
+       }
+       event = parse_events_resolve_symbol(event, r);
+
+       if (r) {
                snprintf(probe_event, 128, "r:uprobes/kp%d %s",
                                event_seq, event);
        } else
@@ -541,7 +582,7 @@ ktap_string *ktapc_parse_eventdef(ktap_string *eventdef)
                goto parse_next_eventdef;
 
        ts = ktapc_ts_new(g_idstr);
-       free(g_idstr);  
+       free(g_idstr);
 
        return ts;
  error:
diff --git a/userspace/symbol.c b/userspace/symbol.c
new file mode 100644
index 0000000..23333b8
--- /dev/null
+++ b/userspace/symbol.c
@@ -0,0 +1,114 @@
+/*
+ * symbol.c
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2013 Azat Khuzhin <a3at.mail@xxxxxxxxx>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "symbol.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <libelf.h>
+
+
+/**
+ * @return v_addr of "LOAD" program header, that have zero offset.
+ */
+static vaddr_t find_load_address(Elf *elf)
+{
+       GElf_Phdr header;
+       size_t headers;
+       vaddr_t address = 0;
+
+       elf_getphdrnum(elf, &headers);
+       while (headers-- > 0) {
+               gelf_getphdr(elf, headers, &header);
+               if (header.p_type != PT_LOAD || header.p_offset != 0)
+                       continue;
+
+               address = header.p_vaddr;
+               break;
+       }
+
+       return address;
+}
+
+static vaddr_t search_symbol(Elf *elf, const char *symbol)
+{
+       Elf_Data *elf_data = NULL;
+       Elf_Scn *scn = NULL;
+       GElf_Sym sym;
+       GElf_Shdr shdr;
+
+       vaddr_t load_address = find_load_address(elf);
+
+       if (!load_address)
+               return 0;
+
+       while ((scn = elf_nextscn(elf, scn))) {
+               int i, symbols;
+               char *current_symbol;
+
+               gelf_getshdr(scn, &shdr);
+
+               if (shdr.sh_type != SHT_SYMTAB)
+                       continue;
+
+               elf_data = elf_getdata(scn, elf_data);
+               symbols = shdr.sh_size / shdr.sh_entsize;
+
+               for (i = 0; i < symbols; i++) {
+                       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);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+vaddr_t find_symbol(const char *exec, const char *symbol)
+{
+       Elf *elf = NULL;
+       int fd = 0;
+       vaddr_t vaddr = 0;
+
+       if (((fd = open(exec, O_RDONLY)) != -1) &&
+           (elf_version(EV_CURRENT) != EV_NONE) &&
+           (elf = elf_begin(fd, ELF_C_READ, NULL)))
+                       vaddr = search_symbol(elf, symbol);
+
+       if (elf)
+               elf_end(elf);
+       if (fd)
+               close(fd);
+       return vaddr;
+}
diff --git a/userspace/symbol.h b/userspace/symbol.h
new file mode 100644
index 0000000..478ad2e
--- /dev/null
+++ b/userspace/symbol.h
@@ -0,0 +1,32 @@
+/*
+ * symbol.h
+ *
+ * This file is part of ktap by Jovi Zhangwei.
+ *
+ * Copyright (C) 2013 Azat Khuzhin <a3at.mail@xxxxxxxxx>.
+ *
+ * ktap is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * ktap is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <gelf.h> // GElf_Addr
+
+
+typedef GElf_Addr vaddr_t;
+
+/**
+ * Find symbol in DSO
+ *
+ * @return 0 on failure, otherwise address of symbol.
+ */
+vaddr_t find_symbol(const char *exec, const char *symbol);
-- 
1.8.4.rc3


Other related posts: