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                  |   11 ++++++++-
 sysdeps/linux-gnu/mipsel/arch.h |    1 +
 sysdeps/linux-gnu/mipsel/plt.c  |   45 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 60 insertions(+), 1 deletions(-)

diff --git a/backend.h b/backend.h
index e241eab..8b4e8fa 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..5793d7f 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);
 
@@ -614,7 +621,7 @@ handle_breakpoint(Event *event)
                         * have the same return address, but were made
                         * for different symbols.  This should only
                         * happen for entry point tracing, i.e. for -x
-                        * everywhere, or -x and -e on PPC64.  */
+                        * everywhere, or -x and -e on MIPS.  */
                        while (event->proc->callstack_depth > 0) {
                                struct callstack_element *prev;
                                size_t d = event->proc->callstack_depth;
@@ -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 d46136b..5f5a7dd 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 8778781..6e8dd9d 100644
--- a/sysdeps/linux-gnu/mipsel/plt.c
+++ b/sysdeps/linux-gnu/mipsel/plt.c
@@ -175,6 +175,51 @@ 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 != MIPS_PLT_UNRESOLVED)
+               return;
+
+       resolved_addr = sym2addr(proc, libsym);
+       libsym->arch.resolved_addr = (uintptr_t) resolved_addr;
+       libsym->arch.type = MIPS_PLT_RESOLVED;
+
+       if (libsym->arch.stub_addr == libsym->arch.resolved_addr) {
+               /* Prelinked symbol. No need to add new breakpoint.  */
+               return;
+       }
+
+       bp = malloc(sizeof (*bp));
+       if (bp == NULL) {
+               fprintf(stderr, "Failed to allocate bp for %s\n",
+                       libsym->name);
+               return;
+       }
+
+       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);
+}
+
 static enum callback_status
 cb_enable_breakpoint_sym(struct library_symbol *libsym, void *data)
 {
-- 
1.7.8.6


_______________________________________________
Ltrace-devel mailing list
[email protected]
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/ltrace-devel

Reply via email to