1 // -*- C++ -*- The GNU C++ exception personality routine.
2 // Copyright (C) 2001 Free Software Foundation, Inc.
4 // This file is part of GNU CC.
6 // GNU CC is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2, or (at your option)
11 // GNU CC is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with GNU CC; see the file COPYING. If not, write to
18 // the Free Software Foundation, 59 Temple Place - Suite 330,
19 // Boston, MA 02111-1307, USA.
21 // As a special exception, you may use this file as part of a free software
22 // library without restriction. Specifically, if other files instantiate
23 // templates or use macros or inline functions from this file, or you compile
24 // this file and link it with other files to produce an executable, this
25 // file does not by itself cause the resulting executable to be covered by
26 // the GNU General Public License. This exception does not however
27 // invalidate any other reasons why the executable file might be covered by
28 // the GNU General Public License.
31 #include <bits/c++config.h>
33 #include <exception_defines.h>
34 #include "unwind-cxx.h"
36 using namespace __cxxabiv1
;
38 #include "unwind-pe.h"
41 struct lsda_header_info
45 _Unwind_Ptr ttype_base
;
46 const unsigned char *TType
;
47 const unsigned char *action_table
;
48 unsigned char ttype_encoding
;
49 unsigned char call_site_encoding
;
52 static const unsigned char *
53 parse_lsda_header (_Unwind_Context
*context
, const unsigned char *p
,
54 lsda_header_info
*info
)
57 unsigned char lpstart_encoding
;
59 info
->Start
= (context
? _Unwind_GetRegionStart (context
) : 0);
61 // Find @LPStart, the base to which landing pad offsets are relative.
62 lpstart_encoding
= *p
++;
63 if (lpstart_encoding
!= DW_EH_PE_omit
)
64 p
= read_encoded_value (context
, lpstart_encoding
, p
, &info
->LPStart
);
66 info
->LPStart
= info
->Start
;
68 // Find @TType, the base of the handler and exception spec type data.
69 info
->ttype_encoding
= *p
++;
70 if (info
->ttype_encoding
!= DW_EH_PE_omit
)
72 p
= read_uleb128 (p
, &tmp
);
73 info
->TType
= p
+ tmp
;
78 // The encoding and length of the call-site table; the action table
79 // immediately follows.
80 info
->call_site_encoding
= *p
++;
81 p
= read_uleb128 (p
, &tmp
);
82 info
->action_table
= p
+ tmp
;
87 static const std::type_info
*
88 get_ttype_entry (lsda_header_info
*info
, _Unwind_Word i
)
92 i
*= size_of_encoded_value (info
->ttype_encoding
);
93 read_encoded_value_with_base (info
->ttype_encoding
, info
->ttype_base
,
94 info
->TType
- i
, &ptr
);
96 return reinterpret_cast<const std::type_info
*>(ptr
);
99 // Given the thrown type THROW_TYPE, pointer to a variable containing a
100 // pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to
101 // compare against, return whether or not there is a match and if so,
102 // update *THROWN_PTR_P.
105 get_adjusted_ptr (const std::type_info
*catch_type
,
106 const std::type_info
*throw_type
,
109 void *thrown_ptr
= *thrown_ptr_p
;
111 // Pointer types need to adjust the actual pointer, not
112 // the pointer to pointer that is the exception object.
113 // This also has the effect of passing pointer types
114 // "by value" through the __cxa_begin_catch return value.
115 if (throw_type
->__is_pointer_p ())
116 thrown_ptr
= *(void **) thrown_ptr
;
118 if (catch_type
->__do_catch (throw_type
, &thrown_ptr
, 1))
120 *thrown_ptr_p
= thrown_ptr
;
128 check_exception_spec (lsda_header_info
*info
, const std::type_info
*throw_type
,
129 void *thrown_ptr
, _Unwind_Sword filter_value
)
131 const unsigned char *e
= info
->TType
- filter_value
- 1;
135 const std::type_info
*catch_type
;
138 e
= read_uleb128 (e
, &tmp
);
140 // Zero signals the end of the list. If we've not found
141 // a match by now, then we've failed the specification.
145 // Match a ttype entry.
146 catch_type
= get_ttype_entry (info
, tmp
);
148 // ??? There is currently no way to ask the RTTI code about the
149 // relationship between two types without reference to a specific
150 // object. There should be; then we wouldn't need to mess with
152 if (get_adjusted_ptr (catch_type
, throw_type
, &thrown_ptr
))
157 // Using a different personality function name causes link failures
158 // when trying to mix code using different exception handling models.
159 #ifdef _GLIBCPP_SJLJ_EXCEPTIONS
160 #define PERSONALITY_FUNCTION __gxx_personality_sj0
161 #define __builtin_eh_return_data_regno(x) x
163 #define PERSONALITY_FUNCTION __gxx_personality_v0
166 extern "C" _Unwind_Reason_Code
167 PERSONALITY_FUNCTION (int version
,
168 _Unwind_Action actions
,
169 _Unwind_Exception_Class exception_class
,
170 struct _Unwind_Exception
*ue_header
,
171 struct _Unwind_Context
*context
)
173 __cxa_exception
*xh
= __get_exception_header_from_ue (ue_header
);
175 enum found_handler_type
183 lsda_header_info info
;
184 const unsigned char *language_specific_data
;
185 const unsigned char *action_record
;
186 const unsigned char *p
;
187 _Unwind_Ptr landing_pad
, ip
;
188 int handler_switch_value
;
189 void *thrown_ptr
= xh
+ 1;
191 // Interface version check.
193 return _URC_FATAL_PHASE1_ERROR
;
195 // Shortcut for phase 2 found handler for domestic exception.
196 if (actions
== (_UA_CLEANUP_PHASE
| _UA_HANDLER_FRAME
)
197 && exception_class
== __gxx_exception_class
)
199 handler_switch_value
= xh
->handlerSwitchValue
;
200 landing_pad
= (_Unwind_Ptr
) xh
->catchTemp
;
201 found_type
= (landing_pad
== 0 ? found_terminate
: found_handler
);
202 goto install_context
;
205 language_specific_data
= (const unsigned char *)
206 _Unwind_GetLanguageSpecificData (context
);
208 // If no LSDA, then there are no handlers or cleanups.
209 if (! language_specific_data
)
210 return _URC_CONTINUE_UNWIND
;
212 // Parse the LSDA header.
213 p
= parse_lsda_header (context
, language_specific_data
, &info
);
214 info
.ttype_base
= base_of_encoded_value (info
.ttype_encoding
, context
);
215 ip
= _Unwind_GetIP (context
) - 1;
218 handler_switch_value
= 0;
220 #ifdef _GLIBCPP_SJLJ_EXCEPTIONS
221 // The given "IP" is an index into the call-site table, with two
222 // exceptions -- -1 means no-action, and 0 means terminate. But
223 // since we're using uleb128 values, we've not got random access
226 return _URC_CONTINUE_UNWIND
;
229 // Fall through to set found_terminate.
233 _Unwind_Word cs_lp
, cs_action
;
236 p
= read_uleb128 (p
, &cs_lp
);
237 p
= read_uleb128 (p
, &cs_action
);
241 // Can never have null landing pad for sjlj -- that would have
242 // been indicated by a -1 call site index.
243 landing_pad
= cs_lp
+ 1;
245 action_record
= info
.action_table
+ cs_action
- 1;
246 goto found_something
;
249 // Search the call-site table for the action associated with this IP.
250 while (p
< info
.action_table
)
252 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
253 _Unwind_Word cs_action
;
255 // Note that all call-site encodings are "absolute" displacements.
256 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
257 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
258 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
259 p
= read_uleb128 (p
, &cs_action
);
261 // The table is sorted, so if we've passed the ip, stop.
262 if (ip
< info
.Start
+ cs_start
)
263 p
= info
.action_table
;
264 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
267 landing_pad
= info
.LPStart
+ cs_lp
;
269 action_record
= info
.action_table
+ cs_action
- 1;
270 goto found_something
;
273 #endif // _GLIBCPP_SJLJ_EXCEPTIONS
275 // If ip is not present in the table, call terminate. This is for
276 // a destructor inside a cleanup, or a library routine the compiler
277 // was not expecting to throw.
278 found_type
= (actions
& _UA_FORCE_UNWIND
? found_nothing
: found_terminate
);
282 if (landing_pad
== 0)
284 // If ip is present, and has a null landing pad, there are
285 // no cleanups or handlers to be run.
286 found_type
= found_nothing
;
288 else if (action_record
== 0)
290 // If ip is present, has a non-null landing pad, and a null
291 // action table offset, then there are only cleanups present.
292 // Cleanups use a zero switch value, as set above.
293 found_type
= found_cleanup
;
297 // Otherwise we have a catch handler or exception specification.
299 _Unwind_Sword ar_filter
, ar_disp
;
300 const std::type_info
*throw_type
, *catch_type
;
301 bool saw_cleanup
= false;
302 bool saw_handler
= false;
304 // During forced unwinding, we only run cleanups. With a foreign
305 // exception class, there's no exception type.
306 // ??? What to do about GNU Java and GNU Ada exceptions.
308 if ((actions
& _UA_FORCE_UNWIND
)
309 || exception_class
!= __gxx_exception_class
)
312 throw_type
= xh
->exceptionType
;
317 p
= read_sleb128 (p
, &ar_filter
);
318 read_sleb128 (p
, &ar_disp
);
322 // Zero filter values are cleanups.
325 else if (ar_filter
> 0)
327 // Positive filter values are handlers.
328 catch_type
= get_ttype_entry (&info
, ar_filter
);
330 // Null catch type is a catch-all handler. We can catch
331 // foreign exceptions with this.
334 if (!(actions
& _UA_FORCE_UNWIND
))
342 if (get_adjusted_ptr (catch_type
, throw_type
, &thrown_ptr
))
351 // Negative filter values are exception specifications.
352 // ??? How do foreign exceptions fit in? As far as I can
353 // see we can't match because there's no __cxa_exception
354 // object to stuff bits in for __cxa_call_unexpected to use.
356 && ! check_exception_spec (&info
, throw_type
, thrown_ptr
,
366 action_record
= p
+ ar_disp
;
371 handler_switch_value
= ar_filter
;
372 found_type
= found_handler
;
375 found_type
= (saw_cleanup
? found_cleanup
: found_nothing
);
379 if (found_type
== found_nothing
)
380 return _URC_CONTINUE_UNWIND
;
382 if (actions
& _UA_SEARCH_PHASE
)
384 if (found_type
== found_cleanup
)
385 return _URC_CONTINUE_UNWIND
;
387 // For domestic exceptions, we cache data from phase 1 for phase 2.
388 if (exception_class
== __gxx_exception_class
)
390 xh
->handlerSwitchValue
= handler_switch_value
;
391 xh
->actionRecord
= action_record
;
392 xh
->languageSpecificData
= language_specific_data
;
393 xh
->adjustedPtr
= thrown_ptr
;
395 // ??? Completely unknown what this field is supposed to be for.
396 // ??? Need to cache TType encoding base for call_unexpected.
397 xh
->catchTemp
= (void *) (_Unwind_Ptr
) landing_pad
;
399 return _URC_HANDLER_FOUND
;
403 if (found_type
== found_terminate
)
405 __cxa_begin_catch (&xh
->unwindHeader
);
406 __terminate (xh
->terminateHandler
);
409 // Cache the TType base value for __cxa_call_unexpected, as we won't
410 // have an _Unwind_Context then.
411 if (handler_switch_value
< 0)
413 parse_lsda_header (context
, xh
->languageSpecificData
, &info
);
414 xh
->catchTemp
= (void *) base_of_encoded_value (info
.ttype_encoding
,
418 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (0),
419 (_Unwind_Ptr
) &xh
->unwindHeader
);
420 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1),
421 handler_switch_value
);
422 _Unwind_SetIP (context
, landing_pad
);
423 return _URC_INSTALL_CONTEXT
;
427 __cxa_call_unexpected (void *exc_obj_in
)
429 _Unwind_Exception
*exc_obj
430 = reinterpret_cast <_Unwind_Exception
*>(exc_obj_in
);
432 __cxa_begin_catch (exc_obj
);
434 // This function is a handler for our exception argument. If we exit
435 // by throwing a different exception, we'll need the original cleaned up.
436 struct end_catch_protect
438 end_catch_protect() { }
439 ~end_catch_protect() { __cxa_end_catch(); }
440 } end_catch_protect_obj
;
442 lsda_header_info info
;
443 __cxa_exception
*xh
= __get_exception_header_from_ue (exc_obj
);
444 const unsigned char *xh_lsda
;
445 _Unwind_Sword xh_switch_value
;
446 std::terminate_handler xh_terminate_handler
;
448 // If the unexpectedHandler rethrows the exception (e.g. to categorize it),
449 // it will clobber data about the current handler. So copy the data out now.
450 xh_lsda
= xh
->languageSpecificData
;
451 xh_switch_value
= xh
->handlerSwitchValue
;
452 xh_terminate_handler
= xh
->terminateHandler
;
453 info
.ttype_base
= (_Unwind_Ptr
) xh
->catchTemp
;
456 { __unexpected (xh
->unexpectedHandler
); }
459 // Get the exception thrown from unexpected.
460 // ??? Foreign exceptions can't be stacked this way.
462 __cxa_eh_globals
*globals
= __cxa_get_globals_fast ();
463 __cxa_exception
*new_xh
= globals
->caughtExceptions
;
464 void *new_ptr
= new_xh
+ 1;
466 // We don't quite have enough stuff cached; re-parse the LSDA.
467 parse_lsda_header (0, xh_lsda
, &info
);
469 // If this new exception meets the exception spec, allow it.
470 if (check_exception_spec (&info
, new_xh
->exceptionType
,
471 new_ptr
, xh_switch_value
))
472 __throw_exception_again
;
474 // If the exception spec allows std::bad_exception, throw that.
475 // We don't have a thrown object to compare against, but since
476 // bad_exception doesn't have virtual bases, that's OK; just pass 0.
478 const std::type_info
&bad_exc
= typeid (std::bad_exception
);
479 if (check_exception_spec (&info
, &bad_exc
, 0, xh_switch_value
))
480 throw std::bad_exception();
483 __terminate (xh_terminate_handler
);