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