1 //===---------------------- backtrace_test.cpp ----------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // UNSUPPORTED: libcxxabi-no-exceptions
11 
12 #include <assert.h>
13 #include <stddef.h>
14 #include <unwind.h>
15 
16 extern "C" _Unwind_Reason_Code
trace_function(struct _Unwind_Context *,void * ntraced)17 trace_function(struct _Unwind_Context*, void* ntraced) {
18   (*reinterpret_cast<size_t*>(ntraced))++;
19   // We should never have a call stack this deep...
20   assert(*reinterpret_cast<size_t*>(ntraced) < 20);
21   return _URC_NO_REASON;
22 }
23 
24 __attribute__ ((__noinline__))
call3_throw(size_t * ntraced)25 void call3_throw(size_t* ntraced) {
26   try {
27     _Unwind_Backtrace(trace_function, ntraced);
28   } catch (...) {
29     assert(false);
30   }
31 }
32 
33 __attribute__ ((__noinline__, __disable_tail_calls__))
call3_nothrow(size_t * ntraced)34 void call3_nothrow(size_t* ntraced) {
35   _Unwind_Backtrace(trace_function, ntraced);
36 }
37 
38 __attribute__ ((__noinline__, __disable_tail_calls__))
call2(size_t * ntraced,bool do_throw)39 void call2(size_t* ntraced, bool do_throw) {
40   if (do_throw) {
41     call3_throw(ntraced);
42   } else {
43     call3_nothrow(ntraced);
44   }
45 }
46 
47 __attribute__ ((__noinline__, __disable_tail_calls__))
call1(size_t * ntraced,bool do_throw)48 void call1(size_t* ntraced, bool do_throw) {
49   call2(ntraced, do_throw);
50 }
51 
main()52 int main() {
53   size_t throw_ntraced = 0;
54   size_t nothrow_ntraced = 0;
55 
56   call1(&nothrow_ntraced, false);
57 
58   try {
59     call1(&throw_ntraced, true);
60   } catch (...) {
61     assert(false);
62   }
63 
64   // Different platforms (and different runtimes) will unwind a different number
65   // of times, so we can't make any better assumptions than this.
66   assert(nothrow_ntraced > 1);
67   assert(throw_ntraced == nothrow_ntraced); // Make sure we unwind through catch
68   return 0;
69 }
70