1 /*
2 * Spawn a child and set it up for ptrace()-ing
3 *
4 * Copyright (c) 2008 Analog Devices Inc.
5 *
6 * Licensed under the GPL-2 or later
7 */
8
9 /*
10 * To use:
11 * - add this line after your normal includes:
12 * #include "spawn_ptrace_child.c"
13 * - add this line to the top of your main():
14 * make_a_baby(argc, argv);
15 * - access the child pid via the "pid" variable
16 */
17
18 #include <errno.h> /* errno */
19 #include <signal.h> /* signal() */
20 #include <stdbool.h> /* true */
21 #include <string.h> /* strcmp() */
22 #include <unistd.h> /* execlp() sleep() vfork() */
23 #include <sys/ptrace.h> /* ptrace() */
24 #include <sys/wait.h>
25
26 #include "test.h"
27
28 static pid_t pid;
29
30 #ifdef __sparc__
31 /* sparce swaps addr/data for get/set regs */
32 # define maybe_swap(request, addr, data) \
33 do { \
34 if (request == PTRACE_GETREGS || request == PTRACE_SETREGS) { \
35 void *__s = addr; \
36 addr = data; \
37 data = __s; \
38 } \
39 } while (0)
40 #else
41 # define maybe_swap(...)
42 #endif
43 #define vptrace(request, pid, addr, data) \
44 ({ \
45 errno = 0; \
46 long __ret; \
47 void *__addr = (void *)(addr); \
48 void *__data = (void *)(data); \
49 maybe_swap(request, __addr, __data); \
50 __ret = ptrace(request, pid, __addr, __data); \
51 if (__ret && errno) \
52 perror("ptrace(" #request ", " #pid ", " #addr ", " #data ")"); \
53 __ret; \
54 })
55
make_a_baby(int argc,char * argv[])56 static void make_a_baby(int argc, char *argv[])
57 {
58 if (argc > 1 && !strcmp(argv[1], "child")) {
59 /* if we're the child, just sit around doing nothing */
60 int i = 60;
61 while (i--) {
62 close(-100);
63 sleep(1);
64 }
65 exit(1);
66 }
67
68 signal(SIGCHLD, SIG_IGN);
69
70 pid = vfork();
71 if (pid == -1) {
72 tst_resm(TFAIL, "vfork() failed");
73 tst_exit();
74 } else if (pid) {
75 int status;
76
77 if (wait(&status) != pid) {
78 tst_brkm(TBROK | TERRNO, NULL, "wait(%i) failed: %#x", pid, status);
79 kill(pid, SIGKILL);
80 exit(1);
81 }
82 if (!WIFSTOPPED(status)) {
83 tst_brkm(TBROK, NULL, "child status not stopped: %#x", status);
84 kill(pid, SIGKILL);
85 exit(1);
86 }
87
88 return;
89 }
90
91 errno = 0;
92 long ret = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
93 if (ret && errno) {
94 tst_resm(TFAIL, "PTRACE_TRACEME failed");
95 tst_exit();
96 }
97
98 execlp(argv[0], argv[0], "child", NULL);
99 tst_resm(TFAIL, "execlp() failed");
100 tst_exit();
101 }
102
103 #define SPT(x) [PTRACE_##x] = #x,
104 static char *strings[] = {
105 SPT(TRACEME)
106 SPT(PEEKTEXT)
107 SPT(PEEKDATA)
108 SPT(PEEKUSER)
109 SPT(POKETEXT)
110 SPT(POKEDATA)
111 SPT(POKEUSER)
112 #ifdef PTRACE_GETREGS
113 SPT(GETREGS)
114 #endif
115 #ifdef PTRACE_SETREGS
116 SPT(SETREGS)
117 #endif
118 #ifdef PTRACE_GETSIGINFO
119 SPT(GETSIGINFO)
120 #endif
121 #ifdef PTRACE_SETSIGINFO
122 SPT(SETSIGINFO)
123 #endif
124 #ifdef PTRACE_GETFGREGS
125 SPT(GETFGREGS)
126 #endif
127 #ifdef PTRACE_SETFGREGS
128 SPT(SETFGREGS)
129 #endif
130 SPT(KILL)
131 SPT(SINGLESTEP)
132 };
strptrace(enum __ptrace_request request)133 static inline char *strptrace(enum __ptrace_request request)
134 {
135 return strings[request];
136 }
137