---
 common.h                   |    6 ++
 defs.h                     |    2 +-
 handle_event.c             |    5 +-
 ltrace-elf.c               |   26 +++++-
 sysdeps/README             |    1 +
 sysdeps/linux-gnu/events.c |    8 ++-
 sysdeps/linux-gnu/proc.c   |  209 ++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 249 insertions(+), 8 deletions(-)

diff --git a/common.h b/common.h
index 115b954..baf66d5 100644
--- a/common.h
+++ b/common.h
@@ -177,6 +177,8 @@ struct Process {
        struct library_symbol * list_of_symbols;
 
        /* Arch-dependent: */
+       void * debug;   /* arch-dep process debug struct */
+       long debug_state; /* arch-dep debug state */
        void * instruction_pointer;
        void * stack_pointer;      /* To get return addr, args... */
        void * return_addr;
@@ -267,4 +269,8 @@ extern int umovelong (Process * proc, void * addr, long * 
result, arg_type_info
 extern size_t umovebytes (Process *proc, void * addr, void * laddr, size_t 
count);
 extern int ffcheck(void * maddr);
 extern void * sym2addr(Process *, struct library_symbol *);
+extern int linkmap_init(Process *, struct ltelf *);
+extern void arch_check_dbg(Process *proc);
 
+extern int libdl_hooked;
+extern struct ltelf main_lte;
diff --git a/defs.h b/defs.h
index b694099..dea000b 100644
--- a/defs.h
+++ b/defs.h
@@ -15,4 +15,4 @@
 #define DEFAULT_ARRAYLEN  4    /* default maximum # array elements */
 #endif                         /* (-A switch) */
 
-#define MAX_LIBRARIES 30
+#define MAX_LIBRARIES 200
diff --git a/handle_event.c b/handle_event.c
index b6ea172..1664016 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -609,7 +609,10 @@ handle_breakpoint(Event *event) {
        }
 
        if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) {
-               if (event->proc->state != STATE_IGNORED) {
+               if (strcmp(sbp->libsym->name, "") == 0) {
+                       debug(2, "Hit _dl_debug_state breakpoint!\n");
+                       arch_check_dbg(event->proc);
+               } else if (event->proc->state != STATE_IGNORED) {
                        event->proc->stack_pointer = 
get_stack_pointer(event->proc);
                        event->proc->return_addr =
                                get_return_addr(event->proc, 
event->proc->stack_pointer);
diff --git a/ltrace-elf.c b/ltrace-elf.c
index ee5e350..a9ac0d2 100644
--- a/ltrace-elf.c
+++ b/ltrace-elf.c
@@ -1,4 +1,4 @@
-# include "config.h"
+#include "config.h"
 
 #include <endian.h>
 #include <errno.h>
@@ -21,10 +21,14 @@ int in_load_libraries(const char *name, struct ltelf *lte, 
size_t count, GElf_Sy
 static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr);
 
 struct library_symbol *library_symbols = NULL;
+struct ltelf main_lte;
+
 #ifdef PLT_REINITALISATION_BP
 extern char *PLTs_initialized_by_here;
 #endif
 
+int libdl_hooked = 0;
+
 void
 do_init_elf(struct ltelf *lte, const char *filename) {
        int i;
@@ -34,7 +38,6 @@ do_init_elf(struct ltelf *lte, const char *filename) {
        debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename);
        debug(1, "Reading ELF from %s...", filename);
 
-       memset(lte, 0, sizeof(*lte));
        lte->fd = open(filename, O_RDONLY);
        if (lte->fd == -1)
                error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename);
@@ -478,14 +481,27 @@ read_elf(Process *proc) {
 
        debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename);
 
+       memset(lte, 0, sizeof(lte));
        library_symbols = NULL;
        library_num = 0;
+       libdl_hooked = 0;
+
        elf_version(EV_CURRENT);
 
        do_init_elf(lte, proc->filename);
+
+       memcpy(&main_lte, lte, sizeof(struct ltelf));
+
+       if (opt_p && opt_p->pid > 0) {
+               linkmap_init(proc, lte);
+               libdl_hooked = 1;
+       }
+
        proc->e_machine = lte->ehdr.e_machine;
-       for (i = 0; i < library_num; ++i)
+
+       for (i = 0; i < library_num; ++i) {
                do_init_elf(&lte[i + 1], library[i]);
+       }
 
        if (!options.no_plt) {
 #ifdef __mips__
@@ -653,8 +669,8 @@ read_elf(Process *proc) {
                        }
 #endif
                        fprintf (stderr,
-                                "%s: Couldn't find symbol \"%s\" in file \"%s"
-                                "\"\n", badthing, xptr->name, proc->filename);
+                                "%s: Couldn't find symbol \"%s\" in file 
\"%s\" assuming it will be loaded by libdl!"
+                                "\n", badthing, xptr->name, proc->filename);
                }
        if (exit_out) {
                exit (1);
diff --git a/sysdeps/README b/sysdeps/README
index ce033ef..0a37909 100644
--- a/sysdeps/README
+++ b/sysdeps/README
@@ -30,3 +30,4 @@ char * pid2name(pid_t pid);
 void trace_me(void);
 int trace_pid(pid_t pid);
 void untrace_pid(pid_t pid);
+void linkmap_init(Process *, struct ltelf *);
diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
index a1e2a14..5b636f5 100644
--- a/sysdeps/linux-gnu/events.c
+++ b/sysdeps/linux-gnu/events.c
@@ -49,13 +49,19 @@ next_event(void) {
        event.proc->instruction_pointer = NULL;
        debug(3, "event from pid %u", pid);
        if (event.proc->breakpoints_enabled == -1) {
-               enable_all_breakpoints(event.proc);
                event.type = EVENT_NONE;
                trace_set_options(event.proc, event.proc->pid);
+               enable_all_breakpoints(event.proc);
                continue_process(event.proc->pid);
                debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling 
breakpoints)", pid);
                return &event;
+       } else if (!libdl_hooked) {
+               /* debug struct may not have been written yet.. */
+               if (linkmap_init(event.proc, &main_lte) == 0) {
+                       libdl_hooked = 1;
+               }
        }
+
        if (opt_i) {
                event.proc->instruction_pointer =
                        get_instruction_pointer(event.proc);
diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c
index 86ad301..eaf9b5f 100644
--- a/sysdeps/linux-gnu/proc.c
+++ b/sysdeps/linux-gnu/proc.c
@@ -68,3 +68,212 @@ find_dynamic_entry_addr(Process *proc, void *pvAddr, int 
d_tag, void **addr) {
                return -1;
        }
 }
+
+struct cb_data {
+       const char *lib_name;
+       struct ltelf *lte;
+       ElfW(Addr) addr;
+       Process *proc;
+};
+
+static void
+crawl_linkmap(Process *proc, struct r_debug *dbg, void (*callback)(void *), 
struct cb_data *data) {
+       struct link_map rlm;
+       char lib_name[BUFSIZ];
+       struct link_map *lm = NULL;
+
+       debug (DEBUG_FUNCTION, "crawl_linkmap()");
+
+       if (!dbg || !dbg->r_map) {
+               debug(2, "Debug structure or it's linkmap are NULL!");
+               return;
+       }
+
+       lm = dbg->r_map;
+
+       while (lm) {
+               if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) {
+                       debug(2, "Unable to read link map\n");
+                       return;
+               }
+
+               lm = rlm.l_next;
+               if (rlm.l_name == NULL) {
+                       debug(2, "Invalid library name referenced in dynamic 
linker map\n");
+                       return;
+               }
+
+               umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name));
+
+               if (lib_name[0] == '\0') {
+                       debug(2, "Library name is an empty string");
+                       continue;
+               }
+
+               if (callback) {
+                       debug(2, "Dispatching callback for: %s, Loaded at 
0x%x\n", lib_name, rlm.l_addr);
+                       data->addr = rlm.l_addr;
+                       data->lib_name = lib_name;
+                       callback(data);
+               }
+       }
+       return;
+}
+
+static struct r_debug *
+load_debug_struct(Process *proc) {
+       struct r_debug *rdbg = NULL;
+
+       debug(DEBUG_FUNCTION, "load_debug_struct");
+
+       rdbg = malloc(sizeof(*rdbg));
+       if (!rdbg) {
+               return NULL;
+       }
+
+       if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != 
sizeof(*rdbg)) {
+               debug(2, "This process does not have a debug structure!\n");
+               free(rdbg);
+               return NULL;
+       }
+
+       return rdbg;
+}
+
+static void
+linkmap_add_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) {
+       int i = 0;
+       struct cb_data *lm_add = data;
+       struct ltelf lte;
+       struct opt_x_t *xptr;
+
+       debug(DEBUG_FUNCTION, "linkmap_add_cb");
+
+       /*
+               XXX
+               iterate through library[i]'s to see if this lib is in the list.
+               if not, add it
+        */
+       for(;i < library_num;i++) {
+               if (strcmp(library[i], lm_add->lib_name) == 0) {
+                       /* found it, so its not new */
+                       return;
+               }
+       }
+
+       /* new library linked! */
+       debug(2, "New libdl loaded library found: %s\n", lm_add->lib_name);
+
+       if (library_num < MAX_LIBRARIES) {
+               library[library_num++] = strdup(lm_add->lib_name);
+               memset(&lte, 0, sizeof(struct ltelf));
+               lte.base_addr = lm_add->addr;
+               do_init_elf(&lte, library[library_num-1]);
+               /* add bps */
+               for (xptr = opt_x; xptr; xptr = xptr->next) {
+                       if (xptr->found)
+                               continue;
+
+                       GElf_Sym sym;
+                       GElf_Addr addr;
+
+                       if (in_load_libraries(xptr->name, &lte, 1, &sym)) {
+                               debug(2, "found symbol %s @ %lx, adding it.", 
xptr->name, sym.st_value);
+                               addr = sym.st_value;
+                               add_library_symbol(addr, xptr->name, 
&library_symbols, LS_TOPLT_NONE, 0);
+                               xptr->found = 1;
+                               insert_breakpoint(lm_add->proc, 
sym2addr(lm_add->proc, library_symbols), library_symbols);
+                       }
+               }
+               do_close_elf(&lte);
+       }
+}
+
+void
+arch_check_dbg(Process *proc) {
+       struct r_debug *dbg = NULL;
+       struct cb_data data;
+
+       debug(DEBUG_FUNCTION, "arch_check_dbg");
+
+       if (!(dbg = load_debug_struct(proc))) {
+               debug(2, "Unable to load debug structure!");
+               return;
+       }
+
+       if (dbg->r_state == RT_CONSISTENT) {
+               debug(2, "Linkmap is now consistent");
+               if (proc->debug_state == RT_ADD) {
+                       debug(2, "Adding DSO to linkmap");
+                       data.proc = proc;
+                       crawl_linkmap(proc, dbg, linkmap_add_cb, &data);
+               } else if (proc->debug_state == RT_DELETE) {
+                       debug(2, "Removing DSO from linkmap");
+               } else {
+                       debug(2, "Unexpected debug state!");
+               }
+       }
+
+       proc->debug_state = dbg->r_state;
+
+       return;
+}
+
+static void
+hook_libdl_cb(void *data) { //const char *lib_name, ElfW(Addr) addr) {
+       struct cb_data *hook_data = data;
+       const char *lib_name = NULL;
+       ElfW(Addr) addr;
+       struct ltelf *lte = NULL;
+
+       debug(DEBUG_FUNCTION, "add_library_cb");
+
+       if (!data) {
+               debug(2, "No callback data");
+               return;
+       }
+
+       lib_name = hook_data->lib_name;
+       addr = hook_data->addr;
+       lte = hook_data->lte;
+
+       if (library_num < MAX_LIBRARIES) {
+               library[library_num++] = strdup(lib_name);
+               lte[library_num].base_addr = addr;
+       }
+       else {
+               fprintf (stderr, "MAX LIBS REACHED\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+int
+linkmap_init(Process *proc, struct ltelf *lte) {
+       void *dbg_addr = NULL;
+       struct r_debug *rdbg = NULL;
+       struct cb_data data;
+
+       debug(DEBUG_FUNCTION, "linkmap_init()");
+
+       if (find_dynamic_entry_addr(proc, (void *)lte->dyn_addr, DT_DEBUG, 
&dbg_addr) == -1) {
+               debug(2, "Couldn't find debug structure!");
+               return -1;
+       }
+
+       proc->debug = dbg_addr;
+
+       if (!(rdbg = load_debug_struct(proc))) {
+               debug(2, "No debug structure or no memory to allocate one!");
+               return -1;
+       }
+
+       data.lte = lte;
+
+       add_library_symbol(rdbg->r_brk, "", &library_symbols, LS_TOPLT_NONE, 0);
+       insert_breakpoint(proc, sym2addr(proc, library_symbols), 
library_symbols);
+
+       crawl_linkmap(proc, rdbg, hook_libdl_cb, &data);
+
+       free(rdbg);
+       return 0;
+}
-- 
1.7.0.4


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

Reply via email to