]>
Commit | Line | Data |
---|---|---|
89797976 | 1 | /* Exception handling and frame unwind runtime interface routines. -*- C -*- |
99dee823 | 2 | Copyright (C) 2001-2021 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); | |
5707be3c | 76 | _Unwind_Frames_Increment (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 RH |
162 | code = uw_frame_state_for (context, &fs); |
163 | if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) | |
164 | return _URC_FATAL_PHASE2_ERROR; | |
165 | ||
166 | /* Unwind successful. */ | |
4c21ef03 RH |
167 | action = _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE; |
168 | if (code == _URC_END_OF_STACK) | |
169 | action |= _UA_END_OF_STACK; | |
170 | stop_code = (*stop) (1, action, exc->exception_class, exc, | |
171 | context, stop_argument); | |
52a11cbf RH |
172 | if (stop_code != _URC_NO_REASON) |
173 | return _URC_FATAL_PHASE2_ERROR; | |
174 | ||
175 | /* Stop didn't want to do anything. Invoke the personality | |
176 | handler, if applicable, to run cleanups. */ | |
177 | if (code == _URC_END_OF_STACK) | |
178 | break; | |
179 | ||
180 | if (fs.personality) | |
181 | { | |
182 | code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, | |
183 | exc->exception_class, exc, context); | |
184 | if (code == _URC_INSTALL_CONTEXT) | |
185 | break; | |
186 | if (code != _URC_CONTINUE_UNWIND) | |
187 | return _URC_FATAL_PHASE2_ERROR; | |
188 | } | |
189 | ||
60aef23e DJ |
190 | /* Update cur_context to describe the same frame as fs, and discard |
191 | the previous context if necessary. */ | |
192 | uw_advance_context (context, &fs); | |
5707be3c | 193 | _Unwind_Frames_Increment (context, frames); |
52a11cbf RH |
194 | } |
195 | ||
6a10fff4 | 196 | *frames_p = frames; |
52a11cbf RH |
197 | return code; |
198 | } | |
199 | ||
200 | ||
201 | /* Raise an exception for forced unwinding. */ | |
202 | ||
56e449d3 | 203 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
204 | _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, |
205 | _Unwind_Stop_Fn stop, void * stop_argument) | |
206 | { | |
207 | struct _Unwind_Context this_context, cur_context; | |
208 | _Unwind_Reason_Code code; | |
6a10fff4 | 209 | unsigned long frames; |
52a11cbf RH |
210 | |
211 | uw_init_context (&this_context); | |
212 | cur_context = this_context; | |
213 | ||
214 | exc->private_1 = (_Unwind_Ptr) stop; | |
215 | exc->private_2 = (_Unwind_Ptr) stop_argument; | |
216 | ||
6a10fff4 | 217 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context, &frames); |
52a11cbf RH |
218 | if (code != _URC_INSTALL_CONTEXT) |
219 | return code; | |
220 | ||
6a10fff4 | 221 | uw_install_context (&this_context, &cur_context, frames); |
52a11cbf RH |
222 | } |
223 | ||
224 | ||
225 | /* Resume propagation of an existing exception. This is used after | |
226 | e.g. executing cleanup code, and not to implement rethrowing. */ | |
227 | ||
56e449d3 | 228 | void LIBGCC2_UNWIND_ATTRIBUTE |
52a11cbf RH |
229 | _Unwind_Resume (struct _Unwind_Exception *exc) |
230 | { | |
231 | struct _Unwind_Context this_context, cur_context; | |
232 | _Unwind_Reason_Code code; | |
6a10fff4 | 233 | unsigned long frames; |
52a11cbf RH |
234 | |
235 | uw_init_context (&this_context); | |
236 | cur_context = this_context; | |
237 | ||
238 | /* Choose between continuing to process _Unwind_RaiseException | |
239 | or _Unwind_ForcedUnwind. */ | |
240 | if (exc->private_1 == 0) | |
6a10fff4 | 241 | code = _Unwind_RaiseException_Phase2 (exc, &cur_context, &frames); |
52a11cbf | 242 | else |
6a10fff4 | 243 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context, &frames); |
52a11cbf | 244 | |
79d0dfa3 | 245 | gcc_assert (code == _URC_INSTALL_CONTEXT); |
52a11cbf | 246 | |
6a10fff4 | 247 | uw_install_context (&this_context, &cur_context, frames); |
52a11cbf RH |
248 | } |
249 | ||
a944ceb9 RH |
250 | |
251 | /* Resume propagation of an FORCE_UNWIND exception, or to rethrow | |
252 | a normal exception that was handled. */ | |
253 | ||
56e449d3 | 254 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
a944ceb9 RH |
255 | _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc) |
256 | { | |
257 | struct _Unwind_Context this_context, cur_context; | |
258 | _Unwind_Reason_Code code; | |
6a10fff4 | 259 | unsigned long frames; |
a944ceb9 RH |
260 | |
261 | /* Choose between continuing to process _Unwind_RaiseException | |
262 | or _Unwind_ForcedUnwind. */ | |
263 | if (exc->private_1 == 0) | |
264 | return _Unwind_RaiseException (exc); | |
265 | ||
266 | uw_init_context (&this_context); | |
267 | cur_context = this_context; | |
268 | ||
6a10fff4 | 269 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context, &frames); |
a944ceb9 | 270 | |
79d0dfa3 | 271 | gcc_assert (code == _URC_INSTALL_CONTEXT); |
a944ceb9 | 272 | |
6a10fff4 | 273 | uw_install_context (&this_context, &cur_context, frames); |
a944ceb9 RH |
274 | } |
275 | ||
276 | ||
52a11cbf RH |
277 | /* A convenience function that calls the exception_cleanup field. */ |
278 | ||
279 | void | |
280 | _Unwind_DeleteException (struct _Unwind_Exception *exc) | |
281 | { | |
a944ceb9 RH |
282 | if (exc->exception_cleanup) |
283 | (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); | |
52a11cbf | 284 | } |
7344f3d7 UW |
285 | |
286 | ||
287 | /* Perform stack backtrace through unwind data. */ | |
288 | ||
56e449d3 | 289 | _Unwind_Reason_Code LIBGCC2_UNWIND_ATTRIBUTE |
7344f3d7 UW |
290 | _Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument) |
291 | { | |
292 | struct _Unwind_Context context; | |
293 | _Unwind_Reason_Code code; | |
294 | ||
295 | uw_init_context (&context); | |
296 | ||
297 | while (1) | |
298 | { | |
299 | _Unwind_FrameState fs; | |
300 | ||
301 | /* Set up fs to describe the FDE for the caller of context. */ | |
302 | code = uw_frame_state_for (&context, &fs); | |
303 | if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) | |
304 | return _URC_FATAL_PHASE1_ERROR; | |
305 | ||
306 | /* Call trace function. */ | |
307 | if ((*trace) (&context, trace_argument) != _URC_NO_REASON) | |
308 | return _URC_FATAL_PHASE1_ERROR; | |
309 | ||
310 | /* We're done at end of stack. */ | |
311 | if (code == _URC_END_OF_STACK) | |
312 | break; | |
313 | ||
314 | /* Update context to describe the same frame as fs. */ | |
315 | uw_update_context (&context, &fs); | |
316 | } | |
317 | ||
318 | return code; | |
319 | } |