breakpoints.c revision 3d7e4b8d6119c1cda159e2665b40b6dcd4052e85
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#ifdef __arm__ 27 int thumb_mode = (int)addr & 1; 28 if (thumb_mode) 29 addr = (void *)((int)addr & ~1); 30#endif 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 = 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) + strlen(sym->name) + 1); 133 memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1); 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 (proc->list_of_symbols != NULL) { 183 struct library_symbol * sym = proc->list_of_symbols; 184 while (sym != NULL) { 185 struct library_symbol * next = sym->next; 186 free(sym); 187 sym = next; 188 } 189 } 190 proc->list_of_symbols = NULL; 191 192 if (options.libcalls && proc->filename) { 193 proc->list_of_symbols = read_elf(proc); 194 if (opt_e) { 195 struct library_symbol **tmp1 = &(proc->list_of_symbols); 196 while (*tmp1) { 197 struct opt_e_t *tmp2 = opt_e; 198 int keep = !opt_e_enable; 199 200 while (tmp2) { 201 if (!strcmp((*tmp1)->name, tmp2->name)) { 202 keep = opt_e_enable; 203 } 204 tmp2 = tmp2->next; 205 } 206 if (!keep) { 207 *tmp1 = (*tmp1)->next; 208 } else { 209 tmp1 = &((*tmp1)->next); 210 } 211 } 212 } 213 } 214 for (sym = proc->list_of_symbols; sym; sym = sym->next) { 215 /* proc->pid==0 delays enabling. */ 216 insert_breakpoint(proc, sym2addr(proc, sym), sym); 217 } 218 proc->callstack_depth = 0; 219 proc->breakpoints_enabled = -1; 220} 221 222void 223reinitialize_breakpoints(Process *proc) { 224 struct library_symbol *sym; 225 226 debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid); 227 228 sym = proc->list_of_symbols; 229 230 while (sym) { 231 if (sym->needs_init) { 232 insert_breakpoint(proc, sym2addr(proc, sym), 233 sym); 234 if (sym->needs_init && !sym->is_weak) { 235 fprintf(stderr, 236 "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", 237 sym->name, proc->filename); 238 exit(1); 239 } 240 } 241 sym = sym->next; 242 } 243} 244