Hello everybody,

I noticed a very strange phenomenon - not sure if it's caused by ptrace, but I cannot understand why is it happening...

Here is a simple example (the code is attached below): trace a very simple process (even "Hello World!" will do) with PTRACE_SINGLESTEP and count # of steps. The number of steps varies from run to run! For example, when tracing "echo foo":

$ ./test echo foo
foo
instr = 138191
$ ./test echo foo
foo
instr = 138191
$ ./test echo foo
foo
instr = 138184
$ ./test echo foo
foo
instr = 138188
$ ./test echo foo
foo
instr = 138184

and so on...

It seems to happen only when tracee is 32 bit and is dynamically linked. For 64 bit and/or statically linked tracees the results are always consistent. It also seems that the variation occurs at the early stage, prior to the first tracee's system call. Apparently, it is system-dependent: I see it on my both Fedora systems (2.6.27.21-78.2.41.fc9.x86_64 and 2.6.27.12-170.2.5.fc10.i686) but not on Ubuntu (Linux 2.6.24-23-generic). Turning off address space randomization did not help.

Is this an expected behavior?

Thank you in advance!

Best,

Roni.

// Usage: ./test <tracee-and-its-args>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <sys/ptrace.h>
#include <sys/wait.h>

using namespace std;

static inline void error_exit()
{
  cerr << strerror(errno) << endl;
  exit(-1);
}


int main(int argc, char **argv)
{
  int status;
  pid_t pid;
  unsigned long long instr = 0;

  argv++;
  pid = fork();

  if(pid == 0)
    {
      if((ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) || (execvp(*argv, argv)))
	error_exit();
    }
  else
    {
      if((pid == -1) || (waitpid(pid, &status, 0) != pid) ||
	 (WIFEXITED(status)))
	error_exit();

      while((ptrace(PTRACE_SINGLESTEP, pid, 0, 0) == 0) && 
	    (waitpid(pid, &status, 0) == pid) && (!WIFEXITED(status)))
	{
	  instr++;
	}

      if(!WIFEXITED(status))
	error_exit();
      
      cout << "instr = " << instr << endl;
    }

  return 0;
}

Reply via email to