breakpoints.c revision 1228a91e6560c5e5ac4fdd051adc9b34bf9fc047
1#if HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#include <stdlib.h> 6#include <string.h> 7#include <assert.h> 8 9#ifdef __powerpc__ 10#include <sys/ptrace.h> 11#endif 12 13#include "ltrace.h" 14#include "options.h" 15#include "debug.h" 16#include "dict.h" 17#include "elf.h" 18 19/*****************************************************************************/ 20 21struct breakpoint *address2bpstruct(struct process *proc, void *addr) 22{ 23 return dict_find_entry(proc->breakpoints, addr); 24} 25 26void 27insert_breakpoint(struct process *proc, void *addr, 28 struct library_symbol *libsym) 29{ 30 struct breakpoint *sbp; 31 debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); 32 33 if (!proc->breakpoints) { 34 proc->breakpoints = 35 dict_init(dict_key2hash_int, dict_key_cmp_int); 36 /* atexit(brk_dict_clear); *//* why bother to do this on exit? */ 37 } 38 39 if (!addr) 40 return; 41 42 if (libsym) 43 libsym->needs_init = 0; 44 45 sbp = dict_find_entry(proc->breakpoints, addr); 46 if (!sbp) { 47 sbp = calloc(1, sizeof(struct breakpoint)); 48 if (!sbp) { 49 return; /* TODO FIXME XXX: error_mem */ 50 } 51 dict_enter(proc->breakpoints, addr, sbp); 52 sbp->addr = addr; 53 sbp->libsym = libsym; 54 if (libsym) 55 libsym->brkpnt = sbp; 56 } 57 sbp->enabled++; 58 if (sbp->enabled == 1 && proc->pid) 59 enable_breakpoint(proc->pid, sbp); 60} 61 62void delete_breakpoint(struct process *proc, void *addr) 63{ 64 struct breakpoint *sbp = dict_find_entry(proc->breakpoints, addr); 65 assert(sbp); /* FIXME: remove after debugging has been done. */ 66 /* This should only happen on out-of-memory conditions. */ 67 if (sbp == NULL) 68 return; 69 70 sbp->enabled--; 71 if (sbp->enabled == 0) 72 disable_breakpoint(proc->pid, sbp); 73 assert(sbp->enabled >= 0); 74} 75 76static void enable_bp_cb(void *addr, void *sbp, void *proc) 77{ 78 if (((struct breakpoint *)sbp)->enabled) { 79 enable_breakpoint(((struct process *)proc)->pid, sbp); 80 } 81} 82 83void enable_all_breakpoints(struct process *proc) 84{ 85 if (proc->breakpoints_enabled <= 0) { 86#ifdef __powerpc__ 87 unsigned long a; 88 89 /* 90 * PPC HACK! (XXX FIXME TODO) 91 * If the dynamic linker hasn't populated the PLT then 92 * dont enable the breakpoints 93 */ 94 if (opt_L) { 95 a = ptrace(PTRACE_PEEKTEXT, proc->pid, 96 sym2addr(proc, proc->list_of_symbols), 97 0); 98 if (a == 0x0) 99 return; 100 } 101#endif 102 103 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 104 if (proc->breakpoints) { 105 dict_apply_to_all(proc->breakpoints, enable_bp_cb, 106 proc); 107 } 108#ifdef __mips__ 109 { 110 // I'm sure there is a nicer way to do this. We need to 111 // insert breakpoints _after_ the child has been started. 112 struct library_symbol *sym; 113 struct library_symbol *new_sym; 114 sym=proc->list_of_symbols; 115 while(sym){ 116 void *addr= sym2addr(proc,sym); 117 if(!addr){ 118 sym=sym->next; 119 continue; 120 } 121 if(dict_find_entry(proc->breakpoints,addr)){ 122 sym=sym->next; 123 continue; 124 } 125 debug(2,"inserting bp %p %s",addr,sym->name); 126 new_sym=malloc(sizeof(*new_sym)); 127 memcpy(new_sym,sym,sizeof(*new_sym)); 128 new_sym->next=proc->list_of_symbols; 129 proc->list_of_symbols=new_sym; 130 new_sym->brkpnt=0; 131 insert_breakpoint(proc, addr, new_sym); 132 sym=sym->next; 133 } 134 } 135#endif 136 } 137 proc->breakpoints_enabled = 1; 138} 139 140static void disable_bp_cb(void *addr, void *sbp, void *proc) 141{ 142 if (((struct breakpoint *)sbp)->enabled) { 143 disable_breakpoint(((struct process *)proc)->pid, sbp); 144 } 145} 146 147void disable_all_breakpoints(struct process *proc) 148{ 149 if (proc->breakpoints_enabled) { 150 debug(1, "Disabling breakpoints for pid %u...", proc->pid); 151 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); 152 } 153 proc->breakpoints_enabled = 0; 154} 155 156static void free_bp_cb(void *addr, void *sbp, void *data) 157{ 158 assert(sbp); 159 free(sbp); 160} 161 162void breakpoints_init(struct process *proc) 163{ 164 struct library_symbol *sym; 165 166 if (proc->breakpoints) { /* let's remove that struct */ 167 /* TODO FIXME XXX: free() all "struct breakpoint"s */ 168 dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL); 169 dict_clear(proc->breakpoints); 170 proc->breakpoints = NULL; 171 } 172 173 if (opt_L && proc->filename) { 174 proc->list_of_symbols = read_elf(proc); 175 if (opt_e) { 176 struct library_symbol **tmp1 = &(proc->list_of_symbols); 177 while (*tmp1) { 178 struct opt_e_t *tmp2 = opt_e; 179 int keep = !opt_e_enable; 180 181 while (tmp2) { 182 if (!strcmp((*tmp1)->name, tmp2->name)) { 183 keep = opt_e_enable; 184 } 185 tmp2 = tmp2->next; 186 } 187 if (!keep) { 188 *tmp1 = (*tmp1)->next; 189 } else { 190 tmp1 = &((*tmp1)->next); 191 } 192 } 193 } 194 } else { 195 proc->list_of_symbols = NULL; 196 } 197 for (sym = proc->list_of_symbols; sym; sym = sym->next) { 198 /* proc->pid==0 delays enabling. */ 199 insert_breakpoint(proc, sym2addr(proc, sym), sym); 200 } 201 proc->callstack_depth = 0; 202 proc->breakpoints_enabled = -1; 203} 204 205void reinitialize_breakpoints(struct process *proc) 206{ 207 struct library_symbol *sym = proc->list_of_symbols; 208 209 while (sym) { 210 if (sym->needs_init) { 211 insert_breakpoint(proc, sym2addr(proc, sym), 212 sym); 213 if (sym->needs_init && !sym->is_weak) { 214 fprintf(stderr, 215 "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", 216 sym->name, proc->filename); 217 exit(1); 218 } 219 } 220 sym = sym->next; 221 } 222} 223