| #include <errno.h> |
| #include <fcntl.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include <sys/types.h> |
| #include <sys/ptrace.h> |
| #include <sys/stat.h> |
| #include <sys/wait.h> |
| |
| #if defined(PTRACE_ATTACH) |
| #define ATTACH_REQUEST PTRACE_ATTACH |
| #define DETACH_REQUEST PTRACE_DETACH |
| #elif defined(PT_ATTACH) |
| #define ATTACH_REQUEST PT_ATTACH |
| #define DETACH_REQUEST PT_DETACH |
| #else |
| #error "Unsupported platform" |
| #endif |
| |
| bool writePid (const char* file_name, const pid_t pid) |
| { |
| char *tmp_file_name = (char *)malloc(strlen(file_name) + 16); |
| strcpy(tmp_file_name, file_name); |
| strcat(tmp_file_name, "_tmp"); |
| int fd = open (tmp_file_name, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); |
| if (fd == -1) |
| { |
| fprintf (stderr, "open(%s) failed: %s\n", tmp_file_name, strerror (errno)); |
| free(tmp_file_name); |
| return false; |
| } |
| char buffer[64]; |
| snprintf (buffer, sizeof(buffer), "%ld", (long)pid); |
| |
| bool res = true; |
| if (write (fd, buffer, strlen (buffer)) == -1) |
| { |
| fprintf (stderr, "write(%s) failed: %s\n", buffer, strerror (errno)); |
| res = false; |
| } |
| close (fd); |
| |
| if (rename (tmp_file_name, file_name) == -1) |
| { |
| fprintf (stderr, "rename(%s, %s) failed: %s\n", tmp_file_name, file_name, strerror (errno)); |
| res = false; |
| } |
| free(tmp_file_name); |
| |
| return res; |
| } |
| |
| void signal_handler (int) |
| { |
| } |
| |
| int main (int argc, char const *argv[]) |
| { |
| if (argc < 2) |
| { |
| fprintf (stderr, "invalid number of command line arguments\n"); |
| return 1; |
| } |
| |
| const pid_t pid = fork (); |
| if (pid == -1) |
| { |
| fprintf (stderr, "fork failed: %s\n", strerror (errno)); |
| return 1; |
| } |
| |
| if (pid > 0) |
| { |
| // Make pause call to return when a signal is received. Normally this happens when the |
| // test runner tries to terminate us. |
| signal (SIGHUP, signal_handler); |
| signal (SIGTERM, signal_handler); |
| if (ptrace (ATTACH_REQUEST, pid, NULL, 0) == -1) |
| { |
| fprintf (stderr, "ptrace(ATTACH) failed: %s\n", strerror (errno)); |
| } |
| else |
| { |
| if (writePid (argv[1], pid)) |
| pause (); // Waiting for the debugger trying attach to the child. |
| |
| if (ptrace (DETACH_REQUEST, pid, NULL, 0) != 0) |
| fprintf (stderr, "ptrace(DETACH) failed: %s\n", strerror (errno)); |
| } |
| |
| kill (pid, SIGTERM); |
| int status = 0; |
| if (waitpid (pid, &status, 0) == -1) |
| fprintf (stderr, "waitpid failed: %s\n", strerror (errno)); |
| } |
| else |
| { |
| // child inferior. |
| pause (); |
| } |
| |
| printf ("Exiting now\n"); |
| return 0; |
| } |