]>
Commit | Line | Data |
---|---|---|
01936f3a AH |
1 | // dwarf2-signal.h - Catch runtime signals and turn them into exceptions. |
2 | ||
3 | /* Copyright (C) 2000, 2001 Free Software Foundation | |
4 | ||
5 | This file is part of libgcj. | |
6 | ||
c9bffcd5 AH |
7 | Use this file for a target for which the dwarf2 unwinder in libgcc |
8 | can unwind through signal handlers. | |
01936f3a AH |
9 | |
10 | This software is copyrighted work licensed under the terms of the | |
11 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
12 | details. */ | |
13 | ||
14 | #ifndef JAVA_SIGNAL_H | |
15 | #define JAVA_SIGNAL_H 1 | |
16 | ||
17 | #include <signal.h> | |
18 | #include <sys/syscall.h> | |
19 | ||
20 | #define HANDLE_SEGV 1 | |
21 | #undef HANDLE_FPE | |
22 | ||
23 | #define SIGNAL_HANDLER(_name) \ | |
714708c8 | 24 | static void _Jv_##_name (int, siginfo_t *_sip, void *_p) |
01936f3a AH |
25 | |
26 | class java::lang::Throwable; | |
27 | ||
28 | // Unwind the stack to the point at which the signal was generated and | |
c9bffcd5 AH |
29 | // then throw an exception. With the dwarf2 unwinder we don't usually |
30 | // need to do anything, with some minor exceptions. | |
31 | ||
32 | #ifdef __alpha__ | |
33 | #define MAKE_THROW_FRAME(_exception) \ | |
34 | do \ | |
35 | { \ | |
36 | /* Alpha either leaves PC pointing at a faulting instruction or the \ | |
37 | following instruction, depending on the signal. SEGV always does \ | |
38 | the former, so we adjust the saved PC to point to the following \ | |
39 | instruction; this is what the handler in libgcc expects. */ \ | |
40 | struct sigcontext *_sc = (struct sigcontext *)_p; \ | |
41 | _sc->sc_pc += 4; \ | |
42 | } \ | |
43 | while (0) | |
3cb20545 AH |
44 | |
45 | #elif defined(__ia64__) | |
46 | ||
47 | #define MAKE_THROW_FRAME(_exception) \ | |
48 | do \ | |
49 | { \ | |
50 | /* IA-64 either leaves PC pointing at a faulting instruction or the \ | |
51 | following instruction, depending on the signal. SEGV always does \ | |
52 | the former, so we adjust the saved PC to point to the following \ | |
53 | instruction; this is what the handler in libgcc expects. */ \ | |
54 | /* Note that we are lying to the unwinder here, which expects the \ | |
55 | faulting pc, not pc+1. But we claim the unwind information can't \ | |
56 | be changed by such a ld or st instruction, so it doesn't matter. */ \ | |
57 | struct sigcontext *_sc = (struct sigcontext *)_p; \ | |
58 | _sc->sc_ip++; \ | |
59 | } \ | |
60 | while (0) | |
714708c8 DM |
61 | #elif defined(__sparc__) |
62 | /* We could do the unwind of the signal frame quickly by hand here like | |
63 | sparc-signal.h does under Solaris, but that makes debugging unwind | |
64 | failures almost impossible. */ | |
65 | #if !defined(__arch64__) | |
66 | #define MAKE_THROW_FRAME(_exception) \ | |
67 | do \ | |
68 | { \ | |
69 | /* Sparc-32 leaves PC pointing at a faulting instruction \ | |
6ea53170 DM |
70 | always. \ |
71 | We advance the PC one instruction past the exception causing PC. \ | |
72 | This is done because FDEs are found with "context->ra - 1" in the \ | |
73 | unwinder. \ | |
74 | Also, the dwarf2 unwind machinery is going to add 8 to the \ | |
75 | PC it uses on Sparc. So we adjust the PC here. We do it here \ | |
76 | because we run once for such an exception, however the Sparc specific\ | |
77 | unwind can run multiple times for the same exception and it would \ | |
78 | adjust the PC more than once resulting in a bogus value. */ \ | |
714708c8 DM |
79 | struct sig_regs { \ |
80 | unsigned int psr, pc, npc, y, u_regs[16]; \ | |
81 | } *regp; \ | |
82 | unsigned int insn; \ | |
83 | __asm__ __volatile__("ld [%%i7 + 8], %0" : "=r" (insn)); \ | |
4bf01445 | 84 | /* mov __NR_sigaction, %g1; Old signal stack layout */ \ |
714708c8 DM |
85 | if (insn == 0x821020d8) \ |
86 | regp = (struct sig_regs *) _sip; \ | |
87 | else \ | |
4bf01445 | 88 | /* mov __NR_rt_sigaction, %g1; New signal stack layout */ \ |
714708c8 | 89 | regp = (struct sig_regs *) (_sip + 1); \ |
6ea53170 | 90 | regp->pc = ((regp->pc + 4) - 8); \ |
714708c8 DM |
91 | } \ |
92 | while (0) | |
93 | #else | |
94 | #define MAKE_THROW_FRAME(_exception) \ | |
95 | do \ | |
96 | { \ | |
97 | /* Sparc-64 leaves PC pointing at a faulting instruction \ | |
6ea53170 DM |
98 | always. \ |
99 | We advance the PC one instruction past the exception causing PC. \ | |
100 | This is done because FDEs are found with "context->ra - 1" in the \ | |
101 | unwinder. \ | |
102 | Also, the dwarf2 unwind machinery is going to add 8 to the \ | |
103 | PC it uses on Sparc. So we adjust the PC here. We do it here \ | |
104 | because we run once for such an exception, however the Sparc specific\ | |
105 | unwind can run multiple times for the same exception and it would \ | |
106 | adjust the PC more than once resulting in a bogus value. */ \ | |
714708c8 DM |
107 | struct pt_regs { \ |
108 | unsigned long u_regs[16]; \ | |
109 | unsigned long tstate, tpc, tnpc; \ | |
110 | unsigned int y, fprs; \ | |
111 | } *regp = (struct pt_regs *) (_sip + 1); \ | |
6ea53170 | 112 | regp->tpc = ((regp->tpc + 4) - 8); \ |
714708c8 DM |
113 | } \ |
114 | while (0) | |
115 | #endif | |
c9bffcd5 | 116 | #else |
01936f3a AH |
117 | #define MAKE_THROW_FRAME(_exception) \ |
118 | do \ | |
119 | { \ | |
c9bffcd5 | 120 | (void)_p; \ |
01936f3a AH |
121 | } \ |
122 | while (0) | |
c9bffcd5 | 123 | #endif |
01936f3a | 124 | |
fd84ba84 DM |
125 | #if defined(__sparc__) |
126 | #if defined(__arch64__) | |
127 | extern "C" { | |
128 | static void __rt_sigreturn_stub(void) | |
129 | { | |
130 | __asm__("mov %0, %%g1\n\t" | |
131 | "ta 0x6d\n\t" | |
132 | : /* no outputs */ | |
133 | : "i" (__NR_rt_sigreturn)); | |
134 | } | |
135 | struct kernel_sigaction | |
136 | { | |
137 | void (*k_sa_sigaction)(int,siginfo_t *,void *); | |
138 | unsigned long k_sa_flags; | |
139 | void (*k_sa_restorer)(void); | |
140 | sigset_t k_sa_mask; | |
141 | }; | |
142 | } | |
143 | #define INIT_SEGV \ | |
144 | do \ | |
145 | { \ | |
fd84ba84 DM |
146 | struct kernel_sigaction act; \ |
147 | unsigned long stub = ((unsigned long)&__rt_sigreturn_stub); \ | |
148 | act.k_sa_sigaction = _Jv_catch_segv; \ | |
149 | sigemptyset (&act.k_sa_mask); \ | |
150 | act.k_sa_flags = SA_SIGINFO; \ | |
151 | act.k_sa_restorer = NULL; \ | |
152 | syscall (SYS_rt_sigaction, SIGSEGV, &act, NULL, \ | |
153 | stub - 8, _NSIG / 8); \ | |
154 | } \ | |
155 | while (0) | |
156 | ||
157 | #define INIT_FPE \ | |
158 | do \ | |
159 | { \ | |
fd84ba84 DM |
160 | struct kernel_sigaction act; \ |
161 | unsigned long stub = ((unsigned long)&__rt_sigreturn_stub); \ | |
162 | act.k_sa_sigaction = _Jv_catch_fpe; \ | |
163 | sigemptyset (&act.k_sa_mask); \ | |
164 | act.k_sa_flags = SA_SIGINFO; \ | |
165 | act.k_sa_restorer = NULL; \ | |
166 | syscall (SYS_rt_sigaction, SIGFPE, &act, NULL, \ | |
167 | stub - 8, _NSIG / 8); \ | |
168 | } \ | |
169 | while (0) | |
170 | #else /* __arch64__ */ | |
171 | ||
172 | extern "C" { | |
173 | struct kernel_sigaction | |
174 | { | |
175 | void (*k_sa_sigaction)(int,siginfo_t *,void *); | |
176 | unsigned long k_sa_mask, k_sa_flags; | |
177 | void (*k_sa_restorer)(void); | |
178 | }; | |
179 | } | |
180 | ||
181 | #define INIT_SEGV \ | |
182 | do \ | |
183 | { \ | |
184 | struct kernel_sigaction act; \ | |
fd84ba84 DM |
185 | act.k_sa_sigaction = _Jv_catch_segv; \ |
186 | act.k_sa_mask = 0; \ | |
187 | act.k_sa_flags = SA_SIGINFO; \ | |
188 | act.k_sa_restorer = NULL; \ | |
189 | syscall (SYS_sigaction, -SIGSEGV, &act, NULL); \ | |
190 | } \ | |
191 | while (0) | |
192 | ||
193 | #define INIT_FPE \ | |
194 | do \ | |
195 | { \ | |
fd84ba84 DM |
196 | struct kernel_sigaction act; \ |
197 | act.k_sa_sigaction = _Jv_catch_fpe; \ | |
198 | act.k_sa_mask = 0; \ | |
199 | act.k_sa_flags = SA_SIGINFO; \ | |
200 | act.k_sa_restorer = NULL; \ | |
201 | syscall (SYS_sigaction, -SIGFPE, &act, NULL); \ | |
202 | } \ | |
203 | while (0) | |
204 | #endif | |
205 | #elif !defined(__ia64__) | |
01936f3a AH |
206 | #define INIT_SEGV \ |
207 | do \ | |
208 | { \ | |
01936f3a | 209 | struct sigaction act; \ |
c9bffcd5 | 210 | act.sa_sigaction = _Jv_catch_segv; \ |
01936f3a | 211 | sigemptyset (&act.sa_mask); \ |
c9bffcd5 | 212 | act.sa_flags = SA_SIGINFO; \ |
d6220b3a | 213 | syscall (SYS_sigaction, SIGSEGV, &act, NULL); \ |
01936f3a AH |
214 | } \ |
215 | while (0) | |
216 | ||
217 | #define INIT_FPE \ | |
218 | do \ | |
219 | { \ | |
01936f3a | 220 | struct sigaction act; \ |
c9bffcd5 | 221 | act.sa_sigaction = _Jv_catch_fpe; \ |
01936f3a | 222 | sigemptyset (&act.sa_mask); \ |
c9bffcd5 | 223 | act.sa_flags = SA_SIGINFO; \ |
d6220b3a | 224 | syscall (SYS_sigaction, SIGFPE, &act, NULL); \ |
01936f3a AH |
225 | } \ |
226 | while (0) | |
227 | ||
228 | /* We use syscall(SYS_sigaction) in INIT_SEGV and INIT_FPE instead of | |
229 | * sigaction() because on some systems the pthreads wrappers for | |
230 | * signal handlers are not compiled with unwind information, so it's | |
231 | * not possible to unwind through them. This is a problem that will | |
232 | * go away once all systems have pthreads libraries that are | |
233 | * compiled with full unwind info. */ | |
234 | ||
fd84ba84 | 235 | #else /* __ia64__ */ |
3cb20545 | 236 | |
ce4b2ca6 HB |
237 | // On IA64, unwind information is mandatory, so we can unwind |
238 | // correctly through glibc frames. Thus we call the ordinary | |
239 | // sigaction. | |
3cb20545 AH |
240 | |
241 | #define INIT_SEGV \ | |
242 | do \ | |
243 | { \ | |
3cb20545 AH |
244 | struct sigaction act; \ |
245 | act.sa_sigaction = _Jv_catch_segv; \ | |
246 | sigemptyset (&act.sa_mask); \ | |
247 | act.sa_flags = SA_SIGINFO; \ | |
ce4b2ca6 | 248 | sigaction (SIGSEGV, &act, NULL); \ |
3cb20545 AH |
249 | } \ |
250 | while (0) | |
251 | ||
252 | #define INIT_FPE \ | |
253 | do \ | |
254 | { \ | |
3cb20545 AH |
255 | struct sigaction act; \ |
256 | act.sa_sigaction = _Jv_catch_fpe; \ | |
257 | sigemptyset (&act.sa_mask); \ | |
258 | act.sa_flags = SA_SIGINFO; \ | |
ce4b2ca6 | 259 | sigaction (SIGFPE, &act, NULL); \ |
3cb20545 AH |
260 | } \ |
261 | while (0) | |
714708c8 | 262 | #endif /* __ia64__ || __sparc__ */ |
01936f3a | 263 | #endif /* JAVA_SIGNAL_H */ |