1/* libunwind - a platform-independent unwind library
2   Copyright (C) 2003-2004 Hewlett-Packard Co
3	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
4
5Permission is hereby granted, free of charge, to any person obtaining
6a copy of this software and associated documentation files (the
7"Software"), to deal in the Software without restriction, including
8without limitation the rights to use, copy, modify, merge, publish,
9distribute, sublicense, and/or sell copies of the Software, and to
10permit persons to whom the Software is furnished to do so, subject to
11the following conditions:
12
13The above copyright notice and this permission notice shall be
14included in all copies or substantial portions of the Software.
15
16THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
23
24/*  Verify that unw_resume() restores the signal mask at proper time.  */
25
26#ifdef HAVE_CONFIG_H
27# include "config.h"
28#endif
29
30#include "compiler.h"
31
32#include <libunwind.h>
33#include <signal.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#include <unistd.h>
38#include <errno.h>
39
40#ifdef HAVE_IA64INTRIN_H
41# include <ia64intrin.h>
42#endif
43
44#define panic(args...)						\
45	do { fprintf (stderr, args); ++nerrors; } while (0)
46
47int verbose;
48int nerrors;
49int got_usr1, got_usr2;
50char *sigusr1_sp;
51
52uintptr_t
53get_bsp (void)
54{
55#if UNW_TARGET_IA64
56# ifdef __INTEL_COMPILER
57  return __getReg (_IA64_REG_AR_BSP);
58# else
59  return (uintptr_t) __builtin_ia64_bsp ();
60# endif
61#else
62  return 0;
63#endif
64}
65
66#ifdef TEST_WITH_SIGINFO
67void
68handler (int sig,
69         siginfo_t *si UNUSED,
70         void *ucontext UNUSED)
71#else
72void
73handler (int sig)
74#endif
75{
76  unw_word_t ip;
77  sigset_t mask, oldmask;
78  unw_context_t uc;
79  unw_cursor_t c;
80  char foo;
81  int ret;
82
83#if UNW_TARGET_IA64
84  if (verbose)
85    printf ("bsp = %llx\n", (unsigned long long) get_bsp ());
86#endif
87
88  if (verbose)
89    printf ("got signal %d\n", sig);
90
91  if (sig == SIGUSR1)
92    {
93      ++got_usr1;
94      sigusr1_sp = &foo;
95
96      sigemptyset (&mask);
97      sigaddset (&mask, SIGUSR2);
98      sigprocmask (SIG_BLOCK, &mask, &oldmask);
99      kill (getpid (), SIGUSR2);	/* pend SIGUSR2 */
100
101      signal (SIGUSR1, SIG_IGN);
102
103      if ((ret = unw_getcontext (&uc)) < 0)
104	panic ("unw_getcontext() failed: ret=%d\n", ret);
105#if UNW_TARGET_X86_64
106      /* unw_getcontext() doesn't save signal mask to avoid a syscall */
107      uc.uc_sigmask = oldmask;
108#endif
109      if ((ret = unw_init_local (&c, &uc)) < 0)
110	panic ("unw_init_local() failed: ret=%d\n", ret);
111
112      if ((ret = unw_step (&c)) < 0)		/* step to signal trampoline */
113	panic ("unw_step(1) failed: ret=%d\n", ret);
114
115      if ((ret = unw_step (&c)) < 0)		/* step to kill() */
116	panic ("unw_step(2) failed: ret=%d\n", ret);
117
118      if ((ret = unw_get_reg (&c, UNW_REG_IP, &ip)) < 0)
119	panic ("unw_get_reg(IP) failed: ret=%d\n", ret);
120      if (verbose)
121	printf ("resuming at 0x%lx, with SIGUSR2 pending\n",
122		(unsigned long) ip);
123      unw_resume (&c);
124    }
125  else if (sig == SIGUSR2)
126    {
127      ++got_usr2;
128      if (got_usr1)
129	{
130	  if (verbose)
131	    printf ("OK: stack still at %p\n", &foo);
132	}
133      signal (SIGUSR2, SIG_IGN);
134    }
135  else
136    panic ("Got unexpected signal %d\n", sig);
137}
138
139int
140main (int argc, char **argv UNUSED)
141{
142  struct sigaction sa;
143  float d = 1.0;
144  int n = 0;
145
146  if (argc > 1)
147    verbose = 1;
148
149  memset (&sa, 0, sizeof(sa));
150#ifdef TEST_WITH_SIGINFO
151  sa.sa_sigaction = handler;
152  sa.sa_flags = SA_SIGINFO;
153#else
154  sa.sa_handler = handler;
155#endif
156
157  if (sigaction (SIGUSR1, &sa, NULL) != 0 ||
158      sigaction (SIGUSR2, &sa, NULL) != 0)
159    {
160      fprintf (stderr, "sigaction() failed: %s\n", strerror (errno));
161      return -1;
162    }
163
164  /* Use the FPU a bit; otherwise we get spurious errors should the
165     signal handler need to use the FPU for any reason.  This seems to
166     happen on x86-64.  */
167  while (d > 0.0)
168    {
169      d /= 2.0;
170      ++n;
171    }
172  if (n > 9999)
173    return -1;	/* can't happen, but don't tell the compiler... */
174
175  if (verbose)
176    printf ("sending SIGUSR1\n");
177  kill (getpid (), SIGUSR1);
178
179  if (!got_usr2)
180    panic ("failed to get SIGUSR2\n");
181
182  if (nerrors)
183    {
184      fprintf (stderr, "FAILURE: detected %d errors\n", nerrors);
185      exit (-1);
186    }
187
188  if (verbose)
189    printf ("SUCCESS\n");
190  return 0;
191}
192