[Ltrace-devel] [PATCH 6/8] mipsel: Add mips specific symbol info loading
edgar.iglesias at gmail.com
edgar.iglesias at gmail.com
Wed Sep 26 15:39:48 UTC 2012
From: "Edgar E. Iglesias" <edgar at axis.com>
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 at axis.com>
---
proc.c | 13 +++
sysdeps/linux-gnu/mipsel/arch.h | 18 +++++
sysdeps/linux-gnu/mipsel/plt.c | 159 +++++++++++++++++++++++++++++++++++++++
3 files changed, 190 insertions(+), 0 deletions(-)
diff --git a/proc.c b/proc.c
index 319ef31..d76a556 100644
--- a/proc.c
+++ b/proc.c
@@ -637,6 +637,19 @@ breakpoint_for_symbol(struct library_symbol *libsym, void *data)
assert(proc->leader == proc);
bp_addr = sym2addr(proc, libsym);
+
+ /* For external function pointers, MIPS brings in stub-less funcs
+ * that point to zero at startup. These symbols get resolved by
+ * the dynamic linker and are ready to use at arch_dynlink_done().
+ *
+ * Allow the backend to add these into the process representation
+ * but don't put breakpoints at this point. Let the backend fix that
+ * up later. */
+ if (!bp_addr && libsym->plt_type == LS_TOPLT_GOTONLY) {
+ /* Don't add breakpoints yet. */
+ return CBS_CONT;
+ }
+
/* If there is an artificial breakpoint on the same address,
* its libsym will be NULL, and we can smuggle our libsym
* there. That artificial breakpoint is there presumably for
diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h
index 1209423..cfb5a4d 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
+{
+ UNRESOLVED,
+ 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..bc2a622 100644
--- a/sysdeps/linux-gnu/mipsel/plt.c
+++ b/sysdeps/linux-gnu/mipsel/plt.c
@@ -1,3 +1,4 @@
+#include <string.h>
#include <error.h>
#include <gelf.h>
#include <sys/ptrace.h>
@@ -6,6 +7,7 @@
#include "debug.h"
#include "proc.h"
#include "library.h"
+#include "breakpoint.h"
#include "backend.h"
/**
@@ -81,6 +83,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,
+ GElf_Rela *rela, GElf_Sym *sym, size_t sym_index)
+{
+ 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 +163,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 +174,128 @@ arch_elf_destroy(struct ltelf *lte)
{
}
+enum callback_status cb_each_sym(struct library_symbol *libsym, void *data)
+{
+ struct Process *proc = data;
+ struct breakpoint *bp;
+
+ if (libsym->plt_type != LS_TOPLT_GOTONLY)
+ return CBS_CONT;
+
+ /* Update state. */
+ libsym->arch.resolved_addr = (uintptr_t) sym2addr(proc, libsym);
+
+ if (!libsym->arch.resolved_addr)
+ /* FIXME: What does this mean? */
+ return CBS_CONT;
+
+ libsym->arch.type = RESOLVED;
+
+ /* Add breakpoint. */
+ bp = malloc(sizeof *bp);
+ if (!bp
+ || breakpoint_init(bp, proc,
+ (void *) (uintptr_t) libsym->arch.resolved_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_FAIL;
+}
+
+enum callback_status cb_each_lib(struct Process *proc,
+ struct library *lib, void *data)
+{
+ struct library_symbol *libsym = NULL;
+ while ((libsym = library_each_symbol(lib, libsym,
+ cb_each_sym, proc)) != NULL) {
+ }
+ return CBS_CONT;
+}
+
+void arch_dynlink_done(struct Process *proc)
+{
+ proc_each_library(proc, NULL, cb_each_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)
+{
+ struct library_symbol *libsym = NULL;
+ arch_addr_t bp_addr;
+ char *name = NULL;
+ int sym_index = ndx + lte->arch.mips_gotsym;
+
+ libsym = malloc(sizeof(*libsym));
+ if (!libsym)
+ return plt_fail;
+
+ GElf_Addr addr = arch_plt_sym_val(lte, sym_index, 0);
+
+ name = strdup(a_name);
+ 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;
+ }
+
+ bp_addr = sym2addr(proc, libsym);
+ libsym->arch.stub_addr = (uintptr_t) bp_addr;
+
+ if (!bp_addr) {
+ /* Function pointers without PLT entries. */
+ libsym->plt_type = LS_TOPLT_GOTONLY;
+ libsym->arch.type = 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 = UNRESOLVED;
+ if (libsym->plt_type == LS_TOPLT_NONE) {
+ libsym->arch.type = 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;
+}
+
/**@}*/
--
1.7.8.6
More information about the Ltrace-devel
mailing list