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