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