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