From: "Edgar E. Iglesias" <[email protected]> When functions return we check if the symbol went from unresolved to resolved and if the resolved address differs from the unresolved one. If so, we add a new breakpoint at the resolved address.
This is not thread-safe. Signed-off-by: Edgar E. Iglesias <[email protected]> --- backend.h | 4 +++ handle_event.c | 9 ++++++++ sysdeps/linux-gnu/mipsel/arch.h | 1 + sysdeps/linux-gnu/mipsel/plt.c | 39 ++++++++++++++++++++++++++++++++++++++ sysdeps/linux-gnu/mipsel/trace.c | 2 +- 5 files changed, 54 insertions(+), 1 deletions(-) diff --git a/backend.h b/backend.h index 60d682d..c562728 100644 --- a/backend.h +++ b/backend.h @@ -308,6 +308,10 @@ enum plt_status arch_elf_add_plt_entry(struct Process *proc, struct ltelf *lte, * done with the process startup. */ void arch_dynlink_done(struct Process *proc); +/* This callback needs to be implemented if arch.h defines + * ARCH_HAVE_SYMBOL_RET. It is called after a traced call returns. */ +void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym); + /* If arch.h defines ARCH_HAVE_FETCH_ARG, the following callbacks have * to be implemented: arch_fetch_arg_init, arch_fetch_arg_clone, * arch_fetch_arg_done, arch_fetch_arg_next and arch_fetch_retval. diff --git a/handle_event.c b/handle_event.c index 384e868..3782946 100644 --- a/handle_event.c +++ b/handle_event.c @@ -573,6 +573,12 @@ output_right_tos(struct Process *proc) output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc); } +#ifndef ARCH_HAVE_SYMBOL_RET +void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym) +{ +} +#endif + static void handle_breakpoint(Event *event) { @@ -606,6 +612,7 @@ handle_breakpoint(Event *event) struct library_symbol *libsym = event->proc->callstack[i].c_un.libfunc; + arch_symbol_ret(event->proc, libsym); output_right_tos(event->proc); callstack_pop(event->proc); @@ -624,6 +631,8 @@ handle_breakpoint(Event *event) || prev->return_addr != brk_addr) break; + arch_symbol_ret(event->proc, + prev->c_un.libfunc); output_right_tos(event->proc); callstack_pop(event->proc); } diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h index 23fe167..9144d83 100644 --- a/sysdeps/linux-gnu/mipsel/arch.h +++ b/sysdeps/linux-gnu/mipsel/arch.h @@ -43,6 +43,7 @@ struct arch_ltelf_data { #define ARCH_HAVE_DYNLINK_DONE #define ARCH_HAVE_ADD_PLT_ENTRY #define ARCH_HAVE_ATOMIC_SINGLESTEP +#define ARCH_HAVE_SYMBOL_RET #define ARCH_HAVE_LIBRARY_SYMBOL_DATA enum mips_plt_type diff --git a/sysdeps/linux-gnu/mipsel/plt.c b/sysdeps/linux-gnu/mipsel/plt.c index bc2a622..d595c61 100644 --- a/sysdeps/linux-gnu/mipsel/plt.c +++ b/sysdeps/linux-gnu/mipsel/plt.c @@ -174,6 +174,45 @@ arch_elf_destroy(struct ltelf *lte) { } +/* When functions return we check if the symbol needs an updated + breakpoint with the resolved address. */ +void arch_symbol_ret(struct Process *proc, struct library_symbol *libsym) +{ + struct breakpoint *bp; + arch_addr_t resolved_addr; + + /* Only deal with unresolved symbols. */ + if (libsym->arch.type != UNRESOLVED) + return; + + resolved_addr = sym2addr(proc, libsym); + libsym->arch.resolved_addr = (uintptr_t) resolved_addr; + libsym->arch.type = RESOLVED; + + if (libsym->arch.stub_addr == libsym->arch.resolved_addr) { + /* Prelinked symbol. No need to add new breakpoint. */ + return; + } + + bp = malloc (sizeof *bp); + if (breakpoint_init(bp, proc, resolved_addr, libsym) < 0) + goto err; + + if (proc_add_breakpoint(proc, bp) < 0) { + breakpoint_destroy(bp); + goto err; + } + + if (breakpoint_turn_on(bp, proc) < 0) { + proc_remove_breakpoint(proc, bp); + breakpoint_destroy(bp); + goto err; + } + return; +err: + free(bp); +} + enum callback_status cb_each_sym(struct library_symbol *libsym, void *data) { struct Process *proc = data; diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c index 1143397..dae416b 100644 --- a/sysdeps/linux-gnu/mipsel/trace.c +++ b/sysdeps/linux-gnu/mipsel/trace.c @@ -243,7 +243,7 @@ arch_atomic_singlestep(struct Process *proc, struct breakpoint *sbp, while (nr--) { arch_addr_t baddr = (void *) newpcs[nr]; - /* Not sure what to do here. We've already got a bp. */ + /* Not sure what to do here. We've already got a bp? */ if (dict_find_entry(proc->breakpoints, baddr)) { fprintf(stderr, "skip %p %p\n", baddr, add_cb_data); continue; -- 1.7.8.6 _______________________________________________ Ltrace-devel mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/ltrace-devel
