]>
Commit | Line | Data |
---|---|---|
89797976 | 1 | /* Exception handling and frame unwind runtime interface routines. -*- C -*- |
52a11cbf RH |
2 | Copyright (C) 2001 Free Software Foundation, Inc. |
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 | ||
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 RH |
15 | |
16 | You should have received a copy of the GNU General Public License | |
1322177d LB |
17 | along with GCC; see the file COPYING. If not, write to the Free |
18 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA | |
19 | 02111-1307, USA. */ | |
52a11cbf RH |
20 | |
21 | /* This is derived from the C++ ABI for IA-64. Where we diverge | |
22 | for cross-architecture compatibility are noted with "@@@". | |
23 | This file is included from unwind-dw2.c or unwind-ia64.c. */ | |
24 | ||
25 | /* Subroutine of _Unwind_RaiseException also invoked from _Unwind_Resume. | |
26 | ||
27 | Unwind the stack calling the personality routine to find both the | |
28 | exception handler and intermediary cleanup code. We'll only locate | |
29 | the first such frame here. Cleanup code will call back into | |
30 | _Unwind_Resume and we'll continue Phase 2 there. */ | |
31 | ||
32 | static _Unwind_Reason_Code | |
33 | _Unwind_RaiseException_Phase2(struct _Unwind_Exception *exc, | |
34 | struct _Unwind_Context *context) | |
35 | { | |
36 | _Unwind_Reason_Code code; | |
37 | ||
38 | while (1) | |
39 | { | |
40 | _Unwind_FrameState fs; | |
41 | int match_handler; | |
42 | ||
43 | code = uw_frame_state_for (context, &fs); | |
44 | ||
45 | /* Identify when we've reached the designated handler context. */ | |
46 | match_handler = (uw_identify_context (context) == exc->private_2 | |
47 | ? _UA_HANDLER_FRAME : 0); | |
48 | ||
49 | if (code != _URC_NO_REASON) | |
50 | /* Some error encountered. Ususally the unwinder doesn't | |
51 | diagnose these and merely crashes. */ | |
52 | return _URC_FATAL_PHASE2_ERROR; | |
53 | ||
54 | /* Unwind successful. Run the personality routine, if any. */ | |
55 | if (fs.personality) | |
56 | { | |
57 | code = (*fs.personality) (1, _UA_CLEANUP_PHASE | match_handler, | |
58 | exc->exception_class, exc, context); | |
59 | if (code == _URC_INSTALL_CONTEXT) | |
60 | break; | |
61 | if (code != _URC_CONTINUE_UNWIND) | |
62 | return _URC_FATAL_PHASE2_ERROR; | |
63 | } | |
64 | ||
65 | /* Don't let us unwind past the handler context. */ | |
66 | if (match_handler) | |
67 | abort (); | |
68 | ||
69 | uw_update_context (context, &fs); | |
70 | } | |
71 | ||
72 | return code; | |
73 | } | |
74 | ||
75 | ||
76 | /* Raise an exception, passing along the given exception object. */ | |
77 | ||
78 | _Unwind_Reason_Code | |
79 | _Unwind_RaiseException(struct _Unwind_Exception *exc) | |
80 | { | |
81 | struct _Unwind_Context this_context, cur_context; | |
82 | _Unwind_Reason_Code code; | |
83 | ||
84 | uw_init_context (&this_context); | |
85 | cur_context = this_context; | |
86 | ||
87 | /* Phase 1: Search. Unwind the stack, calling the personality routine | |
88 | with the _UA_SEARCH_PHASE flag set. Do not modify the stack yet. */ | |
89 | while (1) | |
90 | { | |
91 | _Unwind_FrameState fs; | |
92 | ||
93 | code = uw_frame_state_for (&cur_context, &fs); | |
94 | ||
95 | if (code == _URC_END_OF_STACK) | |
96 | /* Hit end of stack with no handler found. */ | |
97 | return _URC_END_OF_STACK; | |
98 | ||
99 | if (code != _URC_NO_REASON) | |
100 | /* Some error encountered. Ususally the unwinder doesn't | |
101 | diagnose these and merely crashes. */ | |
102 | return _URC_FATAL_PHASE1_ERROR; | |
103 | ||
104 | /* Unwind successful. Run the personality routine, if any. */ | |
105 | if (fs.personality) | |
106 | { | |
107 | code = (*fs.personality) (1, _UA_SEARCH_PHASE, exc->exception_class, | |
108 | exc, &cur_context); | |
109 | if (code == _URC_HANDLER_FOUND) | |
110 | break; | |
111 | else if (code != _URC_CONTINUE_UNWIND) | |
112 | return _URC_FATAL_PHASE1_ERROR; | |
113 | } | |
114 | ||
115 | uw_update_context (&cur_context, &fs); | |
116 | } | |
117 | ||
118 | /* Indicate to _Unwind_Resume and associated subroutines that this | |
119 | is not a forced unwind. Further, note where we found a handler. */ | |
120 | exc->private_1 = 0; | |
121 | exc->private_2 = uw_identify_context (&cur_context); | |
122 | ||
123 | cur_context = this_context; | |
124 | code = _Unwind_RaiseException_Phase2 (exc, &cur_context); | |
125 | if (code != _URC_INSTALL_CONTEXT) | |
126 | return code; | |
127 | ||
128 | uw_install_context (&this_context, &cur_context); | |
129 | } | |
130 | ||
131 | ||
132 | /* Subroutine of _Unwind_ForcedUnwind also invoked from _Unwind_Resume. */ | |
133 | ||
134 | static _Unwind_Reason_Code | |
135 | _Unwind_ForcedUnwind_Phase2(struct _Unwind_Exception *exc, | |
136 | struct _Unwind_Context *context) | |
137 | { | |
9e800206 RH |
138 | _Unwind_Stop_Fn stop = (_Unwind_Stop_Fn) (_Unwind_Ptr) exc->private_1; |
139 | void *stop_argument = (void *) (_Unwind_Ptr) exc->private_2; | |
52a11cbf RH |
140 | _Unwind_Reason_Code code, stop_code; |
141 | ||
142 | while (1) | |
143 | { | |
144 | _Unwind_FrameState fs; | |
145 | ||
146 | code = uw_frame_state_for (context, &fs); | |
147 | if (code != _URC_NO_REASON && code != _URC_END_OF_STACK) | |
148 | return _URC_FATAL_PHASE2_ERROR; | |
149 | ||
150 | /* Unwind successful. */ | |
151 | stop_code = (*stop) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, | |
152 | exc->exception_class, exc, context, stop_argument); | |
153 | if (stop_code != _URC_NO_REASON) | |
154 | return _URC_FATAL_PHASE2_ERROR; | |
155 | ||
156 | /* Stop didn't want to do anything. Invoke the personality | |
157 | handler, if applicable, to run cleanups. */ | |
158 | if (code == _URC_END_OF_STACK) | |
159 | break; | |
160 | ||
161 | if (fs.personality) | |
162 | { | |
163 | code = (*fs.personality) (1, _UA_FORCE_UNWIND | _UA_CLEANUP_PHASE, | |
164 | exc->exception_class, exc, context); | |
165 | if (code == _URC_INSTALL_CONTEXT) | |
166 | break; | |
167 | if (code != _URC_CONTINUE_UNWIND) | |
168 | return _URC_FATAL_PHASE2_ERROR; | |
169 | } | |
170 | ||
171 | uw_update_context (context, &fs); | |
172 | } | |
173 | ||
174 | return code; | |
175 | } | |
176 | ||
177 | ||
178 | /* Raise an exception for forced unwinding. */ | |
179 | ||
180 | _Unwind_Reason_Code | |
181 | _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, | |
182 | _Unwind_Stop_Fn stop, void * stop_argument) | |
183 | { | |
184 | struct _Unwind_Context this_context, cur_context; | |
185 | _Unwind_Reason_Code code; | |
186 | ||
187 | uw_init_context (&this_context); | |
188 | cur_context = this_context; | |
189 | ||
190 | exc->private_1 = (_Unwind_Ptr) stop; | |
191 | exc->private_2 = (_Unwind_Ptr) stop_argument; | |
192 | ||
193 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); | |
194 | if (code != _URC_INSTALL_CONTEXT) | |
195 | return code; | |
196 | ||
197 | uw_install_context (&this_context, &cur_context); | |
198 | } | |
199 | ||
200 | ||
201 | /* Resume propagation of an existing exception. This is used after | |
202 | e.g. executing cleanup code, and not to implement rethrowing. */ | |
203 | ||
204 | void | |
205 | _Unwind_Resume (struct _Unwind_Exception *exc) | |
206 | { | |
207 | struct _Unwind_Context this_context, cur_context; | |
208 | _Unwind_Reason_Code code; | |
209 | ||
210 | uw_init_context (&this_context); | |
211 | cur_context = this_context; | |
212 | ||
213 | /* Choose between continuing to process _Unwind_RaiseException | |
214 | or _Unwind_ForcedUnwind. */ | |
215 | if (exc->private_1 == 0) | |
216 | code = _Unwind_RaiseException_Phase2 (exc, &cur_context); | |
217 | else | |
218 | code = _Unwind_ForcedUnwind_Phase2 (exc, &cur_context); | |
219 | ||
220 | if (code != _URC_INSTALL_CONTEXT) | |
221 | abort (); | |
222 | ||
223 | uw_install_context (&this_context, &cur_context); | |
224 | } | |
225 | ||
226 | /* A convenience function that calls the exception_cleanup field. */ | |
227 | ||
228 | void | |
229 | _Unwind_DeleteException (struct _Unwind_Exception *exc) | |
230 | { | |
231 | (*exc->exception_cleanup) (_URC_FOREIGN_EXCEPTION_CAUGHT, exc); | |
232 | } |