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