handle_event.c revision 4007d74c2435ce4b50305d64ffe831627f989335
1#include "config.h" 2 3#define _GNU_SOURCE 4#include <stdio.h> 5#include <string.h> 6#include <stdlib.h> 7#include <signal.h> 8#include <assert.h> 9#include <sys/time.h> 10 11#include "common.h" 12 13#ifdef __powerpc__ 14#include <sys/ptrace.h> 15#endif 16 17static void handle_signal(Event *event); 18static void handle_exit(Event *event); 19static void handle_exit_signal(Event *event); 20static void handle_syscall(Event *event); 21static void handle_arch_syscall(Event *event); 22static void handle_sysret(Event *event); 23static void handle_arch_sysret(Event *event); 24static void handle_clone(Event *event); 25static void handle_exec(Event *event); 26static void handle_breakpoint(Event *event); 27static void handle_new(Event *event); 28 29static void callstack_push_syscall(Process *proc, int sysnum); 30static void callstack_push_symfunc(Process *proc, 31 struct library_symbol *sym); 32static void callstack_pop(Process *proc); 33 34static char * shortsignal(Process *proc, int signum); 35static char * sysname(Process *proc, int sysnum); 36static char * arch_sysname(Process *proc, int sysnum); 37 38void 39handle_event(Event *event) { 40 debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", 41 event->proc ? event->proc->pid : -1, event->type); 42 /* If the thread group defines an overriding event handler, 43 give it a chance to kick in. */ 44 if (event->proc != NULL 45 && event->proc->leader != NULL) { 46 Event_Handler * handler = event->proc->leader->event_handler; 47 if (handler != NULL) { 48 event = (*handler->on_event) (handler, event); 49 if (event == NULL) 50 /* It was handled. */ 51 return; 52 } 53 } 54 55 switch (event->type) { 56 case EVENT_NONE: 57 debug(1, "event: none"); 58 return; 59 case EVENT_SIGNAL: 60 debug(1, "event: signal (%s [%d])", 61 shortsignal(event->proc, event->e_un.signum), 62 event->e_un.signum); 63 handle_signal(event); 64 return; 65 case EVENT_EXIT: 66 debug(1, "event: exit (%d)", event->e_un.ret_val); 67 handle_exit(event); 68 return; 69 case EVENT_EXIT_SIGNAL: 70 debug(1, "event: exit signal (%s [%d])", 71 shortsignal(event->proc, event->e_un.signum), 72 event->e_un.signum); 73 handle_exit_signal(event); 74 return; 75 case EVENT_SYSCALL: 76 debug(1, "event: syscall (%s [%d])", 77 sysname(event->proc, event->e_un.sysnum), 78 event->e_un.sysnum); 79 handle_syscall(event); 80 return; 81 case EVENT_SYSRET: 82 debug(1, "event: sysret (%s [%d])", 83 sysname(event->proc, event->e_un.sysnum), 84 event->e_un.sysnum); 85 handle_sysret(event); 86 return; 87 case EVENT_ARCH_SYSCALL: 88 debug(1, "event: arch_syscall (%s [%d])", 89 arch_sysname(event->proc, event->e_un.sysnum), 90 event->e_un.sysnum); 91 handle_arch_syscall(event); 92 return; 93 case EVENT_ARCH_SYSRET: 94 debug(1, "event: arch_sysret (%s [%d])", 95 arch_sysname(event->proc, event->e_un.sysnum), 96 event->e_un.sysnum); 97 handle_arch_sysret(event); 98 return; 99 case EVENT_CLONE: 100 debug(1, "event: clone (%u)", event->e_un.newpid); 101 handle_clone(event); 102 return; 103 case EVENT_EXEC: 104 debug(1, "event: exec()"); 105 handle_exec(event); 106 return; 107 case EVENT_BREAKPOINT: 108 debug(1, "event: breakpoint"); 109 handle_breakpoint(event); 110 return; 111 case EVENT_NEW: 112 debug(1, "event: new process"); 113 handle_new(event); 114 return; 115 default: 116 fprintf(stderr, "Error! unknown event?\n"); 117 exit(1); 118 } 119} 120 121/* TODO */ 122static void * 123address_clone(void * addr) { 124 debug(DEBUG_FUNCTION, "address_clone(%p)", addr); 125 return addr; 126} 127 128static void * 129breakpoint_clone(void * bp) { 130 Breakpoint * b; 131 debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp); 132 b = malloc(sizeof(Breakpoint)); 133 if (!b) { 134 perror("malloc()"); 135 exit(1); 136 } 137 memcpy(b, bp, sizeof(Breakpoint)); 138 return b; 139} 140 141typedef struct Pending_New Pending_New; 142struct Pending_New { 143 pid_t pid; 144 Pending_New * next; 145}; 146static Pending_New * pending_news = NULL; 147 148static int 149pending_new(pid_t pid) { 150 Pending_New * p; 151 152 debug(DEBUG_FUNCTION, "pending_new(%d)", pid); 153 154 p = pending_news; 155 while (p) { 156 if (p->pid == pid) { 157 return 1; 158 } 159 p = p->next; 160 } 161 return 0; 162} 163 164static void 165pending_new_insert(pid_t pid) { 166 Pending_New * p; 167 168 debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid); 169 170 p = malloc(sizeof(Pending_New)); 171 if (!p) { 172 perror("malloc()"); 173 exit(1); 174 } 175 p->pid = pid; 176 p->next = pending_news; 177 pending_news = p; 178} 179 180static void 181pending_new_remove(pid_t pid) { 182 Pending_New *p, *pred; 183 184 debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid); 185 186 p = pending_news; 187 if (p->pid == pid) { 188 pending_news = p->next; 189 free(p); 190 } else { 191 while (p) { 192 if (p->pid == pid) { 193 pred->next = p->next; 194 free(p); 195 } 196 pred = p; 197 p = p->next; 198 } 199 } 200} 201 202static void 203handle_clone(Event * event) { 204 Process *p; 205 206 debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid); 207 208 p = malloc(sizeof(Process)); 209 if (!p) { 210 perror("malloc()"); 211 exit(1); 212 } 213 memcpy(p, event->proc, sizeof(Process)); 214 p->breakpoints = dict_clone(event->proc->breakpoints, address_clone, breakpoint_clone); 215 p->pid = event->e_un.newpid; 216 p->parent = event->proc; 217 218 if (pending_new(p->pid)) { 219 pending_new_remove(p->pid); 220 if (p->breakpoint_being_enabled) { 221 enable_breakpoint(p, p->breakpoint_being_enabled); 222 p->breakpoint_being_enabled = NULL; 223 } 224 if (p->event_handler != NULL) 225 destroy_event_handler(p); 226 if (event->proc->state == STATE_ATTACHED && options.follow) { 227 p->state = STATE_ATTACHED; 228 } else { 229 p->state = STATE_IGNORED; 230 } 231 continue_process(p->pid); 232 add_process(p); 233 } else { 234 p->state = STATE_BEING_CREATED; 235 add_process(p); 236 } 237 continue_process(event->proc->pid); 238} 239 240static void 241handle_new(Event * event) { 242 Process * proc; 243 244 debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid); 245 246 proc = pid2proc(event->e_un.newpid); 247 if (!proc) { 248 pending_new_insert(event->e_un.newpid); 249 } else { 250 assert(proc->state == STATE_BEING_CREATED); 251 if (proc->breakpoint_being_enabled) { 252 enable_breakpoint(proc, proc->breakpoint_being_enabled); 253 proc->breakpoint_being_enabled = NULL; 254 } 255 if (proc->event_handler != NULL) 256 destroy_event_handler(proc); 257 if (options.follow) { 258 proc->state = STATE_ATTACHED; 259 } else { 260 proc->state = STATE_IGNORED; 261 } 262 continue_process(proc->pid); 263 } 264} 265 266static char * 267shortsignal(Process *proc, int signum) { 268 static char *signalent0[] = { 269#include "signalent.h" 270 }; 271 static char *signalent1[] = { 272#include "signalent1.h" 273 }; 274 static char **signalents[] = { signalent0, signalent1 }; 275 int nsignals[] = { sizeof signalent0 / sizeof signalent0[0], 276 sizeof signalent1 / sizeof signalent1[0] 277 }; 278 279 debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum); 280 281 if (proc->personality > sizeof signalents / sizeof signalents[0]) 282 abort(); 283 if (signum < 0 || signum >= nsignals[proc->personality]) { 284 return "UNKNOWN_SIGNAL"; 285 } else { 286 return signalents[proc->personality][signum]; 287 } 288} 289 290static char * 291sysname(Process *proc, int sysnum) { 292 static char result[128]; 293 static char *syscalent0[] = { 294#include "syscallent.h" 295 }; 296 static char *syscalent1[] = { 297#include "syscallent1.h" 298 }; 299 static char **syscalents[] = { syscalent0, syscalent1 }; 300 int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0], 301 sizeof syscalent1 / sizeof syscalent1[0] 302 }; 303 304 debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); 305 306 if (proc->personality > sizeof syscalents / sizeof syscalents[0]) 307 abort(); 308 if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) { 309 sprintf(result, "SYS_%d", sysnum); 310 return result; 311 } else { 312 sprintf(result, "SYS_%s", 313 syscalents[proc->personality][sysnum]); 314 return result; 315 } 316} 317 318static char * 319arch_sysname(Process *proc, int sysnum) { 320 static char result[128]; 321 static char *arch_syscalent[] = { 322#include "arch_syscallent.h" 323 }; 324 int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0]; 325 326 debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); 327 328 if (sysnum < 0 || sysnum >= nsyscals) { 329 sprintf(result, "ARCH_%d", sysnum); 330 return result; 331 } else { 332 sprintf(result, "ARCH_%s", 333 arch_syscalent[sysnum]); 334 return result; 335 } 336} 337 338static void 339handle_signal(Event *event) { 340 debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); 341 if (exiting && event->e_un.signum == SIGSTOP) { 342 pid_t pid = event->proc->pid; 343 disable_all_breakpoints(event->proc); 344 untrace_pid(pid); 345 remove_process(event->proc); 346 return; 347 } 348 if (event->proc->state != STATE_IGNORED && !options.no_signals) { 349 output_line(event->proc, "--- %s (%s) ---", 350 shortsignal(event->proc, event->e_un.signum), 351 strsignal(event->e_un.signum)); 352 } 353 continue_after_signal(event->proc->pid, event->e_un.signum); 354} 355 356static void 357handle_exit(Event *event) { 358 debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val); 359 if (event->proc->state != STATE_IGNORED) { 360 output_line(event->proc, "+++ exited (status %d) +++", 361 event->e_un.ret_val); 362 } 363 remove_process(event->proc); 364} 365 366static void 367handle_exit_signal(Event *event) { 368 debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); 369 if (event->proc->state != STATE_IGNORED) { 370 output_line(event->proc, "+++ killed by %s +++", 371 shortsignal(event->proc, event->e_un.signum)); 372 } 373 remove_process(event->proc); 374} 375 376static void 377handle_syscall(Event *event) { 378 debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 379 if (event->proc->state != STATE_IGNORED) { 380 callstack_push_syscall(event->proc, event->e_un.sysnum); 381 if (options.syscalls) { 382 output_left(LT_TOF_SYSCALL, event->proc, 383 sysname(event->proc, event->e_un.sysnum)); 384 } 385 if (event->proc->breakpoints_enabled == 0) { 386 enable_all_breakpoints(event->proc); 387 } 388 } 389 continue_process(event->proc->pid); 390} 391 392static void 393handle_exec(Event * event) { 394 Process * proc = event->proc; 395 pid_t saved_pid; 396 397 debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid); 398 if (proc->state == STATE_IGNORED) { 399 untrace_pid(proc->pid); 400 remove_process(proc); 401 return; 402 } 403 output_line(proc, "--- Called exec() ---"); 404 proc->mask_32bit = 0; 405 proc->personality = 0; 406 proc->arch_ptr = NULL; 407 free(proc->filename); 408 proc->filename = pid2name(proc->pid); 409 saved_pid = proc->pid; 410 proc->pid = 0; 411 breakpoints_init(proc, 0); 412 proc->pid = saved_pid; 413 proc->callstack_depth = 0; 414 continue_process(proc->pid); 415} 416 417static void 418handle_arch_syscall(Event *event) { 419 debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 420 if (event->proc->state != STATE_IGNORED) { 421 callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum); 422 if (options.syscalls) { 423 output_left(LT_TOF_SYSCALL, event->proc, 424 arch_sysname(event->proc, event->e_un.sysnum)); 425 } 426 if (event->proc->breakpoints_enabled == 0) { 427 enable_all_breakpoints(event->proc); 428 } 429 } 430 continue_process(event->proc->pid); 431} 432 433struct timeval current_time_spent; 434 435static void 436calc_time_spent(Process *proc) { 437 struct timeval tv; 438 struct timezone tz; 439 struct timeval diff; 440 struct callstack_element *elem; 441 442 debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid); 443 elem = &proc->callstack[proc->callstack_depth - 1]; 444 445 gettimeofday(&tv, &tz); 446 447 diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec; 448 if (tv.tv_usec >= elem->time_spent.tv_usec) { 449 diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec; 450 } else { 451 diff.tv_sec++; 452 diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec; 453 } 454 current_time_spent = diff; 455} 456 457static void 458handle_sysret(Event *event) { 459 debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 460 if (event->proc->state != STATE_IGNORED) { 461 if (opt_T || options.summary) { 462 calc_time_spent(event->proc); 463 } 464 if (options.syscalls) { 465 output_right(LT_TOF_SYSCALLR, event->proc, 466 sysname(event->proc, event->e_un.sysnum)); 467 } 468 callstack_pop(event->proc); 469 } 470 continue_process(event->proc->pid); 471} 472 473static void 474handle_arch_sysret(Event *event) { 475 debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 476 if (event->proc->state != STATE_IGNORED) { 477 if (opt_T || options.summary) { 478 calc_time_spent(event->proc); 479 } 480 if (options.syscalls) { 481 output_right(LT_TOF_SYSCALLR, event->proc, 482 arch_sysname(event->proc, event->e_un.sysnum)); 483 } 484 callstack_pop(event->proc); 485 } 486 continue_process(event->proc->pid); 487} 488 489#ifdef __powerpc__ 490void *get_count_register (Process *proc); 491#endif 492 493static void 494handle_breakpoint(Event *event) { 495 int i, j; 496 Breakpoint *sbp; 497 Process *leader = event->proc->leader; 498 499 /* The leader has terminated. */ 500 if (leader == NULL) { 501 continue_process(event->proc->pid); 502 return; 503 } 504 505 debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr); 506 debug(2, "event: breakpoint (%p)", event->e_un.brk_addr); 507 508#ifdef __powerpc__ 509 /* Need to skip following NOP's to prevent a fake function from being stacked. */ 510 long stub_addr = (long) get_count_register(event->proc); 511 Breakpoint *stub_bp = NULL; 512 char nop_instruction[] = PPC_NOP; 513 514 stub_bp = address2bpstruct(leader, event->e_un.brk_addr); 515 516 if (stub_bp) { 517 unsigned char *bp_instruction = stub_bp->orig_value; 518 519 if (memcmp(bp_instruction, nop_instruction, 520 PPC_NOP_LENGTH) == 0) { 521 if (stub_addr != (long) event->e_un.brk_addr) { 522 set_instruction_pointer (event->proc, event->e_un.brk_addr + 4); 523 continue_process(event->proc->pid); 524 return; 525 } 526 } 527 } 528#endif 529 if ((sbp = event->proc->breakpoint_being_enabled) != 0) { 530 /* Reinsert breakpoint */ 531 sbp = event->proc->breakpoint_being_enabled; 532 continue_enabling_breakpoint(event->proc, sbp); 533 event->proc->breakpoint_being_enabled = NULL; 534 return; 535 } 536 537 for (i = event->proc->callstack_depth - 1; i >= 0; i--) { 538 if (event->e_un.brk_addr == 539 event->proc->callstack[i].return_addr) { 540#ifdef __powerpc__ 541 /* 542 * PPC HACK! (XXX FIXME TODO) 543 * The PLT gets modified during the first call, 544 * so be sure to re-enable the breakpoint. 545 */ 546 unsigned long a; 547 struct library_symbol *libsym = 548 event->proc->callstack[i].c_un.libfunc; 549 void *addr = sym2addr(event->proc, libsym); 550 551 if (libsym->plt_type != LS_TOPLT_POINT) { 552 unsigned char break_insn[] = BREAKPOINT_VALUE; 553 554 sbp = address2bpstruct(leader, addr); 555 assert(sbp); 556 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, 557 addr); 558 559 if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) { 560 sbp->enabled--; 561 insert_breakpoint(event->proc, addr, 562 libsym); 563 } 564 } else { 565 sbp = dict_find_entry(leader->breakpoints, addr); 566 /* On powerpc, the breakpoint address 567 may end up being actual entry point 568 of the library symbol, not the PLT 569 address we computed. In that case, 570 sbp is NULL. */ 571 if (sbp == NULL || addr != sbp->addr) { 572 insert_breakpoint(event->proc, addr, 573 libsym); 574 } 575 } 576#elif defined(__mips__) 577 void *addr = NULL; 578 struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc; 579 struct library_symbol *new_sym; 580 assert(sym); 581 addr = sym2addr(leader, sym); 582 sbp = dict_find_entry(leader->breakpoints, addr); 583 if (sbp) { 584 if (addr != sbp->addr) { 585 insert_breakpoint(event->proc, addr, sym); 586 } 587 } else { 588 new_sym=malloc(sizeof(*new_sym) + strlen(sym->name) + 1); 589 memcpy(new_sym,sym,sizeof(*new_sym) + strlen(sym->name) + 1); 590 new_sym->next = leader->list_of_symbols; 591 leader->list_of_symbols = new_sym; 592 insert_breakpoint(event->proc, addr, new_sym); 593 } 594#endif 595 for (j = event->proc->callstack_depth - 1; j > i; j--) { 596 callstack_pop(event->proc); 597 } 598 if (event->proc->state != STATE_IGNORED) { 599 if (opt_T || options.summary) { 600 calc_time_spent(event->proc); 601 } 602 } 603 event->proc->return_addr = event->e_un.brk_addr; 604 if (event->proc->state != STATE_IGNORED) { 605 output_right(LT_TOF_FUNCTIONR, event->proc, 606 event->proc->callstack[i].c_un.libfunc->name); 607 } 608 callstack_pop(event->proc); 609 sbp = address2bpstruct(leader, event->e_un.brk_addr); 610 continue_after_breakpoint(event->proc, sbp); 611 return; 612 } 613 } 614 615 if ((sbp = address2bpstruct(leader, event->e_un.brk_addr))) { 616 if (sbp->libsym == NULL) { 617 continue_after_breakpoint(event->proc, sbp); 618 return; 619 } 620 621 if (strcmp(sbp->libsym->name, "") == 0) { 622 debug(DEBUG_PROCESS, "Hit _dl_debug_state breakpoint!\n"); 623 arch_check_dbg(leader); 624 } 625 626 if (event->proc->state != STATE_IGNORED) { 627 event->proc->stack_pointer = get_stack_pointer(event->proc); 628 event->proc->return_addr = 629 get_return_addr(event->proc, event->proc->stack_pointer); 630 callstack_push_symfunc(event->proc, sbp->libsym); 631 output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name); 632 } 633#ifdef PLT_REINITALISATION_BP 634 if (event->proc->need_to_reinitialize_breakpoints 635 && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) == 636 0)) 637 reinitialize_breakpoints(leader); 638#endif 639 640 continue_after_breakpoint(event->proc, sbp); 641 return; 642 } 643 644 if (event->proc->state != STATE_IGNORED && !options.no_plt) { 645 output_line(event->proc, "unexpected breakpoint at %p", 646 (void *)event->e_un.brk_addr); 647 } 648 continue_process(event->proc->pid); 649} 650 651static void 652callstack_push_syscall(Process *proc, int sysnum) { 653 struct callstack_element *elem; 654 655 debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum); 656 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 657 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 658 fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__); 659 abort(); 660 return; 661 } 662 663 elem = &proc->callstack[proc->callstack_depth]; 664 elem->is_syscall = 1; 665 elem->c_un.syscall = sysnum; 666 elem->return_addr = NULL; 667 668 proc->callstack_depth++; 669 if (opt_T || options.summary) { 670 struct timezone tz; 671 gettimeofday(&elem->time_spent, &tz); 672 } 673} 674 675static void 676callstack_push_symfunc(Process *proc, struct library_symbol *sym) { 677 struct callstack_element *elem, *prev; 678 679 debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name); 680 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 681 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 682 fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__); 683 abort(); 684 return; 685 } 686 687 prev = &proc->callstack[proc->callstack_depth-1]; 688 elem = &proc->callstack[proc->callstack_depth]; 689 elem->is_syscall = 0; 690 elem->c_un.libfunc = sym; 691 692 elem->return_addr = proc->return_addr; 693 if (elem->return_addr) { 694 insert_breakpoint(proc, elem->return_addr, NULL, 1); 695 } 696 697 /* handle functions like atexit() on mips which have no return */ 698 if (elem->return_addr != prev->return_addr) 699 proc->callstack_depth++; 700 if (opt_T || options.summary) { 701 struct timezone tz; 702 gettimeofday(&elem->time_spent, &tz); 703 } 704} 705 706static void 707callstack_pop(Process *proc) { 708 struct callstack_element *elem; 709 assert(proc->callstack_depth > 0); 710 711 debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid); 712 elem = &proc->callstack[proc->callstack_depth - 1]; 713 if (!elem->is_syscall && elem->return_addr) { 714 assert(proc->leader != NULL); 715 delete_breakpoint(proc, elem->return_addr); 716 } 717 if (elem->arch_ptr != NULL) { 718 free(elem->arch_ptr); 719 elem->arch_ptr = NULL; 720 } 721 proc->callstack_depth--; 722} 723