GNU coding style.
[debugger.git] / testsuite.c
1 /* Copyright 2007, Red Hat Inc.  */
2
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <assert.h>
6 #include <sys/types.h>
7 #include <sys/wait.h>
8 #include <linux/unistd.h>
9 #include <limits.h>
10 #include <string.h>
11 #include <pthread.h>
12
13 #include "debugger.h"
14
15 #define LIBRARY 1
16 #include "debugger.c"
17
18
19 _syscall2(int, tkill, int, tid, int, sig)
20 int tkill(int tid, int sig);
21
22
23 static int attach_checked (pid_t pid, int redelivered_expect)
24 {
25   int stopped;
26
27   STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED));
28   stopped = attach (pid);
29   if (attach_redelivered != redelivered_expect)
30     {
31       fprintf (stderr, "Expecting redelivery of %d but found %d\n",
32                redelivered_expect, attach_redelivered);
33       abort ();
34     }
35   /* FIXME: Why also STATE_STOPPED?  */
36   STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED));
37   return stopped;
38 }
39
40 static void detach_checked (pid_t pid, int stopped)
41 {
42   /* FIXME: Why STATE_STOPPED?  */
43   STATE (pid, (stopped ? 1 << STATE_STOPPED : 1 << STATE_PTRACED));
44   detach (pid, stopped);
45   STATE (pid, (stopped ? 1 << STATE_STOPPED : (1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
46 }
47
48 struct registry
49   {
50     struct registry *next;
51     pid_t pid;
52   };
53 struct registry *registry_list;
54
55 static void registry_add (pid_t pid)
56 {
57   struct registry *new;
58
59   new = malloc (sizeof (*new));
60   assert (new != NULL);
61   new->pid = pid;
62   new->next = registry_list;
63   registry_list = new;
64 }
65
66 static void registry_remove (pid_t pid)
67 {
68   struct registry **iter_pointer;
69
70   for (iter_pointer = &registry_list; *iter_pointer != NULL;
71        iter_pointer = &(*iter_pointer)->next)
72     {
73       struct registry *found = *iter_pointer;
74       if (found->pid != pid)
75         continue;
76
77       *iter_pointer = found->next;
78       free (found);
79       return;
80     }
81   abort ();
82 }
83
84 static void registry_atexit (void)
85 {
86   struct registry *iter;
87
88   for (iter = registry_list; iter != NULL; iter = iter->next)
89     kill (iter->pid, SIGKILL);
90 }
91
92 static void registry_handler (int signo)
93 {
94   signal (signo, SIG_DFL);
95   registry_atexit ();
96   raise (signo);
97 }
98
99 static void child_pause (void)
100 {
101   for (;;)
102     pause ();
103   /* NOTREACHED */
104   abort ();
105 }
106
107 static void child_alrm_handler (int signo)
108 {
109   assert (signo == SIGALRM);
110   raise (SIGALRM);
111 }
112
113 static void child_alrm (void)
114 {
115   void (*handler_orig) (int signo);
116 #if 0
117   int i;
118   sigset_t oldset;
119 #endif
120
121   handler_orig = signal (SIGALRM, child_alrm_handler);
122   assert (handler_orig == SIG_DFL);
123
124 #if 0
125   i = sigprocmask (SIG_BLOCK, NULL, &oldset);
126   assert (i == 0);
127   printf ("sigprocmask () -> sigismember (SIGALRM) == %d\n", sigismember (&oldset, SIGALRM));
128 #endif
129
130   for (;;)
131     pause ();
132   /* NOTREACHED */
133   abort ();
134 }
135
136 static pid_t spawn (void *(*child) (void *data, void *input), void *data,
137                     void *input, int fd_close)
138 {
139   pid_t pid;
140
141   pid = fork();
142   switch (pid)
143     {
144       case -1:
145         perror ("fork()");
146         exit (EXIT_FAILURE);
147         /* NOTREACHED */
148       case 0:
149         if (fd_close != -1)
150           {
151             int i;
152
153             i = close (fd_close);
154             assert (i == 0);
155           }
156         child (data, input);
157         /* NOTREACHED */
158         abort ();
159       default:;
160         /* PASSTHRU */
161     }
162   /* Parent.  */
163
164   registry_add (pid);
165   STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING));
166   return pid;
167 }
168
169 static void murder (pid_t pid)
170 {
171   int i;
172   pid_t pid_got;
173   int status;
174
175   if (pid == 0)
176     return;
177
178   i = kill (pid, SIGKILL);
179   assert (i == 0);
180
181   pid_got = waitpid (pid, &status, 0);
182   if (!(pid_got == -1 && errno == ECHILD))
183     {
184       assert (pid_got == pid);
185       assert ((WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)
186               || (WIFEXITED (status) && WEXITSTATUS (status) == 0));
187       STATE (pid, 1 << STATE_ENOENT);
188     }
189   else
190     STATE (pid, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE));
191
192   registry_remove (pid);
193 }
194
195
196 struct child_spawner
197   {
198     void *(*child) (void *data, void *input);
199     void *data;
200     int fd;
201   };
202
203 static void *child_spawner (void *param_voidpointer, void *input)
204 {
205   struct child_spawner *param = param_voidpointer;
206   pid_t inferior;
207   ssize_t inferior_size;
208   int i;
209
210   inferior = spawn (param->child, param->data, input, param->fd);
211
212   inferior_size = write (param->fd, &inferior, sizeof (inferior));
213   assert (inferior_size == sizeof (inferior));
214   i = close (param->fd);
215   assert (i == 0);
216
217   waitpid (inferior, NULL, 0);
218   _exit (EXIT_SUCCESS);
219   /* NOTREACHED */
220   abort ();
221 }
222
223 struct spawner
224   {
225     void *(*func) (void *data, void *input);
226     void *data;
227   };
228
229 static void *spawn_with_waiter (void *data, void *input)
230 {
231   pid_t waiter;
232   struct child_spawner param_local;
233   int pipefds[2];
234   int i;
235   pid_t inferior;
236   ssize_t inferior_size;
237   unsigned char buf;
238   ssize_t buf_size;
239   struct spawner *param = data;
240
241   assert (data != NULL);
242
243   i = pipe (pipefds);
244   assert (i == 0);
245
246   param_local.child = param->func;
247   param_local.data = param->data;
248   param_local.fd = pipefds[1];
249   waiter = spawn (child_spawner, &param_local, input, pipefds[0]);
250
251   i = close (pipefds[1]);
252   assert (i == 0);
253   inferior_size = read (pipefds[0], &inferior, sizeof (inferior));
254   assert (inferior_size == sizeof (inferior));
255   buf_size = read (pipefds[0], &buf, sizeof (buf));
256   assert (buf_size == 0);
257   i = close (pipefds[0]);
258   assert (i == 0);
259
260   registry_add (inferior);
261
262   return (void *) (unsigned long) inferior;
263 }
264
265 static void *spawn_without_waiter (void *data, void *input)
266 {
267   struct spawner *param = data;
268
269   return (void *) (unsigned long) spawn (param->func, param->data, input, -1);
270 }
271
272 static void body_spawner (void *(*child) (void *data, void *input), void *data,
273                           void *input)
274 {
275   pid_t inferior;
276   int stopped;
277   int i;
278
279   assert (input == NULL);
280
281   /* Plain attach/detach.  */
282   inferior = (unsigned long) (*child) (data, child_pause);
283   stopped = attach_checked (inferior, 0);
284   assert (stopped == 0);
285   detach_checked (inferior, stopped);
286   murder (inferior);
287
288   /* Attach to a process stopped by standard kill(2).  */
289   inferior = (unsigned long) (*child) (data, child_pause);
290   delay ();
291   i = kill (inferior, SIGSTOP);
292   assert (i == 0);
293   STATE (inferior, 1 << STATE_STOPPED);
294   stopped = attach_checked (inferior, 0);
295   assert (stopped == 1);
296   detach_checked (inferior, stopped);
297   murder (inferior);
298
299   /* Attach to a process stopped by Linux specific tkill(2).  */
300   inferior = (unsigned long) (*child) (data, child_pause);
301   delay ();
302   i = tkill (inferior, SIGSTOP);
303   assert (i == 0);
304   STATE (inferior, 1 << STATE_STOPPED);
305   stopped = attach_checked (inferior, 0);
306   assert (stopped == 1);
307   detach_checked (inferior, stopped);
308   murder (inferior);
309
310   /* Attach to a stopped process with already pending SIGALRM.  */
311   inferior = (unsigned long) (*child) (data, child_alrm);
312   STATE (inferior, 1 << STATE_SLEEPING);
313   delay ();
314   i = tkill (inferior, SIGSTOP);
315   assert (i == 0);
316   delay ();
317   i = tkill (inferior, SIGALRM);
318   assert (i == 0);
319   STATE (inferior, 1 << STATE_STOPPED);
320   /* FIXME: SIGALRM did not get redelivered?  */
321 #if 0
322   stopped = attach_checked (inferior, SIGALRM);
323 #else
324   stopped = attach_checked (inferior, 0);
325 #endif
326   assert (stopped == 1);
327   detach_checked (inferior, stopped);
328   STATE (inferior, 1 << STATE_STOPPED);
329   delay ();
330   i = tkill (inferior, SIGCONT);
331   assert (i == 0);
332   STATE (inferior, 1 << STATE_RUNNING);
333   murder (inferior);
334 }
335
336 static void *pass (void *data, void *input)
337 {
338   struct spawner *param = data;
339   void (*input_func) (void) = input;
340
341   if (param != NULL)
342     return (*param->func) (param->data, input);
343
344   assert (input_func != NULL);
345   (*input_func) ();
346   /* NOTREACHED */
347   abort ();
348 }
349
350 static void *spawn_singlethreaded (void *data, void *input)
351 {
352   return pass (data, input);
353 }
354
355 static void *spawn_threaded_parent_start (void *arg)
356 {
357   for (;;)
358     pause ();
359   /* NOTREACHED */
360   abort ();
361 }
362
363 static void *spawn_threaded_parent (void *data, void *input)
364 {
365   pthread_t thread;
366   int i;
367
368   i = pthread_create (&thread, NULL, spawn_threaded_parent_start, NULL);
369   assert (i == 0);
370   return pass (data, input);
371 }
372
373 struct spawn_threaded_child_start
374   {
375     void *data;
376     void *input;
377   };
378
379 static void *spawn_threaded_child_start (void *arg_voidpointer)
380 {
381   struct spawn_threaded_child_start *arg = arg_voidpointer;
382
383   return pass (arg->data, arg->input);
384   /* NOTREACHED */
385 }
386
387 static void *spawn_threaded_child (void *data, void *input)
388 {
389   pthread_t thread;
390   int i;
391   struct spawn_threaded_child_start arg_local;
392
393   arg_local.data = data;
394   arg_local.input = input;
395   i = pthread_create (&thread, NULL, spawn_threaded_child_start, &arg_local);
396   assert (i == 0);
397   i = pthread_join (thread, NULL);
398   assert (i == 0);
399
400   _exit (EXIT_SUCCESS);
401 }
402
403 static void body_maywaiter (void *(*child) (void *data, void *input),
404                             void *data, void *input)
405 {
406   struct spawner param_local;
407
408   param_local.func = child;
409   param_local.data = data;
410   body_spawner (spawn_without_waiter, &param_local, NULL);
411   body_spawner (spawn_with_waiter, &param_local, NULL);
412 }
413
414 int main (int argc, char **argv)
415 {
416   atexit (registry_atexit);
417   signal (SIGINT, registry_handler);
418   signal (SIGABRT, registry_handler);
419
420   body_maywaiter (spawn_singlethreaded, NULL, NULL);
421   body_maywaiter (spawn_threaded_parent, NULL, NULL);
422   body_maywaiter (spawn_threaded_child, NULL, NULL);
423
424   return EXIT_SUCCESS;
425 }