aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/linux-gnu/trace.c
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2013-10-15 10:46:28 +0200
committerPetr Machata <pmachata@redhat.com>2013-10-23 01:00:03 +0200
commitb420a226cd2fc5d6028adcaf236c512a1f1fb437 (patch)
tree59421b8cf2d90e1220bf1cc6828d1697bf6a55d0 /sysdeps/linux-gnu/trace.c
parent7a29f9e7a2bd5849886519eb82e9c043d24c6a40 (diff)
downloadltrace-b420a226cd2fc5d6028adcaf236c512a1f1fb437.tar.gz
Add support for tracing of IRELATIVE PLT entries
- Because the IRELATIVE entries have no associated symbol name, we need to allow arch_elf_add_plt_entry to override the name. This is done by that callback returning PLT_OK and returning the new symbol via libsym-chain return argument. Filtering is postponed until we have that symbol, and the filter is applied to the whole returned chain. - Add linux_elf_add_plt_entry_irelative to support proper naming of IRELATIVE PLT entries. This needs to be called from arch backend, as the numbers of IRELATIVE relocations differ per-architecture.
Diffstat (limited to 'sysdeps/linux-gnu/trace.c')
-rw-r--r--sysdeps/linux-gnu/trace.c67
1 files changed, 64 insertions, 3 deletions
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 677438e..5567eb6 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -24,25 +24,28 @@
#include "config.h"
#include <asm/unistd.h>
-#include <sys/types.h>
-#include <sys/wait.h>
#include <assert.h>
#include <errno.h>
+#include <gelf.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#ifdef HAVE_LIBSELINUX
# include <selinux/selinux.h>
#endif
-#include "linux-gnu/trace.h"
#include "linux-gnu/trace-defs.h"
+#include "linux-gnu/trace.h"
#include "backend.h"
#include "breakpoint.h"
#include "debug.h"
#include "events.h"
+#include "ltrace-elf.h"
#include "options.h"
#include "proc.h"
#include "ptrace.h"
@@ -1220,3 +1223,61 @@ umovebytes(struct process *proc, void *addr, void *laddr, size_t len)
return bytes_read;
}
+
+struct irelative_name_data_t {
+ GElf_Addr addr;
+ const char *found_name;
+};
+
+static enum callback_status
+irelative_name_cb(GElf_Sym *symbol, const char *name, void *d)
+{
+ struct irelative_name_data_t *data = d;
+
+ if (symbol->st_value == data->addr) {
+ bool is_ifunc = false;
+#ifdef STT_GNU_IFUNC
+ is_ifunc = GELF_ST_TYPE(symbol->st_info) == STT_GNU_IFUNC;
+#endif
+ data->found_name = name;
+
+ /* Keep looking, unless we found the actual IFUNC
+ * symbol. What we matched may have been a symbol
+ * denoting the resolver function, which would have
+ * the same address. */
+ return CBS_STOP_IF(is_ifunc);
+ }
+
+ return CBS_CONT;
+}
+
+enum plt_status
+linux_elf_add_plt_entry_irelative(struct process *proc, struct ltelf *lte,
+ GElf_Rela *rela, size_t ndx,
+ struct library_symbol **ret)
+
+{
+ struct irelative_name_data_t data = { rela->r_addend, NULL };
+ if (rela->r_addend != 0
+ && elf_each_symbol(lte, 0,
+ irelative_name_cb, &data).status < 0)
+ return -1;
+
+ const char *name;
+ if (data.found_name != NULL) {
+ name = data.found_name;
+ } else {
+#define NAME "IREL."
+ /* NAME\0 + 0x + digits. */
+ char *tmp_name = alloca(sizeof NAME + 2 + 16);
+ sprintf(tmp_name, NAME "%#" PRIx64,
+ (uint64_t)rela->r_addend);
+ name = tmp_name;
+#undef NAME
+ }
+
+ if (default_elf_add_plt_entry(proc, lte, name, rela, ndx, ret) < 0)
+ return PLT_FAIL;
+
+ return PLT_OK;
+}