ia64-fbsd.c revision 192943
1106716Smarcel/* 2106716Smarcel * Copryight 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: head/usr.bin/truss/ia64-fbsd.c 192943 2009-05-28 00:38:24Z delphij $"; 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 64106716Smarcelstatic int cpid = -1; 65106716Smarcel 66106716Smarcel#include "syscalls.h" 67106716Smarcel 68106716Smarcelstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 69106716Smarcel 70106716Smarcel/* 71106716Smarcel * This is what this particular file uses to keep track of a system call. 72106716Smarcel * It is probably not quite sufficient -- I can probably use the same 73106716Smarcel * structure for the various syscall personalities, and I also probably 74106716Smarcel * need to nest system calls (for signal handlers). 75106716Smarcel * 76106716Smarcel * 'struct syscall' describes the system call; it may be NULL, however, 77106716Smarcel * if we don't know about this particular system call yet. 78106716Smarcel */ 79106716Smarcelstatic struct freebsd_syscall { 80106716Smarcel struct syscall *sc; 81106716Smarcel const char *name; 82106716Smarcel int number; 83106716Smarcel unsigned long *args; 84106716Smarcel int nargs; /* number of arguments -- *not* number of words! */ 85106716Smarcel char **s_args; /* the printable arguments */ 86106716Smarcel} fsc; 87106716Smarcel 88106716Smarcel/* Clear up and free parts of the fsc structure. */ 89106716Smarcelstatic __inline void 90106716Smarcelclear_fsc(void) { 91106716Smarcel if (fsc.args) { 92106716Smarcel free(fsc.args); 93106716Smarcel } 94106716Smarcel if (fsc.s_args) { 95106716Smarcel int i; 96106716Smarcel for (i = 0; i < fsc.nargs; i++) 97106716Smarcel if (fsc.s_args[i]) 98106716Smarcel free(fsc.s_args[i]); 99106716Smarcel free(fsc.s_args); 100106716Smarcel } 101106716Smarcel memset(&fsc, 0, sizeof(fsc)); 102106716Smarcel} 103106716Smarcel 104106716Smarcel/* 105106716Smarcel * Called when a process has entered a system call. nargs is the 106106716Smarcel * number of words, not number of arguments (a necessary distinction 107106716Smarcel * in some cases). Note that if the STOPEVENT() code in ia64/ia64/trap.c 108106716Smarcel * is ever changed these functions need to keep up. 109106716Smarcel */ 110106716Smarcel 111106716Smarcelvoid 112106716Smarcelia64_syscall_entry(struct trussinfo *trussinfo, int nargs) { 113106716Smarcel struct reg regs; 114106716Smarcel int syscall_num; 115106716Smarcel int i; 116118367Smarcel unsigned long *parm_offset; 117106716Smarcel struct syscall *sc; 118106716Smarcel 119168569Sdelphij cpid = trussinfo->curthread->tid; 120106716Smarcel 121106716Smarcel clear_fsc(); 122168569Sdelphij if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) { 123106716Smarcel fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 124106716Smarcel return; 125106716Smarcel } 126118367Smarcel parm_offset = ®s.r_scratch.gr16; 127106716Smarcel 128106716Smarcel /* 129106716Smarcel * FreeBSD has two special kinds of system call redirctions -- 130106716Smarcel * SYS_syscall, and SYS___syscall. The former is the old syscall() 131106716Smarcel * routine, basicly; the latter is for quad-aligned arguments. 132106716Smarcel */ 133115084Smarcel syscall_num = regs.r_scratch.gr15; /* XXX double-check. */ 134118367Smarcel if (syscall_num == SYS_syscall || syscall_num == SYS___syscall) 135118367Smarcel syscall_num = (int)*parm_offset++; 136106716Smarcel 137106716Smarcel fsc.number = syscall_num; 138192943Sdelphij fsc.name = (syscall_num < 0 || syscall_num >= nsyscalls) 139106716Smarcel ? NULL : syscallnames[syscall_num]; 140106716Smarcel if (!fsc.name) { 141106716Smarcel fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); 142106716Smarcel } 143106716Smarcel 144106716Smarcel if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 145106716Smarcel && ((!strcmp(fsc.name, "fork") 146106716Smarcel || !strcmp(fsc.name, "rfork") 147106716Smarcel || !strcmp(fsc.name, "vfork")))) 148106716Smarcel { 149168569Sdelphij trussinfo->curthread->in_fork = 1; 150106716Smarcel } 151106716Smarcel 152106716Smarcel if (nargs == 0) 153106716Smarcel return; 154106716Smarcel 155106716Smarcel fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 156118367Smarcel memcpy(fsc.args, parm_offset, nargs * sizeof(long)); 157106716Smarcel 158106716Smarcel sc = get_syscall(fsc.name); 159106716Smarcel if (sc) { 160106716Smarcel fsc.nargs = sc->nargs; 161106716Smarcel } else { 162106716Smarcel#if DEBUG 163106716Smarcel fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 164106716Smarcel fsc.name, nargs); 165106716Smarcel#endif 166106716Smarcel fsc.nargs = nargs; 167106716Smarcel } 168106716Smarcel 169192153Sdelphij fsc.s_args = calloc(1, (1+fsc.nargs) * sizeof(char*)); 170106716Smarcel fsc.sc = sc; 171106716Smarcel 172106716Smarcel /* 173106716Smarcel * At this point, we set up the system call arguments. 174106716Smarcel * We ignore any OUT ones, however -- those are arguments that 175106716Smarcel * are set by the system call, and so are probably meaningless 176106716Smarcel * now. This doesn't currently support arguments that are 177106716Smarcel * passed in *and* out, however. 178106716Smarcel */ 179106716Smarcel 180106716Smarcel if (fsc.name) { 181106716Smarcel 182106716Smarcel#if DEBUG 183106716Smarcel fprintf(stderr, "syscall %s(", fsc.name); 184106716Smarcel#endif 185106716Smarcel for (i = 0; i < fsc.nargs; i++) { 186106716Smarcel#if DEBUG 187106716Smarcel fprintf(stderr, "0x%x%s", 188106716Smarcel sc 189106716Smarcel ? fsc.args[sc->args[i].offset] 190106716Smarcel : fsc.args[i], 191106716Smarcel i < (fsc.nargs - 1) ? "," : ""); 192106716Smarcel#endif 193106716Smarcel if (sc && !(sc->args[i].type & OUT)) { 194168569Sdelphij fsc.s_args[i] = print_arg(&sc->args[i], fsc.args, 0, trussinfo); 195106716Smarcel } 196106716Smarcel } 197106716Smarcel#if DEBUG 198106716Smarcel fprintf(stderr, ")\n"); 199106716Smarcel#endif 200106716Smarcel } 201106716Smarcel 202106716Smarcel#if DEBUG 203106716Smarcel fprintf(trussinfo->outfile, "\n"); 204106716Smarcel#endif 205106716Smarcel 206158626Spav if (fsc.name != NULL && 207158626Spav (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) { 208106716Smarcel 209106716Smarcel /* XXX 210106716Smarcel * This could be done in a more general 211106716Smarcel * manner but it still wouldn't be very pretty. 212106716Smarcel */ 213106716Smarcel if (!strcmp(fsc.name, "execve")) { 214106716Smarcel if ((trussinfo->flags & EXECVEARGS) == 0) 215106716Smarcel if (fsc.s_args[1]) { 216106716Smarcel free(fsc.s_args[1]); 217106716Smarcel fsc.s_args[1] = NULL; 218106716Smarcel } 219106716Smarcel if ((trussinfo->flags & EXECVEENVS) == 0) 220106716Smarcel if (fsc.s_args[2]) { 221106716Smarcel free(fsc.s_args[2]); 222106716Smarcel fsc.s_args[2] = NULL; 223106716Smarcel } 224106716Smarcel } 225106716Smarcel } 226106716Smarcel 227106716Smarcel return; 228106716Smarcel} 229106716Smarcel 230106716Smarcel/* 231106716Smarcel * And when the system call is done, we handle it here. 232106716Smarcel * Currently, no attempt is made to ensure that the system calls 233106716Smarcel * match -- this needs to be fixed (and is, in fact, why S_SCX includes 234106716Smarcel * the sytem call number instead of, say, an error status). 235106716Smarcel */ 236106716Smarcel 237122348Smarcellong 238122348Smarcelia64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 239122348Smarcel{ 240106716Smarcel struct reg regs; 241122348Smarcel long retval; 242106716Smarcel int i; 243106716Smarcel int errorp; 244106716Smarcel struct syscall *sc; 245106716Smarcel 246171055Sdelphij if (fsc.name == NULL) 247171055Sdelphij return (-1); 248168569Sdelphij cpid = trussinfo->curthread->tid; 249106716Smarcel 250168569Sdelphij if (ptrace(PT_GETREGS, cpid, (caddr_t)®s, 0) < 0) { 251106716Smarcel fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 252106716Smarcel return (-1); 253106716Smarcel } 254115084Smarcel retval = regs.r_scratch.gr8; 255115084Smarcel errorp = (regs.r_scratch.gr10 != 0) ? 1 : 0; 256106716Smarcel 257106716Smarcel /* 258106716Smarcel * This code, while simpler than the initial versions I used, could 259106716Smarcel * stand some significant cleaning. 260106716Smarcel */ 261106716Smarcel 262106716Smarcel sc = fsc.sc; 263106716Smarcel if (!sc) { 264122348Smarcel for (i = 0; i < fsc.nargs; i++) 265122348Smarcel asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]); 266106716Smarcel } else { 267106716Smarcel /* 268106716Smarcel * Here, we only look for arguments that have OUT masked in -- 269106716Smarcel * otherwise, they were handled in the syscall_entry function. 270106716Smarcel */ 271106716Smarcel for (i = 0; i < sc->nargs; i++) { 272106716Smarcel char *temp; 273106716Smarcel if (sc->args[i].type & OUT) { 274106716Smarcel /* 275106716Smarcel * If an error occurred, than don't bothe getting the data; 276106716Smarcel * it may not be valid. 277106716Smarcel */ 278122348Smarcel if (errorp) 279122348Smarcel asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]); 280122348Smarcel else 281168569Sdelphij temp = print_arg(&sc->args[i], fsc.args, retval, trussinfo); 282106716Smarcel fsc.s_args[i] = temp; 283106716Smarcel } 284106716Smarcel } 285106716Smarcel } 286106716Smarcel 287171055Sdelphij if (fsc.name != NULL && 288171055Sdelphij (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) { 289171055Sdelphij trussinfo->curthread->in_syscall = 1; 290171055Sdelphij } 291106716Smarcel /* 292106716Smarcel * It would probably be a good idea to merge the error handling, 293106716Smarcel * but that complicates things considerably. 294106716Smarcel */ 295106716Smarcel 296192025Sdds print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, 297192025Sdds fsc.sc, retval); 298106716Smarcel clear_fsc(); 299106716Smarcel 300106716Smarcel return (retval); 301106716Smarcel} 302