summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Albert <danalbert@google.com>2017-12-13 23:58:08 +0000
committerandroid-build-merger <android-build-merger@google.com>2017-12-13 23:58:08 +0000
commitb92b9a89cb75cbbda26b53ca44b37354b51aca96 (patch)
treed1846b037ba06ce7fddc8446aeac680cf82b51c0
parent8eb95bd73a80b82d5071ff5e6d857639ca0bac71 (diff)
parent9ca0ad7a15a8b9868f22f67d13fe49a2d02601dc (diff)
downloadlibunwind_llvm-b92b9a89cb75cbbda26b53ca44b37354b51aca96.tar.gz
Merge to upstream r320528.
am: 9ca0ad7a15 Change-Id: I95e6c15c01b8f081e1eb7675e1f97b109e723118
-rw-r--r--CMakeLists.txt31
-rw-r--r--CREDITS.txt71
-rw-r--r--cmake/config-ix.cmake14
-rw-r--r--docs/conf.py4
-rw-r--r--docs/index.rst25
-rw-r--r--include/__libunwind_config.h56
-rw-r--r--include/libunwind.h62
-rw-r--r--include/unwind.h4
-rw-r--r--src/AddressSpace.hpp203
-rw-r--r--src/CMakeLists.txt27
-rw-r--r--src/DwarfInstructions.hpp2
-rw-r--r--src/DwarfParser.hpp21
-rw-r--r--src/EHHeaderParser.hpp4
-rw-r--r--src/RWMutex.hpp77
-rw-r--r--src/Registers.hpp497
-rw-r--r--src/Unwind-EHABI.cpp25
-rw-r--r--src/Unwind-sjlj.c66
-rw-r--r--src/UnwindCursor.hpp81
-rw-r--r--src/UnwindLevel1-gcc-ext.c8
-rw-r--r--src/UnwindLevel1.c42
-rw-r--r--src/UnwindRegistersRestore.S159
-rw-r--r--src/UnwindRegistersSave.S191
-rw-r--r--src/Unwind_AppleExtras.cpp30
-rw-r--r--src/assembly.h21
-rw-r--r--src/config.h40
-rw-r--r--src/libunwind.cpp14
-rw-r--r--src/unwind_ext.h37
-rw-r--r--test/CMakeLists.txt34
-rw-r--r--test/alignment.pass.cpp12
-rw-r--r--test/libunwind/__init__.py0
-rw-r--r--test/libunwind/test/__init__.py0
-rw-r--r--test/libunwind/test/config.py71
-rw-r--r--test/libunwind_02.pass.cpp1
-rw-r--r--test/lit.cfg67
-rw-r--r--test/lit.site.cfg.in27
35 files changed, 1627 insertions, 397 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 032df56..b28e4d0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -133,6 +133,9 @@ option(LIBUNWIND_ENABLE_THREADS "Build libunwind with threading support." ON)
option(LIBUNWIND_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
option(LIBUNWIND_INCLUDE_DOCS "Build the libunwind documentation." ${LLVM_INCLUDE_DOCS})
+set(LIBUNWIND_LIBDIR_SUFFIX "${LLVM_LIBDIR_SUFFIX}" CACHE STRING
+ "Define suffix of library directory name (32/64)")
+option(LIBUNWIND_INSTALL_LIBRARY "Install the libunwind library." ON)
set(LIBUNWIND_TARGET_TRIPLE "" CACHE STRING "Target triple for cross compiling.")
set(LIBUNWIND_GCC_TOOLCHAIN "" CACHE PATH "GCC toolchain for cross compiling.")
set(LIBUNWIND_SYSROOT "" CACHE PATH "Sysroot for cross compiling.")
@@ -162,7 +165,22 @@ set(CMAKE_MODULE_PATH
set(LIBUNWIND_COMPILER ${CMAKE_CXX_COMPILER})
set(LIBUNWIND_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LIBUNWIND_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
-set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LLVM_LIBDIR_SUFFIX})
+if (LLVM_LIBRARY_OUTPUT_INTDIR)
+ set(LIBUNWIND_LIBRARY_DIR ${LLVM_LIBRARY_OUTPUT_INTDIR})
+else()
+ set(LIBUNWIND_LIBRARY_DIR ${CMAKE_BINARY_DIR}/lib${LIBUNWIND_LIBDIR_SUFFIX})
+endif()
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${LIBUNWIND_LIBRARY_DIR})
+
+set(LIBUNWIND_INSTALL_PREFIX "" CACHE STRING
+ "Define libunwind destination prefix.")
+
+if (NOT LIBUNWIND_INSTALL_PREFIX MATCHES "^$|.*/")
+ message(FATAL_ERROR "LIBUNWIND_INSTALL_PREFIX has to end with \"/\".")
+endif()
set(LIBUNWIND_C_FLAGS "")
set(LIBUNWIND_CXX_FLAGS "")
@@ -193,6 +211,10 @@ add_target_flags_if(LIBUNWIND_GCC_TOOLCHAIN
add_target_flags_if(LIBUNWIND_SYSROOT
"--sysroot=${LIBUNWIND_SYSROOT}")
+if (LIBUNWIND_TARGET_TRIPLE)
+ set(TARGET_TRIPLE "${LIBUNWIND_TARGET_TRIPLE}")
+endif()
+
# Configure compiler.
include(config-ix)
@@ -290,6 +312,11 @@ if (MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif()
+# Disable DLL annotations on Windows for static builds.
+if (WIN32 AND LIBUNWIND_ENABLE_STATIC AND NOT LIBUNWIND_ENABLE_SHARED)
+ add_definitions(-D_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
+endif()
+
#===============================================================================
# Setup Source Code
#===============================================================================
@@ -321,3 +348,5 @@ add_subdirectory(src)
if (LIBUNWIND_INCLUDE_DOCS)
add_subdirectory(docs)
endif()
+
+add_subdirectory(test)
diff --git a/CREDITS.txt b/CREDITS.txt
deleted file mode 100644
index 9c910fc..0000000
--- a/CREDITS.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-This file is a partial list of people who have contributed to the LLVM/libc++abi
-project. If you have contributed a patch or made some other contribution to
-LLVM/libc++abi, please submit a patch to this file to add yourself, and it will be
-done!
-
-The list is sorted by surname and formatted to allow easy grepping and
-beautification by scripts. The fields are: name (N), email (E), web-address
-(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
-(S).
-
-N: Aaron Ballman
-E: aaron@aaronballman.com
-D: Minor patches
-
-N: Logan Chien
-E: logan.chien@mediatek.com
-D: ARM EHABI Unwind & Exception Handling
-
-N: Marshall Clow
-E: mclow.lists@gmail.com
-E: marshall@idio.com
-D: Architect and primary coauthor of libc++abi
-
-N: Matthew Dempsky
-E: matthew@dempsky.org
-D: Minor patches and bug fixes.
-
-N: Nowar Gu
-E: wenhan.gu@gmail.com
-D: Minor patches and fixes
-
-N: Howard Hinnant
-E: hhinnant@apple.com
-D: Architect and primary coauthor of libc++abi
-
-N: Dana Jansens
-E: danakj@chromium.org
-D: ARM EHABI Unwind & Exception Handling
-
-N: Nick Kledzik
-E: kledzik@apple.com
-
-N: Antoine Labour
-E: piman@chromium.org
-D: ARM EHABI Unwind & Exception Handling
-
-N: Bruce Mitchener, Jr.
-E: bruce.mitchener@gmail.com
-D: Minor typo fixes
-
-N: Andrew Morrow
-E: andrew.c.morrow@gmail.com
-D: Minor patches and fixes
-
-N: Erik Olofsson
-E: erik.olofsson@hansoft.se
-E: erik@olofsson.info
-D: Minor patches and fixes
-
-N: Jon Roelofs
-E: jonathan@codesourcery.com
-D: ARM EHABI Unwind & Exception Handling, Bare-metal
-
-N: Nico Weber
-E: thakis@chromium.org
-D: ARM EHABI Unwind & Exception Handling
-
-N: Albert J. Wong
-E: ajwong@google.com
-D: ARM EHABI Unwind & Exception Handling
-
diff --git a/cmake/config-ix.cmake b/cmake/config-ix.cmake
index 40a5dd1..2d4da64 100644
--- a/cmake/config-ix.cmake
+++ b/cmake/config-ix.cmake
@@ -29,6 +29,19 @@ if (LIBUNWIND_HAS_NODEFAULTLIBS_FLAG)
elseif (LIBUNWIND_HAS_GCC_S_LIB)
list(APPEND CMAKE_REQUIRED_LIBRARIES gcc_s)
endif ()
+ if (MINGW)
+ # Mingw64 requires quite a few "C" runtime libraries in order for basic
+ # programs to link successfully with -nodefaultlibs.
+ if (LIBUNWIND_USE_COMPILER_RT)
+ set(MINGW_RUNTIME ${LIBUNWIND_BUILTINS_LIBRARY})
+ else ()
+ set(MINGW_RUNTIME gcc_s gcc)
+ endif()
+ set(MINGW_LIBRARIES mingw32 ${MINGW_RUNTIME} moldname mingwex msvcrt advapi32
+ shell32 user32 kernel32 mingw32 ${MINGW_RUNTIME}
+ moldname mingwex msvcrt)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES ${MINGW_LIBRARIES})
+ endif()
if (CMAKE_C_FLAGS MATCHES -fsanitize OR CMAKE_CXX_FLAGS MATCHES -fsanitize)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-sanitize=all")
endif ()
@@ -39,7 +52,6 @@ endif ()
# Check compiler flags
check_c_compiler_flag(-funwind-tables LIBUNWIND_HAS_FUNWIND_TABLES)
-check_cxx_compiler_flag(-fPIC LIBUNWIND_HAS_FPIC_FLAG)
check_cxx_compiler_flag(-fno-exceptions LIBUNWIND_HAS_NO_EXCEPTIONS_FLAG)
check_cxx_compiler_flag(-fno-rtti LIBUNWIND_HAS_NO_RTTI_FLAG)
check_cxx_compiler_flag(-fstrict-aliasing LIBUNWIND_HAS_FSTRICT_ALIASING_FLAG)
diff --git a/docs/conf.py b/docs/conf.py
index 5a2f070..29c95f3 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -47,9 +47,9 @@ copyright = u'2011-2017, LLVM Project'
# built documents.
#
# The short X.Y version.
-version = '5.0'
+version = '6.0'
# The full version, including alpha/beta/rc tags.
-release = '5.0'
+release = '6.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/docs/index.rst b/docs/index.rst
index 7e0b600..7e7277e 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -15,7 +15,7 @@ that never materialized (e.g. remote unwinding).
The unwinder has two levels of API. The high level APIs are the `_Unwind_*`
functions which implement functionality required by `__cxa_*` exception
-funcionts. The low level APIs are the `unw_*` functions which are an interface
+functions. The low level APIs are the `unw_*` functions which are an interface
defined by the old HP libunwind project.
Getting Started with libunwind
@@ -41,16 +41,19 @@ Platform and Compiler Support
libunwind is known to work on the following platforms:
-============ ==================== ============ ========================
-OS Arch Compilers Unwind Info
-============ ==================== ============ ========================
-Mac OS X i386, x86_64 Clang, GCC DWARF CFI
-iOS ARM Clang SjLj
-Linux i386, x86_64 Clang, GCC DWARF CFI
-Linux ARM Clang, GCC EHABI
-Bare Metal ARM Clang, GCC EHABI
-NetBSD x86_64 Clang, GCC DWARF CFI
-============ ==================== ============ ========================
+============ ======================== ============ ========================
+OS Arch Compilers Unwind Info
+============ ======================== ============ ========================
+Any i386, x86_64, ARM Clang SjLj
+Bare Metal ARM Clang, GCC EHABI
+FreeBSD i386, x86_64, ARM64 Clang DWARF CFI
+iOS ARM Clang SjLj
+Linux ARM Clang, GCC EHABI
+Linux i386, x86_64, ARM64 Clang, GCC DWARF CFI
+Mac OS X i386, x86_64 Clang, GCC DWARF CFI
+NetBSD x86_64 Clang, GCC DWARF CFI
+Windows i386, x86_64, ARM, ARM64 Clang DWARF CFI
+============ ======================== ============ ========================
The following minimum compiler versions are strongly recommended.
diff --git a/include/__libunwind_config.h b/include/__libunwind_config.h
index 83f4f47..69a4996 100644
--- a/include/__libunwind_config.h
+++ b/include/__libunwind_config.h
@@ -15,42 +15,68 @@
#define _LIBUNWIND_ARM_EHABI
#endif
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86 8
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64 32
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC 112
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 31
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
+
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__i386__)
# define _LIBUNWIND_TARGET_I386
# define _LIBUNWIND_CONTEXT_SIZE 8
-# define _LIBUNWIND_CURSOR_SIZE 19
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 9
+# define _LIBUNWIND_CURSOR_SIZE 15
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86
# elif defined(__x86_64__)
# define _LIBUNWIND_TARGET_X86_64 1
-# define _LIBUNWIND_CONTEXT_SIZE 21
-# define _LIBUNWIND_CURSOR_SIZE 33
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 17
+# if defined(_WIN64)
+# define _LIBUNWIND_CONTEXT_SIZE 54
+# define _LIBUNWIND_CURSOR_SIZE 66
+# else
+# define _LIBUNWIND_CONTEXT_SIZE 21
+# define _LIBUNWIND_CURSOR_SIZE 33
+# endif
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64
# elif defined(__ppc__)
# define _LIBUNWIND_TARGET_PPC 1
# define _LIBUNWIND_CONTEXT_SIZE 117
-# define _LIBUNWIND_CURSOR_SIZE 128
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 113
+# define _LIBUNWIND_CURSOR_SIZE 124
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
# elif defined(__aarch64__)
# define _LIBUNWIND_TARGET_AARCH64 1
# define _LIBUNWIND_CONTEXT_SIZE 66
# define _LIBUNWIND_CURSOR_SIZE 78
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 96
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
# elif defined(__arm__)
# define _LIBUNWIND_TARGET_ARM 1
# if defined(__ARM_WMMX)
-# define _LIBUNWIND_CONTEXT_SIZE 60
-# define _LIBUNWIND_CURSOR_SIZE 67
+# define _LIBUNWIND_CONTEXT_SIZE 61
+# define _LIBUNWIND_CURSOR_SIZE 68
# else
# define _LIBUNWIND_CONTEXT_SIZE 42
# define _LIBUNWIND_CURSOR_SIZE 49
# endif
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 96
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM
# elif defined(__or1k__)
# define _LIBUNWIND_TARGET_OR1K 1
# define _LIBUNWIND_CONTEXT_SIZE 16
-# define _LIBUNWIND_CURSOR_SIZE 28
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 32
+# define _LIBUNWIND_CURSOR_SIZE 24
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
+# elif defined(__mips__)
+# if defined(_ABIO32) && defined(__mips_soft_float)
+# define _LIBUNWIND_TARGET_MIPS_O32 1
+# define _LIBUNWIND_CONTEXT_SIZE 18
+# define _LIBUNWIND_CURSOR_SIZE 24
+# elif defined(_ABI64) && defined(__mips_soft_float)
+# define _LIBUNWIND_TARGET_MIPS_N64 1
+# define _LIBUNWIND_CONTEXT_SIZE 35
+# define _LIBUNWIND_CURSOR_SIZE 47
+# else
+# error "Unsupported MIPS ABI and/or environment"
+# endif
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
# else
# error "Unsupported architecture."
# endif
@@ -61,9 +87,11 @@
# define _LIBUNWIND_TARGET_AARCH64 1
# define _LIBUNWIND_TARGET_ARM 1
# define _LIBUNWIND_TARGET_OR1K 1
+# define _LIBUNWIND_TARGET_MIPS_O32 1
+# define _LIBUNWIND_TARGET_MIPS_N64 1
# define _LIBUNWIND_CONTEXT_SIZE 128
# define _LIBUNWIND_CURSOR_SIZE 140
-# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 120
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
#endif // _LIBUNWIND_IS_NATIVE_ONLY
#endif // ____LIBUNWIND_CONFIG_H__
diff --git a/include/libunwind.h b/include/libunwind.h
index cd09037..9011d55 100644
--- a/include/libunwind.h
+++ b/include/libunwind.h
@@ -72,11 +72,10 @@ typedef struct unw_cursor_t unw_cursor_t;
typedef struct unw_addr_space *unw_addr_space_t;
typedef int unw_regnum_t;
-#if defined(_LIBUNWIND_ARM_EHABI)
-typedef uint32_t unw_word_t;
+typedef uintptr_t unw_word_t;
+#if defined(__arm__)
typedef uint64_t unw_fpreg_t;
#else
-typedef uint64_t unw_word_t;
typedef double unw_fpreg_t;
#endif
@@ -188,7 +187,24 @@ enum {
UNW_X86_64_R12 = 12,
UNW_X86_64_R13 = 13,
UNW_X86_64_R14 = 14,
- UNW_X86_64_R15 = 15
+ UNW_X86_64_R15 = 15,
+ UNW_X86_64_RIP = 16,
+ UNW_X86_64_XMM0 = 17,
+ UNW_X86_64_XMM1 = 18,
+ UNW_X86_64_XMM2 = 19,
+ UNW_X86_64_XMM3 = 20,
+ UNW_X86_64_XMM4 = 21,
+ UNW_X86_64_XMM5 = 22,
+ UNW_X86_64_XMM6 = 23,
+ UNW_X86_64_XMM7 = 24,
+ UNW_X86_64_XMM8 = 25,
+ UNW_X86_64_XMM9 = 26,
+ UNW_X86_64_XMM10 = 27,
+ UNW_X86_64_XMM11 = 28,
+ UNW_X86_64_XMM12 = 29,
+ UNW_X86_64_XMM13 = 30,
+ UNW_X86_64_XMM14 = 31,
+ UNW_X86_64_XMM15 = 32,
};
@@ -547,4 +563,42 @@ enum {
UNW_OR1K_R31 = 31,
};
+// MIPS registers
+enum {
+ UNW_MIPS_R0 = 0,
+ UNW_MIPS_R1 = 1,
+ UNW_MIPS_R2 = 2,
+ UNW_MIPS_R3 = 3,
+ UNW_MIPS_R4 = 4,
+ UNW_MIPS_R5 = 5,
+ UNW_MIPS_R6 = 6,
+ UNW_MIPS_R7 = 7,
+ UNW_MIPS_R8 = 8,
+ UNW_MIPS_R9 = 9,
+ UNW_MIPS_R10 = 10,
+ UNW_MIPS_R11 = 11,
+ UNW_MIPS_R12 = 12,
+ UNW_MIPS_R13 = 13,
+ UNW_MIPS_R14 = 14,
+ UNW_MIPS_R15 = 15,
+ UNW_MIPS_R16 = 16,
+ UNW_MIPS_R17 = 17,
+ UNW_MIPS_R18 = 18,
+ UNW_MIPS_R19 = 19,
+ UNW_MIPS_R20 = 20,
+ UNW_MIPS_R21 = 21,
+ UNW_MIPS_R22 = 22,
+ UNW_MIPS_R23 = 23,
+ UNW_MIPS_R24 = 24,
+ UNW_MIPS_R25 = 25,
+ UNW_MIPS_R26 = 26,
+ UNW_MIPS_R27 = 27,
+ UNW_MIPS_R28 = 28,
+ UNW_MIPS_R29 = 29,
+ UNW_MIPS_R30 = 30,
+ UNW_MIPS_R31 = 31,
+ UNW_MIPS_HI = 64,
+ UNW_MIPS_LO = 65,
+};
+
#endif
diff --git a/include/unwind.h b/include/unwind.h
index fc7d122..0ab87dd 100644
--- a/include/unwind.h
+++ b/include/unwind.h
@@ -100,7 +100,7 @@ struct _Unwind_Control_Block {
} pr_cache;
long long int :0; /* Enforce the 8-byte alignment */
-};
+} __attribute__((__aligned__(8)));
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
(_Unwind_State state,
@@ -122,7 +122,7 @@ struct _Unwind_Exception {
_Unwind_Exception *exc);
uintptr_t private_1; // non-zero means forced unwind
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
-#ifndef __LP64__
+#if __SIZEOF_POINTER__ == 4
// The implementation of _Unwind_Exception uses an attribute mode on the
// above fields which has the side effect of causing this whole struct to
// round up to 32 bytes in size. To be more explicit, we add pad fields
diff --git a/src/AddressSpace.hpp b/src/AddressSpace.hpp
index 402cfe0..2be16af 100644
--- a/src/AddressSpace.hpp
+++ b/src/AddressSpace.hpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
#include <string.h>
-#ifndef _LIBUNWIND_IS_BAREMETAL
+#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
#include <dlfcn.h>
#endif
@@ -35,6 +35,80 @@ namespace libunwind {
#include "EHHeaderParser.hpp"
#include "Registers.hpp"
+#ifdef __APPLE__
+
+ struct dyld_unwind_sections
+ {
+ const struct mach_header* mh;
+ const void* dwarf_section;
+ uintptr_t dwarf_section_length;
+ const void* compact_unwind_section;
+ uintptr_t compact_unwind_section_length;
+ };
+ #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
+ && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
+ || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+ // In 10.7.0 or later, libSystem.dylib implements this function.
+ extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
+ #else
+ // In 10.6.x and earlier, we need to implement this functionality. Note
+ // that this requires a newer version of libmacho (from cctools) than is
+ // present in libSystem on 10.6.x (for getsectiondata).
+ static inline bool _dyld_find_unwind_sections(void* addr,
+ dyld_unwind_sections* info) {
+ // Find mach-o image containing address.
+ Dl_info dlinfo;
+ if (!dladdr(addr, &dlinfo))
+ return false;
+#if __LP64__
+ const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
+#else
+ const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
+#endif
+
+ // Initialize the return struct
+ info->mh = (const struct mach_header *)mh;
+ info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
+ info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
+
+ if (!info->dwarf_section) {
+ info->dwarf_section_length = 0;
+ }
+
+ if (!info->compact_unwind_section) {
+ info->compact_unwind_section_length = 0;
+ }
+
+ return true;
+ }
+ #endif
+
+#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
+
+// When statically linked on bare-metal, the symbols for the EH table are looked
+// up without going through the dynamic loader.
+extern char __exidx_start;
+extern char __exidx_end;
+
+#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+// ELF-based systems may use dl_iterate_phdr() to access sections
+// containing unwinding information. The ElfW() macro for pointer-size
+// independent ELF header traversal is not provided by <link.h> on some
+// systems (e.g., FreeBSD). On these systems the data structures are
+// just called Elf_XXX. Define ElfW() locally.
+#ifndef _WIN32
+#include <link.h>
+#else
+#include <windows.h>
+#include <psapi.h>
+#endif
+#if !defined(ElfW)
+#define ElfW(type) Elf_##type
+#endif
+
+#endif
+
namespace libunwind {
/// Used by findUnwindSections() to return info about needed sections.
@@ -68,13 +142,8 @@ struct UnwindInfoSections {
/// making local unwinds fast.
class __attribute__((visibility("hidden"))) LocalAddressSpace {
public:
-#ifdef __LP64__
- typedef uint64_t pint_t;
- typedef int64_t sint_t;
-#else
- typedef uint32_t pint_t;
- typedef int32_t sint_t;
-#endif
+ typedef uintptr_t pint_t;
+ typedef intptr_t sint_t;
uint8_t get8(pint_t addr) {
uint8_t val;
memcpy(&val, (void *)addr, sizeof(val));
@@ -120,7 +189,7 @@ public:
};
inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
-#ifdef __LP64__
+#if __SIZEOF_POINTER__ == 8
return get64(addr);
#else
return get32(addr);
@@ -168,7 +237,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
} while (byte & 0x80);
// sign extend negative numbers
if ((byte & 0x40) != 0)
- result |= (-1LL) << bit;
+ result |= (-1ULL) << bit;
addr = (pint_t) p;
return result;
}
@@ -265,75 +334,6 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
return result;
}
-#ifdef __APPLE__
-
- struct dyld_unwind_sections
- {
- const struct mach_header* mh;
- const void* dwarf_section;
- uintptr_t dwarf_section_length;
- const void* compact_unwind_section;
- uintptr_t compact_unwind_section_length;
- };
- #if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) \
- && (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)) \
- || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
- // In 10.7.0 or later, libSystem.dylib implements this function.
- extern "C" bool _dyld_find_unwind_sections(void *, dyld_unwind_sections *);
- #else
- // In 10.6.x and earlier, we need to implement this functionality. Note
- // that this requires a newer version of libmacho (from cctools) than is
- // present in libSystem on 10.6.x (for getsectiondata).
- static inline bool _dyld_find_unwind_sections(void* addr,
- dyld_unwind_sections* info) {
- // Find mach-o image containing address.
- Dl_info dlinfo;
- if (!dladdr(addr, &dlinfo))
- return false;
-#if __LP64__
- const struct mach_header_64 *mh = (const struct mach_header_64 *)dlinfo.dli_fbase;
-#else
- const struct mach_header *mh = (const struct mach_header *)dlinfo.dli_fbase;
-#endif
-
- // Initialize the return struct
- info->mh = (const struct mach_header *)mh;
- info->dwarf_section = getsectiondata(mh, "__TEXT", "__eh_frame", &info->dwarf_section_length);
- info->compact_unwind_section = getsectiondata(mh, "__TEXT", "__unwind_info", &info->compact_unwind_section_length);
-
- if (!info->dwarf_section) {
- info->dwarf_section_length = 0;
- }
-
- if (!info->compact_unwind_section) {
- info->compact_unwind_section_length = 0;
- }
-
- return true;
- }
- #endif
-
-#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
-
-// When statically linked on bare-metal, the symbols for the EH table are looked
-// up without going through the dynamic loader.
-extern char __exidx_start;
-extern char __exidx_end;
-
-#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-
-// ELF-based systems may use dl_iterate_phdr() to access sections
-// containing unwinding information. The ElfW() macro for pointer-size
-// independent ELF header traversal is not provided by <link.h> on some
-// systems (e.g., FreeBSD). On these systems the data structures are
-// just called Elf_XXX. Define ElfW() locally.
-#include <link.h>
-#if !defined(ElfW)
-#define ElfW(type) Elf_##type
-#endif
-
-#endif
-
inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
UnwindInfoSections &info) {
#ifdef __APPLE__
@@ -356,6 +356,49 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
info.arm_section, info.arm_section_length);
if (info.arm_section && info.arm_section_length)
return true;
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_WIN32)
+ HMODULE mods[1024];
+ HANDLE process = GetCurrentProcess();
+ DWORD needed;
+
+ if (!EnumProcessModules(process, mods, sizeof(mods), &needed))
+ return false;
+
+ for (unsigned i = 0; i < (needed / sizeof(HMODULE)); i++) {
+ PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)mods[i];
+ PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE *)pidh + pidh->e_lfanew);
+ PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
+ PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh);
+ bool found_obj = false;
+ bool found_hdr = false;
+
+ info.dso_base = (uintptr_t)mods[i];
+ for (unsigned j = 0; j < pifh->NumberOfSections; j++, pish++) {
+ uintptr_t begin = pish->VirtualAddress + (uintptr_t)mods[i];
+ uintptr_t end = begin + pish->Misc.VirtualSize;
+ if (!strncmp((const char *)pish->Name, ".text",
+ IMAGE_SIZEOF_SHORT_NAME)) {
+ if (targetAddr >= begin && targetAddr < end)
+ found_obj = true;
+ } else if (!strncmp((const char *)pish->Name, ".eh_frame",
+ IMAGE_SIZEOF_SHORT_NAME)) {
+ info.dwarf_section = begin;
+ info.dwarf_section_length = pish->Misc.VirtualSize;
+ found_hdr = true;
+ }
+ if (found_obj && found_hdr)
+ return true;
+ }
+ }
+ return false;
+#elif defined(_LIBUNWIND_ARM_EHABI) && defined(__BIONIC__) && \
+ (__ANDROID_API__ < 21)
+ int length = 0;
+ info.arm_section =
+ (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
+ info.arm_section_length = (uintptr_t)length;
+ if (info.arm_section && info.arm_section_length)
+ return true;
#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
struct dl_iterate_cb_data {
LocalAddressSpace *addressSpace;
@@ -478,7 +521,7 @@ inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
size_t bufLen,
unw_word_t *offset) {
-#ifndef _LIBUNWIND_IS_BAREMETAL
+#if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
Dl_info dyldInfo;
if (dladdr((void *)addr, &dyldInfo)) {
if (dyldInfo.dli_sname != NULL) {
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 0c78523..2d2ec13 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -30,8 +30,8 @@ set(LIBUNWIND_HEADERS
DwarfParser.hpp
libunwind_ext.h
Registers.hpp
+ RWMutex.hpp
UnwindCursor.hpp
- unwind_ext.h
${CMAKE_CURRENT_SOURCE_DIR}/../include/libunwind.h
${CMAKE_CURRENT_SOURCE_DIR}/../include/unwind.h)
@@ -58,7 +58,6 @@ if (LIBUNWIND_ENABLE_THREADS)
endif()
# Setup flags.
-append_if(LIBUNWIND_COMPILE_FLAGS LIBUNWIND_HAS_FPIC_FLAG -fPIC)
append_if(LIBUNWIND_CXX_FLAGS LIBUNWIND_HAS_NO_RTTI_FLAG -fno-rtti)
append_if(LIBUNWIND_LINK_FLAGS LIBUNWIND_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs)
@@ -101,7 +100,8 @@ add_library(unwind_objects OBJECT ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS})
set_target_properties(unwind_objects
PROPERTIES
- COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}")
+ COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}"
+ POSITION_INDEPENDENT_CODE ON)
set(LIBUNWIND_TARGETS)
@@ -132,7 +132,22 @@ endif()
# Add a meta-target for both libraries.
add_custom_target(unwind DEPENDS ${LIBUNWIND_TARGETS})
-install(TARGETS ${LIBUNWIND_TARGETS}
- LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
- ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
+if (LIBUNWIND_INSTALL_LIBRARY)
+ install(TARGETS ${LIBUNWIND_TARGETS}
+ LIBRARY DESTINATION ${LIBUNWIND_INSTALL_PREFIX}lib${LIBUNWIND_LIBDIR_SUFFIX} COMPONENT unwind
+ ARCHIVE DESTINATION ${LIBUNWIND_INSTALL_PREFIX}lib${LIBUNWIND_LIBDIR_SUFFIX} COMPONENT unwind)
+endif()
+if (NOT CMAKE_CONFIGURATION_TYPES AND LIBUNWIND_INSTALL_LIBRARY)
+ add_custom_target(install-unwind
+ DEPENDS unwind
+ COMMAND "${CMAKE_COMMAND}"
+ -DCMAKE_INSTALL_COMPONENT=unwind
+ -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake")
+ add_custom_target(install-unwind-stripped
+ DEPENDS unwind
+ COMMAND "${CMAKE_COMMAND}"
+ -DCMAKE_INSTALL_COMPONENT=unwind
+ -DCMAKE_INSTALL_DO_STRIP=1
+ -P "${LIBUNWIND_BINARY_DIR}/cmake_install.cmake")
+endif()
diff --git a/src/DwarfInstructions.hpp b/src/DwarfInstructions.hpp
index a428633..bd1448b 100644
--- a/src/DwarfInstructions.hpp
+++ b/src/DwarfInstructions.hpp
@@ -167,7 +167,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
R newRegisters = registers;
pint_t returnAddress = 0;
const int lastReg = R::lastDwarfRegNum();
- assert((int)CFI_Parser<A>::kMaxRegisterNumber > lastReg &&
+ assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
"register range too large");
assert(lastReg >= (int)cieInfo.returnAddressRegister &&
"register range does not contain return address register");
diff --git a/src/DwarfParser.hpp b/src/DwarfParser.hpp
index 3c98d30..95af7a6 100644
--- a/src/DwarfParser.hpp
+++ b/src/DwarfParser.hpp
@@ -87,7 +87,7 @@ public:
uint32_t codeOffsetAtStackDecrement;
bool registersInOtherRegisters;
bool sameValueUsed;
- RegisterLocation savedRegisters[kMaxRegisterNumber];
+ RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
};
struct PrologInfoStackEntry {
@@ -605,6 +605,13 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
break;
case DW_CFA_val_offset:
reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_val_offset DWARF unwind, reg (%" PRIu64
+ ") out of range\n",
+ reg);
+ return false;
+ }
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
@@ -668,6 +675,12 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
switch (opcode & 0xC0) {
case DW_CFA_offset:
reg = operand;
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr, "malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
+ ") out of range\n",
+ reg);
+ return false;
+ }
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterInCFA;
@@ -682,6 +695,12 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
break;
case DW_CFA_restore:
reg = operand;
+ if (reg > kMaxRegisterNumber) {
+ fprintf(stderr, "malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
+ ") out of range\n",
+ reg);
+ return false;
+ }
results->savedRegisters[reg] = initialState.savedRegisters[reg];
_LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
static_cast<uint64_t>(operand));
diff --git a/src/EHHeaderParser.hpp b/src/EHHeaderParser.hpp
index c66af21..9bdaf55 100644
--- a/src/EHHeaderParser.hpp
+++ b/src/EHHeaderParser.hpp
@@ -67,7 +67,9 @@ void EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
ehHdrInfo.eh_frame_ptr =
addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
ehHdrInfo.fde_count =
- addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
+ fde_count_enc == DW_EH_PE_omit
+ ? 0
+ : addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
ehHdrInfo.table = p;
}
diff --git a/src/RWMutex.hpp b/src/RWMutex.hpp
new file mode 100644
index 0000000..50a78a5
--- /dev/null
+++ b/src/RWMutex.hpp
@@ -0,0 +1,77 @@
+//===----------------------------- Registers.hpp --------------------------===//
+//
+// 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.
+//
+//
+// Abstract interface to shared reader/writer log, hiding platform and
+// configuration differences.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __RWMUTEX_HPP__
+#define __RWMUTEX_HPP__
+
+#if defined(_WIN32)
+#include <windows.h>
+#elif !defined(_LIBUNWIND_HAS_NO_THREADS)
+#include <pthread.h>
+#endif
+
+namespace libunwind {
+
+#if defined(_LIBUNWIND_HAS_NO_THREADS)
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+ bool lock_shared() { return true; }
+ bool unlock_shared() { return true; }
+ bool lock() { return true; }
+ bool unlock() { return true; }
+};
+
+#elif defined(_WIN32)
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+ bool lock_shared() {
+ AcquireSRWLockShared(&_lock);
+ return true;
+ }
+ bool unlock_shared() {
+ ReleaseSRWLockShared(&_lock);
+ return true;
+ }
+ bool lock() {
+ AcquireSRWLockExclusive(&_lock);
+ return true;
+ }
+ bool unlock() {
+ ReleaseSRWLockExclusive(&_lock);
+ return true;
+ }
+
+private:
+ SRWLOCK _lock = SRWLOCK_INIT;
+};
+
+#else
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+ bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; }
+ bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; }
+ bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; }
+ bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; }
+
+private:
+ pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
+};
+
+#endif
+
+} // namespace libunwind
+
+#endif // __RWMUTEX_HPP__
diff --git a/src/Registers.hpp b/src/Registers.hpp
index ff57c60..d881e20 100644
--- a/src/Registers.hpp
+++ b/src/Registers.hpp
@@ -44,7 +44,7 @@ public:
void setVectorRegister(int num, v128 value);
const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 8; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
uint32_t getSP() const { return _registers.__esp; }
void setSP(uint32_t value) { _registers.__esp = value; }
@@ -245,12 +245,12 @@ public:
bool validFloatRegister(int) const { return false; }
double getFloatRegister(int num) const;
void setFloatRegister(int num, double value);
- bool validVectorRegister(int) const { return false; }
+ bool validVectorRegister(int) const;
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 16; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
uint64_t getSP() const { return _registers.__rsp; }
void setSP(uint64_t value) { _registers.__rsp = value; }
@@ -292,8 +292,14 @@ private:
uint64_t __cs;
uint64_t __fs;
uint64_t __gs;
+#if defined(_WIN64)
+ uint64_t __padding; // 16-byte align
+#endif
};
GPRs _registers;
+#if defined(_WIN64)
+ v128 _xmm[16];
+#endif
};
inline Registers_x86_64::Registers_x86_64(const void *registers) {
@@ -458,6 +464,38 @@ inline const char *Registers_x86_64::getRegisterName(int regNum) {
return "r14";
case UNW_X86_64_R15:
return "r15";
+ case UNW_X86_64_XMM0:
+ return "xmm0";
+ case UNW_X86_64_XMM1:
+ return "xmm1";
+ case UNW_X86_64_XMM2:
+ return "xmm2";
+ case UNW_X86_64_XMM3:
+ return "xmm3";
+ case UNW_X86_64_XMM4:
+ return "xmm4";
+ case UNW_X86_64_XMM5:
+ return "xmm5";
+ case UNW_X86_64_XMM6:
+ return "xmm6";
+ case UNW_X86_64_XMM7:
+ return "xmm7";
+ case UNW_X86_64_XMM8:
+ return "xmm8";
+ case UNW_X86_64_XMM9:
+ return "xmm9";
+ case UNW_X86_64_XMM10:
+ return "xmm10";
+ case UNW_X86_64_XMM11:
+ return "xmm11";
+ case UNW_X86_64_XMM12:
+ return "xmm12";
+ case UNW_X86_64_XMM13:
+ return "xmm13";
+ case UNW_X86_64_XMM14:
+ return "xmm14";
+ case UNW_X86_64_XMM15:
+ return "xmm15";
default:
return "unknown register";
}
@@ -471,12 +509,34 @@ inline void Registers_x86_64::setFloatRegister(int, double) {
_LIBUNWIND_ABORT("no x86_64 float registers");
}
-inline v128 Registers_x86_64::getVectorRegister(int) const {
+inline bool Registers_x86_64::validVectorRegister(int regNum) const {
+#if defined(_WIN64)
+ if (regNum < UNW_X86_64_XMM0)
+ return false;
+ if (regNum > UNW_X86_64_XMM15)
+ return false;
+ return true;
+#else
+ return false;
+#endif
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int regNum) const {
+#if defined(_WIN64)
+ assert(validVectorRegister(regNum));
+ return _xmm[regNum - UNW_X86_64_XMM0];
+#else
_LIBUNWIND_ABORT("no x86_64 vector registers");
+#endif
}
-inline void Registers_x86_64::setVectorRegister(int, v128) {
+inline void Registers_x86_64::setVectorRegister(int regNum, v128 value) {
+#if defined(_WIN64)
+ assert(validVectorRegister(regNum));
+ _xmm[regNum - UNW_X86_64_XMM0] = value;
+#else
_LIBUNWIND_ABORT("no x86_64 vector registers");
+#endif
}
#endif // _LIBUNWIND_TARGET_X86_64
@@ -500,7 +560,7 @@ public:
void setVectorRegister(int num, v128 value);
const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 112; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; }
uint64_t getSP() const { return _registers.__r1; }
void setSP(uint32_t value) { _registers.__r1 = value; }
@@ -1066,7 +1126,7 @@ public:
void setVectorRegister(int num, v128 value);
const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 95; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
uint64_t getSP() const { return _registers.__sp; }
void setSP(uint64_t value) { _registers.__sp = value; }
@@ -1326,7 +1386,7 @@ public:
Registers_arm(const void *registers);
bool validRegister(int num) const;
- uint32_t getRegister(int num);
+ uint32_t getRegister(int num) const;
void setRegister(int num, uint32_t value);
bool validFloatRegister(int num) const;
unw_fpreg_t getFloatRegister(int num);
@@ -1339,6 +1399,7 @@ public:
restoreSavedFloatRegisters();
restoreCoreAndJumpTo();
}
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }
uint32_t getSP() const { return _registers.__sp; }
void setSP(uint32_t value) { _registers.__sp = value; }
@@ -1412,11 +1473,11 @@ private:
// Whether iWMMX data registers are saved.
bool _saved_iwmmx;
// Whether iWMMX control registers are saved.
- bool _saved_iwmmx_control;
+ mutable bool _saved_iwmmx_control;
// iWMMX registers
unw_fpreg_t _iwmmx[16];
// iWMMX control registers
- uint32_t _iwmmx_control[4];
+ mutable uint32_t _iwmmx_control[4];
#endif
};
@@ -1473,7 +1534,7 @@ inline bool Registers_arm::validRegister(int regNum) const {
return false;
}
-inline uint32_t Registers_arm::getRegister(int regNum) {
+inline uint32_t Registers_arm::getRegister(int regNum) const {
if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
return _registers.__sp;
@@ -1815,7 +1876,7 @@ public:
void setVectorRegister(int num, v128 value);
const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 31; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; }
uint64_t getSP() const { return _registers.__r[1]; }
void setSP(uint32_t value) { _registers.__r[1] = value; }
@@ -1980,6 +2041,418 @@ inline const char *Registers_or1k::getRegisterName(int regNum) {
}
#endif // _LIBUNWIND_TARGET_OR1K
+
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+/// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS
+/// process.
+class _LIBUNWIND_HIDDEN Registers_mips_o32 {
+public:
+ Registers_mips_o32();
+ Registers_mips_o32(const void *registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+
+ uint32_t getSP() const { return _registers.__r[29]; }
+ void setSP(uint32_t value) { _registers.__r[29] = value; }
+ uint32_t getIP() const { return _registers.__pc; }
+ void setIP(uint32_t value) { _registers.__pc = value; }
+
+private:
+ struct mips_o32_thread_state_t {
+ uint32_t __r[32];
+ uint32_t __pc;
+ uint32_t __hi;
+ uint32_t __lo;
+ };
+
+ mips_o32_thread_state_t _registers;
+};
+
+inline Registers_mips_o32::Registers_mips_o32(const void *registers) {
+ static_assert((check_fit<Registers_mips_o32, unw_context_t>::does_fit),
+ "mips_o32 registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast<const uint8_t *>(registers),
+ sizeof(_registers));
+}
+
+inline Registers_mips_o32::Registers_mips_o32() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_mips_o32::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum <= UNW_MIPS_R31)
+ return true;
+ if (regNum == UNW_MIPS_HI)
+ return true;
+ if (regNum == UNW_MIPS_LO)
+ return true;
+ // FIXME: Hard float, DSP accumulator registers, MSA registers
+ return false;
+}
+
+inline uint32_t Registers_mips_o32::getRegister(int regNum) const {
+ if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31)
+ return _registers.__r[regNum - UNW_MIPS_R0];
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__pc;
+ case UNW_REG_SP:
+ return _registers.__r[29];
+ case UNW_MIPS_HI:
+ return _registers.__hi;
+ case UNW_MIPS_LO:
+ return _registers.__lo;
+ }
+ _LIBUNWIND_ABORT("unsupported mips_o32 register");
+}
+
+inline void Registers_mips_o32::setRegister(int regNum, uint32_t value) {
+ if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) {
+ _registers.__r[regNum - UNW_MIPS_R0] = value;
+ return;
+ }
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__pc = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__r[29] = value;
+ return;
+ case UNW_MIPS_HI:
+ _registers.__hi = value;
+ return;
+ case UNW_MIPS_LO:
+ _registers.__lo = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported mips_o32 register");
+}
+
+inline bool Registers_mips_o32::validFloatRegister(int /* regNum */) const {
+ return false;
+}
+
+inline double Registers_mips_o32::getFloatRegister(int /* regNum */) const {
+ _LIBUNWIND_ABORT("mips_o32 float support not implemented");
+}
+
+inline void Registers_mips_o32::setFloatRegister(int /* regNum */,
+ double /* value */) {
+ _LIBUNWIND_ABORT("mips_o32 float support not implemented");
+}
+
+inline bool Registers_mips_o32::validVectorRegister(int /* regNum */) const {
+ return false;
+}
+
+inline v128 Registers_mips_o32::getVectorRegister(int /* regNum */) const {
+ _LIBUNWIND_ABORT("mips_o32 vector support not implemented");
+}
+
+inline void Registers_mips_o32::setVectorRegister(int /* regNum */, v128 /* value */) {
+ _LIBUNWIND_ABORT("mips_o32 vector support not implemented");
+}
+
+inline const char *Registers_mips_o32::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_MIPS_R0:
+ return "$0";
+ case UNW_MIPS_R1:
+ return "$1";
+ case UNW_MIPS_R2:
+ return "$2";
+ case UNW_MIPS_R3:
+ return "$3";
+ case UNW_MIPS_R4:
+ return "$4";
+ case UNW_MIPS_R5:
+ return "$5";
+ case UNW_MIPS_R6:
+ return "$6";
+ case UNW_MIPS_R7:
+ return "$7";
+ case UNW_MIPS_R8:
+ return "$8";
+ case UNW_MIPS_R9:
+ return "$9";
+ case UNW_MIPS_R10:
+ return "$10";
+ case UNW_MIPS_R11:
+ return "$11";
+ case UNW_MIPS_R12:
+ return "$12";
+ case UNW_MIPS_R13:
+ return "$13";
+ case UNW_MIPS_R14:
+ return "$14";
+ case UNW_MIPS_R15:
+ return "$15";
+ case UNW_MIPS_R16:
+ return "$16";
+ case UNW_MIPS_R17:
+ return "$17";
+ case UNW_MIPS_R18:
+ return "$18";
+ case UNW_MIPS_R19:
+ return "$19";
+ case UNW_MIPS_R20:
+ return "$20";
+ case UNW_MIPS_R21:
+ return "$21";
+ case UNW_MIPS_R22:
+ return "$22";
+ case UNW_MIPS_R23:
+ return "$23";
+ case UNW_MIPS_R24:
+ return "$24";
+ case UNW_MIPS_R25:
+ return "$25";
+ case UNW_MIPS_R26:
+ return "$26";
+ case UNW_MIPS_R27:
+ return "$27";
+ case UNW_MIPS_R28:
+ return "$28";
+ case UNW_MIPS_R29:
+ return "$29";
+ case UNW_MIPS_R30:
+ return "$30";
+ case UNW_MIPS_R31:
+ return "$31";
+ case UNW_MIPS_HI:
+ return "$hi";
+ case UNW_MIPS_LO:
+ return "$lo";
+ default:
+ return "unknown register";
+ }
+}
+#endif // _LIBUNWIND_TARGET_MIPS_O32
+
+#if defined(_LIBUNWIND_TARGET_MIPS_N64)
+/// Registers_mips_n64 holds the register state of a thread in a 64-bit MIPS
+/// process.
+class _LIBUNWIND_HIDDEN Registers_mips_n64 {
+public:
+ Registers_mips_n64();
+ Registers_mips_n64(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+
+ uint64_t getSP() const { return _registers.__r[29]; }
+ void setSP(uint64_t value) { _registers.__r[29] = value; }
+ uint64_t getIP() const { return _registers.__pc; }
+ void setIP(uint64_t value) { _registers.__pc = value; }
+
+private:
+ struct mips_n64_thread_state_t {
+ uint64_t __r[32];
+ uint64_t __pc;
+ uint64_t __hi;
+ uint64_t __lo;
+ };
+
+ mips_n64_thread_state_t _registers;
+};
+
+inline Registers_mips_n64::Registers_mips_n64(const void *registers) {
+ static_assert((check_fit<Registers_mips_n64, unw_context_t>::does_fit),
+ "mips_n64 registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast<const uint8_t *>(registers),
+ sizeof(_registers));
+}
+
+inline Registers_mips_n64::Registers_mips_n64() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_mips_n64::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum <= UNW_MIPS_R31)
+ return true;
+ if (regNum == UNW_MIPS_HI)
+ return true;
+ if (regNum == UNW_MIPS_LO)
+ return true;
+ // FIXME: Hard float, DSP accumulator registers, MSA registers
+ return false;
+}
+
+inline uint64_t Registers_mips_n64::getRegister(int regNum) const {
+ if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31)
+ return _registers.__r[regNum - UNW_MIPS_R0];
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__pc;
+ case UNW_REG_SP:
+ return _registers.__r[29];
+ case UNW_MIPS_HI:
+ return _registers.__hi;
+ case UNW_MIPS_LO:
+ return _registers.__lo;
+ }
+ _LIBUNWIND_ABORT("unsupported mips_n64 register");
+}
+
+inline void Registers_mips_n64::setRegister(int regNum, uint64_t value) {
+ if (regNum >= UNW_MIPS_R0 && regNum <= UNW_MIPS_R31) {
+ _registers.__r[regNum - UNW_MIPS_R0] = value;
+ return;
+ }
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__pc = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__r[29] = value;
+ return;
+ case UNW_MIPS_HI:
+ _registers.__hi = value;
+ return;
+ case UNW_MIPS_LO:
+ _registers.__lo = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported mips_n64 register");
+}
+
+inline bool Registers_mips_n64::validFloatRegister(int /* regNum */) const {
+ return false;
+}
+
+inline double Registers_mips_n64::getFloatRegister(int /* regNum */) const {
+ _LIBUNWIND_ABORT("mips_n64 float support not implemented");
+}
+
+inline void Registers_mips_n64::setFloatRegister(int /* regNum */,
+ double /* value */) {
+ _LIBUNWIND_ABORT("mips_n64 float support not implemented");
+}
+
+inline bool Registers_mips_n64::validVectorRegister(int /* regNum */) const {
+ return false;
+}
+
+inline v128 Registers_mips_n64::getVectorRegister(int /* regNum */) const {
+ _LIBUNWIND_ABORT("mips_n64 vector support not implemented");
+}
+
+inline void Registers_mips_n64::setVectorRegister(int /* regNum */, v128 /* value */) {
+ _LIBUNWIND_ABORT("mips_n64 vector support not implemented");
+}
+
+inline const char *Registers_mips_n64::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_MIPS_R0:
+ return "$0";
+ case UNW_MIPS_R1:
+ return "$1";
+ case UNW_MIPS_R2:
+ return "$2";
+ case UNW_MIPS_R3:
+ return "$3";
+ case UNW_MIPS_R4:
+ return "$4";
+ case UNW_MIPS_R5:
+ return "$5";
+ case UNW_MIPS_R6:
+ return "$6";
+ case UNW_MIPS_R7:
+ return "$7";
+ case UNW_MIPS_R8:
+ return "$8";
+ case UNW_MIPS_R9:
+ return "$9";
+ case UNW_MIPS_R10:
+ return "$10";
+ case UNW_MIPS_R11:
+ return "$11";
+ case UNW_MIPS_R12:
+ return "$12";
+ case UNW_MIPS_R13:
+ return "$13";
+ case UNW_MIPS_R14:
+ return "$14";
+ case UNW_MIPS_R15:
+ return "$15";
+ case UNW_MIPS_R16:
+ return "$16";
+ case UNW_MIPS_R17:
+ return "$17";
+ case UNW_MIPS_R18:
+ return "$18";
+ case UNW_MIPS_R19:
+ return "$19";
+ case UNW_MIPS_R20:
+ return "$20";
+ case UNW_MIPS_R21:
+ return "$21";
+ case UNW_MIPS_R22:
+ return "$22";
+ case UNW_MIPS_R23:
+ return "$23";
+ case UNW_MIPS_R24:
+ return "$24";
+ case UNW_MIPS_R25:
+ return "$25";
+ case UNW_MIPS_R26:
+ return "$26";
+ case UNW_MIPS_R27:
+ return "$27";
+ case UNW_MIPS_R28:
+ return "$28";
+ case UNW_MIPS_R29:
+ return "$29";
+ case UNW_MIPS_R30:
+ return "$30";
+ case UNW_MIPS_R31:
+ return "$31";
+ case UNW_MIPS_HI:
+ return "$hi";
+ case UNW_MIPS_LO:
+ return "$lo";
+ default:
+ return "unknown register";
+ }
+}
+#endif // _LIBUNWIND_TARGET_MIPS_N64
} // namespace libunwind
#endif // __REGISTERS_HPP__
diff --git a/src/Unwind-EHABI.cpp b/src/Unwind-EHABI.cpp
index 109b272..f37732c 100644
--- a/src/Unwind-EHABI.cpp
+++ b/src/Unwind-EHABI.cpp
@@ -14,6 +14,7 @@
#if defined(_LIBUNWIND_ARM_EHABI)
+#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -468,11 +469,11 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_word_t pc;
unw_get_reg(cursor, UNW_REG_IP, &pc);
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): pc=0x%llX, start_ip=0x%llX, func=%s, "
- "lsda=0x%llX, personality=0x%llX",
- static_cast<void *>(exception_object), (long long)pc,
- (long long)frameInfo.start_ip, functionName,
- (long long)frameInfo.lsda, (long long)frameInfo.handler);
+ "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR ", func=%s, "
+ "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
+ static_cast<void *>(exception_object), pc,
+ frameInfo.start_ip, functionName,
+ frameInfo.lsda, frameInfo.handler);
}
// If there is a personality routine, ask it if it will want to stop at
@@ -584,11 +585,11 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
(frameInfo.start_ip + offset > frameInfo.end_ip))
functionName = ".anonymous.";
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2(ex_ojb=%p): start_ip=0x%llX, func=%s, sp=0x%llX, "
- "lsda=0x%llX, personality=0x%llX",
- static_cast<void *>(exception_object), (long long)frameInfo.start_ip,
- functionName, (long long)sp, (long long)frameInfo.lsda,
- (long long)frameInfo.handler);
+ "unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR ", func=%s, sp=0x%" PRIxPTR ", "
+ "lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
+ static_cast<void *>(exception_object), frameInfo.start_ip,
+ functionName, sp, frameInfo.lsda,
+ frameInfo.handler);
}
// If there is a personality routine, tell it we are unwinding.
@@ -627,9 +628,9 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
unw_get_reg(cursor, UNW_REG_IP, &pc);
unw_get_reg(cursor, UNW_REG_SP, &sp);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
- "user code with ip=0x%llX, sp=0x%llX",
+ "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR,
static_cast<void *>(exception_object),
- (long long)pc, (long long)sp);
+ pc, sp);
}
{
diff --git a/src/Unwind-sjlj.c b/src/Unwind-sjlj.c
index f01e652..90cac3f 100644
--- a/src/Unwind-sjlj.c
+++ b/src/Unwind-sjlj.c
@@ -17,20 +17,14 @@
#include <stdlib.h>
#include "config.h"
-#include "unwind_ext.h"
-//
-// 32-bit iOS uses setjump/longjump based C++ exceptions.
-// Other architectures use "zero cost" exceptions.
-//
-// With SJLJ based exceptions, any function that has a catch clause or needs to
-// do any clean up when an exception propagates through it, needs to call
-// _Unwind_SjLj_Register() at the start of the function and
-// _Unwind_SjLj_Unregister() at the end. The register function is called with
-// the address of a block of memory in the function's stack frame. The runtime
-// keeps a linked list (stack) of these blocks - one per thread. The calling
-// function also sets the personality and lsda fields of the block.
-//
+/// With SJLJ based exceptions, any function that has a catch clause or needs to
+/// do any clean up when an exception propagates through it, needs to call
+/// \c _Unwind_SjLj_Register at the start of the function and
+/// \c _Unwind_SjLj_Unregister at the end. The register function is called with
+/// the address of a block of memory in the function's stack frame. The runtime
+/// keeps a linked list (stack) of these blocks - one per thread. The calling
+/// function also sets the personality and lsda fields of the block.
#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
@@ -39,10 +33,10 @@ struct _Unwind_FunctionContext {
struct _Unwind_FunctionContext *prev;
// set by calling function before registering to be the landing pad
- uintptr_t resumeLocation;
+ uint32_t resumeLocation;
// set by personality handler to be parameters passed to landing pad function
- uintptr_t resumeParameters[4];
+ uint32_t resumeParameters[4];
// set by calling function before registering
__personality_routine personality; // arm offset=24
@@ -53,6 +47,48 @@ struct _Unwind_FunctionContext {
void *jbuf[];
};
+#if defined(_LIBUNWIND_HAS_NO_THREADS)
+# define _LIBUNWIND_THREAD_LOCAL
+#else
+# if __STDC_VERSION__ >= 201112L
+# define _LIBUNWIND_THREAD_LOCAL _Thread_local
+# elif defined(_WIN32)
+# define _LIBUNWIND_THREAD_LOCAL __declspec(thread)
+# elif defined(__GNUC__) || defined(__clang__)
+# define _LIBUNWIND_THREAD_LOCAL __thread
+# else
+# error Unable to create thread local storage
+# endif
+#endif
+
+
+#if !defined(FOR_DYLD)
+
+#if defined(__APPLE__)
+#include <System/pthread_machdep.h>
+#else
+static _LIBUNWIND_THREAD_LOCAL struct _Unwind_FunctionContext *stack = NULL;
+#endif
+
+static struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
+#if defined(__APPLE__)
+ return _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
+#else
+ return stack;
+#endif
+}
+
+static void
+__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
+#if defined(__APPLE__)
+ _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
+#else
+ stack = fc;
+#endif
+}
+
+#endif
+
/// Called at start of each function that catches exceptions
_LIBUNWIND_EXPORT void
diff --git a/src/UnwindCursor.hpp b/src/UnwindCursor.hpp
index 5f9cba9..f09bd23 100644
--- a/src/UnwindCursor.hpp
+++ b/src/UnwindCursor.hpp
@@ -16,9 +16,6 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#ifndef _LIBUNWIND_HAS_NO_THREADS
- #include <pthread.h>
-#endif
#include <unwind.h>
#ifdef __APPLE__
@@ -34,6 +31,7 @@
#include "EHHeaderParser.hpp"
#include "libunwind.h"
#include "Registers.hpp"
+#include "RWMutex.hpp"
#include "Unwind-EHABI.h"
namespace libunwind {
@@ -62,9 +60,7 @@ private:
// These fields are all static to avoid needing an initializer.
// There is only one instance of this class per process.
-#ifndef _LIBUNWIND_HAS_NO_THREADS
- static pthread_rwlock_t _lock;
-#endif
+ static RWMutex _lock;
#ifdef __APPLE__
static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide);
static bool _registeredForDyldUnloads;
@@ -91,10 +87,8 @@ DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64];
template <typename A>
typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64];
-#ifndef _LIBUNWIND_HAS_NO_THREADS
template <typename A>
-pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER;
-#endif
+RWMutex DwarfFDECache<A>::_lock;
#ifdef __APPLE__
template <typename A>
@@ -104,7 +98,7 @@ bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
template <typename A>
typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
pint_t result = 0;
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_rdlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.lock_shared());
for (entry *p = _buffer; p < _bufferUsed; ++p) {
if ((mh == p->mh) || (mh == 0)) {
if ((p->ip_start <= pc) && (pc < p->ip_end)) {
@@ -113,7 +107,7 @@ typename A::pint_t DwarfFDECache<A>::findFDE(pint_t mh, pint_t pc) {
}
}
}
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.unlock_shared());
return result;
}
@@ -121,7 +115,7 @@ template <typename A>
void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
pint_t fde) {
#if !defined(_LIBUNWIND_NO_HEAP)
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
if (_bufferUsed >= _bufferEnd) {
size_t oldSize = (size_t)(_bufferEnd - _buffer);
size_t newSize = oldSize * 4;
@@ -145,13 +139,13 @@ void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
_registeredForDyldUnloads = true;
}
#endif
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
#endif
}
template <typename A>
void DwarfFDECache<A>::removeAllIn(pint_t mh) {
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
entry *d = _buffer;
for (const entry *s = _buffer; s < _bufferUsed; ++s) {
if (s->mh != mh) {
@@ -161,7 +155,7 @@ void DwarfFDECache<A>::removeAllIn(pint_t mh) {
}
}
_bufferUsed = d;
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
}
#ifdef __APPLE__
@@ -174,11 +168,11 @@ void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) {
template <typename A>
void DwarfFDECache<A>::iterateCacheEntries(void (*func)(
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.lock());
for (entry *p = _buffer; p < _bufferUsed; ++p) {
(*func)(p->ip_start, p->ip_end, p->fde, p->mh);
}
- _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+ _LIBUNWIND_LOG_IF_FALSE(_lock.unlock());
}
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -514,6 +508,18 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+ int stepWithCompactEncoding(Registers_mips_o32 &) {
+ return UNW_EINVAL;
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_N64)
+ int stepWithCompactEncoding(Registers_mips_n64 &) {
+ return UNW_EINVAL;
+ }
+#endif
+
bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
R dummy;
return compactSaysUseDwarf(dummy, offset);
@@ -557,6 +563,18 @@ private:
return false;
}
#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+ bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const {
+ return true;
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_N64)
+ bool compactSaysUseDwarf(Registers_mips_n64 &, uint32_t *) const {
+ return true;
+ }
+#endif
#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -589,11 +607,29 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_ARM)
+ compact_unwind_encoding_t dwarfEncoding(Registers_arm &) const {
+ return 0;
+ }
+#endif
+
#if defined (_LIBUNWIND_TARGET_OR1K)
compact_unwind_encoding_t dwarfEncoding(Registers_or1k &) const {
return 0;
}
#endif
+
+#if defined (_LIBUNWIND_TARGET_MIPS_O32)
+ compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const {
+ return 0;
+ }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_MIPS_N64)
+ compact_unwind_encoding_t dwarfEncoding(Registers_mips_n64 &) const {
+ return 0;
+ }
+#endif
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -744,14 +780,21 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
EHABISectionIterator<A>::begin(_addressSpace, sects);
EHABISectionIterator<A> end =
EHABISectionIterator<A>::end(_addressSpace, sects);
+ if (begin == end)
+ return false;
EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc);
- if (itNextPC == begin || itNextPC == end)
+ if (itNextPC == begin)
return false;
EHABISectionIterator<A> itThisPC = itNextPC - 1;
pint_t thisPC = itThisPC.functionAddress();
- pint_t nextPC = itNextPC.functionAddress();
+ // If an exception is thrown from a function, corresponding to the last entry
+ // in the table, we don't really know the function extent and have to choose a
+ // value for nextPC. Choosing max() will allow the range check during trace to
+ // succeed.
+ pint_t nextPC = (itNextPC == end) ? std::numeric_limits<pint_t>::max()
+ : itNextPC.functionAddress();
pint_t indexDataAddr = itThisPC.dataAddress();
if (indexDataAddr == 0)
diff --git a/src/UnwindLevel1-gcc-ext.c b/src/UnwindLevel1-gcc-ext.c
index f8c1fb4..10619ba 100644
--- a/src/UnwindLevel1-gcc-ext.c
+++ b/src/UnwindLevel1-gcc-ext.c
@@ -164,8 +164,8 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
unw_get_proc_name(&cursor, functionName, 512, &offset);
unw_get_proc_info(&cursor, &frame);
_LIBUNWIND_TRACE_UNWINDING(
- " _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p",
- (long long)frame.start_ip, functionName, (long long)frame.lsda,
+ " _backtrace: start_ip=0x%" PRIxPTR ", func=%s, lsda=0x%" PRIxPTR ", context=%p",
+ frame.start_ip, functionName, frame.lsda,
(void *)&cursor);
}
@@ -206,8 +206,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_word_t result;
unw_get_reg(cursor, UNW_REG_SP, &result);
- _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIx64,
- (void *)context, (uint64_t)result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
+ (void *)context, result);
return (uintptr_t)result;
}
diff --git a/src/UnwindLevel1.c b/src/UnwindLevel1.c
index 19116fa..518577b 100644
--- a/src/UnwindLevel1.c
+++ b/src/UnwindLevel1.c
@@ -30,7 +30,7 @@
#include "unwind.h"
#include "config.h"
-#if !defined(_LIBUNWIND_ARM_EHABI)
+#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
static _Unwind_Reason_Code
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
@@ -76,8 +76,8 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_word_t pc;
unw_get_reg(cursor, UNW_REG_IP, &pc);
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): pc=0x%" PRIx64 ", start_ip=0x%" PRIx64
- ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64 "",
+ "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
+ ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
(void *)exception_object, pc, frameInfo.start_ip, functionName,
frameInfo.lsda, frameInfo.handler);
}
@@ -86,7 +86,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
// this frame.
if (frameInfo.handler != 0) {
__personality_routine p =
- (__personality_routine)(long)(frameInfo.handler);
+ (__personality_routine)(uintptr_t)(frameInfo.handler);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): calling personality function %p",
(void *)exception_object, (void *)(uintptr_t)p);
@@ -170,9 +170,9 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
&offset) != UNW_ESUCCESS) ||
(frameInfo.start_ip + offset > frameInfo.end_ip))
functionName = ".anonymous.";
- _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIx64
- ", func=%s, sp=0x%" PRIx64 ", lsda=0x%" PRIx64
- ", personality=0x%" PRIx64,
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR
+ ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR
+ ", personality=0x%" PRIxPTR,
(void *)exception_object, frameInfo.start_ip,
functionName, sp, frameInfo.lsda,
frameInfo.handler);
@@ -181,7 +181,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
// If there is a personality routine, tell it we are unwinding.
if (frameInfo.handler != 0) {
__personality_routine p =
- (__personality_routine)(long)(frameInfo.handler);
+ (__personality_routine)(uintptr_t)(frameInfo.handler);
_Unwind_Action action = _UA_CLEANUP_PHASE;
if (sp == exception_object->private_2) {
// Tell personality this was the frame it marked in phase 1.
@@ -213,8 +213,8 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_get_reg(cursor, UNW_REG_IP, &pc);
unw_get_reg(cursor, UNW_REG_SP, &sp);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
- "user code with ip=0x%" PRIx64
- ", sp=0x%" PRIx64,
+ "user code with ip=0x%" PRIxPTR
+ ", sp=0x%" PRIxPTR,
(void *)exception_object, pc, sp);
}
unw_resume(cursor);
@@ -262,8 +262,8 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
(frameInfo.start_ip + offset > frameInfo.end_ip))
functionName = ".anonymous.";
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64
- ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64,
+ "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
+ ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
(void *)exception_object, frameInfo.start_ip, functionName,
frameInfo.lsda, frameInfo.handler);
}
@@ -467,17 +467,17 @@ _Unwind_GetGR(struct _Unwind_Context *context, int index) {
unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_word_t result;
unw_get_reg(cursor, index, &result);
- _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIx64,
- (void *)context, index, (uint64_t)result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIxPTR,
+ (void *)context, index, result);
return (uintptr_t)result;
}
/// Called by personality handler during phase 2 to alter register values.
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
uintptr_t value) {
- _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIx64
+ _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR
")",
- (void *)context, index, (uint64_t)value);
+ (void *)context, index, value);
unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_set_reg(cursor, index, value);
}
@@ -487,8 +487,8 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_word_t result;
unw_get_reg(cursor, UNW_REG_IP, &result);
- _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIx64,
- (void *)context, (uint64_t)result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
+ (void *)context, result);
return (uintptr_t)result;
}
@@ -497,10 +497,10 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
/// start executing in the landing pad.
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
uintptr_t value) {
- _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIx64 ")",
- (void *)context, (uint64_t)value);
+ _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0" PRIxPTR ")",
+ (void *)context, value);
unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_set_reg(cursor, UNW_REG_IP, value);
}
-#endif // !defined(_LIBUNWIND_ARM_EHABI)
+#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
diff --git a/src/UnwindRegistersRestore.S b/src/UnwindRegistersRestore.S
index 408ba03..bd797f6 100644
--- a/src/UnwindRegistersRestore.S
+++ b/src/UnwindRegistersRestore.S
@@ -11,11 +11,17 @@
.text
+#if !defined(__USING_SJLJ_EXCEPTIONS__)
+
#if defined(__i386__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
#
# void libunwind::Registers_x86::jumpto()
#
+#if defined(_WIN32)
+# On windows, the 'this' pointer is passed in ecx instead of on the stack
+ movl %ecx, %eax
+#else
# On entry:
# + +
# +-----------------------+
@@ -25,6 +31,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
# +-----------------------+ <-- SP
# + +
movl 4(%esp), %eax
+#endif
# set up eax and ret on new stack location
movl 28(%eax), %edx # edx holds new stack pointer
subl $8,%edx
@@ -58,7 +65,16 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
#
# void libunwind::Registers_x86_64::jumpto()
#
+#if defined(_WIN64)
+# On entry, thread_state pointer is in rcx; move it into rdi
+# to share restore code below. Since this routine restores and
+# overwrites all registers, we can use the same registers for
+# pointers and temporaries as on unix even though win64 normally
+# mustn't clobber some of them.
+ movq %rcx, %rdi
+#else
# On entry, thread_state pointer is in rdi
+#endif
movq 56(%rdi), %rax # rax holds new stack pointer
subq $16, %rax
@@ -88,6 +104,25 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
# skip cs
# skip fs
# skip gs
+
+#if defined(_WIN64)
+ movdqu 176(%rdi),%xmm0
+ movdqu 192(%rdi),%xmm1
+ movdqu 208(%rdi),%xmm2
+ movdqu 224(%rdi),%xmm3
+ movdqu 240(%rdi),%xmm4
+ movdqu 256(%rdi),%xmm5
+ movdqu 272(%rdi),%xmm6
+ movdqu 288(%rdi),%xmm7
+ movdqu 304(%rdi),%xmm8
+ movdqu 320(%rdi),%xmm9
+ movdqu 336(%rdi),%xmm10
+ movdqu 352(%rdi),%xmm11
+ movdqu 368(%rdi),%xmm12
+ movdqu 384(%rdi),%xmm13
+ movdqu 400(%rdi),%xmm14
+ movdqu 416(%rdi),%xmm15
+#endif
movq 56(%rdi), %rsp # cut back rsp to new location
pop %rdi # rdi was saved here earlier
ret # rip was saved here
@@ -356,7 +391,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJu
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.fpu vfpv3-d16
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMDEPy)
@ VFP and iwMMX instructions are only available when compiling with the flags
@ that enable them. We do not want to do that in the library (because we do not
@@ -375,7 +412,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFL
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.fpu vfpv3-d16
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy)
vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
JMP(lr)
@@ -387,7 +426,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFL
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.fpu vfpv3
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
vldmia r0, {d16-d31}
JMP(lr)
@@ -401,7 +442,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.arch armv5te
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8
ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8
@@ -428,7 +471,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.arch armv5te
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreiWMMXControlEPj)
ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4
ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4
@@ -489,7 +534,121 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
l.jr r9
l.nop
+#elif defined(__mips__) && defined(_ABIO32) && defined(__mips_soft_float)
+
+//
+// void libunwind::Registers_mips_o32::jumpto()
+//
+// On entry:
+// thread state pointer is in a0 ($4)
+//
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_o326jumptoEv)
+ .set push
+ .set noat
+ .set noreorder
+ .set nomacro
+ // restore hi and lo
+ lw $8, (4 * 33)($4)
+ mthi $8
+ lw $8, (4 * 34)($4)
+ mtlo $8
+ // r0 is zero
+ lw $1, (4 * 1)($4)
+ lw $2, (4 * 2)($4)
+ lw $3, (4 * 3)($4)
+ // skip a0 for now
+ lw $5, (4 * 5)($4)
+ lw $6, (4 * 6)($4)
+ lw $7, (4 * 7)($4)
+ lw $8, (4 * 8)($4)
+ lw $9, (4 * 9)($4)
+ lw $10, (4 * 10)($4)
+ lw $11, (4 * 11)($4)
+ lw $12, (4 * 12)($4)
+ lw $13, (4 * 13)($4)
+ lw $14, (4 * 14)($4)
+ lw $15, (4 * 15)($4)
+ lw $16, (4 * 16)($4)
+ lw $17, (4 * 17)($4)
+ lw $18, (4 * 18)($4)
+ lw $19, (4 * 19)($4)
+ lw $20, (4 * 20)($4)
+ lw $21, (4 * 21)($4)
+ lw $22, (4 * 22)($4)
+ lw $23, (4 * 23)($4)
+ lw $24, (4 * 24)($4)
+ lw $25, (4 * 25)($4)
+ lw $26, (4 * 26)($4)
+ lw $27, (4 * 27)($4)
+ lw $28, (4 * 28)($4)
+ lw $29, (4 * 29)($4)
+ lw $30, (4 * 30)($4)
+ // load new pc into ra
+ lw $31, (4 * 32)($4)
+ // jump to ra, load a0 in the delay slot
+ jr $31
+ lw $4, (4 * 4)($4)
+ .set pop
+
+#elif defined(__mips__) && defined(_ABI64) && defined(__mips_soft_float)
+
+//
+// void libunwind::Registers_mips_n64::jumpto()
+//
+// On entry:
+// thread state pointer is in a0 ($4)
+//
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind18Registers_mips_n646jumptoEv)
+ .set push
+ .set noat
+ .set noreorder
+ .set nomacro
+ // restore hi and lo
+ ld $8, (8 * 33)($4)
+ mthi $8
+ ld $8, (8 * 34)($4)
+ mtlo $8
+ // r0 is zero
+ ld $1, (8 * 1)($4)
+ ld $2, (8 * 2)($4)
+ ld $3, (8 * 3)($4)
+ // skip a0 for now
+ ld $5, (8 * 5)($4)
+ ld $6, (8 * 6)($4)
+ ld $7, (8 * 7)($4)
+ ld $8, (8 * 8)($4)
+ ld $9, (8 * 9)($4)
+ ld $10, (8 * 10)($4)
+ ld $11, (8 * 11)($4)
+ ld $12, (8 * 12)($4)
+ ld $13, (8 * 13)($4)
+ ld $14, (8 * 14)($4)
+ ld $15, (8 * 15)($4)
+ ld $16, (8 * 16)($4)
+ ld $17, (8 * 17)($4)
+ ld $18, (8 * 18)($4)
+ ld $19, (8 * 19)($4)
+ ld $20, (8 * 20)($4)
+ ld $21, (8 * 21)($4)
+ ld $22, (8 * 22)($4)
+ ld $23, (8 * 23)($4)
+ ld $24, (8 * 24)($4)
+ ld $25, (8 * 25)($4)
+ ld $26, (8 * 26)($4)
+ ld $27, (8 * 27)($4)
+ ld $28, (8 * 28)($4)
+ ld $29, (8 * 29)($4)
+ ld $30, (8 * 30)($4)
+ // load new pc into ra
+ ld $31, (8 * 32)($4)
+ // jump to ra, load a0 in the delay slot
+ jr $31
+ ld $4, (8 * 4)($4)
+ .set pop
+
#endif
+#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
+
NO_EXEC_STACK_DIRECTIVE
diff --git a/src/UnwindRegistersSave.S b/src/UnwindRegistersSave.S
index 4860e8f..4583f50 100644
--- a/src/UnwindRegistersSave.S
+++ b/src/UnwindRegistersSave.S
@@ -11,6 +11,8 @@
.text
+#if !defined(__USING_SJLJ_EXCEPTIONS__)
+
#if defined(__i386__)
#
@@ -61,32 +63,171 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
# thread_state pointer is in rdi
#
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
- movq %rax, (%rdi)
- movq %rbx, 8(%rdi)
- movq %rcx, 16(%rdi)
- movq %rdx, 24(%rdi)
- movq %rdi, 32(%rdi)
- movq %rsi, 40(%rdi)
- movq %rbp, 48(%rdi)
- movq %rsp, 56(%rdi)
- addq $8, 56(%rdi)
- movq %r8, 64(%rdi)
- movq %r9, 72(%rdi)
- movq %r10, 80(%rdi)
- movq %r11, 88(%rdi)
- movq %r12, 96(%rdi)
- movq %r13,104(%rdi)
- movq %r14,112(%rdi)
- movq %r15,120(%rdi)
- movq (%rsp),%rsi
- movq %rsi,128(%rdi) # store return address as rip
+#if defined(_WIN64)
+#define PTR %rcx
+#define TMP %rdx
+#else
+#define PTR %rdi
+#define TMP %rsi
+#endif
+
+ movq %rax, (PTR)
+ movq %rbx, 8(PTR)
+ movq %rcx, 16(PTR)
+ movq %rdx, 24(PTR)
+ movq %rdi, 32(PTR)
+ movq %rsi, 40(PTR)
+ movq %rbp, 48(PTR)
+ movq %rsp, 56(PTR)
+ addq $8, 56(PTR)
+ movq %r8, 64(PTR)
+ movq %r9, 72(PTR)
+ movq %r10, 80(PTR)
+ movq %r11, 88(PTR)
+ movq %r12, 96(PTR)
+ movq %r13,104(PTR)
+ movq %r14,112(PTR)
+ movq %r15,120(PTR)
+ movq (%rsp),TMP
+ movq TMP,128(PTR) # store return address as rip
# skip rflags
# skip cs
# skip fs
# skip gs
+
+#if defined(_WIN64)
+ movdqu %xmm0,176(PTR)
+ movdqu %xmm1,192(PTR)
+ movdqu %xmm2,208(PTR)
+ movdqu %xmm3,224(PTR)
+ movdqu %xmm4,240(PTR)
+ movdqu %xmm5,256(PTR)
+ movdqu %xmm6,272(PTR)
+ movdqu %xmm7,288(PTR)
+ movdqu %xmm8,304(PTR)
+ movdqu %xmm9,320(PTR)
+ movdqu %xmm10,336(PTR)
+ movdqu %xmm11,352(PTR)
+ movdqu %xmm12,368(PTR)
+ movdqu %xmm13,384(PTR)
+ movdqu %xmm14,400(PTR)
+ movdqu %xmm15,416(PTR)
+#endif
xorl %eax, %eax # return UNW_ESUCCESS
ret
+#elif defined(__mips__) && defined(_ABIO32) && defined(__mips_soft_float)
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in a0 ($4)
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ .set push
+ .set noat
+ .set noreorder
+ .set nomacro
+ sw $1, (4 * 1)($4)
+ sw $2, (4 * 2)($4)
+ sw $3, (4 * 3)($4)
+ sw $4, (4 * 4)($4)
+ sw $5, (4 * 5)($4)
+ sw $6, (4 * 6)($4)
+ sw $7, (4 * 7)($4)
+ sw $8, (4 * 8)($4)
+ sw $9, (4 * 9)($4)
+ sw $10, (4 * 10)($4)
+ sw $11, (4 * 11)($4)
+ sw $12, (4 * 12)($4)
+ sw $13, (4 * 13)($4)
+ sw $14, (4 * 14)($4)
+ sw $15, (4 * 15)($4)
+ sw $16, (4 * 16)($4)
+ sw $17, (4 * 17)($4)
+ sw $18, (4 * 18)($4)
+ sw $19, (4 * 19)($4)
+ sw $20, (4 * 20)($4)
+ sw $21, (4 * 21)($4)
+ sw $22, (4 * 22)($4)
+ sw $23, (4 * 23)($4)
+ sw $24, (4 * 24)($4)
+ sw $25, (4 * 25)($4)
+ sw $26, (4 * 26)($4)
+ sw $27, (4 * 27)($4)
+ sw $28, (4 * 28)($4)
+ sw $29, (4 * 29)($4)
+ sw $30, (4 * 30)($4)
+ sw $31, (4 * 31)($4)
+ # Store return address to pc
+ sw $31, (4 * 32)($4)
+ # hi and lo
+ mfhi $8
+ sw $8, (4 * 33)($4)
+ mflo $8
+ sw $8, (4 * 34)($4)
+ jr $31
+ # return UNW_ESUCCESS
+ or $2, $0, $0
+ .set pop
+
+#elif defined(__mips__) && defined(_ABI64) && defined(__mips_soft_float)
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in a0 ($4)
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ .set push
+ .set noat
+ .set noreorder
+ .set nomacro
+ sd $1, (8 * 1)($4)
+ sd $2, (8 * 2)($4)
+ sd $3, (8 * 3)($4)
+ sd $4, (8 * 4)($4)
+ sd $5, (8 * 5)($4)
+ sd $6, (8 * 6)($4)
+ sd $7, (8 * 7)($4)
+ sd $8, (8 * 8)($4)
+ sd $9, (8 * 9)($4)
+ sd $10, (8 * 10)($4)
+ sd $11, (8 * 11)($4)
+ sd $12, (8 * 12)($4)
+ sd $13, (8 * 13)($4)
+ sd $14, (8 * 14)($4)
+ sd $15, (8 * 15)($4)
+ sd $16, (8 * 16)($4)
+ sd $17, (8 * 17)($4)
+ sd $18, (8 * 18)($4)
+ sd $19, (8 * 19)($4)
+ sd $20, (8 * 20)($4)
+ sd $21, (8 * 21)($4)
+ sd $22, (8 * 22)($4)
+ sd $23, (8 * 23)($4)
+ sd $24, (8 * 24)($4)
+ sd $25, (8 * 25)($4)
+ sd $26, (8 * 26)($4)
+ sd $27, (8 * 27)($4)
+ sd $28, (8 * 28)($4)
+ sd $29, (8 * 29)($4)
+ sd $30, (8 * 30)($4)
+ sd $31, (8 * 31)($4)
+ # Store return address to pc
+ sd $31, (8 * 32)($4)
+ # hi and lo
+ mfhi $8
+ sd $8, (8 * 33)($4)
+ mflo $8
+ sd $8, (8 * 34)($4)
+ jr $31
+ # return UNW_ESUCCESS
+ or $2, $0, $0
+ .set pop
+
# elif defined(__mips__)
#
@@ -346,7 +487,9 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.fpu vfpv3-d16
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy)
vstmia r0, {d0-d15}
JMP(lr)
@@ -358,7 +501,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMD
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.fpu vfpv3-d16
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy)
vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
JMP(lr)
@@ -370,7 +515,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMX
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.fpu vfpv3
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
@ VFP and iwMMX instructions are only available when compiling with the flags
@ that enable them. We do not want to do that in the library (because we do not
@@ -391,7 +538,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.arch armv5te
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8
stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
@@ -418,7 +567,9 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
@ values pointer is in r0
@
.p2align 2
+#if defined(__ELF__)
.arch armv5te
+#endif
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveiWMMXControlEPj)
stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
@@ -471,5 +622,7 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
l.sw 124(r3), r31
#endif
+#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
+
NO_EXEC_STACK_DIRECTIVE
diff --git a/src/Unwind_AppleExtras.cpp b/src/Unwind_AppleExtras.cpp
index 471059b..39f379c 100644
--- a/src/Unwind_AppleExtras.cpp
+++ b/src/Unwind_AppleExtras.cpp
@@ -11,7 +11,6 @@
#include "config.h"
#include "AddressSpace.hpp"
#include "DwarfParser.hpp"
-#include "unwind_ext.h"
// private keymgr stuff
@@ -183,32 +182,3 @@ bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
}
-
-#if !defined(FOR_DYLD) && defined(_LIBUNWIND_BUILD_SJLJ_APIS)
-
-#ifndef _LIBUNWIND_HAS_NO_THREADS
- #include <System/pthread_machdep.h>
-#else
- _Unwind_FunctionContext *fc_ = nullptr;
-#endif
-
-// Accessors to get get/set linked list of frames for sjlj based execeptions.
-_LIBUNWIND_HIDDEN
-struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
-#ifndef _LIBUNWIND_HAS_NO_THREADS
- return (struct _Unwind_FunctionContext *)
- _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
-#else
- return fc_;
-#endif
-}
-
-_LIBUNWIND_HIDDEN
-void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
-#ifndef _LIBUNWIND_HAS_NO_THREADS
- _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
-#else
- fc_ = fc;
-#endif
-}
-#endif
diff --git a/src/assembly.h b/src/assembly.h
index 9fb9905..2b2269c 100644
--- a/src/assembly.h
+++ b/src/assembly.h
@@ -24,12 +24,6 @@
#define SEPARATOR ;
#endif
-#if defined(__APPLE__)
-#define HIDDEN_DIRECTIVE .private_extern
-#else
-#define HIDDEN_DIRECTIVE .hidden
-#endif
-
#define GLUE2(a, b) a ## b
#define GLUE(a, b) GLUE2(a, b)
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
@@ -37,6 +31,7 @@
#if defined(__APPLE__)
#define SYMBOL_IS_FUNC(name)
+#define HIDDEN_SYMBOL(name) .private_extern name
#define NO_EXEC_STACK_DIRECTIVE
#elif defined(__ELF__)
@@ -46,24 +41,30 @@
#else
#define SYMBOL_IS_FUNC(name) .type name,@function
#endif
+#define HIDDEN_SYMBOL(name) .hidden name
-#if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__) || \
- defined(__Fuchsia__)
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
+ defined(__linux__)
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
#else
#define NO_EXEC_STACK_DIRECTIVE
#endif
-#else
+#elif defined(_WIN32)
#define SYMBOL_IS_FUNC(name) \
.def name SEPARATOR \
.scl 2 SEPARATOR \
.type 32 SEPARATOR \
.endef
+#define HIDDEN_SYMBOL(name)
#define NO_EXEC_STACK_DIRECTIVE
+#else
+
+#error Unsupported target
+
#endif
#define DEFINE_LIBUNWIND_FUNCTION(name) \
@@ -73,7 +74,7 @@
#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name) \
.globl SYMBOL_NAME(name) SEPARATOR \
- HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR \
+ HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_NAME(name):
diff --git a/src/config.h b/src/config.h
index 4be98c8..0f29b77 100644
--- a/src/config.h
+++ b/src/config.h
@@ -37,6 +37,8 @@
#define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#endif
+#elif defined(_WIN32)
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#else
#if defined(__ARM_DWARF_EH__) || !defined(__arm__)
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
@@ -44,9 +46,18 @@
#endif
#endif
-// FIXME: these macros are not correct for COFF targets
-#define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
-#define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
+#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
+ #define _LIBUNWIND_EXPORT
+ #define _LIBUNWIND_HIDDEN
+#else
+ #if !defined(__ELF__) && !defined(__MACH__)
+ #define _LIBUNWIND_EXPORT __declspec(dllexport)
+ #define _LIBUNWIND_HIDDEN
+ #else
+ #define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
+ #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
+ #endif
+#endif
#if (defined(__APPLE__) && defined(__arm__)) || defined(__USING_SJLJ_EXCEPTIONS__)
#define _LIBUNWIND_BUILD_SJLJ_APIS
@@ -60,7 +71,7 @@
defined(__ppc__) || defined(__ppc64__) || \
(!defined(__APPLE__) && defined(__arm__)) || \
(defined(__arm64__) || defined(__aarch64__)) || \
- (defined(__APPLE__) && defined(__mips__))
+ defined(__mips__)
#define _LIBUNWIND_BUILD_ZERO_COST_APIS
#endif
@@ -86,20 +97,15 @@
fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__)
#endif
-#if defined(_LIBUNWIND_HAS_NO_THREADS)
- // only used with pthread calls, not needed for the single-threaded builds
- #define _LIBUNWIND_LOG_NON_ZERO(x)
+#if defined(NDEBUG)
+ #define _LIBUNWIND_LOG_IF_FALSE(x) x
#else
- #if defined(NDEBUG)
- #define _LIBUNWIND_LOG_NON_ZERO(x) x
- #else
- #define _LIBUNWIND_LOG_NON_ZERO(x) \
- do { \
- int _err = x; \
- if (_err != 0) \
- _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \
- } while (0)
- #endif
+ #define _LIBUNWIND_LOG_IF_FALSE(x) \
+ do { \
+ bool _ret = x; \
+ if (!_ret) \
+ _LIBUNWIND_LOG("" #x " failed in %s", __FUNCTION__); \
+ } while (0)
#endif
// Macros that define away in non-Debug builds
diff --git a/src/libunwind.cpp b/src/libunwind.cpp
index f072d55..0b7fb40 100644
--- a/src/libunwind.cpp
+++ b/src/libunwind.cpp
@@ -24,6 +24,7 @@
#include <stdlib.h>
+#if !defined(__USING_SJLJ_EXCEPTIONS__)
#include "AddressSpace.hpp"
#include "UnwindCursor.hpp"
@@ -54,12 +55,16 @@ _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
# define REGISTER_KIND Registers_ppc
#elif defined(__aarch64__)
# define REGISTER_KIND Registers_arm64
-#elif defined(_LIBUNWIND_ARM_EHABI)
+#elif defined(__arm__)
# define REGISTER_KIND Registers_arm
#elif defined(__or1k__)
# define REGISTER_KIND Registers_or1k
+#elif defined(__mips__) && defined(_ABIO32) && defined(__mips_soft_float)
+# define REGISTER_KIND Registers_mips_o32
+#elif defined(__mips__) && defined(_ABI64) && defined(__mips_soft_float)
+# define REGISTER_KIND Registers_mips_n64
#elif defined(__mips__)
-# warning The MIPS architecture is not supported.
+# warning The MIPS architecture is not supported with this ABI and environment!
#else
# error Architecture not supported
#endif
@@ -173,8 +178,8 @@ _LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
/// Set value of specified register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_word_t value) {
- _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)",
- static_cast<void *>(cursor), regNum, (long long)value);
+ _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%" PRIxPTR ")",
+ static_cast<void *>(cursor), regNum, value);
typedef LocalAddressSpace::pint_t pint_t;
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
if (co->validReg(regNum)) {
@@ -341,6 +346,7 @@ void _unw_remove_dynamic_fde(unw_word_t fde) {
DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
}
#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
diff --git a/src/unwind_ext.h b/src/unwind_ext.h
deleted file mode 100644
index c40ce6a..0000000
--- a/src/unwind_ext.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//===-------------------------- unwind_ext.h ------------------------------===//
-//
-// 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.
-//
-//
-// Extensions to unwind API.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef __UNWIND_EXT__
-#define __UNWIND_EXT__
-
-#include "unwind.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// These platform specific functions to get and set the top context are
-// implemented elsewhere.
-
-extern struct _Unwind_FunctionContext *
-__Unwind_SjLj_GetTopOfFunctionStack();
-
-extern void
-__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // __UNWIND_EXT__
-
-
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..97917b8
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,34 @@
+include(AddLLVM) # for add_lit_testsuite
+macro(pythonize_bool var)
+ if (${var})
+ set(${var} True)
+ else()
+ set(${var} False)
+ endif()
+endmacro()
+
+if (NOT DEFINED LIBCXX_ENABLE_SHARED)
+ set(LIBCXX_ENABLE_SHARED ON)
+endif()
+
+pythonize_bool(LIBUNWIND_BUILD_32_BITS)
+pythonize_bool(LIBCXX_ENABLE_SHARED)
+pythonize_bool(LIBUNWIND_ENABLE_SHARED)
+pythonize_bool(LIBUNWIND_ENABLE_THREADS)
+pythonize_bool(LIBUNWIND_ENABLE_EXCEPTIONS)
+pythonize_bool(LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY)
+set(LIBUNWIND_TARGET_INFO "libcxx.test.target_info.LocalTI" CACHE STRING
+ "TargetInfo to use when setting up test environment.")
+set(LIBUNWIND_EXECUTOR "None" CACHE STRING
+ "Executor to use when running tests.")
+
+set(AUTO_GEN_COMMENT "## Autogenerated by libunwind configuration.\n# Do not edit!")
+configure_file(
+ ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in
+ ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg
+ @ONLY)
+
+add_lit_testsuite(check-unwind "Running libunwind tests"
+ ${CMAKE_CURRENT_BINARY_DIR}
+ DEPENDS ${LIBUNWIND_TEST_DEPS}
+ )
diff --git a/test/alignment.pass.cpp b/test/alignment.pass.cpp
index 5ab5584..1a3ca5a 100644
--- a/test/alignment.pass.cpp
+++ b/test/alignment.pass.cpp
@@ -13,8 +13,16 @@
#include <unwind.h>
-struct MaxAligned {} __attribute__((aligned));
-static_assert(alignof(_Unwind_Exception) == alignof(MaxAligned), "");
+// EHABI : 8-byte aligned
+// itanium: largest supported alignment for the system
+#if defined(_LIBUNWIND_ARM_EHABI)
+static_assert(alignof(_Unwind_Control_Block) == 8,
+ "_Unwind_Control_Block must be double-word aligned");
+#else
+struct MaxAligned {} __attribute__((__aligned__));
+static_assert(alignof(_Unwind_Exception) == alignof(MaxAligned),
+ "_Unwind_Exception must be maximally aligned");
+#endif
int main()
{
diff --git a/test/libunwind/__init__.py b/test/libunwind/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/libunwind/__init__.py
diff --git a/test/libunwind/test/__init__.py b/test/libunwind/test/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/libunwind/test/__init__.py
diff --git a/test/libunwind/test/config.py b/test/libunwind/test/config.py
new file mode 100644
index 0000000..2a0c828
--- /dev/null
+++ b/test/libunwind/test/config.py
@@ -0,0 +1,71 @@
+#===----------------------------------------------------------------------===##
+#
+# 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.
+#
+#===----------------------------------------------------------------------===##
+import os
+import sys
+
+from libcxx.test.config import Configuration as LibcxxConfiguration
+
+
+class Configuration(LibcxxConfiguration):
+ # pylint: disable=redefined-outer-name
+ def __init__(self, lit_config, config):
+ super(Configuration, self).__init__(lit_config, config)
+ self.libunwind_src_root = None
+ self.libunwind_obj_root = None
+ self.abi_library_path = None
+ self.libcxx_src_root = None
+
+ def configure_src_root(self):
+ self.libunwind_src_root = self.get_lit_conf(
+ 'libunwind_src_root',
+ os.path.dirname(self.config.test_source_root))
+ self.libcxx_src_root = self.get_lit_conf(
+ 'libcxx_src_root',
+ os.path.join(self.libunwind_src_root, '/../libcxx'))
+
+ def configure_obj_root(self):
+ self.libunwind_obj_root = self.get_lit_conf('libunwind_obj_root')
+ super(Configuration, self).configure_obj_root()
+
+ def has_cpp_feature(self, feature, required_value):
+ return int(self.cxx.dumpMacros().get('__cpp_' + feature, 0)) >= required_value
+
+ def configure_features(self):
+ super(Configuration, self).configure_features()
+ if not self.get_lit_bool('enable_exceptions', True):
+ self.config.available_features.add('libcxxabi-no-exceptions')
+
+ def configure_compile_flags(self):
+ self.cxx.compile_flags += ['-DLIBUNWIND_NO_TIMER']
+ if not self.get_lit_bool('enable_exceptions', True):
+ self.cxx.compile_flags += ['-fno-exceptions', '-DLIBUNWIND_HAS_NO_EXCEPTIONS']
+ # Stack unwinding tests need unwinding tables and these are not
+ # generated by default on all Targets.
+ self.cxx.compile_flags += ['-funwind-tables']
+ if not self.get_lit_bool('enable_threads', True):
+ self.cxx.compile_flags += ['-D_LIBUNWIND_HAS_NO_THREADS']
+ self.config.available_features.add('libunwind-no-threads')
+ super(Configuration, self).configure_compile_flags()
+
+ def configure_compile_flags_header_includes(self):
+ self.configure_config_site_header()
+
+ libunwind_headers = self.get_lit_conf(
+ 'libunwind_headers',
+ os.path.join(self.libunwind_src_root, 'include'))
+ if not os.path.isdir(libunwind_headers):
+ self.lit_config.fatal("libunwind_headers='%s' is not a directory."
+ % libunwind_headers)
+ self.cxx.compile_flags += ['-I' + libunwind_headers]
+
+ def configure_compile_flags_exceptions(self):
+ pass
+
+ def configure_compile_flags_rtti(self):
+ pass
diff --git a/test/libunwind_02.pass.cpp b/test/libunwind_02.pass.cpp
index 892c087..a0efd1d 100644
--- a/test/libunwind_02.pass.cpp
+++ b/test/libunwind_02.pass.cpp
@@ -6,6 +6,7 @@
#define NUM_FRAMES_UPPER_BOUND 100
_Unwind_Reason_Code callback(_Unwind_Context *context, void *cnt) {
+ (void)context;
int *i = (int *)cnt;
++*i;
if (*i > NUM_FRAMES_UPPER_BOUND) {
diff --git a/test/lit.cfg b/test/lit.cfg
new file mode 100644
index 0000000..272bc16
--- /dev/null
+++ b/test/lit.cfg
@@ -0,0 +1,67 @@
+# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
+
+# Configuration file for the 'lit' test runner.
+
+
+import os
+import site
+
+site.addsitedir(os.path.dirname(__file__))
+
+
+# Tell pylint that we know config and lit_config exist somewhere.
+if 'PYLINT_IMPORT' in os.environ:
+ config = object()
+ lit_config = object()
+
+# name: The name of this test suite.
+config.name = 'libunwind'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.cpp', '.s']
+
+# test_source_root: The root path where tests are located.
+config.test_source_root = os.path.dirname(__file__)
+
+# Infer the libcxx_test_source_root for configuration import.
+# If libcxx_source_root isn't specified in the config, assume that the libcxx
+# and libunwind source directories are sibling directories.
+libcxx_src_root = getattr(config, 'libcxx_src_root', None)
+if not libcxx_src_root:
+ libcxx_src_root = os.path.join(config.test_source_root, '../../libcxx')
+libcxx_test_src_root = os.path.join(libcxx_src_root, 'utils')
+if os.path.isfile(os.path.join(libcxx_test_src_root, 'libcxx', '__init__.py')):
+ site.addsitedir(libcxx_test_src_root)
+else:
+ lit_config.fatal('Could not find libcxx test directory for test imports'
+ ' in: %s' % libcxx_test_src_root)
+
+# Infer the test_exec_root from the libcxx_object root.
+obj_root = getattr(config, 'libunwind_obj_root', None)
+
+# Check that the test exec root is known.
+if obj_root is None:
+ import libcxx.test.config
+ libcxx.test.config.loadSiteConfig(
+ lit_config, config, 'libunwind_site_config', 'LIBUNWIND_SITE_CONFIG')
+ obj_root = getattr(config, 'libunwind_obj_root', None)
+ if obj_root is None:
+ import tempfile
+ obj_root = tempfile.mkdtemp(prefix='libunwind-testsuite-')
+ lit_config.warning('Creating temporary directory for object root: %s' %
+ obj_root)
+
+config.test_exec_root = os.path.join(obj_root, 'test')
+
+cfg_variant = getattr(config, 'configuration_variant', 'libunwind')
+if cfg_variant:
+ lit_config.note('Using configuration variant: %s' % cfg_variant)
+
+# Load the Configuration class from the module name <cfg_variant>.test.config.
+config_module_name = '.'.join([cfg_variant, 'test', 'config'])
+config_module = __import__(config_module_name, fromlist=['Configuration'])
+
+configuration = config_module.Configuration(lit_config, config)
+configuration.configure()
+configuration.print_config_info()
+config.test_format = configuration.get_test_format()
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
new file mode 100644
index 0000000..888b960
--- /dev/null
+++ b/test/lit.site.cfg.in
@@ -0,0 +1,27 @@
+@AUTO_GEN_COMMENT@
+config.cxx_under_test = "@LIBUNWIND_COMPILER@"
+config.project_obj_root = "@CMAKE_BINARY_DIR@"
+config.libunwind_src_root = "@LIBUNWIND_SOURCE_DIR@"
+config.libunwind_obj_root = "@LIBUNWIND_BINARY_DIR@"
+config.abi_library_path = "@LIBUNWIND_LIBRARY_DIR@"
+config.libcxx_src_root = "@LIBUNWIND_LIBCXX_PATH@"
+config.libunwind_headers = "@LIBUNWIND_SOURCE_DIR@/include"
+config.cxx_library_root = "@LIBUNWIND_LIBCXX_LIBRARY_PATH@"
+config.llvm_unwinder = "1"
+config.enable_threads = "@LIBUNWIND_ENABLE_THREADS@"
+config.use_sanitizer = "@LLVM_USE_SANITIZER@"
+config.enable_32bit = "@LIBUNWIND_BUILD_32_BITS@"
+config.target_info = "@LIBUNWIND_TARGET_INFO@"
+config.executor = "@LIBUNWIND_EXECUTOR@"
+config.libunwind_shared = "@LIBUNWIND_ENABLE_SHARED@"
+config.enable_shared = "@LIBCXX_ENABLE_SHARED@"
+config.enable_exceptions = "@LIBUNWIND_ENABLE_EXCEPTIONS@"
+config.host_triple = "@LLVM_HOST_TRIPLE@"
+config.target_triple = "@TARGET_TRIPLE@"
+config.use_target = len("@LIBUNWIND_TARGET_TRIPLE@") > 0
+config.sysroot = "@LIBUNWIND_SYSROOT@"
+config.gcc_toolchain = "@LIBUNWIND_GCC_TOOLCHAIN@"
+config.cxx_ext_threads = "@LIBUNWIND_BUILD_EXTERNAL_THREAD_LIBRARY@"
+
+# Let the main config do the real work.
+lit_config.load_config(config, "@LIBUNWIND_SOURCE_DIR@/test/lit.cfg")