1 /*- 2 * Copyright 1997 Sean Eric Fagan 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Sean Eric Fagan 15 * 4. Neither the name of the author may be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 /* 36 * Various setup functions for truss. Not the cleanest-written code, 37 * I'm afraid. 38 */ 39 40 #include <sys/ptrace.h> 41 #include <sys/sysctl.h> 42 #include <sys/wait.h> 43 44 #include <assert.h> 45 #include <err.h> 46 #include <errno.h> 47 #include <signal.h> 48 #include <stdint.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <sysdecode.h> 53 #include <time.h> 54 #include <unistd.h> 55 56 #include "truss.h" 57 #include "syscall.h" 58 #include "extern.h" 59 60 SET_DECLARE(procabi, struct procabi); 61 62 static sig_atomic_t detaching; 63 64 static void enter_syscall(struct trussinfo *, struct threadinfo *, 65 struct ptrace_lwpinfo *); 66 static void new_proc(struct trussinfo *, pid_t, lwpid_t); 67 68 /* 69 * setup_and_wait() is called to start a process. All it really does 70 * is fork(), enable tracing in the child, and then exec the given 71 * command. At that point, the child process stops, and the parent 72 * can wake up and deal with it. 73 */ 74 void 75 setup_and_wait(struct trussinfo *info, char *command[]) 76 { 77 pid_t pid; 78 79 pid = vfork(); 80 if (pid == -1) 81 err(1, "fork failed"); 82 if (pid == 0) { /* Child */ 83 ptrace(PT_TRACE_ME, 0, 0, 0); 84 execvp(command[0], command); 85 err(1, "execvp %s", command[0]); 86 } 87 88 /* Only in the parent here */ 89 if (waitpid(pid, NULL, 0) < 0) 90 err(1, "unexpect stop in waitpid"); 91 92 new_proc(info, pid, 0); 93 } 94 95 /* 96 * start_tracing is called to attach to an existing process. 97 */ 98 void 99 start_tracing(struct trussinfo *info, pid_t pid) 100 { 101 int ret, retry; 102 103 retry = 10; 104 do { 105 ret = ptrace(PT_ATTACH, pid, NULL, 0); 106 usleep(200); 107 } while (ret && retry-- > 0); 108 if (ret) 109 err(1, "can not attach to target process"); 110 111 if (waitpid(pid, NULL, 0) < 0) 112 err(1, "Unexpect stop in waitpid"); 113 114 new_proc(info, pid, 0); 115 } 116 117 /* 118 * Restore a process back to it's pre-truss state. 119 * Called for SIGINT, SIGTERM, SIGQUIT. This only 120 * applies if truss was told to monitor an already-existing 121 * process. 122 */ 123 void 124 restore_proc(int signo __unused) 125 { 126 127 detaching = 1; 128 } 129 130 static void 131 detach_proc(pid_t pid) 132 { 133 134 /* stop the child so that we can detach */ 135 kill(pid, SIGSTOP); 136 if (waitpid(pid, NULL, 0) < 0) 137 err(1, "Unexpected stop in waitpid"); 138 139 if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) 140 err(1, "Can not detach the process"); 141 142 kill(pid, SIGCONT); 143 } 144 145 /* 146 * Determine the ABI. This is called after every exec, and when 147 * a process is first monitored. 148 */ 149 static struct procabi * 150 find_abi(pid_t pid) 151 { 152 struct procabi **pabi; 153 size_t len; 154 int error; 155 int mib[4]; 156 char progt[32]; 157 158 len = sizeof(progt); 159 mib[0] = CTL_KERN; 160 mib[1] = KERN_PROC; 161 mib[2] = KERN_PROC_SV_NAME; 162 mib[3] = pid; 163 error = sysctl(mib, 4, progt, &len, NULL, 0); 164 if (error != 0) 165 err(2, "can not get sysvec name"); 166 167 SET_FOREACH(pabi, procabi) { 168 if (strcmp((*pabi)->type, progt) == 0) 169 return (*pabi); 170 } 171 warnx("ABI %s for pid %ld is not supported", progt, (long)pid); 172 return (NULL); 173 } 174 175 static struct threadinfo * 176 new_thread(struct procinfo *p, lwpid_t lwpid) 177 { 178 struct threadinfo *nt; 179 180 /* 181 * If this happens it means there is a bug in truss. Unfortunately 182 * this will kill any processes truss is attached to. 183 */ 184 LIST_FOREACH(nt, &p->threadlist, entries) { 185 if (nt->tid == lwpid) 186 errx(1, "Duplicate thread for LWP %ld", (long)lwpid); 187 } 188 189 nt = calloc(1, sizeof(struct threadinfo)); 190 if (nt == NULL) 191 err(1, "calloc() failed"); 192 nt->proc = p; 193 nt->tid = lwpid; 194 LIST_INSERT_HEAD(&p->threadlist, nt, entries); 195 return (nt); 196 } 197 198 static void 199 free_thread(struct threadinfo *t) 200 { 201 202 LIST_REMOVE(t, entries); 203 free(t); 204 } 205 206 static void 207 add_threads(struct trussinfo *info, struct procinfo *p) 208 { 209 struct ptrace_lwpinfo pl; 210 struct threadinfo *t; 211 lwpid_t *lwps; 212 int i, nlwps; 213 214 nlwps = ptrace(PT_GETNUMLWPS, p->pid, NULL, 0); 215 if (nlwps == -1) 216 err(1, "Unable to fetch number of LWPs"); 217 assert(nlwps > 0); 218 lwps = calloc(nlwps, sizeof(*lwps)); 219 nlwps = ptrace(PT_GETLWPLIST, p->pid, (caddr_t)lwps, nlwps); 220 if (nlwps == -1) 221 err(1, "Unable to fetch LWP list"); 222 for (i = 0; i < nlwps; i++) { 223 t = new_thread(p, lwps[i]); 224 if (ptrace(PT_LWPINFO, lwps[i], (caddr_t)&pl, sizeof(pl)) == -1) 225 err(1, "ptrace(PT_LWPINFO)"); 226 if (pl.pl_flags & PL_FLAG_SCE) 227 enter_syscall(info, t, &pl); 228 } 229 free(lwps); 230 } 231 232 static void 233 new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 234 { 235 struct procinfo *np; 236 237 /* 238 * If this happens it means there is a bug in truss. Unfortunately 239 * this will kill any processes truss is attached to. 240 */ 241 LIST_FOREACH(np, &info->proclist, entries) { 242 if (np->pid == pid) 243 errx(1, "Duplicate process for pid %ld", (long)pid); 244 } 245 246 if (info->flags & FOLLOWFORKS) 247 if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) 248 err(1, "Unable to follow forks for pid %ld", (long)pid); 249 if (ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1) 250 err(1, "Unable to enable LWP events for pid %ld", (long)pid); 251 np = calloc(1, sizeof(struct procinfo)); 252 np->pid = pid; 253 np->abi = find_abi(pid); 254 LIST_INIT(&np->threadlist); 255 LIST_INSERT_HEAD(&info->proclist, np, entries); 256 257 if (lwpid != 0) 258 new_thread(np, lwpid); 259 else 260 add_threads(info, np); 261 } 262 263 static void 264 free_proc(struct procinfo *p) 265 { 266 struct threadinfo *t, *t2; 267 268 LIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) { 269 free(t); 270 } 271 LIST_REMOVE(p, entries); 272 free(p); 273 } 274 275 static void 276 detach_all_procs(struct trussinfo *info) 277 { 278 struct procinfo *p, *p2; 279 280 LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) { 281 detach_proc(p->pid); 282 free_proc(p); 283 } 284 } 285 286 static struct procinfo * 287 find_proc(struct trussinfo *info, pid_t pid) 288 { 289 struct procinfo *np; 290 291 LIST_FOREACH(np, &info->proclist, entries) { 292 if (np->pid == pid) 293 return (np); 294 } 295 296 return (NULL); 297 } 298 299 /* 300 * Change curthread member based on (pid, lwpid). 301 */ 302 static void 303 find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 304 { 305 struct procinfo *np; 306 struct threadinfo *nt; 307 308 np = find_proc(info, pid); 309 assert(np != NULL); 310 311 LIST_FOREACH(nt, &np->threadlist, entries) { 312 if (nt->tid == lwpid) { 313 info->curthread = nt; 314 return; 315 } 316 } 317 errx(1, "could not find thread"); 318 } 319 320 /* 321 * When a process exits, it should have exactly one thread left. 322 * All of the other threads should have reported thread exit events. 323 */ 324 static void 325 find_exit_thread(struct trussinfo *info, pid_t pid) 326 { 327 struct procinfo *p; 328 329 p = find_proc(info, pid); 330 assert(p != NULL); 331 332 info->curthread = LIST_FIRST(&p->threadlist); 333 assert(info->curthread != NULL); 334 assert(LIST_NEXT(info->curthread, entries) == NULL); 335 } 336 337 static void 338 alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) 339 { 340 u_int i; 341 342 assert(t->in_syscall == 0); 343 assert(t->cs.number == 0); 344 assert(t->cs.name == NULL); 345 assert(t->cs.nargs == 0); 346 for (i = 0; i < nitems(t->cs.s_args); i++) 347 assert(t->cs.s_args[i] == NULL); 348 memset(t->cs.args, 0, sizeof(t->cs.args)); 349 t->cs.number = pl->pl_syscall_code; 350 t->in_syscall = 1; 351 } 352 353 static void 354 free_syscall(struct threadinfo *t) 355 { 356 u_int i; 357 358 for (i = 0; i < t->cs.nargs; i++) 359 free(t->cs.s_args[i]); 360 memset(&t->cs, 0, sizeof(t->cs)); 361 t->in_syscall = 0; 362 } 363 364 static void 365 enter_syscall(struct trussinfo *info, struct threadinfo *t, 366 struct ptrace_lwpinfo *pl) 367 { 368 struct syscall *sc; 369 u_int i, narg; 370 371 alloc_syscall(t, pl); 372 narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args)); 373 if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) { 374 free_syscall(t); 375 return; 376 } 377 378 t->cs.name = sysdecode_syscallname(t->proc->abi->abi, t->cs.number); 379 if (t->cs.name == NULL) 380 fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", 381 t->proc->abi->type, t->cs.number); 382 383 sc = get_syscall(t->cs.name, narg); 384 t->cs.nargs = sc->nargs; 385 assert(sc->nargs <= nitems(t->cs.s_args)); 386 387 t->cs.sc = sc; 388 389 /* 390 * At this point, we set up the system call arguments. 391 * We ignore any OUT ones, however -- those are arguments that 392 * are set by the system call, and so are probably meaningless 393 * now. This doesn't currently support arguments that are 394 * passed in *and* out, however. 395 */ 396 if (t->cs.name != NULL) { 397 #if DEBUG 398 fprintf(stderr, "syscall %s(", t->cs.name); 399 #endif 400 for (i = 0; i < t->cs.nargs; i++) { 401 #if DEBUG 402 fprintf(stderr, "0x%lx%s", sc ? 403 t->cs.args[sc->args[i].offset] : t->cs.args[i], 404 i < (t->cs.nargs - 1) ? "," : ""); 405 #endif 406 if (!(sc->args[i].type & OUT)) { 407 t->cs.s_args[i] = print_arg(&sc->args[i], 408 t->cs.args, 0, info); 409 } 410 } 411 #if DEBUG 412 fprintf(stderr, ")\n"); 413 #endif 414 } 415 416 clock_gettime(CLOCK_REALTIME, &t->before); 417 } 418 419 /* 420 * When a thread exits voluntarily (including when a thread calls 421 * exit() to trigger a process exit), the thread's internal state 422 * holds the arguments passed to the exit system call. When the 423 * thread's exit is reported, log that system call without a return 424 * value. 425 */ 426 static void 427 thread_exit_syscall(struct trussinfo *info) 428 { 429 struct threadinfo *t; 430 431 t = info->curthread; 432 if (!t->in_syscall) 433 return; 434 435 clock_gettime(CLOCK_REALTIME, &t->after); 436 437 print_syscall_ret(info, 0, NULL); 438 free_syscall(t); 439 } 440 441 static void 442 exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 443 { 444 struct threadinfo *t; 445 struct procinfo *p; 446 struct syscall *sc; 447 long retval[2]; 448 u_int i; 449 int errorp; 450 451 t = info->curthread; 452 if (!t->in_syscall) 453 return; 454 455 clock_gettime(CLOCK_REALTIME, &t->after); 456 p = t->proc; 457 if (p->abi->fetch_retval(info, retval, &errorp) < 0) { 458 free_syscall(t); 459 return; 460 } 461 462 sc = t->cs.sc; 463 /* 464 * Here, we only look for arguments that have OUT masked in -- 465 * otherwise, they were handled in enter_syscall(). 466 */ 467 for (i = 0; i < sc->nargs; i++) { 468 char *temp; 469 470 if (sc->args[i].type & OUT) { 471 /* 472 * If an error occurred, then don't bother 473 * getting the data; it may not be valid. 474 */ 475 if (errorp) { 476 asprintf(&temp, "0x%lx", 477 t->cs.args[sc->args[i].offset]); 478 } else { 479 temp = print_arg(&sc->args[i], 480 t->cs.args, retval, info); 481 } 482 t->cs.s_args[i] = temp; 483 } 484 } 485 486 print_syscall_ret(info, errorp, retval); 487 free_syscall(t); 488 489 /* 490 * If the process executed a new image, check the ABI. If the 491 * new ABI isn't supported, stop tracing this process. 492 */ 493 if (pl->pl_flags & PL_FLAG_EXEC) { 494 assert(LIST_NEXT(LIST_FIRST(&p->threadlist), entries) == NULL); 495 p->abi = find_abi(p->pid); 496 if (p->abi == NULL) { 497 if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0) 498 err(1, "Can not detach the process"); 499 free_proc(p); 500 } 501 } 502 } 503 504 int 505 print_line_prefix(struct trussinfo *info) 506 { 507 struct timespec timediff; 508 struct threadinfo *t; 509 int len; 510 511 len = 0; 512 t = info->curthread; 513 if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) { 514 if (info->flags & FOLLOWFORKS) 515 len += fprintf(info->outfile, "%5d", t->proc->pid); 516 if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) == 517 (FOLLOWFORKS | DISPLAYTIDS)) 518 len += fprintf(info->outfile, " "); 519 if (info->flags & DISPLAYTIDS) 520 len += fprintf(info->outfile, "%6d", t->tid); 521 len += fprintf(info->outfile, ": "); 522 } 523 if (info->flags & ABSOLUTETIMESTAMPS) { 524 timespecsubt(&t->after, &info->start_time, &timediff); 525 len += fprintf(info->outfile, "%jd.%09ld ", 526 (intmax_t)timediff.tv_sec, timediff.tv_nsec); 527 } 528 if (info->flags & RELATIVETIMESTAMPS) { 529 timespecsubt(&t->after, &t->before, &timediff); 530 len += fprintf(info->outfile, "%jd.%09ld ", 531 (intmax_t)timediff.tv_sec, timediff.tv_nsec); 532 } 533 return (len); 534 } 535 536 static void 537 report_thread_death(struct trussinfo *info) 538 { 539 struct threadinfo *t; 540 541 t = info->curthread; 542 clock_gettime(CLOCK_REALTIME, &t->after); 543 print_line_prefix(info); 544 fprintf(info->outfile, "<thread %ld exited>\n", (long)t->tid); 545 } 546 547 static void 548 report_thread_birth(struct trussinfo *info) 549 { 550 struct threadinfo *t; 551 552 t = info->curthread; 553 clock_gettime(CLOCK_REALTIME, &t->after); 554 t->before = t->after; 555 print_line_prefix(info); 556 fprintf(info->outfile, "<new thread %ld>\n", (long)t->tid); 557 } 558 559 static void 560 report_exit(struct trussinfo *info, siginfo_t *si) 561 { 562 struct threadinfo *t; 563 564 t = info->curthread; 565 clock_gettime(CLOCK_REALTIME, &t->after); 566 print_line_prefix(info); 567 if (si->si_code == CLD_EXITED) 568 fprintf(info->outfile, "process exit, rval = %u\n", 569 si->si_status); 570 else 571 fprintf(info->outfile, "process killed, signal = %u%s\n", 572 si->si_status, si->si_code == CLD_DUMPED ? 573 " (core dumped)" : ""); 574 } 575 576 static void 577 report_new_child(struct trussinfo *info) 578 { 579 struct threadinfo *t; 580 581 t = info->curthread; 582 clock_gettime(CLOCK_REALTIME, &t->after); 583 t->before = t->after; 584 print_line_prefix(info); 585 fprintf(info->outfile, "<new process>\n"); 586 } 587 588 static void 589 report_signal(struct trussinfo *info, siginfo_t *si) 590 { 591 struct threadinfo *t; 592 char *signame; 593 594 t = info->curthread; 595 clock_gettime(CLOCK_REALTIME, &t->after); 596 print_line_prefix(info); 597 signame = strsig(si->si_status); 598 fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status, 599 signame == NULL ? "?" : signame); 600 } 601 602 /* 603 * Wait for events until all the processes have exited or truss has been 604 * asked to stop. 605 */ 606 void 607 eventloop(struct trussinfo *info) 608 { 609 struct ptrace_lwpinfo pl; 610 siginfo_t si; 611 int pending_signal; 612 613 while (!LIST_EMPTY(&info->proclist)) { 614 if (detaching) { 615 detach_all_procs(info); 616 return; 617 } 618 619 if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { 620 if (errno == EINTR) 621 continue; 622 err(1, "Unexpected error from waitid"); 623 } 624 625 assert(si.si_signo == SIGCHLD); 626 627 switch (si.si_code) { 628 case CLD_EXITED: 629 case CLD_KILLED: 630 case CLD_DUMPED: 631 find_exit_thread(info, si.si_pid); 632 if ((info->flags & COUNTONLY) == 0) { 633 if (si.si_code == CLD_EXITED) 634 thread_exit_syscall(info); 635 report_exit(info, &si); 636 } 637 free_proc(info->curthread->proc); 638 info->curthread = NULL; 639 break; 640 case CLD_TRAPPED: 641 if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl, 642 sizeof(pl)) == -1) 643 err(1, "ptrace(PT_LWPINFO)"); 644 645 if (pl.pl_flags & PL_FLAG_CHILD) { 646 new_proc(info, si.si_pid, pl.pl_lwpid); 647 assert(LIST_FIRST(&info->proclist)->abi != 648 NULL); 649 } else if (pl.pl_flags & PL_FLAG_BORN) 650 new_thread(find_proc(info, si.si_pid), 651 pl.pl_lwpid); 652 find_thread(info, si.si_pid, pl.pl_lwpid); 653 654 if (si.si_status == SIGTRAP && 655 (pl.pl_flags & (PL_FLAG_BORN|PL_FLAG_EXITED| 656 PL_FLAG_SCE|PL_FLAG_SCX)) != 0) { 657 if (pl.pl_flags & PL_FLAG_BORN) { 658 if ((info->flags & COUNTONLY) == 0) 659 report_thread_birth(info); 660 } else if (pl.pl_flags & PL_FLAG_EXITED) { 661 if ((info->flags & COUNTONLY) == 0) 662 report_thread_death(info); 663 free_thread(info->curthread); 664 info->curthread = NULL; 665 } else if (pl.pl_flags & PL_FLAG_SCE) 666 enter_syscall(info, info->curthread, &pl); 667 else if (pl.pl_flags & PL_FLAG_SCX) 668 exit_syscall(info, &pl); 669 pending_signal = 0; 670 } else if (pl.pl_flags & PL_FLAG_CHILD) { 671 if ((info->flags & COUNTONLY) == 0) 672 report_new_child(info); 673 pending_signal = 0; 674 } else { 675 if ((info->flags & NOSIGS) == 0) 676 report_signal(info, &si); 677 pending_signal = si.si_status; 678 } 679 ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1, 680 pending_signal); 681 break; 682 case CLD_STOPPED: 683 errx(1, "waitid reported CLD_STOPPED"); 684 case CLD_CONTINUED: 685 break; 686 } 687 } 688 } 689