1154047Sgrehan/* 2154047Sgrehan * Copyright 2006 Peter Grehan <grehan@freebsd.org> 3204977Simp * Copyright 2005 Orlando Bassotto <orlando@break.net> 4204977Simp * Copyright 1998 Sean Eric Fagan 5154047Sgrehan * 6154047Sgrehan * Redistribution and use in source and binary forms, with or without 7154047Sgrehan * modification, are permitted provided that the following conditions 8154047Sgrehan * are met: 9154047Sgrehan * 1. Redistributions of source code must retain the above copyright 10154047Sgrehan * notice, this list of conditions and the following disclaimer. 11154047Sgrehan * 2. Redistributions in binary form must reproduce the above copyright 12154047Sgrehan * notice, this list of conditions and the following disclaimer in the 13154047Sgrehan * documentation and/or other materials provided with the distribution. 14154047Sgrehan * 15154047Sgrehan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16154047Sgrehan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17154047Sgrehan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18154047Sgrehan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19154047Sgrehan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20154047Sgrehan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21154047Sgrehan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22154047Sgrehan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23154047Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24154047Sgrehan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25154047Sgrehan * SUCH DAMAGE. 26154047Sgrehan */ 27154047Sgrehan 28154047Sgrehan#ifndef lint 29154047Sgrehanstatic const char rcsid[] = 30154047Sgrehan "$FreeBSD$"; 31154047Sgrehan#endif /* not lint */ 32154047Sgrehan 33154047Sgrehan/* 34154047Sgrehan * FreeBSD/powerpc-specific system call handling. This is probably the most 35154047Sgrehan * complex part of the entire truss program, although I've got lots of 36154047Sgrehan * it handled relatively cleanly now. The system call names are generated 37154047Sgrehan * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 38154047Sgrehan * names used for the various structures are confusing, I sadly admit. 39154047Sgrehan * 40154047Sgrehan * This file is almost nothing more than a slightly-edited i386-fbsd.c. 41154047Sgrehan */ 42154047Sgrehan 43154047Sgrehan#include <sys/types.h> 44168569Sdelphij#include <sys/ptrace.h> 45154047Sgrehan#include <sys/syscall.h> 46154047Sgrehan 47154047Sgrehan#include <machine/reg.h> 48154047Sgrehan#include <machine/frame.h> 49154047Sgrehan 50154047Sgrehan#include <err.h> 51154047Sgrehan#include <errno.h> 52154047Sgrehan#include <fcntl.h> 53154047Sgrehan#include <signal.h> 54154047Sgrehan#include <stdio.h> 55154047Sgrehan#include <stdlib.h> 56154047Sgrehan#include <string.h> 57154047Sgrehan#include <time.h> 58154047Sgrehan#include <unistd.h> 59154047Sgrehan 60154047Sgrehan#include "truss.h" 61154047Sgrehan#include "syscall.h" 62154047Sgrehan#include "extern.h" 63154047Sgrehan 64154047Sgrehan#include "syscalls.h" 65154047Sgrehan 66154047Sgrehanstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 67154047Sgrehan 68154047Sgrehan/* 69154047Sgrehan * This is what this particular file uses to keep track of a system call. 70154047Sgrehan * It is probably not quite sufficient -- I can probably use the same 71154047Sgrehan * structure for the various syscall personalities, and I also probably 72154047Sgrehan * need to nest system calls (for signal handlers). 73154047Sgrehan * 74154047Sgrehan * 'struct syscall' describes the system call; it may be NULL, however, 75154047Sgrehan * if we don't know about this particular system call yet. 76154047Sgrehan */ 77240562Szontstruct freebsd_syscall { 78154047Sgrehan struct syscall *sc; 79154047Sgrehan const char *name; 80154047Sgrehan int number; 81154047Sgrehan unsigned long *args; 82154047Sgrehan int nargs; /* number of arguments -- *not* number of words! */ 83154047Sgrehan char **s_args; /* the printable arguments */ 84240562Szont}; 85154047Sgrehan 86240562Szontstatic struct freebsd_syscall * 87240562Szontalloc_fsc(void) 88240562Szont{ 89240562Szont 90240562Szont return (malloc(sizeof(struct freebsd_syscall))); 91240562Szont} 92240562Szont 93154047Sgrehan/* 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); 106154047Sgrehan} 107154047Sgrehan 108154047Sgrehan/* 109154047Sgrehan * Called when a process has entered a system call. nargs is the 110154047Sgrehan * number of words, not number of arguments (a necessary distinction 111154047Sgrehan * in some cases). Note that if the STOPEVENT() code in powerpc/powerpc/trap.c 112154047Sgrehan * is ever changed these functions need to keep up. 113154047Sgrehan */ 114154047Sgrehan 115154047Sgrehanvoid 116240005Szontpowerpc64_syscall_entry(struct trussinfo *trussinfo, int nargs) 117240005Szont{ 118240005Szont struct ptrace_io_desc iorequest; 119240005Szont struct reg regs; 120240562Szont struct freebsd_syscall *fsc; 121240005Szont struct syscall *sc; 122240005Szont void *args; 123240562Szont lwpid_t tid; 124240005Szont int i, regargs, syscall_num; 125154047Sgrehan 126240562Szont tid = trussinfo->curthread->tid; 127154047Sgrehan 128240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 129240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 130240005Szont return; 131240005Szont } 132154047Sgrehan 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 regargs = NARGREG; 139240005Szont syscall_num = regs.fixreg[0]; 140240005Szont args = ®s.fixreg[3]; 141240005Szont if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) { 142240005Szont args = ®s.fixreg[4]; 143240005Szont regargs -= 1; 144240005Szont syscall_num = regs.fixreg[3]; 145240005Szont } 146154047Sgrehan 147240562Szont fsc = alloc_fsc(); 148240562Szont if (fsc == NULL) 149240562Szont return; 150240562Szont fsc->number = syscall_num; 151240562Szont fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 152240005Szont NULL : syscallnames[syscall_num]; 153240562Szont if (!fsc->name) { 154240005Szont fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 155240005Szont syscall_num); 156240005Szont } 157154047Sgrehan 158240562Szont if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && 159240562Szont (strcmp(fsc->name, "fork") == 0 || 160240562Szont strcmp(fsc->name, "rfork") == 0 || 161240562Szont strcmp(fsc->name, "vfork") == 0)) 162240005Szont trussinfo->curthread->in_fork = 1; 163154047Sgrehan 164240005Szont if (nargs == 0) 165240005Szont return; 166154047Sgrehan 167240562Szont fsc->args = malloc((1 + nargs) * sizeof(unsigned long)); 168168569Sdelphij 169240005Szont if (nargs > regargs) { 170240562Szont memmove(&fsc->args[0], args, regargs * sizeof(fsc->args[0])); 171154047Sgrehan 172240005Szont iorequest.piod_op = PIOD_READ_D; 173240005Szont iorequest.piod_offs = (void *)(regs.fixreg[1] + 48); 174240562Szont iorequest.piod_addr = &fsc->args[regargs]; 175240562Szont iorequest.piod_len = (nargs - regargs) * sizeof(fsc->args[0]); 176240562Szont ptrace(PT_IO, tid, (caddr_t)&iorequest, 0); 177240005Szont if (iorequest.piod_len == 0) 178240005Szont return; 179240005Szont } else 180240562Szont memmove(&fsc->args[0], args, nargs * sizeof(fsc->args[0])); 181240005Szont 182240562Szont sc = get_syscall(fsc->name); 183240005Szont if (sc) 184240562Szont fsc->nargs = sc->nargs; 185240005Szont else { 186154047Sgrehan#if DEBUG 187240005Szont fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 188240562Szont "args to %d\n", fsc->name, nargs); 189154047Sgrehan#endif 190240562Szont fsc->nargs = nargs; 191240005Szont } 192154047Sgrehan 193240562Szont fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); 194240562Szont fsc->sc = sc; 195154047Sgrehan 196240005Szont /* 197240005Szont * At this point, we set up the system call arguments. 198240005Szont * We ignore any OUT ones, however -- those are arguments that 199240005Szont * are set by the system call, and so are probably meaningless 200240005Szont * now. This doesn't currently support arguments that are 201240005Szont * passed in *and* out, however. 202240005Szont */ 203154047Sgrehan 204240562Szont if (fsc->name) { 205154047Sgrehan#if DEBUG 206240562Szont fprintf(stderr, "syscall %s(", fsc->name); 207154047Sgrehan#endif 208240562Szont for (i = 0; i < fsc->nargs; i++) { 209154047Sgrehan#if DEBUG 210240005Szont fprintf(stderr, "0x%x%s", sc ? 211240562Szont fsc->args[sc->args[i].offset] : fsc->args[i], 212240562Szont i < (fsc->nargs - 1) ? "," : ""); 213154047Sgrehan#endif 214240005Szont if (sc && !(sc->args[i].type & OUT)) { 215240562Szont fsc->s_args[i] = print_arg(&sc->args[i], 216240562Szont fsc->args, 0, trussinfo); 217240005Szont } 218240005Szont } 219154047Sgrehan#if DEBUG 220240005Szont fprintf(stderr, ")\n"); 221154047Sgrehan#endif 222240005Szont } 223154047Sgrehan 224154047Sgrehan#if DEBUG 225240005Szont fprintf(trussinfo->outfile, "\n"); 226154047Sgrehan#endif 227154047Sgrehan 228240562Szont if (fsc->name && (strcmp(fsc->name, "execve") == 0 || 229240562Szont strcmp(fsc->name, "exit") == 0)) { 230240005Szont /* 231240005Szont * XXX 232240005Szont * This could be done in a more general 233240005Szont * manner but it still wouldn't be very pretty. 234240005Szont */ 235240562Szont if (strcmp(fsc->name, "execve") == 0) { 236240005Szont if ((trussinfo->flags & EXECVEARGS) == 0) { 237240562Szont if (fsc->s_args[1]) { 238240562Szont free(fsc->s_args[1]); 239240562Szont fsc->s_args[1] = NULL; 240240005Szont } 241240005Szont } 242240005Szont if ((trussinfo->flags & EXECVEENVS) == 0) { 243240562Szont if (fsc->s_args[2]) { 244240562Szont free(fsc->s_args[2]); 245240562Szont fsc->s_args[2] = NULL; 246240005Szont } 247240005Szont } 248240005Szont } 249240005Szont } 250240562Szont trussinfo->curthread->fsc = fsc; 251154047Sgrehan} 252154047Sgrehan 253154047Sgrehan/* 254154047Sgrehan * And when the system call is done, we handle it here. 255154047Sgrehan * Currently, no attempt is made to ensure that the system calls 256154047Sgrehan * match -- this needs to be fixed (and is, in fact, why S_SCX includes 257213799Sbcr * the system call number instead of, say, an error status). 258154047Sgrehan */ 259154047Sgrehan 260154047Sgrehanlong 261211935Snwhitehornpowerpc64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 262154047Sgrehan{ 263240005Szont struct reg regs; 264240562Szont struct freebsd_syscall *fsc; 265240005Szont struct syscall *sc; 266240562Szont lwpid_t tid; 267240005Szont long retval; 268240005Szont int errorp, i; 269154047Sgrehan 270240562Szont if (trussinfo->curthread->fsc == NULL) 271240005Szont return (-1); 272171055Sdelphij 273240562Szont tid = trussinfo->curthread->tid; 274154047Sgrehan 275240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 276240005Szont fprintf(trussinfo->outfile, "\n"); 277240005Szont return (-1); 278240005Szont } 279154047Sgrehan 280240005Szont retval = regs.fixreg[3]; 281240005Szont errorp = !!(regs.cr & 0x10000000); 282154047Sgrehan 283154047Sgrehan /* 284240005Szont * This code, while simpler than the initial versions I used, could 285240005Szont * stand some significant cleaning. 286154047Sgrehan */ 287154047Sgrehan 288240562Szont fsc = trussinfo->curthread->fsc; 289240562Szont sc = fsc->sc; 290240005Szont if (!sc) { 291240562Szont for (i = 0; i < fsc->nargs; i++) 292240562Szont asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); 293240005Szont } else { 294240005Szont /* 295240005Szont * Here, we only look for arguments that have OUT masked in -- 296240005Szont * otherwise, they were handled in the syscall_entry function. 297240005Szont */ 298240005Szont for (i = 0; i < sc->nargs; i++) { 299240005Szont char *temp; 300240005Szont if (sc->args[i].type & OUT) { 301240005Szont /* 302240005Szont * If an error occurred, then don't bother 303240005Szont * getting the data; it may not be valid. 304240005Szont */ 305240005Szont if (errorp) { 306240005Szont asprintf(&temp, "0x%lx", 307240562Szont fsc->args[sc->args[i].offset]); 308240005Szont } else { 309240005Szont temp = print_arg(&sc->args[i], 310240562Szont fsc->args, retval, trussinfo); 311240005Szont } 312240562Szont fsc->s_args[i] = temp; 313240005Szont } 314240005Szont } 315240005Szont } 316171055Sdelphij 317240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "execve") == 0 || 318240562Szont strcmp(fsc->name, "exit") == 0)) 319240005Szont trussinfo->curthread->in_syscall = 1; 320171055Sdelphij 321240005Szont /* 322240005Szont * It would probably be a good idea to merge the error handling, 323240005Szont * but that complicates things considerably. 324240005Szont */ 325154047Sgrehan 326240562Szont print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, 327240562Szont retval, fsc->sc); 328240562Szont free_fsc(fsc); 329154047Sgrehan 330240005Szont return (retval); 331154047Sgrehan} 332