i386-linux.c revision 106713
1/* 2 * Copryight 1997 Sean Eric Fagan 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Sean Eric Fagan 15 * 4. Neither the name of the author may be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#ifndef lint 33static const char rcsid[] = 34 "$FreeBSD: head/usr.bin/truss/i386-linux.c 106713 2002-11-09 22:46:51Z dwmalone $"; 35#endif /* not lint */ 36 37/* 38 * Linux/i386-specific system call handling. Given how much of this code 39 * is taken from the freebsd equivalent, I can probably put even more of 40 * it in support routines that can be used by any personality support. 41 */ 42 43#include <sys/types.h> 44#include <sys/ioctl.h> 45#include <sys/pioctl.h> 46 47#include <machine/reg.h> 48#include <machine/psl.h> 49 50#include <errno.h> 51#include <fcntl.h> 52#include <signal.h> 53#include <stdio.h> 54#include <stdlib.h> 55#include <string.h> 56#include <time.h> 57#include <unistd.h> 58 59#include "truss.h" 60#include "syscall.h" 61#include "extern.h" 62 63static int fd = -1; 64static int cpid = -1; 65extern int Procfd; 66 67#include "linux_syscalls.h" 68 69static int nsyscalls = 70 sizeof(linux_syscallnames) / sizeof(linux_syscallnames[0]); 71 72/* 73 * This is what this particular file uses to keep track of a system call. 74 * It is probably not quite sufficient -- I can probably use the same 75 * structure for the various syscall personalities, and I also probably 76 * need to nest system calls (for signal handlers). 77 * 78 * 'struct syscall' describes the system call; it may be NULL, however, 79 * if we don't know about this particular system call yet. 80 */ 81static struct linux_syscall { 82 struct syscall *sc; 83 const char *name; 84 int number; 85 unsigned long args[5]; 86 int nargs; /* number of arguments -- *not* number of words! */ 87 char **s_args; /* the printable arguments */ 88} fsc; 89 90/* Clear up and free parts of the fsc structure. */ 91static __inline void 92clear_fsc(void) { 93 if (fsc.s_args) { 94 int i; 95 for (i = 0; i < fsc.nargs; i++) 96 if (fsc.s_args[i]) 97 free(fsc.s_args[i]); 98 free(fsc.s_args); 99 } 100 memset(&fsc, 0, sizeof(fsc)); 101} 102 103/* 104 * Called when a process has entered a system call. nargs is the 105 * number of words, not number of arguments (a necessary distinction 106 * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 107 * is ever changed these functions need to keep up. 108 */ 109 110void 111i386_linux_syscall_entry(struct trussinfo *trussinfo, int nargs) { 112 char buf[32]; 113 struct reg regs; 114 int syscall_num; 115 int i; 116 struct syscall *sc; 117 118 if (fd == -1 || trussinfo->pid != cpid) { 119 sprintf(buf, "/proc/%d/regs", trussinfo->pid); 120 fd = open(buf, O_RDWR); 121 if (fd == -1) { 122 fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 123 return; 124 } 125 cpid = trussinfo->pid; 126 } 127 128 clear_fsc(); 129 lseek(fd, 0L, 0); 130 if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 131 fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n"); 132 return; 133 } 134 syscall_num = regs.r_eax; 135 136 fsc.number = syscall_num; 137 fsc.name = 138 (syscall_num < 0 || syscall_num > nsyscalls) ? NULL : linux_syscallnames[syscall_num]; 139 if (!fsc.name) { 140 fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num); 141 } 142 143 if (fsc.name && (trussinfo->flags & FOLLOWFORKS) 144 && ((!strcmp(fsc.name, "linux_fork") 145 || !strcmp(fsc.name, "linux_vfork")))) 146 { 147 trussinfo->in_fork = 1; 148 } 149 150 if (nargs == 0) 151 return; 152 153 /* 154 * Linux passes syscall arguments in registers, not 155 * on the stack. Fortunately, we've got access to the 156 * register set. Note that we don't bother checking the 157 * number of arguments. And what does linux do for syscalls 158 * that have more than five arguments? 159 */ 160 161 fsc.args[0] = regs.r_ebx; 162 fsc.args[1] = regs.r_ecx; 163 fsc.args[2] = regs.r_edx; 164 fsc.args[3] = regs.r_esi; 165 fsc.args[4] = regs.r_edi; 166 167 sc = get_syscall(fsc.name); 168 if (sc) { 169 fsc.nargs = sc->nargs; 170 } else { 171#if DEBUG 172 fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n", 173 fsc.name, nargs); 174#endif 175 fsc.nargs = nargs; 176 } 177 178 fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 179 memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 180 fsc.sc = sc; 181 182 /* 183 * At this point, we set up the system call arguments. 184 * We ignore any OUT ones, however -- those are arguments that 185 * are set by the system call, and so are probably meaningless 186 * now. This doesn't currently support arguments that are 187 * passed in *and* out, however. 188 */ 189 190 if (fsc.name) { 191 192#if DEBUG 193 fprintf(stderr, "syscall %s(", fsc.name); 194#endif 195 for (i = 0; i < fsc.nargs; i++) { 196#if DEBUG 197 fprintf(stderr, "0x%x%s", 198 sc 199 ? fsc.args[sc->args[i].offset] 200 : fsc.args[i], 201 i < (fsc.nargs - 1) ? "," : ""); 202#endif 203 if (sc && !(sc->args[i].type & OUT)) { 204 fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 205 } 206 } 207#if DEBUG 208 fprintf(stderr, ")\n"); 209#endif 210 } 211 212#if DEBUG 213 fprintf(trussinfo->outfile, "\n"); 214#endif 215 216 /* 217 * Some system calls should be printed out before they are done -- 218 * execve() and exit(), for example, never return. Possibly change 219 * this to work for any system call that doesn't have an OUT 220 * parameter? 221 */ 222 223 if (!strcmp(fsc.name, "linux_execve") || !strcmp(fsc.name, "exit")) { 224 225 /* XXX 226 * This could be done in a more general 227 * manner but it still wouldn't be very pretty. 228 */ 229 if (!strcmp(fsc.name, "linux_execve")) { 230 if ((trussinfo->flags & EXECVEARGS) == 0) 231 if (fsc.s_args[1]) { 232 free(fsc.s_args[1]); 233 fsc.s_args[1] = NULL; 234 } 235 if ((trussinfo->flags & EXECVEENVS) == 0) 236 if (fsc.s_args[2]) { 237 free(fsc.s_args[2]); 238 fsc.s_args[2] = NULL; 239 } 240 } 241 242 print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args); 243 fprintf(trussinfo->outfile, "\n"); 244 } 245 246 return; 247} 248 249/* 250 * Linux syscalls return negative errno's, we do positive and map them 251 */ 252const int bsd_to_linux_errno[] = { 253 -0, -1, -2, -3, -4, -5, -6, -7, -8, -9, 254 -10, -35, -12, -13, -14, -15, -16, -17, -18, -19, 255 -20, -21, -22, -23, -24, -25, -26, -27, -28, -29, 256 -30, -31, -32, -33, -34, -11,-115,-114, -88, -89, 257 -90, -91, -92, -93, -94, -95, -96, -97, -98, -99, 258 -100,-101,-102,-103,-104,-105,-106,-107,-108,-109, 259 -110,-111, -40, -36,-112,-113, -39, -11, -87,-122, 260 -116, -66, -6, -6, -6, -6, -6, -37, -38, -9, 261 -6, 262}; 263 264int 265i386_linux_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) { 266 char buf[32]; 267 struct reg regs; 268 int retval; 269 int i; 270 int errorp; 271 struct syscall *sc; 272 273 if (fd == -1 || trussinfo->pid != cpid) { 274 sprintf(buf, "/proc/%d/regs", trussinfo->pid); 275 fd = open(buf, O_RDONLY); 276 if (fd == -1) { 277 fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n"); 278 return (-1); 279 } 280 cpid = trussinfo->pid; 281 } 282 283 lseek(fd, 0L, 0); 284 if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) { 285 fprintf(trussinfo->outfile, "\n"); 286 return (-1); 287 } 288 retval = regs.r_eax; 289 errorp = !!(regs.r_eflags & PSL_C); 290 291 /* 292 * This code, while simpler than the initial versions I used, could 293 * stand some significant cleaning. 294 */ 295 296 sc = fsc.sc; 297 if (!sc) { 298 for (i = 0; i < fsc.nargs; i++) { 299 fsc.s_args[i] = malloc(12); 300 sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 301 } 302 } else { 303 /* 304 * Here, we only look for arguments that have OUT masked in -- 305 * otherwise, they were handled in the syscall_entry function. 306 */ 307 for (i = 0; i < sc->nargs; i++) { 308 char *temp; 309 if (sc->args[i].type & OUT) { 310 /* 311 * If an error occurred, than don't bothe getting the data; 312 * it may not be valid. 313 */ 314 if (errorp) { 315 temp = malloc(12); 316 sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 317 } else { 318 temp = print_arg(Procfd, &sc->args[i], fsc.args); 319 } 320 fsc.s_args[i] = temp; 321 } 322 } 323 } 324 325 /* 326 * It would probably be a good idea to merge the error handling, 327 * but that complicates things considerably. 328 */ 329 if (errorp) { 330 for (i = 0; (size_t)i < sizeof(bsd_to_linux_errno) / sizeof(int); i++) 331 if (retval == bsd_to_linux_errno[i]) 332 break; 333 } 334 print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, 335 errorp ? i : retval); 336 clear_fsc(); 337 338 return (retval); 339} 340