handle_event.c revision 03192f890af95bf9abf5ea1c3dc0998f6b12550d
1#if HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#define _GNU_SOURCE 6#include <stdio.h> 7#include <string.h> 8#include <stdlib.h> 9#include <signal.h> 10#include <assert.h> 11#include <sys/time.h> 12 13#include "common.h" 14#include "output.h" 15#include "options.h" 16#include "elf.h" 17#include "debug.h" 18 19#ifdef __powerpc__ 20#include <sys/ptrace.h> 21#endif 22 23static void handle_signal(Event *event); 24static void handle_exit(Event *event); 25static void handle_exit_signal(Event *event); 26static void handle_syscall(Event *event); 27static void handle_arch_syscall(Event *event); 28static void handle_sysret(Event *event); 29static void handle_arch_sysret(Event *event); 30static void handle_clone(Event *event); 31static void handle_exec(Event *event); 32static void handle_breakpoint(Event *event); 33static void handle_new(Event *event); 34static void remove_proc(Process *proc); 35 36static void callstack_push_syscall(Process *proc, int sysnum); 37static void callstack_push_symfunc(Process *proc, 38 struct library_symbol *sym); 39static void callstack_pop(Process *proc); 40 41/* TODO */ 42void * address_clone(void * addr) { 43 debug(DEBUG_FUNCTION, "address_clone(%p)", addr); 44 return addr; 45} 46 47void * breakpoint_clone(void * bp) { 48 Breakpoint * b; 49 debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp); 50 b = malloc(sizeof(Breakpoint)); 51 if (!b) { 52 perror("malloc()"); 53 exit(1); 54 } 55 memcpy(b, bp, sizeof(Breakpoint)); 56 return b; 57} 58 59typedef struct Pending_New Pending_New; 60struct Pending_New { 61 pid_t pid; 62 Pending_New * next; 63}; 64static Pending_New * pending_news = NULL; 65 66static int 67pending_new(pid_t pid) { 68 Pending_New * p; 69 70 debug(DEBUG_FUNCTION, "pending_new(%d)", pid); 71 72 p = pending_news; 73 while (p) { 74 if (p->pid == pid) { 75 return 1; 76 } 77 p = p->next; 78 } 79 return 0; 80} 81 82static void 83pending_new_insert(pid_t pid) { 84 Pending_New * p; 85 86 debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid); 87 88 p = malloc(sizeof(Pending_New)); 89 if (!p) { 90 perror("malloc()"); 91 exit(1); 92 } 93 p->pid = pid; 94 p->next = pending_news; 95 pending_news = p; 96} 97 98static void 99pending_new_remove(pid_t pid) { 100 Pending_New *p, *pred; 101 102 debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid); 103 104 p = pending_news; 105 if (p->pid == pid) { 106 pending_news = p->next; 107 free(p); 108 } else { 109 while (p) { 110 if (p->pid == pid) { 111 pred->next = p->next; 112 free(p); 113 } 114 pred = p; 115 p = p->next; 116 } 117 } 118} 119 120static void 121handle_clone(Event * event) { 122 Process *p; 123 124 debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid); 125 126 p = malloc(sizeof(Process)); 127 if (!p) { 128 perror("malloc()"); 129 exit(1); 130 } 131 memcpy(p, event->proc, sizeof(Process)); 132 p->breakpoints = dict_clone(event->proc->breakpoints, address_clone, breakpoint_clone); 133 p->pid = event->e_un.newpid; 134 p->parent = event->proc; 135 136 if (pending_new(p->pid)) { 137 pending_new_remove(p->pid); 138 if (p->breakpoint_being_enabled) { 139 enable_breakpoint(p->pid, p->breakpoint_being_enabled); 140 p->breakpoint_being_enabled = NULL; 141 } 142 if (event->proc->state == STATE_ATTACHED && options.follow) { 143 p->state = STATE_ATTACHED; 144 } else { 145 p->state = STATE_IGNORED; 146 } 147 continue_process(p->pid); 148 p->next = list_of_processes; 149 list_of_processes = p; 150 } else { 151 p->state = STATE_BEING_CREATED; 152 p->next = list_of_processes; 153 list_of_processes = p; 154 } 155 continue_process(event->proc->pid); 156} 157 158static void 159handle_new(Event * event) { 160 Process * proc; 161 162 debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid); 163 164 proc = pid2proc(event->e_un.newpid); 165 if (!proc) { 166 pending_new_insert(event->e_un.newpid); 167 } else { 168 assert(proc->state == STATE_BEING_CREATED); 169 if (proc->breakpoint_being_enabled) { 170 enable_breakpoint(proc->pid, proc->breakpoint_being_enabled); 171 proc->breakpoint_being_enabled = NULL; 172 } 173 if (options.follow) { 174 proc->state = STATE_ATTACHED; 175 } else { 176 proc->state = STATE_IGNORED; 177 } 178 continue_process(proc->pid); 179 } 180} 181 182static char * 183shortsignal(Process *proc, int signum) { 184 static char *signalent0[] = { 185#include "signalent.h" 186 }; 187 static char *signalent1[] = { 188#include "signalent1.h" 189 }; 190 static char **signalents[] = { signalent0, signalent1 }; 191 int nsignals[] = { sizeof signalent0 / sizeof signalent0[0], 192 sizeof signalent1 / sizeof signalent1[0] 193 }; 194 195 debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum); 196 197 if (proc->personality > sizeof signalents / sizeof signalents[0]) 198 abort(); 199 if (signum < 0 || signum >= nsignals[proc->personality]) { 200 return "UNKNOWN_SIGNAL"; 201 } else { 202 return signalents[proc->personality][signum]; 203 } 204} 205 206static char * 207sysname(Process *proc, int sysnum) { 208 static char result[128]; 209 static char *syscalent0[] = { 210#include "syscallent.h" 211 }; 212 static char *syscalent1[] = { 213#include "syscallent1.h" 214 }; 215 static char **syscalents[] = { syscalent0, syscalent1 }; 216 int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0], 217 sizeof syscalent1 / sizeof syscalent1[0] 218 }; 219 220 debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); 221 222 if (proc->personality > sizeof syscalents / sizeof syscalents[0]) 223 abort(); 224 if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) { 225 sprintf(result, "SYS_%d", sysnum); 226 return result; 227 } else { 228 sprintf(result, "SYS_%s", 229 syscalents[proc->personality][sysnum]); 230 return result; 231 } 232} 233 234static char * 235arch_sysname(Process *proc, int sysnum) { 236 static char result[128]; 237 static char *arch_syscalent[] = { 238#include "arch_syscallent.h" 239 }; 240 int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0]; 241 242 debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); 243 244 if (sysnum < 0 || sysnum >= nsyscals) { 245 sprintf(result, "ARCH_%d", sysnum); 246 return result; 247 } else { 248 sprintf(result, "ARCH_%s", 249 arch_syscalent[sysnum]); 250 return result; 251 } 252} 253 254void 255handle_event(Event *event) { 256 debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type); 257 switch (event->type) { 258 case EVENT_NONE: 259 debug(1, "event: none"); 260 return; 261 case EVENT_SIGNAL: 262 debug(1, "event: signal (%s [%d])", 263 shortsignal(event->proc, event->e_un.signum), 264 event->e_un.signum); 265 handle_signal(event); 266 return; 267 case EVENT_EXIT: 268 debug(1, "event: exit (%d)", event->e_un.ret_val); 269 handle_exit(event); 270 return; 271 case EVENT_EXIT_SIGNAL: 272 debug(1, "event: exit signal (%s [%d])", 273 shortsignal(event->proc, event->e_un.signum), 274 event->e_un.signum); 275 handle_exit_signal(event); 276 return; 277 case EVENT_SYSCALL: 278 debug(1, "event: syscall (%s [%d])", 279 sysname(event->proc, event->e_un.sysnum), 280 event->e_un.sysnum); 281 handle_syscall(event); 282 return; 283 case EVENT_SYSRET: 284 debug(1, "event: sysret (%s [%d])", 285 sysname(event->proc, event->e_un.sysnum), 286 event->e_un.sysnum); 287 handle_sysret(event); 288 return; 289 case EVENT_ARCH_SYSCALL: 290 debug(1, "event: arch_syscall (%s [%d])", 291 arch_sysname(event->proc, event->e_un.sysnum), 292 event->e_un.sysnum); 293 handle_arch_syscall(event); 294 return; 295 case EVENT_ARCH_SYSRET: 296 debug(1, "event: arch_sysret (%s [%d])", 297 arch_sysname(event->proc, event->e_un.sysnum), 298 event->e_un.sysnum); 299 handle_arch_sysret(event); 300 return; 301 case EVENT_CLONE: 302 debug(1, "event: clone (%u)", event->e_un.newpid); 303 handle_clone(event); 304 return; 305 case EVENT_EXEC: 306 debug(1, "event: exec()"); 307 handle_exec(event); 308 return; 309 case EVENT_BREAKPOINT: 310 debug(1, "event: breakpoint"); 311 handle_breakpoint(event); 312 return; 313 case EVENT_NEW: 314 debug(1, "event: new process"); 315 handle_new(event); 316 return; 317 default: 318 fprintf(stderr, "Error! unknown event?\n"); 319 exit(1); 320 } 321} 322 323static void 324handle_signal(Event *event) { 325 debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); 326 if (exiting && event->e_un.signum == SIGSTOP) { 327 pid_t pid = event->proc->pid; 328 disable_all_breakpoints(event->proc); 329 untrace_pid(pid); 330 remove_proc(event->proc); 331 return; 332 } 333 if (event->proc->state != STATE_IGNORED) { 334 output_line(event->proc, "--- %s (%s) ---", 335 shortsignal(event->proc, event->e_un.signum), 336 strsignal(event->e_un.signum)); 337 } 338 continue_after_signal(event->proc->pid, event->e_un.signum); 339} 340 341static void 342handle_exit(Event *event) { 343 debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val); 344 if (event->proc->state != STATE_IGNORED) { 345 output_line(event->proc, "+++ exited (status %d) +++", 346 event->e_un.ret_val); 347 } 348 remove_proc(event->proc); 349} 350 351static void 352handle_exit_signal(Event *event) { 353 debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); 354 if (event->proc->state != STATE_IGNORED) { 355 output_line(event->proc, "+++ killed by %s +++", 356 shortsignal(event->proc, event->e_un.signum)); 357 } 358 remove_proc(event->proc); 359} 360 361static void 362remove_proc(Process *proc) { 363 Process *tmp, *tmp2; 364 365 debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid); 366 367 if (list_of_processes == proc) { 368 tmp = list_of_processes; 369 list_of_processes = list_of_processes->next; 370 free(tmp); 371 return; 372 } 373 tmp = list_of_processes; 374 while (tmp->next) { 375 if (tmp->next == proc) { 376 tmp2 = tmp->next; 377 tmp->next = tmp->next->next; 378 free(tmp2); 379 continue; 380 } 381 tmp = tmp->next; 382 } 383} 384 385static void 386handle_syscall(Event *event) { 387 debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 388 if (event->proc->state != STATE_IGNORED) { 389 if (options.syscalls) { 390 output_left(LT_TOF_SYSCALL, event->proc, 391 sysname(event->proc, event->e_un.sysnum)); 392 } 393 if (event->proc->breakpoints_enabled == 0) { 394 enable_all_breakpoints(event->proc); 395 } 396 callstack_push_syscall(event->proc, event->e_un.sysnum); 397 } 398 continue_process(event->proc->pid); 399} 400 401static void 402handle_exec(Event * event) { 403 Process * proc = event->proc; 404 pid_t saved_pid; 405 406 debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid); 407 if (proc->state == STATE_IGNORED) { 408 untrace_pid(proc->pid); 409 remove_proc(proc); 410 return; 411 } 412 output_line(proc, "--- Called exec() ---"); 413 proc->mask_32bit = 0; 414 proc->personality = 0; 415 proc->arch_ptr = NULL; 416 free(proc->filename); 417 proc->filename = pid2name(proc->pid); 418 saved_pid = proc->pid; 419 proc->pid = 0; 420 breakpoints_init(proc); 421 proc->pid = saved_pid; 422 proc->callstack_depth = 0; 423 continue_process(proc->pid); 424} 425 426static void 427handle_arch_syscall(Event *event) { 428 debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 429 if (event->proc->state != STATE_IGNORED) { 430 if (options.syscalls) { 431 output_left(LT_TOF_SYSCALL, event->proc, 432 arch_sysname(event->proc, event->e_un.sysnum)); 433 } 434 if (event->proc->breakpoints_enabled == 0) { 435 enable_all_breakpoints(event->proc); 436 } 437 callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum); 438 } 439 continue_process(event->proc->pid); 440} 441 442struct timeval current_time_spent; 443 444static void 445calc_time_spent(Process *proc) { 446 struct timeval tv; 447 struct timezone tz; 448 struct timeval diff; 449 struct callstack_element *elem; 450 451 debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid); 452 elem = &proc->callstack[proc->callstack_depth - 1]; 453 454 gettimeofday(&tv, &tz); 455 456 diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec; 457 if (tv.tv_usec >= elem->time_spent.tv_usec) { 458 diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec; 459 } else { 460 diff.tv_sec++; 461 diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec; 462 } 463 current_time_spent = diff; 464} 465 466static void 467handle_sysret(Event *event) { 468 debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 469 if (event->proc->state != STATE_IGNORED) { 470 if (opt_T || options.summary) { 471 calc_time_spent(event->proc); 472 } 473 callstack_pop(event->proc); 474 if (options.syscalls) { 475 output_right(LT_TOF_SYSCALLR, event->proc, 476 sysname(event->proc, event->e_un.sysnum)); 477 } 478 } 479 continue_process(event->proc->pid); 480} 481 482static void 483handle_arch_sysret(Event *event) { 484 debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); 485 if (event->proc->state != STATE_IGNORED) { 486 if (opt_T || options.summary) { 487 calc_time_spent(event->proc); 488 } 489 callstack_pop(event->proc); 490 if (options.syscalls) { 491 output_right(LT_TOF_SYSCALLR, event->proc, 492 arch_sysname(event->proc, event->e_un.sysnum)); 493 } 494 } 495 continue_process(event->proc->pid); 496} 497 498static void 499handle_breakpoint(Event *event) { 500 int i, j; 501 Breakpoint *sbp; 502 503 debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr); 504 debug(2, "event: breakpoint (%p)", event->e_un.brk_addr); 505 506#ifdef __powerpc__ 507 /* Need to skip following NOP's to prevent a fake function from being stacked. */ 508 long stub_addr = (long) get_count_register(event->proc); 509 Breakpoint *stub_bp = NULL; 510 char nop_instruction[] = PPC_NOP; 511 512 stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr); 513 514 if (stub_bp) { 515 unsigned char *bp_instruction = stub_bp->orig_value; 516 517 if (memcmp(bp_instruction, nop_instruction, 518 PPC_NOP_LENGTH) == 0) { 519 if (stub_addr != (long) event->e_un.brk_addr) { 520 set_instruction_pointer (event->proc, event->e_un.brk_addr + 4); 521 continue_process(event->proc->pid); 522 return; 523 } 524 } 525 } 526#endif 527 if ((sbp = event->proc->breakpoint_being_enabled) != 0) { 528 /* Reinsert breakpoint */ 529 continue_enabling_breakpoint(event->proc->pid, 530 event->proc-> 531 breakpoint_being_enabled); 532 event->proc->breakpoint_being_enabled = NULL; 533 return; 534 } 535 536 for (i = event->proc->callstack_depth - 1; i >= 0; i--) { 537 if (event->e_un.brk_addr == 538 event->proc->callstack[i].return_addr) { 539#ifdef __powerpc__ 540 /* 541 * PPC HACK! (XXX FIXME TODO) 542 * The PLT gets modified during the first call, 543 * so be sure to re-enable the breakpoint. 544 */ 545 unsigned long a; 546 struct library_symbol *libsym = 547 event->proc->callstack[i].c_un.libfunc; 548 void *addr = sym2addr(event->proc, libsym); 549 550 if (libsym->plt_type != LS_TOPLT_POINT) { 551 unsigned char break_insn[] = BREAKPOINT_VALUE; 552 553 sbp = address2bpstruct(event->proc, addr); 554 assert(sbp); 555 a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, 556 addr); 557 558 if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) { 559 sbp->enabled--; 560 insert_breakpoint(event->proc, addr, 561 libsym); 562 } 563 } else { 564 sbp = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, libsym)); 565 assert(sbp); 566 if (addr != sbp->addr) { 567 insert_breakpoint(event->proc, addr, 568 libsym); 569 } 570 } 571#elif defined(__mips__) 572 void *addr; 573 void *old_addr; 574 struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc; 575 assert(sym); 576 old_addr = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, sym))->addr; 577 addr=sym2addr(event->proc,sym); 578 assert(old_addr !=0 && addr !=0); 579 if(addr != old_addr){ 580 struct library_symbol *new_sym; 581 new_sym=malloc(sizeof(*new_sym)); 582 memcpy(new_sym,sym,sizeof(*new_sym)); 583 new_sym->next=event->proc->list_of_symbols; 584 event->proc->list_of_symbols=new_sym; 585 insert_breakpoint(event->proc, addr, new_sym); 586 } 587#endif 588 for (j = event->proc->callstack_depth - 1; j > i; j--) { 589 callstack_pop(event->proc); 590 } 591 if (event->proc->state != STATE_IGNORED) { 592 if (opt_T || options.summary) { 593 calc_time_spent(event->proc); 594 } 595 } 596 callstack_pop(event->proc); 597 event->proc->return_addr = event->e_un.brk_addr; 598 if (event->proc->state != STATE_IGNORED) { 599 output_right(LT_TOF_FUNCTIONR, event->proc, 600 event->proc->callstack[i].c_un.libfunc->name); 601 } 602 continue_after_breakpoint(event->proc, 603 address2bpstruct(event->proc, 604 event->e_un.brk_addr)); 605 return; 606 } 607 } 608 609 if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) { 610 if (event->proc->state != STATE_IGNORED) { 611 event->proc->stack_pointer = get_stack_pointer(event->proc); 612 event->proc->return_addr = 613 get_return_addr(event->proc, event->proc->stack_pointer); 614 output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name); 615 callstack_push_symfunc(event->proc, sbp->libsym); 616 } 617#ifdef PLT_REINITALISATION_BP 618 if (event->proc->need_to_reinitialize_breakpoints 619 && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) == 620 0)) 621 reinitialize_breakpoints(event->proc); 622#endif 623 624 continue_after_breakpoint(event->proc, sbp); 625 return; 626 } 627 628 if (event->proc->state != STATE_IGNORED) { 629 output_line(event->proc, "unexpected breakpoint at %p", 630 (void *)event->e_un.brk_addr); 631 } 632 continue_process(event->proc->pid); 633} 634 635static void 636callstack_push_syscall(Process *proc, int sysnum) { 637 struct callstack_element *elem; 638 639 debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum); 640 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 641 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 642 fprintf(stderr, "Error: call nesting too deep!\n"); 643 return; 644 } 645 646 elem = &proc->callstack[proc->callstack_depth]; 647 elem->is_syscall = 1; 648 elem->c_un.syscall = sysnum; 649 elem->return_addr = NULL; 650 651 proc->callstack_depth++; 652 if (opt_T || options.summary) { 653 struct timezone tz; 654 gettimeofday(&elem->time_spent, &tz); 655 } 656} 657 658static void 659callstack_push_symfunc(Process *proc, struct library_symbol *sym) { 660 struct callstack_element *elem; 661 662 debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name); 663 /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ 664 if (proc->callstack_depth == MAX_CALLDEPTH - 1) { 665 fprintf(stderr, "Error: call nesting too deep!\n"); 666 return; 667 } 668 669 elem = &proc->callstack[proc->callstack_depth]; 670 elem->is_syscall = 0; 671 elem->c_un.libfunc = sym; 672 673 elem->return_addr = proc->return_addr; 674 if (elem->return_addr) { 675 insert_breakpoint(proc, elem->return_addr, 0); 676 } 677 678 proc->callstack_depth++; 679 if (opt_T || options.summary) { 680 struct timezone tz; 681 gettimeofday(&elem->time_spent, &tz); 682 } 683} 684 685static void 686callstack_pop(Process *proc) { 687 struct callstack_element *elem; 688 assert(proc->callstack_depth > 0); 689 690 debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid); 691 elem = &proc->callstack[proc->callstack_depth - 1]; 692 if (!elem->is_syscall && elem->return_addr) { 693 delete_breakpoint(proc, elem->return_addr); 694 } 695 proc->callstack_depth--; 696} 697