Reputation: 23571
I couldn't trace fork / exec events when I attached to another process, the status
returned from waitpid was always zero (after right shift of 16 times).
I've successfully attached to bash shell, but whatever commands I ran, the status was always zero, so I didn't catch any fork or exec events:
#define PALL PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE \
| PTRACE_O_TRACEEXEC | PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACEEXIT
int main(int argc, char **argv)
{
pid_t child = 0;
int status = 0;
if (argc != 2) { ... }
child = atoi (argv[1]);
if (ptrace (PTRACE_ATTACH, child, 0, 0) < 0) { ... }
ptrace(PTRACE_SETOPTIONS, child, NULL, PALL);
ptrace(PTRACE_SYSCALL, child, NULL, NULL);
ptrace(PTRACE_CONT, child, NULL, NULL);
while(1) {
waitpid(child, &status, 0);
if(WIFEXITED(status))
break;
status >>= 16;
if (status != 0)
printf ("Status: %d\n", status >> 16);
ptrace(PTRACE_SYSCALL, child, NULL, NULL);
}
ptrace(PTRACE_DETACH, child, NULL, NULL);
return 0;
}
Upvotes: 1
Views: 1068
Reputation: 19395
the
status
returned from waitpid was always zero (after right shift of 16 times).
You shifted the status
bits not 16, but 32 times by doing status >>= 16
first and then printf (…, status >> 16);
so always 0
was printed. Also there are some less obvious flaws:
WIFSIGNALED
.wait
for and process them as well.PTRACE_SYSCALL
immediately preceding PTRACE_CONT
doesn't make sense.PTRACE_SETOPTIONS
may fail if PTRACE_ATTACH
has not yet completed, thus we must wait
.Considering all this, the program could look like
#include <stdio.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#define PALL PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE \
| PTRACE_O_TRACEEXEC | PTRACE_O_TRACEVFORKDONE | PTRACE_O_TRACEEXIT
int main(int argc, char **argv)
{
pid_t child, pid;
int status;
if (argc != 2) { return 2; }
child = atoi(argv[1]);
if (ptrace(PTRACE_ATTACH, child, 0, 0) < 0) { return 1; }
wait(NULL); // PTRACE_SETOPTIONS may work only after this
ptrace(PTRACE_SETOPTIONS, child, NULL, PALL);
ptrace(PTRACE_CONT, child, NULL, NULL);
while (pid = wait(&status), pid > 0)
{
if (WIFEXITED(status) || WIFSIGNALED(status))
{
if (pid == child) break;
printf("grandchild %d exited\n", pid);
continue;
}
if (status>>16)
printf("[%d] Status: %x\n", pid, status);
int signal = WSTOPSIG(status);
if (signal == SIGTRAP)
{ // system call or ptrace event
signal = 0;
if (status>>16)
printf("ptrace event: %d\n", status>>16);
}
ptrace(PTRACE_CONT, pid, 0, signal);
}
ptrace(PTRACE_DETACH, child, NULL, NULL);
return 0;
}
Upvotes: 1