1149423Spjd/* 2149423Spjd * Copyright 1997 Sean Eric Fagan 3149423Spjd * 4149423Spjd * Redistribution and use in source and binary forms, with or without 5149423Spjd * modification, are permitted provided that the following conditions 6149423Spjd * are met: 7149423Spjd * 1. Redistributions of source code must retain the above copyright 8149423Spjd * notice, this list of conditions and the following disclaimer. 9149423Spjd * 2. Redistributions in binary form must reproduce the above copyright 10149423Spjd * notice, this list of conditions and the following disclaimer in the 11149423Spjd * documentation and/or other materials provided with the distribution. 12149423Spjd * 3. All advertising materials mentioning features or use of this software 13149423Spjd * must display the following acknowledgement: 14149423Spjd * This product includes software developed by Sean Eric Fagan 15149423Spjd * 4. Neither the name of the author may be used to endorse or promote 16149423Spjd * products derived from this software without specific prior written 17149423Spjd * permission. 18149423Spjd * 19149423Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20149423Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21149423Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22149423Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23149423Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24149423Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25149423Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26149423Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27184092Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28149423Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29149423Spjd * SUCH DAMAGE. 30149423Spjd */ 31149423Spjd 32149423Spjd#ifndef lint 33149423Spjdstatic const char rcsid[] = 34149423Spjd "$FreeBSD$"; 35152579Sru#endif /* not lint */ 36149423Spjd 37149423Spjd/* 38149423Spjd * Linux/i386-specific system call handling. Given how much of this code 39149423Spjd * is taken from the freebsd equivalent, I can probably put even more of 40149423Spjd * it in support routines that can be used by any personality support. 41152579Sru */ 42149423Spjd 43149423Spjd#include <sys/types.h> 44149423Spjd#include <sys/ptrace.h> 45149423Spjd 46149423Spjd#include <machine/reg.h> 47149423Spjd#include <machine/psl.h> 48149423Spjd 49233837Sghelmer#include <errno.h> 50233837Sghelmer#include <fcntl.h> 51149423Spjd#include <signal.h> 52149423Spjd#include <stdio.h> 53152579Sru#include <stdlib.h> 54152579Sru#include <string.h> 55149423Spjd#include <time.h> 56184092Sdes#include <unistd.h> 57152579Sru 58149423Spjd#include "truss.h" 59149423Spjd#include "syscall.h" 60149423Spjd#include "extern.h" 61152579Sru 62149423Spjd#include "linux_syscalls.h" 63184092Sdes 64152579Srustatic int nsyscalls = 65152579Sru sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]); 66149423Spjd 67152579Sru/* 68152579Sru * This is what this particular file uses to keep track of a system call. 69152579Sru * It is probably not quite sufficient -- I can probably use the same 70152579Sru * structure for the various syscall personalities, and I also probably 71152579Sru * need to nest system calls (for signal handlers). 72152579Sru * 73152579Sru * 'struct syscall' describes the system call; it may be NULL, however, 74149423Spjd * if we don't know about this particular system call yet. 75152579Sru */ 76152579Srustruct linux_syscall { 77152579Sru struct syscall *sc; 78149423Spjd const char *name; 79149423Spjd int number; 80149423Spjd unsigned long args[5]; 81149423Spjd int nargs; /* number of arguments -- *not* number of words! */ 82152579Sru char **s_args; /* the printable arguments */ 83149423Spjd}; 84149423Spjd 85149423Spjdstatic struct linux_syscall * 86152579Srualloc_fsc(void) 87152579Sru{ 88152579Sru 89152579Sru return (malloc(sizeof(struct linux_syscall))); 90149423Spjd} 91149423Spjd 92149423Spjd/* Clear up and free parts of the fsc structure. */ 93152579Srustatic void 94233837Sghelmerfree_fsc(struct linux_syscall *fsc) 95233837Sghelmer{ 96233837Sghelmer int i; 97233856Sghelmer 98149423Spjd if (fsc->s_args) { 99149423Spjd for (i = 0; i < fsc->nargs; i++) 100149423Spjd free(fsc->s_args[i]); 101152579Sru free(fsc->s_args); 102152579Sru } 103152579Sru free(fsc); 104149423Spjd} 105149423Spjd 106152579Sru/* 107149423Spjd * Called when a process has entered a system call. nargs is the 108149423Spjd * number of words, not number of arguments (a necessary distinction 109193589Sdes * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 110149423Spjd * is ever changed these functions need to keep up. 111233837Sghelmer */ 112233837Sghelmer 113233837Sghelmervoid 114233837Sghelmeri386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) 115233856Sghelmer{ 116233856Sghelmer struct reg regs; 117233856Sghelmer struct linux_syscall *fsc; 118233837Sghelmer struct syscall *sc; 119233837Sghelmer lwpid_t tid; 120233837Sghelmer int i, syscall_num; 121233837Sghelmer 122149423Spjd tid = trussinfo->curthread->tid; 123152579Sru 124154952Spjd if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 125154952Spjd fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 126154952Spjd return; 127154952Spjd } 128233837Sghelmer 129233837Sghelmer syscall_num = regs.r_eax; 130154952Spjd 131233837Sghelmer fsc = alloc_fsc(); 132154952Spjd if (fsc == NULL) 133149423Spjd return; 134149423Spjd fsc->number = syscall_num; 135149423Spjd fsc->name = (syscall_num < 0 || syscall_num >= nsyscalls) ? 136149423Spjd NULL : linux_syscallnames[syscall_num]; 137150214Spjd if (!fsc->name) { 138149423Spjd fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", 139154952Spjd syscall_num); 140156280Skeramida } 141156280Skeramida 142154952Spjd if (fsc->name && (trussinfo->flags & FOLLOWFORKS) && 143149423Spjd (strcmp(fsc->name, "linux_fork") == 0 || 144149423Spjd strcmp(fsc->name, "linux_vfork") == 0)) 145149423Spjd trussinfo->curthread->in_fork = 1; 146149423Spjd 147149423Spjd if (nargs == 0) 148149423Spjd return; 149149423Spjd 150149423Spjd /* 151149423Spjd * Linux passes syscall arguments in registers, not 152149423Spjd * on the stack. Fortunately, we've got access to the 153149423Spjd * register set. Note that we don't bother checking the 154149423Spjd * number of arguments. And what does linux do for syscalls 155149423Spjd * that have more than five arguments? 156149423Spjd */ 157149423Spjd 158149423Spjd fsc->args[0] = regs.r_ebx; 159149423Spjd fsc->args[1] = regs.r_ecx; 160149423Spjd fsc->args[2] = regs.r_edx; 161149423Spjd fsc->args[3] = regs.r_esi; 162149423Spjd fsc->args[4] = regs.r_edi; 163149423Spjd 164149423Spjd sc = get_syscall(fsc->name); 165149423Spjd if (sc) 166149423Spjd fsc->nargs = sc->nargs; 167156280Skeramida else { 168149423Spjd#if DEBUG 169149423Spjd fprintf(trussinfo->outfile, "unknown syscall %s -- setting " 170149423Spjd "args to %d\n", fsc->name, nargs); 171149423Spjd#endif 172149423Spjd fsc->nargs = nargs; 173149423Spjd } 174149423Spjd 175149423Spjd fsc->s_args = calloc(1, (1 + fsc->nargs) * sizeof(char *)); 176149423Spjd fsc->sc = sc; 177149423Spjd 178149423Spjd /* 179149423Spjd * At this point, we set up the system call arguments. 180149423Spjd * We ignore any OUT ones, however -- those are arguments that 181152579Sru * are set by the system call, and so are probably meaningless 182149423Spjd * now. This doesn't currently support arguments that are 183149423Spjd * passed in *and* out, however. 184149423Spjd */ 185149423Spjd 186149423Spjd if (fsc->name) { 187149423Spjd#if DEBUG 188172577Skib fprintf(stderr, "syscall %s(", fsc->name); 189172577Skib#endif 190172611Ssimon for (i = 0; i < fsc->nargs; i++) { 191172611Ssimon#if DEBUG 192172577Skib fprintf(stderr, "0x%x%s", sc ? 193149423Spjd fsc->args[sc->args[i].offset] : fsc->args[i], 194149423Spjd i < (fsc->nargs - 1) ? "," : ""); 195149423Spjd#endif 196149423Spjd if (sc && !(sc->args[i].type & OUT)) { 197149423Spjd fsc->s_args[i] = print_arg(&sc->args[i], 198149423Spjd fsc->args, 0, trussinfo); 199149423Spjd } 200149423Spjd } 201149423Spjd#if DEBUG 202152579Sru fprintf(stderr, ")\n"); 203149423Spjd#endif 204152579Sru } 205149423Spjd 206149423Spjd#if DEBUG 207149423Spjd fprintf(trussinfo->outfile, "\n"); 208149423Spjd#endif 209149423Spjd 210149423Spjd if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || 211152579Sru strcmp(fsc->name, "exit") == 0)) { 212149423Spjd /* 213149423Spjd * XXX 214149423Spjd * This could be done in a more general 215149423Spjd * manner but it still wouldn't be very pretty. 216149423Spjd */ 217149423Spjd if (strcmp(fsc->name, "linux_execve") == 0) { 218149423Spjd if ((trussinfo->flags & EXECVEARGS) == 0) { 219149423Spjd if (fsc->s_args[1]) { 220149423Spjd free(fsc->s_args[1]); 221149423Spjd fsc->s_args[1] = NULL; 222149423Spjd } 223152579Sru } 224149423Spjd if ((trussinfo->flags & EXECVEENVS) == 0) { 225152579Sru if (fsc->s_args[2]) { 226149423Spjd free(fsc->s_args[2]); 227149423Spjd fsc->s_args[2] = NULL; 228149423Spjd } 229149423Spjd } 230149423Spjd } 231149423Spjd } 232152579Sru trussinfo->curthread->fsc = fsc; 233152579Sru} 234149423Spjd 235152579Sru/* 236149423Spjd * Linux syscalls return negative errno's, we do positive and map them 237149423Spjd */ 238149423Spjdconst int bsd_to_linux_errno[] = { 239149423Spjd -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 240149423Spjd -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 241149423Spjd -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 242152579Sru -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 243149423Spjd -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 244149423Spjd -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 245149423Spjd -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 246149423Spjd -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 247149423Spjd -6, 248149423Spjd}; 249149423Spjd 250149423Spjdlong 251149423Spjdi386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) 252149423Spjd{ 253149423Spjd struct reg regs; 254149423Spjd struct linux_syscall *fsc; 255152579Sru struct syscall *sc; 256149423Spjd lwpid_t tid; 257184092Sdes long retval; 258184092Sdes int errorp, i; 259184092Sdes 260233837Sghelmer if (trussinfo->curthread->fsc == NULL) 261233837Sghelmer return (-1); 262233837Sghelmer 263233837Sghelmer tid = trussinfo->curthread->tid; 264233837Sghelmer 265233837Sghelmer if (ptrace(PT_GETREGS, tid, (caddr_t)®s, 0) < 0) { 266233837Sghelmer fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 267233837Sghelmer return (-1); 268233837Sghelmer } 269233837Sghelmer 270149423Spjd retval = regs.r_eax; 271149423Spjd errorp = !!(regs.r_eflags & PSL_C); 272184092Sdes 273184092Sdes /* 274149423Spjd * This code, while simpler than the initial versions I used, could 275149423Spjd * stand some significant cleaning. 276149423Spjd */ 277152579Sru 278149423Spjd fsc = trussinfo->curthread->fsc; 279149423Spjd sc = fsc->sc; 280149423Spjd if (!sc) { 281149423Spjd for (i = 0; i < fsc->nargs; i++) 282149423Spjd asprintf(&fsc->s_args[i], "0x%lx", fsc->args[i]); 283 } else { 284 /* 285 * Here, we only look for arguments that have OUT masked in -- 286 * otherwise, they were handled in the syscall_entry function. 287 */ 288 for (i = 0; i < sc->nargs; i++) { 289 char *temp; 290 if (sc->args[i].type & OUT) { 291 /* 292 * If an error occurred, then don't bother 293 * getting the data; it may not be valid. 294 */ 295 if (errorp) { 296 asprintf(&temp, "0x%lx", 297 fsc->args[sc->args[i].offset]); 298 } else { 299 temp = print_arg(&sc->args[i], 300 fsc->args, retval, trussinfo); 301 } 302 fsc->s_args[i] = temp; 303 } 304 } 305 } 306 307 /* 308 * It would probably be a good idea to merge the error handling, 309 * but that complicates things considerably. 310 */ 311 if (errorp) { 312 for (i = 0; 313 (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) { 314 if (retval == bsd_to_linux_errno[i]) 315 break; 316 } 317 } 318 319 if (fsc->name != NULL && (strcmp(fsc->name, "linux_execve") == 0 || 320 strcmp(fsc->name, "exit") == 0)) 321 trussinfo->curthread->in_syscall = 1; 322 323 print_syscall_ret(trussinfo, fsc->name, fsc->nargs, fsc->s_args, errorp, 324 errorp ? i : retval, fsc->sc); 325 free_fsc(fsc); 326 327 return (retval); 328} 329