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