i386-fbsd.c revision 100357
155714Skris/* 2280304Sjkim * Copryight 1997 Sean Eric Fagan 3280304Sjkim * 4280304Sjkim * Redistribution and use in source and binary forms, with or without 555714Skris * modification, are permitted provided that the following conditions 655714Skris * are met: 755714Skris * 1. Redistributions of source code must retain the above copyright 855714Skris * notice, this list of conditions and the following disclaimer. 955714Skris * 2. Redistributions in binary form must reproduce the above copyright 1055714Skris * notice, this list of conditions and the following disclaimer in the 1155714Skris * documentation and/or other materials provided with the distribution. 1255714Skris * 3. All advertising materials mentioning features or use of this software 1355714Skris * must display the following acknowledgement: 14280304Sjkim * This product includes software developed by Sean Eric Fagan 1555714Skris * 4. Neither the name of the author may be used to endorse or promote 1655714Skris * products derived from this software without specific prior written 1755714Skris * permission. 1855714Skris * 1955714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2055714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2155714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2255714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2355714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2455714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2555714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2655714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2755714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2855714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2955714Skris * SUCH DAMAGE. 3055714Skris */ 3155714Skris 3255714Skris#ifndef lint 3355714Skrisstatic const char rcsid[] = 3455714Skris "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 100357 2002-07-19 13:49:37Z markm $"; 3555714Skris#endif /* not lint */ 3655714Skris 3755714Skris/* 3855714Skris * FreeBSD/386-specific system call handling. This is probably the most 3955714Skris * complex part of the entire truss program, although I've got lots of 4055714Skris * it handled relatively cleanly now. The system call names are generated 4155714Skris * automatically, thanks to /usr/src/sys/kern/syscalls.master. The 4255714Skris * names used for the various structures are confusing, I sadly admit. 4355714Skris */ 4455714Skris 4555714Skris#include <sys/types.h> 4655714Skris#include <sys/ioctl.h> 4755714Skris#include <sys/pioctl.h> 4855714Skris#include <sys/syscall.h> 4955714Skris 5055714Skris#include <machine/reg.h> 5155714Skris#include <machine/psl.h> 5255714Skris 5355714Skris#include <errno.h> 5455714Skris#include <fcntl.h> 5555714Skris#include <signal.h> 5655714Skris#include <stdio.h> 5755714Skris#include <stdlib.h> 5855714Skris#include <string.h> 5955714Skris#include <unistd.h> 6055714Skris 6155714Skris#include "syscall.h" 6255714Skris 6355714Skrisstatic int fd = -1; 6455714Skrisstatic int cpid = -1; 6555714Skrisextern int Procfd; 6655714Skris 6755714Skrisextern FILE *outfile; 68280304Sjkim#include "syscalls.h" 69280304Sjkim 70109998Smarkmstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]); 7155714Skris 7255714Skris/* 73280304Sjkim * This is what this particular file uses to keep track of a system call. 74280304Sjkim * It is probably not quite sufficient -- I can probably use the same 7555714Skris * structure for the various syscall personalities, and I also probably 76280304Sjkim * need to nest system calls (for signal handlers). 77280304Sjkim * 78280304Sjkim * 'struct syscall' describes the system call; it may be NULL, however, 79280304Sjkim * if we don't know about this particular system call yet. 80280304Sjkim */ 81280304Sjkimstatic struct freebsd_syscall { 82280304Sjkim struct syscall *sc; 83280304Sjkim char *name; 84280304Sjkim int number; 85280304Sjkim unsigned long *args; 86280304Sjkim int nargs; /* number of arguments -- *not* number of words! */ 87280304Sjkim char **s_args; /* the printable arguments */ 88280304Sjkim} fsc; 89280304Sjkim 90280304Sjkim/* Clear up and free parts of the fsc structure. */ 91280304Sjkimstatic __inline void 92280304Sjkimclear_fsc() { 93280304Sjkim if (fsc.args) { 94280304Sjkim free(fsc.args); 9559191Skris } 96280304Sjkim if (fsc.s_args) { 97280304Sjkim int i; 9859191Skris for (i = 0; i < fsc.nargs; i++) 99280304Sjkim if (fsc.s_args[i]) 100280304Sjkim free(fsc.s_args[i]); 101280304Sjkim free(fsc.s_args); 102280304Sjkim } 103280304Sjkim memset(&fsc, 0, sizeof(fsc)); 104280304Sjkim} 105280304Sjkim 106280304Sjkim/* 107280304Sjkim * Called when a process has entered a system call. nargs is the 108280304Sjkim * number of words, not number of arguments (a necessary distinction 109280304Sjkim * in some cases). Note that if the STOPEVENT() code in i386/i386/trap.c 11059191Skris * is ever changed these functions need to keep up. 111280304Sjkim */ 112280304Sjkim 113280304Sjkimvoid 11455714Skrisi386_syscall_entry(int pid, int nargs) { 11555714Skris char buf[32]; 11655714Skris struct reg regs = { 0 }; 11755714Skris int syscall; 118280304Sjkim int i; 119280304Sjkim unsigned int parm_offset; 12055714Skris struct syscall *sc; 121280304Sjkim 122280304Sjkim if (fd == -1 || pid != cpid) { 123280304Sjkim sprintf(buf, "/proc/%d/regs", pid); 124280304Sjkim fd = open(buf, O_RDWR); 125280304Sjkim if (fd == -1) { 126280304Sjkim fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 127160814Ssimon return; 128280304Sjkim } 129280304Sjkim cpid = pid; 130280304Sjkim } 131280304Sjkim 132280304Sjkim clear_fsc(); 133280304Sjkim lseek(fd, 0L, 0); 134280304Sjkim i = read(fd, ®s, sizeof(regs)); 135280304Sjkim parm_offset = regs.r_esp + sizeof(int); 136280304Sjkim 137109998Smarkm /* 138280304Sjkim * FreeBSD has two special kinds of system call redirctions -- 139280304Sjkim * SYS_syscall, and SYS___syscall. The former is the old syscall() 140109998Smarkm * routine, basicly; the latter is for quad-aligned arguments. 141280304Sjkim */ 142280304Sjkim syscall = regs.r_eax; 143280304Sjkim switch (syscall) { 144280304Sjkim case SYS_syscall: 145280304Sjkim lseek(Procfd, parm_offset, SEEK_SET); 14659191Skris read(Procfd, &syscall, sizeof(int)); 147280304Sjkim parm_offset += sizeof(int); 14859191Skris break; 149280304Sjkim case SYS___syscall: 150280304Sjkim lseek(Procfd, parm_offset, SEEK_SET); 151280304Sjkim read(Procfd, &syscall, sizeof(int)); 152280304Sjkim parm_offset += sizeof(quad_t); 153280304Sjkim break; 154280304Sjkim } 155280304Sjkim 156280304Sjkim fsc.number = syscall; 157280304Sjkim fsc.name = 158280304Sjkim (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall]; 159280304Sjkim if (!fsc.name) { 16059191Skris fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall); 161280304Sjkim } 162280304Sjkim 163280304Sjkim if (nargs == 0) 164280304Sjkim return; 165280304Sjkim 166280304Sjkim fsc.args = malloc((1+nargs) * sizeof(unsigned long)); 167280304Sjkim lseek(Procfd, parm_offset, SEEK_SET); 168280304Sjkim if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1) 169280304Sjkim return; 170280304Sjkim 171280304Sjkim sc = get_syscall(fsc.name); 172280304Sjkim if (sc) { 17355714Skris fsc.nargs = sc->nargs; 174280304Sjkim } else { 175280304Sjkim#if DEBUG 176280304Sjkim fprintf(outfile, "unknown syscall %s -- setting args to %d\n", 177280304Sjkim fsc.name, nargs); 178280304Sjkim#endif 179280304Sjkim fsc.nargs = nargs; 180280304Sjkim } 181280304Sjkim 182280304Sjkim fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*)); 18355714Skris memset(fsc.s_args, 0, fsc.nargs * sizeof(char*)); 18455714Skris fsc.sc = sc; 185280304Sjkim 186280304Sjkim /* 187280304Sjkim * At this point, we set up the system call arguments. 188109998Smarkm * We ignore any OUT ones, however -- those are arguments that 189280304Sjkim * are set by the system call, and so are probably meaningless 190109998Smarkm * now. This doesn't currently support arguments that are 191280304Sjkim * passed in *and* out, however. 192280304Sjkim */ 193109998Smarkm 194280304Sjkim if (fsc.name) { 195280304Sjkim 196280304Sjkim#if DEBUG 197280304Sjkim fprintf(stderr, "syscall %s(", fsc.name); 198109998Smarkm#endif 199280304Sjkim for (i = 0; i < fsc.nargs; i++) { 200280304Sjkim#if DEBUG 201280304Sjkim fprintf(stderr, "0x%x%s", 202280304Sjkim sc 203280304Sjkim ? fsc.args[sc->args[i].offset] 204280304Sjkim : fsc.args[i], 205280304Sjkim i < (fsc.nargs -1) ? "," : ""); 206280304Sjkim#endif 207280304Sjkim if (sc && !(sc->args[i].type & OUT)) { 208280304Sjkim fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args); 209280304Sjkim } 210280304Sjkim } 211280304Sjkim#if DEBUG 212280304Sjkim fprintf(stderr, ")\n"); 213280304Sjkim#endif 214280304Sjkim } 215280304Sjkim 216280304Sjkim#if DEBUG 217280304Sjkim fprintf(outfile, "\n"); 218109998Smarkm#endif 219109998Smarkm 220280304Sjkim /* 221280304Sjkim * Some system calls should be printed out before they are done -- 222109998Smarkm * execve() and exit(), for example, never return. Possibly change 223280304Sjkim * this to work for any system call that doesn't have an OUT 224109998Smarkm * parameter? 225280304Sjkim */ 226280304Sjkim 227109998Smarkm if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) { 228280304Sjkim print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args); 229280304Sjkim } 230280304Sjkim 231280304Sjkim return; 232280304Sjkim} 233280304Sjkim 234109998Smarkm/* 235280304Sjkim * And when the system call is done, we handle it here. 236280304Sjkim * Currently, no attempt is made to ensure that the system calls 237280304Sjkim * match -- this needs to be fixed (and is, in fact, why S_SCX includes 238280304Sjkim * the sytem call number instead of, say, an error status). 239280304Sjkim */ 240280304Sjkim 241280304Sjkimvoid 242109998Smarkmi386_syscall_exit(int pid, int syscall) { 243280304Sjkim char buf[32]; 244280304Sjkim struct reg regs; 245280304Sjkim int retval; 246109998Smarkm int i; 247109998Smarkm int errorp; 248109998Smarkm struct syscall *sc; 24955714Skris 25055714Skris if (fd == -1 || pid != cpid) { 251280304Sjkim sprintf(buf, "/proc/%d/regs", pid); 252280304Sjkim fd = open(buf, O_RDONLY); 253280304Sjkim if (fd == -1) { 254280304Sjkim fprintf(outfile, "-- CANNOT READ REGISTERS --\n"); 255280304Sjkim return; 256280304Sjkim } 257280304Sjkim cpid = pid; 25855714Skris } 25955714Skris 260 lseek(fd, 0L, 0); 261 if (read(fd, ®s, sizeof(regs)) != sizeof(regs)) 262 return; 263 retval = regs.r_eax; 264 errorp = !!(regs.r_eflags & PSL_C); 265 266 /* 267 * This code, while simpler than the initial versions I used, could 268 * stand some significant cleaning. 269 */ 270 271 sc = fsc.sc; 272 if (!sc) { 273 for (i = 0; i < fsc.nargs; i++) { 274 fsc.s_args[i] = malloc(12); 275 sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]); 276 } 277 } else { 278 /* 279 * Here, we only look for arguments that have OUT masked in -- 280 * otherwise, they were handled in the syscall_entry function. 281 */ 282 for (i = 0; i < sc->nargs; i++) { 283 char *temp; 284 if (sc->args[i].type & OUT) { 285 /* 286 * If an error occurred, than don't bothe getting the data; 287 * it may not be valid. 288 */ 289 if (errorp) { 290 temp = malloc(12); 291 sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]); 292 } else { 293 temp = print_arg(Procfd, &sc->args[i], fsc.args); 294 } 295 fsc.s_args[i] = temp; 296 } 297 } 298 } 299 300 /* 301 * It would probably be a good idea to merge the error handling, 302 * but that complicates things considerably. 303 */ 304 305 print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval); 306 clear_fsc(); 307 308 return; 309} 310