1d5303c80SXin LI /*- 2*df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3*df57947fSPedro F. Giffuni * 40a6c71f8SWarner Losh * Copyright 1997 Sean Eric Fagan 509d64da3SSean Eric Fagan * 609d64da3SSean Eric Fagan * Redistribution and use in source and binary forms, with or without 709d64da3SSean Eric Fagan * modification, are permitted provided that the following conditions 809d64da3SSean Eric Fagan * are met: 909d64da3SSean Eric Fagan * 1. Redistributions of source code must retain the above copyright 1009d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer. 1109d64da3SSean Eric Fagan * 2. Redistributions in binary form must reproduce the above copyright 1209d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer in the 1309d64da3SSean Eric Fagan * documentation and/or other materials provided with the distribution. 1409d64da3SSean Eric Fagan * 3. All advertising materials mentioning features or use of this software 1509d64da3SSean Eric Fagan * must display the following acknowledgement: 1609d64da3SSean Eric Fagan * This product includes software developed by Sean Eric Fagan 1709d64da3SSean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote 1809d64da3SSean Eric Fagan * products derived from this software without specific prior written 1909d64da3SSean Eric Fagan * permission. 2009d64da3SSean Eric Fagan * 2109d64da3SSean Eric Fagan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2209d64da3SSean Eric Fagan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2309d64da3SSean Eric Fagan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2409d64da3SSean Eric Fagan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2509d64da3SSean Eric Fagan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2609d64da3SSean Eric Fagan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2709d64da3SSean Eric Fagan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2809d64da3SSean Eric Fagan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2909d64da3SSean Eric Fagan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3009d64da3SSean Eric Fagan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3109d64da3SSean Eric Fagan * SUCH DAMAGE. 3209d64da3SSean Eric Fagan */ 3309d64da3SSean Eric Fagan 34b956c13cSPhilippe Charnier #include <sys/cdefs.h> 35b956c13cSPhilippe Charnier __FBSDID("$FreeBSD$"); 363cf51049SPhilippe Charnier 3709d64da3SSean Eric Fagan /* 38b2bf146eSBenedict Reuschling * The main module for truss. Surprisingly 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 432b75c8adSJohn Baldwin #include <sys/ptrace.h> 44580e0a2bSDag-Erling Smørgrav 453cf51049SPhilippe Charnier #include <err.h> 463cf51049SPhilippe Charnier #include <signal.h> 479289f547SJohn Baldwin #include <stdbool.h> 48bbeaf6c0SSean Eric Fagan #include <stdio.h> 49bbeaf6c0SSean Eric Fagan #include <stdlib.h> 50a5f14abfSJohn Baldwin #include <sysdecode.h> 5137169f94SMatthew N. Dodd #include <time.h> 5295c4ef65SPeter Wemm #include <unistd.h> 53bbeaf6c0SSean Eric Fagan 54ec0bed25SMatthew N. Dodd #include "truss.h" 551be5d704SMark Murray #include "extern.h" 56ee3b0f6eSDiomidis Spinellis #include "syscall.h" 57bbeaf6c0SSean Eric Fagan 585321ae86SAlfred Perlstein static void 593cf51049SPhilippe Charnier usage(void) 603cf51049SPhilippe Charnier { 613cf51049SPhilippe Charnier fprintf(stderr, "%s\n%s\n", 62fe7f211cSEd Maste "usage: truss [-cfaedDHS] [-o file] [-s strsize] -p pid", 63fe7f211cSEd Maste " truss [-cfaedDHS] [-o file] [-s strsize] command [args]"); 64bbeaf6c0SSean Eric Fagan exit(1); 65bbeaf6c0SSean Eric Fagan } 66bbeaf6c0SSean Eric Fagan 673cf51049SPhilippe Charnier int 685321ae86SAlfred Perlstein main(int ac, char **av) 695321ae86SAlfred Perlstein { 70896fc463SAndrey Zonov struct sigaction sa; 71ec0bed25SMatthew N. Dodd struct trussinfo *trussinfo; 7294355cfdSAndrey Zonov char *fname; 7394355cfdSAndrey Zonov char **command; 742b75c8adSJohn Baldwin pid_t pid; 752b75c8adSJohn Baldwin int c; 76bbeaf6c0SSean Eric Fagan 7772aa911aSAlfred Perlstein fname = NULL; 7872aa911aSAlfred Perlstein 79ec0bed25SMatthew N. Dodd /* Initialize the trussinfo struct */ 80216fa4c6SXin LI trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo)); 81ec0bed25SMatthew N. Dodd if (trussinfo == NULL) 82216fa4c6SXin LI errx(1, "calloc() failed"); 835d2d083cSXin LI 842b75c8adSJohn Baldwin pid = 0; 85ec0bed25SMatthew N. Dodd trussinfo->outfile = stderr; 860cf21b4fSBrian Somers trussinfo->strsize = 32; 875d2d083cSXin LI trussinfo->curthread = NULL; 882b75c8adSJohn Baldwin LIST_INIT(&trussinfo->proclist); 896c61b0f3SBryan Drewery init_syscalls(); 90d70876fdSJohn Baldwin while ((c = getopt(ac, av, "p:o:facedDs:SH")) != -1) { 91bbeaf6c0SSean Eric Fagan switch (c) { 92bbeaf6c0SSean Eric Fagan case 'p': /* specified pid */ 932b75c8adSJohn Baldwin pid = atoi(optarg); 94ef29ac7fSXin LI /* make sure i don't trace me */ 952b75c8adSJohn Baldwin if (pid == getpid()) { 962b75c8adSJohn Baldwin errx(2, "attempt to grab self."); 97ef29ac7fSXin LI } 98bbeaf6c0SSean Eric Fagan break; 99c03bfcc8SMatthew N. Dodd case 'f': /* Follow fork()'s */ 100c03bfcc8SMatthew N. Dodd trussinfo->flags |= FOLLOWFORKS; 101c03bfcc8SMatthew N. Dodd break; 1029897b203SMatthew N. Dodd case 'a': /* Print execve() argument strings. */ 1039897b203SMatthew N. Dodd trussinfo->flags |= EXECVEARGS; 1049897b203SMatthew N. Dodd break; 105ee3b0f6eSDiomidis Spinellis case 'c': /* Count number of system calls and time. */ 1067096af2eSBryan Drewery trussinfo->flags |= (COUNTONLY | NOSIGS); 107ee3b0f6eSDiomidis Spinellis break; 1089897b203SMatthew N. Dodd case 'e': /* Print execve() environment strings. */ 1099897b203SMatthew N. Dodd trussinfo->flags |= EXECVEENVS; 1109897b203SMatthew N. Dodd break; 1110d0bd00eSMatthew N. Dodd case 'd': /* Absolute timestamps */ 1120d0bd00eSMatthew N. Dodd trussinfo->flags |= ABSOLUTETIMESTAMPS; 1130d0bd00eSMatthew N. Dodd break; 1140d0bd00eSMatthew N. Dodd case 'D': /* Relative timestamps */ 1150d0bd00eSMatthew N. Dodd trussinfo->flags |= RELATIVETIMESTAMPS; 1160d0bd00eSMatthew N. Dodd break; 117bbeaf6c0SSean Eric Fagan case 'o': /* Specified output file */ 1183cf51049SPhilippe Charnier fname = optarg; 119bbeaf6c0SSean Eric Fagan break; 1200cf21b4fSBrian Somers case 's': /* Specified string size */ 1210cf21b4fSBrian Somers trussinfo->strsize = atoi(optarg); 1220cf21b4fSBrian Somers break; 123bbeaf6c0SSean Eric Fagan case 'S': /* Don't trace signals */ 124ec0bed25SMatthew N. Dodd trussinfo->flags |= NOSIGS; 125bbeaf6c0SSean Eric Fagan break; 126d70876fdSJohn Baldwin case 'H': 127d70876fdSJohn Baldwin trussinfo->flags |= DISPLAYTIDS; 128d70876fdSJohn Baldwin break; 129bbeaf6c0SSean Eric Fagan default: 130bbeaf6c0SSean Eric Fagan usage(); 131bbeaf6c0SSean Eric Fagan } 132bbeaf6c0SSean Eric Fagan } 133bbeaf6c0SSean Eric Fagan 134bbeaf6c0SSean Eric Fagan ac -= optind; av += optind; 1352b75c8adSJohn Baldwin if ((pid == 0 && ac == 0) || 1362b75c8adSJohn Baldwin (pid != 0 && ac != 0)) 137bbeaf6c0SSean Eric Fagan usage(); 138bbeaf6c0SSean Eric Fagan 1393cf51049SPhilippe Charnier if (fname != NULL) { /* Use output file */ 140ecbb6d34SJaakko Heinonen /* 141c2b51d44SMateusz Guzik * Set close-on-exec ('e'), so that the output file is not 142c2b51d44SMateusz Guzik * shared with the traced process. 143ecbb6d34SJaakko Heinonen */ 144c2b51d44SMateusz Guzik if ((trussinfo->outfile = fopen(fname, "we")) == NULL) 145c2b51d44SMateusz Guzik err(1, "cannot open %s", fname); 146e04c3786SJaakko Heinonen } 1473cf51049SPhilippe Charnier 148bbeaf6c0SSean Eric Fagan /* 149bbeaf6c0SSean Eric Fagan * If truss starts the process itself, it will ignore some signals -- 150bbeaf6c0SSean Eric Fagan * they should be passed off to the process, which may or may not 151bbeaf6c0SSean Eric Fagan * exit. If, however, we are examining an already-running process, 152bbeaf6c0SSean Eric Fagan * then we restore the event mask on these same signals. 153bbeaf6c0SSean Eric Fagan */ 1542b75c8adSJohn Baldwin if (pid == 0) { 1552b75c8adSJohn Baldwin /* Start a command ourselves */ 156bbeaf6c0SSean Eric Fagan command = av; 1572b75c8adSJohn Baldwin setup_and_wait(trussinfo, command); 158bbeaf6c0SSean Eric Fagan signal(SIGINT, SIG_IGN); 159bbeaf6c0SSean Eric Fagan signal(SIGTERM, SIG_IGN); 160bbeaf6c0SSean Eric Fagan signal(SIGQUIT, SIG_IGN); 161bbeaf6c0SSean Eric Fagan } else { 162896fc463SAndrey Zonov sa.sa_handler = restore_proc; 163896fc463SAndrey Zonov sa.sa_flags = 0; 164896fc463SAndrey Zonov sigemptyset(&sa.sa_mask); 165896fc463SAndrey Zonov sigaction(SIGINT, &sa, NULL); 166896fc463SAndrey Zonov sigaction(SIGQUIT, &sa, NULL); 167896fc463SAndrey Zonov sigaction(SIGTERM, &sa, NULL); 1682b75c8adSJohn Baldwin start_tracing(trussinfo, pid); 169bbeaf6c0SSean Eric Fagan } 170bbeaf6c0SSean Eric Fagan 171bbeaf6c0SSean Eric Fagan /* 172bbeaf6c0SSean Eric Fagan * At this point, if we started the process, it is stopped waiting to 173bbeaf6c0SSean Eric Fagan * be woken up, either in exit() or in execve(). 174bbeaf6c0SSean Eric Fagan */ 1752b75c8adSJohn Baldwin if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) { 1762b75c8adSJohn Baldwin /* 1772b75c8adSJohn Baldwin * If we are not able to handle this ABI, detach from the 1782b75c8adSJohn Baldwin * process and exit. If we just created a new process to 1792b75c8adSJohn Baldwin * run a command, kill the new process rather than letting 1802b75c8adSJohn Baldwin * it run untraced. 1812b75c8adSJohn Baldwin */ 1822b75c8adSJohn Baldwin if (pid == 0) 1832b75c8adSJohn Baldwin kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL); 1842b75c8adSJohn Baldwin ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL, 1852b75c8adSJohn Baldwin 0); 1862b75c8adSJohn Baldwin return (1); 1872b75c8adSJohn Baldwin } 1882b75c8adSJohn Baldwin ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1, 1892b75c8adSJohn Baldwin 0); 190bbeaf6c0SSean Eric Fagan 191bbeaf6c0SSean Eric Fagan /* 192bbeaf6c0SSean Eric Fagan * At this point, it's a simple loop, waiting for the process to 193bbeaf6c0SSean Eric Fagan * stop, finding out why, printing out why, and then continuing it. 194bbeaf6c0SSean Eric Fagan * All of the grunt work is done in the support routines. 195bbeaf6c0SSean Eric Fagan */ 196203098d8SMatthew N. Dodd clock_gettime(CLOCK_REALTIME, &trussinfo->start_time); 1970d0bd00eSMatthew N. Dodd 1982b75c8adSJohn Baldwin eventloop(trussinfo); 199d5303c80SXin LI 200ee3b0f6eSDiomidis Spinellis if (trussinfo->flags & COUNTONLY) 201ee3b0f6eSDiomidis Spinellis print_summary(trussinfo); 202ee3b0f6eSDiomidis Spinellis 203ee3b0f6eSDiomidis Spinellis fflush(trussinfo->outfile); 204ee3b0f6eSDiomidis Spinellis 2055321ae86SAlfred Perlstein return (0); 206bbeaf6c0SSean Eric Fagan } 207