annotate libgcc/unwind.inc @ 111:04ced10e8804

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