utrace.c

utrace is a program written by David Mosberger to demonstrate the use of ptrace() on IA64. It was posted to the linux-ia64 mailing lists, and is provided below.

/*
That's correct.  I'm attaching a small test program I wrote a while
ago.  It shows how to single step individual instructions, basic
blocks, and system calls.

        --david
*/

/*
    utrace -- micro tracing tool 
    Copyright (C) 1999-2001  Hewlett-Packard Company
    Contributed by David Mosberger-Tang <davidm@hpl.hp.com>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA
*/

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include <sys/ptrace.h>
#include <sys/wait.h>

char *prog_name;

#if defined(__ia64__)

#include <asm/fpu.h>
#include <asm/ptrace.h>
#include <asm/ptrace_offsets.h>
#include <asm/rse.h>

int singlestep;

static inline double
fpreg_to_double (struct ia64_fpreg *fp)
{
  double result;

  asm ("ldf.fill %0=%1" : "=f"(result) : "m"(*fp));
  return result;
}

void
print_syscall (int child_pid, int state)
{
  long scnum, result, error, val;
#if 0
  struct ia64_fpreg fp;
#endif
  unsigned long bsp;
  int i;

  if (state == 0)
    return;

  errno = 0;
  scnum = ptrace (PTRACE_PEEKUSER, child_pid, PT_R15, 0);
  result = ptrace (PTRACE_PEEKUSER, child_pid, PT_R8, 0);
  error = ptrace (PTRACE_PEEKUSER, child_pid, PT_R10, 0);
  bsp = ptrace (PTRACE_PEEKUSER, child_pid, PT_AR_BSP, 0);

#if 0
  fp.u.bits[0] = ptrace (PTRACE_PEEKUSER, child_pid, PT_F32 + 0, 0);
  fp.u.bits[1] = ptrace (PTRACE_PEEKUSER, child_pid, PT_F32 + 8, 0);
  printf ("f32=%f\n", fpreg_to_double (&fp));
#endif

  if (errno)
    {
      printf ("%s: ptrace() failed, errno=%d\n", prog_name, errno);
      return;
    }
  printf ("<sc%04ld(", scnum);

  for (i = 0; i < 4; ++i)
    {
      val = ptrace (PTRACE_PEEKDATA, child_pid,
                    (long) ia64_rse_skip_regs ((long *) bsp, i), 0);
      printf ("%lx,", val);
    }

  if (error)
    printf ("...) -> errno=%ld\n", result);
  else
    printf ("...) -> %ld\n", result);
}

void
print_state (int child_pid, int with_slot)
{
  long ip, slot;

  ip = ptrace (PTRACE_PEEKUSER, child_pid, PT_CR_IIP, 0);
  if (with_slot)
    {
      slot = (ptrace (PTRACE_PEEKUSER, child_pid, PT_CR_IPSR, 0) >> 41) & 0x3;
      printf ("%016lx:%ld\n", ip, slot);
    }
  else
    printf ("%016lx\n", ip);
}

#elif defined(__i386__)

void
print_syscall (int child_pid, int state)
{
  int scnum, result;

  scnum = ptrace (PTRACE_PEEKUSER, child_pid, 11*4, 0); /* read EAX */
  errno = 0;
  result = ptrace (PTRACE_PEEKUSER, child_pid, 6*4, 0); /* read ORIG_EAX */

  if (result == -ENOSYS)
    return;

  if (errno)
    {
      printf ("%s: ptrace() failed, errno=%d\n", prog_name, errno);
      return;
    }
  printf ("<sc%03d>() -> %d\n", scnum, result);
}

#else
# error Sorry, you're architecture isn't supported.
#endif

int
main (int argc, char **argv, char **envp)
{
  int status, pid, child_pid, state = 1, arg;

  prog_name = argv[0];

  if (argc < 2 || strcmp (argv[1], "-h") == 0)
    {
      printf ("Usage: %s [-abB] command args...\n", prog_name);
      printf ("  -a: trace instruction execution\n");
      printf ("  -b: trace basic block execution\n");
      printf ("  -s: trace system call execution (default)\n");
      exit (-1);
    }

  arg = 1;
  if (strcmp (argv[arg], "-a") == 0)
    {
      singlestep = 1;
      ++arg;
    }
  if (strcmp (argv[arg], "-b") == 0)
    {
      singlestep = 2;
      ++arg;
    }
  if (strcmp (argv[arg], "-s") == 0)
    {
      singlestep = 0;
      ++arg;
    }

  child_pid = fork ();
  if (child_pid == 0)
    {
      ptrace (PTRACE_TRACEME, 0, 0, 0);
      execve (argv[arg], argv + arg, envp);
      printf ("%s: execve failed (errno=%d)\n", prog_name, errno);
      exit (-2);
    }

  while (1)
    {
      pid = wait4 (-1, &status, 0, 0);
      if (pid == -1)
        {
          if (errno == EINTR)
            continue;

          printf ("%s: wait4() failed (errno=%d)\n", prog_name, errno);
        }
      if (WIFSIGNALED (status) || WIFEXITED (status)
          || (WIFSTOPPED (status) && WSTOPSIG (status) != SIGTRAP))
        {
          if (WIFEXITED (status))
            {
              printf ("%s: exit status %d\n", prog_name, WEXITSTATUS (status));
              break;
            }
          else if (WIFSIGNALED (status))
            {
              printf ("%s: terminated by signal %d\n",
                      prog_name, WTERMSIG (status));
            }
          else
            printf ("%s: got signal %d\n", prog_name, WSTOPSIG (status));
        }

      if (singlestep)
        {
          /* single stepping through program: */
          if (singlestep == 2)
            {
              print_state (child_pid, 0);
              ptrace (PTRACE_SINGLEBLOCK, child_pid, 0, 0);
            }
          else
            {
              print_state (child_pid, 1);
              ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0);
            }
        }
      else
        {
          /* syscall tracing */
          print_syscall (child_pid, state);
          state = (state + 1) & 1;
          ptrace (PTRACE_SYSCALL, child_pid, 0, 0);             /* continue */
        }
    }
  return 0;
}

IA64wiki: utrace (last edited 2009-12-10 03:14:01 by localhost)

Gelato@UNSW is sponsored by
the University of New South Wales National ICT Australia The Gelato Federation Hewlett-Packard Company Australian Research Council
Please contact us with any questions or comments.