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