Index: Makefile =================================================================== RCS file: /home/ncvs/src/usr.bin/truss/Makefile,v retrieving revision 1.22.2.1 diff -u -p -r1.22.2.1 Makefile --- Makefile 23 May 2008 20:04:20 -0000 1.22.2.1 +++ Makefile 3 Dec 2008 18:54:55 -0000 @@ -5,6 +5,13 @@ NO_WERROR= PROG= truss SRCS= main.c setup.c syscalls.c syscalls.h ioctl.c ${MACHINE_ARCH}-fbsd.c +LDADD= -lsbuf + +DEBUG_FLAGS= -g + +#CC=ccache gcc +#CC=ccache gcc34 -fbounds-checking -static + CFLAGS+= -I${.CURDIR} -I. CLEANFILES= syscalls.master syscalls.h ioctl.c Index: i386-fbsd.c =================================================================== RCS file: /home/ncvs/src/usr.bin/truss/i386-fbsd.c,v retrieving revision 1.29.2.1 diff -u -p -r1.29.2.1 i386-fbsd.c --- i386-fbsd.c 11 Jun 2009 00:42:53 -0000 1.29.2.1 +++ i386-fbsd.c 12 Jun 2009 16:29:12 -0000 @@ -49,6 +49,7 @@ static const char rcsid[] = #include #include +#include #include #include #include @@ -77,29 +78,29 @@ static int nsyscalls = sizeof(syscallnam * 'struct syscall' describes the system call; it may be NULL, however, * if we don't know about this particular system call yet. */ -static struct freebsd_syscall { +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 */ -} fsc; +}; /* Clear up and free parts of the fsc structure. */ static __inline void -clear_fsc(void) { - if (fsc.args) { - free(fsc.args); +clear_fsc(struct freebsd_syscall *fsc) { + if (fsc->args) { + free(fsc->args); } - if (fsc.s_args) { + if (fsc->s_args) { int i; - for (i = 0; i < fsc.nargs; i++) - if (fsc.s_args[i]) - free(fsc.s_args[i]); - free(fsc.s_args); + for (i = 0; i < fsc->nargs; i++) + if (fsc->s_args[i]) + free(fsc->s_args[i]); + free(fsc->s_args); } - memset(&fsc, 0, sizeof(fsc)); + memset(fsc, 0, sizeof(*fsc)); } /* @@ -117,9 +118,20 @@ i386_syscall_entry(struct trussinfo *tru unsigned int parm_offset; struct syscall *sc = NULL; struct ptrace_io_desc iorequest; + struct freebsd_syscall *fsc; + cpid = trussinfo->curthread->tid; - clear_fsc(); + fsc = trussinfo->curthread->fsc; + if (fsc == NULL) + { + fsc = malloc(sizeof(*fsc)); + if (fsc == NULL) + errx(1, "cannot allocate syscall struct"); + memset(fsc, 0, sizeof(*fsc)); + trussinfo->curthread->fsc = fsc; + } else + clear_fsc(fsc); if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) { @@ -131,7 +143,7 @@ i386_syscall_entry(struct trussinfo *tru /* * FreeBSD has two special kinds of system call redirctions -- * SYS_syscall, and SYS___syscall. The former is the old syscall() - * routine, basicly; the latter is for quad-aligned arguments. + * routine, basically; the latter is for quad-aligned arguments. */ syscall_num = regs.r_eax; switch (syscall_num) { @@ -143,19 +155,30 @@ i386_syscall_entry(struct trussinfo *tru syscall_num = ptrace(PT_READ_D, cpid, (caddr_t)parm_offset, 0); parm_offset += sizeof(quad_t); break; + default: +/* fprintf(trussinfo->outfile, "Trapped syscall entry, but unknown syscall method %d\n", syscall_num); */ + break; } - 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); + fsc->number = syscall_num; + fsc->name = + (syscall_num < 0 || syscall_num > nsyscalls) ? NULL : syscallnames[syscall_num]; + if (!fsc->name) { + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %u (0x%08x) --\n", syscall_num, syscall_num); + if ((unsigned int)syscall_num > 0x1000) { + /* When attaching to a running process, we have a 50-50 chance + of attaching to a process waiting in a syscall, which means + our first trap is an exit instead of an entry and we're out + of synch. Reset our flag */ + trussinfo->curthread->in_syscall = 0; + } } + trussinfo->curthread->syscallname = fsc->name; - if (fsc.name && (trussinfo->flags & FOLLOWFORKS) - && ((!strcmp(fsc.name, "fork") - || !strcmp(fsc.name, "rfork") - || !strcmp(fsc.name, "vfork")))) + if (fsc->name && (trussinfo->flags & FOLLOWFORKS) + && ((!strcmp(fsc->name, "fork") + || !strcmp(fsc->name, "rfork") + || !strcmp(fsc->name, "vfork")))) { trussinfo->curthread->in_fork = 1; } @@ -163,30 +186,30 @@ i386_syscall_entry(struct trussinfo *tru if (nargs == 0) return; - fsc.args = malloc((1+nargs) * sizeof(unsigned long)); + 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_addr = fsc->args; iorequest.piod_len = (1+nargs) * sizeof(unsigned long); ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0); if (iorequest.piod_len == 0) return; - if (fsc.name) - sc = get_syscall(fsc.name); + if (fsc->name) + sc = get_syscall(fsc->name); if (sc) { - fsc.nargs = sc->nargs; + fsc->nargs = sc->nargs; } else { #if DEBUG fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", - fsc.name, nargs); + fsc->name, nargs); #endif - fsc.nargs = nargs; + fsc->nargs = nargs; } - fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); - memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); - fsc.sc = sc; + fsc->s_args = malloc((1+fsc->nargs) * sizeof(char*)); + memset(fsc->s_args, 0, (1+fsc->nargs) * sizeof(char*)); + fsc->sc = sc; /* * At this point, we set up the system call arguments. @@ -196,21 +219,21 @@ i386_syscall_entry(struct trussinfo *tru * passed in *and* out, however. */ - if (fsc.name) { + if (fsc->name) { #if DEBUG - fprintf(stderr, "syscall %s(", fsc.name); + fprintf(stderr, "syscall %s(", fsc->name); #endif - for (i = 0; i < fsc.nargs; i++) { + 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) ? "," : ""); + ? 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); + fsc->s_args[i] = print_arg(&sc->args[i], fsc->args, 0, trussinfo); } } #if DEBUG @@ -222,28 +245,34 @@ i386_syscall_entry(struct trussinfo *tru fprintf(trussinfo->outfile, "\n"); #endif - if (fsc.name != NULL && - (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) { + if (fsc->name != NULL && + (!strcmp(fsc->name, "execve") || !strcmp(fsc->name, "exit"))) { /* XXX * This could be done in a more general * manner but it still wouldn't be very pretty. */ - if (!strcmp(fsc.name, "execve")) { + if (!strcmp(fsc->name, "execve")) { if ((trussinfo->flags & EXECVEARGS) == 0) - if (fsc.s_args[1]) { - free(fsc.s_args[1]); - fsc.s_args[1] = NULL; + if (fsc->s_args[1]) { + free(fsc->s_args[1]); + fsc->s_args[1] = NULL; } if ((trussinfo->flags & EXECVEENVS) == 0) - if (fsc.s_args[2]) { - free(fsc.s_args[2]); - fsc.s_args[2] = NULL; + if (fsc->s_args[2]) { + free(fsc->s_args[2]); + fsc->s_args[2] = NULL; } } } +/* + trussinfo->curthread->flags |= ENTRY_ONLY; + print_syscall(trussinfo, fsc->name, fsc->nargs, fsc->s_args); + fprintf(trussinfo->outfile, "\n"); fflush(trussinfo->outfile); +*/ + return; } @@ -262,9 +291,13 @@ i386_syscall_exit(struct trussinfo *trus int i; int errorp; struct syscall *sc; + struct freebsd_syscall *fsc; - if (fsc.name == NULL) + fsc = trussinfo->curthread->fsc; + if (fsc->name == NULL) { + fprintf(trussinfo->outfile, "No syscall?\n"); fflush(trussinfo->outfile); return (-1); + } cpid = trussinfo->curthread->tid; if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) @@ -281,10 +314,10 @@ i386_syscall_exit(struct trussinfo *trus * stand some significant cleaning. */ - sc = fsc.sc; + sc = fsc->sc; if (!sc) { - for (i = 0; i < fsc.nargs; i++) - asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]); + 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 -- @@ -298,10 +331,10 @@ i386_syscall_exit(struct trussinfo *trus * it may not be valid. */ if (errorp) - asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]); + 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; + temp = print_arg(&sc->args[i], fsc->args, retval, trussinfo); + fsc->s_args[i] = temp; } } } @@ -312,15 +345,15 @@ i386_syscall_exit(struct trussinfo *trus * The nargs check is so we don't have to do yet another strcmp on every * syscall. */ - if (!errorp && fsc.nargs == 0 && fsc.name && strcmp(fsc.name, "pipe") == 0) { - fsc.nargs = 1; - fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); - asprintf(&fsc.s_args[0], "[%d,%d]", (int)retval, regs.r_edx); + if (!errorp && fsc->nargs == 0 && fsc->name && strcmp(fsc->name, "pipe") == 0) { + fsc->nargs = 1; + fsc->s_args = malloc((1+fsc->nargs) * sizeof(char*)); + asprintf(&fsc->s_args[0], "[%d,%d]", (int)retval, regs.r_edx); retval = 0; } - if (fsc.name != NULL && - (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) { + if (fsc->name != NULL && + (!strcmp(fsc->name, "execve") || !strcmp(fsc->name, "exit"))) { trussinfo->curthread->in_syscall = 1; } @@ -329,8 +362,8 @@ i386_syscall_exit(struct trussinfo *trus * but that complicates things considerably. */ - print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); - clear_fsc(); + print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, retval); + clear_fsc(fsc); return (retval); } Index: main.c =================================================================== RCS file: /home/ncvs/src/usr.bin/truss/main.c,v retrieving revision 1.46.2.3 diff -u -p -r1.46.2.3 main.c --- main.c 6 May 2009 22:26:49 -0000 1.46.2.3 +++ main.c 26 May 2009 19:37:11 -0000 @@ -59,7 +59,7 @@ __FBSDID("$FreeBSD: src/usr.bin/truss/ma #include "truss.h" #include "extern.h" -#define MAXARGS 6 +#define MAXARGS 7 /* sendfile is 7 args */ static void usage(void) @@ -103,6 +103,12 @@ struct ex_types { { 0, 0, 0 }, }; +/* dummy signal handler so we can break out of wait */ +static void trapalrm(int signo __unused) +{ + return; +} + /* * Set the execution type. This is called after every exec, and when * a process is first monitored. @@ -179,9 +185,11 @@ main(int ac, char **av) bzero(trussinfo, sizeof(struct trussinfo)); trussinfo->outfile = stderr; + setlinebuf(trussinfo->outfile); trussinfo->strsize = 32; trussinfo->pr_why = S_NONE; trussinfo->curthread = NULL; + trussinfo->threadcount = 0; SLIST_INIT(&trussinfo->threadlist); while ((c = getopt(ac, av, "p:o:faedDs:S")) != -1) { switch (c) { @@ -251,7 +259,8 @@ main(int ac, char **av) signal(SIGTERM, restore_proc); signal(SIGQUIT, restore_proc); } - + signal(SIGALRM, trapalrm); + siginterrupt(SIGALRM, 1); /* * At this point, if we started the process, it is stopped waiting to Index: setup.c =================================================================== RCS file: /home/ncvs/src/usr.bin/truss/setup.c,v retrieving revision 1.24.2.1 diff -u -p -r1.24.2.1 setup.c --- setup.c 6 May 2009 22:26:04 -0000 1.24.2.1 +++ setup.c 26 May 2009 20:24:30 -0000 @@ -56,9 +56,15 @@ __FBSDID("$FreeBSD: src/usr.bin/truss/se #include "truss.h" #include "extern.h" +#include "syscall.h" static int child_pid; +/* Are we waiting for the child to trap, handling a syscall/signal, or + trying to exit? Note that this is our status, not the child's */ +static enum { TS_WAITING, TS_RUNNING, TS_EXITING } + truss_state = TS_WAITING; + /* * 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 @@ -78,7 +84,6 @@ setup_and_wait(char *command[]) } if (pid == 0) { /* Child */ ptrace(PT_TRACE_ME, 0, 0, 0); - setpgid (0, 0); execvp(command[0], command); err(1, "execvp %s", command[0]); } @@ -105,18 +110,21 @@ start_tracing(int pid) { int waitval; int ret; - int retry = 10; + int retry = 0; + /* If we just forked a process, it may not be created immediately. + Retry for up to 2 seconds. */ do { + if (retry) + usleep(200); ret = ptrace(PT_ATTACH, pid, NULL, 0); - usleep(200); - } while(ret && retry-- > 0); + } while(ret && retry++ < 10); if (ret) err(1, "can not attach to target process"); - child_pid = pid; - if (waitpid(pid, &waitval, 0) < -1) - err(1, "Unexpect stop in waitpid"); + child_pid = pid; + if (waitpid(pid, &waitval, 0) < -1) + err(1, "Unexpected stop in waitpid"); return (0); } @@ -132,8 +140,18 @@ restore_proc(int signo __unused) { int waitval; - /* stop the child so that we can detach */ + /* If we are currently processing a syscall, we can't detach from + the child. Return and we will exit after we have finished + with the current syscall */ + if (truss_state == TS_RUNNING) + { + truss_state = TS_EXITING; + return; + } + kill(child_pid, SIGSTOP); + + /* stop the child so that we can detach */ if (waitpid(child_pid, &waitval, 0) < -1) err(1, "Unexpected stop in waitpid"); @@ -166,12 +184,15 @@ find_thread(struct trussinfo *info, lwpi np->tid = lwpid; np->in_fork = 0; np->in_syscall = 0; + np->threadnum = info->threadcount; + np->fsc = NULL; SLIST_INSERT_HEAD(&info->threadlist, np, entries); info->curthread = np; + info->threadcount++; } /* - * Start the traced process and wait until it stoped. + * Start the traced process and wait until it stopped. * Fill trussinfo structure. * When this even returns, the traced process is in stop state. */ @@ -179,14 +200,54 @@ void waitevent(struct trussinfo *info) { int waitval; + int rv; static int pending_signal = 0; - ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal); + if (truss_state == TS_RUNNING) + truss_state = TS_WAITING; + + rv = ptrace(PT_SYSCALL, info->pid, (caddr_t)1, pending_signal); + if (rv == -1) { + if (errno == ESRCH) + exit(0); + err(1, "ptrace error"); + } + + if (truss_state == TS_EXITING) + restore_proc(0); + + truss_state = TS_RUNNING; + if (info->curthread) + info->curthread->flags &= ~(ENTRY_ONLY|PRINTED_ENTRY|EXIT_ONLY); + pending_signal = 0; - if (waitpid(info->pid, &waitval, 0) < -1) { - err(1, "Unexpected stop in waitpid"); + AGAIN: + if (info->curthread && info->curthread->in_syscall && + (info->curthread->flags & PRINTED_ENTRY) == 0) + { + alarm(2); + } + rv = waitpid(info->pid, &waitval, 0); + if (rv == -1) + { + if (errno == EINTR) + { + /* The 2-second timer interrupted us, so we must be + waiting on a slow syscall. Print its name and + continue waiting, this time forever. */ + info->curthread->flags |= ENTRY_ONLY; + print_syscall(info, info->curthread->syscallname, 1, NULL); + fprintf(info->outfile, "...sleeping)\n"); + fflush(info->outfile); + alarm(0); + goto AGAIN; + } else + err(1, "Unexpected stop in waitpid"); } + + if (info->curthread && info->curthread->in_syscall) + alarm(0); if (WIFCONTINUED(waitval)) { info->pr_why = S_NONE; @@ -200,11 +261,15 @@ waitevent(struct trussinfo *info) if (WIFSTOPPED(waitval)) { struct ptrace_lwpinfo lwpinfo; ptrace(PT_LWPINFO, info->pid, (caddr_t)&lwpinfo, sizeof(lwpinfo)); + /* fprintf(info->outfile,"[%d/%d]", lwpinfo.pl_lwpid,lwpinfo.pl_event); + fflush(info->outfile); */ find_thread(info, lwpinfo.pl_lwpid); switch(WSTOPSIG(waitval)) { case SIGTRAP: info->pr_why = info->curthread->in_syscall?S_SCX:S_SCE; info->curthread->in_syscall = 1 - info->curthread->in_syscall; + /* fprintf(info->outfile,"\n",info->curthread->in_syscall); + fflush(info->outfile); */ break; default: info->pr_why = S_SIG; @@ -215,7 +280,7 @@ waitevent(struct trussinfo *info) } if (WIFSIGNALED(waitval)) { info->pr_why = S_EXIT; - info->pr_data = 0; + info->pr_data = WTERMSIG(waitval)+128; return; } } Index: syscall.h =================================================================== RCS file: /home/ncvs/src/usr.bin/truss/syscall.h,v retrieving revision 1.18.2.1 diff -u -p -r1.18.2.1 syscall.h --- syscall.h 14 Aug 2008 01:36:47 -0000 1.18.2.1 +++ syscall.h 20 Nov 2008 17:39:09 -0000 @@ -26,6 +26,20 @@ * Sigprocmask -- the first argument to sigprocmask(). Prints the name. * Kevent -- a pointer to an array of struct kevents. Prints all elements. * Pathconf -- the 2nd argument of pathconf(). + * Umtxop -- the 2nd argument to _umtx_op(). + * Msgflags -- the flags argument of recvmsg, sendmsg and friends. + * Int32Ptr -- pointer to an int32. + * Ptrace -- the 1st argument to ptrace(). + * WaitStat -- the "int *status" argument to waitpid, wait3, wait4. + * WaitOpts -- the "int options" argument to waitpid, wait4. + * Clockid -- clockid_t type; 1st argument to clock_gettime(). + * Chflags -- the 2nd argument to chflags(). + * Sendfilehdtr -- the 5th argument to sendfile(). + * Sendfileflags -- the 7th argument to sendfile(). + * Madvise -- the 3rd argument to madvise(). + * UmtxArg1, UmtxArg4, UmtxArg5 -- _umtx_op is heavily overloaded, and the + * types of these arguments depends on the value of Umtxop + * Utrace -- the 1st argument to utrace(). * * In addition, the pointer types (String, Ptr) may have OUT masked in -- * this means that the data is set on *return* from the system call -- or @@ -37,10 +51,12 @@ enum Argtype { None = 1, Hex, Octal, Int, Name, Ptr, Stat, Ioctl, Quad, Signal, Sockaddr, StringArray, Timespec, Timeval, Itimerval, Pollfd, - Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Readlinkres, + Fd_set, Sigaction, Fcntl, Mprot, Mmapflags, Whence, Umtx, Sigset, Sigprocmask, Kevent, Sockdomain, Socktype, Open, Fcntlflag, Rusage, BinString, Shutdown, Resource, Rlimit, Timeval2, - Pathconf }; + Iovec, Pathconf, Umtxop, Msgflags, Int32Ptr, Ptrace, Waitstat, + Waitopts, Clockid, Chflags, Sendfilehdtr, Sendfileflags, Madvise, + UmtxArg1, UmtxArg4, UmtxArg5, Utrace }; #define ARG_MASK 0xff #define OUT 0x100 Index: syscalls.c =================================================================== RCS file: /home/ncvs/src/usr.bin/truss/syscalls.c,v retrieving revision 1.55.2.2 diff -u -p -r1.55.2.2 syscalls.c --- syscalls.c 14 Aug 2008 01:36:47 -0000 1.55.2.2 +++ syscalls.c 3 Dec 2008 22:44:22 -0000 @@ -43,6 +43,7 @@ static const char rcsid[] = #include #include #include +#include #include #include #include @@ -54,6 +55,8 @@ static const char rcsid[] = #include #include #include +#include +#include #include #include @@ -93,8 +96,19 @@ static const char rcsid[] = struct syscall syscalls[] = { { "fcntl", 1, 3, { { Int, 0 } , { Fcntl, 1 }, { Fcntlflag | OUT, 2 } } }, + { "fork", 1, 0, { } }, + { "getegid", 1, 0, { } }, + { "geteuid", 1, 0, { } }, + { "getgid", 1, 0, { } }, + { "getpgrp", 1, 0, { } }, + { "getpid", 1, 0, { } }, + { "getppid", 1, 0, { } }, + { "getuid", 1, 0, { } }, + { "issetugid", 1, 0, { } }, + { "kqueue", 1, 0, { } }, + { "pipe", 1, 0, { } }, { "readlink", 1, 3, - { { Name, 0 } , { Readlinkres | OUT, 1 }, { Int, 2 } } }, + { { Name, 0 } , { BinString | OUT, 1 }, { Int, 2 } } }, { "lseek", 2, 3, { { Int, 0 }, { Quad, 1 + QUAD_ALIGN }, { Whence, 1 + QUAD_SLOTS + QUAD_ALIGN } } }, { "linux_lseek", 2, 3, @@ -117,6 +131,8 @@ struct syscall syscalls[] = { { { Name, 0 } } }, { "chdir", 0, 1, { { Name, 0 } } }, + { "fchdir", 0, 1, + { { Int, 0 } } }, { "chroot", 0, 1, { { Name, 0 } } }, { "mknod", 0, 3, @@ -141,6 +157,10 @@ struct syscall syscalls[] = { { { Int, 0 }, { Ptr | OUT, 1 } } }, { "write", 1, 3, { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 } } }, + { "pwrite", 1, 4, + { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Quad, 3 + QUAD_ALIGN } } }, + { "writev", 1, 3, + { { Int, 0 }, { Iovec | IN, 1 }, { Int, 2 } } }, { "ioctl", 1, 3, { { Int, 0 }, { Ioctl, 1 }, { Hex, 2 } } }, { "break", 1, 1, { { Ptr, 0 } } }, @@ -149,19 +169,23 @@ struct syscall syscalls[] = { { "sigaction", 1, 3, { { Signal, 0 }, { Sigaction | IN, 1 }, { Sigaction | OUT, 2 } } }, { "accept", 1, 3, - { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, + { { Int, 0 }, { Sockaddr | OUT, 1 }, { Int32Ptr | OUT, 2 } } }, { "bind", 1, 3, { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, { "connect", 1, 3, { { Int, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, { "getpeername", 1, 3, - { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, + { { Int, 0 }, { Sockaddr | OUT, 1 }, { Int32Ptr | OUT, 2 } } }, { "getsockname", 1, 3, - { { Int, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, + { { Int, 0 }, { Sockaddr | OUT, 1 }, { Int32Ptr | OUT, 2 } } }, { "recvfrom", 1, 6, - { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | OUT, 4 }, { Ptr | OUT, 5 } } }, + { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Msgflags, 3 }, { Sockaddr | OUT, 4 }, { Int32Ptr | OUT, 5 } } }, { "sendto", 1, 6, - { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Hex, 3 }, { Sockaddr | IN, 4 }, { Ptr | IN, 5 } } }, + { { Int, 0 }, { BinString | IN, 1 }, { Int, 2 }, { Msgflags, 3 }, { Sockaddr | IN, 4 }, { Int32Ptr | IN, 5 } } }, + { "recvmsg", 1, 3, + { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } }, + { "sendmsg", 1, 3, + { { Int, 0 }, { Ptr, 1 }, { Msgflags, 2 } } }, { "execve", 1, 3, { { Name | IN, 0 }, { StringArray | IN, 1 }, { StringArray | IN, 2 } } }, { "linux_execve", 1, 3, @@ -176,7 +200,7 @@ struct syscall syscalls[] = { { "select", 1, 5, { { Int, 0 }, { Fd_set, 1 }, { Fd_set, 2 }, { Fd_set, 3 }, { Timeval, 4 } } }, { "poll", 1, 3, { { Pollfd, 0 }, { Int, 1 }, { Int, 2 } } }, { "gettimeofday", 1, 2, { { Timeval | OUT, 0 }, { Ptr, 1 } } }, - { "clock_gettime", 1, 2, { { Int, 0 }, { Timespec | OUT, 1 } } }, + { "clock_gettime", 1, 2, { { Clockid, 0 }, { Timespec | OUT, 1 } } }, { "getitimer", 1, 2, { { Int, 0 }, { Itimerval | OUT, 2 } } }, { "setitimer", 1, 3, { { Int, 0 }, { Itimerval, 1 } , { Itimerval | OUT, 2 } } }, { "kse_release", 0, 1, { { Timespec, 0 } } }, @@ -198,25 +222,56 @@ struct syscall syscalls[] = { { "futimes", 1, 2, { { Int, 0 }, { Timeval | IN, 1 } } }, { "chflags", 1, 2, - { { Name | IN, 0 }, { Hex, 1 } } }, + { { Name | IN, 0 }, { Chflags | IN, 1 } } }, { "lchflags", 1, 2, - { { Name | IN, 0 }, { Hex, 1 } } }, + { { Name | IN, 0 }, { Chflags | IN, 1 } } }, + { "fchflags", 1, 2, + { { Int | IN, 0 }, { Chflags | IN, 1 } } }, { "pathconf", 1, 2, { { Name | IN, 0 }, { Pathconf, 1 } } }, { "truncate", 1, 3, - { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, + { { Name | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 + QUAD_ALIGN } } }, { "ftruncate", 1, 3, - { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 } } }, + { { Int | IN, 0 }, { Int | IN, 1 }, { Quad | IN, 2 + QUAD_ALIGN } } }, { "kill", 1, 2, { { Int | IN, 0 }, { Signal | IN, 1 } } }, { "munmap", 1, 2, { { Ptr, 0 }, { Int, 1 } } }, { "read", 1, 3, { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 } } }, + { "pread", 1, 4, + { { Int, 0 }, { BinString | OUT, 1 }, { Int, 2 }, { Quad, 3 + QUAD_ALIGN } } }, + { "readv", 1, 3, + { { Int, 0 }, { Iovec | OUT, 1 }, { Int, 2 } } }, { "rename", 1, 2, { { Name , 0 } , { Name, 1 } } }, { "symlink", 1, 2, { { Name , 0 } , { Name, 1 } } }, + { "_umtx_op", 1, 5, + { { UmtxArg1, 0 }, { Umtxop, 1 } , { Int , 2 } , { UmtxArg4, 3 }, { UmtxArg5, 4 } } }, + { "ptrace", 1, 4, + { { Ptrace, 0 }, { Int, 1 } , { Ptr , 2 } , { Int, 3 } } }, + { "wait4", 1, 4, + { { Int, 0 }, { Waitstat | OUT, 1 } , { Waitopts , 2 } , { Rusage, 3 } } }, + { "waitpid", 1, 3, + { { Int, 0 }, { Waitstat | OUT, 1 } , { Waitopts , 2 } } }, + { "sigreturn", 0, 1, + { { Ptr, 0 } } }, + { "madvise", 1, 3, + { { Ptr, 0 }, { Int, 1 } , { Madvise , 2 } } }, + { "thr_set_name", 1, 2, + { { Int, 0 }, { Name, 1 } } }, + { "sendfile", 1, 7, + { { Int, 0 }, + { Int, 1 }, + { Quad, 2 + QUAD_ALIGN }, + { Int, 2 + QUAD_SLOTS + QUAD_ALIGN }, + { Sendfilehdtr, 3 + QUAD_SLOTS + QUAD_ALIGN }, + { Int32Ptr | OUT, 4 + QUAD_SLOTS + QUAD_ALIGN }, + { Sendfileflags, 5 + QUAD_SLOTS + QUAD_ALIGN } } }, + { "utrace", 1, 2, + { { Utrace | IN, 0 }, { Int, 1 } } }, + { 0, 0, 0, { { 0, 0 } } }, }; @@ -276,6 +331,7 @@ static struct xlat fcntlfd_arg[] = { }; static struct xlat fcntlfl_arg[] = { + X(FREAD) X(FWRITE) /* these two can't be set but may be returned by GETFL */ X(O_APPEND) X(O_ASYNC) X(O_FSYNC) X(O_NONBLOCK) X(O_NOFOLLOW) X(O_DIRECT) XEND }; @@ -326,6 +382,65 @@ static struct xlat pathconf_arg[] = { XEND }; +static struct xlat umtxop_arg[] = { + X(UMTX_OP_LOCK) X(UMTX_OP_UNLOCK) X(UMTX_OP_WAIT) X(UMTX_OP_WAKE) + X(UMTX_OP_MUTEX_TRYLOCK) X(UMTX_OP_MUTEX_LOCK) + X(UMTX_OP_MUTEX_UNLOCK) X(UMTX_OP_SET_CEILING) X(UMTX_OP_CV_WAIT) + X(UMTX_OP_CV_SIGNAL) X(UMTX_OP_CV_BROADCAST) X(UMTX_OP_WAIT_UINT) + X(UMTX_OP_RW_RDLOCK) X(UMTX_OP_RW_WRLOCK) X(UMTX_OP_RW_UNLOCK) + XEND +}; + +static struct xlat msg_flags[] = { + X(MSG_OOB) X(MSG_PEEK) X(MSG_DONTROUTE) X(MSG_EOR) X(MSG_TRUNC) + X(MSG_CTRUNC) X(MSG_WAITALL) X(MSG_DONTWAIT) X(MSG_EOF) + X(MSG_NBIO) X(MSG_COMPAT) X(MSG_NOSIGNAL) + XEND +}; + +static struct xlat ptrace_arg[] = { + X(PT_TRACE_ME) X(PT_READ_I) X(PT_READ_D) X(PT_WRITE_I) + X(PT_WRITE_D) X(PT_CONTINUE) X(PT_KILL) X(PT_STEP) + X(PT_ATTACH) X(PT_DETACH) X(PT_IO) X(PT_LWPINFO) X(PT_GETNUMLWPS) + X(PT_GETLWPLIST) X(PT_CLEARSTEP) X(PT_SETSTEP) X(PT_SUSPEND) + X(PT_RESUME) X(PT_TO_SCE) X(PT_TO_SCX) X(PT_SYSCALL) X(PT_GETREGS) + X(PT_SETREGS) X(PT_GETFPREGS) X(PT_SETFPREGS) X(PT_GETDBREGS) + X(PT_SETDBREGS) X(PT_FIRSTMACH) + XEND +}; + +static struct xlat clockid_arg[] = { + X(CLOCK_REALTIME) X(CLOCK_VIRTUAL) X(CLOCK_PROF) X(CLOCK_MONOTONIC) + X(CLOCK_UPTIME) X(CLOCK_UPTIME_PRECISE) X(CLOCK_UPTIME_FAST) + X(CLOCK_REALTIME_PRECISE) X(CLOCK_REALTIME_FAST) + X(CLOCK_MONOTONIC_PRECISE) X(CLOCK_MONOTONIC_FAST) X(CLOCK_SECOND) + XEND +}; + +static struct xlat chflags_flags[] = { + X(UF_NODUMP) X(UF_IMMUTABLE) X(UF_APPEND) X(UF_OPAQUE) + X(UF_NOUNLINK) X(SF_ARCHIVED) X(SF_IMMUTABLE) X(SF_APPEND) + X(SF_NOUNLINK) X(SF_SNAPSHOT) + XEND +}; + +static struct xlat waitopts_flags[] = { + X(WCONTINUED) X(WNOHANG) X(WUNTRACED) + XEND +}; + +static struct xlat sendfile_flags[] = { + X(SF_NODISKIO) + XEND +}; + +static struct xlat madvise_arg[] = { + X(MADV_NORMAL) X(MADV_RANDOM) X(MADV_SEQUENTIAL) X(MADV_WILLNEED) + X(MADV_DONTNEED) X(MADV_FREE) X(MADV_NOSYNC) X(MADV_AUTOSYNC) + X(MADV_NOCORE) X(MADV_CORE) X(MADV_PROTECT) + XEND +}; + #undef X #undef XEND @@ -434,8 +549,53 @@ get_struct(int pid, void *offset, void * return (0); } -#define MAXSIZE 4096 -#define BLOCKSIZE 1024 + +/* + * get_binstring + * + * Read 'len' bytes starting at 'offset', convert them to a readable + * format truncating at 'maxlen' characters, and return the string as a + * malloc'ed pointer. If flags is non-NULL and we had to truncate, set + * BS_TRUNCATED. + */ +#define BS_TRUNCATED 0x01 + +static char * +get_binstring(int pid, void *offset, int len, int maxlen, int *flags) { + char *tmp; + char *tmp2, *tmp3; + int truncated = 0; + + /* Don't print more than maxlen characters, to avoid wrapping a line. + * If we have to truncate, put '...' after the string. + */ + if (len > maxlen) { + len = maxlen; + truncated = 1; + } + + tmp2 = malloc(maxlen+1); + if (len && tmp2 && get_struct(pid, offset, tmp2, len) != -1) { + tmp3 = malloc(len * 4 + 1); + while (len) { + if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= maxlen) + break; + len--; + truncated = 1; + } + asprintf(&tmp, "\"%s\"%s", tmp3, truncated ? "..." : ""); + free(tmp3); + } else + asprintf(&tmp, "0x%p", offset); + if (tmp2) + free(tmp2); + if (flags && truncated) + *flags |= BS_TRUNCATED; + return tmp; +} + +#define MAXSIZE 4096 +#define BLOCKSIZE 1024 /* * get_string * Copy a string from the process. Note that it is @@ -521,36 +681,14 @@ print_arg(struct syscall_args *sc, unsig XXX If type|OUT, assume that the length is the syscall's return value. Otherwise, assume that the length of the block is in the next syscall argument. */ - int max_string = trussinfo->strsize; - char tmp2[max_string+1], *tmp3; int len; - int truncated = 0; if (sc->type & OUT) len = retval; else len = args[sc->offset + 1]; - /* Don't print more than max_string characters, to avoid word - wrap. If we have to truncate put some ... after the string. - */ - if (len > max_string) { - len = max_string; - truncated = 1; - } - if (len && get_struct(pid, (void*)args[sc->offset], &tmp2, len) != -1) { - tmp3 = malloc(len * 4 + 1); - while (len) { - if (strvisx(tmp3, tmp2, len, VIS_CSTYLE|VIS_TAB|VIS_NL) <= max_string) - break; - len--; - truncated = 1; - }; - asprintf(&tmp, "\"%s\"%s", tmp3, truncated?"...":""); - free(tmp3); - } else { - asprintf(&tmp, "0x%lx", args[sc->offset]); - } + tmp = get_binstring(pid, (void*)args[sc->offset], len, trussinfo->strsize, NULL); break; } case StringArray: { @@ -561,7 +699,8 @@ print_arg(struct syscall_args *sc, unsig if (get_struct(pid, (void *)args[sc->offset], (void *)&strarray, sizeof(strarray)) == -1) { - err(1, "get_struct %p", (void *)args[sc->offset]); + asprintf(&tmp, "0x%lx", args[sc->offset]); + break; } num = 0; size = 0; @@ -586,6 +725,93 @@ print_arg(struct syscall_args *sc, unsig tmp2 += sprintf(tmp2, "]"); break; } + case Iovec: { + /* + * XXX: An Iovec argument expects the /next/ syscall argument to + * be the size of the array. This matches the writev and readv + * syscalls. + */ + struct sbuf *sb; + struct iovec *io; + int num = args[sc->offset+1]; + int bytes = sizeof(struct iovec) * num; + sb = sbuf_new(NULL, NULL, 80, SBUF_AUTOEXTEND); + io = malloc(bytes); + + if (get_struct(pid, (void *)args[sc->offset], io, bytes) != -1) { + int i; + sbuf_putc(sb, '{'); + for (i = 0 ; i < num ; i++) { + char *tmp2; + int flags = 0; + if (i) sbuf_cat(sb,", "); + tmp2 = get_binstring(pid, io[i].iov_base, + io[i].iov_len, trussinfo->strsize, &flags); + if (tmp2) { + /* If our string was truncated, print the iovec length + after it */ + if (flags & BS_TRUNCATED) + sbuf_printf(sb, "%s/%d", tmp2, io[i].iov_len); + else + sbuf_cat(sb, tmp2); + free(tmp2); + } else + sbuf_printf(sb, "0x%p/%d", io[i].iov_base, io[i].iov_len); + } + sbuf_putc(sb, '}'); + } else + sbuf_printf(sb, "0x%lx", args[sc->offset]); + sbuf_finish(sb); + tmp = strdup(sbuf_data(sb)); + sbuf_delete(sb); + free(io); + + break; + } + case Sendfilehdtr: { + struct sf_hdtr sf; + struct sbuf *sb; + sb = sbuf_new(NULL, NULL, 80, SBUF_AUTOEXTEND); + if (sb && get_struct(pid, (void *)args[sc->offset], &sf, sizeof(sf)) != -1) { + struct iovec *io; + io = malloc(sizeof(struct iovec) * (sf.hdr_cnt + sf.trl_cnt + 1)); + sbuf_putc(sb, '{'); + if (io && get_struct(pid, (void *)sf.headers, + io, sizeof(struct iovec) * sf.hdr_cnt) != -1) { + int i; + sbuf_putc(sb, '{'); + for (i = 0 ; i < sf.hdr_cnt ; i++) { + if (i) sbuf_cat(sb,", "); + sbuf_printf(sb, "0x%p/%d", io[i].iov_base, io[i].iov_len); + } + sbuf_putc(sb, '}'); + } else + sbuf_printf(sb, "0x%p", sf.headers); + sbuf_printf(sb, ", %d,", sf.hdr_cnt); + + if (io && get_struct(pid, (void *)sf.trailers, + io, sizeof(struct iovec)*sf.trl_cnt) != -1) { + int i; + sbuf_putc(sb, '{'); + for (i = 0 ; i < sf.trl_cnt ; i++) { + if (i) sbuf_cat(sb,", "); + sbuf_printf(sb, "0x%p/%d", io[i].iov_base, io[i].iov_len); + } + sbuf_putc(sb, '}'); + } else + sbuf_printf(sb, "0x%p", sf.headers); + sbuf_printf(sb, ", %d", sf.trl_cnt); + + sbuf_putc(sb, '}'); + sbuf_finish(sb); + tmp = strdup(sbuf_data(sb)); + sbuf_delete(sb); + if (io) free(io); + } else + asprintf(&tmp, "0x%lx", args[sc->offset]); + + break; + } #ifdef __LP64__ case Quad: asprintf(&tmp, "0x%lx", args[sc->offset]); @@ -601,17 +827,48 @@ print_arg(struct syscall_args *sc, unsig case Ptr: asprintf(&tmp, "0x%lx", args[sc->offset]); break; - case Readlinkres: { - char *tmp2; - if (retval == -1) { - tmp = strdup(""); - break; + case Int32Ptr: { + int arg; + if (get_struct(pid, (void *)args[sc->offset], &arg, sizeof(arg)) != -1) { + asprintf(&tmp, "{%d}", arg); + } else { + asprintf(&tmp, "0x%lx", args[sc->offset]); } - tmp2 = get_string(pid, (void*)args[sc->offset], retval); - asprintf(&tmp, "\"%s\"", tmp2); - free(tmp2); break; } + case Waitstat: { + int arg; + if (get_struct(pid, (void *)args[sc->offset], &arg, sizeof(arg)) != -1) { + char *tmp1 = NULL; + if (WIFSTOPPED(arg)) { + tmp1 = strsig(WSTOPSIG(arg)); + if (!tmp1) asprintf(&tmp1, "%d", WSTOPSIG(arg)); + asprintf(&tmp, "{STOP %s}", tmp1); + } else if (WIFSIGNALED(arg)) { + tmp1 = strsig(WTERMSIG(arg)); + if (!tmp1) asprintf(&tmp1, "%d", WTERMSIG(arg)); + asprintf(&tmp, "{SIG %s%s}", tmp1, + WCOREDUMP(arg)?" (core)":""); + } else if (WIFEXITED(arg)) { + asprintf(&tmp, "{EXIT %d}", WEXITSTATUS(arg)); + } else { + asprintf(&tmp, "{%x}",arg); + } + if (tmp1) free(tmp1); + } else { + asprintf(&tmp, "0x%lx", args[sc->offset]); + } + break; + } + case Waitopts: + tmp = strdup(xlookup_bits(waitopts_flags, args[sc->offset])); + break; + case Madvise: + tmp = strdup(xlookup(madvise_arg, args[sc->offset])); + break; + case Sendfileflags: + tmp = strdup(xlookup_bits(sendfile_flags, args[sc->offset])); + break; case Ioctl: { const char *temp = ioctlname(args[sc->offset]); if (temp) { @@ -633,10 +890,25 @@ print_arg(struct syscall_args *sc, unsig asprintf(&tmp, "0x%lx", args[sc->offset]); break; } + case Umtxop: + tmp = strdup(xlookup(umtxop_arg, args[sc->offset])); + break; + case UmtxArg1: + asprintf(&tmp, "0x%lx", args[sc->offset]); + break; + case UmtxArg4: + asprintf(&tmp, "0x%lx", args[sc->offset]); + break; + case UmtxArg5: + asprintf(&tmp, "0x%lx", args[sc->offset]); + break; + case Clockid: + tmp = strdup(xlookup(clockid_arg, args[sc->offset])); + break; case Timespec: { struct timespec ts; if (get_struct(pid, (void *)args[sc->offset], &ts, sizeof(ts)) != -1) - asprintf(&tmp, "{%ld.%09ld }", (long)ts.tv_sec, ts.tv_nsec); + asprintf(&tmp, "{%ld.%09ld}", (long)ts.tv_sec, ts.tv_nsec); else asprintf(&tmp, "0x%lx", args[sc->offset]); break; @@ -644,7 +916,7 @@ print_arg(struct syscall_args *sc, unsig case Timeval: { struct timeval tv; if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) - asprintf(&tmp, "{%ld.%06ld }", (long)tv.tv_sec, tv.tv_usec); + asprintf(&tmp, "{%ld.%06ld}", (long)tv.tv_sec, tv.tv_usec); else asprintf(&tmp, "0x%lx", args[sc->offset]); break; @@ -652,7 +924,7 @@ print_arg(struct syscall_args *sc, unsig case Timeval2: { struct timeval tv[2]; if (get_struct(pid, (void *)args[sc->offset], &tv, sizeof(tv)) != -1) - asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", + asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}", (long)tv[0].tv_sec, tv[0].tv_usec, (long)tv[1].tv_sec, tv[1].tv_usec); else @@ -662,7 +934,7 @@ print_arg(struct syscall_args *sc, unsig case Itimerval: { struct itimerval itv; if (get_struct(pid, (void *)args[sc->offset], &itv, sizeof(itv)) != -1) - asprintf(&tmp, "{%ld.%06ld, %ld.%06ld }", + asprintf(&tmp, "{%ld.%06ld, %ld.%06ld}", (long)itv.it_interval.tv_sec, itv.it_interval.tv_usec, (long)itv.it_value.tv_sec, @@ -682,14 +954,13 @@ print_arg(struct syscall_args *sc, unsig int i, tmpsize, u, used; const int per_fd = 100; - if ((pfd = malloc(bytes)) == NULL) - err(1, "Cannot malloc %d bytes for pollfd array", bytes); - if (get_struct(pid, (void *)args[sc->offset], pfd, bytes) != -1) { + pfd = malloc(bytes); + tmpsize = 1 + per_fd * numfds + 2; + tmp = malloc(tmpsize); + if (pfd && tmp && + get_struct(pid, (void *)args[sc->offset], pfd, bytes) != -1) { used = 0; - tmpsize = 1 + per_fd * numfds + 2; - if ((tmp = malloc(tmpsize)) == NULL) - err(1, "Cannot alloc %d bytes for poll output", tmpsize); tmp[used++] = '{'; for (i = 0; i < numfds; i++) { @@ -705,9 +976,10 @@ print_arg(struct syscall_args *sc, unsig tmp[used++] = '}'; tmp[used++] = '\0'; } else { + if (tmp) free(tmp); asprintf(&tmp, "0x%lx", args[sc->offset]); } - free(pfd); + if (pfd) free(pfd); break; } case Fd_set: { @@ -721,13 +993,12 @@ print_arg(struct syscall_args *sc, unsig int i, tmpsize, u, used; const int per_fd = 20; - if ((fds = malloc(bytes)) == NULL) - err(1, "Cannot malloc %d bytes for fd_set array", bytes); - if (get_struct(pid, (void *)args[sc->offset], fds, bytes) != -1) { + fds = malloc(bytes); + tmpsize = 1 + numfds * per_fd + 2; + tmp = malloc(tmpsize); + if (fds && tmp && + get_struct(pid, (void *)args[sc->offset], fds, bytes) != -1) { used = 0; - tmpsize = 1 + numfds * per_fd + 2; - if ((tmp = malloc(tmpsize)) == NULL) - err(1, "Cannot alloc %d bytes for fd_set output", tmpsize); tmp[used++] = '{'; for (i = 0; i < numfds; i++) { @@ -742,9 +1013,10 @@ print_arg(struct syscall_args *sc, unsig tmp[used++] = '}'; tmp[used++] = '\0'; } else { + if (tmp) free(tmp); asprintf(&tmp, "0x%lx", args[sc->offset]); } - free(fds); + if (fds) free(fds); break; } case Signal: { @@ -841,6 +1113,12 @@ print_arg(struct syscall_args *sc, unsig case Pathconf: tmp = strdup(xlookup(pathconf_arg, args[sc->offset])); break; + case Msgflags: + tmp = strdup(xlookup_bits(msg_flags, args[sc->offset])); + break; + case Chflags: + tmp = strdup(xlookup_bits(chflags_flags, args[sc->offset])); + break; case Sockaddr: { struct sockaddr_storage ss; char addr[64]; @@ -853,14 +1131,16 @@ print_arg(struct syscall_args *sc, unsig int i; if (args[sc->offset] == 0) { - asprintf(&tmp, "NULL"); + tmp = strdup("0x0"); break; } /* yuck: get ss_len */ if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, - sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) - err(1, "get_struct %p", (void *)args[sc->offset]); + sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) { + asprintf(&tmp, "0x%lx", args[sc->offset]); + break; + } /* * If ss_len is 0, then try to guess from the sockaddr type. * AF_UNIX may be initialized incorrectly, so always frob @@ -881,7 +1161,8 @@ print_arg(struct syscall_args *sc, unsig } if (get_struct(pid, (void *)args[sc->offset], (void *)&ss, ss.ss_len) == -1) { - err(2, "get_struct %p", (void *)args[sc->offset]); + asprintf(&tmp, "0x%lx", args[sc->offset]); + break; } switch (ss.ss_family) { @@ -955,22 +1236,23 @@ print_arg(struct syscall_args *sc, unsig else if (sc->offset == 3 && retval != -1) numevents = retval; - if (numevents >= 0) + if (numevents > 0) bytes = sizeof(struct kevent) * numevents; - if ((ke = malloc(bytes)) == NULL) - err(1, "Cannot malloc %d bytes for kevent array", bytes); - if (numevents >= 0 && get_struct(pid, (void *)args[sc->offset], ke, bytes) != -1) { + + tmpsize = 1 + per_ke * numevents + 2; + tmp = malloc(tmpsize); + ke = malloc(bytes+1); + + if (tmp && ke && numevents > 0 && + get_struct(pid, (void *)args[sc->offset], ke, bytes) != -1) { used = 0; - tmpsize = 1 + per_ke * numevents + 2; - if ((tmp = malloc(tmpsize)) == NULL) - err(1, "Cannot alloc %d bytes for kevent output", tmpsize); tmp[used++] = '{'; for (i = 0; i < numevents; i++) { u = snprintf(tmp + used, per_ke, - "%s%p,%s,%s,%d,%p,%p", + "%s%d,%s,%s,%d,%p,%p", i > 0 ? " " : "", - (void *)ke[i].ident, + ke[i].ident, xlookup(kevent_filters, ke[i].filter), xlookup_bits(kevent_flags, ke[i].flags), ke[i].fflags, @@ -982,9 +1264,10 @@ print_arg(struct syscall_args *sc, unsig tmp[used++] = '}'; tmp[used++] = '\0'; } else { + if (tmp) free(tmp); asprintf(&tmp, "0x%lx", args[sc->offset]); } - free(ke); + if (ke) free(ke); break; } case Stat: { @@ -1022,6 +1305,40 @@ print_arg(struct syscall_args *sc, unsig } break; } + case Ptrace: + tmp = strdup(xlookup(ptrace_arg, args[sc->offset])); + break; + case Utrace: { + /* Ugly - guess based on various parameters what the buffer + is supposed to hold. */ + int len; + char buf[80]; + struct utrace_malloc { + void *p; + size_t s; + void *r; + } *ut; + + len = args[sc->offset + 1]; + get_struct(pid,(void *)args[sc->offset],&buf, len<80?len:80); + + if (len == sizeof(struct utrace_malloc)) { + ut = (struct utrace_malloc *)&buf; + if (ut->p == NULL) { + if (ut->s == 0 && ut->r == NULL) + tmp=strdup("malloc_init()"); + else + asprintf(&tmp,"%p = malloc(%zu)", ut->r, ut->s); + } else { + if (ut->s == 0) + asprintf(&tmp,"free(%p)", ut->p); + else + asprintf(&tmp,"%p = realloc(%p, %zu)", ut->r, ut->p, ut->s); + } + } else + tmp = get_binstring(pid, (void*)args[sc->offset], len, trussinfo->strsize, NULL); + break; + } default: errx(1, "Invalid argument type %d\n", sc->type & ARG_MASK); } @@ -1042,26 +1359,41 @@ print_syscall(struct trussinfo *trussinf int len = 0; struct timespec timediff; - if (trussinfo->flags & FOLLOWFORKS) - len += fprintf(trussinfo->outfile, "%5d: ", trussinfo->pid); + if ((trussinfo->curthread->flags & EXIT_ONLY) == 0) { + if (trussinfo->flags & FOLLOWFORKS) + len += fprintf(trussinfo->outfile, "%5d", trussinfo->pid); - if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) { - clock_gettime(CLOCK_REALTIME, &trussinfo->after); - } + if (trussinfo->threadcount > 1) + len += fprintf(trussinfo->outfile, "/%d", trussinfo->curthread->tid/*threadnum*/); - if (trussinfo->flags & ABSOLUTETIMESTAMPS) { - timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff); - len += fprintf(trussinfo->outfile, "%ld.%09ld ", - (long)timediff.tv_sec, timediff.tv_nsec); - } + if ((trussinfo->flags & FOLLOWFORKS) || (trussinfo->threadcount > 1)) + len += fprintf(trussinfo->outfile, ": "); + + if (name != NULL && (!strcmp(name, "execve") || !strcmp(name, "exit"))) { + clock_gettime(CLOCK_REALTIME, &trussinfo->after); + } - if (trussinfo->flags & RELATIVETIMESTAMPS) { - timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); - len += fprintf(trussinfo->outfile, "%ld.%09ld ", - (long)timediff.tv_sec, timediff.tv_nsec); + if (trussinfo->flags & ABSOLUTETIMESTAMPS) { + timespecsubt(&trussinfo->after, &trussinfo->start_time, &timediff); + len += fprintf(trussinfo->outfile, "%ld.%09ld ", + (long)timediff.tv_sec, timediff.tv_nsec); + } + + if (trussinfo->flags & RELATIVETIMESTAMPS) { + timespecsubt(&trussinfo->after, &trussinfo->before, &timediff); + len += fprintf(trussinfo->outfile, "%ld.%09ld ", + (long)timediff.tv_sec, timediff.tv_nsec); + } + + len += fprintf(trussinfo->outfile, "%s(", name); } - len += fprintf(trussinfo->outfile, "%s(", name); + if ((trussinfo->curthread->flags & ENTRY_ONLY)) { + fflush(trussinfo->outfile); + trussinfo->curthread->flags |= PRINTED_ENTRY; + trussinfo->curthread->flags &= ~ENTRY_ONLY; + return; + } for (i = 0; i < nargs; i++) { if (s_args[i]) Index: truss.h =================================================================== RCS file: /home/ncvs/src/usr.bin/truss/truss.h,v retrieving revision 1.8 diff -u -p -r1.8 truss.h --- truss.h 10 Apr 2007 04:03:34 -0000 1.8 +++ truss.h 3 Dec 2008 17:35:58 -0000 @@ -33,13 +33,20 @@ #define NOSIGS 0x00000008 #define EXECVEARGS 0x00000010 #define EXECVEENVS 0x00000020 +#define ENTRY_ONLY 0x00000040 /* Print syscall name only */ +#define PRINTED_ENTRY 0x00000080 /* Printed syscall name already */ +#define EXIT_ONLY 0x00000100 /* Print syscall args & retval only */ struct threadinfo { SLIST_ENTRY(threadinfo) entries; lwpid_t tid; + int threadnum; /* counts from 1 (i.e. this is not threadid) */ int in_syscall; + const char *syscallname; + void *fsc; int in_fork; + int flags; }; struct trussinfo @@ -49,6 +56,7 @@ struct trussinfo int pr_why; int pr_data; int strsize; + int threadcount; /* Number of threads seen in this process */ FILE *outfile; struct timespec start_time;