diff options
author | Paul Brook <paul@codesourcery.com> | 2004-09-22 15:40:33 +0000 |
---|---|---|
committer | Paul Brook <paul@codesourcery.com> | 2004-09-22 15:40:33 +0000 |
commit | 6bfd420c2d1bb3ba2b41143b97e625e12b5ddda2 (patch) | |
tree | 2b2f06f3f1d89e42e734e2acdbbe39cd860066f3 /libstdc++-v3 | |
parent | ea896bdbd1c1d7492f111b3e6db179763a2378f4 (diff) |
* Makefile.in (USER_H): Add unwind-arm.h.
* except.c (fnspec_ttable_indirect): Add.
(init_eh): Set it.
(add_ehspec_entry): Handle fnspec_ttable_indirect.
(output_ttype): New function.
(output_function_exception_table): Use it. Handle
fnspec_ttable_indirect.
* target-def.h (TARGET_ASM_TTYPE): Define.
(TARGET_EH_FNSPEC_TTABLE_INDIRECT): Ditto.
* target.h (struct gcc_target): Add asm_out.ttype and
eh_fnspec_ttable_indirect.
* unwind-arm.h: New file.
* unwind-c.c (CONTINUE_UNWINDING): Define.
(PERSONALITY_FUNCTION): Add ARM EABI prototype and initialization
code. Use CONTINUE_UNWINDING.
* unwind.h: Include unwind-arm.h when using ARM EABI unwinder.
* config/arm/arm.c (arm_unwind_emit, arm_output_ttype): New functions.
(arm_unwind_emit_stm, arm_unwind_emit_set): New functions.
(TARGET_UNWIND_EMIT, TARGET_ASM_TTYPE): Define.
(TARGET_EH_FNSPEC_TTABLE_INDIRECT): Ditto.
(thumb_pushpop, thumb_output_function_prologue): Output frame
unwinding directives.
* config/arm/arm.h (MUST_USE_SJLJ_EXCEPTIONS): Only define when
!TARGET_UNWIND_INFO.
* config/arm/bpabi.h (TARGET_UNWIND_INFO): Define.
* config/arm/elf.h (ASM_DECLARE_FUNCTION_NAME,
ASM_DECLARE_FUNCTION_SIZE): Output frame unwinding annotatons.
* config/arm/lib1funcs.asm: Include libunwind.s
* config/arm/libunwind.S: New file.
* config/arm/t-bpabi (LIB1ASMFUNCS): Add _unwind.
(LIB2ADDEH, LIB2ADDEHDEP): Set.
* config/arm/t-symbian (LIB2ADDEH, LIB2ADDEHDEP): Set.
* config/arm/unwind-arm.c: New file.
* doc/tm.texi: Document TARGET_ASM_TTYPE and
TARGET_EH_FNSPEC_TTABLE_INDIRECT.
libstdc++/
Add support for ARM EABI unwinding library.
* libsupc++/Makefile.am (sources): Add eh_arm.cc and eh_call.cc.
* libsupc++/Makefile.in: Regenerate.
* libsupc++/eh_arm.cc: New file.
* libsupc++/eh_call.cc: New file.
* libsupc++/eh_catch.cc (__cxa_begin_catch): Call _Unwind_Complete.
Use __is_gxx_exception_class.
(__cxa_end_catch): Use __is_gxx_exception_class.
* libsupc++/eh_personality.cc (NO_SIZE_OF_ENCODED_VALUE): Define if
using ARM EABI unwinder.
(_throw_typet): Declare.
(check_exception_spec, get_ttype_entry, get_adjusted_ptr): Add
ARM EABI implementations.
(CONTINUE_UNWINDING): Define.
(PERSONALITY_FUNCTION): Use CONTINUE_UNWINDING and
__cxa_call_terminate. Add Support for ARM EABI. Including changes
to function prototype, initialization code, exception object format,
and calling __cxa_begin_cleanup.
(__cxa_call_unexpected): Disable on arm systems.
* libsupc++/eh_throw.cc (__cxa_throw): Use __GXX_INIT_EXCEPTION_CLASS.
(__cxa_rethrow): Use __is_gxx_exception_class. Always call
_Unwind_RaiseException on ARM EABI targets.
* libsupc++/unwind-cxx.h (__cxa_call_terminate): Declare.
(__cxa_type_match, __cxa_begin_cleanup, __cxa_end_cleanup): Declare.
(__is_gxx_exception_class, __GXX_INIT_EXCEPTION_CLASS): Define.
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/csl-arm-branch@87867 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
-rw-r--r-- | libstdc++-v3/libsupc++/Makefile.am | 2 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/Makefile.in | 29 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/eh_arm.cc | 81 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/eh_call.cc | 156 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/eh_catch.cc | 13 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/eh_personality.cc | 210 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/eh_throw.cc | 6 | ||||
-rw-r--r-- | libstdc++-v3/libsupc++/unwind-cxx.h | 47 |
8 files changed, 506 insertions, 38 deletions
diff --git a/libstdc++-v3/libsupc++/Makefile.am b/libstdc++-v3/libsupc++/Makefile.am index a55ef6626a2..c67c294fca0 100644 --- a/libstdc++-v3/libsupc++/Makefile.am +++ b/libstdc++-v3/libsupc++/Makefile.am @@ -45,7 +45,9 @@ sources = \ del_opv.cc \ del_opvnt.cc \ eh_alloc.cc \ + eh_arm.cc \ eh_aux_runtime.cc \ + eh_call.cc \ eh_catch.cc \ eh_exception.cc \ eh_globals.cc \ diff --git a/libstdc++-v3/libsupc++/Makefile.in b/libstdc++-v3/libsupc++/Makefile.in index 7de32387a09..924ca77f556 100644 --- a/libstdc++-v3/libsupc++/Makefile.in +++ b/libstdc++-v3/libsupc++/Makefile.in @@ -241,7 +241,9 @@ sources = \ del_opv.cc \ del_opvnt.cc \ eh_alloc.cc \ + eh_arm.cc \ eh_aux_runtime.cc \ + eh_call.cc \ eh_catch.cc \ eh_exception.cc \ eh_globals.cc \ @@ -347,30 +349,31 @@ LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES) libsupc___la_LDFLAGS = libsupc___la_LIBADD = am__libsupc___la_SOURCES_DIST = del_op.cc del_opnt.cc del_opv.cc \ - del_opvnt.cc eh_alloc.cc eh_aux_runtime.cc eh_catch.cc \ - eh_exception.cc eh_globals.cc eh_personality.cc \ + del_opvnt.cc eh_alloc.cc eh_arm.cc eh_aux_runtime.cc eh_call.cc \ + eh_catch.cc eh_exception.cc eh_globals.cc eh_personality.cc \ eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \ eh_unex_handler.cc guard.cc new_handler.cc new_op.cc \ new_opnt.cc new_opv.cc new_opvnt.cc pure.cc tinfo.cc tinfo2.cc \ vec.cc vterminate.cc cp-demangle.c am__objects_1 = del_op.lo del_opnt.lo del_opv.lo del_opvnt.lo \ - eh_alloc.lo eh_aux_runtime.lo eh_catch.lo eh_exception.lo \ - eh_globals.lo eh_personality.lo eh_term_handler.lo \ - eh_terminate.lo eh_throw.lo eh_type.lo eh_unex_handler.lo \ - guard.lo new_handler.lo new_op.lo new_opnt.lo new_opv.lo \ - new_opvnt.lo pure.lo tinfo.lo tinfo2.lo vec.lo vterminate.lo + eh_alloc.lo eh_arm.lo eh_aux_runtime.lo eh_call.lo eh_catch.lo \ + eh_exception.lo eh_globals.lo eh_personality.lo \ + eh_term_handler.lo eh_terminate.lo eh_throw.lo eh_type.lo \ + eh_unex_handler.lo guard.lo new_handler.lo new_op.lo \ + new_opnt.lo new_opv.lo new_opvnt.lo pure.lo tinfo.lo tinfo2.lo \ + vec.lo vterminate.lo @GLIBCXX_HOSTED_TRUE@am__objects_2 = cp-demangle.lo am_libsupc___la_OBJECTS = $(am__objects_1) $(am__objects_2) libsupc___la_OBJECTS = $(am_libsupc___la_OBJECTS) libsupc__convenience_la_LDFLAGS = libsupc__convenience_la_LIBADD = am__libsupc__convenience_la_SOURCES_DIST = del_op.cc del_opnt.cc \ - del_opv.cc del_opvnt.cc eh_alloc.cc eh_aux_runtime.cc \ - eh_catch.cc eh_exception.cc eh_globals.cc eh_personality.cc \ - eh_term_handler.cc eh_terminate.cc eh_throw.cc eh_type.cc \ - eh_unex_handler.cc guard.cc new_handler.cc new_op.cc \ - new_opnt.cc new_opv.cc new_opvnt.cc pure.cc tinfo.cc tinfo2.cc \ - vec.cc vterminate.cc cp-demangle.c + del_opv.cc del_opvnt.cc eh_alloc.cc eh_arm.cc eh_aux_runtime.cc \ + eh_call.cc eh_catch.cc eh_exception.cc eh_globals.cc \ + eh_personality.cc eh_term_handler.cc eh_terminate.cc \ + eh_throw.cc eh_type.cc eh_unex_handler.cc guard.cc \ + new_handler.cc new_op.cc new_opnt.cc new_opv.cc new_opvnt.cc \ + pure.cc tinfo.cc tinfo2.cc vec.cc vterminate.cc cp-demangle.c am_libsupc__convenience_la_OBJECTS = $(am__objects_1) $(am__objects_2) libsupc__convenience_la_OBJECTS = $(am_libsupc__convenience_la_OBJECTS) diff --git a/libstdc++-v3/libsupc++/eh_arm.cc b/libstdc++-v3/libsupc++/eh_arm.cc new file mode 100644 index 00000000000..0a4f1345d73 --- /dev/null +++ b/libstdc++-v3/libsupc++/eh_arm.cc @@ -0,0 +1,81 @@ +// -*- C++ -*- ARM specific Exception handling support routines. +// Copyright (C) 2004 Free Software Foundation, Inc. +// +// This file is part of GCC. +// +// GCC is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GCC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + + +#include "unwind-cxx.h" + +using namespace __cxxabiv1; + + +// Given the thrown type THROW_TYPE, pointer to a variable containing a +// pointer to the exception object THROWN_PTR_P and a type CATCH_TYPE to +// compare against, return whether or not there is a match and if so, +// update *THROWN_PTR_P. + +extern "C" bool +__cxa_type_match(_Unwind_Exception* ue_header, + const std::type_info* catch_type, + void** thrown_ptr_p) +{ + if (!__is_gxx_exception_class(ue_header->exception_class)) + return false; + + __cxa_exception* xh = __get_exception_header_from_ue(ue_header); + const std::type_info* throw_type = xh->exceptionType; + void* thrown_ptr = *thrown_ptr_p; + + // Pointer types need to adjust the actual pointer, not + // the pointer to pointer that is the exception object. + // This also has the effect of passing pointer types + // "by value" through the __cxa_begin_catch return value. + if (throw_type->__is_pointer_p()) + thrown_ptr = *(void**) thrown_ptr; + + if (catch_type->__do_catch(throw_type, &thrown_ptr, 1)) + { + *thrown_ptr_p = thrown_ptr; + return true; + } + + return false; +} + +extern "C" void +__cxa_begin_cleanup(_Unwind_Exception* ue_header __attribute__((unused))) +{ +} + +extern "C" void +__cxa_end_cleanup(_Unwind_Exception* ue_header) +{ + /* TODO: This should really be an assembly stub which doesn't corrupt any + registers. */ + _Unwind_Resume(ue_header); +} + diff --git a/libstdc++-v3/libsupc++/eh_call.cc b/libstdc++-v3/libsupc++/eh_call.cc new file mode 100644 index 00000000000..e3aeb47436c --- /dev/null +++ b/libstdc++-v3/libsupc++/eh_call.cc @@ -0,0 +1,156 @@ +// -*- C++ -*- Helpers for calling unextected and terminate +// Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. +// +// This file is part of GCC. +// +// GCC is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2, or (at your option) +// any later version. +// +// GCC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with GCC; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, +// Boston, MA 02111-1307, USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + + +#include <bits/c++config.h> +#include <cstdlib> +#include <exception_defines.h> +#include "unwind-cxx.h" + +using namespace __cxxabiv1; + +#include "unwind-pe.h" + +extern "C" void +__cxa_call_terminate(_Unwind_Exception* ue_header) +{ + + if (ue_header) + { + __cxa_begin_catch(ue_header); + + /* Call the terminate handler that was in effect when we threw this + exception. */ + if (__is_gxx_exception_class(ue_header->exception_class)) + { + __cxa_exception* xh; + + xh = __get_exception_header_from_ue(ue_header); + __terminate(xh->terminateHandler); + } + } + /* Call the global routine if we don't have anything better. */ + std::terminate(); +} + + +#ifdef __ARM_EABI_UNWINDER__ +// The ARM EABI version has the same semantics as the generic routine, but +// the exception specification has a different format. +extern "C" void +__cxa_call_unexpected(void* exc_obj_in) +{ + _Unwind_Exception* exc_obj + = reinterpret_cast<_Unwind_Exception*>(exc_obj_in); + + int rtti_count = 0; + _Unwind_Word rtti_stride = 0; + _Unwind_Word* rtti_list = NULL; + bool foreign_exception; + std::unexpected_handler unexpectedHandler = NULL; + std::terminate_handler terminateHandler = NULL; + __cxa_exception* xh; + if (__is_gxx_exception_class(exc_obj->exception_class)) + { + // Save data from the EO, which may be clobbered by _cxa_begin_catch. + xh = __get_exception_header_from_ue(exc_obj); + unexpectedHandler = xh->unexpectedHandler; + terminateHandler = xh->terminateHandler; + rtti_count = exc_obj->barrier_cache.bitpattern[1]; + + rtti_stride = exc_obj->barrier_cache.bitpattern[3]; + rtti_list = (_Unwind_Word*) exc_obj->barrier_cache.bitpattern[4]; + foreign_exception = false; + } + else + foreign_exception = true; + + /* This must be called after extracting data from the EO, but before + calling unexpected(). */ + __cxa_begin_catch(exc_obj); + + // This function is a handler for our exception argument. If we exit + // by throwing a different exception, we'll need the original cleaned up. + struct end_catch_protect + { + end_catch_protect() { } + ~end_catch_protect() { __cxa_end_catch(); } + } end_catch_protect_obj; + + + try + { + if (foreign_exception) + std::unexpected(); + else + __unexpected(unexpectedHandler); + } + catch(...) + { + /* See if the new exception matches the rtti list. */ + if (foreign_exception) + std::terminate(); + + // Get the exception thrown from unexpected. + + __cxa_eh_globals* globals = __cxa_get_globals_fast(); + __cxa_exception* new_xh = globals->caughtExceptions; + void* new_ptr = new_xh + 1; + const std::type_info* catch_type; + int n; + bool bad_exception_allowed = false; + const std::type_info& bad_exc = typeid(std::bad_exception); + + // Check the new exception against the rtti list + for (n = 0; n < rtti_count; n++) + { + _Unwind_Word offset; + + offset = (_Unwind_Word) &rtti_list[n * (rtti_stride >> 2)]; + offset = _Unwind_decode_target2(offset); + catch_type = (const std::type_info*) (offset); + + if (__cxa_type_match(&new_xh->unwindHeader, catch_type, &new_ptr)) + __throw_exception_again; + + if (catch_type->__do_catch(&bad_exc, 0, 1)) + bad_exception_allowed = true; + } + + // If the exception spec allows std::bad_exception, throw that. +#ifdef __EXCEPTIONS + if (bad_exception_allowed) + throw std::bad_exception(); +#endif + + // Otherwise, die. + __terminate(terminateHandler); + } +} +#endif // __ARM_EABI_UNWINDER__ diff --git a/libstdc++-v3/libsupc++/eh_catch.cc b/libstdc++-v3/libsupc++/eh_catch.cc index bdcbd7e085c..6da410cae48 100644 --- a/libstdc++-v3/libsupc++/eh_catch.cc +++ b/libstdc++-v3/libsupc++/eh_catch.cc @@ -42,12 +42,13 @@ __cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw() __cxa_eh_globals *globals = __cxa_get_globals (); __cxa_exception *prev = globals->caughtExceptions; __cxa_exception *header = __get_exception_header_from_ue (exceptionObject); + void* objectp; // Foreign exceptions can't be stacked here. If the exception stack is // empty, then fine. Otherwise we really have no choice but to terminate. // Note that this use of "header" is a lie. It's fine so long as we only // examine header->unwindHeader though. - if (header->unwindHeader.exception_class != __gxx_exception_class) + if (!__is_gxx_exception_class(header->unwindHeader.exception_class)) { if (prev != 0) std::terminate (); @@ -77,7 +78,13 @@ __cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw() globals->caughtExceptions = header; } - return header->adjustedPtr; +#ifdef __ARM_EABI_UNWINDER__ + objectp = (void*) exceptionObject->barrier_cache.bitpattern[0]; + _Unwind_Complete(exceptionObject); +#else + objectp = header->adjustedPtr; +#endif + return objectp; } @@ -94,7 +101,7 @@ __cxxabiv1::__cxa_end_catch () // A foreign exception couldn't have been stacked (see above), // so by definition processing must be complete. - if (header->unwindHeader.exception_class != __gxx_exception_class) + if (!__is_gxx_exception_class(header->unwindHeader.exception_class)) { globals->caughtExceptions = 0; _Unwind_DeleteException (&header->unwindHeader); diff --git a/libstdc++-v3/libsupc++/eh_personality.cc b/libstdc++-v3/libsupc++/eh_personality.cc index 4d5ae57b8d2..cf8bfa42fc5 100644 --- a/libstdc++-v3/libsupc++/eh_personality.cc +++ b/libstdc++-v3/libsupc++/eh_personality.cc @@ -35,6 +35,10 @@ using namespace __cxxabiv1; +#ifdef __ARM_EABI_UNWINDER__ +#define NO_SIZE_OF_ENCODED_VALUE +#endif + #include "unwind-pe.h" @@ -84,6 +88,66 @@ parse_lsda_header (_Unwind_Context *context, const unsigned char *p, return p; } +#ifdef __ARM_EABI_UNWINDER__ +static const std::type_info* +get_ttype_entry(lsda_header_info* info, _Unwind_Word i) +{ + _Unwind_Ptr ptr; + + ptr = (_Unwind_Ptr) (info->TType - (i * 4)); + ptr = _Unwind_decode_target2(ptr); + + return reinterpret_cast<const std::type_info *>(ptr); +} + +/* The ABI provides a routine for matching exception object types. */ +typedef _Unwind_Control_Block _throw_typet; +#define get_adjusted_ptr(catch_type, throw_type, thrown_ptr_p) \ + __cxa_type_match (throw_type, catch_type, thrown_ptr_p) + +// Return true if THROW_TYPE matches one if the filter types. + +static bool +check_exception_spec(lsda_header_info* info, _throw_typet* throw_type, + void* thrown_ptr, _Unwind_Sword filter_value) +{ + const _Unwind_Word* e = ((const _Unwind_Word*) info->TType) + - filter_value - 1; + + while (1) + { + const std::type_info* catch_type; + _Unwind_Word tmp; + + tmp = *e; + + // Zero signals the end of the list. If we've not found + // a match by now, then we've failed the specification. + if (tmp == 0) + return false; + + tmp = _Unwind_decode_target2((_Unwind_Word) e); + + // Match a ttype entry. + catch_type = reinterpret_cast<const std::type_info*>(tmp); + + // ??? There is currently no way to ask the RTTI code about the + // relationship between two types without reference to a specific + // object. There should be; then we wouldn't need to mess with + // thrown_ptr here. + if (get_adjusted_ptr(catch_type, throw_type, &thrown_ptr)) + return true; + + /* Advance to the next entry. */ + e++; + } +} +#else +typedef const std::type_info _throw_typet; + + +// Return an element from a type table. + static const std::type_info * get_ttype_entry (lsda_header_info *info, _Unwind_Word i) { @@ -127,8 +191,8 @@ get_adjusted_ptr (const std::type_info *catch_type, // Return true if THROW_TYPE matches one if the filter types. static bool -check_exception_spec (lsda_header_info *info, const std::type_info *throw_type, - void *thrown_ptr, _Unwind_Sword filter_value) +check_exception_spec(lsda_header_info* info, _throw_typet* throw_type, + void* thrown_ptr, _Unwind_Sword filter_value) { const unsigned char *e = info->TType - filter_value - 1; @@ -155,6 +219,7 @@ check_exception_spec (lsda_header_info *info, const std::type_info *throw_type, return true; } } +#endif // Return true if the filter spec is empty, ie throw(). @@ -168,6 +233,20 @@ empty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value) return tmp == 0; } +#ifdef __ARM_EABI_UNWINDER__ +// ARM EABI personality routines must also unwind the stack. +#define CONTINUE_UNWINDING \ + do \ + { \ + if (__gnu_unwind_frame(ue_header, context) != _URC_OK) \ + return _URC_FAILURE; \ + return _URC_CONTINUE_UNWIND; \ + } \ + while (0) +#else +#define CONTINUE_UNWINDING return _URC_CONTINUE_UNWIND +#endif + // Using a different personality function name causes link failures // when trying to mix code using different exception handling models. #ifdef _GLIBCXX_SJLJ_EXCEPTIONS @@ -178,14 +257,18 @@ empty_exception_spec (lsda_header_info *info, _Unwind_Sword filter_value) #endif extern "C" _Unwind_Reason_Code +#ifdef __ARM_EABI_UNWINDER__ +PERSONALITY_FUNCTION (_Unwind_State state, + struct _Unwind_Exception* ue_header, + struct _Unwind_Context* context) +#else PERSONALITY_FUNCTION (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) +#endif { - __cxa_exception *xh = __get_exception_header_from_ue (ue_header); - enum found_handler_type { found_nothing, @@ -200,19 +283,66 @@ PERSONALITY_FUNCTION (int version, const unsigned char *p; _Unwind_Ptr landing_pad, ip; int handler_switch_value; - void *thrown_ptr = xh + 1; + void* thrown_ptr = ue_header + 1; + bool foreign_exception; + +#ifdef __ARM_EABI_UNWINDER__ + _Unwind_Action actions; + + switch (state) + { + case _US_VIRTUAL_UNWIND_FRAME: + actions = _UA_SEARCH_PHASE; + break; + + case _US_UNWIND_FRAME_STARTING: + actions = _UA_CLEANUP_PHASE; + if (ue_header->barrier_cache.sp == _Unwind_GetGR(context, 13)) + actions |= _UA_HANDLER_FRAME; + break; + + case _US_UNWIND_FRAME_RESUME: + CONTINUE_UNWINDING; + break; + + default: + abort(); + } + + /* We don't know which runtime we're working with, so can't check this. + However the ABI routines hide this from us, and we don't actually need + to know. */ + foreign_exception = false; + + /* The dwarf unwinder assumes the context structure holds things like the + function and LSDA pointers. The ARM implementation caches these in + the exception header (UCB). To avoid rewriting everything we make the + virtual IP register point at the UCB. */ + ip = (_Unwind_Ptr) ue_header; + _Unwind_SetGR(context, 12, ip); +#else + __cxa_exception* xh = __get_exception_header_from_ue(ue_header); // Interface version check. if (version != 1) return _URC_FATAL_PHASE1_ERROR; + foreign_exception = !__is_gxx_exception_class(exception_class); +#endif // Shortcut for phase 2 found handler for domestic exception. if (actions == (_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME) - && exception_class == __gxx_exception_class) + && !foreign_exception) { +#ifdef __ARM_EABI_UNWINDER__ + handler_switch_value = (int) ue_header->barrier_cache.bitpattern[1]; + language_specific_data = + (const unsigned char*) ue_header->barrier_cache.bitpattern[2]; + landing_pad = (_Unwind_Ptr) ue_header->barrier_cache.bitpattern[3]; +#else handler_switch_value = xh->handlerSwitchValue; language_specific_data = xh->languageSpecificData; landing_pad = (_Unwind_Ptr) xh->catchTemp; +#endif found_type = (landing_pad == 0 ? found_terminate : found_handler); goto install_context; } @@ -222,11 +352,11 @@ PERSONALITY_FUNCTION (int version, // If no LSDA, then there are no handlers or cleanups. if (! language_specific_data) - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; // Parse the LSDA header. p = parse_lsda_header (context, language_specific_data, &info); - info.ttype_base = base_of_encoded_value (info.ttype_encoding, context); + info.ttype_base = 0; ip = _Unwind_GetIP (context) - 1; landing_pad = 0; action_record = 0; @@ -312,7 +442,8 @@ PERSONALITY_FUNCTION (int version, // Otherwise we have a catch handler or exception specification. _Unwind_Sword ar_filter, ar_disp; - const std::type_info *throw_type, *catch_type; + const std::type_info* catch_type; + _throw_typet* throw_type; bool saw_cleanup = false; bool saw_handler = false; @@ -320,11 +451,15 @@ PERSONALITY_FUNCTION (int version, // exception class, there's no exception type. // ??? What to do about GNU Java and GNU Ada exceptions. +#ifdef __ARM_EABI_UNWINDER__ + throw_type = ue_header; +#else if ((actions & _UA_FORCE_UNWIND) - || exception_class != __gxx_exception_class) + || foreign_exception) throw_type = 0; else throw_type = xh->exceptionType; +#endif while (1) { @@ -387,16 +522,25 @@ PERSONALITY_FUNCTION (int version, do_something: if (found_type == found_nothing) - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; if (actions & _UA_SEARCH_PHASE) { if (found_type == found_cleanup) - return _URC_CONTINUE_UNWIND; + CONTINUE_UNWINDING; // For domestic exceptions, we cache data from phase 1 for phase 2. - if (exception_class == __gxx_exception_class) + if (!foreign_exception) { +#ifdef __ARM_EABI_UNWINDER__ + ue_header->barrier_cache.sp = _Unwind_GetGR(context, 13); + ue_header->barrier_cache.bitpattern[0] = (_uw) thrown_ptr; + ue_header->barrier_cache.bitpattern[1] + = (_uw) handler_switch_value; + ue_header->barrier_cache.bitpattern[2] + = (_uw) language_specific_data; + ue_header->barrier_cache.bitpattern[3] = (_uw) landing_pad; +#else xh->handlerSwitchValue = handler_switch_value; xh->actionRecord = action_record; xh->languageSpecificData = language_specific_data; @@ -405,16 +549,19 @@ PERSONALITY_FUNCTION (int version, // ??? Completely unknown what this field is supposed to be for. // ??? Need to cache TType encoding base for call_unexpected. xh->catchTemp = landing_pad; +#endif } return _URC_HANDLER_FOUND; } install_context: + +#ifndef __ARM_EABI_UNWINDER__ // We can't use any of the cxa routines with foreign exceptions, // because they all expect ue_header to be a struct __cxa_exception. // So in that case, call terminate or unexpected directly. if ((actions & _UA_FORCE_UNWIND) - || exception_class != __gxx_exception_class) + || foreign_exception) { if (found_type == found_terminate) std::terminate (); @@ -427,32 +574,56 @@ PERSONALITY_FUNCTION (int version, } } else +#endif { if (found_type == found_terminate) - { - __cxa_begin_catch (&xh->unwindHeader); - __terminate (xh->terminateHandler); - } + __cxa_call_terminate(ue_header); // Cache the TType base value for __cxa_call_unexpected, as we won't // have an _Unwind_Context then. if (handler_switch_value < 0) { parse_lsda_header (context, language_specific_data, &info); + +#ifdef __ARM_EABI_UNWINDER__ + const _Unwind_Word* e; + _Unwind_Word n; + + e = ((const _Unwind_Word*) info.TType) - handler_switch_value - 1; + /* Count the number of rtti objects. */ + n = 0; + while (e[n] != 0) + n++; + + // Count. + ue_header->barrier_cache.bitpattern[1] = n; + // Base (obsolete) + ue_header->barrier_cache.bitpattern[2] = 0; + // Stride. + ue_header->barrier_cache.bitpattern[3] = 4; + // List head. + ue_header->barrier_cache.bitpattern[4] = (_Unwind_Word) e; +#else xh->catchTemp = base_of_encoded_value (info.ttype_encoding, context); +#endif } } /* For targets with pointers smaller than the word size, we must extend the pointer, and this extension is target dependent. */ _Unwind_SetGR (context, __builtin_eh_return_data_regno (0), - __builtin_extend_pointer (&xh->unwindHeader)); + __builtin_extend_pointer (ue_header)); _Unwind_SetGR (context, __builtin_eh_return_data_regno (1), handler_switch_value); _Unwind_SetIP (context, landing_pad); +#ifdef __ARM_EABI_UNWINDER__ + if (found_type == found_cleanup) + __cxa_begin_cleanup(ue_header); +#endif return _URC_INSTALL_CONTEXT; } +#ifndef __ARM_EABI_UNWINDER__ extern "C" void __cxa_call_unexpected (void *exc_obj_in) { @@ -513,3 +684,4 @@ __cxa_call_unexpected (void *exc_obj_in) __terminate (xh_terminate_handler); } } +#endif // !__ARM_EABI_UNWINDER__ diff --git a/libstdc++-v3/libsupc++/eh_throw.cc b/libstdc++-v3/libsupc++/eh_throw.cc index b02efdad6dc..7e33fb66165 100644 --- a/libstdc++-v3/libsupc++/eh_throw.cc +++ b/libstdc++-v3/libsupc++/eh_throw.cc @@ -63,7 +63,7 @@ __cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo, header->exceptionDestructor = dest; header->unexpectedHandler = __unexpected_handler; header->terminateHandler = __terminate_handler; - header->unwindHeader.exception_class = __gxx_exception_class; + __GXX_INIT_EXCEPTION_CLASS(header->unwindHeader.exception_class); header->unwindHeader.exception_cleanup = __gxx_exception_cleanup; __cxa_eh_globals *globals = __cxa_get_globals (); @@ -90,7 +90,7 @@ __cxxabiv1::__cxa_rethrow () if (header) { // Tell __cxa_end_catch this is a rethrow. - if (header->unwindHeader.exception_class != __gxx_exception_class) + if (!__is_gxx_exception_class(header->unwindHeader.exception_class)) globals->caughtExceptions = 0; else header->handlerCount = -header->handlerCount; @@ -98,7 +98,7 @@ __cxxabiv1::__cxa_rethrow () #ifdef _GLIBCXX_SJLJ_EXCEPTIONS _Unwind_SjLj_Resume_or_Rethrow (&header->unwindHeader); #else -#ifdef _LIBUNWIND_STD_ABI +#if defined(_LIBUNWIND_STD_ABI) || defined (__ARM_EABI_UNWINDER__) _Unwind_RaiseException (&header->unwindHeader); #else _Unwind_Resume_or_Rethrow (&header->unwindHeader); diff --git a/libstdc++-v3/libsupc++/unwind-cxx.h b/libstdc++-v3/libsupc++/unwind-cxx.h index 67ea5cc2110..34e226ced8a 100644 --- a/libstdc++-v3/libsupc++/unwind-cxx.h +++ b/libstdc++-v3/libsupc++/unwind-cxx.h @@ -121,6 +121,15 @@ extern "C" void __cxa_bad_typeid (); // throws, and if bad_exception needs to be thrown. Called from the // compiler. extern "C" void __cxa_call_unexpected (void *) __attribute__((noreturn)); +extern "C" void __cxa_call_terminate (void*) __attribute__((noreturn)); + +#ifdef __ARM_EABI_UNWINDER__ +/* Arm EABI specified routines. */ +extern "C" bool __cxa_type_match (_Unwind_Exception*, const std::type_info*, + void**); +extern "C" void __cxa_begin_cleanup (_Unwind_Exception*); +extern "C" void __cxa_end_cleanup (_Unwind_Exception*); +#endif // Invokes given handler, dying appropriately if the user handler was // so inconsiderate as to return. @@ -133,6 +142,35 @@ extern std::unexpected_handler __unexpected_handler; // These are explicitly GNU C++ specific. +#ifdef __ARM_EABI_UNWINDER__ +static inline bool +__is_gxx_exception_class(_Unwind_Exception_Class c) +{ + /* TODO: Take advantage of the fact that c will always be word aligned. */ + return c[0] == 'G' + && c[1] == 'N' + && c[2] == 'U' + && c[3] == 'C' + && c[4] == 'C' + && c[5] == '+' + && c[6] == '+' + && c[7] == '\0'; +} + +static inline void +__GXX_INIT_EXCEPTION_CLASS(_Unwind_Exception_Class c) +{ + c[0] = 'G'; + c[1] = 'N'; + c[2] = 'U'; + c[3] = 'C'; + c[4] = 'C'; + c[5] = '+'; + c[6] = '+'; + c[7] = '\0'; +} + +#else // This is the exception class we report -- "GNUCC++\0". const _Unwind_Exception_Class __gxx_exception_class = ((((((((_Unwind_Exception_Class) 'G' @@ -144,6 +182,14 @@ const _Unwind_Exception_Class __gxx_exception_class << 8 | (_Unwind_Exception_Class) '+') << 8 | (_Unwind_Exception_Class) '\0'); +static inline bool +__is_gxx_exception_class(_Unwind_Exception_Class c) +{ + return c == __gxx_exception_class; +} + +#define __GXX_INIT_EXCEPTION_CLASS(c) c = __gxx_exception_class + // GNU C++ personality routine, Version 0. extern "C" _Unwind_Reason_Code __gxx_personality_v0 (int, _Unwind_Action, _Unwind_Exception_Class, @@ -153,6 +199,7 @@ extern "C" _Unwind_Reason_Code __gxx_personality_v0 extern "C" _Unwind_Reason_Code __gxx_personality_sj0 (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, struct _Unwind_Context *); +#endif // Acquire the C++ exception header from the C++ object. static inline __cxa_exception * |