Index: head/usr.bin/truss/alpha-fbsd.c =================================================================== --- head/usr.bin/truss/alpha-fbsd.c (revision 101281) +++ head/usr.bin/truss/alpha-fbsd.c (revision 101282) @@ -1,330 +1,332 @@ /* * Copryight 1998 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * FreeBSD/alpha-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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "syscalls.h" static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); /* * 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. */ static struct freebsd_syscall { struct syscall *sc; 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() { if (fsc.args) { free(fsc.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); } memset(&fsc, 0, sizeof(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 alpha/alpha/trap.c * is ever changed these functions need to keep up. */ void -alpha_syscall_entry(int pid, int nargs) { +alpha_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { { 0 } }; int syscall; int i; unsigned int parm_offset; struct syscall *sc; int indir = 0; /* indirect system call */ - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_fsc(); lseek(fd, 0L, 0); i = read(fd, ®s, sizeof(regs)); parm_offset = regs.r_regs[R_SP] + sizeof(int); /* * 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. */ syscall = regs.r_regs[R_V0]; if (syscall == SYS_syscall || syscall == SYS___syscall) { indir = 1; syscall = regs.r_regs[R_A0]; } fsc.number = syscall; fsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; if (!fsc.name) { - fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); } if (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!!! */ lseek(Procfd, regs.r_regs[R_SP], SEEK_SET); read(fd, &fsc.args[6], (nargs - 6) * sizeof(fsc.args[0])); case 6: fsc.args[5] = regs.r_regs[R_A5]; case 5: fsc.args[4] = regs.r_regs[R_A4]; case 4: fsc.args[3] = regs.r_regs[R_A3]; case 3: fsc.args[2] = regs.r_regs[R_A2]; case 2: fsc.args[1] = regs.r_regs[R_A1]; case 1: fsc.args[0] = regs.r_regs[R_A0]; case 0: break; } 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(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", fsc.name, nargs); #endif fsc.nargs = nargs; } fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); memset(fsc.s_args, 0, 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(Procfd, &sc->args[i], fsc.args); } } #if DEBUG fprintf(stderr, ")\n"); #endif } #if DEBUG - fprintf(outfile, "\n"); + fprintf(trussinfo->outfile, "\n"); #endif /* * Some system calls should be printed out before they are done -- * execve() and exit(), for example, never return. Possibly change * this to work for any system call that doesn't have an OUT * parameter? */ if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { - print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); + print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); } return; } /* * 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 sytem call number instead of, say, an error status). */ -void -alpha_syscall_exit(int pid, int syscall) { +int +alpha_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; int i; int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); - if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) + if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { + fprintf(trussinfo->outfile, "\n"); return; + } retval = regs.r_regs[R_V0]; errorp = !!(regs.r_regs[R_A3]); /* * This code, while simpler than the initial versions I used, could * stand some significant cleaning. */ sc = fsc.sc; if (!sc) { for (i = 0; i < fsc.nargs; i++) { fsc.s_args[i] = malloc(12); sprintf(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, than don't bothe getting the data; * it may not be valid. */ if (errorp) { temp = malloc(12); sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); } else { temp = print_arg(Procfd, &sc->args[i], fsc.args); } fsc.s_args[i] = temp; } } } /* * It would probably be a good idea to merge the error handling, * but that complicates things considerably. */ - print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); + print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); clear_fsc(); - return; + return (retval); } Index: head/usr.bin/truss/amd64-fbsd32.c =================================================================== --- head/usr.bin/truss/amd64-fbsd32.c (revision 101281) +++ head/usr.bin/truss/amd64-fbsd32.c (revision 101282) @@ -1,309 +1,311 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * FreeBSD/386-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 #include #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "syscalls.h" static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); /* * 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. */ static struct freebsd_syscall { struct syscall *sc; 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() { if (fsc.args) { free(fsc.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); } memset(&fsc, 0, sizeof(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(int pid, int nargs) { +i386_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { 0 }; int syscall; int i; unsigned int parm_offset; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_fsc(); lseek(fd, 0L, 0); i = read(fd, ®s, sizeof(regs)); parm_offset = regs.r_esp + sizeof(int); /* * 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. */ syscall = regs.r_eax; switch (syscall) { case SYS_syscall: lseek(Procfd, parm_offset, SEEK_SET); read(Procfd, &syscall, sizeof(int)); parm_offset += sizeof(int); break; case SYS___syscall: lseek(Procfd, parm_offset, SEEK_SET); read(Procfd, &syscall, sizeof(int)); parm_offset += sizeof(quad_t); break; } fsc.number = syscall; fsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; if (!fsc.name) { - fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); } if (nargs == 0) return; fsc.args = malloc((1+nargs) * sizeof(unsigned long)); lseek(Procfd, parm_offset, SEEK_SET); if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) return; sc = get_syscall(fsc.name); if (sc) { fsc.nargs = sc->nargs; } else { #if DEBUG - fprintf(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", fsc.name, nargs); #endif fsc.nargs = nargs; } fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); memset(fsc.s_args, 0, 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(Procfd, &sc->args[i], fsc.args); } } #if DEBUG fprintf(stderr, ")\n"); #endif } #if DEBUG - fprintf(outfile, "\n"); + fprintf(trussinfo->outfile, "\n"); #endif /* * Some system calls should be printed out before they are done -- * execve() and exit(), for example, never return. Possibly change * this to work for any system call that doesn't have an OUT * parameter? */ if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { - print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); + print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); } return; } /* * 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 sytem call number instead of, say, an error status). */ -void -i386_syscall_exit(int pid, int syscall) { +int +i386_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; int i; int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); - if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) + if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { + fprintf(trussinfo->outfile, "\n"); return; + } 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. */ sc = fsc.sc; if (!sc) { for (i = 0; i < fsc.nargs; i++) { fsc.s_args[i] = malloc(12); sprintf(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, than don't bothe getting the data; * it may not be valid. */ if (errorp) { temp = malloc(12); sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); } else { temp = print_arg(Procfd, &sc->args[i], fsc.args); } fsc.s_args[i] = temp; } } } /* * It would probably be a good idea to merge the error handling, * but that complicates things considerably. */ - print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); + print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); clear_fsc(); - return; + return (retval); } Index: head/usr.bin/truss/amd64-linux32.c =================================================================== --- head/usr.bin/truss/amd64-linux32.c (revision 101281) +++ head/usr.bin/truss/amd64-linux32.c (revision 101282) @@ -1,254 +1,256 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "extern.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "linux_syscalls.h" static int nsyscalls = sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]); /* See the comment in i386-fbsd.c about this structure. */ static struct linux_syscall { struct syscall *sc; char *name; int number; unsigned long args[5]; int nargs; /* number of arguments -- *not* number of words! */ char **s_args; /* the printable arguments */ } lsc; static __inline void clear_lsc() { if (lsc.s_args) { int i; for (i = 0; i < lsc.nargs; i++) if (lsc.s_args[i]) free(lsc.s_args[i]); free(lsc.s_args); } memset(&lsc, 0, sizeof(lsc)); } void -i386_linux_syscall_entry(int pid, int nargs) { +i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { 0 }; int syscall; int i; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_lsc(); lseek(fd, 0L, 0); i = read(fd, ®s, sizeof(regs)); syscall = regs.r_eax; lsc.number = syscall; lsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : linux_syscallnames[syscall]; if (!lsc.name) { - fprintf (outfile, "-- UNKNOWN SYSCALL %d\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d\n", syscall); } if (nargs == 0) return; /* * Linux passes syscall arguments in registers, not * on the stack. Fortunately, we've got access to the * register set. Note that we don't bother checking the * number of arguments. And what does linux do for syscalls * that have more than five arguments? */ lsc.args[0] = regs.r_ebx; lsc.args[1] = regs.r_ecx; lsc.args[2] = regs.r_edx; lsc.args[3] = regs.r_esi; lsc.args[4] = regs.r_edi; sc = get_syscall(lsc.name); if (sc) { lsc.nargs = sc->nargs; } else { #ifdef DEBUG - fprintf(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", lsc.name, nargs); #endif lsc.nargs = nargs; } lsc.s_args = malloc((1+lsc.nargs) * sizeof(char*)); memset(lsc.s_args, 0, lsc.nargs * sizeof(char*)); lsc.sc = sc; if (lsc.name) { #ifdef DEBUG fprintf(stderr, "syscall %s(", lsc.name); #endif for (i = 0; i < lsc.nargs ; i++) { #ifdef DEBUG fprintf(stderr, "0x%x%s", sc ? lsc.args[sc->args[i].offset] : lsc.args[i], i < (lsc.nargs - 1) ? "," : ""); #endif if (sc && !(sc->args[i].type & OUT)) { lsc.s_args[i] = print_arg(Procfd, &sc->args[i], lsc.args); } } #ifdef DEBUG fprintf(stderr, ")\n"); #endif } if (!strcmp(lsc.name, "linux_execve") || !strcmp(lsc.name, "exit")) { - print_syscall(outfile, lsc.name, lsc.nargs, lsc.s_args); + print_syscall(trussinfo, lsc.name, lsc.nargs, lsc.s_args); } return; } /* * Linux syscalls return negative errno's, we do positive and map them */ const int bsd_to_linux_errno[] = { -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, -6, }; -void -i386_linux_syscall_exit(int pid, int syscall) { +int +i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; int i; int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); - if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) + if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { + fprintf(trussinfo->outfile, "\n"); return; - + } retval = regs.r_eax; errorp = !!(regs.r_eflags & PSL_C); sc = lsc.sc; if (!sc) { for (i = 0; i < lsc.nargs; i++) { lsc.s_args[i] = malloc(12); sprintf(lsc.s_args[i], "0x%lx", lsc.args[i]); } } else { for (i = 0; i < sc->nargs; i++) { char *temp; if (sc->args[i].type & OUT) { if (errorp) { temp = malloc(12); sprintf(temp, "0x%lx", lsc.args[sc->args[i].offset]); } else { temp = print_arg(Procfd, &sc->args[i], lsc.args); } lsc.s_args[i] = temp; } } } if (errorp) { for (i = 0; i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) if (retval == bsd_to_linux_errno[i]) break; } - print_syscall_ret(outfile, lsc.name, lsc.nargs, lsc.s_args, errorp, - errorp ? i : retval); + print_syscall_ret(trussinfo, lsc.name, lsc.nargs, lsc.s_args, errorp, + errorp ? i : retval); clear_lsc(); - return; + + return (retval); } Index: head/usr.bin/truss/extern.h =================================================================== --- head/usr.bin/truss/extern.h (revision 101281) +++ head/usr.bin/truss/extern.h (revision 101282) @@ -1,47 +1,47 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ extern int setup_and_wait(char **); extern int start_tracing(int, int); extern void restore_proc(int); extern const char *ioctlname(register_t val); #ifdef __alpha__ -extern void alpha_syscall_entry(int, int); -extern void alpha_syscall_exit(int, int); +extern void alpha_syscall_entry(struct trussinfo *, int); +extern int alpha_syscall_exit(struct trussinfo *, int); #endif #ifdef __i386__ -extern void i386_syscall_entry(int, int); -extern void i386_syscall_exit(int, int); -extern void i386_linux_syscall_entry(int, int); -extern void i386_linux_syscall_exit(int, int); +extern void i386_syscall_entry(struct trussinfo *, int); +extern int i386_syscall_exit(struct trussinfo *, int); +extern void i386_linux_syscall_entry(struct trussinfo *, int); +extern int i386_linux_syscall_exit(struct trussinfo *, int); #endif Index: head/usr.bin/truss/i386-fbsd.c =================================================================== --- head/usr.bin/truss/i386-fbsd.c (revision 101281) +++ head/usr.bin/truss/i386-fbsd.c (revision 101282) @@ -1,309 +1,311 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * FreeBSD/386-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 #include #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "syscalls.h" static int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); /* * 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. */ static struct freebsd_syscall { struct syscall *sc; 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() { if (fsc.args) { free(fsc.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); } memset(&fsc, 0, sizeof(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(int pid, int nargs) { +i386_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { 0 }; int syscall; int i; unsigned int parm_offset; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_fsc(); lseek(fd, 0L, 0); i = read(fd, ®s, sizeof(regs)); parm_offset = regs.r_esp + sizeof(int); /* * 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. */ syscall = regs.r_eax; switch (syscall) { case SYS_syscall: lseek(Procfd, parm_offset, SEEK_SET); read(Procfd, &syscall, sizeof(int)); parm_offset += sizeof(int); break; case SYS___syscall: lseek(Procfd, parm_offset, SEEK_SET); read(Procfd, &syscall, sizeof(int)); parm_offset += sizeof(quad_t); break; } fsc.number = syscall; fsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; if (!fsc.name) { - fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); } if (nargs == 0) return; fsc.args = malloc((1+nargs) * sizeof(unsigned long)); lseek(Procfd, parm_offset, SEEK_SET); if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) return; sc = get_syscall(fsc.name); if (sc) { fsc.nargs = sc->nargs; } else { #if DEBUG - fprintf(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", fsc.name, nargs); #endif fsc.nargs = nargs; } fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); memset(fsc.s_args, 0, 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(Procfd, &sc->args[i], fsc.args); } } #if DEBUG fprintf(stderr, ")\n"); #endif } #if DEBUG - fprintf(outfile, "\n"); + fprintf(trussinfo->outfile, "\n"); #endif /* * Some system calls should be printed out before they are done -- * execve() and exit(), for example, never return. Possibly change * this to work for any system call that doesn't have an OUT * parameter? */ if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { - print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); + print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); } return; } /* * 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 sytem call number instead of, say, an error status). */ -void -i386_syscall_exit(int pid, int syscall) { +int +i386_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; int i; int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); - if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) + if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { + fprintf(trussinfo->outfile, "\n"); return; + } 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. */ sc = fsc.sc; if (!sc) { for (i = 0; i < fsc.nargs; i++) { fsc.s_args[i] = malloc(12); sprintf(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, than don't bothe getting the data; * it may not be valid. */ if (errorp) { temp = malloc(12); sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); } else { temp = print_arg(Procfd, &sc->args[i], fsc.args); } fsc.s_args[i] = temp; } } } /* * It would probably be a good idea to merge the error handling, * but that complicates things considerably. */ - print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); + print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); clear_fsc(); - return; + return (retval); } Index: head/usr.bin/truss/i386-linux.c =================================================================== --- head/usr.bin/truss/i386-linux.c (revision 101281) +++ head/usr.bin/truss/i386-linux.c (revision 101282) @@ -1,254 +1,256 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "extern.h" #include "syscall.h" static int fd = -1; static int cpid = -1; extern int Procfd; -extern FILE *outfile; #include "linux_syscalls.h" static int nsyscalls = sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]); /* See the comment in i386-fbsd.c about this structure. */ static struct linux_syscall { struct syscall *sc; char *name; int number; unsigned long args[5]; int nargs; /* number of arguments -- *not* number of words! */ char **s_args; /* the printable arguments */ } lsc; static __inline void clear_lsc() { if (lsc.s_args) { int i; for (i = 0; i < lsc.nargs; i++) if (lsc.s_args[i]) free(lsc.s_args[i]); free(lsc.s_args); } memset(&lsc, 0, sizeof(lsc)); } void -i386_linux_syscall_entry(int pid, int nargs) { +i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) { char buf[32]; struct reg regs = { 0 }; int syscall; int i; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDWR); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } clear_lsc(); lseek(fd, 0L, 0); i = read(fd, ®s, sizeof(regs)); syscall = regs.r_eax; lsc.number = syscall; lsc.name = (syscall < 0 || syscall > nsyscalls) ? NULL : linux_syscallnames[syscall]; if (!lsc.name) { - fprintf (outfile, "-- UNKNOWN SYSCALL %d\n", syscall); + fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d\n", syscall); } if (nargs == 0) return; /* * Linux passes syscall arguments in registers, not * on the stack. Fortunately, we've got access to the * register set. Note that we don't bother checking the * number of arguments. And what does linux do for syscalls * that have more than five arguments? */ lsc.args[0] = regs.r_ebx; lsc.args[1] = regs.r_ecx; lsc.args[2] = regs.r_edx; lsc.args[3] = regs.r_esi; lsc.args[4] = regs.r_edi; sc = get_syscall(lsc.name); if (sc) { lsc.nargs = sc->nargs; } else { #ifdef DEBUG - fprintf(outfile, "unknown syscall %s -- setting args to %d\n", + fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", lsc.name, nargs); #endif lsc.nargs = nargs; } lsc.s_args = malloc((1+lsc.nargs) * sizeof(char*)); memset(lsc.s_args, 0, lsc.nargs * sizeof(char*)); lsc.sc = sc; if (lsc.name) { #ifdef DEBUG fprintf(stderr, "syscall %s(", lsc.name); #endif for (i = 0; i < lsc.nargs ; i++) { #ifdef DEBUG fprintf(stderr, "0x%x%s", sc ? lsc.args[sc->args[i].offset] : lsc.args[i], i < (lsc.nargs - 1) ? "," : ""); #endif if (sc && !(sc->args[i].type & OUT)) { lsc.s_args[i] = print_arg(Procfd, &sc->args[i], lsc.args); } } #ifdef DEBUG fprintf(stderr, ")\n"); #endif } if (!strcmp(lsc.name, "linux_execve") || !strcmp(lsc.name, "exit")) { - print_syscall(outfile, lsc.name, lsc.nargs, lsc.s_args); + print_syscall(trussinfo, lsc.name, lsc.nargs, lsc.s_args); } return; } /* * Linux syscalls return negative errno's, we do positive and map them */ const int bsd_to_linux_errno[] = { -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, -6, }; -void -i386_linux_syscall_exit(int pid, int syscall) { +int +i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall) { char buf[32]; struct reg regs; int retval; int i; int errorp; struct syscall *sc; - if (fd == -1 || pid != cpid) { - sprintf(buf, "/proc/%d/regs", pid); + if (fd == -1 || trussinfo->pid != cpid) { + sprintf(buf, "/proc/%d/regs", trussinfo->pid); fd = open(buf, O_RDONLY); if (fd == -1) { - fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); + fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); return; } - cpid = pid; + cpid = trussinfo->pid; } lseek(fd, 0L, 0); - if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) + if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { + fprintf(trussinfo->outfile, "\n"); return; - + } retval = regs.r_eax; errorp = !!(regs.r_eflags & PSL_C); sc = lsc.sc; if (!sc) { for (i = 0; i < lsc.nargs; i++) { lsc.s_args[i] = malloc(12); sprintf(lsc.s_args[i], "0x%lx", lsc.args[i]); } } else { for (i = 0; i < sc->nargs; i++) { char *temp; if (sc->args[i].type & OUT) { if (errorp) { temp = malloc(12); sprintf(temp, "0x%lx", lsc.args[sc->args[i].offset]); } else { temp = print_arg(Procfd, &sc->args[i], lsc.args); } lsc.s_args[i] = temp; } } } if (errorp) { for (i = 0; i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) if (retval == bsd_to_linux_errno[i]) break; } - print_syscall_ret(outfile, lsc.name, lsc.nargs, lsc.s_args, errorp, - errorp ? i : retval); + print_syscall_ret(trussinfo, lsc.name, lsc.nargs, lsc.s_args, errorp, + errorp ? i : retval); clear_lsc(); - return; + + return (retval); } Index: head/usr.bin/truss/main.c =================================================================== --- head/usr.bin/truss/main.c (revision 101281) +++ head/usr.bin/truss/main.c (revision 101282) @@ -1,262 +1,268 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * The main module for truss. Suprisingly simple, but, then, the other * files handle the bulk of the work. And, of course, the kernel has to * do a lot of the work :). */ #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "extern.h" /* - * These should really be parameterized -- I don't like having globals, - * but this is the easiest way, right now, to deal with them. + * It's difficult to parameterize this because it must be + * accessible in a signal handler. */ -int pid = 0; -int nosigs = 0; -FILE *outfile; int Procfd; static __inline void usage(void) { fprintf(stderr, "%s\n%s\n", "usage: truss [-S] [-o file] -p pid", " truss [-S] [-o file] command [args]"); exit(1); } /* * WARNING! "FreeBSD a.out" must be first, or set_etype will not * work correctly. */ struct ex_types { const char *type; - void (*enter_syscall)(int, int); - void (*exit_syscall)(int, int); + void (*enter_syscall)(struct trussinfo *, int); + int (*exit_syscall)(struct trussinfo *, int); } ex_types[] = { #ifdef __alpha__ { "FreeBSD ELF", alpha_syscall_entry, alpha_syscall_exit }, #endif #ifdef __i386__ { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit }, { "FreeBSD ELF", i386_syscall_entry, i386_syscall_exit }, { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit }, #endif { 0, 0, 0 }, }; /* * Set the execution type. This is called after every exec, and when * a process is first monitored. The procfs pseudo-file "etype" has * the execution module type -- see /proc/curproc/etype for an example. */ static struct ex_types * -set_etype(void) { +set_etype(struct trussinfo *trussinfo) { struct ex_types *funcs; char etype[24]; char progt[32]; int fd; - sprintf(etype, "/proc/%d/etype", pid); + sprintf(etype, "/proc/%d/etype", trussinfo->pid); if ((fd = open(etype, O_RDONLY)) == -1) { strcpy(progt, "FreeBSD a.out"); } else { int len = read(fd, progt, sizeof(progt)); progt[len-1] = '\0'; close(fd); } for (funcs = ex_types; funcs->type; funcs++) if (!strcmp(funcs->type, progt)) break; if (funcs->type == NULL) { funcs = &ex_types[0]; warn("Execution type %s is not supported -- using %s\n", progt, funcs->type); } return funcs; } int main(int ac, char **av) { int c; int i; char **command; struct procfs_status pfs; struct ex_types *funcs; int in_exec = 0; char *fname = NULL; int sigexit = 0; + struct trussinfo *trussinfo; - outfile = stderr; + /* Initialize the trussinfo struct */ + trussinfo = (struct trussinfo *)malloc(sizeof(struct trussinfo)); + if (trussinfo == NULL) + errx(1, "malloc() failed"); + bzero(trussinfo, sizeof(struct trussinfo)); + trussinfo->outfile = stderr; + while ((c = getopt(ac, av, "p:o:S")) != -1) { switch (c) { case 'p': /* specified pid */ - pid = atoi(optarg); + trussinfo->pid = atoi(optarg); break; case 'o': /* Specified output file */ fname = optarg; break; case 'S': /* Don't trace signals */ - nosigs = 1; + trussinfo->flags |= NOSIGS; break; default: usage(); } } ac -= optind; av += optind; - if ((pid == 0 && ac == 0) || (pid != 0 && ac != 0)) + if ((trussinfo->pid == 0 && ac == 0) || (trussinfo->pid != 0 && ac != 0)) usage(); if (fname != NULL) { /* Use output file */ - if ((outfile = fopen(fname, "w")) == NULL) + if ((trussinfo->outfile = fopen(fname, "w")) == NULL) errx(1, "cannot open %s", fname); } /* * If truss starts the process itself, it will ignore some signals -- * they should be passed off to the process, which may or may not * exit. If, however, we are examining an already-running process, * then we restore the event mask on these same signals. */ - if (pid == 0) { /* Start a command ourselves */ + if (trussinfo->pid == 0) { /* Start a command ourselves */ command = av; - pid = setup_and_wait(command); + trussinfo->pid = setup_and_wait(command); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal(SIGQUIT, SIG_IGN); } else { signal(SIGINT, restore_proc); signal(SIGTERM, restore_proc); signal(SIGQUIT, restore_proc); } /* * At this point, if we started the process, it is stopped waiting to * be woken up, either in exit() or in execve(). */ - Procfd = start_tracing(pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | - (nosigs ? 0 : S_SIG)); + Procfd = start_tracing( + trussinfo->pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT | + ((trussinfo->flags & NOSIGS) ? 0 : S_SIG)); if (Procfd == -1) return 0; pfs.why = 0; - funcs = set_etype(); + funcs = set_etype(trussinfo); /* * At this point, it's a simple loop, waiting for the process to * stop, finding out why, printing out why, and then continuing it. * All of the grunt work is done in the support routines. */ do { int val = 0; if (ioctl(Procfd, PIOCWAIT, &pfs) == -1) warn("PIOCWAIT top of loop"); else { switch(i = pfs.why) { case S_SCE: - funcs->enter_syscall(pid, pfs.val); + funcs->enter_syscall(trussinfo, pfs.val); break; case S_SCX: /* * This is so we don't get two messages for an exec -- one * for the S_EXEC, and one for the syscall exit. It also, * conveniently, ensures that the first message printed out * isn't the return-from-syscall used to create the process. */ if (in_exec) { in_exec = 0; break; } - funcs->exit_syscall(pid, pfs.val); + funcs->exit_syscall(trussinfo, pfs.val); break; case S_SIG: - fprintf(outfile, "SIGNAL %lu\n", pfs.val); + fprintf(trussinfo->outfile, "SIGNAL %lu\n", pfs.val); sigexit = pfs.val; break; case S_EXIT: - fprintf (outfile, "process exit, rval = %lu\n", pfs.val); + fprintf (trussinfo->outfile, "process exit, rval = %lu\n", pfs.val); break; case S_EXEC: - funcs = set_etype(); + funcs = set_etype(trussinfo); in_exec = 1; break; default: - fprintf (outfile, "Process stopped because of: %d\n", i); + fprintf (trussinfo->outfile, "Process stopped because of: %d\n", i); break; } } if (ioctl(Procfd, PIOCCONT, val) == -1) { - if (kill(pid, 0) == -1 && errno == ESRCH) + if (kill(trussinfo->pid, 0) == -1 && errno == ESRCH) break; else warn("PIOCCONT"); } } while (pfs.why != S_EXIT); - fflush(outfile); + fflush(trussinfo->outfile); if (sigexit) { if (sigexit == SIGQUIT) exit(sigexit); (void) signal(sigexit, SIG_DFL); (void) kill(getpid(), sigexit); } return 0; } Index: head/usr.bin/truss/setup.c =================================================================== --- head/usr.bin/truss/setup.c (revision 101281) +++ head/usr.bin/truss/setup.c (revision 101282) @@ -1,184 +1,185 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * Various setup functions for truss. Not the cleanest-written code, * I'm afraid. */ #include #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "extern.h" static int evflags = 0; /* * 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. */ int setup_and_wait(char *command[]) { struct procfs_status pfs; char buf[32]; int fd; int pid; int flags; pid = fork(); if (pid == -1) { err(1, "fork failed"); } if (pid == 0) { /* Child */ int mask = S_EXEC | S_EXIT; fd = open("/proc/curproc/mem", O_WRONLY); if (fd == -1) err(2, "cannot open /proc/curproc/mem"); fcntl(fd, F_SETFD, 1); if (ioctl(fd, PIOCBIS, mask) == -1) err(3, "PIOCBIS"); flags = PF_LINGER; /* * The PF_LINGER flag tells procfs not to wake up the * process on last close; normally, this is the behaviour * we want. */ if (ioctl(fd, PIOCSFL, flags) == -1) warn("cannot set PF_LINGER"); execvp(command[0], command); mask = ~0; ioctl(fd, PIOCBIC, ~0); err(4, "execvp %s", command[0]); } /* Only in the parent here */ if (waitpid(pid, NULL, WNOHANG) != 0) { /* * Process exited before it got to us -- meaning the exec failed * miserably -- so we just quietly exit. */ exit(1); } sprintf(buf, "/proc/%d/mem", pid); if ((fd = open(buf, O_RDWR)) == -1) err(5, "cannot open %s", buf); if (ioctl(fd, PIOCWAIT, &pfs) == -1) err(6, "PIOCWAIT"); if (pfs.why == S_EXIT) { fprintf(stderr, "process exited before exec'ing\n"); ioctl(fd, PIOCCONT, 0); wait(0); exit(7); } close(fd); return 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. */ int start_tracing(int pid, int flags) { int fd; char buf[32]; struct procfs_status tmp; sprintf(buf, "/proc/%d/mem", pid); fd = open(buf, O_RDWR); if (fd == -1) { /* * The process may have run away before we could start -- this * happens with SUGID programs. So we need to see if it still * exists before we complain bitterly. */ if (kill(pid, 0) == -1) return -1; err(8, "cannot open %s", buf); } if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { err(10, "cannot get procfs status struct"); } evflags = tmp.events; if (ioctl(fd, PIOCBIS, flags) == -1) err(9, "cannot set procfs event bit mask"); /* * This clears the PF_LINGER set above in setup_and_wait(); * if truss happens to die before this, then the process * needs to be woken up via procctl. */ if (ioctl(fd, PIOCSFL, 0) == -1) warn("cannot clear PF_LINGER"); return fd; } /* * Restore a process back to it's pre-truss state. * Called for SIGINT, SIGTERM, SIGQUIT. This only * applies if truss was told to monitor an already-existing * process. */ void restore_proc(int signo __unused) { extern int Procfd; ioctl(Procfd, PIOCBIC, ~0); if (evflags) ioctl(Procfd, PIOCBIS, evflags); exit(0); } Index: head/usr.bin/truss/syscall.h =================================================================== --- head/usr.bin/truss/syscall.h (revision 101281) +++ head/usr.bin/truss/syscall.h (revision 101282) @@ -1,48 +1,48 @@ /* * See i386-fbsd.c for copyright and license terms. * * System call arguments come in several flavours: * Hex -- values that should be printed in hex (addresses) * Octal -- Same as above, but octal * Int -- normal integer values (file descriptors, for example) * String -- pointers to sensible data. Note that we treat read() and * write() arguments as such, even though they may *not* be * printable data. * Ptr -- pointer to some specific structure. Just print as hex for now. * Quad -- a double-word value. e.g., lseek(int, offset_t, int) * Stat -- a pointer to a stat buffer. Currently unused. * Ioctl -- an ioctl command. Woefully limited. * * 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 * IN (meaning that the data is passed *into* the system call). */ /* * $FreeBSD$ */ enum Argtype { None = 1, Hex, Octal, Int, String, Ptr, Stat, Ioctl, Quad, Signal, Sockaddr }; #define ARG_MASK 0xff #define OUT 0x100 #define IN /*0x20*/0 struct syscall_args { enum Argtype type; int offset; }; struct syscall { const char *name; int ret_type; /* 0, 1, or 2 return values */ int nargs; /* actual number of meaningful arguments */ /* Hopefully, no syscalls with > 10 args */ struct syscall_args args[10]; }; struct syscall *get_syscall(const char*); char *get_string(int, void*, int); char *print_arg(int, struct syscall_args *, unsigned long*); -void print_syscall(FILE *, const char *, int, char **); -void print_syscall_ret(FILE *, const char *, int, char **, int, int); +void print_syscall(struct trussinfo *, const char *, int, char **); +void print_syscall_ret(struct trussinfo *, const char *, int, char **, int, int); Index: head/usr.bin/truss/syscalls.c =================================================================== --- head/usr.bin/truss/syscalls.c (revision 101281) +++ head/usr.bin/truss/syscalls.c (revision 101282) @@ -1,380 +1,381 @@ /* * Copryight 1997 Sean Eric Fagan * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Sean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * This file has routines used to print out system calls and their * arguments. */ #include #include #include #include #include #include #include #include #include #include #include #include +#include "truss.h" #include "extern.h" #include "syscall.h" /* * This should probably be in its own file. */ struct syscall syscalls[] = { { "readlink", 1, 3, { { String, 0 } , { String | OUT, 1 }, { Int, 2 }}}, { "lseek", 2, 3, { { Int, 0 }, {Quad, 2 }, { Int, 4 }}}, { "mmap", 2, 6, { { Hex, 0 }, {Int, 1}, {Hex, 2}, {Hex, 3}, {Int, 4}, {Quad, 6}}}, { "open", 1, 3, { { String | IN, 0} , { Hex, 1}, {Octal, 2}}}, { "linux_open", 1, 3, { { String, 0 }, { Hex, 1}, { Octal, 2 }}}, { "close", 1, 1, { { Int, 0 } } }, { "fstat", 1, 2, { { Int, 0}, {Ptr | OUT , 1 }}}, { "stat", 1, 2, { { String | IN, 0 }, { Ptr | OUT, 1 }}}, { "lstat", 1, 2, { { String | IN, 0 }, { Ptr | OUT, 1 }}}, { "linux_newstat", 1, 2, { { String | IN, 0 }, { Ptr | OUT, 1 }}}, { "linux_newfstat", 1, 2, { { Int, 0 }, { Ptr | OUT, 1 }}}, { "write", 1, 3, { { Int, 0}, { Ptr | IN, 1 }, { Int, 2 }}}, { "ioctl", 1, 3, { { Int, 0}, { Ioctl, 1 }, { Hex, 2 }}}, { "break", 1, 1, { { Hex, 0 }}}, { "exit", 0, 1, { { Hex, 0 }}}, { "access", 1, 2, { { String | IN, 0 }, { Int, 1 }}}, { "sigaction", 1, 3, { { Signal, 0 }, { Ptr | IN, 1 }, { Ptr | OUT, 2 }}}, { "accept", 1, 3, { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, { "bind", 1, 3, { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, { "connect", 1, 3, { { Hex, 0 }, { Sockaddr | IN, 1 }, { Int, 2 } } }, { "getpeername", 1, 3, { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, { "getsockname", 1, 3, { { Hex, 0 }, { Sockaddr | OUT, 1 }, { Ptr | OUT, 2 } } }, { 0, 0, 0, { { 0, 0 }}}, }; /* * If/when the list gets big, it might be desirable to do it * as a hash table or binary search. */ struct syscall * get_syscall(const char *name) { struct syscall *sc = syscalls; while (sc->name) { if (!strcmp(name, sc->name)) return sc; sc++; } return NULL; } /* * get_struct * * Copy a fixed amount of bytes from the process. */ static int get_struct(int procfd, void *offset, void *buf, int len) { char *pos; FILE *p; int c, fd; if ((fd = dup(procfd)) == -1) err(1, "dup"); if ((p = fdopen(fd, "r")) == NULL) err(1, "fdopen"); fseeko(p, (uintptr_t)offset, SEEK_SET); for (pos = (char *)buf; len--; pos++) { if ((c = fgetc(p)) == EOF) return -1; *pos = c; } fclose(p); return 0; } /* * get_string * Copy a string from the process. Note that it is * expected to be a C string, but if max is set, it will * only get that much. */ char * get_string(int procfd, void *offset, int max) { char *buf; int size, len, c, fd; FILE *p; if ((fd = dup(procfd)) == -1) err(1, "dup"); if ((p = fdopen(fd, "r")) == NULL) err(1, "fdopen"); buf = malloc( size = (max ? max : 64 ) ); len = 0; buf[0] = 0; fseeko(p, (uintptr_t)offset, SEEK_SET); while ((c = fgetc(p)) != EOF) { buf[len++] = c; if (c == 0 || len == max) { buf[len] = 0; break; } if (len == size) { char *tmp; tmp = realloc(buf, size+64); if (tmp == NULL) { buf[len] = 0; fclose(p); return buf; } size += 64; buf = tmp; } } fclose(p); return buf; } /* * Gag. This is really unportable. Multiplication is more portable. * But slower, from the code I saw. */ static long long make_quad(unsigned long p1, unsigned long p2) { union { long long ll; unsigned long l[2]; } t; t.l[0] = p1; t.l[1] = p2; return t.ll; } /* * print_arg * Converts a syscall argument into a string. Said string is * allocated via malloc(), so needs to be free()'d. The file * descriptor is for the process' memory (via /proc), and is used * to get any data (where the argument is a pointer). sc is * a pointer to the syscall description (see above); args is * an array of all of the system call arguments. */ char * print_arg(int fd, struct syscall_args *sc, unsigned long *args) { char *tmp = NULL; switch (sc->type & ARG_MASK) { case Hex: tmp = malloc(12); sprintf(tmp, "0x%lx", args[sc->offset]); break; case Octal: tmp = malloc(13); sprintf(tmp, "0%lo", args[sc->offset]); break; case Int: tmp = malloc(12); sprintf(tmp, "%ld", args[sc->offset]); break; case String: { char *tmp2; tmp2 = get_string(fd, (void*)args[sc->offset], 0); tmp = malloc(strlen(tmp2) + 3); sprintf(tmp, "\"%s\"", tmp2); free(tmp2); } break; case Quad: { unsigned long long t; unsigned long l1, l2; l1 = args[sc->offset]; l2 = args[sc->offset+1]; t = make_quad(l1, l2); tmp = malloc(24); sprintf(tmp, "0x%qx", t); break; } case Ptr: tmp = malloc(12); sprintf(tmp, "0x%lx", args[sc->offset]); break; case Ioctl: { const char *temp = ioctlname(args[sc->offset]); if (temp) tmp = strdup(temp); else { tmp = malloc(12); sprintf(tmp, "0x%lx", args[sc->offset]); } } break; case Signal: { long sig; sig = args[sc->offset]; tmp = malloc(12); if (sig > 0 && sig < NSIG) { int i; sprintf(tmp, "sig%s", sys_signame[sig]); for (i = 0; tmp[i] != '\0'; ++i) tmp[i] = toupper(tmp[i]); } else { sprintf(tmp, "%ld", sig); } } break; case Sockaddr: { struct sockaddr_storage ss; char addr[64]; struct sockaddr_in *lsin; struct sockaddr_in6 *lsin6; struct sockaddr_un *sun; struct sockaddr *sa; char *p; u_char *q; int i; /* yuck: get ss_len */ if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, sizeof(ss.ss_len) + sizeof(ss.ss_family)) == -1) err(1, "get_struct %p", (void *)args[sc->offset]); /* sockaddr_un never have the length filled in! */ if (ss.ss_family == AF_UNIX) { if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, sizeof(*sun)) == -1) err(2, "get_struct %p", (void *)args[sc->offset]); } else { if (get_struct(fd, (void *)args[sc->offset], (void *)&ss, ss.ss_len) == -1) err(2, "get_struct %p", (void *)args[sc->offset]); } switch (ss.ss_family) { case AF_INET: lsin = (struct sockaddr_in *)&ss; inet_ntop(AF_INET, &lsin->sin_addr, addr, sizeof addr); asprintf(&tmp, "{ AF_INET %s:%d }", addr, htons(lsin->sin_port)); break; case AF_INET6: lsin6 = (struct sockaddr_in6 *)&ss; inet_ntop(AF_INET6, &lsin6->sin6_addr, addr, sizeof addr); asprintf(&tmp, "{ AF_INET6 [%s]:%d }", addr, htons(lsin6->sin6_port)); break; case AF_UNIX: sun = (struct sockaddr_un *)&ss; asprintf(&tmp, "{ AF_UNIX \"%s\" }", sun->sun_path); break; default: sa = (struct sockaddr *)&ss; asprintf(&tmp, "{ sa_len = %d, sa_family = %d, sa_data = {%n%*s } }", (int)sa->sa_len, (int)sa->sa_family, &i, 6 * (int)(sa->sa_len - ((char *)&sa->sa_data - (char *)sa)), ""); if (tmp != NULL) { p = tmp + i; for (q = (u_char *)&sa->sa_data; q < (u_char *)sa + sa->sa_len; q++) p += sprintf(p, " %#02x,", *q); } } } break; } return tmp; } /* * print_syscall * Print (to outfile) the system call and its arguments. Note that * nargs is the number of arguments (not the number of words; this is * potentially confusing, I know). */ void -print_syscall(FILE *outfile, const char *name, int nargs, char **s_args) { +print_syscall(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args) { int i; int len = 0; - len += fprintf(outfile, "%s(", name); + len += fprintf(trussinfo->outfile, "%s(", name); for (i = 0; i < nargs; i++) { if (s_args[i]) - len += fprintf(outfile, "%s", s_args[i]); + len += fprintf(trussinfo->outfile, "%s", s_args[i]); else - len += fprintf(outfile, ""); - len += fprintf(outfile, "%s", i < (nargs - 1) ? "," : ""); + len += fprintf(trussinfo->outfile, ""); + len += fprintf(trussinfo->outfile, "%s", i < (nargs - 1) ? "," : ""); } - len += fprintf(outfile, ")"); + len += fprintf(trussinfo->outfile, ")"); for (i = 0; i < 6 - (len / 8); i++) - fprintf(outfile, "\t"); + fprintf(trussinfo->outfile, "\t"); } void -print_syscall_ret(FILE *outfile, const char *name, int nargs, char **s_args, int errorp, int retval) { - print_syscall(outfile, name, nargs, s_args); +print_syscall_ret(struct trussinfo *trussinfo, const char *name, int nargs, char **s_args, int errorp, int retval) { + print_syscall(trussinfo, name, nargs, s_args); if (errorp) { - fprintf(outfile, " ERR#%d '%s'\n", retval, strerror(retval)); + fprintf(trussinfo->outfile, " ERR#%d '%s'\n", retval, strerror(retval)); } else { - fprintf(outfile, " = %d (0x%x)\n", retval, retval); + fprintf(trussinfo->outfile, " = %d (0x%x)\n", retval, retval); } } Index: head/usr.bin/truss/truss.h =================================================================== --- head/usr.bin/truss/truss.h (nonexistent) +++ head/usr.bin/truss/truss.h (revision 101282) @@ -0,0 +1,35 @@ +/* + * Copryight 2001 Jamey Wood + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#define NOSIGS 0x00000008 + +struct trussinfo +{ + int pid; + int flags; + FILE *outfile; +}; Property changes on: head/usr.bin/truss/truss.h ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property