1d4e76214Sopenharmony_ci/* libunwind - a platform-independent unwind library
2d4e76214Sopenharmony_ci   Copyright (C) 2003 Hewlett-Packard Co
3d4e76214Sopenharmony_ci	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4d4e76214Sopenharmony_ci
5d4e76214Sopenharmony_ciPermission is hereby granted, free of charge, to any person obtaining
6d4e76214Sopenharmony_cia copy of this software and associated documentation files (the
7d4e76214Sopenharmony_ci"Software"), to deal in the Software without restriction, including
8d4e76214Sopenharmony_ciwithout limitation the rights to use, copy, modify, merge, publish,
9d4e76214Sopenharmony_cidistribute, sublicense, and/or sell copies of the Software, and to
10d4e76214Sopenharmony_cipermit persons to whom the Software is furnished to do so, subject to
11d4e76214Sopenharmony_cithe following conditions:
12d4e76214Sopenharmony_ci
13d4e76214Sopenharmony_ciThe above copyright notice and this permission notice shall be
14d4e76214Sopenharmony_ciincluded in all copies or substantial portions of the Software.
15d4e76214Sopenharmony_ci
16d4e76214Sopenharmony_ciTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17d4e76214Sopenharmony_ciEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18d4e76214Sopenharmony_ciMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19d4e76214Sopenharmony_ciNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20d4e76214Sopenharmony_ciLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21d4e76214Sopenharmony_ciOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22d4e76214Sopenharmony_ciWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
23d4e76214Sopenharmony_ci
24d4e76214Sopenharmony_ci/* The setjmp()/longjmp(), sigsetjmp()/siglongjmp().  */
25d4e76214Sopenharmony_ci
26d4e76214Sopenharmony_ci#include "compiler.h"
27d4e76214Sopenharmony_ci
28d4e76214Sopenharmony_ci#include <setjmp.h>
29d4e76214Sopenharmony_ci#include <signal.h>
30d4e76214Sopenharmony_ci#include <stdio.h>
31d4e76214Sopenharmony_ci#include <stdlib.h>
32d4e76214Sopenharmony_ci#include <string.h>
33d4e76214Sopenharmony_ci#include <unistd.h>
34d4e76214Sopenharmony_ci
35d4e76214Sopenharmony_ciint nerrors;
36d4e76214Sopenharmony_ciint verbose;
37d4e76214Sopenharmony_ci
38d4e76214Sopenharmony_cistatic jmp_buf jbuf;
39d4e76214Sopenharmony_cistatic sigjmp_buf sigjbuf;
40d4e76214Sopenharmony_cistatic sigset_t sigset4;
41d4e76214Sopenharmony_ci
42d4e76214Sopenharmony_civoid
43d4e76214Sopenharmony_ciraise_longjmp (jmp_buf jbuf, int i, int n)
44d4e76214Sopenharmony_ci{
45d4e76214Sopenharmony_ci  while (i < n)
46d4e76214Sopenharmony_ci    raise_longjmp (jbuf, i + 1, n);
47d4e76214Sopenharmony_ci
48d4e76214Sopenharmony_ci  longjmp (jbuf, n);
49d4e76214Sopenharmony_ci}
50d4e76214Sopenharmony_ci
51d4e76214Sopenharmony_civoid
52d4e76214Sopenharmony_citest_setjmp (void)
53d4e76214Sopenharmony_ci{
54d4e76214Sopenharmony_ci  volatile int i;
55d4e76214Sopenharmony_ci  jmp_buf jbuf;
56d4e76214Sopenharmony_ci  int ret;
57d4e76214Sopenharmony_ci
58d4e76214Sopenharmony_ci  for (i = 0; i < 10; ++i)
59d4e76214Sopenharmony_ci    {
60d4e76214Sopenharmony_ci      if ((ret = setjmp (jbuf)))
61d4e76214Sopenharmony_ci	{
62d4e76214Sopenharmony_ci	  if (verbose)
63d4e76214Sopenharmony_ci	    printf ("%s: secondary setjmp () return, ret=%d\n",
64d4e76214Sopenharmony_ci		    __FUNCTION__, ret);
65d4e76214Sopenharmony_ci	  if (ret != i + 1)
66d4e76214Sopenharmony_ci	    {
67d4e76214Sopenharmony_ci	      fprintf (stderr, "%s: setjmp() returned %d, expected %d\n",
68d4e76214Sopenharmony_ci		       __FUNCTION__, ret, i + 1);
69d4e76214Sopenharmony_ci	      ++nerrors;
70d4e76214Sopenharmony_ci	    }
71d4e76214Sopenharmony_ci	  continue;
72d4e76214Sopenharmony_ci	}
73d4e76214Sopenharmony_ci      if (verbose)
74d4e76214Sopenharmony_ci	printf ("%s.%d: done with setjmp(); calling children\n",
75d4e76214Sopenharmony_ci		__FUNCTION__, i + 1);
76d4e76214Sopenharmony_ci
77d4e76214Sopenharmony_ci      raise_longjmp (jbuf, 0, i + 1);
78d4e76214Sopenharmony_ci
79d4e76214Sopenharmony_ci      fprintf (stderr, "%s: raise_longjmp() returned unexpectedly\n",
80d4e76214Sopenharmony_ci	       __FUNCTION__);
81d4e76214Sopenharmony_ci      ++nerrors;
82d4e76214Sopenharmony_ci    }
83d4e76214Sopenharmony_ci}
84d4e76214Sopenharmony_ci
85d4e76214Sopenharmony_ci
86d4e76214Sopenharmony_civoid
87d4e76214Sopenharmony_ciraise_siglongjmp (sigjmp_buf jbuf, int i, int n)
88d4e76214Sopenharmony_ci{
89d4e76214Sopenharmony_ci  while (i < n)
90d4e76214Sopenharmony_ci    raise_siglongjmp (jbuf, i + 1, n);
91d4e76214Sopenharmony_ci
92d4e76214Sopenharmony_ci  siglongjmp (jbuf, n);
93d4e76214Sopenharmony_ci}
94d4e76214Sopenharmony_ci
95d4e76214Sopenharmony_civoid
96d4e76214Sopenharmony_citest_sigsetjmp (void)
97d4e76214Sopenharmony_ci{
98d4e76214Sopenharmony_ci  sigjmp_buf jbuf;
99d4e76214Sopenharmony_ci  volatile int i;
100d4e76214Sopenharmony_ci  int ret;
101d4e76214Sopenharmony_ci
102d4e76214Sopenharmony_ci  for (i = 0; i < 10; ++i)
103d4e76214Sopenharmony_ci    {
104d4e76214Sopenharmony_ci      if ((ret = sigsetjmp (jbuf, 1)))
105d4e76214Sopenharmony_ci	{
106d4e76214Sopenharmony_ci	  if (verbose)
107d4e76214Sopenharmony_ci	    printf ("%s: secondary sigsetjmp () return, ret=%d\n",
108d4e76214Sopenharmony_ci		    __FUNCTION__, ret);
109d4e76214Sopenharmony_ci	  if (ret != i + 1)
110d4e76214Sopenharmony_ci	    {
111d4e76214Sopenharmony_ci	      fprintf (stderr, "%s: sigsetjmp() returned %d, expected %d\n",
112d4e76214Sopenharmony_ci		       __FUNCTION__, ret, i + 1);
113d4e76214Sopenharmony_ci	      ++nerrors;
114d4e76214Sopenharmony_ci	    }
115d4e76214Sopenharmony_ci	  continue;
116d4e76214Sopenharmony_ci	}
117d4e76214Sopenharmony_ci      if (verbose)
118d4e76214Sopenharmony_ci	printf ("%s.%d: done with sigsetjmp(); calling children\n",
119d4e76214Sopenharmony_ci		__FUNCTION__, i + 1);
120d4e76214Sopenharmony_ci
121d4e76214Sopenharmony_ci      raise_siglongjmp (jbuf, 0, i + 1);
122d4e76214Sopenharmony_ci
123d4e76214Sopenharmony_ci      fprintf (stderr, "%s: raise_siglongjmp() returned unexpectedly\n",
124d4e76214Sopenharmony_ci	       __FUNCTION__);
125d4e76214Sopenharmony_ci      ++nerrors;
126d4e76214Sopenharmony_ci    }
127d4e76214Sopenharmony_ci}
128d4e76214Sopenharmony_ci
129d4e76214Sopenharmony_civoid
130d4e76214Sopenharmony_cisighandler (int signal)
131d4e76214Sopenharmony_ci{
132d4e76214Sopenharmony_ci  if (verbose)
133d4e76214Sopenharmony_ci    printf ("%s: got signal %d\n", __FUNCTION__, signal);
134d4e76214Sopenharmony_ci
135d4e76214Sopenharmony_ci  sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset4);
136d4e76214Sopenharmony_ci  if (verbose)
137d4e76214Sopenharmony_ci    printf ("%s: back from sigprocmask\n", __FUNCTION__);
138d4e76214Sopenharmony_ci
139d4e76214Sopenharmony_ci  siglongjmp (sigjbuf, 1);
140d4e76214Sopenharmony_ci  printf ("%s: siglongjmp() returned unexpectedly!\n", __FUNCTION__);
141d4e76214Sopenharmony_ci}
142d4e76214Sopenharmony_ci
143d4e76214Sopenharmony_ciint
144d4e76214Sopenharmony_cimain (int argc, char **argv UNUSED)
145d4e76214Sopenharmony_ci{
146d4e76214Sopenharmony_ci  volatile sigset_t sigset1, sigset2, sigset3;
147d4e76214Sopenharmony_ci  volatile struct sigaction act;
148d4e76214Sopenharmony_ci
149d4e76214Sopenharmony_ci  if (argc > 1)
150d4e76214Sopenharmony_ci    verbose = 1;
151d4e76214Sopenharmony_ci
152d4e76214Sopenharmony_ci  memset (&sigset1, 0, sizeof (sigset1));
153d4e76214Sopenharmony_ci  memset (&sigset2, 0, sizeof (sigset2));
154d4e76214Sopenharmony_ci  memset (&sigset3, 0, sizeof (sigset3));
155d4e76214Sopenharmony_ci
156d4e76214Sopenharmony_ci  sigemptyset ((sigset_t *) &sigset1);
157d4e76214Sopenharmony_ci  sigaddset ((sigset_t *) &sigset1, SIGUSR1);
158d4e76214Sopenharmony_ci  sigemptyset ((sigset_t *) &sigset2);
159d4e76214Sopenharmony_ci  sigaddset ((sigset_t *) &sigset2, SIGUSR2);
160d4e76214Sopenharmony_ci
161d4e76214Sopenharmony_ci  memset ((void *) &act, 0, sizeof (act));
162d4e76214Sopenharmony_ci  act.sa_handler = sighandler;
163d4e76214Sopenharmony_ci  sigaction (SIGTERM, (struct sigaction *) &act, NULL);
164d4e76214Sopenharmony_ci
165d4e76214Sopenharmony_ci  test_setjmp ();
166d4e76214Sopenharmony_ci  test_sigsetjmp ();
167d4e76214Sopenharmony_ci
168d4e76214Sopenharmony_ci  /* _setjmp() MUST NOT change signal mask: */
169d4e76214Sopenharmony_ci  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
170d4e76214Sopenharmony_ci  if (_setjmp (jbuf))
171d4e76214Sopenharmony_ci    {
172d4e76214Sopenharmony_ci      sigemptyset ((sigset_t *) &sigset3);
173d4e76214Sopenharmony_ci      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
174d4e76214Sopenharmony_ci      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
175d4e76214Sopenharmony_ci		  sizeof (sigset_t)) != 0)
176d4e76214Sopenharmony_ci	{
177d4e76214Sopenharmony_ci	  fprintf (stderr, "FAILURE: _longjmp() manipulated signal mask!\n");
178d4e76214Sopenharmony_ci	  ++nerrors;
179d4e76214Sopenharmony_ci	}
180d4e76214Sopenharmony_ci      else if (verbose)
181d4e76214Sopenharmony_ci	printf ("OK: _longjmp() seems not to change signal mask\n");
182d4e76214Sopenharmony_ci    }
183d4e76214Sopenharmony_ci  else
184d4e76214Sopenharmony_ci    {
185d4e76214Sopenharmony_ci      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
186d4e76214Sopenharmony_ci      _longjmp (jbuf, 1);
187d4e76214Sopenharmony_ci    }
188d4e76214Sopenharmony_ci
189d4e76214Sopenharmony_ci  /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
190d4e76214Sopenharmony_ci  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
191d4e76214Sopenharmony_ci  if (sigsetjmp (sigjbuf, 1))
192d4e76214Sopenharmony_ci    {
193d4e76214Sopenharmony_ci      sigemptyset ((sigset_t *) &sigset3);
194d4e76214Sopenharmony_ci      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
195d4e76214Sopenharmony_ci      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
196d4e76214Sopenharmony_ci		  sizeof (sigset_t)) != 0)
197d4e76214Sopenharmony_ci	{
198d4e76214Sopenharmony_ci	  fprintf (stderr,
199d4e76214Sopenharmony_ci		   "FAILURE: siglongjmp() didn't restore signal mask!\n");
200d4e76214Sopenharmony_ci	  ++nerrors;
201d4e76214Sopenharmony_ci	}
202d4e76214Sopenharmony_ci      else if (verbose)
203d4e76214Sopenharmony_ci	printf ("OK: siglongjmp() restores signal mask when asked to\n");
204d4e76214Sopenharmony_ci    }
205d4e76214Sopenharmony_ci  else
206d4e76214Sopenharmony_ci    {
207d4e76214Sopenharmony_ci      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
208d4e76214Sopenharmony_ci      siglongjmp (sigjbuf, 1);
209d4e76214Sopenharmony_ci    }
210d4e76214Sopenharmony_ci
211d4e76214Sopenharmony_ci  /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
212d4e76214Sopenharmony_ci  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
213d4e76214Sopenharmony_ci  if (sigsetjmp (sigjbuf, 0))
214d4e76214Sopenharmony_ci    {
215d4e76214Sopenharmony_ci      sigemptyset ((sigset_t *) &sigset3);
216d4e76214Sopenharmony_ci      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
217d4e76214Sopenharmony_ci      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset2,
218d4e76214Sopenharmony_ci		  sizeof (sigset_t)) != 0)
219d4e76214Sopenharmony_ci	{
220d4e76214Sopenharmony_ci	  fprintf (stderr,
221d4e76214Sopenharmony_ci		   "FAILURE: siglongjmp() changed signal mask!\n");
222d4e76214Sopenharmony_ci	  ++nerrors;
223d4e76214Sopenharmony_ci	}
224d4e76214Sopenharmony_ci      else if (verbose)
225d4e76214Sopenharmony_ci	printf ("OK: siglongjmp() leaves signal mask alone when asked to\n");
226d4e76214Sopenharmony_ci    }
227d4e76214Sopenharmony_ci  else
228d4e76214Sopenharmony_ci    {
229d4e76214Sopenharmony_ci      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
230d4e76214Sopenharmony_ci      siglongjmp (sigjbuf, 1);
231d4e76214Sopenharmony_ci    }
232d4e76214Sopenharmony_ci
233d4e76214Sopenharmony_ci  /* sigsetjmp(jbuf, 1) MUST preserve signal mask: */
234d4e76214Sopenharmony_ci  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
235d4e76214Sopenharmony_ci  if (sigsetjmp (sigjbuf, 1))
236d4e76214Sopenharmony_ci    {
237d4e76214Sopenharmony_ci      sigemptyset ((sigset_t *) &sigset3);
238d4e76214Sopenharmony_ci      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
239d4e76214Sopenharmony_ci      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset1,
240d4e76214Sopenharmony_ci		  sizeof (sigset_t)) != 0)
241d4e76214Sopenharmony_ci	{
242d4e76214Sopenharmony_ci	  fprintf (stderr,
243d4e76214Sopenharmony_ci		   "FAILURE: siglongjmp() didn't restore signal mask!\n");
244d4e76214Sopenharmony_ci	  ++nerrors;
245d4e76214Sopenharmony_ci	}
246d4e76214Sopenharmony_ci      else if (verbose)
247d4e76214Sopenharmony_ci	printf ("OK: siglongjmp() restores signal mask when asked to\n");
248d4e76214Sopenharmony_ci    }
249d4e76214Sopenharmony_ci  else
250d4e76214Sopenharmony_ci    {
251d4e76214Sopenharmony_ci      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
252d4e76214Sopenharmony_ci      kill (getpid (), SIGTERM);
253d4e76214Sopenharmony_ci      fprintf (stderr, "FAILURE: unexpected return from kill()\n");
254d4e76214Sopenharmony_ci      ++nerrors;
255d4e76214Sopenharmony_ci    }
256d4e76214Sopenharmony_ci
257d4e76214Sopenharmony_ci  /* sigsetjmp(jbuf, 0) MUST NOT preserve signal mask: */
258d4e76214Sopenharmony_ci  sigprocmask (SIG_SETMASK, (sigset_t *) &sigset1, NULL);
259d4e76214Sopenharmony_ci  if (sigsetjmp (sigjbuf, 0))
260d4e76214Sopenharmony_ci    {
261d4e76214Sopenharmony_ci      sigemptyset ((sigset_t *) &sigset3);
262d4e76214Sopenharmony_ci      sigprocmask (SIG_BLOCK, NULL, (sigset_t *) &sigset3);
263d4e76214Sopenharmony_ci      if (memcmp ((sigset_t *) &sigset3, (sigset_t *) &sigset4,
264d4e76214Sopenharmony_ci		  sizeof (sigset_t)) != 0)
265d4e76214Sopenharmony_ci	{
266d4e76214Sopenharmony_ci	  fprintf (stderr,
267d4e76214Sopenharmony_ci		   "FAILURE: siglongjmp() changed signal mask!\n");
268d4e76214Sopenharmony_ci	  ++nerrors;
269d4e76214Sopenharmony_ci	}
270d4e76214Sopenharmony_ci      else if (verbose)
271d4e76214Sopenharmony_ci	printf ("OK: siglongjmp() leaves signal mask alone when asked to\n");
272d4e76214Sopenharmony_ci    }
273d4e76214Sopenharmony_ci  else
274d4e76214Sopenharmony_ci    {
275d4e76214Sopenharmony_ci      sigprocmask (SIG_SETMASK, (sigset_t *) &sigset2, NULL);
276d4e76214Sopenharmony_ci      kill (getpid (), SIGTERM);
277d4e76214Sopenharmony_ci      fprintf (stderr, "FAILURE: unexpected return from kill()\n");
278d4e76214Sopenharmony_ci      ++nerrors;
279d4e76214Sopenharmony_ci    }
280d4e76214Sopenharmony_ci
281d4e76214Sopenharmony_ci  if (nerrors > 0)
282d4e76214Sopenharmony_ci    {
283d4e76214Sopenharmony_ci      fprintf (stderr, "FAILURE: detected %d failures\n", nerrors);
284d4e76214Sopenharmony_ci      exit (-1);
285d4e76214Sopenharmony_ci    }
286d4e76214Sopenharmony_ci  if (verbose)
287d4e76214Sopenharmony_ci    printf ("SUCCESS\n");
288d4e76214Sopenharmony_ci  return 0;
289d4e76214Sopenharmony_ci}
290