#include #include #include #include #include #include #include #include #define ERRCHECK(E)\ if ((E) == -1) {perror(argv[0]); kill(pid, SIGHUP); return -1;} int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "usage: %s COMMAND [ARGS]...\n" , argv[0]); return -1; } pid_t pid = fork(); if (pid == -1) { perror(argv[0]); return -1; } if (pid == 0) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); raise(SIGSTOP); if (execvp(argv[1], argv + 1) == -1) { perror(argv[0]); return -1; } } else { ERRCHECK(ptrace(PTRACE_ATTACH, pid, NULL, NULL)); int status; pid_t w = waitpid(pid, &status, __WALL); ERRCHECK(w); ERRCHECK(ptrace(PTRACE_CONT, pid, NULL, NULL)); while (1) { pid_t w = waitpid(pid, &status, __WALL); ERRCHECK(w); if (WIFEXITED(status)) return WEXITSTATUS(status); if (WIFSTOPPED(status)) { if (WIFSIGNALED(status)) { errno = 0; switch (WSTOPSIG(status)) { case SIGABRT: case SIGBUS: case SIGFPE: case SIGILL: case SIGSEGV: ptrace(PTRACE_CONT, pid, NULL, NULL); break; default: ptrace(PTRACE_CONT, pid, NULL, WSTOPSIG(status)); break; } if (errno && errno != ESRCH) { perror("ptrace"); kill(pid, SIGHUP); return -1; } } else ptrace(PTRACE_CONT, pid, NULL, NULL); } } } }