Make _Unwind_Backtrace() work on ARM.
Summary: Since the personality functions do the actual unwinding on ARM,
and will also stop unwinding when they encounter a handler, we invoke
_Unwind_VRS_Interpret() directly form _Unwind_Backtrace().
To simplify, the logic for decoding an EHT is moved out of
unwindOneFrame() and into its own function, decode_eht_entry(). Unlike
unwindOneFrame(), which could only handle ARM's compact personality
function entries (section 6.3) decode_eht_entry() can handle the generic
entries (section 6.2).
Reviewers: jroelofs
Reviewed By: jroelofs
Subscribers: piman, aemerson, cfe-commits
Differential Revision: http://reviews.llvm.org/D5112
git-svn-id: https://llvm.org/svn/llvm-project/libcxxabi/trunk@216730 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/backtrace_test.cpp b/test/backtrace_test.cpp
new file mode 100644
index 0000000..25dccb3
--- /dev/null
+++ b/test/backtrace_test.cpp
@@ -0,0 +1,61 @@
+//===---------------------- backtrace_test.cpp ----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <assert.h>
+#include <unwind.h>
+
+extern "C" _Unwind_Reason_Code
+trace_function(struct _Unwind_Context* context, void* ntraced) {
+ (*reinterpret_cast<size_t*>(ntraced))++;
+ // We should never have a call stack this deep...
+ assert(*reinterpret_cast<size_t*>(ntraced) < 20);
+ return _URC_NO_REASON;
+}
+
+void call3_throw(size_t* ntraced) {
+ try {
+ _Unwind_Backtrace(trace_function, ntraced);
+ } catch (...) {
+ assert(false);
+ }
+}
+
+void call3_nothrow(size_t* ntraced) {
+ _Unwind_Backtrace(trace_function, ntraced);
+}
+
+void call2(size_t* ntraced, bool do_throw) {
+ if (do_throw) {
+ call3_throw(ntraced);
+ } else {
+ call3_nothrow(ntraced);
+ }
+}
+
+void call1(size_t* ntraced, bool do_throw) {
+ call2(ntraced, do_throw);
+}
+
+int main() {
+ size_t throw_ntraced = 0;
+ size_t nothrow_ntraced = 0;
+
+ call1(¬hrow_ntraced, false);
+
+ try {
+ call1(&throw_ntraced, true);
+ } catch (...) {
+ assert(false);
+ }
+
+ // Different platforms (and different runtimes) will unwind a different number
+ // of times, so we can't make any better assumptions than this.
+ assert(nothrow_ntraced > 1);
+ assert(throw_ntraced == nothrow_ntraced); // Make sure we unwind through catch
+ return 0;
+}