main.c revision 288832
1191005Sdelphij/*-
2204977Simp * Copyright 1997 Sean Eric Fagan
331899Ssef *
431899Ssef * Redistribution and use in source and binary forms, with or without
531899Ssef * modification, are permitted provided that the following conditions
631899Ssef * are met:
731899Ssef * 1. Redistributions of source code must retain the above copyright
831899Ssef *    notice, this list of conditions and the following disclaimer.
931899Ssef * 2. Redistributions in binary form must reproduce the above copyright
1031899Ssef *    notice, this list of conditions and the following disclaimer in the
1131899Ssef *    documentation and/or other materials provided with the distribution.
1231899Ssef * 3. All advertising materials mentioning features or use of this software
1331899Ssef *    must display the following acknowledgement:
1431899Ssef *	This product includes software developed by Sean Eric Fagan
1531899Ssef * 4. Neither the name of the author may be used to endorse or promote
1631899Ssef *    products derived from this software without specific prior written
1731899Ssef *    permission.
1831899Ssef *
1931899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2031899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2131899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2231899Ssef * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2331899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2431899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2531899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2631899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2731899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2831899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2931899Ssef * SUCH DAMAGE.
3031899Ssef */
3131899Ssef
32119852Scharnier#include <sys/cdefs.h>
33119852Scharnier__FBSDID("$FreeBSD: head/usr.bin/truss/main.c 288832 2015-10-05 18:08:35Z bdrewery $");
3432275Scharnier
3531899Ssef/*
36222103Sbcr * The main module for truss.  Surprisingly simple, but, then, the other
3731567Ssef * files handle the bulk of the work.  And, of course, the kernel has to
3831567Ssef * do a lot of the work :).
3931567Ssef */
4031567Ssef
41288424Sjhb#include <sys/ptrace.h>
4285301Sdes
4332275Scharnier#include <err.h>
4432275Scharnier#include <signal.h>
4531567Ssef#include <stdio.h>
4631567Ssef#include <stdlib.h>
47101423Smdodd#include <time.h>
4831579Speter#include <unistd.h>
4931567Ssef
50101282Smdodd#include "truss.h"
5187703Smarkm#include "extern.h"
52192025Sdds#include "syscall.h"
5331567Ssef
54144177Salfredstatic void
5532275Scharnierusage(void)
5632275Scharnier{
57144177Salfred	fprintf(stderr, "%s\n%s\n",
58192025Sdds	    "usage: truss [-cfaedDS] [-o file] [-s strsize] -p pid",
59192025Sdds	    "       truss [-cfaedDS] [-o file] [-s strsize] command [args]");
60144177Salfred	exit(1);
6131567Ssef}
6231567Ssef
63132306Salfredchar *
64132306Salfredstrsig(int sig)
65132306Salfred{
66286913Sjhb	static char tmp[64];
67132306Salfred
68132306Salfred	if (sig > 0 && sig < NSIG) {
69286913Sjhb		snprintf(tmp, sizeof(tmp), "SIG%s", sys_signame[sig]);
70286913Sjhb		return (tmp);
71132306Salfred	}
72286913Sjhb	return (NULL);
73132306Salfred}
74132306Salfred
7532275Scharnierint
76144177Salfredmain(int ac, char **av)
77144177Salfred{
78240393Szont	struct sigaction sa;
79240005Szont	struct trussinfo *trussinfo;
80144178Salfred	char *fname;
81240005Szont	char **command;
82288424Sjhb	pid_t pid;
83288424Sjhb	int c;
8431567Ssef
85144178Salfred	fname = NULL;
86144178Salfred
87144177Salfred	/* Initialize the trussinfo struct */
88192153Sdelphij	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
89144177Salfred	if (trussinfo == NULL)
90192153Sdelphij		errx(1, "calloc() failed");
91192153Sdelphij
92288424Sjhb	pid = 0;
93144177Salfred	trussinfo->outfile = stderr;
94153963Sbrian	trussinfo->strsize = 32;
95168569Sdelphij	trussinfo->curthread = NULL;
96288424Sjhb	LIST_INIT(&trussinfo->proclist);
97288832Sbdrewery	init_syscalls();
98192025Sdds	while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
99144177Salfred		switch (c) {
100144177Salfred		case 'p':	/* specified pid */
101288424Sjhb			pid = atoi(optarg);
102171055Sdelphij			/* make sure i don't trace me */
103288424Sjhb			if (pid == getpid()) {
104288424Sjhb				errx(2, "attempt to grab self.");
105171055Sdelphij			}
106144177Salfred			break;
107144177Salfred		case 'f': /* Follow fork()'s */
108144177Salfred			trussinfo->flags |= FOLLOWFORKS;
109144177Salfred			break;
110144177Salfred		case 'a': /* Print execve() argument strings. */
111144177Salfred			trussinfo->flags |= EXECVEARGS;
112144177Salfred			break;
113192025Sdds		case 'c': /* Count number of system calls and time. */
114192025Sdds			trussinfo->flags |= COUNTONLY;
115192025Sdds			break;
116144177Salfred		case 'e': /* Print execve() environment strings. */
117144177Salfred			trussinfo->flags |= EXECVEENVS;
118144177Salfred			break;
119144177Salfred		case 'd': /* Absolute timestamps */
120144177Salfred			trussinfo->flags |= ABSOLUTETIMESTAMPS;
121144177Salfred			break;
122144177Salfred		case 'D': /* Relative timestamps */
123144177Salfred			trussinfo->flags |= RELATIVETIMESTAMPS;
124144177Salfred			break;
125144177Salfred		case 'o':	/* Specified output file */
126144177Salfred			fname = optarg;
127144177Salfred			break;
128153963Sbrian		case 's':	/* Specified string size */
129153963Sbrian			trussinfo->strsize = atoi(optarg);
130153963Sbrian			break;
131240005Szont		case 'S':	/* Don't trace signals */
132144177Salfred			trussinfo->flags |= NOSIGS;
133144177Salfred			break;
134144177Salfred		default:
135144177Salfred			usage();
136144177Salfred		}
137144177Salfred	}
13831567Ssef
139144177Salfred	ac -= optind; av += optind;
140288424Sjhb	if ((pid == 0 && ac == 0) ||
141288424Sjhb	    (pid != 0 && ac != 0))
142144177Salfred		usage();
14331567Ssef
144144177Salfred	if (fname != NULL) { /* Use output file */
145215235Sjh		/*
146245957Smjg		 * Set close-on-exec ('e'), so that the output file is not
147245957Smjg		 * shared with the traced process.
148215235Sjh		 */
149245957Smjg		if ((trussinfo->outfile = fopen(fname, "we")) == NULL)
150245957Smjg			err(1, "cannot open %s", fname);
151144177Salfred	}
15232275Scharnier
153144177Salfred	/*
154144177Salfred	 * If truss starts the process itself, it will ignore some signals --
155144177Salfred	 * they should be passed off to the process, which may or may not
156144177Salfred	 * exit.  If, however, we are examining an already-running process,
157144177Salfred	 * then we restore the event mask on these same signals.
158144177Salfred	 */
159288424Sjhb	if (pid == 0) {
160288424Sjhb		/* Start a command ourselves */
161144177Salfred		command = av;
162288424Sjhb		setup_and_wait(trussinfo, command);
163144177Salfred		signal(SIGINT, SIG_IGN);
164144177Salfred		signal(SIGTERM, SIG_IGN);
165144177Salfred		signal(SIGQUIT, SIG_IGN);
166144177Salfred	} else {
167240393Szont		sa.sa_handler = restore_proc;
168240393Szont		sa.sa_flags = 0;
169240393Szont		sigemptyset(&sa.sa_mask);
170240393Szont		sigaction(SIGINT, &sa, NULL);
171240393Szont		sigaction(SIGQUIT, &sa, NULL);
172240393Szont		sigaction(SIGTERM, &sa, NULL);
173288424Sjhb		start_tracing(trussinfo, pid);
174144177Salfred	}
17531567Ssef
176144177Salfred	/*
177144177Salfred	 * At this point, if we started the process, it is stopped waiting to
178144177Salfred	 * be woken up, either in exit() or in execve().
179144177Salfred	 */
180288424Sjhb	if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) {
181288424Sjhb		/*
182288424Sjhb		 * If we are not able to handle this ABI, detach from the
183288424Sjhb		 * process and exit.  If we just created a new process to
184288424Sjhb		 * run a command, kill the new process rather than letting
185288424Sjhb		 * it run untraced.
186288424Sjhb		 */
187288424Sjhb		if (pid == 0)
188288424Sjhb			kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL);
189288424Sjhb		ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL,
190288424Sjhb		    0);
191288424Sjhb		return (1);
192288424Sjhb	}
193288424Sjhb	ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1,
194288424Sjhb	    0);
19531567Ssef
196144177Salfred	/*
197144177Salfred	 * At this point, it's a simple loop, waiting for the process to
198144177Salfred	 * stop, finding out why, printing out why, and then continuing it.
199144177Salfred	 * All of the grunt work is done in the support routines.
200144177Salfred	 */
201144177Salfred	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
202101285Smdodd
203288424Sjhb	eventloop(trussinfo);
20431567Ssef
205240005Szont	if (trussinfo->flags & COUNTONLY)
206240005Szont		print_summary(trussinfo);
207192025Sdds
208192025Sdds	fflush(trussinfo->outfile);
209192025Sdds
210144177Salfred	return (0);
21131567Ssef}
212