i386-fbsd.c revision 122348
11541Srgrimes/* 21541Srgrimes * Copryight 1997 Sean Eric Fagan 350477Speter * 41541Srgrimes * Redistribution and use in source and binary forms, with or without 51541Srgrimes * modification, are permitted provided that the following conditions 61541Srgrimes * are met: 799854Salfred * 1. Redistributions of source code must retain the above copyright 81541Srgrimes * notice, this list of conditions and the following disclaimer. 999854Salfred * 2. Redistributions in binary form must reproduce the above copyright 10171208Speter * notice, this list of conditions and the following disclaimer in the 11194833Sjhb * documentation and/or other materials provided with the distribution. 121541Srgrimes * 3. All advertising materials mentioning features or use of this software 131541Srgrimes * must display the following acknowledgement: 141541Srgrimes * This product includes software developed by Sean Eric Fagan 1510905Sbde * 4. Neither the name of the author may be used to endorse or promote 1610905Sbde * products derived from this software without specific prior written 171541Srgrimes * permission. 1834354Sjb * 191541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2011294Sswallace * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2111294Sswallace * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2211294Sswallace * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23160942Sjb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 241541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 251541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26161327Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2731627Sjmg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2831627Sjmg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2931627Sjmg * SUCH DAMAGE. 3099854Salfred */ 3199854Salfred 32171208Speter#ifndef lint 33171208Speterstatic const char rcsid[] = 34194833Sjhb "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 122348 2003-11-09 03:48:13Z marcel $"; 35194833Sjhb#endif /* not lint */ 3631627Sjmg 3731627Sjmg/* 3831627Sjmg * FreeBSD/i386-specific system call handling. This is probably the most 3999854Salfred * complex part of the entire truss program, although I've got lots of 40177656Sjb * it handled relatively cleanly now. The system call names are generated 411541Srgrimes * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 42219131Srwatson * names used for the various structures are confusing, I sadly admit. 43219131Srwatson */ 44219131Srwatson 45219131Srwatson#include <sys/types.h> 46219131Srwatson#include <sys/ioctl.h> 47219131Srwatson#include <sys/pioctl.h> 48219131Srwatson#include <sys/syscall.h> 49194833Sjhb 501541Srgrimes#include <machine/reg.h> 51194833Sjhb#include <machine/psl.h> 5224373Speter 531541Srgrimes#include <errno.h> 5495258Sdes#include <fcntl.h> 551541Srgrimes#include <signal.h> 561541Srgrimes#include <stdio.h> 571541Srgrimes#include <stdlib.h> 581541Srgrimes#include <string.h> 5936735Sdfr#include <time.h> 6011294Sswallace#include <unistd.h> 6111294Sswallace 6211294Sswallace#include "truss.h" 6311294Sswallace#include "syscall.h" 6411294Sswallace#include "extern.h" 6511294Sswallace 6611294Sswallacestatic int fd = -1; 6711294Sswallacestatic int cpid = -1; 6811294Sswallaceextern int Procfd; 6911294Sswallace 7011294Sswallace#include "syscalls.h" 7111294Sswallace 7211294Sswallacestatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7311294Sswallace 7411294Sswallace/* 7511294Sswallace * This is what this particular file uses to keep track of a system call. 761541Srgrimes * It is probably not quite sufficient -- I can probably use the same 77161327Sjhb * structure for the various syscall personalities, and I also probably 781541Srgrimes * need to nest system calls (for signal handlers). 7910905Sbde * 8099854Salfred * 'struct syscall' describes the system call; it may be NULL, however, 8110905Sbde * if we don't know about this particular system call yet. 821541Srgrimes */ 8311294Sswallacestatic struct freebsd_syscall { 8499854Salfred struct syscall *sc; 8599854Salfred const char *name; 86171208Speter int number; 87171208Speter unsigned long *args; 88194833Sjhb int nargs; /* number of arguments -- *not* number of words! */ 89194833Sjhb char **s_args; /* the printable arguments */ 901541Srgrimes} fsc; 9136782Sbde 9211294Sswallace/* Clear up and free parts of the fsc structure. */ 9311294Sswallacestatic __inline void 941541Srgrimesclear_fsc(void) { 951541Srgrimes if (fsc.args) { 9634354Sjb free(fsc.args); 97160942Sjb } 98177656Sjb if (fsc.s_args) { 991541Srgrimes int i; 10099854Salfred for (i = 0; i < fsc.nargs; i++) 101171208Speter if (fsc.s_args[i]) 102194833Sjhb free(fsc.s_args[i]); 10311294Sswallace free(fsc.s_args); 10411294Sswallace } 10511294Sswallace memset(&fsc, 0, sizeof(fsc)); 1061541Srgrimes} 107219131Srwatson 1081541Srgrimes/* 1091541Srgrimes * Called when a process has entered a system call. nargs is the 110219131Srwatson * number of words, not number of arguments (a necessary distinction 111219131Srwatson * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11236782Sbde * is ever changed these functions need to keep up. 11336782Sbde */ 11489977Sbde 11510905Sbdevoid 11611294Sswallacei386_syscall_entry(struct trussinfo *trussinfo, int nargs) { 11711294Sswallace char buf[32]; 11889977Sbde struct reg regs; 1191541Srgrimes int syscall_num; 12031785Seivind int i; 12199854Salfred unsigned int parm_offset; 122171208Speter struct syscall *sc; 123194833Sjhb 1241541Srgrimes if (fd == -1 || trussinfo->pid != cpid) { 1251541Srgrimes sprintf(buf, "/proc/%d/regs", trussinfo->pid); 1261541Srgrimes fd = open(buf, O_RDWR); 12789977Sbde if (fd == -1) { 1281541Srgrimes fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 1291541Srgrimes return; 1301541Srgrimes } 13189977Sbde cpid = trussinfo->pid; 13234354Sjb } 13334354Sjb 13489984Sbde clear_fsc(); 135160942Sjb lseek(fd, 0L, 0); 136160942Sjb if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 137160942Sjb fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 138160942Sjb return; 1391541Srgrimes } 1401541Srgrimes parm_offset = regs.r_esp + sizeof(int); 14150478Speter 14210906Sbde /* 14311294Sswallace * FreeBSD has two special kinds of system call redirctions -- 14436782Sbde * SYS_syscall, and SYS___syscall. The former is the old syscall() 14511294Sswallace * routine, basicly; the latter is for quad-aligned arguments. 14636782Sbde */ 14711294Sswallace syscall_num = regs.r_eax; 14810905Sbde switch (syscall_num) { 14911294Sswallace case SYS_syscall: 15033039Sbde lseek(Procfd, parm_offset, SEEK_SET); 15133039Sbde read(Procfd, &syscall_num, sizeof(int)); 152103574Salfred parm_offset += sizeof(int); 153103574Salfred break; 154177597Sru case SYS___syscall: 155164184Strhodes lseek(Procfd, parm_offset, SEEK_SET); 156258106Sjhb read(Procfd, &syscall_num, sizeof(int)); 157258106Sjhb parm_offset += sizeof(quad_t); 158161327Sjhb break; 15933039Sbde } 16083366Sjulian 16136770Sbde fsc.number = syscall_num; 16236770Sbde fsc.name = 16382149Stmm (syscall_num < 0 || syscall_num > nsyscalls) ? NULL : syscallnames[syscall_num]; 16482149Stmm if (!fsc.name) { 16582149Stmm fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); 16682149Stmm } 16782149Stmm 16882149Stmm if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 16982149Stmm && ((!strcmp(fsc.name, "fork") 1701541Srgrimes || !strcmp(fsc.name, "rfork") 1711541Srgrimes || !strcmp(fsc.name, "vfork")))) 172106149Sdwmalone { 1731541Srgrimes trussinfo->in_fork = 1; 1741541Srgrimes } 1752700Swollman 17634354Sjb if (nargs == 0) 17734354Sjb return; 178160942Sjb 179209390Sed fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 180160942Sjb lseek(Procfd, parm_offset, SEEK_SET); 181160942Sjb if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 182160942Sjb return; 183177656Sjb 184177656Sjb sc = get_syscall(fsc.name); 185177656Sjb if (sc) { 1861541Srgrimes fsc.nargs = sc->nargs; 1871541Srgrimes } else { 1881541Srgrimes#if DEBUG 1891541Srgrimes fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 1901541Srgrimes fsc.name, nargs); 19111294Sswallace#endif 19211294Sswallace fsc.nargs = nargs; 19311294Sswallace } 19411294Sswallace 1951541Srgrimes fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 1961541Srgrimes memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 1971541Srgrimes fsc.sc = sc; 19811294Sswallace 1991541Srgrimes /* 20099854Salfred * At this point, we set up the system call arguments. 201171208Speter * We ignore any OUT ones, however -- those are arguments that 202194833Sjhb * are set by the system call, and so are probably meaningless 2031541Srgrimes * now. This doesn't currently support arguments that are 204219559Savg * passed in *and* out, however. 205219559Savg */ 2061541Srgrimes 2071541Srgrimes if (fsc.name) { 2081541Srgrimes 2091541Srgrimes#if DEBUG 2101541Srgrimes fprintf(stderr, "syscall %s(", fsc.name); 2111541Srgrimes#endif 21211294Sswallace for (i = 0; i < fsc.nargs; i++) { 2131541Srgrimes#if DEBUG 21499854Salfred fprintf(stderr, "0x%x%s", 215171208Speter sc 216194833Sjhb ? fsc.args[sc->args[i].offset] 2171541Srgrimes : fsc.args[i], 218219559Savg i < (fsc.nargs - 1) ? "," : ""); 219219559Savg#endif 2201541Srgrimes if (sc && !(sc->args[i].type & OUT)) { 2211541Srgrimes fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 2221541Srgrimes } 2231541Srgrimes } 2241541Srgrimes#if DEBUG 2251541Srgrimes fprintf(stderr, ")\n"); 22611294Sswallace#endif 2271541Srgrimes } 22899854Salfred 229171208Speter#if DEBUG 230194833Sjhb fprintf(trussinfo->outfile, "\n"); 2311541Srgrimes#endif 232219559Savg 233219559Savg /* 2341541Srgrimes * Some system calls should be printed out before they are done -- 2351541Srgrimes * execve() and exit(), for example, never return. Possibly change 2361541Srgrimes * this to work for any system call that doesn't have an OUT 23736770Sbde * parameter? 23836770Sbde */ 2391541Srgrimes 2401541Srgrimes if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 2411541Srgrimes 2421541Srgrimes /* XXX 243194390Sjhb * This could be done in a more general 244194390Sjhb * manner but it still wouldn't be very pretty. 245194390Sjhb */ 246194390Sjhb if (!strcmp(fsc.name, "execve")) { 247194390Sjhb if ((trussinfo->flags & EXECVEARGS) == 0) 248194390Sjhb if (fsc.s_args[1]) { 249194390Sjhb free(fsc.s_args[1]); 250194390Sjhb fsc.s_args[1] = NULL; 251194390Sjhb } 252194390Sjhb if ((trussinfo->flags & EXECVEENVS) == 0) 253194390Sjhb if (fsc.s_args[2]) { 254194390Sjhb free(fsc.s_args[2]); 255194390Sjhb fsc.s_args[2] = NULL; 25660287Sbde } 25760287Sbde } 25860287Sbde 25960287Sbde print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); 26060287Sbde fprintf(trussinfo->outfile, "\n"); 26160287Sbde } 26260287Sbde 26360287Sbde return; 26411294Sswallace} 26536770Sbde 26611294Sswallace/* 26711294Sswallace * And when the system call is done, we handle it here. 26811294Sswallace * Currently, no attempt is made to ensure that the system calls 26911294Sswallace * match -- this needs to be fixed (and is, in fact, why S_SCX includes 270146806Srwatson * the sytem call number instead of, say, an error status). 27111294Sswallace */ 27260287Sbde 273209579Skiblong 274209579Skibi386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 275209579Skib{ 276209579Skib char buf[32]; 27711294Sswallace struct reg regs; 27811294Sswallace long retval; 27911294Sswallace int i; 28011294Sswallace int errorp; 28111294Sswallace struct syscall *sc; 28211294Sswallace 28311294Sswallace if (fd == -1 || trussinfo->pid != cpid) { 28411294Sswallace sprintf(buf, "/proc/%d/regs", trussinfo->pid); 28511294Sswallace fd = open(buf, O_RDONLY); 28611294Sswallace if (fd == -1) { 28710905Sbde fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 288194390Sjhb return (-1); 289146806Srwatson } 290146806Srwatson cpid = trussinfo->pid; 291146806Srwatson } 29211294Sswallace 29311294Sswallace lseek(fd, 0L, 0); 29411294Sswallace if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 29511294Sswallace fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 29611294Sswallace return (-1); 29711294Sswallace } 29811294Sswallace retval = regs.r_eax; 29911294Sswallace errorp = !!(regs.r_eflags & PSL_C); 30011294Sswallace 30111294Sswallace /* 30211294Sswallace * This code, while simpler than the initial versions I used, could 30311294Sswallace * stand some significant cleaning. 30411294Sswallace */ 30511294Sswallace 30611294Sswallace sc = fsc.sc; 30711294Sswallace if (!sc) { 30811294Sswallace for (i = 0; i < fsc.nargs; i++) 30911294Sswallace asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]); 310219131Srwatson } else { 311219131Srwatson /* 312219131Srwatson * Here, we only look for arguments that have OUT masked in -- 313219131Srwatson * otherwise, they were handled in the syscall_entry function. 314219131Srwatson */ 315219131Srwatson for (i = 0; i < sc->nargs; i++) { 316219131Srwatson char *temp; 317219131Srwatson if (sc->args[i].type & OUT) { 318219131Srwatson /* 319219131Srwatson * If an error occurred, than don't bothe getting the data; 320219131Srwatson * it may not be valid. 321219131Srwatson */ 32211294Sswallace if (errorp) 32311294Sswallace asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]); 32411294Sswallace else 32511294Sswallace temp = print_arg(Procfd, &sc->args[i], fsc.args); 326194390Sjhb fsc.s_args[i] = temp; 32711330Sswallace } 328194390Sjhb } 32999854Salfred } 330194390Sjhb 331171208Speter /* 332194833Sjhb * It would probably be a good idea to merge the error handling, 333194833Sjhb * but that complicates things considerably. 33411294Sswallace */ 33511294Sswallace 33611294Sswallace print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 33711294Sswallace clear_fsc(); 33811294Sswallace 33911294Sswallace return (retval); 34011294Sswallace} 34111294Sswallace