Skip to contentSkip to conversation

One other question

Linux-ia64 Weihaw CHUANG 3 participants 3 messages Apr 18, 2001

lore
Share & tools
lore
#0 lore raw

In regards to my previous email.

What I'm really trying to get at is, is there a method to single step instructions with user level interrupts?

-Wei

#1 lore raw

Hi,

Quoted 5 lines · Weihaw CHUANG

In regards to my previous email.

What I'm really trying to get at is, is there a method to single step instructions with user level interrupts?

I believe you can simply do this using the ptrace() system call and giving it the PTRACE_SINGLESTEP command. Look at arch/ia64/kernel/ptrace.c for more details.

Signature · 1 line
-Stephane
#2 lore raw
In reply to Weihaw CHUANG
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Stephane Eranian

Stephane> Hi, On Tue, Apr 17, 2001 at 10:11:19PM -0700, Weihaw

Quoted 4 lines · Stephane> CHUANG wrote:
Quoted 4 lines

In regards to my previous email.

What I'm really trying to get at is, is there a method to single step instructions with user level interrupts?

Stephane> I believe you can simply do this using the ptrace() system Stephane> call and giving it the PTRACE_SINGLESTEP command. Look at Stephane> arch/ia64/kernel/ptrace.c for more details.

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 <[email protected]>

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;
}