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