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 65179051Sjhb#include "freebsd32_syscalls.h" 6631567Ssef 67179051Sjhbstatic int nsyscalls = sizeof(freebsd32_syscallnames) / 68179051Sjhb sizeof(freebsd32_syscallnames[0]); 6931567Ssef 7031567Ssef/* 7131567Ssef * This is what this particular file uses to keep track of a system call. 7231567Ssef * It is probably not quite sufficient -- I can probably use the same 7331567Ssef * structure for the various syscall personalities, and I also probably 7431567Ssef * need to nest system calls (for signal handlers). 7531567Ssef * 7631567Ssef * 'struct syscall' describes the system call; it may be NULL, however, 7731567Ssef * if we don't know about this particular system call yet. 7831567Ssef */ 79240562Szontstruct freebsd32_syscall { 8031567Ssef struct syscall *sc; 81106713Sdwmalone const char *name; 8231567Ssef int number; 8331567Ssef unsigned long *args; 84179051Sjhb unsigned int *args32; 8531567Ssef int nargs; /* number of arguments -- *not* number of words! */ 8631567Ssef char **s_args; /* the printable arguments */ 87240562Szont}; 8831567Ssef 89240562Szontstatic struct freebsd32_syscall * 90240562Szontalloc_fsc(void) 91240562Szont{ 92240562Szont 93240562Szont return (malloc(sizeof(struct freebsd32_syscall))); 94240562Szont} 95240562Szont 9631567Ssef/* Clear up and free parts of the fsc structure. */ 97240562Szontstatic void 98240562Szontfree_fsc(struct freebsd32_syscall *fsc) 99240005Szont{ 100240005Szont int i; 101240005Szont 102240562Szont free(fsc->args); 103240562Szont free(fsc->args32); 104240562Szont if (fsc->s_args) { 105240562Szont for (i = 0; i < fsc->nargs; i++) 106240562Szont free(fsc->s_args[i]); 107240562Szont free(fsc->s_args); 108240005Szont } 109240562Szont free(fsc); 11031567Ssef} 11131567Ssef 11231567Ssef/* 11331567Ssef * Called when a process has entered a system call. nargs is the 11431567Ssef * number of words, not number of arguments (a necessary distinction 11531567Ssef * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11631567Ssef * is ever changed these functions need to keep up. 11731567Ssef */ 11831567Ssef 11931567Ssefvoid 120240005Szontamd64_fbsd32_syscall_entry(struct trussinfo *trussinfo, int nargs) 121240005Szont{ 122240005Szont struct ptrace_io_desc iorequest; 123240005Szont struct reg regs; 124240562Szont struct freebsd32_syscall *fsc; 125240005Szont struct syscall *sc; 126240562Szont lwpid_t tid; 127240005Szont unsigned long parm_offset; 128240005Szont int i, syscall_num; 12931567Ssef 130240562Szont tid = trussinfo->curthread->tid; 13131567Ssef 132240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 133240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 134240005Szont return; 135240005Szont } 136240005Szont parm_offset = regs.r_rsp + sizeof(int); 13731567Ssef 138240005Szont /* 139240005Szont * FreeBSD has two special kinds of system call redirctions -- 140240005Szont * SYS_syscall, and SYS___syscall. The former is the old syscall() 141240005Szont * routine, basically; the latter is for quad-aligned arguments. 142240005Szont */ 143240005Szont syscall_num = regs.r_rax; 144240005Szont switch (syscall_num) { 145240005Szont case SYS_syscall: 146240562Szont syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); 147240005Szont parm_offset += sizeof(int); 148240005Szont break; 149240005Szont case SYS___syscall: 150240562Szont syscall_num = ptrace(PT_READ_D, tid, (caddr_t)parm_offset, 0); 151240005Szont parm_offset += sizeof(quad_t); 152240005Szont break; 153240005Szont } 154101283Smdodd 155240562Szont fsc = alloc_fsc(); 156240562Szont if (fsc == NULL) 157240562Szont return; 158240562Szont fsc->number = syscall_num; 159240562Szont fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 160240005Szont NULL : freebsd32_syscallnames[syscall_num]; 161240562Szont if (!fsc->name) { 162240005Szont fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 163240005Szont syscall_num); 164240005Szont } 16531567Ssef 166240562Szont if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && 167240562Szont (strcmp(fsc->name, "fork") == 0 || 168240562Szont strcmp(fsc->name, "rfork") == 0 || 169240562Szont strcmp(fsc->name, "vfork") == 0)) 170240005Szont trussinfo->curthread->in_fork = 1; 17131567Ssef 172240005Szont if (nargs == 0) 173240005Szont return; 174179051Sjhb 175240562Szont fsc->args32 = malloc((1 + nargs) * sizeof(unsigned int)); 176240005Szont iorequest.piod_op = PIOD_READ_D; 177240005Szont iorequest.piod_offs = (void *)parm_offset; 178240562Szont iorequest.piod_addr = fsc->args32; 179240005Szont iorequest.piod_len = (1 + nargs) * sizeof(unsigned int); 180240562Szont ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); 181240005Szont if (iorequest.piod_len == 0) 182240005Szont return; 183240005Szont 184240562Szont fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); 185240005Szont for (i = 0; i < nargs + 1; i++) 186240562Szont fsc->args[i] = fsc->args32[i]; 187240005Szont 188240005Szont sc = NULL; 189240562Szont if (fsc->name) 190240562Szont sc = get_syscall(fsc->name); 191240005Szont if (sc) 192240562Szont fsc->nargs = sc->nargs; 193240005Szont else { 19431567Ssef#if DEBUG 195240005Szont fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 196240562Szont "args to %d\n", fsc->name, nargs); 19731567Ssef#endif 198240562Szont fsc->nargs = nargs; 199240005Szont } 20031567Ssef 201240562Szont fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); 202240562Szont fsc->sc = sc; 20331567Ssef 204240005Szont /* 205240005Szont * At this point, we set up the system call arguments. 206240005Szont * We ignore any OUT ones, however -- those are arguments that 207240005Szont * are set by the system call, and so are probably meaningless 208240005Szont * now. This doesn't currently support arguments that are 209240005Szont * passed in *and* out, however. 210240005Szont */ 21131567Ssef 212240562Szont if (fsc->name) { 21331567Ssef#if DEBUG 214240562Szont fprintf(stderr, "syscall %s(", fsc->name); 21531567Ssef#endif 216240562Szont for (i = 0; i < fsc->nargs; i++) { 21731567Ssef#if DEBUG 218240005Szont fprintf(stderr, "0x%x%s", sc ? 219240562Szont fsc->args[sc->args[i].offset] : fsc->args[i], 220240562Szont i < (fsc->nargs - 1) ? "," : ""); 22131567Ssef#endif 222240005Szont if (sc && !(sc->args[i].type & OUT)) { 223240562Szont fsc->s_args[i] = print_arg(&sc->args[i], 224240562Szont fsc->args, 0, trussinfo); 225240005Szont } 226240005Szont } 22731567Ssef#if DEBUG 228240005Szont fprintf(stderr, ")\n"); 22931567Ssef#endif 230240005Szont } 23131567Ssef 23231567Ssef#if DEBUG 233240005Szont fprintf(trussinfo->outfile, "\n"); 23431567Ssef#endif 23531567Ssef 236240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "freebsd32_execve") == 0 || 237240562Szont strcmp(fsc->name, "exit") == 0)) { 238240005Szont /* 239240005Szont * XXX 240240005Szont * This could be done in a more general 241240005Szont * manner but it still wouldn't be very pretty. 242240005Szont */ 243240562Szont if (strcmp(fsc->name, "freebsd32_execve") == 0) { 244240005Szont if ((trussinfo->flags & EXECVEARGS) == 0) { 245240562Szont if (fsc->s_args[1]) { 246240562Szont free(fsc->s_args[1]); 247240562Szont fsc->s_args[1] = NULL; 248240005Szont } 249240005Szont } 250240005Szont if ((trussinfo->flags & EXECVEENVS) == 0) { 251240562Szont if (fsc->s_args[2]) { 252240562Szont free(fsc->s_args[2]); 253240562Szont fsc->s_args[2] = NULL; 254240005Szont } 255240005Szont } 256240005Szont } 257240005Szont } 258240562Szont trussinfo->curthread->fsc = fsc; 25931567Ssef} 26031567Ssef 26131567Ssef/* 26231567Ssef * And when the system call is done, we handle it here. 26331567Ssef * Currently, no attempt is made to ensure that the system calls 26431567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes 265213799Sbcr * the system call number instead of, say, an error status). 26631567Ssef */ 26731567Ssef 268122348Smarcellong 269179051Sjhbamd64_fbsd32_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 270122348Smarcel{ 271240005Szont struct reg regs; 272240562Szont struct freebsd32_syscall *fsc; 273240005Szont struct syscall *sc; 274240562Szont lwpid_t tid; 275240005Szont long retval; 276240005Szont int errorp, i; 27731567Ssef 278240562Szont if (trussinfo->curthread->fsc == NULL) 279240005Szont return (-1); 28031567Ssef 281240562Szont tid = trussinfo->curthread->tid; 28231567Ssef 283240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 284240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 285240005Szont return (-1); 286240005Szont } 28731567Ssef 288240005Szont retval = regs.r_rax; 289240005Szont errorp = !!(regs.r_rflags & PSL_C); 290240005Szont 29131567Ssef /* 292240005Szont * This code, while simpler than the initial versions I used, could 293240005Szont * stand some significant cleaning. 29431567Ssef */ 29531567Ssef 296240562Szont fsc = trussinfo->curthread->fsc; 297240562Szont sc = fsc->sc; 298240005Szont if (!sc) { 299240562Szont for (i = 0; i < fsc->nargs; i++) 300240562Szont asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); 301240005Szont } else { 302240005Szont /* 303240005Szont * Here, we only look for arguments that have OUT masked in -- 304240005Szont * otherwise, they were handled in the syscall_entry function. 305240005Szont */ 306240005Szont for (i = 0; i < sc->nargs; i++) { 307240005Szont char *temp; 308240005Szont if (sc->args[i].type & OUT) { 309240005Szont /* 310240005Szont * If an error occurred, then don't bother 311240005Szont * getting the data; it may not be valid. 312240005Szont */ 313240005Szont if (errorp) { 314240005Szont asprintf(&temp, "0x%lx", 315240562Szont fsc->args[sc->args[i].offset]); 316240005Szont } else { 317240005Szont temp = print_arg(&sc->args[i], 318240562Szont fsc->args, retval, trussinfo); 319240005Szont } 320240562Szont fsc->s_args[i] = temp; 321240005Szont } 322240005Szont } 323240005Szont } 324171055Sdelphij 325240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "freebsd32_execve") == 0 || 326240562Szont strcmp(fsc->name, "exit") == 0)) 327240005Szont trussinfo->curthread->in_syscall = 1; 32831567Ssef 329240005Szont /* 330240005Szont * It would probably be a good idea to merge the error handling, 331240005Szont * but that complicates things considerably. 332240005Szont */ 33331567Ssef 334240562Szont print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, 335240562Szont retval, fsc->sc); 336240562Szont free_fsc(fsc); 337240005Szont 338240005Szont return (retval); 33931567Ssef} 340