breakpoints.c revision 0b55b5852b9fe2ed6cceada004db303fe6efe6ce
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 71/* On second thought, I don't think we need PROC. All the translation 72 * (arch_translate_address in particular) should be doable using 73 * static lookups of various sections in the ELF file. We shouldn't 74 * need process for anything. */ 75int 76breakpoint_init(struct breakpoint *bp, struct Process *proc, 77 target_address_t addr, struct library_symbol *libsym) 78{ 79 bp->cbs = NULL; 80 bp->proc = NULL; 81 bp->addr = addr; 82 memset(bp->orig_value, 0, sizeof(bp->orig_value)); 83 bp->enabled = 0; 84 bp->libsym = libsym; 85 return arch_breakpoint_init(proc, bp); 86} 87 88void 89breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs) 90{ 91 if (bp->cbs != NULL) 92 assert(bp->cbs == NULL); 93 bp->cbs = cbs; 94} 95 96void 97breakpoint_destroy(struct breakpoint *bp) 98{ 99 if (bp == NULL) 100 return; 101 102 /* XXX I'm not convinced that we need on_destroy. We already 103 * have arch_breakpoint_destroy, which is necessary as a 104 * counterpart of arch_breakpoint_init in any case. */ 105 if (bp->cbs != NULL && bp->cbs->on_destroy != NULL) 106 (bp->cbs->on_destroy) (bp); 107 108 arch_breakpoint_destroy(bp); 109} 110 111int 112breakpoint_turn_on(struct breakpoint *bp) 113{ 114 /* Make sure it was inserted. XXX In a clean world, we would 115 * have breakpoint_site representing a place and breakpoint 116 * representing inserted breakpoint. */ 117 assert(bp->proc != NULL); 118 bp->enabled++; 119 if (bp->enabled == 1) { 120 assert(bp->proc->pid != 0); 121 enable_breakpoint(bp->proc, bp); 122 } 123 return 0; 124} 125 126int 127breakpoint_turn_off(struct breakpoint *bp) 128{ 129 assert(bp->proc != NULL); 130 bp->enabled--; 131 if (bp->enabled == 0) 132 disable_breakpoint(bp->proc, bp); 133 assert(bp->enabled >= 0); 134 return 0; 135} 136 137struct breakpoint * 138insert_breakpoint(struct Process *proc, void *addr, 139 struct library_symbol *libsym) 140{ 141 Process *leader = proc->leader; 142 143 /* Only the group leader should be getting the breakpoints and 144 * thus have ->breakpoint initialized. */ 145 assert(leader != NULL); 146 assert(leader->breakpoints != NULL); 147 148 debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL"); 149 debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); 150 151 if (addr == 0) { 152 /* XXX we need a better way to deal with this. For 153 * now, just abuse errno to carry the error 154 * information. */ 155 errno = EINVAL; 156 return NULL; 157 } 158 159 /* XXX what we need to do instead is have a list of 160 * breakpoints that are enabled at this address. The 161 * following works if every breakpoint is the same and there's 162 * no extra data, but that doesn't hold anymore. For now it 163 * will suffice, about the only realistic case where we need 164 * to have more than one breakpoint per address is return from 165 * a recursive library call. */ 166 struct breakpoint *sbp = dict_find_entry(leader->breakpoints, addr); 167 if (sbp == NULL) { 168 sbp = malloc(sizeof(*sbp)); 169 if (sbp == NULL 170 || breakpoint_init(sbp, proc, addr, libsym) < 0) { 171 free(sbp); 172 return NULL; 173 } 174 if (proc_add_breakpoint(proc, sbp) < 0) { 175 fail: 176 breakpoint_destroy(sbp); 177 free(sbp); 178 return NULL; 179 } 180 } 181 182 if (breakpoint_turn_on(sbp) < 0) 183 goto fail; 184 185 return sbp; 186} 187 188void 189delete_breakpoint(Process *proc, void *addr) 190{ 191 struct breakpoint *sbp; 192 193 debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); 194 195 Process * leader = proc->leader; 196 assert(leader != NULL); 197 198 sbp = dict_find_entry(leader->breakpoints, addr); 199 assert(sbp); /* FIXME: remove after debugging has been done. */ 200 /* This should only happen on out-of-memory conditions. */ 201 if (sbp == NULL) 202 return; 203 204 if (breakpoint_turn_off(sbp) < 0) { 205 fprintf(stderr, "Couldn't turn off the breakpoint %s@%p\n", 206 breakpoint_name(sbp), sbp->addr); 207 return; 208 } 209} 210 211const char * 212breakpoint_name(const struct breakpoint *bp) 213{ 214 assert(bp != NULL); 215 return bp->libsym != NULL ? bp->libsym->name : NULL; 216} 217 218struct library * 219breakpoint_library(const struct breakpoint *bp) 220{ 221 assert(bp != NULL); 222 return bp->libsym != NULL ? bp->libsym->lib : NULL; 223} 224 225static void 226enable_bp_cb(void *addr, void *sbp, void *proc) 227{ 228 debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); 229 if (((struct breakpoint *)sbp)->enabled) 230 enable_breakpoint(proc, sbp); 231} 232 233void 234enable_all_breakpoints(Process *proc) 235{ 236 debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); 237 238 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 239 if (proc->breakpoints) { 240 dict_apply_to_all(proc->breakpoints, enable_bp_cb, 241 proc); 242 } 243#ifdef __mips__ 244 { 245 /* 246 * I'm sure there is a nicer way to do this. We need to 247 * insert breakpoints _after_ the child has been started. 248 */ 249 struct library_symbol *sym; 250 struct library_symbol *new_sym; 251 sym=proc->list_of_symbols; 252 while(sym){ 253 void *addr= sym2addr(proc,sym); 254 if(!addr){ 255 sym=sym->next; 256 continue; 257 } 258 if(dict_find_entry(proc->breakpoints,addr)){ 259 sym=sym->next; 260 continue; 261 } 262 debug(2,"inserting bp %p %s",addr,sym->name); 263 new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1); 264 memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1); 265 new_sym->next=proc->list_of_symbols; 266 proc->list_of_symbols=new_sym; 267 insert_breakpoint(proc, addr, new_sym); 268 sym=sym->next; 269 } 270 } 271#endif 272} 273 274static void 275disable_bp_cb(void *addr, void *sbp, void *proc) 276{ 277 debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); 278 if (((struct breakpoint *)sbp)->enabled) 279 disable_breakpoint(proc, sbp); 280} 281 282void 283disable_all_breakpoints(Process *proc) { 284 debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); 285 assert(proc->leader == proc); 286 dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); 287} 288 289struct entry_breakpoint { 290 struct breakpoint super; 291 target_address_t dyn_addr; 292}; 293 294static void 295entry_breakpoint_on_hit(struct breakpoint *a, struct Process *proc) 296{ 297 struct entry_breakpoint *bp = (void *)a; 298 fprintf(stderr, "entry_callback_hit\n"); 299 if (proc == NULL || proc->leader == NULL) 300 return; 301 delete_breakpoint(proc, bp->super.addr); // xxx 302 //enable_all_breakpoints(proc); 303 304 linkmap_init(proc, bp->dyn_addr); 305} 306 307static void 308entry_breakpoint_on_destroy(struct breakpoint *a) 309{ 310} 311 312int 313entry_breakpoint_init(struct Process *proc, 314 struct entry_breakpoint *bp, target_address_t addr, 315 struct library *lib) 316{ 317 int err; 318 if ((err = breakpoint_init(&bp->super, proc, addr, NULL)) < 0) 319 return err; 320 321 static struct bp_callbacks entry_callbacks = { 322 .on_hit = entry_breakpoint_on_hit, 323 .on_destroy = entry_breakpoint_on_destroy, 324 }; 325 bp->super.cbs = &entry_callbacks; 326 bp->dyn_addr = lib->dyn_addr; 327 return 0; 328} 329 330int 331breakpoints_init(Process *proc, int enable) 332{ 333 fprintf(stderr, "breakpoints_init %d enable=%d\n", proc->pid, enable); 334 debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); 335 336 /* XXX breakpoint dictionary should be initialized 337 * outside. Here we just put in breakpoints. */ 338 assert(proc->breakpoints != NULL); 339 340 /* Only the thread group leader should hold the breakpoints. */ 341 assert(proc->leader == proc); 342 343 if (options.libcalls && proc->filename) { 344 struct library *lib = ltelf_read_main_binary(proc, 345 proc->filename); 346 struct entry_breakpoint *entry_bp = NULL; 347 int bp_state = 0; 348 int result = -1; 349 switch (lib != NULL) { 350 fail: 351 proc_remove_library(proc, lib); 352 library_destroy(lib); 353 switch (bp_state) { 354 case 2: 355 proc_remove_breakpoint(proc, &entry_bp->super); 356 case 1: 357 breakpoint_destroy(&entry_bp->super); 358 } 359 free(entry_bp); 360 case 0: 361 return result; 362 } 363 364 proc_add_library(proc, lib); 365 366 entry_bp = malloc(sizeof(*entry_bp)); 367 if (entry_bp == NULL 368 || (result = entry_breakpoint_init(proc, entry_bp, 369 lib->entry, lib)) < 0) 370 goto fail; 371 372 ++bp_state; 373 if ((result = proc_add_breakpoint(proc, &entry_bp->super)) < 0) 374 goto fail; 375 376 ++bp_state; 377 if ((result = breakpoint_turn_on(&entry_bp->super)) < 0) 378 goto fail; 379 } 380 381 proc->callstack_depth = 0; 382 return 0; 383} 384