i386-fbsd.c revision 101282
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 101282 2002-08-04 00:46:48Z 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
16331567Ssef  if (nargs == 0)
16431567Ssef    return;
16531567Ssef
16631567Ssef  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
16731567Ssef  lseek(Procfd, parm_offset, SEEK_SET);
16831567Ssef  if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
16931567Ssef    return;
17031567Ssef
17131567Ssef  sc = get_syscall(fsc.name);
17231567Ssef  if (sc) {
17331567Ssef    fsc.nargs = sc->nargs;
17431567Ssef  } else {
17531567Ssef#if DEBUG
176101282Smdodd    fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
17731567Ssef	   fsc.name, nargs);
17831567Ssef#endif
17931567Ssef    fsc.nargs = nargs;
18031567Ssef  }
18131567Ssef
18231567Ssef  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
18331567Ssef  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
18431567Ssef  fsc.sc = sc;
18531567Ssef
18631567Ssef  /*
18731567Ssef   * At this point, we set up the system call arguments.
18831567Ssef   * We ignore any OUT ones, however -- those are arguments that
18931567Ssef   * are set by the system call, and so are probably meaningless
19031567Ssef   * now.  This doesn't currently support arguments that are
19131567Ssef   * passed in *and* out, however.
19231567Ssef   */
19331567Ssef
19431567Ssef  if (fsc.name) {
19531567Ssef
19631567Ssef#if DEBUG
19731567Ssef    fprintf(stderr, "syscall %s(", fsc.name);
19831567Ssef#endif
19931567Ssef    for (i = 0; i < fsc.nargs; i++) {
20031567Ssef#if DEBUG
20131567Ssef      fprintf(stderr, "0x%x%s",
20231567Ssef	     sc
20331567Ssef	     ? fsc.args[sc->args[i].offset]
20431567Ssef	     : fsc.args[i],
20531567Ssef	     i < (fsc.nargs -1) ? "," : "");
20631567Ssef#endif
20731567Ssef      if (sc && !(sc->args[i].type & OUT)) {
20831567Ssef	fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
20931567Ssef      }
21031567Ssef    }
21131567Ssef#if DEBUG
21231567Ssef    fprintf(stderr, ")\n");
21331567Ssef#endif
21431567Ssef  }
21531567Ssef
21631567Ssef#if DEBUG
217101282Smdodd  fprintf(trussinfo->outfile, "\n");
21831567Ssef#endif
21931567Ssef
22031567Ssef  /*
22131567Ssef   * Some system calls should be printed out before they are done --
22231567Ssef   * execve() and exit(), for example, never return.  Possibly change
22331567Ssef   * this to work for any system call that doesn't have an OUT
22431567Ssef   * parameter?
22531567Ssef   */
22631567Ssef
22731567Ssef  if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) {
228101282Smdodd    print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args);
22931567Ssef  }
23031567Ssef
23131567Ssef  return;
23231567Ssef}
23331567Ssef
23431567Ssef/*
23531567Ssef * And when the system call is done, we handle it here.
23631567Ssef * Currently, no attempt is made to ensure that the system calls
23731567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes
23831567Ssef * the sytem call number instead of, say, an error status).
23931567Ssef */
24031567Ssef
241101282Smdoddint
242101282Smdoddi386_syscall_exit(struct trussinfo *trussinfo, int syscall) {
24331567Ssef  char buf[32];
24431567Ssef  struct reg regs;
24531567Ssef  int retval;
24631567Ssef  int i;
24731567Ssef  int errorp;
24831567Ssef  struct syscall *sc;
24931567Ssef
250101282Smdodd  if (fd == -1 || trussinfo->pid != cpid) {
251101282Smdodd    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
25231567Ssef    fd = open(buf, O_RDONLY);
25331567Ssef    if (fd == -1) {
254101282Smdodd      fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
25531567Ssef      return;
25631567Ssef    }
257101282Smdodd    cpid = trussinfo->pid;
25831567Ssef  }
25931567Ssef
26031567Ssef  lseek(fd, 0L, 0);
261101282Smdodd  if (read(fd, &regs, sizeof(regs)) != sizeof(regs)) {
262101282Smdodd    fprintf(trussinfo->outfile, "\n");
26331567Ssef    return;
264101282Smdodd  }
26531567Ssef  retval = regs.r_eax;
26631567Ssef  errorp = !!(regs.r_eflags & PSL_C);
26731567Ssef
26831567Ssef  /*
26931567Ssef   * This code, while simpler than the initial versions I used, could
27031567Ssef   * stand some significant cleaning.
27131567Ssef   */
27231567Ssef
27331567Ssef  sc = fsc.sc;
27431567Ssef  if (!sc) {
27531567Ssef    for (i = 0; i < fsc.nargs; i++) {
27631567Ssef      fsc.s_args[i] = malloc(12);
27737453Sbde      sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]);
27831567Ssef    }
27931567Ssef  } else {
28031567Ssef    /*
28131567Ssef     * Here, we only look for arguments that have OUT masked in --
28231567Ssef     * otherwise, they were handled in the syscall_entry function.
28331567Ssef     */
28431567Ssef    for (i = 0; i < sc->nargs; i++) {
28531567Ssef      char *temp;
28631567Ssef      if (sc->args[i].type & OUT) {
28731567Ssef	/*
28831567Ssef	 * If an error occurred, than don't bothe getting the data;
28931567Ssef	 * it may not be valid.
29031567Ssef	 */
29131567Ssef	if (errorp) {
29231567Ssef	  temp = malloc(12);
29337453Sbde	  sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]);
29431567Ssef	} else {
29531567Ssef	  temp = print_arg(Procfd, &sc->args[i], fsc.args);
29631567Ssef	}
29731567Ssef	fsc.s_args[i] = temp;
29831567Ssef      }
29931567Ssef    }
30031567Ssef  }
30131567Ssef
30231567Ssef  /*
30331567Ssef   * It would probably be a good idea to merge the error handling,
30431567Ssef   * but that complicates things considerably.
30531567Ssef   */
30631567Ssef
307101282Smdodd  print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
30831567Ssef  clear_fsc();
30931567Ssef
310101282Smdodd  return (retval);
31131567Ssef}
312