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