i386-fbsd.c revision 85301
118334Speter/*
290075Sobrien * Copryight 1997 Sean Eric Fagan
3132730Skan *
418334Speter * Redistribution and use in source and binary forms, with or without
590075Sobrien * modification, are permitted provided that the following conditions
618334Speter * are met:
790075Sobrien * 1. Redistributions of source code must retain the above copyright
890075Sobrien *    notice, this list of conditions and the following disclaimer.
990075Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1090075Sobrien *    notice, this list of conditions and the following disclaimer in the
1118334Speter *    documentation and/or other materials provided with the distribution.
1290075Sobrien * 3. All advertising materials mentioning features or use of this software
1390075Sobrien *    must display the following acknowledgement:
1490075Sobrien *	This product includes software developed by Sean Eric Fagan
1590075Sobrien * 4. Neither the name of the author may be used to endorse or promote
1618334Speter *    products derived from this software without specific prior written
1718334Speter *    permission.
1890075Sobrien *
1990075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2090075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2118334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2296549Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2396549Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2418334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2518334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2618334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2718334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2818334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2918334Speter * SUCH DAMAGE.
3018334Speter */
3118334Speter
3250397Sobrien#ifndef lint
33132730Skanstatic const char rcsid[] =
34132730Skan  "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 85301 2001-10-22 02:02:00Z des $";
3590075Sobrien#endif /* not lint */
3618334Speter
3790075Sobrien/*
3890075Sobrien * FreeBSD/386-specific system call handling.  This is probably the most
3918334Speter * complex part of the entire truss program, although I've got lots of
4090075Sobrien * it handled relatively cleanly now.  The system call names are generated
4118334Speter * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
4290075Sobrien * names used for the various structures are confusing, I sadly admit.
4318334Speter */
4450397Sobrien
4590075Sobrien#include <sys/types.h>
4690075Sobrien#include <sys/ioctl.h>
4750397Sobrien#include <sys/pioctl.h>
4890075Sobrien#include <sys/syscall.h>
4990075Sobrien
50132730Skan#include <machine/reg.h>
5190075Sobrien#include <machine/psl.h>
5290075Sobrien
5396263Sobrien#include <errno.h>
54132730Skan#include <fcntl.h>
55132730Skan#include <signal.h>
56117421Skan#include <stdio.h>
57117421Skan#include <stdlib.h>
58132730Skan#include <string.h>
5950397Sobrien#include <unistd.h>
6018334Speter
6118334Speter#include "syscall.h"
6218334Speter
6318334Speterstatic int fd = -1;
6418334Speterstatic int cpid = -1;
6518334Speterextern int Procfd;
6618334Speter
6718334Speterextern FILE *outfile;
6818334Speter#include "syscalls.h"
6918334Speter
7018334Speterstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
7118334Speter
7218334Speter/*
7318334Speter * This is what this particular file uses to keep track of a system call.
74132730Skan * It is probably not quite sufficient -- I can probably use the same
7518334Speter * structure for the various syscall personalities, and I also probably
7618334Speter * need to nest system calls (for signal handlers).
7718334Speter *
7818334Speter * 'struct syscall' describes the system call; it may be NULL, however,
7918334Speter * if we don't know about this particular system call yet.
8018334Speter */
8118334Speterstatic struct freebsd_syscall {
8218334Speter	struct syscall *sc;
8318334Speter	char *name;
8418334Speter	int number;
8518334Speter	unsigned long *args;
8618334Speter	int nargs;	/* number of arguments -- *not* number of words! */
8718334Speter	char **s_args;	/* the printable arguments */
8818334Speter} fsc;
89132730Skan
9018334Speter/* Clear up and free parts of the fsc structure. */
9118334Speterstatic inline void
9218334Speterclear_fsc() {
93132730Skan  if (fsc.args) {
94132730Skan    free(fsc.args);
9518334Speter  }
9618334Speter  if (fsc.s_args) {
9718334Speter    int i;
98132730Skan    for (i = 0; i < fsc.nargs; i++)
99132730Skan      if (fsc.s_args[i])
100132730Skan	free(fsc.s_args[i]);
101132730Skan    free(fsc.s_args);
102132730Skan  }
10318334Speter  memset(&fsc, 0, sizeof(fsc));
104132730Skan}
105132730Skan
10618334Speter/*
10718334Speter * Called when a process has entered a system call.  nargs is the
10818334Speter * number of words, not number of arguments (a necessary distinction
10918334Speter * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
110132730Skan * is ever changed these functions need to keep up.
11118334Speter */
11218334Speter
113132730Skanvoid
114132730Skani386_syscall_entry(int pid, int nargs) {
115132730Skan  char buf[32];
116132730Skan  struct reg regs = { 0 };
11718334Speter  int syscall;
11818334Speter  int i;
11918334Speter  unsigned int parm_offset;
120132730Skan  struct syscall *sc;
121132730Skan
12290075Sobrien  if (fd == -1 || pid != cpid) {
12390075Sobrien    sprintf(buf, "/proc/%d/regs", pid);
124117421Skan    fd = open(buf, O_RDWR);
12590075Sobrien    if (fd == -1) {
12690075Sobrien      fprintf(outfile, "-- CANNOT READ REGISTERS --\n");
12790075Sobrien      return;
128117421Skan    }
12990075Sobrien    cpid = pid;
130132730Skan  }
131132730Skan
132132730Skan  clear_fsc();
13318334Speter  lseek(fd, 0L, 0);
134132730Skan  i = read(fd, &regs, sizeof(regs));
135132730Skan  parm_offset = regs.r_esp + sizeof(int);
136132730Skan
13718334Speter  /*
138132730Skan   * FreeBSD has two special kinds of system call redirctions --
13918334Speter   * SYS_syscall, and SYS___syscall.  The former is the old syscall()
140132730Skan   * routine, basicly; the latter is for quad-aligned arguments.
141132730Skan   */
14218334Speter  syscall = regs.r_eax;
143132730Skan  switch (syscall) {
144132730Skan  case SYS_syscall:
145132730Skan    lseek(Procfd, parm_offset, SEEK_SET);
146132730Skan    read(Procfd, &syscall, sizeof(int));
14718334Speter    parm_offset += sizeof(int);
14818334Speter    break;
14918334Speter  case SYS___syscall:
15018334Speter    lseek(Procfd, parm_offset, SEEK_SET);
15118334Speter    read(Procfd, &syscall, sizeof(int));
15218334Speter    parm_offset += sizeof(quad_t);
15318334Speter    break;
15418334Speter  }
15518334Speter
15618334Speter  fsc.number = syscall;
15796263Sobrien  fsc.name =
15896263Sobrien    (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall];
15996263Sobrien  if (!fsc.name) {
16096263Sobrien    fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall);
16196263Sobrien  }
16218334Speter
16318334Speter  if (nargs == 0)
16418334Speter    return;
16518334Speter
16618334Speter  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
16718334Speter  lseek(Procfd, parm_offset, SEEK_SET);
16818334Speter  if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
16918334Speter    return;
17018334Speter
171132730Skan  sc = get_syscall(fsc.name);
172132730Skan  if (sc) {
173132730Skan    fsc.nargs = sc->nargs;
17418334Speter  } else {
175132730Skan#if DEBUG
17618334Speter    fprintf(outfile, "unknown syscall %s -- setting args to %d\n",
177132730Skan	   fsc.name, nargs);
178132730Skan#endif
179132730Skan    fsc.nargs = nargs;
180132730Skan  }
181132730Skan
18218334Speter  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
183132730Skan  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
184132730Skan  fsc.sc = sc;
185132730Skan
186132730Skan  /*
18718334Speter   * At this point, we set up the system call arguments.
188132730Skan   * We ignore any OUT ones, however -- those are arguments that
189132730Skan   * are set by the system call, and so are probably meaningless
190132730Skan   * now.  This doesn't currently support arguments that are
191132730Skan   * passed in *and* out, however.
19218334Speter   */
193132730Skan
194132730Skan  if (fsc.name) {
19518334Speter
196132730Skan#if DEBUG
197132730Skan    fprintf(stderr, "syscall %s(", fsc.name);
198132730Skan#endif
199132730Skan    for (i = 0; i < fsc.nargs; i++) {
20018334Speter#if DEBUG
201132730Skan      fprintf(stderr, "0x%x%s",
202132730Skan	     sc
20318334Speter	     ? fsc.args[sc->args[i].offset]
204132730Skan	     : fsc.args[i],
205132730Skan	     i < (fsc.nargs -1) ? "," : "");
206132730Skan#endif
20718334Speter      if (sc && !(sc->args[i].type & OUT)) {
208132730Skan	fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
209132730Skan      }
210132730Skan    }
211132730Skan#if DEBUG
21218334Speter    fprintf(stderr, ")\n");
213132730Skan#endif
214132730Skan  }
21518334Speter
216132730Skan#if DEBUG
217132730Skan  fprintf(outfile, "\n");
218132730Skan#endif
219132730Skan
220132730Skan  /*
22118334Speter   * Some system calls should be printed out before they are done --
222132730Skan   * execve() and exit(), for example, never return.  Possibly change
223132730Skan   * this to work for any system call that doesn't have an OUT
224132730Skan   * parameter?
225132730Skan   */
226132730Skan
22718334Speter  if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) {
228132730Skan    print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args);
229132730Skan  }
230132730Skan
231132730Skan  return;
23218334Speter}
233132730Skan
234132730Skan/*
235132730Skan * And when the system call is done, we handle it here.
23618334Speter * Currently, no attempt is made to ensure that the system calls
237132730Skan * match -- this needs to be fixed (and is, in fact, why S_SCX includes
238132730Skan * the sytem call number instead of, say, an error status).
239132730Skan */
240132730Skan
24190075Sobrienvoid
242132730Skani386_syscall_exit(int pid, int syscall) {
243132730Skan  char buf[32];
244132730Skan  struct reg regs;
245132730Skan  int retval;
246132730Skan  int i;
24718334Speter  int errorp;
248132730Skan  struct syscall *sc;
249132730Skan
250132730Skan  if (fd == -1 || pid != cpid) {
25118334Speter    sprintf(buf, "/proc/%d/regs", pid);
252132730Skan    fd = open(buf, O_RDONLY);
25318334Speter    if (fd == -1) {
254132730Skan      fprintf(outfile, "-- CANNOT READ REGISTERS --\n");
25518334Speter      return;
256132730Skan    }
25718334Speter    cpid = pid;
258132730Skan  }
25918334Speter
260132730Skan  lseek(fd, 0L, 0);
261132730Skan  if (read(fd, &regs, sizeof(regs)) != sizeof(regs))
262132730Skan    return;
26318334Speter  retval = regs.r_eax;
264132730Skan  errorp = !!(regs.r_eflags & PSL_C);
26518334Speter
266132730Skan  /*
267132730Skan   * This code, while simpler than the initial versions I used, could
26818334Speter   * stand some significant cleaning.
269132730Skan   */
27018334Speter
271132730Skan  sc = fsc.sc;
272132730Skan  if (!sc) {
273132730Skan    for (i = 0; i < fsc.nargs; i++) {
274132730Skan      fsc.s_args[i] = malloc(12);
275132730Skan      sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]);
276132730Skan    }
277132730Skan  } else {
278132730Skan    /*
279132730Skan     * Here, we only look for arguments that have OUT masked in --
280132730Skan     * otherwise, they were handled in the syscall_entry function.
28118334Speter     */
282132730Skan    for (i = 0; i < sc->nargs; i++) {
283132730Skan      char *temp;
284132730Skan      if (sc->args[i].type & OUT) {
285132730Skan	/*
286132730Skan	 * If an error occurred, than don't bothe getting the data;
287132730Skan	 * it may not be valid.
288132730Skan	 */
289132730Skan	if (errorp) {
290132730Skan	  temp = malloc(12);
291132730Skan	  sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]);
29290075Sobrien	} else {
293132730Skan	  temp = print_arg(Procfd, &sc->args[i], fsc.args);
29418334Speter	}
295132730Skan	fsc.s_args[i] = temp;
29618334Speter      }
297132730Skan    }
298132730Skan  }
299132730Skan
300132730Skan  /*
301132730Skan   * It would probably be a good idea to merge the error handling,
302132730Skan   * but that complicates things considerably.
30318334Speter   */
30418334Speter
30518334Speter  print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
30618334Speter  clear_fsc();
30718334Speter
30818334Speter  return;
309132730Skan}
310132730Skan