]>
Commit | Line | Data |
---|---|---|
89797976 | 1 | /* Exception handling and frame unwind runtime interface routines. -*- C -*- |
83ffe9cd | 2 | Copyright (C) 2001-2023 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 | |
748086b7 | 8 | the Free Software Foundation; either version 3, or (at your option) |
52a11cbf RH |
9 | any later version. |
10 | ||
1322177d LB |
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. | |
52a11cbf | 15 | |
748086b7 JJ |
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/>. */ | |
52a11cbf RH |
24 | |
25 | /* This is derived from the C++ ABI for IA-64. Where we diverge | |
26 | for cross-architecture compatibility are noted with "@@@". | |
cb96cf3b BE |
27 | This file is included from unwind-dw2.c, unwind-sjlj.c or |
28 | unwind-ia64.c. */ | |
52a11cbf RH |
29 | |
30 | /* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. | |
31 | ||
32 | Unwind the stack calling the personality routine to find both the | |
33 | exception handler and intermediary cleanup code. We'll only locate | |
34 | the first such frame here. Cleanup code will call back into | |
35 | _Unwind_Resume and we'll continue Phase 2 there. */ | |
36 | ||
37 | static _Unwind_Reason_Code | |
38 | _Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, | |
6a10fff4 IT |
39 | struct _Unwind_Context *context, |
40 | unsigned long *frames_p) | |
52a11cbf RH |
41 | { |
42 | _Unwind_Reason_Code code; | |
6a10fff4 | 43 | unsigned long frames = 1; |
52a11cbf RH |
44 | |
45 | while (1) | |
46 | { | |
47 | _Unwind_FrameState fs; | |
48 | int match_handler; | |
49 | ||
50 | code = uw_frame_state_for (context, &fs); | |
51 | ||
52 | /* Identify when we've reached the designated handler context. */ | |
53 | match_handler = (uw_identify_context (context) == exc->private_2 | |
54 | ? _UA_HANDLER_FRAME : 0); | |
55 | ||
56 | if (code != _URC_NO_REASON) | |
e3aafbad | 57 | /* Some error encountered. Usually the unwinder doesn't |
52a11cbf RH |
58 | diagnose these and merely crashes. */ |
59 | return _URC_FATAL_PHASE2_ERROR; | |
60 | ||
61 | /* Unwind successful. Run the personality routine, if any. */ | |
62 | if (fs.personality) | |
63 | { | |
64 | code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler, | |
65 | exc->exception_class, exc, context); | |
66 | if (code == _URC_INSTALL_CONTEXT) | |
67 | break; | |
68 | if (code != _URC_CONTINUE_UNWIND) | |
69 | return _URC_FATAL_PHASE2_ERROR; | |
70 | } | |
71 | ||
72 | /* Don't let us unwind past the handler context. */ | |
79d0dfa3 | 73 | gcc_assert (!match_handler); |
52a11cbf RH |
74 | |
75 | uw_update_context (context, &fs); | |
9072db9d | 76 | _Unwind_Frames_Increment (exc, context, frames); |
52a11cbf RH |
77 | } |
78 | ||
6a10fff4 | 79 | *frames_p = frames; |
52a11cbf RH |
80 | return code; |
81 | } | |
82 | ||
52a11cbf RH |
83 | /* Raise an exception, passing along the given exception object. */ |
84 | ||
56e449d3 | 85 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
86 | _Unwind_RaiseException(struct _Unwind_Exception *exc) |
87 | { | |
88 | struct _Unwind_Context this_context, cur_context; | |
89 | _Unwind_Reason_Code code; | |
6a10fff4 | 90 | unsigned long frames; |
52a11cbf | 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; | |
6a10fff4 | 136 | code = _Unwind_RaiseException_Phase2 (exc, &cur_context, &frames); |
52a11cbf RH |
137 | if (code != _URC_INSTALL_CONTEXT) |
138 | return code; | |
139 | ||
6a10fff4 | 140 | uw_install_context (&this_context, &cur_context, frames); |
52a11cbf RH |
141 | } |
142 | ||
143 | ||
144 | /* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */ | |
145 | ||
146 | static _Unwind_Reason_Code | |
79d0dfa3 | 147 | _Unwind_ForcedUnwind_Phase2 (struct _Unwind_Exception *exc, |
6a10fff4 IT |
148 | struct _Unwind_Context *context, |
149 | unsigned long *frames_p) | |
52a11cbf | 150 | { |
9e800206 RH |
151 | _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; |
152 | void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; | |
52a11cbf | 153 | _Unwind_Reason_Code code, stop_code; |
6a10fff4 | 154 | unsigned long frames = 1; |
52a11cbf RH |
155 | |
156 | while (1) | |
157 | { | |
158 | _Unwind_FrameState fs; | |
4c21ef03 | 159 | int action; |
52a11cbf | 160 | |
81a60e6c | 161 | /* Set up fs to describe the FDE for the caller of cur_context. */ |
52a11cbf | 162 | code = uw_frame_state_for (context, &fs); |
8d71d3a3 RMZ |
163 | if (code != _URC_NO_REASON && code != _URC_END_OF_STACK |
164 | && code != _URC_NORMAL_STOP) | |
52a11cbf RH |
165 | return _URC_FATAL_PHASE2_ERROR; |
166 | ||
167 | /* Unwind successful. */ | |
4c21ef03 | 168 | action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; |
8d71d3a3 | 169 | if (code == _URC_END_OF_STACK || code == _URC_NORMAL_STOP) |
4c21ef03 RH |
170 | action |= _UA_END_OF_STACK; |
171 | stop_code = (*stop) (1, action, exc->exception_class, exc, | |
172 | context, stop_argument); | |
52a11cbf RH |
173 | if (stop_code != _URC_NO_REASON) |
174 | return _URC_FATAL_PHASE2_ERROR; | |
175 | ||
176 | /* Stop didn't want to do anything. Invoke the personality | |
177 | handler, if applicable, to run cleanups. */ | |
178 | if (code == _URC_END_OF_STACK) | |
179 | break; | |
180 | ||
181 | if (fs.personality) | |
182 | { | |
183 | code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, | |
184 | exc->exception_class, exc, context); | |
185 | if (code == _URC_INSTALL_CONTEXT) | |
186 | break; | |
187 | if (code != _URC_CONTINUE_UNWIND) | |
188 | return _URC_FATAL_PHASE2_ERROR; | |
189 | } | |
190 | ||
60aef23e DJ |
191 | /* Update cur_context to describe the same frame as fs, and discard |
192 | the previous context if necessary. */ | |
193 | uw_advance_context (context, &fs); | |
9072db9d | 194 | _Unwind_Frames_Increment (exc, context, frames); |
52a11cbf RH |
195 | } |
196 | ||
6a10fff4 | 197 | *frames_p = frames; |
52a11cbf RH |
198 | return code; |
199 | } | |
200 | ||
201 | ||
202 | /* Raise an exception for forced unwinding. */ | |
203 | ||
56e449d3 | 204 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
205 | _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, |
206 | _Unwind_Stop_Fn stop, void * stop_argument) | |
207 | { | |
208 | struct _Unwind_Context this_context, cur_context; | |
209 | _Unwind_Reason_Code code; | |
6a10fff4 | 210 | unsigned long frames; |
52a11cbf RH |
211 | |
212 | uw_init_context (&this_context); | |
213 | cur_context = this_context; | |
214 | ||
215 | exc->private_1 = (_Unwind_Ptr) stop; | |
216 | exc->private_2 = (_Unwind_Ptr) stop_argument; | |
217 | ||
6a10fff4 | 218 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context, &frames); |
52a11cbf RH |
219 | if (code != _URC_INSTALL_CONTEXT) |
220 | return code; | |
221 | ||
6a10fff4 | 222 | uw_install_context (&this_context, &cur_context, frames); |
52a11cbf RH |
223 | } |
224 | ||
225 | ||
226 | /* Resume propagation of an existing exception. This is used after | |
227 | e.g. executing cleanup code, and not to implement rethrowing. */ | |
228 | ||
56e449d3 | 229 | void LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
230 | _Unwind_Resume (struct _Unwind_Exception *exc) |
231 | { | |
232 | struct _Unwind_Context this_context, cur_context; | |
233 | _Unwind_Reason_Code code; | |
6a10fff4 | 234 | unsigned long frames; |
52a11cbf RH |
235 | |
236 | uw_init_context (&this_context); | |
237 | cur_context = this_context; | |
238 | ||
239 | /* Choose between continuing to process _Unwind_RaiseException | |
240 | or _Unwind_ForcedUnwind. */ | |
241 | if (exc->private_1 == 0) | |
6a10fff4 | 242 | code = _Unwind_RaiseException_Phase2 (exc, &cur_context, &frames); |
52a11cbf | 243 | else |
6a10fff4 | 244 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context, &frames); |
52a11cbf | 245 | |
79d0dfa3 | 246 | gcc_assert (code == _URC_INSTALL_CONTEXT); |
52a11cbf | 247 | |
6a10fff4 | 248 | uw_install_context (&this_context, &cur_context, frames); |
52a11cbf RH |
249 | } |
250 | ||
a944ceb9 RH |
251 | |
252 | /* Resume propagation of an FORCE_UNWIND exception, or to rethrow | |
253 | a normal exception that was handled. */ | |
254 | ||
56e449d3 | 255 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
a944ceb9 RH |
256 | _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) |
257 | { | |
258 | struct _Unwind_Context this_context, cur_context; | |
259 | _Unwind_Reason_Code code; | |
6a10fff4 | 260 | unsigned long frames; |
a944ceb9 RH |
261 | |
262 | /* Choose between continuing to process _Unwind_RaiseException | |
263 | or _Unwind_ForcedUnwind. */ | |
264 | if (exc->private_1 == 0) | |
265 | return _Unwind_RaiseException (exc); | |
266 | ||
267 | uw_init_context (&this_context); | |
268 | cur_context = this_context; | |
269 | ||
6a10fff4 | 270 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context, &frames); |
a944ceb9 | 271 | |
79d0dfa3 | 272 | gcc_assert (code == _URC_INSTALL_CONTEXT); |
a944ceb9 | 273 | |
6a10fff4 | 274 | uw_install_context (&this_context, &cur_context, frames); |
a944ceb9 RH |
275 | } |
276 | ||
277 | ||
52a11cbf RH |
278 | /* A convenience function that calls the exception_cleanup field. */ |
279 | ||
280 | void | |
281 | _Unwind_DeleteException (struct _Unwind_Exception *exc) | |
282 | { | |
a944ceb9 RH |
283 | if (exc->exception_cleanup) |
284 | (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); | |
52a11cbf | 285 | } |
7344f3d7 UW |
286 | |
287 | ||
288 | /* Perform stack backtrace through unwind data. */ | |
289 | ||
56e449d3 | 290 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
7344f3d7 UW |
291 | _Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument) |
292 | { | |
293 | struct _Unwind_Context context; | |
294 | _Unwind_Reason_Code code; | |
295 | ||
296 | uw_init_context (&context); | |
297 | ||
298 | while (1) | |
299 | { | |
300 | _Unwind_FrameState fs; | |
301 | ||
302 | /* Set up fs to describe the FDE for the caller of context. */ | |
303 | code = uw_frame_state_for (&context, &fs); | |
b7561b5d RMZ |
304 | if (code != _URC_NO_REASON && code != _URC_END_OF_STACK |
305 | && code != _URC_NORMAL_STOP) | |
7344f3d7 UW |
306 | return _URC_FATAL_PHASE1_ERROR; |
307 | ||
308 | /* Call trace function. */ | |
309 | if ((*trace) (&context, trace_argument) != _URC_NO_REASON) | |
310 | return _URC_FATAL_PHASE1_ERROR; | |
311 | ||
b7561b5d RMZ |
312 | #ifdef MD_BACKCHAIN_FALLBACK |
313 | /* Do a backchain if there is no DWARF data. */ | |
314 | if (code == _URC_NORMAL_STOP) | |
315 | { | |
316 | MD_BACKCHAIN_FALLBACK(&context, trace_argument); | |
317 | break; | |
318 | } | |
319 | #endif | |
320 | ||
321 | /* We're done at end of stack. */ | |
7344f3d7 UW |
322 | if (code == _URC_END_OF_STACK) |
323 | break; | |
324 | ||
325 | /* Update context to describe the same frame as fs. */ | |
326 | uw_update_context (&context, &fs); | |
327 | } | |
328 | ||
329 | return code; | |
330 | } |