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