Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F135023846
D3575.id8606.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
130 KB
Referenced Files
None
Subscribers
None
D3575.id8606.diff
View Options
Index: usr.bin/truss/amd64-fbsd.c
===================================================================
--- usr.bin/truss/amd64-fbsd.c
+++ usr.bin/truss/amd64-fbsd.c
@@ -29,290 +29,103 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * FreeBSD/amd64-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- */
+/* FreeBSD/amd64-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <machine/reg.h>
#include <machine/psl.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "syscalls.h"
-static int nsyscalls = nitems(syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in amd64/amd64/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-amd64_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+amd64_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
+ struct current_syscall *cs;
lwpid_t tid;
- int i, reg, syscall_num;
+ int i, reg;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
+ return (-1);
}
/*
- * FreeBSD has two special kinds of system call redirctions --
+ * FreeBSD has two special kinds of system call redirections --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over %rax if it contains
+ * either of these values.
*/
reg = 0;
- syscall_num = regs.r_rax;
- switch (syscall_num) {
+ switch (regs.r_rax) {
case SYS_syscall:
case SYS___syscall:
- syscall_num = regs.r_rdi;
reg++;
break;
}
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
- }
-
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
- for (i = 0; i < nargs && reg < 6; i++, reg++) {
+ for (i = 0; i < cs->nargs && reg < 6; i++, reg++) {
switch (reg) {
- case 0: fsc->args[i] = regs.r_rdi; break;
- case 1: fsc->args[i] = regs.r_rsi; break;
- case 2: fsc->args[i] = regs.r_rdx; break;
- case 3: fsc->args[i] = regs.r_rcx; break;
- case 4: fsc->args[i] = regs.r_r8; break;
- case 5: fsc->args[i] = regs.r_r9; break;
+ case 0: cs->args[i] = regs.r_rdi; break;
+ case 1: cs->args[i] = regs.r_rsi; break;
+ case 2: cs->args[i] = regs.r_rdx; break;
+ case 3: cs->args[i] = regs.r_rcx; break;
+ case 4: cs->args[i] = regs.r_r8; break;
+ case 5: cs->args[i] = regs.r_r9; break;
}
}
- if (nargs > i) {
+ if (cs->nargs > i) {
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)(regs.r_rsp + sizeof(register_t));
- iorequest.piod_addr = &fsc->args[i];
- iorequest.piod_len = (nargs - i) * sizeof(register_t);
+ iorequest.piod_addr = &cs->args[i];
+ iorequest.piod_len = (cs->nargs - i) * sizeof(register_t);
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
- return;
- }
-
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
+ return (-1);
}
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%lx%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-amd64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+amd64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r_rax;
- errorp = !!(regs.r_rflags & PSL_C);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
-
- if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
-
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
+ retval[0] = regs.r_rax;
+ retval[1] = regs.r_rdx;
+ *errorp = !!(regs.r_rflags & PSL_C);
+ return (0);
+}
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi amd64_fbsd = {
+ "FreeBSD ELF64",
+ syscallnames,
+ nitems(syscallnames),
+ amd64_fetch_args,
+ amd64_fetch_retval
+};
- return (retval);
-}
+PROCABI(amd64_fbsd);
Index: usr.bin/truss/amd64-fbsd32.c
===================================================================
--- usr.bin/truss/amd64-fbsd32.c
+++ usr.bin/truss/amd64-fbsd32.c
@@ -29,290 +29,112 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * FreeBSD/i386-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- */
+/* FreeBSD/i386-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <machine/reg.h>
#include <machine/psl.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "freebsd32_syscalls.h"
-static int nsyscalls = nitems(freebsd32_syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd32_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- unsigned int *args32;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd32_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd32_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd32_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- free(fsc->args32);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-amd64_fbsd32_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+amd64_fbsd32_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd32_syscall *fsc;
- struct syscall *sc;
- lwpid_t tid;
+ struct current_syscall *cs;
+ unsigned int *args32;
unsigned long parm_offset;
- int i, syscall_num;
+ lwpid_t tid;
+ int i;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
+ return (-1);
}
parm_offset = regs.r_rsp + sizeof(int);
/*
- * FreeBSD has two special kinds of system call redirctions --
+ * FreeBSD has two special kinds of system call redirections --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over the first argument.
*/
- syscall_num = regs.r_rax;
- switch (syscall_num) {
+ switch (regs.r_rax) {
case SYS_syscall:
- syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
parm_offset += sizeof(int);
break;
case SYS___syscall:
- syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
parm_offset += sizeof(quad_t);
break;
}
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : freebsd32_syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
- }
-
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args32 = malloc((1 + nargs) * sizeof(unsigned int));
+ args32 = calloc(1 + cs->nargs, sizeof(unsigned int));
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)parm_offset;
- iorequest.piod_addr = fsc->args32;
- iorequest.piod_len = (1 + nargs) * sizeof(unsigned int);
+ iorequest.piod_addr = args32;
+ iorequest.piod_len = (1 + cs->nargs) * sizeof(unsigned int);
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
- if (iorequest.piod_len == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
- for (i = 0; i < nargs + 1; i++)
- fsc->args[i] = fsc->args32[i];
-
- sc = NULL;
- if (fsc->name)
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
- }
-
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
+ if (iorequest.piod_len == 0) {
+ free(args32);
+ return (-1);
}
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ for (i = 0; i < cs->nargs + 1; i++)
+ cs->args[i] = args32[i];
+ free(args32);
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-amd64_fbsd32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+amd64_fbsd32_fetch_retval(struct trussinfo *trussinfo, long *retval,
+ int *errorp)
{
struct reg regs;
- struct freebsd32_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r_rax;
- errorp = !!(regs.r_rflags & PSL_C);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
+ retval[0] = regs.r_rax & 0xffffffff;
+ retval[1] = regs.r_rdx & 0xffffffff;
+ *errorp = !!(regs.r_rflags & PSL_C);
+ return (0);
+}
- if (fsc->name != NULL && (strcmp(fsc->name, "freebsd32_execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
+static struct procabi amd64_fbsd32 = {
+ "FreeBSD ELF32",
+ freebsd32_syscallnames,
+ nitems(freebsd32_syscallnames),
+ amd64_fbsd32_fetch_args,
+ amd64_fbsd32_fetch_retval
+};
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
+PROCABI(amd64_fbsd32);
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi amd64_fbsd32_aout = {
+ "FreeBSD a.out",
+ freebsd32_syscallnames,
+ nitems(freebsd32_syscallnames),
+ amd64_fbsd32_fetch_args,
+ amd64_fbsd32_fetch_retval
+};
- return (retval);
-}
+PROCABI(amd64_fbsd32_aout);
Index: usr.bin/truss/amd64-linux32.c
===================================================================
--- usr.bin/truss/amd64-linux32.c
+++ usr.bin/truss/amd64-linux32.c
@@ -29,123 +29,36 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * Linux/i386-specific system call handling. Given how much of this code
- * is taken from the freebsd equivalent, I can probably put even more of
- * it in support routines that can be used by any personality support.
- */
+/* Linux/i386-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <machine/reg.h>
#include <machine/psl.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "linux32_syscalls.h"
-static int nsyscalls = nitems(linux32_syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct linux_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long args[5];
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct linux_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct linux_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct linux_syscall *fsc)
-{
- int i;
-
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-amd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+amd64_linux32_fetch_args(struct trussinfo *trussinfo)
{
struct reg regs;
- struct linux_syscall *fsc;
- struct syscall *sc;
+ struct current_syscall *cs;
lwpid_t tid;
- int i, syscall_num;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
- }
-
- syscall_num = regs.r_rax;
-
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : linux32_syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
+ return (-1);
}
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "linux_fork") == 0 ||
- strcmp(fsc->name, "linux_vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
/*
* Linux passes syscall arguments in registers, not
* on the stack. Fortunately, we've got access to the
@@ -153,60 +66,22 @@
* number of arguments. And what does linux do for syscalls
* that have more than five arguments?
*/
-
- fsc->args[0] = regs.r_rbx;
- fsc->args[1] = regs.r_rcx;
- fsc->args[2] = regs.r_rdx;
- fsc->args[3] = regs.r_rsi;
- fsc->args[4] = regs.r_rdi;
-
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
+ switch (cs->nargs) {
+ default:
+ cs->args[5] = regs.r_rbp; /* Unconfirmed */
+ case 5:
+ cs->args[4] = regs.r_rdi;
+ case 4:
+ cs->args[3] = regs.r_rsi;
+ case 3:
+ cs->args[2] = regs.r_rdx;
+ case 2:
+ cs->args[1] = regs.r_rcx;
+ case 1:
+ cs->args[0] = regs.r_rbx;
}
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
/*
@@ -224,83 +99,43 @@
-6,
};
-long
-amd64_linux32_syscall_exit(struct trussinfo *trussinfo,
- int syscall_num __unused)
+static int
+amd64_linux32_fetch_retval(struct trussinfo *trussinfo, long *retval,
+ int *errorp)
{
struct reg regs;
- struct linux_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
+ size_t i;
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r_rax;
- errorp = !!(regs.r_rflags & PSL_C);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
+ retval[0] = regs.r_rax & 0xffffffff;
+ retval[1] = regs.r_rdx & 0xffffffff;
+ *errorp = !!(regs.r_rflags & PSL_C);
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
+ if (*errorp) {
+ for (i = 0; i < nitems(bsd_to_linux_errno); i++) {
+ if (retval[0] == bsd_to_linux_errno[i]) {
+ retval[0] = i;
+ return (0);
}
}
- }
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
- if (errorp) {
- for (i = 0; (size_t)i < nitems(bsd_to_linux_errno); i++) {
- if (retval == bsd_to_linux_errno[i])
- break;
- }
+ /* XXX: How to handle unknown errors? */
}
+ return (0);
+}
- if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
-
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- errorp ? i : retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi amd64_linux32 = {
+ "Linux ELF32",
+ linux32_syscallnames,
+ nitems(linux32_syscallnames),
+ amd64_linux32_fetch_args,
+ amd64_linux32_fetch_retval
+};
- return (retval);
-}
+PROCABI(amd64_linux32);
Index: usr.bin/truss/arm-fbsd.c
===================================================================
--- usr.bin/truss/arm-fbsd.c
+++ usr.bin/truss/arm-fbsd.c
@@ -29,17 +29,11 @@
* SUCH DAMAGE.
*/
-/*
- * FreeBSD/arm-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- */
-
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+
+/* FreeBSD/arm-specific system call handling. */
+
#include <sys/ptrace.h>
#include <sys/syscall.h>
@@ -47,303 +41,98 @@
#include <machine/armreg.h>
#include <machine/ucontext.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <err.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "syscalls.h"
-
-static int nsyscalls = nitems(syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-arm_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+arm_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
+ struct current_syscall *cs;
lwpid_t tid;
- int i, syscall_num;
- register_t *ap;
+ int i, reg, syscall_num;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
+ return (-1);
}
- ap = ®s.r[0];
/*
- * FreeBSD has two special kinds of system call redirctions --
+ * FreeBSD has two special kinds of system call redirections --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over the first argument.
*/
#ifdef __ARM_EABI__
syscall_num = regs.r[7];
#else
- if ((syscall_num = ptrace(PT_READ_I, tid,
+ if ((syscall_num = ptrace(PT_READ_I, tid,
(caddr_t)(regs.r[_REG_PC] - INSN_SIZE), 0)) == -1) {
fprintf(trussinfo->outfile, "-- CANNOT READ PC --\n");
- return;
+ return (-1);
}
syscall_num = syscall_num & 0x000fffff;
#endif
+
+ reg = 0;
switch (syscall_num) {
case SYS_syscall:
- syscall_num = *ap++;
- nargs--;
+ reg = 1;
break;
case SYS___syscall:
- syscall_num = ap[_QUAD_LOWWORD];
- ap += 2;
- nargs -= 2;
+ reg = 2;
break;
}
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
- }
-
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
- switch (nargs) {
- default:
- /*
- * The OS doesn't seem to allow more than 10 words of
- * parameters (yay!). So we shouldn't be here.
- */
- warn("More than 10 words (%d) of arguments!\n", nargs);
- break;
- case 10:
- case 9:
- case 8:
- case 7:
- case 6:
- case 5:
- /*
- * If there are 7-10 words of arguments, they are placed
- * on the stack, as is normal for other processors.
- * The fall-through for all of these is deliberate!!!
- */
- // XXX BAD constant used here
+ for (i = 0; i < cs->nargs && reg < 4; i++, reg++)
+ cs->args[i] = regs.r[reg];
+ if (cs->nargs > i) {
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)(regs.r_sp +
4 * sizeof(uint32_t));
- iorequest.piod_addr = &fsc->args[4];
- iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]);
+ iorequest.piod_addr = &cs->args[i];
+ iorequest.piod_len = (cs->nargs - i) * sizeof(cs->args[0]);
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
- return;
- case 4: fsc->args[3] = ap[3];
- case 3: fsc->args[2] = ap[2];
- case 2: fsc->args[1] = ap[1];
- case 1: fsc->args[0] = ap[0];
- case 0: break;
+ return (-1);
}
- sc = NULL;
- if (fsc->name)
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
- }
-
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-arm_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+arm_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r[0];
- errorp = !!(regs.r_cpsr & PSR_C);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
-
- if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
-
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
+ /* XXX: Does not have the __ARMEB__ handling for __syscall(). */
+ retval[0] = regs.r[0];
+ retval[1] = regs.r[1];
+ *errorp = !!(regs.r_cpsr & PSR_C);
+ return (0);
+}
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi arm_fbsd = {
+ "FreeBSD ELF32",
+ syscallnames,
+ nitems(syscallnames),
+ arm_fetch_args,
+ arm_fetch_retval
+};
- return (retval);
-}
+PROCABI(arm_fbsd);
Index: usr.bin/truss/extern.h
===================================================================
--- usr.bin/truss/extern.h
+++ usr.bin/truss/extern.h
@@ -31,42 +31,9 @@
* $FreeBSD$
*/
-extern int setup_and_wait(char **);
-extern int start_tracing(pid_t);
+extern void setup_and_wait(struct trussinfo *, char **);
+extern void start_tracing(struct trussinfo *, pid_t);
extern void restore_proc(int);
-extern void waitevent(struct trussinfo *);
+extern void eventloop(struct trussinfo *);
extern const char *ioctlname(unsigned long val);
extern char *strsig(int sig);
-#ifdef __arm__
-extern void arm_syscall_entry(struct trussinfo *, int);
-extern long arm_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __amd64__
-extern void amd64_syscall_entry(struct trussinfo *, int);
-extern long amd64_syscall_exit(struct trussinfo *, int);
-extern void amd64_linux32_syscall_entry(struct trussinfo *, int);
-extern long amd64_linux32_syscall_exit(struct trussinfo *, int);
-extern void amd64_fbsd32_syscall_entry(struct trussinfo *, int);
-extern long amd64_fbsd32_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __i386__
-extern void i386_syscall_entry(struct trussinfo *, int);
-extern long i386_syscall_exit(struct trussinfo *, int);
-extern void i386_linux_syscall_entry(struct trussinfo *, int);
-extern long i386_linux_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __powerpc__
-extern void powerpc_syscall_entry(struct trussinfo *, int);
-extern long powerpc_syscall_exit(struct trussinfo *, int);
-extern void powerpc64_syscall_entry(struct trussinfo *, int);
-extern long powerpc64_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __sparc64__
-extern void sparc64_syscall_entry(struct trussinfo *, int);
-extern long sparc64_syscall_exit(struct trussinfo *, int);
-#endif
-#ifdef __mips__
-extern void mips_syscall_entry(struct trussinfo *, int);
-extern long mips_syscall_exit(struct trussinfo *, int);
-#endif
-
Index: usr.bin/truss/i386-fbsd.c
===================================================================
--- usr.bin/truss/i386-fbsd.c
+++ usr.bin/truss/i386-fbsd.c
@@ -29,284 +29,103 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * FreeBSD/i386-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- */
+/* FreeBSD/i386-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <machine/reg.h>
#include <machine/psl.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "syscalls.h"
-static int nsyscalls = nitems(syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-i386_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+i386_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
+ struct current_syscall *cs;
lwpid_t tid;
unsigned int parm_offset;
- int i, syscall_num;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
+ return (-1);
}
parm_offset = regs.r_esp + sizeof(int);
/*
- * FreeBSD has two special kinds of system call redirctions --
+ * FreeBSD has two special kinds of system call redirections --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over the first argument.
*/
- syscall_num = regs.r_eax;
- switch (syscall_num) {
+ switch (regs.r_eax) {
case SYS_syscall:
- syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
parm_offset += sizeof(int);
break;
case SYS___syscall:
- syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0);
parm_offset += sizeof(quad_t);
break;
}
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
- }
-
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)parm_offset;
- iorequest.piod_addr = fsc->args;
- iorequest.piod_len = (1 + nargs) * sizeof(unsigned long);
+ iorequest.piod_addr = cs->args;
+ iorequest.piod_len = (1 + cs->nargs) * sizeof(unsigned long);
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
- return;
-
- sc = NULL;
- if (fsc->name)
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
- }
-
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
+ return (-1);
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-i386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+i386_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r_eax;
- errorp = !!(regs.r_eflags & PSL_C);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
+ retval[0] = regs.r_eax;
+ retval[1] = regs.r_edx;
+ *errorp = !!(regs.r_eflags & PSL_C);
+ return (0);
+}
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
+static struct procabi i386_fbsd = {
+ "FreeBSD ELF32",
+ syscallnames,
+ nitems(syscallnames),
+ i386_fetch_args,
+ i386_fetch_retval
+};
- if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
+PROCABI(i386_fbsd);
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
+static struct procabi i386_fbsd_aout = {
+ "FreeBSD a.out",
+ syscallnames,
+ nitems(syscallnames),
+ i386_fetch_args,
+ i386_fetch_retval
+};
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+PROCABI(i386_fbsd_aout);
- return (retval);
-}
Index: usr.bin/truss/i386-linux.c
===================================================================
--- usr.bin/truss/i386-linux.c
+++ usr.bin/truss/i386-linux.c
@@ -29,123 +29,36 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * Linux/i386-specific system call handling. Given how much of this code
- * is taken from the freebsd equivalent, I can probably put even more of
- * it in support routines that can be used by any personality support.
- */
+/* Linux/i386-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <machine/reg.h>
#include <machine/psl.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "linux_syscalls.h"
-static int nsyscalls = nitems(linux_syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct linux_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long args[5];
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct linux_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct linux_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct linux_syscall *fsc)
-{
- int i;
-
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+i386_linux_fetch_args(struct trussinfo *trussinfo)
{
struct reg regs;
- struct linux_syscall *fsc;
- struct syscall *sc;
+ struct current_syscall *cs;
lwpid_t tid;
- int i, syscall_num;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
- }
-
- syscall_num = regs.r_eax;
-
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : linux_syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
+ return (-1);
}
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "linux_fork") == 0 ||
- strcmp(fsc->name, "linux_vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
/*
* Linux passes syscall arguments in registers, not
* on the stack. Fortunately, we've got access to the
@@ -153,60 +66,22 @@
* number of arguments. And what does linux do for syscalls
* that have more than five arguments?
*/
-
- fsc->args[0] = regs.r_ebx;
- fsc->args[1] = regs.r_ecx;
- fsc->args[2] = regs.r_edx;
- fsc->args[3] = regs.r_esi;
- fsc->args[4] = regs.r_edi;
-
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
+ switch (cs->nargs) {
+ default:
+ cs->args[5] = regs.r_ebp; /* Unconfirmed */
+ case 5:
+ cs->args[4] = regs.r_edi;
+ case 4:
+ cs->args[3] = regs.r_esi;
+ case 3:
+ cs->args[2] = regs.r_edx;
+ case 2:
+ cs->args[1] = regs.r_ecx;
+ case 1:
+ cs->args[0] = regs.r_ebx;
}
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
/*
@@ -224,82 +99,42 @@
-6,
};
-long
-i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+i386_linux_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct linux_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
+ size_t i;
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r_eax;
- errorp = !!(regs.r_eflags & PSL_C);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
+ retval[0] = regs.r_eax;
+ retval[1] = regs.r_edx;
+ *errorp = !!(regs.r_eflags & PSL_C);
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
+ if (*errorp) {
+ for (i = 0; i < nitems(bsd_to_linux_errno); i++) {
+ if (retval[0] == bsd_to_linux_errno[i]) {
+ retval[0] = i;
+ return (0);
}
}
- }
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
- if (errorp) {
- for (i = 0; (size_t)i < nitems(bsd_to_linux_errno); i++) {
- if (retval == bsd_to_linux_errno[i])
- break;
- }
+ /* XXX: How to handle unknown errors? */
}
+ return (0);
+}
- if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
-
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- errorp ? i : retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi i386_linux = {
+ "Linux ELF32",
+ linux_syscallnames,
+ nitems(linux_syscallnames),
+ i386_linux_fetch_args,
+ i386_linux_fetch_retval
+};
- return (retval);
-}
+PROCABI(i386_linux);
Index: usr.bin/truss/main.c
===================================================================
--- usr.bin/truss/main.c
+++ usr.bin/truss/main.c
@@ -38,21 +38,12 @@
* do a lot of the work :).
*/
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/sysctl.h>
-#include <sys/wait.h>
+#include <sys/ptrace.h>
#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
#include <signal.h>
-#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <time.h>
#include <unistd.h>
@@ -60,8 +51,6 @@
#include "extern.h"
#include "syscall.h"
-#define MAXARGS 6
-
static void
usage(void)
{
@@ -71,82 +60,6 @@
exit(1);
}
-/*
- * WARNING! "FreeBSD a.out" must be first, or set_etype will not
- * work correctly.
- */
-static struct ex_types {
- const char *type;
- void (*enter_syscall)(struct trussinfo *, int);
- long (*exit_syscall)(struct trussinfo *, int);
-} ex_types[] = {
-#ifdef __arm__
- { "FreeBSD ELF32", arm_syscall_entry, arm_syscall_exit },
-#endif
-#ifdef __amd64__
- { "FreeBSD ELF64", amd64_syscall_entry, amd64_syscall_exit },
- { "FreeBSD ELF32", amd64_fbsd32_syscall_entry, amd64_fbsd32_syscall_exit },
- { "Linux ELF32", amd64_linux32_syscall_entry, amd64_linux32_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 },
-#endif
-#ifdef __powerpc__
- { "FreeBSD ELF", powerpc_syscall_entry, powerpc_syscall_exit },
- { "FreeBSD ELF32", powerpc_syscall_entry, powerpc_syscall_exit },
-#ifdef __powerpc64__
- { "FreeBSD ELF64", powerpc64_syscall_entry, powerpc64_syscall_exit },
-#endif
-#endif
-#ifdef __sparc64__
- { "FreeBSD ELF64", sparc64_syscall_entry, sparc64_syscall_exit },
-#endif
-#ifdef __mips__
- { "FreeBSD ELF", mips_syscall_entry, mips_syscall_exit },
- { "FreeBSD ELF32", mips_syscall_entry, mips_syscall_exit },
- { "FreeBSD ELF64", mips_syscall_entry, mips_syscall_exit }, // XXX
-#endif
- { 0, 0, 0 },
-};
-
-/*
- * Set the execution type. This is called after every exec, and when
- * a process is first monitored.
- */
-
-static struct ex_types *
-set_etype(struct trussinfo *trussinfo)
-{
- struct ex_types *funcs;
- size_t len;
- int error;
- int mib[4];
- char progt[32];
-
- len = sizeof(progt);
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_SV_NAME;
- mib[3] = trussinfo->pid;
- error = sysctl(mib, 4, progt, &len, NULL, 0);
- if (error != 0)
- err(2, "can not get etype");
-
- for (funcs = ex_types; funcs->type; funcs++)
- if (strcmp(funcs->type, progt) == 0)
- break;
-
- if (funcs->type == NULL) {
- funcs = &ex_types[0];
- warn("execution type %s is not supported -- using %s",
- progt, funcs->type);
- }
- return (funcs);
-}
-
char *
strsig(int sig)
{
@@ -162,37 +75,32 @@
int
main(int ac, char **av)
{
- struct timespec timediff;
struct sigaction sa;
- struct ex_types *funcs;
struct trussinfo *trussinfo;
char *fname;
- char *signame;
char **command;
- pid_t childpid;
- int c, initial_open, status;
+ pid_t pid;
+ int c;
fname = NULL;
- initial_open = 1;
/* Initialize the trussinfo struct */
trussinfo = (struct trussinfo *)calloc(1, sizeof(struct trussinfo));
if (trussinfo == NULL)
errx(1, "calloc() failed");
+ pid = 0;
trussinfo->outfile = stderr;
trussinfo->strsize = 32;
- trussinfo->pr_why = S_NONE;
trussinfo->curthread = NULL;
- SLIST_INIT(&trussinfo->threadlist);
+ LIST_INIT(&trussinfo->proclist);
while ((c = getopt(ac, av, "p:o:facedDs:S")) != -1) {
switch (c) {
case 'p': /* specified pid */
- trussinfo->pid = atoi(optarg);
+ pid = atoi(optarg);
/* make sure i don't trace me */
- if (trussinfo->pid == getpid()) {
- fprintf(stderr, "attempt to grab self.\n");
- exit(2);
+ if (pid == getpid()) {
+ errx(2, "attempt to grab self.");
}
break;
case 'f': /* Follow fork()'s */
@@ -228,8 +136,8 @@
}
ac -= optind; av += optind;
- if ((trussinfo->pid == 0 && ac == 0) ||
- (trussinfo->pid != 0 && ac != 0))
+ if ((pid == 0 && ac == 0) ||
+ (pid != 0 && ac != 0))
usage();
if (fname != NULL) { /* Use output file */
@@ -247,10 +155,10 @@
* 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 */
+ if (pid == 0) {
+ /* Start a command ourselves */
command = av;
- trussinfo->pid = setup_and_wait(command);
+ setup_and_wait(trussinfo, command);
signal(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
@@ -261,119 +169,40 @@
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
- start_tracing(trussinfo->pid);
+ start_tracing(trussinfo, pid);
}
-
/*
* At this point, if we started the process, it is stopped waiting to
* be woken up, either in exit() or in execve().
*/
+ if (LIST_FIRST(&trussinfo->proclist)->abi == NULL) {
+ /*
+ * If we are not able to handle this ABI, detach from the
+ * process and exit. If we just created a new process to
+ * run a command, kill the new process rather than letting
+ * it run untraced.
+ *
+ * XXX: I believe this fetches the ABI before exec so not
+ * quite what we want?
+ */
+ if (pid == 0)
+ kill(LIST_FIRST(&trussinfo->proclist)->pid, SIGKILL);
+ ptrace(PT_DETACH, LIST_FIRST(&trussinfo->proclist)->pid, NULL,
+ 0);
+ return (1);
+ }
+ ptrace(PT_SYSCALL, LIST_FIRST(&trussinfo->proclist)->pid, (caddr_t)1,
+ 0);
-START_TRACE:
- funcs = set_etype(trussinfo);
-
- initial_open = 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 {
- waitevent(trussinfo);
-
- switch (trussinfo->pr_why) {
- case S_SCE:
- funcs->enter_syscall(trussinfo, MAXARGS);
- clock_gettime(CLOCK_REALTIME,
- &trussinfo->curthread->before);
- break;
- case S_SCX:
- clock_gettime(CLOCK_REALTIME,
- &trussinfo->curthread->after);
-
- if (trussinfo->curthread->in_fork &&
- (trussinfo->flags & FOLLOWFORKS)) {
- trussinfo->curthread->in_fork = 0;
- childpid = funcs->exit_syscall(trussinfo,
- trussinfo->pr_data);
-
- /*
- * Fork a new copy of ourself to trace
- * the child of the original traced
- * process.
- */
- if (fork() == 0) {
- trussinfo->pid = childpid;
- start_tracing(trussinfo->pid);
- goto START_TRACE;
- }
- break;
- }
- funcs->exit_syscall(trussinfo, MAXARGS);
- break;
- case S_SIG:
- if (trussinfo->flags & NOSIGS)
- break;
- if (trussinfo->flags & FOLLOWFORKS)
- fprintf(trussinfo->outfile, "%5d: ",
- trussinfo->pid);
- if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
- timespecsubt(&trussinfo->curthread->after,
- &trussinfo->start_time, &timediff);
- fprintf(trussinfo->outfile, "%jd.%09ld ",
- (intmax_t)timediff.tv_sec,
- timediff.tv_nsec);
- }
- if (trussinfo->flags & RELATIVETIMESTAMPS) {
- timespecsubt(&trussinfo->curthread->after,
- &trussinfo->curthread->before, &timediff);
- fprintf(trussinfo->outfile, "%jd.%09ld ",
- (intmax_t)timediff.tv_sec,
- timediff.tv_nsec);
- }
- signame = strsig(trussinfo->pr_data);
- fprintf(trussinfo->outfile,
- "SIGNAL %u (%s)\n", trussinfo->pr_data,
- signame == NULL ? "?" : signame);
- break;
- case S_EXIT:
- if (trussinfo->flags & COUNTONLY)
- break;
- if (trussinfo->flags & FOLLOWFORKS)
- fprintf(trussinfo->outfile, "%5d: ",
- trussinfo->pid);
- if (trussinfo->flags & ABSOLUTETIMESTAMPS) {
- timespecsubt(&trussinfo->curthread->after,
- &trussinfo->start_time, &timediff);
- fprintf(trussinfo->outfile, "%jd.%09ld ",
- (intmax_t)timediff.tv_sec,
- timediff.tv_nsec);
- }
- if (trussinfo->flags & RELATIVETIMESTAMPS) {
- timespecsubt(&trussinfo->curthread->after,
- &trussinfo->curthread->before, &timediff);
- fprintf(trussinfo->outfile, "%jd.%09ld ",
- (intmax_t)timediff.tv_sec,
- timediff.tv_nsec);
- }
- fprintf(trussinfo->outfile,
- "process exit, rval = %u\n", trussinfo->pr_data);
- break;
- default:
- break;
- }
- } while (trussinfo->pr_why != S_EXIT &&
- trussinfo->pr_why != S_DETACHED);
-
- if (trussinfo->flags & FOLLOWFORKS) {
- do {
- childpid = wait(&status);
- } while (childpid != -1);
- }
+ eventloop(trussinfo);
if (trussinfo->flags & COUNTONLY)
print_summary(trussinfo);
Index: usr.bin/truss/mips-fbsd.c
===================================================================
--- usr.bin/truss/mips-fbsd.c
+++ usr.bin/truss/mips-fbsd.c
@@ -29,318 +29,113 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * FreeBSD/sparc64-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/mips-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <machine/frame.h>
#include <machine/reg.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stddef.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "syscalls.h"
-static int nsyscalls = nitems(syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in sparc64/sparc64/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-mips_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+mips_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
+ struct current_syscall *cs;
lwpid_t tid;
- int i, syscall_num;
- int indir; /* indirect system call */
+ int i, reg;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
- }
-
- indir = 0;
- syscall_num = regs.r_regs[V0];
- if (syscall_num == SYS_syscall) {
- indir = 1;
- syscall_num = regs.r_regs[A0];
+ return (-1);
}
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
+ /*
+ * FreeBSD has two special kinds of system call redirections --
+ * SYS_syscall, and SYS___syscall. The former is the old syscall()
+ * routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over the first argument.
+ */
+ reg = A0;
+ switch (regs.r_regs[V0]) {
+ case SYS_syscall:
+ reg = A1;
+ break;
+ case SYS___syscall:
+#if defined(__mips_n32) || defined(__mips_n64)
+ reg = A1;
+#else
+ reg = A2;
+#endif
+ break;
}
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-#if 0 // XXX
- iorequest.piod_op = PIOD_READ_D;
- iorequest.piod_offs = (void *)parm_offset;
- iorequest.piod_addr = fsc->args;
- iorequest.piod_len = (1 + nargs) * sizeof(unsigned long);
- ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
- if (iorequest.piod_len == 0)
- return;
+#if defined(__mips_n32) || defined(__mips_n64)
+#define MAXREG A7
#else
- iorequest.piod_op = PIOD_READ_D;
+#define MAXREG A3
#endif
- switch (nargs) {
- default:
- /*
- * The OS doesn't seem to allow more than 10 words of
- * parameters (yay!). So we shouldn't be here.
- */
- warn("More than 10 words (%d) of arguments!\n", nargs);
- break;
- case 10:
- case 9:
- case 8:
- case 7:
- case 6:
- case 5:
- /*
- * If there are 7-10 words of arguments, they are placed
- * on the stack, as is normal for other processors.
- * The fall-through for all of these is deliberate!!!
- */
- // XXX BAD constant used here
+ for (i = 0; i < cs->nargs && reg <= MAXREG; i++, reg++)
+ cs->args[i] = regs.r_regs[reg];
+ if (cs->nargs > i) {
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)(regs.r_regs[SP] +
- 4 * sizeof(uint32_t));
- iorequest.piod_addr = &fsc->args[4];
- iorequest.piod_len = (nargs - 4) * sizeof(fsc->args[0]);
+ 4 * sizeof(cs->args[0]));
+ iorequest.piod_addr = &cs->args[i];
+ iorequest.piod_len = (cs->nargs - i) * sizeof(cs->args[0]);
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
- return;
- case 4: fsc->args[3] = regs.r_regs[A3];
- case 3: fsc->args[2] = regs.r_regs[A2];
- case 2: fsc->args[1] = regs.r_regs[A1];
- case 1: fsc->args[0] = regs.r_regs[A0];
- case 0: break;
- }
- if (indir) {
- memmove(&fsc->args[0], &fsc->args[1],
- (nargs - 1) * sizeof(fsc->args[0]));
+ return (-1);
}
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
- }
-
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-mips_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+mips_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
- fprintf(trussinfo->outfile, "\n");
+ fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r_regs[V0];
- errorp = !!regs.r_regs[A3];
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
-
- if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
+ /* XXX: Does not have special handling for __syscall(). */
+ retval[0] = regs.r_regs[V0];
+ retval[1] = regs.r_regs[V1];
+ *errorp = !!regs.r_regs[A3];
+ return (0);
+}
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi mips_fbsd = {
+#ifdef __mips_n64
+ "FreeBSD ELF64",
+#else
+ "FreeBSD ELF32",
+#endif
+ syscallnames,
+ nitems(syscallnames),
+ mips_fetch_args,
+ mips_fetch_retval
+};
- return (retval);
-}
+PROCABI(mips_fbsd);
Index: usr.bin/truss/powerpc-fbsd.c
===================================================================
--- usr.bin/truss/powerpc-fbsd.c
+++ usr.bin/truss/powerpc-fbsd.c
@@ -25,41 +25,20 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * FreeBSD/powerpc-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/powerpc-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <machine/reg.h>
#include <machine/frame.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#ifdef __powerpc64__ /* 32-bit compatibility */
#include "freebsd32_syscalls.h"
@@ -68,264 +47,112 @@
#include "syscalls.h"
#endif
-static int nsyscalls = nitems(syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in powerpc/powerpc/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-powerpc_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+powerpc_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd_syscall *fsc;
+ struct current_syscall *cs;
struct syscall *sc;
- void *args;
lwpid_t tid;
- int i, regargs, syscall_num;
+ int i, reg;
+#if 0
/* Account for a 64-bit argument with corresponding alignment. */
nargs += 2;
+#endif
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
+ return (-1);
}
/*
- * FreeBSD has two special kinds of system call redirctions --
+ * FreeBSD has two special kinds of system call redirections --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over the first argument.
*/
- regargs = NARGREG;
- syscall_num = regs.fixreg[0];
- args = ®s.fixreg[3];
- if (syscall_num == SYS_syscall) {
- args = ®s.fixreg[4];
- regargs -= 1;
- syscall_num = regs.fixreg[3];
- } else if (syscall_num == SYS___syscall) {
- args = ®s.fixreg[5];
- regargs -= 2;
- syscall_num = regs.fixreg[4];
+ reg = 0;
+ switch (regs.fixreg[0]) {
+ case SYS_syscall:
+ reg += 1;
+ break;
+ case SYS___syscall:
+ reg += 2;
+ break;
}
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
+ for (i = 0; i < cs->nargs && reg < NARGREG; i++, reg++) {
+#ifdef __powerpc64__
+ cs->args[i] = regs.fixreg[FIRSTARG + reg] & 0xffffffff;
+#else
+ cs->args[i] = regs.fixreg[FIRSTARG + reg];
+#endif
}
+ if (cs->nargs > i) {
+#ifdef __powerpc64__
+ uint32_t *args32;
+ int j;
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-
- if (nargs > regargs) {
- memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0]));
-
+ args32 = calloc(cs->nargs - i, sizeof(uint32_t));
+#endif
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)(regs.fixreg[1] + 8);
- iorequest.piod_addr = &fsc->args[regargs];
- iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]);
+#ifdef __powerpc64__
+ iorequest.piod_addr = args32;
+ iorequest.piod_len = (cs->nargs - i) * sizeof(args32[0]);
+#else
+ iorequest.piod_addr = &cs->args[i];
+ iorequest.piod_len = (cs->nargs - i) * sizeof(cs->args[0]);
+#endif
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
- return;
- } else
- memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0]));
-
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
+ return (-1);
+#ifdef __powerpc64__
+ for (j = 0; j < cs->nargs - i; j++)
+ cs->args[i + j] = args32[j];
+ free(args32);
#endif
- fsc->nargs = nargs;
}
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-powerpc_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+powerpc_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
- fprintf(trussinfo->outfile, "\n");
+ fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.fixreg[3];
- errorp = !!(regs.cr & 0x10000000);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * On 32-bit big-endian, the low word of a 64-bit return is
- * in the greater address. Switch to this. XXX note that
- * print_syscall_ret can't handle 64-bit return values (llseek)
- */
- if (sc->ret_type == 2)
- retval = regs.fixreg[4];
-
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
-
- if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
-
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
+ /* XXX: Does not have fixup for __syscall(). */
+#ifdef __powerpc64__
+ retval[0] = regs.fixreg[3] & 0xffffffff;
+ retval[1] = regs.fixreg[4] & 0xffffffff;
+#else
+ retval[0] = regs.fixreg[3];
+ retval[1] = regs.fixreg[4];
+#endif
+ *errorp = !!(regs.cr & 0x10000000);
+ return (0);
+}
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi powerpc_fbsd = {
+ "FreeBSD ELF32",
+ syscallnames,
+ nitems(syscallnames),
+ powerpc_fetch_args,
+ powerpc_fetch_retval
+};
- return (retval);
-}
+PROCABI(powerpc_fbsd);
Index: usr.bin/truss/powerpc64-fbsd.c
===================================================================
--- usr.bin/truss/powerpc64-fbsd.c
+++ usr.bin/truss/powerpc64-fbsd.c
@@ -25,287 +25,94 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * FreeBSD/powerpc-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/powerpc64-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <machine/reg.h>
#include <machine/frame.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "syscalls.h"
-static int nsyscalls = nitems(syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in powerpc/powerpc/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-powerpc64_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+powerpc64_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
- void *args;
+ struct current_syscall *cs;
lwpid_t tid;
- int i, regargs, syscall_num;
+ int i, reg;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
+ return (-1);
}
/*
- * FreeBSD has two special kinds of system call redirctions --
+ * FreeBSD has two special kinds of system call redirections --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over the first argument.
*/
- regargs = NARGREG;
- syscall_num = regs.fixreg[0];
- args = ®s.fixreg[3];
- if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) {
- args = ®s.fixreg[4];
- regargs -= 1;
- syscall_num = regs.fixreg[3];
- }
-
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
+ reg = 0;
+ switch (regs.fixreg[0]) {
+ case SYS_syscall:
+ case SYS___syscall:
+ reg += 1;
+ break;
}
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
-
- if (nargs > regargs) {
- memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0]));
-
+ for (i = 0; i < cs->nargs && reg < NARGREG; i++, reg++)
+ cs->args[i] = regs.fixreg[FIRSTARG + reg];
+ if (cs->nargs > i) {
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)(regs.fixreg[1] + 48);
- iorequest.piod_addr = &fsc->args[regargs];
- iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]);
+ iorequest.piod_addr = &cs->args[i];
+ iorequest.piod_len = (cs->nargs - i) * sizeof(cs->args[0]);
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
- return;
- } else
- memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0]));
-
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
- }
-
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
+ return (-1);
}
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-powerpc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+powerpc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
- fprintf(trussinfo->outfile, "\n");
+ fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.fixreg[3];
- errorp = !!(regs.cr & 0x10000000);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
-
- if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
-
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
+ retval[0] = regs.fixreg[3];
+ retval[1] = regs.fixreg[4];
+ *errorp = !!(regs.cr & 0x10000000);
+ return (0);
+}
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi powerpc64_fbsd = {
+ "FreeBSD ELF64",
+ syscallnames,
+ nitems(syscallnames),
+ powerpc64_fetch_args,
+ powerpc64_fetch_retval
+};
- return (retval);
-}
+PROCABI(powerpc64_fbsd);
Index: usr.bin/truss/setup.c
===================================================================
--- usr.bin/truss/setup.c
+++ usr.bin/truss/setup.c
@@ -37,37 +37,39 @@
* I'm afraid.
*/
-#include <sys/param.h>
-#include <sys/types.h>
#include <sys/ptrace.h>
+#include <sys/sysctl.h>
#include <sys/wait.h>
+#include <assert.h>
#include <err.h>
#include <errno.h>
-#include <fcntl.h>
#include <signal.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
-#include <machine/reg.h>
-
#include "truss.h"
+#include "syscall.h"
#include "extern.h"
+SET_DECLARE(procabi, struct procabi);
+
static sig_atomic_t detaching;
+static void new_proc(struct trussinfo *, pid_t);
+
/*
* setup_and_wait() is called to start a process. All it really does
- * is fork(), set itself up to stop on exec or exit, and then exec
- * the given command. At that point, the child process stops, and
- * the parent can wake up and deal with it.
+ * is fork(), enable tracing in the child, and then exec the given
+ * command. At that point, the child process stops, and the parent
+ * can wake up and deal with it.
*/
-
-int
-setup_and_wait(char *command[])
+void
+setup_and_wait(struct trussinfo *info, char *command[])
{
pid_t pid;
@@ -84,17 +86,14 @@
if (waitpid(pid, NULL, 0) < 0)
err(1, "unexpect stop in waitpid");
- return (pid);
+ new_proc(info, pid);
}
/*
- * start_tracing picks up where setup_and_wait() dropped off -- namely,
- * it sets the event mask for the given process id. Called for both
- * monitoring an existing process and when we create our own.
+ * start_tracing is called to attach to an existing process.
*/
-
-int
-start_tracing(pid_t pid)
+void
+start_tracing(struct trussinfo *info, pid_t pid)
{
int ret, retry;
@@ -109,7 +108,7 @@
if (waitpid(pid, NULL, 0) < 0)
err(1, "Unexpect stop in waitpid");
- return (0);
+ new_proc(info, pid);
}
/*
@@ -118,7 +117,6 @@
* applies if truss was told to monitor an already-existing
* process.
*/
-
void
restore_proc(int signo __unused)
{
@@ -126,116 +124,479 @@
detaching = 1;
}
-static int
+static void
detach_proc(pid_t pid)
{
- int waitval;
/* stop the child so that we can detach */
kill(pid, SIGSTOP);
- if (waitpid(pid, &waitval, 0) < 0)
+ if (waitpid(pid, NULL, 0) < 0)
err(1, "Unexpected stop in waitpid");
if (ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0)
err(1, "Can not detach the process");
kill(pid, SIGCONT);
+}
+
+/*
+ * Determine the ABI. This is called after every exec, and when
+ * a process is first monitored.
+ */
+static struct procabi *
+find_abi(pid_t pid)
+{
+ struct procabi **pabi;
+ size_t len;
+ int error;
+ int mib[4];
+ char progt[32];
+
+ len = sizeof(progt);
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_SV_NAME;
+ mib[3] = pid;
+ error = sysctl(mib, 4, progt, &len, NULL, 0);
+ if (error != 0)
+ err(2, "can not get sysvec name");
+
+ SET_FOREACH(pabi, procabi) {
+ if (strcmp((*pabi)->type, progt) == 0)
+ break;
+ }
+ if (*pabi == NULL)
+ warnx("ABI %s for pid %ld is not supported", progt, (long)pid);
+ return (*pabi);
+}
+
+static void
+new_proc(struct trussinfo *info, pid_t pid)
+{
+ struct procinfo *np;
+
+ /*
+ * If this happens it means there is a bug in truss. Unfortunately
+ * this will kill any processes are attached to.
+ */
+ LIST_FOREACH(np, &info->proclist, entries) {
+ if (np->pid == pid)
+ errx(1, "Duplicate process for pid %ld", (long)pid);
+ }
+
+ if (info->flags & FOLLOWFORKS)
+ if (ptrace(PT_FOLLOW_FORK, pid, NULL, 1) == -1)
+ err(1, "Unable to follow forks for pid %ld", (long)pid);
+ np = calloc(1, sizeof(struct procinfo));
+ np->pid = pid;
+ np->abi = find_abi(pid);
+ SLIST_INIT(&np->threadlist);
+ LIST_INSERT_HEAD(&info->proclist, np, entries);
+}
+
+static void
+free_proc(struct procinfo *p)
+{
+ struct threadinfo *t, *t2;
+
+ SLIST_FOREACH_SAFE(t, &p->threadlist, entries, t2) {
+ free(t);
+ }
+ LIST_REMOVE(p, entries);
+ free(p);
+}
+
+static void
+detach_all_procs(struct trussinfo *info)
+{
+ struct procinfo *p, *p2;
- return (waitval);
+ LIST_FOREACH_SAFE(p, &info->proclist, entries, p2) {
+ detach_proc(p->pid);
+ free_proc(p);
+ }
+}
+
+static struct procinfo *
+find_proc(struct trussinfo *info, pid_t pid)
+{
+ struct procinfo *np;
+
+ LIST_FOREACH(np, &info->proclist, entries) {
+ if (np->pid == pid)
+ return (np);
+ }
+
+ return (NULL);
}
/*
- * Change curthread member based on lwpid.
- * If it is a new thread, create a threadinfo structure
+ * Change curthread member based on (pid, lwpid).
+ * If it is a new thread, create a threadinfo structure.
*/
static void
-find_thread(struct trussinfo *info, lwpid_t lwpid)
+find_thread(struct trussinfo *info, pid_t pid, lwpid_t lwpid)
{
- struct threadinfo *np;
+ struct procinfo *np;
+ struct threadinfo *nt;
+
+ np = find_proc(info, pid);
+ assert(np != NULL);
- info->curthread = NULL;
- SLIST_FOREACH(np, &info->threadlist, entries) {
- if (np->tid == lwpid) {
- info->curthread = np;
+ SLIST_FOREACH(nt, &np->threadlist, entries) {
+ if (nt->tid == lwpid) {
+ info->curthread = nt;
return;
}
}
- np = (struct threadinfo *)calloc(1, sizeof(struct threadinfo));
- if (np == NULL)
+ nt = calloc(1, sizeof(struct threadinfo));
+ if (nt == NULL)
err(1, "calloc() failed");
- np->tid = lwpid;
- SLIST_INSERT_HEAD(&info->threadlist, np, entries);
- info->curthread = np;
+ nt->proc = np;
+ nt->tid = lwpid;
+ SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
+ info->curthread = nt;
}
/*
- * Start the traced process and wait until it stoped.
- * Fill trussinfo structure.
- * When this even returns, the traced process is in stop state.
+ * When a process exits, it no longer has any threads left. However,
+ * the main loop expects a valid curthread. In cases when a thread
+ * triggers the termination (e.g. calling exit or triggering a fault)
+ * we would ideally use that thread. However, if a process is killed
+ * by a signal sent from another process then there is no "correct"
+ * thread. We just punt and use the first thread.
*/
-void
-waitevent(struct trussinfo *info)
+static void
+find_exit_thread(struct trussinfo *info, pid_t pid)
+{
+ struct procinfo *np;
+ struct threadinfo *nt;
+
+ np = find_proc(info, pid);
+ assert(np != NULL);
+
+ if (SLIST_EMPTY(&np->threadlist)) {
+ /*
+ * If an existing process exits right after we attach
+ * to it but before it posts any events, there won't
+ * be any threads. Create a dummy thread and set its
+ * "before" time to the global start time.
+ */
+ nt = calloc(1, sizeof(struct threadinfo));
+ if (nt == NULL)
+ err(1, "calloc() failed");
+ nt->proc = np;
+ nt->tid = 0;
+ SLIST_INSERT_HEAD(&np->threadlist, nt, entries);
+ nt->before = info->start_time;
+ }
+ info->curthread = SLIST_FIRST(&np->threadlist);
+}
+
+static void
+alloc_syscall(struct threadinfo *t, struct ptrace_lwpinfo *pl)
+{
+
+ assert(t->in_syscall == 0);
+ assert(t->cs.number == 0);
+ assert(t->cs.name == NULL);
+ assert(t->cs.args == NULL);
+ assert(t->cs.nargs == 0);
+ assert(t->cs.s_args == NULL);
+ t->cs.number = pl->pl_syscall_code;
+ t->cs.nargs = pl->pl_syscall_narg;
+ if (t->cs.nargs != 0)
+ t->cs.args = calloc(1 + t->cs.nargs, sizeof(t->cs.args[0]));
+ t->in_syscall = 1;
+}
+
+static void
+free_syscall(struct threadinfo *t)
{
- struct ptrace_lwpinfo lwpinfo;
- static int pending_signal = 0;
- int waitval;
+ int i;
- ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal);
- pending_signal = 0;
+ free(t->cs.args);
+ if (t->cs.s_args) {
+ for (i = 0; i < t->cs.nargs; i++)
+ free(t->cs.s_args[i]);
+ free(t->cs.s_args);
+ }
+ memset(&t->cs, 0, sizeof(t->cs));
+ t->in_syscall = 0;
+}
-detach:
- if (detaching) {
- waitval = detach_proc(info->pid);
- info->pr_why = S_DETACHED;
- info->pr_data = WEXITSTATUS(waitval);
+static void
+enter_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
+{
+ struct threadinfo *t;
+ struct syscall *sc;
+ int i;
+
+ t = info->curthread;
+ alloc_syscall(t, pl);
+ if (t->cs.nargs != 0 && t->proc->abi->fetch_args(info) != 0) {
+ free_syscall(t);
return;
}
- if (waitpid(info->pid, &waitval, 0) == -1) {
- if (errno == EINTR)
- goto detach;
- err(1, "Unexpected stop in waitpid");
+ if (t->cs.number >= 0 && t->cs.number < t->proc->abi->nsyscalls)
+ t->cs.name = t->proc->abi->syscallnames[t->cs.number];
+ if (t->cs.name == NULL)
+ fprintf(info->outfile, "-- UNKNOWN %s SYSCALL %d --\n",
+ t->proc->abi->type, t->cs.number);
+
+ sc = get_syscall(t->cs.name);
+ if (sc)
+ t->cs.nargs = sc->nargs;
+ else {
+#if DEBUG
+ fprintf(stderr, "unknown syscall %s -- setting "
+ "args to %d\n", t->cs.name, t->cs.nargs);
+#endif
}
- if (WIFCONTINUED(waitval)) {
- info->pr_why = S_NONE;
- return;
+ t->cs.s_args = calloc(1 + t->cs.nargs, sizeof(char *));
+ t->cs.sc = sc;
+
+ /*
+ * At this point, we set up the system call arguments.
+ * We ignore any OUT ones, however -- those are arguments that
+ * are set by the system call, and so are probably meaningless
+ * now. This doesn't currently support arguments that are
+ * passed in *and* out, however.
+ */
+ if (t->cs.name != NULL) {
+#if DEBUG
+ fprintf(stderr, "syscall %s(", t->cs.name);
+#endif
+ for (i = 0; i < t->cs.nargs; i++) {
+#if DEBUG
+ fprintf(stderr, "0x%lx%s", sc ?
+ t->cs.args[sc->args[i].offset] : t->cs.args[i],
+ i < (t->cs.nargs - 1) ? "," : "");
+#endif
+ if (sc && !(sc->args[i].type & OUT)) {
+ t->cs.s_args[i] = print_arg(&sc->args[i],
+ t->cs.args, 0, info);
+ }
+ }
+#if DEBUG
+ fprintf(stderr, ")\n");
+#endif
}
- if (WIFEXITED(waitval)) {
- info->pr_why = S_EXIT;
- info->pr_data = WEXITSTATUS(waitval);
+
+ clock_gettime(CLOCK_REALTIME, &t->before);
+}
+
+static void
+exit_syscall(struct trussinfo *info, struct ptrace_lwpinfo *pl)
+{
+ struct threadinfo *t;
+ struct procinfo *p;
+ struct syscall *sc;
+ long retval[2];
+ int errorp, i;
+
+ t = info->curthread;
+ if (!t->in_syscall)
return;
+
+ clock_gettime(CLOCK_REALTIME, &t->after);
+ p = t->proc;
+ if (p->abi->fetch_retval(info, retval, &errorp) < 0) {
+ free_syscall(t);
+ return;
+ }
+
+ sc = t->cs.sc;
+ if (sc == NULL) {
+ for (i = 0; i < t->cs.nargs; i++)
+ asprintf(&t->cs.s_args[i], "0x%lx", t->cs.args[i]);
+ } else {
+ /*
+ * Here, we only look for arguments that have OUT masked in --
+ * otherwise, they were handled in enter_syscall().
+ */
+ for (i = 0; i < sc->nargs; i++) {
+ char *temp;
+
+ if (sc->args[i].type & OUT) {
+ /*
+ * If an error occurred, then don't bother
+ * getting the data; it may not be valid.
+ */
+ if (errorp) {
+ asprintf(&temp, "0x%lx",
+ t->cs.args[sc->args[i].offset]);
+ } else {
+ temp = print_arg(&sc->args[i],
+ t->cs.args, retval, info);
+ }
+ t->cs.s_args[i] = temp;
+ }
+ }
+ }
+
+ print_syscall_ret(info, t->cs.name, t->cs.nargs, t->cs.s_args,
+ errorp, retval, sc);
+ free_syscall(t);
+
+ /*
+ * If the process executed a new image, check the ABI. If the
+ * new ABI isn't supported, stop tracing this process.
+ */
+ if (pl->pl_flags & PL_FLAG_EXEC) {
+ p->abi = find_abi(p->pid);
+ if (p->abi == NULL) {
+ detach_proc(p->pid);
+ free_proc(p);
+ }
}
- if (WIFSTOPPED(waitval)) {
- ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo,
- sizeof(lwpinfo));
- find_thread(info, lwpinfo.pl_lwpid);
- switch (WSTOPSIG(waitval)) {
- case SIGTRAP:
- if (lwpinfo.pl_flags & PL_FLAG_SCE) {
- info->pr_why = S_SCE;
- info->curthread->in_syscall = 1;
- break;
- } else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
- info->pr_why = S_SCX;
- info->curthread->in_syscall = 0;
- break;
- } else {
- errx(1,
+}
+
+/*
+ * Wait for events until all the processes have exited or truss has been
+ * asked to stop.
+ */
+void
+eventloop(struct trussinfo *info)
+{
+ struct ptrace_lwpinfo pl;
+ struct timespec timediff;
+ siginfo_t si;
+ char *signame;
+ int pending_signal;
+
+ while (!LIST_EMPTY(&info->proclist)) {
+ if (detaching) {
+ detach_all_procs(info);
+ return;
+ }
+
+ if (waitid(P_ALL, 0, &si, WTRAPPED | WEXITED) == -1) {
+ if (errno == EINTR)
+ continue;
+ err(1, "Unexpected error from waitid");
+ }
+
+ assert(si.si_signo == SIGCHLD);
+
+ switch (si.si_code) {
+ case CLD_EXITED:
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ find_exit_thread(info, si.si_pid);
+ if ((info->flags & COUNTONLY) == 0) {
+ if (info->flags & FOLLOWFORKS)
+ fprintf(info->outfile, "%5d: ",
+ si.si_pid);
+ clock_gettime(CLOCK_REALTIME,
+ &info->curthread->after);
+ if (info->flags & ABSOLUTETIMESTAMPS) {
+ timespecsubt(&info->curthread->after,
+ &info->start_time, &timediff);
+ fprintf(info->outfile, "%jd.%09ld ",
+ (intmax_t)timediff.tv_sec,
+ timediff.tv_nsec);
+ }
+ if (info->flags & RELATIVETIMESTAMPS) {
+ timespecsubt(&info->curthread->after,
+ &info->curthread->before,
+ &timediff);
+ fprintf(info->outfile, "%jd.%09ld ",
+ (intmax_t)timediff.tv_sec,
+ timediff.tv_nsec);
+ }
+ if (si.si_code == CLD_EXITED)
+ fprintf(info->outfile,
+ "process exit, rval = %u\n",
+ si.si_status);
+ else
+ fprintf(info->outfile,
+ "process killed, signal = %u%s\n",
+ si.si_status,
+ si.si_code == CLD_DUMPED ?
+ " (core dumped)" : "");
+ }
+ free_proc(info->curthread->proc);
+ info->curthread = NULL;
+ break;
+ case CLD_TRAPPED:
+ if (ptrace(PT_LWPINFO, si.si_pid, (caddr_t)&pl,
+ sizeof(pl)) == -1)
+ err(1, "ptrace(PT_LWPINFO)");
+
+ if (pl.pl_flags & PL_FLAG_CHILD) {
+ new_proc(info, si.si_pid);
+ assert(LIST_FIRST(&info->proclist)->abi !=
+ NULL);
+ }
+ find_thread(info, si.si_pid, pl.pl_lwpid);
+
+ if (si.si_status == SIGTRAP) {
+ if (pl.pl_flags & PL_FLAG_SCE)
+ enter_syscall(info, &pl);
+ else if (pl.pl_flags & PL_FLAG_SCX)
+ exit_syscall(info, &pl);
+ else
+ errx(1,
"pl_flags %x contains neither PL_FLAG_SCE nor PL_FLAG_SCX",
- lwpinfo.pl_flags);
+ pl.pl_flags);
+ pending_signal = 0;
+ } else if (pl.pl_flags & PL_FLAG_CHILD) {
+ clock_gettime(CLOCK_REALTIME,
+ &info->curthread->after);
+ assert(info->flags & FOLLOWFORKS);
+ fprintf(info->outfile, "%5d: ", si.si_pid);
+ if (info->flags & ABSOLUTETIMESTAMPS) {
+ timespecsubt(&info->curthread->after,
+ &info->start_time, &timediff);
+ fprintf(info->outfile, "%jd.%09ld ",
+ (intmax_t)timediff.tv_sec,
+ timediff.tv_nsec);
+ }
+ if (info->flags & RELATIVETIMESTAMPS) {
+ timediff.tv_sec = 0;
+ timediff.tv_nsec = 0;
+ fprintf(info->outfile, "%jd.%09ld ",
+ (intmax_t)timediff.tv_sec,
+ timediff.tv_nsec);
+ }
+ fprintf(info->outfile, "<new process>\n");
+ pending_signal = 0;
+ } else if ((info->flags & NOSIGS) == 0) {
+ if (info->flags & FOLLOWFORKS)
+ fprintf(info->outfile, "%5d: ",
+ si.si_pid);
+ if (info->flags & ABSOLUTETIMESTAMPS) {
+ timespecsubt(&info->curthread->after,
+ &info->start_time, &timediff);
+ fprintf(info->outfile, "%jd.%09ld ",
+ (intmax_t)timediff.tv_sec,
+ timediff.tv_nsec);
+ }
+ if (info->flags & RELATIVETIMESTAMPS) {
+ timespecsubt(&info->curthread->after,
+ &info->curthread->before,
+ &timediff);
+ fprintf(info->outfile, "%jd.%09ld ",
+ (intmax_t)timediff.tv_sec,
+ timediff.tv_nsec);
+ }
+ signame = strsig(si.si_status);
+ fprintf(info->outfile,
+ "SIGNAL %u (%s)\n", si.si_status,
+ signame == NULL ? "?" : signame);
+ pending_signal = si.si_status;
}
- default:
- info->pr_why = S_SIG;
- info->pr_data = WSTOPSIG(waitval);
- pending_signal = info->pr_data;
+ ptrace(PT_SYSCALL, si.si_pid, (caddr_t)1,
+ pending_signal);
+ break;
+ case CLD_STOPPED:
+ errx(1, "waitid reported CLD_STOPPED");
+ case CLD_CONTINUED:
break;
}
}
- if (WIFSIGNALED(waitval)) {
- info->pr_why = S_EXIT;
- info->pr_data = 0;
- return;
- }
}
Index: usr.bin/truss/sparc64-fbsd.c
===================================================================
--- usr.bin/truss/sparc64-fbsd.c
+++ usr.bin/truss/sparc64-fbsd.c
@@ -29,22 +29,11 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
-/*
- * FreeBSD/sparc64-specific system call handling. This is probably the most
- * complex part of the entire truss program, although I've got lots of
- * it handled relatively cleanly now. The system call names are generated
- * automatically, thanks to /usr/src/sys/kern/syscalls.master. The
- * names used for the various structures are confusing, I sadly admit.
- *
- * This file is almost nothing more than a slightly-edited i386-fbsd.c.
- */
+/* FreeBSD/sparc64-specific system call handling. */
-#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
@@ -52,289 +41,85 @@
#include <machine/reg.h>
#include <machine/tstate.h>
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
#include <stddef.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
#include "truss.h"
-#include "syscall.h"
-#include "extern.h"
#include "syscalls.h"
-static int nsyscalls = nitems(syscallnames);
-
-/*
- * This is what this particular file uses to keep track of a system call.
- * It is probably not quite sufficient -- I can probably use the same
- * structure for the various syscall personalities, and I also probably
- * need to nest system calls (for signal handlers).
- *
- * 'struct syscall' describes the system call; it may be NULL, however,
- * if we don't know about this particular system call yet.
- */
-struct freebsd_syscall {
- struct syscall *sc;
- const char *name;
- int number;
- unsigned long *args;
- int nargs; /* number of arguments -- *not* number of words! */
- char **s_args; /* the printable arguments */
-};
-
-static struct freebsd_syscall *
-alloc_fsc(void)
-{
-
- return (malloc(sizeof(struct freebsd_syscall)));
-}
-
-/* Clear up and free parts of the fsc structure. */
-static void
-free_fsc(struct freebsd_syscall *fsc)
-{
- int i;
-
- free(fsc->args);
- if (fsc->s_args) {
- for (i = 0; i < fsc->nargs; i++)
- free(fsc->s_args[i]);
- free(fsc->s_args);
- }
- free(fsc);
-}
-
-/*
- * Called when a process has entered a system call. nargs is the
- * number of words, not number of arguments (a necessary distinction
- * in some cases). Note that if the STOPEVENT() code in sparc64/sparc64/trap.c
- * is ever changed these functions need to keep up.
- */
-
-void
-sparc64_syscall_entry(struct trussinfo *trussinfo, int nargs)
+static int
+sparc64_fetch_args(struct trussinfo *trussinfo)
{
struct ptrace_io_desc iorequest;
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
+ struct current_syscall *cs;
lwpid_t tid;
- int i, syscall_num;
- int indir; /* indirect system call */
+ int i, reg;
tid = trussinfo->curthread->tid;
-
+ cs = &trussinfo->curthread->cs;
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
- return;
+ return (-1);
}
/*
- * FreeBSD has two special kinds of system call redirctions --
+ * FreeBSD has two special kinds of system call redirections --
* SYS_syscall, and SYS___syscall. The former is the old syscall()
* routine, basically; the latter is for quad-aligned arguments.
+ *
+ * The system call argument count and code from ptrace() already
+ * account for these, but we need to skip over the first argument.
*/
- indir = 0;
- syscall_num = regs.r_global[1];
- if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) {
- indir = 1;
- syscall_num = regs.r_out[0];
- }
-
- fsc = alloc_fsc();
- if (fsc == NULL)
- return;
- fsc->number = syscall_num;
- fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ?
- NULL : syscallnames[syscall_num];
- if (!fsc->name) {
- fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n",
- syscall_num);
+ reg = 0;
+ switch (regs.r_global[1]) {
+ case SYS_syscall:
+ case SYS___syscall:
+ reg = 1;
+ break;
}
- if (fsc->name && (trussinfo->flags & FOLLOWFORKS) &&
- (strcmp(fsc->name, "fork") == 0 ||
- strcmp(fsc->name, "pdfork") == 0 ||
- strcmp(fsc->name, "rfork") == 0 ||
- strcmp(fsc->name, "vfork") == 0))
- trussinfo->curthread->in_fork = 1;
-
- if (nargs == 0)
- return;
-
- fsc->args = malloc((1 + nargs) * sizeof(unsigned long));
- switch (nargs) {
- default:
- /*
- * The OS doesn't seem to allow more than 10 words of
- * parameters (yay!). So we shouldn't be here.
- */
- warn("More than 10 words (%d) of arguments!\n", nargs);
- break;
- case 10:
- case 9:
- case 8:
- case 7:
- /*
- * If there are 7-10 words of arguments, they are placed
- * on the stack, as is normal for other processors.
- * The fall-through for all of these is deliberate!!!
- */
+ for (i = 0; i < cs->nargs && reg < 6; i++, reg++)
+ cs->args[i] = regs.r_out[reg];
+ if (cs->nargs > i) {
iorequest.piod_op = PIOD_READ_D;
iorequest.piod_offs = (void *)(regs.r_out[6] + SPOFF +
offsetof(struct frame, fr_pad[6]));
- iorequest.piod_addr = &fsc->args[6];
- iorequest.piod_len = (nargs - 6) * sizeof(fsc->args[0]);
+ iorequest.piod_addr = &cs->args[i];
+ iorequest.piod_len = (cs->nargs - i) * sizeof(cs->args[0]);
ptrace(PT_IO, tid, (caddr_t)&iorequest, 0);
if (iorequest.piod_len == 0)
- return;
- case 6: fsc->args[5] = regs.r_out[5];
- case 5: fsc->args[4] = regs.r_out[4];
- case 4: fsc->args[3] = regs.r_out[3];
- case 3: fsc->args[2] = regs.r_out[2];
- case 2: fsc->args[1] = regs.r_out[1];
- case 1: fsc->args[0] = regs.r_out[0];
- case 0:
- break;
+ return (-1);
}
- if (indir)
- memmove(&fsc->args[0], &fsc->args[1], (nargs - 1) *
- sizeof(fsc->args[0]));
-
- sc = get_syscall(fsc->name);
- if (sc)
- fsc->nargs = sc->nargs;
- else {
-#if DEBUG
- fprintf(trussinfo->outfile, "unknown syscall %s -- setting "
- "args to %d\n", fsc->name, nargs);
-#endif
- fsc->nargs = nargs;
- }
-
- fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *));
- fsc->sc = sc;
-
- /*
- * At this point, we set up the system call arguments.
- * We ignore any OUT ones, however -- those are arguments that
- * are set by the system call, and so are probably meaningless
- * now. This doesn't currently support arguments that are
- * passed in *and* out, however.
- */
-
- if (fsc->name) {
-#if DEBUG
- fprintf(stderr, "syscall %s(", fsc->name);
-#endif
- for (i = 0; i < fsc->nargs; i++) {
-#if DEBUG
- fprintf(stderr, "0x%x%s", sc ?
- fsc->args[sc->args[i].offset] : fsc->args[i],
- i < (fsc->nargs - 1) ? "," : "");
-#endif
- if (sc && !(sc->args[i].type & OUT)) {
- fsc->s_args[i] = print_arg(&sc->args[i],
- fsc->args, 0, trussinfo);
- }
- }
-#if DEBUG
- fprintf(stderr, ")\n");
-#endif
- }
-
-#if DEBUG
- fprintf(trussinfo->outfile, "\n");
-#endif
-
- trussinfo->curthread->fsc = fsc;
+ return (0);
}
-/*
- * And when the system call is done, we handle it here.
- * Currently, no attempt is made to ensure that the system calls
- * match -- this needs to be fixed (and is, in fact, why S_SCX includes
- * the system call number instead of, say, an error status).
- */
-
-long
-sparc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
+static int
+sparc64_fetch_retval(struct trussinfo *trussinfo, long *retval, int *errorp)
{
struct reg regs;
- struct freebsd_syscall *fsc;
- struct syscall *sc;
lwpid_t tid;
- long retval;
- int errorp, i;
-
- if (trussinfo->curthread->fsc == NULL)
- return (-1);
tid = trussinfo->curthread->tid;
-
if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) {
- fprintf(trussinfo->outfile, "\n");
+ fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
return (-1);
}
- retval = regs.r_out[0];
- errorp = !!(regs.r_tstate & TSTATE_XCC_C);
-
- /*
- * This code, while simpler than the initial versions I used, could
- * stand some significant cleaning.
- */
-
- fsc = trussinfo->curthread->fsc;
- sc = fsc->sc;
- if (!sc) {
- for (i = 0; i < fsc->nargs; i++)
- asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]);
- } else {
- /*
- * Here, we only look for arguments that have OUT masked in --
- * otherwise, they were handled in the syscall_entry function.
- */
- for (i = 0; i < sc->nargs; i++) {
- char *temp;
-
- if (sc->args[i].type & OUT) {
- /*
- * If an error occurred, then don't bother
- * getting the data; it may not be valid.
- */
- if (errorp) {
- asprintf(&temp, "0x%lx",
- fsc->args[sc->args[i].offset]);
- } else {
- temp = print_arg(&sc->args[i],
- fsc->args, retval, trussinfo);
- }
- fsc->s_args[i] = temp;
- }
- }
- }
-
- if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 ||
- strcmp(fsc->name, "exit") == 0))
- trussinfo->curthread->in_syscall = 1;
-
- /*
- * It would probably be a good idea to merge the error handling,
- * but that complicates things considerably.
- */
+ retval[0] = regs.r_out[0];
+ retval[1] = regs.r_out[1];
+ *errorp = !!(regs.r_tstate & TSTATE_XCC_C);
+ return (0);
+}
- print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp,
- retval, fsc->sc);
- free_fsc(fsc);
+static struct procabi sparc64_fbsd = {
+ "FreeBSD ELF64",
+ syscallnames,
+ nitems(syscallnames),
+ sparc64_fetch_args,
+ sparc64_fetch_retval
+};
- return (retval);
-}
+PROCABI(sparc64_fbsd);
Index: usr.bin/truss/syscall.h
===================================================================
--- usr.bin/truss/syscall.h
+++ usr.bin/truss/syscall.h
@@ -42,7 +42,7 @@
Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2,
Pathconf, Rforkflags, ExitStatus, Waitoptions, Idtype, Procctl,
LinuxSockArgs, Umtxop, Atfd, Atflags, Timespec2, Accessmode, Long,
- Sysarch, ExecArgs, ExecEnv };
+ Sysarch, ExecArgs, ExecEnv, PipeFds };
#define ARG_MASK 0xff
#define OUT 0x100
@@ -65,7 +65,7 @@
};
struct syscall *get_syscall(const char*);
-char *print_arg(struct syscall_args *, unsigned long*, long, struct trussinfo *);
+char *print_arg(struct syscall_args *, unsigned long*, long *, struct trussinfo *);
/*
* Linux Socket defines
@@ -86,11 +86,11 @@
#define LINUX_SETSOCKOPT 14
#define LINUX_GETSOCKOPT 15
#define LINUX_SENDMSG 16
-#define LINUX_RECVMSG 17
+#define LINUX_RECVMSG 17
#define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \
0 : sizeof(register_t) - sizeof(t))
-
+
#if BYTE_ORDER == LITTLE_ENDIAN
#define PADL_(t) 0
#define PADR_(t) PAD_(t)
@@ -109,5 +109,5 @@
void print_syscall(struct trussinfo *, const char *, int, char **);
void print_syscall_ret(struct trussinfo *, const char *, int, char **, int,
- long, struct syscall *);
+ long *, struct syscall *);
void print_summary(struct trussinfo *trussinfo);
Index: usr.bin/truss/syscalls.c
===================================================================
--- usr.bin/truss/syscalls.c
+++ usr.bin/truss/syscalls.c
@@ -29,10 +29,8 @@
* SUCH DAMAGE.
*/
-#ifndef lint
-static const char rcsid[] =
- "$FreeBSD$";
-#endif /* not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
/*
* This file has routines used to print out system calls and their
@@ -40,23 +38,20 @@
*/
#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/ioccom.h>
#include <sys/mman.h>
#include <sys/procctl.h>
#include <sys/ptrace.h>
+#include <sys/resource.h>
#include <sys/socket.h>
-#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/umtx.h>
#include <sys/un.h>
#include <sys/wait.h>
+#include <machine/sysarch.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <sys/ioccom.h>
-#include <machine/atomic.h>
-#include <errno.h>
-#include <sys/umtx.h>
-#include <sys/event.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-#include <machine/sysarch.h>
#include <ctype.h>
#include <err.h>
@@ -125,7 +120,7 @@
{ Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } },
{ .name = "linux_lseek", .ret_type = 2, .nargs = 3,
.args = { { Int, 0 }, { Int, 1 }, { Whence, 2 } } },
- { .name = "mmap", .ret_type = 2, .nargs = 6,
+ { .name = "mmap", .ret_type = 1, .nargs = 6,
.args = { { Ptr, 0 }, { Int, 1 }, { Mprot, 2 }, { Mmapflags, 3 },
{ Int, 4 }, { Quad, 5 + QUAD_ALIGN } } },
{ .name = "linux_mkdir", .ret_type = 1, .nargs = 2,
@@ -145,49 +140,49 @@
.args = { { Name, 0 }, { Hex, 1 }, { Octal, 2 } } },
{ .name = "close", .ret_type = 1, .nargs = 1,
.args = { { Int, 0 } } },
- { .name = "link", .ret_type = 0, .nargs = 2,
+ { .name = "link", .ret_type = 1, .nargs = 2,
.args = { { Name, 0 }, { Name, 1 } } },
- { .name = "linkat", .ret_type = 0, .nargs = 5,
+ { .name = "linkat", .ret_type = 1, .nargs = 5,
.args = { { Atfd, 0 }, { Name, 1 }, { Atfd, 2 }, { Name, 3 },
{ Atflags, 4 } } },
- { .name = "unlink", .ret_type = 0, .nargs = 1,
+ { .name = "unlink", .ret_type = 1, .nargs = 1,
.args = { { Name, 0 } } },
- { .name = "unlinkat", .ret_type = 0, .nargs = 3,
+ { .name = "unlinkat", .ret_type = 1, .nargs = 3,
.args = { { Atfd, 0 }, { Name, 1 }, { Atflags, 2 } } },
- { .name = "chdir", .ret_type = 0, .nargs = 1,
+ { .name = "chdir", .ret_type = 1, .nargs = 1,
.args = { { Name, 0 } } },
- { .name = "chroot", .ret_type = 0, .nargs = 1,
+ { .name = "chroot", .ret_type = 1, .nargs = 1,
.args = { { Name, 0 } } },
- { .name = "mkfifo", .ret_type = 0, .nargs = 2,
+ { .name = "mkfifo", .ret_type = 1, .nargs = 2,
.args = { { Name, 0 }, { Octal, 1 } } },
- { .name = "mkfifoat", .ret_type = 0, .nargs = 3,
+ { .name = "mkfifoat", .ret_type = 1, .nargs = 3,
.args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 } } },
- { .name = "mknod", .ret_type = 0, .nargs = 3,
+ { .name = "mknod", .ret_type = 1, .nargs = 3,
.args = { { Name, 0 }, { Octal, 1 }, { Int, 2 } } },
- { .name = "mknodat", .ret_type = 0, .nargs = 4,
+ { .name = "mknodat", .ret_type = 1, .nargs = 4,
.args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Int, 3 } } },
- { .name = "chmod", .ret_type = 0, .nargs = 2,
+ { .name = "chmod", .ret_type = 1, .nargs = 2,
.args = { { Name, 0 }, { Octal, 1 } } },
- { .name = "fchmod", .ret_type = 0, .nargs = 2,
+ { .name = "fchmod", .ret_type = 1, .nargs = 2,
.args = { { Int, 0 }, { Octal, 1 } } },
- { .name = "lchmod", .ret_type = 0, .nargs = 2,
+ { .name = "lchmod", .ret_type = 1, .nargs = 2,
.args = { { Name, 0 }, { Octal, 1 } } },
- { .name = "fchmodat", .ret_type = 0, .nargs = 4,
+ { .name = "fchmodat", .ret_type = 1, .nargs = 4,
.args = { { Atfd, 0 }, { Name, 1 }, { Octal, 2 }, { Atflags, 3 } } },
- { .name = "chown", .ret_type = 0, .nargs = 3,
+ { .name = "chown", .ret_type = 1, .nargs = 3,
.args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
- { .name = "fchown", .ret_type = 0, .nargs = 3,
+ { .name = "fchown", .ret_type = 1, .nargs = 3,
.args = { { Int, 0 }, { Int, 1 }, { Int, 2 } } },
- { .name = "lchown", .ret_type = 0, .nargs = 3,
+ { .name = "lchown", .ret_type = 1, .nargs = 3,
.args = { { Name, 0 }, { Int, 1 }, { Int, 2 } } },
- { .name = "fchownat", .ret_type = 0, .nargs = 5,
+ { .name = "fchownat", .ret_type = 1, .nargs = 5,
.args = { { Atfd, 0 }, { Name, 1 }, { Int, 2 }, { Int, 3 },
{ Atflags, 4 } } },
{ .name = "linux_stat64", .ret_type = 1, .nargs = 3,
.args = { { Name | IN, 0 }, { Ptr | OUT, 1 }, { Ptr | IN, 1 } } },
- { .name = "mount", .ret_type = 0, .nargs = 4,
+ { .name = "mount", .ret_type = 1, .nargs = 4,
.args = { { Name, 0 }, { Name, 1 }, { Int, 2 }, { Ptr, 3 } } },
- { .name = "umount", .ret_type = 0, .nargs = 2,
+ { .name = "umount", .ret_type = 1, .nargs = 2,
.args = { { Name, 0 }, { Int, 2 } } },
{ .name = "fstat", .ret_type = 1, .nargs = 2,
.args = { { Int, 0 }, { Stat | OUT, 1 } } },
@@ -250,19 +245,19 @@
{ .name = "linux_execve", .ret_type = 1, .nargs = 3,
.args = { { Name | IN, 0 }, { ExecArgs | IN, 1 },
{ ExecEnv | IN, 2 } } },
- { .name = "kldload", .ret_type = 0, .nargs = 1,
+ { .name = "kldload", .ret_type = 1, .nargs = 1,
.args = { { Name | IN, 0 } } },
- { .name = "kldunload", .ret_type = 0, .nargs = 1,
+ { .name = "kldunload", .ret_type = 1, .nargs = 1,
.args = { { Int, 0 } } },
- { .name = "kldfind", .ret_type = 0, .nargs = 1,
+ { .name = "kldfind", .ret_type = 1, .nargs = 1,
.args = { { Name | IN, 0 } } },
- { .name = "kldnext", .ret_type = 0, .nargs = 1,
+ { .name = "kldnext", .ret_type = 1, .nargs = 1,
.args = { { Int, 0 } } },
- { .name = "kldstat", .ret_type = 0, .nargs = 2,
+ { .name = "kldstat", .ret_type = 1, .nargs = 2,
.args = { { Int, 0 }, { Ptr, 1 } } },
- { .name = "kldfirstmod", .ret_type = 0, .nargs = 1,
+ { .name = "kldfirstmod", .ret_type = 1, .nargs = 1,
.args = { { Int, 0 } } },
- { .name = "nanosleep", .ret_type = 0, .nargs = 1,
+ { .name = "nanosleep", .ret_type = 1, .nargs = 1,
.args = { { Timespec, 0 } } },
{ .name = "select", .ret_type = 1, .nargs = 5,
.args = { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 },
@@ -279,18 +274,18 @@
.args = { { Int, 0 }, { Itimerval, 1 }, { Itimerval | OUT, 2 } } },
{ .name = "kse_release", .ret_type = 0, .nargs = 1,
.args = { { Timespec, 0 } } },
- { .name = "kevent", .ret_type = 0, .nargs = 6,
+ { .name = "kevent", .ret_type = 1, .nargs = 6,
.args = { { Int, 0 }, { Kevent, 1 }, { Int, 2 }, { Kevent | OUT, 3 },
{ Int, 4 }, { Timespec, 5 } } },
- { .name = "sigpending", .ret_type = 0, .nargs = 1,
+ { .name = "sigpending", .ret_type = 1, .nargs = 1,
.args = { { Sigset | OUT, 0 } } },
- { .name = "sigprocmask", .ret_type = 0, .nargs = 3,
+ { .name = "sigprocmask", .ret_type = 1, .nargs = 3,
.args = { { Sigprocmask, 0 }, { Sigset, 1 }, { Sigset | OUT, 2 } } },
- { .name = "sigqueue", .ret_type = 0, .nargs = 3,
+ { .name = "sigqueue", .ret_type = 1, .nargs = 3,
.args = { { Int, 0 }, { Signal, 1 }, { LongHex, 2 } } },
- { .name = "sigreturn", .ret_type = 0, .nargs = 1,
+ { .name = "sigreturn", .ret_type = 1, .nargs = 1,
.args = { { Ptr, 0 } } },
- { .name = "sigsuspend", .ret_type = 0, .nargs = 1,
+ { .name = "sigsuspend", .ret_type = 1, .nargs = 1,
.args = { { Sigset | IN, 0 } } },
{ .name = "sigtimedwait", .ret_type = 1, .nargs = 3,
.args = { { Sigset | IN, 0 }, { Ptr, 1 }, { Timespec | IN, 2 } } },
@@ -332,7 +327,7 @@
{ .name = "pathconf", .ret_type = 1, .nargs = 2,
.args = { { Name | IN, 0 }, { Pathconf, 1 } } },
{ .name = "pipe", .ret_type = 1, .nargs = 1,
- .args = { { Ptr, 0 } } },
+ .args = { { PipeFds | OUT, 0 } } },
{ .name = "pipe2", .ret_type = 1, .nargs = 2,
.args = { { Ptr, 0 }, { Open, 1 } } },
{ .name = "truncate", .ret_type = 1, .nargs = 3,
@@ -368,9 +363,9 @@
{ .name = "_umtx_op", .ret_type = 1, .nargs = 5,
.args = { { Ptr, 0 }, { Umtxop, 1 }, { LongHex, 2 }, { Ptr, 3 },
{ Ptr, 4 } } },
- { .name = "thr_kill", .ret_type = 0, .nargs = 2,
+ { .name = "thr_kill", .ret_type = 1, .nargs = 2,
.args = { { Long, 0 }, { Signal, 1 } } },
- { .name = "thr_self", .ret_type = 0, .nargs = 1,
+ { .name = "thr_self", .ret_type = 1, .nargs = 1,
.args = { { Ptr, 0 } } },
{ .name = 0 },
};
@@ -534,7 +529,9 @@
};
static struct xlat procctl_arg[] = {
- X(PROC_SPROTECT) XEND
+ X(PROC_SPROTECT) X(PROC_REAP_ACQUIRE) X(PROC_REAP_RELEASE)
+ X(PROC_REAP_STATUS) X(PROC_REAP_GETPIDS) X(PROC_REAP_KILL)
+ X(PROC_TRACE_CTL) X(PROC_TRACE_STATUS) XEND
};
static struct xlat umtx_ops[] = {
@@ -809,7 +806,7 @@
int ctrl, data;
ctrl = ke->fflags & NOTE_FFCTRLMASK;
- data = ke->fflags & NOTE_FFLAGSMASK;
+ data = ke->fflags & NOTE_FFLAGSMASK;
if (input) {
fputs(xlookup(kevent_user_ffctrl, ctrl), fp);
if (ke->fflags & NOTE_TRIGGER)
@@ -834,7 +831,7 @@
* an array of all of the system call arguments.
*/
char *
-print_arg(struct syscall_args *sc, unsigned long *args, long retval,
+print_arg(struct syscall_args *sc, unsigned long *args, long *retval,
struct trussinfo *trussinfo)
{
FILE *fp;
@@ -843,7 +840,7 @@
pid_t pid;
fp = open_memstream(&tmp, &tmplen);
- pid = trussinfo->pid;
+ pid = trussinfo->curthread->proc->pid;
switch (sc->type & ARG_MASK) {
case Hex:
fprintf(fp, "0x%x", (int)args[sc->offset]);
@@ -882,7 +879,7 @@
int truncated = 0;
if (sc->type & OUT)
- len = retval;
+ len = retval[0];
else
len = args[sc->offset + 1];
@@ -935,7 +932,7 @@
fprintf(fp, "0x%lx", args[sc->offset]);
break;
}
-
+
/*
* Read a page of pointers at a time. Punt if the top-level
* pointer is not aligned. Note that the first read is of
@@ -996,9 +993,9 @@
case Readlinkres: {
char *tmp2;
- if (retval == -1)
+ if (retval[0] == -1)
break;
- tmp2 = get_string(pid, (void*)args[sc->offset], retval);
+ tmp2 = get_string(pid, (void*)args[sc->offset], retval[0]);
fprintf(fp, "\"%s\"", tmp2);
free(tmp2);
break;
@@ -1395,8 +1392,8 @@
if (sc->offset == 1)
numevents = args[sc->offset+1];
- else if (sc->offset == 3 && retval != -1)
- numevents = retval;
+ else if (sc->offset == 3 && retval[0] != -1)
+ numevents = retval[0];
if (numevents >= 0) {
bytes = sizeof(struct kevent) * numevents;
@@ -1515,6 +1512,21 @@
case Sysarch:
fputs(xlookup(sysarch_ops, args[sc->offset]), fp);
break;
+ case PipeFds:
+ /*
+ * The pipe() system call in the kernel returns its
+ * two file descriptors via return values. However,
+ * the interface exposed by libc is that pipe()
+ * accepts a pointer to an array of descriptors.
+ * Format the output to match the libc API by printing
+ * the returned file descriptors as a fake argument.
+ *
+ * Overwrite the first retval to signal a successful
+ * return as well.
+ */
+ fprintf(fp, "{ %ld, %ld }", retval[0], retval[1]);
+ retval[0] = 0;
+ break;
default:
errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK);
}
@@ -1536,7 +1548,8 @@
len = 0;
if (trussinfo->flags & FOLLOWFORKS)
- len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid);
+ len += fprintf(trussinfo->outfile, "%5d: ",
+ trussinfo->curthread->proc->pid);
if (name != NULL && (strcmp(name, "execve") == 0 ||
strcmp(name, "exit") == 0)) {
@@ -1575,7 +1588,7 @@
void
print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs,
- char **s_args, int errorp, long retval, struct syscall *sc)
+ char **s_args, int errorp, long *retval, struct syscall *sc)
{
struct timespec timediff;
@@ -1595,17 +1608,24 @@
print_syscall(trussinfo, name, nargs, s_args);
fflush(trussinfo->outfile);
if (errorp)
- fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval,
- strerror(retval));
- else {
- /*
- * Because pipe(2) has a special assembly glue to provide the
- * libc API, we have to adjust retval.
- */
- if (name != NULL && strcmp(name, "pipe") == 0)
- retval = 0;
- fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval, retval);
+ fprintf(trussinfo->outfile, " ERR#%ld '%s'\n", retval[0],
+ strerror(retval[0]));
+#ifndef __LP64__
+ else if (sc != NULL && sc->ret_type == 2) {
+ off_t off;
+
+#if _BYTE_ORDER == _LITTLE_ENDIAN
+ off = (off_t)retval[1] << 32 | retval[0];
+#else
+ off = (off_t)retval[0] << 32 | retval[1];
+#endif
+ fprintf(trussinfo->outfile, " = %jd (0x%jx)\n", (intmax_t)off,
+ (intmax_t)off);
}
+#endif
+ else
+ fprintf(trussinfo->outfile, " = %ld (0x%lx)\n", retval[0],
+ retval[0]);
}
void
Index: usr.bin/truss/truss.h
===================================================================
--- usr.bin/truss/truss.h
+++ usr.bin/truss/truss.h
@@ -25,6 +25,7 @@
* $FreeBSD$
*/
+#include <sys/linker_set.h>
#include <sys/queue.h>
#define FOLLOWFORKS 0x00000001
@@ -35,23 +36,55 @@
#define EXECVEENVS 0x00000020
#define COUNTONLY 0x00000040
+struct procinfo;
+struct trussinfo;
+
+struct procabi {
+ const char *type;
+ const char **syscallnames;
+ int nsyscalls;
+ int (*fetch_args)(struct trussinfo *);
+ int (*fetch_retval)(struct trussinfo *, long *, int *);
+};
+
+#define PROCABI(abi) DATA_SET(procabi, abi)
+
+/*
+ * This is confusingly named. It holds per-thread state about the
+ * currently executing system call. syscalls.h defines a struct
+ * syscall that holds metadata used to format system call arguments.
+ */
+struct current_syscall {
+ struct syscall *sc;
+ const char *name;
+ int number;
+ unsigned long *args;
+ int nargs;
+ char **s_args; /* the printable arguments */
+};
+
struct threadinfo
{
SLIST_ENTRY(threadinfo) entries;
+ struct procinfo *proc;
lwpid_t tid;
int in_syscall;
- int in_fork;
- void *fsc;
+ struct current_syscall cs;
struct timespec before;
struct timespec after;
};
+struct procinfo {
+ LIST_ENTRY(procinfo) entries;
+ pid_t pid;
+ struct procabi *abi;
+
+ SLIST_HEAD(, threadinfo) threadlist;
+};
+
struct trussinfo
{
- pid_t pid;
int flags;
- int pr_why;
- int pr_data;
int strsize;
FILE *outfile;
@@ -59,7 +92,7 @@
struct threadinfo *curthread;
- SLIST_HEAD(, threadinfo) threadlist;
+ LIST_HEAD(, procinfo) proclist;
};
#define timespecsubt(tvp, uvp, vvp) \
@@ -81,11 +114,3 @@
(vvp)->tv_nsec -= 1000000000; \
} \
} while (0)
-
-#define S_NONE 0
-#define S_SCE 1
-#define S_SCX 2
-#define S_EXIT 3
-#define S_SIG 4
-#define S_EXEC 5
-#define S_DETACHED 6
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Nov 6, 10:15 PM (18 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24960707
Default Alt Text
D3575.id8606.diff (130 KB)
Attached To
Mode
D3575: Refactor truss.
Attached
Detach File
Event Timeline
Log In to Comment