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 <time.h> 53 #include <unistd.h> 54 55 #include "truss.h" 56 #include "syscall.h" 57 #include "extern.h" 58 59 SET_DECLARE(procabi, struct procabi); 60 61 static sig_atomic_t detaching; 62 63 static void new_proc(struct trussinfo *, pid_t); 64 65 /* 66 * setup_and_wait() is called to start a process. All it really does 67 * is fork(), enable tracing in the child, and then exec the given 68 * command. At that point, the child process stops, and the parent 69 * can wake up and deal with it. 70 */ 71 void 72 setup_and_wait(struct trussinfo *info, char *command[]) 73 { 74 pid_t pid; 75 76 pid = vfork(); 77 if (pid == -1) 78 err(1, "fork failed"); 79 if (pid == 0) { /* Child */ 80 ptrace(PT_TRACE_ME, 0, 0, 0); 81 execvp(command[0], command); 82 err(1, "execvp %s", command[0]); 83 } 84 85 /* Only in the parent here */ 86 if (waitpid(pid, NULL, 0) < 0) 87 err(1, "unexpect stop in waitpid"); 88 89 new_proc(info, pid); 90 } 91 92 /* 93 * start_tracing is called to attach to an existing process. 94 */ 95 void 96 start_tracing(struct trussinfo *info, pid_t pid) 97 { 98 int ret, retry; 99 100 retry = 10; 101 do { 102 ret = ptrace(PT_ATTACH, pid, NULL, 0); 103 usleep(200); 104 } while (ret && retry-- > 0); 105 if (ret) 106 err(1, "can not attach to target process"); 107 108 if (waitpid(pid, NULL, 0) < 0) 109 err(1, "Unexpect stop in waitpid"); 110 111 new_proc(info, pid); 112 } 113 114 /* 115 * Restore a process back to it's pre-truss state. 116 * Called for SIGINT, SIGTERM, SIGQUIT. This only 117 * applies if truss was told to monitor an already-existing 118 * process. 119 */ 120 void 121 restore_proc(int signo __unused) 122 { 123 124 detaching = 1; 125 } 126 127 static void 128 detach_proc(pid_t pid) 129 { 130 131 /* stop the child so that we can detach */ 132 kill(pid, SIGSTOP); 133 if (waitpid(pid, NULL, 0) < 0) 134 err(1, "Unexpected stop in waitpid"); 135 136 if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) 137 err(1, "Can not detach the process"); 138 139 kill(pid, SIGCONT); 140 } 141 142 /* 143 * Determine the ABI. This is called after every exec, and when 144 * a process is first monitored. 145 */ 146 static struct procabi * 147 find_abi(pid_t pid) 148 { 149 struct procabi **pabi; 150 size_t len; 151 int error; 152 int mib[4]; 153 char progt[32]; 154 155 len = sizeof(progt); 156 mib[0] = CTL_KERN; 157 mib[1] = KERN_PROC; 158 mib[2] = KERN_PROC_SV_NAME; 159 mib[3] = pid; 160 error = sysctl(mib, 4, progt, &len, NULL, 0); 161 if (error != 0) 162 err(2, "can not get sysvec name"); 163 164 SET_FOREACH(pabi, procabi) { 165 if (strcmp((*pabi)->type, progt) == 0) 166 return (*pabi); 167 } 168 warnx("ABI %s for pid %ld is not supported", progt, (long)pid); 169 return (NULL); 170 } 171 172 static void 173 new_proc(struct trussinfo *info, pid_t pid) 174 { 175 struct procinfo *np; 176 177 /* 178 * If this happens it means there is a bug in truss. Unfortunately 179 * this will kill any processes are attached to. 180 */ 181 LIST_FOREACH(np, &info->proclist, entries) { 182 if (np->pid == pid) 183 errx(1, "Duplicate process for pid %ld", (long)pid); 184 } 185 186 if (info->flags & FOLLOWFORKS) 187 if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) 188 err(1, "Unable to follow forks for pid %ld", (long)pid); 189 np = calloc(1, sizeof(struct procinfo)); 190 np->pid = pid; 191 np->abi = find_abi(pid); 192 SLIST_INIT(&np->threadlist); 193 LIST_INSERT_HEAD(&info->proclist, np, entries); 194 } 195 196 static void 197 free_proc(struct procinfo *p) 198 { 199 struct threadinfo *t, *t2; 200 201 SLIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) { 202 free(t); 203 } 204 LIST_REMOVE(p, entries); 205 free(p); 206 } 207 208 static void 209 detach_all_procs(struct trussinfo *info) 210 { 211 struct procinfo *p, *p2; 212 213 LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) { 214 detach_proc(p->pid); 215 free_proc(p); 216 } 217 } 218 219 static struct procinfo * 220 find_proc(struct trussinfo *info, pid_t pid) 221 { 222 struct procinfo *np; 223 224 LIST_FOREACH(np, &info->proclist, entries) { 225 if (np->pid == pid) 226 return (np); 227 } 228 229 return (NULL); 230 } 231 232 /* 233 * Change curthread member based on (pid, lwpid). 234 * If it is a new thread, create a threadinfo structure. 235 */ 236 static void 237 find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 238 { 239 struct procinfo *np; 240 struct threadinfo *nt; 241 242 np = find_proc(info, pid); 243 assert(np != NULL); 244 245 SLIST_FOREACH(nt, &np->threadlist, entries) { 246 if (nt->tid == lwpid) { 247 info->curthread = nt; 248 return; 249 } 250 } 251 252 nt = calloc(1, sizeof(struct threadinfo)); 253 if (nt == NULL) 254 err(1, "calloc() failed"); 255 nt->proc = np; 256 nt->tid = lwpid; 257 SLIST_INSERT_HEAD(&np->threadlist, nt, entries); 258 info->curthread = nt; 259 } 260 261 /* 262 * When a process exits, it no longer has any threads left. However, 263 * the main loop expects a valid curthread. In cases when a thread 264 * triggers the termination (e.g. calling exit or triggering a fault) 265 * we would ideally use that thread. However, if a process is killed 266 * by a signal sent from another process then there is no "correct" 267 * thread. We just punt and use the first thread. 268 */ 269 static void 270 find_exit_thread(struct trussinfo *info, pid_t pid) 271 { 272 struct procinfo *np; 273 struct threadinfo *nt; 274 275 np = find_proc(info, pid); 276 assert(np != NULL); 277 278 if (SLIST_EMPTY(&np->threadlist)) { 279 /* 280 * If an existing process exits right after we attach 281 * to it but before it posts any events, there won't 282 * be any threads. Create a dummy thread and set its 283 * "before" time to the global start time. 284 */ 285 nt = calloc(1, sizeof(struct threadinfo)); 286 if (nt == NULL) 287 err(1, "calloc() failed"); 288 nt->proc = np; 289 nt->tid = 0; 290 SLIST_INSERT_HEAD(&np->threadlist, nt, entries); 291 nt->before = info->start_time; 292 } 293 info->curthread = SLIST_FIRST(&np->threadlist); 294 } 295 296 static void 297 alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) 298 { 299 u_int i; 300 301 assert(t->in_syscall == 0); 302 assert(t->cs.number == 0); 303 assert(t->cs.name == NULL); 304 assert(t->cs.nargs == 0); 305 for (i = 0; i < nitems(t->cs.s_args); i++) 306 assert(t->cs.s_args[i] == NULL); 307 memset(t->cs.args, 0, sizeof(t->cs.args)); 308 t->cs.number = pl->pl_syscall_code; 309 t->in_syscall = 1; 310 } 311 312 static void 313 free_syscall(struct threadinfo *t) 314 { 315 u_int i; 316 317 for (i = 0; i < t->cs.nargs; i++) 318 free(t->cs.s_args[i]); 319 memset(&t->cs, 0, sizeof(t->cs)); 320 t->in_syscall = 0; 321 } 322 323 static void 324 enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 325 { 326 struct threadinfo *t; 327 struct syscall *sc; 328 u_int i, narg; 329 330 t = info->curthread; 331 alloc_syscall(t, pl); 332 narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args)); 333 if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) { 334 free_syscall(t); 335 return; 336 } 337 338 if (t->cs.number >= 0 && t->cs.number < t->proc->abi->nsyscalls) 339 t->cs.name = t->proc->abi->syscallnames[t->cs.number]; 340 if (t->cs.name == NULL) 341 fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", 342 t->proc->abi->type, t->cs.number); 343 344 sc = get_syscall(t->cs.name); 345 if (sc) { 346 t->cs.nargs = sc->nargs; 347 assert(sc->nargs <= nitems(t->cs.s_args)); 348 } else { 349 #if DEBUG 350 fprintf(stderr, "unknown syscall %s -- setting " 351 "args to %d\n", t->cs.name, t->cs.nargs); 352 #endif 353 t->cs.nargs = narg; 354 } 355 356 t->cs.sc = sc; 357 358 /* 359 * At this point, we set up the system call arguments. 360 * We ignore any OUT ones, however -- those are arguments that 361 * are set by the system call, and so are probably meaningless 362 * now. This doesn't currently support arguments that are 363 * passed in *and* out, however. 364 */ 365 if (t->cs.name != NULL) { 366 #if DEBUG 367 fprintf(stderr, "syscall %s(", t->cs.name); 368 #endif 369 for (i = 0; i < t->cs.nargs; i++) { 370 #if DEBUG 371 fprintf(stderr, "0x%lx%s", sc ? 372 t->cs.args[sc->args[i].offset] : t->cs.args[i], 373 i < (t->cs.nargs - 1) ? "," : ""); 374 #endif 375 if (sc && !(sc->args[i].type & OUT)) { 376 t->cs.s_args[i] = print_arg(&sc->args[i], 377 t->cs.args, 0, info); 378 } 379 } 380 #if DEBUG 381 fprintf(stderr, ")\n"); 382 #endif 383 } 384 385 clock_gettime(CLOCK_REALTIME, &t->before); 386 } 387 388 static void 389 exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 390 { 391 struct threadinfo *t; 392 struct procinfo *p; 393 struct syscall *sc; 394 long retval[2]; 395 u_int i; 396 int errorp; 397 398 t = info->curthread; 399 if (!t->in_syscall) 400 return; 401 402 clock_gettime(CLOCK_REALTIME, &t->after); 403 p = t->proc; 404 if (p->abi->fetch_retval(info, retval, &errorp) < 0) { 405 free_syscall(t); 406 return; 407 } 408 409 sc = t->cs.sc; 410 if (sc == NULL) { 411 for (i = 0; i < t->cs.nargs; i++) 412 asprintf(&t->cs.s_args[i], "0x%lx", t->cs.args[i]); 413 } else { 414 /* 415 * Here, we only look for arguments that have OUT masked in -- 416 * otherwise, they were handled in enter_syscall(). 417 */ 418 for (i = 0; i < sc->nargs; i++) { 419 char *temp; 420 421 if (sc->args[i].type & OUT) { 422 /* 423 * If an error occurred, then don't bother 424 * getting the data; it may not be valid. 425 */ 426 if (errorp) { 427 asprintf(&temp, "0x%lx", 428 t->cs.args[sc->args[i].offset]); 429 } else { 430 temp = print_arg(&sc->args[i], 431 t->cs.args, retval, info); 432 } 433 t->cs.s_args[i] = temp; 434 } 435 } 436 } 437 438 print_syscall_ret(info, t->cs.name, t->cs.nargs, t->cs.s_args, 439 errorp, retval, sc); 440 free_syscall(t); 441 442 /* 443 * If the process executed a new image, check the ABI. If the 444 * new ABI isn't supported, stop tracing this process. 445 */ 446 if (pl->pl_flags & PL_FLAG_EXEC) { 447 p->abi = find_abi(p->pid); 448 if (p->abi == NULL) { 449 if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0) 450 err(1, "Can not detach the process"); 451 free_proc(p); 452 } 453 } 454 } 455 456 static void 457 report_exit(struct trussinfo *info, siginfo_t *si) 458 { 459 struct timespec timediff; 460 461 if (info->flags & FOLLOWFORKS) 462 fprintf(info->outfile, "%5d: ", si->si_pid); 463 clock_gettime(CLOCK_REALTIME, &info->curthread->after); 464 if (info->flags & ABSOLUTETIMESTAMPS) { 465 timespecsubt(&info->curthread->after, &info->start_time, 466 &timediff); 467 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, 468 timediff.tv_nsec); 469 } 470 if (info->flags & RELATIVETIMESTAMPS) { 471 timespecsubt(&info->curthread->after, &info->curthread->before, 472 &timediff); 473 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, 474 timediff.tv_nsec); 475 } 476 if (si->si_code == CLD_EXITED) 477 fprintf(info->outfile, "process exit, rval = %u\n", 478 si->si_status); 479 else 480 fprintf(info->outfile, "process killed, signal = %u%s\n", 481 si->si_status, si->si_code == CLD_DUMPED ? 482 " (core dumped)" : ""); 483 } 484 485 static void 486 report_new_child(struct trussinfo *info, pid_t pid) 487 { 488 struct timespec timediff; 489 490 clock_gettime(CLOCK_REALTIME, &info->curthread->after); 491 assert(info->flags & FOLLOWFORKS); 492 fprintf(info->outfile, "%5d: ", pid); 493 if (info->flags & ABSOLUTETIMESTAMPS) { 494 timespecsubt(&info->curthread->after, &info->start_time, 495 &timediff); 496 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, 497 timediff.tv_nsec); 498 } 499 if (info->flags & RELATIVETIMESTAMPS) { 500 timediff.tv_sec = 0; 501 timediff.tv_nsec = 0; 502 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, 503 timediff.tv_nsec); 504 } 505 fprintf(info->outfile, "<new process>\n"); 506 } 507 508 static void 509 report_signal(struct trussinfo *info, siginfo_t *si) 510 { 511 struct timespec timediff; 512 char *signame; 513 514 if (info->flags & FOLLOWFORKS) 515 fprintf(info->outfile, "%5d: ", si->si_pid); 516 if (info->flags & ABSOLUTETIMESTAMPS) { 517 timespecsubt(&info->curthread->after, &info->start_time, 518 &timediff); 519 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, 520 timediff.tv_nsec); 521 } 522 if (info->flags & RELATIVETIMESTAMPS) { 523 timespecsubt(&info->curthread->after, &info->curthread->before, 524 &timediff); 525 fprintf(info->outfile, "%jd.%09ld ", (intmax_t)timediff.tv_sec, 526 timediff.tv_nsec); 527 } 528 signame = strsig(si->si_status); 529 fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status, 530 signame == NULL ? "?" : signame); 531 } 532 533 /* 534 * Wait for events until all the processes have exited or truss has been 535 * asked to stop. 536 */ 537 void 538 eventloop(struct trussinfo *info) 539 { 540 struct ptrace_lwpinfo pl; 541 siginfo_t si; 542 int pending_signal; 543 544 while (!LIST_EMPTY(&info->proclist)) { 545 if (detaching) { 546 detach_all_procs(info); 547 return; 548 } 549 550 if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { 551 if (errno == EINTR) 552 continue; 553 err(1, "Unexpected error from waitid"); 554 } 555 556 assert(si.si_signo == SIGCHLD); 557 558 switch (si.si_code) { 559 case CLD_EXITED: 560 case CLD_KILLED: 561 case CLD_DUMPED: 562 find_exit_thread(info, si.si_pid); 563 if ((info->flags & COUNTONLY) == 0) 564 report_exit(info, &si); 565 free_proc(info->curthread->proc); 566 info->curthread = NULL; 567 break; 568 case CLD_TRAPPED: 569 if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl, 570 sizeof(pl)) == -1) 571 err(1, "ptrace(PT_LWPINFO)"); 572 573 if (pl.pl_flags & PL_FLAG_CHILD) { 574 new_proc(info, si.si_pid); 575 assert(LIST_FIRST(&info->proclist)->abi != 576 NULL); 577 } 578 find_thread(info, si.si_pid, pl.pl_lwpid); 579 580 if (si.si_status == SIGTRAP) { 581 if (pl.pl_flags & PL_FLAG_SCE) 582 enter_syscall(info, &pl); 583 else if (pl.pl_flags & PL_FLAG_SCX) 584 exit_syscall(info, &pl); 585 else 586 errx(1, 587 "pl_flags %x contains neither PL_FLAG_SCE nor PL_FLAG_SCX", 588 pl.pl_flags); 589 pending_signal = 0; 590 } else if (pl.pl_flags & PL_FLAG_CHILD) { 591 if ((info->flags & COUNTONLY) == 0) 592 report_new_child(info, si.si_pid); 593 pending_signal = 0; 594 } else { 595 if ((info->flags & NOSIGS) == 0) 596 report_signal(info, &si); 597 pending_signal = si.si_status; 598 } 599 ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1, 600 pending_signal); 601 break; 602 case CLD_STOPPED: 603 errx(1, "waitid reported CLD_STOPPED"); 604 case CLD_CONTINUED: 605 break; 606 } 607 } 608 } 609