i386-fbsd.c revision 101283
131567Ssef/* 231899Ssef * Copryight 1997 Sean Eric Fagan 331899Ssef * 431899Ssef * Redistribution and use in source and binary forms, with or without 531899Ssef * modification, are permitted provided that the following conditions 631899Ssef * are met: 731899Ssef * 1. Redistributions of source code must retain the above copyright 831899Ssef * notice, this list of conditions and the following disclaimer. 931899Ssef * 2. Redistributions in binary form must reproduce the above copyright 1031899Ssef * notice, this list of conditions and the following disclaimer in the 1131899Ssef * documentation and/or other materials provided with the distribution. 1231899Ssef * 3. All advertising materials mentioning features or use of this software 1331899Ssef * must display the following acknowledgement: 1431899Ssef * This product includes software developed by Sean Eric Fagan 1531899Ssef * 4. Neither the name of the author may be used to endorse or promote 1631899Ssef * products derived from this software without specific prior written 1731899Ssef * permission. 1831899Ssef * 1931899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2031899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2131899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2231899Ssef * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2331899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2431899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2531899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2631899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2731899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2831899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2931899Ssef * SUCH DAMAGE. 3031899Ssef */ 3131899Ssef 3232275Scharnier#ifndef lint 3332275Scharnierstatic const char rcsid[] = 3450477Speter "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 101283 2002-08-04 01:02:52Z mdodd $"; 3532275Scharnier#endif /* not lint */ 3632275Scharnier 3731899Ssef/* 3831567Ssef * FreeBSD/386-specific system call handling. This is probably the most 3931567Ssef * complex part of the entire truss program, although I've got lots of 4031567Ssef * it handled relatively cleanly now. The system call names are generated 4131567Ssef * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 4231567Ssef * names used for the various structures are confusing, I sadly admit. 4331567Ssef */ 4431567Ssef 4585301Sdes#include <sys/types.h> 4685301Sdes#include <sys/ioctl.h> 4785301Sdes#include <sys/pioctl.h> 4885301Sdes#include <sys/syscall.h> 4985301Sdes 5085301Sdes#include <machine/reg.h> 5185301Sdes#include <machine/psl.h> 5285301Sdes 5332275Scharnier#include <errno.h> 5432275Scharnier#include <fcntl.h> 5532275Scharnier#include <signal.h> 5631567Ssef#include <stdio.h> 5731567Ssef#include <stdlib.h> 5831567Ssef#include <string.h> 5931567Ssef#include <unistd.h> 6031567Ssef 61101282Smdodd#include "truss.h" 6231567Ssef#include "syscall.h" 6331567Ssef 6431567Ssefstatic int fd = -1; 6531567Ssefstatic int cpid = -1; 6631567Ssefextern int Procfd; 6731567Ssef 6831567Ssef#include "syscalls.h" 6931567Ssef 7031567Ssefstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7131567Ssef 7231567Ssef/* 7331567Ssef * This is what this particular file uses to keep track of a system call. 7431567Ssef * It is probably not quite sufficient -- I can probably use the same 7531567Ssef * structure for the various syscall personalities, and I also probably 7631567Ssef * need to nest system calls (for signal handlers). 7731567Ssef * 7831567Ssef * 'struct syscall' describes the system call; it may be NULL, however, 7931567Ssef * if we don't know about this particular system call yet. 8031567Ssef */ 8131567Ssefstatic struct freebsd_syscall { 8231567Ssef struct syscall *sc; 8331567Ssef char *name; 8431567Ssef int number; 8531567Ssef unsigned long *args; 8631567Ssef int nargs; /* number of arguments -- *not* number of words! */ 8731567Ssef char **s_args; /* the printable arguments */ 8831567Ssef} fsc; 8931567Ssef 9031567Ssef/* Clear up and free parts of the fsc structure. */ 91100357Smarkmstatic __inline void 9231567Ssefclear_fsc() { 9331567Ssef if (fsc.args) { 9431567Ssef free(fsc.args); 9531567Ssef } 9631567Ssef if (fsc.s_args) { 9731567Ssef int i; 9831567Ssef for (i = 0; i < fsc.nargs; i++) 9931567Ssef if (fsc.s_args[i]) 10031567Ssef free(fsc.s_args[i]); 10131567Ssef free(fsc.s_args); 10231567Ssef } 10331567Ssef memset(&fsc, 0, sizeof(fsc)); 10431567Ssef} 10531567Ssef 10631567Ssef/* 10731567Ssef * Called when a process has entered a system call. nargs is the 10831567Ssef * number of words, not number of arguments (a necessary distinction 10931567Ssef * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11031567Ssef * is ever changed these functions need to keep up. 11131567Ssef */ 11231567Ssef 11331567Ssefvoid 114101282Smdoddi386_syscall_entry(struct trussinfo *trussinfo, int nargs) { 11531567Ssef char buf[32]; 11631567Ssef struct reg regs = { 0 }; 11731567Ssef int syscall; 11831567Ssef int i; 11931567Ssef unsigned int parm_offset; 12031567Ssef struct syscall *sc; 12131567Ssef 122101282Smdodd if (fd == -1 || trussinfo->pid != cpid) { 123101282Smdodd sprintf(buf, "/proc/%d/regs", trussinfo->pid); 12431567Ssef fd = open(buf, O_RDWR); 12531567Ssef if (fd == -1) { 126101282Smdodd fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 12731567Ssef return; 12831567Ssef } 129101282Smdodd cpid = trussinfo->pid; 13031567Ssef } 13131567Ssef 13231567Ssef clear_fsc(); 13331567Ssef lseek(fd, 0L, 0); 13431567Ssef i = read(fd, ®s, sizeof(regs)); 13531567Ssef parm_offset = regs.r_esp + sizeof(int); 13631567Ssef 13731567Ssef /* 13831567Ssef * FreeBSD has two special kinds of system call redirctions -- 13931567Ssef * SYS_syscall, and SYS___syscall. The former is the old syscall() 14031567Ssef * routine, basicly; the latter is for quad-aligned arguments. 14131567Ssef */ 14231567Ssef syscall = regs.r_eax; 14331567Ssef switch (syscall) { 14431567Ssef case SYS_syscall: 14531567Ssef lseek(Procfd, parm_offset, SEEK_SET); 14631567Ssef read(Procfd, &syscall, sizeof(int)); 14731567Ssef parm_offset += sizeof(int); 14831567Ssef break; 14931567Ssef case SYS___syscall: 15031567Ssef lseek(Procfd, parm_offset, SEEK_SET); 15131567Ssef read(Procfd, &syscall, sizeof(int)); 15231567Ssef parm_offset += sizeof(quad_t); 15331567Ssef break; 15431567Ssef } 15531567Ssef 15631567Ssef fsc.number = syscall; 15731567Ssef fsc.name = 15831567Ssef (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; 15931567Ssef if (!fsc.name) { 160101282Smdodd fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); 16131567Ssef } 16231567Ssef 163101283Smdodd if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 164101283Smdodd && ((!strcmp(fsc.name, "fork") 165101283Smdodd || !strcmp(fsc.name, "rfork") 166101283Smdodd || !strcmp(fsc.name, "vfork")))) 167101283Smdodd { 168101283Smdodd trussinfo->in_fork = 1; 169101283Smdodd } 170101283Smdodd 17131567Ssef if (nargs == 0) 17231567Ssef return; 17331567Ssef 17431567Ssef fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 17531567Ssef lseek(Procfd, parm_offset, SEEK_SET); 17631567Ssef if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 17731567Ssef return; 17831567Ssef 17931567Ssef sc = get_syscall(fsc.name); 18031567Ssef if (sc) { 18131567Ssef fsc.nargs = sc->nargs; 18231567Ssef } else { 18331567Ssef#if DEBUG 184101282Smdodd fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 18531567Ssef fsc.name, nargs); 18631567Ssef#endif 18731567Ssef fsc.nargs = nargs; 18831567Ssef } 18931567Ssef 19031567Ssef fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 19131567Ssef memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 19231567Ssef fsc.sc = sc; 19331567Ssef 19431567Ssef /* 19531567Ssef * At this point, we set up the system call arguments. 19631567Ssef * We ignore any OUT ones, however -- those are arguments that 19731567Ssef * are set by the system call, and so are probably meaningless 19831567Ssef * now. This doesn't currently support arguments that are 19931567Ssef * passed in *and* out, however. 20031567Ssef */ 20131567Ssef 20231567Ssef if (fsc.name) { 20331567Ssef 20431567Ssef#if DEBUG 20531567Ssef fprintf(stderr, "syscall %s(", fsc.name); 20631567Ssef#endif 20731567Ssef for (i = 0; i < fsc.nargs; i++) { 20831567Ssef#if DEBUG 20931567Ssef fprintf(stderr, "0x%x%s", 21031567Ssef sc 21131567Ssef ? fsc.args[sc->args[i].offset] 21231567Ssef : fsc.args[i], 21331567Ssef i < (fsc.nargs -1) ? "," : ""); 21431567Ssef#endif 21531567Ssef if (sc && !(sc->args[i].type & OUT)) { 21631567Ssef fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 21731567Ssef } 21831567Ssef } 21931567Ssef#if DEBUG 22031567Ssef fprintf(stderr, ")\n"); 22131567Ssef#endif 22231567Ssef } 22331567Ssef 22431567Ssef#if DEBUG 225101282Smdodd fprintf(trussinfo->outfile, "\n"); 22631567Ssef#endif 22731567Ssef 22831567Ssef /* 22931567Ssef * Some system calls should be printed out before they are done -- 23031567Ssef * execve() and exit(), for example, never return. Possibly change 23131567Ssef * this to work for any system call that doesn't have an OUT 23231567Ssef * parameter? 23331567Ssef */ 23431567Ssef 23531567Ssef if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 236101282Smdodd print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); 23731567Ssef } 23831567Ssef 23931567Ssef return; 24031567Ssef} 24131567Ssef 24231567Ssef/* 24331567Ssef * And when the system call is done, we handle it here. 24431567Ssef * Currently, no attempt is made to ensure that the system calls 24531567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes 24631567Ssef * the sytem call number instead of, say, an error status). 24731567Ssef */ 24831567Ssef 249101282Smdoddint 250101282Smdoddi386_syscall_exit(struct trussinfo *trussinfo, int syscall) { 25131567Ssef char buf[32]; 25231567Ssef struct reg regs; 25331567Ssef int retval; 25431567Ssef int i; 25531567Ssef int errorp; 25631567Ssef struct syscall *sc; 25731567Ssef 258101282Smdodd if (fd == -1 || trussinfo->pid != cpid) { 259101282Smdodd sprintf(buf, "/proc/%d/regs", trussinfo->pid); 26031567Ssef fd = open(buf, O_RDONLY); 26131567Ssef if (fd == -1) { 262101282Smdodd fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 26331567Ssef return; 26431567Ssef } 265101282Smdodd cpid = trussinfo->pid; 26631567Ssef } 26731567Ssef 26831567Ssef lseek(fd, 0L, 0); 269101282Smdodd if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 270101282Smdodd fprintf(trussinfo->outfile, "\n"); 27131567Ssef return; 272101282Smdodd } 27331567Ssef retval = regs.r_eax; 27431567Ssef errorp = !!(regs.r_eflags & PSL_C); 27531567Ssef 27631567Ssef /* 27731567Ssef * This code, while simpler than the initial versions I used, could 27831567Ssef * stand some significant cleaning. 27931567Ssef */ 28031567Ssef 28131567Ssef sc = fsc.sc; 28231567Ssef if (!sc) { 28331567Ssef for (i = 0; i < fsc.nargs; i++) { 28431567Ssef fsc.s_args[i] = malloc(12); 28537453Sbde sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 28631567Ssef } 28731567Ssef } else { 28831567Ssef /* 28931567Ssef * Here, we only look for arguments that have OUT masked in -- 29031567Ssef * otherwise, they were handled in the syscall_entry function. 29131567Ssef */ 29231567Ssef for (i = 0; i < sc->nargs; i++) { 29331567Ssef char *temp; 29431567Ssef if (sc->args[i].type & OUT) { 29531567Ssef /* 29631567Ssef * If an error occurred, than don't bothe getting the data; 29731567Ssef * it may not be valid. 29831567Ssef */ 29931567Ssef if (errorp) { 30031567Ssef temp = malloc(12); 30137453Sbde sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 30231567Ssef } else { 30331567Ssef temp = print_arg(Procfd, &sc->args[i], fsc.args); 30431567Ssef } 30531567Ssef fsc.s_args[i] = temp; 30631567Ssef } 30731567Ssef } 30831567Ssef } 30931567Ssef 31031567Ssef /* 31131567Ssef * It would probably be a good idea to merge the error handling, 31231567Ssef * but that complicates things considerably. 31331567Ssef */ 31431567Ssef 315101282Smdodd print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 31631567Ssef clear_fsc(); 31731567Ssef 318101282Smdodd return (retval); 31931567Ssef} 320