131567Ssef/* 2204977Simp * Copyright 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$"; 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> 46240005Szont#include <sys/ptrace.h> 4785301Sdes#include <sys/syscall.h> 4885301Sdes 4985301Sdes#include <machine/reg.h> 5085301Sdes#include <machine/psl.h> 5185301Sdes 5232275Scharnier#include <errno.h> 5332275Scharnier#include <fcntl.h> 5432275Scharnier#include <signal.h> 5531567Ssef#include <stdio.h> 5631567Ssef#include <stdlib.h> 5731567Ssef#include <string.h> 58101423Smdodd#include <time.h> 5931567Ssef#include <unistd.h> 6031567Ssef 61101282Smdodd#include "truss.h" 6231567Ssef#include "syscall.h" 63106713Sdwmalone#include "extern.h" 6431567Ssef 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 */ 78240562Szontstruct freebsd_syscall { 7931567Ssef struct syscall *sc; 80106713Sdwmalone const 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 */ 85240562Szont}; 8631567Ssef 87240562Szontstatic struct freebsd_syscall * 88240562Szontalloc_fsc(void) 89240562Szont{ 90240562Szont 91240562Szont return (malloc(sizeof(struct freebsd_syscall))); 92240562Szont} 93240562Szont 9431567Ssef/* Clear up and free parts of the fsc structure. */ 95240562Szontstatic void 96240562Szontfree_fsc(struct freebsd_syscall *fsc) 97240005Szont{ 98240005Szont int i; 99240005Szont 100240562Szont free(fsc->args); 101240562Szont if (fsc->s_args) { 102240562Szont for (i = 0; i < fsc->nargs; i++) 103240562Szont free(fsc->s_args[i]); 104240562Szont free(fsc->s_args); 105240005Szont } 106240562Szont free(fsc); 10731567Ssef} 10831567Ssef 10931567Ssef/* 11031567Ssef * Called when a process has entered a system call. nargs is the 11131567Ssef * number of words, not number of arguments (a necessary distinction 11231567Ssef * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11331567Ssef * is ever changed these functions need to keep up. 11431567Ssef */ 11531567Ssef 11631567Ssefvoid 117240005Szonti386_syscall_entry(struct trussinfo *trussinfo, int nargs) 118240005Szont{ 119240005Szont struct ptrace_io_desc iorequest; 120240005Szont struct reg regs; 121240562Szont struct freebsd_syscall *fsc; 122240005Szont struct syscall *sc; 123240562Szont lwpid_t tid; 124240005Szont unsigned int parm_offset; 125240005Szont int i, syscall_num; 12631567Ssef 127240562Szont tid = trussinfo->curthread->tid; 12831567Ssef 129240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 130240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 131240005Szont return; 132240005Szont } 133240005Szont parm_offset = regs.r_esp + sizeof(int); 13431567Ssef 135240005Szont /* 136240005Szont * FreeBSD has two special kinds of system call redirctions -- 137240005Szont * SYS_syscall, and SYS___syscall. The former is the old syscall() 138240005Szont * routine, basically; the latter is for quad-aligned arguments. 139240005Szont */ 140240005Szont syscall_num = regs.r_eax; 141240005Szont switch (syscall_num) { 142240005Szont case SYS_syscall: 143240562Szont syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); 144240005Szont parm_offset += sizeof(int); 145240005Szont break; 146240005Szont case SYS___syscall: 147240562Szont syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); 148240005Szont parm_offset += sizeof(quad_t); 149240005Szont break; 150240005Szont } 151101283Smdodd 152240562Szont fsc = alloc_fsc(); 153240562Szont if (fsc == NULL) 154240562Szont return; 155240562Szont fsc->number = syscall_num; 156240562Szont fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 157240005Szont NULL : syscallnames[syscall_num]; 158240562Szont if (!fsc->name) { 159240005Szont fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 160240005Szont syscall_num); 161240005Szont } 16231567Ssef 163240562Szont if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && 164240562Szont (strcmp(fsc->name, "fork") == 0 || 165240562Szont strcmp(fsc->name, "rfork") == 0 || 166240562Szont strcmp(fsc->name, "vfork") == 0)) 167240005Szont trussinfo->curthread->in_fork = 1; 16831567Ssef 169240005Szont if (nargs == 0) 170240005Szont return; 171240005Szont 172240562Szont fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); 173240005Szont iorequest.piod_op = PIOD_READ_D; 174240005Szont iorequest.piod_offs = (void *)parm_offset; 175240562Szont iorequest.piod_addr = fsc->args; 176240005Szont iorequest.piod_len = (1 + nargs) * sizeof(unsigned long); 177240562Szont ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); 178240005Szont if (iorequest.piod_len == 0) 179240005Szont return; 180240005Szont 181240005Szont sc = NULL; 182240562Szont if (fsc->name) 183240562Szont sc = get_syscall(fsc->name); 184240005Szont if (sc) 185240562Szont fsc->nargs = sc->nargs; 186240005Szont else { 18731567Ssef#if DEBUG 188240005Szont fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 189240562Szont "args to %d\n", fsc->name, nargs); 19031567Ssef#endif 191240562Szont fsc->nargs = nargs; 192240005Szont } 19331567Ssef 194240562Szont fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); 195240562Szont fsc->sc = sc; 19631567Ssef 197240005Szont /* 198240005Szont * At this point, we set up the system call arguments. 199240005Szont * We ignore any OUT ones, however -- those are arguments that 200240005Szont * are set by the system call, and so are probably meaningless 201240005Szont * now. This doesn't currently support arguments that are 202240005Szont * passed in *and* out, however. 203240005Szont */ 20431567Ssef 205240562Szont if (fsc->name) { 20631567Ssef#if DEBUG 207240562Szont fprintf(stderr, "syscall %s(", fsc->name); 20831567Ssef#endif 209240562Szont for (i = 0; i < fsc->nargs; i++) { 21031567Ssef#if DEBUG 211240005Szont fprintf(stderr, "0x%x%s", sc ? 212240562Szont fsc->args[sc->args[i].offset] : fsc->args[i], 213240562Szont i < (fsc->nargs - 1) ? "," : ""); 21431567Ssef#endif 215240005Szont if (sc && !(sc->args[i].type & OUT)) { 216240562Szont fsc->s_args[i] = print_arg(&sc->args[i], 217240562Szont fsc->args, 0, trussinfo); 218240005Szont } 219240005Szont } 22031567Ssef#if DEBUG 221240005Szont fprintf(stderr, ")\n"); 22231567Ssef#endif 223240005Szont } 22431567Ssef 22531567Ssef#if DEBUG 226240005Szont fprintf(trussinfo->outfile, "\n"); 22731567Ssef#endif 22831567Ssef 229240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || 230240562Szont strcmp(fsc->name, "exit") == 0)) { 231240005Szont /* 232240005Szont * XXX 233240005Szont * This could be done in a more general 234240005Szont * manner but it still wouldn't be very pretty. 235240005Szont */ 236240562Szont if (strcmp(fsc->name, "execve") == 0) { 237240005Szont if ((trussinfo->flags & EXECVEARGS) == 0) { 238240562Szont if (fsc->s_args[1]) { 239240562Szont free(fsc->s_args[1]); 240240562Szont fsc->s_args[1] = NULL; 241240005Szont } 242240005Szont } 243240005Szont if ((trussinfo->flags & EXECVEENVS) == 0) { 244240562Szont if (fsc->s_args[2]) { 245240562Szont free(fsc->s_args[2]); 246240562Szont fsc->s_args[2] = NULL; 247240005Szont } 248240005Szont } 249240005Szont } 250240005Szont } 251240562Szont trussinfo->curthread->fsc = fsc; 25231567Ssef} 25331567Ssef 25431567Ssef/* 25531567Ssef * And when the system call is done, we handle it here. 25631567Ssef * Currently, no attempt is made to ensure that the system calls 25731567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes 258213799Sbcr * the system call number instead of, say, an error status). 25931567Ssef */ 26031567Ssef 261122348Smarcellong 262122348Smarceli386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 263122348Smarcel{ 264240005Szont struct reg regs; 265240562Szont struct freebsd_syscall *fsc; 266240005Szont struct syscall *sc; 267240562Szont lwpid_t tid; 268240005Szont long retval; 269240005Szont int errorp, i; 27031567Ssef 271240562Szont if (trussinfo->curthread->fsc == NULL) 272240005Szont return (-1); 27331567Ssef 274240562Szont tid = trussinfo->curthread->tid; 27531567Ssef 276240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 277240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 278240005Szont return (-1); 279240005Szont } 28031567Ssef 281240005Szont retval = regs.r_eax; 282240005Szont errorp = !!(regs.r_eflags & PSL_C); 283240005Szont 28431567Ssef /* 285240005Szont * This code, while simpler than the initial versions I used, could 286240005Szont * stand some significant cleaning. 28731567Ssef */ 28831567Ssef 289240562Szont fsc = trussinfo->curthread->fsc; 290240562Szont sc = fsc->sc; 291240005Szont if (!sc) { 292240562Szont for (i = 0; i < fsc->nargs; i++) 293240562Szont asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); 294240005Szont } else { 295240005Szont /* 296240005Szont * Here, we only look for arguments that have OUT masked in -- 297240005Szont * otherwise, they were handled in the syscall_entry function. 298240005Szont */ 299240005Szont for (i = 0; i < sc->nargs; i++) { 300240005Szont char *temp; 301240005Szont if (sc->args[i].type & OUT) { 302240005Szont /* 303240005Szont * If an error occurred, then don't bother 304240005Szont * getting the data; it may not be valid. 305240005Szont */ 306240005Szont if (errorp) { 307240005Szont asprintf(&temp, "0x%lx", 308240562Szont fsc->args[sc->args[i].offset]); 309240005Szont } else { 310240005Szont temp = print_arg(&sc->args[i], 311240562Szont fsc->args, retval, trussinfo); 312240005Szont } 313240562Szont fsc->s_args[i] = temp; 314240005Szont } 315240005Szont } 316240005Szont } 317171055Sdelphij 318240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || 319240562Szont strcmp(fsc->name, "exit") == 0)) 320240005Szont trussinfo->curthread->in_syscall = 1; 32131567Ssef 322240005Szont /* 323240005Szont * It would probably be a good idea to merge the error handling, 324240005Szont * but that complicates things considerably. 325240005Szont */ 32631567Ssef 327240562Szont print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, 328240562Szont retval, fsc->sc); 329240562Szont free_fsc(fsc); 330240005Szont 331240005Szont return (retval); 33231567Ssef} 333