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