i386-fbsd.c revision 101289
1193323Sed/* 2193323Sed * Copryight 1997 Sean Eric Fagan 3193323Sed * 4193323Sed * Redistribution and use in source and binary forms, with or without 5193323Sed * modification, are permitted provided that the following conditions 6193323Sed * are met: 7193323Sed * 1. Redistributions of source code must retain the above copyright 8193323Sed * notice, this list of conditions and the following disclaimer. 9193323Sed * 2. Redistributions in binary form must reproduce the above copyright 10193323Sed * notice, this list of conditions and the following disclaimer in the 11193323Sed * documentation and/or other materials provided with the distribution. 12193323Sed * 3. All advertising materials mentioning features or use of this software 13193323Sed * must display the following acknowledgement: 14193323Sed * This product includes software developed by Sean Eric Fagan 15193323Sed * 4. Neither the name of the author may be used to endorse or promote 16193323Sed * products derived from this software without specific prior written 17193323Sed * permission. 18193323Sed * 19193323Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21198090Srdivacky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22193323Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24198892Srdivacky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29193323Sed * SUCH DAMAGE. 30193323Sed */ 31193323Sed 32212904Sdim#ifndef lint 33198892Srdivackystatic const char rcsid[] = 34193323Sed "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 101289 2002-08-04 02:24:21Z mdodd $"; 35193323Sed#endif /* not lint */ 36218893Sdim 37218893Sdim/* 38218893Sdim * FreeBSD/386-specific system call handling. This is probably the most 39193323Sed * complex part of the entire truss program, although I've got lots of 40193323Sed * it handled relatively cleanly now. The system call names are generated 41193323Sed * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 42193323Sed * names used for the various structures are confusing, I sadly admit. 43193323Sed */ 44193323Sed 45212904Sdim#include <sys/types.h> 46193323Sed#include <sys/ioctl.h> 47193323Sed#include <sys/pioctl.h> 48193323Sed#include <sys/syscall.h> 49193323Sed 50193323Sed#include <machine/reg.h> 51193323Sed#include <machine/psl.h> 52193323Sed 53193323Sed#include <errno.h> 54212904Sdim#include <fcntl.h> 55193323Sed#include <signal.h> 56193323Sed#include <stdio.h> 57193323Sed#include <stdlib.h> 58193323Sed#include <string.h> 59193323Sed#include <unistd.h> 60193323Sed 61193323Sed#include "truss.h" 62193323Sed#include "syscall.h" 63193323Sed 64193323Sedstatic int fd = -1; 65193323Sedstatic int cpid = -1; 66193323Sedextern int Procfd; 67193323Sed 68193323Sed#include "syscalls.h" 69193323Sed 70193323Sedstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 71193323Sed 72193323Sed/* 73193323Sed * This is what this particular file uses to keep track of a system call. 74193323Sed * It is probably not quite sufficient -- I can probably use the same 75193323Sed * structure for the various syscall personalities, and I also probably 76193323Sed * need to nest system calls (for signal handlers). 77193323Sed * 78193323Sed * 'struct syscall' describes the system call; it may be NULL, however, 79193323Sed * if we don't know about this particular system call yet. 80193323Sed */ 81193323Sedstatic struct freebsd_syscall { 82193323Sed struct syscall *sc; 83193323Sed char *name; 84212904Sdim int number; 85218893Sdim unsigned long *args; 86193323Sed int nargs; /* number of arguments -- *not* number of words! */ 87221345Sdim char **s_args; /* the printable arguments */ 88212904Sdim} fsc; 89193323Sed 90193323Sed/* Clear up and free parts of the fsc structure. */ 91193323Sedstatic __inline void 92193323Sedclear_fsc() { 93193323Sed if (fsc.args) { 94193323Sed free(fsc.args); 95193323Sed } 96193323Sed if (fsc.s_args) { 97193323Sed int i; 98193323Sed for (i = 0; i < fsc.nargs; i++) 99193323Sed if (fsc.s_args[i]) 100193323Sed free(fsc.s_args[i]); 101193323Sed free(fsc.s_args); 102193323Sed } 103193323Sed memset(&fsc, 0, sizeof(fsc)); 104193323Sed} 105193323Sed 106193323Sed/* 107193323Sed * Called when a process has entered a system call. nargs is the 108193323Sed * number of words, not number of arguments (a necessary distinction 109193323Sed * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 110193323Sed * is ever changed these functions need to keep up. 111198090Srdivacky */ 112218893Sdim 113218893Sdimvoid 114198090Srdivackyi386_syscall_entry(struct trussinfo *trussinfo, int nargs) { 115198090Srdivacky char buf[32]; 116193323Sed struct reg regs = { 0 }; 117193323Sed int syscall; 118193323Sed int i; 119193323Sed unsigned int parm_offset; 120193323Sed struct syscall *sc; 121193323Sed 122193323Sed if (fd == -1 || trussinfo->pid != cpid) { 123193323Sed sprintf(buf, "/proc/%d/regs", trussinfo->pid); 124193323Sed fd = open(buf, O_RDWR); 125193323Sed if (fd == -1) { 126193323Sed fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 127193323Sed return; 128193323Sed } 129193323Sed cpid = trussinfo->pid; 130193323Sed } 131193323Sed 132193323Sed clear_fsc(); 133193323Sed lseek(fd, 0L, 0); 134193323Sed i = read(fd, ®s, sizeof(regs)); 135193323Sed parm_offset = regs.r_esp + sizeof(int); 136193323Sed 137193323Sed /* 138193323Sed * FreeBSD has two special kinds of system call redirctions -- 139193323Sed * SYS_syscall, and SYS___syscall. The former is the old syscall() 140193323Sed * routine, basicly; the latter is for quad-aligned arguments. 141202375Srdivacky */ 142193323Sed syscall = regs.r_eax; 143202375Srdivacky switch (syscall) { 144193323Sed case SYS_syscall: 145193323Sed lseek(Procfd, parm_offset, SEEK_SET); 146202375Srdivacky read(Procfd, &syscall, sizeof(int)); 147193323Sed parm_offset += sizeof(int); 148193323Sed break; 149193323Sed case SYS___syscall: 150193323Sed lseek(Procfd, parm_offset, SEEK_SET); 151193323Sed read(Procfd, &syscall, sizeof(int)); 152193323Sed parm_offset += sizeof(quad_t); 153193323Sed break; 154193323Sed } 155193323Sed 156193323Sed fsc.number = syscall; 157193323Sed fsc.name = 158198090Srdivacky (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; 159193323Sed if (!fsc.name) { 160193323Sed fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); 161193323Sed } 162198090Srdivacky 163198090Srdivacky if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 164193323Sed && ((!strcmp(fsc.name, "fork") 165193323Sed || !strcmp(fsc.name, "rfork") 166193323Sed || !strcmp(fsc.name, "vfork")))) 167193323Sed { 168193323Sed trussinfo->in_fork = 1; 169193323Sed } 170193323Sed 171193323Sed if (nargs == 0) 172193323Sed return; 173193323Sed 174193323Sed fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 175193323Sed lseek(Procfd, parm_offset, SEEK_SET); 176193323Sed if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 177193323Sed return; 178193323Sed 179193323Sed sc = get_syscall(fsc.name); 180198090Srdivacky if (sc) { 181193323Sed fsc.nargs = sc->nargs; 182193323Sed } else { 183193323Sed#if DEBUG 184193323Sed fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 185193323Sed fsc.name, nargs); 186193323Sed#endif 187193323Sed fsc.nargs = nargs; 188198090Srdivacky } 189198090Srdivacky 190193323Sed fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 191193323Sed memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 192193323Sed fsc.sc = sc; 193193323Sed 194198090Srdivacky /* 195198090Srdivacky * At this point, we set up the system call arguments. 196193323Sed * We ignore any OUT ones, however -- those are arguments that 197193323Sed * are set by the system call, and so are probably meaningless 198198090Srdivacky * now. This doesn't currently support arguments that are 199198090Srdivacky * passed in *and* out, however. 200193323Sed */ 201193323Sed 202193323Sed if (fsc.name) { 203193323Sed 204193323Sed#if DEBUG 205193323Sed fprintf(stderr, "syscall %s(", fsc.name); 206193323Sed#endif 207198090Srdivacky for (i = 0; i < fsc.nargs; i++) { 208198090Srdivacky#if DEBUG 209193323Sed fprintf(stderr, "0x%x%s", 210193323Sed sc 211193323Sed ? fsc.args[sc->args[i].offset] 212193323Sed : fsc.args[i], 213193323Sed i < (fsc.nargs -1) ? "," : ""); 214193323Sed#endif 215193323Sed if (sc && !(sc->args[i].type & OUT)) { 216193323Sed fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 217193323Sed } 218193323Sed } 219193323Sed#if DEBUG 220193323Sed fprintf(stderr, ")\n"); 221193323Sed#endif 222193323Sed } 223193323Sed 224193323Sed#if DEBUG 225193323Sed fprintf(trussinfo->outfile, "\n"); 226193323Sed#endif 227193323Sed 228193323Sed /* 229193323Sed * Some system calls should be printed out before they are done -- 230193323Sed * execve() and exit(), for example, never return. Possibly change 231193323Sed * this to work for any system call that doesn't have an OUT 232193323Sed * parameter? 233193323Sed */ 234193323Sed 235193323Sed if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 236193323Sed 237193323Sed /* XXX 238193323Sed * This could be done in a more general 239193323Sed * manner but it still wouldn't be very pretty. 240193323Sed */ 241193323Sed if (!strcmp(fsc.name, "execve")) { 242193323Sed if ((trussinfo->flags & EXECVEARGS) == 0) 243193323Sed if (fsc.s_args[1]) { 244193323Sed free(fsc.s_args[1]); 245193323Sed fsc.s_args[1] = NULL; 246193323Sed } 247193323Sed if ((trussinfo->flags & EXECVEENVS) == 0) 248200581Srdivacky if (fsc.s_args[2]) { 249193323Sed free(fsc.s_args[2]); 250193323Sed fsc.s_args[2] = NULL; 251193323Sed } 252193323Sed } 253193323Sed 254193323Sed print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); 255193323Sed fprintf(trussinfo->outfile, "\n"); 256193323Sed } 257193323Sed 258193323Sed return; 259193323Sed} 260193323Sed 261193323Sed/* 262193323Sed * And when the system call is done, we handle it here. 263193323Sed * Currently, no attempt is made to ensure that the system calls 264193323Sed * match -- this needs to be fixed (and is, in fact, why S_SCX includes 265193323Sed * the sytem call number instead of, say, an error status). 266193323Sed */ 267193323Sed 268193323Sedint 269193323Sedi386_syscall_exit(struct trussinfo *trussinfo, int syscall) { 270193323Sed char buf[32]; 271193323Sed struct reg regs; 272193323Sed int retval; 273193323Sed int i; 274193323Sed int errorp; 275193323Sed struct syscall *sc; 276193323Sed 277193323Sed if (fd == -1 || trussinfo->pid != cpid) { 278193323Sed sprintf(buf, "/proc/%d/regs", trussinfo->pid); 279193323Sed fd = open(buf, O_RDONLY); 280226633Sdim if (fd == -1) { 281193323Sed fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 282193323Sed return; 283193323Sed } 284226633Sdim cpid = trussinfo->pid; 285193323Sed } 286193323Sed 287193323Sed lseek(fd, 0L, 0); 288193323Sed if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 289193323Sed fprintf(trussinfo->outfile, "\n"); 290193323Sed return; 291193323Sed } 292198090Srdivacky retval = regs.r_eax; 293193323Sed errorp = !!(regs.r_eflags & PSL_C); 294193323Sed 295193323Sed /* 296193323Sed * This code, while simpler than the initial versions I used, could 297193323Sed * stand some significant cleaning. 298193323Sed */ 299193323Sed 300193323Sed sc = fsc.sc; 301193323Sed if (!sc) { 302193323Sed for (i = 0; i < fsc.nargs; i++) { 303193323Sed fsc.s_args[i] = malloc(12); 304193323Sed sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 305193323Sed } 306193323Sed } else { 307193323Sed /* 308193323Sed * Here, we only look for arguments that have OUT masked in -- 309193323Sed * otherwise, they were handled in the syscall_entry function. 310202375Srdivacky */ 311198090Srdivacky for (i = 0; i < sc->nargs; i++) { 312202375Srdivacky char *temp; 313198090Srdivacky if (sc->args[i].type & OUT) { 314193323Sed /* 315193323Sed * If an error occurred, than don't bothe getting the data; 316193323Sed * it may not be valid. 317193323Sed */ 318193323Sed if (errorp) { 319193323Sed temp = malloc(12); 320193323Sed sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 321193323Sed } else { 322193323Sed temp = print_arg(Procfd, &sc->args[i], fsc.args); 323193323Sed } 324 fsc.s_args[i] = temp; 325 } 326 } 327 } 328 329 /* 330 * It would probably be a good idea to merge the error handling, 331 * but that complicates things considerably. 332 */ 333 334 print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 335 clear_fsc(); 336 337 return (retval); 338} 339