1f0bcd5c3SXin LI /*- 20a6c71f8SWarner Losh * Copyright 1997 Sean Eric Fagan 309d64da3SSean Eric Fagan * 409d64da3SSean Eric Fagan * Redistribution and use in source and binary forms, with or without 509d64da3SSean Eric Fagan * modification, are permitted provided that the following conditions 609d64da3SSean Eric Fagan * are met: 709d64da3SSean Eric Fagan * 1. Redistributions of source code must retain the above copyright 809d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer. 909d64da3SSean Eric Fagan * 2. Redistributions in binary form must reproduce the above copyright 1009d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer in the 1109d64da3SSean Eric Fagan * documentation and/or other materials provided with the distribution. 1209d64da3SSean Eric Fagan * 3. All advertising materials mentioning features or use of this software 1309d64da3SSean Eric Fagan * must display the following acknowledgement: 1409d64da3SSean Eric Fagan * This product includes software developed by Sean Eric Fagan 1509d64da3SSean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote 1609d64da3SSean Eric Fagan * products derived from this software without specific prior written 1709d64da3SSean Eric Fagan * permission. 1809d64da3SSean Eric Fagan * 1909d64da3SSean Eric Fagan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2009d64da3SSean Eric Fagan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2109d64da3SSean Eric Fagan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2209d64da3SSean Eric Fagan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2309d64da3SSean Eric Fagan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2409d64da3SSean Eric Fagan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2509d64da3SSean Eric Fagan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2609d64da3SSean Eric Fagan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2709d64da3SSean Eric Fagan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2809d64da3SSean Eric Fagan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2909d64da3SSean Eric Fagan * SUCH DAMAGE. 3009d64da3SSean Eric Fagan */ 3109d64da3SSean Eric Fagan 32b956c13cSPhilippe Charnier #include <sys/cdefs.h> 33b956c13cSPhilippe Charnier __FBSDID("$FreeBSD$"); 343cf51049SPhilippe Charnier 3509d64da3SSean Eric Fagan /* 36bbeaf6c0SSean Eric Fagan * Various setup functions for truss. Not the cleanest-written code, 37bbeaf6c0SSean Eric Fagan * I'm afraid. 38bbeaf6c0SSean Eric Fagan */ 39bbeaf6c0SSean Eric Fagan 405d2d083cSXin LI #include <sys/ptrace.h> 412b75c8adSJohn Baldwin #include <sys/sysctl.h> 42580e0a2bSDag-Erling Smørgrav #include <sys/wait.h> 43580e0a2bSDag-Erling Smørgrav 442b75c8adSJohn Baldwin #include <assert.h> 453cf51049SPhilippe Charnier #include <err.h> 46821df508SXin LI #include <errno.h> 473cf51049SPhilippe Charnier #include <signal.h> 482b75c8adSJohn Baldwin #include <stdint.h> 49bbeaf6c0SSean Eric Fagan #include <stdio.h> 50bbeaf6c0SSean Eric Fagan #include <stdlib.h> 51821df508SXin LI #include <string.h> 52a5f14abfSJohn Baldwin #include <sysdecode.h> 53821df508SXin LI #include <time.h> 54bbeaf6c0SSean Eric Fagan #include <unistd.h> 55bbeaf6c0SSean Eric Fagan 56ec0bed25SMatthew N. Dodd #include "truss.h" 572b75c8adSJohn Baldwin #include "syscall.h" 581be5d704SMark Murray #include "extern.h" 591be5d704SMark Murray 602b75c8adSJohn Baldwin SET_DECLARE(procabi, struct procabi); 612b75c8adSJohn Baldwin 62896fc463SAndrey Zonov static sig_atomic_t detaching; 63bbeaf6c0SSean Eric Fagan 642b75c8adSJohn Baldwin static void new_proc(struct trussinfo *, pid_t); 652b75c8adSJohn Baldwin 66bbeaf6c0SSean Eric Fagan /* 67bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 682b75c8adSJohn Baldwin * is fork(), enable tracing in the child, and then exec the given 692b75c8adSJohn Baldwin * command. At that point, the child process stops, and the parent 702b75c8adSJohn Baldwin * can wake up and deal with it. 71bbeaf6c0SSean Eric Fagan */ 722b75c8adSJohn Baldwin void 732b75c8adSJohn Baldwin setup_and_wait(struct trussinfo *info, char *command[]) 745321ae86SAlfred Perlstein { 75be305c9cSAndrey Zonov pid_t pid; 76bbeaf6c0SSean Eric Fagan 775d2d083cSXin LI pid = vfork(); 7894355cfdSAndrey Zonov if (pid == -1) 791fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 80bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 815d2d083cSXin LI ptrace(PT_TRACE_ME, 0, 0, 0); 82bbeaf6c0SSean Eric Fagan execvp(command[0], command); 835d2d083cSXin LI err(1, "execvp %s", command[0]); 84bbeaf6c0SSean Eric Fagan } 855d2d083cSXin LI 86bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 87310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 885d2d083cSXin LI err(1, "unexpect stop in waitpid"); 89bbeaf6c0SSean Eric Fagan 902b75c8adSJohn Baldwin new_proc(info, pid); 91bbeaf6c0SSean Eric Fagan } 92bbeaf6c0SSean Eric Fagan 93bbeaf6c0SSean Eric Fagan /* 942b75c8adSJohn Baldwin * start_tracing is called to attach to an existing process. 95bbeaf6c0SSean Eric Fagan */ 962b75c8adSJohn Baldwin void 972b75c8adSJohn Baldwin start_tracing(struct trussinfo *info, pid_t pid) 985321ae86SAlfred Perlstein { 99310da894SAndrey Zonov int ret, retry; 1005321ae86SAlfred Perlstein 10194355cfdSAndrey Zonov retry = 10; 1025d2d083cSXin LI do { 1035d2d083cSXin LI ret = ptrace(PT_ATTACH, pid, NULL, 0); 1045d2d083cSXin LI usleep(200); 1055d2d083cSXin LI } while (ret && retry-- > 0); 1065d2d083cSXin LI if (ret) 1075d2d083cSXin LI err(1, "can not attach to target process"); 10820fa828fSSean Eric Fagan 109310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 1105d2d083cSXin LI err(1, "Unexpect stop in waitpid"); 111bbeaf6c0SSean Eric Fagan 1122b75c8adSJohn Baldwin new_proc(info, pid); 113bbeaf6c0SSean Eric Fagan } 114bbeaf6c0SSean Eric Fagan 115bbeaf6c0SSean Eric Fagan /* 116bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 117bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 118bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 119bbeaf6c0SSean Eric Fagan * process. 120bbeaf6c0SSean Eric Fagan */ 121bbeaf6c0SSean Eric Fagan void 1225d2d083cSXin LI restore_proc(int signo __unused) 1235d2d083cSXin LI { 124896fc463SAndrey Zonov 125896fc463SAndrey Zonov detaching = 1; 126896fc463SAndrey Zonov } 127896fc463SAndrey Zonov 1282b75c8adSJohn Baldwin static void 129896fc463SAndrey Zonov detach_proc(pid_t pid) 130896fc463SAndrey Zonov { 131bbeaf6c0SSean Eric Fagan 1325d2d083cSXin LI /* stop the child so that we can detach */ 133896fc463SAndrey Zonov kill(pid, SIGSTOP); 1342b75c8adSJohn Baldwin if (waitpid(pid, NULL, 0) < 0) 1355d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 1365d2d083cSXin LI 137896fc463SAndrey Zonov if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) 1385d2d083cSXin LI err(1, "Can not detach the process"); 1395d2d083cSXin LI 140896fc463SAndrey Zonov kill(pid, SIGCONT); 141bbeaf6c0SSean Eric Fagan } 1425d2d083cSXin LI 1435d2d083cSXin LI /* 1442b75c8adSJohn Baldwin * Determine the ABI. This is called after every exec, and when 1452b75c8adSJohn Baldwin * a process is first monitored. 1462b75c8adSJohn Baldwin */ 1472b75c8adSJohn Baldwin static struct procabi * 1482b75c8adSJohn Baldwin find_abi(pid_t pid) 1492b75c8adSJohn Baldwin { 1502b75c8adSJohn Baldwin struct procabi **pabi; 1512b75c8adSJohn Baldwin size_t len; 1522b75c8adSJohn Baldwin int error; 1532b75c8adSJohn Baldwin int mib[4]; 1542b75c8adSJohn Baldwin char progt[32]; 1552b75c8adSJohn Baldwin 1562b75c8adSJohn Baldwin len = sizeof(progt); 1572b75c8adSJohn Baldwin mib[0] = CTL_KERN; 1582b75c8adSJohn Baldwin mib[1] = KERN_PROC; 1592b75c8adSJohn Baldwin mib[2] = KERN_PROC_SV_NAME; 1602b75c8adSJohn Baldwin mib[3] = pid; 1612b75c8adSJohn Baldwin error = sysctl(mib, 4, progt, &len, NULL, 0); 1622b75c8adSJohn Baldwin if (error != 0) 1632b75c8adSJohn Baldwin err(2, "can not get sysvec name"); 1642b75c8adSJohn Baldwin 1652b75c8adSJohn Baldwin SET_FOREACH(pabi, procabi) { 1662b75c8adSJohn Baldwin if (strcmp((*pabi)->type, progt) == 0) 1672b75c8adSJohn Baldwin return (*pabi); 1682b75c8adSJohn Baldwin } 1692b75c8adSJohn Baldwin warnx("ABI %s for pid %ld is not supported", progt, (long)pid); 1702b75c8adSJohn Baldwin return (NULL); 1712b75c8adSJohn Baldwin } 1722b75c8adSJohn Baldwin 1732b75c8adSJohn Baldwin static void 1742b75c8adSJohn Baldwin new_proc(struct trussinfo *info, pid_t pid) 1752b75c8adSJohn Baldwin { 1762b75c8adSJohn Baldwin struct procinfo *np; 1772b75c8adSJohn Baldwin 1782b75c8adSJohn Baldwin /* 1792b75c8adSJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately 1802b75c8adSJohn Baldwin * this will kill any processes are attached to. 1812b75c8adSJohn Baldwin */ 1822b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 1832b75c8adSJohn Baldwin if (np->pid == pid) 1842b75c8adSJohn Baldwin errx(1, "Duplicate process for pid %ld", (long)pid); 1852b75c8adSJohn Baldwin } 1862b75c8adSJohn Baldwin 1872b75c8adSJohn Baldwin if (info->flags & FOLLOWFORKS) 1882b75c8adSJohn Baldwin if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) 1892b75c8adSJohn Baldwin err(1, "Unable to follow forks for pid %ld", (long)pid); 1902b75c8adSJohn Baldwin np = calloc(1, sizeof(struct procinfo)); 1912b75c8adSJohn Baldwin np->pid = pid; 1922b75c8adSJohn Baldwin np->abi = find_abi(pid); 1932b75c8adSJohn Baldwin SLIST_INIT(&np->threadlist); 1942b75c8adSJohn Baldwin LIST_INSERT_HEAD(&info->proclist, np, entries); 1952b75c8adSJohn Baldwin } 1962b75c8adSJohn Baldwin 1972b75c8adSJohn Baldwin static void 1982b75c8adSJohn Baldwin free_proc(struct procinfo *p) 1992b75c8adSJohn Baldwin { 2002b75c8adSJohn Baldwin struct threadinfo *t, *t2; 2012b75c8adSJohn Baldwin 2022b75c8adSJohn Baldwin SLIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) { 2032b75c8adSJohn Baldwin free(t); 2042b75c8adSJohn Baldwin } 2052b75c8adSJohn Baldwin LIST_REMOVE(p, entries); 2062b75c8adSJohn Baldwin free(p); 2072b75c8adSJohn Baldwin } 2082b75c8adSJohn Baldwin 2092b75c8adSJohn Baldwin static void 2102b75c8adSJohn Baldwin detach_all_procs(struct trussinfo *info) 2112b75c8adSJohn Baldwin { 2122b75c8adSJohn Baldwin struct procinfo *p, *p2; 2132b75c8adSJohn Baldwin 2142b75c8adSJohn Baldwin LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) { 2152b75c8adSJohn Baldwin detach_proc(p->pid); 2162b75c8adSJohn Baldwin free_proc(p); 2172b75c8adSJohn Baldwin } 2182b75c8adSJohn Baldwin } 2192b75c8adSJohn Baldwin 2202b75c8adSJohn Baldwin static struct procinfo * 2212b75c8adSJohn Baldwin find_proc(struct trussinfo *info, pid_t pid) 2222b75c8adSJohn Baldwin { 2232b75c8adSJohn Baldwin struct procinfo *np; 2242b75c8adSJohn Baldwin 2252b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 2262b75c8adSJohn Baldwin if (np->pid == pid) 2272b75c8adSJohn Baldwin return (np); 2282b75c8adSJohn Baldwin } 2292b75c8adSJohn Baldwin 2302b75c8adSJohn Baldwin return (NULL); 2312b75c8adSJohn Baldwin } 2322b75c8adSJohn Baldwin 2332b75c8adSJohn Baldwin /* 2342b75c8adSJohn Baldwin * Change curthread member based on (pid, lwpid). 2352b75c8adSJohn Baldwin * If it is a new thread, create a threadinfo structure. 2365d2d083cSXin LI */ 2375d2d083cSXin LI static void 2382b75c8adSJohn Baldwin find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 2395d2d083cSXin LI { 2402b75c8adSJohn Baldwin struct procinfo *np; 2412b75c8adSJohn Baldwin struct threadinfo *nt; 24294355cfdSAndrey Zonov 2432b75c8adSJohn Baldwin np = find_proc(info, pid); 2442b75c8adSJohn Baldwin assert(np != NULL); 2452b75c8adSJohn Baldwin 2462b75c8adSJohn Baldwin SLIST_FOREACH(nt, &np->threadlist, entries) { 2472b75c8adSJohn Baldwin if (nt->tid == lwpid) { 2482b75c8adSJohn Baldwin info->curthread = nt; 2495d2d083cSXin LI return; 2505d2d083cSXin LI } 2515d2d083cSXin LI } 2525d2d083cSXin LI 2532b75c8adSJohn Baldwin nt = calloc(1, sizeof(struct threadinfo)); 2542b75c8adSJohn Baldwin if (nt == NULL) 2555695afdeSAndrey Zonov err(1, "calloc() failed"); 2562b75c8adSJohn Baldwin nt->proc = np; 2572b75c8adSJohn Baldwin nt->tid = lwpid; 2582b75c8adSJohn Baldwin SLIST_INSERT_HEAD(&np->threadlist, nt, entries); 2592b75c8adSJohn Baldwin info->curthread = nt; 2605d2d083cSXin LI } 2615d2d083cSXin LI 2625d2d083cSXin LI /* 2632b75c8adSJohn Baldwin * When a process exits, it no longer has any threads left. However, 2642b75c8adSJohn Baldwin * the main loop expects a valid curthread. In cases when a thread 2652b75c8adSJohn Baldwin * triggers the termination (e.g. calling exit or triggering a fault) 2662b75c8adSJohn Baldwin * we would ideally use that thread. However, if a process is killed 2672b75c8adSJohn Baldwin * by a signal sent from another process then there is no "correct" 2682b75c8adSJohn Baldwin * thread. We just punt and use the first thread. 2692b75c8adSJohn Baldwin */ 2702b75c8adSJohn Baldwin static void 2712b75c8adSJohn Baldwin find_exit_thread(struct trussinfo *info, pid_t pid) 2722b75c8adSJohn Baldwin { 2732b75c8adSJohn Baldwin struct procinfo *np; 2742b75c8adSJohn Baldwin struct threadinfo *nt; 2752b75c8adSJohn Baldwin 2762b75c8adSJohn Baldwin np = find_proc(info, pid); 2772b75c8adSJohn Baldwin assert(np != NULL); 2782b75c8adSJohn Baldwin 2792b75c8adSJohn Baldwin if (SLIST_EMPTY(&np->threadlist)) { 2802b75c8adSJohn Baldwin /* 2812b75c8adSJohn Baldwin * If an existing process exits right after we attach 2822b75c8adSJohn Baldwin * to it but before it posts any events, there won't 2832b75c8adSJohn Baldwin * be any threads. Create a dummy thread and set its 2842b75c8adSJohn Baldwin * "before" time to the global start time. 2852b75c8adSJohn Baldwin */ 2862b75c8adSJohn Baldwin nt = calloc(1, sizeof(struct threadinfo)); 2872b75c8adSJohn Baldwin if (nt == NULL) 2882b75c8adSJohn Baldwin err(1, "calloc() failed"); 2892b75c8adSJohn Baldwin nt->proc = np; 2902b75c8adSJohn Baldwin nt->tid = 0; 2912b75c8adSJohn Baldwin SLIST_INSERT_HEAD(&np->threadlist, nt, entries); 2922b75c8adSJohn Baldwin nt->before = info->start_time; 2932b75c8adSJohn Baldwin } 2942b75c8adSJohn Baldwin info->curthread = SLIST_FIRST(&np->threadlist); 2952b75c8adSJohn Baldwin } 2962b75c8adSJohn Baldwin 2972b75c8adSJohn Baldwin static void 2982b75c8adSJohn Baldwin alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) 2992b75c8adSJohn Baldwin { 3002b75c8adSJohn Baldwin u_int i; 3012b75c8adSJohn Baldwin 3022b75c8adSJohn Baldwin assert(t->in_syscall == 0); 3032b75c8adSJohn Baldwin assert(t->cs.number == 0); 3042b75c8adSJohn Baldwin assert(t->cs.name == NULL); 3052b75c8adSJohn Baldwin assert(t->cs.nargs == 0); 3062b75c8adSJohn Baldwin for (i = 0; i < nitems(t->cs.s_args); i++) 3072b75c8adSJohn Baldwin assert(t->cs.s_args[i] == NULL); 3082b75c8adSJohn Baldwin memset(t->cs.args, 0, sizeof(t->cs.args)); 3092b75c8adSJohn Baldwin t->cs.number = pl->pl_syscall_code; 3102b75c8adSJohn Baldwin t->in_syscall = 1; 3112b75c8adSJohn Baldwin } 3122b75c8adSJohn Baldwin 3132b75c8adSJohn Baldwin static void 3142b75c8adSJohn Baldwin free_syscall(struct threadinfo *t) 3152b75c8adSJohn Baldwin { 3162b75c8adSJohn Baldwin u_int i; 3172b75c8adSJohn Baldwin 3182b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) 3192b75c8adSJohn Baldwin free(t->cs.s_args[i]); 3202b75c8adSJohn Baldwin memset(&t->cs, 0, sizeof(t->cs)); 3212b75c8adSJohn Baldwin t->in_syscall = 0; 3222b75c8adSJohn Baldwin } 3232b75c8adSJohn Baldwin 3242b75c8adSJohn Baldwin static void 3252b75c8adSJohn Baldwin enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 3262b75c8adSJohn Baldwin { 3272b75c8adSJohn Baldwin struct threadinfo *t; 3282b75c8adSJohn Baldwin struct syscall *sc; 3292b75c8adSJohn Baldwin u_int i, narg; 3302b75c8adSJohn Baldwin 3312b75c8adSJohn Baldwin t = info->curthread; 3322b75c8adSJohn Baldwin alloc_syscall(t, pl); 3332b75c8adSJohn Baldwin narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args)); 3342b75c8adSJohn Baldwin if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) { 3352b75c8adSJohn Baldwin free_syscall(t); 3362b75c8adSJohn Baldwin return; 3372b75c8adSJohn Baldwin } 3382b75c8adSJohn Baldwin 339a5f14abfSJohn Baldwin t->cs.name = sysdecode_syscallname(t->proc->abi->abi, t->cs.number); 3402b75c8adSJohn Baldwin if (t->cs.name == NULL) 3412b75c8adSJohn Baldwin fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", 3422b75c8adSJohn Baldwin t->proc->abi->type, t->cs.number); 3432b75c8adSJohn Baldwin 3446c61b0f3SBryan Drewery sc = get_syscall(t->cs.name, narg); 3452b75c8adSJohn Baldwin t->cs.nargs = sc->nargs; 3462b75c8adSJohn Baldwin assert(sc->nargs <= nitems(t->cs.s_args)); 3472b75c8adSJohn Baldwin 3482b75c8adSJohn Baldwin t->cs.sc = sc; 3492b75c8adSJohn Baldwin 3502b75c8adSJohn Baldwin /* 3512b75c8adSJohn Baldwin * At this point, we set up the system call arguments. 3522b75c8adSJohn Baldwin * We ignore any OUT ones, however -- those are arguments that 3532b75c8adSJohn Baldwin * are set by the system call, and so are probably meaningless 3542b75c8adSJohn Baldwin * now. This doesn't currently support arguments that are 3552b75c8adSJohn Baldwin * passed in *and* out, however. 3562b75c8adSJohn Baldwin */ 3572b75c8adSJohn Baldwin if (t->cs.name != NULL) { 3582b75c8adSJohn Baldwin #if DEBUG 3592b75c8adSJohn Baldwin fprintf(stderr, "syscall %s(", t->cs.name); 3602b75c8adSJohn Baldwin #endif 3612b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) { 3622b75c8adSJohn Baldwin #if DEBUG 3632b75c8adSJohn Baldwin fprintf(stderr, "0x%lx%s", sc ? 3642b75c8adSJohn Baldwin t->cs.args[sc->args[i].offset] : t->cs.args[i], 3652b75c8adSJohn Baldwin i < (t->cs.nargs - 1) ? "," : ""); 3662b75c8adSJohn Baldwin #endif 3676c61b0f3SBryan Drewery if (!(sc->args[i].type & OUT)) { 3682b75c8adSJohn Baldwin t->cs.s_args[i] = print_arg(&sc->args[i], 3692b75c8adSJohn Baldwin t->cs.args, 0, info); 3702b75c8adSJohn Baldwin } 3712b75c8adSJohn Baldwin } 3722b75c8adSJohn Baldwin #if DEBUG 3732b75c8adSJohn Baldwin fprintf(stderr, ")\n"); 3742b75c8adSJohn Baldwin #endif 3752b75c8adSJohn Baldwin } 3762b75c8adSJohn Baldwin 3772b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->before); 3782b75c8adSJohn Baldwin } 3792b75c8adSJohn Baldwin 3802b75c8adSJohn Baldwin static void 3812b75c8adSJohn Baldwin exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 3822b75c8adSJohn Baldwin { 3832b75c8adSJohn Baldwin struct threadinfo *t; 3842b75c8adSJohn Baldwin struct procinfo *p; 3852b75c8adSJohn Baldwin struct syscall *sc; 3862b75c8adSJohn Baldwin long retval[2]; 3872b75c8adSJohn Baldwin u_int i; 3882b75c8adSJohn Baldwin int errorp; 3892b75c8adSJohn Baldwin 3902b75c8adSJohn Baldwin t = info->curthread; 3912b75c8adSJohn Baldwin if (!t->in_syscall) 3922b75c8adSJohn Baldwin return; 3932b75c8adSJohn Baldwin 3942b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 3952b75c8adSJohn Baldwin p = t->proc; 3962b75c8adSJohn Baldwin if (p->abi->fetch_retval(info, retval, &errorp) < 0) { 3972b75c8adSJohn Baldwin free_syscall(t); 3982b75c8adSJohn Baldwin return; 3992b75c8adSJohn Baldwin } 4002b75c8adSJohn Baldwin 4012b75c8adSJohn Baldwin sc = t->cs.sc; 4022b75c8adSJohn Baldwin /* 4032b75c8adSJohn Baldwin * Here, we only look for arguments that have OUT masked in -- 4042b75c8adSJohn Baldwin * otherwise, they were handled in enter_syscall(). 4052b75c8adSJohn Baldwin */ 4062b75c8adSJohn Baldwin for (i = 0; i < sc->nargs; i++) { 4072b75c8adSJohn Baldwin char *temp; 4082b75c8adSJohn Baldwin 4092b75c8adSJohn Baldwin if (sc->args[i].type & OUT) { 4102b75c8adSJohn Baldwin /* 4112b75c8adSJohn Baldwin * If an error occurred, then don't bother 4122b75c8adSJohn Baldwin * getting the data; it may not be valid. 4132b75c8adSJohn Baldwin */ 4142b75c8adSJohn Baldwin if (errorp) { 4152b75c8adSJohn Baldwin asprintf(&temp, "0x%lx", 4162b75c8adSJohn Baldwin t->cs.args[sc->args[i].offset]); 4172b75c8adSJohn Baldwin } else { 4182b75c8adSJohn Baldwin temp = print_arg(&sc->args[i], 4192b75c8adSJohn Baldwin t->cs.args, retval, info); 4202b75c8adSJohn Baldwin } 4212b75c8adSJohn Baldwin t->cs.s_args[i] = temp; 4222b75c8adSJohn Baldwin } 4232b75c8adSJohn Baldwin } 4242b75c8adSJohn Baldwin 42500ddbdf2SJohn Baldwin print_syscall_ret(info, errorp, retval); 4262b75c8adSJohn Baldwin free_syscall(t); 4272b75c8adSJohn Baldwin 4282b75c8adSJohn Baldwin /* 4292b75c8adSJohn Baldwin * If the process executed a new image, check the ABI. If the 4302b75c8adSJohn Baldwin * new ABI isn't supported, stop tracing this process. 4312b75c8adSJohn Baldwin */ 4322b75c8adSJohn Baldwin if (pl->pl_flags & PL_FLAG_EXEC) { 4332b75c8adSJohn Baldwin p->abi = find_abi(p->pid); 4342b75c8adSJohn Baldwin if (p->abi == NULL) { 4352b75c8adSJohn Baldwin if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0) 4362b75c8adSJohn Baldwin err(1, "Can not detach the process"); 4372b75c8adSJohn Baldwin free_proc(p); 4382b75c8adSJohn Baldwin } 4392b75c8adSJohn Baldwin } 4402b75c8adSJohn Baldwin } 4412b75c8adSJohn Baldwin 442*d70876fdSJohn Baldwin int 443*d70876fdSJohn Baldwin print_line_prefix(struct trussinfo *info) 444*d70876fdSJohn Baldwin { 445*d70876fdSJohn Baldwin struct timespec timediff; 446*d70876fdSJohn Baldwin struct threadinfo *t; 447*d70876fdSJohn Baldwin int len; 448*d70876fdSJohn Baldwin 449*d70876fdSJohn Baldwin len = 0; 450*d70876fdSJohn Baldwin t = info->curthread; 451*d70876fdSJohn Baldwin if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) { 452*d70876fdSJohn Baldwin if (info->flags & FOLLOWFORKS) 453*d70876fdSJohn Baldwin len += fprintf(info->outfile, "%5d", t->proc->pid); 454*d70876fdSJohn Baldwin if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) == 455*d70876fdSJohn Baldwin (FOLLOWFORKS | DISPLAYTIDS)) 456*d70876fdSJohn Baldwin len += fprintf(info->outfile, " "); 457*d70876fdSJohn Baldwin if (info->flags & DISPLAYTIDS) 458*d70876fdSJohn Baldwin len += fprintf(info->outfile, "%6d", t->tid); 459*d70876fdSJohn Baldwin len += fprintf(info->outfile, ": "); 460*d70876fdSJohn Baldwin } 461*d70876fdSJohn Baldwin if (info->flags & ABSOLUTETIMESTAMPS) { 462*d70876fdSJohn Baldwin timespecsubt(&t->after, &info->start_time, &timediff); 463*d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 464*d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 465*d70876fdSJohn Baldwin } 466*d70876fdSJohn Baldwin if (info->flags & RELATIVETIMESTAMPS) { 467*d70876fdSJohn Baldwin timespecsubt(&t->after, &t->before, &timediff); 468*d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 469*d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 470*d70876fdSJohn Baldwin } 471*d70876fdSJohn Baldwin return (len); 472*d70876fdSJohn Baldwin } 473*d70876fdSJohn Baldwin 4742b75c8adSJohn Baldwin static void 4752b75c8adSJohn Baldwin report_exit(struct trussinfo *info, siginfo_t *si) 4762b75c8adSJohn Baldwin { 477*d70876fdSJohn Baldwin struct threadinfo *t; 4782b75c8adSJohn Baldwin 479*d70876fdSJohn Baldwin t = info->curthread; 480*d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 481*d70876fdSJohn Baldwin print_line_prefix(info); 4822b75c8adSJohn Baldwin if (si->si_code == CLD_EXITED) 4832b75c8adSJohn Baldwin fprintf(info->outfile, "process exit, rval = %u\n", 4842b75c8adSJohn Baldwin si->si_status); 4852b75c8adSJohn Baldwin else 4862b75c8adSJohn Baldwin fprintf(info->outfile, "process killed, signal = %u%s\n", 4872b75c8adSJohn Baldwin si->si_status, si->si_code == CLD_DUMPED ? 4882b75c8adSJohn Baldwin " (core dumped)" : ""); 4892b75c8adSJohn Baldwin } 4902b75c8adSJohn Baldwin 4912b75c8adSJohn Baldwin static void 492*d70876fdSJohn Baldwin report_new_child(struct trussinfo *info) 4932b75c8adSJohn Baldwin { 494*d70876fdSJohn Baldwin struct threadinfo *t; 4952b75c8adSJohn Baldwin 496*d70876fdSJohn Baldwin t = info->curthread; 497*d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 498*d70876fdSJohn Baldwin t->before = t->after; 499*d70876fdSJohn Baldwin print_line_prefix(info); 5002b75c8adSJohn Baldwin fprintf(info->outfile, "<new process>\n"); 5012b75c8adSJohn Baldwin } 5022b75c8adSJohn Baldwin 5032b75c8adSJohn Baldwin static void 5042b75c8adSJohn Baldwin report_signal(struct trussinfo *info, siginfo_t *si) 5052b75c8adSJohn Baldwin { 506*d70876fdSJohn Baldwin struct threadinfo *t; 5072b75c8adSJohn Baldwin char *signame; 5082b75c8adSJohn Baldwin 509*d70876fdSJohn Baldwin t = info->curthread; 510*d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 511*d70876fdSJohn Baldwin print_line_prefix(info); 5122b75c8adSJohn Baldwin signame = strsig(si->si_status); 5132b75c8adSJohn Baldwin fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status, 5142b75c8adSJohn Baldwin signame == NULL ? "?" : signame); 5152b75c8adSJohn Baldwin } 5162b75c8adSJohn Baldwin 5172b75c8adSJohn Baldwin /* 5182b75c8adSJohn Baldwin * Wait for events until all the processes have exited or truss has been 5192b75c8adSJohn Baldwin * asked to stop. 5205d2d083cSXin LI */ 5215d2d083cSXin LI void 5222b75c8adSJohn Baldwin eventloop(struct trussinfo *info) 5235d2d083cSXin LI { 5242b75c8adSJohn Baldwin struct ptrace_lwpinfo pl; 5252b75c8adSJohn Baldwin siginfo_t si; 5262b75c8adSJohn Baldwin int pending_signal; 5275d2d083cSXin LI 5282b75c8adSJohn Baldwin while (!LIST_EMPTY(&info->proclist)) { 529896fc463SAndrey Zonov if (detaching) { 5302b75c8adSJohn Baldwin detach_all_procs(info); 531896fc463SAndrey Zonov return; 532896fc463SAndrey Zonov } 533896fc463SAndrey Zonov 5342b75c8adSJohn Baldwin if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { 535896fc463SAndrey Zonov if (errno == EINTR) 5362b75c8adSJohn Baldwin continue; 5372b75c8adSJohn Baldwin err(1, "Unexpected error from waitid"); 538896fc463SAndrey Zonov } 5395d2d083cSXin LI 5402b75c8adSJohn Baldwin assert(si.si_signo == SIGCHLD); 5412b75c8adSJohn Baldwin 5422b75c8adSJohn Baldwin switch (si.si_code) { 5432b75c8adSJohn Baldwin case CLD_EXITED: 5442b75c8adSJohn Baldwin case CLD_KILLED: 5452b75c8adSJohn Baldwin case CLD_DUMPED: 5462b75c8adSJohn Baldwin find_exit_thread(info, si.si_pid); 5472b75c8adSJohn Baldwin if ((info->flags & COUNTONLY) == 0) 5482b75c8adSJohn Baldwin report_exit(info, &si); 5492b75c8adSJohn Baldwin free_proc(info->curthread->proc); 5502b75c8adSJohn Baldwin info->curthread = NULL; 5515d2d083cSXin LI break; 5522b75c8adSJohn Baldwin case CLD_TRAPPED: 5532b75c8adSJohn Baldwin if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl, 5542b75c8adSJohn Baldwin sizeof(pl)) == -1) 5552b75c8adSJohn Baldwin err(1, "ptrace(PT_LWPINFO)"); 5562b75c8adSJohn Baldwin 5572b75c8adSJohn Baldwin if (pl.pl_flags & PL_FLAG_CHILD) { 5582b75c8adSJohn Baldwin new_proc(info, si.si_pid); 5592b75c8adSJohn Baldwin assert(LIST_FIRST(&info->proclist)->abi != 5602b75c8adSJohn Baldwin NULL); 5612b75c8adSJohn Baldwin } 5622b75c8adSJohn Baldwin find_thread(info, si.si_pid, pl.pl_lwpid); 5632b75c8adSJohn Baldwin 56494746562SBryan Drewery if (si.si_status == SIGTRAP && 56594746562SBryan Drewery (pl.pl_flags & (PL_FLAG_SCE|PL_FLAG_SCX)) != 0) { 5662b75c8adSJohn Baldwin if (pl.pl_flags & PL_FLAG_SCE) 5672b75c8adSJohn Baldwin enter_syscall(info, &pl); 5682b75c8adSJohn Baldwin else if (pl.pl_flags & PL_FLAG_SCX) 5692b75c8adSJohn Baldwin exit_syscall(info, &pl); 5702b75c8adSJohn Baldwin pending_signal = 0; 5712b75c8adSJohn Baldwin } else if (pl.pl_flags & PL_FLAG_CHILD) { 5722b75c8adSJohn Baldwin if ((info->flags & COUNTONLY) == 0) 573*d70876fdSJohn Baldwin report_new_child(info); 5742b75c8adSJohn Baldwin pending_signal = 0; 5752b75c8adSJohn Baldwin } else { 5762b75c8adSJohn Baldwin if ((info->flags & NOSIGS) == 0) 5772b75c8adSJohn Baldwin report_signal(info, &si); 5782b75c8adSJohn Baldwin pending_signal = si.si_status; 57997695ad4SKonstantin Belousov } 5802b75c8adSJohn Baldwin ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1, 5812b75c8adSJohn Baldwin pending_signal); 5822b75c8adSJohn Baldwin break; 5832b75c8adSJohn Baldwin case CLD_STOPPED: 5842b75c8adSJohn Baldwin errx(1, "waitid reported CLD_STOPPED"); 5852b75c8adSJohn Baldwin case CLD_CONTINUED: 5865d2d083cSXin LI break; 5875d2d083cSXin LI } 5885d2d083cSXin LI } 5895d2d083cSXin LI } 590