ia64-fbsd.c revision 111176
174462Salfred/*
274462Salfred * Copryight 1997 Sean Eric Fagan
3258578Shrs *
4258578Shrs * Redistribution and use in source and binary forms, with or without
5258578Shrs * modification, are permitted provided that the following conditions
6258578Shrs * are met:
7258578Shrs * 1. Redistributions of source code must retain the above copyright
8258578Shrs *    notice, this list of conditions and the following disclaimer.
9258578Shrs * 2. Redistributions in binary form must reproduce the above copyright
10258578Shrs *    notice, this list of conditions and the following disclaimer in the
11258578Shrs *    documentation and/or other materials provided with the distribution.
12258578Shrs * 3. All advertising materials mentioning features or use of this software
13258578Shrs *    must display the following acknowledgement:
14258578Shrs *	This product includes software developed by Sean Eric Fagan
15258578Shrs * 4. Neither the name of the author may be used to endorse or promote
16258578Shrs *    products derived from this software without specific prior written
1774462Salfred *    permission.
18258578Shrs *
19258578Shrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20258578Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21258578Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22258578Shrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23258578Shrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24258578Shrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25258578Shrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26258578Shrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27258578Shrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28258578Shrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2974462Salfred * SUCH DAMAGE.
3074462Salfred */
3174462Salfred
3274462Salfred#ifndef lint
3374462Salfredstatic const char rcsid[] =
34136581Sobrien  "$FreeBSD: head/usr.bin/truss/ia64-fbsd.c 111176 2003-02-20 15:05:39Z ru $";
35136581Sobrien#endif /* not lint */
3674462Salfred
3774462Salfred/*
3892990Sobrien * FreeBSD/ia64-specific system call handling.  This is probably the most
3992990Sobrien * complex part of the entire truss program, although I've got lots of
4074462Salfred * it handled relatively cleanly now.  The system call names are generated
4174462Salfred * automatically, thanks to /usr/src/sys/kern/syscalls.master.  The
4274462Salfred * names used for the various structures are confusing, I sadly admit.
4374462Salfred */
4474462Salfred
4575094Siedowse#include <sys/types.h>
4674462Salfred#include <sys/ioctl.h>
4774462Salfred#include <sys/pioctl.h>
48105189Siedowse#include <sys/syscall.h>
4974462Salfred
5074462Salfred#include <machine/reg.h>
5174462Salfred
5290868Smike#include <errno.h>
5374462Salfred#include <fcntl.h>
54181344Sdfr#include <signal.h>
5574462Salfred#include <stdio.h>
5674462Salfred#include <stdlib.h>
5774462Salfred#include <string.h>
5874462Salfred#include <time.h>
5974462Salfred#include <unistd.h>
6074462Salfred
6174462Salfred#include "truss.h"
6274462Salfred#include "syscall.h"
63156090Sdeischen#include "extern.h"
6474462Salfred
6574462Salfredstatic int fd = -1;
66167199Ssimonstatic int cpid = -1;
67167199Ssimonextern int Procfd;
68167199Ssimon
69167199Ssimon#include "syscalls.h"
70167199Ssimon
71167199Ssimonstatic int nsyscalls = sizeof(syscallnames) / sizeof(syscallnames[0]);
7274462Salfred
73167199Ssimon/*
7474462Salfred * This is what this particular file uses to keep track of a system call.
7574462Salfred * It is probably not quite sufficient -- I can probably use the same
7692905Sobrien * structure for the various syscall personalities, and I also probably
7792905Sobrien * need to nest system calls (for signal handlers).
7895658Sdes *
7995658Sdes * 'struct syscall' describes the system call; it may be NULL, however,
8092905Sobrien * if we don't know about this particular system call yet.
8195658Sdes */
8292905Sobrienstatic struct freebsd_syscall {
8399996Salfred	struct syscall *sc;
8492905Sobrien	const char *name;
8574462Salfred	int number;
8674462Salfred	unsigned long *args;
8774462Salfred	int nargs;	/* number of arguments -- *not* number of words! */
8874462Salfred	char **s_args;	/* the printable arguments */
8974462Salfred} fsc;
9074462Salfred
9174462Salfred/* Clear up and free parts of the fsc structure. */
9274462Salfredstatic __inline void
9374462Salfredclear_fsc(void) {
9474462Salfred  if (fsc.args) {
9574462Salfred    free(fsc.args);
9674462Salfred  }
9774462Salfred  if (fsc.s_args) {
9874462Salfred    int i;
9974462Salfred    for (i = 0; i < fsc.nargs; i++)
10074462Salfred      if (fsc.s_args[i])
10174462Salfred	free(fsc.s_args[i]);
10274462Salfred    free(fsc.s_args);
10374462Salfred  }
10474462Salfred  memset(&fsc, 0, sizeof(fsc));
10574462Salfred}
10675144Siedowse
10774462Salfred/*
108105189Siedowse * Called when a process has entered a system call.  nargs is the
10974462Salfred * number of words, not number of arguments (a necessary distinction
11074462Salfred * in some cases).  Note that if the STOPEVENT() code in ia64/ia64/trap.c
11174462Salfred * is ever changed these functions need to keep up.
11274462Salfred */
11374462Salfred
11474462Salfredvoid
11574462Salfredia64_syscall_entry(struct trussinfo *trussinfo, int nargs) {
116181344Sdfr  char buf[32];
117181344Sdfr  struct reg regs;
11874462Salfred  int syscall_num;
11974462Salfred  int i;
12074462Salfred  unsigned int parm_offset;
12174462Salfred  struct syscall *sc;
12274462Salfred
12374462Salfred  if (fd == -1 || trussinfo->pid != cpid) {
12474462Salfred    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
12574462Salfred    fd = open(buf, O_RDWR);
12674462Salfred    if (fd == -1) {
12774462Salfred      fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n");
12874462Salfred      return;
12974462Salfred    }
13074462Salfred    cpid = trussinfo->pid;
13174462Salfred  }
132181344Sdfr
13374462Salfred  clear_fsc();
13474462Salfred  lseek(fd, 0L, 0);
13574879Swpaul  if (read(fd, &regs, sizeof(regs)) != sizeof(regs)) {
13678678Siedowse    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
13778678Siedowse    return;
138105189Siedowse  }
139105189Siedowse  parm_offset = regs.r_gr[12] + 16;
14074462Salfred
14174462Salfred  /*
14274462Salfred   * FreeBSD has two special kinds of system call redirctions --
14374462Salfred   * SYS_syscall, and SYS___syscall.  The former is the old syscall()
14474462Salfred   * routine, basicly; the latter is for quad-aligned arguments.
14574462Salfred   */
14674462Salfred  syscall_num = regs.r_gr[15];
14774462Salfred  switch (syscall_num) {
14874462Salfred  case SYS_syscall:
14974462Salfred    lseek(Procfd, parm_offset, SEEK_SET);
15074462Salfred    read(Procfd, &syscall_num, sizeof(int));
15174462Salfred    parm_offset += sizeof(int);
15274462Salfred    break;
15374462Salfred  case SYS___syscall:
15474462Salfred    lseek(Procfd, parm_offset, SEEK_SET);
15574462Salfred    read(Procfd, &syscall_num, sizeof(int));
156287341Srodrigc    parm_offset += sizeof(quad_t);
157287341Srodrigc    break;
158287341Srodrigc  }
159287341Srodrigc
160287341Srodrigc  fsc.number = syscall_num;
161287341Srodrigc  fsc.name = (syscall_num < 0 || syscall_num > nsyscalls)
162287341Srodrigc      ? NULL : syscallnames[syscall_num];
16374462Salfred  if (!fsc.name) {
16474462Salfred    fprintf(trussinfo->outfile, "-- UNKNOWN SYSCALL %d --\n", syscall_num);
165287341Srodrigc  }
166287341Srodrigc
16774462Salfred  if (fsc.name && (trussinfo->flags & FOLLOWFORKS)
16874462Salfred   && ((!strcmp(fsc.name, "fork")
16974462Salfred    || !strcmp(fsc.name, "rfork")
17074462Salfred    || !strcmp(fsc.name, "vfork"))))
17174462Salfred  {
17274462Salfred    trussinfo->in_fork = 1;
17374462Salfred  }
17474462Salfred
17574462Salfred  if (nargs == 0)
17674462Salfred    return;
17774462Salfred
17874462Salfred  fsc.args = malloc((1+nargs) * sizeof(unsigned long));
17974462Salfred  lseek(Procfd, parm_offset, SEEK_SET);
18074462Salfred  if (read(Procfd, fsc.args, nargs * sizeof(unsigned long)) == -1)
18174462Salfred    return;
18274462Salfred
18374462Salfred  sc = get_syscall(fsc.name);
18474462Salfred  if (sc) {
18574462Salfred    fsc.nargs = sc->nargs;
18674462Salfred  } else {
18774462Salfred#if DEBUG
18874462Salfred    fprintf(trussinfo->outfile, "unknown syscall %s -- setting args to %d\n",
18974462Salfred	   fsc.name, nargs);
19074462Salfred#endif
19174462Salfred    fsc.nargs = nargs;
19274462Salfred  }
19374462Salfred
19474462Salfred  fsc.s_args = malloc((1+fsc.nargs) * sizeof(char*));
19574462Salfred  memset(fsc.s_args, 0, fsc.nargs * sizeof(char*));
19674462Salfred  fsc.sc = sc;
19774462Salfred
19874462Salfred  /*
19974462Salfred   * At this point, we set up the system call arguments.
20074462Salfred   * We ignore any OUT ones, however -- those are arguments that
20174462Salfred   * are set by the system call, and so are probably meaningless
20274462Salfred   * now.  This doesn't currently support arguments that are
20374462Salfred   * passed in *and* out, however.
20474462Salfred   */
20574462Salfred
20674462Salfred  if (fsc.name) {
20774462Salfred
20874462Salfred#if DEBUG
20974462Salfred    fprintf(stderr, "syscall %s(", fsc.name);
21074462Salfred#endif
21174462Salfred    for (i = 0; i < fsc.nargs; i++) {
21274462Salfred#if DEBUG
21374462Salfred      fprintf(stderr, "0x%x%s",
21474462Salfred	      sc
21574462Salfred	      ? fsc.args[sc->args[i].offset]
21674462Salfred	      : fsc.args[i],
21774462Salfred	      i < (fsc.nargs - 1) ? "," : "");
21874462Salfred#endif
21974462Salfred      if (sc && !(sc->args[i].type & OUT)) {
22074462Salfred	fsc.s_args[i] = print_arg(Procfd, &sc->args[i], fsc.args);
22174462Salfred      }
22274462Salfred    }
22374462Salfred#if DEBUG
22474462Salfred    fprintf(stderr, ")\n");
22574462Salfred#endif
22674462Salfred  }
22774462Salfred
22874462Salfred#if DEBUG
22974462Salfred  fprintf(trussinfo->outfile, "\n");
23074462Salfred#endif
23174462Salfred
23274462Salfred  /*
23374462Salfred   * Some system calls should be printed out before they are done --
23474462Salfred   * execve() and exit(), for example, never return.  Possibly change
23574462Salfred   * this to work for any system call that doesn't have an OUT
23674462Salfred   * parameter?
23774462Salfred   */
23874462Salfred
23974462Salfred  if (!strcmp(fsc.name, "execve") || !strcmp(fsc.name, "exit")) {
24074462Salfred
24174462Salfred    /* XXX
24274462Salfred     * This could be done in a more general
24374462Salfred     * manner but it still wouldn't be very pretty.
24474462Salfred     */
24574462Salfred    if (!strcmp(fsc.name, "execve")) {
24674462Salfred        if ((trussinfo->flags & EXECVEARGS) == 0)
24774462Salfred          if (fsc.s_args[1]) {
24874462Salfred            free(fsc.s_args[1]);
24974462Salfred            fsc.s_args[1] = NULL;
25074462Salfred          }
25174462Salfred        if ((trussinfo->flags & EXECVEENVS) == 0)
25274462Salfred          if (fsc.s_args[2]) {
25374462Salfred            free(fsc.s_args[2]);
25474879Swpaul            fsc.s_args[2] = NULL;
25578678Siedowse          }
25678678Siedowse    }
25774462Salfred
25874462Salfred    print_syscall(trussinfo, fsc.name, fsc.nargs, fsc.s_args);
25974462Salfred    fprintf(trussinfo->outfile, "\n");
26074462Salfred  }
261181344Sdfr
262181344Sdfr  return;
263181344Sdfr}
26474462Salfred
26574462Salfred/*
26674462Salfred * And when the system call is done, we handle it here.
26774462Salfred * Currently, no attempt is made to ensure that the system calls
26874462Salfred * match -- this needs to be fixed (and is, in fact, why S_SCX includes
269181344Sdfr * the sytem call number instead of, say, an error status).
270181344Sdfr */
27174462Salfred
27274462Salfredint
27374462Salfredia64_syscall_exit(struct trussinfo *trussinfo, int syscall_num __unused) {
27474462Salfred  char buf[32];
27574462Salfred  struct reg regs;
27674462Salfred  int retval;
27774462Salfred  int i;
27874462Salfred  int errorp;
27974462Salfred  struct syscall *sc;
28074462Salfred
28174462Salfred  if (fd == -1 || trussinfo->pid != cpid) {
28274462Salfred    sprintf(buf, "/proc/%d/regs", trussinfo->pid);
28374462Salfred    fd = open(buf, O_RDONLY);
28474462Salfred    if (fd == -1) {
28574462Salfred      fprintf(trussinfo->outfile, "-- CANNOT OPEN REGISTERS --\n");
28674462Salfred      return (-1);
28774462Salfred    }
28874462Salfred    cpid = trussinfo->pid;
28974462Salfred  }
290105189Siedowse
291105189Siedowse  lseek(fd, 0L, 0);
29274462Salfred  if (read(fd, &regs, sizeof(regs)) != sizeof(regs)) {
29374462Salfred    fprintf(trussinfo->outfile, "-- CANNOT READ REGISTERS --\n");
29474462Salfred    return (-1);
29574462Salfred  }
29674462Salfred  retval = regs.r_gr[8];
29774462Salfred  errorp = (regs.r_gr[10] != 0) ? 1 : 0;
29874462Salfred
29974462Salfred  /*
30074462Salfred   * This code, while simpler than the initial versions I used, could
30174462Salfred   * stand some significant cleaning.
30274462Salfred   */
30374462Salfred
30474462Salfred  sc = fsc.sc;
30574462Salfred  if (!sc) {
306287341Srodrigc    for (i = 0; i < fsc.nargs; i++) {
307287341Srodrigc      fsc.s_args[i] = malloc(12);
308287341Srodrigc      sprintf(fsc.s_args[i], "0x%lx", fsc.args[i]);
309287341Srodrigc    }
310287341Srodrigc  } else {
311287341Srodrigc    /*
312287341Srodrigc     * Here, we only look for arguments that have OUT masked in --
313287341Srodrigc     * otherwise, they were handled in the syscall_entry function.
314287341Srodrigc     */
31574462Salfred    for (i = 0; i < sc->nargs; i++) {
316287341Srodrigc      char *temp;
317287341Srodrigc      if (sc->args[i].type & OUT) {
31874462Salfred	/*
31974462Salfred	 * If an error occurred, than don't bothe getting the data;
32074462Salfred	 * it may not be valid.
321105189Siedowse	 */
32274462Salfred	if (errorp) {
32374462Salfred	  temp = malloc(12);
32474462Salfred	  sprintf(temp, "0x%lx", fsc.args[sc->args[i].offset]);
32574462Salfred	} else {
326181344Sdfr	  temp = print_arg(Procfd, &sc->args[i], fsc.args);
32774462Salfred	}
32874462Salfred	fsc.s_args[i] = temp;
329105189Siedowse      }
330105189Siedowse    }
331105189Siedowse  }
33278678Siedowse
33374462Salfred  /*
33474462Salfred   * It would probably be a good idea to merge the error handling,
335278932Spfg   * but that complicates things considerably.
33674462Salfred   */
337105189Siedowse
33874879Swpaul  print_syscall_ret(trussinfo, fsc.name, fsc.nargs, fsc.s_args, errorp, retval);
33974462Salfred  clear_fsc();
34090271Salfred
34174462Salfred  return (retval);
34274462Salfred}
34374462Salfred