1f0bcd5c3SXin LI /*- 2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3df57947fSPedro F. Giffuni * 40a6c71f8SWarner Losh * Copyright 1997 Sean Eric Fagan 509d64da3SSean Eric Fagan * 609d64da3SSean Eric Fagan * Redistribution and use in source and binary forms, with or without 709d64da3SSean Eric Fagan * modification, are permitted provided that the following conditions 809d64da3SSean Eric Fagan * are met: 909d64da3SSean Eric Fagan * 1. Redistributions of source code must retain the above copyright 1009d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer. 1109d64da3SSean Eric Fagan * 2. Redistributions in binary form must reproduce the above copyright 1209d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer in the 1309d64da3SSean Eric Fagan * documentation and/or other materials provided with the distribution. 1409d64da3SSean Eric Fagan * 3. All advertising materials mentioning features or use of this software 1509d64da3SSean Eric Fagan * must display the following acknowledgement: 1609d64da3SSean Eric Fagan * This product includes software developed by Sean Eric Fagan 1709d64da3SSean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote 1809d64da3SSean Eric Fagan * products derived from this software without specific prior written 1909d64da3SSean Eric Fagan * permission. 2009d64da3SSean Eric Fagan * 2109d64da3SSean Eric Fagan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2209d64da3SSean Eric Fagan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2309d64da3SSean Eric Fagan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2409d64da3SSean Eric Fagan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2509d64da3SSean Eric Fagan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2609d64da3SSean Eric Fagan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2709d64da3SSean Eric Fagan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2809d64da3SSean Eric Fagan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2909d64da3SSean Eric Fagan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3009d64da3SSean Eric Fagan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3109d64da3SSean Eric Fagan * SUCH DAMAGE. 3209d64da3SSean Eric Fagan */ 3309d64da3SSean Eric Fagan 34b956c13cSPhilippe Charnier #include <sys/cdefs.h> 35b956c13cSPhilippe Charnier __FBSDID("$FreeBSD$"); 363cf51049SPhilippe Charnier 3709d64da3SSean Eric Fagan /* 38bbeaf6c0SSean Eric Fagan * Various setup functions for truss. Not the cleanest-written code, 39bbeaf6c0SSean Eric Fagan * I'm afraid. 40bbeaf6c0SSean Eric Fagan */ 41bbeaf6c0SSean Eric Fagan 425d2d083cSXin LI #include <sys/ptrace.h> 432b75c8adSJohn Baldwin #include <sys/sysctl.h> 44*6040822cSAlan Somers #include <sys/time.h> 45580e0a2bSDag-Erling Smørgrav #include <sys/wait.h> 46580e0a2bSDag-Erling Smørgrav 472b75c8adSJohn Baldwin #include <assert.h> 483cf51049SPhilippe Charnier #include <err.h> 49821df508SXin LI #include <errno.h> 503cf51049SPhilippe Charnier #include <signal.h> 519289f547SJohn Baldwin #include <stdbool.h> 522b75c8adSJohn Baldwin #include <stdint.h> 53bbeaf6c0SSean Eric Fagan #include <stdio.h> 54bbeaf6c0SSean Eric Fagan #include <stdlib.h> 55821df508SXin LI #include <string.h> 56a5f14abfSJohn Baldwin #include <sysdecode.h> 57821df508SXin LI #include <time.h> 58bbeaf6c0SSean Eric Fagan #include <unistd.h> 59bbeaf6c0SSean Eric Fagan 60ec0bed25SMatthew N. Dodd #include "truss.h" 612b75c8adSJohn Baldwin #include "syscall.h" 621be5d704SMark Murray #include "extern.h" 631be5d704SMark Murray 642b75c8adSJohn Baldwin SET_DECLARE(procabi, struct procabi); 652b75c8adSJohn Baldwin 66896fc463SAndrey Zonov static sig_atomic_t detaching; 67bbeaf6c0SSean Eric Fagan 68b9befd33SJohn Baldwin static void enter_syscall(struct trussinfo *, struct threadinfo *, 69b9befd33SJohn Baldwin struct ptrace_lwpinfo *); 70b9befd33SJohn Baldwin static void new_proc(struct trussinfo *, pid_t, lwpid_t); 712b75c8adSJohn Baldwin 72bbeaf6c0SSean Eric Fagan /* 73bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 742b75c8adSJohn Baldwin * is fork(), enable tracing in the child, and then exec the given 752b75c8adSJohn Baldwin * command. At that point, the child process stops, and the parent 762b75c8adSJohn Baldwin * can wake up and deal with it. 77bbeaf6c0SSean Eric Fagan */ 782b75c8adSJohn Baldwin void 792b75c8adSJohn Baldwin setup_and_wait(struct trussinfo *info, char *command[]) 805321ae86SAlfred Perlstein { 81be305c9cSAndrey Zonov pid_t pid; 82bbeaf6c0SSean Eric Fagan 835d2d083cSXin LI pid = vfork(); 8494355cfdSAndrey Zonov if (pid == -1) 851fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 86bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 875d2d083cSXin LI ptrace(PT_TRACE_ME, 0, 0, 0); 88bbeaf6c0SSean Eric Fagan execvp(command[0], command); 895d2d083cSXin LI err(1, "execvp %s", command[0]); 90bbeaf6c0SSean Eric Fagan } 915d2d083cSXin LI 92bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 93310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 945d2d083cSXin LI err(1, "unexpect stop in waitpid"); 95bbeaf6c0SSean Eric Fagan 96b9befd33SJohn Baldwin new_proc(info, pid, 0); 97bbeaf6c0SSean Eric Fagan } 98bbeaf6c0SSean Eric Fagan 99bbeaf6c0SSean Eric Fagan /* 1002b75c8adSJohn Baldwin * start_tracing is called to attach to an existing process. 101bbeaf6c0SSean Eric Fagan */ 1022b75c8adSJohn Baldwin void 1032b75c8adSJohn Baldwin start_tracing(struct trussinfo *info, pid_t pid) 1045321ae86SAlfred Perlstein { 105310da894SAndrey Zonov int ret, retry; 1065321ae86SAlfred Perlstein 10794355cfdSAndrey Zonov retry = 10; 1085d2d083cSXin LI do { 1095d2d083cSXin LI ret = ptrace(PT_ATTACH, pid, NULL, 0); 1105d2d083cSXin LI usleep(200); 1115d2d083cSXin LI } while (ret && retry-- > 0); 1125d2d083cSXin LI if (ret) 1135d2d083cSXin LI err(1, "can not attach to target process"); 11420fa828fSSean Eric Fagan 115310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 1165d2d083cSXin LI err(1, "Unexpect stop in waitpid"); 117bbeaf6c0SSean Eric Fagan 118b9befd33SJohn Baldwin new_proc(info, pid, 0); 119bbeaf6c0SSean Eric Fagan } 120bbeaf6c0SSean Eric Fagan 121bbeaf6c0SSean Eric Fagan /* 122bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 123bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 124bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 125bbeaf6c0SSean Eric Fagan * process. 126bbeaf6c0SSean Eric Fagan */ 127bbeaf6c0SSean Eric Fagan void 1285d2d083cSXin LI restore_proc(int signo __unused) 1295d2d083cSXin LI { 130896fc463SAndrey Zonov 131896fc463SAndrey Zonov detaching = 1; 132896fc463SAndrey Zonov } 133896fc463SAndrey Zonov 1342b75c8adSJohn Baldwin static void 135896fc463SAndrey Zonov detach_proc(pid_t pid) 136896fc463SAndrey Zonov { 137bbeaf6c0SSean Eric Fagan 1385d2d083cSXin LI /* stop the child so that we can detach */ 139896fc463SAndrey Zonov kill(pid, SIGSTOP); 1402b75c8adSJohn Baldwin if (waitpid(pid, NULL, 0) < 0) 1415d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 1425d2d083cSXin LI 143896fc463SAndrey Zonov if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) 1445d2d083cSXin LI err(1, "Can not detach the process"); 1455d2d083cSXin LI 146896fc463SAndrey Zonov kill(pid, SIGCONT); 147bbeaf6c0SSean Eric Fagan } 1485d2d083cSXin LI 1495d2d083cSXin LI /* 1502b75c8adSJohn Baldwin * Determine the ABI. This is called after every exec, and when 1512b75c8adSJohn Baldwin * a process is first monitored. 1522b75c8adSJohn Baldwin */ 1532b75c8adSJohn Baldwin static struct procabi * 1542b75c8adSJohn Baldwin find_abi(pid_t pid) 1552b75c8adSJohn Baldwin { 1562b75c8adSJohn Baldwin struct procabi **pabi; 1572b75c8adSJohn Baldwin size_t len; 1582b75c8adSJohn Baldwin int error; 1592b75c8adSJohn Baldwin int mib[4]; 1602b75c8adSJohn Baldwin char progt[32]; 1612b75c8adSJohn Baldwin 1622b75c8adSJohn Baldwin len = sizeof(progt); 1632b75c8adSJohn Baldwin mib[0] = CTL_KERN; 1642b75c8adSJohn Baldwin mib[1] = KERN_PROC; 1652b75c8adSJohn Baldwin mib[2] = KERN_PROC_SV_NAME; 1662b75c8adSJohn Baldwin mib[3] = pid; 1672b75c8adSJohn Baldwin error = sysctl(mib, 4, progt, &len, NULL, 0); 1682b75c8adSJohn Baldwin if (error != 0) 1692b75c8adSJohn Baldwin err(2, "can not get sysvec name"); 1702b75c8adSJohn Baldwin 1712b75c8adSJohn Baldwin SET_FOREACH(pabi, procabi) { 1722b75c8adSJohn Baldwin if (strcmp((*pabi)->type, progt) == 0) 1732b75c8adSJohn Baldwin return (*pabi); 1742b75c8adSJohn Baldwin } 1752b75c8adSJohn Baldwin warnx("ABI %s for pid %ld is not supported", progt, (long)pid); 1762b75c8adSJohn Baldwin return (NULL); 1772b75c8adSJohn Baldwin } 1782b75c8adSJohn Baldwin 179b9befd33SJohn Baldwin static struct threadinfo * 180b9befd33SJohn Baldwin new_thread(struct procinfo *p, lwpid_t lwpid) 181b9befd33SJohn Baldwin { 182b9befd33SJohn Baldwin struct threadinfo *nt; 183b9befd33SJohn Baldwin 184b9befd33SJohn Baldwin /* 185b9befd33SJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately 186b9befd33SJohn Baldwin * this will kill any processes truss is attached to. 187b9befd33SJohn Baldwin */ 188b9befd33SJohn Baldwin LIST_FOREACH(nt, &p->threadlist, entries) { 189b9befd33SJohn Baldwin if (nt->tid == lwpid) 190b9befd33SJohn Baldwin errx(1, "Duplicate thread for LWP %ld", (long)lwpid); 191b9befd33SJohn Baldwin } 192b9befd33SJohn Baldwin 193b9befd33SJohn Baldwin nt = calloc(1, sizeof(struct threadinfo)); 194b9befd33SJohn Baldwin if (nt == NULL) 195b9befd33SJohn Baldwin err(1, "calloc() failed"); 196b9befd33SJohn Baldwin nt->proc = p; 197b9befd33SJohn Baldwin nt->tid = lwpid; 198b9befd33SJohn Baldwin LIST_INSERT_HEAD(&p->threadlist, nt, entries); 199b9befd33SJohn Baldwin return (nt); 200b9befd33SJohn Baldwin } 201b9befd33SJohn Baldwin 2022b75c8adSJohn Baldwin static void 203b9befd33SJohn Baldwin free_thread(struct threadinfo *t) 204b9befd33SJohn Baldwin { 205b9befd33SJohn Baldwin 206b9befd33SJohn Baldwin LIST_REMOVE(t, entries); 207b9befd33SJohn Baldwin free(t); 208b9befd33SJohn Baldwin } 209b9befd33SJohn Baldwin 210b9befd33SJohn Baldwin static void 211b9befd33SJohn Baldwin add_threads(struct trussinfo *info, struct procinfo *p) 212b9befd33SJohn Baldwin { 213b9befd33SJohn Baldwin struct ptrace_lwpinfo pl; 214b9befd33SJohn Baldwin struct threadinfo *t; 215b9befd33SJohn Baldwin lwpid_t *lwps; 216b9befd33SJohn Baldwin int i, nlwps; 217b9befd33SJohn Baldwin 218b9befd33SJohn Baldwin nlwps = ptrace(PT_GETNUMLWPS, p->pid, NULL, 0); 219b9befd33SJohn Baldwin if (nlwps == -1) 220b9befd33SJohn Baldwin err(1, "Unable to fetch number of LWPs"); 221b9befd33SJohn Baldwin assert(nlwps > 0); 222b9befd33SJohn Baldwin lwps = calloc(nlwps, sizeof(*lwps)); 223b9befd33SJohn Baldwin nlwps = ptrace(PT_GETLWPLIST, p->pid, (caddr_t)lwps, nlwps); 224b9befd33SJohn Baldwin if (nlwps == -1) 225b9befd33SJohn Baldwin err(1, "Unable to fetch LWP list"); 226b9befd33SJohn Baldwin for (i = 0; i < nlwps; i++) { 227b9befd33SJohn Baldwin t = new_thread(p, lwps[i]); 228b9befd33SJohn Baldwin if (ptrace(PT_LWPINFO, lwps[i], (caddr_t)&pl, sizeof(pl)) == -1) 229b9befd33SJohn Baldwin err(1, "ptrace(PT_LWPINFO)"); 2300f21f528SBaptiste Daroussin if (pl.pl_flags & PL_FLAG_SCE) { 2310f21f528SBaptiste Daroussin info->curthread = t; 232b9befd33SJohn Baldwin enter_syscall(info, t, &pl); 233b9befd33SJohn Baldwin } 2340f21f528SBaptiste Daroussin } 235b9befd33SJohn Baldwin free(lwps); 236b9befd33SJohn Baldwin } 237b9befd33SJohn Baldwin 238b9befd33SJohn Baldwin static void 239b9befd33SJohn Baldwin new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 2402b75c8adSJohn Baldwin { 2412b75c8adSJohn Baldwin struct procinfo *np; 2422b75c8adSJohn Baldwin 2432b75c8adSJohn Baldwin /* 2442b75c8adSJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately 245b9befd33SJohn Baldwin * this will kill any processes truss is attached to. 2462b75c8adSJohn Baldwin */ 2472b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 2482b75c8adSJohn Baldwin if (np->pid == pid) 2492b75c8adSJohn Baldwin errx(1, "Duplicate process for pid %ld", (long)pid); 2502b75c8adSJohn Baldwin } 2512b75c8adSJohn Baldwin 2522b75c8adSJohn Baldwin if (info->flags & FOLLOWFORKS) 2532b75c8adSJohn Baldwin if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) 2542b75c8adSJohn Baldwin err(1, "Unable to follow forks for pid %ld", (long)pid); 255b9befd33SJohn Baldwin if (ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1) 256b9befd33SJohn Baldwin err(1, "Unable to enable LWP events for pid %ld", (long)pid); 2572b75c8adSJohn Baldwin np = calloc(1, sizeof(struct procinfo)); 2582b75c8adSJohn Baldwin np->pid = pid; 2592b75c8adSJohn Baldwin np->abi = find_abi(pid); 260b9befd33SJohn Baldwin LIST_INIT(&np->threadlist); 2612b75c8adSJohn Baldwin LIST_INSERT_HEAD(&info->proclist, np, entries); 262b9befd33SJohn Baldwin 263b9befd33SJohn Baldwin if (lwpid != 0) 264b9befd33SJohn Baldwin new_thread(np, lwpid); 265b9befd33SJohn Baldwin else 266b9befd33SJohn Baldwin add_threads(info, np); 2672b75c8adSJohn Baldwin } 2682b75c8adSJohn Baldwin 2692b75c8adSJohn Baldwin static void 2702b75c8adSJohn Baldwin free_proc(struct procinfo *p) 2712b75c8adSJohn Baldwin { 2722b75c8adSJohn Baldwin struct threadinfo *t, *t2; 2732b75c8adSJohn Baldwin 274b9befd33SJohn Baldwin LIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) { 2752b75c8adSJohn Baldwin free(t); 2762b75c8adSJohn Baldwin } 2772b75c8adSJohn Baldwin LIST_REMOVE(p, entries); 2782b75c8adSJohn Baldwin free(p); 2792b75c8adSJohn Baldwin } 2802b75c8adSJohn Baldwin 2812b75c8adSJohn Baldwin static void 2822b75c8adSJohn Baldwin detach_all_procs(struct trussinfo *info) 2832b75c8adSJohn Baldwin { 2842b75c8adSJohn Baldwin struct procinfo *p, *p2; 2852b75c8adSJohn Baldwin 2862b75c8adSJohn Baldwin LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) { 2872b75c8adSJohn Baldwin detach_proc(p->pid); 2882b75c8adSJohn Baldwin free_proc(p); 2892b75c8adSJohn Baldwin } 2902b75c8adSJohn Baldwin } 2912b75c8adSJohn Baldwin 2922b75c8adSJohn Baldwin static struct procinfo * 2932b75c8adSJohn Baldwin find_proc(struct trussinfo *info, pid_t pid) 2942b75c8adSJohn Baldwin { 2952b75c8adSJohn Baldwin struct procinfo *np; 2962b75c8adSJohn Baldwin 2972b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 2982b75c8adSJohn Baldwin if (np->pid == pid) 2992b75c8adSJohn Baldwin return (np); 3002b75c8adSJohn Baldwin } 3012b75c8adSJohn Baldwin 3022b75c8adSJohn Baldwin return (NULL); 3032b75c8adSJohn Baldwin } 3042b75c8adSJohn Baldwin 3052b75c8adSJohn Baldwin /* 3062b75c8adSJohn Baldwin * Change curthread member based on (pid, lwpid). 3075d2d083cSXin LI */ 3085d2d083cSXin LI static void 3092b75c8adSJohn Baldwin find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 3105d2d083cSXin LI { 3112b75c8adSJohn Baldwin struct procinfo *np; 3122b75c8adSJohn Baldwin struct threadinfo *nt; 31394355cfdSAndrey Zonov 3142b75c8adSJohn Baldwin np = find_proc(info, pid); 3152b75c8adSJohn Baldwin assert(np != NULL); 3162b75c8adSJohn Baldwin 317b9befd33SJohn Baldwin LIST_FOREACH(nt, &np->threadlist, entries) { 3182b75c8adSJohn Baldwin if (nt->tid == lwpid) { 3192b75c8adSJohn Baldwin info->curthread = nt; 3205d2d083cSXin LI return; 3215d2d083cSXin LI } 3225d2d083cSXin LI } 323b9befd33SJohn Baldwin errx(1, "could not find thread"); 3245d2d083cSXin LI } 3255d2d083cSXin LI 3265d2d083cSXin LI /* 327b9befd33SJohn Baldwin * When a process exits, it should have exactly one thread left. 328b9befd33SJohn Baldwin * All of the other threads should have reported thread exit events. 3292b75c8adSJohn Baldwin */ 3302b75c8adSJohn Baldwin static void 3312b75c8adSJohn Baldwin find_exit_thread(struct trussinfo *info, pid_t pid) 3322b75c8adSJohn Baldwin { 333b9befd33SJohn Baldwin struct procinfo *p; 3342b75c8adSJohn Baldwin 335b9befd33SJohn Baldwin p = find_proc(info, pid); 336b9befd33SJohn Baldwin assert(p != NULL); 3372b75c8adSJohn Baldwin 338b9befd33SJohn Baldwin info->curthread = LIST_FIRST(&p->threadlist); 339b9befd33SJohn Baldwin assert(info->curthread != NULL); 340b9befd33SJohn Baldwin assert(LIST_NEXT(info->curthread, entries) == NULL); 3412b75c8adSJohn Baldwin } 3422b75c8adSJohn Baldwin 3432b75c8adSJohn Baldwin static void 3442b75c8adSJohn Baldwin alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) 3452b75c8adSJohn Baldwin { 3462b75c8adSJohn Baldwin u_int i; 3472b75c8adSJohn Baldwin 3482b75c8adSJohn Baldwin assert(t->in_syscall == 0); 3492b75c8adSJohn Baldwin assert(t->cs.number == 0); 3501175b23fSJohn Baldwin assert(t->cs.sc == NULL); 3512b75c8adSJohn Baldwin assert(t->cs.nargs == 0); 3522b75c8adSJohn Baldwin for (i = 0; i < nitems(t->cs.s_args); i++) 3532b75c8adSJohn Baldwin assert(t->cs.s_args[i] == NULL); 3542b75c8adSJohn Baldwin memset(t->cs.args, 0, sizeof(t->cs.args)); 3552b75c8adSJohn Baldwin t->cs.number = pl->pl_syscall_code; 3562b75c8adSJohn Baldwin t->in_syscall = 1; 3572b75c8adSJohn Baldwin } 3582b75c8adSJohn Baldwin 3592b75c8adSJohn Baldwin static void 3602b75c8adSJohn Baldwin free_syscall(struct threadinfo *t) 3612b75c8adSJohn Baldwin { 3622b75c8adSJohn Baldwin u_int i; 3632b75c8adSJohn Baldwin 3642b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) 3652b75c8adSJohn Baldwin free(t->cs.s_args[i]); 3662b75c8adSJohn Baldwin memset(&t->cs, 0, sizeof(t->cs)); 3672b75c8adSJohn Baldwin t->in_syscall = 0; 3682b75c8adSJohn Baldwin } 3692b75c8adSJohn Baldwin 3702b75c8adSJohn Baldwin static void 371b9befd33SJohn Baldwin enter_syscall(struct trussinfo *info, struct threadinfo *t, 372b9befd33SJohn Baldwin struct ptrace_lwpinfo *pl) 3732b75c8adSJohn Baldwin { 3742b75c8adSJohn Baldwin struct syscall *sc; 3752b75c8adSJohn Baldwin u_int i, narg; 3762b75c8adSJohn Baldwin 3772b75c8adSJohn Baldwin alloc_syscall(t, pl); 3782b75c8adSJohn Baldwin narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args)); 3792b75c8adSJohn Baldwin if (narg != 0 && t->proc->abi->fetch_args(info, narg) != 0) { 3802b75c8adSJohn Baldwin free_syscall(t); 3812b75c8adSJohn Baldwin return; 3822b75c8adSJohn Baldwin } 3832b75c8adSJohn Baldwin 3841175b23fSJohn Baldwin sc = get_syscall(t, t->cs.number, narg); 3851175b23fSJohn Baldwin if (sc->unknown) 3862b75c8adSJohn Baldwin fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", 3872b75c8adSJohn Baldwin t->proc->abi->type, t->cs.number); 3882b75c8adSJohn Baldwin 3892b75c8adSJohn Baldwin t->cs.nargs = sc->nargs; 3902b75c8adSJohn Baldwin assert(sc->nargs <= nitems(t->cs.s_args)); 3912b75c8adSJohn Baldwin 3922b75c8adSJohn Baldwin t->cs.sc = sc; 3932b75c8adSJohn Baldwin 3942b75c8adSJohn Baldwin /* 3952b75c8adSJohn Baldwin * At this point, we set up the system call arguments. 3962b75c8adSJohn Baldwin * We ignore any OUT ones, however -- those are arguments that 3972b75c8adSJohn Baldwin * are set by the system call, and so are probably meaningless 3982b75c8adSJohn Baldwin * now. This doesn't currently support arguments that are 3992b75c8adSJohn Baldwin * passed in *and* out, however. 4002b75c8adSJohn Baldwin */ 4012b75c8adSJohn Baldwin #if DEBUG 4021175b23fSJohn Baldwin fprintf(stderr, "syscall %s(", sc->name); 4032b75c8adSJohn Baldwin #endif 4042b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) { 4052b75c8adSJohn Baldwin #if DEBUG 4061175b23fSJohn Baldwin fprintf(stderr, "0x%lx%s", t->cs.args[sc->args[i].offset], 4072b75c8adSJohn Baldwin i < (t->cs.nargs - 1) ? "," : ""); 4082b75c8adSJohn Baldwin #endif 4096c61b0f3SBryan Drewery if (!(sc->args[i].type & OUT)) { 4102b75c8adSJohn Baldwin t->cs.s_args[i] = print_arg(&sc->args[i], 4112b75c8adSJohn Baldwin t->cs.args, 0, info); 4122b75c8adSJohn Baldwin } 4132b75c8adSJohn Baldwin } 4142b75c8adSJohn Baldwin #if DEBUG 4152b75c8adSJohn Baldwin fprintf(stderr, ")\n"); 4162b75c8adSJohn Baldwin #endif 4172b75c8adSJohn Baldwin 4182b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->before); 4192b75c8adSJohn Baldwin } 4202b75c8adSJohn Baldwin 421b9befd33SJohn Baldwin /* 422b9befd33SJohn Baldwin * When a thread exits voluntarily (including when a thread calls 423b9befd33SJohn Baldwin * exit() to trigger a process exit), the thread's internal state 424b9befd33SJohn Baldwin * holds the arguments passed to the exit system call. When the 425b9befd33SJohn Baldwin * thread's exit is reported, log that system call without a return 426b9befd33SJohn Baldwin * value. 427b9befd33SJohn Baldwin */ 428b9befd33SJohn Baldwin static void 429b9befd33SJohn Baldwin thread_exit_syscall(struct trussinfo *info) 430b9befd33SJohn Baldwin { 431b9befd33SJohn Baldwin struct threadinfo *t; 432b9befd33SJohn Baldwin 433b9befd33SJohn Baldwin t = info->curthread; 434b9befd33SJohn Baldwin if (!t->in_syscall) 435b9befd33SJohn Baldwin return; 436b9befd33SJohn Baldwin 437b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 438b9befd33SJohn Baldwin 439b9befd33SJohn Baldwin print_syscall_ret(info, 0, NULL); 440b9befd33SJohn Baldwin free_syscall(t); 441b9befd33SJohn Baldwin } 442b9befd33SJohn Baldwin 4432b75c8adSJohn Baldwin static void 4442b75c8adSJohn Baldwin exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 4452b75c8adSJohn Baldwin { 4462b75c8adSJohn Baldwin struct threadinfo *t; 4472b75c8adSJohn Baldwin struct procinfo *p; 4482b75c8adSJohn Baldwin struct syscall *sc; 4492b75c8adSJohn Baldwin long retval[2]; 4502b75c8adSJohn Baldwin u_int i; 4512b75c8adSJohn Baldwin int errorp; 4522b75c8adSJohn Baldwin 4532b75c8adSJohn Baldwin t = info->curthread; 4542b75c8adSJohn Baldwin if (!t->in_syscall) 4552b75c8adSJohn Baldwin return; 4562b75c8adSJohn Baldwin 4572b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 4582b75c8adSJohn Baldwin p = t->proc; 4592b75c8adSJohn Baldwin if (p->abi->fetch_retval(info, retval, &errorp) < 0) { 4602b75c8adSJohn Baldwin free_syscall(t); 4612b75c8adSJohn Baldwin return; 4622b75c8adSJohn Baldwin } 4632b75c8adSJohn Baldwin 4642b75c8adSJohn Baldwin sc = t->cs.sc; 4652b75c8adSJohn Baldwin /* 4662b75c8adSJohn Baldwin * Here, we only look for arguments that have OUT masked in -- 4672b75c8adSJohn Baldwin * otherwise, they were handled in enter_syscall(). 4682b75c8adSJohn Baldwin */ 4692b75c8adSJohn Baldwin for (i = 0; i < sc->nargs; i++) { 4702b75c8adSJohn Baldwin char *temp; 4712b75c8adSJohn Baldwin 4722b75c8adSJohn Baldwin if (sc->args[i].type & OUT) { 4732b75c8adSJohn Baldwin /* 4742b75c8adSJohn Baldwin * If an error occurred, then don't bother 4752b75c8adSJohn Baldwin * getting the data; it may not be valid. 4762b75c8adSJohn Baldwin */ 4772b75c8adSJohn Baldwin if (errorp) { 4782b75c8adSJohn Baldwin asprintf(&temp, "0x%lx", 4792b75c8adSJohn Baldwin t->cs.args[sc->args[i].offset]); 4802b75c8adSJohn Baldwin } else { 4812b75c8adSJohn Baldwin temp = print_arg(&sc->args[i], 4822b75c8adSJohn Baldwin t->cs.args, retval, info); 4832b75c8adSJohn Baldwin } 4842b75c8adSJohn Baldwin t->cs.s_args[i] = temp; 4852b75c8adSJohn Baldwin } 4862b75c8adSJohn Baldwin } 4872b75c8adSJohn Baldwin 48800ddbdf2SJohn Baldwin print_syscall_ret(info, errorp, retval); 4892b75c8adSJohn Baldwin free_syscall(t); 4902b75c8adSJohn Baldwin 4912b75c8adSJohn Baldwin /* 4922b75c8adSJohn Baldwin * If the process executed a new image, check the ABI. If the 4932b75c8adSJohn Baldwin * new ABI isn't supported, stop tracing this process. 4942b75c8adSJohn Baldwin */ 4952b75c8adSJohn Baldwin if (pl->pl_flags & PL_FLAG_EXEC) { 496b9befd33SJohn Baldwin assert(LIST_NEXT(LIST_FIRST(&p->threadlist), entries) == NULL); 4972b75c8adSJohn Baldwin p->abi = find_abi(p->pid); 4982b75c8adSJohn Baldwin if (p->abi == NULL) { 4992b75c8adSJohn Baldwin if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0) 5002b75c8adSJohn Baldwin err(1, "Can not detach the process"); 5012b75c8adSJohn Baldwin free_proc(p); 5022b75c8adSJohn Baldwin } 5032b75c8adSJohn Baldwin } 5042b75c8adSJohn Baldwin } 5052b75c8adSJohn Baldwin 506d70876fdSJohn Baldwin int 507d70876fdSJohn Baldwin print_line_prefix(struct trussinfo *info) 508d70876fdSJohn Baldwin { 509d70876fdSJohn Baldwin struct timespec timediff; 510d70876fdSJohn Baldwin struct threadinfo *t; 511d70876fdSJohn Baldwin int len; 512d70876fdSJohn Baldwin 513d70876fdSJohn Baldwin len = 0; 514d70876fdSJohn Baldwin t = info->curthread; 515d70876fdSJohn Baldwin if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) { 516d70876fdSJohn Baldwin if (info->flags & FOLLOWFORKS) 517d70876fdSJohn Baldwin len += fprintf(info->outfile, "%5d", t->proc->pid); 518d70876fdSJohn Baldwin if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) == 519d70876fdSJohn Baldwin (FOLLOWFORKS | DISPLAYTIDS)) 520d70876fdSJohn Baldwin len += fprintf(info->outfile, " "); 521d70876fdSJohn Baldwin if (info->flags & DISPLAYTIDS) 522d70876fdSJohn Baldwin len += fprintf(info->outfile, "%6d", t->tid); 523d70876fdSJohn Baldwin len += fprintf(info->outfile, ": "); 524d70876fdSJohn Baldwin } 525d70876fdSJohn Baldwin if (info->flags & ABSOLUTETIMESTAMPS) { 526*6040822cSAlan Somers timespecsub(&t->after, &info->start_time, &timediff); 527d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 528d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 529d70876fdSJohn Baldwin } 530d70876fdSJohn Baldwin if (info->flags & RELATIVETIMESTAMPS) { 531*6040822cSAlan Somers timespecsub(&t->after, &t->before, &timediff); 532d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 533d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 534d70876fdSJohn Baldwin } 535d70876fdSJohn Baldwin return (len); 536d70876fdSJohn Baldwin } 537d70876fdSJohn Baldwin 5382b75c8adSJohn Baldwin static void 539b9befd33SJohn Baldwin report_thread_death(struct trussinfo *info) 540b9befd33SJohn Baldwin { 541b9befd33SJohn Baldwin struct threadinfo *t; 542b9befd33SJohn Baldwin 543b9befd33SJohn Baldwin t = info->curthread; 544b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 545b9befd33SJohn Baldwin print_line_prefix(info); 546b9befd33SJohn Baldwin fprintf(info->outfile, "<thread %ld exited>\n", (long)t->tid); 547b9befd33SJohn Baldwin } 548b9befd33SJohn Baldwin 549b9befd33SJohn Baldwin static void 550b9befd33SJohn Baldwin report_thread_birth(struct trussinfo *info) 551b9befd33SJohn Baldwin { 552b9befd33SJohn Baldwin struct threadinfo *t; 553b9befd33SJohn Baldwin 554b9befd33SJohn Baldwin t = info->curthread; 555b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 556b9befd33SJohn Baldwin t->before = t->after; 557b9befd33SJohn Baldwin print_line_prefix(info); 558b9befd33SJohn Baldwin fprintf(info->outfile, "<new thread %ld>\n", (long)t->tid); 559b9befd33SJohn Baldwin } 560b9befd33SJohn Baldwin 561b9befd33SJohn Baldwin static void 5622b75c8adSJohn Baldwin report_exit(struct trussinfo *info, siginfo_t *si) 5632b75c8adSJohn Baldwin { 564d70876fdSJohn Baldwin struct threadinfo *t; 5652b75c8adSJohn Baldwin 566d70876fdSJohn Baldwin t = info->curthread; 567d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 568d70876fdSJohn Baldwin print_line_prefix(info); 5692b75c8adSJohn Baldwin if (si->si_code == CLD_EXITED) 5702b75c8adSJohn Baldwin fprintf(info->outfile, "process exit, rval = %u\n", 5712b75c8adSJohn Baldwin si->si_status); 5722b75c8adSJohn Baldwin else 5732b75c8adSJohn Baldwin fprintf(info->outfile, "process killed, signal = %u%s\n", 5742b75c8adSJohn Baldwin si->si_status, si->si_code == CLD_DUMPED ? 5752b75c8adSJohn Baldwin " (core dumped)" : ""); 5762b75c8adSJohn Baldwin } 5772b75c8adSJohn Baldwin 5782b75c8adSJohn Baldwin static void 579d70876fdSJohn Baldwin report_new_child(struct trussinfo *info) 5802b75c8adSJohn Baldwin { 581d70876fdSJohn Baldwin struct threadinfo *t; 5822b75c8adSJohn Baldwin 583d70876fdSJohn Baldwin t = info->curthread; 584d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 585d70876fdSJohn Baldwin t->before = t->after; 586d70876fdSJohn Baldwin print_line_prefix(info); 5872b75c8adSJohn Baldwin fprintf(info->outfile, "<new process>\n"); 5882b75c8adSJohn Baldwin } 5892b75c8adSJohn Baldwin 59013e5e6b6SJohn Baldwin void 591ff577cb6SJohn Baldwin decode_siginfo(FILE *fp, siginfo_t *si) 592ff577cb6SJohn Baldwin { 593ff577cb6SJohn Baldwin const char *str; 594ff577cb6SJohn Baldwin 595ff577cb6SJohn Baldwin fprintf(fp, " code="); 596ff577cb6SJohn Baldwin str = sysdecode_sigcode(si->si_signo, si->si_code); 597ff577cb6SJohn Baldwin if (str == NULL) 598ff577cb6SJohn Baldwin fprintf(fp, "%d", si->si_code); 599ff577cb6SJohn Baldwin else 600ff577cb6SJohn Baldwin fprintf(fp, "%s", str); 601ff577cb6SJohn Baldwin switch (si->si_code) { 602ff577cb6SJohn Baldwin case SI_NOINFO: 603ff577cb6SJohn Baldwin break; 604ff577cb6SJohn Baldwin case SI_QUEUE: 605ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 606ff577cb6SJohn Baldwin /* FALLTHROUGH */ 607ff577cb6SJohn Baldwin case SI_USER: 608ff577cb6SJohn Baldwin case SI_LWP: 609ff577cb6SJohn Baldwin fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid, 610ff577cb6SJohn Baldwin (intmax_t)si->si_uid); 611ff577cb6SJohn Baldwin break; 612ff577cb6SJohn Baldwin case SI_TIMER: 613ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 614ff577cb6SJohn Baldwin fprintf(fp, " timerid=%d", si->si_timerid); 615ff577cb6SJohn Baldwin fprintf(fp, " overrun=%d", si->si_overrun); 616ff577cb6SJohn Baldwin if (si->si_errno != 0) 617ff577cb6SJohn Baldwin fprintf(fp, " errno=%d", si->si_errno); 618ff577cb6SJohn Baldwin break; 619ff577cb6SJohn Baldwin case SI_ASYNCIO: 620ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 621ff577cb6SJohn Baldwin break; 622ff577cb6SJohn Baldwin case SI_MESGQ: 623ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 624ff577cb6SJohn Baldwin fprintf(fp, " mqd=%d", si->si_mqd); 625ff577cb6SJohn Baldwin break; 626ff577cb6SJohn Baldwin default: 627ff577cb6SJohn Baldwin switch (si->si_signo) { 628ff577cb6SJohn Baldwin case SIGILL: 629ff577cb6SJohn Baldwin case SIGFPE: 630ff577cb6SJohn Baldwin case SIGSEGV: 631ff577cb6SJohn Baldwin case SIGBUS: 632ff577cb6SJohn Baldwin fprintf(fp, " trapno=%d", si->si_trapno); 633ff577cb6SJohn Baldwin fprintf(fp, " addr=%p", si->si_addr); 634ff577cb6SJohn Baldwin break; 635ff577cb6SJohn Baldwin case SIGCHLD: 636ff577cb6SJohn Baldwin fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid, 637ff577cb6SJohn Baldwin (intmax_t)si->si_uid); 638ff577cb6SJohn Baldwin fprintf(fp, " status=%d", si->si_status); 639ff577cb6SJohn Baldwin break; 640ff577cb6SJohn Baldwin } 641ff577cb6SJohn Baldwin } 642ff577cb6SJohn Baldwin } 643ff577cb6SJohn Baldwin 644ff577cb6SJohn Baldwin static void 645ff577cb6SJohn Baldwin report_signal(struct trussinfo *info, siginfo_t *si, struct ptrace_lwpinfo *pl) 6462b75c8adSJohn Baldwin { 647d70876fdSJohn Baldwin struct threadinfo *t; 6489289f547SJohn Baldwin const char *signame; 6492b75c8adSJohn Baldwin 650d70876fdSJohn Baldwin t = info->curthread; 651d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 652d70876fdSJohn Baldwin print_line_prefix(info); 6539289f547SJohn Baldwin signame = sysdecode_signal(si->si_status); 6549289f547SJohn Baldwin if (signame == NULL) 6559289f547SJohn Baldwin signame = "?"; 656ff577cb6SJohn Baldwin fprintf(info->outfile, "SIGNAL %u (%s)", si->si_status, signame); 657ff577cb6SJohn Baldwin if (pl->pl_event == PL_EVENT_SIGNAL && pl->pl_flags & PL_FLAG_SI) 658ff577cb6SJohn Baldwin decode_siginfo(info->outfile, &pl->pl_siginfo); 659ff577cb6SJohn Baldwin fprintf(info->outfile, "\n"); 660ff577cb6SJohn Baldwin 6612b75c8adSJohn Baldwin } 6622b75c8adSJohn Baldwin 6632b75c8adSJohn Baldwin /* 6642b75c8adSJohn Baldwin * Wait for events until all the processes have exited or truss has been 6652b75c8adSJohn Baldwin * asked to stop. 6665d2d083cSXin LI */ 6675d2d083cSXin LI void 6682b75c8adSJohn Baldwin eventloop(struct trussinfo *info) 6695d2d083cSXin LI { 6702b75c8adSJohn Baldwin struct ptrace_lwpinfo pl; 6712b75c8adSJohn Baldwin siginfo_t si; 6722b75c8adSJohn Baldwin int pending_signal; 6735d2d083cSXin LI 6742b75c8adSJohn Baldwin while (!LIST_EMPTY(&info->proclist)) { 675896fc463SAndrey Zonov if (detaching) { 6762b75c8adSJohn Baldwin detach_all_procs(info); 677896fc463SAndrey Zonov return; 678896fc463SAndrey Zonov } 679896fc463SAndrey Zonov 6802b75c8adSJohn Baldwin if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { 681896fc463SAndrey Zonov if (errno == EINTR) 6822b75c8adSJohn Baldwin continue; 6832b75c8adSJohn Baldwin err(1, "Unexpected error from waitid"); 684896fc463SAndrey Zonov } 6855d2d083cSXin LI 6862b75c8adSJohn Baldwin assert(si.si_signo == SIGCHLD); 6872b75c8adSJohn Baldwin 6882b75c8adSJohn Baldwin switch (si.si_code) { 6892b75c8adSJohn Baldwin case CLD_EXITED: 6902b75c8adSJohn Baldwin case CLD_KILLED: 6912b75c8adSJohn Baldwin case CLD_DUMPED: 6922b75c8adSJohn Baldwin find_exit_thread(info, si.si_pid); 693b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) { 694b9befd33SJohn Baldwin if (si.si_code == CLD_EXITED) 695b9befd33SJohn Baldwin thread_exit_syscall(info); 6962b75c8adSJohn Baldwin report_exit(info, &si); 697b9befd33SJohn Baldwin } 6982b75c8adSJohn Baldwin free_proc(info->curthread->proc); 6992b75c8adSJohn Baldwin info->curthread = NULL; 7005d2d083cSXin LI break; 7012b75c8adSJohn Baldwin case CLD_TRAPPED: 7022b75c8adSJohn Baldwin if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl, 7032b75c8adSJohn Baldwin sizeof(pl)) == -1) 7042b75c8adSJohn Baldwin err(1, "ptrace(PT_LWPINFO)"); 7052b75c8adSJohn Baldwin 7062b75c8adSJohn Baldwin if (pl.pl_flags & PL_FLAG_CHILD) { 707b9befd33SJohn Baldwin new_proc(info, si.si_pid, pl.pl_lwpid); 7082b75c8adSJohn Baldwin assert(LIST_FIRST(&info->proclist)->abi != 7092b75c8adSJohn Baldwin NULL); 710b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_BORN) 711b9befd33SJohn Baldwin new_thread(find_proc(info, si.si_pid), 712b9befd33SJohn Baldwin pl.pl_lwpid); 7132b75c8adSJohn Baldwin find_thread(info, si.si_pid, pl.pl_lwpid); 7142b75c8adSJohn Baldwin 71594746562SBryan Drewery if (si.si_status == SIGTRAP && 716b9befd33SJohn Baldwin (pl.pl_flags & (PL_FLAG_BORN|PL_FLAG_EXITED| 717b9befd33SJohn Baldwin PL_FLAG_SCE|PL_FLAG_SCX)) != 0) { 718b9befd33SJohn Baldwin if (pl.pl_flags & PL_FLAG_BORN) { 719b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) 720b9befd33SJohn Baldwin report_thread_birth(info); 721b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_EXITED) { 722b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) 723b9befd33SJohn Baldwin report_thread_death(info); 724b9befd33SJohn Baldwin free_thread(info->curthread); 725b9befd33SJohn Baldwin info->curthread = NULL; 726b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_SCE) 727b9befd33SJohn Baldwin enter_syscall(info, info->curthread, &pl); 7282b75c8adSJohn Baldwin else if (pl.pl_flags & PL_FLAG_SCX) 7292b75c8adSJohn Baldwin exit_syscall(info, &pl); 7302b75c8adSJohn Baldwin pending_signal = 0; 7312b75c8adSJohn Baldwin } else if (pl.pl_flags & PL_FLAG_CHILD) { 7322b75c8adSJohn Baldwin if ((info->flags & COUNTONLY) == 0) 733d70876fdSJohn Baldwin report_new_child(info); 7342b75c8adSJohn Baldwin pending_signal = 0; 7352b75c8adSJohn Baldwin } else { 7362b75c8adSJohn Baldwin if ((info->flags & NOSIGS) == 0) 737ff577cb6SJohn Baldwin report_signal(info, &si, &pl); 7382b75c8adSJohn Baldwin pending_signal = si.si_status; 73997695ad4SKonstantin Belousov } 7402b75c8adSJohn Baldwin ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1, 7412b75c8adSJohn Baldwin pending_signal); 7422b75c8adSJohn Baldwin break; 7432b75c8adSJohn Baldwin case CLD_STOPPED: 7442b75c8adSJohn Baldwin errx(1, "waitid reported CLD_STOPPED"); 7452b75c8adSJohn Baldwin case CLD_CONTINUED: 7465d2d083cSXin LI break; 7475d2d083cSXin LI } 7485d2d083cSXin LI } 7495d2d083cSXin LI } 750