handle_event.c revision 8e682c2763991227c1492cb17aa0744eb04bc0a0
1/* 2 * This file is part of ltrace. 3 * Copyright (C) 2011,2012,2013 Petr Machata, Red Hat Inc. 4 * Copyright (C) 2010 Arnaud Patard, Mandriva SA 5 * Copyright (C) 1998,2001,2002,2003,2004,2007,2008,2009 Juan Cespedes 6 * Copyright (C) 2008 Luis Machado, IBM Corporation 7 * Copyright (C) 2006 Ian Wienand 8 * Copyright (C) 2006 Paul Gilliam, IBM Corporation 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License as 12 * published by the Free Software Foundation; either version 2 of the 13 * License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 23 * 02110-1301 USA 24 */ 25 26#include "config.h" 27 28#define _GNU_SOURCE 29#include <assert.h> 30#include <errno.h> 31#include <signal.h> 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35#include <sys/time.h> 36 37#include "backend.h" 38#include "breakpoint.h" 39#include "common.h" 40#include "fetch.h" 41#include "library.h" 42#include "proc.h" 43#include "value_dict.h" 44 45static void handle_signal(Event *event); 46static void handle_exit(Event *event); 47static void handle_exit_signal(Event *event); 48static void handle_syscall(Event *event); 49static void handle_arch_syscall(Event *event); 50static void handle_sysret(Event *event); 51static void handle_arch_sysret(Event *event); 52static void handle_clone(Event *event); 53static void handle_exec(Event *event); 54static void handle_breakpoint(Event *event); 55static void handle_new(Event *event); 56 57static void callstack_push_syscall(struct process *proc, int sysnum); 58static void callstack_push_symfunc(struct process *proc, 59 struct library_symbol *sym); 60/* XXX Stack maintenance should be moved to a dedicated module, or to 61 * proc.c, and push/pop should be visible outside this module. For 62 * now, because we need this in proc.c, this is non-static. */ 63void callstack_pop(struct process *proc); 64 65static char *shortsignal(struct process *proc, int signum); 66static char *sysname(struct process *proc, int sysnum); 67static char *arch_sysname(struct process *proc, int sysnum); 68 69static Event * 70call_handler(struct process *proc, Event *event) 71{ 72 assert(proc != NULL); 73 74 struct event_handler *handler = proc->event_handler; 75 if (handler == NULL) 76 return event; 77 78 return (*handler->on_event) (handler, event); 79} 80 81void 82handle_event(Event *event) 83{ 84 if (exiting == 1) { 85 debug(1, "ltrace about to exit"); 86 os_ltrace_exiting(); 87 exiting = 2; 88 } 89 debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", 90 event->proc ? event->proc->pid : -1, event->type); 91 92 /* If the thread group or an individual task define an 93 overriding event handler, give them a chance to kick in. 94 We will end up calling both handlers, if the first one 95 doesn't sink the event. */ 96 if (event->proc != NULL) { 97 event = call_handler(event->proc, event); 98 if (event == NULL) 99 /* It was handled. */ 100 return; 101 102 /* Note: the previous handler has a chance to alter 103 * the event. */ 104 if (event->proc != NULL 105 && event->proc->leader != NULL 106 && event->proc != event->proc->leader) { 107 event = call_handler(event->proc->leader, event); 108 if (event == NULL) 109 return; 110 } 111 } 112 113 switch (event->type) { 114 case EVENT_NONE: 115 debug(1, "event: none"); 116 return; 117 118 case EVENT_SIGNAL: 119 assert(event->proc != NULL); 120 debug(1, "[%d] event: signal (%s [%d])", 121 event->proc->pid, 122 shortsignal(event->proc, event->e_un.signum), 123 event->e_un.signum); 124 handle_signal(event); 125 return; 126 127 case EVENT_EXIT: 128 assert(event->proc != NULL); 129 debug(1, "[%d] event: exit (%d)", 130 event->proc->pid, 131 event->e_un.ret_val); 132 handle_exit(event); 133 return; 134 135 case EVENT_EXIT_SIGNAL: 136 assert(event->proc != NULL); 137 debug(1, "[%d] event: exit signal (%s [%d])", 138 event->proc->pid, 139 shortsignal(event->proc, event->e_un.signum), 140 event->e_un.signum); 141 handle_exit_signal(event); 142 return; 143 144 case EVENT_SYSCALL: 145 assert(event->proc != NULL); 146 debug(1, "[%d] event: syscall (%s [%d])", 147 event->proc->pid, 148 sysname(event->proc, event->e_un.sysnum), 149 event->e_un.sysnum); 150 handle_syscall(event); 151 return; 152 153 case EVENT_SYSRET: 154 assert(event->proc != NULL); 155 debug(1, "[%d] event: sysret (%s [%d])", 156 event->proc->pid, 157 sysname(event->proc, event->e_un.sysnum), 158 event->e_un.sysnum); 159 handle_sysret(event); 160 return; 161 162 case EVENT_ARCH_SYSCALL: 163 assert(event->proc != NULL); 164 debug(1, "[%d] event: arch_syscall (%s [%d])", 165 event->proc->pid, 166 arch_sysname(event->proc, event->e_un.sysnum), 167 event->e_un.sysnum); 168 handle_arch_syscall(event); 169 return; 170 171 case EVENT_ARCH_SYSRET: 172 assert(event->proc != NULL); 173 debug(1, "[%d] event: arch_sysret (%s [%d])", 174 event->proc->pid, 175 arch_sysname(event->proc, event->e_un.sysnum), 176 event->e_un.sysnum); 177 handle_arch_sysret(event); 178 return; 179 180 case EVENT_CLONE: 181 case EVENT_VFORK: 182 assert(event->proc != NULL); 183 debug(1, "[%d] event: clone (%u)", 184 event->proc->pid, event->e_un.newpid); 185 handle_clone(event); 186 return; 187 188 case EVENT_EXEC: 189 assert(event->proc != NULL); 190 debug(1, "[%d] event: exec()", 191 event->proc->pid); 192 handle_exec(event); 193 return; 194 195 case EVENT_BREAKPOINT: 196 assert(event->proc != NULL); 197 debug(1, "[%d] event: breakpoint %p", 198 event->proc->pid, event->e_un.brk_addr); 199 handle_breakpoint(event); 200 return; 201 202 case EVENT_NEW: 203 debug(1, "[%d] event: new process", 204 event->e_un.newpid); 205 handle_new(event); 206 return; 207 default: 208 fprintf(stderr, "Error! unknown event?\n"); 209 exit(1); 210 } 211} 212 213typedef struct Pending_New Pending_New; 214struct Pending_New { 215 pid_t pid; 216 Pending_New * next; 217}; 218static Pending_New * pending_news = NULL; 219 220static int 221pending_new(pid_t pid) { 222 Pending_New * p; 223 224 debug(DEBUG_FUNCTION, "pending_new(%d)", pid); 225 226 p = pending_news; 227 while (p) { 228 if (p->pid == pid) { 229 return 1; 230 } 231 p = p->next; 232 } 233 return 0; 234} 235 236static void 237pending_new_insert(pid_t pid) { 238 Pending_New * p; 239 240 debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid); 241 242 p = malloc(sizeof(Pending_New)); 243 if (!p) { 244 perror("malloc()"); 245 exit(1); 246 } 247 p->pid = pid; 248 p->next = pending_news; 249 pending_news = p; 250} 251 252static void 253pending_new_remove(pid_t pid) { 254 Pending_New *p, *pred; 255 256 debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid); 257 258 p = pending_news; 259 pred = NULL; 260 if (p->pid == pid) { 261 pending_news = p->next; 262 free(p); 263 } else { 264 while (p) { 265 if (p->pid == pid) { 266 pred->next = p->next; 267 free(p); 268 } 269 pred = p; 270 p = p->next; 271 } 272 } 273} 274 275static void 276handle_clone(Event *event) 277{ 278 debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid); 279 280 struct process *proc = malloc(sizeof(*proc)); 281 pid_t newpid = event->e_un.newpid; 282 if (proc == NULL 283 || process_clone(proc, event->proc, newpid) < 0) { 284 free(proc); 285 proc = NULL; 286 fprintf(stderr, 287 "Couldn't initialize tracing of process %d.\n", 288 newpid); 289 290 } else { 291 proc->parent = event->proc; 292 /* We save register values to the arch pointer, and 293 * these need to be per-thread. XXX arch_ptr should 294 * be retired in favor of fetch interface anyway. */ 295 proc->arch_ptr = NULL; 296 } 297 298 if (pending_new(newpid)) { 299 pending_new_remove(newpid); 300 301 if (proc != NULL) { 302 proc->event_handler = NULL; 303 if (event->proc->state == STATE_ATTACHED 304 && options.follow) 305 proc->state = STATE_ATTACHED; 306 else 307 proc->state = STATE_IGNORED; 308 } 309 310 continue_process(newpid); 311 312 } else if (proc != NULL) { 313 proc->state = STATE_BEING_CREATED; 314 } 315 316 if (event->type != EVENT_VFORK) 317 continue_process(event->proc->pid); 318 else if (proc != NULL) 319 continue_after_vfork(proc); 320 else 321 continue_process(newpid); 322} 323 324static void 325handle_new(Event *event) 326{ 327 debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid); 328 329 struct process *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(struct process *proc, int signum) 345{ 346 static char *signalent0[] = { 347#include "signalent.h" 348 }; 349 static char *signalent1[] = { 350#include "signalent1.h" 351 }; 352 static char **signalents[] = { signalent0, signalent1 }; 353 int nsignals[] = { sizeof signalent0 / sizeof signalent0[0], 354 sizeof signalent1 / sizeof signalent1[0] 355 }; 356 357 debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum); 358 359 assert(proc->personality < sizeof signalents / sizeof signalents[0]); 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(struct process *proc, int sysnum) 369{ 370 static char result[128]; 371 static char *syscallent0[] = { 372#include "syscallent.h" 373 }; 374 static char *syscallent1[] = { 375#include "syscallent1.h" 376 }; 377 static char **syscallents[] = { syscallent0, syscallent1 }; 378 int nsyscalls[] = { 379 sizeof syscallent0 / sizeof syscallent0[0], 380 sizeof syscallent1 / sizeof syscallent1[0], 381 }; 382 383 debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); 384 385 assert(proc->personality < sizeof syscallents / sizeof syscallents[0]); 386 if (sysnum < 0 || sysnum >= nsyscalls[proc->personality]) { 387 sprintf(result, "SYS_%d", sysnum); 388 return result; 389 } else { 390 sprintf(result, "SYS_%s", 391 syscallents[proc->personality][sysnum]); 392 return result; 393 } 394} 395 396static char * 397arch_sysname(struct process *proc, int sysnum) 398{ 399 static char result[128]; 400 static char *arch_syscallent[] = { 401#include "arch_syscallent.h" 402 }; 403 int nsyscalls = sizeof arch_syscallent / sizeof arch_syscallent[0]; 404 405 debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); 406 407 if (sysnum < 0 || sysnum >= nsyscalls) { 408 sprintf(result, "ARCH_%d", sysnum); 409 return result; 410 } else { 411 sprintf(result, "ARCH_%s", arch_syscallent[sysnum]); 412 return result; 413 } 414} 415 416#ifndef HAVE_STRSIGNAL 417# define strsignal(SIGNUM) "???" 418#endif 419 420static void 421handle_signal(Event *event) { 422 debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); 423 if (event->proc->state != STATE_IGNORED && !options.no_signals) { 424 output_line(event->proc, "--- %s (%s) ---", 425 shortsignal(event->proc, event->e_un.signum), 426 strsignal(event->e_un.signum)); 427 } 428 continue_after_signal(event->proc->pid, event->e_un.signum); 429} 430 431static void 432handle_exit(Event *event) { 433 debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val); 434 if (event->proc->state != STATE_IGNORED) { 435 output_line(event->proc, "+++ exited (status %d) +++", 436 event->e_un.ret_val); 437 } 438 remove_process(event->proc); 439} 440 441static void 442handle_exit_signal(Event *event) { 443 debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); 444 if (event->proc->state != STATE_IGNORED) { 445 output_line(event->proc, "+++ killed by %s +++", 446 shortsignal(event->proc, event->e_un.signum)); 447 } 448 remove_process(event->proc); 449} 450 451static void 452output_syscall(struct process *proc, const char *name, enum tof tof, 453 void (*output)(enum tof, struct process *, 454 struct library_symbol *)) 455{ 456 struct library_symbol syscall; 457 if (library_symbol_init(&syscall, 0, name, 0, LS_TOPLT_NONE) >= 0) { 458 (*output)(tof, proc, &syscall); 459 library_symbol_destroy(&syscall); 460 } 461} 462 463static void 464output_syscall_left(struct process *proc, const char *name) 465{ 466 output_syscall(proc, name, LT_TOF_SYSCALL, &output_left); 467} 468 469static void 470output_syscall_right(struct process *proc, const char *name) 471{ 472 output_syscall(proc, name, LT_TOF_SYSCALLR, &output_right); 473} 474 475static void 476handle_syscall(Event *event) { 477 debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 478 if (event->proc->state != STATE_IGNORED) { 479 callstack_push_syscall(event->proc, event->e_un.sysnum); 480 if (options.syscalls) 481 output_syscall_left(event->proc, 482 sysname(event->proc, 483 event->e_un.sysnum)); 484 } 485 continue_after_syscall(event->proc, event->e_un.sysnum, 0); 486} 487 488static void 489handle_exec(Event *event) 490{ 491 struct process *proc = event->proc; 492 493 /* Save the PID so that we can use it after unsuccessful 494 * process_exec. */ 495 pid_t pid = proc->pid; 496 497 debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid); 498 if (proc->state == STATE_IGNORED) { 499 untrace: 500 untrace_pid(pid); 501 remove_process(proc); 502 return; 503 } 504 output_line(proc, "--- Called exec() ---"); 505 506 if (process_exec(proc) < 0) { 507 fprintf(stderr, 508 "couldn't reinitialize process %d after exec\n", pid); 509 goto untrace; 510 } 511 512 continue_after_exec(proc); 513} 514 515static void 516handle_arch_syscall(Event *event) { 517 debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 518 if (event->proc->state != STATE_IGNORED) { 519 callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum); 520 if (options.syscalls) { 521 output_syscall_left(event->proc, 522 arch_sysname(event->proc, 523 event->e_un.sysnum)); 524 } 525 } 526 continue_process(event->proc->pid); 527} 528 529struct timeval current_time_spent; 530 531static void 532calc_time_spent(struct process *proc) 533{ 534 struct timeval tv; 535 struct timezone tz; 536 struct timeval diff; 537 struct callstack_element *elem; 538 539 debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid); 540 elem = &proc->callstack[proc->callstack_depth - 1]; 541 542 gettimeofday(&tv, &tz); 543 544 diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec; 545 if (tv.tv_usec >= elem->time_spent.tv_usec) { 546 diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec; 547 } else { 548 diff.tv_sec--; 549 diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec; 550 } 551 current_time_spent = diff; 552} 553 554static void 555handle_sysret(Event *event) { 556 debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 557 if (event->proc->state != STATE_IGNORED) { 558 if (opt_T || options.summary) { 559 calc_time_spent(event->proc); 560 } 561 if (options.syscalls) 562 output_syscall_right(event->proc, 563 sysname(event->proc, 564 event->e_un.sysnum)); 565 566 assert(event->proc->callstack_depth > 0); 567 unsigned d = event->proc->callstack_depth - 1; 568 assert(event->proc->callstack[d].is_syscall); 569 callstack_pop(event->proc); 570 } 571 continue_after_syscall(event->proc, event->e_un.sysnum, 1); 572} 573 574static void 575handle_arch_sysret(Event *event) { 576 debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 577 if (event->proc->state != STATE_IGNORED) { 578 if (opt_T || options.summary) { 579 calc_time_spent(event->proc); 580 } 581 if (options.syscalls) 582 output_syscall_right(event->proc, 583 arch_sysname(event->proc, 584 event->e_un.sysnum)); 585 callstack_pop(event->proc); 586 } 587 continue_process(event->proc->pid); 588} 589 590static void 591output_right_tos(struct process *proc) 592{ 593 size_t d = proc->callstack_depth; 594 struct callstack_element *elem = &proc->callstack[d - 1]; 595 if (proc->state != STATE_IGNORED) 596 output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc); 597} 598 599#ifndef ARCH_HAVE_SYMBOL_RET 600void arch_symbol_ret(struct process *proc, struct library_symbol *libsym) 601{ 602} 603#endif 604 605static void 606handle_breakpoint(Event *event) 607{ 608 int i, j; 609 struct breakpoint *sbp; 610 struct process *leader = event->proc->leader; 611 void *brk_addr = event->e_un.brk_addr; 612 613 /* The leader has terminated. */ 614 if (leader == NULL) { 615 continue_process(event->proc->pid); 616 return; 617 } 618 619 debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", 620 event->proc->pid, brk_addr); 621 debug(2, "event: breakpoint (%p)", brk_addr); 622 623 for (i = event->proc->callstack_depth - 1; i >= 0; i--) { 624 if (brk_addr == event->proc->callstack[i].return_addr) { 625 for (j = event->proc->callstack_depth - 1; j > i; j--) { 626 callstack_pop(event->proc); 627 } 628 if (event->proc->state != STATE_IGNORED) { 629 if (opt_T || options.summary) { 630 calc_time_spent(event->proc); 631 } 632 } 633 event->proc->return_addr = brk_addr; 634 635 struct library_symbol *libsym = 636 event->proc->callstack[i].c_un.libfunc; 637 638 arch_symbol_ret(event->proc, libsym); 639 output_right_tos(event->proc); 640 callstack_pop(event->proc); 641 642 /* Pop also any other entries that seem like 643 * they are linked to the current one: they 644 * have the same return address, but were made 645 * for different symbols. This should only 646 * happen for entry point tracing, i.e. for -x 647 * everywhere, or -x and -e on MIPS. */ 648 while (event->proc->callstack_depth > 0) { 649 struct callstack_element *prev; 650 size_t d = event->proc->callstack_depth; 651 prev = &event->proc->callstack[d - 1]; 652 653 if (prev->c_un.libfunc == libsym 654 || prev->return_addr != brk_addr) 655 break; 656 657 arch_symbol_ret(event->proc, 658 prev->c_un.libfunc); 659 output_right_tos(event->proc); 660 callstack_pop(event->proc); 661 } 662 663 /* Maybe the previous callstack_pop's got rid 664 * of the breakpoint, but if we are in a 665 * recursive call, it's still enabled. In 666 * that case we need to skip it properly. */ 667 if ((sbp = address2bpstruct(leader, brk_addr)) != NULL) { 668 continue_after_breakpoint(event->proc, sbp); 669 } else { 670 set_instruction_pointer(event->proc, brk_addr); 671 continue_process(event->proc->pid); 672 } 673 return; 674 } 675 } 676 677 if ((sbp = address2bpstruct(leader, brk_addr)) != NULL) 678 breakpoint_on_hit(sbp, event->proc); 679 else if (event->proc->state != STATE_IGNORED) 680 output_line(event->proc, 681 "unexpected breakpoint at %p", brk_addr); 682 683 /* breakpoint_on_hit may delete its own breakpoint, so we have 684 * to look it up again. */ 685 if ((sbp = address2bpstruct(leader, brk_addr)) != NULL) { 686 if (event->proc->state != STATE_IGNORED 687 && sbp->libsym != NULL) { 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); 693 } 694 695 breakpoint_on_continue(sbp, event->proc); 696 return; 697 } else { 698 set_instruction_pointer(event->proc, brk_addr); 699 } 700 701 continue_process(event->proc->pid); 702} 703 704static void 705callstack_push_syscall(struct process *proc, int sysnum) 706{ 707 struct callstack_element *elem; 708 709 debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum); 710 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 711 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 712 fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__); 713 abort(); 714 return; 715 } 716 717 elem = &proc->callstack[proc->callstack_depth]; 718 *elem = (struct callstack_element){}; 719 elem->is_syscall = 1; 720 elem->c_un.syscall = sysnum; 721 elem->return_addr = NULL; 722 723 proc->callstack_depth++; 724 if (opt_T || options.summary) { 725 struct timezone tz; 726 gettimeofday(&elem->time_spent, &tz); 727 } 728} 729 730static void 731callstack_push_symfunc(struct process *proc, struct library_symbol *sym) 732{ 733 struct callstack_element *elem; 734 735 debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name); 736 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 737 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 738 fprintf(stderr, "%s: Error: call nesting too deep!\n", __func__); 739 abort(); 740 return; 741 } 742 743 elem = &proc->callstack[proc->callstack_depth++]; 744 *elem = (struct callstack_element){}; 745 elem->is_syscall = 0; 746 elem->c_un.libfunc = sym; 747 748 elem->return_addr = proc->return_addr; 749 if (elem->return_addr) 750 insert_breakpoint(proc, elem->return_addr, NULL); 751 752 if (opt_T || options.summary) { 753 struct timezone tz; 754 gettimeofday(&elem->time_spent, &tz); 755 } 756} 757 758void 759callstack_pop(struct process *proc) 760{ 761 struct callstack_element *elem; 762 assert(proc->callstack_depth > 0); 763 764 debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid); 765 elem = &proc->callstack[proc->callstack_depth - 1]; 766 if (!elem->is_syscall && elem->return_addr) 767 delete_breakpoint(proc, elem->return_addr); 768 769 if (elem->fetch_context != NULL) 770 fetch_arg_done(elem->fetch_context); 771 772 if (elem->arguments != NULL) { 773 val_dict_destroy(elem->arguments); 774 free(elem->arguments); 775 } 776 777 proc->callstack_depth--; 778} 779