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[] = 34c3aac50fSPeter Wemm "$FreeBSD$"; 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 43580e0a2bSDag-Erling Smørgrav #include <sys/param.h> 44580e0a2bSDag-Erling Smørgrav #include <sys/ioctl.h> 45580e0a2bSDag-Erling Smørgrav #include <sys/pioctl.h> 46580e0a2bSDag-Erling Smørgrav 473cf51049SPhilippe Charnier #include <err.h> 483cf51049SPhilippe Charnier #include <errno.h> 493cf51049SPhilippe Charnier #include <fcntl.h> 503cf51049SPhilippe Charnier #include <signal.h> 51bbeaf6c0SSean Eric Fagan #include <stdio.h> 52bbeaf6c0SSean Eric Fagan #include <stdlib.h> 53bbeaf6c0SSean Eric Fagan #include <string.h> 5495c4ef65SPeter Wemm #include <unistd.h> 55bbeaf6c0SSean Eric Fagan 561be5d704SMark Murray #include "extern.h" 57bbeaf6c0SSean Eric Fagan 58bbeaf6c0SSean Eric Fagan /* 59bbeaf6c0SSean Eric Fagan * These should really be parameterized -- I don't like having globals, 60bbeaf6c0SSean Eric Fagan * but this is the easiest way, right now, to deal with them. 61bbeaf6c0SSean Eric Fagan */ 62bbeaf6c0SSean Eric Fagan 63bbeaf6c0SSean Eric Fagan int pid = 0; 64bbeaf6c0SSean Eric Fagan int nosigs = 0; 659a2e7f15SPeter Wemm FILE *outfile; 66bbeaf6c0SSean Eric Fagan int Procfd; 67bbeaf6c0SSean Eric Fagan 68bbeaf6c0SSean Eric Fagan static inline void 693cf51049SPhilippe Charnier usage(void) 703cf51049SPhilippe Charnier { 713cf51049SPhilippe Charnier fprintf(stderr, "%s\n%s\n", 723cf51049SPhilippe Charnier "usage: truss [-S] [-o file] -p pid", 733cf51049SPhilippe Charnier " truss [-S] [-o file] command [args]"); 74bbeaf6c0SSean Eric Fagan exit(1); 75bbeaf6c0SSean Eric Fagan } 76bbeaf6c0SSean Eric Fagan 773625b514SSean Eric Fagan /* 783625b514SSean Eric Fagan * WARNING! "FreeBSD a.out" must be first, or set_etype will not 793625b514SSean Eric Fagan * work correctly. 803625b514SSean Eric Fagan */ 81bbeaf6c0SSean Eric Fagan struct ex_types { 821be5d704SMark Murray const char *type; 83bbeaf6c0SSean Eric Fagan void (*enter_syscall)(int, int); 84bbeaf6c0SSean Eric Fagan void (*exit_syscall)(int, int); 85bbeaf6c0SSean Eric Fagan } ex_types[] = { 8650cc4492SSean Eric Fagan #ifdef __alpha__ 8750cc4492SSean Eric Fagan { "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit }, 8850cc4492SSean Eric Fagan #endif 8950cc4492SSean Eric Fagan #ifdef __i386__ 90bbeaf6c0SSean Eric Fagan { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit }, 9187893934SPeter Wemm { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit }, 92bbeaf6c0SSean Eric Fagan { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit }, 9350cc4492SSean Eric Fagan #endif 94bbeaf6c0SSean Eric Fagan { 0, 0, 0 }, 95bbeaf6c0SSean Eric Fagan }; 96bbeaf6c0SSean Eric Fagan 97bbeaf6c0SSean Eric Fagan /* 98bbeaf6c0SSean Eric Fagan * Set the execution type. This is called after every exec, and when 99bbeaf6c0SSean Eric Fagan * a process is first monitored. The procfs pseudo-file "etype" has 100bbeaf6c0SSean Eric Fagan * the execution module type -- see /proc/curproc/etype for an example. 101bbeaf6c0SSean Eric Fagan */ 102bbeaf6c0SSean Eric Fagan 103bbeaf6c0SSean Eric Fagan static struct ex_types * 1041be5d704SMark Murray set_etype(void) { 105bbeaf6c0SSean Eric Fagan struct ex_types *funcs; 106bbeaf6c0SSean Eric Fagan char etype[24]; 1071be5d704SMark Murray char progt[32]; 108bbeaf6c0SSean Eric Fagan int fd; 109bbeaf6c0SSean Eric Fagan 110bbeaf6c0SSean Eric Fagan sprintf(etype, "/proc/%d/etype", pid); 111bbeaf6c0SSean Eric Fagan if ((fd = open(etype, O_RDONLY)) == -1) { 1121be5d704SMark Murray strcpy(progt, "FreeBSD a.out"); 113bbeaf6c0SSean Eric Fagan } else { 1141be5d704SMark Murray int len = read(fd, progt, sizeof(progt)); 1151be5d704SMark Murray progt[len-1] = '\0'; 11687893934SPeter Wemm close(fd); 117bbeaf6c0SSean Eric Fagan } 118bbeaf6c0SSean Eric Fagan 119bbeaf6c0SSean Eric Fagan for (funcs = ex_types; funcs->type; funcs++) 1201be5d704SMark Murray if (!strcmp(funcs->type, progt)) 121bbeaf6c0SSean Eric Fagan break; 122bbeaf6c0SSean Eric Fagan 1233625b514SSean Eric Fagan if (funcs == NULL) { 1243625b514SSean Eric Fagan warn("Execution type %s is not supported -- using FreeBSD a.out\n", 1251be5d704SMark Murray progt); 1263625b514SSean Eric Fagan funcs = &ex_types[0]; 1273625b514SSean Eric Fagan } 128bbeaf6c0SSean Eric Fagan return funcs; 129bbeaf6c0SSean Eric Fagan } 130bbeaf6c0SSean Eric Fagan 1313cf51049SPhilippe Charnier int 132bbeaf6c0SSean Eric Fagan main(int ac, char **av) { 133bbeaf6c0SSean Eric Fagan int c; 134bbeaf6c0SSean Eric Fagan int i; 135bbeaf6c0SSean Eric Fagan char **command; 136bbeaf6c0SSean Eric Fagan struct procfs_status pfs; 137bbeaf6c0SSean Eric Fagan struct ex_types *funcs; 138bbeaf6c0SSean Eric Fagan int in_exec = 0; 1393cf51049SPhilippe Charnier char *fname = NULL; 1409a4902a9SMartin Cracauer int sigexit = 0; 141bbeaf6c0SSean Eric Fagan 1429a2e7f15SPeter Wemm outfile = stdout; 143ad6af66eSJohn-Mark Gurney while ((c = getopt(ac, av, "p:o:S")) != -1) { 144bbeaf6c0SSean Eric Fagan switch (c) { 145bbeaf6c0SSean Eric Fagan case 'p': /* specified pid */ 146bbeaf6c0SSean Eric Fagan pid = atoi(optarg); 147bbeaf6c0SSean Eric Fagan break; 148bbeaf6c0SSean Eric Fagan case 'o': /* Specified output file */ 1493cf51049SPhilippe Charnier fname = optarg; 150bbeaf6c0SSean Eric Fagan break; 151bbeaf6c0SSean Eric Fagan case 'S': /* Don't trace signals */ 152bbeaf6c0SSean Eric Fagan nosigs = 1; 153bbeaf6c0SSean Eric Fagan break; 154bbeaf6c0SSean Eric Fagan default: 155bbeaf6c0SSean Eric Fagan usage(); 156bbeaf6c0SSean Eric Fagan } 157bbeaf6c0SSean Eric Fagan } 158bbeaf6c0SSean Eric Fagan 159bbeaf6c0SSean Eric Fagan ac -= optind; av += optind; 160ad9e0260SSean Eric Fagan if ((pid == 0 && ac == 0) || (pid != 0 && ac != 0)) 161bbeaf6c0SSean Eric Fagan usage(); 162bbeaf6c0SSean Eric Fagan 1633cf51049SPhilippe Charnier if (fname != NULL) { /* Use output file */ 1643cf51049SPhilippe Charnier if ((outfile = fopen(fname, "w")) == NULL) 1653cf51049SPhilippe Charnier errx(1, "cannot open %s", fname); 1663cf51049SPhilippe Charnier } 1673cf51049SPhilippe Charnier 168bbeaf6c0SSean Eric Fagan /* 169bbeaf6c0SSean Eric Fagan * If truss starts the process itself, it will ignore some signals -- 170bbeaf6c0SSean Eric Fagan * they should be passed off to the process, which may or may not 171bbeaf6c0SSean Eric Fagan * exit. If, however, we are examining an already-running process, 172bbeaf6c0SSean Eric Fagan * then we restore the event mask on these same signals. 173bbeaf6c0SSean Eric Fagan */ 174bbeaf6c0SSean Eric Fagan 175bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Start a command ourselves */ 176bbeaf6c0SSean Eric Fagan command = av; 177bbeaf6c0SSean Eric Fagan pid = setup_and_wait(command); 178bbeaf6c0SSean Eric Fagan signal(SIGINT, SIG_IGN); 179bbeaf6c0SSean Eric Fagan signal(SIGTERM, SIG_IGN); 180bbeaf6c0SSean Eric Fagan signal(SIGQUIT, SIG_IGN); 181bbeaf6c0SSean Eric Fagan } else { 182bbeaf6c0SSean Eric Fagan signal(SIGINT, restore_proc); 183bbeaf6c0SSean Eric Fagan signal(SIGTERM, restore_proc); 184bbeaf6c0SSean Eric Fagan signal(SIGQUIT, restore_proc); 185bbeaf6c0SSean Eric Fagan } 186bbeaf6c0SSean Eric Fagan 187bbeaf6c0SSean Eric Fagan 188bbeaf6c0SSean Eric Fagan /* 189bbeaf6c0SSean Eric Fagan * At this point, if we started the process, it is stopped waiting to 190bbeaf6c0SSean Eric Fagan * be woken up, either in exit() or in execve(). 191bbeaf6c0SSean Eric Fagan */ 192bbeaf6c0SSean Eric Fagan 193bbeaf6c0SSean Eric Fagan Procfd = start_tracing(pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | 194bbeaf6c0SSean Eric Fagan (nosigs ? 0 : S_SIG)); 19589361835SSean Eric Fagan if (Procfd == -1) 19689361835SSean Eric Fagan return 0; 19789361835SSean Eric Fagan 198bbeaf6c0SSean Eric Fagan pfs.why = 0; 199bbeaf6c0SSean Eric Fagan 200bbeaf6c0SSean Eric Fagan funcs = set_etype(); 201bbeaf6c0SSean Eric Fagan /* 202bbeaf6c0SSean Eric Fagan * At this point, it's a simple loop, waiting for the process to 203bbeaf6c0SSean Eric Fagan * stop, finding out why, printing out why, and then continuing it. 204bbeaf6c0SSean Eric Fagan * All of the grunt work is done in the support routines. 205bbeaf6c0SSean Eric Fagan */ 206bbeaf6c0SSean Eric Fagan 207bbeaf6c0SSean Eric Fagan do { 208bbeaf6c0SSean Eric Fagan int val = 0; 209bbeaf6c0SSean Eric Fagan 210bbeaf6c0SSean Eric Fagan if (ioctl(Procfd, PIOCWAIT, &pfs) == -1) 2113cf51049SPhilippe Charnier warn("PIOCWAIT top of loop"); 212bbeaf6c0SSean Eric Fagan else { 213bbeaf6c0SSean Eric Fagan switch(i = pfs.why) { 214bbeaf6c0SSean Eric Fagan case S_SCE: 215bbeaf6c0SSean Eric Fagan funcs->enter_syscall(pid, pfs.val); 216bbeaf6c0SSean Eric Fagan break; 217bbeaf6c0SSean Eric Fagan case S_SCX: 218bbeaf6c0SSean Eric Fagan /* 219bbeaf6c0SSean Eric Fagan * This is so we don't get two messages for an exec -- one 220bbeaf6c0SSean Eric Fagan * for the S_EXEC, and one for the syscall exit. It also, 221bbeaf6c0SSean Eric Fagan * conveniently, ensures that the first message printed out 222bbeaf6c0SSean Eric Fagan * isn't the return-from-syscall used to create the process. 223bbeaf6c0SSean Eric Fagan */ 224bbeaf6c0SSean Eric Fagan 225bbeaf6c0SSean Eric Fagan if (in_exec) { 226bbeaf6c0SSean Eric Fagan in_exec = 0; 227bbeaf6c0SSean Eric Fagan break; 228bbeaf6c0SSean Eric Fagan } 229bbeaf6c0SSean Eric Fagan funcs->exit_syscall(pid, pfs.val); 230bbeaf6c0SSean Eric Fagan break; 231bbeaf6c0SSean Eric Fagan case S_SIG: 23222694ebaSBruce Evans fprintf(outfile, "SIGNAL %lu\n", pfs.val); 2339a4902a9SMartin Cracauer sigexit = pfs.val; 234bbeaf6c0SSean Eric Fagan break; 235bbeaf6c0SSean Eric Fagan case S_EXIT: 23622694ebaSBruce Evans fprintf (outfile, "process exit, rval = %lu\n", pfs.val); 237bbeaf6c0SSean Eric Fagan break; 238bbeaf6c0SSean Eric Fagan case S_EXEC: 239bbeaf6c0SSean Eric Fagan funcs = set_etype(); 240bbeaf6c0SSean Eric Fagan in_exec = 1; 241bbeaf6c0SSean Eric Fagan break; 242bbeaf6c0SSean Eric Fagan default: 243bbeaf6c0SSean Eric Fagan fprintf (outfile, "Process stopped because of: %d\n", i); 244bbeaf6c0SSean Eric Fagan break; 245bbeaf6c0SSean Eric Fagan } 246bbeaf6c0SSean Eric Fagan } 24789361835SSean Eric Fagan if (ioctl(Procfd, PIOCCONT, val) == -1) { 24889361835SSean Eric Fagan if (kill(pid, 0) == -1 && errno == ESRCH) 24989361835SSean Eric Fagan break; 25089361835SSean Eric Fagan else 2513cf51049SPhilippe Charnier warn("PIOCCONT"); 25289361835SSean Eric Fagan } 253bbeaf6c0SSean Eric Fagan } while (pfs.why != S_EXIT); 254dcbdc0b9SMike Smith fflush(outfile); 2559a4902a9SMartin Cracauer if (sigexit) { 2569a4902a9SMartin Cracauer if (sigexit == SIGQUIT) 2579a4902a9SMartin Cracauer exit(sigexit); 2589a4902a9SMartin Cracauer (void) signal(sigexit, SIG_DFL); 2599a4902a9SMartin Cracauer (void) kill(getpid(), sigexit); 2609a4902a9SMartin Cracauer } 261bbeaf6c0SSean Eric Fagan return 0; 262bbeaf6c0SSean Eric Fagan } 263