i386-fbsd.c revision 111176
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 111176 2003-02-20 15:05:39Z ru $"; 3532275Scharnier#endif /* not lint */ 3632275Scharnier 3731899Ssef/* 38111176Sru * FreeBSD/i386-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> 59101423Smdodd#include <time.h> 6031567Ssef#include <unistd.h> 6131567Ssef 62101282Smdodd#include "truss.h" 6331567Ssef#include "syscall.h" 64106713Sdwmalone#include "extern.h" 6531567Ssef 6631567Ssefstatic int fd = -1; 6731567Ssefstatic int cpid = -1; 6831567Ssefextern int Procfd; 6931567Ssef 7031567Ssef#include "syscalls.h" 7131567Ssef 7231567Ssefstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7331567Ssef 7431567Ssef/* 7531567Ssef * This is what this particular file uses to keep track of a system call. 7631567Ssef * It is probably not quite sufficient -- I can probably use the same 7731567Ssef * structure for the various syscall personalities, and I also probably 7831567Ssef * need to nest system calls (for signal handlers). 7931567Ssef * 8031567Ssef * 'struct syscall' describes the system call; it may be NULL, however, 8131567Ssef * if we don't know about this particular system call yet. 8231567Ssef */ 8331567Ssefstatic struct freebsd_syscall { 8431567Ssef struct syscall *sc; 85106713Sdwmalone const char *name; 8631567Ssef int number; 8731567Ssef unsigned long *args; 8831567Ssef int nargs; /* number of arguments -- *not* number of words! */ 8931567Ssef char **s_args; /* the printable arguments */ 9031567Ssef} fsc; 9131567Ssef 9231567Ssef/* Clear up and free parts of the fsc structure. */ 93100357Smarkmstatic __inline void 94106713Sdwmaloneclear_fsc(void) { 9531567Ssef if (fsc.args) { 9631567Ssef free(fsc.args); 9731567Ssef } 9831567Ssef if (fsc.s_args) { 9931567Ssef int i; 10031567Ssef for (i = 0; i < fsc.nargs; i++) 10131567Ssef if (fsc.s_args[i]) 10231567Ssef free(fsc.s_args[i]); 10331567Ssef free(fsc.s_args); 10431567Ssef } 10531567Ssef memset(&fsc, 0, sizeof(fsc)); 10631567Ssef} 10731567Ssef 10831567Ssef/* 10931567Ssef * Called when a process has entered a system call. nargs is the 11031567Ssef * number of words, not number of arguments (a necessary distinction 11131567Ssef * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11231567Ssef * is ever changed these functions need to keep up. 11331567Ssef */ 11431567Ssef 11531567Ssefvoid 116101282Smdoddi386_syscall_entry(struct trussinfo *trussinfo, int nargs) { 11731567Ssef char buf[32]; 118106713Sdwmalone struct reg regs; 119106713Sdwmalone int syscall_num; 12031567Ssef int i; 12131567Ssef unsigned int parm_offset; 12231567Ssef struct syscall *sc; 12331567Ssef 124101282Smdodd if (fd == -1 || trussinfo->pid != cpid) { 125101282Smdodd sprintf(buf, "/proc/%d/regs", trussinfo->pid); 12631567Ssef fd = open(buf, O_RDWR); 12731567Ssef if (fd == -1) { 128106713Sdwmalone fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 12931567Ssef return; 13031567Ssef } 131101282Smdodd cpid = trussinfo->pid; 13231567Ssef } 13331567Ssef 13431567Ssef clear_fsc(); 13531567Ssef lseek(fd, 0L, 0); 136106713Sdwmalone if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 137106713Sdwmalone fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 138106713Sdwmalone return; 139106713Sdwmalone } 14031567Ssef parm_offset = regs.r_esp + sizeof(int); 14131567Ssef 14231567Ssef /* 14331567Ssef * FreeBSD has two special kinds of system call redirctions -- 14431567Ssef * SYS_syscall, and SYS___syscall. The former is the old syscall() 14531567Ssef * routine, basicly; the latter is for quad-aligned arguments. 14631567Ssef */ 147106713Sdwmalone syscall_num = regs.r_eax; 148106713Sdwmalone switch (syscall_num) { 14931567Ssef case SYS_syscall: 15031567Ssef lseek(Procfd, parm_offset, SEEK_SET); 151106713Sdwmalone read(Procfd, &syscall_num, sizeof(int)); 15231567Ssef parm_offset += sizeof(int); 15331567Ssef break; 15431567Ssef case SYS___syscall: 15531567Ssef lseek(Procfd, parm_offset, SEEK_SET); 156106713Sdwmalone read(Procfd, &syscall_num, sizeof(int)); 15731567Ssef parm_offset += sizeof(quad_t); 15831567Ssef break; 15931567Ssef } 16031567Ssef 161106713Sdwmalone fsc.number = syscall_num; 16231567Ssef fsc.name = 163106713Sdwmalone (syscall_num < 0 || syscall_num > nsyscalls) ? NULL : syscallnames[syscall_num]; 16431567Ssef if (!fsc.name) { 165106713Sdwmalone fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); 16631567Ssef } 16731567Ssef 168101283Smdodd if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 169101283Smdodd && ((!strcmp(fsc.name, "fork") 170101283Smdodd || !strcmp(fsc.name, "rfork") 171101283Smdodd || !strcmp(fsc.name, "vfork")))) 172101283Smdodd { 173101283Smdodd trussinfo->in_fork = 1; 174101283Smdodd } 175101283Smdodd 17631567Ssef if (nargs == 0) 17731567Ssef return; 17831567Ssef 17931567Ssef fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 18031567Ssef lseek(Procfd, parm_offset, SEEK_SET); 18131567Ssef if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 18231567Ssef return; 18331567Ssef 18431567Ssef sc = get_syscall(fsc.name); 18531567Ssef if (sc) { 18631567Ssef fsc.nargs = sc->nargs; 18731567Ssef } else { 18831567Ssef#if DEBUG 189101282Smdodd fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 19031567Ssef fsc.name, nargs); 19131567Ssef#endif 19231567Ssef fsc.nargs = nargs; 19331567Ssef } 19431567Ssef 19531567Ssef fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 19631567Ssef memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 19731567Ssef fsc.sc = sc; 19831567Ssef 19931567Ssef /* 20031567Ssef * At this point, we set up the system call arguments. 20131567Ssef * We ignore any OUT ones, however -- those are arguments that 20231567Ssef * are set by the system call, and so are probably meaningless 20331567Ssef * now. This doesn't currently support arguments that are 20431567Ssef * passed in *and* out, however. 20531567Ssef */ 20631567Ssef 20731567Ssef if (fsc.name) { 20831567Ssef 20931567Ssef#if DEBUG 21031567Ssef fprintf(stderr, "syscall %s(", fsc.name); 21131567Ssef#endif 21231567Ssef for (i = 0; i < fsc.nargs; i++) { 21331567Ssef#if DEBUG 21431567Ssef fprintf(stderr, "0x%x%s", 215101374Smdodd sc 216101374Smdodd ? fsc.args[sc->args[i].offset] 217101374Smdodd : fsc.args[i], 218101374Smdodd i < (fsc.nargs - 1) ? "," : ""); 21931567Ssef#endif 22031567Ssef if (sc && !(sc->args[i].type & OUT)) { 22131567Ssef fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 22231567Ssef } 22331567Ssef } 22431567Ssef#if DEBUG 22531567Ssef fprintf(stderr, ")\n"); 22631567Ssef#endif 22731567Ssef } 22831567Ssef 22931567Ssef#if DEBUG 230101282Smdodd fprintf(trussinfo->outfile, "\n"); 23131567Ssef#endif 23231567Ssef 23331567Ssef /* 23431567Ssef * Some system calls should be printed out before they are done -- 23531567Ssef * execve() and exit(), for example, never return. Possibly change 23631567Ssef * this to work for any system call that doesn't have an OUT 23731567Ssef * parameter? 23831567Ssef */ 23931567Ssef 24031567Ssef if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 241101289Smdodd 242101289Smdodd /* XXX 243101289Smdodd * This could be done in a more general 244101289Smdodd * manner but it still wouldn't be very pretty. 245101289Smdodd */ 246101289Smdodd if (!strcmp(fsc.name, "execve")) { 247101289Smdodd if ((trussinfo->flags & EXECVEARGS) == 0) 248101374Smdodd if (fsc.s_args[1]) { 249101289Smdodd free(fsc.s_args[1]); 250101289Smdodd fsc.s_args[1] = NULL; 251101289Smdodd } 252101289Smdodd if ((trussinfo->flags & EXECVEENVS) == 0) 253101374Smdodd if (fsc.s_args[2]) { 254101289Smdodd free(fsc.s_args[2]); 255101289Smdodd fsc.s_args[2] = NULL; 256101289Smdodd } 257101289Smdodd } 258101289Smdodd 259101282Smdodd print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); 260101286Smdodd fprintf(trussinfo->outfile, "\n"); 26131567Ssef } 26231567Ssef 26331567Ssef return; 26431567Ssef} 26531567Ssef 26631567Ssef/* 26731567Ssef * And when the system call is done, we handle it here. 26831567Ssef * Currently, no attempt is made to ensure that the system calls 26931567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes 27031567Ssef * the sytem call number instead of, say, an error status). 27131567Ssef */ 27231567Ssef 273101282Smdoddint 274106713Sdwmalonei386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) { 27531567Ssef char buf[32]; 27631567Ssef struct reg regs; 27731567Ssef int retval; 27831567Ssef int i; 27931567Ssef int errorp; 28031567Ssef struct syscall *sc; 28131567Ssef 282101282Smdodd if (fd == -1 || trussinfo->pid != cpid) { 283101282Smdodd sprintf(buf, "/proc/%d/regs", trussinfo->pid); 28431567Ssef fd = open(buf, O_RDONLY); 28531567Ssef if (fd == -1) { 286106713Sdwmalone fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 287106713Sdwmalone return (-1); 28831567Ssef } 289101282Smdodd cpid = trussinfo->pid; 29031567Ssef } 29131567Ssef 29231567Ssef lseek(fd, 0L, 0); 293101282Smdodd if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 294106713Sdwmalone fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 295106713Sdwmalone return (-1); 296101282Smdodd } 29731567Ssef retval = regs.r_eax; 29831567Ssef errorp = !!(regs.r_eflags & PSL_C); 29931567Ssef 30031567Ssef /* 30131567Ssef * This code, while simpler than the initial versions I used, could 30231567Ssef * stand some significant cleaning. 30331567Ssef */ 30431567Ssef 30531567Ssef sc = fsc.sc; 30631567Ssef if (!sc) { 30731567Ssef for (i = 0; i < fsc.nargs; i++) { 30831567Ssef fsc.s_args[i] = malloc(12); 30937453Sbde sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 31031567Ssef } 31131567Ssef } else { 31231567Ssef /* 31331567Ssef * Here, we only look for arguments that have OUT masked in -- 31431567Ssef * otherwise, they were handled in the syscall_entry function. 31531567Ssef */ 31631567Ssef for (i = 0; i < sc->nargs; i++) { 31731567Ssef char *temp; 31831567Ssef if (sc->args[i].type & OUT) { 31931567Ssef /* 32031567Ssef * If an error occurred, than don't bothe getting the data; 32131567Ssef * it may not be valid. 32231567Ssef */ 32331567Ssef if (errorp) { 32431567Ssef temp = malloc(12); 32537453Sbde sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 32631567Ssef } else { 32731567Ssef temp = print_arg(Procfd, &sc->args[i], fsc.args); 32831567Ssef } 32931567Ssef fsc.s_args[i] = temp; 33031567Ssef } 33131567Ssef } 33231567Ssef } 33331567Ssef 33431567Ssef /* 33531567Ssef * It would probably be a good idea to merge the error handling, 33631567Ssef * but that complicates things considerably. 33731567Ssef */ 33831567Ssef 339101282Smdodd print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 34031567Ssef clear_fsc(); 34131567Ssef 342101282Smdodd return (retval); 34331567Ssef} 344