breakpoints.c revision e9aebd6cfb4710f96b27b5d268208ddd7f0d9eac
1#include "config.h" 2 3#include <stdlib.h> 4#include <string.h> 5#include <assert.h> 6#include <error.h> 7#include <errno.h> 8 9#ifdef __powerpc__ 10#include <sys/ptrace.h> 11#endif 12 13#include "breakpoint.h" 14#include "common.h" 15#include "proc.h" 16#include "library.h" 17 18void 19breakpoint_on_hit(struct breakpoint *bp, struct Process *proc) 20{ 21 assert(bp != NULL); 22 if (bp->cbs != NULL && bp->cbs->on_hit != NULL) 23 (bp->cbs->on_hit) (bp, proc); 24} 25 26/*****************************************************************************/ 27 28struct breakpoint * 29address2bpstruct(Process *proc, void *addr) 30{ 31 assert(proc != NULL); 32 assert(proc->breakpoints != NULL); 33 assert(proc->leader == proc); 34 debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); 35 return dict_find_entry(proc->breakpoints, addr); 36} 37 38#ifndef ARCH_HAVE_BREAKPOINT_DATA 39int 40arch_breakpoint_init(struct Process *proc, struct breakpoint *sbp) 41{ 42 return 0; 43} 44 45void 46arch_breakpoint_destroy(struct breakpoint *sbp) 47{ 48} 49#endif 50 51int 52breakpoint_init(struct breakpoint *bp, struct Process *proc, 53 target_address_t addr, struct library_symbol *libsym, 54 struct bp_callbacks *cbs) 55{ 56 bp->cbs = cbs; 57 bp->addr = addr; 58 memset(bp->orig_value, 0, sizeof(bp->orig_value)); 59 bp->enabled = 0; 60 bp->libsym = libsym; 61 return arch_breakpoint_init(proc, bp); 62} 63 64void 65breakpoint_destroy(struct breakpoint *bp) 66{ 67 if (bp == NULL) 68 return; 69 70 /* XXX I'm not convinced that we need on_destroy. We already 71 * have arch_breakpoint_destroy, which is necessary as a 72 * counterpart of arch_breakpoint_init in any case. */ 73 if (bp->cbs != NULL && bp->cbs->on_destroy != NULL) 74 (bp->cbs->on_destroy) (bp); 75 76 arch_breakpoint_destroy(bp); 77} 78 79struct breakpoint * 80insert_breakpoint(Process *proc, void *addr, 81 struct library_symbol *libsym, int enable) 82{ 83 Process * leader = proc->leader; 84 85 /* Only the group leader should be getting the breakpoints and 86 * thus have ->breakpoint initialized. */ 87 assert(leader != NULL); 88 assert(leader->breakpoints != NULL); 89 90 debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL"); 91 debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); 92 93 if (addr == 0) { 94 /* XXX we need a better way to deal with this. For 95 * now, just abuse errno to carry the error 96 * information. */ 97 errno = EINVAL; 98 return NULL; 99 } 100 101 struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr); 102 if (sbp == NULL) { 103 sbp = malloc(sizeof(*sbp)); 104 if (sbp == NULL 105 || breakpoint_init(sbp, proc, addr, libsym, NULL) < 0 106 || dict_enter(leader->breakpoints, addr, sbp) < 0) { 107 free(sbp); 108 return NULL; 109 } 110 } 111 112 sbp->enabled++; 113 if (sbp->enabled == 1 && enable) { 114 assert(proc->pid != 0); 115 enable_breakpoint(proc, sbp); 116 } 117 118 return sbp; 119} 120 121void 122delete_breakpoint(Process *proc, void *addr) 123{ 124 struct breakpoint *sbp; 125 126 debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); 127 128 Process * leader = proc->leader; 129 assert(leader != NULL); 130 131 sbp = dict_find_entry(leader->breakpoints, addr); 132 assert(sbp); /* FIXME: remove after debugging has been done. */ 133 /* This should only happen on out-of-memory conditions. */ 134 if (sbp == NULL) 135 return; 136 137 sbp->enabled--; 138 if (sbp->enabled == 0) 139 disable_breakpoint(proc, sbp); 140 assert(sbp->enabled >= 0); 141} 142 143const char * 144breakpoint_name(const struct breakpoint *bp) 145{ 146 assert(bp != NULL); 147 return bp->libsym != NULL ? bp->libsym->name : NULL; 148} 149 150static void 151enable_bp_cb(void *addr, void *sbp, void *proc) 152{ 153 debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); 154 if (((struct breakpoint *)sbp)->enabled) 155 enable_breakpoint(proc, sbp); 156} 157 158void 159enable_all_breakpoints(Process *proc) 160{ 161 debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); 162 163 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 164 if (proc->breakpoints) { 165 dict_apply_to_all(proc->breakpoints, enable_bp_cb, 166 proc); 167 } 168#ifdef __mips__ 169 { 170 /* 171 * I'm sure there is a nicer way to do this. We need to 172 * insert breakpoints _after_ the child has been started. 173 */ 174 struct library_symbol *sym; 175 struct library_symbol *new_sym; 176 sym=proc->list_of_symbols; 177 while(sym){ 178 void *addr= sym2addr(proc,sym); 179 if(!addr){ 180 sym=sym->next; 181 continue; 182 } 183 if(dict_find_entry(proc->breakpoints,addr)){ 184 sym=sym->next; 185 continue; 186 } 187 debug(2,"inserting bp %p %s",addr,sym->name); 188 new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1); 189 memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1); 190 new_sym->next=proc->list_of_symbols; 191 proc->list_of_symbols=new_sym; 192 insert_breakpoint(proc, addr, new_sym); 193 sym=sym->next; 194 } 195 } 196#endif 197} 198 199static void 200disable_bp_cb(void *addr, void *sbp, void *proc) 201{ 202 debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); 203 if (((struct breakpoint *)sbp)->enabled) 204 disable_breakpoint(proc, sbp); 205} 206 207void 208disable_all_breakpoints(Process *proc) { 209 debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); 210 assert(proc->leader == proc); 211 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); 212} 213 214static void 215entry_callback_hit(struct breakpoint *bp, struct Process *proc) 216{ 217 fprintf(stderr, "entry_callback_hit\n"); 218 if (proc == NULL || proc->leader == NULL) 219 return; 220 delete_breakpoint(proc, bp->addr); // xxx 221 enable_all_breakpoints(proc); 222 223 linkmap_init(proc); 224} 225 226int 227breakpoints_init(Process *proc, int enable) 228{ 229 fprintf(stderr, "breakpoints_init %d enable=%d\n", proc->pid, enable); 230 debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); 231 232 /* XXX breakpoint dictionary should be initialized 233 * outside. Here we just put in breakpoints. */ 234 assert(proc->breakpoints != NULL); 235 236 /* Only the thread group leader should hold the breakpoints. */ 237 assert(proc->leader == proc); 238 239 if (options.libcalls && proc->filename) { 240 struct library *lib = ltelf_read_main_binary(proc, proc->filename); 241 switch (lib != NULL) { 242 fail: 243 proc_remove_library(proc, lib); 244 library_destroy(lib); 245 case 0: 246 return -1; 247 } 248 proc_add_library(proc, lib); 249 fprintf(stderr, "note: symbols in %s were not filtered.\n", 250 lib->name); 251 252 struct breakpoint *entry_bp 253 = insert_breakpoint(proc, lib->entry, NULL, 1); 254 if (entry_bp == NULL) { 255 error(0, errno, "couldn't insert entry breakpoint"); 256 goto fail; 257 } 258 259 fprintf(stderr, "setting entry_callbacks by hand, fix it\n"); 260 static struct bp_callbacks entry_callbacks = { 261 .on_hit = entry_callback_hit, 262 }; 263 entry_bp->cbs = &entry_callbacks; 264 } 265 266 proc->callstack_depth = 0; 267 return 0; 268} 269