ramsdell(a)mitre.org (John D. Ramsdell) writes:
The tricky part seems to be that the SIGTRAP generated by the
parent's immediate child has to be converted to a SIGSTOP before
continuing the child.
If you trace a shell, you find out you must always convert a SIGTRAP
to a SIGSTOP.
John
static int /* Watch all children */
watch(pid_t pid) /* This process' child is pid */
{ /* Function returns an exit code */
if (add_rule(pid))
return 1;
for (;;) {
int status;
pid = wait_for_it(&status);
if (pid < 0) {
if (errno == ECHILD) /* No children to wait for */
return 0; /* Declare success */
perror("wait");
return 1;
}
if (WIFSTOPPED(status)) {
int signal = WSTOPSIG(status);
if (signal == SIGTRAP) { /* Tracing causes this signal */
signal =
SIGSTOP;
unsigned long msg;
if (geteventmsg(pid, &msg) < 0) {
perror("ptrace(PTRACE_GETEVENTMSG, ...)");
return 1;
}
pid_t child = (pid_t)msg;
if (child) {
/* The child of each traced fork is noted here */
if (add_rule(child))
return 1;
}
/* Only this process' child gets to this location, and just
one time */
else if (setoptions(pid, PTRACE_O_TRACEFORK) < 0) {
perror("ptrace(PTRACE_SETOPTIONS, ...)");
return 1;
}
/* Wrong
else
signal = SIGSTOP;
*/
}
if (restart(pid, signal) < 0) {
perror("ptrace(PTRACE_CONT, ...)");
return 1;
}
}
}
}