i386-fbsd.c revision 101283
131567Ssef/*
231899Ssef * Copryight 1997 Sean Eric Fagan
331899Ssef *
431899Ssef * Redistribution and use in source and binary forms, with or without
531899Ssef * modification, are permitted provided that the following conditions
631899Ssef * are met:
731899Ssef * 1. Redistributions of source code must retain the above copyright
831899Ssef *    notice, this list of conditions and the following disclaimer.
931899Ssef * 2. Redistributions in binary form must reproduce the above copyright
1031899Ssef *    notice, this list of conditions and the following disclaimer in the
1131899Ssef *    documentation and/or other materials provided with the distribution.
1231899Ssef * 3. All advertising materials mentioning features or use of this software
1331899Ssef *    must display the following acknowledgement:
1431899Ssef *	This product includes software developed by Sean Eric Fagan
1531899Ssef * 4. Neither the name of the author may be used to endorse or promote
1631899Ssef *    products derived from this software without specific prior written
1731899Ssef *    permission.
1831899Ssef *
1931899Ssef * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2031899Ssef * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2131899Ssef * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2231899Ssef * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2331899Ssef * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2431899Ssef * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2531899Ssef * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2631899Ssef * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2731899Ssef * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2831899Ssef * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2931899Ssef * SUCH DAMAGE.
3031899Ssef */
3131899Ssef
3232275Scharnier#ifndef lint
3332275Scharnierstatic const char rcsid[] =
3450477Speter  "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 101283 2002-08-04 01:02:52Z mdodd $";
3532275Scharnier#endif /* not lint */
3632275Scharnier
3731899Ssef/*
3831567Ssef * FreeBSD/386-specific system call handling.  This is probably the most
3931567Ssef * complex part of the entire truss program, although I've got lots of
4031567Ssef * it handled relatively cleanly now.  The system call names are generated
4131567Ssef * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
4231567Ssef * names used for the various structures are confusing, I sadly admit.
4331567Ssef */
4431567Ssef
4585301Sdes#include <sys/types.h>
4685301Sdes#include <sys/ioctl.h>
4785301Sdes#include <sys/pioctl.h>
4885301Sdes#include <sys/syscall.h>
4985301Sdes
5085301Sdes#include <machine/reg.h>
5185301Sdes#include <machine/psl.h>
5285301Sdes
5332275Scharnier#include <errno.h>
5432275Scharnier#include <fcntl.h>
5532275Scharnier#include <signal.h>
5631567Ssef#include <stdio.h>
5731567Ssef#include <stdlib.h>
5831567Ssef#include <string.h>
5931567Ssef#include <unistd.h>
6031567Ssef
61101282Smdodd#include "truss.h"
6231567Ssef#include "syscall.h"
6331567Ssef
6431567Ssefstatic int fd = -1;
6531567Ssefstatic int cpid = -1;
6631567Ssefextern int Procfd;
6731567Ssef
6831567Ssef#include "syscalls.h"
6931567Ssef
7031567Ssefstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
7131567Ssef
7231567Ssef/*
7331567Ssef * This is what this particular file uses to keep track of a system call.
7431567Ssef * It is probably not quite sufficient -- I can probably use the same
7531567Ssef * structure for the various syscall personalities, and I also probably
7631567Ssef * need to nest system calls (for signal handlers).
7731567Ssef *
7831567Ssef * 'struct syscall' describes the system call; it may be NULL, however,
7931567Ssef * if we don't know about this particular system call yet.
8031567Ssef */
8131567Ssefstatic struct freebsd_syscall {
8231567Ssef	struct syscall *sc;
8331567Ssef	char *name;
8431567Ssef	int number;
8531567Ssef	unsigned long *args;
8631567Ssef	int nargs;	/* number of arguments -- *not* number of words! */
8731567Ssef	char **s_args;	/* the printable arguments */
8831567Ssef} fsc;
8931567Ssef
9031567Ssef/* Clear up and free parts of the fsc structure. */
91100357Smarkmstatic __inline void
9231567Ssefclear_fsc() {
9331567Ssef  if (fsc.args) {
9431567Ssef    free(fsc.args);
9531567Ssef  }
9631567Ssef  if (fsc.s_args) {
9731567Ssef    int i;
9831567Ssef    for (i = 0; i < fsc.nargs; i++)
9931567Ssef      if (fsc.s_args[i])
10031567Ssef	free(fsc.s_args[i]);
10131567Ssef    free(fsc.s_args);
10231567Ssef  }
10331567Ssef  memset(&fsc, 0, sizeof(fsc));
10431567Ssef}
10531567Ssef
10631567Ssef/*
10731567Ssef * Called when a process has entered a system call.  nargs is the
10831567Ssef * number of words, not number of arguments (a necessary distinction
10931567Ssef * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
11031567Ssef * is ever changed these functions need to keep up.
11131567Ssef */
11231567Ssef
11331567Ssefvoid
114101282Smdoddi386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
11531567Ssef  char buf[32];
11631567Ssef  struct reg regs = { 0 };
11731567Ssef  int syscall;
11831567Ssef  int i;
11931567Ssef  unsigned int parm_offset;
12031567Ssef  struct syscall *sc;
12131567Ssef
122101282Smdodd  if (fd == -1 || trussinfo->pid != cpid) {
123101282Smdodd    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
12431567Ssef    fd = open(buf, O_RDWR);
12531567Ssef    if (fd == -1) {
126101282Smdodd      fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
12731567Ssef      return;
12831567Ssef    }
129101282Smdodd    cpid = trussinfo->pid;
13031567Ssef  }
13131567Ssef
13231567Ssef  clear_fsc();
13331567Ssef  lseek(fd, 0L, 0);
13431567Ssef  i = read(fd, &regs, sizeof(regs));
13531567Ssef  parm_offset = regs.r_esp + sizeof(int);
13631567Ssef
13731567Ssef  /*
13831567Ssef   * FreeBSD has two special kinds of system call redirctions --
13931567Ssef   * SYS_syscall, and SYS___syscall.  The former is the old syscall()
14031567Ssef   * routine, basicly; the latter is for quad-aligned arguments.
14131567Ssef   */
14231567Ssef  syscall = regs.r_eax;
14331567Ssef  switch (syscall) {
14431567Ssef  case SYS_syscall:
14531567Ssef    lseek(Procfd, parm_offset, SEEK_SET);
14631567Ssef    read(Procfd, &syscall, sizeof(int));
14731567Ssef    parm_offset += sizeof(int);
14831567Ssef    break;
14931567Ssef  case SYS___syscall:
15031567Ssef    lseek(Procfd, parm_offset, SEEK_SET);
15131567Ssef    read(Procfd, &syscall, sizeof(int));
15231567Ssef    parm_offset += sizeof(quad_t);
15331567Ssef    break;
15431567Ssef  }
15531567Ssef
15631567Ssef  fsc.number = syscall;
15731567Ssef  fsc.name =
15831567Ssef    (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall];
15931567Ssef  if (!fsc.name) {
160101282Smdodd    fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall);
16131567Ssef  }
16231567Ssef
163101283Smdodd  if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
164101283Smdodd   && ((!strcmp(fsc.name, "fork")
165101283Smdodd    || !strcmp(fsc.name, "rfork")
166101283Smdodd    || !strcmp(fsc.name, "vfork"))))
167101283Smdodd  {
168101283Smdodd    trussinfo->in_fork = 1;
169101283Smdodd  }
170101283Smdodd
17131567Ssef  if (nargs == 0)
17231567Ssef    return;
17331567Ssef
17431567Ssef  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
17531567Ssef  lseek(Procfd, parm_offset, SEEK_SET);
17631567Ssef  if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
17731567Ssef    return;
17831567Ssef
17931567Ssef  sc = get_syscall(fsc.name);
18031567Ssef  if (sc) {
18131567Ssef    fsc.nargs = sc->nargs;
18231567Ssef  } else {
18331567Ssef#if DEBUG
184101282Smdodd    fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
18531567Ssef	   fsc.name, nargs);
18631567Ssef#endif
18731567Ssef    fsc.nargs = nargs;
18831567Ssef  }
18931567Ssef
19031567Ssef  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
19131567Ssef  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
19231567Ssef  fsc.sc = sc;
19331567Ssef
19431567Ssef  /*
19531567Ssef   * At this point, we set up the system call arguments.
19631567Ssef   * We ignore any OUT ones, however -- those are arguments that
19731567Ssef   * are set by the system call, and so are probably meaningless
19831567Ssef   * now.  This doesn't currently support arguments that are
19931567Ssef   * passed in *and* out, however.
20031567Ssef   */
20131567Ssef
20231567Ssef  if (fsc.name) {
20331567Ssef
20431567Ssef#if DEBUG
20531567Ssef    fprintf(stderr, "syscall %s(", fsc.name);
20631567Ssef#endif
20731567Ssef    for (i = 0; i < fsc.nargs; i++) {
20831567Ssef#if DEBUG
20931567Ssef      fprintf(stderr, "0x%x%s",
21031567Ssef	     sc
21131567Ssef	     ? fsc.args[sc->args[i].offset]
21231567Ssef	     : fsc.args[i],
21331567Ssef	     i < (fsc.nargs -1) ? "," : "");
21431567Ssef#endif
21531567Ssef      if (sc && !(sc->args[i].type & OUT)) {
21631567Ssef	fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
21731567Ssef      }
21831567Ssef    }
21931567Ssef#if DEBUG
22031567Ssef    fprintf(stderr, ")\n");
22131567Ssef#endif
22231567Ssef  }
22331567Ssef
22431567Ssef#if DEBUG
225101282Smdodd  fprintf(trussinfo->outfile, "\n");
22631567Ssef#endif
22731567Ssef
22831567Ssef  /*
22931567Ssef   * Some system calls should be printed out before they are done --
23031567Ssef   * execve() and exit(), for example, never return.  Possibly change
23131567Ssef   * this to work for any system call that doesn't have an OUT
23231567Ssef   * parameter?
23331567Ssef   */
23431567Ssef
23531567Ssef  if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) {
236101282Smdodd    print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args);
23731567Ssef  }
23831567Ssef
23931567Ssef  return;
24031567Ssef}
24131567Ssef
24231567Ssef/*
24331567Ssef * And when the system call is done, we handle it here.
24431567Ssef * Currently, no attempt is made to ensure that the system calls
24531567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes
24631567Ssef * the sytem call number instead of, say, an error status).
24731567Ssef */
24831567Ssef
249101282Smdoddint
250101282Smdoddi386_syscall_exit(struct trussinfo *trussinfo, int syscall) {
25131567Ssef  char buf[32];
25231567Ssef  struct reg regs;
25331567Ssef  int retval;
25431567Ssef  int i;
25531567Ssef  int errorp;
25631567Ssef  struct syscall *sc;
25731567Ssef
258101282Smdodd  if (fd == -1 || trussinfo->pid != cpid) {
259101282Smdodd    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
26031567Ssef    fd = open(buf, O_RDONLY);
26131567Ssef    if (fd == -1) {
262101282Smdodd      fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
26331567Ssef      return;
26431567Ssef    }
265101282Smdodd    cpid = trussinfo->pid;
26631567Ssef  }
26731567Ssef
26831567Ssef  lseek(fd, 0L, 0);
269101282Smdodd  if (read(fd, &regs, sizeof(regs)) != sizeof(regs)) {
270101282Smdodd    fprintf(trussinfo->outfile, "\n");
27131567Ssef    return;
272101282Smdodd  }
27331567Ssef  retval = regs.r_eax;
27431567Ssef  errorp = !!(regs.r_eflags & PSL_C);
27531567Ssef
27631567Ssef  /*
27731567Ssef   * This code, while simpler than the initial versions I used, could
27831567Ssef   * stand some significant cleaning.
27931567Ssef   */
28031567Ssef
28131567Ssef  sc = fsc.sc;
28231567Ssef  if (!sc) {
28331567Ssef    for (i = 0; i < fsc.nargs; i++) {
28431567Ssef      fsc.s_args[i] = malloc(12);
28537453Sbde      sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]);
28631567Ssef    }
28731567Ssef  } else {
28831567Ssef    /*
28931567Ssef     * Here, we only look for arguments that have OUT masked in --
29031567Ssef     * otherwise, they were handled in the syscall_entry function.
29131567Ssef     */
29231567Ssef    for (i = 0; i < sc->nargs; i++) {
29331567Ssef      char *temp;
29431567Ssef      if (sc->args[i].type & OUT) {
29531567Ssef	/*
29631567Ssef	 * If an error occurred, than don't bothe getting the data;
29731567Ssef	 * it may not be valid.
29831567Ssef	 */
29931567Ssef	if (errorp) {
30031567Ssef	  temp = malloc(12);
30137453Sbde	  sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]);
30231567Ssef	} else {
30331567Ssef	  temp = print_arg(Procfd, &sc->args[i], fsc.args);
30431567Ssef	}
30531567Ssef	fsc.s_args[i] = temp;
30631567Ssef      }
30731567Ssef    }
30831567Ssef  }
30931567Ssef
31031567Ssef  /*
31131567Ssef   * It would probably be a good idea to merge the error handling,
31231567Ssef   * but that complicates things considerably.
31331567Ssef   */
31431567Ssef
315101282Smdodd  print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
31631567Ssef  clear_fsc();
31731567Ssef
318101282Smdodd  return (retval);
31931567Ssef}
320