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