i386-fbsd.c revision 111176
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 111176 2003-02-20 15:05:39Z ru $";
3532275Scharnier#endif /* not lint */
3632275Scharnier
3731899Ssef/*
38111176Sru * FreeBSD/i386-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>
59101423Smdodd#include <time.h>
6031567Ssef#include <unistd.h>
6131567Ssef
62101282Smdodd#include "truss.h"
6331567Ssef#include "syscall.h"
64106713Sdwmalone#include "extern.h"
6531567Ssef
6631567Ssefstatic int fd = -1;
6731567Ssefstatic int cpid = -1;
6831567Ssefextern int Procfd;
6931567Ssef
7031567Ssef#include "syscalls.h"
7131567Ssef
7231567Ssefstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
7331567Ssef
7431567Ssef/*
7531567Ssef * This is what this particular file uses to keep track of a system call.
7631567Ssef * It is probably not quite sufficient -- I can probably use the same
7731567Ssef * structure for the various syscall personalities, and I also probably
7831567Ssef * need to nest system calls (for signal handlers).
7931567Ssef *
8031567Ssef * 'struct syscall' describes the system call; it may be NULL, however,
8131567Ssef * if we don't know about this particular system call yet.
8231567Ssef */
8331567Ssefstatic struct freebsd_syscall {
8431567Ssef	struct syscall *sc;
85106713Sdwmalone	const char *name;
8631567Ssef	int number;
8731567Ssef	unsigned long *args;
8831567Ssef	int nargs;	/* number of arguments -- *not* number of words! */
8931567Ssef	char **s_args;	/* the printable arguments */
9031567Ssef} fsc;
9131567Ssef
9231567Ssef/* Clear up and free parts of the fsc structure. */
93100357Smarkmstatic __inline void
94106713Sdwmaloneclear_fsc(void) {
9531567Ssef  if (fsc.args) {
9631567Ssef    free(fsc.args);
9731567Ssef  }
9831567Ssef  if (fsc.s_args) {
9931567Ssef    int i;
10031567Ssef    for (i = 0; i < fsc.nargs; i++)
10131567Ssef      if (fsc.s_args[i])
10231567Ssef	free(fsc.s_args[i]);
10331567Ssef    free(fsc.s_args);
10431567Ssef  }
10531567Ssef  memset(&fsc, 0, sizeof(fsc));
10631567Ssef}
10731567Ssef
10831567Ssef/*
10931567Ssef * Called when a process has entered a system call.  nargs is the
11031567Ssef * number of words, not number of arguments (a necessary distinction
11131567Ssef * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
11231567Ssef * is ever changed these functions need to keep up.
11331567Ssef */
11431567Ssef
11531567Ssefvoid
116101282Smdoddi386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
11731567Ssef  char buf[32];
118106713Sdwmalone  struct reg regs;
119106713Sdwmalone  int syscall_num;
12031567Ssef  int i;
12131567Ssef  unsigned int parm_offset;
12231567Ssef  struct syscall *sc;
12331567Ssef
124101282Smdodd  if (fd == -1 || trussinfo->pid != cpid) {
125101282Smdodd    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
12631567Ssef    fd = open(buf, O_RDWR);
12731567Ssef    if (fd == -1) {
128106713Sdwmalone      fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n");
12931567Ssef      return;
13031567Ssef    }
131101282Smdodd    cpid = trussinfo->pid;
13231567Ssef  }
13331567Ssef
13431567Ssef  clear_fsc();
13531567Ssef  lseek(fd, 0L, 0);
136106713Sdwmalone  if (read(fd, &regs, sizeof(regs)) != sizeof(regs)) {
137106713Sdwmalone    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
138106713Sdwmalone    return;
139106713Sdwmalone  }
14031567Ssef  parm_offset = regs.r_esp + sizeof(int);
14131567Ssef
14231567Ssef  /*
14331567Ssef   * FreeBSD has two special kinds of system call redirctions --
14431567Ssef   * SYS_syscall, and SYS___syscall.  The former is the old syscall()
14531567Ssef   * routine, basicly; the latter is for quad-aligned arguments.
14631567Ssef   */
147106713Sdwmalone  syscall_num = regs.r_eax;
148106713Sdwmalone  switch (syscall_num) {
14931567Ssef  case SYS_syscall:
15031567Ssef    lseek(Procfd, parm_offset, SEEK_SET);
151106713Sdwmalone    read(Procfd, &syscall_num, sizeof(int));
15231567Ssef    parm_offset += sizeof(int);
15331567Ssef    break;
15431567Ssef  case SYS___syscall:
15531567Ssef    lseek(Procfd, parm_offset, SEEK_SET);
156106713Sdwmalone    read(Procfd, &syscall_num, sizeof(int));
15731567Ssef    parm_offset += sizeof(quad_t);
15831567Ssef    break;
15931567Ssef  }
16031567Ssef
161106713Sdwmalone  fsc.number = syscall_num;
16231567Ssef  fsc.name =
163106713Sdwmalone    (syscall_num < 0 || syscall_num > nsyscalls) ? NULL : syscallnames[syscall_num];
16431567Ssef  if (!fsc.name) {
165106713Sdwmalone    fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
16631567Ssef  }
16731567Ssef
168101283Smdodd  if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
169101283Smdodd   && ((!strcmp(fsc.name, "fork")
170101283Smdodd    || !strcmp(fsc.name, "rfork")
171101283Smdodd    || !strcmp(fsc.name, "vfork"))))
172101283Smdodd  {
173101283Smdodd    trussinfo->in_fork = 1;
174101283Smdodd  }
175101283Smdodd
17631567Ssef  if (nargs == 0)
17731567Ssef    return;
17831567Ssef
17931567Ssef  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
18031567Ssef  lseek(Procfd, parm_offset, SEEK_SET);
18131567Ssef  if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
18231567Ssef    return;
18331567Ssef
18431567Ssef  sc = get_syscall(fsc.name);
18531567Ssef  if (sc) {
18631567Ssef    fsc.nargs = sc->nargs;
18731567Ssef  } else {
18831567Ssef#if DEBUG
189101282Smdodd    fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
19031567Ssef	   fsc.name, nargs);
19131567Ssef#endif
19231567Ssef    fsc.nargs = nargs;
19331567Ssef  }
19431567Ssef
19531567Ssef  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
19631567Ssef  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
19731567Ssef  fsc.sc = sc;
19831567Ssef
19931567Ssef  /*
20031567Ssef   * At this point, we set up the system call arguments.
20131567Ssef   * We ignore any OUT ones, however -- those are arguments that
20231567Ssef   * are set by the system call, and so are probably meaningless
20331567Ssef   * now.  This doesn't currently support arguments that are
20431567Ssef   * passed in *and* out, however.
20531567Ssef   */
20631567Ssef
20731567Ssef  if (fsc.name) {
20831567Ssef
20931567Ssef#if DEBUG
21031567Ssef    fprintf(stderr, "syscall %s(", fsc.name);
21131567Ssef#endif
21231567Ssef    for (i = 0; i < fsc.nargs; i++) {
21331567Ssef#if DEBUG
21431567Ssef      fprintf(stderr, "0x%x%s",
215101374Smdodd	      sc
216101374Smdodd	      ? fsc.args[sc->args[i].offset]
217101374Smdodd	      : fsc.args[i],
218101374Smdodd	      i < (fsc.nargs - 1) ? "," : "");
21931567Ssef#endif
22031567Ssef      if (sc && !(sc->args[i].type & OUT)) {
22131567Ssef	fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
22231567Ssef      }
22331567Ssef    }
22431567Ssef#if DEBUG
22531567Ssef    fprintf(stderr, ")\n");
22631567Ssef#endif
22731567Ssef  }
22831567Ssef
22931567Ssef#if DEBUG
230101282Smdodd  fprintf(trussinfo->outfile, "\n");
23131567Ssef#endif
23231567Ssef
23331567Ssef  /*
23431567Ssef   * Some system calls should be printed out before they are done --
23531567Ssef   * execve() and exit(), for example, never return.  Possibly change
23631567Ssef   * this to work for any system call that doesn't have an OUT
23731567Ssef   * parameter?
23831567Ssef   */
23931567Ssef
24031567Ssef  if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) {
241101289Smdodd
242101289Smdodd    /* XXX
243101289Smdodd     * This could be done in a more general
244101289Smdodd     * manner but it still wouldn't be very pretty.
245101289Smdodd     */
246101289Smdodd    if (!strcmp(fsc.name, "execve")) {
247101289Smdodd        if ((trussinfo->flags & EXECVEARGS) == 0)
248101374Smdodd          if (fsc.s_args[1]) {
249101289Smdodd            free(fsc.s_args[1]);
250101289Smdodd            fsc.s_args[1] = NULL;
251101289Smdodd          }
252101289Smdodd        if ((trussinfo->flags & EXECVEENVS) == 0)
253101374Smdodd          if (fsc.s_args[2]) {
254101289Smdodd            free(fsc.s_args[2]);
255101289Smdodd            fsc.s_args[2] = NULL;
256101289Smdodd          }
257101289Smdodd    }
258101289Smdodd
259101282Smdodd    print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args);
260101286Smdodd    fprintf(trussinfo->outfile, "\n");
26131567Ssef  }
26231567Ssef
26331567Ssef  return;
26431567Ssef}
26531567Ssef
26631567Ssef/*
26731567Ssef * And when the system call is done, we handle it here.
26831567Ssef * Currently, no attempt is made to ensure that the system calls
26931567Ssef * match -- this needs to be fixed (and is, in fact, why S_SCX includes
27031567Ssef * the sytem call number instead of, say, an error status).
27131567Ssef */
27231567Ssef
273101282Smdoddint
274106713Sdwmalonei386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) {
27531567Ssef  char buf[32];
27631567Ssef  struct reg regs;
27731567Ssef  int retval;
27831567Ssef  int i;
27931567Ssef  int errorp;
28031567Ssef  struct syscall *sc;
28131567Ssef
282101282Smdodd  if (fd == -1 || trussinfo->pid != cpid) {
283101282Smdodd    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
28431567Ssef    fd = open(buf, O_RDONLY);
28531567Ssef    if (fd == -1) {
286106713Sdwmalone      fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n");
287106713Sdwmalone      return (-1);
28831567Ssef    }
289101282Smdodd    cpid = trussinfo->pid;
29031567Ssef  }
29131567Ssef
29231567Ssef  lseek(fd, 0L, 0);
293101282Smdodd  if (read(fd, &regs, sizeof(regs)) != sizeof(regs)) {
294106713Sdwmalone    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
295106713Sdwmalone    return (-1);
296101282Smdodd  }
29731567Ssef  retval = regs.r_eax;
29831567Ssef  errorp = !!(regs.r_eflags & PSL_C);
29931567Ssef
30031567Ssef  /*
30131567Ssef   * This code, while simpler than the initial versions I used, could
30231567Ssef   * stand some significant cleaning.
30331567Ssef   */
30431567Ssef
30531567Ssef  sc = fsc.sc;
30631567Ssef  if (!sc) {
30731567Ssef    for (i = 0; i < fsc.nargs; i++) {
30831567Ssef      fsc.s_args[i] = malloc(12);
30937453Sbde      sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]);
31031567Ssef    }
31131567Ssef  } else {
31231567Ssef    /*
31331567Ssef     * Here, we only look for arguments that have OUT masked in --
31431567Ssef     * otherwise, they were handled in the syscall_entry function.
31531567Ssef     */
31631567Ssef    for (i = 0; i < sc->nargs; i++) {
31731567Ssef      char *temp;
31831567Ssef      if (sc->args[i].type & OUT) {
31931567Ssef	/*
32031567Ssef	 * If an error occurred, than don't bothe getting the data;
32131567Ssef	 * it may not be valid.
32231567Ssef	 */
32331567Ssef	if (errorp) {
32431567Ssef	  temp = malloc(12);
32537453Sbde	  sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]);
32631567Ssef	} else {
32731567Ssef	  temp = print_arg(Procfd, &sc->args[i], fsc.args);
32831567Ssef	}
32931567Ssef	fsc.s_args[i] = temp;
33031567Ssef      }
33131567Ssef    }
33231567Ssef  }
33331567Ssef
33431567Ssef  /*
33531567Ssef   * It would probably be a good idea to merge the error handling,
33631567Ssef   * but that complicates things considerably.
33731567Ssef   */
33831567Ssef
339101282Smdodd  print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
34031567Ssef  clear_fsc();
34131567Ssef
342101282Smdodd  return (retval);
34331567Ssef}
344