1d5303c80SXin LI /*- 20a6c71f8SWarner Losh * Copyright 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 32b956c13cSPhilippe Charnier #include <sys/cdefs.h> 33b956c13cSPhilippe Charnier __FBSDID("$FreeBSD$"); 343cf51049SPhilippe Charnier 3509d64da3SSean Eric Fagan /* 36b2bf146eSBenedict Reuschling * The main module for truss. Surprisingly simple, but, then, the other 37bbeaf6c0SSean Eric Fagan * files handle the bulk of the work. And, of course, the kernel has to 38bbeaf6c0SSean Eric Fagan * do a lot of the work :). 39bbeaf6c0SSean Eric Fagan */ 40bbeaf6c0SSean Eric Fagan 412b75c8adSJohn Baldwin #include <sys/ptrace.h> 42580e0a2bSDag-Erling Smørgrav 433cf51049SPhilippe Charnier #include <err.h> 443cf51049SPhilippe Charnier #include <signal.h> 45bbeaf6c0SSean Eric Fagan #include <stdio.h> 46bbeaf6c0SSean Eric Fagan #include <stdlib.h> 4737169f94SMatthew N. Dodd #include <time.h> 4895c4ef65SPeter Wemm #include <unistd.h> 49bbeaf6c0SSean Eric Fagan 50ec0bed25SMatthew N. Dodd #include "truss.h" 511be5d704SMark Murray #include "extern.h" 52ee3b0f6eSDiomidis Spinellis #include "syscall.h" 53bbeaf6c0SSean Eric Fagan 545321ae86SAlfred Perlstein static void 553cf51049SPhilippe Charnier usage(void) 563cf51049SPhilippe Charnier { 573cf51049SPhilippe Charnier fprintf(stderr, "%s\n%s\n", 58ee3b0f6eSDiomidis Spinellis "usage: truss [-cfaedDS] [-o file] [-s strsize] -p pid", 59ee3b0f6eSDiomidis Spinellis " truss [-cfaedDS] [-o file] [-s strsize] command [args]"); 60bbeaf6c0SSean Eric Fagan exit(1); 61bbeaf6c0SSean Eric Fagan } 62bbeaf6c0SSean Eric Fagan 63d75300bfSAlfred Perlstein char * 64d75300bfSAlfred Perlstein strsig(int sig) 65d75300bfSAlfred Perlstein { 66f083f689SJohn Baldwin static char tmp[64]; 67d75300bfSAlfred Perlstein 68d75300bfSAlfred Perlstein if (sig > 0 && sig < NSIG) { 69f083f689SJohn Baldwin snprintf(tmp, sizeof(tmp), "SIG%s", sys_signame[sig]); 70f083f689SJohn Baldwin return (tmp); 71d75300bfSAlfred Perlstein } 72f083f689SJohn Baldwin return (NULL); 73d75300bfSAlfred Perlstein } 74d75300bfSAlfred Perlstein 753cf51049SPhilippe Charnier int 765321ae86SAlfred Perlstein main(int ac, char **av) 775321ae86SAlfred Perlstein { 78896fc463SAndrey Zonov struct sigaction sa; 79ec0bed25SMatthew N. Dodd struct trussinfo *trussinfo; 8094355cfdSAndrey Zonov char *fname; 8194355cfdSAndrey Zonov char **command; 822b75c8adSJohn Baldwin pid_t pid; 832b75c8adSJohn Baldwin int c; 84bbeaf6c0SSean Eric Fagan 8572aa911aSAlfred Perlstein fname = NULL; 8672aa911aSAlfred Perlstein 87ec0bed25SMatthew N. Dodd /* Initialize the trussinfo struct */ 88216fa4c6SXin LI trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo)); 89ec0bed25SMatthew N. Dodd if (trussinfo == NULL) 90216fa4c6SXin LI errx(1, "calloc() failed"); 915d2d083cSXin LI 922b75c8adSJohn Baldwin pid = 0; 93ec0bed25SMatthew N. Dodd trussinfo->outfile = stderr; 940cf21b4fSBrian Somers trussinfo->strsize = 32; 955d2d083cSXin LI trussinfo->curthread = NULL; 962b75c8adSJohn Baldwin LIST_INIT(&trussinfo->proclist); 976c61b0f3SBryan Drewery init_syscalls(); 98ee3b0f6eSDiomidis Spinellis while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) { 99bbeaf6c0SSean Eric Fagan switch (c) { 100bbeaf6c0SSean Eric Fagan case 'p': /* specified pid */ 1012b75c8adSJohn Baldwin pid = atoi(optarg); 102ef29ac7fSXin LI /* make sure i don't trace me */ 1032b75c8adSJohn Baldwin if (pid == getpid()) { 1042b75c8adSJohn Baldwin errx(2, "attempt to grab self."); 105ef29ac7fSXin LI } 106bbeaf6c0SSean Eric Fagan break; 107c03bfcc8SMatthew N. Dodd case 'f': /* Follow fork()'s */ 108c03bfcc8SMatthew N. Dodd trussinfo->flags |= FOLLOWFORKS; 109c03bfcc8SMatthew N. Dodd break; 1109897b203SMatthew N. Dodd case 'a': /* Print execve() argument strings. */ 1119897b203SMatthew N. Dodd trussinfo->flags |= EXECVEARGS; 1129897b203SMatthew N. Dodd break; 113ee3b0f6eSDiomidis Spinellis case 'c': /* Count number of system calls and time. */ 114*7096af2eSBryan Drewery trussinfo->flags |= (COUNTONLY | NOSIGS); 115ee3b0f6eSDiomidis Spinellis break; 1169897b203SMatthew N. Dodd case 'e': /* Print execve() environment strings. */ 1179897b203SMatthew N. Dodd trussinfo->flags |= EXECVEENVS; 1189897b203SMatthew N. Dodd break; 1190d0bd00eSMatthew N. Dodd case 'd': /* Absolute timestamps */ 1200d0bd00eSMatthew N. Dodd trussinfo->flags |= ABSOLUTETIMESTAMPS; 1210d0bd00eSMatthew N. Dodd break; 1220d0bd00eSMatthew N. Dodd case 'D': /* Relative timestamps */ 1230d0bd00eSMatthew N. Dodd trussinfo->flags |= RELATIVETIMESTAMPS; 1240d0bd00eSMatthew N. Dodd break; 125bbeaf6c0SSean Eric Fagan case 'o': /* Specified output file */ 1263cf51049SPhilippe Charnier fname = optarg; 127bbeaf6c0SSean Eric Fagan break; 1280cf21b4fSBrian Somers case 's': /* Specified string size */ 1290cf21b4fSBrian Somers trussinfo->strsize = atoi(optarg); 1300cf21b4fSBrian Somers break; 131bbeaf6c0SSean Eric Fagan case 'S': /* Don't trace signals */ 132ec0bed25SMatthew N. Dodd trussinfo->flags |= NOSIGS; 133bbeaf6c0SSean Eric Fagan break; 134bbeaf6c0SSean Eric Fagan default: 135bbeaf6c0SSean Eric Fagan usage(); 136bbeaf6c0SSean Eric Fagan } 137bbeaf6c0SSean Eric Fagan } 138bbeaf6c0SSean Eric Fagan 139bbeaf6c0SSean Eric Fagan ac -= optind; av += optind; 1402b75c8adSJohn Baldwin if ((pid == 0 && ac == 0) || 1412b75c8adSJohn Baldwin (pid != 0 && ac != 0)) 142bbeaf6c0SSean Eric Fagan usage(); 143bbeaf6c0SSean Eric Fagan 1443cf51049SPhilippe Charnier if (fname != NULL) { /* Use output file */ 145ecbb6d34SJaakko Heinonen /* 146c2b51d44SMateusz Guzik * Set close-on-exec ('e'), so that the output file is not 147c2b51d44SMateusz Guzik * shared with the traced process. 148ecbb6d34SJaakko Heinonen */ 149c2b51d44SMateusz Guzik if ((trussinfo->outfile = fopen(fname, "we")) == NULL) 150c2b51d44SMateusz Guzik err(1, "cannot open %s", fname); 151e04c3786SJaakko Heinonen } 1523cf51049SPhilippe Charnier 153bbeaf6c0SSean Eric Fagan /* 154bbeaf6c0SSean Eric Fagan * If truss starts the process itself, it will ignore some signals -- 155bbeaf6c0SSean Eric Fagan * they should be passed off to the process, which may or may not 156bbeaf6c0SSean Eric Fagan * exit. If, however, we are examining an already-running process, 157bbeaf6c0SSean Eric Fagan * then we restore the event mask on these same signals. 158bbeaf6c0SSean Eric Fagan */ 1592b75c8adSJohn Baldwin if (pid == 0) { 1602b75c8adSJohn Baldwin /* Start a command ourselves */ 161bbeaf6c0SSean Eric Fagan command = av; 1622b75c8adSJohn Baldwin setup_and_wait(trussinfo, command); 163bbeaf6c0SSean Eric Fagan signal(SIGINT, SIG_IGN); 164bbeaf6c0SSean Eric Fagan signal(SIGTERM, SIG_IGN); 165bbeaf6c0SSean Eric Fagan signal(SIGQUIT, SIG_IGN); 166bbeaf6c0SSean Eric Fagan } else { 167896fc463SAndrey Zonov sa.sa_handler = restore_proc; 168896fc463SAndrey Zonov sa.sa_flags = 0; 169896fc463SAndrey Zonov sigemptyset(&sa.sa_mask); 170896fc463SAndrey Zonov sigaction(SIGINT, &sa, NULL); 171896fc463SAndrey Zonov sigaction(SIGQUIT, &sa, NULL); 172896fc463SAndrey Zonov sigaction(SIGTERM, &sa, NULL); 1732b75c8adSJohn Baldwin start_tracing(trussinfo, pid); 174bbeaf6c0SSean Eric Fagan } 175bbeaf6c0SSean Eric Fagan 176bbeaf6c0SSean Eric Fagan /* 177bbeaf6c0SSean Eric Fagan * At this point, if we started the process, it is stopped waiting to 178bbeaf6c0SSean Eric Fagan * be woken up, either in exit() or in execve(). 179bbeaf6c0SSean Eric Fagan */ 1802b75c8adSJohn Baldwin if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) { 1812b75c8adSJohn Baldwin /* 1822b75c8adSJohn Baldwin * If we are not able to handle this ABI, detach from the 1832b75c8adSJohn Baldwin * process and exit. If we just created a new process to 1842b75c8adSJohn Baldwin * run a command, kill the new process rather than letting 1852b75c8adSJohn Baldwin * it run untraced. 1862b75c8adSJohn Baldwin */ 1872b75c8adSJohn Baldwin if (pid == 0) 1882b75c8adSJohn Baldwin kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL); 1892b75c8adSJohn Baldwin ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL, 1902b75c8adSJohn Baldwin 0); 1912b75c8adSJohn Baldwin return (1); 1922b75c8adSJohn Baldwin } 1932b75c8adSJohn Baldwin ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1, 1942b75c8adSJohn Baldwin 0); 195bbeaf6c0SSean Eric Fagan 196bbeaf6c0SSean Eric Fagan /* 197bbeaf6c0SSean Eric Fagan * At this point, it's a simple loop, waiting for the process to 198bbeaf6c0SSean Eric Fagan * stop, finding out why, printing out why, and then continuing it. 199bbeaf6c0SSean Eric Fagan * All of the grunt work is done in the support routines. 200bbeaf6c0SSean Eric Fagan */ 201203098d8SMatthew N. Dodd clock_gettime(CLOCK_REALTIME, &trussinfo->start_time); 2020d0bd00eSMatthew N. Dodd 2032b75c8adSJohn Baldwin eventloop(trussinfo); 204d5303c80SXin LI 205ee3b0f6eSDiomidis Spinellis if (trussinfo->flags & COUNTONLY) 206ee3b0f6eSDiomidis Spinellis print_summary(trussinfo); 207ee3b0f6eSDiomidis Spinellis 208ee3b0f6eSDiomidis Spinellis fflush(trussinfo->outfile); 209ee3b0f6eSDiomidis Spinellis 2105321ae86SAlfred Perlstein return (0); 211bbeaf6c0SSean Eric Fagan } 212