summaryrefslogtreecommitdiffstats
path: root/usr.bin/truss
diff options
context:
space:
mode:
authoralfred <alfred@FreeBSD.org>2005-03-27 12:47:04 +0000
committeralfred <alfred@FreeBSD.org>2005-03-27 12:47:04 +0000
commit9e2b623bb53bb398a766b27fc6714ca9564ca285 (patch)
tree2455ba9de956e732e4192e0e6894a749db47fa75 /usr.bin/truss
parent74837aa85b0d646e89c04c798b9dcb89c2742630 (diff)
downloadFreeBSD-src-9e2b623bb53bb398a766b27fc6714ca9564ca285.zip
FreeBSD-src-9e2b623bb53bb398a766b27fc6714ca9564ca285.tar.gz
I've been working on this somewhat so I'm moving the
parts I'm touching to be as style(9) compliant as I can.
Diffstat (limited to 'usr.bin/truss')
-rw-r--r--usr.bin/truss/main.c449
-rw-r--r--usr.bin/truss/setup.c193
2 files changed, 329 insertions, 313 deletions
diff --git a/usr.bin/truss/main.c b/usr.bin/truss/main.c
index 8822d9e..ce61db2 100644
--- a/usr.bin/truss/main.c
+++ b/usr.bin/truss/main.c
@@ -66,13 +66,13 @@ __FBSDID("$FreeBSD$");
int Procfd;
-static __inline void
+static void
usage(void)
{
- fprintf(stderr, "%s\n%s\n",
- "usage: truss [-faedDS] [-o file] -p pid",
- " truss [-faedDS] [-o file] command [args]");
- exit(1);
+ fprintf(stderr, "%s\n%s\n",
+ "usage: truss [-faedDS] [-o file] -p pid",
+ " truss [-faedDS] [-o file] command [args]");
+ exit(1);
}
/*
@@ -80,29 +80,29 @@ usage(void)
* work correctly.
*/
struct ex_types {
- const char *type;
- void (*enter_syscall)(struct trussinfo *, int);
- long (*exit_syscall)(struct trussinfo *, int);
+ const char *type;
+ void (*enter_syscall)(struct trussinfo *, int);
+ long (*exit_syscall)(struct trussinfo *, int);
} ex_types[] = {
#ifdef __alpha__
- { "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit },
+ { "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit },
#endif
#ifdef __amd64__
- { "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit },
+ { "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit },
#endif
#ifdef __i386__
- { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },
- { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit },
- { "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit },
- { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit },
+ { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },
+ { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit },
+ { "FreeBSD ELF32", i386_syscall_entry, i386_syscall_exit },
+ { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit },
#endif
#ifdef __ia64__
- { "FreeBSD ELF64", ia64_syscall_entry, ia64_syscall_exit },
+ { "FreeBSD ELF64", ia64_syscall_entry, ia64_syscall_exit },
#endif
#ifdef __sparc64__
- { "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
+ { "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
#endif
- { 0, 0, 0 },
+ { 0, 0, 0 },
};
/*
@@ -112,31 +112,32 @@ struct ex_types {
*/
static struct ex_types *
-set_etype(struct trussinfo *trussinfo) {
- struct ex_types *funcs;
- char etype[24];
- char progt[32];
- int fd;
-
- sprintf(etype, "/proc/%d/etype", trussinfo->pid);
- if ((fd = open(etype, O_RDONLY)) == -1) {
- strcpy(progt, "FreeBSD a.out");
- } else {
- int len = read(fd, progt, sizeof(progt));
- progt[len-1] = '\0';
- close(fd);
- }
-
- for (funcs = ex_types; funcs->type; funcs++)
- if (!strcmp(funcs->type, progt))
- break;
-
- if (funcs->type == NULL) {
- funcs = &ex_types[0];
- warn("execution type %s is not supported -- using %s",
- progt, funcs->type);
- }
- return funcs;
+set_etype(struct trussinfo *trussinfo)
+{
+ struct ex_types *funcs;
+ char etype[24];
+ char progt[32];
+ int fd;
+
+ sprintf(etype, "/proc/%d/etype", trussinfo->pid);
+ if ((fd = open(etype, O_RDONLY)) == -1) {
+ strcpy(progt, "FreeBSD a.out");
+ } else {
+ int len = read(fd, progt, sizeof(progt));
+ progt[len-1] = '\0';
+ close(fd);
+ }
+
+ for (funcs = ex_types; funcs->type; funcs++)
+ if (!strcmp(funcs->type, progt))
+ break;
+
+ if (funcs->type == NULL) {
+ funcs = &ex_types[0];
+ warn("execution type %s is not supported -- using %s",
+ progt, funcs->type);
+ }
+ return (funcs);
}
char *
@@ -157,187 +158,199 @@ strsig(int sig)
}
int
-main(int ac, char **av) {
- int c;
- int i;
- char **command;
- struct procfs_status pfs;
- struct ex_types *funcs;
- int in_exec = 0;
- char *fname = NULL;
- int sigexit = 0;
- struct trussinfo *trussinfo;
- char *signame;
-
- /* Initialize the trussinfo struct */
- trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo));
- if (trussinfo == NULL)
- errx(1, "malloc() failed");
- bzero(trussinfo, sizeof(struct trussinfo));
- trussinfo->outfile = stderr;
-
- while ((c = getopt(ac, av, "p:o:faedDS")) != -1) {
- switch (c) {
- case 'p': /* specified pid */
- trussinfo->pid = atoi(optarg);
- break;
- case 'f': /* Follow fork()'s */
- trussinfo->flags |= FOLLOWFORKS;
- break;
- case 'a': /* Print execve() argument strings. */
- trussinfo->flags |= EXECVEARGS;
- break;
- case 'e': /* Print execve() environment strings. */
- trussinfo->flags |= EXECVEENVS;
- break;
- case 'd': /* Absolute timestamps */
- trussinfo->flags |= ABSOLUTETIMESTAMPS;
- break;
- case 'D': /* Relative timestamps */
- trussinfo->flags |= RELATIVETIMESTAMPS;
- break;
- case 'o': /* Specified output file */
- fname = optarg;
- break;
- case 'S': /* Don't trace signals */
- trussinfo->flags |= NOSIGS;
- break;
- default:
- usage();
- }
- }
-
- ac -= optind; av += optind;
- if ((trussinfo->pid == 0 && ac == 0) || (trussinfo->pid != 0 && ac != 0))
- usage();
-
- if (fname != NULL) { /* Use output file */
- if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
- errx(1, "cannot open %s", fname);
- }
-
- /*
- * If truss starts the process itself, it will ignore some signals --
- * they should be passed off to the process, which may or may not
- * exit. If, however, we are examining an already-running process,
- * then we restore the event mask on these same signals.
- */
-
- if (trussinfo->pid == 0) { /* Start a command ourselves */
- command = av;
- trussinfo->pid = setup_and_wait(command);
- signal(SIGINT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- } else {
- signal(SIGINT, restore_proc);
- signal(SIGTERM, restore_proc);
- signal(SIGQUIT, restore_proc);
- }
-
-
- /*
- * At this point, if we started the process, it is stopped waiting to
- * be woken up, either in exit() or in execve().
- */
+main(int ac, char **av)
+{
+ int c;
+ int i;
+ char **command;
+ struct procfs_status pfs;
+ struct ex_types *funcs;
+ int in_exec = 0;
+ char *fname = NULL;
+ int sigexit = 0;
+ struct trussinfo *trussinfo;
+ char *signame;
+
+ /* Initialize the trussinfo struct */
+ trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo));
+ if (trussinfo == NULL)
+ errx(1, "malloc() failed");
+ bzero(trussinfo, sizeof(struct trussinfo));
+ trussinfo->outfile = stderr;
+
+ while ((c = getopt(ac, av, "p:o:faedDS")) != -1) {
+ switch (c) {
+ case 'p': /* specified pid */
+ trussinfo->pid = atoi(optarg);
+ break;
+ case 'f': /* Follow fork()'s */
+ trussinfo->flags |= FOLLOWFORKS;
+ break;
+ case 'a': /* Print execve() argument strings. */
+ trussinfo->flags |= EXECVEARGS;
+ break;
+ case 'e': /* Print execve() environment strings. */
+ trussinfo->flags |= EXECVEENVS;
+ break;
+ case 'd': /* Absolute timestamps */
+ trussinfo->flags |= ABSOLUTETIMESTAMPS;
+ break;
+ case 'D': /* Relative timestamps */
+ trussinfo->flags |= RELATIVETIMESTAMPS;
+ break;
+ case 'o': /* Specified output file */
+ fname = optarg;
+ break;
+ case 'S': /* Don't trace signals */
+ trussinfo->flags |= NOSIGS;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ ac -= optind; av += optind;
+ if ((trussinfo->pid == 0 && ac == 0) ||
+ (trussinfo->pid != 0 && ac != 0))
+ usage();
+
+ if (fname != NULL) { /* Use output file */
+ if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
+ errx(1, "cannot open %s", fname);
+ }
-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(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.
- */
-
- clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
-
- do {
- int val = 0;
-
- if (ioctl(Procfd, PIOCWAIT, &pfs) == -1)
- warn("PIOCWAIT top of loop");
- else {
- switch(i = pfs.why) {
- case S_SCE:
- funcs->enter_syscall(trussinfo, pfs.val);
- clock_gettime(CLOCK_REALTIME, &trussinfo->before);
- break;
- case S_SCX:
- clock_gettime(CLOCK_REALTIME, &trussinfo->after);
/*
- * 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 truss starts the process itself, it will ignore some signals --
+ * they should be passed off to the process, which may or may not
+ * exit. If, however, we are examining an already-running process,
+ * then we restore the event mask on these same signals.
*/
- if (in_exec) {
- in_exec = 0;
- break;
+ if (trussinfo->pid == 0) { /* Start a command ourselves */
+ command = av;
+ trussinfo->pid = setup_and_wait(command);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTERM, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ } else {
+ signal(SIGINT, restore_proc);
+ signal(SIGTERM, restore_proc);
+ signal(SIGQUIT, restore_proc);
}
- 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:
- signame = strsig(pfs.val);
- fprintf(trussinfo->outfile, "SIGNAL %lu (%s)\n", pfs.val,
- signame == NULL ? "?" : signame);
- free(signame);
- sigexit = pfs.val;
- break;
- case S_EXIT:
- fprintf (trussinfo->outfile, "process exit, rval = %lu\n", pfs.val);
- break;
- case S_EXEC:
+
+ /*
+ * At this point, if we started the process, it is stopped waiting to
+ * 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 & FOLLOWFORKS) ? PF_FORK : 0));
+ if (Procfd == -1)
+ return (0);
+
+ pfs.why = 0;
+
funcs = set_etype(trussinfo);
- in_exec = 1;
- break;
- default:
- fprintf (trussinfo->outfile, "Process stopped because of: %d\n", i);
- break;
- }
- }
- if (ioctl(Procfd, PIOCCONT, val) == -1) {
- if (kill(trussinfo->pid, 0) == -1 && errno == ESRCH)
- break;
- else
- warn("PIOCCONT");
- }
- } while (pfs.why != S_EXIT);
- fflush(trussinfo->outfile);
- if (sigexit) {
- struct rlimit rlp;
-
- rlp.rlim_cur = 0;
- rlp.rlim_max = 0;
- setrlimit(RLIMIT_CORE, &rlp);
- (void) signal(sigexit, SIG_DFL);
- (void) kill(getpid(), sigexit);
- }
- return 0;
+ /*
+ * 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.
+ */
+
+ clock_gettime(CLOCK_REALTIME, &trussinfo->start_time);
+
+ do {
+ int val = 0;
+
+ if (ioctl(Procfd, PIOCWAIT, &pfs) == -1)
+ warn("PIOCWAIT top of loop");
+ else {
+ switch(i = pfs.why) {
+ case S_SCE:
+ funcs->enter_syscall(trussinfo, pfs.val);
+ clock_gettime(CLOCK_REALTIME,
+ &trussinfo->before);
+ break;
+ case S_SCX:
+ clock_gettime(CLOCK_REALTIME,
+ &trussinfo->after);
+ /*
+ * 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:
+ signame = strsig(pfs.val);
+ fprintf(trussinfo->outfile,
+ "SIGNAL %lu (%s)\n", pfs.val,
+ signame == NULL ? "?" : signame);
+ free(signame);
+ sigexit = pfs.val;
+ break;
+ case S_EXIT:
+ fprintf(trussinfo->outfile,
+ "process exit, rval = %lu\n", pfs.val);
+ break;
+ case S_EXEC:
+ funcs = set_etype(trussinfo);
+ in_exec = 1;
+ break;
+ default:
+ fprintf(trussinfo->outfile,
+ "Process stopped because of: %d\n", i);
+ break;
+ }
+ }
+ if (ioctl(Procfd, PIOCCONT, val) == -1) {
+ if (kill(trussinfo->pid, 0) == -1 && errno == ESRCH)
+ break;
+ else
+ warn("PIOCCONT");
+ }
+ } while (pfs.why != S_EXIT);
+ fflush(trussinfo->outfile);
+ if (sigexit) {
+ struct rlimit rlp;
+
+ rlp.rlim_cur = 0;
+ rlp.rlim_max = 0;
+ setrlimit(RLIMIT_CORE, &rlp);
+ (void) signal(sigexit, SIG_DFL);
+ (void) kill(getpid(), sigexit);
+ }
+ return (0);
}
diff --git a/usr.bin/truss/setup.c b/usr.bin/truss/setup.c
index 91cd1cf..fa52dd6 100644
--- a/usr.bin/truss/setup.c
+++ b/usr.bin/truss/setup.c
@@ -64,61 +64,62 @@ static int evflags = 0;
*/
int
-setup_and_wait(char *command[]) {
- struct procfs_status pfs;
- char buf[32];
- int fd;
- int pid;
- int flags;
-
- pid = fork();
- if (pid == -1) {
- err(1, "fork failed");
- }
- if (pid == 0) { /* Child */
- int mask = S_EXEC | S_EXIT;
- fd = open("/proc/curproc/mem", O_WRONLY);
- if (fd == -1)
- err(2, "cannot open /proc/curproc/mem");
- fcntl(fd, F_SETFD, 1);
- if (ioctl(fd, PIOCBIS, mask) == -1)
- err(3, "PIOCBIS");
- flags = PF_LINGER;
- /*
- * The PF_LINGER flag tells procfs not to wake up the
- * process on last close; normally, this is the behaviour
- * we want.
- */
- if (ioctl(fd, PIOCSFL, flags) == -1)
- warn("cannot set PF_LINGER");
- execvp(command[0], command);
- mask = ~0;
- ioctl(fd, PIOCBIC, ~0);
- err(4, "execvp %s", command[0]);
- }
- /* Only in the parent here */
-
- if (waitpid(pid, NULL, WNOHANG) != 0) {
- /*
- * Process exited before it got to us -- meaning the exec failed
- * miserably -- so we just quietly exit.
- */
- exit(1);
- }
-
- sprintf(buf, "/proc/%d/mem", pid);
- if ((fd = open(buf, O_RDWR)) == -1)
- err(5, "cannot open %s", buf);
- if (ioctl(fd, PIOCWAIT, &pfs) == -1)
- err(6, "PIOCWAIT");
- if (pfs.why == S_EXIT) {
- warnx("process exited before exec'ing");
- ioctl(fd, PIOCCONT, 0);
- wait(0);
- exit(7);
- }
- close(fd);
- return pid;
+setup_and_wait(char *command[])
+{
+ struct procfs_status pfs;
+ char buf[32];
+ int fd;
+ int pid;
+ int flags;
+
+ pid = fork();
+ if (pid == -1) {
+ err(1, "fork failed");
+ }
+ if (pid == 0) { /* Child */
+ int mask = S_EXEC | S_EXIT;
+ fd = open("/proc/curproc/mem", O_WRONLY);
+ if (fd == -1)
+ err(2, "cannot open /proc/curproc/mem");
+ fcntl(fd, F_SETFD, 1);
+ if (ioctl(fd, PIOCBIS, mask) == -1)
+ err(3, "PIOCBIS");
+ flags = PF_LINGER;
+ /*
+ * The PF_LINGER flag tells procfs not to wake up the
+ * process on last close; normally, this is the behaviour
+ * we want.
+ */
+ if (ioctl(fd, PIOCSFL, flags) == -1)
+ warn("cannot set PF_LINGER");
+ execvp(command[0], command);
+ mask = ~0;
+ ioctl(fd, PIOCBIC, ~0);
+ err(4, "execvp %s", command[0]);
+ }
+ /* Only in the parent here */
+
+ if (waitpid(pid, NULL, WNOHANG) != 0) {
+ /*
+ * Process exited before it got to us -- meaning the exec failed
+ * miserably -- so we just quietly exit.
+ */
+ exit(1);
+ }
+
+ sprintf(buf, "/proc/%d/mem", pid);
+ if ((fd = open(buf, O_RDWR)) == -1)
+ err(5, "cannot open %s", buf);
+ if (ioctl(fd, PIOCWAIT, &pfs) == -1)
+ err(6, "PIOCWAIT");
+ if (pfs.why == S_EXIT) {
+ warnx("process exited before exec'ing");
+ ioctl(fd, PIOCCONT, 0);
+ wait(0);
+ exit(7);
+ }
+ close(fd);
+ return (pid);
}
/*
@@ -128,42 +129,44 @@ setup_and_wait(char *command[]) {
*/
int
-start_tracing(int pid, int eventflags, int flags) {
- int fd;
- char buf[32];
- struct procfs_status tmp;
- sprintf(buf, "/proc/%d/mem", pid);
-
- fd = open(buf, O_RDWR);
- if (fd == -1) {
- /*
- * The process may have run away before we could start -- this
- * happens with SUGID programs. So we need to see if it still
- * exists before we complain bitterly.
- */
- if (kill(pid, 0) == -1)
- return -1;
- err(8, "cannot open %s", buf);
- }
-
- if (ioctl(fd, PIOCSTATUS, &tmp) == -1) {
- err(10, "cannot get procfs status struct");
- }
- evflags = tmp.events;
-
- if (ioctl(fd, PIOCBIS, eventflags) == -1)
- err(9, "cannot set procfs event bit mask");
-
- /*
- * This clears the PF_LINGER set above in setup_and_wait();
- * if truss happens to die before this, then the process
- * needs to be woken up via procctl.
- */
-
- if (ioctl(fd, PIOCSFL, flags) == -1)
- warn("cannot clear PF_LINGER");
-
- return fd;
+start_tracing(int pid, int eventflags, int flags)
+{
+ int fd;
+ char buf[32];
+ struct procfs_status tmp;
+
+ sprintf(buf, "/proc/%d/mem", pid);
+
+ fd = open(buf, O_RDWR);
+ if (fd == -1) {
+ /*
+ * The process may have run away before we could start -- this
+ * happens with SUGID programs. So we need to see if it still
+ * exists before we complain bitterly.
+ */
+ if (kill(pid, 0) == -1)
+ return -1;
+ err(8, "cannot open %s", buf);
+ }
+
+ if (ioctl(fd, PIOCSTATUS, &tmp) == -1) {
+ err(10, "cannot get procfs status struct");
+ }
+ evflags = tmp.events;
+
+ if (ioctl(fd, PIOCBIS, eventflags) == -1)
+ err(9, "cannot set procfs event bit mask");
+
+ /*
+ * This clears the PF_LINGER set above in setup_and_wait();
+ * if truss happens to die before this, then the process
+ * needs to be woken up via procctl.
+ */
+
+ if (ioctl(fd, PIOCSFL, flags) == -1)
+ warn("cannot clear PF_LINGER");
+
+ return (fd);
}
/*
@@ -175,8 +178,8 @@ start_tracing(int pid, int eventflags, int flags) {
void
restore_proc(int signo __unused) {
- ioctl(Procfd, PIOCBIC, ~0);
- if (evflags)
- ioctl(Procfd, PIOCBIS, evflags);
- exit(0);
+ ioctl(Procfd, PIOCBIC, ~0);
+ if (evflags)
+ ioctl(Procfd, PIOCBIS, evflags);
+ exit(0);
}
OpenPOWER on IntegriCloud