xref: /openbsd/gnu/usr.bin/gcc/gcc/unwind-sjlj.c (revision c87b03e5)
1*c87b03e5Sespie /* DWARF2 exception handling and frame unwind runtime interface routines.
2*c87b03e5Sespie    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002
3*c87b03e5Sespie    Free Software Foundation, Inc.
4*c87b03e5Sespie 
5*c87b03e5Sespie    This file is part of GCC.
6*c87b03e5Sespie 
7*c87b03e5Sespie    GCC is free software; you can redistribute it and/or modify it
8*c87b03e5Sespie    under the terms of the GNU General Public License as published by
9*c87b03e5Sespie    the Free Software Foundation; either version 2, or (at your option)
10*c87b03e5Sespie    any later version.
11*c87b03e5Sespie 
12*c87b03e5Sespie    GCC is distributed in the hope that it will be useful, but WITHOUT
13*c87b03e5Sespie    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14*c87b03e5Sespie    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15*c87b03e5Sespie    License for more details.
16*c87b03e5Sespie 
17*c87b03e5Sespie    You should have received a copy of the GNU General Public License
18*c87b03e5Sespie    along with GCC; see the file COPYING.  If not, write to the Free
19*c87b03e5Sespie    Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20*c87b03e5Sespie    02111-1307, USA.  */
21*c87b03e5Sespie 
22*c87b03e5Sespie #include "tconfig.h"
23*c87b03e5Sespie #include "tsystem.h"
24*c87b03e5Sespie #include "unwind.h"
25*c87b03e5Sespie #include "gthr.h"
26*c87b03e5Sespie 
27*c87b03e5Sespie #ifdef __USING_SJLJ_EXCEPTIONS__
28*c87b03e5Sespie 
29*c87b03e5Sespie #ifdef DONT_USE_BUILTIN_SETJMP
30*c87b03e5Sespie #ifndef inhibit_libc
31*c87b03e5Sespie #include <setjmp.h>
32*c87b03e5Sespie #else
33*c87b03e5Sespie typedef void *jmp_buf[JMP_BUF_SIZE];
34*c87b03e5Sespie extern void longjmp(jmp_buf, int) __attribute__((noreturn));
35*c87b03e5Sespie #endif
36*c87b03e5Sespie #else
37*c87b03e5Sespie #define setjmp __builtin_setjmp
38*c87b03e5Sespie #define longjmp __builtin_longjmp
39*c87b03e5Sespie #endif
40*c87b03e5Sespie 
41*c87b03e5Sespie /* This structure is allocated on the stack of the target function.
42*c87b03e5Sespie    This must match the definition created in except.c:init_eh.  */
43*c87b03e5Sespie struct SjLj_Function_Context
44*c87b03e5Sespie {
45*c87b03e5Sespie   /* This is the chain through all registered contexts.  It is
46*c87b03e5Sespie      filled in by _Unwind_SjLj_Register.  */
47*c87b03e5Sespie   struct SjLj_Function_Context *prev;
48*c87b03e5Sespie 
49*c87b03e5Sespie   /* This is assigned in by the target function before every call
50*c87b03e5Sespie      to the index of the call site in the lsda.  It is assigned by
51*c87b03e5Sespie      the personality routine to the landing pad index.  */
52*c87b03e5Sespie   int call_site;
53*c87b03e5Sespie 
54*c87b03e5Sespie   /* This is how data is returned from the personality routine to
55*c87b03e5Sespie      the target function's handler.  */
56*c87b03e5Sespie   _Unwind_Word data[4];
57*c87b03e5Sespie 
58*c87b03e5Sespie   /* These are filled in once by the target function before any
59*c87b03e5Sespie      exceptions are expected to be handled.  */
60*c87b03e5Sespie   _Unwind_Personality_Fn personality;
61*c87b03e5Sespie   void *lsda;
62*c87b03e5Sespie 
63*c87b03e5Sespie #ifdef DONT_USE_BUILTIN_SETJMP
64*c87b03e5Sespie   /* We don't know what sort of alignment requirements the system
65*c87b03e5Sespie      jmp_buf has.  We over estimated in except.c, and now we have
66*c87b03e5Sespie      to match that here just in case the system *didn't* have more
67*c87b03e5Sespie      restrictive requirements.  */
68*c87b03e5Sespie   jmp_buf jbuf __attribute__((aligned));
69*c87b03e5Sespie #else
70*c87b03e5Sespie   void *jbuf[];
71*c87b03e5Sespie #endif
72*c87b03e5Sespie };
73*c87b03e5Sespie 
74*c87b03e5Sespie struct _Unwind_Context
75*c87b03e5Sespie {
76*c87b03e5Sespie   struct SjLj_Function_Context *fc;
77*c87b03e5Sespie };
78*c87b03e5Sespie 
79*c87b03e5Sespie typedef struct
80*c87b03e5Sespie {
81*c87b03e5Sespie   _Unwind_Personality_Fn personality;
82*c87b03e5Sespie } _Unwind_FrameState;
83*c87b03e5Sespie 
84*c87b03e5Sespie 
85*c87b03e5Sespie /* Manage the chain of registered function contexts.  */
86*c87b03e5Sespie 
87*c87b03e5Sespie /* Single threaded fallback chain.  */
88*c87b03e5Sespie static struct SjLj_Function_Context *fc_static;
89*c87b03e5Sespie 
90*c87b03e5Sespie #if __GTHREADS
91*c87b03e5Sespie static __gthread_key_t fc_key;
92*c87b03e5Sespie static int use_fc_key = -1;
93*c87b03e5Sespie 
94*c87b03e5Sespie static void
fc_key_dtor(void * ptr)95*c87b03e5Sespie fc_key_dtor (void *ptr)
96*c87b03e5Sespie {
97*c87b03e5Sespie   __gthread_key_dtor (fc_key, ptr);
98*c87b03e5Sespie }
99*c87b03e5Sespie 
100*c87b03e5Sespie static void
fc_key_init(void)101*c87b03e5Sespie fc_key_init (void)
102*c87b03e5Sespie {
103*c87b03e5Sespie   use_fc_key = __gthread_key_create (&fc_key, fc_key_dtor) == 0;
104*c87b03e5Sespie }
105*c87b03e5Sespie 
106*c87b03e5Sespie static void
fc_key_init_once(void)107*c87b03e5Sespie fc_key_init_once (void)
108*c87b03e5Sespie {
109*c87b03e5Sespie   static __gthread_once_t once = __GTHREAD_ONCE_INIT;
110*c87b03e5Sespie   if (__gthread_once (&once, fc_key_init) != 0 || use_fc_key < 0)
111*c87b03e5Sespie     use_fc_key = 0;
112*c87b03e5Sespie }
113*c87b03e5Sespie #endif
114*c87b03e5Sespie 
115*c87b03e5Sespie void
_Unwind_SjLj_Register(struct SjLj_Function_Context * fc)116*c87b03e5Sespie _Unwind_SjLj_Register (struct SjLj_Function_Context *fc)
117*c87b03e5Sespie {
118*c87b03e5Sespie #if __GTHREADS
119*c87b03e5Sespie   if (use_fc_key < 0)
120*c87b03e5Sespie     fc_key_init_once ();
121*c87b03e5Sespie 
122*c87b03e5Sespie   if (use_fc_key)
123*c87b03e5Sespie     {
124*c87b03e5Sespie       fc->prev = __gthread_getspecific (fc_key);
125*c87b03e5Sespie       __gthread_setspecific (fc_key, fc);
126*c87b03e5Sespie     }
127*c87b03e5Sespie   else
128*c87b03e5Sespie #endif
129*c87b03e5Sespie     {
130*c87b03e5Sespie       fc->prev = fc_static;
131*c87b03e5Sespie       fc_static = fc;
132*c87b03e5Sespie     }
133*c87b03e5Sespie }
134*c87b03e5Sespie 
135*c87b03e5Sespie static inline struct SjLj_Function_Context *
_Unwind_SjLj_GetContext(void)136*c87b03e5Sespie _Unwind_SjLj_GetContext (void)
137*c87b03e5Sespie {
138*c87b03e5Sespie #if __GTHREADS
139*c87b03e5Sespie   if (use_fc_key < 0)
140*c87b03e5Sespie     fc_key_init_once ();
141*c87b03e5Sespie 
142*c87b03e5Sespie   if (use_fc_key)
143*c87b03e5Sespie     return __gthread_getspecific (fc_key);
144*c87b03e5Sespie #endif
145*c87b03e5Sespie   return fc_static;
146*c87b03e5Sespie }
147*c87b03e5Sespie 
148*c87b03e5Sespie static inline void
_Unwind_SjLj_SetContext(struct SjLj_Function_Context * fc)149*c87b03e5Sespie _Unwind_SjLj_SetContext (struct SjLj_Function_Context *fc)
150*c87b03e5Sespie {
151*c87b03e5Sespie #if __GTHREADS
152*c87b03e5Sespie   if (use_fc_key < 0)
153*c87b03e5Sespie     fc_key_init_once ();
154*c87b03e5Sespie 
155*c87b03e5Sespie   if (use_fc_key)
156*c87b03e5Sespie     __gthread_setspecific (fc_key, fc);
157*c87b03e5Sespie   else
158*c87b03e5Sespie #endif
159*c87b03e5Sespie     fc_static = fc;
160*c87b03e5Sespie }
161*c87b03e5Sespie 
162*c87b03e5Sespie void
_Unwind_SjLj_Unregister(struct SjLj_Function_Context * fc)163*c87b03e5Sespie _Unwind_SjLj_Unregister (struct SjLj_Function_Context *fc)
164*c87b03e5Sespie {
165*c87b03e5Sespie   _Unwind_SjLj_SetContext (fc->prev);
166*c87b03e5Sespie }
167*c87b03e5Sespie 
168*c87b03e5Sespie 
169*c87b03e5Sespie /* Get/set the return data value at INDEX in CONTEXT.  */
170*c87b03e5Sespie 
171*c87b03e5Sespie _Unwind_Word
_Unwind_GetGR(struct _Unwind_Context * context,int index)172*c87b03e5Sespie _Unwind_GetGR (struct _Unwind_Context *context, int index)
173*c87b03e5Sespie {
174*c87b03e5Sespie   return context->fc->data[index];
175*c87b03e5Sespie }
176*c87b03e5Sespie 
177*c87b03e5Sespie /* Get the value of the CFA as saved in CONTEXT.  */
178*c87b03e5Sespie 
179*c87b03e5Sespie _Unwind_Word
_Unwind_GetCFA(struct _Unwind_Context * context)180*c87b03e5Sespie _Unwind_GetCFA (struct _Unwind_Context *context)
181*c87b03e5Sespie {
182*c87b03e5Sespie   /* ??? Ideally __builtin_setjmp places the CFA in the jmpbuf.  */
183*c87b03e5Sespie   return NULL;
184*c87b03e5Sespie }
185*c87b03e5Sespie 
186*c87b03e5Sespie void
_Unwind_SetGR(struct _Unwind_Context * context,int index,_Unwind_Word val)187*c87b03e5Sespie _Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
188*c87b03e5Sespie {
189*c87b03e5Sespie   context->fc->data[index] = val;
190*c87b03e5Sespie }
191*c87b03e5Sespie 
192*c87b03e5Sespie /* Get the call-site index as saved in CONTEXT.  */
193*c87b03e5Sespie 
194*c87b03e5Sespie _Unwind_Ptr
_Unwind_GetIP(struct _Unwind_Context * context)195*c87b03e5Sespie _Unwind_GetIP (struct _Unwind_Context *context)
196*c87b03e5Sespie {
197*c87b03e5Sespie   return context->fc->call_site + 1;
198*c87b03e5Sespie }
199*c87b03e5Sespie 
200*c87b03e5Sespie /* Set the return landing pad index in CONTEXT.  */
201*c87b03e5Sespie 
202*c87b03e5Sespie void
_Unwind_SetIP(struct _Unwind_Context * context,_Unwind_Ptr val)203*c87b03e5Sespie _Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
204*c87b03e5Sespie {
205*c87b03e5Sespie   context->fc->call_site = val - 1;
206*c87b03e5Sespie }
207*c87b03e5Sespie 
208*c87b03e5Sespie void *
_Unwind_GetLanguageSpecificData(struct _Unwind_Context * context)209*c87b03e5Sespie _Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
210*c87b03e5Sespie {
211*c87b03e5Sespie   return context->fc->lsda;
212*c87b03e5Sespie }
213*c87b03e5Sespie 
214*c87b03e5Sespie _Unwind_Ptr
_Unwind_GetRegionStart(struct _Unwind_Context * context)215*c87b03e5Sespie _Unwind_GetRegionStart (struct _Unwind_Context *context __attribute__((unused)) )
216*c87b03e5Sespie {
217*c87b03e5Sespie   return 0;
218*c87b03e5Sespie }
219*c87b03e5Sespie 
220*c87b03e5Sespie void *
_Unwind_FindEnclosingFunction(void * pc)221*c87b03e5Sespie _Unwind_FindEnclosingFunction (void *pc)
222*c87b03e5Sespie {
223*c87b03e5Sespie   return NULL;
224*c87b03e5Sespie }
225*c87b03e5Sespie 
226*c87b03e5Sespie #ifndef __ia64__
227*c87b03e5Sespie _Unwind_Ptr
_Unwind_GetDataRelBase(struct _Unwind_Context * context)228*c87b03e5Sespie _Unwind_GetDataRelBase (struct _Unwind_Context *context __attribute__((unused)) )
229*c87b03e5Sespie {
230*c87b03e5Sespie   return 0;
231*c87b03e5Sespie }
232*c87b03e5Sespie 
233*c87b03e5Sespie _Unwind_Ptr
_Unwind_GetTextRelBase(struct _Unwind_Context * context)234*c87b03e5Sespie _Unwind_GetTextRelBase (struct _Unwind_Context *context __attribute__((unused)) )
235*c87b03e5Sespie {
236*c87b03e5Sespie   return 0;
237*c87b03e5Sespie }
238*c87b03e5Sespie #endif
239*c87b03e5Sespie 
240*c87b03e5Sespie static inline _Unwind_Reason_Code
uw_frame_state_for(struct _Unwind_Context * context,_Unwind_FrameState * fs)241*c87b03e5Sespie uw_frame_state_for (struct _Unwind_Context *context, _Unwind_FrameState *fs)
242*c87b03e5Sespie {
243*c87b03e5Sespie   if (context->fc == NULL)
244*c87b03e5Sespie     {
245*c87b03e5Sespie       fs->personality = NULL;
246*c87b03e5Sespie       return _URC_END_OF_STACK;
247*c87b03e5Sespie     }
248*c87b03e5Sespie   else
249*c87b03e5Sespie     {
250*c87b03e5Sespie       fs->personality = context->fc->personality;
251*c87b03e5Sespie       return _URC_NO_REASON;
252*c87b03e5Sespie     }
253*c87b03e5Sespie }
254*c87b03e5Sespie 
255*c87b03e5Sespie static inline void
uw_update_context(struct _Unwind_Context * context,_Unwind_FrameState * fs)256*c87b03e5Sespie uw_update_context (struct _Unwind_Context *context,
257*c87b03e5Sespie 		   _Unwind_FrameState *fs __attribute__((unused)) )
258*c87b03e5Sespie {
259*c87b03e5Sespie   context->fc = context->fc->prev;
260*c87b03e5Sespie }
261*c87b03e5Sespie 
262*c87b03e5Sespie static inline void
uw_init_context(struct _Unwind_Context * context)263*c87b03e5Sespie uw_init_context (struct _Unwind_Context *context)
264*c87b03e5Sespie {
265*c87b03e5Sespie   context->fc = _Unwind_SjLj_GetContext ();
266*c87b03e5Sespie }
267*c87b03e5Sespie 
268*c87b03e5Sespie /* ??? There appear to be bugs in integrate.c wrt __builtin_longjmp and
269*c87b03e5Sespie    virtual-stack-vars.  An inline version of this segfaults on SPARC.  */
270*c87b03e5Sespie #define uw_install_context(CURRENT, TARGET)		\
271*c87b03e5Sespie   do							\
272*c87b03e5Sespie     {							\
273*c87b03e5Sespie       _Unwind_SjLj_SetContext ((TARGET)->fc);		\
274*c87b03e5Sespie       longjmp ((TARGET)->fc->jbuf, 1);			\
275*c87b03e5Sespie     }							\
276*c87b03e5Sespie   while (0)
277*c87b03e5Sespie 
278*c87b03e5Sespie 
279*c87b03e5Sespie static inline _Unwind_Ptr
uw_identify_context(struct _Unwind_Context * context)280*c87b03e5Sespie uw_identify_context (struct _Unwind_Context *context)
281*c87b03e5Sespie {
282*c87b03e5Sespie   return (_Unwind_Ptr) context->fc;
283*c87b03e5Sespie }
284*c87b03e5Sespie 
285*c87b03e5Sespie 
286*c87b03e5Sespie /* Play games with unwind symbols so that we can have call frame
287*c87b03e5Sespie    and sjlj symbols in the same shared library.  Not that you can
288*c87b03e5Sespie    use them simultaneously...  */
289*c87b03e5Sespie #define _Unwind_RaiseException		_Unwind_SjLj_RaiseException
290*c87b03e5Sespie #define _Unwind_ForcedUnwind		_Unwind_SjLj_ForcedUnwind
291*c87b03e5Sespie #define _Unwind_Resume			_Unwind_SjLj_Resume
292*c87b03e5Sespie #define _Unwind_Resume_or_Rethrow	_Unwind_SjLj_Resume_or_Rethrow
293*c87b03e5Sespie 
294*c87b03e5Sespie #include "unwind.inc"
295*c87b03e5Sespie 
296*c87b03e5Sespie #endif /* USING_SJLJ_EXCEPTIONS */
297