i386-linux.c revision 31567
1/* 2 * Linux/i386-specific system call handling. Given how much of this code 3 * is taken from the freebsd equivalent, I can probably put even more of 4 * it in support routines that can be used by any personality support. 5 */ 6/* 7 * $Id$ 8 */ 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <errno.h> 13#include <err.h> 14#include <signal.h> 15#include <fcntl.h> 16#include <unistd.h> 17#include <sys/ioctl.h> 18#include <sys/pioctl.h> 19#include <machine/reg.h> 20#include <machine/psl.h> 21 22#include "syscall.h" 23 24static int fd = -1; 25static int cpid = -1; 26extern int Procfd; 27 28extern FILE *outfile; 29#include "linux_syscalls.h" 30 31static int nsyscalls = 32 sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]); 33 34/* See the comment in i386-fbsd.c about this structure. */ 35static struct linux_syscall { 36 struct syscall *sc; 37 char *name; 38 int number; 39 unsigned long args[5]; 40 int nargs; /* number of arguments -- *not* number of words! */ 41 char **s_args; /* the printable arguments */ 42} lsc; 43 44static inline void 45clear_lsc() { 46 if (lsc.s_args) { 47 int i; 48 for (i = 0; i < lsc.nargs; i++) 49 if (lsc.s_args[i]) 50 free(lsc.s_args[i]); 51 free(lsc.s_args); 52 } 53 memset(&lsc, 0, sizeof(lsc)); 54} 55 56void 57i386_linux_syscall_entry(int pid, int nargs) { 58 char buf[32]; 59 struct reg regs = { 0 }; 60 int syscall; 61 int i; 62 int memfd; 63 struct syscall *sc; 64 65 if (fd == -1 || pid != cpid) { 66 sprintf(buf, "/proc/%d/regs", pid); 67 fd = open(buf, O_RDWR); 68 if (fd == -1) { 69 fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 70 return; 71 } 72 cpid = pid; 73 } 74 75 clear_lsc(); 76 lseek(fd, 0L, 0); 77 i = read(fd, ®s, sizeof(regs)); 78 syscall = regs.r_eax; 79 80 lsc.number = syscall; 81 lsc.name = 82 (syscall < 0 || syscall > nsyscalls) ? NULL : linux_syscallnames[syscall]; 83 if (!lsc.name) { 84 fprintf (outfile, "-- UNKNOWN SYSCALL %d\n", syscall); 85 } 86 87 if (nargs == 0) 88 return; 89 90 /* 91 * Linux passes syscall arguments in registers, not 92 * on the stack. Fortunately, we've got access to the 93 * register set. Note that we don't bother checking the 94 * number of arguments. And what does linux do for syscalls 95 * that have more than five arguments? 96 */ 97 98 lsc.args[0] = regs.r_ebx; 99 lsc.args[1] = regs.r_ecx; 100 lsc.args[2] = regs.r_edx; 101 lsc.args[3] = regs.r_esi; 102 lsc.args[4] = regs.r_edi; 103 104 sc = get_syscall(lsc.name); 105 if (sc) { 106 lsc.nargs = sc->nargs; 107 } else { 108#ifdef DEBUG 109 fprintf(outfile, "unknown syscall %s -- setting args to %d\n", 110 lsc.name, nargs); 111#endif 112 lsc.nargs = nargs; 113 } 114 115 lsc.s_args = malloc((1+lsc.nargs) * sizeof(char*)); 116 memset(lsc.s_args, 0, lsc.nargs * sizeof(char*)); 117 lsc.sc = sc; 118 119 if (lsc.name) { 120 char *tmp; 121 122#ifdef DEBUG 123 fprintf(stderr, "syscall %s(", lsc.name); 124#endif 125 for (i = 0; i < lsc.nargs ; i++) { 126#ifdef DEBUG 127 fprintf(stderr, "0x%x%s", 128 sc ? 129 lsc.args[sc->args[i].offset] 130 : lsc.args[i], 131 i < (lsc.nargs - 1) ? "," : ""); 132#endif 133 if (sc && !(sc->args[i].type & OUT)) { 134 lsc.s_args[i] = print_arg(Procfd, &sc->args[i], lsc.args); 135 } 136 } 137#ifdef DEBUG 138 fprintf(stderr, ")\n"); 139#endif 140 } 141 142 if (!strcmp(lsc.name, "linux_execve") || !strcmp(lsc.name, "exit")) { 143 print_syscall(outfile, lsc.name, lsc.nargs, lsc.s_args); 144 } 145 146 return; 147} 148 149/* 150 * Linux syscalls return negative errno's, we do positive and map them 151 */ 152int bsd_to_linux_errno[] = { 153 -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 154 -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 155 -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 156 -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 157 -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 158 -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 159 -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 160 -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 161 -6, 162}; 163 164void 165i386_linux_syscall_exit(int pid, int syscall) { 166 char buf[32]; 167 struct reg regs; 168 int retval; 169 int i; 170 int errorp; 171 struct syscall *sc; 172 173 if (fd == -1 || pid != cpid) { 174 sprintf(buf, "/proc/%d/regs", pid); 175 fd = open(buf, O_RDONLY); 176 if (fd == -1) { 177 fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 178 return; 179 } 180 cpid = pid; 181 } 182 183 lseek(fd, 0L, 0); 184 if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) 185 return; 186 187 retval = regs.r_eax; 188 errorp = !!(regs.r_eflags & PSL_C); 189 190 sc = lsc.sc; 191 if (!sc) { 192 for (i = 0; i < lsc.nargs; i++) { 193 lsc.s_args[i] = malloc(12); 194 sprintf(lsc.s_args[i], "0x%x", lsc.args[i]); 195 } 196 } else { 197 for (i = 0; i < sc->nargs; i++) { 198 char *temp; 199 if (sc->args[i].type & OUT) { 200 if (errorp) { 201 temp = malloc(12); 202 sprintf(temp, "0x%x", lsc.args[sc->args[i].offset]); 203 } else { 204 temp = print_arg(Procfd, &sc->args[i], lsc.args); 205 } 206 lsc.s_args[i] = temp; 207 } 208 } 209 } 210 print_syscall(outfile, lsc.name, lsc.nargs, lsc.s_args); 211 if (errorp) { 212 for (i = 0; i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) 213 if (retval == bsd_to_linux_errno[i]) 214 break; 215 fprintf(outfile, "errno %d '%s'\n", retval, strerror(i)); 216 } else { 217 fprintf(outfile, "returns %d (0x%x)\n", retval, retval); 218 } 219 clear_lsc(); 220 return; 221} 222