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