xref: /freebsd/usr.bin/truss/main.c (revision ee3b0f6e2e053c63a22950421e05ff93ebc3cd73)
1d5303c80SXin LI /*-
209d64da3SSean Eric Fagan  * Copryight 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>
503cf51049SPhilippe Charnier #include <errno.h>
513cf51049SPhilippe Charnier #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 },
1007fa9dc1cSPeter Grehan #endif
101f84c971aSJake Burkholder #ifdef __sparc64__
102f84c971aSJake Burkholder 	{ "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
103f84c971aSJake Burkholder #endif
10489fe547fSWarner Losh #ifdef __mips__
10589fe547fSWarner Losh 	{ "FreeBSD ELF", mips_syscall_entry, mips_syscall_exit },
10689fe547fSWarner Losh 	{ "FreeBSD ELF32", mips_syscall_entry, mips_syscall_exit },
10789fe547fSWarner Losh 	{ "FreeBSD ELF64", mips_syscall_entry, mips_syscall_exit }, // XXX
10889fe547fSWarner Losh #endif
109bbeaf6c0SSean Eric Fagan 	{ 0, 0, 0 },
110bbeaf6c0SSean Eric Fagan };
111bbeaf6c0SSean Eric Fagan 
112bbeaf6c0SSean Eric Fagan /*
113bbeaf6c0SSean Eric Fagan  * Set the execution type.  This is called after every exec, and when
1145d2d083cSXin LI  * a process is first monitored.
115bbeaf6c0SSean Eric Fagan  */
116bbeaf6c0SSean Eric Fagan 
117bbeaf6c0SSean Eric Fagan static struct ex_types *
1185321ae86SAlfred Perlstein set_etype(struct trussinfo *trussinfo)
1195321ae86SAlfred Perlstein {
120bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
1211be5d704SMark Murray 	char progt[32];
122bbeaf6c0SSean Eric Fagan 
1235d2d083cSXin LI 	size_t len = sizeof(progt);
1245d2d083cSXin LI 	int mib[4];
1255d2d083cSXin LI 	int error;
1265d2d083cSXin LI 
1275d2d083cSXin LI 	mib[0] = CTL_KERN;
1285d2d083cSXin LI 	mib[1] = KERN_PROC;
1295d2d083cSXin LI 	mib[2] = KERN_PROC_SV_NAME;
1305d2d083cSXin LI 	mib[3] = trussinfo->pid;
1315d2d083cSXin LI 	error = sysctl(mib, 4, progt, &len, NULL, 0);
1325d2d083cSXin LI 	if (error != 0)
1335d2d083cSXin LI 		err(2, "can not get etype");
134bbeaf6c0SSean Eric Fagan 
135bbeaf6c0SSean Eric Fagan 	for (funcs = ex_types; funcs->type; funcs++)
1361be5d704SMark Murray 		if (!strcmp(funcs->type, progt))
137bbeaf6c0SSean Eric Fagan 			break;
138bbeaf6c0SSean Eric Fagan 
1394525f3a8SDag-Erling Smørgrav 	if (funcs->type == NULL) {
1403625b514SSean Eric Fagan 		funcs = &ex_types[0];
141b956c13cSPhilippe Charnier 		warn("execution type %s is not supported -- using %s",
1424525f3a8SDag-Erling Smørgrav 		    progt, funcs->type);
1433625b514SSean Eric Fagan 	}
1445321ae86SAlfred Perlstein 	return (funcs);
145bbeaf6c0SSean Eric Fagan }
146bbeaf6c0SSean Eric Fagan 
147d75300bfSAlfred Perlstein char *
148d75300bfSAlfred Perlstein strsig(int sig)
149d75300bfSAlfred Perlstein {
150d75300bfSAlfred Perlstein 	char *ret;
151d75300bfSAlfred Perlstein 
152d75300bfSAlfred Perlstein 	ret = NULL;
153d75300bfSAlfred Perlstein 	if (sig > 0 && sig < NSIG) {
154d75300bfSAlfred Perlstein 		int i;
155d75300bfSAlfred Perlstein 		asprintf(&ret, "sig%s", sys_signame[sig]);
156d75300bfSAlfred Perlstein 		if (ret == NULL)
157d75300bfSAlfred Perlstein 			return (NULL);
158d75300bfSAlfred Perlstein 		for (i = 0; ret[i] != '\0'; ++i)
159d75300bfSAlfred Perlstein 			ret[i] = toupper(ret[i]);
160d75300bfSAlfred Perlstein 	}
161d75300bfSAlfred Perlstein 	return (ret);
162d75300bfSAlfred Perlstein }
163d75300bfSAlfred Perlstein 
1643cf51049SPhilippe Charnier int
1655321ae86SAlfred Perlstein main(int ac, char **av)
1665321ae86SAlfred Perlstein {
167bbeaf6c0SSean Eric Fagan 	int c;
168bbeaf6c0SSean Eric Fagan 	int i;
169d5303c80SXin LI 	pid_t childpid;
170d5303c80SXin LI 	int status;
171bbeaf6c0SSean Eric Fagan 	char **command;
172bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
173ef29ac7fSXin LI 	int initial_open;
17472aa911aSAlfred Perlstein 	char *fname;
175ec0bed25SMatthew N. Dodd 	struct trussinfo *trussinfo;
176d75300bfSAlfred Perlstein 	char *signame;
177bbeaf6c0SSean Eric Fagan 
17872aa911aSAlfred Perlstein 	fname = NULL;
17972aa911aSAlfred Perlstein 	initial_open = 1;
18072aa911aSAlfred Perlstein 
181ec0bed25SMatthew N. Dodd 	/* Initialize the trussinfo struct */
182ec0bed25SMatthew N. Dodd 	trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo));
183ec0bed25SMatthew N. Dodd 	if (trussinfo == NULL)
184ec0bed25SMatthew N. Dodd 		errx(1, "malloc() failed");
185ec0bed25SMatthew N. Dodd 	bzero(trussinfo, sizeof(struct trussinfo));
1865d2d083cSXin LI 
187ec0bed25SMatthew N. Dodd 	trussinfo->outfile = stderr;
1880cf21b4fSBrian Somers 	trussinfo->strsize = 32;
1895d2d083cSXin LI 	trussinfo->pr_why = S_NONE;
1905d2d083cSXin LI 	trussinfo->curthread = NULL;
1915d2d083cSXin LI 	SLIST_INIT(&trussinfo->threadlist);
192ee3b0f6eSDiomidis Spinellis 	while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
193bbeaf6c0SSean Eric Fagan 		switch (c) {
194bbeaf6c0SSean Eric Fagan 		case 'p':	/* specified pid */
195ec0bed25SMatthew N. Dodd 			trussinfo->pid = atoi(optarg);
196ef29ac7fSXin LI 			/* make sure i don't trace me */
197ef29ac7fSXin LI 			if(trussinfo->pid == getpid()) {
198ef29ac7fSXin LI 				fprintf(stderr, "attempt to grab self.\n");
199ef29ac7fSXin LI 				exit(2);
200ef29ac7fSXin LI 			}
201bbeaf6c0SSean Eric Fagan 			break;
202c03bfcc8SMatthew N. Dodd 		case 'f': /* Follow fork()'s */
203c03bfcc8SMatthew N. Dodd 			trussinfo->flags |= FOLLOWFORKS;
204c03bfcc8SMatthew N. Dodd 			break;
2059897b203SMatthew N. Dodd 		case 'a': /* Print execve() argument strings. */
2069897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEARGS;
2079897b203SMatthew N. Dodd 			break;
208ee3b0f6eSDiomidis Spinellis 		case 'c': /* Count number of system calls and time. */
209ee3b0f6eSDiomidis Spinellis 			trussinfo->flags |= COUNTONLY;
210ee3b0f6eSDiomidis Spinellis 			break;
2119897b203SMatthew N. Dodd 		case 'e': /* Print execve() environment strings. */
2129897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEENVS;
2139897b203SMatthew N. Dodd 			break;
2140d0bd00eSMatthew N. Dodd 		case 'd': /* Absolute timestamps */
2150d0bd00eSMatthew N. Dodd 			trussinfo->flags |= ABSOLUTETIMESTAMPS;
2160d0bd00eSMatthew N. Dodd 			break;
2170d0bd00eSMatthew N. Dodd 		case 'D': /* Relative timestamps */
2180d0bd00eSMatthew N. Dodd 			trussinfo->flags |= RELATIVETIMESTAMPS;
2190d0bd00eSMatthew N. Dodd 			break;
220bbeaf6c0SSean Eric Fagan 		case 'o':	/* Specified output file */
2213cf51049SPhilippe Charnier 			fname = optarg;
222bbeaf6c0SSean Eric Fagan 			break;
2230cf21b4fSBrian Somers 		case 's':	/* Specified string size */
2240cf21b4fSBrian Somers 			trussinfo->strsize = atoi(optarg);
2250cf21b4fSBrian Somers 			break;
226bbeaf6c0SSean Eric Fagan 		case 'S':	/* Don't trace signals */
227ec0bed25SMatthew N. Dodd 			trussinfo->flags |= NOSIGS;
228bbeaf6c0SSean Eric Fagan 			break;
229bbeaf6c0SSean Eric Fagan 		default:
230bbeaf6c0SSean Eric Fagan 			usage();
231bbeaf6c0SSean Eric Fagan 		}
232bbeaf6c0SSean Eric Fagan 	}
233bbeaf6c0SSean Eric Fagan 
234bbeaf6c0SSean Eric Fagan 	ac -= optind; av += optind;
2355321ae86SAlfred Perlstein 	if ((trussinfo->pid == 0 && ac == 0) ||
2365321ae86SAlfred Perlstein 	    (trussinfo->pid != 0 && ac != 0))
237bbeaf6c0SSean Eric Fagan 		usage();
238bbeaf6c0SSean Eric Fagan 
2393cf51049SPhilippe Charnier 	if (fname != NULL) { /* Use output file */
240ec0bed25SMatthew N. Dodd 		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
2413cf51049SPhilippe Charnier 			errx(1, "cannot open %s", fname);
2423cf51049SPhilippe Charnier 	}
2433cf51049SPhilippe Charnier 
244bbeaf6c0SSean Eric Fagan 	/*
245bbeaf6c0SSean Eric Fagan 	 * If truss starts the process itself, it will ignore some signals --
246bbeaf6c0SSean Eric Fagan 	 * they should be passed off to the process, which may or may not
247bbeaf6c0SSean Eric Fagan 	 * exit.  If, however, we are examining an already-running process,
248bbeaf6c0SSean Eric Fagan 	 * then we restore the event mask on these same signals.
249bbeaf6c0SSean Eric Fagan 	 */
250bbeaf6c0SSean Eric Fagan 
251ec0bed25SMatthew N. Dodd 	if (trussinfo->pid == 0) {	/* Start a command ourselves */
252bbeaf6c0SSean Eric Fagan 		command = av;
253ec0bed25SMatthew N. Dodd 		trussinfo->pid = setup_and_wait(command);
254bbeaf6c0SSean Eric Fagan 		signal(SIGINT, SIG_IGN);
255bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, SIG_IGN);
256bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, SIG_IGN);
257bbeaf6c0SSean Eric Fagan 	} else {
2585d2d083cSXin LI 		start_tracing(trussinfo->pid);
259bbeaf6c0SSean Eric Fagan 		signal(SIGINT, restore_proc);
260bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, restore_proc);
261bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, restore_proc);
262bbeaf6c0SSean Eric Fagan 	}
263bbeaf6c0SSean Eric Fagan 
264bbeaf6c0SSean Eric Fagan 
265bbeaf6c0SSean Eric Fagan 	/*
266bbeaf6c0SSean Eric Fagan 	 * At this point, if we started the process, it is stopped waiting to
267bbeaf6c0SSean Eric Fagan 	 * be woken up, either in exit() or in execve().
268bbeaf6c0SSean Eric Fagan 	 */
269bbeaf6c0SSean Eric Fagan 
270c03bfcc8SMatthew N. Dodd START_TRACE:
271ec0bed25SMatthew N. Dodd 	funcs = set_etype(trussinfo);
2725d2d083cSXin LI 
2735d2d083cSXin LI 	initial_open = 0;
274bbeaf6c0SSean Eric Fagan 	/*
275bbeaf6c0SSean Eric Fagan 	 * At this point, it's a simple loop, waiting for the process to
276bbeaf6c0SSean Eric Fagan 	 * stop, finding out why, printing out why, and then continuing it.
277bbeaf6c0SSean Eric Fagan 	 * All of the grunt work is done in the support routines.
278bbeaf6c0SSean Eric Fagan 	 */
279bbeaf6c0SSean Eric Fagan 
280203098d8SMatthew N. Dodd 	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
2810d0bd00eSMatthew N. Dodd 
282bbeaf6c0SSean Eric Fagan 	do {
283081e5c48SPav Lucistnik 		struct timespec timediff;
2845d2d083cSXin LI 		waitevent(trussinfo);
285bbeaf6c0SSean Eric Fagan 
2865d2d083cSXin LI 		switch(i = trussinfo->pr_why) {
287bbeaf6c0SSean Eric Fagan 		case S_SCE:
2885d2d083cSXin LI 			funcs->enter_syscall(trussinfo, MAXARGS);
2895321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
2905321ae86SAlfred Perlstein 			    &trussinfo->before);
291bbeaf6c0SSean Eric Fagan 			break;
292bbeaf6c0SSean Eric Fagan 		case S_SCX:
2935321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
2945321ae86SAlfred Perlstein 			    &trussinfo->after);
295c03bfcc8SMatthew N. Dodd 
2965d2d083cSXin LI 			if (trussinfo->curthread->in_fork &&
2975321ae86SAlfred Perlstein 			    (trussinfo->flags & FOLLOWFORKS)) {
2985d2d083cSXin LI 				trussinfo->curthread->in_fork = 0;
2995321ae86SAlfred Perlstein 				childpid =
3005321ae86SAlfred Perlstein 				    funcs->exit_syscall(trussinfo,
3015d2d083cSXin LI 					trussinfo->pr_data);
302c03bfcc8SMatthew N. Dodd 
303c03bfcc8SMatthew N. Dodd 				/*
3045321ae86SAlfred Perlstein 				 * Fork a new copy of ourself to trace
3055321ae86SAlfred Perlstein 				 * the child of the original traced
3065321ae86SAlfred Perlstein 				 * process.
307c03bfcc8SMatthew N. Dodd 				 */
308c03bfcc8SMatthew N. Dodd 				if (fork() == 0) {
309c03bfcc8SMatthew N. Dodd 					trussinfo->pid = childpid;
3105d2d083cSXin LI 					start_tracing(trussinfo->pid);
311c03bfcc8SMatthew N. Dodd 					goto START_TRACE;
312c03bfcc8SMatthew N. Dodd 				}
313c03bfcc8SMatthew N. Dodd 				break;
314c03bfcc8SMatthew N. Dodd 			}
3155d2d083cSXin LI 			funcs->exit_syscall(trussinfo, MAXARGS);
316bbeaf6c0SSean Eric Fagan 			break;
317bbeaf6c0SSean Eric Fagan 		case S_SIG:
3185d2d083cSXin LI 			if (trussinfo->flags & NOSIGS)
3195d2d083cSXin LI 				break;
320081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
321081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
322081e5c48SPav Lucistnik 				    trussinfo->pid);
323081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
324081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
325081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
326081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
327081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
328081e5c48SPav Lucistnik 				    timediff.tv_nsec);
329081e5c48SPav Lucistnik 			}
330081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
331081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
332081e5c48SPav Lucistnik 				    &trussinfo->before, &timediff);
333081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
334081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
335081e5c48SPav Lucistnik 				    timediff.tv_nsec);
336081e5c48SPav Lucistnik 			}
3375d2d083cSXin LI 			signame = strsig(trussinfo->pr_data);
3385321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3395d2d083cSXin LI 			    "SIGNAL %u (%s)\n", trussinfo->pr_data,
340d75300bfSAlfred Perlstein 			    signame == NULL ? "?" : signame);
341d75300bfSAlfred Perlstein 			free(signame);
342bbeaf6c0SSean Eric Fagan 			break;
343bbeaf6c0SSean Eric Fagan 		case S_EXIT:
344ee3b0f6eSDiomidis Spinellis 			if (trussinfo->flags & COUNTONLY)
345ee3b0f6eSDiomidis Spinellis 				break;
346081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
347081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
348081e5c48SPav Lucistnik 				    trussinfo->pid);
349081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
350081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
351081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
352081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
353081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
354081e5c48SPav Lucistnik 				    timediff.tv_nsec);
355081e5c48SPav Lucistnik 			}
356081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
357081e5c48SPav Lucistnik 			  timespecsubt(&trussinfo->after,
358081e5c48SPav Lucistnik 			      &trussinfo->before, &timediff);
359081e5c48SPav Lucistnik 			  fprintf(trussinfo->outfile, "%ld.%09ld ",
360081e5c48SPav Lucistnik 			    (long)timediff.tv_sec, timediff.tv_nsec);
361081e5c48SPav Lucistnik 			}
3625321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3635d2d083cSXin LI 			    "process exit, rval = %u\n", trussinfo->pr_data);
364bbeaf6c0SSean Eric Fagan 			break;
365bbeaf6c0SSean Eric Fagan 		default:
366bbeaf6c0SSean Eric Fagan 			break;
367bbeaf6c0SSean Eric Fagan 		}
3685d2d083cSXin LI 	} while (trussinfo->pr_why != S_EXIT);
3695d2d083cSXin LI 
370d5303c80SXin LI 	if (trussinfo->flags & FOLLOWFORKS)
371d5303c80SXin LI 		do {
372d5303c80SXin LI 			childpid = wait(&status);
373d5303c80SXin LI 		} while (childpid != -1);
374d5303c80SXin LI 
375ee3b0f6eSDiomidis Spinellis  	if (trussinfo->flags & COUNTONLY)
376ee3b0f6eSDiomidis Spinellis  		print_summary(trussinfo);
377ee3b0f6eSDiomidis Spinellis 
378ee3b0f6eSDiomidis Spinellis 	fflush(trussinfo->outfile);
379ee3b0f6eSDiomidis Spinellis 
3805321ae86SAlfred Perlstein 	return (0);
381bbeaf6c0SSean Eric Fagan }
382