breakpoints.c revision 9f819d5747dc2b8e0f7ac54b38dc321115de6dda
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2006,2007,2011,2012,2013 Petr Machata, Red Hat Inc. 4 * Copyright (C) 2009 Juan Cespedes 5 * Copyright (C) 1998,2001,2002,2003,2007,2008,2009 Juan Cespedes 6 * Copyright (C) 2006 Ian Wienand 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License as 10 * published by the Free Software Foundation; either version 2 of the 11 * License, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 21 * 02110-1301 USA 22 */ 23 24#include "config.h" 25 26#include <assert.h> 27#include <errno.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31 32#ifdef __powerpc__ 33#include <sys/ptrace.h> 34#endif 35 36#include "backend.h" 37#include "breakpoint.h" 38#include "debug.h" 39#include "library.h" 40#include "ltrace-elf.h" 41#include "proc.h" 42 43#ifndef ARCH_HAVE_TRANSLATE_ADDRESS 44int 45arch_translate_address_dyn(struct process *proc, 46 arch_addr_t addr, arch_addr_t *ret) 47{ 48 *ret = addr; 49 return 0; 50} 51 52struct ltelf; 53int 54arch_translate_address(struct ltelf *lte, 55 arch_addr_t addr, arch_addr_t *ret) 56{ 57 *ret = addr; 58 return 0; 59} 60#endif 61 62void 63breakpoint_on_hit(struct breakpoint *bp, struct process *proc) 64{ 65 assert(bp != NULL); 66 if (bp->cbs != NULL && bp->cbs->on_hit != NULL) 67 (bp->cbs->on_hit)(bp, proc); 68} 69 70void 71breakpoint_on_continue(struct breakpoint *bp, struct process *proc) 72{ 73 assert(bp != NULL); 74 if (bp->cbs != NULL && bp->cbs->on_continue != NULL) 75 (bp->cbs->on_continue)(bp, proc); 76 else 77 continue_after_breakpoint(proc, bp); 78} 79 80void 81breakpoint_on_retract(struct breakpoint *bp, struct process *proc) 82{ 83 assert(bp != NULL); 84 if (bp->cbs != NULL && bp->cbs->on_retract != NULL) 85 (bp->cbs->on_retract)(bp, proc); 86} 87 88/*****************************************************************************/ 89 90struct breakpoint * 91address2bpstruct(struct process *proc, arch_addr_t addr) 92{ 93 assert(proc != NULL); 94 assert(proc->breakpoints != NULL); 95 assert(proc->leader == proc); 96 debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); 97 98 struct breakpoint *found; 99 if (DICT_FIND_VAL(proc->breakpoints, &addr, &found) < 0) 100 return NULL; 101 return found; 102} 103 104#ifndef OS_HAVE_BREAKPOINT_DATA 105int 106os_breakpoint_init(struct process *proc, struct breakpoint *sbp) 107{ 108 return 0; 109} 110 111void 112os_breakpoint_destroy(struct breakpoint *sbp) 113{ 114} 115 116int 117os_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) 118{ 119 return 0; 120} 121#endif 122 123#ifndef ARCH_HAVE_BREAKPOINT_DATA 124int 125arch_breakpoint_init(struct process *proc, struct breakpoint *sbp) 126{ 127 return 0; 128} 129 130void 131arch_breakpoint_destroy(struct breakpoint *sbp) 132{ 133} 134 135int 136arch_breakpoint_clone(struct breakpoint *retp, struct breakpoint *sbp) 137{ 138 return 0; 139} 140#endif 141 142static void 143breakpoint_init_base(struct breakpoint *bp, 144 arch_addr_t addr, struct library_symbol *libsym) 145{ 146 bp->cbs = NULL; 147 bp->addr = addr; 148 memset(bp->orig_value, 0, sizeof(bp->orig_value)); 149 bp->enabled = 0; 150 bp->libsym = libsym; 151} 152 153/* On second thought, I don't think we need PROC. All the translation 154 * (arch_translate_address in particular) should be doable using 155 * static lookups of various sections in the ELF file. We shouldn't 156 * need process for anything. */ 157int 158breakpoint_init(struct breakpoint *bp, struct process *proc, 159 arch_addr_t addr, struct library_symbol *libsym) 160{ 161 breakpoint_init_base(bp, addr, libsym); 162 if (os_breakpoint_init(proc, bp) < 0) 163 return -1; 164 if (arch_breakpoint_init(proc, bp) < 0) { 165 os_breakpoint_destroy(bp); 166 return -1; 167 } 168 return 0; 169} 170 171void 172breakpoint_set_callbacks(struct breakpoint *bp, struct bp_callbacks *cbs) 173{ 174 if (bp->cbs != NULL) 175 assert(bp->cbs == NULL); 176 bp->cbs = cbs; 177} 178 179void 180breakpoint_destroy(struct breakpoint *bp) 181{ 182 if (bp == NULL) 183 return; 184 arch_breakpoint_destroy(bp); 185 os_breakpoint_destroy(bp); 186} 187 188int 189breakpoint_clone(struct breakpoint *retp, struct process *new_proc, 190 struct breakpoint *bp) 191{ 192 struct library_symbol *libsym = NULL; 193 if (bp->libsym != NULL) { 194 int rc = proc_find_symbol(new_proc, bp->libsym, NULL, &libsym); 195 assert(rc == 0); 196 } 197 198 breakpoint_init_base(retp, bp->addr, libsym); 199 memcpy(retp->orig_value, bp->orig_value, sizeof(bp->orig_value)); 200 retp->enabled = bp->enabled; 201 if (os_breakpoint_clone(retp, bp) < 0) 202 return -1; 203 if (arch_breakpoint_clone(retp, bp) < 0) { 204 os_breakpoint_destroy(retp); 205 return -1; 206 } 207 breakpoint_set_callbacks(retp, bp->cbs); 208 return 0; 209} 210 211int 212breakpoint_turn_on(struct breakpoint *bp, struct process *proc) 213{ 214 bp->enabled++; 215 if (bp->enabled == 1) { 216 assert(proc->pid != 0); 217 enable_breakpoint(proc, bp); 218 } 219 return 0; 220} 221 222int 223breakpoint_turn_off(struct breakpoint *bp, struct process *proc) 224{ 225 bp->enabled--; 226 if (bp->enabled == 0) 227 disable_breakpoint(proc, bp); 228 assert(bp->enabled >= 0); 229 return 0; 230} 231 232struct breakpoint * 233insert_breakpoint_at(struct process *proc, arch_addr_t addr, 234 struct library_symbol *libsym) 235{ 236 debug(DEBUG_FUNCTION, 237 "insert_breakpoint_at(pid=%d, addr=%p, symbol=%s)", 238 proc->pid, addr, libsym ? libsym->name : "NULL"); 239 240 assert(addr != 0); 241 242 struct breakpoint *bp = malloc(sizeof *bp); 243 if (bp == NULL || breakpoint_init(bp, proc, addr, libsym) < 0) { 244 free(bp); 245 return NULL; 246 } 247 248 /* N.B. (and XXX): BP->addr might differ from ADDR. On ARM 249 * this is a real possibility. The problem here is that to 250 * create a return breakpoint ltrace calls get_return_addr and 251 * then insert_breakpoint_at. So get_return_addr needs to 252 * encode all the information necessary for breakpoint_init 253 * into the address itself, so ADDR is potentially 254 * mangled. */ 255 256 struct breakpoint *tmp = insert_breakpoint(proc, bp); 257 if (tmp != bp) { 258 breakpoint_destroy(bp); 259 free(bp); 260 } 261 return tmp; 262} 263 264struct breakpoint * 265insert_breakpoint(struct process *proc, struct breakpoint *bp) 266{ 267 /* Only the group leader should be getting the breakpoints and 268 * thus have ->breakpoint initialized. */ 269 struct process *leader = proc->leader; 270 assert(leader != NULL); 271 assert(leader->breakpoints != NULL); 272 273 /* XXX what we need to do instead is have a list of 274 * breakpoints that are enabled at this address. The 275 * following works if every breakpoint is the same and there's 276 * no extra data, but that doesn't hold anymore. For now it 277 * will suffice, about the only realistic case where we need 278 * to have more than one breakpoint per address is return from 279 * a recursive library call. */ 280 struct breakpoint *ext_bp = bp; 281 if (DICT_FIND_VAL(leader->breakpoints, &bp->addr, &ext_bp) != 0) { 282 if (proc_add_breakpoint(leader, bp) < 0) 283 return NULL; 284 ext_bp = bp; 285 } 286 287 if (breakpoint_turn_on(ext_bp, proc) < 0) { 288 if (ext_bp != bp) 289 proc_remove_breakpoint(leader, bp); 290 return NULL; 291 } 292 293 return ext_bp; 294} 295 296void 297delete_breakpoint(struct process *proc, arch_addr_t addr) 298{ 299 debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); 300 301 struct process *leader = proc->leader; 302 assert(leader != NULL); 303 304 struct breakpoint *sbp = NULL; 305 DICT_FIND_VAL(leader->breakpoints, &addr, &sbp); 306 assert(sbp != NULL); 307 308 if (breakpoint_turn_off(sbp, proc) < 0) { 309 fprintf(stderr, "Couldn't turn off the breakpoint %s@%p\n", 310 breakpoint_name(sbp), sbp->addr); 311 return; 312 } 313 if (sbp->enabled == 0) { 314 proc_remove_breakpoint(leader, sbp); 315 breakpoint_destroy(sbp); 316 free(sbp); 317 } 318} 319 320const char * 321breakpoint_name(const struct breakpoint *bp) 322{ 323 assert(bp != NULL); 324 return bp->libsym != NULL ? bp->libsym->name : NULL; 325} 326 327struct library * 328breakpoint_library(const struct breakpoint *bp) 329{ 330 assert(bp != NULL); 331 return bp->libsym != NULL ? bp->libsym->lib : NULL; 332} 333 334static enum callback_status 335enable_bp_cb(arch_addr_t *addr, struct breakpoint **bpp, void *data) 336{ 337 struct process *proc = data; 338 debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", proc->pid); 339 if ((*bpp)->enabled) 340 enable_breakpoint(proc, *bpp); 341 return CBS_CONT; 342} 343 344void 345enable_all_breakpoints(struct process *proc) 346{ 347 debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); 348 349 debug(1, "Enabling breakpoints for pid %u...", proc->pid); 350 if (proc->breakpoints != NULL) 351 DICT_EACH(proc->breakpoints, arch_addr_t, struct breakpoint *, 352 NULL, enable_bp_cb, proc); 353} 354 355static enum callback_status 356disable_bp_cb(arch_addr_t *addr, struct breakpoint **bpp, void *data) 357{ 358 struct process *proc = data; 359 debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", proc->pid); 360 if ((*bpp)->enabled) 361 disable_breakpoint(proc, *bpp); 362 return CBS_CONT; 363} 364 365void 366disable_all_breakpoints(struct process *proc) 367{ 368 debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); 369 assert(proc->leader == proc); 370 DICT_EACH(proc->breakpoints, arch_addr_t, struct breakpoint *, 371 NULL, disable_bp_cb, proc); 372} 373 374static void 375entry_breakpoint_on_hit(struct breakpoint *bp, struct process *proc) 376{ 377 if (proc == NULL || proc->leader == NULL) 378 return; 379 delete_breakpoint(proc, bp->addr); 380 process_hit_start(proc); 381} 382 383int 384entry_breakpoint_init(struct process *proc, 385 struct breakpoint *bp, arch_addr_t addr, 386 struct library *lib) 387{ 388 assert(addr != 0); 389 int err = breakpoint_init(bp, proc, addr, NULL); 390 if (err < 0) 391 return err; 392 393 static struct bp_callbacks entry_callbacks = { 394 .on_hit = entry_breakpoint_on_hit, 395 }; 396 bp->cbs = &entry_callbacks; 397 return 0; 398} 399 400int 401breakpoints_init(struct process *proc) 402{ 403 debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); 404 405 /* XXX breakpoint dictionary should be initialized 406 * outside. Here we just put in breakpoints. */ 407 assert(proc->breakpoints != NULL); 408 409 /* Only the thread group leader should hold the breakpoints. */ 410 assert(proc->leader == proc); 411 412 /* N.B. the following used to be conditional on this, and 413 * maybe it still needs to be. */ 414 assert(proc->filename != NULL); 415 416 struct library *lib = ltelf_read_main_binary(proc, proc->filename); 417 struct breakpoint *entry_bp = NULL; 418 int bp_state = 0; 419 int result = -1; 420 switch ((int)(lib != NULL)) { 421 fail: 422 switch (bp_state) { 423 case 2: 424 proc_remove_library(proc, lib); 425 proc_remove_breakpoint(proc, entry_bp); 426 case 1: 427 breakpoint_destroy(entry_bp); 428 } 429 library_destroy(lib); 430 free(entry_bp); 431 case 0: 432 return result; 433 } 434 435 entry_bp = malloc(sizeof(*entry_bp)); 436 if (entry_bp == NULL 437 || (entry_breakpoint_init(proc, entry_bp, 438 lib->entry, lib)) < 0) { 439 fprintf(stderr, 440 "Couldn't initialize entry breakpoint for PID %d.\n" 441 "Some tracing events may be missed.\n", proc->pid); 442 free(entry_bp); 443 444 } else { 445 ++bp_state; 446 447 if ((result = proc_add_breakpoint(proc, entry_bp)) < 0) 448 goto fail; 449 ++bp_state; 450 451 if ((result = breakpoint_turn_on(entry_bp, proc)) < 0) 452 goto fail; 453 } 454 proc_add_library(proc, lib); 455 456 proc->callstack_depth = 0; 457 return 0; 458} 459