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> 446040822cSAlan 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 64caa449b6SJohn Baldwin struct procabi_table { 65caa449b6SJohn Baldwin const char *name; 66caa449b6SJohn Baldwin struct procabi *abi; 67caa449b6SJohn Baldwin }; 682b75c8adSJohn Baldwin 69896fc463SAndrey Zonov static sig_atomic_t detaching; 70bbeaf6c0SSean Eric Fagan 71b9befd33SJohn Baldwin static void enter_syscall(struct trussinfo *, struct threadinfo *, 72b9befd33SJohn Baldwin struct ptrace_lwpinfo *); 73b9befd33SJohn Baldwin static void new_proc(struct trussinfo *, pid_t, lwpid_t); 742b75c8adSJohn Baldwin 75caa449b6SJohn Baldwin 76caa449b6SJohn Baldwin static struct procabi cloudabi32 = { 777daca4e2SAlex Richardson .type = "CloudABI32", 787daca4e2SAlex Richardson .abi = SYSDECODE_ABI_CLOUDABI32, 797daca4e2SAlex Richardson .pointer_size = sizeof(uint32_t), 807daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(cloudabi32.extra_syscalls), 817daca4e2SAlex Richardson .syscalls = { NULL } 82caa449b6SJohn Baldwin }; 83caa449b6SJohn Baldwin 84caa449b6SJohn Baldwin static struct procabi cloudabi64 = { 857daca4e2SAlex Richardson .type = "CloudABI64", 867daca4e2SAlex Richardson .abi = SYSDECODE_ABI_CLOUDABI64, 877daca4e2SAlex Richardson .pointer_size = sizeof(uint64_t), 887daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(cloudabi64.extra_syscalls), 897daca4e2SAlex Richardson .syscalls = { NULL } 90caa449b6SJohn Baldwin }; 91caa449b6SJohn Baldwin 92caa449b6SJohn Baldwin static struct procabi freebsd = { 937daca4e2SAlex Richardson .type = "FreeBSD", 947daca4e2SAlex Richardson .abi = SYSDECODE_ABI_FREEBSD, 957daca4e2SAlex Richardson .pointer_size = sizeof(void *), 967daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(freebsd.extra_syscalls), 977daca4e2SAlex Richardson .syscalls = { NULL } 98caa449b6SJohn Baldwin }; 99caa449b6SJohn Baldwin 1007daca4e2SAlex Richardson #if !defined(__SIZEOF_POINTER__) 1017daca4e2SAlex Richardson #error "Use a modern compiler." 1027daca4e2SAlex Richardson #endif 1037daca4e2SAlex Richardson 1047daca4e2SAlex Richardson #if __SIZEOF_POINTER__ > 4 105caa449b6SJohn Baldwin static struct procabi freebsd32 = { 1067daca4e2SAlex Richardson .type = "FreeBSD32", 1077daca4e2SAlex Richardson .abi = SYSDECODE_ABI_FREEBSD32, 1087daca4e2SAlex Richardson .pointer_size = sizeof(uint32_t), 109*3cbad828SAlex Richardson .compat_prefix = "freebsd32_", 1107daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(freebsd32.extra_syscalls), 1117daca4e2SAlex Richardson .syscalls = { NULL } 112caa449b6SJohn Baldwin }; 113caa449b6SJohn Baldwin #endif 114caa449b6SJohn Baldwin 115caa449b6SJohn Baldwin static struct procabi linux = { 1167daca4e2SAlex Richardson .type = "Linux", 1177daca4e2SAlex Richardson .abi = SYSDECODE_ABI_LINUX, 1187daca4e2SAlex Richardson .pointer_size = sizeof(void *), 1197daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(linux.extra_syscalls), 1207daca4e2SAlex Richardson .syscalls = { NULL } 121caa449b6SJohn Baldwin }; 122caa449b6SJohn Baldwin 1237daca4e2SAlex Richardson #if __SIZEOF_POINTER__ > 4 124caa449b6SJohn Baldwin static struct procabi linux32 = { 1257daca4e2SAlex Richardson .type = "Linux32", 1267daca4e2SAlex Richardson .abi = SYSDECODE_ABI_LINUX32, 1277daca4e2SAlex Richardson .pointer_size = sizeof(uint32_t), 1287daca4e2SAlex Richardson .extra_syscalls = STAILQ_HEAD_INITIALIZER(linux32.extra_syscalls), 1297daca4e2SAlex Richardson .syscalls = { NULL } 130caa449b6SJohn Baldwin }; 131caa449b6SJohn Baldwin #endif 132caa449b6SJohn Baldwin 133caa449b6SJohn Baldwin static struct procabi_table abis[] = { 134caa449b6SJohn Baldwin { "CloudABI ELF32", &cloudabi32 }, 135caa449b6SJohn Baldwin { "CloudABI ELF64", &cloudabi64 }, 1367daca4e2SAlex Richardson #if __SIZEOF_POINTER__ == 4 1377daca4e2SAlex Richardson { "FreeBSD ELF32", &freebsd }, 1387daca4e2SAlex Richardson #elif __SIZEOF_POINTER__ == 8 139caa449b6SJohn Baldwin { "FreeBSD ELF64", &freebsd }, 140caa449b6SJohn Baldwin { "FreeBSD ELF32", &freebsd32 }, 141caa449b6SJohn Baldwin #else 1427daca4e2SAlex Richardson #error "Unsupported pointer size" 143caa449b6SJohn Baldwin #endif 144caa449b6SJohn Baldwin #if defined(__powerpc64__) 145caa449b6SJohn Baldwin { "FreeBSD ELF64 V2", &freebsd }, 146caa449b6SJohn Baldwin #endif 147caa449b6SJohn Baldwin #if defined(__amd64__) 148caa449b6SJohn Baldwin { "FreeBSD a.out", &freebsd32 }, 149caa449b6SJohn Baldwin #endif 150caa449b6SJohn Baldwin #if defined(__i386__) 151caa449b6SJohn Baldwin { "FreeBSD a.out", &freebsd }, 152caa449b6SJohn Baldwin #endif 1537daca4e2SAlex Richardson #if __SIZEOF_POINTER__ >= 8 154caa449b6SJohn Baldwin { "Linux ELF64", &linux }, 155caa449b6SJohn Baldwin { "Linux ELF32", &linux32 }, 156caa449b6SJohn Baldwin #else 1575faeda90SJessica Clarke { "Linux ELF32", &linux }, 158caa449b6SJohn Baldwin #endif 159caa449b6SJohn Baldwin }; 160caa449b6SJohn Baldwin 161bbeaf6c0SSean Eric Fagan /* 162bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 1632b75c8adSJohn Baldwin * is fork(), enable tracing in the child, and then exec the given 1642b75c8adSJohn Baldwin * command. At that point, the child process stops, and the parent 1652b75c8adSJohn Baldwin * can wake up and deal with it. 166bbeaf6c0SSean Eric Fagan */ 1672b75c8adSJohn Baldwin void 1682b75c8adSJohn Baldwin setup_and_wait(struct trussinfo *info, char *command[]) 1695321ae86SAlfred Perlstein { 170be305c9cSAndrey Zonov pid_t pid; 171bbeaf6c0SSean Eric Fagan 1725d2d083cSXin LI pid = vfork(); 17394355cfdSAndrey Zonov if (pid == -1) 1741fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 175bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 1765d2d083cSXin LI ptrace(PT_TRACE_ME, 0, 0, 0); 177bbeaf6c0SSean Eric Fagan execvp(command[0], command); 1785d2d083cSXin LI err(1, "execvp %s", command[0]); 179bbeaf6c0SSean Eric Fagan } 1805d2d083cSXin LI 181bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 182310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 1835d2d083cSXin LI err(1, "unexpect stop in waitpid"); 184bbeaf6c0SSean Eric Fagan 185b9befd33SJohn Baldwin new_proc(info, pid, 0); 186bbeaf6c0SSean Eric Fagan } 187bbeaf6c0SSean Eric Fagan 188bbeaf6c0SSean Eric Fagan /* 1892b75c8adSJohn Baldwin * start_tracing is called to attach to an existing process. 190bbeaf6c0SSean Eric Fagan */ 1912b75c8adSJohn Baldwin void 1922b75c8adSJohn Baldwin start_tracing(struct trussinfo *info, pid_t pid) 1935321ae86SAlfred Perlstein { 194310da894SAndrey Zonov int ret, retry; 1955321ae86SAlfred Perlstein 19694355cfdSAndrey Zonov retry = 10; 1975d2d083cSXin LI do { 1985d2d083cSXin LI ret = ptrace(PT_ATTACH, pid, NULL, 0); 1995d2d083cSXin LI usleep(200); 2005d2d083cSXin LI } while (ret && retry-- > 0); 2015d2d083cSXin LI if (ret) 2025d2d083cSXin LI err(1, "can not attach to target process"); 20320fa828fSSean Eric Fagan 204310da894SAndrey Zonov if (waitpid(pid, NULL, 0) < 0) 2055d2d083cSXin LI err(1, "Unexpect stop in waitpid"); 206bbeaf6c0SSean Eric Fagan 207b9befd33SJohn Baldwin new_proc(info, pid, 0); 208bbeaf6c0SSean Eric Fagan } 209bbeaf6c0SSean Eric Fagan 210bbeaf6c0SSean Eric Fagan /* 211bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 212bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 213bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 214bbeaf6c0SSean Eric Fagan * process. 215bbeaf6c0SSean Eric Fagan */ 216bbeaf6c0SSean Eric Fagan void 2175d2d083cSXin LI restore_proc(int signo __unused) 2185d2d083cSXin LI { 219896fc463SAndrey Zonov 220896fc463SAndrey Zonov detaching = 1; 221896fc463SAndrey Zonov } 222896fc463SAndrey Zonov 2232b75c8adSJohn Baldwin static void 224896fc463SAndrey Zonov detach_proc(pid_t pid) 225896fc463SAndrey Zonov { 226bbeaf6c0SSean Eric Fagan 2275d2d083cSXin LI /* stop the child so that we can detach */ 228896fc463SAndrey Zonov kill(pid, SIGSTOP); 2292b75c8adSJohn Baldwin if (waitpid(pid, NULL, 0) < 0) 2305d2d083cSXin LI err(1, "Unexpected stop in waitpid"); 2315d2d083cSXin LI 232896fc463SAndrey Zonov if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) 2335d2d083cSXin LI err(1, "Can not detach the process"); 2345d2d083cSXin LI 235896fc463SAndrey Zonov kill(pid, SIGCONT); 236bbeaf6c0SSean Eric Fagan } 2375d2d083cSXin LI 2385d2d083cSXin LI /* 2392b75c8adSJohn Baldwin * Determine the ABI. This is called after every exec, and when 2402b75c8adSJohn Baldwin * a process is first monitored. 2412b75c8adSJohn Baldwin */ 2422b75c8adSJohn Baldwin static struct procabi * 2432b75c8adSJohn Baldwin find_abi(pid_t pid) 2442b75c8adSJohn Baldwin { 2452b75c8adSJohn Baldwin size_t len; 246caa449b6SJohn Baldwin unsigned int i; 2472b75c8adSJohn Baldwin int error; 2482b75c8adSJohn Baldwin int mib[4]; 2492b75c8adSJohn Baldwin char progt[32]; 2502b75c8adSJohn Baldwin 2512b75c8adSJohn Baldwin len = sizeof(progt); 2522b75c8adSJohn Baldwin mib[0] = CTL_KERN; 2532b75c8adSJohn Baldwin mib[1] = KERN_PROC; 2542b75c8adSJohn Baldwin mib[2] = KERN_PROC_SV_NAME; 2552b75c8adSJohn Baldwin mib[3] = pid; 2562b75c8adSJohn Baldwin error = sysctl(mib, 4, progt, &len, NULL, 0); 2572b75c8adSJohn Baldwin if (error != 0) 2582b75c8adSJohn Baldwin err(2, "can not get sysvec name"); 2592b75c8adSJohn Baldwin 260caa449b6SJohn Baldwin for (i = 0; i < nitems(abis); i++) { 261caa449b6SJohn Baldwin if (strcmp(abis[i].name, progt) == 0) 262caa449b6SJohn Baldwin return (abis[i].abi); 2632b75c8adSJohn Baldwin } 2642b75c8adSJohn Baldwin warnx("ABI %s for pid %ld is not supported", progt, (long)pid); 2652b75c8adSJohn Baldwin return (NULL); 2662b75c8adSJohn Baldwin } 2672b75c8adSJohn Baldwin 268b9befd33SJohn Baldwin static struct threadinfo * 269b9befd33SJohn Baldwin new_thread(struct procinfo *p, lwpid_t lwpid) 270b9befd33SJohn Baldwin { 271b9befd33SJohn Baldwin struct threadinfo *nt; 272b9befd33SJohn Baldwin 273b9befd33SJohn Baldwin /* 274b9befd33SJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately 275b9befd33SJohn Baldwin * this will kill any processes truss is attached to. 276b9befd33SJohn Baldwin */ 277b9befd33SJohn Baldwin LIST_FOREACH(nt, &p->threadlist, entries) { 278b9befd33SJohn Baldwin if (nt->tid == lwpid) 279b9befd33SJohn Baldwin errx(1, "Duplicate thread for LWP %ld", (long)lwpid); 280b9befd33SJohn Baldwin } 281b9befd33SJohn Baldwin 282b9befd33SJohn Baldwin nt = calloc(1, sizeof(struct threadinfo)); 283b9befd33SJohn Baldwin if (nt == NULL) 284b9befd33SJohn Baldwin err(1, "calloc() failed"); 285b9befd33SJohn Baldwin nt->proc = p; 286b9befd33SJohn Baldwin nt->tid = lwpid; 287b9befd33SJohn Baldwin LIST_INSERT_HEAD(&p->threadlist, nt, entries); 288b9befd33SJohn Baldwin return (nt); 289b9befd33SJohn Baldwin } 290b9befd33SJohn Baldwin 2912b75c8adSJohn Baldwin static void 292b9befd33SJohn Baldwin free_thread(struct threadinfo *t) 293b9befd33SJohn Baldwin { 294b9befd33SJohn Baldwin 295b9befd33SJohn Baldwin LIST_REMOVE(t, entries); 296b9befd33SJohn Baldwin free(t); 297b9befd33SJohn Baldwin } 298b9befd33SJohn Baldwin 299b9befd33SJohn Baldwin static void 300b9befd33SJohn Baldwin add_threads(struct trussinfo *info, struct procinfo *p) 301b9befd33SJohn Baldwin { 302b9befd33SJohn Baldwin struct ptrace_lwpinfo pl; 303b9befd33SJohn Baldwin struct threadinfo *t; 304b9befd33SJohn Baldwin lwpid_t *lwps; 305b9befd33SJohn Baldwin int i, nlwps; 306b9befd33SJohn Baldwin 307b9befd33SJohn Baldwin nlwps = ptrace(PT_GETNUMLWPS, p->pid, NULL, 0); 308b9befd33SJohn Baldwin if (nlwps == -1) 309b9befd33SJohn Baldwin err(1, "Unable to fetch number of LWPs"); 310b9befd33SJohn Baldwin assert(nlwps > 0); 311b9befd33SJohn Baldwin lwps = calloc(nlwps, sizeof(*lwps)); 312b9befd33SJohn Baldwin nlwps = ptrace(PT_GETLWPLIST, p->pid, (caddr_t)lwps, nlwps); 313b9befd33SJohn Baldwin if (nlwps == -1) 314b9befd33SJohn Baldwin err(1, "Unable to fetch LWP list"); 315b9befd33SJohn Baldwin for (i = 0; i < nlwps; i++) { 316b9befd33SJohn Baldwin t = new_thread(p, lwps[i]); 317b9befd33SJohn Baldwin if (ptrace(PT_LWPINFO, lwps[i], (caddr_t)&pl, sizeof(pl)) == -1) 318b9befd33SJohn Baldwin err(1, "ptrace(PT_LWPINFO)"); 3190f21f528SBaptiste Daroussin if (pl.pl_flags & PL_FLAG_SCE) { 3200f21f528SBaptiste Daroussin info->curthread = t; 321b9befd33SJohn Baldwin enter_syscall(info, t, &pl); 322b9befd33SJohn Baldwin } 3230f21f528SBaptiste Daroussin } 324b9befd33SJohn Baldwin free(lwps); 325b9befd33SJohn Baldwin } 326b9befd33SJohn Baldwin 327b9befd33SJohn Baldwin static void 328b9befd33SJohn Baldwin new_proc(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 3292b75c8adSJohn Baldwin { 3302b75c8adSJohn Baldwin struct procinfo *np; 3312b75c8adSJohn Baldwin 3322b75c8adSJohn Baldwin /* 3332b75c8adSJohn Baldwin * If this happens it means there is a bug in truss. Unfortunately 334b9befd33SJohn Baldwin * this will kill any processes truss is attached to. 3352b75c8adSJohn Baldwin */ 3362b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 3372b75c8adSJohn Baldwin if (np->pid == pid) 3382b75c8adSJohn Baldwin errx(1, "Duplicate process for pid %ld", (long)pid); 3392b75c8adSJohn Baldwin } 3402b75c8adSJohn Baldwin 3412b75c8adSJohn Baldwin if (info->flags & FOLLOWFORKS) 3422b75c8adSJohn Baldwin if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1) 3432b75c8adSJohn Baldwin err(1, "Unable to follow forks for pid %ld", (long)pid); 344b9befd33SJohn Baldwin if (ptrace(PT_LWP_EVENTS, pid, NULL, 1) == -1) 345b9befd33SJohn Baldwin err(1, "Unable to enable LWP events for pid %ld", (long)pid); 3462b75c8adSJohn Baldwin np = calloc(1, sizeof(struct procinfo)); 3472b75c8adSJohn Baldwin np->pid = pid; 3482b75c8adSJohn Baldwin np->abi = find_abi(pid); 349b9befd33SJohn Baldwin LIST_INIT(&np->threadlist); 3502b75c8adSJohn Baldwin LIST_INSERT_HEAD(&info->proclist, np, entries); 351b9befd33SJohn Baldwin 352b9befd33SJohn Baldwin if (lwpid != 0) 353b9befd33SJohn Baldwin new_thread(np, lwpid); 354b9befd33SJohn Baldwin else 355b9befd33SJohn Baldwin add_threads(info, np); 3562b75c8adSJohn Baldwin } 3572b75c8adSJohn Baldwin 3582b75c8adSJohn Baldwin static void 3592b75c8adSJohn Baldwin free_proc(struct procinfo *p) 3602b75c8adSJohn Baldwin { 3612b75c8adSJohn Baldwin struct threadinfo *t, *t2; 3622b75c8adSJohn Baldwin 363b9befd33SJohn Baldwin LIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) { 3642b75c8adSJohn Baldwin free(t); 3652b75c8adSJohn Baldwin } 3662b75c8adSJohn Baldwin LIST_REMOVE(p, entries); 3672b75c8adSJohn Baldwin free(p); 3682b75c8adSJohn Baldwin } 3692b75c8adSJohn Baldwin 3702b75c8adSJohn Baldwin static void 3712b75c8adSJohn Baldwin detach_all_procs(struct trussinfo *info) 3722b75c8adSJohn Baldwin { 3732b75c8adSJohn Baldwin struct procinfo *p, *p2; 3742b75c8adSJohn Baldwin 3752b75c8adSJohn Baldwin LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) { 3762b75c8adSJohn Baldwin detach_proc(p->pid); 3772b75c8adSJohn Baldwin free_proc(p); 3782b75c8adSJohn Baldwin } 3792b75c8adSJohn Baldwin } 3802b75c8adSJohn Baldwin 3812b75c8adSJohn Baldwin static struct procinfo * 3822b75c8adSJohn Baldwin find_proc(struct trussinfo *info, pid_t pid) 3832b75c8adSJohn Baldwin { 3842b75c8adSJohn Baldwin struct procinfo *np; 3852b75c8adSJohn Baldwin 3862b75c8adSJohn Baldwin LIST_FOREACH(np, &info->proclist, entries) { 3872b75c8adSJohn Baldwin if (np->pid == pid) 3882b75c8adSJohn Baldwin return (np); 3892b75c8adSJohn Baldwin } 3902b75c8adSJohn Baldwin 3912b75c8adSJohn Baldwin return (NULL); 3922b75c8adSJohn Baldwin } 3932b75c8adSJohn Baldwin 3942b75c8adSJohn Baldwin /* 3952b75c8adSJohn Baldwin * Change curthread member based on (pid, lwpid). 3965d2d083cSXin LI */ 3975d2d083cSXin LI static void 3982b75c8adSJohn Baldwin find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid) 3995d2d083cSXin LI { 4002b75c8adSJohn Baldwin struct procinfo *np; 4012b75c8adSJohn Baldwin struct threadinfo *nt; 40294355cfdSAndrey Zonov 4032b75c8adSJohn Baldwin np = find_proc(info, pid); 4042b75c8adSJohn Baldwin assert(np != NULL); 4052b75c8adSJohn Baldwin 406b9befd33SJohn Baldwin LIST_FOREACH(nt, &np->threadlist, entries) { 4072b75c8adSJohn Baldwin if (nt->tid == lwpid) { 4082b75c8adSJohn Baldwin info->curthread = nt; 4095d2d083cSXin LI return; 4105d2d083cSXin LI } 4115d2d083cSXin LI } 412b9befd33SJohn Baldwin errx(1, "could not find thread"); 4135d2d083cSXin LI } 4145d2d083cSXin LI 4155d2d083cSXin LI /* 416b9befd33SJohn Baldwin * When a process exits, it should have exactly one thread left. 417b9befd33SJohn Baldwin * All of the other threads should have reported thread exit events. 4182b75c8adSJohn Baldwin */ 4192b75c8adSJohn Baldwin static void 4202b75c8adSJohn Baldwin find_exit_thread(struct trussinfo *info, pid_t pid) 4212b75c8adSJohn Baldwin { 422b9befd33SJohn Baldwin struct procinfo *p; 4232b75c8adSJohn Baldwin 424b9befd33SJohn Baldwin p = find_proc(info, pid); 425b9befd33SJohn Baldwin assert(p != NULL); 4262b75c8adSJohn Baldwin 427b9befd33SJohn Baldwin info->curthread = LIST_FIRST(&p->threadlist); 428b9befd33SJohn Baldwin assert(info->curthread != NULL); 429b9befd33SJohn Baldwin assert(LIST_NEXT(info->curthread, entries) == NULL); 4302b75c8adSJohn Baldwin } 4312b75c8adSJohn Baldwin 4322b75c8adSJohn Baldwin static void 4332b75c8adSJohn Baldwin alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl) 4342b75c8adSJohn Baldwin { 4352b75c8adSJohn Baldwin u_int i; 4362b75c8adSJohn Baldwin 4372b75c8adSJohn Baldwin assert(t->in_syscall == 0); 4382b75c8adSJohn Baldwin assert(t->cs.number == 0); 4391175b23fSJohn Baldwin assert(t->cs.sc == NULL); 4402b75c8adSJohn Baldwin assert(t->cs.nargs == 0); 4412b75c8adSJohn Baldwin for (i = 0; i < nitems(t->cs.s_args); i++) 4422b75c8adSJohn Baldwin assert(t->cs.s_args[i] == NULL); 4432b75c8adSJohn Baldwin memset(t->cs.args, 0, sizeof(t->cs.args)); 4442b75c8adSJohn Baldwin t->cs.number = pl->pl_syscall_code; 4452b75c8adSJohn Baldwin t->in_syscall = 1; 4462b75c8adSJohn Baldwin } 4472b75c8adSJohn Baldwin 4482b75c8adSJohn Baldwin static void 4492b75c8adSJohn Baldwin free_syscall(struct threadinfo *t) 4502b75c8adSJohn Baldwin { 4512b75c8adSJohn Baldwin u_int i; 4522b75c8adSJohn Baldwin 4532b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) 4542b75c8adSJohn Baldwin free(t->cs.s_args[i]); 4552b75c8adSJohn Baldwin memset(&t->cs, 0, sizeof(t->cs)); 4562b75c8adSJohn Baldwin t->in_syscall = 0; 4572b75c8adSJohn Baldwin } 4582b75c8adSJohn Baldwin 4592b75c8adSJohn Baldwin static void 460b9befd33SJohn Baldwin enter_syscall(struct trussinfo *info, struct threadinfo *t, 461b9befd33SJohn Baldwin struct ptrace_lwpinfo *pl) 4622b75c8adSJohn Baldwin { 4632b75c8adSJohn Baldwin struct syscall *sc; 4642b75c8adSJohn Baldwin u_int i, narg; 4652b75c8adSJohn Baldwin 4662b75c8adSJohn Baldwin alloc_syscall(t, pl); 4672b75c8adSJohn Baldwin narg = MIN(pl->pl_syscall_narg, nitems(t->cs.args)); 468caa449b6SJohn Baldwin if (narg != 0 && ptrace(PT_GET_SC_ARGS, t->tid, (caddr_t)t->cs.args, 469caa449b6SJohn Baldwin sizeof(t->cs.args)) != 0) { 4702b75c8adSJohn Baldwin free_syscall(t); 4712b75c8adSJohn Baldwin return; 4722b75c8adSJohn Baldwin } 4732b75c8adSJohn Baldwin 4741175b23fSJohn Baldwin sc = get_syscall(t, t->cs.number, narg); 4751175b23fSJohn Baldwin if (sc->unknown) 4762b75c8adSJohn Baldwin fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n", 4772b75c8adSJohn Baldwin t->proc->abi->type, t->cs.number); 4782b75c8adSJohn Baldwin 4796019514bSAlex Richardson t->cs.nargs = sc->decode.nargs; 4806019514bSAlex Richardson assert(sc->decode.nargs <= nitems(t->cs.s_args)); 4812b75c8adSJohn Baldwin 4822b75c8adSJohn Baldwin t->cs.sc = sc; 4832b75c8adSJohn Baldwin 4842b75c8adSJohn Baldwin /* 4852b75c8adSJohn Baldwin * At this point, we set up the system call arguments. 4862b75c8adSJohn Baldwin * We ignore any OUT ones, however -- those are arguments that 4872b75c8adSJohn Baldwin * are set by the system call, and so are probably meaningless 4882b75c8adSJohn Baldwin * now. This doesn't currently support arguments that are 4892b75c8adSJohn Baldwin * passed in *and* out, however. 4902b75c8adSJohn Baldwin */ 4912b75c8adSJohn Baldwin #if DEBUG 4921175b23fSJohn Baldwin fprintf(stderr, "syscall %s(", sc->name); 4932b75c8adSJohn Baldwin #endif 4942b75c8adSJohn Baldwin for (i = 0; i < t->cs.nargs; i++) { 4952b75c8adSJohn Baldwin #if DEBUG 4966019514bSAlex Richardson fprintf(stderr, "0x%lx%s", 4976019514bSAlex Richardson t->cs.args[sc->decode.args[i].offset], 4982b75c8adSJohn Baldwin i < (t->cs.nargs - 1) ? "," : ""); 4992b75c8adSJohn Baldwin #endif 5006019514bSAlex Richardson if (!(sc->decode.args[i].type & OUT)) { 5016019514bSAlex Richardson t->cs.s_args[i] = print_arg(&sc->decode.args[i], 502caa449b6SJohn Baldwin t->cs.args, NULL, info); 5032b75c8adSJohn Baldwin } 5042b75c8adSJohn Baldwin } 5052b75c8adSJohn Baldwin #if DEBUG 5062b75c8adSJohn Baldwin fprintf(stderr, ")\n"); 5072b75c8adSJohn Baldwin #endif 5082b75c8adSJohn Baldwin 5092b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->before); 5102b75c8adSJohn Baldwin } 5112b75c8adSJohn Baldwin 512b9befd33SJohn Baldwin /* 513b9befd33SJohn Baldwin * When a thread exits voluntarily (including when a thread calls 514b9befd33SJohn Baldwin * exit() to trigger a process exit), the thread's internal state 515b9befd33SJohn Baldwin * holds the arguments passed to the exit system call. When the 516b9befd33SJohn Baldwin * thread's exit is reported, log that system call without a return 517b9befd33SJohn Baldwin * value. 518b9befd33SJohn Baldwin */ 519b9befd33SJohn Baldwin static void 520b9befd33SJohn Baldwin thread_exit_syscall(struct trussinfo *info) 521b9befd33SJohn Baldwin { 522b9befd33SJohn Baldwin struct threadinfo *t; 523b9befd33SJohn Baldwin 524b9befd33SJohn Baldwin t = info->curthread; 525b9befd33SJohn Baldwin if (!t->in_syscall) 526b9befd33SJohn Baldwin return; 527b9befd33SJohn Baldwin 528b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 529b9befd33SJohn Baldwin 530b9befd33SJohn Baldwin print_syscall_ret(info, 0, NULL); 531b9befd33SJohn Baldwin free_syscall(t); 532b9befd33SJohn Baldwin } 533b9befd33SJohn Baldwin 5342b75c8adSJohn Baldwin static void 5352b75c8adSJohn Baldwin exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl) 5362b75c8adSJohn Baldwin { 5372b75c8adSJohn Baldwin struct threadinfo *t; 5382b75c8adSJohn Baldwin struct procinfo *p; 5392b75c8adSJohn Baldwin struct syscall *sc; 540caa449b6SJohn Baldwin struct ptrace_sc_ret psr; 5412b75c8adSJohn Baldwin u_int i; 5422b75c8adSJohn Baldwin 5432b75c8adSJohn Baldwin t = info->curthread; 5442b75c8adSJohn Baldwin if (!t->in_syscall) 5452b75c8adSJohn Baldwin return; 5462b75c8adSJohn Baldwin 5472b75c8adSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 5482b75c8adSJohn Baldwin p = t->proc; 549caa449b6SJohn Baldwin if (ptrace(PT_GET_SC_RET, t->tid, (caddr_t)&psr, sizeof(psr)) != 0) { 5502b75c8adSJohn Baldwin free_syscall(t); 5512b75c8adSJohn Baldwin return; 5522b75c8adSJohn Baldwin } 5532b75c8adSJohn Baldwin 5542b75c8adSJohn Baldwin sc = t->cs.sc; 5552b75c8adSJohn Baldwin /* 5562b75c8adSJohn Baldwin * Here, we only look for arguments that have OUT masked in -- 5572b75c8adSJohn Baldwin * otherwise, they were handled in enter_syscall(). 5582b75c8adSJohn Baldwin */ 5596019514bSAlex Richardson for (i = 0; i < sc->decode.nargs; i++) { 5602b75c8adSJohn Baldwin char *temp; 5612b75c8adSJohn Baldwin 5626019514bSAlex Richardson if (sc->decode.args[i].type & OUT) { 5632b75c8adSJohn Baldwin /* 5642b75c8adSJohn Baldwin * If an error occurred, then don't bother 5652b75c8adSJohn Baldwin * getting the data; it may not be valid. 5662b75c8adSJohn Baldwin */ 567caa449b6SJohn Baldwin if (psr.sr_error != 0) { 5682b75c8adSJohn Baldwin asprintf(&temp, "0x%lx", 5696019514bSAlex Richardson t->cs.args[sc->decode.args[i].offset]); 5702b75c8adSJohn Baldwin } else { 5716019514bSAlex Richardson temp = print_arg(&sc->decode.args[i], 572caa449b6SJohn Baldwin t->cs.args, psr.sr_retval, info); 5732b75c8adSJohn Baldwin } 5742b75c8adSJohn Baldwin t->cs.s_args[i] = temp; 5752b75c8adSJohn Baldwin } 5762b75c8adSJohn Baldwin } 5772b75c8adSJohn Baldwin 578caa449b6SJohn Baldwin print_syscall_ret(info, psr.sr_error, psr.sr_retval); 5792b75c8adSJohn Baldwin free_syscall(t); 5802b75c8adSJohn Baldwin 5812b75c8adSJohn Baldwin /* 5822b75c8adSJohn Baldwin * If the process executed a new image, check the ABI. If the 5832b75c8adSJohn Baldwin * new ABI isn't supported, stop tracing this process. 5842b75c8adSJohn Baldwin */ 5852b75c8adSJohn Baldwin if (pl->pl_flags & PL_FLAG_EXEC) { 586b9befd33SJohn Baldwin assert(LIST_NEXT(LIST_FIRST(&p->threadlist), entries) == NULL); 5872b75c8adSJohn Baldwin p->abi = find_abi(p->pid); 5882b75c8adSJohn Baldwin if (p->abi == NULL) { 5892b75c8adSJohn Baldwin if (ptrace(PT_DETACH, p->pid, (caddr_t)1, 0) < 0) 5902b75c8adSJohn Baldwin err(1, "Can not detach the process"); 5912b75c8adSJohn Baldwin free_proc(p); 5922b75c8adSJohn Baldwin } 5932b75c8adSJohn Baldwin } 5942b75c8adSJohn Baldwin } 5952b75c8adSJohn Baldwin 596d70876fdSJohn Baldwin int 597d70876fdSJohn Baldwin print_line_prefix(struct trussinfo *info) 598d70876fdSJohn Baldwin { 599d70876fdSJohn Baldwin struct timespec timediff; 600d70876fdSJohn Baldwin struct threadinfo *t; 601d70876fdSJohn Baldwin int len; 602d70876fdSJohn Baldwin 603d70876fdSJohn Baldwin len = 0; 604d70876fdSJohn Baldwin t = info->curthread; 605d70876fdSJohn Baldwin if (info->flags & (FOLLOWFORKS | DISPLAYTIDS)) { 606d70876fdSJohn Baldwin if (info->flags & FOLLOWFORKS) 607d70876fdSJohn Baldwin len += fprintf(info->outfile, "%5d", t->proc->pid); 608d70876fdSJohn Baldwin if ((info->flags & (FOLLOWFORKS | DISPLAYTIDS)) == 609d70876fdSJohn Baldwin (FOLLOWFORKS | DISPLAYTIDS)) 610d70876fdSJohn Baldwin len += fprintf(info->outfile, " "); 611d70876fdSJohn Baldwin if (info->flags & DISPLAYTIDS) 612d70876fdSJohn Baldwin len += fprintf(info->outfile, "%6d", t->tid); 613d70876fdSJohn Baldwin len += fprintf(info->outfile, ": "); 614d70876fdSJohn Baldwin } 615d70876fdSJohn Baldwin if (info->flags & ABSOLUTETIMESTAMPS) { 6166040822cSAlan Somers timespecsub(&t->after, &info->start_time, &timediff); 617d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 618d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 619d70876fdSJohn Baldwin } 620d70876fdSJohn Baldwin if (info->flags & RELATIVETIMESTAMPS) { 6216040822cSAlan Somers timespecsub(&t->after, &t->before, &timediff); 622d70876fdSJohn Baldwin len += fprintf(info->outfile, "%jd.%09ld ", 623d70876fdSJohn Baldwin (intmax_t)timediff.tv_sec, timediff.tv_nsec); 624d70876fdSJohn Baldwin } 625d70876fdSJohn Baldwin return (len); 626d70876fdSJohn Baldwin } 627d70876fdSJohn Baldwin 6282b75c8adSJohn Baldwin static void 629b9befd33SJohn Baldwin report_thread_death(struct trussinfo *info) 630b9befd33SJohn Baldwin { 631b9befd33SJohn Baldwin struct threadinfo *t; 632b9befd33SJohn Baldwin 633b9befd33SJohn Baldwin t = info->curthread; 634b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 635b9befd33SJohn Baldwin print_line_prefix(info); 636b9befd33SJohn Baldwin fprintf(info->outfile, "<thread %ld exited>\n", (long)t->tid); 637b9befd33SJohn Baldwin } 638b9befd33SJohn Baldwin 639b9befd33SJohn Baldwin static void 640b9befd33SJohn Baldwin report_thread_birth(struct trussinfo *info) 641b9befd33SJohn Baldwin { 642b9befd33SJohn Baldwin struct threadinfo *t; 643b9befd33SJohn Baldwin 644b9befd33SJohn Baldwin t = info->curthread; 645b9befd33SJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 646b9befd33SJohn Baldwin t->before = t->after; 647b9befd33SJohn Baldwin print_line_prefix(info); 648b9befd33SJohn Baldwin fprintf(info->outfile, "<new thread %ld>\n", (long)t->tid); 649b9befd33SJohn Baldwin } 650b9befd33SJohn Baldwin 651b9befd33SJohn Baldwin static void 6522b75c8adSJohn Baldwin report_exit(struct trussinfo *info, siginfo_t *si) 6532b75c8adSJohn Baldwin { 654d70876fdSJohn Baldwin struct threadinfo *t; 6552b75c8adSJohn Baldwin 656d70876fdSJohn Baldwin t = info->curthread; 657d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 658d70876fdSJohn Baldwin print_line_prefix(info); 6592b75c8adSJohn Baldwin if (si->si_code == CLD_EXITED) 6602b75c8adSJohn Baldwin fprintf(info->outfile, "process exit, rval = %u\n", 6612b75c8adSJohn Baldwin si->si_status); 6622b75c8adSJohn Baldwin else 6632b75c8adSJohn Baldwin fprintf(info->outfile, "process killed, signal = %u%s\n", 6642b75c8adSJohn Baldwin si->si_status, si->si_code == CLD_DUMPED ? 6652b75c8adSJohn Baldwin " (core dumped)" : ""); 6662b75c8adSJohn Baldwin } 6672b75c8adSJohn Baldwin 6682b75c8adSJohn Baldwin static void 669d70876fdSJohn Baldwin report_new_child(struct trussinfo *info) 6702b75c8adSJohn Baldwin { 671d70876fdSJohn Baldwin struct threadinfo *t; 6722b75c8adSJohn Baldwin 673d70876fdSJohn Baldwin t = info->curthread; 674d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 675d70876fdSJohn Baldwin t->before = t->after; 676d70876fdSJohn Baldwin print_line_prefix(info); 6772b75c8adSJohn Baldwin fprintf(info->outfile, "<new process>\n"); 6782b75c8adSJohn Baldwin } 6792b75c8adSJohn Baldwin 68013e5e6b6SJohn Baldwin void 681ff577cb6SJohn Baldwin decode_siginfo(FILE *fp, siginfo_t *si) 682ff577cb6SJohn Baldwin { 683ff577cb6SJohn Baldwin const char *str; 684ff577cb6SJohn Baldwin 685ff577cb6SJohn Baldwin fprintf(fp, " code="); 686ff577cb6SJohn Baldwin str = sysdecode_sigcode(si->si_signo, si->si_code); 687ff577cb6SJohn Baldwin if (str == NULL) 688ff577cb6SJohn Baldwin fprintf(fp, "%d", si->si_code); 689ff577cb6SJohn Baldwin else 690ff577cb6SJohn Baldwin fprintf(fp, "%s", str); 691ff577cb6SJohn Baldwin switch (si->si_code) { 692ff577cb6SJohn Baldwin case SI_NOINFO: 693ff577cb6SJohn Baldwin break; 694ff577cb6SJohn Baldwin case SI_QUEUE: 695ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 696ff577cb6SJohn Baldwin /* FALLTHROUGH */ 697ff577cb6SJohn Baldwin case SI_USER: 698ff577cb6SJohn Baldwin case SI_LWP: 699ff577cb6SJohn Baldwin fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid, 700ff577cb6SJohn Baldwin (intmax_t)si->si_uid); 701ff577cb6SJohn Baldwin break; 702ff577cb6SJohn Baldwin case SI_TIMER: 703ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 704ff577cb6SJohn Baldwin fprintf(fp, " timerid=%d", si->si_timerid); 705ff577cb6SJohn Baldwin fprintf(fp, " overrun=%d", si->si_overrun); 706ff577cb6SJohn Baldwin if (si->si_errno != 0) 707ff577cb6SJohn Baldwin fprintf(fp, " errno=%d", si->si_errno); 708ff577cb6SJohn Baldwin break; 709ff577cb6SJohn Baldwin case SI_ASYNCIO: 710ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 711ff577cb6SJohn Baldwin break; 712ff577cb6SJohn Baldwin case SI_MESGQ: 713ff577cb6SJohn Baldwin fprintf(fp, " value=%p", si->si_value.sival_ptr); 714ff577cb6SJohn Baldwin fprintf(fp, " mqd=%d", si->si_mqd); 715ff577cb6SJohn Baldwin break; 716ff577cb6SJohn Baldwin default: 717ff577cb6SJohn Baldwin switch (si->si_signo) { 718ff577cb6SJohn Baldwin case SIGILL: 719ff577cb6SJohn Baldwin case SIGFPE: 720ff577cb6SJohn Baldwin case SIGSEGV: 721ff577cb6SJohn Baldwin case SIGBUS: 722ff577cb6SJohn Baldwin fprintf(fp, " trapno=%d", si->si_trapno); 723ff577cb6SJohn Baldwin fprintf(fp, " addr=%p", si->si_addr); 724ff577cb6SJohn Baldwin break; 725ff577cb6SJohn Baldwin case SIGCHLD: 726ff577cb6SJohn Baldwin fprintf(fp, " pid=%jd uid=%jd", (intmax_t)si->si_pid, 727ff577cb6SJohn Baldwin (intmax_t)si->si_uid); 728ff577cb6SJohn Baldwin fprintf(fp, " status=%d", si->si_status); 729ff577cb6SJohn Baldwin break; 730ff577cb6SJohn Baldwin } 731ff577cb6SJohn Baldwin } 732ff577cb6SJohn Baldwin } 733ff577cb6SJohn Baldwin 734ff577cb6SJohn Baldwin static void 735ff577cb6SJohn Baldwin report_signal(struct trussinfo *info, siginfo_t *si, struct ptrace_lwpinfo *pl) 7362b75c8adSJohn Baldwin { 737d70876fdSJohn Baldwin struct threadinfo *t; 7389289f547SJohn Baldwin const char *signame; 7392b75c8adSJohn Baldwin 740d70876fdSJohn Baldwin t = info->curthread; 741d70876fdSJohn Baldwin clock_gettime(CLOCK_REALTIME, &t->after); 742d70876fdSJohn Baldwin print_line_prefix(info); 7439289f547SJohn Baldwin signame = sysdecode_signal(si->si_status); 7449289f547SJohn Baldwin if (signame == NULL) 7459289f547SJohn Baldwin signame = "?"; 746ff577cb6SJohn Baldwin fprintf(info->outfile, "SIGNAL %u (%s)", si->si_status, signame); 747ff577cb6SJohn Baldwin if (pl->pl_event == PL_EVENT_SIGNAL && pl->pl_flags & PL_FLAG_SI) 748ff577cb6SJohn Baldwin decode_siginfo(info->outfile, &pl->pl_siginfo); 749ff577cb6SJohn Baldwin fprintf(info->outfile, "\n"); 750ff577cb6SJohn Baldwin 7512b75c8adSJohn Baldwin } 7522b75c8adSJohn Baldwin 7532b75c8adSJohn Baldwin /* 7542b75c8adSJohn Baldwin * Wait for events until all the processes have exited or truss has been 7552b75c8adSJohn Baldwin * asked to stop. 7565d2d083cSXin LI */ 7575d2d083cSXin LI void 7582b75c8adSJohn Baldwin eventloop(struct trussinfo *info) 7595d2d083cSXin LI { 7602b75c8adSJohn Baldwin struct ptrace_lwpinfo pl; 7612b75c8adSJohn Baldwin siginfo_t si; 7622b75c8adSJohn Baldwin int pending_signal; 7635d2d083cSXin LI 7642b75c8adSJohn Baldwin while (!LIST_EMPTY(&info->proclist)) { 765896fc463SAndrey Zonov if (detaching) { 7662b75c8adSJohn Baldwin detach_all_procs(info); 767896fc463SAndrey Zonov return; 768896fc463SAndrey Zonov } 769896fc463SAndrey Zonov 7702b75c8adSJohn Baldwin if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) { 771896fc463SAndrey Zonov if (errno == EINTR) 7722b75c8adSJohn Baldwin continue; 7732b75c8adSJohn Baldwin err(1, "Unexpected error from waitid"); 774896fc463SAndrey Zonov } 7755d2d083cSXin LI 7762b75c8adSJohn Baldwin assert(si.si_signo == SIGCHLD); 7772b75c8adSJohn Baldwin 7782b75c8adSJohn Baldwin switch (si.si_code) { 7792b75c8adSJohn Baldwin case CLD_EXITED: 7802b75c8adSJohn Baldwin case CLD_KILLED: 7812b75c8adSJohn Baldwin case CLD_DUMPED: 7822b75c8adSJohn Baldwin find_exit_thread(info, si.si_pid); 783b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) { 784b9befd33SJohn Baldwin if (si.si_code == CLD_EXITED) 785b9befd33SJohn Baldwin thread_exit_syscall(info); 7862b75c8adSJohn Baldwin report_exit(info, &si); 787b9befd33SJohn Baldwin } 7882b75c8adSJohn Baldwin free_proc(info->curthread->proc); 7892b75c8adSJohn Baldwin info->curthread = NULL; 7905d2d083cSXin LI break; 7912b75c8adSJohn Baldwin case CLD_TRAPPED: 7922b75c8adSJohn Baldwin if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl, 7932b75c8adSJohn Baldwin sizeof(pl)) == -1) 7942b75c8adSJohn Baldwin err(1, "ptrace(PT_LWPINFO)"); 7952b75c8adSJohn Baldwin 7962b75c8adSJohn Baldwin if (pl.pl_flags & PL_FLAG_CHILD) { 797b9befd33SJohn Baldwin new_proc(info, si.si_pid, pl.pl_lwpid); 7982b75c8adSJohn Baldwin assert(LIST_FIRST(&info->proclist)->abi != 7992b75c8adSJohn Baldwin NULL); 800b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_BORN) 801b9befd33SJohn Baldwin new_thread(find_proc(info, si.si_pid), 802b9befd33SJohn Baldwin pl.pl_lwpid); 8032b75c8adSJohn Baldwin find_thread(info, si.si_pid, pl.pl_lwpid); 8042b75c8adSJohn Baldwin 80594746562SBryan Drewery if (si.si_status == SIGTRAP && 806b9befd33SJohn Baldwin (pl.pl_flags & (PL_FLAG_BORN|PL_FLAG_EXITED| 807b9befd33SJohn Baldwin PL_FLAG_SCE|PL_FLAG_SCX)) != 0) { 808b9befd33SJohn Baldwin if (pl.pl_flags & PL_FLAG_BORN) { 809b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) 810b9befd33SJohn Baldwin report_thread_birth(info); 811b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_EXITED) { 812b9befd33SJohn Baldwin if ((info->flags & COUNTONLY) == 0) 813b9befd33SJohn Baldwin report_thread_death(info); 814b9befd33SJohn Baldwin free_thread(info->curthread); 815b9befd33SJohn Baldwin info->curthread = NULL; 816b9befd33SJohn Baldwin } else if (pl.pl_flags & PL_FLAG_SCE) 817b9befd33SJohn Baldwin enter_syscall(info, info->curthread, &pl); 8182b75c8adSJohn Baldwin else if (pl.pl_flags & PL_FLAG_SCX) 8192b75c8adSJohn Baldwin exit_syscall(info, &pl); 8202b75c8adSJohn Baldwin pending_signal = 0; 8212b75c8adSJohn Baldwin } else if (pl.pl_flags & PL_FLAG_CHILD) { 8222b75c8adSJohn Baldwin if ((info->flags & COUNTONLY) == 0) 823d70876fdSJohn Baldwin report_new_child(info); 8242b75c8adSJohn Baldwin pending_signal = 0; 8252b75c8adSJohn Baldwin } else { 8262b75c8adSJohn Baldwin if ((info->flags & NOSIGS) == 0) 827ff577cb6SJohn Baldwin report_signal(info, &si, &pl); 8282b75c8adSJohn Baldwin pending_signal = si.si_status; 82997695ad4SKonstantin Belousov } 8302b75c8adSJohn Baldwin ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1, 8312b75c8adSJohn Baldwin pending_signal); 8322b75c8adSJohn Baldwin break; 8332b75c8adSJohn Baldwin case CLD_STOPPED: 8342b75c8adSJohn Baldwin errx(1, "waitid reported CLD_STOPPED"); 8352b75c8adSJohn Baldwin case CLD_CONTINUED: 8365d2d083cSXin LI break; 8375d2d083cSXin LI } 8385d2d083cSXin LI } 8395d2d083cSXin LI } 840