I am trying to code a program that traces itself for system calls. I am having a difficult time making this work. I tried calling a fork() to create an instance of itself (the c
The problem is that when the child calls ptrace(TRACEME)
it sets itself up for tracing but doesn't actually stop -- it keeps going until it calls exec
(in which case it stops with a SIGTRAP), or it gets some other signal. So in order for you to have the parent see what it does WITHOUT an exec call, you need to arrange for the child to receive a signal. The easiest way to do that is probably to have the child call raise(SIGCONT);
(or any other signal) immediately after calling ptrace(TRACEME)
Now in the parent you just wait (once) and assume that the child is now stopped at a system call. This won't be the case if it stopped at a signal, so you instead need to call wait(&status)
to get the child status and call WIFSTOPPED(status)
and WSTOPSIG(status)
to see WHY it has stopped. If it has stopped due to a syscall, the signal will be SIGTRAP.
If you want to see multiple system calls in the client, you'll need to do all of this in a loop; something like:
while(1) {
wait(&status);
if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGTRAP) {
// stopped before or after a system call -- query the child and print out info
}
if (WIFEXITED(status) || WIFSIGNALED(status)) {
// child has exited or terminated
break;
}
ptrace(PTRACE_SYSCALL, 0, 0, 0); // ignore any signal and continue the child
}
Note that it will stop TWICE for each system call -- once before the system call and a second time just after the system call completes.