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>
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>
426040822cSAlan Somers #include <sys/time.h>
43580e0a2bSDag-Erling Smørgrav #include <sys/wait.h>
44580e0a2bSDag-Erling Smørgrav
452b75c8adSJohn Baldwin #include <assert.h>
463cf51049SPhilippe Charnier #include <err.h>
47821df508SXin LI #include <errno.h>
483cf51049SPhilippe Charnier #include <signal.h>
499289f547SJohn Baldwin #include <stdbool.h>
502b75c8adSJohn Baldwin #include <stdint.h>
51bbeaf6c0SSean Eric Fagan #include <stdio.h>
52bbeaf6c0SSean Eric Fagan #include <stdlib.h>
53821df508SXin LI #include <string.h>
54a5f14abfSJohn Baldwin #include <sysdecode.h>
55821df508SXin LI #include <time.h>
56bbeaf6c0SSean Eric Fagan #include <unistd.h>
57bbeaf6c0SSean Eric Fagan
58ec0bed25SMatthew N. Dodd #include "truss.h"
592b75c8adSJohn Baldwin #include "syscall.h"
601be5d704SMark Murray #include "extern.h"
611be5d704SMark Murray
62caa449b6SJohn Baldwin struct procabi_table {
63caa449b6SJohn Baldwin const char *name;
64caa449b6SJohn Baldwin struct procabi *abi;
65caa449b6SJohn Baldwin };
662b75c8adSJohn Baldwin
67896fc463SAndrey Zonov static sig_atomic_t detaching;
68bbeaf6c0SSean Eric Fagan
69b9befd33SJohn Baldwin static void enter_syscall(struct trussinfo *, struct threadinfo *,
70b9befd33SJohn Baldwin struct ptrace_lwpinfo *);
71b9befd33SJohn Baldwin static void new_proc(struct trussinfo *, pid_t, lwpid_t);
722b75c8adSJohn Baldwin
73caa449b6SJohn Baldwin
74caa449b6SJohn Baldwin static struct procabi freebsd = {
757daca4e2SAlex Richardson .type = "FreeBSD",
767daca4e2SAlex Richardson .abi = SYSDECODE_ABI_FREEBSD,
777daca4e2SAlex Richardson .pointer_size = sizeof(void *),
787daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(freebsd.extra_syscalls),
797daca4e2SAlex Richardson .syscalls = { NULL }
80caa449b6SJohn Baldwin };
81caa449b6SJohn Baldwin
827daca4e2SAlex Richardson #if !defined(__SIZEOF_POINTER__)
837daca4e2SAlex Richardson #error "Use a modern compiler."
847daca4e2SAlex Richardson #endif
857daca4e2SAlex Richardson
867daca4e2SAlex Richardson #if __SIZEOF_POINTER__ > 4
87caa449b6SJohn Baldwin static struct procabi freebsd32 = {
887daca4e2SAlex Richardson .type = "FreeBSD32",
897daca4e2SAlex Richardson .abi = SYSDECODE_ABI_FREEBSD32,
907daca4e2SAlex Richardson .pointer_size = sizeof(uint32_t),
913cbad828SAlex Richardson .compat_prefix = "freebsd32_",
927daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(freebsd32.extra_syscalls),
937daca4e2SAlex Richardson .syscalls = { NULL }
94caa449b6SJohn Baldwin };
95caa449b6SJohn Baldwin #endif
96caa449b6SJohn Baldwin
97caa449b6SJohn Baldwin static struct procabi linux = {
987daca4e2SAlex Richardson .type = "Linux",
997daca4e2SAlex Richardson .abi = SYSDECODE_ABI_LINUX,
1007daca4e2SAlex Richardson .pointer_size = sizeof(void *),
1017daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(linux.extra_syscalls),
1027daca4e2SAlex Richardson .syscalls = { NULL }
103caa449b6SJohn Baldwin };
104caa449b6SJohn Baldwin
1057daca4e2SAlex Richardson #if __SIZEOF_POINTER__ > 4
106caa449b6SJohn Baldwin static struct procabi linux32 = {
1077daca4e2SAlex Richardson .type = "Linux32",
1087daca4e2SAlex Richardson .abi = SYSDECODE_ABI_LINUX32,
1097daca4e2SAlex Richardson .pointer_size = sizeof(uint32_t),
1107daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(linux32.extra_syscalls),
1117daca4e2SAlex Richardson .syscalls = { NULL }
112caa449b6SJohn Baldwin };
113caa449b6SJohn Baldwin #endif
114caa449b6SJohn Baldwin
115caa449b6SJohn Baldwin static struct procabi_table abis[] = {
1167daca4e2SAlex Richardson #if __SIZEOF_POINTER__ == 4
1177daca4e2SAlex Richardson { "FreeBSD ELF32", &freebsd },
1187daca4e2SAlex Richardson #elif __SIZEOF_POINTER__ == 8
119caa449b6SJohn Baldwin { "FreeBSD ELF64", &freebsd },
120caa449b6SJohn Baldwin { "FreeBSD ELF32", &freebsd32 },
121caa449b6SJohn Baldwin #else
1227daca4e2SAlex Richardson #error "Unsupported pointer size"
123caa449b6SJohn Baldwin #endif
124caa449b6SJohn Baldwin #if defined(__powerpc64__)
125caa449b6SJohn Baldwin { "FreeBSD ELF64 V2", &freebsd },
126caa449b6SJohn Baldwin #endif
127caa449b6SJohn Baldwin #if defined(__amd64__)
128caa449b6SJohn Baldwin { "FreeBSD a.out", &freebsd32 },
129caa449b6SJohn Baldwin #endif
130caa449b6SJohn Baldwin #if defined(__i386__)
131caa449b6SJohn Baldwin { "FreeBSD a.out", &freebsd },
132caa449b6SJohn Baldwin #endif
1337daca4e2SAlex Richardson #if __SIZEOF_POINTER__ >= 8
134caa449b6SJohn Baldwin { "Linux ELF64", &linux },
135caa449b6SJohn Baldwin { "Linux ELF32", &linux32 },
136caa449b6SJohn Baldwin #else
1375faeda90SJessica Clarke { "Linux ELF32", &linux },
138caa449b6SJohn Baldwin #endif
139caa449b6SJohn Baldwin };
140caa449b6SJohn Baldwin
141bbeaf6c0SSean Eric Fagan /*
142bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does
1432b75c8adSJohn Baldwin * is fork(), enable tracing in the child, and then exec the given
1442b75c8adSJohn Baldwin * command. At that point, the child process stops, and the parent
1452b75c8adSJohn Baldwin * can wake up and deal with it.
146bbeaf6c0SSean Eric Fagan */
1472b75c8adSJohn Baldwin void
setup_and_wait(struct trussinfo * info,char * command[])1482b75c8adSJohn Baldwin setup_and_wait(struct trussinfo *info, char *command[])
1495321ae86SAlfred Perlstein {
150be305c9cSAndrey Zonov pid_t pid;
151bbeaf6c0SSean Eric Fagan
1525d2d083cSXin LI pid = vfork();
15394355cfdSAndrey Zonov if (pid == -1)
1541fd98d7dSDag-Erling Smørgrav err(1, "fork failed");
155bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */
1565d2d083cSXin LI ptrace(PT_TRACE_ME, 0, 0, 0);
157bbeaf6c0SSean Eric Fagan execvp(command[0], command);
1585d2d083cSXin LI err(1, "execvp %s", command[0]);
159bbeaf6c0SSean Eric Fagan }
1605d2d083cSXin LI
161bbeaf6c0SSean Eric Fagan /* Only in the parent here */
162310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0)
163*501c4801SCy Schubert err(1, "unexpected stop in waitpid");
164bbeaf6c0SSean Eric Fagan
165b9befd33SJohn Baldwin new_proc(info, pid, 0);
166bbeaf6c0SSean Eric Fagan }
167bbeaf6c0SSean Eric Fagan
168bbeaf6c0SSean Eric Fagan /*
1692b75c8adSJohn Baldwin * start_tracing is called to attach to an existing process.
170bbeaf6c0SSean Eric Fagan */
1712b75c8adSJohn Baldwin void
start_tracing(struct trussinfo * info,pid_t pid)1722b75c8adSJohn Baldwin start_tracing(struct trussinfo *info, pid_t pid)
1735321ae86SAlfred Perlstein {
174310da894SAndrey Zonov int ret, retry;
1755321ae86SAlfred Perlstein
17694355cfdSAndrey Zonov retry = 10;
1775d2d083cSXin LI do {
1785d2d083cSXin LI ret = ptrace(PT_ATTACH, pid, NULL, 0);
1795d2d083cSXin LI usleep(200);
1805d2d083cSXin LI } while (ret && retry-- > 0);
1815d2d083cSXin LI if (ret)
182*501c4801SCy Schubert err(1, "Cannot attach to target process");
18320fa828fSSean Eric Fagan
184310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0)
185*501c4801SCy Schubert err(1, "Unexpected stop in waitpid");
186bbeaf6c0SSean Eric Fagan
187b9befd33SJohn Baldwin new_proc(info, pid, 0);
188bbeaf6c0SSean Eric Fagan }
189bbeaf6c0SSean Eric Fagan
190bbeaf6c0SSean Eric Fagan /*
191bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state.
192bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only
193bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing
194bbeaf6c0SSean Eric Fagan * process.
195bbeaf6c0SSean Eric Fagan */
196bbeaf6c0SSean Eric Fagan void
restore_proc(int signo __unused)1975d2d083cSXin LI restore_proc(int signo __unused)
1985d2d083cSXin LI {
199896fc463SAndrey Zonov
200896fc463SAndrey Zonov detaching = 1;
201896fc463SAndrey Zonov }
202896fc463SAndrey Zonov
2032b75c8adSJohn Baldwin static void
detach_proc(pid_t pid)204896fc463SAndrey Zonov detach_proc(pid_t pid)
205896fc463SAndrey Zonov {
20612f747e6SKonstantin Belousov int sig, status;
207bbeaf6c0SSean Eric Fagan
20812f747e6SKonstantin Belousov /*
20912f747e6SKonstantin Belousov * Stop the child so that we can detach. Filter out possible
21012f747e6SKonstantin Belousov * lingering SIGTRAP events buffered in the threads.
21112f747e6SKonstantin Belousov */
212896fc463SAndrey Zonov kill(pid, SIGSTOP);
21312f747e6SKonstantin Belousov for (;;) {
21412f747e6SKonstantin Belousov if (waitpid(pid, &status, 0) < 0)
21512f747e6SKonstantin Belousov err(1, "Unexpected error in waitpid");
21612f747e6SKonstantin Belousov sig = WIFSTOPPED(status) ? WSTOPSIG(status) : 0;
21712f747e6SKonstantin Belousov if (sig == SIGSTOP)
21812f747e6SKonstantin Belousov break;
21912f747e6SKonstantin Belousov if (sig == SIGTRAP)
22012f747e6SKonstantin Belousov sig = 0;
22112f747e6SKonstantin Belousov if (ptrace(PT_CONTINUE, pid, (caddr_t)1, sig) < 0)
22212f747e6SKonstantin Belousov err(1, "Can not continue for detach");
22312f747e6SKonstantin Belousov }
2245d2d083cSXin LI
225896fc463SAndrey Zonov if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
2265d2d083cSXin LI err(1, "Can not detach the process");
2275d2d083cSXin LI
228896fc463SAndrey Zonov kill(pid, SIGCONT);
229bbeaf6c0SSean Eric Fagan }
2305d2d083cSXin LI
2315d2d083cSXin LI /*
2322b75c8adSJohn Baldwin * Determine the ABI. This is called after every exec, and when
2332b75c8adSJohn Baldwin * a process is first monitored.
2342b75c8adSJohn Baldwin */
2352b75c8adSJohn Baldwin static struct procabi *
find_abi(pid_t pid)2362b75c8adSJohn Baldwin find_abi(pid_t pid)
2372b75c8adSJohn Baldwin {
2382b75c8adSJohn Baldwin size_t len;
239caa449b6SJohn Baldwin unsigned int i;
2402b75c8adSJohn Baldwin int error;
2412b75c8adSJohn Baldwin int mib[4];
2422b75c8adSJohn Baldwin char progt[32];
2432b75c8adSJohn Baldwin
2442b75c8adSJohn Baldwin len = sizeof(progt);
2452b75c8adSJohn Baldwin mib[0] = CTL_KERN;
2462b75c8adSJohn Baldwin mib[1] = KERN_PROC;
2472b75c8adSJohn Baldwin mib[2] = KERN_PROC_SV_NAME;
2482b75c8adSJohn Baldwin mib[3] = pid;
2492b75c8adSJohn Baldwin error = sysctl(mib, 4, progt, &len, NULL, 0);
2502b75c8adSJohn Baldwin if (error != 0)
2512b75c8adSJohn Baldwin err(2, "can not get sysvec name");
2522b75c8adSJohn Baldwin
253caa449b6SJohn Baldwin for (i = 0; i < nitems(abis); i++) {
254caa449b6SJohn Baldwin if (strcmp(abis[i].name, progt) == 0)
255caa449b6SJohn Baldwin return (abis[i].abi);
2562b75c8adSJohn Baldwin }
2572b75c8adSJohn Baldwin warnx("ABI %s for pid %ld is not supported", progt, (long)pid);
2582b75c8adSJohn Baldwin return (NULL);
2592b75c8adSJohn Baldwin }
2602b75c8adSJohn Baldwin
261b9befd33SJohn Baldwin static struct threadinfo *
new_thread(struct procinfo * p,lwpid_t lwpid)262b9befd33SJohn Baldwin new_thread(struct procinfo *p, lwpid_t lwpid)
263b9befd33SJohn Baldwin {
264b9befd33SJohn Baldwin struct threadinfo *nt;
265b9befd33SJohn Baldwin
266b9befd33SJohn Baldwin /*
267b9befd33SJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately
268b9befd33SJohn Baldwin * this will kill any processes truss is attached to.
269b9befd33SJohn Baldwin */
270b9befd33SJohn Baldwin LIST_FOREACH(nt, &p->threadlist, entries) {
271b9befd33SJohn Baldwin if (nt->tid == lwpid)
272b9befd33SJohn Baldwin errx(1, "Duplicate thread for LWP %ld", (long)lwpid);
273b9befd33SJohn Baldwin }
274b9befd33SJohn Baldwin
275b9befd33SJohn Baldwin nt = calloc(1, sizeof(struct threadinfo));
276b9befd33SJohn Baldwin if (nt == NULL)
277b9befd33SJohn Baldwin err(1, "calloc() failed");
278b9befd33SJohn Baldwin nt->proc = p;
279b9befd33SJohn Baldwin nt->tid = lwpid;
280b9befd33SJohn Baldwin LIST_INSERT_HEAD(&p->threadlist, nt, entries);
281b9befd33SJohn Baldwin return (nt);
282b9befd33SJohn Baldwin }
283b9befd33SJohn Baldwin
2842b75c8adSJohn Baldwin static void
free_thread(struct threadinfo * t)285b9befd33SJohn Baldwin free_thread(struct threadinfo *t)
286b9befd33SJohn Baldwin {
287b9befd33SJohn Baldwin
288b9befd33SJohn Baldwin LIST_REMOVE(t, entries);
289b9befd33SJohn Baldwin free(t);
290b9befd33SJohn Baldwin }
291b9befd33SJohn Baldwin
292b9befd33SJohn Baldwin static void
add_threads(struct trussinfo * info,struct procinfo * p)293b9befd33SJohn Baldwin add_threads(struct trussinfo *info, struct procinfo *p)
294b9befd33SJohn Baldwin {
295b9befd33SJohn Baldwin struct ptrace_lwpinfo pl;
296b9befd33SJohn Baldwin struct threadinfo *t;
297b9befd33SJohn Baldwin lwpid_t *lwps;
298b9befd33SJohn Baldwin int i, nlwps;
299b9befd33SJohn Baldwin
300b9befd33SJohn Baldwin nlwps = ptrace(PT_GETNUMLWPS, p->pid, NULL, 0);
301b9befd33SJohn Baldwin if (nlwps == -1)
302b9befd33SJohn Baldwin err(1, "Unable to fetch number of LWPs");
303b9befd33SJohn Baldwin assert(nlwps > 0);
304b9befd33SJohn Baldwin lwps = calloc(nlwps, sizeof(*lwps));
305b9befd33SJohn Baldwin nlwps = ptrace(PT_GETLWPLIST, p->pid, (caddr_t)lwps, nlwps);
306b9befd33SJohn Baldwin if (nlwps == -1)
307b9befd33SJohn Baldwin err(1, "Unable to fetch LWP list");
308b9befd33SJohn Baldwin for (i = 0; i < nlwps; i++) {
309b9befd33SJohn Baldwin t = new_thread(p, lwps[i]);
310b9befd33SJohn Baldwin if (ptrace(PT_LWPINFO, lwps[i], (caddr_t)&pl, sizeof(pl)) == -1)
311b9befd33SJohn Baldwin err(1, "ptrace(PT_LWPINFO)");
3120f21f528SBaptiste Daroussin if (pl.pl_flags & PL_FLAG_SCE) {
3130f21f528SBaptiste Daroussin info->curthread = t;
314b9befd33SJohn Baldwin enter_syscall(info, t, &pl);
315b9befd33SJohn Baldwin }
3160f21f528SBaptiste Daroussin }
317b9befd33SJohn Baldwin free(lwps);
318b9befd33SJohn Baldwin }
319b9befd33SJohn Baldwin
320b9befd33SJohn Baldwin static void
new_proc(struct trussinfo * info,pid_t pid,lwpid_t lwpid)321b9befd33SJohn Baldwin new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
3222b75c8adSJohn Baldwin {
3232b75c8adSJohn Baldwin struct procinfo *np;
3242b75c8adSJohn Baldwin
3252b75c8adSJohn Baldwin /*
3262b75c8adSJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately
327b9befd33SJohn Baldwin * this will kill any processes truss is attached to.
3282b75c8adSJohn Baldwin */
3292b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) {
3302b75c8adSJohn Baldwin if (np->pid == pid)
3312b75c8adSJohn Baldwin errx(1, "Duplicate process for pid %ld", (long)pid);
3322b75c8adSJohn Baldwin }
3332b75c8adSJohn Baldwin
3342b75c8adSJohn Baldwin if (info->flags & FOLLOWFORKS)
3352b75c8adSJohn Baldwin if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1)
3362b75c8adSJohn Baldwin err(1, "Unable to follow forks for pid %ld", (long)pid);
337b9befd33SJohn Baldwin if (ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1)
338b9befd33SJohn Baldwin err(1, "Unable to enable LWP events for pid %ld", (long)pid);
3392b75c8adSJohn Baldwin np = calloc(1, sizeof(struct procinfo));
3402b75c8adSJohn Baldwin np->pid = pid;
3412b75c8adSJohn Baldwin np->abi = find_abi(pid);
342b9befd33SJohn Baldwin LIST_INIT(&np->threadlist);
3432b75c8adSJohn Baldwin LIST_INSERT_HEAD(&info->proclist, np, entries);
344b9befd33SJohn Baldwin
345b9befd33SJohn Baldwin if (lwpid != 0)
346b9befd33SJohn Baldwin new_thread(np, lwpid);
347b9befd33SJohn Baldwin else
348b9befd33SJohn Baldwin add_threads(info, np);
3492b75c8adSJohn Baldwin }
3502b75c8adSJohn Baldwin
3512b75c8adSJohn Baldwin static void
free_proc(struct procinfo * p)3522b75c8adSJohn Baldwin free_proc(struct procinfo *p)
3532b75c8adSJohn Baldwin {
3542b75c8adSJohn Baldwin struct threadinfo *t, *t2;
3552b75c8adSJohn Baldwin
356b9befd33SJohn Baldwin LIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) {
3572b75c8adSJohn Baldwin free(t);
3582b75c8adSJohn Baldwin }
3592b75c8adSJohn Baldwin LIST_REMOVE(p, entries);
3602b75c8adSJohn Baldwin free(p);
3612b75c8adSJohn Baldwin }
3622b75c8adSJohn Baldwin
3632b75c8adSJohn Baldwin static void
detach_all_procs(struct trussinfo * info)3642b75c8adSJohn Baldwin detach_all_procs(struct trussinfo *info)
3652b75c8adSJohn Baldwin {
3662b75c8adSJohn Baldwin struct procinfo *p, *p2;
3672b75c8adSJohn Baldwin
3682b75c8adSJohn Baldwin LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) {
3692b75c8adSJohn Baldwin detach_proc(p->pid);
3702b75c8adSJohn Baldwin free_proc(p);
3712b75c8adSJohn Baldwin }
3722b75c8adSJohn Baldwin }
3732b75c8adSJohn Baldwin
3742b75c8adSJohn Baldwin static struct procinfo *
find_proc(struct trussinfo * info,pid_t pid)3752b75c8adSJohn Baldwin find_proc(struct trussinfo *info, pid_t pid)
3762b75c8adSJohn Baldwin {
3772b75c8adSJohn Baldwin struct procinfo *np;
3782b75c8adSJohn Baldwin
3792b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) {
3802b75c8adSJohn Baldwin if (np->pid == pid)
3812b75c8adSJohn Baldwin return (np);
3822b75c8adSJohn Baldwin }
3832b75c8adSJohn Baldwin
3842b75c8adSJohn Baldwin return (NULL);
3852b75c8adSJohn Baldwin }
3862b75c8adSJohn Baldwin
3872b75c8adSJohn Baldwin /*
3882b75c8adSJohn Baldwin * Change curthread member based on (pid, lwpid).
3895d2d083cSXin LI */
3905d2d083cSXin LI static void
find_thread(struct trussinfo * info,pid_t pid,lwpid_t lwpid)3912b75c8adSJohn Baldwin find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
3925d2d083cSXin LI {
3932b75c8adSJohn Baldwin struct procinfo *np;
3942b75c8adSJohn Baldwin struct threadinfo *nt;
39594355cfdSAndrey Zonov
3962b75c8adSJohn Baldwin np = find_proc(info, pid);
3972b75c8adSJohn Baldwin assert(np != NULL);
3982b75c8adSJohn Baldwin
399b9befd33SJohn Baldwin LIST_FOREACH(nt, &np->threadlist, entries) {
4002b75c8adSJohn Baldwin if (nt->tid == lwpid) {
4012b75c8adSJohn Baldwin info->curthread = nt;
4025d2d083cSXin LI return;
4035d2d083cSXin LI }
4045d2d083cSXin LI }
405b9befd33SJohn Baldwin errx(1, "could not find thread");
4065d2d083cSXin LI }
4075d2d083cSXin LI
4085d2d083cSXin LI /*
409b9befd33SJohn Baldwin * When a process exits, it should have exactly one thread left.
410b9befd33SJohn Baldwin * All of the other threads should have reported thread exit events.
4112b75c8adSJohn Baldwin */
4122b75c8adSJohn Baldwin static void
find_exit_thread(struct trussinfo * info,pid_t pid)4132b75c8adSJohn Baldwin find_exit_thread(struct trussinfo *info, pid_t pid)
4142b75c8adSJohn Baldwin {
415b9befd33SJohn Baldwin struct procinfo *p;
4162b75c8adSJohn Baldwin
417b9befd33SJohn Baldwin p = find_proc(info, pid);
418b9befd33SJohn Baldwin assert(p != NULL);
4192b75c8adSJohn Baldwin
420b9befd33SJohn Baldwin info->curthread = LIST_FIRST(&p->threadlist);
421b9befd33SJohn Baldwin assert(info->curthread != NULL);
422b9befd33SJohn Baldwin assert(LIST_NEXT(info->curthread, entries) == NULL);
4232b75c8adSJohn Baldwin }
4242b75c8adSJohn Baldwin
4252b75c8adSJohn Baldwin static void
alloc_syscall(struct threadinfo * t,struct ptrace_lwpinfo * pl)4262b75c8adSJohn Baldwin alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl)
4272b75c8adSJohn Baldwin {
4282b75c8adSJohn Baldwin u_int i;
4292b75c8adSJohn Baldwin
4302b75c8adSJohn Baldwin assert(t->in_syscall == 0);
4312b75c8adSJohn Baldwin assert(t->cs.number == 0);
4321175b23fSJohn Baldwin assert(t->cs.sc == NULL);
4332b75c8adSJohn Baldwin assert(t->cs.nargs == 0);
4342b75c8adSJohn Baldwin for (i = 0; i < nitems(t->cs.s_args); i++)
4352b75c8adSJohn Baldwin assert(t->cs.s_args[i] == NULL);
4362b75c8adSJohn Baldwin memset(t->cs.args, 0, sizeof(t->cs.args));
4372b75c8adSJohn Baldwin t->cs.number = pl->pl_syscall_code;
4382b75c8adSJohn Baldwin t->in_syscall = 1;
4392b75c8adSJohn Baldwin }
4402b75c8adSJohn Baldwin
4412b75c8adSJohn Baldwin static void
free_syscall(struct threadinfo * t)4422b75c8adSJohn Baldwin free_syscall(struct threadinfo *t)
4432b75c8adSJohn Baldwin {
4442b75c8adSJohn Baldwin u_int i;
4452b75c8adSJohn Baldwin
4462b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++)
4472b75c8adSJohn Baldwin free(t->cs.s_args[i]);
4482b75c8adSJohn Baldwin memset(&t->cs, 0, sizeof(t->cs));
4492b75c8adSJohn Baldwin t->in_syscall = 0;
4502b75c8adSJohn Baldwin }
4512b75c8adSJohn Baldwin
4522b75c8adSJohn Baldwin static void
enter_syscall(struct trussinfo * info,struct threadinfo * t,struct ptrace_lwpinfo * pl)453b9befd33SJohn Baldwin enter_syscall(struct trussinfo *info, struct threadinfo *t,
454b9befd33SJohn Baldwin struct ptrace_lwpinfo *pl)
4552b75c8adSJohn Baldwin {
4562b75c8adSJohn Baldwin struct syscall *sc;
4572b75c8adSJohn Baldwin u_int i, narg;
4582b75c8adSJohn Baldwin
4592b75c8adSJohn Baldwin alloc_syscall(t, pl);
4602b75c8adSJohn Baldwin narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args));
461caa449b6SJohn Baldwin if (narg != 0 && ptrace(PT_GET_SC_ARGS, t->tid, (caddr_t)t->cs.args,
462caa449b6SJohn Baldwin sizeof(t->cs.args)) != 0) {
4632b75c8adSJohn Baldwin free_syscall(t);
4642b75c8adSJohn Baldwin return;
4652b75c8adSJohn Baldwin }
4662b75c8adSJohn Baldwin
4671175b23fSJohn Baldwin sc = get_syscall(t, t->cs.number, narg);
4681175b23fSJohn Baldwin if (sc->unknown)
4692b75c8adSJohn Baldwin fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n",
4702b75c8adSJohn Baldwin t->proc->abi->type, t->cs.number);
4712b75c8adSJohn Baldwin
4726019514bSAlex Richardson t->cs.nargs = sc->decode.nargs;
4736019514bSAlex Richardson assert(sc->decode.nargs <= nitems(t->cs.s_args));
4742b75c8adSJohn Baldwin
4752b75c8adSJohn Baldwin t->cs.sc = sc;
4762b75c8adSJohn Baldwin
4772b75c8adSJohn Baldwin /*
4782b75c8adSJohn Baldwin * At this point, we set up the system call arguments.
4792b75c8adSJohn Baldwin * We ignore any OUT ones, however -- those are arguments that
4802b75c8adSJohn Baldwin * are set by the system call, and so are probably meaningless
4812b75c8adSJohn Baldwin * now. This doesn't currently support arguments that are
4822b75c8adSJohn Baldwin * passed in *and* out, however.
4832b75c8adSJohn Baldwin */
4842b75c8adSJohn Baldwin #if DEBUG
4851175b23fSJohn Baldwin fprintf(stderr, "syscall %s(", sc->name);
4862b75c8adSJohn Baldwin #endif
4872b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) {
4882b75c8adSJohn Baldwin #if DEBUG
4896019514bSAlex Richardson fprintf(stderr, "0x%lx%s",
4906019514bSAlex Richardson t->cs.args[sc->decode.args[i].offset],
4912b75c8adSJohn Baldwin i < (t->cs.nargs - 1) ? "," : "");
4922b75c8adSJohn Baldwin #endif
4936019514bSAlex Richardson if (!(sc->decode.args[i].type & OUT)) {
4946019514bSAlex Richardson t->cs.s_args[i] = print_arg(&sc->decode.args[i],
495caa449b6SJohn Baldwin t->cs.args, NULL, info);
4962b75c8adSJohn Baldwin }
4972b75c8adSJohn Baldwin }
4982b75c8adSJohn Baldwin #if DEBUG
4992b75c8adSJohn Baldwin fprintf(stderr, ")\n");
5002b75c8adSJohn Baldwin #endif
5012b75c8adSJohn Baldwin
5022b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->before);
5032b75c8adSJohn Baldwin }
5042b75c8adSJohn Baldwin
505b9befd33SJohn Baldwin /*
506b9befd33SJohn Baldwin * When a thread exits voluntarily (including when a thread calls
507b9befd33SJohn Baldwin * exit() to trigger a process exit), the thread's internal state
508b9befd33SJohn Baldwin * holds the arguments passed to the exit system call. When the
509b9befd33SJohn Baldwin * thread's exit is reported, log that system call without a return
510b9befd33SJohn Baldwin * value.
511b9befd33SJohn Baldwin */
512b9befd33SJohn Baldwin static void
thread_exit_syscall(struct trussinfo * info)513b9befd33SJohn Baldwin thread_exit_syscall(struct trussinfo *info)
514b9befd33SJohn Baldwin {
515b9befd33SJohn Baldwin struct threadinfo *t;
516b9befd33SJohn Baldwin
517b9befd33SJohn Baldwin t = info->curthread;
518b9befd33SJohn Baldwin if (!t->in_syscall)
519b9befd33SJohn Baldwin return;
520b9befd33SJohn Baldwin
521b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after);
522b9befd33SJohn Baldwin
523b9befd33SJohn Baldwin print_syscall_ret(info, 0, NULL);
524b9befd33SJohn Baldwin free_syscall(t);
525b9befd33SJohn Baldwin }
526b9befd33SJohn Baldwin
5272b75c8adSJohn Baldwin static void
exit_syscall(struct trussinfo * info,struct ptrace_lwpinfo * pl)5282b75c8adSJohn Baldwin exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
5292b75c8adSJohn Baldwin {
5302b75c8adSJohn Baldwin struct threadinfo *t;
5312b75c8adSJohn Baldwin struct procinfo *p;
5322b75c8adSJohn Baldwin struct syscall *sc;
533caa449b6SJohn Baldwin struct ptrace_sc_ret psr;
5342b75c8adSJohn Baldwin u_int i;
5352b75c8adSJohn Baldwin
5362b75c8adSJohn Baldwin t = info->curthread;
5372b75c8adSJohn Baldwin if (!t->in_syscall)
5382b75c8adSJohn Baldwin return;
5392b75c8adSJohn Baldwin
5402b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after);
5412b75c8adSJohn Baldwin p = t->proc;
542caa449b6SJohn Baldwin if (ptrace(PT_GET_SC_RET, t->tid, (caddr_t)&psr, sizeof(psr)) != 0) {
5432b75c8adSJohn Baldwin free_syscall(t);
5442b75c8adSJohn Baldwin return;
5452b75c8adSJohn Baldwin }
5462b75c8adSJohn Baldwin
5472b75c8adSJohn Baldwin sc = t->cs.sc;
5482b75c8adSJohn Baldwin /*
5492b75c8adSJohn Baldwin * Here, we only look for arguments that have OUT masked in --
5502b75c8adSJohn Baldwin * otherwise, they were handled in enter_syscall().
5512b75c8adSJohn Baldwin */
5526019514bSAlex Richardson for (i = 0; i < sc->decode.nargs; i++) {
5532b75c8adSJohn Baldwin char *temp;
5542b75c8adSJohn Baldwin
5556019514bSAlex Richardson if (sc->decode.args[i].type & OUT) {
5562b75c8adSJohn Baldwin /*
5572b75c8adSJohn Baldwin * If an error occurred, then don't bother
5582b75c8adSJohn Baldwin * getting the data; it may not be valid.
5592b75c8adSJohn Baldwin */
560caa449b6SJohn Baldwin if (psr.sr_error != 0) {
5612b75c8adSJohn Baldwin asprintf(&temp, "0x%lx",
562b1ad6a90SBrooks Davis (long)t->cs.args[sc->decode.args[i].offset]);
5632b75c8adSJohn Baldwin } else {
5646019514bSAlex Richardson temp = print_arg(&sc->decode.args[i],
565caa449b6SJohn Baldwin t->cs.args, psr.sr_retval, info);
5662b75c8adSJohn Baldwin }
5672b75c8adSJohn Baldwin t->cs.s_args[i] = temp;
5682b75c8adSJohn Baldwin }
5692b75c8adSJohn Baldwin }
5702b75c8adSJohn Baldwin
571caa449b6SJohn Baldwin print_syscall_ret(info, psr.sr_error, psr.sr_retval);
5722b75c8adSJohn Baldwin free_syscall(t);
5732b75c8adSJohn Baldwin
5742b75c8adSJohn Baldwin /*
5752b75c8adSJohn Baldwin * If the process executed a new image, check the ABI. If the
5762b75c8adSJohn Baldwin * new ABI isn't supported, stop tracing this process.
5772b75c8adSJohn Baldwin */
5782b75c8adSJohn Baldwin if (pl->pl_flags & PL_FLAG_EXEC) {
579b9befd33SJohn Baldwin assert(LIST_NEXT(LIST_FIRST(&p->threadlist), entries) == NULL);
5802b75c8adSJohn Baldwin p->abi = find_abi(p->pid);
5812b75c8adSJohn Baldwin if (p->abi == NULL) {
5822b75c8adSJohn Baldwin if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0)
5832b75c8adSJohn Baldwin err(1, "Can not detach the process");
5842b75c8adSJohn Baldwin free_proc(p);
5852b75c8adSJohn Baldwin }
5862b75c8adSJohn Baldwin }
5872b75c8adSJohn Baldwin }
5882b75c8adSJohn Baldwin
589d70876fdSJohn Baldwin int
print_line_prefix(struct trussinfo * info)590d70876fdSJohn Baldwin print_line_prefix(struct trussinfo *info)
591d70876fdSJohn Baldwin {
592d70876fdSJohn Baldwin struct timespec timediff;
593d70876fdSJohn Baldwin struct threadinfo *t;
594d70876fdSJohn Baldwin int len;
595d70876fdSJohn Baldwin
596d70876fdSJohn Baldwin len = 0;
597d70876fdSJohn Baldwin t = info->curthread;
598d70876fdSJohn Baldwin if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) {
599d70876fdSJohn Baldwin if (info->flags & FOLLOWFORKS)
600d70876fdSJohn Baldwin len += fprintf(info->outfile, "%5d", t->proc->pid);
601d70876fdSJohn Baldwin if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) ==
602d70876fdSJohn Baldwin (FOLLOWFORKS | DISPLAYTIDS))
603d70876fdSJohn Baldwin len += fprintf(info->outfile, " ");
604d70876fdSJohn Baldwin if (info->flags & DISPLAYTIDS)
605d70876fdSJohn Baldwin len += fprintf(info->outfile, "%6d", t->tid);
606d70876fdSJohn Baldwin len += fprintf(info->outfile, ": ");
607d70876fdSJohn Baldwin }
608d70876fdSJohn Baldwin if (info->flags & ABSOLUTETIMESTAMPS) {
6096040822cSAlan Somers timespecsub(&t->after, &info->start_time, &timediff);
610d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ",
611d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec);
612d70876fdSJohn Baldwin }
613d70876fdSJohn Baldwin if (info->flags & RELATIVETIMESTAMPS) {
6146040822cSAlan Somers timespecsub(&t->after, &t->before, &timediff);
615d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ",
616d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec);
617d70876fdSJohn Baldwin }
618d70876fdSJohn Baldwin return (len);
619d70876fdSJohn Baldwin }
620d70876fdSJohn Baldwin
6212b75c8adSJohn Baldwin static void
report_thread_death(struct trussinfo * info)622b9befd33SJohn Baldwin report_thread_death(struct trussinfo *info)
623b9befd33SJohn Baldwin {
624b9befd33SJohn Baldwin struct threadinfo *t;
625b9befd33SJohn Baldwin
626b9befd33SJohn Baldwin t = info->curthread;
627b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after);
628b9befd33SJohn Baldwin print_line_prefix(info);
629b9befd33SJohn Baldwin fprintf(info->outfile, "<thread %ld exited>\n", (long)t->tid);
630b9befd33SJohn Baldwin }
631b9befd33SJohn Baldwin
632b9befd33SJohn Baldwin static void
report_thread_birth(struct trussinfo * info)633b9befd33SJohn Baldwin report_thread_birth(struct trussinfo *info)
634b9befd33SJohn Baldwin {
635b9befd33SJohn Baldwin struct threadinfo *t;
636b9befd33SJohn Baldwin
637b9befd33SJohn Baldwin t = info->curthread;
638b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after);
639b9befd33SJohn Baldwin t->before = t->after;
640b9befd33SJohn Baldwin print_line_prefix(info);
641b9befd33SJohn Baldwin fprintf(info->outfile, "<new thread %ld>\n", (long)t->tid);
642b9befd33SJohn Baldwin }
643b9befd33SJohn Baldwin
644b9befd33SJohn Baldwin static void
report_exit(struct trussinfo * info,siginfo_t * si)6452b75c8adSJohn Baldwin report_exit(struct trussinfo *info, siginfo_t *si)
6462b75c8adSJohn Baldwin {
647d70876fdSJohn Baldwin struct threadinfo *t;
6482b75c8adSJohn Baldwin
649d70876fdSJohn Baldwin t = info->curthread;
650d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after);
651d70876fdSJohn Baldwin print_line_prefix(info);
6522b75c8adSJohn Baldwin if (si->si_code == CLD_EXITED)
6532b75c8adSJohn Baldwin fprintf(info->outfile, "process exit, rval = %u\n",
6542b75c8adSJohn Baldwin si->si_status);
6552b75c8adSJohn Baldwin else
6562b75c8adSJohn Baldwin fprintf(info->outfile, "process killed, signal = %u%s\n",
6572b75c8adSJohn Baldwin si->si_status, si->si_code == CLD_DUMPED ?
6582b75c8adSJohn Baldwin " (core dumped)" : "");
6592b75c8adSJohn Baldwin }
6602b75c8adSJohn Baldwin
6612b75c8adSJohn Baldwin static void
report_new_child(struct trussinfo * info)662d70876fdSJohn Baldwin report_new_child(struct trussinfo *info)
6632b75c8adSJohn Baldwin {
664d70876fdSJohn Baldwin struct threadinfo *t;
6652b75c8adSJohn Baldwin
666d70876fdSJohn Baldwin t = info->curthread;
667d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after);
668d70876fdSJohn Baldwin t->before = t->after;
669d70876fdSJohn Baldwin print_line_prefix(info);
6702b75c8adSJohn Baldwin fprintf(info->outfile, "<new process>\n");
6712b75c8adSJohn Baldwin }
6722b75c8adSJohn Baldwin
67313e5e6b6SJohn Baldwin void
decode_siginfo(FILE * fp,siginfo_t * si)674ff577cb6SJohn Baldwin decode_siginfo(FILE *fp, siginfo_t *si)
675ff577cb6SJohn Baldwin {
676ff577cb6SJohn Baldwin const char *str;
677ff577cb6SJohn Baldwin
678ff577cb6SJohn Baldwin fprintf(fp, " code=");
679ff577cb6SJohn Baldwin str = sysdecode_sigcode(si->si_signo, si->si_code);
680ff577cb6SJohn Baldwin if (str == NULL)
681ff577cb6SJohn Baldwin fprintf(fp, "%d", si->si_code);
682ff577cb6SJohn Baldwin else
683ff577cb6SJohn Baldwin fprintf(fp, "%s", str);
684ff577cb6SJohn Baldwin switch (si->si_code) {
685ff577cb6SJohn Baldwin case SI_NOINFO:
686ff577cb6SJohn Baldwin break;
687ff577cb6SJohn Baldwin case SI_QUEUE:
688ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr);
689ff577cb6SJohn Baldwin /* FALLTHROUGH */
690ff577cb6SJohn Baldwin case SI_USER:
691ff577cb6SJohn Baldwin case SI_LWP:
692ff577cb6SJohn Baldwin fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid,
693ff577cb6SJohn Baldwin (intmax_t)si->si_uid);
694ff577cb6SJohn Baldwin break;
695ff577cb6SJohn Baldwin case SI_TIMER:
696ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr);
697ff577cb6SJohn Baldwin fprintf(fp, " timerid=%d", si->si_timerid);
698ff577cb6SJohn Baldwin fprintf(fp, " overrun=%d", si->si_overrun);
699ff577cb6SJohn Baldwin if (si->si_errno != 0)
700ff577cb6SJohn Baldwin fprintf(fp, " errno=%d", si->si_errno);
701ff577cb6SJohn Baldwin break;
702ff577cb6SJohn Baldwin case SI_ASYNCIO:
703ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr);
704ff577cb6SJohn Baldwin break;
705ff577cb6SJohn Baldwin case SI_MESGQ:
706ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr);
707ff577cb6SJohn Baldwin fprintf(fp, " mqd=%d", si->si_mqd);
708ff577cb6SJohn Baldwin break;
709ff577cb6SJohn Baldwin default:
710ff577cb6SJohn Baldwin switch (si->si_signo) {
711ff577cb6SJohn Baldwin case SIGILL:
712ff577cb6SJohn Baldwin case SIGFPE:
713ff577cb6SJohn Baldwin case SIGSEGV:
714ff577cb6SJohn Baldwin case SIGBUS:
715ff577cb6SJohn Baldwin fprintf(fp, " trapno=%d", si->si_trapno);
716ff577cb6SJohn Baldwin fprintf(fp, " addr=%p", si->si_addr);
717ff577cb6SJohn Baldwin break;
718ff577cb6SJohn Baldwin case SIGCHLD:
719ff577cb6SJohn Baldwin fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid,
720ff577cb6SJohn Baldwin (intmax_t)si->si_uid);
721ff577cb6SJohn Baldwin fprintf(fp, " status=%d", si->si_status);
722ff577cb6SJohn Baldwin break;
723ff577cb6SJohn Baldwin }
724ff577cb6SJohn Baldwin }
725ff577cb6SJohn Baldwin }
726ff577cb6SJohn Baldwin
727ff577cb6SJohn Baldwin static void
report_signal(struct trussinfo * info,siginfo_t * si,struct ptrace_lwpinfo * pl)728ff577cb6SJohn Baldwin report_signal(struct trussinfo *info, siginfo_t *si, struct ptrace_lwpinfo *pl)
7292b75c8adSJohn Baldwin {
730d70876fdSJohn Baldwin struct threadinfo *t;
7319289f547SJohn Baldwin const char *signame;
7322b75c8adSJohn Baldwin
733d70876fdSJohn Baldwin t = info->curthread;
734d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after);
735d70876fdSJohn Baldwin print_line_prefix(info);
7369289f547SJohn Baldwin signame = sysdecode_signal(si->si_status);
7379289f547SJohn Baldwin if (signame == NULL)
7389289f547SJohn Baldwin signame = "?";
739ff577cb6SJohn Baldwin fprintf(info->outfile, "SIGNAL %u (%s)", si->si_status, signame);
740ff577cb6SJohn Baldwin if (pl->pl_event == PL_EVENT_SIGNAL && pl->pl_flags & PL_FLAG_SI)
741ff577cb6SJohn Baldwin decode_siginfo(info->outfile, &pl->pl_siginfo);
742ff577cb6SJohn Baldwin fprintf(info->outfile, "\n");
743ff577cb6SJohn Baldwin
7442b75c8adSJohn Baldwin }
7452b75c8adSJohn Baldwin
7462b75c8adSJohn Baldwin /*
7472b75c8adSJohn Baldwin * Wait for events until all the processes have exited or truss has been
7482b75c8adSJohn Baldwin * asked to stop.
7495d2d083cSXin LI */
7505d2d083cSXin LI void
eventloop(struct trussinfo * info)7512b75c8adSJohn Baldwin eventloop(struct trussinfo *info)
7525d2d083cSXin LI {
7532b75c8adSJohn Baldwin struct ptrace_lwpinfo pl;
7542b75c8adSJohn Baldwin siginfo_t si;
7552b75c8adSJohn Baldwin int pending_signal;
7565d2d083cSXin LI
7572b75c8adSJohn Baldwin while (!LIST_EMPTY(&info->proclist)) {
758896fc463SAndrey Zonov if (detaching) {
7592b75c8adSJohn Baldwin detach_all_procs(info);
760896fc463SAndrey Zonov return;
761896fc463SAndrey Zonov }
762896fc463SAndrey Zonov
7632b75c8adSJohn Baldwin if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) {
764896fc463SAndrey Zonov if (errno == EINTR)
7652b75c8adSJohn Baldwin continue;
7662b75c8adSJohn Baldwin err(1, "Unexpected error from waitid");
767896fc463SAndrey Zonov }
7685d2d083cSXin LI
7692b75c8adSJohn Baldwin assert(si.si_signo == SIGCHLD);
7702b75c8adSJohn Baldwin
7712b75c8adSJohn Baldwin switch (si.si_code) {
7722b75c8adSJohn Baldwin case CLD_EXITED:
7732b75c8adSJohn Baldwin case CLD_KILLED:
7742b75c8adSJohn Baldwin case CLD_DUMPED:
7752b75c8adSJohn Baldwin find_exit_thread(info, si.si_pid);
776b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) {
777b9befd33SJohn Baldwin if (si.si_code == CLD_EXITED)
778b9befd33SJohn Baldwin thread_exit_syscall(info);
7792b75c8adSJohn Baldwin report_exit(info, &si);
780b9befd33SJohn Baldwin }
7812b75c8adSJohn Baldwin free_proc(info->curthread->proc);
7822b75c8adSJohn Baldwin info->curthread = NULL;
7835d2d083cSXin LI break;
7842b75c8adSJohn Baldwin case CLD_TRAPPED:
7852b75c8adSJohn Baldwin if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl,
7862b75c8adSJohn Baldwin sizeof(pl)) == -1)
7872b75c8adSJohn Baldwin err(1, "ptrace(PT_LWPINFO)");
7882b75c8adSJohn Baldwin
7892b75c8adSJohn Baldwin if (pl.pl_flags & PL_FLAG_CHILD) {
790b9befd33SJohn Baldwin new_proc(info, si.si_pid, pl.pl_lwpid);
7912b75c8adSJohn Baldwin assert(LIST_FIRST(&info->proclist)->abi !=
7922b75c8adSJohn Baldwin NULL);
793b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_BORN)
794b9befd33SJohn Baldwin new_thread(find_proc(info, si.si_pid),
795b9befd33SJohn Baldwin pl.pl_lwpid);
7962b75c8adSJohn Baldwin find_thread(info, si.si_pid, pl.pl_lwpid);
7972b75c8adSJohn Baldwin
79894746562SBryan Drewery if (si.si_status == SIGTRAP &&
799b9befd33SJohn Baldwin (pl.pl_flags & (PL_FLAG_BORN|PL_FLAG_EXITED|
800b9befd33SJohn Baldwin PL_FLAG_SCE|PL_FLAG_SCX)) != 0) {
801b9befd33SJohn Baldwin if (pl.pl_flags & PL_FLAG_BORN) {
802b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0)
803b9befd33SJohn Baldwin report_thread_birth(info);
804b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_EXITED) {
805b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0)
806b9befd33SJohn Baldwin report_thread_death(info);
807b9befd33SJohn Baldwin free_thread(info->curthread);
808b9befd33SJohn Baldwin info->curthread = NULL;
809b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_SCE)
810b9befd33SJohn Baldwin enter_syscall(info, info->curthread, &pl);
8112b75c8adSJohn Baldwin else if (pl.pl_flags & PL_FLAG_SCX)
8122b75c8adSJohn Baldwin exit_syscall(info, &pl);
8132b75c8adSJohn Baldwin pending_signal = 0;
8142b75c8adSJohn Baldwin } else if (pl.pl_flags & PL_FLAG_CHILD) {
8152b75c8adSJohn Baldwin if ((info->flags & COUNTONLY) == 0)
816d70876fdSJohn Baldwin report_new_child(info);
8172b75c8adSJohn Baldwin pending_signal = 0;
8182b75c8adSJohn Baldwin } else {
8192b75c8adSJohn Baldwin if ((info->flags & NOSIGS) == 0)
820ff577cb6SJohn Baldwin report_signal(info, &si, &pl);
8212b75c8adSJohn Baldwin pending_signal = si.si_status;
82297695ad4SKonstantin Belousov }
8232b75c8adSJohn Baldwin ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
8242b75c8adSJohn Baldwin pending_signal);
8252b75c8adSJohn Baldwin break;
8262b75c8adSJohn Baldwin case CLD_STOPPED:
8272b75c8adSJohn Baldwin errx(1, "waitid reported CLD_STOPPED");
8282b75c8adSJohn Baldwin case CLD_CONTINUED:
8295d2d083cSXin LI break;
8305d2d083cSXin LI }
8315d2d083cSXin LI }
8325d2d083cSXin LI }
833