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