diff --git a/usr.bin/truss/alpha-fbsd.c b/usr.bin/truss/alpha-fbsd.c index 4a88ff1d94b5..a7b5baf12443 100644 --- a/usr.bin/truss/alpha-fbsd.c +++ b/usr.bin/truss/alpha-fbsd.c @@ -155,6 +155,14 @@ alpha_syscall_entry(struct trussinfo *trussinfo, int nargs) { 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")))) + { + trussinfo->in_fork = 1; + } + if (nargs == 0) return; diff --git a/usr.bin/truss/amd64-fbsd32.c b/usr.bin/truss/amd64-fbsd32.c index 702db80213f3..6364927ca620 100644 --- a/usr.bin/truss/amd64-fbsd32.c +++ b/usr.bin/truss/amd64-fbsd32.c @@ -160,6 +160,14 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) { 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")))) + { + trussinfo->in_fork = 1; + } + if (nargs == 0) return; diff --git a/usr.bin/truss/amd64-linux32.c b/usr.bin/truss/amd64-linux32.c index e6a560a34a4e..f307c8017307 100644 --- a/usr.bin/truss/amd64-linux32.c +++ b/usr.bin/truss/amd64-linux32.c @@ -120,6 +120,13 @@ i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) { fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d\n", syscall); } + if (lsc.name && (trussinfo->flags & FOLLOWFORKS) + && ((!strcmp(lsc.name, "linux_fork") + || !strcmp(lsc.name, "linux_vfork")))) + { + trussinfo->in_fork = 1; + } + if (nargs == 0) return; diff --git a/usr.bin/truss/extern.h b/usr.bin/truss/extern.h index ea7c435521b3..a708dda1b490 100644 --- a/usr.bin/truss/extern.h +++ b/usr.bin/truss/extern.h @@ -32,7 +32,7 @@ */ extern int setup_and_wait(char **); -extern int start_tracing(int, int); +extern int start_tracing(int, int, int); extern void restore_proc(int); extern const char *ioctlname(register_t val); #ifdef __alpha__ diff --git a/usr.bin/truss/i386-fbsd.c b/usr.bin/truss/i386-fbsd.c index 702db80213f3..6364927ca620 100644 --- a/usr.bin/truss/i386-fbsd.c +++ b/usr.bin/truss/i386-fbsd.c @@ -160,6 +160,14 @@ i386_syscall_entry(struct trussinfo *trussinfo, int nargs) { 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")))) + { + trussinfo->in_fork = 1; + } + if (nargs == 0) return; diff --git a/usr.bin/truss/i386-linux.c b/usr.bin/truss/i386-linux.c index e6a560a34a4e..f307c8017307 100644 --- a/usr.bin/truss/i386-linux.c +++ b/usr.bin/truss/i386-linux.c @@ -120,6 +120,13 @@ i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) { fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d\n", syscall); } + if (lsc.name && (trussinfo->flags & FOLLOWFORKS) + && ((!strcmp(lsc.name, "linux_fork") + || !strcmp(lsc.name, "linux_vfork")))) + { + trussinfo->in_fork = 1; + } + if (nargs == 0) return; diff --git a/usr.bin/truss/main.c b/usr.bin/truss/main.c index 503329ffc93e..d1a236a7992a 100644 --- a/usr.bin/truss/main.c +++ b/usr.bin/truss/main.c @@ -67,8 +67,8 @@ 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 [-fS] [-o file] -p pid", + " truss [-fS] [-o file] command [args]"); exit(1); } @@ -145,11 +145,14 @@ main(int ac, char **av) { bzero(trussinfo, sizeof(struct trussinfo)); trussinfo->outfile = stderr; - while ((c = getopt(ac, av, "p:o:S")) != -1) { + while ((c = getopt(ac, av, "p:o:fS")) != -1) { switch (c) { case 'p': /* specified pid */ trussinfo->pid = atoi(optarg); break; + case 'f': /* Follow fork()'s */ + trussinfo->flags |= FOLLOWFORKS; + break; case 'o': /* Specified output file */ fname = optarg; break; @@ -195,9 +198,11 @@ main(int ac, char **av) { * be woken up, either in exit() or in execve(). */ +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 & NOSIGS) ? 0 : S_SIG), + ((trussinfo->flags & FOLLOWFORKS) ? PF_FORK : 0)); if (Procfd == -1) return 0; @@ -232,6 +237,23 @@ main(int ac, char **av) { 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: diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c index baeb570af403..e3d52a4e5e93 100644 --- a/usr.bin/truss/setup.c +++ b/usr.bin/truss/setup.c @@ -130,7 +130,7 @@ setup_and_wait(char *command[]) { */ int -start_tracing(int pid, int flags) { +start_tracing(int pid, int eventflags, int flags) { int fd; char buf[32]; struct procfs_status tmp; @@ -153,7 +153,7 @@ start_tracing(int pid, int flags) { } evflags = tmp.events; - if (ioctl(fd, PIOCBIS, flags) == -1) + if (ioctl(fd, PIOCBIS, eventflags) == -1) err(9, "cannot set procfs event bit mask"); /* @@ -162,7 +162,7 @@ start_tracing(int pid, int flags) { * 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; diff --git a/usr.bin/truss/syscalls.c b/usr.bin/truss/syscalls.c index 432197fd89e1..8056aa122270 100644 --- a/usr.bin/truss/syscalls.c +++ b/usr.bin/truss/syscalls.c @@ -357,7 +357,12 @@ void print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) { int i; int len = 0; + + if (trussinfo->flags & FOLLOWFORKS) + len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); + len += fprintf(trussinfo->outfile, "%s(", name); + for (i = 0; i < nargs; i++) { if (s_args[i]) len += fprintf(trussinfo->outfile, "%s", s_args[i]); diff --git a/usr.bin/truss/truss.1 b/usr.bin/truss/truss.1 index f2a99cc79c03..58f9ac53d820 100644 --- a/usr.bin/truss/truss.1 +++ b/usr.bin/truss/truss.1 @@ -8,11 +8,11 @@ .Nd trace system calls .Sh SYNOPSIS .Nm -.Op Fl S +.Op Fl fS .Op Fl o Ar file .Fl p Ar pid .Nm -.Op Fl S +.Op Fl fS .Op Fl o Ar file command .Op args @@ -26,6 +26,9 @@ It does this by stopping and restarting the process being monitored via .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 S Do not display information about signals received by the process. (Normally, diff --git a/usr.bin/truss/truss.h b/usr.bin/truss/truss.h index 24396ad301e1..f77202aec264 100644 --- a/usr.bin/truss/truss.h +++ b/usr.bin/truss/truss.h @@ -25,11 +25,13 @@ * $FreeBSD$ */ +#define FOLLOWFORKS 0x00000001 #define NOSIGS 0x00000008 struct trussinfo { int pid; int flags; + int in_fork; FILE *outfile; };