i386-fbsd.c revision 101423
143939Sabial/*
246493Sabial * Copryight 1997 Sean Eric Fagan
343939Sabial *
443939Sabial * Redistribution and use in source and binary forms, with or without
543939Sabial * modification, are permitted provided that the following conditions
643939Sabial * are met:
746493Sabial * 1. Redistributions of source code must retain the above copyright
846493Sabial *    notice, this list of conditions and the following disclaimer.
943939Sabial * 2. Redistributions in binary form must reproduce the above copyright
1043939Sabial *    notice, this list of conditions and the following disclaimer in the
1143939Sabial *    documentation and/or other materials provided with the distribution.
1243939Sabial * 3. All advertising materials mentioning features or use of this software
1343939Sabial *    must display the following acknowledgement:
1443939Sabial *	This product includes software developed by Sean Eric Fagan
1543939Sabial * 4. Neither the name of the author may be used to endorse or promote
1643939Sabial *    products derived from this software without specific prior written
1743939Sabial *    permission.
1843939Sabial *
1943939Sabial * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2043939Sabial * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2143939Sabial * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2243939Sabial * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2343939Sabial * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2443939Sabial * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2543939Sabial * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2643939Sabial * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2743939Sabial * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2843939Sabial * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2943939Sabial * SUCH DAMAGE.
3046493Sabial */
3138589Sabial
3238589Sabial#ifndef lint
3338589Sabialstatic const char rcsid[] =
3438589Sabial  "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 101423 2002-08-06 12:46:14Z mdodd $";
3538589Sabial#endif /* not lint */
3638589Sabial
3746493Sabial/*
3838589Sabial * FreeBSD/386-specific system call handling.  This is probably the most
3938589Sabial * complex part of the entire truss program, although I've got lots of
4046493Sabial * it handled relatively cleanly now.  The system call names are generated
4146493Sabial * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
4238589Sabial * names used for the various structures are confusing, I sadly admit.
4346493Sabial */
4446493Sabial
4546493Sabial#include <sys/types.h>
4638589Sabial#include <sys/ioctl.h>
4746493Sabial#include <sys/pioctl.h>
4846493Sabial#include <sys/syscall.h>
4938589Sabial
5046493Sabial#include <machine/reg.h>
5146493Sabial#include <machine/psl.h>
5246493Sabial
5338589Sabial#include <errno.h>
5446493Sabial#include <fcntl.h>
5546493Sabial#include <signal.h>
5646493Sabial#include <stdio.h>
5746493Sabial#include <stdlib.h>
5838589Sabial#include <string.h>
5946493Sabial#include <time.h>
6038589Sabial#include <unistd.h>
6146493Sabial
6238589Sabial#include "truss.h"
6346493Sabial#include "syscall.h"
6446493Sabial
6546493Sabialstatic int fd = -1;
6646493Sabialstatic int cpid = -1;
6746493Sabialextern int Procfd;
6846493Sabial
6946493Sabial#include "syscalls.h"
7046493Sabial
7146493Sabialstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
7246493Sabial
7346493Sabial/*
7446493Sabial * This is what this particular file uses to keep track of a system call.
7546493Sabial * It is probably not quite sufficient -- I can probably use the same
7646493Sabial * structure for the various syscall personalities, and I also probably
7746493Sabial * need to nest system calls (for signal handlers).
7846493Sabial *
7946493Sabial * 'struct syscall' describes the system call; it may be NULL, however,
8046493Sabial * if we don't know about this particular system call yet.
8146493Sabial */
8246493Sabialstatic struct freebsd_syscall {
8346493Sabial	struct syscall *sc;
8438589Sabial	char *name;
8538589Sabial	int number;
8638589Sabial	unsigned long *args;
8738589Sabial	int nargs;	/* number of arguments -- *not* number of words! */
8838589Sabial	char **s_args;	/* the printable arguments */
8938589Sabial} fsc;
9038589Sabial
9138589Sabial/* Clear up and free parts of the fsc structure. */
9238589Sabialstatic __inline void
9338589Sabialclear_fsc() {
9438589Sabial  if (fsc.args) {
9538589Sabial    free(fsc.args);
9638589Sabial  }
9738589Sabial  if (fsc.s_args) {
9838589Sabial    int i;
9938589Sabial    for (i = 0; i < fsc.nargs; i++)
10038589Sabial      if (fsc.s_args[i])
10138589Sabial	free(fsc.s_args[i]);
10246493Sabial    free(fsc.s_args);
10338589Sabial  }
10438589Sabial  memset(&fsc, 0, sizeof(fsc));
10546493Sabial}
10646493Sabial
10746493Sabial/*
10846493Sabial * Called when a process has entered a system call.  nargs is the
10938589Sabial * number of words, not number of arguments (a necessary distinction
11038589Sabial * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
11138589Sabial * is ever changed these functions need to keep up.
11238589Sabial */
11338589Sabial
11438589Sabialvoid
11538589Sabiali386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
11638589Sabial  char buf[32];
11738589Sabial  struct reg regs = { 0 };
11838589Sabial  int syscall;
11938589Sabial  int i;
12038589Sabial  unsigned int parm_offset;
12146493Sabial  struct syscall *sc;
12246493Sabial
12346493Sabial  if (fd == -1 || trussinfo->pid != cpid) {
12446493Sabial    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
12538589Sabial    fd = open(buf, O_RDWR);
12638589Sabial    if (fd == -1) {
12738589Sabial      fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
12838589Sabial      return;
12938589Sabial    }
13038589Sabial    cpid = trussinfo->pid;
13138589Sabial  }
13246493Sabial
13338589Sabial  clear_fsc();
13438589Sabial  lseek(fd, 0L, 0);
13546493Sabial  i = read(fd, &regs, sizeof(regs));
13646493Sabial  parm_offset = regs.r_esp + sizeof(int);
13746493Sabial
13846493Sabial  /*
13946493Sabial   * FreeBSD has two special kinds of system call redirctions --
14046493Sabial   * SYS_syscall, and SYS___syscall.  The former is the old syscall()
14146493Sabial   * routine, basicly; the latter is for quad-aligned arguments.
14246493Sabial   */
14338589Sabial  syscall = regs.r_eax;
14438589Sabial  switch (syscall) {
14546493Sabial  case SYS_syscall:
14646493Sabial    lseek(Procfd, parm_offset, SEEK_SET);
14746493Sabial    read(Procfd, &syscall, sizeof(int));
14846493Sabial    parm_offset += sizeof(int);
14946493Sabial    break;
15038589Sabial  case SYS___syscall:
15146493Sabial    lseek(Procfd, parm_offset, SEEK_SET);
15246493Sabial    read(Procfd, &syscall, sizeof(int));
15346493Sabial    parm_offset += sizeof(quad_t);
15446493Sabial    break;
15546493Sabial  }
15638589Sabial
15746493Sabial  fsc.number = syscall;
15846493Sabial  fsc.name =
15946493Sabial    (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall];
16046493Sabial  if (!fsc.name) {
16146493Sabial    fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall);
16246493Sabial  }
16346493Sabial
16446493Sabial  if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
16546493Sabial   && ((!strcmp(fsc.name, "fork")
16646493Sabial    || !strcmp(fsc.name, "rfork")
16746493Sabial    || !strcmp(fsc.name, "vfork"))))
16846493Sabial  {
16946493Sabial    trussinfo->in_fork = 1;
17038589Sabial  }
17146493Sabial
17246493Sabial  if (nargs == 0)
17346493Sabial    return;
17446493Sabial
17546493Sabial  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
17646493Sabial  lseek(Procfd, parm_offset, SEEK_SET);
17746493Sabial  if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
17846493Sabial    return;
17946493Sabial
18046493Sabial  sc = get_syscall(fsc.name);
18146493Sabial  if (sc) {
18246493Sabial    fsc.nargs = sc->nargs;
18346493Sabial  } else {
18446493Sabial#if DEBUG
18546493Sabial    fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
18638589Sabial	   fsc.name, nargs);
18738589Sabial#endif
18846493Sabial    fsc.nargs = nargs;
18946493Sabial  }
19046493Sabial
19146493Sabial  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
19246493Sabial  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
19338589Sabial  fsc.sc = sc;
19446493Sabial
19546493Sabial  /*
19646493Sabial   * At this point, we set up the system call arguments.
19746493Sabial   * We ignore any OUT ones, however -- those are arguments that
19838589Sabial   * are set by the system call, and so are probably meaningless
19946493Sabial   * now.  This doesn't currently support arguments that are
20038589Sabial   * passed in *and* out, however.
20138589Sabial   */
20246493Sabial
20338589Sabial  if (fsc.name) {
20438589Sabial
20538589Sabial#if DEBUG
20638589Sabial    fprintf(stderr, "syscall %s(", fsc.name);
20738589Sabial#endif
20838589Sabial    for (i = 0; i < fsc.nargs; i++) {
20946493Sabial#if DEBUG
21038589Sabial      fprintf(stderr, "0x%x%s",
21146493Sabial	      sc
21238589Sabial	      ? fsc.args[sc->args[i].offset]
21346493Sabial	      : fsc.args[i],
21446493Sabial	      i < (fsc.nargs - 1) ? "," : "");
21546493Sabial#endif
21646493Sabial      if (sc && !(sc->args[i].type & OUT)) {
21746493Sabial	fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
21846493Sabial      }
21938589Sabial    }
22046493Sabial#if DEBUG
22146493Sabial    fprintf(stderr, ")\n");
22238589Sabial#endif
22346493Sabial  }
22446493Sabial
22546493Sabial#if DEBUG
22646493Sabial  fprintf(trussinfo->outfile, "\n");
22746493Sabial#endif
22838589Sabial
22938589Sabial  /*
23038589Sabial   * Some system calls should be printed out before they are done --
23138589Sabial   * execve() and exit(), for example, never return.  Possibly change
23238589Sabial   * this to work for any system call that doesn't have an OUT
23346493Sabial   * parameter?
23438589Sabial   */
23538589Sabial
23638589Sabial  if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) {
23746493Sabial
23846493Sabial    /* XXX
23946493Sabial     * This could be done in a more general
24038589Sabial     * manner but it still wouldn't be very pretty.
24138589Sabial     */
24238589Sabial    if (!strcmp(fsc.name, "execve")) {
24338589Sabial        if ((trussinfo->flags & EXECVEARGS) == 0)
24438589Sabial          if (fsc.s_args[1]) {
24538589Sabial            free(fsc.s_args[1]);
24638589Sabial            fsc.s_args[1] = NULL;
24738589Sabial          }
24838589Sabial        if ((trussinfo->flags & EXECVEENVS) == 0)
24946493Sabial          if (fsc.s_args[2]) {
25046493Sabial            free(fsc.s_args[2]);
25146493Sabial            fsc.s_args[2] = NULL;
25238589Sabial          }
25338589Sabial    }
25438589Sabial
25538589Sabial    print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args);
25646493Sabial    fprintf(trussinfo->outfile, "\n");
25746493Sabial  }
25846493Sabial
25946493Sabial  return;
26046493Sabial}
26146493Sabial
26238589Sabial/*
26338589Sabial * And when the system call is done, we handle it here.
26438589Sabial * Currently, no attempt is made to ensure that the system calls
26538589Sabial * match -- this needs to be fixed (and is, in fact, why S_SCX includes
26638589Sabial * the sytem call number instead of, say, an error status).
26738589Sabial */
26846493Sabial
26946493Sabialint
27046493Sabiali386_syscall_exit(struct trussinfo *trussinfo, int syscall) {
27138589Sabial  char buf[32];
27246493Sabial  struct reg regs;
27346493Sabial  int retval;
27446493Sabial  int i;
27538589Sabial  int errorp;
27638589Sabial  struct syscall *sc;
27746493Sabial
27846493Sabial  if (fd == -1 || trussinfo->pid != cpid) {
27946493Sabial    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
28046493Sabial    fd = open(buf, O_RDONLY);
28146493Sabial    if (fd == -1) {
28246493Sabial      fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
28346493Sabial      return;
28446493Sabial    }
28538589Sabial    cpid = trussinfo->pid;
28638589Sabial  }
28746493Sabial
28846493Sabial  lseek(fd, 0L, 0);
28946493Sabial  if (read(fd, &regs, sizeof(regs)) != sizeof(regs)) {
29038589Sabial    fprintf(trussinfo->outfile, "\n");
29146493Sabial    return;
29246493Sabial  }
29346493Sabial  retval = regs.r_eax;
29446493Sabial  errorp = !!(regs.r_eflags & PSL_C);
29546493Sabial
29646493Sabial  /*
29738589Sabial   * This code, while simpler than the initial versions I used, could
29846493Sabial   * stand some significant cleaning.
29946493Sabial   */
30046493Sabial
30146493Sabial  sc = fsc.sc;
30246493Sabial  if (!sc) {
30346493Sabial    for (i = 0; i < fsc.nargs; i++) {
30446493Sabial      fsc.s_args[i] = malloc(12);
30538589Sabial      sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]);
30646493Sabial    }
30746493Sabial  } else {
30846493Sabial    /*
30946493Sabial     * Here, we only look for arguments that have OUT masked in --
31046493Sabial     * otherwise, they were handled in the syscall_entry function.
31138589Sabial     */
31246493Sabial    for (i = 0; i < sc->nargs; i++) {
31338589Sabial      char *temp;
31446493Sabial      if (sc->args[i].type & OUT) {
31546493Sabial	/*
31646493Sabial	 * If an error occurred, than don't bothe getting the data;
31746493Sabial	 * it may not be valid.
31846493Sabial	 */
31946493Sabial	if (errorp) {
32046493Sabial	  temp = malloc(12);
32146493Sabial	  sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]);
32246493Sabial	} else {
32346493Sabial	  temp = print_arg(Procfd, &sc->args[i], fsc.args);
32446493Sabial	}
32546493Sabial	fsc.s_args[i] = temp;
32646493Sabial      }
32746493Sabial    }
32846493Sabial  }
32946493Sabial
33046493Sabial  /*
33146493Sabial   * It would probably be a good idea to merge the error handling,
33238589Sabial   * but that complicates things considerably.
33346493Sabial   */
33438589Sabial
33546493Sabial  print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
33646493Sabial  clear_fsc();
33738589Sabial
33838589Sabial  return (retval);
33946493Sabial}
34038589Sabial