i386-fbsd.c revision 85301
118334Speter/* 290075Sobrien * Copryight 1997 Sean Eric Fagan 3132730Skan * 418334Speter * Redistribution and use in source and binary forms, with or without 590075Sobrien * modification, are permitted provided that the following conditions 618334Speter * are met: 790075Sobrien * 1. Redistributions of source code must retain the above copyright 890075Sobrien * notice, this list of conditions and the following disclaimer. 990075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1090075Sobrien * notice, this list of conditions and the following disclaimer in the 1118334Speter * documentation and/or other materials provided with the distribution. 1290075Sobrien * 3. All advertising materials mentioning features or use of this software 1390075Sobrien * must display the following acknowledgement: 1490075Sobrien * This product includes software developed by Sean Eric Fagan 1590075Sobrien * 4. Neither the name of the author may be used to endorse or promote 1618334Speter * products derived from this software without specific prior written 1718334Speter * permission. 1890075Sobrien * 1990075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2090075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2118334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2296549Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2396549Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2418334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2518334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2618334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2718334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2818334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2918334Speter * SUCH DAMAGE. 3018334Speter */ 3118334Speter 3250397Sobrien#ifndef lint 33132730Skanstatic const char rcsid[] = 34132730Skan "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 85301 2001-10-22 02:02:00Z des $"; 3590075Sobrien#endif /* not lint */ 3618334Speter 3790075Sobrien/* 3890075Sobrien * FreeBSD/386-specific system call handling. This is probably the most 3918334Speter * complex part of the entire truss program, although I've got lots of 4090075Sobrien * it handled relatively cleanly now. The system call names are generated 4118334Speter * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 4290075Sobrien * names used for the various structures are confusing, I sadly admit. 4318334Speter */ 4450397Sobrien 4590075Sobrien#include <sys/types.h> 4690075Sobrien#include <sys/ioctl.h> 4750397Sobrien#include <sys/pioctl.h> 4890075Sobrien#include <sys/syscall.h> 4990075Sobrien 50132730Skan#include <machine/reg.h> 5190075Sobrien#include <machine/psl.h> 5290075Sobrien 5396263Sobrien#include <errno.h> 54132730Skan#include <fcntl.h> 55132730Skan#include <signal.h> 56117421Skan#include <stdio.h> 57117421Skan#include <stdlib.h> 58132730Skan#include <string.h> 5950397Sobrien#include <unistd.h> 6018334Speter 6118334Speter#include "syscall.h" 6218334Speter 6318334Speterstatic int fd = -1; 6418334Speterstatic int cpid = -1; 6518334Speterextern int Procfd; 6618334Speter 6718334Speterextern FILE *outfile; 6818334Speter#include "syscalls.h" 6918334Speter 7018334Speterstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7118334Speter 7218334Speter/* 7318334Speter * This is what this particular file uses to keep track of a system call. 74132730Skan * It is probably not quite sufficient -- I can probably use the same 7518334Speter * structure for the various syscall personalities, and I also probably 7618334Speter * need to nest system calls (for signal handlers). 7718334Speter * 7818334Speter * 'struct syscall' describes the system call; it may be NULL, however, 7918334Speter * if we don't know about this particular system call yet. 8018334Speter */ 8118334Speterstatic struct freebsd_syscall { 8218334Speter struct syscall *sc; 8318334Speter char *name; 8418334Speter int number; 8518334Speter unsigned long *args; 8618334Speter int nargs; /* number of arguments -- *not* number of words! */ 8718334Speter char **s_args; /* the printable arguments */ 8818334Speter} fsc; 89132730Skan 9018334Speter/* Clear up and free parts of the fsc structure. */ 9118334Speterstatic inline void 9218334Speterclear_fsc() { 93132730Skan if (fsc.args) { 94132730Skan free(fsc.args); 9518334Speter } 9618334Speter if (fsc.s_args) { 9718334Speter int i; 98132730Skan for (i = 0; i < fsc.nargs; i++) 99132730Skan if (fsc.s_args[i]) 100132730Skan free(fsc.s_args[i]); 101132730Skan free(fsc.s_args); 102132730Skan } 10318334Speter memset(&fsc, 0, sizeof(fsc)); 104132730Skan} 105132730Skan 10618334Speter/* 10718334Speter * Called when a process has entered a system call. nargs is the 10818334Speter * number of words, not number of arguments (a necessary distinction 10918334Speter * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 110132730Skan * is ever changed these functions need to keep up. 11118334Speter */ 11218334Speter 113132730Skanvoid 114132730Skani386_syscall_entry(int pid, int nargs) { 115132730Skan char buf[32]; 116132730Skan struct reg regs = { 0 }; 11718334Speter int syscall; 11818334Speter int i; 11918334Speter unsigned int parm_offset; 120132730Skan struct syscall *sc; 121132730Skan 12290075Sobrien if (fd == -1 || pid != cpid) { 12390075Sobrien sprintf(buf, "/proc/%d/regs", pid); 124117421Skan fd = open(buf, O_RDWR); 12590075Sobrien if (fd == -1) { 12690075Sobrien fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 12790075Sobrien return; 128117421Skan } 12990075Sobrien cpid = pid; 130132730Skan } 131132730Skan 132132730Skan clear_fsc(); 13318334Speter lseek(fd, 0L, 0); 134132730Skan i = read(fd, ®s, sizeof(regs)); 135132730Skan parm_offset = regs.r_esp + sizeof(int); 136132730Skan 13718334Speter /* 138132730Skan * FreeBSD has two special kinds of system call redirctions -- 13918334Speter * SYS_syscall, and SYS___syscall. The former is the old syscall() 140132730Skan * routine, basicly; the latter is for quad-aligned arguments. 141132730Skan */ 14218334Speter syscall = regs.r_eax; 143132730Skan switch (syscall) { 144132730Skan case SYS_syscall: 145132730Skan lseek(Procfd, parm_offset, SEEK_SET); 146132730Skan read(Procfd, &syscall, sizeof(int)); 14718334Speter parm_offset += sizeof(int); 14818334Speter break; 14918334Speter case SYS___syscall: 15018334Speter lseek(Procfd, parm_offset, SEEK_SET); 15118334Speter read(Procfd, &syscall, sizeof(int)); 15218334Speter parm_offset += sizeof(quad_t); 15318334Speter break; 15418334Speter } 15518334Speter 15618334Speter fsc.number = syscall; 15796263Sobrien fsc.name = 15896263Sobrien (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; 15996263Sobrien if (!fsc.name) { 16096263Sobrien fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); 16196263Sobrien } 16218334Speter 16318334Speter if (nargs == 0) 16418334Speter return; 16518334Speter 16618334Speter fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 16718334Speter lseek(Procfd, parm_offset, SEEK_SET); 16818334Speter if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 16918334Speter return; 17018334Speter 171132730Skan sc = get_syscall(fsc.name); 172132730Skan if (sc) { 173132730Skan fsc.nargs = sc->nargs; 17418334Speter } else { 175132730Skan#if DEBUG 17618334Speter fprintf(outfile, "unknown syscall %s -- setting args to %d\n", 177132730Skan fsc.name, nargs); 178132730Skan#endif 179132730Skan fsc.nargs = nargs; 180132730Skan } 181132730Skan 18218334Speter fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 183132730Skan memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 184132730Skan fsc.sc = sc; 185132730Skan 186132730Skan /* 18718334Speter * At this point, we set up the system call arguments. 188132730Skan * We ignore any OUT ones, however -- those are arguments that 189132730Skan * are set by the system call, and so are probably meaningless 190132730Skan * now. This doesn't currently support arguments that are 191132730Skan * passed in *and* out, however. 19218334Speter */ 193132730Skan 194132730Skan if (fsc.name) { 19518334Speter 196132730Skan#if DEBUG 197132730Skan fprintf(stderr, "syscall %s(", fsc.name); 198132730Skan#endif 199132730Skan for (i = 0; i < fsc.nargs; i++) { 20018334Speter#if DEBUG 201132730Skan fprintf(stderr, "0x%x%s", 202132730Skan sc 20318334Speter ? fsc.args[sc->args[i].offset] 204132730Skan : fsc.args[i], 205132730Skan i < (fsc.nargs -1) ? "," : ""); 206132730Skan#endif 20718334Speter if (sc && !(sc->args[i].type & OUT)) { 208132730Skan fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 209132730Skan } 210132730Skan } 211132730Skan#if DEBUG 21218334Speter fprintf(stderr, ")\n"); 213132730Skan#endif 214132730Skan } 21518334Speter 216132730Skan#if DEBUG 217132730Skan fprintf(outfile, "\n"); 218132730Skan#endif 219132730Skan 220132730Skan /* 22118334Speter * Some system calls should be printed out before they are done -- 222132730Skan * execve() and exit(), for example, never return. Possibly change 223132730Skan * this to work for any system call that doesn't have an OUT 224132730Skan * parameter? 225132730Skan */ 226132730Skan 22718334Speter if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 228132730Skan print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); 229132730Skan } 230132730Skan 231132730Skan return; 23218334Speter} 233132730Skan 234132730Skan/* 235132730Skan * And when the system call is done, we handle it here. 23618334Speter * Currently, no attempt is made to ensure that the system calls 237132730Skan * match -- this needs to be fixed (and is, in fact, why S_SCX includes 238132730Skan * the sytem call number instead of, say, an error status). 239132730Skan */ 240132730Skan 24190075Sobrienvoid 242132730Skani386_syscall_exit(int pid, int syscall) { 243132730Skan char buf[32]; 244132730Skan struct reg regs; 245132730Skan int retval; 246132730Skan int i; 24718334Speter int errorp; 248132730Skan struct syscall *sc; 249132730Skan 250132730Skan if (fd == -1 || pid != cpid) { 25118334Speter sprintf(buf, "/proc/%d/regs", pid); 252132730Skan fd = open(buf, O_RDONLY); 25318334Speter if (fd == -1) { 254132730Skan fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 25518334Speter return; 256132730Skan } 25718334Speter cpid = pid; 258132730Skan } 25918334Speter 260132730Skan lseek(fd, 0L, 0); 261132730Skan if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) 262132730Skan return; 26318334Speter retval = regs.r_eax; 264132730Skan errorp = !!(regs.r_eflags & PSL_C); 26518334Speter 266132730Skan /* 267132730Skan * This code, while simpler than the initial versions I used, could 26818334Speter * stand some significant cleaning. 269132730Skan */ 27018334Speter 271132730Skan sc = fsc.sc; 272132730Skan if (!sc) { 273132730Skan for (i = 0; i < fsc.nargs; i++) { 274132730Skan fsc.s_args[i] = malloc(12); 275132730Skan sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 276132730Skan } 277132730Skan } else { 278132730Skan /* 279132730Skan * Here, we only look for arguments that have OUT masked in -- 280132730Skan * otherwise, they were handled in the syscall_entry function. 28118334Speter */ 282132730Skan for (i = 0; i < sc->nargs; i++) { 283132730Skan char *temp; 284132730Skan if (sc->args[i].type & OUT) { 285132730Skan /* 286132730Skan * If an error occurred, than don't bothe getting the data; 287132730Skan * it may not be valid. 288132730Skan */ 289132730Skan if (errorp) { 290132730Skan temp = malloc(12); 291132730Skan sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 29290075Sobrien } else { 293132730Skan temp = print_arg(Procfd, &sc->args[i], fsc.args); 29418334Speter } 295132730Skan fsc.s_args[i] = temp; 29618334Speter } 297132730Skan } 298132730Skan } 299132730Skan 300132730Skan /* 301132730Skan * It would probably be a good idea to merge the error handling, 302132730Skan * but that complicates things considerably. 30318334Speter */ 30418334Speter 30518334Speter print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 30618334Speter clear_fsc(); 30718334Speter 30818334Speter return; 309132730Skan} 310132730Skan