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