xref: /freebsd/usr.bin/truss/main.c (revision 3cf51049e025bef7764383535ba0b8094232a587)
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 
323cf51049SPhilippe Charnier #ifndef lint
333cf51049SPhilippe Charnier static const char rcsid[] =
343cf51049SPhilippe Charnier 	"$Id$";
353cf51049SPhilippe Charnier #endif /* not lint */
363cf51049SPhilippe Charnier 
3709d64da3SSean Eric Fagan /*
38bbeaf6c0SSean Eric Fagan  * The main module for truss.  Suprisingly simple, but, then, the other
39bbeaf6c0SSean Eric Fagan  * files handle the bulk of the work.  And, of course, the kernel has to
40bbeaf6c0SSean Eric Fagan  * do a lot of the work :).
41bbeaf6c0SSean Eric Fagan  */
42bbeaf6c0SSean Eric Fagan 
433cf51049SPhilippe Charnier #include <err.h>
443cf51049SPhilippe Charnier #include <errno.h>
453cf51049SPhilippe Charnier #include <fcntl.h>
463cf51049SPhilippe Charnier #include <signal.h>
47bbeaf6c0SSean Eric Fagan #include <stdio.h>
48bbeaf6c0SSean Eric Fagan #include <stdlib.h>
49bbeaf6c0SSean Eric Fagan #include <string.h>
5095c4ef65SPeter Wemm #include <unistd.h>
51bbeaf6c0SSean Eric Fagan #include <sys/ioctl.h>
52bbeaf6c0SSean Eric Fagan #include <sys/pioctl.h>
53bbeaf6c0SSean Eric Fagan 
54bbeaf6c0SSean Eric Fagan extern int setup_and_wait(char **);
55bbeaf6c0SSean Eric Fagan extern int start_tracing(int, int);
56bbeaf6c0SSean Eric Fagan extern void i386_syscall_entry(int, int);
57bbeaf6c0SSean Eric Fagan extern void i386_syscall_exit(int, int);
58bbeaf6c0SSean Eric Fagan extern void i386_linux_syscall_entry(int, int);
59bbeaf6c0SSean Eric Fagan extern void i386_linux_syscall_exit(int, int);
60bbeaf6c0SSean Eric Fagan 
61bbeaf6c0SSean Eric Fagan /*
62bbeaf6c0SSean Eric Fagan  * These should really be parameterized -- I don't like having globals,
63bbeaf6c0SSean Eric Fagan  * but this is the easiest way, right now, to deal with them.
64bbeaf6c0SSean Eric Fagan  */
65bbeaf6c0SSean Eric Fagan 
66bbeaf6c0SSean Eric Fagan int pid = 0;
67bbeaf6c0SSean Eric Fagan int nosigs = 0;
68bbeaf6c0SSean Eric Fagan FILE *outfile = stderr;
69bbeaf6c0SSean Eric Fagan int Procfd;
70bbeaf6c0SSean Eric Fagan char progtype[50];	/* OS and type of executable */
71bbeaf6c0SSean Eric Fagan 
72bbeaf6c0SSean Eric Fagan static inline void
733cf51049SPhilippe Charnier usage(void)
743cf51049SPhilippe Charnier {
753cf51049SPhilippe Charnier   fprintf(stderr, "%s\n%s\n",
763cf51049SPhilippe Charnier 	"usage: truss [-S] [-o file] -p pid",
773cf51049SPhilippe Charnier 	"       truss [-S] [-o file] command [args]");
78bbeaf6c0SSean Eric Fagan   exit(1);
79bbeaf6c0SSean Eric Fagan }
80bbeaf6c0SSean Eric Fagan 
81bbeaf6c0SSean Eric Fagan struct ex_types {
82bbeaf6c0SSean Eric Fagan   char *type;
83bbeaf6c0SSean Eric Fagan   void (*enter_syscall)(int, int);
84bbeaf6c0SSean Eric Fagan   void (*exit_syscall)(int, int);
85bbeaf6c0SSean Eric Fagan } ex_types[] = {
86bbeaf6c0SSean Eric Fagan   { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },
8787893934SPeter Wemm   { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit },
88bbeaf6c0SSean Eric Fagan   { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit },
89bbeaf6c0SSean Eric Fagan   { 0, 0, 0 },
90bbeaf6c0SSean Eric Fagan };
91bbeaf6c0SSean Eric Fagan 
92bbeaf6c0SSean Eric Fagan /*
93bbeaf6c0SSean Eric Fagan  * Set the execution type.  This is called after every exec, and when
94bbeaf6c0SSean Eric Fagan  * a process is first monitored.  The procfs pseudo-file "etype" has
95bbeaf6c0SSean Eric Fagan  * the execution module type -- see /proc/curproc/etype for an example.
96bbeaf6c0SSean Eric Fagan  */
97bbeaf6c0SSean Eric Fagan 
98bbeaf6c0SSean Eric Fagan static struct ex_types *
99bbeaf6c0SSean Eric Fagan set_etype() {
100bbeaf6c0SSean Eric Fagan   struct ex_types *funcs;
101bbeaf6c0SSean Eric Fagan   char etype[24];
102bbeaf6c0SSean Eric Fagan   char progtype[32];
103bbeaf6c0SSean Eric Fagan   int fd;
104bbeaf6c0SSean Eric Fagan 
105bbeaf6c0SSean Eric Fagan   sprintf(etype, "/proc/%d/etype", pid);
106bbeaf6c0SSean Eric Fagan   if ((fd = open(etype, O_RDONLY)) == -1) {
107bbeaf6c0SSean Eric Fagan     strcpy(progtype, "FreeBSD a.out");
108bbeaf6c0SSean Eric Fagan   } else {
109bbeaf6c0SSean Eric Fagan     int len = read(fd, progtype, sizeof(progtype));
110bbeaf6c0SSean Eric Fagan     progtype[len-1] = '\0';
11187893934SPeter Wemm     close(fd);
112bbeaf6c0SSean Eric Fagan   }
113bbeaf6c0SSean Eric Fagan 
114bbeaf6c0SSean Eric Fagan   for (funcs = ex_types; funcs->type; funcs++)
115bbeaf6c0SSean Eric Fagan     if (!strcmp(funcs->type, progtype))
116bbeaf6c0SSean Eric Fagan       break;
117bbeaf6c0SSean Eric Fagan 
118bbeaf6c0SSean Eric Fagan   return funcs;
119bbeaf6c0SSean Eric Fagan }
120bbeaf6c0SSean Eric Fagan 
1213cf51049SPhilippe Charnier int
122bbeaf6c0SSean Eric Fagan main(int ac, char **av) {
123bbeaf6c0SSean Eric Fagan   int c;
124bbeaf6c0SSean Eric Fagan   int i;
125bbeaf6c0SSean Eric Fagan   char **command;
126bbeaf6c0SSean Eric Fagan   struct procfs_status pfs;
127bbeaf6c0SSean Eric Fagan   struct ex_types *funcs;
128bbeaf6c0SSean Eric Fagan   int in_exec = 0;
1293cf51049SPhilippe Charnier   char *fname = NULL;
130bbeaf6c0SSean Eric Fagan 
131bbeaf6c0SSean Eric Fagan   while ((c = getopt(ac, av, "p:o:S")) != EOF) {
132bbeaf6c0SSean Eric Fagan     switch (c) {
133bbeaf6c0SSean Eric Fagan     case 'p':	/* specified pid */
134bbeaf6c0SSean Eric Fagan       pid = atoi(optarg);
135bbeaf6c0SSean Eric Fagan       break;
136bbeaf6c0SSean Eric Fagan     case 'o':	/* Specified output file */
1373cf51049SPhilippe Charnier       fname = optarg;
138bbeaf6c0SSean Eric Fagan       break;
139bbeaf6c0SSean Eric Fagan     case 'S':	/* Don't trace signals */
140bbeaf6c0SSean Eric Fagan       nosigs = 1;
141bbeaf6c0SSean Eric Fagan       break;
142bbeaf6c0SSean Eric Fagan     default:
143bbeaf6c0SSean Eric Fagan       usage();
144bbeaf6c0SSean Eric Fagan     }
145bbeaf6c0SSean Eric Fagan   }
146bbeaf6c0SSean Eric Fagan 
147bbeaf6c0SSean Eric Fagan   ac -= optind; av += optind;
148ad9e0260SSean Eric Fagan   if ((pid == 0 && ac == 0) || (pid != 0 && ac != 0))
149bbeaf6c0SSean Eric Fagan     usage();
150bbeaf6c0SSean Eric Fagan 
1513cf51049SPhilippe Charnier   if (fname != NULL) { /* Use output file */
1523cf51049SPhilippe Charnier     if ((outfile = fopen(fname, "w")) == NULL)
1533cf51049SPhilippe Charnier       errx(1, "cannot open %s", fname);
1543cf51049SPhilippe Charnier   }
1553cf51049SPhilippe Charnier 
156bbeaf6c0SSean Eric Fagan   /*
157bbeaf6c0SSean Eric Fagan    * If truss starts the process itself, it will ignore some signals --
158bbeaf6c0SSean Eric Fagan    * they should be passed off to the process, which may or may not
159bbeaf6c0SSean Eric Fagan    * exit.  If, however, we are examining an already-running process,
160bbeaf6c0SSean Eric Fagan    * then we restore the event mask on these same signals.
161bbeaf6c0SSean Eric Fagan    */
162bbeaf6c0SSean Eric Fagan 
163bbeaf6c0SSean Eric Fagan   if (pid == 0) {	/* Start a command ourselves */
164bbeaf6c0SSean Eric Fagan     command = av;
165bbeaf6c0SSean Eric Fagan     pid = setup_and_wait(command);
166bbeaf6c0SSean Eric Fagan     signal(SIGINT, SIG_IGN);
167bbeaf6c0SSean Eric Fagan     signal(SIGTERM, SIG_IGN);
168bbeaf6c0SSean Eric Fagan     signal(SIGQUIT, SIG_IGN);
169bbeaf6c0SSean Eric Fagan   } else {
170bbeaf6c0SSean Eric Fagan     extern void restore_proc(int);
171bbeaf6c0SSean Eric Fagan     signal(SIGINT, restore_proc);
172bbeaf6c0SSean Eric Fagan     signal(SIGTERM, restore_proc);
173bbeaf6c0SSean Eric Fagan     signal(SIGQUIT, restore_proc);
174bbeaf6c0SSean Eric Fagan   }
175bbeaf6c0SSean Eric Fagan 
176bbeaf6c0SSean Eric Fagan 
177bbeaf6c0SSean Eric Fagan   /*
178bbeaf6c0SSean Eric Fagan    * At this point, if we started the process, it is stopped waiting to
179bbeaf6c0SSean Eric Fagan    * be woken up, either in exit() or in execve().
180bbeaf6c0SSean Eric Fagan    */
181bbeaf6c0SSean Eric Fagan 
182bbeaf6c0SSean Eric Fagan   Procfd = start_tracing(pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT |
183bbeaf6c0SSean Eric Fagan 		     (nosigs ? 0 : S_SIG));
184bbeaf6c0SSean Eric Fagan   pfs.why = 0;
185bbeaf6c0SSean Eric Fagan 
186bbeaf6c0SSean Eric Fagan   funcs = set_etype();
187bbeaf6c0SSean Eric Fagan   /*
188bbeaf6c0SSean Eric Fagan    * At this point, it's a simple loop, waiting for the process to
189bbeaf6c0SSean Eric Fagan    * stop, finding out why, printing out why, and then continuing it.
190bbeaf6c0SSean Eric Fagan    * All of the grunt work is done in the support routines.
191bbeaf6c0SSean Eric Fagan    */
192bbeaf6c0SSean Eric Fagan 
193bbeaf6c0SSean Eric Fagan   do {
194bbeaf6c0SSean Eric Fagan     int val = 0;
195bbeaf6c0SSean Eric Fagan 
196bbeaf6c0SSean Eric Fagan     if (ioctl(Procfd, PIOCWAIT, &pfs) == -1)
1973cf51049SPhilippe Charnier       warn("PIOCWAIT top of loop");
198bbeaf6c0SSean Eric Fagan     else {
199bbeaf6c0SSean Eric Fagan       switch(i = pfs.why) {
200bbeaf6c0SSean Eric Fagan       case S_SCE:
201bbeaf6c0SSean Eric Fagan 	funcs->enter_syscall(pid, pfs.val);
202bbeaf6c0SSean Eric Fagan 	break;
203bbeaf6c0SSean Eric Fagan       case S_SCX:
204bbeaf6c0SSean Eric Fagan 	/*
205bbeaf6c0SSean Eric Fagan 	 * This is so we don't get two messages for an exec -- one
206bbeaf6c0SSean Eric Fagan 	 * for the S_EXEC, and one for the syscall exit.  It also,
207bbeaf6c0SSean Eric Fagan 	 * conveniently, ensures that the first message printed out
208bbeaf6c0SSean Eric Fagan 	 * isn't the return-from-syscall used to create the process.
209bbeaf6c0SSean Eric Fagan 	 */
210bbeaf6c0SSean Eric Fagan 
211bbeaf6c0SSean Eric Fagan 	if (in_exec) {
212bbeaf6c0SSean Eric Fagan 	  in_exec = 0;
213bbeaf6c0SSean Eric Fagan 	  break;
214bbeaf6c0SSean Eric Fagan 	}
215bbeaf6c0SSean Eric Fagan 	funcs->exit_syscall(pid, pfs.val);
216bbeaf6c0SSean Eric Fagan 	break;
217bbeaf6c0SSean Eric Fagan       case S_SIG:
218bbeaf6c0SSean Eric Fagan 	fprintf(outfile, "SIGNAL %d\n", pfs.val);
219bbeaf6c0SSean Eric Fagan 	break;
220bbeaf6c0SSean Eric Fagan       case S_EXIT:
221bbeaf6c0SSean Eric Fagan 	fprintf (outfile, "process exit, rval = %d\n", pfs.val);
222bbeaf6c0SSean Eric Fagan 	break;
223bbeaf6c0SSean Eric Fagan       case S_EXEC:
224bbeaf6c0SSean Eric Fagan 	funcs = set_etype();
225bbeaf6c0SSean Eric Fagan 	in_exec = 1;
226bbeaf6c0SSean Eric Fagan 	break;
227bbeaf6c0SSean Eric Fagan       default:
228bbeaf6c0SSean Eric Fagan 	fprintf (outfile, "Process stopped because of:  %d\n", i);
229bbeaf6c0SSean Eric Fagan 	break;
230bbeaf6c0SSean Eric Fagan       }
231bbeaf6c0SSean Eric Fagan     }
232d7b7dcbaSSean Eric Fagan     if (ioctl(Procfd, PIOCCONT, val) == -1)
2333cf51049SPhilippe Charnier       warn("PIOCCONT");
234bbeaf6c0SSean Eric Fagan   } while (pfs.why != S_EXIT);
235bbeaf6c0SSean Eric Fagan   return 0;
236bbeaf6c0SSean Eric Fagan }
237