1106716Smarcel/* 2204977Simp * Copyright 1997 Sean Eric Fagan 3106716Smarcel * 4106716Smarcel * Redistribution and use in source and binary forms, with or without 5106716Smarcel * modification, are permitted provided that the following conditions 6106716Smarcel * are met: 7106716Smarcel * 1. Redistributions of source code must retain the above copyright 8106716Smarcel * notice, this list of conditions and the following disclaimer. 9106716Smarcel * 2. Redistributions in binary form must reproduce the above copyright 10106716Smarcel * notice, this list of conditions and the following disclaimer in the 11106716Smarcel * documentation and/or other materials provided with the distribution. 12106716Smarcel * 3. All advertising materials mentioning features or use of this software 13106716Smarcel * must display the following acknowledgement: 14106716Smarcel * This product includes software developed by Sean Eric Fagan 15106716Smarcel * 4. Neither the name of the author may be used to endorse or promote 16106716Smarcel * products derived from this software without specific prior written 17106716Smarcel * permission. 18106716Smarcel * 19106716Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20106716Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21106716Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22106716Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23106716Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24106716Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25106716Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26106716Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27106716Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28106716Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29106716Smarcel * SUCH DAMAGE. 30106716Smarcel */ 31106716Smarcel 32106716Smarcel#ifndef lint 33106716Smarcelstatic const char rcsid[] = 34106716Smarcel "$FreeBSD$"; 35106716Smarcel#endif /* not lint */ 36106716Smarcel 37106716Smarcel/* 38111176Sru * FreeBSD/ia64-specific system call handling. This is probably the most 39106716Smarcel * complex part of the entire truss program, although I've got lots of 40106716Smarcel * it handled relatively cleanly now. The system call names are generated 41106716Smarcel * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 42106716Smarcel * names used for the various structures are confusing, I sadly admit. 43106716Smarcel */ 44106716Smarcel 45106716Smarcel#include <sys/types.h> 46168569Sdelphij#include <sys/ptrace.h> 47106716Smarcel#include <sys/syscall.h> 48106716Smarcel 49106716Smarcel#include <machine/reg.h> 50106716Smarcel 51106716Smarcel#include <errno.h> 52106716Smarcel#include <fcntl.h> 53106716Smarcel#include <signal.h> 54106716Smarcel#include <stdio.h> 55106716Smarcel#include <stdlib.h> 56106716Smarcel#include <string.h> 57106716Smarcel#include <time.h> 58106716Smarcel#include <unistd.h> 59106716Smarcel 60106716Smarcel#include "truss.h" 61106716Smarcel#include "syscall.h" 62106716Smarcel#include "extern.h" 63106716Smarcel 64106716Smarcel#include "syscalls.h" 65106716Smarcel 66106716Smarcelstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 67106716Smarcel 68106716Smarcel/* 69106716Smarcel * This is what this particular file uses to keep track of a system call. 70106716Smarcel * It is probably not quite sufficient -- I can probably use the same 71106716Smarcel * structure for the various syscall personalities, and I also probably 72106716Smarcel * need to nest system calls (for signal handlers). 73106716Smarcel * 74106716Smarcel * 'struct syscall' describes the system call; it may be NULL, however, 75106716Smarcel * if we don't know about this particular system call yet. 76106716Smarcel */ 77240562Szontstruct freebsd_syscall { 78106716Smarcel struct syscall *sc; 79106716Smarcel const char *name; 80106716Smarcel int number; 81106716Smarcel unsigned long *args; 82106716Smarcel int nargs; /* number of arguments -- *not* number of words! */ 83106716Smarcel char **s_args; /* the printable arguments */ 84240562Szont}; 85106716Smarcel 86240562Szontstatic struct freebsd_syscall * 87240562Szontalloc_fsc(void) 88240562Szont{ 89240562Szont 90240562Szont return (malloc(sizeof(struct freebsd_syscall))); 91240562Szont} 92240562Szont 93106716Smarcel/* Clear up and free parts of the fsc structure. */ 94240562Szontstatic void 95240562Szontfree_fsc(struct freebsd_syscall *fsc) 96240005Szont{ 97240005Szont int i; 98240005Szont 99240562Szont free(fsc->args); 100240562Szont if (fsc->s_args) { 101240562Szont for (i = 0; i < fsc->nargs; i++) 102240562Szont free(fsc->s_args[i]); 103240562Szont free(fsc->s_args); 104240005Szont } 105240562Szont free(fsc); 106106716Smarcel} 107106716Smarcel 108106716Smarcel/* 109106716Smarcel * Called when a process has entered a system call. nargs is the 110106716Smarcel * number of words, not number of arguments (a necessary distinction 111106716Smarcel * in some cases). Note that if the STOPEVENT() code in ia64/ia64/trap.c 112106716Smarcel * is ever changed these functions need to keep up. 113106716Smarcel */ 114106716Smarcel 115106716Smarcelvoid 116240005Szontia64_syscall_entry(struct trussinfo *trussinfo, int nargs) 117240005Szont{ 118240005Szont struct reg regs; 119240562Szont struct freebsd_syscall *fsc; 120240005Szont struct syscall *sc; 121240005Szont unsigned long *parm_offset; 122240562Szont lwpid_t tid; 123240005Szont int i, syscall_num; 124106716Smarcel 125240562Szont tid = trussinfo->curthread->tid; 126106716Smarcel 127240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 128240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 129240005Szont return; 130240005Szont } 131240005Szont parm_offset = ®s.r_scratch.gr16; 132106716Smarcel 133240005Szont /* 134240005Szont * FreeBSD has two special kinds of system call redirctions -- 135240005Szont * SYS_syscall, and SYS___syscall. The former is the old syscall() 136240005Szont * routine, basically; the latter is for quad-aligned arguments. 137240005Szont */ 138240005Szont syscall_num = regs.r_scratch.gr15; /* XXX double-check. */ 139240005Szont if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) 140240005Szont syscall_num = (int)*parm_offset++; 141106716Smarcel 142240562Szont fsc = alloc_fsc(); 143240562Szont if (fsc == NULL) 144240562Szont return; 145240562Szont fsc->number = syscall_num; 146240562Szont fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 147240005Szont NULL : syscallnames[syscall_num]; 148240562Szont if (!fsc->name) { 149240005Szont fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 150240005Szont syscall_num); 151240005Szont } 152106716Smarcel 153240562Szont if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && 154240562Szont (strcmp(fsc->name, "fork") == 0 || 155240562Szont strcmp(fsc->name, "rfork") == 0 || 156240562Szont strcmp(fsc->name, "vfork") == 0)) 157240005Szont trussinfo->curthread->in_fork = 1; 158106716Smarcel 159240005Szont if (nargs == 0) 160240005Szont return; 161106716Smarcel 162240562Szont fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); 163240562Szont memcpy(fsc->args, parm_offset, nargs * sizeof(long)); 164240005Szont 165240562Szont sc = get_syscall(fsc->name); 166240005Szont if (sc) 167240562Szont fsc->nargs = sc->nargs; 168240005Szont else { 169106716Smarcel#if DEBUG 170240005Szont fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 171240562Szont "args to %d\n", fsc->name, nargs); 172106716Smarcel#endif 173240562Szont fsc->nargs = nargs; 174240005Szont } 175106716Smarcel 176240562Szont fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); 177240562Szont fsc->sc = sc; 178106716Smarcel 179240005Szont /* 180240005Szont * At this point, we set up the system call arguments. 181240005Szont * We ignore any OUT ones, however -- those are arguments that 182240005Szont * are set by the system call, and so are probably meaningless 183240005Szont * now. This doesn't currently support arguments that are 184240005Szont * passed in *and* out, however. 185240005Szont */ 186106716Smarcel 187240562Szont if (fsc->name) { 188106716Smarcel#if DEBUG 189240562Szont fprintf(stderr, "syscall %s(", fsc->name); 190106716Smarcel#endif 191240562Szont for (i = 0; i < fsc->nargs; i++) { 192106716Smarcel#if DEBUG 193240005Szont fprintf(stderr, "0x%x%s", sc ? 194240562Szont fsc->args[sc->args[i].offset] : fsc->args[i], 195240562Szont i < (fsc->nargs - 1) ? "," : ""); 196106716Smarcel#endif 197240005Szont if (sc && !(sc->args[i].type & OUT)) { 198240562Szont fsc->s_args[i] = print_arg(&sc->args[i], 199240562Szont fsc->args, 0, trussinfo); 200240005Szont } 201240005Szont } 202106716Smarcel#if DEBUG 203240005Szont fprintf(stderr, ")\n"); 204106716Smarcel#endif 205240005Szont } 206106716Smarcel 207106716Smarcel#if DEBUG 208240005Szont fprintf(trussinfo->outfile, "\n"); 209106716Smarcel#endif 210106716Smarcel 211240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || 212240562Szont strcmp(fsc->name, "exit") == 0)) { 213240005Szont /* 214240005Szont * XXX 215240005Szont * This could be done in a more general 216240005Szont * manner but it still wouldn't be very pretty. 217240005Szont */ 218240562Szont if (strcmp(fsc->name, "execve") == 0) { 219240005Szont if ((trussinfo->flags & EXECVEARGS) == 0) { 220240562Szont if (fsc->s_args[1]) { 221240562Szont free(fsc->s_args[1]); 222240562Szont fsc->s_args[1] = NULL; 223240005Szont } 224240005Szont } 225240005Szont if ((trussinfo->flags & EXECVEENVS) == 0) { 226240562Szont if (fsc->s_args[2]) { 227240562Szont free(fsc->s_args[2]); 228240562Szont fsc->s_args[2] = NULL; 229240005Szont } 230240005Szont } 231240005Szont } 232240005Szont } 233240562Szont trussinfo->curthread->fsc = fsc; 234106716Smarcel} 235106716Smarcel 236106716Smarcel/* 237106716Smarcel * And when the system call is done, we handle it here. 238106716Smarcel * Currently, no attempt is made to ensure that the system calls 239106716Smarcel * match -- this needs to be fixed (and is, in fact, why S_SCX includes 240213799Sbcr * the system call number instead of, say, an error status). 241106716Smarcel */ 242106716Smarcel 243122348Smarcellong 244122348Smarcelia64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 245122348Smarcel{ 246240005Szont struct reg regs; 247240562Szont struct freebsd_syscall *fsc; 248240005Szont struct syscall *sc; 249240562Szont lwpid_t tid; 250240005Szont long retval; 251240005Szont int errorp, i; 252106716Smarcel 253240562Szont if (trussinfo->curthread->fsc == NULL) 254240005Szont return (-1); 255106716Smarcel 256240562Szont tid = trussinfo->curthread->tid; 257106716Smarcel 258240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 259240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 260240005Szont return (-1); 261240005Szont } 262106716Smarcel 263240005Szont retval = regs.r_scratch.gr8; 264240005Szont errorp = (regs.r_scratch.gr10 != 0) ? 1 : 0; 265240005Szont 266106716Smarcel /* 267240005Szont * This code, while simpler than the initial versions I used, could 268240005Szont * stand some significant cleaning. 269106716Smarcel */ 270106716Smarcel 271240562Szont fsc = trussinfo->curthread->fsc; 272240562Szont sc = fsc->sc; 273240005Szont if (!sc) { 274240562Szont for (i = 0; i < fsc->nargs; i++) 275240562Szont asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); 276240005Szont } else { 277240005Szont /* 278240005Szont * Here, we only look for arguments that have OUT masked in -- 279240005Szont * otherwise, they were handled in the syscall_entry function. 280240005Szont */ 281240005Szont for (i = 0; i < sc->nargs; i++) { 282240005Szont char *temp; 283240005Szont if (sc->args[i].type & OUT) { 284240005Szont /* 285240005Szont * If an error occurred, then don't bother 286240005Szont * getting the data; it may not be valid. 287240005Szont */ 288240005Szont if (errorp) { 289240005Szont asprintf(&temp, "0x%lx", 290240562Szont fsc->args[sc->args[i].offset]); 291240005Szont } else { 292240005Szont temp = print_arg(&sc->args[i], 293240562Szont fsc->args, retval, trussinfo); 294240005Szont } 295240562Szont fsc->s_args[i] = temp; 296240005Szont } 297240005Szont } 298240005Szont } 299106716Smarcel 300240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || 301240562Szont strcmp(fsc->name, "exit") == 0)) 302240005Szont trussinfo->curthread->in_syscall = 1; 303240562Szont 304240005Szont /* 305240005Szont * It would probably be a good idea to merge the error handling, 306240005Szont * but that complicates things considerably. 307240005Szont */ 308106716Smarcel 309240562Szont print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, 310240562Szont retval, fsc->sc); 311240562Szont free_fsc(fsc); 312240005Szont 313240005Szont return (retval); 314106716Smarcel} 315