Enable `-funwind-tables` flag when building libunwind

Summary:
Or, rather, don't accidentally forget to pass it.

This is aimed to solve the problem discussed in [this thread](http://lists.llvm.org/pipermail/llvm-dev/2019-November/136890.html), and to fix [a year-old bug](https://bugs.llvm.org/show_bug.cgi?id=38468).

TL;DR: when building libunwind for ARM Linux, we **need** libunwind to be built with the `-funwind-tables` flag, because, well ARM EHABI needs unwind info produced by this flag. Without the flag all the procedures in libunwind are marked `.cantunwind`, which causes all sorts of bad things. From `_Unwind_Backtrace` not working, to C++ exceptions not being caught (which is the aforementioned bug is about).

Previously, this flag was not added because the CMake check `add_compile_flags_if_supported(-funwind-tables)` produced a false negative. Why? With this flag, the compiler generates calls to the `__aeabi_unwind_cpp_pr0` symbol, which is defined in libunwind itself and obviously is not available at configure time, before libunwind is built. This led to failure at link time during the CMake check. We handle this by disabling the linker for CMake checks in linbunwind.

Also, this patch introduces a lit feature `libunwind-arm-ehabi`, which is used to mark the `signal_frame.pass.cpp` test as unsupported (as was advised by @miyuki in D70397).

Reviewers: peter.smith, phosek, EricWF, compnerd, jroelofs, saugustine, miyuki, jfb

Subscribers: mgorny, kristof.beyls, christof, libcxx-commits, miyuki

Tags: #libc

Differential Revision: https://reviews.llvm.org/D70815

GitOrigin-RevId: b3fdf33ba6aa7ef80621696f74aaf2f6f8e1d1de
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 08095d1..7aa1c78 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -220,6 +220,21 @@
 # Setup Compiler Flags
 #===============================================================================
 
+# Don't run the linker in CMake checks.
+#
+# The reason why this was added is that when building libunwind for
+# ARM Linux, we need to pass the -funwind-tables flag in order for it to
+# work properly with ARM EHABI.
+#
+# However, when performing CMake checks, adding this flag causes the check
+# to produce a false negative, because the compiler generates calls
+# to __aeabi_unwind_cpp_pr0, which is defined in libunwind itself,
+# which isn't built yet, so the linker complains about undefined symbols.
+#
+# This leads to libunwind not being built with this flag, which makes
+# libunwind quite useless in this setup.
+set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
+
 # Get required flags.
 add_target_flags_if(LIBUNWIND_BUILD_32_BITS "-m32")
 
@@ -292,6 +307,12 @@
 add_cxx_compile_flags_if_supported(-EHsc)
 
 add_compile_flags_if_supported(-funwind-tables)
+
+if (LIBUNWIND_USES_ARM_EHABI AND NOT LIBUNWIND_SUPPORTS_FUNWIND_TABLES_FLAG)
+  message(SEND_ERROR "The -funwind-tables flag must be supported "
+                     "because this target uses ARM Exception Handling ABI")
+endif()
+
 add_cxx_compile_flags_if_supported(-fno-exceptions)
 add_cxx_compile_flags_if_supported(-fno-rtti)
 
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index 02d2f13..0d833e9 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -2,6 +2,7 @@
 include(CheckCCompilerFlag)
 include(CheckCXXCompilerFlag)
 include(CheckLibraryExists)
+include(CheckSymbolExists)
 include(CheckCSourceCompiles)
 
 check_library_exists(c fopen "" LIBUNWIND_HAS_C_LIB)
@@ -73,3 +74,13 @@
 # Check libraries
 check_library_exists(dl dladdr "" LIBUNWIND_HAS_DL_LIB)
 check_library_exists(pthread pthread_once "" LIBUNWIND_HAS_PTHREAD_LIB)
+
+# Check symbols
+check_symbol_exists(__arm__ "" LIBUNWIND_TARGET_ARM)
+check_symbol_exists(__USING_SJLJ_EXCEPTIONS__ "" LIBUNWIND_USES_SJLJ_EXCEPTIONS)
+check_symbol_exists(__ARM_DWARF_EH__ "" LIBUNWIND_USES_DWARF_EH)
+
+if(LIBUNWIND_TARGET_ARM AND NOT LIBUNWIND_USES_SJLJ_EXCEPTIONS AND NOT LIBUNWIND_USES_DWARF_EH)
+  # This condition is copied from __libunwind_config.h
+  set(LIBUNWIND_USES_ARM_EHABI ON)
+endif()
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d902e3e..40d4acd 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -16,6 +16,7 @@
 pythonize_bool(LIBUNWIND_ENABLE_SHARED)
 pythonize_bool(LIBUNWIND_ENABLE_THREADS)
 pythonize_bool(LIBUNWIND_ENABLE_EXCEPTIONS)
+pythonize_bool(LIBUNWIND_USES_ARM_EHABI)
 pythonize_bool(LIBUNWIND_USE_COMPILER_RT)
 pythonize_bool(LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY)
 set(LIBUNWIND_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING
diff --git a/test/libunwind/test/config.py b/test/libunwind/test/config.py
index 05e3f3c..41ca3f9 100644
--- a/test/libunwind/test/config.py
+++ b/test/libunwind/test/config.py
@@ -37,6 +37,8 @@
         super(Configuration, self).configure_features()
         if not self.get_lit_bool('enable_exceptions', True):
             self.config.available_features.add('libcxxabi-no-exceptions')
+        if self.get_lit_bool('arm_ehabi', False):
+            self.config.available_features.add('libunwind-arm-ehabi')
 
     def configure_compile_flags(self):
         self.cxx.compile_flags += ['-DLIBUNWIND_NO_TIMER']
@@ -66,3 +68,11 @@
 
     def configure_compile_flags_rtti(self):
         pass
+
+    def configure_link_flags_cxx_library(self):
+        # libunwind tests should not link with libc++
+        pass
+
+    def configure_link_flags_abi_library(self):
+        # libunwind tests should not link with libc++abi
+        pass
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index 34da72a..37f90a9 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -19,6 +19,7 @@
 config.libunwind_shared         = @LIBUNWIND_ENABLE_SHARED@
 config.enable_shared            = @LIBCXX_ENABLE_SHARED@
 config.enable_exceptions        = @LIBUNWIND_ENABLE_EXCEPTIONS@
+config.arm_ehabi                = @LIBUNWIND_USES_ARM_EHABI@
 config.host_triple              = "@LLVM_HOST_TRIPLE@"
 config.target_triple            = "@TARGET_TRIPLE@"
 config.use_target               = bool("@LIBUNWIND_TARGET_TRIPLE@")
diff --git a/test/signal_frame.pass.cpp b/test/signal_frame.pass.cpp
index a6f3f48..a899461 100644
--- a/test/signal_frame.pass.cpp
+++ b/test/signal_frame.pass.cpp
@@ -9,6 +9,8 @@
 
 // Ensure that functions marked as signal frames are reported as such.
 
+// UNSUPPORTED: libunwind-arm-ehabi
+
 #include <assert.h>
 #include <stdlib.h>
 #include <libunwind.h>
@@ -20,9 +22,7 @@
   unw_getcontext(&uc);
   unw_init_local(&cursor, &uc);
   assert(unw_step(&cursor) > 0);
-#if !defined(_LIBUNWIND_ARM_EHABI)
   assert(unw_is_signal_frame(&cursor));
-#endif
 }
 
 int main() {