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