Cosmetic error reporting cleanup.
[debugger.git] / testsuite.c
1 /* Copyright 2007, Red Hat Inc.  */
2
3 #define _GNU_SOURCE 1
4
5 #include <unistd.h>
6 #include <stdlib.h>
7 #include <assert.h>
8 #include <sys/types.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
11 #include <limits.h>
12 #include <string.h>
13 #include <pthread.h>
14 #include <sys/syscall.h>
15 #include <dlfcn.h>
16
17 #include "debugger.h"
18
19 #define LIBRARY 1
20 #include "debugger.c"
21
22
23 #define tkill(tid, sig) syscall (SYS_tkill, (tid), (sig))
24
25
26 static volatile int spawned_threads_count;      /* Set for the specific spawner.  */
27
28 static struct attach_state_struct *attach_checked (pid_t pid, int redelivered_expect)
29 {
30   struct attach_state_struct *attach_state;
31
32   STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING) | (1 << STATE_STOPPED));
33   attach_state = attach (pid);
34   if (redelivered_expect != attach_state_redelivered_get (attach_state))
35     {
36       fprintf (stderr, "Expecting redelivery of %d but found %d\n",
37                redelivered_expect, attach_state_redelivered_get (attach_state));
38       abort ();
39     }
40   assert (spawned_threads_count == attach_state_threads_count_get (attach_state));
41   /* FIXME: Why also STATE_STOPPED?  */
42   STATE (pid, (1 << STATE_PTRACED) | (1 << STATE_STOPPED));
43   return attach_state;
44 }
45
46 static void detach_checked (struct attach_state_struct *attach_state)
47 {
48   pid_t pid = attach_state_pid_get (attach_state);
49
50   if (attach_state_stopped_get (attach_state) != 0)
51     {
52       STATE (pid, 1 << STATE_STOPPED);
53       detach (attach_state);
54       STATE (pid, 1 << STATE_STOPPED);
55     }
56   else
57     {
58       STATE (pid, (1 << STATE_PTRACED));
59       detach (attach_state);
60       STATE (pid, ((1 << STATE_SLEEPING) | (1 << STATE_RUNNING)));
61     }
62 }
63
64 struct registry
65   {
66     struct registry *next;
67     pid_t pid;
68   };
69 struct registry *registry_list;
70
71 static void registry_add (pid_t pid)
72 {
73   struct registry *new;
74
75   new = malloc (sizeof (*new));
76   assert (new != NULL);
77   new->pid = pid;
78   new->next = registry_list;
79   registry_list = new;
80 }
81
82 static void registry_remove (pid_t pid)
83 {
84   struct registry **iter_pointer;
85
86   for (iter_pointer = &registry_list; *iter_pointer != NULL;
87        iter_pointer = &(*iter_pointer)->next)
88     {
89       struct registry *found = *iter_pointer;
90       if (found->pid != pid)
91         continue;
92
93       *iter_pointer = found->next;
94       free (found);
95       return;
96     }
97   abort ();
98 }
99
100 static void registry_atexit (void)
101 {
102   struct registry *iter;
103
104   for (iter = registry_list; iter != NULL; iter = iter->next)
105     {
106       tkill (iter->pid, SIGCONT);
107       tkill (iter->pid, SIGKILL);
108       kill (iter->pid, SIGKILL);
109     }
110 }
111
112 static void registry_cleanup (void)
113 {
114   struct registry *iter;
115   pid_t pid;
116
117   registry_atexit ();
118   while ((pid = wait (NULL)) != -1)
119     {
120       for (iter = registry_list; iter != NULL; iter = iter->next)
121         if (iter->pid == pid)
122           break;
123       assert (iter != NULL);
124     }
125   assert (errno == ECHILD);
126   while (registry_list)
127     {
128       iter = registry_list;
129       registry_list = iter->next;
130       free (iter);
131     }
132 }
133
134 static void registry_handler (int signo)
135 {
136   signal (signo, SIG_DFL);
137   registry_atexit ();
138   raise (signo);
139 }
140
141 static void child_pause (void)
142 {
143   for (;;)
144     pause ();
145   /* NOTREACHED */
146   abort ();
147 }
148
149 static void child_alrm_handler (int signo)
150 {
151   assert (signo == SIGALRM);
152   raise (SIGALRM);
153 }
154
155 static void child_alrm (void)
156 {
157   void (*handler_orig) (int signo);
158 #if 0
159   int i;
160   sigset_t oldset;
161 #endif
162
163   handler_orig = signal (SIGALRM, child_alrm_handler);
164   assert (handler_orig == SIG_DFL);
165
166 #if 0
167   i = sigprocmask (SIG_BLOCK, NULL, &oldset);
168   assert (i == 0);
169   printf ("sigprocmask () -> sigismember (SIGALRM) == %d\n", sigismember (&oldset, SIGALRM));
170 #endif
171
172   for (;;)
173     pause ();
174   /* NOTREACHED */
175   abort ();
176 }
177
178 static pid_t spawn (void *(*child) (void *data, void *input), void *data,
179                     void *input, int fd_close)
180 {
181   pid_t pid;
182
183   pid = fork();
184   switch (pid)
185     {
186       case -1:
187         perror ("fork()");
188         exit (EXIT_FAILURE);
189         /* NOTREACHED */
190       case 0:
191         if (fd_close != -1)
192           {
193             int i;
194
195             i = close (fd_close);
196             assert (i == 0);
197           }
198         child (data, input);
199         /* NOTREACHED */
200         abort ();
201       default:;
202         /* PASSTHRU */
203     }
204   /* Parent.  */
205
206   registry_add (pid);
207   STATE (pid, (1 << STATE_SLEEPING) | (1 << STATE_RUNNING));
208   return pid;
209 }
210
211 static void murder (pid_t pid)
212 {
213   int i;
214   pid_t pid_got;
215   int status;
216
217   if (pid == 0)
218     return;
219
220   i = kill (pid, SIGKILL);
221   assert (i == 0);
222
223   pid_got = waitpid (pid, &status, 0);
224   if (!(pid_got == -1 && errno == ECHILD))
225     {
226       assert (pid_got == pid);
227       assert ((WIFSIGNALED (status) && (WTERMSIG (status) == SIGKILL
228                                         || WTERMSIG (status) == SIGUSR2))
229               || (WIFEXITED (status) && WEXITSTATUS (status) == 0));
230       STATE (pid, 1 << STATE_ENOENT);
231     }
232   else
233     STATE (pid, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE));
234
235   registry_remove (pid);
236 }
237
238
239 struct child_spawner
240   {
241     void *(*child) (void *data, void *input);
242     void *data;
243     int fd;
244   };
245
246 static void *child_spawner (void *param_voidpointer, void *input)
247 {
248   struct child_spawner *param = param_voidpointer;
249   pid_t inferior;
250   ssize_t inferior_size;
251   int i;
252
253   inferior = spawn (param->child, param->data, input, param->fd);
254
255   inferior_size = write (param->fd, &inferior, sizeof (inferior));
256   assert (inferior_size == sizeof (inferior));
257   i = close (param->fd);
258   assert (i == 0);
259
260   waitpid (inferior, NULL, 0);
261   _exit (EXIT_SUCCESS);
262   /* NOTREACHED */
263   abort ();
264 }
265
266 struct spawner
267   {
268     void *(*func) (void *data, void *input);
269     void *data;
270   };
271
272 static void *spawn_with_waiter (void *data, void *input)
273 {
274   pid_t waiter;
275   struct child_spawner param_local;
276   int pipefds[2];
277   int i;
278   pid_t inferior;
279   ssize_t inferior_size;
280   unsigned char buf;
281   ssize_t buf_size;
282   struct spawner *param = data;
283
284   assert (data != NULL);
285
286   i = pipe (pipefds);
287   assert (i == 0);
288
289   param_local.child = param->func;
290   param_local.data = param->data;
291   param_local.fd = pipefds[1];
292   waiter = spawn (child_spawner, &param_local, input, pipefds[0]);
293
294   i = close (pipefds[1]);
295   assert (i == 0);
296   inferior_size = read (pipefds[0], &inferior, sizeof (inferior));
297   assert (inferior_size == sizeof (inferior));
298   buf_size = read (pipefds[0], &buf, sizeof (buf));
299   assert (buf_size == 0);
300   i = close (pipefds[0]);
301   assert (i == 0);
302
303   registry_add (inferior);
304
305   return (void *) (unsigned long) inferior;
306 }
307
308 static void *spawn_without_waiter (void *data, void *input)
309 {
310   struct spawner *param = data;
311
312   return (void *) (unsigned long) spawn (param->func, param->data, input, -1);
313 }
314
315 static void body_spawner (void *(*child) (void *data, void *input), void *data,
316                           void *input)
317 {
318   pid_t inferior;
319   struct attach_state_struct *attach_state;
320   int i;
321
322   assert (input == NULL);
323
324   /* Plain attach/detach.  */
325   inferior = (unsigned long) (*child) (data, child_pause);
326   attach_state = attach_checked (inferior, 0);
327   assert (attach_state_stopped_get (attach_state) == 0);
328   detach_checked (attach_state);
329   murder (inferior);
330
331   /* Attach to a process stopped by standard kill(2).  */
332   inferior = (unsigned long) (*child) (data, child_pause);
333   delay ();
334   i = kill (inferior, SIGSTOP);
335   assert (i == 0);
336   STATE (inferior, 1 << STATE_STOPPED);
337   attach_state = attach_checked (inferior, 0);
338   assert (attach_state_stopped_get (attach_state) == 1);
339   detach_checked (attach_state);
340   murder (inferior);
341
342   /* Attach to a process stopped by Linux specific tkill(2).  */
343   inferior = (unsigned long) (*child) (data, child_pause);
344   delay ();
345   i = tkill (inferior, SIGSTOP);
346   assert (i == 0);
347   STATE (inferior, 1 << STATE_STOPPED);
348   attach_state = attach_checked (inferior, 0);
349   assert (attach_state_stopped_get (attach_state) == 1);
350   detach_checked (attach_state);
351   murder (inferior);
352
353   /* Attach to a stopped process with already pending SIGALRM.  */
354   inferior = (unsigned long) (*child) (data, child_alrm);
355   STATE (inferior, 1 << STATE_SLEEPING);
356   delay ();
357   i = tkill (inferior, SIGSTOP);
358   assert (i == 0);
359   /* Wait till it gets stopped otherwise we may get STATE_ENOENT below.  */
360   STATE (inferior, 1 << STATE_STOPPED);
361   delay ();
362   i = tkill (inferior, SIGALRM);
363   assert (i == 0);
364   STATE (inferior, 1 << STATE_STOPPED);
365   /* FIXME: SIGALRM did not get redelivered?  */
366 #if 0
367   attach_state = attach_checked (inferior, SIGALRM);
368 #else
369   attach_state = attach_checked (inferior, 0);
370 #endif
371   assert (attach_state_stopped_get (attach_state) == 1);
372   detach_checked (attach_state);
373   STATE (inferior, 1 << STATE_STOPPED);
374   delay ();
375   i = tkill (inferior, SIGCONT);
376   assert (i == 0);
377   /* This is a race, we may not prove the successful SIGALRM delivery by it.
378      Rather recheck it below.  */
379   STATE (inferior, 1 << STATE_RUNNING);
380   delay ();
381   i = tkill (inferior, SIGSTOP);
382   assert (i == 0);
383   /* Wait till it gets stopped otherwise we may get STATE_ENOENT below.  */
384   STATE (inferior, 1 << STATE_STOPPED);
385   delay ();
386   i = tkill (inferior, SIGUSR2);
387   assert (i == 0);
388   STATE (inferior, 1 << STATE_STOPPED);
389   delay ();
390   i = tkill (inferior, SIGCONT);
391   assert (i == 0);
392   /* Not just STATE_ZOMBIE as we can get spawn with waiter.  FIXME.  */
393   STATE (inferior, (1 << STATE_ENOENT) | (1 << STATE_ZOMBIE) | (1 << STATE_DEAD));
394   /* We would fail on: murder (inferior);  */
395 }
396
397 static void *pass (void *data, void *input)
398 {
399   struct spawner *param = data;
400   void (*input_func) (void) = input;
401
402   if (param != NULL)
403     return (*param->func) (param->data, input);
404
405   assert (input_func != NULL);
406   (*input_func) ();
407   /* NOTREACHED */
408   abort ();
409 }
410
411 static void *spawn_singlethreaded (void *data, void *input)
412 {
413   return pass (data, input);
414 }
415
416 static void *spawn_threaded_parent_start (void *arg)
417 {
418   for (;;)
419     pause ();
420   /* NOTREACHED */
421   abort ();
422 }
423
424 static void *spawn_threaded_parent (void *data, void *input)
425 {
426   pthread_t thread;
427   int i;
428   void *handle;
429   void *retval;
430   int (*pthread_create_pointer) (pthread_t *thread,
431                                  const pthread_attr_t *attr,
432                                  void *(*start_routine) (void *),
433                                  void *arg);
434
435   handle = dlopen ("libpthread.so.0", RTLD_LAZY);
436   assert (handle != NULL);
437   pthread_create_pointer = dlsym (handle, "pthread_create");
438   assert (pthread_create_pointer != NULL);
439
440   i = (*pthread_create_pointer) (&thread, NULL, spawn_threaded_parent_start,
441                                  NULL);
442   assert (i == 0);
443   retval = pass (data, input);
444
445   i = dlclose (handle);
446   assert (i == 0);
447
448   return retval;
449 }
450
451 struct spawn_threaded_child_start
452   {
453     void *data;
454     void *input;
455     void *lib_handle;
456   };
457
458 static void *spawn_threaded_child_start (void *arg_voidpointer)
459 {
460   struct spawn_threaded_child_start *arg = arg_voidpointer;
461   void *retval;
462   int i;
463
464   retval = pass (arg->data, arg->input);
465
466   i = dlclose (arg->lib_handle);
467   assert (i == 0);
468
469   return retval;
470 }
471
472 static void *spawn_threaded_child (void *data, void *input)
473 {
474   pthread_t thread;
475   int i;
476   struct spawn_threaded_child_start arg_local;
477   int (*pthread_create_pointer) (pthread_t *thread,
478                                  const pthread_attr_t *attr,
479                                  void *(*start_routine) (void *),
480                                  void *arg);
481   int (*pthread_join_pointer) (pthread_t thread, void **value_ptr);
482
483   arg_local.lib_handle = dlopen ("libpthread.so.0", RTLD_LAZY);
484   assert (arg_local.lib_handle != NULL);
485   pthread_create_pointer = dlsym (arg_local.lib_handle, "pthread_create");
486   assert (pthread_create_pointer != NULL);
487   pthread_join_pointer = dlsym (arg_local.lib_handle, "pthread_join");
488   assert (pthread_join_pointer != NULL);
489
490   arg_local.data = data;
491   arg_local.input = input;
492   i = (*pthread_create_pointer) (&thread, NULL, spawn_threaded_child_start,
493                                  &arg_local);
494   assert (i == 0);
495   i = (*pthread_join_pointer) (thread, NULL);
496   assert (i == 0);
497
498   _exit (EXIT_SUCCESS);
499 }
500
501 static void body_maywaiter (void *(*child) (void *data, void *input),
502                             void *data, void *input)
503 {
504   struct spawner param_local;
505
506   param_local.func = child;
507   param_local.data = data;
508   body_spawner (spawn_without_waiter, &param_local, NULL);
509   body_spawner (spawn_with_waiter, &param_local, NULL);
510 }
511
512 static volatile unsigned long loops = 0;
513 static volatile int loops_print = 0;
514
515 static void handler_sigusr1 (int signo)
516 {
517   assert (signo == SIGUSR1);
518
519   loops_print++;
520 }
521
522 int main (int argc, char **argv)
523 {
524   int loop = 0;
525   int i;
526
527 #ifdef MEASURE_STATE_PERFORMANCE
528   STATE (1, 1 << STATE_ZOMBIE);
529   return 0;
530 #endif /* MEASURE_STATE_PERFORMANCE */
531
532   if (argc == 1)
533     ;
534   else if (argc == 2 && strcmp (argv[1], "-l") == 0)
535     loop = 1;
536   else
537     abort ();
538
539   i = nice (10);
540   assert (i != -1);
541
542   atexit (registry_atexit);
543   signal (SIGINT, registry_handler);
544   signal (SIGABRT, registry_handler);
545
546   signal (SIGUSR1, handler_sigusr1);
547
548   do
549     {
550       while (loops_print > 0)
551         {
552           printf ("%lu\n", loops);
553           loops_print--;
554         }
555
556       spawned_threads_count = 0;
557       body_maywaiter (spawn_singlethreaded, NULL, NULL);
558
559       spawned_threads_count = 2;
560       body_maywaiter (spawn_threaded_parent, NULL, NULL);
561
562       spawned_threads_count = 2;
563       body_maywaiter (spawn_threaded_child, NULL, NULL);
564
565       registry_cleanup ();
566       loops++;
567     }
568   while (loop != 0);
569
570   return EXIT_SUCCESS;
571 }