#include #include #include #include #include #include #include #include #include #include #define WAITOPTS WEXITED | WSTOPPED | WCONTINUED #define SYSASSERT(_expr) \ if ((_expr) < 0) { \ fprintf (stderr, "assertion error: %s: %s\n", \ #_expr, strerror (errno)); \ abort (); \ } void print_siginfo (siginfo_t *info) { printf (" si_pid: %d\n", info->si_pid); printf (" si_uid: %d\n", info->si_uid); printf (" si_signo: %d\n", info->si_signo); printf (" si_status: %d (%d %d)\n", info->si_status, info->si_status & 0x7f, info->si_status >> 8); if ((info->si_status >> 8) == 1) printf (" PTRACE_EVENT_FORK\n"); if ((info->si_status >> 8) == 4) printf (" PTRACE_EVENT_EXEC\n"); switch (info->si_code) { case CLD_EXITED: printf (" si_code: CLD_EXITED\n"); break; case CLD_KILLED: printf (" si_code: CLD_KILLED\n"); break; case CLD_STOPPED: printf (" si_code: CLD_STOPPED\n"); break; case CLD_CONTINUED: printf (" si_code: CLD_CONTINUED\n"); break; case CLD_DUMPED: printf (" si_code: CLD_DUMPED\n"); break; case CLD_TRAPPED: printf (" si_code: CLD_TRAPPED\n"); break; default: printf (" si_code: %d\n", info->si_code); } } int main (int argc, char *argv[]) { pid_t pid; siginfo_t info; pid = fork (); assert (pid >= 0); if (pid == 0) { printf ("child %d\n", getpid ()); fflush (stdout); SYSASSERT (ptrace (PTRACE_TRACEME, 0, NULL, NULL)); printf ("ptrace_traceme set\n"); fflush (stdout); raise (SIGSTOP); printf ("child exited\n"); fflush (stdout); exit (0); } printf ("wait for process to stop\n"); SYSASSERT (waitid (P_PID, pid, &info, WAITOPTS | WNOWAIT)); print_siginfo (&info); fflush (stdout); SYSASSERT (waitid (P_PID, pid, &info, WAITOPTS)); printf ("set ptrace options\n"); fflush (stdout); SYSASSERT (ptrace (PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACESYSGOOD)); SYSASSERT (ptrace (PTRACE_CONT, pid, NULL, SIGCONT)); printf ("wait for process to exit\n"); SYSASSERT (waitid (P_PID, pid, &info, WAITOPTS)); print_siginfo (&info); fflush (stdout); return 0; }