1 // -*- C++ -*- The GNU C++ exception personality routine.
2 // Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
4 // This file is part of GCC.
6 // GCC 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 // GCC 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 GCC; 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
;
127 // Return true if THROW_TYPE matches one if the filter types.
130 check_exception_spec (lsda_header_info
*info
, const std::type_info
*throw_type
,
131 void *thrown_ptr
, _Unwind_Sword filter_value
)
133 const unsigned char *e
= info
->TType
- filter_value
- 1;
137 const std::type_info
*catch_type
;
140 e
= read_uleb128 (e
, &tmp
);
142 // Zero signals the end of the list. If we've not found
143 // a match by now, then we've failed the specification.
147 // Match a ttype entry.
148 catch_type
= get_ttype_entry (info
, tmp
);
150 // ??? There is currently no way to ask the RTTI code about the
151 // relationship between two types without reference to a specific
152 // object. There should be; then we wouldn't need to mess with
154 if (get_adjusted_ptr (catch_type
, throw_type
, &thrown_ptr
))
159 // Return true if the filter spec is empty, ie throw().
162 empty_exception_spec (lsda_header_info
*info
, _Unwind_Sword filter_value
)
164 const unsigned char *e
= info
->TType
- filter_value
- 1;
167 e
= read_uleb128 (e
, &tmp
);
171 // Using a different personality function name causes link failures
172 // when trying to mix code using different exception handling models.
173 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
174 #define PERSONALITY_FUNCTION __gxx_personality_sj0
175 #define __builtin_eh_return_data_regno(x) x
177 #define PERSONALITY_FUNCTION __gxx_personality_v0
180 extern "C" _Unwind_Reason_Code
181 PERSONALITY_FUNCTION (int version
,
182 _Unwind_Action actions
,
183 _Unwind_Exception_Class exception_class
,
184 struct _Unwind_Exception
*ue_header
,
185 struct _Unwind_Context
*context
)
187 __cxa_exception
*xh
= __get_exception_header_from_ue (ue_header
);
189 enum found_handler_type
197 lsda_header_info info
;
198 const unsigned char *language_specific_data
;
199 const unsigned char *action_record
;
200 const unsigned char *p
;
201 _Unwind_Ptr landing_pad
, ip
;
202 int handler_switch_value
;
203 void *thrown_ptr
= xh
+ 1;
205 // Interface version check.
207 return _URC_FATAL_PHASE1_ERROR
;
209 // Shortcut for phase 2 found handler for domestic exception.
210 if (actions
== (_UA_CLEANUP_PHASE
| _UA_HANDLER_FRAME
)
211 && exception_class
== __gxx_exception_class
)
213 handler_switch_value
= xh
->handlerSwitchValue
;
214 language_specific_data
= xh
->languageSpecificData
;
215 landing_pad
= (_Unwind_Ptr
) xh
->catchTemp
;
216 found_type
= (landing_pad
== 0 ? found_terminate
: found_handler
);
217 goto install_context
;
220 language_specific_data
= (const unsigned char *)
221 _Unwind_GetLanguageSpecificData (context
);
223 // If no LSDA, then there are no handlers or cleanups.
224 if (! language_specific_data
)
225 return _URC_CONTINUE_UNWIND
;
227 // Parse the LSDA header.
228 p
= parse_lsda_header (context
, language_specific_data
, &info
);
229 info
.ttype_base
= base_of_encoded_value (info
.ttype_encoding
, context
);
230 ip
= _Unwind_GetIP (context
) - 1;
233 handler_switch_value
= 0;
235 #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
236 // The given "IP" is an index into the call-site table, with two
237 // exceptions -- -1 means no-action, and 0 means terminate. But
238 // since we're using uleb128 values, we've not got random access
241 return _URC_CONTINUE_UNWIND
;
244 // Fall through to set found_terminate.
248 _Unwind_Word cs_lp
, cs_action
;
251 p
= read_uleb128 (p
, &cs_lp
);
252 p
= read_uleb128 (p
, &cs_action
);
256 // Can never have null landing pad for sjlj -- that would have
257 // been indicated by a -1 call site index.
258 landing_pad
= cs_lp
+ 1;
260 action_record
= info
.action_table
+ cs_action
- 1;
261 goto found_something
;
264 // Search the call-site table for the action associated with this IP.
265 while (p
< info
.action_table
)
267 _Unwind_Ptr cs_start
, cs_len
, cs_lp
;
268 _Unwind_Word cs_action
;
270 // Note that all call-site encodings are "absolute" displacements.
271 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_start
);
272 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_len
);
273 p
= read_encoded_value (0, info
.call_site_encoding
, p
, &cs_lp
);
274 p
= read_uleb128 (p
, &cs_action
);
276 // The table is sorted, so if we've passed the ip, stop.
277 if (ip
< info
.Start
+ cs_start
)
278 p
= info
.action_table
;
279 else if (ip
< info
.Start
+ cs_start
+ cs_len
)
282 landing_pad
= info
.LPStart
+ cs_lp
;
284 action_record
= info
.action_table
+ cs_action
- 1;
285 goto found_something
;
288 #endif // _GLIBCXX_SJLJ_EXCEPTIONS
290 // If ip is not present in the table, call terminate. This is for
291 // a destructor inside a cleanup, or a library routine the compiler
292 // was not expecting to throw.
293 found_type
= found_terminate
;
297 if (landing_pad
== 0)
299 // If ip is present, and has a null landing pad, there are
300 // no cleanups or handlers to be run.
301 found_type
= found_nothing
;
303 else if (action_record
== 0)
305 // If ip is present, has a non-null landing pad, and a null
306 // action table offset, then there are only cleanups present.
307 // Cleanups use a zero switch value, as set above.
308 found_type
= found_cleanup
;
312 // Otherwise we have a catch handler or exception specification.
314 _Unwind_Sword ar_filter
, ar_disp
;
315 const std::type_info
*throw_type
, *catch_type
;
316 bool saw_cleanup
= false;
317 bool saw_handler
= false;
319 // During forced unwinding, we only run cleanups. With a foreign
320 // exception class, there's no exception type.
321 // ??? What to do about GNU Java and GNU Ada exceptions.
323 if ((actions
& _UA_FORCE_UNWIND
)
324 || exception_class
!= __gxx_exception_class
)
327 throw_type
= xh
->exceptionType
;
332 p
= read_sleb128 (p
, &ar_filter
);
333 read_sleb128 (p
, &ar_disp
);
337 // Zero filter values are cleanups.
340 else if (ar_filter
> 0)
342 // Positive filter values are handlers.
343 catch_type
= get_ttype_entry (&info
, ar_filter
);
345 // Null catch type is a catch-all handler; we can catch foreign
346 // exceptions with this. Otherwise we must match types.
349 && get_adjusted_ptr (catch_type
, throw_type
,
358 // Negative filter values are exception specifications.
359 // ??? How do foreign exceptions fit in? As far as I can
360 // see we can't match because there's no __cxa_exception
361 // object to stuff bits in for __cxa_call_unexpected to use.
362 // Allow them iff the exception spec is non-empty. I.e.
363 // a throw() specification results in __unexpected.
365 ? ! check_exception_spec (&info
, throw_type
, thrown_ptr
,
367 : empty_exception_spec (&info
, ar_filter
))
376 action_record
= p
+ ar_disp
;
381 handler_switch_value
= ar_filter
;
382 found_type
= found_handler
;
385 found_type
= (saw_cleanup
? found_cleanup
: found_nothing
);
389 if (found_type
== found_nothing
)
390 return _URC_CONTINUE_UNWIND
;
392 if (actions
& _UA_SEARCH_PHASE
)
394 if (found_type
== found_cleanup
)
395 return _URC_CONTINUE_UNWIND
;
397 // For domestic exceptions, we cache data from phase 1 for phase 2.
398 if (exception_class
== __gxx_exception_class
)
400 xh
->handlerSwitchValue
= handler_switch_value
;
401 xh
->actionRecord
= action_record
;
402 xh
->languageSpecificData
= language_specific_data
;
403 xh
->adjustedPtr
= thrown_ptr
;
405 // ??? Completely unknown what this field is supposed to be for.
406 // ??? Need to cache TType encoding base for call_unexpected.
407 xh
->catchTemp
= landing_pad
;
409 return _URC_HANDLER_FOUND
;
413 // We can't use any of the cxa routines with foreign exceptions,
414 // because they all expect ue_header to be a struct __cxa_exception.
415 // So in that case, call terminate or unexpected directly.
416 if ((actions
& _UA_FORCE_UNWIND
)
417 || exception_class
!= __gxx_exception_class
)
419 if (found_type
== found_terminate
)
421 else if (handler_switch_value
< 0)
424 { std::unexpected (); }
426 { std::terminate (); }
431 if (found_type
== found_terminate
)
433 __cxa_begin_catch (&xh
->unwindHeader
);
434 __terminate (xh
->terminateHandler
);
437 // Cache the TType base value for __cxa_call_unexpected, as we won't
438 // have an _Unwind_Context then.
439 if (handler_switch_value
< 0)
441 parse_lsda_header (context
, language_specific_data
, &info
);
442 xh
->catchTemp
= base_of_encoded_value (info
.ttype_encoding
, context
);
446 /* For targets with pointers smaller than the word size, we must extend the
447 pointer, and this extension is target dependent. */
448 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (0),
449 __builtin_extend_pointer (&xh
->unwindHeader
));
450 _Unwind_SetGR (context
, __builtin_eh_return_data_regno (1),
451 handler_switch_value
);
452 _Unwind_SetIP (context
, landing_pad
);
453 return _URC_INSTALL_CONTEXT
;
457 __cxa_call_unexpected (void *exc_obj_in
)
459 _Unwind_Exception
*exc_obj
460 = reinterpret_cast <_Unwind_Exception
*>(exc_obj_in
);
462 __cxa_begin_catch (exc_obj
);
464 // This function is a handler for our exception argument. If we exit
465 // by throwing a different exception, we'll need the original cleaned up.
466 struct end_catch_protect
468 end_catch_protect() { }
469 ~end_catch_protect() { __cxa_end_catch(); }
470 } end_catch_protect_obj
;
472 lsda_header_info info
;
473 __cxa_exception
*xh
= __get_exception_header_from_ue (exc_obj
);
474 const unsigned char *xh_lsda
;
475 _Unwind_Sword xh_switch_value
;
476 std::terminate_handler xh_terminate_handler
;
478 // If the unexpectedHandler rethrows the exception (e.g. to categorize it),
479 // it will clobber data about the current handler. So copy the data out now.
480 xh_lsda
= xh
->languageSpecificData
;
481 xh_switch_value
= xh
->handlerSwitchValue
;
482 xh_terminate_handler
= xh
->terminateHandler
;
483 info
.ttype_base
= (_Unwind_Ptr
) xh
->catchTemp
;
486 { __unexpected (xh
->unexpectedHandler
); }
489 // Get the exception thrown from unexpected.
491 __cxa_eh_globals
*globals
= __cxa_get_globals_fast ();
492 __cxa_exception
*new_xh
= globals
->caughtExceptions
;
493 void *new_ptr
= new_xh
+ 1;
495 // We don't quite have enough stuff cached; re-parse the LSDA.
496 parse_lsda_header (0, xh_lsda
, &info
);
498 // If this new exception meets the exception spec, allow it.
499 if (check_exception_spec (&info
, new_xh
->exceptionType
,
500 new_ptr
, xh_switch_value
))
501 __throw_exception_again
;
503 // If the exception spec allows std::bad_exception, throw that.
504 // We don't have a thrown object to compare against, but since
505 // bad_exception doesn't have virtual bases, that's OK; just pass 0.
507 const std::type_info
&bad_exc
= typeid (std::bad_exception
);
508 if (check_exception_spec (&info
, &bad_exc
, 0, xh_switch_value
))
509 throw std::bad_exception();
513 __terminate (xh_terminate_handler
);