diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-11-13 07:28:12 -0800 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-11-13 07:28:12 -0800 |
commit | 59749d048d9e452f049f9151735b5256756919c3 (patch) | |
tree | 9b0935c93a3b028fd1dd35a2c632510743e7826f /breakpoints.c | |
download | ltrace-59749d048d9e452f049f9151735b5256756919c3.tar.gz ltrace-59749d048d9e452f049f9151735b5256756919c3.tar.bz2 ltrace-59749d048d9e452f049f9151735b5256756919c3.zip |
Imported Upstream version 0.5.3upstream/0.5.3
Diffstat (limited to 'breakpoints.c')
-rw-r--r-- | breakpoints.c | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/breakpoints.c b/breakpoints.c new file mode 100644 index 0000000..ba3b060 --- /dev/null +++ b/breakpoints.c @@ -0,0 +1,230 @@ +#include "config.h" + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#ifdef __powerpc__ +#include <sys/ptrace.h> +#endif + +#include "common.h" + +/*****************************************************************************/ + +Breakpoint * +address2bpstruct(Process *proc, void *addr) { + debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); + return dict_find_entry(proc->breakpoints, addr); +} + +void +insert_breakpoint(Process *proc, void *addr, + struct library_symbol *libsym) { + Breakpoint *sbp; + + debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL"); + debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); + + if (!addr) + return; + + if (libsym) + libsym->needs_init = 0; + + sbp = dict_find_entry(proc->breakpoints, addr); + if (!sbp) { + sbp = calloc(1, sizeof(Breakpoint)); + if (!sbp) { + return; /* TODO FIXME XXX: error_mem */ + } + dict_enter(proc->breakpoints, addr, sbp); + sbp->addr = addr; + sbp->libsym = libsym; + } +#ifdef __arm__ + sbp->thumb_mode = proc->thumb_mode; + proc->thumb_mode = 0; +#endif + sbp->enabled++; + if (sbp->enabled == 1 && proc->pid) + enable_breakpoint(proc->pid, sbp); +} + +void +delete_breakpoint(Process *proc, void *addr) { + Breakpoint *sbp; + + debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); + + sbp = dict_find_entry(proc->breakpoints, addr); + assert(sbp); /* FIXME: remove after debugging has been done. */ + /* This should only happen on out-of-memory conditions. */ + if (sbp == NULL) + return; + + sbp->enabled--; + if (sbp->enabled == 0) + disable_breakpoint(proc->pid, sbp); + assert(sbp->enabled >= 0); +} + +static void +enable_bp_cb(void *addr, void *sbp, void *proc) { + debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); + if (((Breakpoint *)sbp)->enabled) { + enable_breakpoint(((Process *)proc)->pid, sbp); + } +} + +void +enable_all_breakpoints(Process *proc) { + debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); + if (proc->breakpoints_enabled <= 0) { +#ifdef __powerpc__ + unsigned long a; + + /* + * PPC HACK! (XXX FIXME TODO) + * If the dynamic linker hasn't populated the PLT then + * dont enable the breakpoints + */ + if (options.libcalls) { + a = ptrace(PTRACE_PEEKTEXT, proc->pid, + sym2addr(proc, proc->list_of_symbols), + 0); + if (a == 0x0) + return; + } +#endif + + debug(1, "Enabling breakpoints for pid %u...", proc->pid); + if (proc->breakpoints) { + dict_apply_to_all(proc->breakpoints, enable_bp_cb, + proc); + } +#ifdef __mips__ + { + /* + * I'm sure there is a nicer way to do this. We need to + * insert breakpoints _after_ the child has been started. + */ + struct library_symbol *sym; + struct library_symbol *new_sym; + sym=proc->list_of_symbols; + while(sym){ + void *addr= sym2addr(proc,sym); + if(!addr){ + sym=sym->next; + continue; + } + if(dict_find_entry(proc->breakpoints,addr)){ + sym=sym->next; + continue; + } + debug(2,"inserting bp %p %s",addr,sym->name); + new_sym=malloc(sizeof(*new_sym)); + memcpy(new_sym,sym,sizeof(*new_sym)); + new_sym->next=proc->list_of_symbols; + proc->list_of_symbols=new_sym; + insert_breakpoint(proc, addr, new_sym); + sym=sym->next; + } + } +#endif + } + proc->breakpoints_enabled = 1; +} + +static void +disable_bp_cb(void *addr, void *sbp, void *proc) { + debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); + if (((Breakpoint *)sbp)->enabled) { + disable_breakpoint(((Process *)proc)->pid, sbp); + } +} + +void +disable_all_breakpoints(Process *proc) { + debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); + if (proc->breakpoints_enabled) { + debug(1, "Disabling breakpoints for pid %u...", proc->pid); + dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); + } + proc->breakpoints_enabled = 0; +} + +static void +free_bp_cb(void *addr, void *sbp, void *data) { + debug(DEBUG_FUNCTION, "free_bp_cb(sbp=%p)", sbp); + assert(sbp); + free(sbp); +} + +void +breakpoints_init(Process *proc) { + struct library_symbol *sym; + + debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); + if (proc->breakpoints) { /* let's remove that struct */ + dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL); + dict_clear(proc->breakpoints); + proc->breakpoints = NULL; + } + proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int); + + if (options.libcalls && proc->filename) { + /* FIXME: memory leak when called by exec(): */ + proc->list_of_symbols = read_elf(proc); + if (opt_e) { + struct library_symbol **tmp1 = &(proc->list_of_symbols); + while (*tmp1) { + struct opt_e_t *tmp2 = opt_e; + int keep = !opt_e_enable; + + while (tmp2) { + if (!strcmp((*tmp1)->name, tmp2->name)) { + keep = opt_e_enable; + } + tmp2 = tmp2->next; + } + if (!keep) { + *tmp1 = (*tmp1)->next; + } else { + tmp1 = &((*tmp1)->next); + } + } + } + } else { + proc->list_of_symbols = NULL; + } + for (sym = proc->list_of_symbols; sym; sym = sym->next) { + /* proc->pid==0 delays enabling. */ + insert_breakpoint(proc, sym2addr(proc, sym), sym); + } + proc->callstack_depth = 0; + proc->breakpoints_enabled = -1; +} + +void +reinitialize_breakpoints(Process *proc) { + struct library_symbol *sym; + + debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid); + + sym = proc->list_of_symbols; + + while (sym) { + if (sym->needs_init) { + insert_breakpoint(proc, sym2addr(proc, sym), + sym); + if (sym->needs_init && !sym->is_weak) { + fprintf(stderr, + "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", + sym->name, proc->filename); + exit(1); + } + } + sym = sym->next; + } +} |