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