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 64*b9befd33SJohn Baldwin static void enter_syscall(struct trussinfo *, struct threadinfo *, 65*b9befd33SJohn Baldwin struct ptrace_lwpinfo *); 66*b9befd33SJohn Baldwin static void new_proc(struct trussinfo *, pid_t, lwpid_t); 672b75c8adSJohn Baldwin 68bbeaf6c0SSean Eric Fagan /* 69bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 702b75c8adSJohn Baldwin * is fork(), enable tracing in the child, and then exec the given 712b75c8adSJohn Baldwin * command. At that point, the child process stops, and the parent 722b75c8adSJohn Baldwin * can wake up and deal with it. 73bbeaf6c0SSean Eric Fagan */ 742b75c8adSJohn Baldwin void 752b75c8adSJohn Baldwin setup_and_wait(struct trussinfo *info, char *command[]) 765321ae86SAlfred Perlstein { 77be305c9cSAndrey Zonov pid_t pid; 78bbeaf6c0SSean Eric Fagan 795d2d083cSXin LI pid = vfork(); 8094355cfdSAndrey Zonov if (pid == -1) 811fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 82bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 835d2d083cSXin LI ptrace(PT_TRACE_ME, 0, 0, 0); 84bbeaf6c0SSean Eric Fagan execvp(command[0], command); 855d2d083cSXin LI err(1, "execvp %s", command[0]); 86bbeaf6c0SSean Eric Fagan } 875d2d083cSXin LI 88bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 89310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 905d2d083cSXin LI err(1, "unexpect stop in waitpid"); 91bbeaf6c0SSean Eric Fagan 92*b9befd33SJohn Baldwin new_proc(info, pid, 0); 93bbeaf6c0SSean Eric Fagan } 94bbeaf6c0SSean Eric Fagan 95bbeaf6c0SSean Eric Fagan /* 962b75c8adSJohn Baldwin * start_tracing is called to attach to an existing process. 97bbeaf6c0SSean Eric Fagan */ 982b75c8adSJohn Baldwin void 992b75c8adSJohn Baldwin start_tracing(struct trussinfo *info, pid_t pid) 1005321ae86SAlfred Perlstein { 101310da894SAndrey Zonov int ret, retry; 1025321ae86SAlfred Perlstein 10394355cfdSAndrey Zonov retry = 10; 1045d2d083cSXin LI do { 1055d2d083cSXin LI ret = ptrace(PT_ATTACH, pid, NULL, 0); 1065d2d083cSXin LI usleep(200); 1075d2d083cSXin LI } while (ret && retry-- > 0); 1085d2d083cSXin LI if (ret) 1095d2d083cSXin LI err(1, "can not attach to target process"); 11020fa828fSSean Eric Fagan 111310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 1125d2d083cSXin LI err(1, "Unexpect stop in waitpid"); 113bbeaf6c0SSean Eric Fagan 114*b9befd33SJohn Baldwin new_proc(info, pid, 0); 115bbeaf6c0SSean Eric Fagan } 116bbeaf6c0SSean Eric Fagan 117bbeaf6c0SSean Eric Fagan /* 118bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 119bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 120bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 121bbeaf6c0SSean Eric Fagan * process. 122bbeaf6c0SSean Eric Fagan */ 123bbeaf6c0SSean Eric Fagan void 1245d2d083cSXin LI restore_proc(int signo __unused) 1255d2d083cSXin LI { 126896fc463SAndrey Zonov 127896fc463SAndrey Zonov detaching = 1; 128896fc463SAndrey Zonov } 129896fc463SAndrey Zonov 1302b75c8adSJohn Baldwin static void 131896fc463SAndrey Zonov detach_proc(pid_t pid) 132896fc463SAndrey Zonov { 133bbeaf6c0SSean Eric Fagan 1345d2d083cSXin LI /* stop the child so that we can detach */ 135896fc463SAndrey Zonov kill(pid, SIGSTOP); 1362b75c8adSJohn Baldwin if (waitpid(pid, NULL, 0) < 0) 1375d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 1385d2d083cSXin LI 139896fc463SAndrey Zonov if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) 1405d2d083cSXin LI err(1, "Can not detach the process"); 1415d2d083cSXin LI 142896fc463SAndrey Zonov kill(pid, SIGCONT); 143bbeaf6c0SSean Eric Fagan } 1445d2d083cSXin LI 1455d2d083cSXin LI /* 1462b75c8adSJohn Baldwin * Determine the ABI. This is called after every exec, and when 1472b75c8adSJohn Baldwin * a process is first monitored. 1482b75c8adSJohn Baldwin */ 1492b75c8adSJohn Baldwin static struct procabi * 1502b75c8adSJohn Baldwin find_abi(pid_t pid) 1512b75c8adSJohn Baldwin { 1522b75c8adSJohn Baldwin struct procabi **pabi; 1532b75c8adSJohn Baldwin size_t len; 1542b75c8adSJohn Baldwin int error; 1552b75c8adSJohn Baldwin int mib[4]; 1562b75c8adSJohn Baldwin char progt[32]; 1572b75c8adSJohn Baldwin 1582b75c8adSJohn Baldwin len = sizeof(progt); 1592b75c8adSJohn Baldwin mib[0] = CTL_KERN; 1602b75c8adSJohn Baldwin mib[1] = KERN_PROC; 1612b75c8adSJohn Baldwin mib[2] = KERN_PROC_SV_NAME; 1622b75c8adSJohn Baldwin mib[3] = pid; 1632b75c8adSJohn Baldwin error = sysctl(mib, 4, progt, &len, NULL, 0); 1642b75c8adSJohn Baldwin if (error != 0) 1652b75c8adSJohn Baldwin err(2, "can not get sysvec name"); 1662b75c8adSJohn Baldwin 1672b75c8adSJohn Baldwin SET_FOREACH(pabi, procabi) { 1682b75c8adSJohn Baldwin if (strcmp((*pabi)->type, progt) == 0) 1692b75c8adSJohn Baldwin return (*pabi); 1702b75c8adSJohn Baldwin } 1712b75c8adSJohn Baldwin warnx("ABI %s for pid %ld is not supported", progt, (long)pid); 1722b75c8adSJohn Baldwin return (NULL); 1732b75c8adSJohn Baldwin } 1742b75c8adSJohn Baldwin 175*b9befd33SJohn Baldwin static struct threadinfo * 176*b9befd33SJohn Baldwin new_thread(struct procinfo *p, lwpid_t lwpid) 177*b9befd33SJohn Baldwin { 178*b9befd33SJohn Baldwin struct threadinfo *nt; 179*b9befd33SJohn Baldwin 180*b9befd33SJohn Baldwin /* 181*b9befd33SJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately 182*b9befd33SJohn Baldwin * this will kill any processes truss is attached to. 183*b9befd33SJohn Baldwin */ 184*b9befd33SJohn Baldwin LIST_FOREACH(nt, &p->threadlist, entries) { 185*b9befd33SJohn Baldwin if (nt->tid == lwpid) 186*b9befd33SJohn Baldwin errx(1, "Duplicate thread for LWP %ld", (long)lwpid); 187*b9befd33SJohn Baldwin } 188*b9befd33SJohn Baldwin 189*b9befd33SJohn Baldwin nt = calloc(1, sizeof(struct threadinfo)); 190*b9befd33SJohn Baldwin if (nt == NULL) 191*b9befd33SJohn Baldwin err(1, "calloc() failed"); 192*b9befd33SJohn Baldwin nt->proc = p; 193*b9befd33SJohn Baldwin nt->tid = lwpid; 194*b9befd33SJohn Baldwin LIST_INSERT_HEAD(&p->threadlist, nt, entries); 195*b9befd33SJohn Baldwin return (nt); 196*b9befd33SJohn Baldwin } 197*b9befd33SJohn Baldwin 1982b75c8adSJohn Baldwin static void 199*b9befd33SJohn Baldwin free_thread(struct threadinfo *t) 200*b9befd33SJohn Baldwin { 201*b9befd33SJohn Baldwin 202*b9befd33SJohn Baldwin LIST_REMOVE(t, entries); 203*b9befd33SJohn Baldwin free(t); 204*b9befd33SJohn Baldwin } 205*b9befd33SJohn Baldwin 206*b9befd33SJohn Baldwin static void 207*b9befd33SJohn Baldwin add_threads(struct trussinfo *info, struct procinfo *p) 208*b9befd33SJohn Baldwin { 209*b9befd33SJohn Baldwin struct ptrace_lwpinfo pl; 210*b9befd33SJohn Baldwin struct threadinfo *t; 211*b9befd33SJohn Baldwin lwpid_t *lwps; 212*b9befd33SJohn Baldwin int i, nlwps; 213*b9befd33SJohn Baldwin 214*b9befd33SJohn Baldwin nlwps = ptrace(PT_GETNUMLWPS, p->pid, NULL, 0); 215*b9befd33SJohn Baldwin if (nlwps == -1) 216*b9befd33SJohn Baldwin err(1, "Unable to fetch number of LWPs"); 217*b9befd33SJohn Baldwin assert(nlwps > 0); 218*b9befd33SJohn Baldwin lwps = calloc(nlwps, sizeof(*lwps)); 219*b9befd33SJohn Baldwin nlwps = ptrace(PT_GETLWPLIST, p->pid, (caddr_t)lwps, nlwps); 220*b9befd33SJohn Baldwin if (nlwps == -1) 221*b9befd33SJohn Baldwin err(1, "Unable to fetch LWP list"); 222*b9befd33SJohn Baldwin for (i = 0; i < nlwps; i++) { 223*b9befd33SJohn Baldwin t = new_thread(p, lwps[i]); 224*b9befd33SJohn Baldwin if (ptrace(PT_LWPINFO, lwps[i], (caddr_t)&pl, sizeof(pl)) == -1) 225*b9befd33SJohn Baldwin err(1, "ptrace(PT_LWPINFO)"); 226*b9befd33SJohn Baldwin if (pl.pl_flags & PL_FLAG_SCE) 227*b9befd33SJohn Baldwin enter_syscall(info, t, &pl); 228*b9befd33SJohn Baldwin } 229*b9befd33SJohn Baldwin free(lwps); 230*b9befd33SJohn Baldwin } 231*b9befd33SJohn Baldwin 232*b9befd33SJohn Baldwin static void 233*b9befd33SJohn Baldwin new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 2342b75c8adSJohn Baldwin { 2352b75c8adSJohn Baldwin struct procinfo *np; 2362b75c8adSJohn Baldwin 2372b75c8adSJohn Baldwin /* 2382b75c8adSJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately 239*b9befd33SJohn Baldwin * this will kill any processes truss is attached to. 2402b75c8adSJohn Baldwin */ 2412b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 2422b75c8adSJohn Baldwin if (np->pid == pid) 2432b75c8adSJohn Baldwin errx(1, "Duplicate process for pid %ld", (long)pid); 2442b75c8adSJohn Baldwin } 2452b75c8adSJohn Baldwin 2462b75c8adSJohn Baldwin if (info->flags & FOLLOWFORKS) 2472b75c8adSJohn Baldwin if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) 2482b75c8adSJohn Baldwin err(1, "Unable to follow forks for pid %ld", (long)pid); 249*b9befd33SJohn Baldwin if (ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1) 250*b9befd33SJohn Baldwin err(1, "Unable to enable LWP events for pid %ld", (long)pid); 2512b75c8adSJohn Baldwin np = calloc(1, sizeof(struct procinfo)); 2522b75c8adSJohn Baldwin np->pid = pid; 2532b75c8adSJohn Baldwin np->abi = find_abi(pid); 254*b9befd33SJohn Baldwin LIST_INIT(&np->threadlist); 2552b75c8adSJohn Baldwin LIST_INSERT_HEAD(&info->proclist, np, entries); 256*b9befd33SJohn Baldwin 257*b9befd33SJohn Baldwin if (lwpid != 0) 258*b9befd33SJohn Baldwin new_thread(np, lwpid); 259*b9befd33SJohn Baldwin else 260*b9befd33SJohn Baldwin add_threads(info, np); 2612b75c8adSJohn Baldwin } 2622b75c8adSJohn Baldwin 2632b75c8adSJohn Baldwin static void 2642b75c8adSJohn Baldwin free_proc(struct procinfo *p) 2652b75c8adSJohn Baldwin { 2662b75c8adSJohn Baldwin struct threadinfo *t, *t2; 2672b75c8adSJohn Baldwin 268*b9befd33SJohn Baldwin LIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) { 2692b75c8adSJohn Baldwin free(t); 2702b75c8adSJohn Baldwin } 2712b75c8adSJohn Baldwin LIST_REMOVE(p, entries); 2722b75c8adSJohn Baldwin free(p); 2732b75c8adSJohn Baldwin } 2742b75c8adSJohn Baldwin 2752b75c8adSJohn Baldwin static void 2762b75c8adSJohn Baldwin detach_all_procs(struct trussinfo *info) 2772b75c8adSJohn Baldwin { 2782b75c8adSJohn Baldwin struct procinfo *p, *p2; 2792b75c8adSJohn Baldwin 2802b75c8adSJohn Baldwin LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) { 2812b75c8adSJohn Baldwin detach_proc(p->pid); 2822b75c8adSJohn Baldwin free_proc(p); 2832b75c8adSJohn Baldwin } 2842b75c8adSJohn Baldwin } 2852b75c8adSJohn Baldwin 2862b75c8adSJohn Baldwin static struct procinfo * 2872b75c8adSJohn Baldwin find_proc(struct trussinfo *info, pid_t pid) 2882b75c8adSJohn Baldwin { 2892b75c8adSJohn Baldwin struct procinfo *np; 2902b75c8adSJohn Baldwin 2912b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 2922b75c8adSJohn Baldwin if (np->pid == pid) 2932b75c8adSJohn Baldwin return (np); 2942b75c8adSJohn Baldwin } 2952b75c8adSJohn Baldwin 2962b75c8adSJohn Baldwin return (NULL); 2972b75c8adSJohn Baldwin } 2982b75c8adSJohn Baldwin 2992b75c8adSJohn Baldwin /* 3002b75c8adSJohn Baldwin * Change curthread member based on (pid, lwpid). 3015d2d083cSXin LI */ 3025d2d083cSXin LI static void 3032b75c8adSJohn Baldwin find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 3045d2d083cSXin LI { 3052b75c8adSJohn Baldwin struct procinfo *np; 3062b75c8adSJohn Baldwin struct threadinfo *nt; 30794355cfdSAndrey Zonov 3082b75c8adSJohn Baldwin np = find_proc(info, pid); 3092b75c8adSJohn Baldwin assert(np != NULL); 3102b75c8adSJohn Baldwin 311*b9befd33SJohn Baldwin LIST_FOREACH(nt, &np->threadlist, entries) { 3122b75c8adSJohn Baldwin if (nt->tid == lwpid) { 3132b75c8adSJohn Baldwin info->curthread = nt; 3145d2d083cSXin LI return; 3155d2d083cSXin LI } 3165d2d083cSXin LI } 317*b9befd33SJohn Baldwin errx(1, "could not find thread"); 3185d2d083cSXin LI } 3195d2d083cSXin LI 3205d2d083cSXin LI /* 321*b9befd33SJohn Baldwin * When a process exits, it should have exactly one thread left. 322*b9befd33SJohn Baldwin * All of the other threads should have reported thread exit events. 3232b75c8adSJohn Baldwin */ 3242b75c8adSJohn Baldwin static void 3252b75c8adSJohn Baldwin find_exit_thread(struct trussinfo *info, pid_t pid) 3262b75c8adSJohn Baldwin { 327*b9befd33SJohn Baldwin struct procinfo *p; 3282b75c8adSJohn Baldwin 329*b9befd33SJohn Baldwin p = find_proc(info, pid); 330*b9befd33SJohn Baldwin assert(p != NULL); 3312b75c8adSJohn Baldwin 332*b9befd33SJohn Baldwin info->curthread = LIST_FIRST(&p->threadlist); 333*b9befd33SJohn Baldwin assert(info->curthread != NULL); 334*b9befd33SJohn Baldwin assert(LIST_NEXT(info->curthread, entries) == NULL); 3352b75c8adSJohn Baldwin } 3362b75c8adSJohn Baldwin 3372b75c8adSJohn Baldwin static void 3382b75c8adSJohn Baldwin alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) 3392b75c8adSJohn Baldwin { 3402b75c8adSJohn Baldwin u_int i; 3412b75c8adSJohn Baldwin 3422b75c8adSJohn Baldwin assert(t->in_syscall == 0); 3432b75c8adSJohn Baldwin assert(t->cs.number == 0); 3442b75c8adSJohn Baldwin assert(t->cs.name == NULL); 3452b75c8adSJohn Baldwin assert(t->cs.nargs == 0); 3462b75c8adSJohn Baldwin for (i = 0; i < nitems(t->cs.s_args); i++) 3472b75c8adSJohn Baldwin assert(t->cs.s_args[i] == NULL); 3482b75c8adSJohn Baldwin memset(t->cs.args, 0, sizeof(t->cs.args)); 3492b75c8adSJohn Baldwin t->cs.number = pl->pl_syscall_code; 3502b75c8adSJohn Baldwin t->in_syscall = 1; 3512b75c8adSJohn Baldwin } 3522b75c8adSJohn Baldwin 3532b75c8adSJohn Baldwin static void 3542b75c8adSJohn Baldwin free_syscall(struct threadinfo *t) 3552b75c8adSJohn Baldwin { 3562b75c8adSJohn Baldwin u_int i; 3572b75c8adSJohn Baldwin 3582b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) 3592b75c8adSJohn Baldwin free(t->cs.s_args[i]); 3602b75c8adSJohn Baldwin memset(&t->cs, 0, sizeof(t->cs)); 3612b75c8adSJohn Baldwin t->in_syscall = 0; 3622b75c8adSJohn Baldwin } 3632b75c8adSJohn Baldwin 3642b75c8adSJohn Baldwin static void 365*b9befd33SJohn Baldwin enter_syscall(struct trussinfo *info, struct threadinfo *t, 366*b9befd33SJohn Baldwin struct ptrace_lwpinfo *pl) 3672b75c8adSJohn Baldwin { 3682b75c8adSJohn Baldwin struct syscall *sc; 3692b75c8adSJohn Baldwin u_int i, narg; 3702b75c8adSJohn Baldwin 3712b75c8adSJohn Baldwin alloc_syscall(t, pl); 3722b75c8adSJohn Baldwin narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args)); 3732b75c8adSJohn Baldwin if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) { 3742b75c8adSJohn Baldwin free_syscall(t); 3752b75c8adSJohn Baldwin return; 3762b75c8adSJohn Baldwin } 3772b75c8adSJohn Baldwin 378a5f14abfSJohn Baldwin t->cs.name = sysdecode_syscallname(t->proc->abi->abi, t->cs.number); 3792b75c8adSJohn Baldwin if (t->cs.name == NULL) 3802b75c8adSJohn Baldwin fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", 3812b75c8adSJohn Baldwin t->proc->abi->type, t->cs.number); 3822b75c8adSJohn Baldwin 3836c61b0f3SBryan Drewery sc = get_syscall(t->cs.name, narg); 3842b75c8adSJohn Baldwin t->cs.nargs = sc->nargs; 3852b75c8adSJohn Baldwin assert(sc->nargs <= nitems(t->cs.s_args)); 3862b75c8adSJohn Baldwin 3872b75c8adSJohn Baldwin t->cs.sc = sc; 3882b75c8adSJohn Baldwin 3892b75c8adSJohn Baldwin /* 3902b75c8adSJohn Baldwin * At this point, we set up the system call arguments. 3912b75c8adSJohn Baldwin * We ignore any OUT ones, however -- those are arguments that 3922b75c8adSJohn Baldwin * are set by the system call, and so are probably meaningless 3932b75c8adSJohn Baldwin * now. This doesn't currently support arguments that are 3942b75c8adSJohn Baldwin * passed in *and* out, however. 3952b75c8adSJohn Baldwin */ 3962b75c8adSJohn Baldwin if (t->cs.name != NULL) { 3972b75c8adSJohn Baldwin #if DEBUG 3982b75c8adSJohn Baldwin fprintf(stderr, "syscall %s(", t->cs.name); 3992b75c8adSJohn Baldwin #endif 4002b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) { 4012b75c8adSJohn Baldwin #if DEBUG 4022b75c8adSJohn Baldwin fprintf(stderr, "0x%lx%s", sc ? 4032b75c8adSJohn Baldwin t->cs.args[sc->args[i].offset] : t->cs.args[i], 4042b75c8adSJohn Baldwin i < (t->cs.nargs - 1) ? "," : ""); 4052b75c8adSJohn Baldwin #endif 4066c61b0f3SBryan Drewery if (!(sc->args[i].type & OUT)) { 4072b75c8adSJohn Baldwin t->cs.s_args[i] = print_arg(&sc->args[i], 4082b75c8adSJohn Baldwin t->cs.args, 0, info); 4092b75c8adSJohn Baldwin } 4102b75c8adSJohn Baldwin } 4112b75c8adSJohn Baldwin #if DEBUG 4122b75c8adSJohn Baldwin fprintf(stderr, ")\n"); 4132b75c8adSJohn Baldwin #endif 4142b75c8adSJohn Baldwin } 4152b75c8adSJohn Baldwin 4162b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->before); 4172b75c8adSJohn Baldwin } 4182b75c8adSJohn Baldwin 419*b9befd33SJohn Baldwin /* 420*b9befd33SJohn Baldwin * When a thread exits voluntarily (including when a thread calls 421*b9befd33SJohn Baldwin * exit() to trigger a process exit), the thread's internal state 422*b9befd33SJohn Baldwin * holds the arguments passed to the exit system call. When the 423*b9befd33SJohn Baldwin * thread's exit is reported, log that system call without a return 424*b9befd33SJohn Baldwin * value. 425*b9befd33SJohn Baldwin */ 426*b9befd33SJohn Baldwin static void 427*b9befd33SJohn Baldwin thread_exit_syscall(struct trussinfo *info) 428*b9befd33SJohn Baldwin { 429*b9befd33SJohn Baldwin struct threadinfo *t; 430*b9befd33SJohn Baldwin 431*b9befd33SJohn Baldwin t = info->curthread; 432*b9befd33SJohn Baldwin if (!t->in_syscall) 433*b9befd33SJohn Baldwin return; 434*b9befd33SJohn Baldwin 435*b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 436*b9befd33SJohn Baldwin 437*b9befd33SJohn Baldwin print_syscall_ret(info, 0, NULL); 438*b9befd33SJohn Baldwin free_syscall(t); 439*b9befd33SJohn Baldwin } 440*b9befd33SJohn Baldwin 4412b75c8adSJohn Baldwin static void 4422b75c8adSJohn Baldwin exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 4432b75c8adSJohn Baldwin { 4442b75c8adSJohn Baldwin struct threadinfo *t; 4452b75c8adSJohn Baldwin struct procinfo *p; 4462b75c8adSJohn Baldwin struct syscall *sc; 4472b75c8adSJohn Baldwin long retval[2]; 4482b75c8adSJohn Baldwin u_int i; 4492b75c8adSJohn Baldwin int errorp; 4502b75c8adSJohn Baldwin 4512b75c8adSJohn Baldwin t = info->curthread; 4522b75c8adSJohn Baldwin if (!t->in_syscall) 4532b75c8adSJohn Baldwin return; 4542b75c8adSJohn Baldwin 4552b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 4562b75c8adSJohn Baldwin p = t->proc; 4572b75c8adSJohn Baldwin if (p->abi->fetch_retval(info, retval, &errorp) < 0) { 4582b75c8adSJohn Baldwin free_syscall(t); 4592b75c8adSJohn Baldwin return; 4602b75c8adSJohn Baldwin } 4612b75c8adSJohn Baldwin 4622b75c8adSJohn Baldwin sc = t->cs.sc; 4632b75c8adSJohn Baldwin /* 4642b75c8adSJohn Baldwin * Here, we only look for arguments that have OUT masked in -- 4652b75c8adSJohn Baldwin * otherwise, they were handled in enter_syscall(). 4662b75c8adSJohn Baldwin */ 4672b75c8adSJohn Baldwin for (i = 0; i < sc->nargs; i++) { 4682b75c8adSJohn Baldwin char *temp; 4692b75c8adSJohn Baldwin 4702b75c8adSJohn Baldwin if (sc->args[i].type & OUT) { 4712b75c8adSJohn Baldwin /* 4722b75c8adSJohn Baldwin * If an error occurred, then don't bother 4732b75c8adSJohn Baldwin * getting the data; it may not be valid. 4742b75c8adSJohn Baldwin */ 4752b75c8adSJohn Baldwin if (errorp) { 4762b75c8adSJohn Baldwin asprintf(&temp, "0x%lx", 4772b75c8adSJohn Baldwin t->cs.args[sc->args[i].offset]); 4782b75c8adSJohn Baldwin } else { 4792b75c8adSJohn Baldwin temp = print_arg(&sc->args[i], 4802b75c8adSJohn Baldwin t->cs.args, retval, info); 4812b75c8adSJohn Baldwin } 4822b75c8adSJohn Baldwin t->cs.s_args[i] = temp; 4832b75c8adSJohn Baldwin } 4842b75c8adSJohn Baldwin } 4852b75c8adSJohn Baldwin 48600ddbdf2SJohn Baldwin print_syscall_ret(info, errorp, retval); 4872b75c8adSJohn Baldwin free_syscall(t); 4882b75c8adSJohn Baldwin 4892b75c8adSJohn Baldwin /* 4902b75c8adSJohn Baldwin * If the process executed a new image, check the ABI. If the 4912b75c8adSJohn Baldwin * new ABI isn't supported, stop tracing this process. 4922b75c8adSJohn Baldwin */ 4932b75c8adSJohn Baldwin if (pl->pl_flags & PL_FLAG_EXEC) { 494*b9befd33SJohn Baldwin assert(LIST_NEXT(LIST_FIRST(&p->threadlist), entries) == NULL); 4952b75c8adSJohn Baldwin p->abi = find_abi(p->pid); 4962b75c8adSJohn Baldwin if (p->abi == NULL) { 4972b75c8adSJohn Baldwin if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0) 4982b75c8adSJohn Baldwin err(1, "Can not detach the process"); 4992b75c8adSJohn Baldwin free_proc(p); 5002b75c8adSJohn Baldwin } 5012b75c8adSJohn Baldwin } 5022b75c8adSJohn Baldwin } 5032b75c8adSJohn Baldwin 504d70876fdSJohn Baldwin int 505d70876fdSJohn Baldwin print_line_prefix(struct trussinfo *info) 506d70876fdSJohn Baldwin { 507d70876fdSJohn Baldwin struct timespec timediff; 508d70876fdSJohn Baldwin struct threadinfo *t; 509d70876fdSJohn Baldwin int len; 510d70876fdSJohn Baldwin 511d70876fdSJohn Baldwin len = 0; 512d70876fdSJohn Baldwin t = info->curthread; 513d70876fdSJohn Baldwin if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) { 514d70876fdSJohn Baldwin if (info->flags & FOLLOWFORKS) 515d70876fdSJohn Baldwin len += fprintf(info->outfile, "%5d", t->proc->pid); 516d70876fdSJohn Baldwin if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) == 517d70876fdSJohn Baldwin (FOLLOWFORKS | DISPLAYTIDS)) 518d70876fdSJohn Baldwin len += fprintf(info->outfile, " "); 519d70876fdSJohn Baldwin if (info->flags & DISPLAYTIDS) 520d70876fdSJohn Baldwin len += fprintf(info->outfile, "%6d", t->tid); 521d70876fdSJohn Baldwin len += fprintf(info->outfile, ": "); 522d70876fdSJohn Baldwin } 523d70876fdSJohn Baldwin if (info->flags & ABSOLUTETIMESTAMPS) { 524d70876fdSJohn Baldwin timespecsubt(&t->after, &info->start_time, &timediff); 525d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 526d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 527d70876fdSJohn Baldwin } 528d70876fdSJohn Baldwin if (info->flags & RELATIVETIMESTAMPS) { 529d70876fdSJohn Baldwin timespecsubt(&t->after, &t->before, &timediff); 530d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 531d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 532d70876fdSJohn Baldwin } 533d70876fdSJohn Baldwin return (len); 534d70876fdSJohn Baldwin } 535d70876fdSJohn Baldwin 5362b75c8adSJohn Baldwin static void 537*b9befd33SJohn Baldwin report_thread_death(struct trussinfo *info) 538*b9befd33SJohn Baldwin { 539*b9befd33SJohn Baldwin struct threadinfo *t; 540*b9befd33SJohn Baldwin 541*b9befd33SJohn Baldwin t = info->curthread; 542*b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 543*b9befd33SJohn Baldwin print_line_prefix(info); 544*b9befd33SJohn Baldwin fprintf(info->outfile, "<thread %ld exited>\n", (long)t->tid); 545*b9befd33SJohn Baldwin } 546*b9befd33SJohn Baldwin 547*b9befd33SJohn Baldwin static void 548*b9befd33SJohn Baldwin report_thread_birth(struct trussinfo *info) 549*b9befd33SJohn Baldwin { 550*b9befd33SJohn Baldwin struct threadinfo *t; 551*b9befd33SJohn Baldwin 552*b9befd33SJohn Baldwin t = info->curthread; 553*b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 554*b9befd33SJohn Baldwin t->before = t->after; 555*b9befd33SJohn Baldwin print_line_prefix(info); 556*b9befd33SJohn Baldwin fprintf(info->outfile, "<new thread %ld>\n", (long)t->tid); 557*b9befd33SJohn Baldwin } 558*b9befd33SJohn Baldwin 559*b9befd33SJohn Baldwin static void 5602b75c8adSJohn Baldwin report_exit(struct trussinfo *info, siginfo_t *si) 5612b75c8adSJohn Baldwin { 562d70876fdSJohn Baldwin struct threadinfo *t; 5632b75c8adSJohn Baldwin 564d70876fdSJohn Baldwin t = info->curthread; 565d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 566d70876fdSJohn Baldwin print_line_prefix(info); 5672b75c8adSJohn Baldwin if (si->si_code == CLD_EXITED) 5682b75c8adSJohn Baldwin fprintf(info->outfile, "process exit, rval = %u\n", 5692b75c8adSJohn Baldwin si->si_status); 5702b75c8adSJohn Baldwin else 5712b75c8adSJohn Baldwin fprintf(info->outfile, "process killed, signal = %u%s\n", 5722b75c8adSJohn Baldwin si->si_status, si->si_code == CLD_DUMPED ? 5732b75c8adSJohn Baldwin " (core dumped)" : ""); 5742b75c8adSJohn Baldwin } 5752b75c8adSJohn Baldwin 5762b75c8adSJohn Baldwin static void 577d70876fdSJohn Baldwin report_new_child(struct trussinfo *info) 5782b75c8adSJohn Baldwin { 579d70876fdSJohn Baldwin struct threadinfo *t; 5802b75c8adSJohn Baldwin 581d70876fdSJohn Baldwin t = info->curthread; 582d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 583d70876fdSJohn Baldwin t->before = t->after; 584d70876fdSJohn Baldwin print_line_prefix(info); 5852b75c8adSJohn Baldwin fprintf(info->outfile, "<new process>\n"); 5862b75c8adSJohn Baldwin } 5872b75c8adSJohn Baldwin 5882b75c8adSJohn Baldwin static void 5892b75c8adSJohn Baldwin report_signal(struct trussinfo *info, siginfo_t *si) 5902b75c8adSJohn Baldwin { 591d70876fdSJohn Baldwin struct threadinfo *t; 5922b75c8adSJohn Baldwin char *signame; 5932b75c8adSJohn Baldwin 594d70876fdSJohn Baldwin t = info->curthread; 595d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 596d70876fdSJohn Baldwin print_line_prefix(info); 5972b75c8adSJohn Baldwin signame = strsig(si->si_status); 5982b75c8adSJohn Baldwin fprintf(info->outfile, "SIGNAL %u (%s)\n", si->si_status, 5992b75c8adSJohn Baldwin signame == NULL ? "?" : signame); 6002b75c8adSJohn Baldwin } 6012b75c8adSJohn Baldwin 6022b75c8adSJohn Baldwin /* 6032b75c8adSJohn Baldwin * Wait for events until all the processes have exited or truss has been 6042b75c8adSJohn Baldwin * asked to stop. 6055d2d083cSXin LI */ 6065d2d083cSXin LI void 6072b75c8adSJohn Baldwin eventloop(struct trussinfo *info) 6085d2d083cSXin LI { 6092b75c8adSJohn Baldwin struct ptrace_lwpinfo pl; 6102b75c8adSJohn Baldwin siginfo_t si; 6112b75c8adSJohn Baldwin int pending_signal; 6125d2d083cSXin LI 6132b75c8adSJohn Baldwin while (!LIST_EMPTY(&info->proclist)) { 614896fc463SAndrey Zonov if (detaching) { 6152b75c8adSJohn Baldwin detach_all_procs(info); 616896fc463SAndrey Zonov return; 617896fc463SAndrey Zonov } 618896fc463SAndrey Zonov 6192b75c8adSJohn Baldwin if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { 620896fc463SAndrey Zonov if (errno == EINTR) 6212b75c8adSJohn Baldwin continue; 6222b75c8adSJohn Baldwin err(1, "Unexpected error from waitid"); 623896fc463SAndrey Zonov } 6245d2d083cSXin LI 6252b75c8adSJohn Baldwin assert(si.si_signo == SIGCHLD); 6262b75c8adSJohn Baldwin 6272b75c8adSJohn Baldwin switch (si.si_code) { 6282b75c8adSJohn Baldwin case CLD_EXITED: 6292b75c8adSJohn Baldwin case CLD_KILLED: 6302b75c8adSJohn Baldwin case CLD_DUMPED: 6312b75c8adSJohn Baldwin find_exit_thread(info, si.si_pid); 632*b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) { 633*b9befd33SJohn Baldwin if (si.si_code == CLD_EXITED) 634*b9befd33SJohn Baldwin thread_exit_syscall(info); 6352b75c8adSJohn Baldwin report_exit(info, &si); 636*b9befd33SJohn Baldwin } 6372b75c8adSJohn Baldwin free_proc(info->curthread->proc); 6382b75c8adSJohn Baldwin info->curthread = NULL; 6395d2d083cSXin LI break; 6402b75c8adSJohn Baldwin case CLD_TRAPPED: 6412b75c8adSJohn Baldwin if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl, 6422b75c8adSJohn Baldwin sizeof(pl)) == -1) 6432b75c8adSJohn Baldwin err(1, "ptrace(PT_LWPINFO)"); 6442b75c8adSJohn Baldwin 6452b75c8adSJohn Baldwin if (pl.pl_flags & PL_FLAG_CHILD) { 646*b9befd33SJohn Baldwin new_proc(info, si.si_pid, pl.pl_lwpid); 6472b75c8adSJohn Baldwin assert(LIST_FIRST(&info->proclist)->abi != 6482b75c8adSJohn Baldwin NULL); 649*b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_BORN) 650*b9befd33SJohn Baldwin new_thread(find_proc(info, si.si_pid), 651*b9befd33SJohn Baldwin pl.pl_lwpid); 6522b75c8adSJohn Baldwin find_thread(info, si.si_pid, pl.pl_lwpid); 6532b75c8adSJohn Baldwin 65494746562SBryan Drewery if (si.si_status == SIGTRAP && 655*b9befd33SJohn Baldwin (pl.pl_flags & (PL_FLAG_BORN|PL_FLAG_EXITED| 656*b9befd33SJohn Baldwin PL_FLAG_SCE|PL_FLAG_SCX)) != 0) { 657*b9befd33SJohn Baldwin if (pl.pl_flags & PL_FLAG_BORN) { 658*b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) 659*b9befd33SJohn Baldwin report_thread_birth(info); 660*b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_EXITED) { 661*b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) 662*b9befd33SJohn Baldwin report_thread_death(info); 663*b9befd33SJohn Baldwin free_thread(info->curthread); 664*b9befd33SJohn Baldwin info->curthread = NULL; 665*b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_SCE) 666*b9befd33SJohn Baldwin enter_syscall(info, info->curthread, &pl); 6672b75c8adSJohn Baldwin else if (pl.pl_flags & PL_FLAG_SCX) 6682b75c8adSJohn Baldwin exit_syscall(info, &pl); 6692b75c8adSJohn Baldwin pending_signal = 0; 6702b75c8adSJohn Baldwin } else if (pl.pl_flags & PL_FLAG_CHILD) { 6712b75c8adSJohn Baldwin if ((info->flags & COUNTONLY) == 0) 672d70876fdSJohn Baldwin report_new_child(info); 6732b75c8adSJohn Baldwin pending_signal = 0; 6742b75c8adSJohn Baldwin } else { 6752b75c8adSJohn Baldwin if ((info->flags & NOSIGS) == 0) 6762b75c8adSJohn Baldwin report_signal(info, &si); 6772b75c8adSJohn Baldwin pending_signal = si.si_status; 67897695ad4SKonstantin Belousov } 6792b75c8adSJohn Baldwin ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1, 6802b75c8adSJohn Baldwin pending_signal); 6812b75c8adSJohn Baldwin break; 6822b75c8adSJohn Baldwin case CLD_STOPPED: 6832b75c8adSJohn Baldwin errx(1, "waitid reported CLD_STOPPED"); 6842b75c8adSJohn Baldwin case CLD_CONTINUED: 6855d2d083cSXin LI break; 6865d2d083cSXin LI } 6875d2d083cSXin LI } 6885d2d083cSXin LI } 689