handle_event.c revision f789c9c0d1f3301afad66e5f0520b9093665f242
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, 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, 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 sbp = event->proc->breakpoint_being_enabled; 535 continue_enabling_breakpoint(event->proc, sbp); 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 = leader->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(DEBUG_PROCESS, "Hit _dl_debug_state breakpoint!\n"); 622 arch_check_dbg(event->proc); 623 } 624 if (event->proc->state != STATE_IGNORED) { 625 event->proc->stack_pointer = get_stack_pointer(event->proc); 626 event->proc->return_addr = 627 get_return_addr(event->proc, event->proc->stack_pointer); 628 callstack_push_symfunc(event->proc, sbp->libsym); 629 output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name); 630 } 631#ifdef PLT_REINITALISATION_BP 632 if (event->proc->need_to_reinitialize_breakpoints 633 && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) == 634 0)) 635 reinitialize_breakpoints(event->proc); 636#endif 637 638 continue_after_breakpoint(event->proc, sbp); 639 return; 640 } 641 642 if (event->proc->state != STATE_IGNORED && !options.no_plt) { 643 output_line(event->proc, "unexpected breakpoint at %p", 644 (void *)event->e_un.brk_addr); 645 } 646 continue_process(event->proc->pid); 647} 648 649static void 650callstack_push_syscall(Process *proc, int sysnum) { 651 struct callstack_element *elem; 652 653 debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum); 654 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 655 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 656 fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__); 657 abort(); 658 return; 659 } 660 661 elem = &proc->callstack[proc->callstack_depth]; 662 elem->is_syscall = 1; 663 elem->c_un.syscall = sysnum; 664 elem->return_addr = NULL; 665 666 proc->callstack_depth++; 667 if (opt_T || options.summary) { 668 struct timezone tz; 669 gettimeofday(&elem->time_spent, &tz); 670 } 671} 672 673static void 674callstack_push_symfunc(Process *proc, struct library_symbol *sym) { 675 struct callstack_element *elem, *prev; 676 677 debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name); 678 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 679 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 680 fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__); 681 abort(); 682 return; 683 } 684 685 prev = &proc->callstack[proc->callstack_depth-1]; 686 elem = &proc->callstack[proc->callstack_depth]; 687 elem->is_syscall = 0; 688 elem->c_un.libfunc = sym; 689 690 elem->return_addr = proc->return_addr; 691 if (elem->return_addr) { 692 insert_breakpoint(proc, elem->return_addr, NULL); 693 } 694 695 /* handle functions like atexit() on mips which have no return */ 696 if (elem->return_addr != prev->return_addr) 697 proc->callstack_depth++; 698 if (opt_T || options.summary) { 699 struct timezone tz; 700 gettimeofday(&elem->time_spent, &tz); 701 } 702} 703 704static void 705callstack_pop(Process *proc) { 706 struct callstack_element *elem; 707 assert(proc->callstack_depth > 0); 708 709 debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid); 710 elem = &proc->callstack[proc->callstack_depth - 1]; 711 if (!elem->is_syscall && elem->return_addr) { 712 delete_breakpoint(proc, elem->return_addr); 713 } 714 if (elem->arch_ptr != NULL) { 715 free(elem->arch_ptr); 716 elem->arch_ptr = NULL; 717 } 718 proc->callstack_depth--; 719} 720