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