aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorPaul Brook <paul@codesourcery.com>2004-09-22 15:40:33 +0000
committerPaul Brook <paul@codesourcery.com>2004-09-22 15:40:33 +0000
commit6bfd420c2d1bb3ba2b41143b97e625e12b5ddda2 (patch)
tree2b2f06f3f1d89e42e734e2acdbbe39cd860066f3 /libstdc++-v3
parentea896bdbd1c1d7492f111b3e6db179763a2378f4 (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.am2
-rw-r--r--libstdc++-v3/libsupc++/Makefile.in29
-rw-r--r--libstdc++-v3/libsupc++/eh_arm.cc81
-rw-r--r--libstdc++-v3/libsupc++/eh_call.cc156
-rw-r--r--libstdc++-v3/libsupc++/eh_catch.cc13
-rw-r--r--libstdc++-v3/libsupc++/eh_personality.cc210
-rw-r--r--libstdc++-v3/libsupc++/eh_throw.cc6
-rw-r--r--libstdc++-v3/libsupc++/unwind-cxx.h47
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 *