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: stable/11/usr.bin/truss/main.c 342708 2019-01-02 20:49:41Z jhb $");
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>
45311999Sjhb#include <stdbool.h>
4631567Ssef#include <stdio.h>
4731567Ssef#include <stdlib.h>
48294849Sjhb#include <sysdecode.h>
49101423Smdodd#include <time.h>
5031579Speter#include <unistd.h>
5131567Ssef
52101282Smdodd#include "truss.h"
5387703Smarkm#include "extern.h"
54192025Sdds#include "syscall.h"
5531567Ssef
56144177Salfredstatic void
5732275Scharnierusage(void)
5832275Scharnier{
59144177Salfred	fprintf(stderr, "%s\n%s\n",
60324777Semaste	    "usage: truss [-cfaedDHS] [-o file] [-s strsize] -p pid",
61324777Semaste	    "       truss [-cfaedDHS] [-o file] [-s strsize] command [args]");
62144177Salfred	exit(1);
6331567Ssef}
6431567Ssef
6532275Scharnierint
66144177Salfredmain(int ac, char **av)
67144177Salfred{
68240393Szont	struct sigaction sa;
69240005Szont	struct trussinfo *trussinfo;
70144178Salfred	char *fname;
71240005Szont	char **command;
72342708Sjhb	const char *errstr;
73288424Sjhb	pid_t pid;
74288424Sjhb	int c;
7531567Ssef
76144178Salfred	fname = NULL;
77144178Salfred
78144177Salfred	/* Initialize the trussinfo struct */
79192153Sdelphij	trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
80144177Salfred	if (trussinfo == NULL)
81192153Sdelphij		errx(1, "calloc() failed");
82192153Sdelphij
83288424Sjhb	pid = 0;
84144177Salfred	trussinfo->outfile = stderr;
85153963Sbrian	trussinfo->strsize = 32;
86168569Sdelphij	trussinfo->curthread = NULL;
87288424Sjhb	LIST_INIT(&trussinfo->proclist);
88288832Sbdrewery	init_syscalls();
89295930Sjhb	while ((c = getopt(ac, av, "p:o:facedDs:SH")) != -1) {
90144177Salfred		switch (c) {
91144177Salfred		case 'p':	/* specified pid */
92288424Sjhb			pid = atoi(optarg);
93171055Sdelphij			/* make sure i don't trace me */
94288424Sjhb			if (pid == getpid()) {
95288424Sjhb				errx(2, "attempt to grab self.");
96171055Sdelphij			}
97144177Salfred			break;
98144177Salfred		case 'f': /* Follow fork()'s */
99144177Salfred			trussinfo->flags |= FOLLOWFORKS;
100144177Salfred			break;
101144177Salfred		case 'a': /* Print execve() argument strings. */
102144177Salfred			trussinfo->flags |= EXECVEARGS;
103144177Salfred			break;
104192025Sdds		case 'c': /* Count number of system calls and time. */
105289080Sbdrewery			trussinfo->flags |= (COUNTONLY | NOSIGS);
106192025Sdds			break;
107144177Salfred		case 'e': /* Print execve() environment strings. */
108144177Salfred			trussinfo->flags |= EXECVEENVS;
109144177Salfred			break;
110144177Salfred		case 'd': /* Absolute timestamps */
111144177Salfred			trussinfo->flags |= ABSOLUTETIMESTAMPS;
112144177Salfred			break;
113144177Salfred		case 'D': /* Relative timestamps */
114144177Salfred			trussinfo->flags |= RELATIVETIMESTAMPS;
115144177Salfred			break;
116144177Salfred		case 'o':	/* Specified output file */
117144177Salfred			fname = optarg;
118144177Salfred			break;
119153963Sbrian		case 's':	/* Specified string size */
120342708Sjhb			trussinfo->strsize = strtonum(optarg, 0, INT_MAX, &errstr);
121342708Sjhb			if (errstr)
122342708Sjhb				errx(1, "maximum string size is %s: %s", errstr, optarg);
123153963Sbrian			break;
124240005Szont		case 'S':	/* Don't trace signals */
125144177Salfred			trussinfo->flags |= NOSIGS;
126144177Salfred			break;
127295930Sjhb		case 'H':
128295930Sjhb			trussinfo->flags |= DISPLAYTIDS;
129295930Sjhb			break;
130144177Salfred		default:
131144177Salfred			usage();
132144177Salfred		}
133144177Salfred	}
13431567Ssef
135144177Salfred	ac -= optind; av += optind;
136288424Sjhb	if ((pid == 0 && ac == 0) ||
137288424Sjhb	    (pid != 0 && ac != 0))
138144177Salfred		usage();
13931567Ssef
140144177Salfred	if (fname != NULL) { /* Use output file */
141215235Sjh		/*
142245957Smjg		 * Set close-on-exec ('e'), so that the output file is not
143245957Smjg		 * shared with the traced process.
144215235Sjh		 */
145245957Smjg		if ((trussinfo->outfile = fopen(fname, "we")) == NULL)
146245957Smjg			err(1, "cannot open %s", fname);
147144177Salfred	}
14832275Scharnier
149144177Salfred	/*
150144177Salfred	 * If truss starts the process itself, it will ignore some signals --
151144177Salfred	 * they should be passed off to the process, which may or may not
152144177Salfred	 * exit.  If, however, we are examining an already-running process,
153144177Salfred	 * then we restore the event mask on these same signals.
154144177Salfred	 */
155288424Sjhb	if (pid == 0) {
156288424Sjhb		/* Start a command ourselves */
157144177Salfred		command = av;
158288424Sjhb		setup_and_wait(trussinfo, command);
159144177Salfred		signal(SIGINT, SIG_IGN);
160144177Salfred		signal(SIGTERM, SIG_IGN);
161144177Salfred		signal(SIGQUIT, SIG_IGN);
162144177Salfred	} else {
163240393Szont		sa.sa_handler = restore_proc;
164240393Szont		sa.sa_flags = 0;
165240393Szont		sigemptyset(&sa.sa_mask);
166240393Szont		sigaction(SIGINT, &sa, NULL);
167240393Szont		sigaction(SIGQUIT, &sa, NULL);
168240393Szont		sigaction(SIGTERM, &sa, NULL);
169288424Sjhb		start_tracing(trussinfo, pid);
170144177Salfred	}
17131567Ssef
172144177Salfred	/*
173144177Salfred	 * At this point, if we started the process, it is stopped waiting to
174144177Salfred	 * be woken up, either in exit() or in execve().
175144177Salfred	 */
176288424Sjhb	if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) {
177288424Sjhb		/*
178288424Sjhb		 * If we are not able to handle this ABI, detach from the
179288424Sjhb		 * process and exit.  If we just created a new process to
180288424Sjhb		 * run a command, kill the new process rather than letting
181288424Sjhb		 * it run untraced.
182288424Sjhb		 */
183288424Sjhb		if (pid == 0)
184288424Sjhb			kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL);
185288424Sjhb		ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL,
186288424Sjhb		    0);
187288424Sjhb		return (1);
188288424Sjhb	}
189288424Sjhb	ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1,
190288424Sjhb	    0);
19131567Ssef
192144177Salfred	/*
193144177Salfred	 * At this point, it's a simple loop, waiting for the process to
194144177Salfred	 * stop, finding out why, printing out why, and then continuing it.
195144177Salfred	 * All of the grunt work is done in the support routines.
196144177Salfred	 */
197144177Salfred	clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
198101285Smdodd
199288424Sjhb	eventloop(trussinfo);
20031567Ssef
201240005Szont	if (trussinfo->flags & COUNTONLY)
202240005Szont		print_summary(trussinfo);
203192025Sdds
204192025Sdds	fflush(trussinfo->outfile);
205192025Sdds
206144177Salfred	return (0);
20731567Ssef}
208