main.c revision 31579
131567Ssef/*
231567Ssef * The main module for truss.  Suprisingly simple, but, then, the other
331567Ssef * files handle the bulk of the work.  And, of course, the kernel has to
431567Ssef * do a lot of the work :).
531567Ssef */
631567Ssef/*
731579Speter * $Id: main.c,v 1.1 1997/12/06 05:23:03 sef Exp $
831567Ssef */
931567Ssef
1031567Ssef#include <stdio.h>
1131567Ssef#include <stdlib.h>
1231567Ssef#include <string.h>
1331567Ssef#include <errno.h>
1431567Ssef#include <err.h>
1531567Ssef#include <signal.h>
1631567Ssef#include <fcntl.h>
1731579Speter#include <unistd.h>
1831567Ssef#include <sys/ioctl.h>
1931567Ssef#include <sys/pioctl.h>
2031567Ssef
2131567Ssefextern int setup_and_wait(char **);
2231567Ssefextern int start_tracing(int, int);
2331567Ssefextern void i386_syscall_entry(int, int);
2431567Ssefextern void i386_syscall_exit(int, int);
2531567Ssefextern void i386_linux_syscall_entry(int, int);
2631567Ssefextern void i386_linux_syscall_exit(int, int);
2731567Ssef
2831567Ssef/*
2931567Ssef * These should really be parameterized -- I don't like having globals,
3031567Ssef * but this is the easiest way, right now, to deal with them.
3131567Ssef */
3231567Ssef
3331567Ssefint pid = 0;
3431567Ssefint nosigs = 0;
3531567SsefFILE *outfile = stderr;
3631567Ssefchar *prog;
3731567Ssefint Procfd;
3831567Ssefchar progtype[50];	/* OS and type of executable */
3931567Ssef
4031567Ssefstatic inline void
4131567Ssefusage(void) {
4231567Ssef  fprintf(stderr, "usage:  %s [-o <file>] [-S] { [-p <pid> ] | "
4331567Ssef	  "[ <command> <args>] }\n", prog);
4431567Ssef  exit(1);
4531567Ssef}
4631567Ssef
4731567Ssefstruct ex_types {
4831567Ssef  char *type;
4931567Ssef  void (*enter_syscall)(int, int);
5031567Ssef  void (*exit_syscall)(int, int);
5131567Ssef} ex_types[] = {
5231567Ssef  { "FreeBSD a.out", i386_syscall_entry, i386_syscall_exit },
5331567Ssef  { "Linux ELF", i386_linux_syscall_entry, i386_linux_syscall_exit },
5431567Ssef  { 0, 0, 0 },
5531567Ssef};
5631567Ssef
5731567Ssef/*
5831567Ssef * Set the execution type.  This is called after every exec, and when
5931567Ssef * a process is first monitored.  The procfs pseudo-file "etype" has
6031567Ssef * the execution module type -- see /proc/curproc/etype for an example.
6131567Ssef */
6231567Ssef
6331567Ssefstatic struct ex_types *
6431567Ssefset_etype() {
6531567Ssef  struct ex_types *funcs;
6631567Ssef  char etype[24];
6731567Ssef  char progtype[32];
6831567Ssef  int fd;
6931567Ssef
7031567Ssef  sprintf(etype, "/proc/%d/etype", pid);
7131567Ssef  if ((fd = open(etype, O_RDONLY)) == -1) {
7231567Ssef    strcpy(progtype, "FreeBSD a.out");
7331567Ssef  } else {
7431567Ssef    int len = read(fd, progtype, sizeof(progtype));
7531567Ssef    progtype[len-1] = '\0';
7631567Ssef    close(etype);
7731567Ssef  }
7831567Ssef
7931567Ssef  for (funcs = ex_types; funcs->type; funcs++)
8031567Ssef    if (!strcmp(funcs->type, progtype))
8131567Ssef      break;
8231567Ssef
8331567Ssef  return funcs;
8431567Ssef}
8531567Ssef
8631567Ssefmain(int ac, char **av) {
8731567Ssef  int mask;
8831567Ssef  int c;
8931567Ssef  int i;
9031567Ssef  char **command;
9131567Ssef  struct procfs_status pfs;
9231567Ssef  char etype[25];
9331567Ssef  struct ex_types *funcs;
9431567Ssef  int fd;
9531567Ssef  int in_exec = 0;
9631567Ssef
9731567Ssef  prog = av[0];
9831567Ssef
9931567Ssef  while ((c = getopt(ac, av, "p:o:S")) != EOF) {
10031567Ssef    switch (c) {
10131567Ssef    case 'p':	/* specified pid */
10231567Ssef      pid = atoi(optarg);
10331567Ssef      break;
10431567Ssef    case 'o':	/* Specified output file */
10531567Ssef      if ((outfile = fopen(optarg, "w")) == NULL) {
10631567Ssef	fprintf (stderr, "%s:  cannot open %s\n", av[0], optarg);
10731567Ssef	exit(1);
10831567Ssef      }
10931567Ssef      break;
11031567Ssef    case 'S':	/* Don't trace signals */
11131567Ssef      nosigs = 1;
11231567Ssef      break;
11331567Ssef    default:
11431567Ssef      usage();
11531567Ssef    }
11631567Ssef  }
11731567Ssef
11831567Ssef  ac -= optind; av += optind;
11931567Ssef  if (ac && pid != 0)
12031567Ssef    usage();
12131567Ssef
12231567Ssef  /*
12331567Ssef   * If truss starts the process itself, it will ignore some signals --
12431567Ssef   * they should be passed off to the process, which may or may not
12531567Ssef   * exit.  If, however, we are examining an already-running process,
12631567Ssef   * then we restore the event mask on these same signals.
12731567Ssef   */
12831567Ssef
12931567Ssef  if (pid == 0) {	/* Start a command ourselves */
13031567Ssef    command = av;
13131567Ssef    pid = setup_and_wait(command);
13231567Ssef    signal(SIGINT, SIG_IGN);
13331567Ssef    signal(SIGTERM, SIG_IGN);
13431567Ssef    signal(SIGQUIT, SIG_IGN);
13531567Ssef  } else {
13631567Ssef    extern void restore_proc(int);
13731567Ssef    signal(SIGINT, restore_proc);
13831567Ssef    signal(SIGTERM, restore_proc);
13931567Ssef    signal(SIGQUIT, restore_proc);
14031567Ssef  }
14131567Ssef
14231567Ssef
14331567Ssef  /*
14431567Ssef   * At this point, if we started the process, it is stopped waiting to
14531567Ssef   * be woken up, either in exit() or in execve().
14631567Ssef   */
14731567Ssef
14831567Ssef  Procfd = start_tracing(pid, S_EXEC | S_SCE | S_SCX | S_CORE | S_EXIT |
14931567Ssef		     (nosigs ? 0 : S_SIG));
15031567Ssef  pfs.why = 0;
15131567Ssef
15231567Ssef  funcs = set_etype();
15331567Ssef  /*
15431567Ssef   * At this point, it's a simple loop, waiting for the process to
15531567Ssef   * stop, finding out why, printing out why, and then continuing it.
15631567Ssef   * All of the grunt work is done in the support routines.
15731567Ssef   */
15831567Ssef
15931567Ssef  do {
16031567Ssef    int val = 0;
16131567Ssef
16231567Ssef    if (ioctl(Procfd, PIOCWAIT, &pfs) == -1)
16331567Ssef      perror("PIOCWAIT top of loop");
16431567Ssef    else {
16531567Ssef      switch(i = pfs.why) {
16631567Ssef      case S_SCE:
16731567Ssef	funcs->enter_syscall(pid, pfs.val);
16831567Ssef	break;
16931567Ssef      case S_SCX:
17031567Ssef	/*
17131567Ssef	 * This is so we don't get two messages for an exec -- one
17231567Ssef	 * for the S_EXEC, and one for the syscall exit.  It also,
17331567Ssef	 * conveniently, ensures that the first message printed out
17431567Ssef	 * isn't the return-from-syscall used to create the process.
17531567Ssef	 */
17631567Ssef
17731567Ssef	if (in_exec) {
17831567Ssef	  in_exec = 0;
17931567Ssef	  break;
18031567Ssef	}
18131567Ssef	funcs->exit_syscall(pid, pfs.val);
18231567Ssef	break;
18331567Ssef      case S_SIG:
18431567Ssef	fprintf(outfile, "SIGNAL %d\n", pfs.val);
18531567Ssef	break;
18631567Ssef      case S_EXIT:
18731567Ssef	fprintf (outfile, "process exit, rval = %d\n", pfs.val);
18831567Ssef	break;
18931567Ssef      case S_EXEC:
19031567Ssef	funcs = set_etype();
19131567Ssef	in_exec = 1;
19231567Ssef	break;
19331567Ssef      default:
19431567Ssef	fprintf (outfile, "Process stopped because of:  %d\n", i);
19531567Ssef	break;
19631567Ssef      }
19731567Ssef    }
19831567Ssef    if (ioctl(Procfd, PIOCCONT, &val) == -1)
19931567Ssef      perror("PIOCCONT");
20031567Ssef  } while (pfs.why != S_EXIT);
20131567Ssef  return 0;
20231567Ssef}
203