xref: /freebsd/usr.bin/truss/main.c (revision b2bf146e3e3ef526b82b435c80a344299ff6e1ed)
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 /*
36*b2bf146eSBenedict Reuschling  * The main module for truss.  Surprisingly 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 
483cf51049SPhilippe Charnier #include <err.h>
49821df508SXin LI #include <errno.h>
50821df508SXin LI #include <fcntl.h>
513cf51049SPhilippe Charnier #include <signal.h>
52bbeaf6c0SSean Eric Fagan #include <stdio.h>
53bbeaf6c0SSean Eric Fagan #include <stdlib.h>
54bbeaf6c0SSean Eric Fagan #include <string.h>
5537169f94SMatthew N. Dodd #include <time.h>
5695c4ef65SPeter Wemm #include <unistd.h>
57bbeaf6c0SSean Eric Fagan 
58ec0bed25SMatthew N. Dodd #include "truss.h"
591be5d704SMark Murray #include "extern.h"
60ee3b0f6eSDiomidis Spinellis #include "syscall.h"
61bbeaf6c0SSean Eric Fagan 
623e1b6078SMarcel Moolenaar #define MAXARGS 6
63bbeaf6c0SSean Eric Fagan 
645321ae86SAlfred Perlstein static void
653cf51049SPhilippe Charnier usage(void)
663cf51049SPhilippe Charnier {
673cf51049SPhilippe Charnier 	fprintf(stderr, "%s\n%s\n",
68ee3b0f6eSDiomidis Spinellis 	    "usage: truss [-cfaedDS] [-o file] [-s strsize] -p pid",
69ee3b0f6eSDiomidis Spinellis 	    "       truss [-cfaedDS] [-o file] [-s strsize] command [args]");
70bbeaf6c0SSean Eric Fagan 	exit(1);
71bbeaf6c0SSean Eric Fagan }
72bbeaf6c0SSean Eric Fagan 
733625b514SSean Eric Fagan /*
743625b514SSean Eric Fagan  * WARNING! "FreeBSD a.out" must be first, or set_etype will not
753625b514SSean Eric Fagan  * work correctly.
763625b514SSean Eric Fagan  */
77bbeaf6c0SSean Eric Fagan struct ex_types {
781be5d704SMark Murray 	const char *type;
79ec0bed25SMatthew N. Dodd 	void (*enter_syscall)(struct trussinfo *, int);
801bcb5f5aSMarcel Moolenaar 	long (*exit_syscall)(struct trussinfo *, int);
81bbeaf6c0SSean Eric Fagan } ex_types[] = {
82a5d31d16SDavid Malone #ifdef __amd64__
83a5d31d16SDavid Malone 	{ "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit },
849a55503eSJohn Baldwin 	{ "FreeBSD ELF32", amd64_fbsd32_syscall_entry, amd64_fbsd32_syscall_exit },
859a55503eSJohn Baldwin 	{ "Linux ELF32", amd64_linux32_syscall_entry, amd64_linux32_syscall_exit },
86a5d31d16SDavid Malone #endif
8750cc4492SSean Eric Fagan #ifdef __i386__
88bbeaf6c0SSean Eric Fagan 	{ "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },
8987893934SPeter Wemm 	{ "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit },
900629483cSMatthew N. Dodd 	{ "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit },
91bbeaf6c0SSean Eric Fagan 	{ "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit },
9250cc4492SSean Eric Fagan #endif
93a3e32192SMarcel Moolenaar #ifdef __ia64__
94a3e32192SMarcel Moolenaar 	{ "FreeBSD ELF64", ia64_syscall_entry, ia64_syscall_exit },
95a3e32192SMarcel Moolenaar #endif
967fa9dc1cSPeter Grehan #ifdef __powerpc__
977fa9dc1cSPeter Grehan 	{ "FreeBSD ELF", powerpc_syscall_entry, powerpc_syscall_exit },
987fa9dc1cSPeter Grehan 	{ "FreeBSD ELF32", powerpc_syscall_entry, powerpc_syscall_exit },
994e583321SNathan Whitehorn #ifdef __powerpc64__
1004e583321SNathan Whitehorn 	{ "FreeBSD ELF64", powerpc64_syscall_entry, powerpc64_syscall_exit },
1014e583321SNathan Whitehorn #endif
1027fa9dc1cSPeter Grehan #endif
103f84c971aSJake Burkholder #ifdef __sparc64__
104f84c971aSJake Burkholder 	{ "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
105f84c971aSJake Burkholder #endif
10689fe547fSWarner Losh #ifdef __mips__
10789fe547fSWarner Losh 	{ "FreeBSD ELF", mips_syscall_entry, mips_syscall_exit },
10889fe547fSWarner Losh 	{ "FreeBSD ELF32", mips_syscall_entry, mips_syscall_exit },
10989fe547fSWarner Losh 	{ "FreeBSD ELF64", mips_syscall_entry, mips_syscall_exit }, // XXX
11089fe547fSWarner Losh #endif
111bbeaf6c0SSean Eric Fagan 	{ 0, 0, 0 },
112bbeaf6c0SSean Eric Fagan };
113bbeaf6c0SSean Eric Fagan 
114bbeaf6c0SSean Eric Fagan /*
115bbeaf6c0SSean Eric Fagan  * Set the execution type.  This is called after every exec, and when
1165d2d083cSXin LI  * a process is first monitored.
117bbeaf6c0SSean Eric Fagan  */
118bbeaf6c0SSean Eric Fagan 
119bbeaf6c0SSean Eric Fagan static struct ex_types *
1205321ae86SAlfred Perlstein set_etype(struct trussinfo *trussinfo)
1215321ae86SAlfred Perlstein {
122bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
1231be5d704SMark Murray 	char progt[32];
124bbeaf6c0SSean Eric Fagan 
1255d2d083cSXin LI 	size_t len = sizeof(progt);
1265d2d083cSXin LI 	int mib[4];
1275d2d083cSXin LI 	int error;
1285d2d083cSXin LI 
1295d2d083cSXin LI 	mib[0] = CTL_KERN;
1305d2d083cSXin LI 	mib[1] = KERN_PROC;
1315d2d083cSXin LI 	mib[2] = KERN_PROC_SV_NAME;
1325d2d083cSXin LI 	mib[3] = trussinfo->pid;
1335d2d083cSXin LI 	error = sysctl(mib, 4, progt, &len, NULL, 0);
1345d2d083cSXin LI 	if (error != 0)
1355d2d083cSXin LI 		err(2, "can not get etype");
136bbeaf6c0SSean Eric Fagan 
137bbeaf6c0SSean Eric Fagan 	for (funcs = ex_types; funcs->type; funcs++)
1381be5d704SMark Murray 		if (!strcmp(funcs->type, progt))
139bbeaf6c0SSean Eric Fagan 			break;
140bbeaf6c0SSean Eric Fagan 
1414525f3a8SDag-Erling Smørgrav 	if (funcs->type == NULL) {
1423625b514SSean Eric Fagan 		funcs = &ex_types[0];
143b956c13cSPhilippe Charnier 		warn("execution type %s is not supported -- using %s",
1444525f3a8SDag-Erling Smørgrav 		    progt, funcs->type);
1453625b514SSean Eric Fagan 	}
1465321ae86SAlfred Perlstein 	return (funcs);
147bbeaf6c0SSean Eric Fagan }
148bbeaf6c0SSean Eric Fagan 
149d75300bfSAlfred Perlstein char *
150d75300bfSAlfred Perlstein strsig(int sig)
151d75300bfSAlfred Perlstein {
152d75300bfSAlfred Perlstein 	char *ret;
153d75300bfSAlfred Perlstein 
154d75300bfSAlfred Perlstein 	ret = NULL;
155d75300bfSAlfred Perlstein 	if (sig > 0 && sig < NSIG) {
15612dacf62SJilles Tjoelker 		asprintf(&ret, "SIG%s", sys_signame[sig]);
157d75300bfSAlfred Perlstein 		if (ret == NULL)
158d75300bfSAlfred Perlstein 			return (NULL);
159d75300bfSAlfred Perlstein 	}
160d75300bfSAlfred Perlstein 	return (ret);
161d75300bfSAlfred Perlstein }
162d75300bfSAlfred Perlstein 
1633cf51049SPhilippe Charnier int
1645321ae86SAlfred Perlstein main(int ac, char **av)
1655321ae86SAlfred Perlstein {
166bbeaf6c0SSean Eric Fagan 	int c;
167bbeaf6c0SSean Eric Fagan 	int i;
168d5303c80SXin LI 	pid_t childpid;
169d5303c80SXin LI 	int status;
170bbeaf6c0SSean Eric Fagan 	char **command;
171bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
172ef29ac7fSXin LI 	int initial_open;
17372aa911aSAlfred Perlstein 	char *fname;
174ec0bed25SMatthew N. Dodd 	struct trussinfo *trussinfo;
175d75300bfSAlfred Perlstein 	char *signame;
176bbeaf6c0SSean Eric Fagan 
17772aa911aSAlfred Perlstein 	fname = NULL;
17872aa911aSAlfred Perlstein 	initial_open = 1;
17972aa911aSAlfred Perlstein 
180ec0bed25SMatthew N. Dodd 	/* Initialize the trussinfo struct */
181216fa4c6SXin LI 	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
182ec0bed25SMatthew N. Dodd 	if (trussinfo == NULL)
183216fa4c6SXin LI 		errx(1, "calloc() failed");
1845d2d083cSXin LI 
185ec0bed25SMatthew N. Dodd 	trussinfo->outfile = stderr;
1860cf21b4fSBrian Somers 	trussinfo->strsize = 32;
1875d2d083cSXin LI 	trussinfo->pr_why = S_NONE;
1885d2d083cSXin LI 	trussinfo->curthread = NULL;
1895d2d083cSXin LI 	SLIST_INIT(&trussinfo->threadlist);
190ee3b0f6eSDiomidis Spinellis 	while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
191bbeaf6c0SSean Eric Fagan 		switch (c) {
192bbeaf6c0SSean Eric Fagan 		case 'p':	/* specified pid */
193ec0bed25SMatthew N. Dodd 			trussinfo->pid = atoi(optarg);
194ef29ac7fSXin LI 			/* make sure i don't trace me */
195ef29ac7fSXin LI 			if(trussinfo->pid == getpid()) {
196ef29ac7fSXin LI 				fprintf(stderr, "attempt to grab self.\n");
197ef29ac7fSXin LI 				exit(2);
198ef29ac7fSXin LI 			}
199bbeaf6c0SSean Eric Fagan 			break;
200c03bfcc8SMatthew N. Dodd 		case 'f': /* Follow fork()'s */
201c03bfcc8SMatthew N. Dodd 			trussinfo->flags |= FOLLOWFORKS;
202c03bfcc8SMatthew N. Dodd 			break;
2039897b203SMatthew N. Dodd 		case 'a': /* Print execve() argument strings. */
2049897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEARGS;
2059897b203SMatthew N. Dodd 			break;
206ee3b0f6eSDiomidis Spinellis 		case 'c': /* Count number of system calls and time. */
207ee3b0f6eSDiomidis Spinellis 			trussinfo->flags |= COUNTONLY;
208ee3b0f6eSDiomidis Spinellis 			break;
2099897b203SMatthew N. Dodd 		case 'e': /* Print execve() environment strings. */
2109897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEENVS;
2119897b203SMatthew N. Dodd 			break;
2120d0bd00eSMatthew N. Dodd 		case 'd': /* Absolute timestamps */
2130d0bd00eSMatthew N. Dodd 			trussinfo->flags |= ABSOLUTETIMESTAMPS;
2140d0bd00eSMatthew N. Dodd 			break;
2150d0bd00eSMatthew N. Dodd 		case 'D': /* Relative timestamps */
2160d0bd00eSMatthew N. Dodd 			trussinfo->flags |= RELATIVETIMESTAMPS;
2170d0bd00eSMatthew N. Dodd 			break;
218bbeaf6c0SSean Eric Fagan 		case 'o':	/* Specified output file */
2193cf51049SPhilippe Charnier 			fname = optarg;
220bbeaf6c0SSean Eric Fagan 			break;
2210cf21b4fSBrian Somers 		case 's':	/* Specified string size */
2220cf21b4fSBrian Somers 			trussinfo->strsize = atoi(optarg);
2230cf21b4fSBrian Somers 			break;
224bbeaf6c0SSean Eric Fagan 		case 'S':	/* Don't trace signals */
225ec0bed25SMatthew N. Dodd 			trussinfo->flags |= NOSIGS;
226bbeaf6c0SSean Eric Fagan 			break;
227bbeaf6c0SSean Eric Fagan 		default:
228bbeaf6c0SSean Eric Fagan 			usage();
229bbeaf6c0SSean Eric Fagan 		}
230bbeaf6c0SSean Eric Fagan 	}
231bbeaf6c0SSean Eric Fagan 
232bbeaf6c0SSean Eric Fagan 	ac -= optind; av += optind;
2335321ae86SAlfred Perlstein 	if ((trussinfo->pid == 0 && ac == 0) ||
2345321ae86SAlfred Perlstein 	    (trussinfo->pid != 0 && ac != 0))
235bbeaf6c0SSean Eric Fagan 		usage();
236bbeaf6c0SSean Eric Fagan 
2373cf51049SPhilippe Charnier 	if (fname != NULL) { /* Use output file */
238ec0bed25SMatthew N. Dodd 		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
2393cf51049SPhilippe Charnier 			errx(1, "cannot open %s", fname);
240ecbb6d34SJaakko Heinonen 		/*
241ecbb6d34SJaakko Heinonen 		 * Set FD_CLOEXEC, so that the output file is not shared with
242ecbb6d34SJaakko Heinonen 		 * the traced process.
243ecbb6d34SJaakko Heinonen 		 */
244e04c3786SJaakko Heinonen 		if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) ==
245e04c3786SJaakko Heinonen 		    -1)
246ecbb6d34SJaakko Heinonen 			warn("fcntl()");
247e04c3786SJaakko Heinonen 	}
2483cf51049SPhilippe Charnier 
249bbeaf6c0SSean Eric Fagan 	/*
250bbeaf6c0SSean Eric Fagan 	 * If truss starts the process itself, it will ignore some signals --
251bbeaf6c0SSean Eric Fagan 	 * they should be passed off to the process, which may or may not
252bbeaf6c0SSean Eric Fagan 	 * exit.  If, however, we are examining an already-running process,
253bbeaf6c0SSean Eric Fagan 	 * then we restore the event mask on these same signals.
254bbeaf6c0SSean Eric Fagan 	 */
255bbeaf6c0SSean Eric Fagan 
256ec0bed25SMatthew N. Dodd 	if (trussinfo->pid == 0) {	/* Start a command ourselves */
257bbeaf6c0SSean Eric Fagan 		command = av;
258ec0bed25SMatthew N. Dodd 		trussinfo->pid = setup_and_wait(command);
259bbeaf6c0SSean Eric Fagan 		signal(SIGINT, SIG_IGN);
260bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, SIG_IGN);
261bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, SIG_IGN);
262bbeaf6c0SSean Eric Fagan 	} else {
2635d2d083cSXin LI 		start_tracing(trussinfo->pid);
264bbeaf6c0SSean Eric Fagan 		signal(SIGINT, restore_proc);
265bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, restore_proc);
266bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, restore_proc);
267bbeaf6c0SSean Eric Fagan 	}
268bbeaf6c0SSean Eric Fagan 
269bbeaf6c0SSean Eric Fagan 
270bbeaf6c0SSean Eric Fagan 	/*
271bbeaf6c0SSean Eric Fagan 	 * At this point, if we started the process, it is stopped waiting to
272bbeaf6c0SSean Eric Fagan 	 * be woken up, either in exit() or in execve().
273bbeaf6c0SSean Eric Fagan 	 */
274bbeaf6c0SSean Eric Fagan 
275c03bfcc8SMatthew N. Dodd START_TRACE:
276ec0bed25SMatthew N. Dodd 	funcs = set_etype(trussinfo);
2775d2d083cSXin LI 
2785d2d083cSXin LI 	initial_open = 0;
279bbeaf6c0SSean Eric Fagan 	/*
280bbeaf6c0SSean Eric Fagan 	 * At this point, it's a simple loop, waiting for the process to
281bbeaf6c0SSean Eric Fagan 	 * stop, finding out why, printing out why, and then continuing it.
282bbeaf6c0SSean Eric Fagan 	 * All of the grunt work is done in the support routines.
283bbeaf6c0SSean Eric Fagan 	 */
284bbeaf6c0SSean Eric Fagan 
285203098d8SMatthew N. Dodd 	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
2860d0bd00eSMatthew N. Dodd 
287bbeaf6c0SSean Eric Fagan 	do {
288081e5c48SPav Lucistnik 		struct timespec timediff;
2895d2d083cSXin LI 		waitevent(trussinfo);
290bbeaf6c0SSean Eric Fagan 
2915d2d083cSXin LI 		switch(i = trussinfo->pr_why) {
292bbeaf6c0SSean Eric Fagan 		case S_SCE:
2935d2d083cSXin LI 			funcs->enter_syscall(trussinfo, MAXARGS);
2945321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
2955321ae86SAlfred Perlstein 			    &trussinfo->before);
296bbeaf6c0SSean Eric Fagan 			break;
297bbeaf6c0SSean Eric Fagan 		case S_SCX:
2985321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
2995321ae86SAlfred Perlstein 			    &trussinfo->after);
300c03bfcc8SMatthew N. Dodd 
3015d2d083cSXin LI 			if (trussinfo->curthread->in_fork &&
3025321ae86SAlfred Perlstein 			    (trussinfo->flags & FOLLOWFORKS)) {
3035d2d083cSXin LI 				trussinfo->curthread->in_fork = 0;
3045321ae86SAlfred Perlstein 				childpid =
3055321ae86SAlfred Perlstein 				    funcs->exit_syscall(trussinfo,
3065d2d083cSXin LI 					trussinfo->pr_data);
307c03bfcc8SMatthew N. Dodd 
308c03bfcc8SMatthew N. Dodd 				/*
3095321ae86SAlfred Perlstein 				 * Fork a new copy of ourself to trace
3105321ae86SAlfred Perlstein 				 * the child of the original traced
3115321ae86SAlfred Perlstein 				 * process.
312c03bfcc8SMatthew N. Dodd 				 */
313c03bfcc8SMatthew N. Dodd 				if (fork() == 0) {
314c03bfcc8SMatthew N. Dodd 					trussinfo->pid = childpid;
3155d2d083cSXin LI 					start_tracing(trussinfo->pid);
316c03bfcc8SMatthew N. Dodd 					goto START_TRACE;
317c03bfcc8SMatthew N. Dodd 				}
318c03bfcc8SMatthew N. Dodd 				break;
319c03bfcc8SMatthew N. Dodd 			}
3205d2d083cSXin LI 			funcs->exit_syscall(trussinfo, MAXARGS);
321bbeaf6c0SSean Eric Fagan 			break;
322bbeaf6c0SSean Eric Fagan 		case S_SIG:
3235d2d083cSXin LI 			if (trussinfo->flags & NOSIGS)
3245d2d083cSXin LI 				break;
325081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
326081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
327081e5c48SPav Lucistnik 				    trussinfo->pid);
328081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
329081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
330081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
331081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
332081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
333081e5c48SPav Lucistnik 				    timediff.tv_nsec);
334081e5c48SPav Lucistnik 			}
335081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
336081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
337081e5c48SPav Lucistnik 				    &trussinfo->before, &timediff);
338081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
339081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
340081e5c48SPav Lucistnik 				    timediff.tv_nsec);
341081e5c48SPav Lucistnik 			}
3425d2d083cSXin LI 			signame = strsig(trussinfo->pr_data);
3435321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3445d2d083cSXin LI 			    "SIGNAL %u (%s)\n", trussinfo->pr_data,
345d75300bfSAlfred Perlstein 			    signame == NULL ? "?" : signame);
346d75300bfSAlfred Perlstein 			free(signame);
347bbeaf6c0SSean Eric Fagan 			break;
348bbeaf6c0SSean Eric Fagan 		case S_EXIT:
349ee3b0f6eSDiomidis Spinellis 			if (trussinfo->flags & COUNTONLY)
350ee3b0f6eSDiomidis Spinellis 				break;
351081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
352081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
353081e5c48SPav Lucistnik 				    trussinfo->pid);
354081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
355081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
356081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
357081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
358081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
359081e5c48SPav Lucistnik 				    timediff.tv_nsec);
360081e5c48SPav Lucistnik 			}
361081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
362081e5c48SPav Lucistnik 			  timespecsubt(&trussinfo->after,
363081e5c48SPav Lucistnik 			      &trussinfo->before, &timediff);
364081e5c48SPav Lucistnik 			  fprintf(trussinfo->outfile, "%ld.%09ld ",
365081e5c48SPav Lucistnik 			    (long)timediff.tv_sec, timediff.tv_nsec);
366081e5c48SPav Lucistnik 			}
3675321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3685d2d083cSXin LI 			    "process exit, rval = %u\n", trussinfo->pr_data);
369bbeaf6c0SSean Eric Fagan 			break;
370bbeaf6c0SSean Eric Fagan 		default:
371bbeaf6c0SSean Eric Fagan 			break;
372bbeaf6c0SSean Eric Fagan 		}
3735d2d083cSXin LI 	} while (trussinfo->pr_why != S_EXIT);
3745d2d083cSXin LI 
375d5303c80SXin LI 	if (trussinfo->flags & FOLLOWFORKS)
376d5303c80SXin LI 		do {
377d5303c80SXin LI 			childpid = wait(&status);
378d5303c80SXin LI 		} while (childpid != -1);
379d5303c80SXin LI 
380ee3b0f6eSDiomidis Spinellis  	if (trussinfo->flags & COUNTONLY)
381ee3b0f6eSDiomidis Spinellis  		print_summary(trussinfo);
382ee3b0f6eSDiomidis Spinellis 
383ee3b0f6eSDiomidis Spinellis 	fflush(trussinfo->outfile);
384ee3b0f6eSDiomidis Spinellis 
3855321ae86SAlfred Perlstein 	return (0);
386bbeaf6c0SSean Eric Fagan }
387