i386-fbsd.c revision 171055
1206089Sfabient/*
2206089Sfabient * Copryight 1997 Sean Eric Fagan
3206089Sfabient *
4206089Sfabient * Redistribution and use in source and binary forms, with or without
5206089Sfabient * modification, are permitted provided that the following conditions
6206089Sfabient * are met:
7206089Sfabient * 1. Redistributions of source code must retain the above copyright
8206089Sfabient *    notice, this list of conditions and the following disclaimer.
9206089Sfabient * 2. Redistributions in binary form must reproduce the above copyright
10206089Sfabient *    notice, this list of conditions and the following disclaimer in the
11206089Sfabient *    documentation and/or other materials provided with the distribution.
12231871Sbrueffer * 3. All advertising materials mentioning features or use of this software
13231871Sbrueffer *    must display the following acknowledgement:
14231871Sbrueffer *	This product includes software developed by Sean Eric Fagan
15231871Sbrueffer * 4. Neither the name of the author may be used to endorse or promote
16231871Sbrueffer *    products derived from this software without specific prior written
17231871Sbrueffer *    permission.
18231871Sbrueffer *
19231871Sbrueffer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20231871Sbrueffer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21231871Sbrueffer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22231871Sbrueffer * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23206089Sfabient * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24206089Sfabient * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25206089Sfabient * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26206089Sfabient * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27206622Suqs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28206089Sfabient * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29206089Sfabient * SUCH DAMAGE.
30206089Sfabient */
31206089Sfabient
32206089Sfabient#ifndef lint
33206089Sfabientstatic const char rcsid[] =
34206089Sfabient  "$FreeBSD: head/usr.bin/truss/i386-fbsd.c 171055 2007-06-26 22:42:37Z delphij $";
35206089Sfabient#endif /* not lint */
36206089Sfabient
37206089Sfabient/*
38206089Sfabient * FreeBSD/i386-specific system call handling.  This is probably the most
39206089Sfabient * complex part of the entire truss program, although I've got lots of
40206089Sfabient * it handled relatively cleanly now.  The system call names are generated
41206089Sfabient * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
42206089Sfabient * names used for the various structures are confusing, I sadly admit.
43206089Sfabient */
44206089Sfabient
45206089Sfabient#include <sys/types.h>
46206089Sfabient#include <sys/syscall.h>
47206089Sfabient#include <sys/ptrace.h>
48206089Sfabient
49206089Sfabient#include <machine/reg.h>
50206089Sfabient#include <machine/psl.h>
51206089Sfabient
52206089Sfabient#include <errno.h>
53206089Sfabient#include <fcntl.h>
54206089Sfabient#include <signal.h>
55206089Sfabient#include <stdio.h>
56206089Sfabient#include <stdlib.h>
57206089Sfabient#include <string.h>
58206089Sfabient#include <time.h>
59206089Sfabient#include <unistd.h>
60206089Sfabient
61206089Sfabient#include "truss.h"
62206089Sfabient#include "syscall.h"
63206089Sfabient#include "extern.h"
64206089Sfabient
65206089Sfabientstatic int cpid = -1;
66206089Sfabient
67206089Sfabient#include "syscalls.h"
68206089Sfabient
69206089Sfabientstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
70206089Sfabient
71206089Sfabient/*
72206089Sfabient * This is what this particular file uses to keep track of a system call.
73206089Sfabient * It is probably not quite sufficient -- I can probably use the same
74206089Sfabient * structure for the various syscall personalities, and I also probably
75206089Sfabient * need to nest system calls (for signal handlers).
76206089Sfabient *
77206089Sfabient * 'struct syscall' describes the system call; it may be NULL, however,
78206089Sfabient * if we don't know about this particular system call yet.
79206089Sfabient */
80206089Sfabientstatic struct freebsd_syscall {
81206089Sfabient	struct syscall *sc;
82206089Sfabient	const char *name;
83206089Sfabient	int number;
84206089Sfabient	unsigned long *args;
85206089Sfabient	int nargs;	/* number of arguments -- *not* number of words! */
86206089Sfabient	char **s_args;	/* the printable arguments */
87206089Sfabient} fsc;
88206089Sfabient
89206089Sfabient/* Clear up and free parts of the fsc structure. */
90206089Sfabientstatic __inline void
91206089Sfabientclear_fsc(void) {
92206089Sfabient  if (fsc.args) {
93206089Sfabient    free(fsc.args);
94206089Sfabient  }
95206089Sfabient  if (fsc.s_args) {
96206089Sfabient    int i;
97206089Sfabient    for (i = 0; i < fsc.nargs; i++)
98206089Sfabient      if (fsc.s_args[i])
99206089Sfabient	free(fsc.s_args[i]);
100206089Sfabient    free(fsc.s_args);
101206089Sfabient  }
102206089Sfabient  memset(&fsc, 0, sizeof(fsc));
103206089Sfabient}
104206089Sfabient
105206089Sfabient/*
106206089Sfabient * Called when a process has entered a system call.  nargs is the
107206089Sfabient * number of words, not number of arguments (a necessary distinction
108206089Sfabient * in some cases).  Note that if the STOPEVENT() code in i386/i386/trap.c
109206089Sfabient * is ever changed these functions need to keep up.
110206089Sfabient */
111206089Sfabient
112206089Sfabientvoid
113206089Sfabienti386_syscall_entry(struct trussinfo *trussinfo, int nargs) {
114206089Sfabient  struct reg regs;
115206089Sfabient  int syscall_num;
116206089Sfabient  int i;
117206089Sfabient  unsigned int parm_offset;
118206089Sfabient  struct syscall *sc = NULL;
119206089Sfabient  struct ptrace_io_desc iorequest;
120206089Sfabient  cpid = trussinfo->curthread->tid;
121206089Sfabient
122206089Sfabient  clear_fsc();
123206089Sfabient
124206089Sfabient  if (ptrace(PT_GETREGS, cpid, (caddr_t)&regs, 0) < 0)
125206089Sfabient  {
126206089Sfabient    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
127206089Sfabient    return;
128206089Sfabient  }
129206089Sfabient  parm_offset = regs.r_esp + sizeof(int);
130206089Sfabient
131206089Sfabient  /*
132206089Sfabient   * FreeBSD has two special kinds of system call redirctions --
133206089Sfabient   * SYS_syscall, and SYS___syscall.  The former is the old syscall()
134206089Sfabient   * routine, basicly; the latter is for quad-aligned arguments.
135206089Sfabient   */
136206089Sfabient  syscall_num = regs.r_eax;
137206089Sfabient  switch (syscall_num) {
138206089Sfabient  case SYS_syscall:
139206089Sfabient    syscall_num = ptrace(PT_READ_D, cpid, (caddr_t)parm_offset, 0);
140206089Sfabient    parm_offset += sizeof(int);
141206089Sfabient    break;
142206089Sfabient  case SYS___syscall:
143206089Sfabient    syscall_num = ptrace(PT_READ_D, cpid, (caddr_t)parm_offset, 0);
144206089Sfabient    parm_offset += sizeof(quad_t);
145206089Sfabient    break;
146206089Sfabient  }
147206089Sfabient
148206089Sfabient  fsc.number = syscall_num;
149206089Sfabient  fsc.name =
150206089Sfabient    (syscall_num < 0 || syscall_num > nsyscalls) ? NULL : syscallnames[syscall_num];
151206089Sfabient  if (!fsc.name) {
152206089Sfabient    fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
153206089Sfabient  }
154206089Sfabient
155206089Sfabient  if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
156206089Sfabient   && ((!strcmp(fsc.name, "fork")
157206089Sfabient    || !strcmp(fsc.name, "rfork")
158206089Sfabient    || !strcmp(fsc.name, "vfork"))))
159206089Sfabient  {
160206089Sfabient    trussinfo->curthread->in_fork = 1;
161206089Sfabient  }
162206089Sfabient
163206089Sfabient  if (nargs == 0)
164206089Sfabient    return;
165206089Sfabient
166206089Sfabient  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
167206089Sfabient  iorequest.piod_op = PIOD_READ_D;
168206089Sfabient  iorequest.piod_offs = (void *)parm_offset;
169206089Sfabient  iorequest.piod_addr = fsc.args;
170206089Sfabient  iorequest.piod_len = nargs * sizeof(unsigned long);
171206089Sfabient  ptrace(PT_IO, cpid, (caddr_t)&iorequest, 0);
172206089Sfabient  if (iorequest.piod_len == 0)
173206089Sfabient    return;
174206089Sfabient
175206089Sfabient  if (fsc.name)
176206089Sfabient  	sc = get_syscall(fsc.name);
177206089Sfabient  if (sc) {
178206089Sfabient    fsc.nargs = sc->nargs;
179206089Sfabient  } else {
180206089Sfabient#if DEBUG
181206089Sfabient    fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
182206089Sfabient	   fsc.name, nargs);
183206089Sfabient#endif
184206089Sfabient    fsc.nargs = nargs;
185206089Sfabient  }
186206089Sfabient
187206089Sfabient  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
188206089Sfabient  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
189206089Sfabient  fsc.sc = sc;
190206089Sfabient
191206089Sfabient  /*
192206089Sfabient   * At this point, we set up the system call arguments.
193206089Sfabient   * We ignore any OUT ones, however -- those are arguments that
194206089Sfabient   * are set by the system call, and so are probably meaningless
195206089Sfabient   * now.  This doesn't currently support arguments that are
196206089Sfabient   * passed in *and* out, however.
197206089Sfabient   */
198206089Sfabient
199206089Sfabient  if (fsc.name) {
200206089Sfabient
201206089Sfabient#if DEBUG
202206089Sfabient    fprintf(stderr, "syscall %s(", fsc.name);
203206089Sfabient#endif
204206089Sfabient    for (i = 0; i < fsc.nargs; i++) {
205206089Sfabient#if DEBUG
206206089Sfabient      fprintf(stderr, "0x%x%s",
207206089Sfabient	      sc
208206089Sfabient	      ? fsc.args[sc->args[i].offset]
209206089Sfabient	      : fsc.args[i],
210206089Sfabient	      i < (fsc.nargs - 1) ? "," : "");
211206089Sfabient#endif
212206089Sfabient      if (sc && !(sc->args[i].type & OUT)) {
213206089Sfabient	fsc.s_args[i] = print_arg(&sc->args[i], fsc.args, 0, trussinfo);
214206089Sfabient      }
215206089Sfabient    }
216206089Sfabient#if DEBUG
217206089Sfabient    fprintf(stderr, ")\n");
218206089Sfabient#endif
219206089Sfabient  }
220206089Sfabient
221206089Sfabient#if DEBUG
222206089Sfabient  fprintf(trussinfo->outfile, "\n");
223206089Sfabient#endif
224206089Sfabient
225206089Sfabient  if (fsc.name != NULL &&
226206089Sfabient      (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {
227206089Sfabient
228206089Sfabient    /* XXX
229206089Sfabient     * This could be done in a more general
230206089Sfabient     * manner but it still wouldn't be very pretty.
231206089Sfabient     */
232206089Sfabient    if (!strcmp(fsc.name, "execve")) {
233206089Sfabient        if ((trussinfo->flags & EXECVEARGS) == 0)
234206089Sfabient          if (fsc.s_args[1]) {
235206089Sfabient            free(fsc.s_args[1]);
236206089Sfabient            fsc.s_args[1] = NULL;
237206089Sfabient          }
238206089Sfabient        if ((trussinfo->flags & EXECVEENVS) == 0)
239206089Sfabient          if (fsc.s_args[2]) {
240206089Sfabient            free(fsc.s_args[2]);
241206089Sfabient            fsc.s_args[2] = NULL;
242206089Sfabient          }
243206089Sfabient    }
244206089Sfabient
245206089Sfabient  }
246206089Sfabient
247206089Sfabient  return;
248206089Sfabient}
249206089Sfabient
250206089Sfabient/*
251206089Sfabient * And when the system call is done, we handle it here.
252206089Sfabient * Currently, no attempt is made to ensure that the system calls
253206089Sfabient * match -- this needs to be fixed (and is, in fact, why S_SCX includes
254206089Sfabient * the sytem call number instead of, say, an error status).
255206089Sfabient */
256206089Sfabient
257206089Sfabientlong
258206089Sfabienti386_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused)
259206089Sfabient{
260206089Sfabient  struct reg regs;
261206089Sfabient  long retval;
262206089Sfabient  int i;
263206089Sfabient  int errorp;
264206089Sfabient  struct syscall *sc;
265206089Sfabient
266206089Sfabient  if (fsc.name == NULL)
267206089Sfabient    return (-1);
268206089Sfabient  cpid = trussinfo->curthread->tid;
269206089Sfabient
270206089Sfabient  if (ptrace(PT_GETREGS, cpid, (caddr_t)&regs, 0) < 0)
271206089Sfabient  {
272206089Sfabient    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
273206089Sfabient    return (-1);
274206089Sfabient  }
275206089Sfabient
276206089Sfabient  retval = regs.r_eax;
277206089Sfabient  errorp = !!(regs.r_eflags & PSL_C);
278206089Sfabient
279206089Sfabient  /*
280206089Sfabient   * This code, while simpler than the initial versions I used, could
281206089Sfabient   * stand some significant cleaning.
282206089Sfabient   */
283206089Sfabient
284206089Sfabient  sc = fsc.sc;
285206089Sfabient  if (!sc) {
286206089Sfabient    for (i = 0; i < fsc.nargs; i++)
287206089Sfabient      asprintf(&fsc.s_args[i], "0x%lx", fsc.args[i]);
288206089Sfabient  } else {
289206089Sfabient    /*
290206089Sfabient     * Here, we only look for arguments that have OUT masked in --
291206089Sfabient     * otherwise, they were handled in the syscall_entry function.
292206089Sfabient     */
293206089Sfabient    for (i = 0; i < sc->nargs; i++) {
294206089Sfabient      char *temp;
295206089Sfabient      if (sc->args[i].type & OUT) {
296206089Sfabient	/*
297206089Sfabient	 * If an error occurred, then don't bother getting the data;
298206089Sfabient	 * it may not be valid.
299206089Sfabient	 */
300206089Sfabient	if (errorp)
301206089Sfabient	  asprintf(&temp, "0x%lx", fsc.args[sc->args[i].offset]);
302206089Sfabient	else
303206089Sfabient	  temp = print_arg(&sc->args[i], fsc.args, retval, trussinfo);
304206089Sfabient	fsc.s_args[i] = temp;
305206089Sfabient      }
306206089Sfabient    }
307206089Sfabient  }
308206089Sfabient
309206089Sfabient  /*
310206089Sfabient   * The pipe syscall returns its fds in two registers and has assembly glue
311206089Sfabient   * to provide the libc API, so it cannot be handled like regular syscalls.
312206089Sfabient   * The nargs check is so we don't have to do yet another strcmp on every
313206089Sfabient   * syscall.
314206089Sfabient   */
315206089Sfabient  if (!errorp && fsc.nargs == 0 && fsc.name && strcmp(fsc.name, "pipe") == 0) {
316206089Sfabient      fsc.nargs = 1;
317206089Sfabient      fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
318206089Sfabient      asprintf(&fsc.s_args[0], "[%d,%d]", (int)retval, regs.r_edx);
319206089Sfabient      retval = 0;
320206089Sfabient  }
321206089Sfabient
322206089Sfabient  if (fsc.name != NULL &&
323206089Sfabient      (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit"))) {
324206089Sfabient	trussinfo->curthread->in_syscall = 1;
325206089Sfabient  }
326206089Sfabient
327206089Sfabient  /*
328206089Sfabient   * It would probably be a good idea to merge the error handling,
329206089Sfabient   * but that complicates things considerably.
330206089Sfabient   */
331206089Sfabient
332206089Sfabient  print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
333206089Sfabient  clear_fsc();
334206089Sfabient
335206089Sfabient  return (retval);
336206089Sfabient}
337206089Sfabient