proc.c revision e677c7e0b79fc0af7c98436d924fefca7d43f359
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2011,2012 Petr Machata, Red Hat Inc. 4 * Copyright (C) 2010 Joe Damato 5 * Copyright (C) 1998,2009 Juan Cespedes 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20 * 02110-1301 USA 21 */ 22 23#include "config.h" 24 25#include <sys/types.h> 26#include <assert.h> 27#include <errno.h> 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31 32#if defined(HAVE_LIBUNWIND) 33#include <libunwind.h> 34#include <libunwind-ptrace.h> 35#endif /* defined(HAVE_LIBUNWIND) */ 36 37#include "backend.h" 38#include "breakpoint.h" 39#include "debug.h" 40#include "fetch.h" 41#include "proc.h" 42#include "value_dict.h" 43 44#ifndef ARCH_HAVE_PROCESS_DATA 45int 46arch_process_init(struct Process *proc) 47{ 48 return 0; 49} 50 51void 52arch_process_destroy(struct Process *proc) 53{ 54} 55 56int 57arch_process_clone(struct Process *retp, struct Process *proc) 58{ 59 return 0; 60} 61 62int 63arch_process_exec(struct Process *proc) 64{ 65 return 0; 66} 67#endif 68 69#ifndef ARCH_HAVE_DYNLINK_DONE 70void 71arch_dynlink_done(struct Process *proc) 72{ 73} 74#endif 75 76static void add_process(struct Process *proc, int was_exec); 77static void unlist_process(struct Process *proc); 78 79static void 80destroy_unwind(struct Process *proc) 81{ 82#if defined(HAVE_LIBUNWIND) 83 _UPT_destroy(proc->unwind_priv); 84 unw_destroy_addr_space(proc->unwind_as); 85#endif /* defined(HAVE_LIBUNWIND) */ 86} 87 88static int 89process_bare_init(struct Process *proc, const char *filename, 90 pid_t pid, int was_exec) 91{ 92 if (!was_exec) { 93 memset(proc, 0, sizeof(*proc)); 94 95 proc->filename = strdup(filename); 96 if (proc->filename == NULL) { 97 fail: 98 free(proc->filename); 99 if (proc->breakpoints != NULL) 100 dict_clear(proc->breakpoints); 101 return -1; 102 } 103 } 104 105 /* Add process so that we know who the leader is. */ 106 proc->pid = pid; 107 add_process(proc, was_exec); 108 if (proc->leader == NULL) 109 goto fail; 110 111 if (proc->leader == proc) { 112 proc->breakpoints = dict_init(target_address_hash, 113 target_address_cmp); 114 if (proc->breakpoints == NULL) 115 goto fail; 116 } else { 117 proc->breakpoints = NULL; 118 } 119 120#if defined(HAVE_LIBUNWIND) 121 proc->unwind_priv = _UPT_create(pid); 122 proc->unwind_as = unw_create_addr_space(&_UPT_accessors, 0); 123#endif /* defined(HAVE_LIBUNWIND) */ 124 125 return 0; 126} 127 128static void 129process_bare_destroy(struct Process *proc, int was_exec) 130{ 131 dict_clear(proc->breakpoints); 132 if (!was_exec) { 133 free(proc->filename); 134 unlist_process(proc); 135 destroy_unwind(proc); 136 } 137} 138 139static int 140process_init_main(struct Process *proc) 141{ 142 if (breakpoints_init(proc) < 0) { 143 fprintf(stderr, "failed to init breakpoints %d\n", 144 proc->pid); 145 return -1; 146 } 147 148 return 0; 149} 150 151int 152process_init(struct Process *proc, const char *filename, pid_t pid) 153{ 154 if (process_bare_init(proc, filename, pid, 0) < 0) { 155 fail: 156 fprintf(stderr, "failed to initialize process %d: %s\n", 157 pid, strerror(errno)); 158 return -1; 159 } 160 161 if (arch_process_init(proc) < 0) { 162 process_bare_destroy(proc, 0); 163 goto fail; 164 } 165 166 if (proc->leader != proc) 167 return 0; 168 if (process_init_main(proc) < 0) { 169 process_bare_destroy(proc, 0); 170 goto fail; 171 } 172 return 0; 173} 174 175static enum callback_status 176destroy_breakpoint_cb(struct Process *proc, struct breakpoint *bp, void *data) 177{ 178 breakpoint_destroy(bp); 179 free(bp); 180 return CBS_CONT; 181} 182 183static void 184private_process_destroy(struct Process *proc, int keep_filename) 185{ 186 if (!keep_filename) 187 free(proc->filename); 188 189 /* Libraries and symbols. This is only relevant in 190 * leader. */ 191 struct library *lib; 192 for (lib = proc->libraries; lib != NULL; ) { 193 struct library *next = lib->next; 194 library_destroy(lib); 195 free(lib); 196 lib = next; 197 } 198 proc->libraries = NULL; 199 200 /* Breakpoints. */ 201 if (proc->breakpoints != NULL) { 202 proc_each_breakpoint(proc, NULL, destroy_breakpoint_cb, NULL); 203 dict_clear(proc->breakpoints); 204 proc->breakpoints = NULL; 205 } 206 207 destroy_unwind(proc); 208} 209 210void 211process_destroy(struct Process *proc) 212{ 213 private_process_destroy(proc, 0); 214 arch_process_destroy(proc); 215} 216 217int 218process_exec(struct Process *proc) 219{ 220 /* Call exec first, before we destroy the main state. */ 221 if (arch_process_exec(proc) < 0) 222 return -1; 223 224 private_process_destroy(proc, 1); 225 if (process_bare_init(proc, NULL, proc->pid, 1) < 0) 226 return -1; 227 if (process_init_main(proc) < 0) { 228 process_bare_destroy(proc, 1); 229 return -1; 230 } 231 return 0; 232} 233 234struct Process * 235open_program(const char *filename, pid_t pid) 236{ 237 assert(pid != 0); 238 struct Process *proc = malloc(sizeof(*proc)); 239 if (proc == NULL || process_init(proc, filename, pid) < 0) { 240 free(proc); 241 return NULL; 242 } 243 return proc; 244} 245 246struct clone_single_bp_data { 247 struct Process *old_proc; 248 struct Process *new_proc; 249 int error; 250}; 251 252static void 253clone_single_bp(void *key, void *value, void *u) 254{ 255 struct breakpoint *bp = value; 256 struct clone_single_bp_data *data = u; 257 258 data->error = 0; 259 struct breakpoint *clone = malloc(sizeof(*clone)); 260 if (clone == NULL 261 || breakpoint_clone(clone, data->new_proc, 262 bp, data->old_proc) < 0) { 263 fail: 264 free(clone); 265 data->error = -1; 266 } 267 if (proc_add_breakpoint(data->new_proc->leader, clone) < 0) { 268 breakpoint_destroy(clone); 269 goto fail; 270 } 271} 272 273int 274process_clone(struct Process *retp, struct Process *proc, pid_t pid) 275{ 276 if (process_bare_init(retp, proc->filename, pid, 0) < 0) { 277 fail1: 278 fprintf(stderr, "failed to clone process %d->%d : %s\n", 279 proc->pid, pid, strerror(errno)); 280 return -1; 281 } 282 283 retp->tracesysgood = proc->tracesysgood; 284 retp->e_machine = proc->e_machine; 285 retp->e_class = proc->e_class; 286 287 /* For non-leader processes, that's all we need to do. */ 288 if (retp->leader != retp) 289 return 0; 290 291 /* Clone symbols first so that we can clone and relink 292 * breakpoints. */ 293 struct library *lib; 294 struct library **nlibp = &retp->libraries; 295 for (lib = proc->libraries; lib != NULL; lib = lib->next) { 296 *nlibp = malloc(sizeof(**nlibp)); 297 if (*nlibp == NULL 298 || library_clone(*nlibp, lib) < 0) { 299 fail2: 300 process_bare_destroy(retp, 0); 301 302 /* Error when cloning. Unroll what was done. */ 303 for (lib = retp->libraries; lib != NULL; ) { 304 struct library *next = lib->next; 305 library_destroy(lib); 306 free(lib); 307 lib = next; 308 } 309 goto fail1; 310 } 311 312 nlibp = &(*nlibp)->next; 313 } 314 315 /* Now clone breakpoints. Symbol relinking is done in 316 * clone_single_bp. */ 317 struct clone_single_bp_data data = { 318 .old_proc = proc, 319 .new_proc = retp, 320 .error = 0, 321 }; 322 dict_apply_to_all(proc->breakpoints, &clone_single_bp, &data); 323 if (data.error < 0) 324 goto fail2; 325 326 /* And finally the call stack. */ 327 memcpy(retp->callstack, proc->callstack, sizeof(retp->callstack)); 328 retp->callstack_depth = proc->callstack_depth; 329 330 size_t i; 331 for (i = 0; i < retp->callstack_depth; ++i) { 332 struct fetch_context *ctx = retp->callstack[i].fetch_context; 333 if (ctx != NULL) { 334 struct fetch_context *nctx = fetch_arg_clone(retp, ctx); 335 if (nctx == NULL) { 336 size_t j; 337 fail3: 338 for (j = 0; j < i; ++j) { 339 nctx = retp->callstack[i].fetch_context; 340 fetch_arg_done(nctx); 341 retp->callstack[i].fetch_context = NULL; 342 } 343 goto fail2; 344 } 345 retp->callstack[i].fetch_context = nctx; 346 } 347 348 struct value_dict *args = retp->callstack[i].arguments; 349 if (args != NULL) { 350 struct value_dict *nargs = malloc(sizeof(*nargs)); 351 if (nargs == NULL 352 || val_dict_clone(nargs, args) < 0) { 353 size_t j; 354 fail4: 355 for (j = 0; j < i; ++j) { 356 nargs = retp->callstack[i].arguments; 357 val_dict_destroy(nargs); 358 free(nargs); 359 retp->callstack[i].arguments = NULL; 360 } 361 362 /* Pretend that this round went well, 363 * so that fail3 frees I-th 364 * fetch_context. */ 365 ++i; 366 goto fail3; 367 } 368 retp->callstack[i].arguments = nargs; 369 } 370 } 371 372 if (arch_process_clone(retp, proc) < 0) 373 goto fail4; 374 375 return 0; 376} 377 378static int 379open_one_pid(pid_t pid) 380{ 381 Process *proc; 382 char *filename; 383 debug(DEBUG_PROCESS, "open_one_pid(pid=%d)", pid); 384 385 /* Get the filename first. Should the trace_pid fail, we can 386 * easily free it, untracing is more work. */ 387 if ((filename = pid2name(pid)) == NULL 388 || trace_pid(pid) < 0) { 389 free(filename); 390 return -1; 391 } 392 393 proc = open_program(filename, pid); 394 if (proc == NULL) 395 return -1; 396 trace_set_options(proc); 397 398 return 0; 399} 400 401static enum callback_status 402start_one_pid(Process * proc, void * data) 403{ 404 continue_process(proc->pid); 405 return CBS_CONT; 406} 407 408void 409open_pid(pid_t pid) 410{ 411 debug(DEBUG_PROCESS, "open_pid(pid=%d)", pid); 412 /* If we are already tracing this guy, we should be seeing all 413 * his children via normal tracing route. */ 414 if (pid2proc(pid) != NULL) 415 return; 416 417 /* First, see if we can attach the requested PID itself. */ 418 if (open_one_pid(pid)) { 419 fprintf(stderr, "Cannot attach to pid %u: %s\n", 420 pid, strerror(errno)); 421 trace_fail_warning(pid); 422 return; 423 } 424 425 /* Now attach to all tasks that belong to that PID. There's a 426 * race between process_tasks and open_one_pid. So when we 427 * fail in open_one_pid below, we just do another round. 428 * Chances are that by then that PID will have gone away, and 429 * that's why we have seen the failure. The processes that we 430 * manage to open_one_pid are stopped, so we should eventually 431 * reach a point where process_tasks doesn't give any new 432 * processes (because there's nobody left to produce 433 * them). */ 434 size_t old_ntasks = 0; 435 int have_all; 436 while (1) { 437 pid_t *tasks; 438 size_t ntasks; 439 size_t i; 440 441 if (process_tasks(pid, &tasks, &ntasks) < 0) { 442 fprintf(stderr, "Cannot obtain tasks of pid %u: %s\n", 443 pid, strerror(errno)); 444 break; 445 } 446 447 have_all = 1; 448 for (i = 0; i < ntasks; ++i) 449 if (pid2proc(tasks[i]) == NULL 450 && open_one_pid(tasks[i])) 451 have_all = 0; 452 453 free(tasks); 454 455 if (have_all && old_ntasks == ntasks) 456 break; 457 old_ntasks = ntasks; 458 } 459 460 struct Process *leader = pid2proc(pid)->leader; 461 462 /* XXX Is there a way to figure out whether _start has 463 * actually already been hit? */ 464 arch_dynlink_done(leader); 465 466 /* Done. Continue everyone. */ 467 each_task(leader, NULL, start_one_pid, NULL); 468} 469 470static enum callback_status 471find_proc(Process * proc, void * data) 472{ 473 pid_t pid = (pid_t)(uintptr_t)data; 474 return proc->pid == pid ? CBS_STOP : CBS_CONT; 475} 476 477Process * 478pid2proc(pid_t pid) { 479 return each_process(NULL, &find_proc, (void *)(uintptr_t)pid); 480} 481 482static Process * list_of_processes = NULL; 483 484static void 485unlist_process(Process * proc) 486{ 487 Process *tmp; 488 489 if (list_of_processes == proc) { 490 list_of_processes = list_of_processes->next; 491 return; 492 } 493 494 for (tmp = list_of_processes; ; tmp = tmp->next) { 495 /* If the following assert fails, the process wasn't 496 * in the list. */ 497 assert(tmp->next != NULL); 498 499 if (tmp->next == proc) { 500 tmp->next = tmp->next->next; 501 return; 502 } 503 } 504} 505 506struct Process * 507each_process(struct Process *start_after, 508 enum callback_status(*cb)(struct Process *proc, void *data), 509 void *data) 510{ 511 struct Process *it = start_after == NULL ? list_of_processes 512 : start_after->next; 513 514 while (it != NULL) { 515 /* Callback might call remove_process. */ 516 struct Process *next = it->next; 517 switch ((*cb)(it, data)) { 518 case CBS_FAIL: 519 /* XXX handle me */ 520 case CBS_STOP: 521 return it; 522 case CBS_CONT: 523 break; 524 } 525 it = next; 526 } 527 return NULL; 528} 529 530Process * 531each_task(struct Process *proc, struct Process *start_after, 532 enum callback_status(*cb)(struct Process *proc, void *data), 533 void *data) 534{ 535 assert(proc != NULL); 536 struct Process *it = start_after == NULL ? proc->leader 537 : start_after->next; 538 539 if (it != NULL) { 540 struct Process *leader = it->leader; 541 while (it != NULL && it->leader == leader) { 542 /* Callback might call remove_process. */ 543 struct Process *next = it->next; 544 switch ((*cb)(it, data)) { 545 case CBS_FAIL: 546 /* XXX handle me */ 547 case CBS_STOP: 548 return it; 549 case CBS_CONT: 550 break; 551 } 552 it = next; 553 } 554 } 555 return NULL; 556} 557 558static void 559add_process(struct Process *proc, int was_exec) 560{ 561 Process ** leaderp = &list_of_processes; 562 if (proc->pid) { 563 pid_t tgid = process_leader(proc->pid); 564 if (tgid == 0) 565 /* Must have been terminated before we managed 566 * to fully attach. */ 567 return; 568 if (tgid == proc->pid) 569 proc->leader = proc; 570 else { 571 Process * leader = pid2proc(tgid); 572 proc->leader = leader; 573 if (leader != NULL) 574 leaderp = &leader->next; 575 } 576 } 577 578 if (!was_exec) { 579 proc->next = *leaderp; 580 *leaderp = proc; 581 } 582} 583 584void 585change_process_leader(Process * proc, Process * leader) 586{ 587 Process ** leaderp = &list_of_processes; 588 if (proc->leader == leader) 589 return; 590 591 assert(leader != NULL); 592 unlist_process(proc); 593 if (proc != leader) 594 leaderp = &leader->next; 595 596 proc->leader = leader; 597 proc->next = *leaderp; 598 *leaderp = proc; 599} 600 601static enum callback_status 602clear_leader(struct Process *proc, void *data) 603{ 604 debug(DEBUG_FUNCTION, "detach_task %d from leader %d", 605 proc->pid, proc->leader->pid); 606 proc->leader = NULL; 607 return CBS_CONT; 608} 609 610void 611remove_process(Process *proc) 612{ 613 debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid); 614 615 if (proc->leader == proc) 616 each_task(proc, NULL, &clear_leader, NULL); 617 618 unlist_process(proc); 619 process_removed(proc); 620 process_destroy(proc); 621 free(proc); 622} 623 624void 625install_event_handler(Process *proc, struct event_handler *handler) 626{ 627 debug(DEBUG_FUNCTION, "install_event_handler(pid=%d, %p)", proc->pid, handler); 628 assert(proc->event_handler == NULL); 629 proc->event_handler = handler; 630} 631 632void 633destroy_event_handler(Process * proc) 634{ 635 struct event_handler *handler = proc->event_handler; 636 debug(DEBUG_FUNCTION, "destroy_event_handler(pid=%d, %p)", proc->pid, handler); 637 assert(handler != NULL); 638 if (handler->destroy != NULL) 639 handler->destroy(handler); 640 free(handler); 641 proc->event_handler = NULL; 642} 643 644static int 645breakpoint_for_symbol(struct library_symbol *libsym, struct Process *proc) 646{ 647 arch_addr_t bp_addr; 648 assert(proc->leader == proc); 649 650 /* Don't enable latent or delayed symbols. */ 651 if (libsym->latent || libsym->delayed) 652 return 0; 653 654 bp_addr = sym2addr(proc, libsym); 655 656 /* If there is an artificial breakpoint on the same address, 657 * its libsym will be NULL, and we can smuggle our libsym 658 * there. That artificial breakpoint is there presumably for 659 * the callbacks, which we don't touch. If there is a real 660 * breakpoint, then this is a bug. ltrace-elf.c should filter 661 * symbols and ignore extra symbol aliases. 662 * 663 * The other direction is more complicated and currently not 664 * supported. If a breakpoint has custom callbacks, it might 665 * be also custom-allocated, and we would really need to swap 666 * the two: delete the one now in the dictionary, swap values 667 * around, and put the new breakpoint back in. */ 668 struct breakpoint *bp = dict_find_entry(proc->breakpoints, 669 bp_addr); 670 if (bp != NULL) { 671 assert(bp->libsym == NULL); 672 bp->libsym = libsym; 673 return 0; 674 } 675 676 bp = malloc(sizeof(*bp)); 677 if (bp == NULL 678 || breakpoint_init(bp, proc, bp_addr, libsym) < 0) { 679 fail: 680 free(bp); 681 return -1; 682 } 683 if (proc_add_breakpoint(proc, bp) < 0) { 684 breakpoint_destroy(bp); 685 goto fail; 686 } 687 688 if (breakpoint_turn_on(bp, proc) < 0) { 689 proc_remove_breakpoint(proc, bp); 690 breakpoint_destroy(bp); 691 goto fail; 692 } 693 694 return 0; 695} 696 697static enum callback_status 698cb_breakpoint_for_symbol(struct library_symbol *libsym, void *data) 699{ 700 return breakpoint_for_symbol(libsym, data) < 0 ? CBS_FAIL : CBS_CONT; 701} 702 703static int 704proc_activate_latent_symbol(struct Process *proc, 705 struct library_symbol *libsym) 706{ 707 assert(libsym->latent); 708 libsym->latent = 0; 709 return breakpoint_for_symbol(libsym, proc); 710} 711 712int 713proc_activate_delayed_symbol(struct Process *proc, 714 struct library_symbol *libsym) 715{ 716 assert(libsym->delayed); 717 libsym->delayed = 0; 718 return breakpoint_for_symbol(libsym, proc); 719} 720 721static enum callback_status 722activate_latent_in(struct Process *proc, struct library *lib, void *data) 723{ 724 struct library_exported_name *exported; 725 for (exported = data; exported != NULL; exported = exported->next) { 726 struct library_symbol *libsym = NULL; 727 while ((libsym = library_each_symbol(lib, libsym, 728 library_symbol_named_cb, 729 (void *)exported->name)) 730 != NULL) 731 if (libsym->latent 732 && proc_activate_latent_symbol(proc, libsym) < 0) 733 return CBS_FAIL; 734 } 735 return CBS_CONT; 736} 737 738void 739proc_add_library(struct Process *proc, struct library *lib) 740{ 741 assert(lib->next == NULL); 742 lib->next = proc->libraries; 743 proc->libraries = lib; 744 debug(DEBUG_PROCESS, "added library %s@%p (%s) to %d", 745 lib->soname, lib->base, lib->pathname, proc->pid); 746 747 /* Insert breakpoints for all active (non-latent) symbols. */ 748 struct library_symbol *libsym = NULL; 749 while ((libsym = library_each_symbol(lib, libsym, 750 cb_breakpoint_for_symbol, 751 proc)) != NULL) 752 fprintf(stderr, "Couldn't insert breakpoint for %s to %d: %s.", 753 libsym->name, proc->pid, strerror(errno)); 754 755 /* Look through export list of the new library and compare it 756 * with latent symbols of all libraries (including this 757 * library itself). */ 758 struct library *lib2 = NULL; 759 while ((lib2 = proc_each_library(proc, lib2, activate_latent_in, 760 lib->exported_names)) != NULL) 761 fprintf(stderr, 762 "Couldn't activate latent symbols for %s in %d: %s.", 763 libsym->name, proc->pid, strerror(errno)); 764} 765 766int 767proc_remove_library(struct Process *proc, struct library *lib) 768{ 769 struct library **libp; 770 for (libp = &proc->libraries; *libp != NULL; libp = &(*libp)->next) 771 if (*libp == lib) { 772 *libp = lib->next; 773 return 0; 774 } 775 return -1; 776} 777 778struct library * 779proc_each_library(struct Process *proc, struct library *it, 780 enum callback_status (*cb)(struct Process *proc, 781 struct library *lib, void *data), 782 void *data) 783{ 784 if (it == NULL) 785 it = proc->libraries; 786 787 while (it != NULL) { 788 struct library *next = it->next; 789 790 switch (cb(proc, it, data)) { 791 case CBS_FAIL: 792 /* XXX handle me */ 793 case CBS_STOP: 794 return it; 795 case CBS_CONT: 796 break; 797 } 798 799 it = next; 800 } 801 802 return NULL; 803} 804 805static void 806check_leader(struct Process *proc) 807{ 808 /* Only the group leader should be getting the breakpoints and 809 * thus have ->breakpoint initialized. */ 810 assert(proc->leader != NULL); 811 assert(proc->leader == proc); 812 assert(proc->breakpoints != NULL); 813} 814 815int 816proc_add_breakpoint(struct Process *proc, struct breakpoint *bp) 817{ 818 debug(DEBUG_FUNCTION, "proc_add_breakpoint(pid=%d, %s@%p)", 819 proc->pid, breakpoint_name(bp), bp->addr); 820 check_leader(proc); 821 822 /* XXX We might merge bp->libsym instead of the following 823 * assert, but that's not necessary right now. Read the 824 * comment in breakpoint_for_symbol. */ 825 assert(dict_find_entry(proc->breakpoints, bp->addr) == NULL); 826 827 if (dict_enter(proc->breakpoints, bp->addr, bp) < 0) { 828 fprintf(stderr, 829 "couldn't enter breakpoint %s@%p to dictionary: %s\n", 830 breakpoint_name(bp), bp->addr, strerror(errno)); 831 return -1; 832 } 833 834 return 0; 835} 836 837void 838proc_remove_breakpoint(struct Process *proc, struct breakpoint *bp) 839{ 840 debug(DEBUG_FUNCTION, "proc_remove_breakpoint(pid=%d, %s@%p)", 841 proc->pid, breakpoint_name(bp), bp->addr); 842 check_leader(proc); 843 struct breakpoint *removed = dict_remove(proc->breakpoints, bp->addr); 844 assert(removed == bp); 845} 846 847/* Dict doesn't support iteration restarts, so here's this contraption 848 * for now. XXX add restarts to dict. */ 849struct each_breakpoint_data 850{ 851 void *start; 852 void *end; 853 struct Process *proc; 854 enum callback_status (*cb)(struct Process *proc, 855 struct breakpoint *bp, 856 void *data); 857 void *cb_data; 858}; 859 860static void 861each_breakpoint_cb(void *key, void *value, void *d) 862{ 863 struct each_breakpoint_data *data = d; 864 if (data->end != NULL) 865 return; 866 if (data->start == key) 867 data->start = NULL; 868 869 if (data->start == NULL) { 870 switch (data->cb(data->proc, value, data->cb_data)) { 871 case CBS_FAIL: 872 /* XXX handle me */ 873 case CBS_STOP: 874 data->end = key; 875 case CBS_CONT: 876 return; 877 } 878 } 879} 880 881void * 882proc_each_breakpoint(struct Process *proc, void *start, 883 enum callback_status (*cb)(struct Process *proc, 884 struct breakpoint *bp, 885 void *data), void *data) 886{ 887 struct each_breakpoint_data dd = { 888 .start = start, 889 .proc = proc, 890 .cb = cb, 891 .cb_data = data, 892 }; 893 dict_apply_to_all(proc->breakpoints, &each_breakpoint_cb, &dd); 894 return dd.end; 895} 896