i386-fbsd.c revision 50477
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 50477 1999-08-28 01:08:13Z peter $"; 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 4532275Scharnier#include <errno.h> 4632275Scharnier#include <fcntl.h> 4732275Scharnier#include <signal.h> 4831567Ssef#include <stdio.h> 4931567Ssef#include <stdlib.h> 5031567Ssef#include <string.h> 5131567Ssef#include <unistd.h> 5231567Ssef#include <sys/ioctl.h> 5331567Ssef#include <sys/pioctl.h> 5432367Ssef#include <machine/reg.h> 5532367Ssef#include <machine/psl.h> 5631567Ssef#include <sys/syscall.h> 5731567Ssef 5831567Ssef#include "syscall.h" 5931567Ssef 6031567Ssefstatic int fd = -1; 6131567Ssefstatic int cpid = -1; 6231567Ssefextern int Procfd; 6331567Ssef 6431567Ssefextern FILE *outfile; 6531567Ssef#include "syscalls.h" 6631567Ssef 6731567Ssefstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 6831567Ssef 6931567Ssef/* 7031567Ssef * This is what this particular file uses to keep track of a system call. 7131567Ssef * It is probably not quite sufficient -- I can probably use the same 7231567Ssef * structure for the various syscall personalities, and I also probably 7331567Ssef * need to nest system calls (for signal handlers). 7431567Ssef * 7531567Ssef * 'struct syscall' describes the system call; it may be NULL, however, 7631567Ssef * if we don't know about this particular system call yet. 7731567Ssef */ 7831567Ssefstatic struct freebsd_syscall { 7931567Ssef struct syscall *sc; 8031567Ssef char *name; 8131567Ssef int number; 8231567Ssef unsigned long *args; 8331567Ssef int nargs; /* number of arguments -- *not* number of words! */ 8431567Ssef char **s_args; /* the printable arguments */ 8531567Ssef} fsc; 8631567Ssef 8731567Ssef/* Clear up and free parts of the fsc structure. */ 8831567Ssefstatic inline void 8931567Ssefclear_fsc() { 9031567Ssef if (fsc.args) { 9131567Ssef free(fsc.args); 9231567Ssef } 9331567Ssef if (fsc.s_args) { 9431567Ssef int i; 9531567Ssef for (i = 0; i < fsc.nargs; i++) 9631567Ssef if (fsc.s_args[i]) 9731567Ssef free(fsc.s_args[i]); 9831567Ssef free(fsc.s_args); 9931567Ssef } 10031567Ssef memset(&fsc, 0, sizeof(fsc)); 10131567Ssef} 10231567Ssef 10331567Ssef/* 10431567Ssef * Called when a process has entered a system call. nargs is the 10531567Ssef * number of words, not number of arguments (a necessary distinction 10631567Ssef * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 10731567Ssef * is ever changed these functions need to keep up. 10831567Ssef */ 10931567Ssef 11031567Ssefvoid 11131567Ssefi386_syscall_entry(int pid, int nargs) { 11231567Ssef char buf[32]; 11331567Ssef struct reg regs = { 0 }; 11431567Ssef int syscall; 11531567Ssef int i; 11631567Ssef unsigned int parm_offset; 11731567Ssef struct syscall *sc; 11831567Ssef 11931567Ssef if (fd == -1 || pid != cpid) { 12031567Ssef sprintf(buf, "/proc/%d/regs", pid); 12131567Ssef fd = open(buf, O_RDWR); 12231567Ssef if (fd == -1) { 12331567Ssef fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 12431567Ssef return; 12531567Ssef } 12631567Ssef cpid = pid; 12731567Ssef } 12831567Ssef 12931567Ssef clear_fsc(); 13031567Ssef lseek(fd, 0L, 0); 13131567Ssef i = read(fd, ®s, sizeof(regs)); 13231567Ssef parm_offset = regs.r_esp + sizeof(int); 13331567Ssef 13431567Ssef /* 13531567Ssef * FreeBSD has two special kinds of system call redirctions -- 13631567Ssef * SYS_syscall, and SYS___syscall. The former is the old syscall() 13731567Ssef * routine, basicly; the latter is for quad-aligned arguments. 13831567Ssef */ 13931567Ssef syscall = regs.r_eax; 14031567Ssef switch (syscall) { 14131567Ssef case SYS_syscall: 14231567Ssef lseek(Procfd, parm_offset, SEEK_SET); 14331567Ssef read(Procfd, &syscall, sizeof(int)); 14431567Ssef parm_offset += sizeof(int); 14531567Ssef break; 14631567Ssef case SYS___syscall: 14731567Ssef lseek(Procfd, parm_offset, SEEK_SET); 14831567Ssef read(Procfd, &syscall, sizeof(int)); 14931567Ssef parm_offset += sizeof(quad_t); 15031567Ssef break; 15131567Ssef } 15231567Ssef 15331567Ssef fsc.number = syscall; 15431567Ssef fsc.name = 15531567Ssef (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; 15631567Ssef if (!fsc.name) { 15731567Ssef fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); 15831567Ssef } 15931567Ssef 16031567Ssef if (nargs == 0) 16131567Ssef return; 16231567Ssef 16331567Ssef fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 16431567Ssef lseek(Procfd, parm_offset, SEEK_SET); 16531567Ssef if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 16631567Ssef return; 16731567Ssef 16831567Ssef sc = get_syscall(fsc.name); 16931567Ssef if (sc) { 17031567Ssef fsc.nargs = sc->nargs; 17131567Ssef } else { 17231567Ssef#if DEBUG 17331567Ssef fprintf(outfile, "unknown syscall %s -- setting args to %d\n", 17431567Ssef fsc.name, nargs); 17531567Ssef#endif 17631567Ssef fsc.nargs = nargs; 17731567Ssef } 17831567Ssef 17931567Ssef fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 18031567Ssef memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 18131567Ssef fsc.sc = sc; 18231567Ssef 18331567Ssef /* 18431567Ssef * At this point, we set up the system call arguments. 18531567Ssef * We ignore any OUT ones, however -- those are arguments that 18631567Ssef * are set by the system call, and so are probably meaningless 18731567Ssef * now. This doesn't currently support arguments that are 18831567Ssef * passed in *and* out, however. 18931567Ssef */ 19031567Ssef 19131567Ssef if (fsc.name) { 19231567Ssef 19331567Ssef#if DEBUG 19431567Ssef fprintf(stderr, "syscall %s(", fsc.name); 19531567Ssef#endif 19631567Ssef for (i = 0; i < fsc.nargs; i++) { 19731567Ssef#if DEBUG 19831567Ssef fprintf(stderr, "0x%x%s", 19931567Ssef sc 20031567Ssef ? fsc.args[sc->args[i].offset] 20131567Ssef : fsc.args[i], 20231567Ssef i < (fsc.nargs -1) ? "," : ""); 20331567Ssef#endif 20431567Ssef if (sc && !(sc->args[i].type & OUT)) { 20531567Ssef fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 20631567Ssef } 20731567Ssef } 20831567Ssef#if DEBUG 20931567Ssef fprintf(stderr, ")\n"); 21031567Ssef#endif 21131567Ssef } 21231567Ssef 21331567Ssef#if DEBUG 21431567Ssef fprintf(outfile, "\n"); 21531567Ssef#endif 21631567Ssef 21731567Ssef /* 21831567Ssef * Some system calls should be printed out before they are done -- 21931567Ssef * execve() and exit(), for example, never return. Possibly change 22031567Ssef * this to work for any system call that doesn't have an OUT 22131567Ssef * parameter? 22231567Ssef */ 22331567Ssef 22431567Ssef if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 22531567Ssef print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); 22631567Ssef } 22731567Ssef 22831567Ssef return; 22931567Ssef} 23031567Ssef 23131567Ssef/* 23231567Ssef * And when the system call is done, we handle it here. 23331567Ssef * Currently, no attempt is made to ensure that the system calls 23431567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes 23531567Ssef * the sytem call number instead of, say, an error status). 23631567Ssef */ 23731567Ssef 23831567Ssefvoid 23931567Ssefi386_syscall_exit(int pid, int syscall) { 24031567Ssef char buf[32]; 24131567Ssef struct reg regs; 24231567Ssef int retval; 24331567Ssef int i; 24431567Ssef int errorp; 24531567Ssef struct syscall *sc; 24631567Ssef 24731567Ssef if (fd == -1 || pid != cpid) { 24831567Ssef sprintf(buf, "/proc/%d/regs", pid); 24931567Ssef fd = open(buf, O_RDONLY); 25031567Ssef if (fd == -1) { 25131567Ssef fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 25231567Ssef return; 25331567Ssef } 25431567Ssef cpid = pid; 25531567Ssef } 25631567Ssef 25731567Ssef lseek(fd, 0L, 0); 25831567Ssef if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) 25931567Ssef return; 26031567Ssef retval = regs.r_eax; 26131567Ssef errorp = !!(regs.r_eflags & PSL_C); 26231567Ssef 26331567Ssef /* 26431567Ssef * This code, while simpler than the initial versions I used, could 26531567Ssef * stand some significant cleaning. 26631567Ssef */ 26731567Ssef 26831567Ssef sc = fsc.sc; 26931567Ssef if (!sc) { 27031567Ssef for (i = 0; i < fsc.nargs; i++) { 27131567Ssef fsc.s_args[i] = malloc(12); 27237453Sbde sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 27331567Ssef } 27431567Ssef } else { 27531567Ssef /* 27631567Ssef * Here, we only look for arguments that have OUT masked in -- 27731567Ssef * otherwise, they were handled in the syscall_entry function. 27831567Ssef */ 27931567Ssef for (i = 0; i < sc->nargs; i++) { 28031567Ssef char *temp; 28131567Ssef if (sc->args[i].type & OUT) { 28231567Ssef /* 28331567Ssef * If an error occurred, than don't bothe getting the data; 28431567Ssef * it may not be valid. 28531567Ssef */ 28631567Ssef if (errorp) { 28731567Ssef temp = malloc(12); 28837453Sbde sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 28931567Ssef } else { 29031567Ssef temp = print_arg(Procfd, &sc->args[i], fsc.args); 29131567Ssef } 29231567Ssef fsc.s_args[i] = temp; 29331567Ssef } 29431567Ssef } 29531567Ssef } 29631567Ssef 29731567Ssef /* 29831567Ssef * It would probably be a good idea to merge the error handling, 29931567Ssef * but that complicates things considerably. 30031567Ssef */ 30131567Ssef 30231567Ssef print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); 30331567Ssef if (errorp) { 30431567Ssef fprintf(outfile, "errno %d '%s'\n", retval, strerror(retval)); 30531567Ssef } else { 30631567Ssef fprintf(outfile, "returns %d (0x%x)\n", retval, retval); 30731567Ssef } 30831567Ssef clear_fsc(); 30931567Ssef 31031567Ssef return; 31131567Ssef} 312