xref: /freebsd/usr.bin/truss/main.c (revision ef29ac7f765a07f984fb42ff3ae7b6ad95a9d152)
1bbeaf6c0SSean Eric Fagan /*
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>
46580e0a2bSDag-Erling Smørgrav 
47d75300bfSAlfred Perlstein #include <ctype.h>
483cf51049SPhilippe Charnier #include <err.h>
493cf51049SPhilippe Charnier #include <errno.h>
503cf51049SPhilippe Charnier #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"
60bbeaf6c0SSean Eric Fagan 
615d2d083cSXin LI #define MAXARGS 5
62bbeaf6c0SSean Eric Fagan 
635321ae86SAlfred Perlstein static void
643cf51049SPhilippe Charnier usage(void)
653cf51049SPhilippe Charnier {
663cf51049SPhilippe Charnier 	fprintf(stderr, "%s\n%s\n",
670cf21b4fSBrian Somers 	    "usage: truss [-faedDS] [-o file] [-s strsize] -p pid",
680cf21b4fSBrian Somers 	    "       truss [-faedDS] [-o file] [-s strsize] command [args]");
69bbeaf6c0SSean Eric Fagan 	exit(1);
70bbeaf6c0SSean Eric Fagan }
71bbeaf6c0SSean Eric Fagan 
723625b514SSean Eric Fagan /*
733625b514SSean Eric Fagan  * WARNING! "FreeBSD a.out" must be first, or set_etype will not
743625b514SSean Eric Fagan  * work correctly.
753625b514SSean Eric Fagan  */
76bbeaf6c0SSean Eric Fagan struct ex_types {
771be5d704SMark Murray 	const char *type;
78ec0bed25SMatthew N. Dodd 	void (*enter_syscall)(struct trussinfo *, int);
791bcb5f5aSMarcel Moolenaar 	long (*exit_syscall)(struct trussinfo *, int);
80bbeaf6c0SSean Eric Fagan } ex_types[] = {
8150cc4492SSean Eric Fagan #ifdef __alpha__
8250cc4492SSean Eric Fagan 	{ "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit },
8350cc4492SSean Eric Fagan #endif
84a5d31d16SDavid Malone #ifdef __amd64__
85a5d31d16SDavid Malone 	{ "FreeBSD ELF64", amd64_syscall_entry, amd64_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 },
997fa9dc1cSPeter Grehan #endif
100f84c971aSJake Burkholder #ifdef __sparc64__
101f84c971aSJake Burkholder 	{ "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
102f84c971aSJake Burkholder #endif
103bbeaf6c0SSean Eric Fagan 	{ 0, 0, 0 },
104bbeaf6c0SSean Eric Fagan };
105bbeaf6c0SSean Eric Fagan 
106bbeaf6c0SSean Eric Fagan /*
107bbeaf6c0SSean Eric Fagan  * Set the execution type.  This is called after every exec, and when
1085d2d083cSXin LI  * a process is first monitored.
109bbeaf6c0SSean Eric Fagan  */
110bbeaf6c0SSean Eric Fagan 
111bbeaf6c0SSean Eric Fagan static struct ex_types *
1125321ae86SAlfred Perlstein set_etype(struct trussinfo *trussinfo)
1135321ae86SAlfred Perlstein {
114bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
1151be5d704SMark Murray 	char progt[32];
116bbeaf6c0SSean Eric Fagan 
1175d2d083cSXin LI 	size_t len = sizeof(progt);
1185d2d083cSXin LI 	int mib[4];
1195d2d083cSXin LI 	int error;
1205d2d083cSXin LI 
1215d2d083cSXin LI 	mib[0] = CTL_KERN;
1225d2d083cSXin LI 	mib[1] = KERN_PROC;
1235d2d083cSXin LI 	mib[2] = KERN_PROC_SV_NAME;
1245d2d083cSXin LI 	mib[3] = trussinfo->pid;
1255d2d083cSXin LI 	error = sysctl(mib, 4, progt, &len, NULL, 0);
1265d2d083cSXin LI 	if (error != 0)
1275d2d083cSXin LI 		err(2, "can not get etype");
128bbeaf6c0SSean Eric Fagan 
129bbeaf6c0SSean Eric Fagan 	for (funcs = ex_types; funcs->type; funcs++)
1301be5d704SMark Murray 		if (!strcmp(funcs->type, progt))
131bbeaf6c0SSean Eric Fagan 			break;
132bbeaf6c0SSean Eric Fagan 
1334525f3a8SDag-Erling Smørgrav 	if (funcs->type == NULL) {
1343625b514SSean Eric Fagan 		funcs = &ex_types[0];
135b956c13cSPhilippe Charnier 		warn("execution type %s is not supported -- using %s",
1364525f3a8SDag-Erling Smørgrav 		    progt, funcs->type);
1373625b514SSean Eric Fagan 	}
1385321ae86SAlfred Perlstein 	return (funcs);
139bbeaf6c0SSean Eric Fagan }
140bbeaf6c0SSean Eric Fagan 
141d75300bfSAlfred Perlstein char *
142d75300bfSAlfred Perlstein strsig(int sig)
143d75300bfSAlfred Perlstein {
144d75300bfSAlfred Perlstein 	char *ret;
145d75300bfSAlfred Perlstein 
146d75300bfSAlfred Perlstein 	ret = NULL;
147d75300bfSAlfred Perlstein 	if (sig > 0 && sig < NSIG) {
148d75300bfSAlfred Perlstein 		int i;
149d75300bfSAlfred Perlstein 		asprintf(&ret, "sig%s", sys_signame[sig]);
150d75300bfSAlfred Perlstein 		if (ret == NULL)
151d75300bfSAlfred Perlstein 			return (NULL);
152d75300bfSAlfred Perlstein 		for (i = 0; ret[i] != '\0'; ++i)
153d75300bfSAlfred Perlstein 			ret[i] = toupper(ret[i]);
154d75300bfSAlfred Perlstein 	}
155d75300bfSAlfred Perlstein 	return (ret);
156d75300bfSAlfred Perlstein }
157d75300bfSAlfred Perlstein 
1583cf51049SPhilippe Charnier int
1595321ae86SAlfred Perlstein main(int ac, char **av)
1605321ae86SAlfred Perlstein {
161bbeaf6c0SSean Eric Fagan 	int c;
162bbeaf6c0SSean Eric Fagan 	int i;
163bbeaf6c0SSean Eric Fagan 	char **command;
164bbeaf6c0SSean Eric Fagan 	struct ex_types *funcs;
165ef29ac7fSXin LI 	int initial_open;
16672aa911aSAlfred Perlstein 	char *fname;
167ec0bed25SMatthew N. Dodd 	struct trussinfo *trussinfo;
168d75300bfSAlfred Perlstein 	char *signame;
169bbeaf6c0SSean Eric Fagan 
17072aa911aSAlfred Perlstein 	fname = NULL;
17172aa911aSAlfred Perlstein 	initial_open = 1;
17272aa911aSAlfred Perlstein 
173ec0bed25SMatthew N. Dodd 	/* Initialize the trussinfo struct */
174ec0bed25SMatthew N. Dodd 	trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo));
175ec0bed25SMatthew N. Dodd 	if (trussinfo == NULL)
176ec0bed25SMatthew N. Dodd 		errx(1, "malloc() failed");
177ec0bed25SMatthew N. Dodd 	bzero(trussinfo, sizeof(struct trussinfo));
1785d2d083cSXin LI 
179ec0bed25SMatthew N. Dodd 	trussinfo->outfile = stderr;
1800cf21b4fSBrian Somers 	trussinfo->strsize = 32;
1815d2d083cSXin LI 	trussinfo->pr_why = S_NONE;
1825d2d083cSXin LI 	trussinfo->curthread = NULL;
1835d2d083cSXin LI 	SLIST_INIT(&trussinfo->threadlist);
1840cf21b4fSBrian Somers 	while ((c = getopt(ac, av, "p:o:faedDs:S")) != -1) {
185bbeaf6c0SSean Eric Fagan 		switch (c) {
186bbeaf6c0SSean Eric Fagan 		case 'p':	/* specified pid */
187ec0bed25SMatthew N. Dodd 			trussinfo->pid = atoi(optarg);
188ef29ac7fSXin LI 			/* make sure i don't trace me */
189ef29ac7fSXin LI 			if(trussinfo->pid == getpid()) {
190ef29ac7fSXin LI 				fprintf(stderr, "attempt to grab self.\n");
191ef29ac7fSXin LI 				exit(2);
192ef29ac7fSXin LI 			}
193bbeaf6c0SSean Eric Fagan 			break;
194c03bfcc8SMatthew N. Dodd 		case 'f': /* Follow fork()'s */
195c03bfcc8SMatthew N. Dodd 			trussinfo->flags |= FOLLOWFORKS;
196c03bfcc8SMatthew N. Dodd 			break;
1979897b203SMatthew N. Dodd 		case 'a': /* Print execve() argument strings. */
1989897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEARGS;
1999897b203SMatthew N. Dodd 			break;
2009897b203SMatthew N. Dodd 		case 'e': /* Print execve() environment strings. */
2019897b203SMatthew N. Dodd 			trussinfo->flags |= EXECVEENVS;
2029897b203SMatthew N. Dodd 			break;
2030d0bd00eSMatthew N. Dodd 		case 'd': /* Absolute timestamps */
2040d0bd00eSMatthew N. Dodd 			trussinfo->flags |= ABSOLUTETIMESTAMPS;
2050d0bd00eSMatthew N. Dodd 			break;
2060d0bd00eSMatthew N. Dodd 		case 'D': /* Relative timestamps */
2070d0bd00eSMatthew N. Dodd 			trussinfo->flags |= RELATIVETIMESTAMPS;
2080d0bd00eSMatthew N. Dodd 			break;
209bbeaf6c0SSean Eric Fagan 		case 'o':	/* Specified output file */
2103cf51049SPhilippe Charnier 			fname = optarg;
211bbeaf6c0SSean Eric Fagan 			break;
2120cf21b4fSBrian Somers 		case 's':	/* Specified string size */
2130cf21b4fSBrian Somers 			trussinfo->strsize = atoi(optarg);
2140cf21b4fSBrian Somers 			break;
215bbeaf6c0SSean Eric Fagan 		case 'S':	/* Don't trace signals */
216ec0bed25SMatthew N. Dodd 			trussinfo->flags |= NOSIGS;
217bbeaf6c0SSean Eric Fagan 			break;
218bbeaf6c0SSean Eric Fagan 		default:
219bbeaf6c0SSean Eric Fagan 			usage();
220bbeaf6c0SSean Eric Fagan 		}
221bbeaf6c0SSean Eric Fagan 	}
222bbeaf6c0SSean Eric Fagan 
223bbeaf6c0SSean Eric Fagan 	ac -= optind; av += optind;
2245321ae86SAlfred Perlstein 	if ((trussinfo->pid == 0 && ac == 0) ||
2255321ae86SAlfred Perlstein 	    (trussinfo->pid != 0 && ac != 0))
226bbeaf6c0SSean Eric Fagan 		usage();
227bbeaf6c0SSean Eric Fagan 
2283cf51049SPhilippe Charnier 	if (fname != NULL) { /* Use output file */
229ec0bed25SMatthew N. Dodd 		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
2303cf51049SPhilippe Charnier 			errx(1, "cannot open %s", fname);
2313cf51049SPhilippe Charnier 	}
2323cf51049SPhilippe Charnier 
233bbeaf6c0SSean Eric Fagan 	/*
234bbeaf6c0SSean Eric Fagan 	 * If truss starts the process itself, it will ignore some signals --
235bbeaf6c0SSean Eric Fagan 	 * they should be passed off to the process, which may or may not
236bbeaf6c0SSean Eric Fagan 	 * exit.  If, however, we are examining an already-running process,
237bbeaf6c0SSean Eric Fagan 	 * then we restore the event mask on these same signals.
238bbeaf6c0SSean Eric Fagan 	 */
239bbeaf6c0SSean Eric Fagan 
240ec0bed25SMatthew N. Dodd 	if (trussinfo->pid == 0) {	/* Start a command ourselves */
241bbeaf6c0SSean Eric Fagan 		command = av;
242ec0bed25SMatthew N. Dodd 		trussinfo->pid = setup_and_wait(command);
243bbeaf6c0SSean Eric Fagan 		signal(SIGINT, SIG_IGN);
244bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, SIG_IGN);
245bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, SIG_IGN);
246bbeaf6c0SSean Eric Fagan 	} else {
2475d2d083cSXin LI 		start_tracing(trussinfo->pid);
248bbeaf6c0SSean Eric Fagan 		signal(SIGINT, restore_proc);
249bbeaf6c0SSean Eric Fagan 		signal(SIGTERM, restore_proc);
250bbeaf6c0SSean Eric Fagan 		signal(SIGQUIT, restore_proc);
251bbeaf6c0SSean Eric Fagan 	}
252bbeaf6c0SSean Eric Fagan 
253bbeaf6c0SSean Eric Fagan 
254bbeaf6c0SSean Eric Fagan 	/*
255bbeaf6c0SSean Eric Fagan 	 * At this point, if we started the process, it is stopped waiting to
256bbeaf6c0SSean Eric Fagan 	 * be woken up, either in exit() or in execve().
257bbeaf6c0SSean Eric Fagan 	 */
258bbeaf6c0SSean Eric Fagan 
259c03bfcc8SMatthew N. Dodd START_TRACE:
260ec0bed25SMatthew N. Dodd 	funcs = set_etype(trussinfo);
2615d2d083cSXin LI 
2625d2d083cSXin LI 	initial_open = 0;
263bbeaf6c0SSean Eric Fagan 	/*
264bbeaf6c0SSean Eric Fagan 	 * At this point, it's a simple loop, waiting for the process to
265bbeaf6c0SSean Eric Fagan 	 * stop, finding out why, printing out why, and then continuing it.
266bbeaf6c0SSean Eric Fagan 	 * All of the grunt work is done in the support routines.
267bbeaf6c0SSean Eric Fagan 	 */
268bbeaf6c0SSean Eric Fagan 
269203098d8SMatthew N. Dodd 	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
2700d0bd00eSMatthew N. Dodd 
271bbeaf6c0SSean Eric Fagan 	do {
272081e5c48SPav Lucistnik 		struct timespec timediff;
2735d2d083cSXin LI 		waitevent(trussinfo);
274bbeaf6c0SSean Eric Fagan 
2755d2d083cSXin LI 		switch(i = trussinfo->pr_why) {
276bbeaf6c0SSean Eric Fagan 		case S_SCE:
2775d2d083cSXin LI 			funcs->enter_syscall(trussinfo, MAXARGS);
2785321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
2795321ae86SAlfred Perlstein 			    &trussinfo->before);
280bbeaf6c0SSean Eric Fagan 			break;
281bbeaf6c0SSean Eric Fagan 		case S_SCX:
2825321ae86SAlfred Perlstein 			clock_gettime(CLOCK_REALTIME,
2835321ae86SAlfred Perlstein 			    &trussinfo->after);
284c03bfcc8SMatthew N. Dodd 
2855d2d083cSXin LI 			if (trussinfo->curthread->in_fork &&
2865321ae86SAlfred Perlstein 			    (trussinfo->flags & FOLLOWFORKS)) {
287c03bfcc8SMatthew N. Dodd 				int childpid;
288c03bfcc8SMatthew N. Dodd 
2895d2d083cSXin LI 				trussinfo->curthread->in_fork = 0;
2905321ae86SAlfred Perlstein 				childpid =
2915321ae86SAlfred Perlstein 				    funcs->exit_syscall(trussinfo,
2925d2d083cSXin LI 					trussinfo->pr_data);
293c03bfcc8SMatthew N. Dodd 
294c03bfcc8SMatthew N. Dodd 				/*
2955321ae86SAlfred Perlstein 				 * Fork a new copy of ourself to trace
2965321ae86SAlfred Perlstein 				 * the child of the original traced
2975321ae86SAlfred Perlstein 				 * process.
298c03bfcc8SMatthew N. Dodd 				 */
299c03bfcc8SMatthew N. Dodd 				if (fork() == 0) {
300c03bfcc8SMatthew N. Dodd 					trussinfo->pid = childpid;
3015d2d083cSXin LI 					start_tracing(trussinfo->pid);
302c03bfcc8SMatthew N. Dodd 					goto START_TRACE;
303c03bfcc8SMatthew N. Dodd 				}
304c03bfcc8SMatthew N. Dodd 				break;
305c03bfcc8SMatthew N. Dodd 			}
3065d2d083cSXin LI 			funcs->exit_syscall(trussinfo, MAXARGS);
307bbeaf6c0SSean Eric Fagan 			break;
308bbeaf6c0SSean Eric Fagan 		case S_SIG:
3095d2d083cSXin LI 			if (trussinfo->flags & NOSIGS)
3105d2d083cSXin LI 				break;
311081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
312081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
313081e5c48SPav Lucistnik 				    trussinfo->pid);
314081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
315081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
316081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
317081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
318081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
319081e5c48SPav Lucistnik 				    timediff.tv_nsec);
320081e5c48SPav Lucistnik 			}
321081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
322081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
323081e5c48SPav Lucistnik 				    &trussinfo->before, &timediff);
324081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
325081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
326081e5c48SPav Lucistnik 				    timediff.tv_nsec);
327081e5c48SPav Lucistnik 			}
3285d2d083cSXin LI 			signame = strsig(trussinfo->pr_data);
3295321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3305d2d083cSXin LI 			    "SIGNAL %u (%s)\n", trussinfo->pr_data,
331d75300bfSAlfred Perlstein 			    signame == NULL ? "?" : signame);
332d75300bfSAlfred Perlstein 			free(signame);
333bbeaf6c0SSean Eric Fagan 			break;
334bbeaf6c0SSean Eric Fagan 		case S_EXIT:
335081e5c48SPav Lucistnik 			if (trussinfo->flags & FOLLOWFORKS)
336081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%5d: ",
337081e5c48SPav Lucistnik 				    trussinfo->pid);
338081e5c48SPav Lucistnik 			if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
339081e5c48SPav Lucistnik 				timespecsubt(&trussinfo->after,
340081e5c48SPav Lucistnik 				    &trussinfo->start_time, &timediff);
341081e5c48SPav Lucistnik 				fprintf(trussinfo->outfile, "%ld.%09ld ",
342081e5c48SPav Lucistnik 				    (long)timediff.tv_sec,
343081e5c48SPav Lucistnik 				    timediff.tv_nsec);
344081e5c48SPav Lucistnik 			}
345081e5c48SPav Lucistnik 			if (trussinfo->flags & RELATIVETIMESTAMPS) {
346081e5c48SPav Lucistnik 			  timespecsubt(&trussinfo->after,
347081e5c48SPav Lucistnik 			      &trussinfo->before, &timediff);
348081e5c48SPav Lucistnik 			  fprintf(trussinfo->outfile, "%ld.%09ld ",
349081e5c48SPav Lucistnik 			    (long)timediff.tv_sec, timediff.tv_nsec);
350081e5c48SPav Lucistnik 			}
3515321ae86SAlfred Perlstein 			fprintf(trussinfo->outfile,
3525d2d083cSXin LI 			    "process exit, rval = %u\n", trussinfo->pr_data);
353bbeaf6c0SSean Eric Fagan 			break;
354bbeaf6c0SSean Eric Fagan 		default:
355bbeaf6c0SSean Eric Fagan 			break;
356bbeaf6c0SSean Eric Fagan 		}
3575d2d083cSXin LI 	} while (trussinfo->pr_why != S_EXIT);
358ec0bed25SMatthew N. Dodd 	fflush(trussinfo->outfile);
3595d2d083cSXin LI 
3605321ae86SAlfred Perlstein 	return (0);
361bbeaf6c0SSean Eric Fagan }
362