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 | |
24 | bool writePid (const char* file_name, const pid_t pid) |
25 | { |
26 | char *tmp_file_name = (char *)malloc(size: strlen(s: file_name) + 16); |
27 | strcpy(dest: tmp_file_name, src: file_name); |
28 | strcat(dest: tmp_file_name, src: "_tmp" ); |
29 | int fd = open (file: tmp_file_name, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); |
30 | if (fd == -1) |
31 | { |
32 | fprintf (stderr, format: "open(%s) failed: %s\n" , tmp_file_name, strerror (errno)); |
33 | free(ptr: tmp_file_name); |
34 | return false; |
35 | } |
36 | char buffer[64]; |
37 | snprintf (s: buffer, maxlen: sizeof(buffer), format: "%ld" , (long)pid); |
38 | |
39 | bool res = true; |
40 | if (write (fd: fd, buf: buffer, n: strlen (s: buffer)) == -1) |
41 | { |
42 | fprintf (stderr, format: "write(%s) failed: %s\n" , buffer, strerror (errno)); |
43 | res = false; |
44 | } |
45 | close (fd: fd); |
46 | |
47 | if (rename (old: tmp_file_name, new: file_name) == -1) |
48 | { |
49 | fprintf (stderr, format: "rename(%s, %s) failed: %s\n" , tmp_file_name, file_name, strerror (errno)); |
50 | res = false; |
51 | } |
52 | free(ptr: tmp_file_name); |
53 | |
54 | return res; |
55 | } |
56 | |
57 | void signal_handler (int) |
58 | { |
59 | } |
60 | |
61 | int main (int argc, char const *argv[]) |
62 | { |
63 | if (argc < 2) |
64 | { |
65 | fprintf (stderr, format: "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, format: "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, handler: signal_handler); |
81 | signal (SIGTERM, handler: signal_handler); |
82 | if (ptrace (ATTACH_REQUEST, pid, NULL, 0) == -1) |
83 | { |
84 | fprintf (stderr, format: "ptrace(ATTACH) failed: %s\n" , strerror (errno)); |
85 | } |
86 | else |
87 | { |
88 | if (writePid (file_name: 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, format: "ptrace(DETACH) failed: %s\n" , strerror (errno)); |
93 | } |
94 | |
95 | kill (pid: pid, SIGTERM); |
96 | int status = 0; |
97 | if (waitpid (pid: pid, stat_loc: &status, options: 0) == -1) |
98 | fprintf (stderr, format: "waitpid failed: %s\n" , strerror (errno)); |
99 | } |
100 | else |
101 | { |
102 | // child inferior. |
103 | pause (); |
104 | } |
105 | |
106 | printf (format: "Exiting now\n" ); |
107 | return 0; |
108 | } |
109 | |