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