]>
Commit | Line | Data |
---|---|---|
89797976 | 1 | /* Exception handling and frame unwind runtime interface routines. -*- C -*- |
fa10beec | 2 | Copyright (C) 2001, 2003, 2008 Free Software Foundation, Inc. |
52a11cbf | 3 | |
1322177d | 4 | This file is part of GCC. |
52a11cbf | 5 | |
1322177d LB |
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 | |
52a11cbf RH |
8 | the Free Software Foundation; either version 2, or (at your option) |
9 | any later version. | |
10 | ||
1ee93c1b DJ |
11 | In addition to the permissions in the GNU General Public License, the |
12 | Free Software Foundation gives you unlimited permission to link the | |
13 | compiled version of this file into combinations with other programs, | |
14 | and to distribute those combinations without any restriction coming | |
15 | from the use of this file. (The General Public License restrictions | |
16 | do apply in other respects; for example, they cover modification of | |
17 | the file, and distribution when not linked into a combined | |
18 | executable.) | |
19 | ||
1322177d LB |
20 | GCC is distributed in the hope that it will be useful, but WITHOUT |
21 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |
22 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public | |
23 | License for more details. | |
52a11cbf RH |
24 | |
25 | You should have received a copy of the GNU General Public License | |
1322177d | 26 | along with GCC; see the file COPYING. If not, write to the Free |
366ccddb KC |
27 | Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA |
28 | 02110-1301, USA. */ | |
52a11cbf RH |
29 | |
30 | /* This is derived from the C++ ABI for IA-64. Where we diverge | |
31 | for cross-architecture compatibility are noted with "@@@". | |
cb96cf3b BE |
32 | This file is included from unwind-dw2.c, unwind-sjlj.c or |
33 | unwind-ia64.c. */ | |
52a11cbf RH |
34 | |
35 | /* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. | |
36 | ||
37 | Unwind the stack calling the personality routine to find both the | |
38 | exception handler and intermediary cleanup code. We'll only locate | |
39 | the first such frame here. Cleanup code will call back into | |
40 | _Unwind_Resume and we'll continue Phase 2 there. */ | |
41 | ||
42 | static _Unwind_Reason_Code | |
43 | _Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, | |
44 | struct _Unwind_Context *context) | |
45 | { | |
46 | _Unwind_Reason_Code code; | |
47 | ||
48 | while (1) | |
49 | { | |
50 | _Unwind_FrameState fs; | |
51 | int match_handler; | |
52 | ||
53 | code = uw_frame_state_for (context, &fs); | |
54 | ||
55 | /* Identify when we've reached the designated handler context. */ | |
56 | match_handler = (uw_identify_context (context) == exc->private_2 | |
57 | ? _UA_HANDLER_FRAME : 0); | |
58 | ||
59 | if (code != _URC_NO_REASON) | |
e3aafbad | 60 | /* Some error encountered. Usually the unwinder doesn't |
52a11cbf RH |
61 | diagnose these and merely crashes. */ |
62 | return _URC_FATAL_PHASE2_ERROR; | |
63 | ||
64 | /* Unwind successful. Run the personality routine, if any. */ | |
65 | if (fs.personality) | |
66 | { | |
67 | code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler, | |
68 | exc->exception_class, exc, context); | |
69 | if (code == _URC_INSTALL_CONTEXT) | |
70 | break; | |
71 | if (code != _URC_CONTINUE_UNWIND) | |
72 | return _URC_FATAL_PHASE2_ERROR; | |
73 | } | |
74 | ||
75 | /* Don't let us unwind past the handler context. */ | |
79d0dfa3 | 76 | gcc_assert (!match_handler); |
52a11cbf RH |
77 | |
78 | uw_update_context (context, &fs); | |
79 | } | |
80 | ||
81 | return code; | |
82 | } | |
83 | ||
52a11cbf RH |
84 | /* Raise an exception, passing along the given exception object. */ |
85 | ||
56e449d3 | 86 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
87 | _Unwind_RaiseException(struct _Unwind_Exception *exc) |
88 | { | |
89 | struct _Unwind_Context this_context, cur_context; | |
90 | _Unwind_Reason_Code code; | |
91 | ||
81a60e6c | 92 | /* Set up this_context to describe the current stack frame. */ |
52a11cbf RH |
93 | uw_init_context (&this_context); |
94 | cur_context = this_context; | |
95 | ||
96 | /* Phase 1: Search. Unwind the stack, calling the personality routine | |
97 | with the _UA_SEARCH_PHASE flag set. Do not modify the stack yet. */ | |
98 | while (1) | |
99 | { | |
100 | _Unwind_FrameState fs; | |
101 | ||
81a60e6c JM |
102 | /* Set up fs to describe the FDE for the caller of cur_context. The |
103 | first time through the loop, that means __cxa_throw. */ | |
52a11cbf RH |
104 | code = uw_frame_state_for (&cur_context, &fs); |
105 | ||
106 | if (code == _URC_END_OF_STACK) | |
107 | /* Hit end of stack with no handler found. */ | |
108 | return _URC_END_OF_STACK; | |
109 | ||
110 | if (code != _URC_NO_REASON) | |
fa10beec | 111 | /* Some error encountered. Usually the unwinder doesn't |
52a11cbf RH |
112 | diagnose these and merely crashes. */ |
113 | return _URC_FATAL_PHASE1_ERROR; | |
114 | ||
115 | /* Unwind successful. Run the personality routine, if any. */ | |
116 | if (fs.personality) | |
117 | { | |
118 | code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class, | |
119 | exc, &cur_context); | |
120 | if (code == _URC_HANDLER_FOUND) | |
121 | break; | |
122 | else if (code != _URC_CONTINUE_UNWIND) | |
123 | return _URC_FATAL_PHASE1_ERROR; | |
124 | } | |
125 | ||
81a60e6c | 126 | /* Update cur_context to describe the same frame as fs. */ |
52a11cbf RH |
127 | uw_update_context (&cur_context, &fs); |
128 | } | |
129 | ||
130 | /* Indicate to _Unwind_Resume and associated subroutines that this | |
131 | is not a forced unwind. Further, note where we found a handler. */ | |
132 | exc->private_1 = 0; | |
133 | exc->private_2 = uw_identify_context (&cur_context); | |
134 | ||
135 | cur_context = this_context; | |
136 | code = _Unwind_RaiseException_Phase2 (exc, &cur_context); | |
137 | if (code != _URC_INSTALL_CONTEXT) | |
138 | return code; | |
139 | ||
140 | uw_install_context (&this_context, &cur_context); | |
141 | } | |
142 | ||
143 | ||
144 | /* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */ | |
145 | ||
146 | static _Unwind_Reason_Code | |
79d0dfa3 NS |
147 | _Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc, |
148 | struct _Unwind_Context *context) | |
52a11cbf | 149 | { |
9e800206 RH |
150 | _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; |
151 | void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; | |
52a11cbf RH |
152 | _Unwind_Reason_Code code, stop_code; |
153 | ||
154 | while (1) | |
155 | { | |
156 | _Unwind_FrameState fs; | |
4c21ef03 | 157 | int action; |
52a11cbf | 158 | |
81a60e6c | 159 | /* Set up fs to describe the FDE for the caller of cur_context. */ |
52a11cbf RH |
160 | code = uw_frame_state_for (context, &fs); |
161 | if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) | |
162 | return _URC_FATAL_PHASE2_ERROR; | |
163 | ||
164 | /* Unwind successful. */ | |
4c21ef03 RH |
165 | action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; |
166 | if (code == _URC_END_OF_STACK) | |
167 | action |= _UA_END_OF_STACK; | |
168 | stop_code = (*stop) (1, action, exc->exception_class, exc, | |
169 | context, stop_argument); | |
52a11cbf RH |
170 | if (stop_code != _URC_NO_REASON) |
171 | return _URC_FATAL_PHASE2_ERROR; | |
172 | ||
173 | /* Stop didn't want to do anything. Invoke the personality | |
174 | handler, if applicable, to run cleanups. */ | |
175 | if (code == _URC_END_OF_STACK) | |
176 | break; | |
177 | ||
178 | if (fs.personality) | |
179 | { | |
180 | code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, | |
181 | exc->exception_class, exc, context); | |
182 | if (code == _URC_INSTALL_CONTEXT) | |
183 | break; | |
184 | if (code != _URC_CONTINUE_UNWIND) | |
185 | return _URC_FATAL_PHASE2_ERROR; | |
186 | } | |
187 | ||
60aef23e DJ |
188 | /* Update cur_context to describe the same frame as fs, and discard |
189 | the previous context if necessary. */ | |
190 | uw_advance_context (context, &fs); | |
52a11cbf RH |
191 | } |
192 | ||
193 | return code; | |
194 | } | |
195 | ||
196 | ||
197 | /* Raise an exception for forced unwinding. */ | |
198 | ||
56e449d3 | 199 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
200 | _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, |
201 | _Unwind_Stop_Fn stop, void * stop_argument) | |
202 | { | |
203 | struct _Unwind_Context this_context, cur_context; | |
204 | _Unwind_Reason_Code code; | |
205 | ||
206 | uw_init_context (&this_context); | |
207 | cur_context = this_context; | |
208 | ||
209 | exc->private_1 = (_Unwind_Ptr) stop; | |
210 | exc->private_2 = (_Unwind_Ptr) stop_argument; | |
211 | ||
212 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); | |
213 | if (code != _URC_INSTALL_CONTEXT) | |
214 | return code; | |
215 | ||
216 | uw_install_context (&this_context, &cur_context); | |
217 | } | |
218 | ||
219 | ||
220 | /* Resume propagation of an existing exception. This is used after | |
221 | e.g. executing cleanup code, and not to implement rethrowing. */ | |
222 | ||
56e449d3 | 223 | void LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
224 | _Unwind_Resume (struct _Unwind_Exception *exc) |
225 | { | |
226 | struct _Unwind_Context this_context, cur_context; | |
227 | _Unwind_Reason_Code code; | |
228 | ||
229 | uw_init_context (&this_context); | |
230 | cur_context = this_context; | |
231 | ||
232 | /* Choose between continuing to process _Unwind_RaiseException | |
233 | or _Unwind_ForcedUnwind. */ | |
234 | if (exc->private_1 == 0) | |
235 | code = _Unwind_RaiseException_Phase2 (exc, &cur_context); | |
236 | else | |
237 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); | |
238 | ||
79d0dfa3 | 239 | gcc_assert (code == _URC_INSTALL_CONTEXT); |
52a11cbf RH |
240 | |
241 | uw_install_context (&this_context, &cur_context); | |
242 | } | |
243 | ||
a944ceb9 RH |
244 | |
245 | /* Resume propagation of an FORCE_UNWIND exception, or to rethrow | |
246 | a normal exception that was handled. */ | |
247 | ||
56e449d3 | 248 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
a944ceb9 RH |
249 | _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) |
250 | { | |
251 | struct _Unwind_Context this_context, cur_context; | |
252 | _Unwind_Reason_Code code; | |
253 | ||
254 | /* Choose between continuing to process _Unwind_RaiseException | |
255 | or _Unwind_ForcedUnwind. */ | |
256 | if (exc->private_1 == 0) | |
257 | return _Unwind_RaiseException (exc); | |
258 | ||
259 | uw_init_context (&this_context); | |
260 | cur_context = this_context; | |
261 | ||
262 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); | |
263 | ||
79d0dfa3 | 264 | gcc_assert (code == _URC_INSTALL_CONTEXT); |
a944ceb9 RH |
265 | |
266 | uw_install_context (&this_context, &cur_context); | |
267 | } | |
268 | ||
269 | ||
52a11cbf RH |
270 | /* A convenience function that calls the exception_cleanup field. */ |
271 | ||
272 | void | |
273 | _Unwind_DeleteException (struct _Unwind_Exception *exc) | |
274 | { | |
a944ceb9 RH |
275 | if (exc->exception_cleanup) |
276 | (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); | |
52a11cbf | 277 | } |
7344f3d7 UW |
278 | |
279 | ||
280 | /* Perform stack backtrace through unwind data. */ | |
281 | ||
56e449d3 | 282 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
7344f3d7 UW |
283 | _Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument) |
284 | { | |
285 | struct _Unwind_Context context; | |
286 | _Unwind_Reason_Code code; | |
287 | ||
288 | uw_init_context (&context); | |
289 | ||
290 | while (1) | |
291 | { | |
292 | _Unwind_FrameState fs; | |
293 | ||
294 | /* Set up fs to describe the FDE for the caller of context. */ | |
295 | code = uw_frame_state_for (&context, &fs); | |
296 | if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) | |
297 | return _URC_FATAL_PHASE1_ERROR; | |
298 | ||
299 | /* Call trace function. */ | |
300 | if ((*trace) (&context, trace_argument) != _URC_NO_REASON) | |
301 | return _URC_FATAL_PHASE1_ERROR; | |
302 | ||
303 | /* We're done at end of stack. */ | |
304 | if (code == _URC_END_OF_STACK) | |
305 | break; | |
306 | ||
307 | /* Update context to describe the same frame as fs. */ | |
308 | uw_update_context (&context, &fs); | |
309 | } | |
310 | ||
311 | return code; | |
312 | } |