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