summaryrefslogtreecommitdiff
path: root/src/cxa_exception.cpp
diff options
context:
space:
mode:
authorLogan Chien <tzuhsiang.chien@gmail.com>2014-05-10 00:42:10 +0000
committerLogan Chien <tzuhsiang.chien@gmail.com>2014-05-10 00:42:10 +0000
commit05d51bcf07d0ec1c40785b4a860fd917410b4be1 (patch)
treee77dc951692207dd7ac73c1ea60a2599b906ab8b /src/cxa_exception.cpp
parent4856a67b510b2c50b5d2f1e3afa204ae22dca554 (diff)
Implement ARM EHABI exception handling.
This commit implements the ARM zero-cost exception handling support for libc++abi. git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@208466 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'src/cxa_exception.cpp')
-rw-r--r--src/cxa_exception.cpp95
1 files changed, 95 insertions, 0 deletions
diff --git a/src/cxa_exception.cpp b/src/cxa_exception.cpp
index 9bc6ad6..13c060c 100644
--- a/src/cxa_exception.cpp
+++ b/src/cxa_exception.cpp
@@ -256,11 +256,102 @@ The adjusted pointer is computed by the personality routine during phase 1
void*
__cxa_get_exception_ptr(void* unwind_exception) throw()
{
+#if LIBCXXABI_ARM_EHABI
+ return reinterpret_cast<void*>(
+ static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]);
+#else
return cxa_exception_from_exception_unwind_exception
(
static_cast<_Unwind_Exception*>(unwind_exception)
)->adjustedPtr;
+#endif
+}
+
+#if LIBCXXABI_ARM_EHABI
+/*
+The routine to be called before the cleanup. This will save __cxa_exception in
+__cxa_eh_globals, so that __cxa_end_cleanup() can recover later.
+*/
+bool
+__cxa_begin_cleanup(void* unwind_arg) throw ()
+{
+ _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg);
+ __cxa_eh_globals* globals = __cxa_get_globals();
+ __cxa_exception* exception_header =
+ cxa_exception_from_exception_unwind_exception(unwind_exception);
+
+ if (isOurExceptionClass(unwind_exception))
+ {
+ if (0 == exception_header->propagationCount)
+ {
+ exception_header->nextPropagatingException = globals->propagatingExceptions;
+ globals->propagatingExceptions = exception_header;
+ }
+ ++exception_header->propagationCount;
+ }
+ else
+ {
+ // If the propagatingExceptions stack is not empty, since we can't
+ // chain the foreign exception, terminate it.
+ if (NULL != globals->propagatingExceptions)
+ std::terminate();
+ globals->propagatingExceptions = exception_header;
+ }
+ return true;
+}
+
+/*
+The routine to be called after the cleanup has been performed. It will get the
+propagating __cxa_exception from __cxa_eh_globals, and continue the stack
+unwinding with _Unwind_Resume.
+
+According to ARM EHABI 8.4.1, __cxa_end_cleanup() should not clobber any
+register, thus we have to write this function in assembly so that we can save
+{r1, r2, r3}. We don't have to save r0 because it is the return value and the
+first argument to _Unwind_Resume(). In addition, we are saving r4 in order to
+align the stack to 16 bytes, even though it is a callee-save register.
+*/
+__attribute__((used)) static _Unwind_Exception *
+__cxa_end_cleanup_impl()
+{
+ __cxa_eh_globals* globals = __cxa_get_globals();
+ __cxa_exception* exception_header = globals->propagatingExceptions;
+ if (NULL == exception_header)
+ {
+ // It seems that __cxa_begin_cleanup() is not called properly.
+ // We have no choice but terminate the program now.
+ std::terminate();
+ }
+
+ if (isOurExceptionClass(&exception_header->unwindHeader))
+ {
+ --exception_header->propagationCount;
+ if (0 == exception_header->propagationCount)
+ {
+ globals->propagatingExceptions = exception_header->nextPropagatingException;
+ exception_header->nextPropagatingException = NULL;
+ }
+ }
+ else
+ {
+ globals->propagatingExceptions = NULL;
+ }
+ return &exception_header->unwindHeader;
}
+
+asm (
+ " .pushsection .text.__cxa_end_cleanup\n"
+ " .globl __cxa_end_cleanup\n"
+ " .type __cxa_end_cleanup,%function\n"
+ "__cxa_end_cleanup:\n"
+ " push {r1, r2, r3, r4}\n"
+ " bl __cxa_end_cleanup_impl\n"
+ " pop {r1, r2, r3, r4}\n"
+ " bl _Unwind_Resume\n"
+ " bl abort\n"
+ " .popsection"
+);
+#endif // LIBCXXABI_ARM_EHABI
/*
This routine can catch foreign or native exceptions. If native, the exception
@@ -320,7 +411,11 @@ __cxa_begin_catch(void* unwind_arg) throw()
globals->caughtExceptions = exception_header;
}
globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local
+#if LIBCXXABI_ARM_EHABI
+ return reinterpret_cast<void*>(exception_header->unwindHeader.barrier_cache.bitpattern[0]);
+#else
return exception_header->adjustedPtr;
+#endif
}
// Else this is a foreign exception
// If the caughtExceptions stack is not empty, terminate