1 #include <errno.h>
2 #include <fcntl.h>
3 #include <signal.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 
9 #include <sys/types.h>
10 #include <sys/ptrace.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 
14 #if defined(PTRACE_ATTACH)
15 #define ATTACH_REQUEST PTRACE_ATTACH
16 #define DETACH_REQUEST PTRACE_DETACH
17 #elif defined(PT_ATTACH)
18 #define ATTACH_REQUEST PT_ATTACH
19 #define DETACH_REQUEST PT_DETACH
20 #else
21 #error "Unsupported platform"
22 #endif
23 
writePid(const char * file_name,const pid_t pid)24 bool writePid (const char* file_name, const pid_t pid)
25 {
26     char *tmp_file_name = (char *)malloc(strlen(file_name) + 16);
27     strcpy(tmp_file_name, file_name);
28     strcat(tmp_file_name, "_tmp");
29     int fd = open (tmp_file_name, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR);
30     if (fd == -1)
31     {
32         fprintf (stderr, "open(%s) failed: %s\n", tmp_file_name, strerror (errno));
33         free(tmp_file_name);
34         return false;
35     }
36     char buffer[64];
37     snprintf (buffer, sizeof(buffer), "%ld", (long)pid);
38 
39     bool res = true;
40     if (write (fd, buffer, strlen (buffer)) == -1)
41     {
42         fprintf (stderr, "write(%s) failed: %s\n", buffer, strerror (errno));
43         res = false;
44     }
45     close (fd);
46 
47     if (rename (tmp_file_name, file_name) == -1)
48     {
49         fprintf (stderr, "rename(%s, %s) failed: %s\n", tmp_file_name, file_name, strerror (errno));
50         res = false;
51     }
52     free(tmp_file_name);
53 
54     return res;
55 }
56 
signal_handler(int)57 void signal_handler (int)
58 {
59 }
60 
main(int argc,char const * argv[])61 int main (int argc, char const *argv[])
62 {
63     if (argc < 2)
64     {
65         fprintf (stderr, "invalid number of command line arguments\n");
66         return 1;
67     }
68 
69     const pid_t pid = fork ();
70     if (pid == -1)
71     {
72         fprintf (stderr, "fork failed: %s\n", strerror (errno));
73         return 1;
74     }
75 
76     if (pid > 0)
77     {
78         // Make pause call to return when a signal is received. Normally this happens when the
79         // test runner tries to terminate us.
80         signal (SIGHUP, signal_handler);
81         signal (SIGTERM, signal_handler);
82         if (ptrace (ATTACH_REQUEST, pid, NULL, 0) == -1)
83         {
84             fprintf (stderr, "ptrace(ATTACH) failed: %s\n", strerror (errno));
85         }
86         else
87         {
88             if (writePid (argv[1], pid))
89                 pause ();  // Waiting for the debugger trying attach to the child.
90 
91             if (ptrace (DETACH_REQUEST, pid, NULL, 0) != 0)
92                 fprintf (stderr, "ptrace(DETACH) failed: %s\n", strerror (errno));
93         }
94 
95         kill (pid, SIGTERM);
96         int status = 0;
97         if (waitpid (pid, &status, 0) == -1)
98             fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
99     }
100     else
101     {
102         // child inferior.
103         pause ();
104     }
105 
106     printf ("Exiting now\n");
107     return 0;
108 }
109