From owner-freebsd-bugs Thu Oct 18 2:50:37 2001 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id 5EA2937B405 for ; Thu, 18 Oct 2001 02:50:01 -0700 (PDT) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.4/8.11.4) id f9I9o1n39783; Thu, 18 Oct 2001 02:50:01 -0700 (PDT) (envelope-from gnats) Date: Thu, 18 Oct 2001 02:50:01 -0700 (PDT) Message-Id: <200110180950.f9I9o1n39783@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: Thomas Quinot Subject: bin/25587: truss -f patch updated for -CURRENT 20011017 Reply-To: Thomas Quinot Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org The following reply was made to PR bin/25587; it has been noted by GNATS. From: Thomas Quinot To: freebsd-gnats-submit@freebsd.org Cc: winter@jurai.net Subject: bin/25587: truss -f patch updated for -CURRENT 20011017 Date: Thu, 18 Oct 2001 11:48:59 +0200 Hi, Having sent a PR suggesting the same functionality enhancement (31285) I was pointed to this one, which already had a patch available. I updated the patch for -CURRENT as of yesterday. Matthew, could you have a look at the updated diff? Thanks, Thomas. --- sys/kern/kern_fork.c.orig Wed Oct 10 14:58:20 2001 +++ sys/kern/kern_fork.c Wed Oct 17 18:40:14 2001 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -682,6 +683,16 @@ while (p2->p_flag & P_PPWAIT) msleep(p1, &p2->p_mtx, PWAIT, "ppwait", 0); PROC_UNLOCK(p2); + + /* + * If PF_FORK is set, the child process inherits the + * procfs ioctl flags from its parent. + */ + if (p1->p_pfsflags & PF_FORK) + { + p2->p_stops = p1->p_stops; + p2->p_pfsflags = p1->p_pfsflags; + } /* * Return child proc pointer to parent. --- sys/sys/pioctl.h.orig Sat Aug 28 02:51:55 1999 +++ sys/sys/pioctl.h Wed Oct 17 18:40:22 2001 @@ -74,4 +74,5 @@ # define PF_LINGER 0x01 /* Keep stops around after last close */ # define PF_ISUGID 0x02 /* Ignore UID/GID changes */ +# define PF_FORK 0x04 /* Retain settings on fork() */ #endif --- usr.bin/truss/truss.h.orig Wed Oct 17 18:51:31 2001 +++ usr.bin/truss/truss.h Wed Oct 17 18:47:46 2001 @@ -0,0 +1,41 @@ +/* + * Copryight 2001 Jamey Wood + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define FOLLOWFORKS 0x00000001 +#define RELATIVETIMESTAMPS 0x00000002 +#define ABSOLUTETIMESTAMPS 0x00000004 +#define NOSIGS 0x00000008 + +struct trussinfo +{ + int pid; + int flags; + int in_fork; + FILE *outfile; + + struct timeval start_time; + struct timeval before; + struct timeval after; +}; --- usr.bin/truss/alpha-fbsd.c.orig Sat Mar 18 09:49:40 2000 +++ usr.bin/truss/alpha-fbsd.c Wed Oct 17 18:40:46 2001 @@ -58,13 +58,13 @@ #include #include +#include "truss.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "syscalls.h" static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); @@ -111,7 +111,7 @@ */ void -alpha_syscall_entry(int pid, int nargs) { +alpha_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { { 0 } }; int syscall; @@ -120,14 +120,14 @@ struct syscall *sc; int indir = 0; /* indirect system call */ - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_fsc(); @@ -150,7 +150,15 @@ fsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; if (!fsc.name) { - fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); + } + + if (fsc.name + && ((!strcmp(fsc.name, "fork") + || !strcmp(fsc.name, "rfork") + || !strcmp(fsc.name, "vfork")))) + { + trussinfo->in_fork = 1; } if (nargs == 0) @@ -192,7 +200,7 @@ fsc.nargs = sc->nargs; } else { #if DEBUG - fprintf(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", fsc.name, nargs); #endif fsc.nargs = nargs; @@ -233,7 +241,7 @@ } #if DEBUG - fprintf(outfile, "\n"); + fprintf(trussinfo->outfile, "\n"); #endif /* @@ -244,7 +252,7 @@ */ if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { - print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); + print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); } return; @@ -257,8 +265,8 @@ * the sytem call number instead of, say, an error status). */ -void -alpha_syscall_exit(int pid, int syscall) { +int +alpha_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; @@ -266,14 +274,14 @@ int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); @@ -321,8 +329,8 @@ * but that complicates things considerably. */ - print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); + print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); clear_fsc(); - return; + return retval; } --- usr.bin/truss/i386-fbsd.c.orig Sat Mar 18 09:49:40 2000 +++ usr.bin/truss/i386-fbsd.c Wed Oct 17 18:40:46 2001 @@ -55,13 +55,13 @@ #include #include +#include "truss.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "syscalls.h" static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); @@ -108,7 +108,7 @@ */ void -i386_syscall_entry(int pid, int nargs) { +i386_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { 0 }; int syscall; @@ -116,14 +116,14 @@ unsigned int parm_offset; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_fsc(); @@ -154,7 +154,16 @@ fsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; if (!fsc.name) { - fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); + } + + if (fsc.name && (trussinfo->flags & FOLLOWFORKS) + && ((!strcmp(fsc.name, "fork") + || !strcmp(fsc.name, "rfork") + || !strcmp(fsc.name, "vfork")))) + { + fprintf(stderr, "setting trussinfo->in_fork = 1\n"); + trussinfo->in_fork = 1; } if (nargs == 0) @@ -170,7 +179,7 @@ fsc.nargs = sc->nargs; } else { #if DEBUG - fprintf(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", fsc.name, nargs); #endif fsc.nargs = nargs; @@ -211,7 +220,7 @@ } #if DEBUG - fprintf(outfile, "\n"); + fprintf(trussinfo->outfile, "\n"); #endif /* @@ -222,7 +231,7 @@ */ if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { - print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); + print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); } return; @@ -235,8 +244,8 @@ * the sytem call number instead of, say, an error status). */ -void -i386_syscall_exit(int pid, int syscall) { +int +i386_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; @@ -244,14 +253,14 @@ int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); @@ -299,8 +308,8 @@ * but that complicates things considerably. */ - print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); + print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); clear_fsc(); - return; + return retval; } --- usr.bin/truss/i386-linux.c.orig Sat Mar 18 09:49:40 2000 +++ usr.bin/truss/i386-linux.c Wed Oct 17 18:40:46 2001 @@ -52,13 +52,13 @@ #include #include +#include "truss.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "linux_syscalls.h" static int nsyscalls = @@ -87,21 +87,21 @@ } void -i386_linux_syscall_entry(int pid, int nargs) { +i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { 0 }; int syscall; int i; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_lsc(); @@ -113,7 +113,14 @@ lsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : linux_syscallnames[syscall]; if (!lsc.name) { - fprintf (outfile, "-- UNKNOWN SYSCALL %d\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d\n", syscall); + } + + if (lsc.name + && ((!strcmp(lsc.name, "linux_fork") + || !strcmp(lsc.name, "linux_vfork")))) + { + trussinfo->in_fork = 1; } if (nargs == 0) @@ -138,7 +145,7 @@ lsc.nargs = sc->nargs; } else { #ifdef DEBUG - fprintf(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", lsc.name, nargs); #endif lsc.nargs = nargs; @@ -171,7 +178,7 @@ } if (!strcmp(lsc.name, "linux_execve") || !strcmp(lsc.name, "exit")) { - print_syscall(outfile, lsc.name, lsc.nargs, lsc.s_args); + print_syscall(trussinfo, lsc.name, lsc.nargs, lsc.s_args); } return; @@ -192,8 +199,8 @@ -6, }; -void -i386_linux_syscall_exit(int pid, int syscall) { +int +i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; @@ -201,14 +208,14 @@ int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); @@ -243,7 +250,7 @@ if (retval == bsd_to_linux_errno[i]) break; } - print_syscall_ret(outfile, lsc.name, lsc.nargs, lsc.s_args, errorp, i); + print_syscall_ret(trussinfo, lsc.name, lsc.nargs, lsc.s_args, errorp, i); clear_lsc(); - return; + return retval; } --- usr.bin/truss/setup.c.orig Mon Jan 10 05:09:05 2000 +++ usr.bin/truss/setup.c Wed Oct 17 18:40:46 2001 @@ -126,7 +126,7 @@ */ int -start_tracing(int pid, int flags) { +start_tracing(int pid, int eventflags, int flags) { int fd; char buf[32]; struct procfs_status tmp; @@ -149,7 +149,7 @@ } evflags = tmp.events; - if (ioctl(fd, PIOCBIS, flags) == -1) + if (ioctl(fd, PIOCBIS, eventflags) == -1) err(9, "cannot set procfs event bit mask"); /* @@ -158,7 +158,7 @@ * needs to be woken up via procctl. */ - if (ioctl(fd, PIOCSFL, 0) == -1) + if (ioctl(fd, PIOCSFL, flags) == -1) warn("cannot clear PF_LINGER"); return fd; --- usr.bin/truss/syscall.h.orig Sat Mar 18 09:49:41 2000 +++ usr.bin/truss/syscall.h Wed Oct 17 18:40:46 2001 @@ -44,5 +44,5 @@ struct syscall *get_syscall(const char*); char *get_string(int, void*, int); char *print_arg(int, struct syscall_args *, unsigned long*); -void print_syscall(FILE *, const char *, int, char **); -void print_syscall_ret(FILE *, const char *, int, char **, int, int); +void print_syscall(struct trussinfo *, const char *, int, char **); +void print_syscall_ret(struct trussinfo *, const char *, int, char **, int, int); --- usr.bin/truss/syscalls.c.orig Mon Sep 3 17:23:53 2001 +++ usr.bin/truss/syscalls.c Wed Oct 17 18:40:46 2001 @@ -46,8 +46,15 @@ #include #include #include +#include + +#include "truss.h" #include "syscall.h" +extern int followforks; +extern int relativetimestamps; +extern int absolutetimestamps; + /* * This should probably be in its own file. */ @@ -255,28 +262,60 @@ */ void -print_syscall(FILE *outfile, const char *name, int nargs, char **s_args) { +print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) { int i; int len = 0; - len += fprintf(outfile, "%s(", name); + + struct timeval timediff; + + if (trussinfo->flags & FOLLOWFORKS) + len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); + + if (!strcmp(name, "execve") || !strcmp(name, "exit")) + { + gettimeofday(&trussinfo->after, (struct timezone *)NULL); + } + + if (trussinfo->flags & ABSOLUTETIMESTAMPS) + { + timediff.tv_sec = trussinfo->after.tv_sec - trussinfo->start_time.tv_sec; + timediff.tv_usec = trussinfo->after.tv_usec - trussinfo->start_time.tv_usec; + if (timediff.tv_usec < 0) + timediff.tv_sec--, timediff.tv_usec += 10000000; + + len += fprintf(trussinfo->outfile, "%d.%0.7d ", timediff.tv_sec, timediff.tv_usec); + } + + if (trussinfo->flags & RELATIVETIMESTAMPS) + { + timediff.tv_sec = trussinfo->after.tv_sec - trussinfo->before.tv_sec; + timediff.tv_usec = trussinfo->after.tv_usec - trussinfo->before.tv_usec; + if (timediff.tv_usec < 0) + timediff.tv_sec--, timediff.tv_usec += 10000000; + + len += fprintf(trussinfo->outfile, "%d.%0.7d ", timediff.tv_sec, timediff.tv_usec); + } + + len += fprintf(trussinfo->outfile, "%s(", name); + for (i = 0; i < nargs; i++) { if (s_args[i]) - len += fprintf(outfile, "%s", s_args[i]); + len += fprintf(trussinfo->outfile, "%s", s_args[i]); else - len += fprintf(outfile, ""); - len += fprintf(outfile, "%s", i < (nargs - 1) ? "," : ""); + len += fprintf(trussinfo->outfile, ""); + len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : ""); } - len += fprintf(outfile, ")"); + len += fprintf(trussinfo->outfile, ")"); for (i = 0; i < 6 - (len / 8); i++) - fprintf(outfile, "\t"); + fprintf(trussinfo->outfile, "\t"); } void -print_syscall_ret(FILE *outfile, const char *name, int nargs, char **s_args, int errorp, int retval) { - print_syscall(outfile, name, nargs, s_args); +print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args, int errorp, int retval) { + print_syscall(trussinfo, name, nargs, s_args); if (errorp) { - fprintf(outfile, " ERR#%d '%s'\n", retval, strerror(retval)); + fprintf(trussinfo->outfile, " ERR#%d '%s'\n", retval, strerror(retval)); } else { - fprintf(outfile, " = %d (0x%x)\n", retval, retval); + fprintf(trussinfo->outfile, " = %d (0x%x)\n", retval, retval); } } --- usr.bin/truss/truss.1.orig Mon Jul 16 10:44:19 2001 +++ usr.bin/truss/truss.1 Wed Oct 17 18:40:46 2001 @@ -8,11 +8,11 @@ .Nd trace system calls .Sh SYNOPSIS .Nm -.Op Fl S +.Op Fl fdDS .Op Fl o Ar file .Fl p Ar pid .Nm -.Op Fl S +.Op Fl fdDS .Op Fl o Ar file command .Op args @@ -25,6 +25,15 @@ .Pp The options are as follows: .Bl -tag -width indent +.It Fl f +Trace decendants of the original traced process created by fork(), +vfork, etc. +.It Fl d +Include timestamps in the output showing the time elapsed +since the trace was started. +.It Fl D +Include timestamps in the output showing the time elapsed +since the last recorded event. .It Fl S Do not display information about signals received by the process. (Normally, --- usr.bin/truss/main.c.orig Wed Oct 17 18:56:38 2001 +++ usr.bin/truss/main.c Wed Oct 17 18:47:22 2001 @@ -11,7 +11,7 @@ * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: - * This product includes software developed by Sean Eric Fagan + * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. @@ -50,37 +50,36 @@ #include #include #include +#include + +#include "truss.h" extern int setup_and_wait(char **); -extern int start_tracing(int, int); +extern int start_tracing(int, int, int); #ifdef __alpha__ -extern void alpha_syscall_entry(int, int); -extern void alpha_syscall_exit(int, int); +extern void alpha_syscall_entry(struct trussinfo *, int); +extern void alpha_syscall_exit(struct trussinfo *, int); #endif #ifdef __i386__ -extern void i386_syscall_entry(int, int); -extern void i386_syscall_exit(int, int); -extern void i386_linux_syscall_entry(int, int); -extern void i386_linux_syscall_exit(int, int); +extern void i386_syscall_entry(struct trussinfo *, int); +extern void i386_syscall_exit(struct trussinfo *, int); +extern void i386_linux_syscall_entry(struct trussinfo *, int); +extern void i386_linux_syscall_exit(struct trussinfo *, int); #endif /* - * These should really be parameterized -- I don't like having globals, - * but this is the easiest way, right now, to deal with them. + * It's difficult to parameterize this because it must be + * accessible in a signal handler. */ -int pid = 0; -int nosigs = 0; -FILE *outfile; int Procfd; -char progtype[50]; /* OS and type of executable */ static inline void usage(void) { fprintf(stderr, "%s\n%s\n", - "usage: truss [-S] [-o file] -p pid", - " truss [-S] [-o file] command [args]"); + "usage: truss [-fdDS] [-o file] -p pid", + " truss [-fdDS] [-o file] command [args]"); exit(1); } @@ -90,8 +89,8 @@ */ struct ex_types { char *type; - void (*enter_syscall)(int, int); - void (*exit_syscall)(int, int); + void (*enter_syscall)(struct trussinfo *, int); + int (*exit_syscall)(struct trussinfo *, int); } ex_types[] = { #ifdef __alpha__ { "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit }, @@ -111,13 +110,13 @@ */ static struct ex_types * -set_etype() { +set_etype(struct trussinfo *trussinfo) { struct ex_types *funcs; char etype[24]; char progtype[32]; int fd; - sprintf(etype, "/proc/%d/etype", pid); + sprintf(etype, "/proc/%d/etype", trussinfo->pid); if ((fd = open(etype, O_RDONLY)) == -1) { strcpy(progtype, "FreeBSD a.out"); } else { @@ -148,18 +147,34 @@ int in_exec = 0; char *fname = NULL; int sigexit = 0; + struct trussinfo *trussinfo; + + /* Initialize the trussinfo struct */ + if ((trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo))) + == NULL) + errx(1, "malloc() failed"); + bzero(trussinfo, sizeof(struct trussinfo)); + trussinfo->outfile = stderr; - outfile = stdout; - while ((c = getopt(ac, av, "p:o:S")) != -1) { + while ((c = getopt(ac, av, "p:o:fdDS")) != -1) { switch (c) { - case 'p': /* specified pid */ - pid = atoi(optarg); + case 'p': /* specified pid */ + trussinfo->pid = atoi(optarg); + break; + case 'f': /* Follow fork()'s */ + trussinfo->flags |= FOLLOWFORKS; + break; + case 'd': /* Absolute timestamps */ + trussinfo->flags |= ABSOLUTETIMESTAMPS; break; - case 'o': /* Specified output file */ + case 'D': /* Relative timestamps */ + trussinfo->flags |= RELATIVETIMESTAMPS; + break; + case 'o': /* Specified output file */ fname = optarg; break; - case 'S': /* Don't trace signals */ - nosigs = 1; + case 'S': /* Don't trace signals */ + trussinfo->flags |= NOSIGS; break; default: usage(); @@ -167,11 +183,11 @@ } ac -= optind; av += optind; - if ((pid == 0 && ac == 0) || (pid != 0 && ac != 0)) + if ((trussinfo->pid == 0 && ac == 0) || (trussinfo->pid != 0 && ac != 0)) usage(); if (fname != NULL) { /* Use output file */ - if ((outfile = fopen(fname, "w")) == NULL) + if ((trussinfo->outfile = fopen(fname, "w")) == NULL) errx(1, "cannot open %s", fname); } @@ -182,9 +198,9 @@ * then we restore the event mask on these same signals. */ - if (pid == 0) { /* Start a command ourselves */ + if (trussinfo->pid == 0) { /* Start a command ourselves */ command = av; - pid = setup_and_wait(command); + trussinfo->pid = setup_and_wait(command); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGQUIT, SIG_IGN); @@ -201,20 +217,25 @@ * be woken up, either in exit() or in execve(). */ - Procfd = start_tracing(pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | - (nosigs ? 0 : S_SIG)); +START_TRACE: + Procfd = start_tracing( + trussinfo->pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | + ((trussinfo->flags & NOSIGS) ? 0 : S_SIG), + ((trussinfo->flags & FOLLOWFORKS) ? PF_FORK : 0)); if (Procfd == -1) return 0; pfs.why = 0; - funcs = set_etype(); + funcs = set_etype(trussinfo); /* * At this point, it's a simple loop, waiting for the process to * stop, finding out why, printing out why, and then continuing it. * All of the grunt work is done in the support routines. */ + gettimeofday(&trussinfo->start_time, (struct timezone *)NULL); + do { int val = 0; @@ -223,46 +244,68 @@ else { switch(i = pfs.why) { case S_SCE: - funcs->enter_syscall(pid, pfs.val); - break; + funcs->enter_syscall(trussinfo, pfs.val); + gettimeofday(&trussinfo->before, (struct timezone *)NULL); + break; case S_SCX: - /* - * This is so we don't get two messages for an exec -- one - * for the S_EXEC, and one for the syscall exit. It also, - * conveniently, ensures that the first message printed out - * isn't the return-from-syscall used to create the process. - */ - - if (in_exec) { - in_exec = 0; - break; - } - funcs->exit_syscall(pid, pfs.val); - break; + gettimeofday(&trussinfo->after, (struct timezone *)NULL); + + /* + * This is so we don't get two messages for an exec -- one + * for the S_EXEC, and one for the syscall exit. It also, + * conveniently, ensures that the first message printed out + * isn't the return-from-syscall used to create the process. + */ + + if (in_exec) { + in_exec = 0; + break; + } + + if (trussinfo->in_fork && (trussinfo->flags & FOLLOWFORKS)) + { + int childpid; + + trussinfo->in_fork = 0; + childpid = funcs->exit_syscall(trussinfo, pfs.val); + + /* + * Fork a new copy of ourself to trace the child of the + * original traced process. + */ + if (fork() == 0) + { + trussinfo->pid = childpid; + goto START_TRACE; + } + break; + } + funcs->exit_syscall(trussinfo, pfs.val); + break; case S_SIG: - fprintf(outfile, "SIGNAL %lu\n", pfs.val); - sigexit = pfs.val; - break; + fprintf(trussinfo->outfile, "SIGNAL %lu\n", pfs.val); + sigexit = pfs.val; + break; case S_EXIT: - fprintf (outfile, "process exit, rval = %lu\n", pfs.val); - break; + fprintf (trussinfo->outfile, "process exit, rval = %lu\n", pfs.val); + break; case S_EXEC: - funcs = set_etype(); - in_exec = 1; - break; + funcs = set_etype(trussinfo); + in_exec = 1; + break; default: - fprintf (outfile, "Process stopped because of: %d\n", i); - break; + fprintf (trussinfo->outfile, "Process stopped because of: %d\n", i); + break; } } if (ioctl(Procfd, PIOCCONT, val) == -1) { - if (kill(pid, 0) == -1 && errno == ESRCH) - break; + if (kill(trussinfo->pid, 0) == -1 && errno == ESRCH) + break; else - warn("PIOCCONT"); + warn("PIOCCONT"); } } while (pfs.why != S_EXIT); - fflush(outfile); + fflush(trussinfo->outfile); if (sigexit) { if (sigexit == SIGQUIT) exit(sigexit); -- Thomas Quinot ** Département Informatique & Réseaux ** quinot@inf.enst.fr ENST // 46 rue Barrault // 75634 PARIS CEDEX 13 To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message