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