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/* 3831567Ssef * Linux/i386-specific system call handling. Given how much of this code 3931567Ssef * is taken from the freebsd equivalent, I can probably put even more of 4031567Ssef * it in support routines that can be used by any personality support. 4131567Ssef */ 4232275Scharnier 4385301Sdes#include <sys/types.h> 44168569Sdelphij#include <sys/ptrace.h> 4585301Sdes 4685301Sdes#include <machine/reg.h> 4785301Sdes#include <machine/psl.h> 4885301Sdes 4932275Scharnier#include <errno.h> 5032275Scharnier#include <fcntl.h> 5132275Scharnier#include <signal.h> 5231567Ssef#include <stdio.h> 5331567Ssef#include <stdlib.h> 5431567Ssef#include <string.h> 55101423Smdodd#include <time.h> 5631567Ssef#include <unistd.h> 5731567Ssef 58101282Smdodd#include "truss.h" 5931567Ssef#include "syscall.h" 60106713Sdwmalone#include "extern.h" 6131567Ssef 62179051Sjhb#include "linux32_syscalls.h" 6331567Ssef 6431567Ssefstatic int nsyscalls = 65179051Sjhb sizeof(linux32_syscallnames) / sizeof(linux32_syscallnames[0]); 6631567Ssef 67101374Smdodd/* 68101374Smdodd * This is what this particular file uses to keep track of a system call. 69101374Smdodd * It is probably not quite sufficient -- I can probably use the same 70101374Smdodd * structure for the various syscall personalities, and I also probably 71101374Smdodd * need to nest system calls (for signal handlers). 72101374Smdodd * 73101374Smdodd * 'struct syscall' describes the system call; it may be NULL, however, 74101374Smdodd * if we don't know about this particular system call yet. 75101374Smdodd */ 76240562Szontstruct linux_syscall { 7731567Ssef struct syscall *sc; 78106713Sdwmalone const char *name; 7931567Ssef int number; 8031567Ssef unsigned long args[5]; 8131567Ssef int nargs; /* number of arguments -- *not* number of words! */ 8231567Ssef char **s_args; /* the printable arguments */ 83240562Szont}; 8431567Ssef 85240562Szontstatic struct linux_syscall * 86240562Szontalloc_fsc(void) 87240562Szont{ 88240562Szont 89240562Szont return (malloc(sizeof(struct linux_syscall))); 90240562Szont} 91240562Szont 92101374Smdodd/* Clear up and free parts of the fsc structure. */ 93240562Szontstatic void 94240562Szontfree_fsc(struct linux_syscall *fsc) 95240005Szont{ 96240005Szont int i; 97240005Szont 98240562Szont if (fsc->s_args) { 99240562Szont for (i = 0; i < fsc->nargs; i++) 100240562Szont free(fsc->s_args[i]); 101240562Szont free(fsc->s_args); 102240005Szont } 103240562Szont free(fsc); 10431567Ssef} 10531567Ssef 106101374Smdodd/* 107101374Smdodd * Called when a process has entered a system call. nargs is the 108101374Smdodd * number of words, not number of arguments (a necessary distinction 109101374Smdodd * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 110101374Smdodd * is ever changed these functions need to keep up. 111101374Smdodd */ 112101374Smdodd 11331567Ssefvoid 114240005Szontamd64_linux32_syscall_entry(struct trussinfo *trussinfo, int nargs) 115240005Szont{ 116240005Szont struct reg regs; 117240562Szont struct linux_syscall *fsc; 118240005Szont struct syscall *sc; 119240562Szont lwpid_t tid; 120240005Szont int i, syscall_num; 12131567Ssef 122240562Szont tid = trussinfo->curthread->tid; 12331567Ssef 124240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 125240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 126240005Szont return; 127240005Szont } 12831567Ssef 129240005Szont syscall_num = regs.r_rax; 130101283Smdodd 131240562Szont fsc = alloc_fsc(); 132240562Szont if (fsc == NULL) 133240562Szont return; 134240562Szont fsc->number = syscall_num; 135240562Szont fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 136240005Szont NULL : linux32_syscallnames[syscall_num]; 137240562Szont if (!fsc->name) { 138240005Szont fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 139240005Szont syscall_num); 140240005Szont } 14131567Ssef 142240562Szont if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && 143240562Szont (strcmp(fsc->name, "linux_fork") == 0 || 144240562Szont strcmp(fsc->name, "linux_vfork") == 0)) 145240005Szont trussinfo->curthread->in_fork = 1; 14631567Ssef 147240005Szont if (nargs == 0) 148240005Szont return; 14931567Ssef 150240005Szont /* 151240005Szont * Linux passes syscall arguments in registers, not 152240005Szont * on the stack. Fortunately, we've got access to the 153240005Szont * register set. Note that we don't bother checking the 154240005Szont * number of arguments. And what does linux do for syscalls 155240005Szont * that have more than five arguments? 156240005Szont */ 157240005Szont 158240562Szont fsc->args[0] = regs.r_rbx; 159240562Szont fsc->args[1] = regs.r_rcx; 160240562Szont fsc->args[2] = regs.r_rdx; 161240562Szont fsc->args[3] = regs.r_rsi; 162240562Szont fsc->args[4] = regs.r_rdi; 163240005Szont 164240562Szont sc = get_syscall(fsc->name); 165240005Szont if (sc) 166240562Szont fsc->nargs = sc->nargs; 167240005Szont else { 168101374Smdodd#if DEBUG 169240005Szont fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 170240562Szont "args to %d\n", fsc->name, nargs); 17131567Ssef#endif 172240562Szont fsc->nargs = nargs; 173240005Szont } 17431567Ssef 175240562Szont fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); 176240562Szont fsc->sc = sc; 17731567Ssef 178240005Szont /* 179240005Szont * At this point, we set up the system call arguments. 180240005Szont * We ignore any OUT ones, however -- those are arguments that 181240005Szont * are set by the system call, and so are probably meaningless 182240005Szont * now. This doesn't currently support arguments that are 183240005Szont * passed in *and* out, however. 184240005Szont */ 18531567Ssef 186240562Szont if (fsc->name) { 187101374Smdodd#if DEBUG 188240562Szont fprintf(stderr, "syscall %s(", fsc->name); 18931567Ssef#endif 190240562Szont for (i = 0; i < fsc->nargs; i++) { 191101374Smdodd#if DEBUG 192240005Szont fprintf(stderr, "0x%x%s", sc ? 193240562Szont fsc->args[sc->args[i].offset] : fsc->args[i], 194240562Szont i < (fsc->nargs - 1) ? "," : ""); 19531567Ssef#endif 196240005Szont if (sc && !(sc->args[i].type & OUT)) { 197240562Szont fsc->s_args[i] = print_arg(&sc->args[i], 198240562Szont fsc->args, 0, trussinfo); 199240005Szont } 200240005Szont } 201101374Smdodd#if DEBUG 202240005Szont fprintf(stderr, ")\n"); 20331567Ssef#endif 204240005Szont } 20531567Ssef 206101374Smdodd#if DEBUG 207240005Szont fprintf(trussinfo->outfile, "\n"); 208101374Smdodd#endif 209101289Smdodd 210240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || 211240562Szont strcmp(fsc->name, "exit") == 0)) { 212240005Szont /* 213240005Szont * XXX 214240005Szont * This could be done in a more general 215240005Szont * manner but it still wouldn't be very pretty. 216240005Szont */ 217240562Szont if (strcmp(fsc->name, "linux_execve") == 0) { 218240005Szont if ((trussinfo->flags & EXECVEARGS) == 0) { 219240562Szont if (fsc->s_args[1]) { 220240562Szont free(fsc->s_args[1]); 221240562Szont fsc->s_args[1] = NULL; 222240005Szont } 223240005Szont } 224240005Szont if ((trussinfo->flags & EXECVEENVS) == 0) { 225240562Szont if (fsc->s_args[2]) { 226240562Szont free(fsc->s_args[2]); 227240562Szont fsc->s_args[2] = NULL; 228240005Szont } 229240005Szont } 230240005Szont } 231240005Szont } 232240562Szont trussinfo->curthread->fsc = fsc; 23331567Ssef} 23431567Ssef 23531567Ssef/* 23631567Ssef * Linux syscalls return negative errno's, we do positive and map them 23731567Ssef */ 238228396Sedstatic const int bsd_to_linux_errno[] = { 239240005Szont -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 240240005Szont -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 241240005Szont -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 242240005Szont -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 243240005Szont -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 24431567Ssef -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 24531567Ssef -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 24631567Ssef -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 247240005Szont -6, 24831567Ssef}; 24931567Ssef 250122348Smarcellong 251240005Szontamd64_linux32_syscall_exit(struct trussinfo *trussinfo, 252240005Szont int syscall_num __unused) 253122348Smarcel{ 254240005Szont struct reg regs; 255240562Szont struct linux_syscall *fsc; 256240005Szont struct syscall *sc; 257240562Szont lwpid_t tid; 258240005Szont long retval; 259240005Szont int errorp, i; 26031567Ssef 261240562Szont if (trussinfo->curthread->fsc == NULL) 262240005Szont return (-1); 263171055Sdelphij 264240562Szont tid = trussinfo->curthread->tid; 26531567Ssef 266240562Szont if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 267240005Szont fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 268240005Szont return (-1); 269240005Szont } 27031567Ssef 271240005Szont retval = regs.r_rax; 272240005Szont errorp = !!(regs.r_rflags & PSL_C); 273101374Smdodd 274101374Smdodd /* 275240005Szont * This code, while simpler than the initial versions I used, could 276240005Szont * stand some significant cleaning. 277101374Smdodd */ 278101374Smdodd 279240562Szont fsc = trussinfo->curthread->fsc; 280240562Szont sc = fsc->sc; 281240005Szont if (!sc) { 282240562Szont for (i = 0; i < fsc->nargs; i++) 283240562Szont asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); 284240005Szont } else { 285240005Szont /* 286240005Szont * Here, we only look for arguments that have OUT masked in -- 287240005Szont * otherwise, they were handled in the syscall_entry function. 288240005Szont */ 289240005Szont for (i = 0; i < sc->nargs; i++) { 290240005Szont char *temp; 291240005Szont if (sc->args[i].type & OUT) { 292240005Szont /* 293240005Szont * If an error occurred, then don't bother 294240005Szont * getting the data; it may not be valid. 295240005Szont */ 296240005Szont if (errorp) { 297240005Szont asprintf(&temp, "0x%lx", 298240562Szont fsc->args[sc->args[i].offset]); 299240005Szont } else { 300240005Szont temp = print_arg(&sc->args[i], 301240562Szont fsc->args, retval, trussinfo); 302240005Szont } 303240562Szont fsc->s_args[i] = temp; 304240005Szont } 305240005Szont } 306240005Szont } 307171055Sdelphij 308240005Szont /* 309240005Szont * It would probably be a good idea to merge the error handling, 310240005Szont * but that complicates things considerably. 311240005Szont */ 312240005Szont if (errorp) { 313240005Szont for (i = 0; 314240005Szont (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) { 315240005Szont if (retval == bsd_to_linux_errno[i]) 316240005Szont break; 317240005Szont } 318240005Szont } 319171055Sdelphij 320240562Szont if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || 321240562Szont strcmp(fsc->name, "exit") == 0)) 322240005Szont trussinfo->curthread->in_syscall = 1; 323101282Smdodd 324240562Szont print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, 325240562Szont errorp ? i : retval, fsc->sc); 326240562Szont free_fsc(fsc); 327240005Szont 328240005Szont return (retval); 32931567Ssef} 330