xref: /minix3/minix/tests/test42.c (revision 7c48de6cc4c6d56f2277d378dba01dbac8a8c3b9)
1433d6423SLionel Sambuc /* Tests for MINIX3 ptrace(2) - by D.C. van Moolenbroek */
2433d6423SLionel Sambuc #include <setjmp.h>
3433d6423SLionel Sambuc #include <stdlib.h>
4433d6423SLionel Sambuc #include <stdio.h>
5433d6423SLionel Sambuc #include <string.h>
6433d6423SLionel Sambuc #include <signal.h>
7433d6423SLionel Sambuc #include <unistd.h>
8433d6423SLionel Sambuc #include <errno.h>
9433d6423SLionel Sambuc #include <sys/wait.h>
10433d6423SLionel Sambuc #include <sys/select.h>
11433d6423SLionel Sambuc #include <sys/ptrace.h>
12433d6423SLionel Sambuc #include <sys/syslimits.h>
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #define ITERATIONS 3
15433d6423SLionel Sambuc int max_error = 4;
16433d6423SLionel Sambuc #include "common.h"
17433d6423SLionel Sambuc 
18433d6423SLionel Sambuc #define my_e(n) { \
19433d6423SLionel Sambuc 	if (child) exit(n); printf("Attach type %d, ", attach); e(n); }
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc #define _WIFSTOPPED(s) (WIFSTOPPED(s) && !WIFSIGNALED(s) && !WIFEXITED(s))
23433d6423SLionel Sambuc #define _WIFSIGNALED(s) (!WIFSTOPPED(s) && WIFSIGNALED(s) && !WIFEXITED(s))
24433d6423SLionel Sambuc #define _WIFEXITED(s) (!WIFSTOPPED(s) && !WIFSIGNALED(s) && WIFEXITED(s))
25433d6423SLionel Sambuc 
26433d6423SLionel Sambuc #define timed_test(func) (timed_test_func(#func, func));
27433d6423SLionel Sambuc 
28433d6423SLionel Sambuc int main(int argc, char **argv);
29433d6423SLionel Sambuc void test(int m, int a);
30433d6423SLionel Sambuc void timed_test_func(const char *s, void (* func)(void));
31433d6423SLionel Sambuc void timed_test_timeout(int signum);
32433d6423SLionel Sambuc pid_t traced_fork(void (*c) (void));
33433d6423SLionel Sambuc pid_t traced_pfork(void (*c) (void));
34433d6423SLionel Sambuc void WRITE(int value);
35433d6423SLionel Sambuc int READ(void);
36433d6423SLionel Sambuc void traced_wait(void);
37433d6423SLionel Sambuc void detach_running(pid_t pid);
38433d6423SLionel Sambuc void dummy_handler(int sig);
39433d6423SLionel Sambuc void exit_handler(int sig);
40433d6423SLionel Sambuc void count_handler(int sig);
41433d6423SLionel Sambuc void catch_handler(int sig);
42433d6423SLionel Sambuc void test_wait_child(void);
43433d6423SLionel Sambuc void test_wait(void);
44433d6423SLionel Sambuc void test_exec_child(void);
45433d6423SLionel Sambuc void test_exec(void);
46433d6423SLionel Sambuc void test_step_child(void);
47433d6423SLionel Sambuc void test_step(void);
48433d6423SLionel Sambuc void test_sig_child(void);
49433d6423SLionel Sambuc void test_sig(void);
50433d6423SLionel Sambuc void test_exit_child(void);
51433d6423SLionel Sambuc void test_exit(void);
52433d6423SLionel Sambuc void test_term_child(void);
53433d6423SLionel Sambuc void test_term(void);
54433d6423SLionel Sambuc void test_catch_child(void);
55433d6423SLionel Sambuc void test_catch(void);
56433d6423SLionel Sambuc void test_kill_child(void);
57433d6423SLionel Sambuc void test_kill(void);
58433d6423SLionel Sambuc void test_attach_child(void);
59433d6423SLionel Sambuc void test_attach(void);
60433d6423SLionel Sambuc void test_detach_child(void);
61433d6423SLionel Sambuc void test_detach(void);
62433d6423SLionel Sambuc void test_death_child(void);
63433d6423SLionel Sambuc void test_death(void);
64433d6423SLionel Sambuc void test_zdeath_child(void);
65433d6423SLionel Sambuc void test_zdeath(void);
66433d6423SLionel Sambuc void test_syscall_child(void);
67433d6423SLionel Sambuc void test_syscall(void);
68433d6423SLionel Sambuc void test_tracefork_child(void);
69433d6423SLionel Sambuc void test_tracefork(void);
70433d6423SLionel Sambuc void sigexec(int setflag, int opt, int *traps, int *stop);
71433d6423SLionel Sambuc void test_trapexec(void);
72433d6423SLionel Sambuc void test_altexec(void);
73433d6423SLionel Sambuc void test_noexec(void);
74433d6423SLionel Sambuc void test_defexec(void);
75433d6423SLionel Sambuc void test_reattach_child(void);
76433d6423SLionel Sambuc void test_reattach(void);
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc static char *executable;
79433d6423SLionel Sambuc static int child = 0, attach;
80433d6423SLionel Sambuc static pid_t ppid;
81433d6423SLionel Sambuc static int pfd[4];
82433d6423SLionel Sambuc static int sigs, caught;
83433d6423SLionel Sambuc 
main(argc,argv)84433d6423SLionel Sambuc int main(argc, argv)
85433d6423SLionel Sambuc int argc;
86433d6423SLionel Sambuc char **argv;
87433d6423SLionel Sambuc {
88433d6423SLionel Sambuc   int i, m = 0xFFFFFF, n = 0xF;
89433d6423SLionel Sambuc   char cp_cmd[NAME_MAX + 10];
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc   if (strcmp(argv[0], "DO CHECK") == 0) {
92433d6423SLionel Sambuc 	exit(42);
93433d6423SLionel Sambuc   }
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc   start(42);
96433d6423SLionel Sambuc 
97433d6423SLionel Sambuc   executable = argv[0];
98433d6423SLionel Sambuc 
99433d6423SLionel Sambuc   snprintf(cp_cmd, sizeof(cp_cmd), "cp ../%s .", executable);
100433d6423SLionel Sambuc   system(cp_cmd);
101433d6423SLionel Sambuc 
102433d6423SLionel Sambuc   if (argc >= 2) m = atoi(argv[1]);
103433d6423SLionel Sambuc   if (argc >= 3) n = atoi(argv[2]);
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc   for (i = 0; i < ITERATIONS; i++) {
106433d6423SLionel Sambuc 	if (n & 001) test(m, 0);
107433d6423SLionel Sambuc 	if (n & 002) test(m, 1);
108433d6423SLionel Sambuc 	if (n & 004) test(m, 2);
109433d6423SLionel Sambuc 	if (n & 010) test(m, 3);
110433d6423SLionel Sambuc   }
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc   quit();
113433d6423SLionel Sambuc   return(-1);			/* impossible */
114433d6423SLionel Sambuc }
115433d6423SLionel Sambuc 
test(m,a)116433d6423SLionel Sambuc void test(m, a)
117433d6423SLionel Sambuc int m;
118433d6423SLionel Sambuc int a;
119433d6423SLionel Sambuc {
120433d6423SLionel Sambuc   attach = a;
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc   if (m & 00000001) timed_test(test_wait);
123433d6423SLionel Sambuc   if (m & 00000002) timed_test(test_exec);
124433d6423SLionel Sambuc #if !defined(__arm__)
125433d6423SLionel Sambuc   /* BJG: single-stepping isn't implemented on ARM */
126433d6423SLionel Sambuc   if (m & 00000004) timed_test(test_step);
127433d6423SLionel Sambuc #endif
128433d6423SLionel Sambuc   if (m & 00000010) timed_test(test_sig);
129433d6423SLionel Sambuc   if (m & 00000020) timed_test(test_exit);
130433d6423SLionel Sambuc   if (m & 00000040) timed_test(test_term);
131433d6423SLionel Sambuc   if (m & 00000100) timed_test(test_catch);
132433d6423SLionel Sambuc   if (m & 00000200) timed_test(test_kill);
133433d6423SLionel Sambuc   if (m & 00000400) timed_test(test_attach);
134433d6423SLionel Sambuc   if (m & 00001000) timed_test(test_detach);
135433d6423SLionel Sambuc   if (m & 00002000) timed_test(test_death);
136433d6423SLionel Sambuc   if (m & 00004000) timed_test(test_zdeath);
137433d6423SLionel Sambuc   if (m & 00010000) timed_test(test_syscall);
138433d6423SLionel Sambuc   if (m & 00020000) timed_test(test_tracefork);
139433d6423SLionel Sambuc   if (m & 00040000) timed_test(test_trapexec);
140433d6423SLionel Sambuc   if (m & 00100000) timed_test(test_altexec);
141433d6423SLionel Sambuc   if (m & 00200000) timed_test(test_noexec);
142433d6423SLionel Sambuc   if (m & 00400000) timed_test(test_defexec);
143433d6423SLionel Sambuc   if (m & 01000000) test_reattach(); /* not timed, catches SIGALRM */
144433d6423SLionel Sambuc }
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc static jmp_buf timed_test_context;
147433d6423SLionel Sambuc 
timed_test_timeout(int signum)148433d6423SLionel Sambuc void timed_test_timeout(int signum)
149433d6423SLionel Sambuc {
150433d6423SLionel Sambuc   longjmp(timed_test_context, -1);
151433d6423SLionel Sambuc   my_e(700);
152433d6423SLionel Sambuc   quit();
153433d6423SLionel Sambuc   exit(-1);
154433d6423SLionel Sambuc }
155433d6423SLionel Sambuc 
timed_test_func(const char * s,void (* func)(void))156433d6423SLionel Sambuc void timed_test_func(const char *s, void (* func)(void))
157433d6423SLionel Sambuc {
158433d6423SLionel Sambuc   if (setjmp(timed_test_context) == 0)
159433d6423SLionel Sambuc   {
160433d6423SLionel Sambuc     /* the function gets 60 seconds to complete */
161433d6423SLionel Sambuc     if (signal(SIGALRM, timed_test_timeout) == SIG_ERR) { my_e(701); return; }
162433d6423SLionel Sambuc     alarm(60);
163433d6423SLionel Sambuc     func();
164433d6423SLionel Sambuc     alarm(0);
165433d6423SLionel Sambuc   }
166433d6423SLionel Sambuc   else
167433d6423SLionel Sambuc   {
168433d6423SLionel Sambuc     /* report timeout as error */
169433d6423SLionel Sambuc     printf("timeout in %s\n", s);
170433d6423SLionel Sambuc     my_e(702);
171433d6423SLionel Sambuc   }
172433d6423SLionel Sambuc }
173433d6423SLionel Sambuc 
174433d6423SLionel Sambuc pid_t traced_fork(c)
175433d6423SLionel Sambuc void (*c)(void);
176433d6423SLionel Sambuc {
177433d6423SLionel Sambuc   pid_t pid;
178433d6423SLionel Sambuc   int r, status;
179433d6423SLionel Sambuc 
180433d6423SLionel Sambuc   if (pipe(pfd) != 0) my_e(200);
181433d6423SLionel Sambuc   if (pipe(&pfd[2]) != 0) my_e(201);
182433d6423SLionel Sambuc 
183433d6423SLionel Sambuc   switch (attach) {
184433d6423SLionel Sambuc   case 0:			/* let child volunteer to be traced */
185433d6423SLionel Sambuc   	pid = fork();
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc   	if (pid < 0) my_e(202);
188433d6423SLionel Sambuc 
189433d6423SLionel Sambuc   	if (pid == 0) {
190433d6423SLionel Sambuc 		child = 1;
191433d6423SLionel Sambuc 
192433d6423SLionel Sambuc 		if (ptrace(T_OK, 0, 0, 0) != 0) my_e(203);
193433d6423SLionel Sambuc 
194433d6423SLionel Sambuc 		WRITE(0);
195433d6423SLionel Sambuc 
196433d6423SLionel Sambuc 		c();
197433d6423SLionel Sambuc 
198433d6423SLionel Sambuc 		my_e(204);
199433d6423SLionel Sambuc   	}
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc   	if (READ() != 0) my_e(205);
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc   	break;
204433d6423SLionel Sambuc 
205433d6423SLionel Sambuc   case 1:			/* attach to child process */
206433d6423SLionel Sambuc 	pid = fork();
207433d6423SLionel Sambuc 
208433d6423SLionel Sambuc 	if (pid < 0) my_e(206);
209433d6423SLionel Sambuc 
210433d6423SLionel Sambuc 	if (pid == 0) {
211433d6423SLionel Sambuc 		child = 1;
212433d6423SLionel Sambuc 
213433d6423SLionel Sambuc 		if (READ() != 0) my_e(207);
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 		c();
216433d6423SLionel Sambuc 
217433d6423SLionel Sambuc 		my_e(208);
218433d6423SLionel Sambuc 	}
219433d6423SLionel Sambuc 
220433d6423SLionel Sambuc 	if (ptrace(T_ATTACH, pid, 0, 0) != 0) my_e(209);
221433d6423SLionel Sambuc 
222433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(210);
223433d6423SLionel Sambuc 	if (!_WIFSTOPPED(status)) my_e(211);
224433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGSTOP) my_e(212);
225433d6423SLionel Sambuc 
226433d6423SLionel Sambuc 	if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(213);
227433d6423SLionel Sambuc 
228433d6423SLionel Sambuc 	WRITE(0);
229433d6423SLionel Sambuc 
230433d6423SLionel Sambuc 	break;
231433d6423SLionel Sambuc 
232433d6423SLionel Sambuc   case 2:			/* attach to non-child process */
233433d6423SLionel Sambuc 	ppid = fork();
234433d6423SLionel Sambuc 
235433d6423SLionel Sambuc 	if (ppid < 0) my_e(214);
236433d6423SLionel Sambuc 
237433d6423SLionel Sambuc 	if (ppid == 0) {
238433d6423SLionel Sambuc 		pid = fork();
239433d6423SLionel Sambuc 
240433d6423SLionel Sambuc 		if (pid < 0) exit(215);
241433d6423SLionel Sambuc 
242433d6423SLionel Sambuc 		if (pid == 0) {
243433d6423SLionel Sambuc 			child = 1;
244433d6423SLionel Sambuc 
245433d6423SLionel Sambuc 			if (READ() != 0) my_e(216);
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc 			c();
248433d6423SLionel Sambuc 
249433d6423SLionel Sambuc 			my_e(217);
250433d6423SLionel Sambuc 		}
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc 		child = 1;
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc 		WRITE(pid);
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc 		if (waitpid(pid, &status, 0) != pid) my_e(218);
257433d6423SLionel Sambuc 		if (_WIFSTOPPED(status)) my_e(219);
258433d6423SLionel Sambuc 		if (_WIFEXITED(status) && (r = WEXITSTATUS(status)) != 42) my_e(r);
259433d6423SLionel Sambuc 
260433d6423SLionel Sambuc 		exit(0);
261433d6423SLionel Sambuc 	}
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 	pid = READ();
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 	if (ptrace(T_ATTACH, pid, 0, 0) != 0) my_e(220);
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(221);
268433d6423SLionel Sambuc 	if (!_WIFSTOPPED(status)) my_e(222);
269433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGSTOP) my_e(223);
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc 	if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(224);
272433d6423SLionel Sambuc 
273433d6423SLionel Sambuc 	WRITE(0);
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc   	break;
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc   case 3:			/* attach by forking from child */
278433d6423SLionel Sambuc 	ppid = fork();
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	if (ppid < 0) my_e(225);
281433d6423SLionel Sambuc 
282433d6423SLionel Sambuc 	if (ppid == 0) {
283433d6423SLionel Sambuc 		child = 1;
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc 		if (ptrace(T_OK, 0, 0, 0) != 0) my_e(226);
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 		WRITE(0);
288433d6423SLionel Sambuc 
289433d6423SLionel Sambuc 		if (READ() != 0) my_e(227);
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc 		pid = fork();
292433d6423SLionel Sambuc 
293433d6423SLionel Sambuc 		if (pid < 0) my_e(228);
294433d6423SLionel Sambuc 
295433d6423SLionel Sambuc 		if (pid == 0) {
296433d6423SLionel Sambuc 			c();
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc 			my_e(229);
299433d6423SLionel Sambuc 		}
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc 		WRITE(pid);
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc 		if (waitpid(pid, &status, 0) != pid) my_e(230);
304433d6423SLionel Sambuc 		if (_WIFSTOPPED(status)) my_e(231);
305433d6423SLionel Sambuc 		if (_WIFEXITED(status) && (r = WEXITSTATUS(status)) != 42) my_e(r);
306433d6423SLionel Sambuc 
307433d6423SLionel Sambuc 		exit(0);
308433d6423SLionel Sambuc 	}
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc 	if (READ() != 0) my_e(232);
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc 	if (kill(ppid, SIGSTOP) != 0) my_e(233);
313433d6423SLionel Sambuc 
314433d6423SLionel Sambuc 	if (waitpid(ppid, &status, 0) != ppid) my_e(234);
315433d6423SLionel Sambuc 	if (!_WIFSTOPPED(status)) my_e(235);
316433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGSTOP) my_e(236);
317433d6423SLionel Sambuc 
318433d6423SLionel Sambuc 	if (ptrace(T_SETOPT, ppid, 0, TO_TRACEFORK) != 0) my_e(237);
319433d6423SLionel Sambuc 
320433d6423SLionel Sambuc 	if (ptrace(T_RESUME, ppid, 0, 0) != 0) my_e(238);
321433d6423SLionel Sambuc 
322433d6423SLionel Sambuc 	WRITE(0);
323433d6423SLionel Sambuc 
324433d6423SLionel Sambuc 	pid = READ();
325433d6423SLionel Sambuc 
326433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(239);
327433d6423SLionel Sambuc 	if (!_WIFSTOPPED(status)) my_e(240);
328433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGSTOP) my_e(241);
329433d6423SLionel Sambuc 
330433d6423SLionel Sambuc 	if (ptrace(T_SETOPT, pid, 0, 0) != 0) my_e(242);
331433d6423SLionel Sambuc 	if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(243);
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc 	detach_running(ppid);
334433d6423SLionel Sambuc 
335433d6423SLionel Sambuc 	break;
336*7c48de6cSDavid van Moolenbroek 
337*7c48de6cSDavid van Moolenbroek   default:
338*7c48de6cSDavid van Moolenbroek 	abort();
339433d6423SLionel Sambuc   }
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc   return pid;
342433d6423SLionel Sambuc }
343433d6423SLionel Sambuc 
344433d6423SLionel Sambuc pid_t traced_pfork(c)
345433d6423SLionel Sambuc void(*c) (void);
346433d6423SLionel Sambuc {
347433d6423SLionel Sambuc   pid_t pid;
348433d6423SLionel Sambuc 
349433d6423SLionel Sambuc   if (pipe(pfd) != 0) my_e(300);
350433d6423SLionel Sambuc   if (pipe(&pfd[2]) != 0) my_e(301);
351433d6423SLionel Sambuc 
352433d6423SLionel Sambuc   pid = fork();
353433d6423SLionel Sambuc 
354433d6423SLionel Sambuc   if (pid < 0) my_e(302);
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc   if (pid == 0) {
357433d6423SLionel Sambuc 	child = 1;
358433d6423SLionel Sambuc 
359433d6423SLionel Sambuc 	c();
360433d6423SLionel Sambuc 
361433d6423SLionel Sambuc 	my_e(303);
362433d6423SLionel Sambuc   }
363433d6423SLionel Sambuc 
364433d6423SLionel Sambuc   return pid;
365433d6423SLionel Sambuc }
366433d6423SLionel Sambuc 
WRITE(value)367433d6423SLionel Sambuc void WRITE(value)
368433d6423SLionel Sambuc int value;
369433d6423SLionel Sambuc {
370433d6423SLionel Sambuc   if (write(pfd[child*2+1], &value, sizeof(value)) != sizeof(value)) my_e(400);
371433d6423SLionel Sambuc }
372433d6423SLionel Sambuc 
READ()373433d6423SLionel Sambuc int READ()
374433d6423SLionel Sambuc {
375433d6423SLionel Sambuc   int value;
376433d6423SLionel Sambuc 
377433d6423SLionel Sambuc   if (read(pfd[2-child*2], &value, sizeof(value)) != sizeof(value)) my_e(401);
378433d6423SLionel Sambuc 
379433d6423SLionel Sambuc   return value;
380433d6423SLionel Sambuc }
381433d6423SLionel Sambuc 
traced_wait()382433d6423SLionel Sambuc void traced_wait()
383433d6423SLionel Sambuc {
384433d6423SLionel Sambuc   int r, status;
385433d6423SLionel Sambuc 
386433d6423SLionel Sambuc   if (attach == 2) {
387433d6423SLionel Sambuc 	if (waitpid(ppid, &status, 0) != ppid) my_e(500);
388433d6423SLionel Sambuc 	if (!_WIFEXITED(status)) my_e(501);
389433d6423SLionel Sambuc 	if ((r = WEXITSTATUS(status)) != 0) my_e(r);
390433d6423SLionel Sambuc   }
391433d6423SLionel Sambuc   else {
392433d6423SLionel Sambuc 	/* Quick hack to clean up detached children */
393433d6423SLionel Sambuc   	waitpid(-1, NULL, WNOHANG);
394433d6423SLionel Sambuc   }
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc   close(pfd[0]);
397433d6423SLionel Sambuc   close(pfd[1]);
398433d6423SLionel Sambuc   close(pfd[2]);
399433d6423SLionel Sambuc   close(pfd[3]);
400433d6423SLionel Sambuc }
401433d6423SLionel Sambuc 
detach_running(pid)402433d6423SLionel Sambuc void detach_running(pid)
403433d6423SLionel Sambuc pid_t pid;
404433d6423SLionel Sambuc {
405433d6423SLionel Sambuc /* Detach from a process that is not already stopped. This is the way to do it.
406433d6423SLionel Sambuc  * We have to stop the child in order to detach from it, but as the child may
407433d6423SLionel Sambuc  * have other signals pending for the tracer, we cannot assume we get our own
408433d6423SLionel Sambuc  * signal back immediately. However, because we know that the kill is instant
409433d6423SLionel Sambuc  * and resuming with pending signals will only stop the process immediately
410433d6423SLionel Sambuc  * again, we can use T_RESUME for all the signals until we get our own signal,
411433d6423SLionel Sambuc  * and then detach. A complicating factor is that anywhere during this
412433d6423SLionel Sambuc  * procedure, the child may die (e.g. by getting a SIGKILL). In our tests, this
413433d6423SLionel Sambuc  * will not happen.
414433d6423SLionel Sambuc  */
415433d6423SLionel Sambuc   int status;
416433d6423SLionel Sambuc 
417433d6423SLionel Sambuc   if (kill(pid, SIGSTOP) != 0) my_e(600);
418433d6423SLionel Sambuc 
419433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(601);
420433d6423SLionel Sambuc 
421433d6423SLionel Sambuc   while (_WIFSTOPPED(status)) {
422433d6423SLionel Sambuc 	if (WSTOPSIG(status) == SIGSTOP) {
423433d6423SLionel Sambuc 		if (ptrace(T_DETACH, pid, 0, 0) != 0) my_e(602);
424433d6423SLionel Sambuc 
425433d6423SLionel Sambuc 		return;
426433d6423SLionel Sambuc 	}
427433d6423SLionel Sambuc 
428433d6423SLionel Sambuc 	if (ptrace(T_RESUME, pid, 0, WSTOPSIG(status)) != 0) my_e(603);
429433d6423SLionel Sambuc 
430433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(604);
431433d6423SLionel Sambuc   }
432433d6423SLionel Sambuc 
433433d6423SLionel Sambuc   /* Apparently the process exited. */
434433d6423SLionel Sambuc   if (!_WIFEXITED(status) && !_WIFSIGNALED(status)) my_e(605);
435433d6423SLionel Sambuc 
436433d6423SLionel Sambuc   /* In our tests, that should not happen. */
437433d6423SLionel Sambuc   my_e(606);
438433d6423SLionel Sambuc }
439433d6423SLionel Sambuc 
dummy_handler(sig)440433d6423SLionel Sambuc void dummy_handler(sig)
441433d6423SLionel Sambuc int sig;
442433d6423SLionel Sambuc {
443433d6423SLionel Sambuc }
444433d6423SLionel Sambuc 
exit_handler(sig)445433d6423SLionel Sambuc void exit_handler(sig)
446433d6423SLionel Sambuc int sig;
447433d6423SLionel Sambuc {
448433d6423SLionel Sambuc   exit(42);
449433d6423SLionel Sambuc }
450433d6423SLionel Sambuc 
count_handler(sig)451433d6423SLionel Sambuc void count_handler(sig)
452433d6423SLionel Sambuc int sig;
453433d6423SLionel Sambuc {
454433d6423SLionel Sambuc   sigs++;
455433d6423SLionel Sambuc }
456433d6423SLionel Sambuc 
catch_handler(sig)457433d6423SLionel Sambuc void catch_handler(sig)
458433d6423SLionel Sambuc int sig;
459433d6423SLionel Sambuc {
460433d6423SLionel Sambuc   sigset_t set;
461433d6423SLionel Sambuc   int bit;
462433d6423SLionel Sambuc 
463433d6423SLionel Sambuc   switch (sig) {
464433d6423SLionel Sambuc   case SIGUSR1: bit = 1; break;
465433d6423SLionel Sambuc   case SIGUSR2: bit = 2; break;
466433d6423SLionel Sambuc   case SIGTERM: bit = 4; break;
467cbc8a0dfSDavid van Moolenbroek   default: bit = 0; my_e(100);
468433d6423SLionel Sambuc   }
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc   sigfillset(&set);
471433d6423SLionel Sambuc   sigprocmask(SIG_SETMASK, &set, NULL);
472433d6423SLionel Sambuc 
473433d6423SLionel Sambuc   if (caught & bit) my_e(101);
474433d6423SLionel Sambuc   caught |= bit;
475433d6423SLionel Sambuc }
476433d6423SLionel Sambuc 
test_wait_child()477433d6423SLionel Sambuc void test_wait_child()
478433d6423SLionel Sambuc {
479433d6423SLionel Sambuc   exit(42);
480433d6423SLionel Sambuc }
481433d6423SLionel Sambuc 
test_wait()482433d6423SLionel Sambuc void test_wait()
483433d6423SLionel Sambuc {
484433d6423SLionel Sambuc   pid_t pid;
485433d6423SLionel Sambuc   int status;
486433d6423SLionel Sambuc 
487433d6423SLionel Sambuc   subtest = 1;
488433d6423SLionel Sambuc 
489433d6423SLionel Sambuc   pid = traced_fork(test_wait_child);
490433d6423SLionel Sambuc 
491433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(1);
492433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(2);
493433d6423SLionel Sambuc   if (WEXITSTATUS(status) != 42) my_e(3);
494433d6423SLionel Sambuc 
495433d6423SLionel Sambuc   traced_wait();
496433d6423SLionel Sambuc }
497433d6423SLionel Sambuc 
test_exec_child()498433d6423SLionel Sambuc void test_exec_child()
499433d6423SLionel Sambuc {
500433d6423SLionel Sambuc   if (READ() != 0) my_e(100);
501433d6423SLionel Sambuc 
502433d6423SLionel Sambuc   execl(executable, "DO CHECK", NULL);
503433d6423SLionel Sambuc 
504433d6423SLionel Sambuc   my_e(101);
505433d6423SLionel Sambuc }
506433d6423SLionel Sambuc 
test_exec()507433d6423SLionel Sambuc void test_exec()
508433d6423SLionel Sambuc {
509433d6423SLionel Sambuc   pid_t pid;
510433d6423SLionel Sambuc   int r, status;
511433d6423SLionel Sambuc 
512433d6423SLionel Sambuc   /* This test covers the T_OK case. */
513433d6423SLionel Sambuc   if (attach != 0) return;
514433d6423SLionel Sambuc 
515433d6423SLionel Sambuc   subtest = 2;
516433d6423SLionel Sambuc 
517433d6423SLionel Sambuc   pid = traced_fork(test_exec_child);
518433d6423SLionel Sambuc 
519433d6423SLionel Sambuc   WRITE(0);
520433d6423SLionel Sambuc 
521433d6423SLionel Sambuc   /* An exec() should result in a trap signal. */
522433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(1);
523433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(2);
524433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGTRAP) my_e(3);
525433d6423SLionel Sambuc 
526433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(4);
527433d6423SLionel Sambuc 
528433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(5);
529433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(6);
530433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
531433d6423SLionel Sambuc 
532433d6423SLionel Sambuc   traced_wait();
533433d6423SLionel Sambuc }
534433d6423SLionel Sambuc 
test_step_child()535433d6423SLionel Sambuc void test_step_child()
536433d6423SLionel Sambuc {
537433d6423SLionel Sambuc   sigset_t set;
538433d6423SLionel Sambuc 
539433d6423SLionel Sambuc   signal(SIGUSR1, SIG_IGN);
540433d6423SLionel Sambuc 
541433d6423SLionel Sambuc   WRITE(0);
542433d6423SLionel Sambuc 
543433d6423SLionel Sambuc   if (READ() != 0) my_e(100);
544433d6423SLionel Sambuc 
545433d6423SLionel Sambuc   /* It must not be possible for the child to stop the single-step signal. */
546433d6423SLionel Sambuc   signal(SIGTRAP, SIG_IGN);
547433d6423SLionel Sambuc   sigfillset(&set);
548433d6423SLionel Sambuc   sigprocmask(SIG_SETMASK, &set, NULL);
549433d6423SLionel Sambuc 
550433d6423SLionel Sambuc   exit(42);
551433d6423SLionel Sambuc }
552433d6423SLionel Sambuc 
test_step()553433d6423SLionel Sambuc void test_step()
554433d6423SLionel Sambuc {
555433d6423SLionel Sambuc   pid_t pid;
556433d6423SLionel Sambuc   int r, status, count;
557433d6423SLionel Sambuc 
558433d6423SLionel Sambuc   subtest = 3;
559433d6423SLionel Sambuc 
560433d6423SLionel Sambuc   pid = traced_fork(test_step_child);
561433d6423SLionel Sambuc 
562433d6423SLionel Sambuc   if (READ() != 0) my_e(1);
563433d6423SLionel Sambuc 
564433d6423SLionel Sambuc   /* While the child is running, neither waitpid() nor ptrace() should work. */
565433d6423SLionel Sambuc   if (waitpid(pid, &status, WNOHANG) != 0) my_e(2);
566433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, 0) != -1) my_e(3);
567433d6423SLionel Sambuc   if (errno != EBUSY) my_e(4);
568433d6423SLionel Sambuc 
569433d6423SLionel Sambuc   if (kill(pid, SIGUSR1) != 0) my_e(5);
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc   WRITE(0);
572433d6423SLionel Sambuc 
573433d6423SLionel Sambuc   /* A kill() signal (other than SIGKILL) should be delivered to the tracer. */
574433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(6);
575433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(7);
576433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGUSR1) my_e(8);
577433d6423SLionel Sambuc 
578433d6423SLionel Sambuc   /* ptrace(T_STEP) should result in instruction-wise progress. */
579433d6423SLionel Sambuc   for (count = 0; ; count++) {
580433d6423SLionel Sambuc 	if (ptrace(T_STEP, pid, 0, 0) != 0) my_e(9);
581433d6423SLionel Sambuc 
582433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(10);
583433d6423SLionel Sambuc 	if (_WIFEXITED(status)) break;
584433d6423SLionel Sambuc 	if (!_WIFSTOPPED(status)) my_e(11);
585433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGTRAP) my_e(12);
586433d6423SLionel Sambuc   }
587433d6423SLionel Sambuc 
588433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
589433d6423SLionel Sambuc 
590433d6423SLionel Sambuc   if (count < 10) my_e(13); /* in practice: hundreds */
591433d6423SLionel Sambuc 
592433d6423SLionel Sambuc   traced_wait();
593433d6423SLionel Sambuc }
594433d6423SLionel Sambuc 
test_sig_child()595433d6423SLionel Sambuc void test_sig_child()
596433d6423SLionel Sambuc {
597433d6423SLionel Sambuc   signal(SIGUSR1, exit_handler);
598433d6423SLionel Sambuc 
599433d6423SLionel Sambuc   if (READ() != 0) my_e(100);
600433d6423SLionel Sambuc 
601433d6423SLionel Sambuc   pause();
602433d6423SLionel Sambuc 
603433d6423SLionel Sambuc   my_e(101);
604433d6423SLionel Sambuc }
605433d6423SLionel Sambuc 
test_sig()606433d6423SLionel Sambuc void test_sig()
607433d6423SLionel Sambuc {
608433d6423SLionel Sambuc   pid_t pid;
609433d6423SLionel Sambuc   int r, sig, status;
610433d6423SLionel Sambuc 
611433d6423SLionel Sambuc   subtest = 4;
612433d6423SLionel Sambuc 
613433d6423SLionel Sambuc   pid = traced_fork(test_sig_child);
614433d6423SLionel Sambuc 
615433d6423SLionel Sambuc   WRITE(0);
616433d6423SLionel Sambuc 
617433d6423SLionel Sambuc   /* allow the child to enter the pause */
618433d6423SLionel Sambuc   sleep(1);
619433d6423SLionel Sambuc 
620433d6423SLionel Sambuc   if (kill(pid, SIGUSR1) != 0) my_e(1);
621433d6423SLionel Sambuc   if (kill(pid, SIGUSR2) != 0) my_e(2);
622433d6423SLionel Sambuc 
623433d6423SLionel Sambuc   /* All signals should arrive at the tracer, although in "random" order. */
624433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(3);
625433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(4);
626433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGUSR2) my_e(5);
627433d6423SLionel Sambuc 
628433d6423SLionel Sambuc   /* The tracer should see kills arriving while the tracee is stopped. */
629433d6423SLionel Sambuc   if (kill(pid, WSTOPSIG(status)) != 0) my_e(6);
630433d6423SLionel Sambuc 
631433d6423SLionel Sambuc   if (waitpid(pid, &status, WNOHANG) != pid) my_e(7);
632433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(8);
633433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGUSR2) my_e(9);
634433d6423SLionel Sambuc   sig = (WSTOPSIG(status) == SIGUSR1) ? SIGUSR2 : SIGUSR1;
635433d6423SLionel Sambuc 
636433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(10);
637433d6423SLionel Sambuc 
638433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(11);
639433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(12);
640433d6423SLionel Sambuc   if (WSTOPSIG(status) != sig) my_e(13);
641433d6423SLionel Sambuc 
642433d6423SLionel Sambuc   if (waitpid(pid, &status, WNOHANG) != 0) my_e(14);
643433d6423SLionel Sambuc 
644433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(15);
645433d6423SLionel Sambuc 
646433d6423SLionel Sambuc   /* Ignored signals passed via ptrace() should be ignored. */
647433d6423SLionel Sambuc   if (kill(pid, SIGUSR1) != 0) my_e(16);
648433d6423SLionel Sambuc 
649433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(17);
650433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(18);
651433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGUSR1) my_e(19);
652433d6423SLionel Sambuc 
653433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, SIGCHLD) != 0) my_e(20);
654433d6423SLionel Sambuc 
655433d6423SLionel Sambuc   /* if the pause has been aborted (shouldn't happen!), let the child exit */
656433d6423SLionel Sambuc   sleep(1);
657433d6423SLionel Sambuc 
658433d6423SLionel Sambuc   if (waitpid(pid, &status, WNOHANG) != 0) my_e(21);
659433d6423SLionel Sambuc 
660433d6423SLionel Sambuc   /* Caught signals passed via ptrace() should invoke their signal handlers. */
661433d6423SLionel Sambuc   if (kill(pid, SIGUSR1) != 0) my_e(22);
662433d6423SLionel Sambuc 
663433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(23);
664433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(24);
665433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGUSR1) my_e(25);
666433d6423SLionel Sambuc 
667433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, SIGUSR1) != 0) my_e(26);
668433d6423SLionel Sambuc 
669433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(27);
670433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(28);
671433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(29);
672433d6423SLionel Sambuc 
673433d6423SLionel Sambuc   traced_wait();
674433d6423SLionel Sambuc }
675433d6423SLionel Sambuc 
test_exit_child()676433d6423SLionel Sambuc void test_exit_child()
677433d6423SLionel Sambuc {
678433d6423SLionel Sambuc   WRITE(0);
679433d6423SLionel Sambuc 
680433d6423SLionel Sambuc   for(;;);
681433d6423SLionel Sambuc }
682433d6423SLionel Sambuc 
test_exit()683433d6423SLionel Sambuc void test_exit()
684433d6423SLionel Sambuc {
685433d6423SLionel Sambuc   pid_t pid;
686433d6423SLionel Sambuc   int r, status;
687433d6423SLionel Sambuc 
688433d6423SLionel Sambuc   subtest = 5;
689433d6423SLionel Sambuc 
690433d6423SLionel Sambuc   pid = traced_fork(test_exit_child);
691433d6423SLionel Sambuc 
692433d6423SLionel Sambuc   if (READ() != 0) my_e(1);
693433d6423SLionel Sambuc 
694433d6423SLionel Sambuc   sleep(1);
695433d6423SLionel Sambuc 
696433d6423SLionel Sambuc   if (kill(pid, SIGSTOP) != 0) my_e(2);
697433d6423SLionel Sambuc 
698433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(3);
699433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(4);
700433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGSTOP) my_e(5);
701433d6423SLionel Sambuc 
702433d6423SLionel Sambuc   /* There should be no more signals pending for the tracer now. */
703433d6423SLionel Sambuc   if (waitpid(pid, &status, WNOHANG) != 0) my_e(6);
704433d6423SLionel Sambuc 
705433d6423SLionel Sambuc   /* ptrace(T_EXIT) should terminate the process with the given exit value. */
706433d6423SLionel Sambuc   if (ptrace(T_EXIT, pid, 0, 42) != 0) my_e(7);
707433d6423SLionel Sambuc 
708433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(8);
709433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(9);
710433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
711433d6423SLionel Sambuc 
712433d6423SLionel Sambuc   traced_wait();
713433d6423SLionel Sambuc }
714433d6423SLionel Sambuc 
test_term_child()715433d6423SLionel Sambuc void test_term_child()
716433d6423SLionel Sambuc {
717433d6423SLionel Sambuc   signal(SIGUSR1, SIG_DFL);
718433d6423SLionel Sambuc   signal(SIGUSR2, dummy_handler);
719433d6423SLionel Sambuc 
720433d6423SLionel Sambuc   WRITE(0);
721433d6423SLionel Sambuc 
722433d6423SLionel Sambuc   pause();
723433d6423SLionel Sambuc 
724433d6423SLionel Sambuc   my_e(100);
725433d6423SLionel Sambuc }
726433d6423SLionel Sambuc 
test_term()727433d6423SLionel Sambuc void test_term()
728433d6423SLionel Sambuc {
729433d6423SLionel Sambuc   pid_t pid;
730433d6423SLionel Sambuc   int status;
731433d6423SLionel Sambuc 
732433d6423SLionel Sambuc   subtest = 6;
733433d6423SLionel Sambuc 
734433d6423SLionel Sambuc   pid = traced_fork(test_term_child);
735433d6423SLionel Sambuc 
736433d6423SLionel Sambuc   if (READ() != 0) my_e(1);
737433d6423SLionel Sambuc 
738433d6423SLionel Sambuc   /* If the first of two signals terminates the traced child, the second signal
739433d6423SLionel Sambuc    * may or may not be delivered to the tracer - this is merely a policy issue.
740433d6423SLionel Sambuc    * However, nothing unexpected should happen.
741433d6423SLionel Sambuc    */
742433d6423SLionel Sambuc   if (kill(pid, SIGUSR1) != 0) my_e(2);
743433d6423SLionel Sambuc   if (kill(pid, SIGUSR2) != 0) my_e(3);
744433d6423SLionel Sambuc 
745433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(4);
746433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(5);
747433d6423SLionel Sambuc 
748433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, SIGUSR1) != 0) my_e(6);
749433d6423SLionel Sambuc 
750433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(7);
751433d6423SLionel Sambuc 
752433d6423SLionel Sambuc   if (_WIFSTOPPED(status)) {
753433d6423SLionel Sambuc 	if (ptrace(T_RESUME, pid, 0, SIGUSR1) != 0) my_e(8);
754433d6423SLionel Sambuc 
755433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(9);
756433d6423SLionel Sambuc   }
757433d6423SLionel Sambuc 
758433d6423SLionel Sambuc   if (!_WIFSIGNALED(status)) my_e(10);
759433d6423SLionel Sambuc   if (WTERMSIG(status) != SIGUSR1) my_e(11);
760433d6423SLionel Sambuc 
761433d6423SLionel Sambuc   traced_wait();
762433d6423SLionel Sambuc }
763433d6423SLionel Sambuc 
test_catch_child()764433d6423SLionel Sambuc void test_catch_child()
765433d6423SLionel Sambuc {
766433d6423SLionel Sambuc   struct sigaction sa;
767433d6423SLionel Sambuc   sigset_t set, oset;
768433d6423SLionel Sambuc 
769433d6423SLionel Sambuc   sa.sa_handler = catch_handler;
770433d6423SLionel Sambuc   sigemptyset(&sa.sa_mask);
771433d6423SLionel Sambuc   sa.sa_flags = SA_NODEFER;
772433d6423SLionel Sambuc 
773433d6423SLionel Sambuc   sigaction(SIGUSR1, &sa, NULL);
774433d6423SLionel Sambuc   sigaction(SIGUSR2, &sa, NULL);
775433d6423SLionel Sambuc   sigaction(SIGTERM, &sa, NULL);
776433d6423SLionel Sambuc 
777433d6423SLionel Sambuc   sigfillset(&set);
778433d6423SLionel Sambuc   sigprocmask(SIG_SETMASK, &set, &oset);
779433d6423SLionel Sambuc 
780433d6423SLionel Sambuc   caught = 0;
781433d6423SLionel Sambuc 
782433d6423SLionel Sambuc   WRITE(0);
783433d6423SLionel Sambuc 
784433d6423SLionel Sambuc   while (caught != 7) sigsuspend(&oset);
785433d6423SLionel Sambuc 
786433d6423SLionel Sambuc   exit(42);
787433d6423SLionel Sambuc }
788433d6423SLionel Sambuc 
test_catch()789433d6423SLionel Sambuc void test_catch()
790433d6423SLionel Sambuc {
791433d6423SLionel Sambuc   pid_t pid;
792433d6423SLionel Sambuc   int r, sig, status;
793433d6423SLionel Sambuc 
794433d6423SLionel Sambuc   subtest = 7;
795433d6423SLionel Sambuc 
796433d6423SLionel Sambuc   pid = traced_fork(test_catch_child);
797433d6423SLionel Sambuc 
798433d6423SLionel Sambuc   if (READ() != 0) my_e(1);
799433d6423SLionel Sambuc 
800433d6423SLionel Sambuc   if (kill(pid, SIGUSR1) != 0) my_e(2);
801433d6423SLionel Sambuc   if (kill(pid, SIGUSR2) != 0) my_e(3);
802433d6423SLionel Sambuc 
803433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(4);
804433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(5);
805433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGUSR2) my_e(6);
806433d6423SLionel Sambuc   sig = (WSTOPSIG(status) == SIGUSR1) ? SIGUSR2 : SIGUSR1;
807433d6423SLionel Sambuc 
808433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, WSTOPSIG(status)) != 0) my_e(7);
809433d6423SLionel Sambuc 
810433d6423SLionel Sambuc   if (kill(pid, SIGTERM) != 0) my_e(8);
811433d6423SLionel Sambuc 
812433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(9);
813433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(10);
814433d6423SLionel Sambuc   if (WSTOPSIG(status) != sig && WSTOPSIG(status) != SIGTERM) my_e(11);
815433d6423SLionel Sambuc   if (WSTOPSIG(status) == sig) sig = SIGTERM;
816433d6423SLionel Sambuc 
817433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, WSTOPSIG(status)) != 0) my_e(12);
818433d6423SLionel Sambuc 
819433d6423SLionel Sambuc   if (kill(pid, SIGBUS) != 0) my_e(13);
820433d6423SLionel Sambuc 
821433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(14);
822433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(15);
823433d6423SLionel Sambuc   if (WSTOPSIG(status) != sig && WSTOPSIG(status) != SIGBUS) my_e(16);
824433d6423SLionel Sambuc 
825433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, sig) != 0) my_e(17);
826433d6423SLionel Sambuc 
827433d6423SLionel Sambuc   if (WSTOPSIG(status) == sig) sig = SIGBUS;
828433d6423SLionel Sambuc 
829433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(18);
830433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(19);
831433d6423SLionel Sambuc   if (WSTOPSIG(status) != sig) my_e(20);
832433d6423SLionel Sambuc 
833433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(21);
834433d6423SLionel Sambuc 
835433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(22);
836433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(23);
837433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
838433d6423SLionel Sambuc 
839433d6423SLionel Sambuc   traced_wait();
840433d6423SLionel Sambuc }
841433d6423SLionel Sambuc 
test_kill_child()842433d6423SLionel Sambuc void test_kill_child()
843433d6423SLionel Sambuc {
844433d6423SLionel Sambuc   sigset_t set;
845433d6423SLionel Sambuc 
846433d6423SLionel Sambuc   signal(SIGKILL, SIG_IGN);
847433d6423SLionel Sambuc   sigfillset(&set);
848433d6423SLionel Sambuc   sigprocmask(SIG_SETMASK, &set, NULL);
849433d6423SLionel Sambuc 
850433d6423SLionel Sambuc   WRITE(0);
851433d6423SLionel Sambuc 
852433d6423SLionel Sambuc   pause();
853433d6423SLionel Sambuc 
854433d6423SLionel Sambuc   my_e(100);
855433d6423SLionel Sambuc }
856433d6423SLionel Sambuc 
test_kill()857433d6423SLionel Sambuc void test_kill()
858433d6423SLionel Sambuc {
859433d6423SLionel Sambuc   pid_t pid;
860433d6423SLionel Sambuc   int status;
861433d6423SLionel Sambuc 
862433d6423SLionel Sambuc   subtest = 8;
863433d6423SLionel Sambuc 
864433d6423SLionel Sambuc   pid = traced_fork(test_kill_child);
865433d6423SLionel Sambuc 
866433d6423SLionel Sambuc   if (READ() != 0) my_e(1);
867433d6423SLionel Sambuc 
868433d6423SLionel Sambuc   /* SIGKILL must be unstoppable in every way. */
869433d6423SLionel Sambuc   if (kill(pid, SIGKILL) != 0) my_e(2);
870433d6423SLionel Sambuc 
871433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(3);
872433d6423SLionel Sambuc   if (!_WIFSIGNALED(status)) my_e(4);
873433d6423SLionel Sambuc   if (WTERMSIG(status) != SIGKILL) my_e(5);
874433d6423SLionel Sambuc 
875433d6423SLionel Sambuc   /* After termination, the child must no longer be visible to the tracer. */
876433d6423SLionel Sambuc   if (waitpid(pid, &status, WNOHANG) != -1) my_e(6);
877433d6423SLionel Sambuc   if (errno != ECHILD) my_e(7);
878433d6423SLionel Sambuc 
879433d6423SLionel Sambuc   traced_wait();
880433d6423SLionel Sambuc }
881433d6423SLionel Sambuc 
test_attach_child()882433d6423SLionel Sambuc void test_attach_child()
883433d6423SLionel Sambuc {
884433d6423SLionel Sambuc   if (ptrace(T_OK, 0, 0, 0) != -1) my_e(100);
885433d6423SLionel Sambuc   if (errno != EBUSY) my_e(101);
886433d6423SLionel Sambuc 
887433d6423SLionel Sambuc   WRITE(0);
888433d6423SLionel Sambuc 
889433d6423SLionel Sambuc   if (READ() != 0) my_e(102);
890433d6423SLionel Sambuc 
891433d6423SLionel Sambuc   exit(42);
892433d6423SLionel Sambuc }
893433d6423SLionel Sambuc 
test_attach()894433d6423SLionel Sambuc void test_attach()
895433d6423SLionel Sambuc {
896433d6423SLionel Sambuc   pid_t pid;
897433d6423SLionel Sambuc 
898433d6423SLionel Sambuc   subtest = 9;
899433d6423SLionel Sambuc 
900433d6423SLionel Sambuc   /* Attaching to kernel processes is not allowed. */
901433d6423SLionel Sambuc   if (ptrace(T_ATTACH, -1, 0, 0) != -1) my_e(1);
902433d6423SLionel Sambuc   if (errno != ESRCH) my_e(2);
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc   /* Attaching to self is not allowed. */
905433d6423SLionel Sambuc   if (ptrace(T_ATTACH, getpid(), 0, 0) != -1) my_e(3);
906433d6423SLionel Sambuc   if (errno != EPERM) my_e(4);
907433d6423SLionel Sambuc 
908433d6423SLionel Sambuc   /* Attaching to PM is not allowed. */
909433d6423SLionel Sambuc #if 0
910433d6423SLionel Sambuc   /* FIXME: disabled until we can reliably determine PM's pid */
911433d6423SLionel Sambuc   if (ptrace(T_ATTACH, 0, 0, 0) != -1) my_e(5);
912433d6423SLionel Sambuc   if (errno != EPERM) my_e(6);
913433d6423SLionel Sambuc #endif
914433d6423SLionel Sambuc 
915433d6423SLionel Sambuc   pid = traced_fork(test_attach_child);
916433d6423SLionel Sambuc 
917433d6423SLionel Sambuc   /* Attaching more than once is not allowed. */
918433d6423SLionel Sambuc   if (ptrace(T_ATTACH, pid, 0, 0) != -1) my_e(7);
919433d6423SLionel Sambuc   if (errno != EBUSY) my_e(8);
920433d6423SLionel Sambuc 
921433d6423SLionel Sambuc   if (READ() != 0) my_e(9);
922433d6423SLionel Sambuc 
923433d6423SLionel Sambuc   /* Detaching a running child should not succeed. */
924433d6423SLionel Sambuc   if (ptrace(T_DETACH, pid, 0, 0) == 0) my_e(10);
925433d6423SLionel Sambuc   if (errno != EBUSY) my_e(11);
926433d6423SLionel Sambuc 
927433d6423SLionel Sambuc   detach_running(pid);
928433d6423SLionel Sambuc 
929433d6423SLionel Sambuc   WRITE(0);
930433d6423SLionel Sambuc 
931433d6423SLionel Sambuc   traced_wait();
932433d6423SLionel Sambuc }
933433d6423SLionel Sambuc 
test_detach_child()934433d6423SLionel Sambuc void test_detach_child()
935433d6423SLionel Sambuc {
936433d6423SLionel Sambuc   struct sigaction sa;
937433d6423SLionel Sambuc   sigset_t set, sset, oset;
938433d6423SLionel Sambuc 
939433d6423SLionel Sambuc   sa.sa_handler = catch_handler;
940433d6423SLionel Sambuc   sigemptyset(&sa.sa_mask);
941433d6423SLionel Sambuc   sa.sa_flags = SA_NODEFER;
942433d6423SLionel Sambuc 
943433d6423SLionel Sambuc   sigaction(SIGUSR1, &sa, NULL);
944433d6423SLionel Sambuc   sigaction(SIGUSR2, &sa, NULL);
945433d6423SLionel Sambuc   sigaction(SIGTERM, &sa, NULL);
946433d6423SLionel Sambuc 
947433d6423SLionel Sambuc   sigfillset(&set);
948433d6423SLionel Sambuc   sigprocmask(SIG_SETMASK, &set, &oset);
949433d6423SLionel Sambuc 
950433d6423SLionel Sambuc   sigfillset(&sset);
951433d6423SLionel Sambuc   sigdelset(&sset, SIGUSR1);
952433d6423SLionel Sambuc 
953433d6423SLionel Sambuc   caught = 0;
954433d6423SLionel Sambuc 
955433d6423SLionel Sambuc   WRITE(0);
956433d6423SLionel Sambuc 
957433d6423SLionel Sambuc   if (sigsuspend(&sset) != -1) my_e(102);
958433d6423SLionel Sambuc   if (errno != EINTR) my_e(103);
959433d6423SLionel Sambuc 
960433d6423SLionel Sambuc   if (caught != 1) my_e(104);
961433d6423SLionel Sambuc 
962433d6423SLionel Sambuc   if (READ() != 0) my_e(105);
963433d6423SLionel Sambuc 
964433d6423SLionel Sambuc   while (caught != 7) sigsuspend(&oset);
965433d6423SLionel Sambuc 
966433d6423SLionel Sambuc   exit(42);
967433d6423SLionel Sambuc }
968433d6423SLionel Sambuc 
test_detach()969433d6423SLionel Sambuc void test_detach()
970433d6423SLionel Sambuc {
971433d6423SLionel Sambuc   pid_t pid;
972433d6423SLionel Sambuc   int r, status;
973433d6423SLionel Sambuc 
974433d6423SLionel Sambuc   /* Can't use traced_fork(), so simplify a bit */
975433d6423SLionel Sambuc   if (attach != 0) return;
976433d6423SLionel Sambuc 
977433d6423SLionel Sambuc   subtest = 10;
978433d6423SLionel Sambuc 
979433d6423SLionel Sambuc   pid = traced_pfork(test_detach_child);
980433d6423SLionel Sambuc 
981433d6423SLionel Sambuc   if (READ() != 0) my_e(1);
982433d6423SLionel Sambuc 
983433d6423SLionel Sambuc   /* The tracer should not see signals sent to the process before attaching. */
984433d6423SLionel Sambuc   if (kill(pid, SIGUSR2) != 0) my_e(2);
985433d6423SLionel Sambuc 
986433d6423SLionel Sambuc   if (ptrace(T_ATTACH, pid, 0, 0) != 0) my_e(3);
987433d6423SLionel Sambuc 
988433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(4);
989433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(5);
990433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGSTOP) my_e(6);
991433d6423SLionel Sambuc 
992433d6423SLionel Sambuc   if (ptrace(T_RESUME, pid, 0, 0) != 0) my_e(7);
993433d6423SLionel Sambuc 
994433d6423SLionel Sambuc   if (kill(pid, SIGUSR1) != 0) my_e(8);
995433d6423SLionel Sambuc 
996433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(9);
997433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(10);
998433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGUSR1) my_e(11);
999433d6423SLionel Sambuc 
1000433d6423SLionel Sambuc   /* Signals pending at the tracer should be passed on after detaching. */
1001433d6423SLionel Sambuc   if (kill(pid, SIGTERM) != 0) my_e(12);
1002433d6423SLionel Sambuc 
1003433d6423SLionel Sambuc   /* A signal may be passed with the detach request. */
1004433d6423SLionel Sambuc   if (ptrace(T_DETACH, pid, 0, SIGUSR1) != 0) my_e(13);
1005433d6423SLionel Sambuc 
1006433d6423SLionel Sambuc   WRITE(0);
1007433d6423SLionel Sambuc 
1008433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(14);
1009433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(15);
1010433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
1011433d6423SLionel Sambuc 
1012433d6423SLionel Sambuc   traced_wait();
1013433d6423SLionel Sambuc }
1014433d6423SLionel Sambuc 
test_death_child()1015433d6423SLionel Sambuc void test_death_child()
1016433d6423SLionel Sambuc {
1017433d6423SLionel Sambuc   pid_t pid;
1018433d6423SLionel Sambuc 
1019433d6423SLionel Sambuc   pid = fork();
1020433d6423SLionel Sambuc 
1021433d6423SLionel Sambuc   if (pid < 0) my_e(100);
1022433d6423SLionel Sambuc 
1023433d6423SLionel Sambuc   if (pid == 0) {
1024433d6423SLionel Sambuc 	ptrace(T_OK, 0, 0, 0);
1025433d6423SLionel Sambuc 
1026433d6423SLionel Sambuc 	WRITE(getpid());
1027433d6423SLionel Sambuc 
1028433d6423SLionel Sambuc   	for (;;) pause();
1029433d6423SLionel Sambuc   }
1030433d6423SLionel Sambuc 
1031433d6423SLionel Sambuc   if (READ() != 0) my_e(101);
1032433d6423SLionel Sambuc 
1033433d6423SLionel Sambuc   kill(getpid(), SIGKILL);
1034433d6423SLionel Sambuc 
1035433d6423SLionel Sambuc   my_e(102);
1036433d6423SLionel Sambuc }
1037433d6423SLionel Sambuc 
test_death()1038433d6423SLionel Sambuc void test_death()
1039433d6423SLionel Sambuc {
1040433d6423SLionel Sambuc   pid_t pid, cpid;
1041433d6423SLionel Sambuc   int status;
1042433d6423SLionel Sambuc 
1043433d6423SLionel Sambuc   subtest = 11;
1044433d6423SLionel Sambuc 
1045433d6423SLionel Sambuc   pid = traced_fork(test_death_child);
1046433d6423SLionel Sambuc 
1047433d6423SLionel Sambuc   cpid = READ();
1048433d6423SLionel Sambuc 
1049433d6423SLionel Sambuc   if (kill(cpid, 0) != 0) my_e(1);
1050433d6423SLionel Sambuc 
1051433d6423SLionel Sambuc   WRITE(0);
1052433d6423SLionel Sambuc 
1053433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(2);
1054433d6423SLionel Sambuc   if (!_WIFSIGNALED(status)) my_e(3);
1055433d6423SLionel Sambuc   if (WTERMSIG(status) != SIGKILL) my_e(4);
1056433d6423SLionel Sambuc 
1057433d6423SLionel Sambuc   /* The children of killed tracers should be terminated. */
1058433d6423SLionel Sambuc   while (kill(cpid, 0) == 0) sleep(1);
1059433d6423SLionel Sambuc   if (errno != ESRCH) my_e(5);
1060433d6423SLionel Sambuc 
1061433d6423SLionel Sambuc   traced_wait();
1062433d6423SLionel Sambuc }
1063433d6423SLionel Sambuc 
test_zdeath_child()1064433d6423SLionel Sambuc void test_zdeath_child()
1065433d6423SLionel Sambuc {
1066433d6423SLionel Sambuc   if (READ() != 0) my_e(100);
1067433d6423SLionel Sambuc 
1068433d6423SLionel Sambuc   exit(42);
1069433d6423SLionel Sambuc }
1070433d6423SLionel Sambuc 
test_zdeath()1071433d6423SLionel Sambuc void test_zdeath()
1072433d6423SLionel Sambuc {
1073433d6423SLionel Sambuc   pid_t pid, tpid;
1074433d6423SLionel Sambuc   int r, status;
1075433d6423SLionel Sambuc 
1076433d6423SLionel Sambuc   /* Can't use traced_fork(), so simplify a bit */
1077433d6423SLionel Sambuc   if (attach != 0) return;
1078433d6423SLionel Sambuc 
1079433d6423SLionel Sambuc   subtest = 12;
1080433d6423SLionel Sambuc 
1081433d6423SLionel Sambuc   pid = traced_pfork(test_zdeath_child);
1082433d6423SLionel Sambuc 
1083433d6423SLionel Sambuc   tpid = fork();
1084433d6423SLionel Sambuc 
1085433d6423SLionel Sambuc   if (tpid < 0) my_e(1);
1086433d6423SLionel Sambuc 
1087433d6423SLionel Sambuc   if (tpid == 0) {
1088433d6423SLionel Sambuc 	if (ptrace(T_ATTACH, pid, 0, 0) != 0) exit(101);
1089433d6423SLionel Sambuc 
1090433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) exit(102);
1091433d6423SLionel Sambuc 	if (!_WIFSTOPPED(status)) exit(103);
1092433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGSTOP) exit(104);
1093433d6423SLionel Sambuc 
1094433d6423SLionel Sambuc 	if (ptrace(T_RESUME, pid, 0, 0) != 0) exit(105);
1095433d6423SLionel Sambuc 
1096433d6423SLionel Sambuc 	WRITE(0);
1097433d6423SLionel Sambuc 
1098433d6423SLionel Sambuc 	/* Unwaited-for traced zombies should be passed to their parent. */
1099433d6423SLionel Sambuc 	sleep(2);
1100433d6423SLionel Sambuc 
1101433d6423SLionel Sambuc 	exit(84);
1102433d6423SLionel Sambuc   }
1103433d6423SLionel Sambuc 
1104433d6423SLionel Sambuc   sleep(1);
1105433d6423SLionel Sambuc 
1106433d6423SLionel Sambuc   /* However, that should only happen once the tracer has actually died. */
1107433d6423SLionel Sambuc   if (waitpid(pid, &status, WNOHANG) != 0) my_e(2);
1108433d6423SLionel Sambuc 
1109433d6423SLionel Sambuc   if (waitpid(tpid, &status, 0) != tpid) my_e(3);
1110433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(4);
1111433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 84) my_e(r);
1112433d6423SLionel Sambuc 
1113433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(5);
1114433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(6);
1115433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
1116433d6423SLionel Sambuc 
1117433d6423SLionel Sambuc   traced_wait();
1118433d6423SLionel Sambuc }
1119433d6423SLionel Sambuc 
test_syscall_child()1120433d6423SLionel Sambuc void test_syscall_child()
1121433d6423SLionel Sambuc {
1122433d6423SLionel Sambuc   signal(SIGUSR1, count_handler);
1123433d6423SLionel Sambuc   signal(SIGUSR2, count_handler);
1124433d6423SLionel Sambuc 
1125433d6423SLionel Sambuc   sigs = 0;
1126433d6423SLionel Sambuc 
1127433d6423SLionel Sambuc   WRITE(0);
1128433d6423SLionel Sambuc 
1129433d6423SLionel Sambuc   if (READ() != 0) my_e(100);
1130433d6423SLionel Sambuc 
1131433d6423SLionel Sambuc   /* Three calls (may fail) */
1132433d6423SLionel Sambuc   setuid(0);
1133433d6423SLionel Sambuc   close(123);
1134433d6423SLionel Sambuc   getpid();
1135433d6423SLionel Sambuc 
1136433d6423SLionel Sambuc   if (sigs != 2) my_e(101);
1137433d6423SLionel Sambuc 
1138433d6423SLionel Sambuc   exit(42);
1139433d6423SLionel Sambuc }
1140433d6423SLionel Sambuc 
test_syscall()1141433d6423SLionel Sambuc void test_syscall()
1142433d6423SLionel Sambuc {
1143433d6423SLionel Sambuc   pid_t pid;
1144433d6423SLionel Sambuc   int i, r, sig, status;
1145433d6423SLionel Sambuc 
1146433d6423SLionel Sambuc   subtest = 13;
1147433d6423SLionel Sambuc 
1148433d6423SLionel Sambuc   pid = traced_fork(test_syscall_child);
1149433d6423SLionel Sambuc 
1150433d6423SLionel Sambuc   if (READ() != 0) my_e(1);
1151433d6423SLionel Sambuc 
1152433d6423SLionel Sambuc   if (kill(pid, SIGSTOP) != 0) my_e(2);
1153433d6423SLionel Sambuc 
1154433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(3);
1155433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(4);
1156433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGSTOP) my_e(5);
1157433d6423SLionel Sambuc 
1158433d6423SLionel Sambuc   WRITE(0);
1159433d6423SLionel Sambuc 
1160433d6423SLionel Sambuc   /* Upon resuming a first system call, no syscall leave event must be sent. */
1161433d6423SLionel Sambuc   if (ptrace(T_SYSCALL, pid, 0, 0) != 0) my_e(6);
1162433d6423SLionel Sambuc 
1163433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(7);
1164433d6423SLionel Sambuc 
1165433d6423SLionel Sambuc   for (i = 0; _WIFSTOPPED(status); i++) {
1166433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGTRAP) my_e(8);
1167433d6423SLionel Sambuc 
1168433d6423SLionel Sambuc 	/* Signals passed via T_SYSCALL should arrive, on enter and exit. */
1169433d6423SLionel Sambuc 	if (i == 3) sig = SIGUSR1;
1170433d6423SLionel Sambuc 	else if (i == 6) sig = SIGUSR2;
1171433d6423SLionel Sambuc 	else sig = 0;
1172433d6423SLionel Sambuc 
1173433d6423SLionel Sambuc 	if (ptrace(T_SYSCALL, pid, 0, sig) != 0) my_e(9);
1174433d6423SLionel Sambuc 
1175433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(10);
1176433d6423SLionel Sambuc   }
1177433d6423SLionel Sambuc 
1178433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(11);
1179433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
1180433d6423SLionel Sambuc 
1181433d6423SLionel Sambuc   /* The number of events seen is deterministic but libc-dependent. */
1182433d6423SLionel Sambuc   if (i < 10 || i > 100) my_e(12);
1183433d6423SLionel Sambuc 
1184433d6423SLionel Sambuc   /* The last system call event must be for entering exit(). */
1185433d6423SLionel Sambuc   if (!(i % 2)) my_e(13);
1186433d6423SLionel Sambuc 
1187433d6423SLionel Sambuc   traced_wait();
1188433d6423SLionel Sambuc }
1189433d6423SLionel Sambuc 
test_tracefork_child()1190433d6423SLionel Sambuc void test_tracefork_child()
1191433d6423SLionel Sambuc {
1192433d6423SLionel Sambuc   pid_t pid;
1193433d6423SLionel Sambuc 
1194433d6423SLionel Sambuc   signal(SIGHUP, SIG_IGN);
1195433d6423SLionel Sambuc 
1196433d6423SLionel Sambuc   pid = setsid();
1197433d6423SLionel Sambuc 
1198433d6423SLionel Sambuc   WRITE(pid);
1199433d6423SLionel Sambuc 
1200433d6423SLionel Sambuc   if (READ() != 0) my_e(100);
1201433d6423SLionel Sambuc 
1202433d6423SLionel Sambuc   if ((pid = fork()) < 0) my_e(101);
1203433d6423SLionel Sambuc 
1204433d6423SLionel Sambuc   exit(pid > 0 ? 42 : 84);
1205433d6423SLionel Sambuc }
1206433d6423SLionel Sambuc 
test_tracefork()1207433d6423SLionel Sambuc void test_tracefork()
1208433d6423SLionel Sambuc {
1209433d6423SLionel Sambuc   pid_t pgrp, ppid, cpid, wpid;
1210433d6423SLionel Sambuc   int r, status, gotstop, ptraps, ctraps;
1211433d6423SLionel Sambuc 
1212433d6423SLionel Sambuc   subtest = 14;
1213433d6423SLionel Sambuc 
1214433d6423SLionel Sambuc   ppid = traced_fork(test_tracefork_child);
1215433d6423SLionel Sambuc 
1216433d6423SLionel Sambuc   if ((pgrp = READ()) <= 0) my_e(1);
1217433d6423SLionel Sambuc 
1218433d6423SLionel Sambuc   if (kill(ppid, SIGSTOP) != 0) my_e(2);
1219433d6423SLionel Sambuc 
1220433d6423SLionel Sambuc   if (waitpid(ppid, &status, 0) != ppid) my_e(3);
1221433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(4);
1222433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGSTOP) my_e(5);
1223433d6423SLionel Sambuc 
1224433d6423SLionel Sambuc   if (ptrace(T_SETOPT, ppid, 0, TO_TRACEFORK) != 0) my_e(6);
1225433d6423SLionel Sambuc 
1226433d6423SLionel Sambuc   WRITE(0);
1227433d6423SLionel Sambuc 
1228433d6423SLionel Sambuc   if (ptrace(T_SYSCALL, ppid, 0, 0) != 0) my_e(7);
1229433d6423SLionel Sambuc 
1230433d6423SLionel Sambuc   cpid = -1;
1231433d6423SLionel Sambuc   gotstop = -1;
1232433d6423SLionel Sambuc 
1233433d6423SLionel Sambuc   /* Count how many traps we get for parent and child, until they both exit. */
1234433d6423SLionel Sambuc   for (ptraps = ctraps = 0; ppid || cpid; ) {
1235433d6423SLionel Sambuc 	wpid = waitpid(-pgrp, &status, 0);
1236433d6423SLionel Sambuc 
1237433d6423SLionel Sambuc 	if (wpid <= 0) my_e(8);
1238433d6423SLionel Sambuc 	if (cpid < 0 && wpid != ppid) {
1239433d6423SLionel Sambuc 		cpid = wpid;
1240433d6423SLionel Sambuc 		gotstop = 0;
1241433d6423SLionel Sambuc 	}
1242433d6423SLionel Sambuc 	if (wpid != ppid && wpid != cpid) my_e(9);
1243433d6423SLionel Sambuc 
1244433d6423SLionel Sambuc 	if (_WIFEXITED(status)) {
1245433d6423SLionel Sambuc 		if (wpid == ppid) {
1246433d6423SLionel Sambuc 			if ((r = WEXITSTATUS(status)) != 42) my_e(r);
1247433d6423SLionel Sambuc 			ppid = 0;
1248433d6423SLionel Sambuc 		}
1249433d6423SLionel Sambuc 		else {
1250433d6423SLionel Sambuc 			if ((r = WEXITSTATUS(status)) != 84) my_e(r);
1251433d6423SLionel Sambuc 			cpid = 0;
1252433d6423SLionel Sambuc 		}
1253433d6423SLionel Sambuc 	}
1254433d6423SLionel Sambuc 	else {
1255433d6423SLionel Sambuc 		if (!_WIFSTOPPED(status)) my_e(10);
1256433d6423SLionel Sambuc 
1257433d6423SLionel Sambuc 		switch (WSTOPSIG(status)) {
1258433d6423SLionel Sambuc 		case SIGCHLD:
1259433d6423SLionel Sambuc 		case SIGHUP:
1260433d6423SLionel Sambuc 			break;
1261433d6423SLionel Sambuc 		case SIGSTOP:
1262433d6423SLionel Sambuc 			if (wpid != cpid) my_e(11);
1263433d6423SLionel Sambuc 			if (gotstop) my_e(12);
1264433d6423SLionel Sambuc 			gotstop = 1;
1265433d6423SLionel Sambuc 			break;
1266433d6423SLionel Sambuc 		case SIGTRAP:
1267433d6423SLionel Sambuc 			if (wpid == ppid) ptraps++;
1268433d6423SLionel Sambuc 			else ctraps++;
1269433d6423SLionel Sambuc 			break;
1270433d6423SLionel Sambuc 		default:
1271433d6423SLionel Sambuc 			my_e(13);
1272433d6423SLionel Sambuc 		}
1273433d6423SLionel Sambuc 
1274433d6423SLionel Sambuc 		if (ptrace(T_SYSCALL, wpid, 0, 0) != 0) my_e(14);
1275433d6423SLionel Sambuc 	}
1276433d6423SLionel Sambuc   }
1277433d6423SLionel Sambuc 
1278433d6423SLionel Sambuc   /* The parent should get an odd number of traps: the first one is a syscall
1279433d6423SLionel Sambuc    * enter trap (typically for the fork()), the last one is the syscall enter
1280433d6423SLionel Sambuc    * trap for its exit().
1281433d6423SLionel Sambuc    */
1282433d6423SLionel Sambuc   if (ptraps < 3) my_e(15);
1283433d6423SLionel Sambuc   if (!(ptraps % 2)) my_e(16);
1284433d6423SLionel Sambuc 
1285433d6423SLionel Sambuc   /* The child should get an even number of traps: the first one is a syscall
1286433d6423SLionel Sambuc    * leave trap from the fork(), the last one is the syscall enter trap for
1287433d6423SLionel Sambuc    * its exit().
1288433d6423SLionel Sambuc    */
1289433d6423SLionel Sambuc   if (ctraps < 2) my_e(17);
1290433d6423SLionel Sambuc   if (ctraps % 2) my_e(18);
1291433d6423SLionel Sambuc 
1292433d6423SLionel Sambuc   traced_wait();
1293433d6423SLionel Sambuc }
1294433d6423SLionel Sambuc 
sigexec(setflag,opt,traps,stop)1295433d6423SLionel Sambuc void sigexec(setflag, opt, traps, stop)
1296433d6423SLionel Sambuc int setflag;
1297433d6423SLionel Sambuc int opt;
1298433d6423SLionel Sambuc int *traps;
1299433d6423SLionel Sambuc int *stop;
1300433d6423SLionel Sambuc {
1301433d6423SLionel Sambuc   pid_t pid;
1302433d6423SLionel Sambuc   int r, status;
1303433d6423SLionel Sambuc 
1304433d6423SLionel Sambuc   pid = traced_fork(test_exec_child);
1305433d6423SLionel Sambuc 
1306433d6423SLionel Sambuc   if (kill(pid, SIGSTOP) != 0) my_e(1);
1307433d6423SLionel Sambuc 
1308433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(2);
1309433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(3);
1310433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGSTOP) my_e(4);
1311433d6423SLionel Sambuc 
1312433d6423SLionel Sambuc   if (setflag && ptrace(T_SETOPT, pid, 0, opt) != 0) my_e(5);
1313433d6423SLionel Sambuc 
1314433d6423SLionel Sambuc   WRITE(0);
1315433d6423SLionel Sambuc 
1316433d6423SLionel Sambuc   if (ptrace(T_SYSCALL, pid, 0, 0) != 0) my_e(6);
1317433d6423SLionel Sambuc 
1318433d6423SLionel Sambuc   *traps = 0;
1319433d6423SLionel Sambuc   *stop = -1;
1320433d6423SLionel Sambuc 
1321433d6423SLionel Sambuc   for (;;) {
1322433d6423SLionel Sambuc   	if (waitpid(pid, &status, 0) != pid) my_e(7);
1323433d6423SLionel Sambuc 
1324433d6423SLionel Sambuc   	if (_WIFEXITED(status)) break;
1325433d6423SLionel Sambuc 
1326433d6423SLionel Sambuc   	if (!_WIFSTOPPED(status)) my_e(8);
1327433d6423SLionel Sambuc 
1328433d6423SLionel Sambuc   	switch (WSTOPSIG(status)) {
1329433d6423SLionel Sambuc   	case SIGTRAP:
1330433d6423SLionel Sambuc 		(*traps)++;
1331433d6423SLionel Sambuc 		break;
1332433d6423SLionel Sambuc   	case SIGSTOP:
1333433d6423SLionel Sambuc   		if (*stop >= 0) my_e(9);
1334433d6423SLionel Sambuc   		*stop = *traps;
1335433d6423SLionel Sambuc   		break;
1336433d6423SLionel Sambuc   	default:
1337433d6423SLionel Sambuc 		my_e(10);
1338433d6423SLionel Sambuc   	}
1339433d6423SLionel Sambuc 
1340433d6423SLionel Sambuc   	if (ptrace(T_SYSCALL, pid, 0, 0) != 0) my_e(11);
1341433d6423SLionel Sambuc   }
1342433d6423SLionel Sambuc 
1343433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
1344433d6423SLionel Sambuc 
1345433d6423SLionel Sambuc   traced_wait();
1346433d6423SLionel Sambuc }
1347433d6423SLionel Sambuc 
test_trapexec()1348433d6423SLionel Sambuc void test_trapexec()
1349433d6423SLionel Sambuc {
1350433d6423SLionel Sambuc   int traps, stop;
1351433d6423SLionel Sambuc 
1352433d6423SLionel Sambuc   subtest = 15;
1353433d6423SLionel Sambuc 
1354433d6423SLionel Sambuc   sigexec(1, 0, &traps, &stop);
1355433d6423SLionel Sambuc 
1356433d6423SLionel Sambuc   /* The exec does not cause a SIGSTOP. This gives us an even number of traps;
1357433d6423SLionel Sambuc    * as above, but plus the exec()'s extra SIGTRAP. This trap is
1358433d6423SLionel Sambuc    * indistinguishable from a syscall trap, especially when considering failed
1359433d6423SLionel Sambuc    * exec() calls and immediately following signal handler invocations.
1360433d6423SLionel Sambuc    */
1361433d6423SLionel Sambuc   if (traps < 4) my_e(12);
1362433d6423SLionel Sambuc   if (traps % 2) my_e(13);
1363433d6423SLionel Sambuc   if (stop >= 0) my_e(14);
1364433d6423SLionel Sambuc }
1365433d6423SLionel Sambuc 
test_altexec()1366433d6423SLionel Sambuc void test_altexec()
1367433d6423SLionel Sambuc {
1368433d6423SLionel Sambuc   int traps, stop;
1369433d6423SLionel Sambuc 
1370433d6423SLionel Sambuc   subtest = 16;
1371433d6423SLionel Sambuc 
1372433d6423SLionel Sambuc   sigexec(1, TO_ALTEXEC, &traps, &stop);
1373433d6423SLionel Sambuc 
1374433d6423SLionel Sambuc   /* The exec causes a SIGSTOP. This gives us an odd number of traps: a pair
1375433d6423SLionel Sambuc    * for each system call, plus one for the final exit(). The stop must have
1376433d6423SLionel Sambuc    * taken place after a syscall enter event, i.e. must be odd as well.
1377433d6423SLionel Sambuc    */
1378433d6423SLionel Sambuc   if (traps < 3) my_e(12);
1379433d6423SLionel Sambuc   if (!(traps % 2)) my_e(13);
1380433d6423SLionel Sambuc   if (stop < 0) my_e(14);
1381433d6423SLionel Sambuc   if (!(stop % 2)) my_e(15);
1382433d6423SLionel Sambuc }
1383433d6423SLionel Sambuc 
test_noexec()1384433d6423SLionel Sambuc void test_noexec()
1385433d6423SLionel Sambuc {
1386433d6423SLionel Sambuc   int traps, stop;
1387433d6423SLionel Sambuc 
1388433d6423SLionel Sambuc   subtest = 17;
1389433d6423SLionel Sambuc 
1390433d6423SLionel Sambuc   sigexec(1, TO_NOEXEC, &traps, &stop);
1391433d6423SLionel Sambuc 
1392433d6423SLionel Sambuc   /* The exec causes no signal at all. As above, but without the SIGSTOPs. */
1393433d6423SLionel Sambuc   if (traps < 3) my_e(12);
1394433d6423SLionel Sambuc   if (!(traps % 2)) my_e(13);
1395433d6423SLionel Sambuc   if (stop >= 0) my_e(14);
1396433d6423SLionel Sambuc }
1397433d6423SLionel Sambuc 
test_defexec()1398433d6423SLionel Sambuc void test_defexec()
1399433d6423SLionel Sambuc {
1400433d6423SLionel Sambuc   int traps, stop;
1401433d6423SLionel Sambuc 
1402433d6423SLionel Sambuc   /* We want to test the default of T_OK (0) and T_ATTACH (TO_NOEXEC). */
1403433d6423SLionel Sambuc   if (attach != 0 && attach != 1) return;
1404433d6423SLionel Sambuc 
1405433d6423SLionel Sambuc   subtest = 18;
1406433d6423SLionel Sambuc 
1407433d6423SLionel Sambuc   /* Do not set any options this time. */
1408433d6423SLionel Sambuc   sigexec(0, 0, &traps, &stop);
1409433d6423SLionel Sambuc 
1410433d6423SLionel Sambuc   /* See above. */
1411433d6423SLionel Sambuc   if (attach == 0) {
1412433d6423SLionel Sambuc 	if (traps < 4) my_e(12);
1413433d6423SLionel Sambuc 	if (traps % 2) my_e(13);
1414433d6423SLionel Sambuc 	if (stop >= 0) my_e(14);
1415433d6423SLionel Sambuc   }
1416433d6423SLionel Sambuc   else {
1417433d6423SLionel Sambuc 	if (traps < 3) my_e(15);
1418433d6423SLionel Sambuc 	if (!(traps % 2)) my_e(16);
1419433d6423SLionel Sambuc 	if (stop >= 0) my_e(17);
1420433d6423SLionel Sambuc   }
1421433d6423SLionel Sambuc }
1422433d6423SLionel Sambuc 
test_reattach_child()1423433d6423SLionel Sambuc void test_reattach_child()
1424433d6423SLionel Sambuc {
1425433d6423SLionel Sambuc   struct timeval tv;
1426433d6423SLionel Sambuc 
1427433d6423SLionel Sambuc   if (READ() != 0) my_e(100);
1428433d6423SLionel Sambuc 
1429433d6423SLionel Sambuc   tv.tv_sec = 2;
1430433d6423SLionel Sambuc   tv.tv_usec = 0;
1431433d6423SLionel Sambuc   if (select(0, NULL, NULL, NULL, &tv) != 0) my_e(101);
1432433d6423SLionel Sambuc 
1433433d6423SLionel Sambuc   exit(42);
1434433d6423SLionel Sambuc }
1435433d6423SLionel Sambuc 
test_reattach()1436433d6423SLionel Sambuc void test_reattach()
1437433d6423SLionel Sambuc {
1438433d6423SLionel Sambuc   pid_t pid;
1439433d6423SLionel Sambuc   int r, status, count;
1440433d6423SLionel Sambuc 
1441433d6423SLionel Sambuc   subtest = 19;
1442433d6423SLionel Sambuc 
1443433d6423SLionel Sambuc   pid = traced_fork(test_reattach_child);
1444433d6423SLionel Sambuc 
1445433d6423SLionel Sambuc   if (kill(pid, SIGSTOP) != 0) my_e(1);
1446433d6423SLionel Sambuc 
1447433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(2);
1448433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(3);
1449433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGSTOP) my_e(4);
1450433d6423SLionel Sambuc 
1451433d6423SLionel Sambuc   WRITE(0);
1452433d6423SLionel Sambuc 
1453433d6423SLionel Sambuc   signal(SIGALRM, dummy_handler);
1454433d6423SLionel Sambuc   alarm(1);
1455433d6423SLionel Sambuc 
1456433d6423SLionel Sambuc   /* Start tracing system calls. We don't know how many there will be until
1457433d6423SLionel Sambuc    * we reach the child's select(), so we have to interrupt ourselves.
1458433d6423SLionel Sambuc    * The hard assumption here is that the child is able to enter the select()
1459433d6423SLionel Sambuc    * within a second, despite being traced. If this is not the case, the test
1460433d6423SLionel Sambuc    * may hang or fail, and the child may die from a SIGTRAP.
1461433d6423SLionel Sambuc    */
1462433d6423SLionel Sambuc   if (ptrace(T_SYSCALL, pid, 0, 0) != 0) my_e(5);
1463433d6423SLionel Sambuc 
1464433d6423SLionel Sambuc   for (count = 0; (r = waitpid(pid, &status, 0)) == pid; count++) {
1465433d6423SLionel Sambuc 	if (!_WIFSTOPPED(status)) my_e(6);
1466433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGTRAP) my_e(7);
1467433d6423SLionel Sambuc 
1468433d6423SLionel Sambuc 	if (ptrace(T_SYSCALL, pid, 0, 0) != 0) my_e(8);
1469433d6423SLionel Sambuc   }
1470433d6423SLionel Sambuc 
1471433d6423SLionel Sambuc   if (r != -1 || errno != EINTR) my_e(9);
1472433d6423SLionel Sambuc 
1473433d6423SLionel Sambuc   /* We always start with syscall enter event; the last event we should have
1474433d6423SLionel Sambuc    * seen before the alarm was entering the select() call.
1475433d6423SLionel Sambuc    */
1476433d6423SLionel Sambuc   if (!(count % 2)) my_e(10);
1477433d6423SLionel Sambuc 
1478433d6423SLionel Sambuc   /* Detach, and immediately attach again. */
1479433d6423SLionel Sambuc   detach_running(pid);
1480433d6423SLionel Sambuc 
1481433d6423SLionel Sambuc   if (ptrace(T_ATTACH, pid, 0, 0) != 0) my_e(11);
1482433d6423SLionel Sambuc 
1483433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(12);
1484433d6423SLionel Sambuc   if (!_WIFSTOPPED(status)) my_e(13);
1485433d6423SLionel Sambuc   if (WSTOPSIG(status) != SIGSTOP) my_e(14);
1486433d6423SLionel Sambuc 
1487433d6423SLionel Sambuc   if (ptrace(T_SYSCALL, pid, 0, 0) != 0) my_e(15);
1488433d6423SLionel Sambuc 
1489433d6423SLionel Sambuc   if (waitpid(pid, &status, 0) != pid) my_e(16);
1490433d6423SLionel Sambuc 
1491433d6423SLionel Sambuc   for (count = 0; _WIFSTOPPED(status); count++) {
1492433d6423SLionel Sambuc 	if (WSTOPSIG(status) != SIGTRAP) my_e(17);
1493433d6423SLionel Sambuc 
1494433d6423SLionel Sambuc 	if (ptrace(T_SYSCALL, pid, 0, 0) != 0) my_e(18);
1495433d6423SLionel Sambuc 
1496433d6423SLionel Sambuc 	if (waitpid(pid, &status, 0) != pid) my_e(19);
1497433d6423SLionel Sambuc   }
1498433d6423SLionel Sambuc 
1499433d6423SLionel Sambuc   if (!_WIFEXITED(status)) my_e(20);
1500433d6423SLionel Sambuc   if ((r = WEXITSTATUS(status)) != 42) my_e(r);
1501433d6423SLionel Sambuc 
1502433d6423SLionel Sambuc   /* We must not have seen the select()'s syscall leave event, and the last
1503433d6423SLionel Sambuc    * event will be the syscall enter for the exit().
1504433d6423SLionel Sambuc    */
1505433d6423SLionel Sambuc   if (!(count % 2)) my_e(21);
1506433d6423SLionel Sambuc 
1507433d6423SLionel Sambuc   traced_wait();
1508433d6423SLionel Sambuc }
1509433d6423SLionel Sambuc 
1510