Tracing BSD System Calls
by Sean Eric Fagan


Example 1: 

garth% truss echo "Hello, World"
    returns 0x0 (0)
SYSCALL fstat
 0x1 0xefbfd7ec
    returns 0x0 (0)
SYSCALL readlink
 0x6cac 0xefbfd7d8 0x3f
    errno 2 'No such file or directory'
SYSCALL __syscall
 0xc5 0x0 0x0 0x1000 0x3 0x1002 0xffffffff 0x0
    returns 0x8009000 (134254592)
SYSCALL break
 0xc000
    returns 0x0 (0)
SYSCALL break
 0xe000
    returns 0x0 (0)
SYSCALL write
 0x1 0xc000 0xd
Hello, World
    returns 0xd (13)
SYSCALL exit
 0x0
process exit, rval = 0


Listing One
/* stopevent()
 * Stop a process because of a procfs event; stay stopped until p->p_step is 
 * cleared (cleared by PIOCCONT in procfs).
 */
void
stopevent(struct proc *p, unsigned int event, unsigned int val) {
  p->p_step = 1;
  do {
    p->p_xstat = val;
    p->p_stype = event;   /* Which event caused the stop? */
    wakeup(&p->p_stype);  /* Wake up any PIOCWAIT'ing procs */
    tsleep(&p->p_step, PWAIT, "stopevent", 0);
  } while (p->p_step);
}

Listing Two
/* New file sys/pioctl.h */
#include <sys/ioctl.h>
#if 0
struct procfs_status {
    int state;  /* 0 for running, 1 for stopped */
    int why;    /* what event, if any, proc stopped on */
    unsigned int    val;    /* Any extra data */
};
#else
struct procfs_status {
    int state;  /* Running, stopped, something else? */
    int flags;  /* Any flags */
    unsigned long   events; /* Events to stop on */
    int why;    /* What event, if any, proc stopped on */
    unsigned long   val;    /* Any extra data */
};
#endif

#define PIOCBIS _IOW('p', 1, unsigned int)  /* Set event flag */
#define PIOCBIC _IOW('p', 2, unsigned int)  /* Clear event flag */
#define PIOCSFL _IOR('p', 3, unsigned int)  /* Set flags */
            /* wait for proc to stop */
#define PIOCWAIT    _IOR('p', 4, struct procfs_status)
#define PIOCCONT    _IOW('p', 5, int)   /* Continue a process */
            /* Get proc status */
#define PIOCSTATUS  _IOW('p', 6, struct procfs_status)

#define S_EXEC  0x00000001  /* stop-on-exec */
#define S_SIG   0x00000002  /* stop-on-signal */
#define S_SCE   0x00000004  /* stop on syscall entry */
#define S_SCX   0x00000008  /* stop on syscall exit */
#define S_CORE  0x00000010  /* stop on coredump */
#define S_EXIT  0x00000020  /* stop on exit */


Listing Three
/* Part of procfs_vnops.c */
procfs_ioctl(ap)
    struct vop_ioctl_args *ap;
{
    struct pfsnode *pfs = VTOPFS(ap->a_vp);
    struct proc *procp;
    int error;
    int signo;
    struct procfs_status *psp;

    procp = pfind(pfs->pfs_pid);
    if (procp == NULL) {
        return ENOTTY;
    }
    switch (ap->a_command) {
    case PIOCBIS:
      procp->p_stops |= *(unsigned int*)ap->a_data;
      break;
    case PIOCBIC:
      procp->p_stops &= ~*(unsigned int*)ap->a_data;
      break;
    case PIOCSFL:
      procp->p_pfsflags = (unsigned char)*(unsigned int*)ap->a_data;
      *(unsigned int*)ap->a_data = procp->p_stops;
      break;
    case PIOCSTATUS:
      psp = (struct procfs_status *)ap->a_data;
      psp->state = (procp->p_step == 0);
      psp->flags = procp->p_pfsflags;
      psp->events = procp->p_stops;
      if (procp->p_step) {
        psp->why = procp->p_stype;
        psp->val = procp->p_xstat;
      } else {
        psp->why = psp->val = 0;    /* Not defined values */
      }
      break;
    case PIOCWAIT:
      psp = (struct procfs_status *)ap->a_data;
      if (procp->p_step == 0) {
        error = tsleep(&procp->p_stype, PWAIT | PCATCH, "piocwait", 0);
        if (error)
          return error;
      }
      psp->state = 1;   /* It stopped */
      psp->flags = procp->p_pfsflags;
      psp->events = procp->p_stops;
      psp->why = procp->p_stype;    /* why it stopped */
      psp->val = procp->p_xstat;    /* any extra info */
      break;
    case PIOCCONT:  /* Restart a proc */
      if (procp->p_step == 0)
        return EINVAL;  /* Can only start a stopped process */
      if (ap->a_data && (signo = *(int*)ap->a_data)) {
        if (signo >= NSIG || signo <= 0)
          return EINVAL;
        if (error = psignal(procp, signo))
          return error;
      }
      procp->p_step = 0;
      wakeup(&procp->p_step);
      break;
    default:
      return (ENOTTY);
    }
    return 0;
 }



4


