i386-fbsd.c revision 240005
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: head/usr.bin/truss/i386-fbsd.c 240005 2012-09-02 11:03:18Z zont $"; 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 6531567Ssefstatic int cpid = -1; 6631567Ssef 6731567Ssef#include "syscalls.h" 6831567Ssef 6931567Ssefstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7031567Ssef 7131567Ssef/* 7231567Ssef * This is what this particular file uses to keep track of a system call. 7331567Ssef * It is probably not quite sufficient -- I can probably use the same 7431567Ssef * structure for the various syscall personalities, and I also probably 7531567Ssef * need to nest system calls (for signal handlers). 7631567Ssef * 7731567Ssef * 'struct syscall' describes the system call; it may be NULL, however, 7831567Ssef * if we don't know about this particular system call yet. 7931567Ssef */ 8031567Ssefstatic struct freebsd_syscall { 8131567Ssef struct syscall *sc; 82106713Sdwmalone const char *name; 8331567Ssef int number; 8431567Ssef unsigned long *args; 8531567Ssef int nargs; /* number of arguments -- *not* number of words! */ 8631567Ssef char **s_args; /* the printable arguments */ 8731567Ssef} fsc; 8831567Ssef 8931567Ssef/* Clear up and free parts of the fsc structure. */ 90100357Smarkmstatic __inline void 91240005Szontclear_fsc(void) 92240005Szont{ 93240005Szont int i; 94240005Szont 95240005Szont if (fsc.args) 96240005Szont free(fsc.args); 97240005Szont if (fsc.s_args) { 98240005Szont for (i = 0; i < fsc.nargs; i++) 99240005Szont if (fsc.s_args[i]) 100240005Szont free(fsc.s_args[i]); 101240005Szont free(fsc.s_args); 102240005Szont } 103240005Szont memset(&fsc, 0, sizeof(fsc)); 10431567Ssef} 10531567Ssef 10631567Ssef/* 10731567Ssef * Called when a process has entered a system call. nargs is the 10831567Ssef * number of words, not number of arguments (a necessary distinction 10931567Ssef * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11031567Ssef * is ever changed these functions need to keep up. 11131567Ssef */ 11231567Ssef 11331567Ssefvoid 114240005Szonti386_syscall_entry(struct trussinfo *trussinfo, int nargs) 115240005Szont{ 116240005Szont struct ptrace_io_desc iorequest; 117240005Szont struct reg regs; 118240005Szont struct syscall *sc; 119240005Szont unsigned int parm_offset; 120240005Szont int i, syscall_num; 12131567Ssef 122240005Szont clear_fsc(); 12331567Ssef 124240005Szont cpid = trussinfo->curthread->tid; 12531567Ssef 126240005Szont if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) { 127240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 128240005Szont return; 129240005Szont } 130240005Szont parm_offset = regs.r_esp + sizeof(int); 13131567Ssef 132240005Szont /* 133240005Szont * FreeBSD has two special kinds of system call redirctions -- 134240005Szont * SYS_syscall, and SYS___syscall. The former is the old syscall() 135240005Szont * routine, basically; the latter is for quad-aligned arguments. 136240005Szont */ 137240005Szont syscall_num = regs.r_eax; 138240005Szont switch (syscall_num) { 139240005Szont case SYS_syscall: 140240005Szont syscall_num = ptrace(PT_READ_D, cpid, (caddr_t)parm_offset, 0); 141240005Szont parm_offset += sizeof(int); 142240005Szont break; 143240005Szont case SYS___syscall: 144240005Szont syscall_num = ptrace(PT_READ_D, cpid, (caddr_t)parm_offset, 0); 145240005Szont parm_offset += sizeof(quad_t); 146240005Szont break; 147240005Szont } 148101283Smdodd 149240005Szont fsc.number = syscall_num; 150240005Szont fsc.name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 151240005Szont NULL : syscallnames[syscall_num]; 152240005Szont if (!fsc.name) { 153240005Szont fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 154240005Szont syscall_num); 155240005Szont } 15631567Ssef 157240005Szont if (fsc.name && (trussinfo->flags & FOLLOWFORKS) && 158240005Szont (strcmp(fsc.name, "fork") == 0 || 159240005Szont strcmp(fsc.name, "rfork") == 0 || 160240005Szont strcmp(fsc.name, "vfork") == 0)) 161240005Szont trussinfo->curthread->in_fork = 1; 16231567Ssef 163240005Szont if (nargs == 0) 164240005Szont return; 165240005Szont 166240005Szont fsc.args = malloc((1 + nargs) * sizeof(unsigned long)); 167240005Szont iorequest.piod_op = PIOD_READ_D; 168240005Szont iorequest.piod_offs = (void *)parm_offset; 169240005Szont iorequest.piod_addr = fsc.args; 170240005Szont iorequest.piod_len = (1 + nargs) * sizeof(unsigned long); 171240005Szont ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0); 172240005Szont if (iorequest.piod_len == 0) 173240005Szont return; 174240005Szont 175240005Szont sc = NULL; 176240005Szont if (fsc.name) 177240005Szont sc = get_syscall(fsc.name); 178240005Szont if (sc) 179240005Szont fsc.nargs = sc->nargs; 180240005Szont else { 18131567Ssef#if DEBUG 182240005Szont fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 183240005Szont "args to %d\n", fsc.name, nargs); 18431567Ssef#endif 185240005Szont fsc.nargs = nargs; 186240005Szont } 18731567Ssef 188240005Szont fsc.s_args = calloc(1, (1 + fsc.nargs) * sizeof(char *)); 189240005Szont fsc.sc = sc; 19031567Ssef 191240005Szont /* 192240005Szont * At this point, we set up the system call arguments. 193240005Szont * We ignore any OUT ones, however -- those are arguments that 194240005Szont * are set by the system call, and so are probably meaningless 195240005Szont * now. This doesn't currently support arguments that are 196240005Szont * passed in *and* out, however. 197240005Szont */ 19831567Ssef 199240005Szont if (fsc.name) { 20031567Ssef#if DEBUG 201240005Szont fprintf(stderr, "syscall %s(", fsc.name); 20231567Ssef#endif 203240005Szont for (i = 0; i < fsc.nargs; i++) { 20431567Ssef#if DEBUG 205240005Szont fprintf(stderr, "0x%x%s", sc ? 206240005Szont fsc.args[sc->args[i].offset] : fsc.args[i], 207240005Szont i < (fsc.nargs - 1) ? "," : ""); 20831567Ssef#endif 209240005Szont if (sc && !(sc->args[i].type & OUT)) { 210240005Szont fsc.s_args[i] = print_arg(&sc->args[i], 211240005Szont fsc.args, 0, trussinfo); 212240005Szont } 213240005Szont } 21431567Ssef#if DEBUG 215240005Szont fprintf(stderr, ")\n"); 21631567Ssef#endif 217240005Szont } 21831567Ssef 21931567Ssef#if DEBUG 220240005Szont fprintf(trussinfo->outfile, "\n"); 22131567Ssef#endif 22231567Ssef 223240005Szont if (fsc.name != NULL && (strcmp(fsc.name, "execve") == 0 || 224240005Szont strcmp(fsc.name, "exit") == 0)) { 225240005Szont /* 226240005Szont * XXX 227240005Szont * This could be done in a more general 228240005Szont * manner but it still wouldn't be very pretty. 229240005Szont */ 230240005Szont if (strcmp(fsc.name, "execve") == 0) { 231240005Szont if ((trussinfo->flags & EXECVEARGS) == 0) { 232240005Szont if (fsc.s_args[1]) { 233240005Szont free(fsc.s_args[1]); 234240005Szont fsc.s_args[1] = NULL; 235240005Szont } 236240005Szont } 237240005Szont if ((trussinfo->flags & EXECVEENVS) == 0) { 238240005Szont if (fsc.s_args[2]) { 239240005Szont free(fsc.s_args[2]); 240240005Szont fsc.s_args[2] = NULL; 241240005Szont } 242240005Szont } 243240005Szont } 244240005Szont } 245101289Smdodd 246240005Szont return; 24731567Ssef} 24831567Ssef 24931567Ssef/* 25031567Ssef * And when the system call is done, we handle it here. 25131567Ssef * Currently, no attempt is made to ensure that the system calls 25231567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes 253213799Sbcr * the system call number instead of, say, an error status). 25431567Ssef */ 25531567Ssef 256122348Smarcellong 257122348Smarceli386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 258122348Smarcel{ 259240005Szont struct reg regs; 260240005Szont struct syscall *sc; 261240005Szont long retval; 262240005Szont int errorp, i; 26331567Ssef 264240005Szont if (fsc.name == NULL) 265240005Szont return (-1); 26631567Ssef 267240005Szont cpid = trussinfo->curthread->tid; 26831567Ssef 269240005Szont if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) { 270240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 271240005Szont return (-1); 272240005Szont } 27331567Ssef 274240005Szont retval = regs.r_eax; 275240005Szont errorp = !!(regs.r_eflags & PSL_C); 276240005Szont 27731567Ssef /* 278240005Szont * This code, while simpler than the initial versions I used, could 279240005Szont * stand some significant cleaning. 28031567Ssef */ 28131567Ssef 282240005Szont sc = fsc.sc; 283240005Szont if (!sc) { 284240005Szont for (i = 0; i < fsc.nargs; i++) 285240005Szont asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]); 286240005Szont } else { 287240005Szont /* 288240005Szont * Here, we only look for arguments that have OUT masked in -- 289240005Szont * otherwise, they were handled in the syscall_entry function. 290240005Szont */ 291240005Szont for (i = 0; i < sc->nargs; i++) { 292240005Szont char *temp; 293240005Szont if (sc->args[i].type & OUT) { 294240005Szont /* 295240005Szont * If an error occurred, then don't bother 296240005Szont * getting the data; it may not be valid. 297240005Szont */ 298240005Szont if (errorp) { 299240005Szont asprintf(&temp, "0x%lx", 300240005Szont fsc.args[sc->args[i].offset]); 301240005Szont } else { 302240005Szont temp = print_arg(&sc->args[i], 303240005Szont fsc.args, retval, trussinfo); 304240005Szont } 305240005Szont fsc.s_args[i] = temp; 306240005Szont } 307240005Szont } 308240005Szont } 309171055Sdelphij 310240005Szont if (fsc.name != NULL && (strcmp(fsc.name, "execve") == 0 || 311240005Szont strcmp(fsc.name, "exit") == 0)) 312240005Szont trussinfo->curthread->in_syscall = 1; 31331567Ssef 314240005Szont /* 315240005Szont * It would probably be a good idea to merge the error handling, 316240005Szont * but that complicates things considerably. 317240005Szont */ 31831567Ssef 319240005Szont print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, 320240005Szont retval, fsc.sc); 321240005Szont clear_fsc(); 322240005Szont 323240005Szont return (retval); 32431567Ssef} 325