aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
authorEdgar E. Iglesias <edgar@axis.com>2012-09-27 17:02:38 +0200
committerPetr Machata <pmachata@redhat.com>2012-09-27 17:46:10 +0200
commit6ef7b2597cd3f4edf851a7b3516aef7449e554ad (patch)
tree5f3820dcdfe888b3fdb63d12ae16566625c9ef18 /sysdeps
parent9f274ffc8d38bd73c31c2b181f25349b813cb9dd (diff)
downloadltrace-6ef7b2597cd3f4edf851a7b3516aef7449e554ad.tar.gz
mipsel: Add mips specific symbol info loading
MIPS needs a backend specific way to load symbol info. We add fields to the symbol representation to keep track of the state of the dynamic symbol. At arch_dynlink_done we go through the symbols that are connected to a GOT entry but that where not resolved at startup time (e.g function pointers to external syms). Signed-off-by: Edgar E. Iglesias <edgar@axis.com>
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/linux-gnu/mipsel/arch.h18
-rw-r--r--sysdeps/linux-gnu/mipsel/plt.c168
2 files changed, 186 insertions, 0 deletions
diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h
index 1209423..ffb9b34 100644
--- a/sysdeps/linux-gnu/mipsel/arch.h
+++ b/sysdeps/linux-gnu/mipsel/arch.h
@@ -22,6 +22,7 @@
#define LTRACE_MIPS_ARCH_H
#include <stddef.h>
+#include <gelf.h>
#define BREAKPOINT_VALUE { 0x0d, 0x00, 0x00, 0x00 }
#define BREAKPOINT_LENGTH 4
@@ -38,4 +39,21 @@ struct arch_ltelf_data {
size_t mips_gotsym;
};
+#define ARCH_HAVE_GET_SYMINFO
+#define ARCH_HAVE_DYNLINK_DONE
+#define ARCH_HAVE_ADD_PLT_ENTRY
+
+#define ARCH_HAVE_LIBRARY_SYMBOL_DATA
+enum mips_plt_type
+{
+ MIPS_PLT_UNRESOLVED,
+ MIPS_PLT_RESOLVED,
+};
+
+struct arch_library_symbol_data {
+ enum mips_plt_type type;
+ GElf_Addr resolved_addr;
+ GElf_Addr stub_addr;
+};
+
#endif /* LTRACE_MIPS_ARCH_H */
diff --git a/sysdeps/linux-gnu/mipsel/plt.c b/sysdeps/linux-gnu/mipsel/plt.c
index 6ef67b2..8778781 100644
--- a/sysdeps/linux-gnu/mipsel/plt.c
+++ b/sysdeps/linux-gnu/mipsel/plt.c
@@ -1,4 +1,6 @@
+#include <string.h>
#include <error.h>
+#include <errno.h>
#include <gelf.h>
#include <sys/ptrace.h>
@@ -6,6 +8,7 @@
#include "debug.h"
#include "proc.h"
#include "library.h"
+#include "breakpoint.h"
#include "backend.h"
/**
@@ -81,6 +84,36 @@ sym2addr(Process *proc, struct library_symbol *sym) {
return (void *)ret;;
}
+/*
+ * MIPS doesn't have traditional got.plt entries with corresponding
+ * relocations.
+ *
+ * sym_index is an offset into the external GOT entries. Filter out
+ * stuff that are not functions.
+ */
+int
+arch_get_sym_info(struct ltelf *lte, const char *filename,
+ size_t sym_index, GElf_Rela *rela, GElf_Sym *sym)
+{
+ const char *name;
+
+ /* Fixup the offset. */
+ sym_index += lte->arch.mips_gotsym;
+
+ if (gelf_getsym(lte->dynsym, sym_index, sym) == NULL){
+ error(EXIT_FAILURE, 0,
+ "Couldn't get relocation from \"%s\"", filename);
+ }
+
+ name = lte->dynstr + sym->st_name;
+ if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC) {
+ debug(2, "sym %s not a function", name);
+ return -1;
+ }
+
+ return 0;
+}
+
/**
MIPS ABI Supplement:
@@ -131,6 +164,9 @@ arch_elf_init(struct ltelf *lte, struct library *lib)
}
}
+ /* Tell the generic code how many dynamic trace:able symbols
+ * we've got. */
+ lte->relplt_count = lte->dynsym_count - lte->arch.mips_gotsym;
return 0;
}
@@ -139,4 +175,136 @@ arch_elf_destroy(struct ltelf *lte)
{
}
+static enum callback_status
+cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
+{
+ struct Process *proc = data;
+ struct breakpoint *bp;
+ arch_addr_t bp_addr;
+
+ if (libsym->plt_type != LS_TOPLT_GOTONLY)
+ return CBS_CONT;
+
+ /* Update state. */
+ bp_addr = sym2addr(proc, libsym);
+ /* XXX The cast to uintptr_t should be removed when
+ * arch_addr_t becomes integral type. keywords: double cast. */
+ libsym->arch.resolved_addr = (uintptr_t) bp_addr;
+
+ if (libsym->arch.resolved_addr == 0)
+ /* FIXME: What does this mean? */
+ return CBS_CONT;
+
+ libsym->arch.type = MIPS_PLT_RESOLVED;
+
+ /* Add breakpoint. */
+ bp = malloc(sizeof *bp);
+ if (bp == NULL
+ || breakpoint_init(bp, proc, bp_addr, libsym) < 0) {
+ goto fail;
+ }
+
+ if (proc_add_breakpoint(proc, bp) < 0) {
+ breakpoint_destroy(bp);
+ goto fail;
+ }
+
+ if (breakpoint_turn_on(bp, proc) < 0) {
+ proc_remove_breakpoint(proc, bp);
+ breakpoint_destroy(bp);
+ goto fail;
+ }
+
+ return CBS_CONT;
+fail:
+ free(bp);
+ fprintf(stderr, "Failed to add breakpoint for %s\n", libsym->name);
+ return CBS_CONT;
+}
+
+static enum callback_status
+cb_enable_breakpoint_lib(struct Process *proc, struct library *lib, void *data)
+{
+ library_each_symbol(lib, NULL, cb_enable_breakpoint_sym, proc);
+ return CBS_CONT;
+}
+
+void arch_dynlink_done(struct Process *proc)
+{
+ proc_each_library(proc, NULL, cb_enable_breakpoint_lib, NULL);
+}
+
+enum plt_status
+arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte,
+ const char *a_name, GElf_Rela *rela, size_t ndx,
+ struct library_symbol **ret)
+{
+ char *name = NULL;
+ int sym_index = ndx + lte->arch.mips_gotsym;
+
+ struct library_symbol *libsym = malloc(sizeof(*libsym));
+ if (libsym == NULL)
+ return plt_fail;
+
+ GElf_Addr addr = arch_plt_sym_val(lte, sym_index, 0);
+
+ name = strdup(a_name);
+ if (name == NULL) {
+ fprintf(stderr, "%s: failed %s(%#llx): %s\n", __func__,
+ name, addr, strerror(errno));
+ goto fail;
+ }
+
+ /* XXX The double cast should be removed when
+ * arch_addr_t becomes integral type. */
+ if (library_symbol_init(libsym,
+ (arch_addr_t) (uintptr_t) addr,
+ name, 1, LS_TOPLT_EXEC) < 0) {
+ fprintf(stderr, "%s: failed %s : %llx\n", __func__, name, addr);
+ goto fail;
+ }
+
+ arch_addr_t bp_addr = sym2addr(proc, libsym);
+ /* XXX This cast should be removed when
+ * arch_addr_t becomes integral type. keywords: double cast. */
+ libsym->arch.stub_addr = (uintptr_t) bp_addr;
+
+ if (bp_addr == 0) {
+ /* Function pointers without PLT entries. */
+ libsym->plt_type = LS_TOPLT_GOTONLY;
+ libsym->arch.type = MIPS_PLT_UNRESOLVED;
+ }
+
+ *ret = libsym;
+ return plt_ok;
+
+fail:
+ free(name);
+ free(libsym);
+ return plt_fail;
+}
+
+int
+arch_library_symbol_init(struct library_symbol *libsym)
+{
+ libsym->arch.type = MIPS_PLT_UNRESOLVED;
+ if (libsym->plt_type == LS_TOPLT_NONE) {
+ libsym->arch.type = MIPS_PLT_RESOLVED;
+ }
+ return 0;
+}
+
+void
+arch_library_symbol_destroy(struct library_symbol *libsym)
+{
+}
+
+int
+arch_library_symbol_clone(struct library_symbol *retp,
+ struct library_symbol *libsym)
+{
+ retp->arch = libsym->arch;
+ return 0;
+}
+
/**@}*/