xref: /freebsd/usr.bin/truss/main.c (revision e04c3786831223dd5b746ab9c2a4fc03897e9b99)
1d5303c80SXin LI /*-
20a6c71f8SWarner Losh  * Copyright 1997 Sean Eric Fagan
309d64da3SSean Eric Fagan  *
409d64da3SSean Eric Fagan  * Redistribution and use in source and binary forms, with or without
509d64da3SSean Eric Fagan  * modification, are permitted provided that the following conditions
609d64da3SSean Eric Fagan  * are met:
709d64da3SSean Eric Fagan  * 1. Redistributions of source code must retain the above copyright
809d64da3SSean Eric Fagan  *    notice, this list of conditions and the following disclaimer.
909d64da3SSean Eric Fagan  * 2. Redistributions in binary form must reproduce the above copyright
1009d64da3SSean Eric Fagan  *    notice, this list of conditions and the following disclaimer in the
1109d64da3SSean Eric Fagan  *    documentation and/or other materials provided with the distribution.
1209d64da3SSean Eric Fagan  * 3. All advertising materials mentioning features or use of this software
1309d64da3SSean Eric Fagan  *    must display the following acknowledgement:
1409d64da3SSean Eric Fagan  *	This product includes software developed by Sean Eric Fagan
1509d64da3SSean Eric Fagan  * 4. Neither the name of the author may be used to endorse or promote
1609d64da3SSean Eric Fagan  *    products derived from this software without specific prior written
1709d64da3SSean Eric Fagan  *    permission.
1809d64da3SSean Eric Fagan  *
1909d64da3SSean Eric Fagan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2009d64da3SSean Eric Fagan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2109d64da3SSean Eric Fagan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2209d64da3SSean Eric Fagan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2309d64da3SSean Eric Fagan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2409d64da3SSean Eric Fagan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2509d64da3SSean Eric Fagan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2609d64da3SSean Eric Fagan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2709d64da3SSean Eric Fagan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2809d64da3SSean Eric Fagan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2909d64da3SSean Eric Fagan  * SUCH DAMAGE.
3009d64da3SSean Eric Fagan  */
3109d64da3SSean Eric Fagan 
32b956c13cSPhilippe Charnier #include <sys/cdefs.h>
33b956c13cSPhilippe Charnier __FBSDID("$FreeBSD$");
343cf51049SPhilippe Charnier 
3509d64da3SSean Eric Fagan /*
36bbeaf6c0SSean Eric Fagan  * The main module for truss.  Suprisingly simple, but, then, the other
37bbeaf6c0SSean Eric Fagan  * files handle the bulk of the work.  And, of course, the kernel has to
38bbeaf6c0SSean Eric Fagan  * do a lot of the work :).
39bbeaf6c0SSean Eric Fagan  */
40bbeaf6c0SSean Eric Fagan 
41580e0a2bSDag-Erling Smørgrav #include <sys/param.h>
425cdf6a13SMartin Cracauer #include <sys/types.h>
431d631f7eSMike Barcroft #include <sys/time.h>
445cdf6a13SMartin Cracauer #include <sys/resource.h>
455d2d083cSXin LI #include <sys/sysctl.h>
46d5303c80SXin LI #include <sys/wait.h>
47580e0a2bSDag-Erling Smørgrav 
48d75300bfSAlfred Perlstein #include <ctype.h>
493cf51049SPhilippe Charnier #include <err.h>
50821df508SXin LI #include <errno.h>
51821df508SXin LI #include <fcntl.h>
523cf51049SPhilippe Charnier #include <signal.h>
53bbeaf6c0SSean Eric Fagan #include <stdio.h>
54bbeaf6c0SSean Eric Fagan #include <stdlib.h>
55bbeaf6c0SSean Eric Fagan #include <string.h>
5637169f94SMatthew N. Dodd #include <time.h>
5795c4ef65SPeter Wemm #include <unistd.h>
58bbeaf6c0SSean Eric Fagan 
59ec0bed25SMatthew N. Dodd #include "truss.h"
601be5d704SMark Murray #include "extern.h"
61ee3b0f6eSDiomidis Spinellis #include "syscall.h"
62bbeaf6c0SSean Eric Fagan 
633e1b6078SMarcel Moolenaar #define MAXARGS 6
64bbeaf6c0SSean Eric Fagan 
655321ae86SAlfred Perlstein static void
663cf51049SPhilippe Charnier usage(void)
673cf51049SPhilippe Charnier {
683cf51049SPhilippe Charnier 	fprintf(stderr, "%s\n%s\n",
69ee3b0f6eSDiomidis Spinellis 	    "usage: truss [-cfaedDS] [-o file] [-s strsize] -p pid",
70ee3b0f6eSDiomidis Spinellis 	    "       truss [-cfaedDS] [-o file] [-s strsize] command [args]");
71bbeaf6c0SSean Eric Fagan 	exit(1);
72bbeaf6c0SSean Eric Fagan }
73bbeaf6c0SSean Eric Fagan 
743625b514SSean Eric Fagan /*
753625b514SSean Eric Fagan  * WARNING! "FreeBSD a.out" must be first, or set_etype will not
763625b514SSean Eric Fagan  * work correctly.
773625b514SSean Eric Fagan  */
78bbeaf6c0SSean Eric Fagan struct ex_types {
791be5d704SMark Murray 	const char *type;
80ec0bed25SMatthew N. Dodd 	void (*enter_syscall)(struct trussinfo *, int);
811bcb5f5aSMarcel Moolenaar 	long (*exit_syscall)(struct trussinfo *, int);
82bbeaf6c0SSean Eric Fagan } ex_types[] = {
83a5d31d16SDavid Malone #ifdef __amd64__
84a5d31d16SDavid Malone 	{ "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit },
859a55503eSJohn Baldwin 	{ "FreeBSD ELF32", amd64_fbsd32_syscall_entry, amd64_fbsd32_syscall_exit },
869a55503eSJohn Baldwin 	{ "Linux ELF32", amd64_linux32_syscall_entry, amd64_linux32_syscall_exit },
87a5d31d16SDavid Malone #endif
8850cc4492SSean Eric Fagan #ifdef __i386__
89bbeaf6c0SSean Eric Fagan 	{ "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },
9087893934SPeter Wemm 	{ "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit },
910629483cSMatthew N. Dodd 	{ "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit },
92bbeaf6c0SSean Eric Fagan 	{ "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit },
9350cc4492SSean Eric Fagan #endif
94a3e32192SMarcel Moolenaar #ifdef __ia64__
95a3e32192SMarcel Moolenaar 	{ "FreeBSD ELF64", ia64_syscall_entry, ia64_syscall_exit },
96a3e32192SMarcel Moolenaar #endif
977fa9dc1cSPeter Grehan #ifdef __powerpc__
987fa9dc1cSPeter Grehan 	{ "FreeBSD ELF", powerpc_syscall_entry, powerpc_syscall_exit },
997fa9dc1cSPeter Grehan 	{ "FreeBSD ELF32", powerpc_syscall_entry, powerpc_syscall_exit },
1004e583321SNathan Whitehorn #ifdef __powerpc64__
1014e583321SNathan Whitehorn 	{ "FreeBSD ELF64", powerpc64_syscall_entry, powerpc64_syscall_exit },
1024e583321SNathan Whitehorn #endif
1037fa9dc1cSPeter Grehan #endif
104f84c971aSJake Burkholder #ifdef __sparc64__
105f84c971aSJake Burkholder 	{ "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
106f84c971aSJake Burkholder #endif
10789fe547fSWarner Losh #ifdef __mips__
10889fe547fSWarner Losh 	{ "FreeBSD ELF", mips_syscall_entry, mips_syscall_exit },
10989fe547fSWarner Losh 	{ "FreeBSD ELF32", mips_syscall_entry, mips_syscall_exit },
11089fe547fSWarner Losh 	{ "FreeBSD ELF64", mips_syscall_entry, mips_syscall_exit }, // XXX
11189fe547fSWarner Losh #endif
112bbeaf6c0SSean Eric Fagan 	{ 0, 0, 0 },
113bbeaf6c0SSean Eric Fagan };
114bbeaf6c0SSean Eric Fagan 
115bbeaf6c0SSean Eric Fagan /*
116bbeaf6c0SSean Eric Fagan  * Set the execution type.  This is called after every exec, and when
1175d2d083cSXin LI  * a process is first monitored.
118bbeaf6c0SSean Eric Fagan  */
119bbeaf6c0SSean Eric Fagan 
120bbeaf6c0SSean Eric Fagan static struct ex_types *
1215321ae86SAlfred Perlstein set_etype(struct trussinfo *trussinfo)
1225321ae86SAlfred Perlstein {
123bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
1241be5d704SMark Murray 	char progt[32];
125bbeaf6c0SSean Eric Fagan 
1265d2d083cSXin LI 	size_t len = sizeof(progt);
1275d2d083cSXin LI 	int mib[4];
1285d2d083cSXin LI 	int error;
1295d2d083cSXin LI 
1305d2d083cSXin LI 	mib[0] = CTL_KERN;
1315d2d083cSXin LI 	mib[1] = KERN_PROC;
1325d2d083cSXin LI 	mib[2] = KERN_PROC_SV_NAME;
1335d2d083cSXin LI 	mib[3] = trussinfo->pid;
1345d2d083cSXin LI 	error = sysctl(mib, 4, progt, &len, NULL, 0);
1355d2d083cSXin LI 	if (error != 0)
1365d2d083cSXin LI 		err(2, "can not get etype");
137bbeaf6c0SSean Eric Fagan 
138bbeaf6c0SSean Eric Fagan 	for (funcs = ex_types; funcs->type; funcs++)
1391be5d704SMark Murray 		if (!strcmp(funcs->type, progt))
140bbeaf6c0SSean Eric Fagan 			break;
141bbeaf6c0SSean Eric Fagan 
1424525f3a8SDag-Erling Smørgrav 	if (funcs->type == NULL) {
1433625b514SSean Eric Fagan 		funcs = &ex_types[0];
144b956c13cSPhilippe Charnier 		warn("execution type %s is not supported -- using %s",
1454525f3a8SDag-Erling Smørgrav 		    progt, funcs->type);
1463625b514SSean Eric Fagan 	}
1475321ae86SAlfred Perlstein 	return (funcs);
148bbeaf6c0SSean Eric Fagan }
149bbeaf6c0SSean Eric Fagan 
150d75300bfSAlfred Perlstein char *
151d75300bfSAlfred Perlstein strsig(int sig)
152d75300bfSAlfred Perlstein {
153d75300bfSAlfred Perlstein 	char *ret;
154d75300bfSAlfred Perlstein 
155d75300bfSAlfred Perlstein 	ret = NULL;
156d75300bfSAlfred Perlstein 	if (sig > 0 && sig < NSIG) {
157d75300bfSAlfred Perlstein 		int i;
158d75300bfSAlfred Perlstein 		asprintf(&ret, "sig%s", sys_signame[sig]);
159d75300bfSAlfred Perlstein 		if (ret == NULL)
160d75300bfSAlfred Perlstein 			return (NULL);
161d75300bfSAlfred Perlstein 		for (i = 0; ret[i] != '\0'; ++i)
162d75300bfSAlfred Perlstein 			ret[i] = toupper(ret[i]);
163d75300bfSAlfred Perlstein 	}
164d75300bfSAlfred Perlstein 	return (ret);
165d75300bfSAlfred Perlstein }
166d75300bfSAlfred Perlstein 
1673cf51049SPhilippe Charnier int
1685321ae86SAlfred Perlstein main(int ac, char **av)
1695321ae86SAlfred Perlstein {
170bbeaf6c0SSean Eric Fagan 	int c;
171bbeaf6c0SSean Eric Fagan 	int i;
172d5303c80SXin LI 	pid_t childpid;
173d5303c80SXin LI 	int status;
174bbeaf6c0SSean Eric Fagan 	char **command;
175bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
176ef29ac7fSXin LI 	int initial_open;
17772aa911aSAlfred Perlstein 	char *fname;
178ec0bed25SMatthew N. Dodd 	struct trussinfo *trussinfo;
179d75300bfSAlfred Perlstein 	char *signame;
180bbeaf6c0SSean Eric Fagan 
18172aa911aSAlfred Perlstein 	fname = NULL;
18272aa911aSAlfred Perlstein 	initial_open = 1;
18372aa911aSAlfred Perlstein 
184ec0bed25SMatthew N. Dodd 	/* Initialize the trussinfo struct */
185216fa4c6SXin LI 	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
186ec0bed25SMatthew N. Dodd 	if (trussinfo == NULL)
187216fa4c6SXin LI 		errx(1, "calloc() failed");
1885d2d083cSXin LI 
189ec0bed25SMatthew N. Dodd 	trussinfo->outfile = stderr;
1900cf21b4fSBrian Somers 	trussinfo->strsize = 32;
1915d2d083cSXin LI 	trussinfo->pr_why = S_NONE;
1925d2d083cSXin LI 	trussinfo->curthread = NULL;
1935d2d083cSXin LI 	SLIST_INIT(&trussinfo->threadlist);
194ee3b0f6eSDiomidis Spinellis 	while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
195bbeaf6c0SSean Eric Fagan 		switch (c) {
196bbeaf6c0SSean Eric Fagan 		case 'p':	/* specified pid */
197ec0bed25SMatthew N. Dodd 			trussinfo->pid = atoi(optarg);
198ef29ac7fSXin LI 			/* make sure i don't trace me */
199ef29ac7fSXin LI 			if(trussinfo->pid == getpid()) {
200ef29ac7fSXin LI 				fprintf(stderr, "attempt to grab self.\n");
201ef29ac7fSXin LI 				exit(2);
202ef29ac7fSXin LI 			}
203bbeaf6c0SSean Eric Fagan 			break;
204c03bfcc8SMatthew N. Dodd 		case 'f': /* Follow fork()'s */
205c03bfcc8SMatthew N. Dodd 			trussinfo->flags |= FOLLOWFORKS;
206c03bfcc8SMatthew N. Dodd 			break;
2079897b203SMatthew N. Dodd 		case 'a': /* Print execve() argument strings. */
2089897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEARGS;
2099897b203SMatthew N. Dodd 			break;
210ee3b0f6eSDiomidis Spinellis 		case 'c': /* Count number of system calls and time. */
211ee3b0f6eSDiomidis Spinellis 			trussinfo->flags |= COUNTONLY;
212ee3b0f6eSDiomidis Spinellis 			break;
2139897b203SMatthew N. Dodd 		case 'e': /* Print execve() environment strings. */
2149897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEENVS;
2159897b203SMatthew N. Dodd 			break;
2160d0bd00eSMatthew N. Dodd 		case 'd': /* Absolute timestamps */
2170d0bd00eSMatthew N. Dodd 			trussinfo->flags |= ABSOLUTETIMESTAMPS;
2180d0bd00eSMatthew N. Dodd 			break;
2190d0bd00eSMatthew N. Dodd 		case 'D': /* Relative timestamps */
2200d0bd00eSMatthew N. Dodd 			trussinfo->flags |= RELATIVETIMESTAMPS;
2210d0bd00eSMatthew N. Dodd 			break;
222bbeaf6c0SSean Eric Fagan 		case 'o':	/* Specified output file */
2233cf51049SPhilippe Charnier 			fname = optarg;
224bbeaf6c0SSean Eric Fagan 			break;
2250cf21b4fSBrian Somers 		case 's':	/* Specified string size */
2260cf21b4fSBrian Somers 			trussinfo->strsize = atoi(optarg);
2270cf21b4fSBrian Somers 			break;
228bbeaf6c0SSean Eric Fagan 		case 'S':	/* Don't trace signals */
229ec0bed25SMatthew N. Dodd 			trussinfo->flags |= NOSIGS;
230bbeaf6c0SSean Eric Fagan 			break;
231bbeaf6c0SSean Eric Fagan 		default:
232bbeaf6c0SSean Eric Fagan 			usage();
233bbeaf6c0SSean Eric Fagan 		}
234bbeaf6c0SSean Eric Fagan 	}
235bbeaf6c0SSean Eric Fagan 
236bbeaf6c0SSean Eric Fagan 	ac -= optind; av += optind;
2375321ae86SAlfred Perlstein 	if ((trussinfo->pid == 0 && ac == 0) ||
2385321ae86SAlfred Perlstein 	    (trussinfo->pid != 0 && ac != 0))
239bbeaf6c0SSean Eric Fagan 		usage();
240bbeaf6c0SSean Eric Fagan 
2413cf51049SPhilippe Charnier 	if (fname != NULL) { /* Use output file */
242ec0bed25SMatthew N. Dodd 		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
2433cf51049SPhilippe Charnier 			errx(1, "cannot open %s", fname);
244ecbb6d34SJaakko Heinonen 		/*
245ecbb6d34SJaakko Heinonen 		 * Set FD_CLOEXEC, so that the output file is not shared with
246ecbb6d34SJaakko Heinonen 		 * the traced process.
247ecbb6d34SJaakko Heinonen 		 */
248*e04c3786SJaakko Heinonen 		if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) ==
249*e04c3786SJaakko Heinonen 		    -1)
250ecbb6d34SJaakko Heinonen 			warn("fcntl()");
251*e04c3786SJaakko Heinonen 	}
2523cf51049SPhilippe Charnier 
253bbeaf6c0SSean Eric Fagan 	/*
254bbeaf6c0SSean Eric Fagan 	 * If truss starts the process itself, it will ignore some signals --
255bbeaf6c0SSean Eric Fagan 	 * they should be passed off to the process, which may or may not
256bbeaf6c0SSean Eric Fagan 	 * exit.  If, however, we are examining an already-running process,
257bbeaf6c0SSean Eric Fagan 	 * then we restore the event mask on these same signals.
258bbeaf6c0SSean Eric Fagan 	 */
259bbeaf6c0SSean Eric Fagan 
260ec0bed25SMatthew N. Dodd 	if (trussinfo->pid == 0) {	/* Start a command ourselves */
261bbeaf6c0SSean Eric Fagan 		command = av;
262ec0bed25SMatthew N. Dodd 		trussinfo->pid = setup_and_wait(command);
263bbeaf6c0SSean Eric Fagan 		signal(SIGINT, SIG_IGN);
264bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, SIG_IGN);
265bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, SIG_IGN);
266bbeaf6c0SSean Eric Fagan 	} else {
2675d2d083cSXin LI 		start_tracing(trussinfo->pid);
268bbeaf6c0SSean Eric Fagan 		signal(SIGINT, restore_proc);
269bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, restore_proc);
270bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, restore_proc);
271bbeaf6c0SSean Eric Fagan 	}
272bbeaf6c0SSean Eric Fagan 
273bbeaf6c0SSean Eric Fagan 
274bbeaf6c0SSean Eric Fagan 	/*
275bbeaf6c0SSean Eric Fagan 	 * At this point, if we started the process, it is stopped waiting to
276bbeaf6c0SSean Eric Fagan 	 * be woken up, either in exit() or in execve().
277bbeaf6c0SSean Eric Fagan 	 */
278bbeaf6c0SSean Eric Fagan 
279c03bfcc8SMatthew N. Dodd START_TRACE:
280ec0bed25SMatthew N. Dodd 	funcs = set_etype(trussinfo);
2815d2d083cSXin LI 
2825d2d083cSXin LI 	initial_open = 0;
283bbeaf6c0SSean Eric Fagan 	/*
284bbeaf6c0SSean Eric Fagan 	 * At this point, it's a simple loop, waiting for the process to
285bbeaf6c0SSean Eric Fagan 	 * stop, finding out why, printing out why, and then continuing it.
286bbeaf6c0SSean Eric Fagan 	 * All of the grunt work is done in the support routines.
287bbeaf6c0SSean Eric Fagan 	 */
288bbeaf6c0SSean Eric Fagan 
289203098d8SMatthew N. Dodd 	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
2900d0bd00eSMatthew N. Dodd 
291bbeaf6c0SSean Eric Fagan 	do {
292081e5c48SPav Lucistnik 		struct timespec timediff;
2935d2d083cSXin LI 		waitevent(trussinfo);
294bbeaf6c0SSean Eric Fagan 
2955d2d083cSXin LI 		switch(i = trussinfo->pr_why) {
296bbeaf6c0SSean Eric Fagan 		case S_SCE:
2975d2d083cSXin LI 			funcs->enter_syscall(trussinfo, MAXARGS);
2985321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
2995321ae86SAlfred Perlstein 			    &trussinfo->before);
300bbeaf6c0SSean Eric Fagan 			break;
301bbeaf6c0SSean Eric Fagan 		case S_SCX:
3025321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
3035321ae86SAlfred Perlstein 			    &trussinfo->after);
304c03bfcc8SMatthew N. Dodd 
3055d2d083cSXin LI 			if (trussinfo->curthread->in_fork &&
3065321ae86SAlfred Perlstein 			    (trussinfo->flags & FOLLOWFORKS)) {
3075d2d083cSXin LI 				trussinfo->curthread->in_fork = 0;
3085321ae86SAlfred Perlstein 				childpid =
3095321ae86SAlfred Perlstein 				    funcs->exit_syscall(trussinfo,
3105d2d083cSXin LI 					trussinfo->pr_data);
311c03bfcc8SMatthew N. Dodd 
312c03bfcc8SMatthew N. Dodd 				/*
3135321ae86SAlfred Perlstein 				 * Fork a new copy of ourself to trace
3145321ae86SAlfred Perlstein 				 * the child of the original traced
3155321ae86SAlfred Perlstein 				 * process.
316c03bfcc8SMatthew N. Dodd 				 */
317c03bfcc8SMatthew N. Dodd 				if (fork() == 0) {
318c03bfcc8SMatthew N. Dodd 					trussinfo->pid = childpid;
3195d2d083cSXin LI 					start_tracing(trussinfo->pid);
320c03bfcc8SMatthew N. Dodd 					goto START_TRACE;
321c03bfcc8SMatthew N. Dodd 				}
322c03bfcc8SMatthew N. Dodd 				break;
323c03bfcc8SMatthew N. Dodd 			}
3245d2d083cSXin LI 			funcs->exit_syscall(trussinfo, MAXARGS);
325bbeaf6c0SSean Eric Fagan 			break;
326bbeaf6c0SSean Eric Fagan 		case S_SIG:
3275d2d083cSXin LI 			if (trussinfo->flags & NOSIGS)
3285d2d083cSXin LI 				break;
329081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
330081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
331081e5c48SPav Lucistnik 				    trussinfo->pid);
332081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
333081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
334081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
335081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
336081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
337081e5c48SPav Lucistnik 				    timediff.tv_nsec);
338081e5c48SPav Lucistnik 			}
339081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
340081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
341081e5c48SPav Lucistnik 				    &trussinfo->before, &timediff);
342081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
343081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
344081e5c48SPav Lucistnik 				    timediff.tv_nsec);
345081e5c48SPav Lucistnik 			}
3465d2d083cSXin LI 			signame = strsig(trussinfo->pr_data);
3475321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3485d2d083cSXin LI 			    "SIGNAL %u (%s)\n", trussinfo->pr_data,
349d75300bfSAlfred Perlstein 			    signame == NULL ? "?" : signame);
350d75300bfSAlfred Perlstein 			free(signame);
351bbeaf6c0SSean Eric Fagan 			break;
352bbeaf6c0SSean Eric Fagan 		case S_EXIT:
353ee3b0f6eSDiomidis Spinellis 			if (trussinfo->flags & COUNTONLY)
354ee3b0f6eSDiomidis Spinellis 				break;
355081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
356081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
357081e5c48SPav Lucistnik 				    trussinfo->pid);
358081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
359081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
360081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
361081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
362081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
363081e5c48SPav Lucistnik 				    timediff.tv_nsec);
364081e5c48SPav Lucistnik 			}
365081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
366081e5c48SPav Lucistnik 			  timespecsubt(&trussinfo->after,
367081e5c48SPav Lucistnik 			      &trussinfo->before, &timediff);
368081e5c48SPav Lucistnik 			  fprintf(trussinfo->outfile, "%ld.%09ld ",
369081e5c48SPav Lucistnik 			    (long)timediff.tv_sec, timediff.tv_nsec);
370081e5c48SPav Lucistnik 			}
3715321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3725d2d083cSXin LI 			    "process exit, rval = %u\n", trussinfo->pr_data);
373bbeaf6c0SSean Eric Fagan 			break;
374bbeaf6c0SSean Eric Fagan 		default:
375bbeaf6c0SSean Eric Fagan 			break;
376bbeaf6c0SSean Eric Fagan 		}
3775d2d083cSXin LI 	} while (trussinfo->pr_why != S_EXIT);
3785d2d083cSXin LI 
379d5303c80SXin LI 	if (trussinfo->flags & FOLLOWFORKS)
380d5303c80SXin LI 		do {
381d5303c80SXin LI 			childpid = wait(&status);
382d5303c80SXin LI 		} while (childpid != -1);
383d5303c80SXin LI 
384ee3b0f6eSDiomidis Spinellis  	if (trussinfo->flags & COUNTONLY)
385ee3b0f6eSDiomidis Spinellis  		print_summary(trussinfo);
386ee3b0f6eSDiomidis Spinellis 
387ee3b0f6eSDiomidis Spinellis 	fflush(trussinfo->outfile);
388ee3b0f6eSDiomidis Spinellis 
3895321ae86SAlfred Perlstein 	return (0);
390bbeaf6c0SSean Eric Fagan }
391