i386-fbsd.c revision 100357
155714Skris/*
2280304Sjkim * Copryight 1997 Sean Eric Fagan
3280304Sjkim *
4280304Sjkim * Redistribution and use in source and binary forms, with or without
555714Skris * modification, are permitted provided that the following conditions
655714Skris * are met:
755714Skris * 1. Redistributions of source code must retain the above copyright
855714Skris *    notice, this list of conditions and the following disclaimer.
955714Skris * 2. Redistributions in binary form must reproduce the above copyright
1055714Skris *    notice, this list of conditions and the following disclaimer in the
1155714Skris *    documentation and/or other materials provided with the distribution.
1255714Skris * 3. All advertising materials mentioning features or use of this software
1355714Skris *    must display the following acknowledgement:
14280304Sjkim *	This product includes software developed by Sean Eric Fagan
1555714Skris * 4. Neither the name of the author may be used to endorse or promote
1655714Skris *    products derived from this software without specific prior written
1755714Skris *    permission.
1855714Skris *
1955714Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2055714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2155714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2255714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2355714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2455714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2555714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2655714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2755714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2855714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2955714Skris * SUCH DAMAGE.
3055714Skris */
3155714Skris
3255714Skris#ifndef lint
3355714Skrisstatic const char rcsid[] =
3455714Skris  "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 100357 2002-07-19 13:49:37Z markm $";
3555714Skris#endif /* not lint */
3655714Skris
3755714Skris/*
3855714Skris * FreeBSD/386-specific system call handling.  This is probably the most
3955714Skris * complex part of the entire truss program, although I've got lots of
4055714Skris * it handled relatively cleanly now.  The system call names are generated
4155714Skris * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
4255714Skris * names used for the various structures are confusing, I sadly admit.
4355714Skris */
4455714Skris
4555714Skris#include <sys/types.h>
4655714Skris#include <sys/ioctl.h>
4755714Skris#include <sys/pioctl.h>
4855714Skris#include <sys/syscall.h>
4955714Skris
5055714Skris#include <machine/reg.h>
5155714Skris#include <machine/psl.h>
5255714Skris
5355714Skris#include <errno.h>
5455714Skris#include <fcntl.h>
5555714Skris#include <signal.h>
5655714Skris#include <stdio.h>
5755714Skris#include <stdlib.h>
5855714Skris#include <string.h>
5955714Skris#include <unistd.h>
6055714Skris
6155714Skris#include "syscall.h"
6255714Skris
6355714Skrisstatic int fd = -1;
6455714Skrisstatic int cpid = -1;
6555714Skrisextern int Procfd;
6655714Skris
6755714Skrisextern FILE *outfile;
68280304Sjkim#include "syscalls.h"
69280304Sjkim
70109998Smarkmstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
7155714Skris
7255714Skris/*
73280304Sjkim * This is what this particular file uses to keep track of a system call.
74280304Sjkim * It is probably not quite sufficient -- I can probably use the same
7555714Skris * structure for the various syscall personalities, and I also probably
76280304Sjkim * need to nest system calls (for signal handlers).
77280304Sjkim *
78280304Sjkim * 'struct syscall' describes the system call; it may be NULL, however,
79280304Sjkim * if we don't know about this particular system call yet.
80280304Sjkim */
81280304Sjkimstatic struct freebsd_syscall {
82280304Sjkim	struct syscall *sc;
83280304Sjkim	char *name;
84280304Sjkim	int number;
85280304Sjkim	unsigned long *args;
86280304Sjkim	int nargs;	/* number of arguments -- *not* number of words! */
87280304Sjkim	char **s_args;	/* the printable arguments */
88280304Sjkim} fsc;
89280304Sjkim
90280304Sjkim/* Clear up and free parts of the fsc structure. */
91280304Sjkimstatic __inline void
92280304Sjkimclear_fsc() {
93280304Sjkim  if (fsc.args) {
94280304Sjkim    free(fsc.args);
9559191Skris  }
96280304Sjkim  if (fsc.s_args) {
97280304Sjkim    int i;
9859191Skris    for (i = 0; i < fsc.nargs; i++)
99280304Sjkim      if (fsc.s_args[i])
100280304Sjkim	free(fsc.s_args[i]);
101280304Sjkim    free(fsc.s_args);
102280304Sjkim  }
103280304Sjkim  memset(&fsc, 0, sizeof(fsc));
104280304Sjkim}
105280304Sjkim
106280304Sjkim/*
107280304Sjkim * Called when a process has entered a system call.  nargs is the
108280304Sjkim * number of words, not number of arguments (a necessary distinction
109280304Sjkim * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
11059191Skris * is ever changed these functions need to keep up.
111280304Sjkim */
112280304Sjkim
113280304Sjkimvoid
11455714Skrisi386_syscall_entry(int pid, int nargs) {
11555714Skris  char buf[32];
11655714Skris  struct reg regs = { 0 };
11755714Skris  int syscall;
118280304Sjkim  int i;
119280304Sjkim  unsigned int parm_offset;
12055714Skris  struct syscall *sc;
121280304Sjkim
122280304Sjkim  if (fd == -1 || pid != cpid) {
123280304Sjkim    sprintf(buf, "/proc/%d/regs", pid);
124280304Sjkim    fd = open(buf, O_RDWR);
125280304Sjkim    if (fd == -1) {
126280304Sjkim      fprintf(outfile, "-- CANNOT READ REGISTERS --\n");
127160814Ssimon      return;
128280304Sjkim    }
129280304Sjkim    cpid = pid;
130280304Sjkim  }
131280304Sjkim
132280304Sjkim  clear_fsc();
133280304Sjkim  lseek(fd, 0L, 0);
134280304Sjkim  i = read(fd, &regs, sizeof(regs));
135280304Sjkim  parm_offset = regs.r_esp + sizeof(int);
136280304Sjkim
137109998Smarkm  /*
138280304Sjkim   * FreeBSD has two special kinds of system call redirctions --
139280304Sjkim   * SYS_syscall, and SYS___syscall.  The former is the old syscall()
140109998Smarkm   * routine, basicly; the latter is for quad-aligned arguments.
141280304Sjkim   */
142280304Sjkim  syscall = regs.r_eax;
143280304Sjkim  switch (syscall) {
144280304Sjkim  case SYS_syscall:
145280304Sjkim    lseek(Procfd, parm_offset, SEEK_SET);
14659191Skris    read(Procfd, &syscall, sizeof(int));
147280304Sjkim    parm_offset += sizeof(int);
14859191Skris    break;
149280304Sjkim  case SYS___syscall:
150280304Sjkim    lseek(Procfd, parm_offset, SEEK_SET);
151280304Sjkim    read(Procfd, &syscall, sizeof(int));
152280304Sjkim    parm_offset += sizeof(quad_t);
153280304Sjkim    break;
154280304Sjkim  }
155280304Sjkim
156280304Sjkim  fsc.number = syscall;
157280304Sjkim  fsc.name =
158280304Sjkim    (syscall < 0 || syscall > nsyscalls) ? NULL : syscallnames[syscall];
159280304Sjkim  if (!fsc.name) {
16059191Skris    fprintf(outfile, "-- UNKNOWN SYSCALL %d --\n", syscall);
161280304Sjkim  }
162280304Sjkim
163280304Sjkim  if (nargs == 0)
164280304Sjkim    return;
165280304Sjkim
166280304Sjkim  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
167280304Sjkim  lseek(Procfd, parm_offset, SEEK_SET);
168280304Sjkim  if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
169280304Sjkim    return;
170280304Sjkim
171280304Sjkim  sc = get_syscall(fsc.name);
172280304Sjkim  if (sc) {
17355714Skris    fsc.nargs = sc->nargs;
174280304Sjkim  } else {
175280304Sjkim#if DEBUG
176280304Sjkim    fprintf(outfile, "unknown syscall %s -- setting args to %d\n",
177280304Sjkim	   fsc.name, nargs);
178280304Sjkim#endif
179280304Sjkim    fsc.nargs = nargs;
180280304Sjkim  }
181280304Sjkim
182280304Sjkim  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
18355714Skris  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
18455714Skris  fsc.sc = sc;
185280304Sjkim
186280304Sjkim  /*
187280304Sjkim   * At this point, we set up the system call arguments.
188109998Smarkm   * We ignore any OUT ones, however -- those are arguments that
189280304Sjkim   * are set by the system call, and so are probably meaningless
190109998Smarkm   * now.  This doesn't currently support arguments that are
191280304Sjkim   * passed in *and* out, however.
192280304Sjkim   */
193109998Smarkm
194280304Sjkim  if (fsc.name) {
195280304Sjkim
196280304Sjkim#if DEBUG
197280304Sjkim    fprintf(stderr, "syscall %s(", fsc.name);
198109998Smarkm#endif
199280304Sjkim    for (i = 0; i < fsc.nargs; i++) {
200280304Sjkim#if DEBUG
201280304Sjkim      fprintf(stderr, "0x%x%s",
202280304Sjkim	     sc
203280304Sjkim	     ? fsc.args[sc->args[i].offset]
204280304Sjkim	     : fsc.args[i],
205280304Sjkim	     i < (fsc.nargs -1) ? "," : "");
206280304Sjkim#endif
207280304Sjkim      if (sc && !(sc->args[i].type & OUT)) {
208280304Sjkim	fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
209280304Sjkim      }
210280304Sjkim    }
211280304Sjkim#if DEBUG
212280304Sjkim    fprintf(stderr, ")\n");
213280304Sjkim#endif
214280304Sjkim  }
215280304Sjkim
216280304Sjkim#if DEBUG
217280304Sjkim  fprintf(outfile, "\n");
218109998Smarkm#endif
219109998Smarkm
220280304Sjkim  /*
221280304Sjkim   * Some system calls should be printed out before they are done --
222109998Smarkm   * execve() and exit(), for example, never return.  Possibly change
223280304Sjkim   * this to work for any system call that doesn't have an OUT
224109998Smarkm   * parameter?
225280304Sjkim   */
226280304Sjkim
227109998Smarkm  if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) {
228280304Sjkim    print_syscall(outfile, fsc.name, fsc.nargs, fsc.s_args);
229280304Sjkim  }
230280304Sjkim
231280304Sjkim  return;
232280304Sjkim}
233280304Sjkim
234109998Smarkm/*
235280304Sjkim * And when the system call is done, we handle it here.
236280304Sjkim * Currently, no attempt is made to ensure that the system calls
237280304Sjkim * match -- this needs to be fixed (and is, in fact, why S_SCX includes
238280304Sjkim * the sytem call number instead of, say, an error status).
239280304Sjkim */
240280304Sjkim
241280304Sjkimvoid
242109998Smarkmi386_syscall_exit(int pid, int syscall) {
243280304Sjkim  char buf[32];
244280304Sjkim  struct reg regs;
245280304Sjkim  int retval;
246109998Smarkm  int i;
247109998Smarkm  int errorp;
248109998Smarkm  struct syscall *sc;
24955714Skris
25055714Skris  if (fd == -1 || pid != cpid) {
251280304Sjkim    sprintf(buf, "/proc/%d/regs", pid);
252280304Sjkim    fd = open(buf, O_RDONLY);
253280304Sjkim    if (fd == -1) {
254280304Sjkim      fprintf(outfile, "-- CANNOT READ REGISTERS --\n");
255280304Sjkim      return;
256280304Sjkim    }
257280304Sjkim    cpid = pid;
25855714Skris  }
25955714Skris
260  lseek(fd, 0L, 0);
261  if (read(fd, &regs, sizeof(regs)) != sizeof(regs))
262    return;
263  retval = regs.r_eax;
264  errorp = !!(regs.r_eflags & PSL_C);
265
266  /*
267   * This code, while simpler than the initial versions I used, could
268   * stand some significant cleaning.
269   */
270
271  sc = fsc.sc;
272  if (!sc) {
273    for (i = 0; i < fsc.nargs; i++) {
274      fsc.s_args[i] = malloc(12);
275      sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]);
276    }
277  } else {
278    /*
279     * Here, we only look for arguments that have OUT masked in --
280     * otherwise, they were handled in the syscall_entry function.
281     */
282    for (i = 0; i < sc->nargs; i++) {
283      char *temp;
284      if (sc->args[i].type & OUT) {
285	/*
286	 * If an error occurred, than don't bothe getting the data;
287	 * it may not be valid.
288	 */
289	if (errorp) {
290	  temp = malloc(12);
291	  sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]);
292	} else {
293	  temp = print_arg(Procfd, &sc->args[i], fsc.args);
294	}
295	fsc.s_args[i] = temp;
296      }
297    }
298  }
299
300  /*
301   * It would probably be a good idea to merge the error handling,
302   * but that complicates things considerably.
303   */
304
305  print_syscall_ret(outfile, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
306  clear_fsc();
307
308  return;
309}
310