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