i386-fbsd.c revision 101423
143939Sabial/* 246493Sabial * Copryight 1997 Sean Eric Fagan 343939Sabial * 443939Sabial * Redistribution and use in source and binary forms, with or without 543939Sabial * modification, are permitted provided that the following conditions 643939Sabial * are met: 746493Sabial * 1. Redistributions of source code must retain the above copyright 846493Sabial * notice, this list of conditions and the following disclaimer. 943939Sabial * 2. Redistributions in binary form must reproduce the above copyright 1043939Sabial * notice, this list of conditions and the following disclaimer in the 1143939Sabial * documentation and/or other materials provided with the distribution. 1243939Sabial * 3. All advertising materials mentioning features or use of this software 1343939Sabial * must display the following acknowledgement: 1443939Sabial * This product includes software developed by Sean Eric Fagan 1543939Sabial * 4. Neither the name of the author may be used to endorse or promote 1643939Sabial * products derived from this software without specific prior written 1743939Sabial * permission. 1843939Sabial * 1943939Sabial * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2043939Sabial * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2143939Sabial * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2243939Sabial * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2343939Sabial * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2443939Sabial * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2543939Sabial * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2643939Sabial * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2743939Sabial * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2843939Sabial * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2943939Sabial * SUCH DAMAGE. 3046493Sabial */ 3138589Sabial 3238589Sabial#ifndef lint 3338589Sabialstatic const char rcsid[] = 3438589Sabial "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 101423 2002-08-06 12:46:14Z mdodd $"; 3538589Sabial#endif /* not lint */ 3638589Sabial 3746493Sabial/* 3838589Sabial * FreeBSD/386-specific system call handling. This is probably the most 3938589Sabial * complex part of the entire truss program, although I've got lots of 4046493Sabial * it handled relatively cleanly now. The system call names are generated 4146493Sabial * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 4238589Sabial * names used for the various structures are confusing, I sadly admit. 4346493Sabial */ 4446493Sabial 4546493Sabial#include <sys/types.h> 4638589Sabial#include <sys/ioctl.h> 4746493Sabial#include <sys/pioctl.h> 4846493Sabial#include <sys/syscall.h> 4938589Sabial 5046493Sabial#include <machine/reg.h> 5146493Sabial#include <machine/psl.h> 5246493Sabial 5338589Sabial#include <errno.h> 5446493Sabial#include <fcntl.h> 5546493Sabial#include <signal.h> 5646493Sabial#include <stdio.h> 5746493Sabial#include <stdlib.h> 5838589Sabial#include <string.h> 5946493Sabial#include <time.h> 6038589Sabial#include <unistd.h> 6146493Sabial 6238589Sabial#include "truss.h" 6346493Sabial#include "syscall.h" 6446493Sabial 6546493Sabialstatic int fd = -1; 6646493Sabialstatic int cpid = -1; 6746493Sabialextern int Procfd; 6846493Sabial 6946493Sabial#include "syscalls.h" 7046493Sabial 7146493Sabialstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7246493Sabial 7346493Sabial/* 7446493Sabial * This is what this particular file uses to keep track of a system call. 7546493Sabial * It is probably not quite sufficient -- I can probably use the same 7646493Sabial * structure for the various syscall personalities, and I also probably 7746493Sabial * need to nest system calls (for signal handlers). 7846493Sabial * 7946493Sabial * 'struct syscall' describes the system call; it may be NULL, however, 8046493Sabial * if we don't know about this particular system call yet. 8146493Sabial */ 8246493Sabialstatic struct freebsd_syscall { 8346493Sabial struct syscall *sc; 8438589Sabial char *name; 8538589Sabial int number; 8638589Sabial unsigned long *args; 8738589Sabial int nargs; /* number of arguments -- *not* number of words! */ 8838589Sabial char **s_args; /* the printable arguments */ 8938589Sabial} fsc; 9038589Sabial 9138589Sabial/* Clear up and free parts of the fsc structure. */ 9238589Sabialstatic __inline void 9338589Sabialclear_fsc() { 9438589Sabial if (fsc.args) { 9538589Sabial free(fsc.args); 9638589Sabial } 9738589Sabial if (fsc.s_args) { 9838589Sabial int i; 9938589Sabial for (i = 0; i < fsc.nargs; i++) 10038589Sabial if (fsc.s_args[i]) 10138589Sabial free(fsc.s_args[i]); 10246493Sabial free(fsc.s_args); 10338589Sabial } 10438589Sabial memset(&fsc, 0, sizeof(fsc)); 10546493Sabial} 10646493Sabial 10746493Sabial/* 10846493Sabial * Called when a process has entered a system call. nargs is the 10938589Sabial * number of words, not number of arguments (a necessary distinction 11038589Sabial * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11138589Sabial * is ever changed these functions need to keep up. 11238589Sabial */ 11338589Sabial 11438589Sabialvoid 11538589Sabiali386_syscall_entry(struct trussinfo *trussinfo, int nargs) { 11638589Sabial char buf[32]; 11738589Sabial struct reg regs = { 0 }; 11838589Sabial int syscall; 11938589Sabial int i; 12038589Sabial unsigned int parm_offset; 12146493Sabial struct syscall *sc; 12246493Sabial 12346493Sabial if (fd == -1 || trussinfo->pid != cpid) { 12446493Sabial sprintf(buf, "/proc/%d/regs", trussinfo->pid); 12538589Sabial fd = open(buf, O_RDWR); 12638589Sabial if (fd == -1) { 12738589Sabial fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 12838589Sabial return; 12938589Sabial } 13038589Sabial cpid = trussinfo->pid; 13138589Sabial } 13246493Sabial 13338589Sabial clear_fsc(); 13438589Sabial lseek(fd, 0L, 0); 13546493Sabial i = read(fd, ®s, sizeof(regs)); 13646493Sabial parm_offset = regs.r_esp + sizeof(int); 13746493Sabial 13846493Sabial /* 13946493Sabial * FreeBSD has two special kinds of system call redirctions -- 14046493Sabial * SYS_syscall, and SYS___syscall. The former is the old syscall() 14146493Sabial * routine, basicly; the latter is for quad-aligned arguments. 14246493Sabial */ 14338589Sabial syscall = regs.r_eax; 14438589Sabial switch (syscall) { 14546493Sabial case SYS_syscall: 14646493Sabial lseek(Procfd, parm_offset, SEEK_SET); 14746493Sabial read(Procfd, &syscall, sizeof(int)); 14846493Sabial parm_offset += sizeof(int); 14946493Sabial break; 15038589Sabial case SYS___syscall: 15146493Sabial lseek(Procfd, parm_offset, SEEK_SET); 15246493Sabial read(Procfd, &syscall, sizeof(int)); 15346493Sabial parm_offset += sizeof(quad_t); 15446493Sabial break; 15546493Sabial } 15638589Sabial 15746493Sabial fsc.number = syscall; 15846493Sabial fsc.name = 15946493Sabial (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; 16046493Sabial if (!fsc.name) { 16146493Sabial fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); 16246493Sabial } 16346493Sabial 16446493Sabial if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 16546493Sabial && ((!strcmp(fsc.name, "fork") 16646493Sabial || !strcmp(fsc.name, "rfork") 16746493Sabial || !strcmp(fsc.name, "vfork")))) 16846493Sabial { 16946493Sabial trussinfo->in_fork = 1; 17038589Sabial } 17146493Sabial 17246493Sabial if (nargs == 0) 17346493Sabial return; 17446493Sabial 17546493Sabial fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 17646493Sabial lseek(Procfd, parm_offset, SEEK_SET); 17746493Sabial if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 17846493Sabial return; 17946493Sabial 18046493Sabial sc = get_syscall(fsc.name); 18146493Sabial if (sc) { 18246493Sabial fsc.nargs = sc->nargs; 18346493Sabial } else { 18446493Sabial#if DEBUG 18546493Sabial fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 18638589Sabial fsc.name, nargs); 18738589Sabial#endif 18846493Sabial fsc.nargs = nargs; 18946493Sabial } 19046493Sabial 19146493Sabial fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 19246493Sabial memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 19338589Sabial fsc.sc = sc; 19446493Sabial 19546493Sabial /* 19646493Sabial * At this point, we set up the system call arguments. 19746493Sabial * We ignore any OUT ones, however -- those are arguments that 19838589Sabial * are set by the system call, and so are probably meaningless 19946493Sabial * now. This doesn't currently support arguments that are 20038589Sabial * passed in *and* out, however. 20138589Sabial */ 20246493Sabial 20338589Sabial if (fsc.name) { 20438589Sabial 20538589Sabial#if DEBUG 20638589Sabial fprintf(stderr, "syscall %s(", fsc.name); 20738589Sabial#endif 20838589Sabial for (i = 0; i < fsc.nargs; i++) { 20946493Sabial#if DEBUG 21038589Sabial fprintf(stderr, "0x%x%s", 21146493Sabial sc 21238589Sabial ? fsc.args[sc->args[i].offset] 21346493Sabial : fsc.args[i], 21446493Sabial i < (fsc.nargs - 1) ? "," : ""); 21546493Sabial#endif 21646493Sabial if (sc && !(sc->args[i].type & OUT)) { 21746493Sabial fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 21846493Sabial } 21938589Sabial } 22046493Sabial#if DEBUG 22146493Sabial fprintf(stderr, ")\n"); 22238589Sabial#endif 22346493Sabial } 22446493Sabial 22546493Sabial#if DEBUG 22646493Sabial fprintf(trussinfo->outfile, "\n"); 22746493Sabial#endif 22838589Sabial 22938589Sabial /* 23038589Sabial * Some system calls should be printed out before they are done -- 23138589Sabial * execve() and exit(), for example, never return. Possibly change 23238589Sabial * this to work for any system call that doesn't have an OUT 23346493Sabial * parameter? 23438589Sabial */ 23538589Sabial 23638589Sabial if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 23746493Sabial 23846493Sabial /* XXX 23946493Sabial * This could be done in a more general 24038589Sabial * manner but it still wouldn't be very pretty. 24138589Sabial */ 24238589Sabial if (!strcmp(fsc.name, "execve")) { 24338589Sabial if ((trussinfo->flags & EXECVEARGS) == 0) 24438589Sabial if (fsc.s_args[1]) { 24538589Sabial free(fsc.s_args[1]); 24638589Sabial fsc.s_args[1] = NULL; 24738589Sabial } 24838589Sabial if ((trussinfo->flags & EXECVEENVS) == 0) 24946493Sabial if (fsc.s_args[2]) { 25046493Sabial free(fsc.s_args[2]); 25146493Sabial fsc.s_args[2] = NULL; 25238589Sabial } 25338589Sabial } 25438589Sabial 25538589Sabial print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); 25646493Sabial fprintf(trussinfo->outfile, "\n"); 25746493Sabial } 25846493Sabial 25946493Sabial return; 26046493Sabial} 26146493Sabial 26238589Sabial/* 26338589Sabial * And when the system call is done, we handle it here. 26438589Sabial * Currently, no attempt is made to ensure that the system calls 26538589Sabial * match -- this needs to be fixed (and is, in fact, why S_SCX includes 26638589Sabial * the sytem call number instead of, say, an error status). 26738589Sabial */ 26846493Sabial 26946493Sabialint 27046493Sabiali386_syscall_exit(struct trussinfo *trussinfo, int syscall) { 27138589Sabial char buf[32]; 27246493Sabial struct reg regs; 27346493Sabial int retval; 27446493Sabial int i; 27538589Sabial int errorp; 27638589Sabial struct syscall *sc; 27746493Sabial 27846493Sabial if (fd == -1 || trussinfo->pid != cpid) { 27946493Sabial sprintf(buf, "/proc/%d/regs", trussinfo->pid); 28046493Sabial fd = open(buf, O_RDONLY); 28146493Sabial if (fd == -1) { 28246493Sabial fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 28346493Sabial return; 28446493Sabial } 28538589Sabial cpid = trussinfo->pid; 28638589Sabial } 28746493Sabial 28846493Sabial lseek(fd, 0L, 0); 28946493Sabial if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 29038589Sabial fprintf(trussinfo->outfile, "\n"); 29146493Sabial return; 29246493Sabial } 29346493Sabial retval = regs.r_eax; 29446493Sabial errorp = !!(regs.r_eflags & PSL_C); 29546493Sabial 29646493Sabial /* 29738589Sabial * This code, while simpler than the initial versions I used, could 29846493Sabial * stand some significant cleaning. 29946493Sabial */ 30046493Sabial 30146493Sabial sc = fsc.sc; 30246493Sabial if (!sc) { 30346493Sabial for (i = 0; i < fsc.nargs; i++) { 30446493Sabial fsc.s_args[i] = malloc(12); 30538589Sabial sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 30646493Sabial } 30746493Sabial } else { 30846493Sabial /* 30946493Sabial * Here, we only look for arguments that have OUT masked in -- 31046493Sabial * otherwise, they were handled in the syscall_entry function. 31138589Sabial */ 31246493Sabial for (i = 0; i < sc->nargs; i++) { 31338589Sabial char *temp; 31446493Sabial if (sc->args[i].type & OUT) { 31546493Sabial /* 31646493Sabial * If an error occurred, than don't bothe getting the data; 31746493Sabial * it may not be valid. 31846493Sabial */ 31946493Sabial if (errorp) { 32046493Sabial temp = malloc(12); 32146493Sabial sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 32246493Sabial } else { 32346493Sabial temp = print_arg(Procfd, &sc->args[i], fsc.args); 32446493Sabial } 32546493Sabial fsc.s_args[i] = temp; 32646493Sabial } 32746493Sabial } 32846493Sabial } 32946493Sabial 33046493Sabial /* 33146493Sabial * It would probably be a good idea to merge the error handling, 33238589Sabial * but that complicates things considerably. 33346493Sabial */ 33438589Sabial 33546493Sabial print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 33646493Sabial clear_fsc(); 33738589Sabial 33838589Sabial return (retval); 33946493Sabial} 34038589Sabial