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