1bbeaf6c0SSean Eric Fagan /* 2bbeaf6c0SSean Eric Fagan * The main module for truss. Suprisingly simple, but, then, the other 3bbeaf6c0SSean Eric Fagan * files handle the bulk of the work. And, of course, the kernel has to 4bbeaf6c0SSean Eric Fagan * do a lot of the work :). 5bbeaf6c0SSean Eric Fagan */ 6bbeaf6c0SSean Eric Fagan /* 7bbeaf6c0SSean Eric Fagan * $Id$ 8bbeaf6c0SSean Eric Fagan */ 9bbeaf6c0SSean Eric Fagan 10bbeaf6c0SSean Eric Fagan #include <stdio.h> 11bbeaf6c0SSean Eric Fagan #include <stdlib.h> 12bbeaf6c0SSean Eric Fagan #include <string.h> 13bbeaf6c0SSean Eric Fagan #include <errno.h> 14bbeaf6c0SSean Eric Fagan #include <err.h> 15bbeaf6c0SSean Eric Fagan #include <signal.h> 16bbeaf6c0SSean Eric Fagan #include <fcntl.h> 17bbeaf6c0SSean Eric Fagan #include <sys/ioctl.h> 18bbeaf6c0SSean Eric Fagan #include <sys/pioctl.h> 19bbeaf6c0SSean Eric Fagan 20bbeaf6c0SSean Eric Fagan extern int setup_and_wait(char **); 21bbeaf6c0SSean Eric Fagan extern int start_tracing(int, int); 22bbeaf6c0SSean Eric Fagan extern void i386_syscall_entry(int, int); 23bbeaf6c0SSean Eric Fagan extern void i386_syscall_exit(int, int); 24bbeaf6c0SSean Eric Fagan extern void i386_linux_syscall_entry(int, int); 25bbeaf6c0SSean Eric Fagan extern void i386_linux_syscall_exit(int, int); 26bbeaf6c0SSean Eric Fagan 27bbeaf6c0SSean Eric Fagan /* 28bbeaf6c0SSean Eric Fagan * These should really be parameterized -- I don't like having globals, 29bbeaf6c0SSean Eric Fagan * but this is the easiest way, right now, to deal with them. 30bbeaf6c0SSean Eric Fagan */ 31bbeaf6c0SSean Eric Fagan 32bbeaf6c0SSean Eric Fagan int pid = 0; 33bbeaf6c0SSean Eric Fagan int nosigs = 0; 34bbeaf6c0SSean Eric Fagan FILE *outfile = stderr; 35bbeaf6c0SSean Eric Fagan char *prog; 36bbeaf6c0SSean Eric Fagan int Procfd; 37bbeaf6c0SSean Eric Fagan char progtype[50]; /* OS and type of executable */ 38bbeaf6c0SSean Eric Fagan 39bbeaf6c0SSean Eric Fagan static inline void 40bbeaf6c0SSean Eric Fagan usage(void) { 41bbeaf6c0SSean Eric Fagan fprintf(stderr, "usage: %s [-o <file>] [-S] { [-p <pid> ] | " 42bbeaf6c0SSean Eric Fagan "[ <command> <args>] }\n", prog); 43bbeaf6c0SSean Eric Fagan exit(1); 44bbeaf6c0SSean Eric Fagan } 45bbeaf6c0SSean Eric Fagan 46bbeaf6c0SSean Eric Fagan struct ex_types { 47bbeaf6c0SSean Eric Fagan char *type; 48bbeaf6c0SSean Eric Fagan void (*enter_syscall)(int, int); 49bbeaf6c0SSean Eric Fagan void (*exit_syscall)(int, int); 50bbeaf6c0SSean Eric Fagan } ex_types[] = { 51bbeaf6c0SSean Eric Fagan { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit }, 52bbeaf6c0SSean Eric Fagan { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit }, 53bbeaf6c0SSean Eric Fagan { 0, 0, 0 }, 54bbeaf6c0SSean Eric Fagan }; 55bbeaf6c0SSean Eric Fagan 56bbeaf6c0SSean Eric Fagan /* 57bbeaf6c0SSean Eric Fagan * Set the execution type. This is called after every exec, and when 58bbeaf6c0SSean Eric Fagan * a process is first monitored. The procfs pseudo-file "etype" has 59bbeaf6c0SSean Eric Fagan * the execution module type -- see /proc/curproc/etype for an example. 60bbeaf6c0SSean Eric Fagan */ 61bbeaf6c0SSean Eric Fagan 62bbeaf6c0SSean Eric Fagan static struct ex_types * 63bbeaf6c0SSean Eric Fagan set_etype() { 64bbeaf6c0SSean Eric Fagan struct ex_types *funcs; 65bbeaf6c0SSean Eric Fagan char etype[24]; 66bbeaf6c0SSean Eric Fagan char progtype[32]; 67bbeaf6c0SSean Eric Fagan int fd; 68bbeaf6c0SSean Eric Fagan 69bbeaf6c0SSean Eric Fagan sprintf(etype, "/proc/%d/etype", pid); 70bbeaf6c0SSean Eric Fagan if ((fd = open(etype, O_RDONLY)) == -1) { 71bbeaf6c0SSean Eric Fagan strcpy(progtype, "FreeBSD a.out"); 72bbeaf6c0SSean Eric Fagan } else { 73bbeaf6c0SSean Eric Fagan int len = read(fd, progtype, sizeof(progtype)); 74bbeaf6c0SSean Eric Fagan progtype[len-1] = '\0'; 75bbeaf6c0SSean Eric Fagan close(etype); 76bbeaf6c0SSean Eric Fagan } 77bbeaf6c0SSean Eric Fagan 78bbeaf6c0SSean Eric Fagan for (funcs = ex_types; funcs->type; funcs++) 79bbeaf6c0SSean Eric Fagan if (!strcmp(funcs->type, progtype)) 80bbeaf6c0SSean Eric Fagan break; 81bbeaf6c0SSean Eric Fagan 82bbeaf6c0SSean Eric Fagan return funcs; 83bbeaf6c0SSean Eric Fagan } 84bbeaf6c0SSean Eric Fagan 85bbeaf6c0SSean Eric Fagan main(int ac, char **av) { 86bbeaf6c0SSean Eric Fagan int mask; 87bbeaf6c0SSean Eric Fagan int c; 88bbeaf6c0SSean Eric Fagan int i; 89bbeaf6c0SSean Eric Fagan char **command; 90bbeaf6c0SSean Eric Fagan struct procfs_status pfs; 91bbeaf6c0SSean Eric Fagan char etype[25]; 92bbeaf6c0SSean Eric Fagan struct ex_types *funcs; 93bbeaf6c0SSean Eric Fagan int fd; 94bbeaf6c0SSean Eric Fagan int in_exec = 0; 95bbeaf6c0SSean Eric Fagan 96bbeaf6c0SSean Eric Fagan prog = av[0]; 97bbeaf6c0SSean Eric Fagan 98bbeaf6c0SSean Eric Fagan while ((c = getopt(ac, av, "p:o:S")) != EOF) { 99bbeaf6c0SSean Eric Fagan switch (c) { 100bbeaf6c0SSean Eric Fagan case 'p': /* specified pid */ 101bbeaf6c0SSean Eric Fagan pid = atoi(optarg); 102bbeaf6c0SSean Eric Fagan break; 103bbeaf6c0SSean Eric Fagan case 'o': /* Specified output file */ 104bbeaf6c0SSean Eric Fagan if ((outfile = fopen(optarg, "w")) == NULL) { 105bbeaf6c0SSean Eric Fagan fprintf (stderr, "%s: cannot open %s\n", av[0], optarg); 106bbeaf6c0SSean Eric Fagan exit(1); 107bbeaf6c0SSean Eric Fagan } 108bbeaf6c0SSean Eric Fagan break; 109bbeaf6c0SSean Eric Fagan case 'S': /* Don't trace signals */ 110bbeaf6c0SSean Eric Fagan nosigs = 1; 111bbeaf6c0SSean Eric Fagan break; 112bbeaf6c0SSean Eric Fagan default: 113bbeaf6c0SSean Eric Fagan usage(); 114bbeaf6c0SSean Eric Fagan } 115bbeaf6c0SSean Eric Fagan } 116bbeaf6c0SSean Eric Fagan 117bbeaf6c0SSean Eric Fagan ac -= optind; av += optind; 118bbeaf6c0SSean Eric Fagan if (ac && pid != 0) 119bbeaf6c0SSean Eric Fagan usage(); 120bbeaf6c0SSean Eric Fagan 121bbeaf6c0SSean Eric Fagan /* 122bbeaf6c0SSean Eric Fagan * If truss starts the process itself, it will ignore some signals -- 123bbeaf6c0SSean Eric Fagan * they should be passed off to the process, which may or may not 124bbeaf6c0SSean Eric Fagan * exit. If, however, we are examining an already-running process, 125bbeaf6c0SSean Eric Fagan * then we restore the event mask on these same signals. 126bbeaf6c0SSean Eric Fagan */ 127bbeaf6c0SSean Eric Fagan 128bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Start a command ourselves */ 129bbeaf6c0SSean Eric Fagan command = av; 130bbeaf6c0SSean Eric Fagan pid = setup_and_wait(command); 131bbeaf6c0SSean Eric Fagan signal(SIGINT, SIG_IGN); 132bbeaf6c0SSean Eric Fagan signal(SIGTERM, SIG_IGN); 133bbeaf6c0SSean Eric Fagan signal(SIGQUIT, SIG_IGN); 134bbeaf6c0SSean Eric Fagan } else { 135bbeaf6c0SSean Eric Fagan extern void restore_proc(int); 136bbeaf6c0SSean Eric Fagan signal(SIGINT, restore_proc); 137bbeaf6c0SSean Eric Fagan signal(SIGTERM, restore_proc); 138bbeaf6c0SSean Eric Fagan signal(SIGQUIT, restore_proc); 139bbeaf6c0SSean Eric Fagan } 140bbeaf6c0SSean Eric Fagan 141bbeaf6c0SSean Eric Fagan 142bbeaf6c0SSean Eric Fagan /* 143bbeaf6c0SSean Eric Fagan * At this point, if we started the process, it is stopped waiting to 144bbeaf6c0SSean Eric Fagan * be woken up, either in exit() or in execve(). 145bbeaf6c0SSean Eric Fagan */ 146bbeaf6c0SSean Eric Fagan 147bbeaf6c0SSean Eric Fagan Procfd = start_tracing(pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | 148bbeaf6c0SSean Eric Fagan (nosigs ? 0 : S_SIG)); 149bbeaf6c0SSean Eric Fagan pfs.why = 0; 150bbeaf6c0SSean Eric Fagan 151bbeaf6c0SSean Eric Fagan funcs = set_etype(); 152bbeaf6c0SSean Eric Fagan /* 153bbeaf6c0SSean Eric Fagan * At this point, it's a simple loop, waiting for the process to 154bbeaf6c0SSean Eric Fagan * stop, finding out why, printing out why, and then continuing it. 155bbeaf6c0SSean Eric Fagan * All of the grunt work is done in the support routines. 156bbeaf6c0SSean Eric Fagan */ 157bbeaf6c0SSean Eric Fagan 158bbeaf6c0SSean Eric Fagan do { 159bbeaf6c0SSean Eric Fagan int val = 0; 160bbeaf6c0SSean Eric Fagan 161bbeaf6c0SSean Eric Fagan if (ioctl(Procfd, PIOCWAIT, &pfs) == -1) 162bbeaf6c0SSean Eric Fagan perror("PIOCWAIT top of loop"); 163bbeaf6c0SSean Eric Fagan else { 164bbeaf6c0SSean Eric Fagan switch(i = pfs.why) { 165bbeaf6c0SSean Eric Fagan case S_SCE: 166bbeaf6c0SSean Eric Fagan funcs->enter_syscall(pid, pfs.val); 167bbeaf6c0SSean Eric Fagan break; 168bbeaf6c0SSean Eric Fagan case S_SCX: 169bbeaf6c0SSean Eric Fagan /* 170bbeaf6c0SSean Eric Fagan * This is so we don't get two messages for an exec -- one 171bbeaf6c0SSean Eric Fagan * for the S_EXEC, and one for the syscall exit. It also, 172bbeaf6c0SSean Eric Fagan * conveniently, ensures that the first message printed out 173bbeaf6c0SSean Eric Fagan * isn't the return-from-syscall used to create the process. 174bbeaf6c0SSean Eric Fagan */ 175bbeaf6c0SSean Eric Fagan 176bbeaf6c0SSean Eric Fagan if (in_exec) { 177bbeaf6c0SSean Eric Fagan in_exec = 0; 178bbeaf6c0SSean Eric Fagan break; 179bbeaf6c0SSean Eric Fagan } 180bbeaf6c0SSean Eric Fagan funcs->exit_syscall(pid, pfs.val); 181bbeaf6c0SSean Eric Fagan break; 182bbeaf6c0SSean Eric Fagan case S_SIG: 183bbeaf6c0SSean Eric Fagan fprintf(outfile, "SIGNAL %d\n", pfs.val); 184bbeaf6c0SSean Eric Fagan break; 185bbeaf6c0SSean Eric Fagan case S_EXIT: 186bbeaf6c0SSean Eric Fagan fprintf (outfile, "process exit, rval = %d\n", pfs.val); 187bbeaf6c0SSean Eric Fagan break; 188bbeaf6c0SSean Eric Fagan case S_EXEC: 189bbeaf6c0SSean Eric Fagan funcs = set_etype(); 190bbeaf6c0SSean Eric Fagan in_exec = 1; 191bbeaf6c0SSean Eric Fagan break; 192bbeaf6c0SSean Eric Fagan default: 193bbeaf6c0SSean Eric Fagan fprintf (outfile, "Process stopped because of: %d\n", i); 194bbeaf6c0SSean Eric Fagan break; 195bbeaf6c0SSean Eric Fagan } 196bbeaf6c0SSean Eric Fagan } 197bbeaf6c0SSean Eric Fagan if (ioctl(Procfd, PIOCCONT, &val) == -1) 198bbeaf6c0SSean Eric Fagan perror("PIOCCONT"); 199bbeaf6c0SSean Eric Fagan } while (pfs.why != S_EXIT); 200bbeaf6c0SSean Eric Fagan return 0; 201bbeaf6c0SSean Eric Fagan } 202