aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE.TXT76
-rw-r--r--include/__libunwind_config.h112
-rw-r--r--include/libunwind.h350
-rw-r--r--include/mach-o/compact_unwind_encoding.h32
-rw-r--r--include/unwind.h59
-rw-r--r--src/AddressSpace.hpp380
-rw-r--r--src/CompactUnwinder.hpp9
-rw-r--r--src/DwarfInstructions.hpp55
-rw-r--r--src/DwarfParser.hpp338
-rw-r--r--src/EHHeaderParser.hpp7
-rw-r--r--src/RWMutex.hpp77
-rw-r--r--src/Registers.hpp1713
-rw-r--r--src/Unwind-EHABI.cpp164
-rw-r--r--src/Unwind-EHABI.h4
-rw-r--r--src/Unwind-seh.cpp491
-rw-r--r--src/Unwind-sjlj.c138
-rw-r--r--src/UnwindCursor.hpp721
-rw-r--r--src/UnwindLevel1-gcc-ext.c88
-rw-r--r--src/UnwindLevel1.c109
-rw-r--r--src/UnwindRegistersRestore.S567
-rw-r--r--src/UnwindRegistersSave.S582
-rw-r--r--src/Unwind_AppleExtras.cpp31
-rw-r--r--src/assembly.h60
-rw-r--r--src/config.h126
-rw-r--r--src/dwarf2.h5
-rw-r--r--src/libunwind.cpp95
-rw-r--r--src/libunwind_ext.h2
-rw-r--r--src/unwind_ext.h37
28 files changed, 5563 insertions, 865 deletions
diff --git a/LICENSE.TXT b/LICENSE.TXT
new file mode 100644
index 000000000000..23109b4aa7bb
--- /dev/null
+++ b/LICENSE.TXT
@@ -0,0 +1,76 @@
+==============================================================================
+libunwind License
+==============================================================================
+
+The libunwind library is dual licensed under both the University of Illinois
+"BSD-Like" license and the MIT license. As a user of this code you may choose
+to use it under either license. As a contributor, you agree to allow your code
+to be used under both.
+
+Full text of the relevant licenses is included below.
+
+==============================================================================
+
+University of Illinois/NCSA
+Open Source License
+
+Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
+
+All rights reserved.
+
+Developed by:
+
+ LLVM Team
+
+ University of Illinois at Urbana-Champaign
+
+ http://llvm.org
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal with
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimers.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimers in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the names of the LLVM Team, University of Illinois at
+ Urbana-Champaign, nor the names of its contributors may be used to
+ endorse or promote products derived from this Software without specific
+ prior written permission.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
+SOFTWARE.
+
+==============================================================================
+
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/include/__libunwind_config.h b/include/__libunwind_config.h
index 099d133e744b..a8e30de13a6a 100644
--- a/include/__libunwind_config.h
+++ b/include/__libunwind_config.h
@@ -12,48 +12,130 @@
#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
!defined(__ARM_DWARF_EH__)
-#define _LIBUNWIND_ARM_EHABI 1
-#else
-#define _LIBUNWIND_ARM_EHABI 0
+#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_PPC64 116
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
+
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# if defined(__i386__)
-# define _LIBUNWIND_TARGET_I386 1
+# define _LIBUNWIND_TARGET_I386
# define _LIBUNWIND_CONTEXT_SIZE 8
-# define _LIBUNWIND_CURSOR_SIZE 19
+# 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
+# if defined(_WIN64)
+# define _LIBUNWIND_CONTEXT_SIZE 54
+# ifdef __SEH__
+# define _LIBUNWIND_CURSOR_SIZE 204
+# else
+# define _LIBUNWIND_CURSOR_SIZE 66
+# endif
+# 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(__powerpc64__)
+# define _LIBUNWIND_TARGET_PPC64 1
+# define _LIBUNWIND_CONTEXT_SIZE 167
+# define _LIBUNWIND_CURSOR_SIZE 179
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64
# elif defined(__ppc__)
# define _LIBUNWIND_TARGET_PPC 1
# define _LIBUNWIND_CONTEXT_SIZE 117
-# define _LIBUNWIND_CURSOR_SIZE 128
+# 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
+# if defined(__SEH__)
+# define _LIBUNWIND_CURSOR_SIZE 164
+# else
+# define _LIBUNWIND_CURSOR_SIZE 78
+# endif
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
# elif defined(__arm__)
# define _LIBUNWIND_TARGET_ARM 1
-# define _LIBUNWIND_CONTEXT_SIZE 60
-# define _LIBUNWIND_CURSOR_SIZE 67
+# if defined(__SEH__)
+# define _LIBUNWIND_CONTEXT_SIZE 42
+# define _LIBUNWIND_CURSOR_SIZE 80
+# elif defined(__ARM_WMMX)
+# 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 _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_CURSOR_SIZE 24
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K
+# elif defined(__mips__)
+# if defined(_ABIO32) && _MIPS_SIM == _ABIO32
+# define _LIBUNWIND_TARGET_MIPS_O32 1
+# if defined(__mips_hard_float)
+# define _LIBUNWIND_CONTEXT_SIZE 50
+# define _LIBUNWIND_CURSOR_SIZE 57
+# else
+# define _LIBUNWIND_CONTEXT_SIZE 18
+# define _LIBUNWIND_CURSOR_SIZE 24
+# endif
+# elif defined(_ABIN32) && _MIPS_SIM == _ABIN32
+# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+# if defined(__mips_hard_float)
+# define _LIBUNWIND_CONTEXT_SIZE 67
+# define _LIBUNWIND_CURSOR_SIZE 74
+# else
+# define _LIBUNWIND_CONTEXT_SIZE 35
+# define _LIBUNWIND_CURSOR_SIZE 42
+# endif
+# elif defined(_ABI64) && _MIPS_SIM == _ABI64
+# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+# if defined(__mips_hard_float)
+# define _LIBUNWIND_CONTEXT_SIZE 67
+# define _LIBUNWIND_CURSOR_SIZE 79
+# else
+# define _LIBUNWIND_CONTEXT_SIZE 35
+# define _LIBUNWIND_CURSOR_SIZE 47
+# endif
+# else
+# error "Unsupported MIPS ABI and/or environment"
+# endif
+# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
+# elif defined(__sparc__)
+ #define _LIBUNWIND_TARGET_SPARC 1
+ #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
+ #define _LIBUNWIND_CONTEXT_SIZE 16
+ #define _LIBUNWIND_CURSOR_SIZE 23
# else
# error "Unsupported architecture."
# endif
#else // !_LIBUNWIND_IS_NATIVE_ONLY
-# define _LIBUNWIND_TARGET_I386 1
+# define _LIBUNWIND_TARGET_I386
# define _LIBUNWIND_TARGET_X86_64 1
# define _LIBUNWIND_TARGET_PPC 1
+# define _LIBUNWIND_TARGET_PPC64 1
# define _LIBUNWIND_TARGET_AARCH64 1
# define _LIBUNWIND_TARGET_ARM 1
# define _LIBUNWIND_TARGET_OR1K 1
-# define _LIBUNWIND_CONTEXT_SIZE 128
-# define _LIBUNWIND_CURSOR_SIZE 140
+# define _LIBUNWIND_TARGET_MIPS_O32 1
+# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+# define _LIBUNWIND_TARGET_SPARC 1
+# define _LIBUNWIND_CONTEXT_SIZE 167
+# define _LIBUNWIND_CURSOR_SIZE 179
+# 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 c5b9633b1506..29c4aebde5ac 100644
--- a/include/libunwind.h
+++ b/include/libunwind.h
@@ -6,7 +6,7 @@
// Source Licenses. See LICENSE.TXT for details.
//
//
-// Compatible with libuwind API documented at:
+// Compatible with libunwind API documented at:
// http://www.nongnu.org/libunwind/man/libunwind(3).html
//
//===----------------------------------------------------------------------===//
@@ -20,12 +20,26 @@
#include <stddef.h>
#ifdef __APPLE__
- #include <Availability.h>
- #ifdef __arm__
- #define LIBUNWIND_AVAIL __attribute__((unavailable))
+ #if __clang__
+ #if __has_include(<Availability.h>)
+ #include <Availability.h>
+ #endif
+ #elif __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050
+ #include <Availability.h>
+ #endif
+
+ #ifdef __arm__
+ #define LIBUNWIND_AVAIL __attribute__((unavailable))
+ #elif defined(__OSX_AVAILABLE_STARTING)
+ #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
+ #else
+ #include <AvailabilityMacros.h>
+ #ifdef AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
+ #define LIBUNWIND_AVAIL AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER
#else
- #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
+ #define LIBUNWIND_AVAIL __attribute__((unavailable))
#endif
+ #endif
#else
#define LIBUNWIND_AVAIL
#endif
@@ -43,6 +57,9 @@ enum {
UNW_EINVAL = -6547, /* unsupported operation or bad value */
UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
UNW_ENOINFO = -6549 /* no unwind info found */
+#if defined(_LIBUNWIND_TARGET_AARCH64) && !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+ , UNW_ECROSSRASIGNING = -6550 /* cross unwind with return address signing */
+#endif
};
struct unw_context_t {
@@ -58,11 +75,10 @@ typedef struct unw_cursor_t unw_cursor_t;
typedef struct unw_addr_space *unw_addr_space_t;
typedef int unw_regnum_t;
-#if _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
@@ -75,8 +91,8 @@ struct unw_proc_info_t {
unw_word_t gp; /* not used */
unw_word_t flags; /* not used */
uint32_t format; /* compact unwind encoding, or zero if none */
- uint32_t unwind_info_size; /* size of dwarf unwind info, or zero if none */
- unw_word_t unwind_info; /* address of dwarf unwind info, or zero */
+ uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
+ unw_word_t unwind_info; /* address of DWARF unwind info, or zero */
unw_word_t extra; /* mach_header of mach-o image containing func */
};
typedef struct unw_proc_info_t unw_proc_info_t;
@@ -120,7 +136,7 @@ extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *);
#endif /* UNW_REMOTE */
/*
- * traditional libuwind "remote" API
+ * traditional libunwind "remote" API
* NOT IMPLEMENTED on Mac OS X
*
* extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t,
@@ -174,7 +190,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,
};
@@ -295,6 +328,190 @@ enum {
UNW_PPC_SPEFSCR = 112
};
+// 64-bit ppc register numbers
+enum {
+ UNW_PPC64_R0 = 0,
+ UNW_PPC64_R1 = 1,
+ UNW_PPC64_R2 = 2,
+ UNW_PPC64_R3 = 3,
+ UNW_PPC64_R4 = 4,
+ UNW_PPC64_R5 = 5,
+ UNW_PPC64_R6 = 6,
+ UNW_PPC64_R7 = 7,
+ UNW_PPC64_R8 = 8,
+ UNW_PPC64_R9 = 9,
+ UNW_PPC64_R10 = 10,
+ UNW_PPC64_R11 = 11,
+ UNW_PPC64_R12 = 12,
+ UNW_PPC64_R13 = 13,
+ UNW_PPC64_R14 = 14,
+ UNW_PPC64_R15 = 15,
+ UNW_PPC64_R16 = 16,
+ UNW_PPC64_R17 = 17,
+ UNW_PPC64_R18 = 18,
+ UNW_PPC64_R19 = 19,
+ UNW_PPC64_R20 = 20,
+ UNW_PPC64_R21 = 21,
+ UNW_PPC64_R22 = 22,
+ UNW_PPC64_R23 = 23,
+ UNW_PPC64_R24 = 24,
+ UNW_PPC64_R25 = 25,
+ UNW_PPC64_R26 = 26,
+ UNW_PPC64_R27 = 27,
+ UNW_PPC64_R28 = 28,
+ UNW_PPC64_R29 = 29,
+ UNW_PPC64_R30 = 30,
+ UNW_PPC64_R31 = 31,
+ UNW_PPC64_F0 = 32,
+ UNW_PPC64_F1 = 33,
+ UNW_PPC64_F2 = 34,
+ UNW_PPC64_F3 = 35,
+ UNW_PPC64_F4 = 36,
+ UNW_PPC64_F5 = 37,
+ UNW_PPC64_F6 = 38,
+ UNW_PPC64_F7 = 39,
+ UNW_PPC64_F8 = 40,
+ UNW_PPC64_F9 = 41,
+ UNW_PPC64_F10 = 42,
+ UNW_PPC64_F11 = 43,
+ UNW_PPC64_F12 = 44,
+ UNW_PPC64_F13 = 45,
+ UNW_PPC64_F14 = 46,
+ UNW_PPC64_F15 = 47,
+ UNW_PPC64_F16 = 48,
+ UNW_PPC64_F17 = 49,
+ UNW_PPC64_F18 = 50,
+ UNW_PPC64_F19 = 51,
+ UNW_PPC64_F20 = 52,
+ UNW_PPC64_F21 = 53,
+ UNW_PPC64_F22 = 54,
+ UNW_PPC64_F23 = 55,
+ UNW_PPC64_F24 = 56,
+ UNW_PPC64_F25 = 57,
+ UNW_PPC64_F26 = 58,
+ UNW_PPC64_F27 = 59,
+ UNW_PPC64_F28 = 60,
+ UNW_PPC64_F29 = 61,
+ UNW_PPC64_F30 = 62,
+ UNW_PPC64_F31 = 63,
+ // 64: reserved
+ UNW_PPC64_LR = 65,
+ UNW_PPC64_CTR = 66,
+ // 67: reserved
+ UNW_PPC64_CR0 = 68,
+ UNW_PPC64_CR1 = 69,
+ UNW_PPC64_CR2 = 70,
+ UNW_PPC64_CR3 = 71,
+ UNW_PPC64_CR4 = 72,
+ UNW_PPC64_CR5 = 73,
+ UNW_PPC64_CR6 = 74,
+ UNW_PPC64_CR7 = 75,
+ UNW_PPC64_XER = 76,
+ UNW_PPC64_V0 = 77,
+ UNW_PPC64_V1 = 78,
+ UNW_PPC64_V2 = 79,
+ UNW_PPC64_V3 = 80,
+ UNW_PPC64_V4 = 81,
+ UNW_PPC64_V5 = 82,
+ UNW_PPC64_V6 = 83,
+ UNW_PPC64_V7 = 84,
+ UNW_PPC64_V8 = 85,
+ UNW_PPC64_V9 = 86,
+ UNW_PPC64_V10 = 87,
+ UNW_PPC64_V11 = 88,
+ UNW_PPC64_V12 = 89,
+ UNW_PPC64_V13 = 90,
+ UNW_PPC64_V14 = 91,
+ UNW_PPC64_V15 = 92,
+ UNW_PPC64_V16 = 93,
+ UNW_PPC64_V17 = 94,
+ UNW_PPC64_V18 = 95,
+ UNW_PPC64_V19 = 96,
+ UNW_PPC64_V20 = 97,
+ UNW_PPC64_V21 = 98,
+ UNW_PPC64_V22 = 99,
+ UNW_PPC64_V23 = 100,
+ UNW_PPC64_V24 = 101,
+ UNW_PPC64_V25 = 102,
+ UNW_PPC64_V26 = 103,
+ UNW_PPC64_V27 = 104,
+ UNW_PPC64_V28 = 105,
+ UNW_PPC64_V29 = 106,
+ UNW_PPC64_V30 = 107,
+ UNW_PPC64_V31 = 108,
+ // 109, 111-113: OpenPOWER ELF V2 ABI: reserved
+ // Borrowing VRSAVE number from PPC32.
+ UNW_PPC64_VRSAVE = 109,
+ UNW_PPC64_VSCR = 110,
+ UNW_PPC64_TFHAR = 114,
+ UNW_PPC64_TFIAR = 115,
+ UNW_PPC64_TEXASR = 116,
+ UNW_PPC64_VS0 = UNW_PPC64_F0,
+ UNW_PPC64_VS1 = UNW_PPC64_F1,
+ UNW_PPC64_VS2 = UNW_PPC64_F2,
+ UNW_PPC64_VS3 = UNW_PPC64_F3,
+ UNW_PPC64_VS4 = UNW_PPC64_F4,
+ UNW_PPC64_VS5 = UNW_PPC64_F5,
+ UNW_PPC64_VS6 = UNW_PPC64_F6,
+ UNW_PPC64_VS7 = UNW_PPC64_F7,
+ UNW_PPC64_VS8 = UNW_PPC64_F8,
+ UNW_PPC64_VS9 = UNW_PPC64_F9,
+ UNW_PPC64_VS10 = UNW_PPC64_F10,
+ UNW_PPC64_VS11 = UNW_PPC64_F11,
+ UNW_PPC64_VS12 = UNW_PPC64_F12,
+ UNW_PPC64_VS13 = UNW_PPC64_F13,
+ UNW_PPC64_VS14 = UNW_PPC64_F14,
+ UNW_PPC64_VS15 = UNW_PPC64_F15,
+ UNW_PPC64_VS16 = UNW_PPC64_F16,
+ UNW_PPC64_VS17 = UNW_PPC64_F17,
+ UNW_PPC64_VS18 = UNW_PPC64_F18,
+ UNW_PPC64_VS19 = UNW_PPC64_F19,
+ UNW_PPC64_VS20 = UNW_PPC64_F20,
+ UNW_PPC64_VS21 = UNW_PPC64_F21,
+ UNW_PPC64_VS22 = UNW_PPC64_F22,
+ UNW_PPC64_VS23 = UNW_PPC64_F23,
+ UNW_PPC64_VS24 = UNW_PPC64_F24,
+ UNW_PPC64_VS25 = UNW_PPC64_F25,
+ UNW_PPC64_VS26 = UNW_PPC64_F26,
+ UNW_PPC64_VS27 = UNW_PPC64_F27,
+ UNW_PPC64_VS28 = UNW_PPC64_F28,
+ UNW_PPC64_VS29 = UNW_PPC64_F29,
+ UNW_PPC64_VS30 = UNW_PPC64_F30,
+ UNW_PPC64_VS31 = UNW_PPC64_F31,
+ UNW_PPC64_VS32 = UNW_PPC64_V0,
+ UNW_PPC64_VS33 = UNW_PPC64_V1,
+ UNW_PPC64_VS34 = UNW_PPC64_V2,
+ UNW_PPC64_VS35 = UNW_PPC64_V3,
+ UNW_PPC64_VS36 = UNW_PPC64_V4,
+ UNW_PPC64_VS37 = UNW_PPC64_V5,
+ UNW_PPC64_VS38 = UNW_PPC64_V6,
+ UNW_PPC64_VS39 = UNW_PPC64_V7,
+ UNW_PPC64_VS40 = UNW_PPC64_V8,
+ UNW_PPC64_VS41 = UNW_PPC64_V9,
+ UNW_PPC64_VS42 = UNW_PPC64_V10,
+ UNW_PPC64_VS43 = UNW_PPC64_V11,
+ UNW_PPC64_VS44 = UNW_PPC64_V12,
+ UNW_PPC64_VS45 = UNW_PPC64_V13,
+ UNW_PPC64_VS46 = UNW_PPC64_V14,
+ UNW_PPC64_VS47 = UNW_PPC64_V15,
+ UNW_PPC64_VS48 = UNW_PPC64_V16,
+ UNW_PPC64_VS49 = UNW_PPC64_V17,
+ UNW_PPC64_VS50 = UNW_PPC64_V18,
+ UNW_PPC64_VS51 = UNW_PPC64_V19,
+ UNW_PPC64_VS52 = UNW_PPC64_V20,
+ UNW_PPC64_VS53 = UNW_PPC64_V21,
+ UNW_PPC64_VS54 = UNW_PPC64_V22,
+ UNW_PPC64_VS55 = UNW_PPC64_V23,
+ UNW_PPC64_VS56 = UNW_PPC64_V24,
+ UNW_PPC64_VS57 = UNW_PPC64_V25,
+ UNW_PPC64_VS58 = UNW_PPC64_V26,
+ UNW_PPC64_VS59 = UNW_PPC64_V27,
+ UNW_PPC64_VS60 = UNW_PPC64_V28,
+ UNW_PPC64_VS61 = UNW_PPC64_V29,
+ UNW_PPC64_VS62 = UNW_PPC64_V30,
+ UNW_PPC64_VS63 = UNW_PPC64_V31
+};
+
// 64-bit ARM64 registers
enum {
UNW_ARM64_X0 = 0,
@@ -333,6 +550,8 @@ enum {
UNW_ARM64_X31 = 31,
UNW_ARM64_SP = 31,
// reserved block
+ UNW_ARM64_RA_SIGN_STATE = 34,
+ // reserved block
UNW_ARM64_D0 = 64,
UNW_ARM64_D1 = 65,
UNW_ARM64_D2 = 66,
@@ -531,6 +750,113 @@ enum {
UNW_OR1K_R29 = 29,
UNW_OR1K_R30 = 30,
UNW_OR1K_R31 = 31,
+ UNW_OR1K_EPCR = 32,
+};
+
+// 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_F0 = 32,
+ UNW_MIPS_F1 = 33,
+ UNW_MIPS_F2 = 34,
+ UNW_MIPS_F3 = 35,
+ UNW_MIPS_F4 = 36,
+ UNW_MIPS_F5 = 37,
+ UNW_MIPS_F6 = 38,
+ UNW_MIPS_F7 = 39,
+ UNW_MIPS_F8 = 40,
+ UNW_MIPS_F9 = 41,
+ UNW_MIPS_F10 = 42,
+ UNW_MIPS_F11 = 43,
+ UNW_MIPS_F12 = 44,
+ UNW_MIPS_F13 = 45,
+ UNW_MIPS_F14 = 46,
+ UNW_MIPS_F15 = 47,
+ UNW_MIPS_F16 = 48,
+ UNW_MIPS_F17 = 49,
+ UNW_MIPS_F18 = 50,
+ UNW_MIPS_F19 = 51,
+ UNW_MIPS_F20 = 52,
+ UNW_MIPS_F21 = 53,
+ UNW_MIPS_F22 = 54,
+ UNW_MIPS_F23 = 55,
+ UNW_MIPS_F24 = 56,
+ UNW_MIPS_F25 = 57,
+ UNW_MIPS_F26 = 58,
+ UNW_MIPS_F27 = 59,
+ UNW_MIPS_F28 = 60,
+ UNW_MIPS_F29 = 61,
+ UNW_MIPS_F30 = 62,
+ UNW_MIPS_F31 = 63,
+ UNW_MIPS_HI = 64,
+ UNW_MIPS_LO = 65,
+};
+
+// SPARC registers
+enum {
+ UNW_SPARC_G0 = 0,
+ UNW_SPARC_G1 = 1,
+ UNW_SPARC_G2 = 2,
+ UNW_SPARC_G3 = 3,
+ UNW_SPARC_G4 = 4,
+ UNW_SPARC_G5 = 5,
+ UNW_SPARC_G6 = 6,
+ UNW_SPARC_G7 = 7,
+ UNW_SPARC_O0 = 8,
+ UNW_SPARC_O1 = 9,
+ UNW_SPARC_O2 = 10,
+ UNW_SPARC_O3 = 11,
+ UNW_SPARC_O4 = 12,
+ UNW_SPARC_O5 = 13,
+ UNW_SPARC_O6 = 14,
+ UNW_SPARC_O7 = 15,
+ UNW_SPARC_L0 = 16,
+ UNW_SPARC_L1 = 17,
+ UNW_SPARC_L2 = 18,
+ UNW_SPARC_L3 = 19,
+ UNW_SPARC_L4 = 20,
+ UNW_SPARC_L5 = 21,
+ UNW_SPARC_L6 = 22,
+ UNW_SPARC_L7 = 23,
+ UNW_SPARC_I0 = 24,
+ UNW_SPARC_I1 = 25,
+ UNW_SPARC_I2 = 26,
+ UNW_SPARC_I3 = 27,
+ UNW_SPARC_I4 = 28,
+ UNW_SPARC_I5 = 29,
+ UNW_SPARC_I6 = 30,
+ UNW_SPARC_I7 = 31,
};
#endif
diff --git a/include/mach-o/compact_unwind_encoding.h b/include/mach-o/compact_unwind_encoding.h
index b71c2c8f5b79..de14fd51e53e 100644
--- a/include/mach-o/compact_unwind_encoding.h
+++ b/include/mach-o/compact_unwind_encoding.h
@@ -6,7 +6,7 @@
// Source Licenses. See LICENSE.TXT for details.
//
//
-// Darwin's alternative to dwarf based unwind encodings.
+// Darwin's alternative to DWARF based unwind encodings.
//
//===----------------------------------------------------------------------===//
@@ -17,7 +17,7 @@
#include <stdint.h>
//
-// Compilers can emit standard Dwarf FDEs in the __TEXT,__eh_frame section
+// Compilers can emit standard DWARF FDEs in the __TEXT,__eh_frame section
// of object files. Or compilers can emit compact unwind information in
// the __LD,__compact_unwind section.
//
@@ -26,10 +26,10 @@
// runtime to access unwind info for any given function. If the compiler
// emitted compact unwind info for the function, that compact unwind info will
// be encoded in the __TEXT,__unwind_info section. If the compiler emitted
-// dwarf unwind info, the __TEXT,__unwind_info section will contain the offset
+// DWARF unwind info, the __TEXT,__unwind_info section will contain the offset
// of the FDE in the __TEXT,__eh_frame section in the final linked image.
//
-// Note: Previously, the linker would transform some dwarf unwind infos into
+// Note: Previously, the linker would transform some DWARF unwind infos into
// compact unwind info. But that is fragile and no longer done.
@@ -58,7 +58,7 @@ enum {
// 1-bit: has lsda
// 2-bit: personality index
//
-// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// 4-bits: 0=old, 1=ebp based, 2=stack-imm, 3=stack-ind, 4=DWARF
// ebp based:
// 15-bits (5*3-bits per reg) register permutation
// 8-bits for stack offset
@@ -128,9 +128,9 @@ enum {
// UNWIND_X86_FRAMELESS_STACK_SIZE.
// UNWIND_X86_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the
-// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
+// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
// This mode is never used in object files. It is only generated by the
-// linker in final linked images which have only dwarf unwind info for a
+// linker in final linked images which have only DWARF unwind info for a
// function.
//
// The permutation encoding is a Lehmer code sequence encoded into a
@@ -193,7 +193,7 @@ enum {
// 1-bit: has lsda
// 2-bit: personality index
//
-// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=dwarf
+// 4-bits: 0=old, 1=rbp based, 2=stack-imm, 3=stack-ind, 4=DWARF
// rbp based:
// 15-bits (5*3-bits per reg) register permutation
// 8-bits for stack offset
@@ -262,9 +262,9 @@ enum {
// UNWIND_X86_64_FRAMELESS_STACK_SIZE.
// UNWIND_X86_64_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the
-// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
+// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
// This mode is never used in object files. It is only generated by the
-// linker in final linked images which have only dwarf unwind info for a
+// linker in final linked images which have only DWARF unwind info for a
// function.
//
@@ -275,14 +275,14 @@ enum {
// 1-bit: has lsda
// 2-bit: personality index
//
-// 4-bits: 4=frame-based, 3=dwarf, 2=frameless
+// 4-bits: 4=frame-based, 3=DWARF, 2=frameless
// frameless:
// 12-bits of stack size
// frame-based:
// 4-bits D reg pairs saved
// 5-bits X reg pairs saved
-// dwarf:
-// 24-bits offset of dwarf FDE in __eh_frame section
+// DWARF:
+// 24-bits offset of DWARF FDE in __eh_frame section
//
enum {
UNWIND_ARM64_MODE_MASK = 0x0F000000,
@@ -320,9 +320,9 @@ enum {
// UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK.
// UNWIND_ARM64_MODE_DWARF:
// No compact unwind encoding is available. Instead the low 24-bits of the
-// compact encoding is the offset of the dwarf FDE in the __eh_frame section.
+// compact encoding is the offset of the DWARF FDE in the __eh_frame section.
// This mode is never used in object files. It is only generated by the
-// linker in final linked images which have only dwarf unwind info for a
+// linker in final linked images which have only DWARF unwind info for a
// function.
//
@@ -385,7 +385,7 @@ enum {
// saved at that range of the function.
//
// If a particular function is so wacky that there is no compact unwind way
-// to encode it, then the compiler can emit traditional dwarf unwind info.
+// to encode it, then the compiler can emit traditional DWARF unwind info.
// The runtime will use which ever is available.
//
// Runtime support for compact unwind encodings are only available on 10.6
diff --git a/include/unwind.h b/include/unwind.h
index 94880bfebaed..ae8ae5d24edc 100644
--- a/include/unwind.h
+++ b/include/unwind.h
@@ -19,6 +19,11 @@
#include <stdint.h>
#include <stddef.h>
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) && defined(_WIN32)
+#include <windows.h>
+#include <ntverp.h>
+#endif
+
#if defined(__APPLE__)
#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
#else
@@ -36,7 +41,7 @@ typedef enum {
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8,
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
_URC_FAILURE = 9
#endif
} _Unwind_Reason_Code;
@@ -51,12 +56,13 @@ typedef enum {
typedef struct _Unwind_Context _Unwind_Context; // opaque
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
typedef uint32_t _Unwind_State;
static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME = 0;
static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
static const _Unwind_State _US_UNWIND_FRAME_RESUME = 2;
+static const _Unwind_State _US_ACTION_MASK = 3;
/* Undocumented flag for force unwinding. */
static const _Unwind_State _US_FORCE_UNWIND = 8;
@@ -99,7 +105,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,
@@ -119,16 +125,23 @@ struct _Unwind_Exception {
uint64_t exception_class;
void (*exception_cleanup)(_Unwind_Reason_Code reason,
_Unwind_Exception *exc);
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+ uintptr_t private_[6];
+#else
uintptr_t private_1; // non-zero means forced unwind
uintptr_t private_2; // holds sp that phase1 found for phase2 to use
-#ifndef __LP64__
- // The gcc implementation of _Unwind_Exception used attribute mode on the
- // above fields which had the side effect of causing this whole struct to
- // round up to 32 bytes in size. To be more explicit, we add pad fields
- // added for binary compatibility.
+#endif
+#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 (48 with SEH). To be more explicit, we add
+ // pad fields added for binary compatibility.
uint32_t reserved[3];
#endif
-};
+ // The Itanium ABI requires that _Unwind_Exception objects are "double-word
+ // aligned". GCC has interpreted this to mean "use the maximum useful
+ // alignment for the target"; so do we.
+} __attribute__((__aligned__));
typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
(int version,
@@ -164,7 +177,7 @@ extern void _Unwind_Resume(_Unwind_Exception *exception_object);
#endif
extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
typedef enum {
_UVRSC_CORE = 0, /* integer register */
_UVRSC_VFP = 1, /* vfp */
@@ -204,7 +217,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
_Unwind_VRS_DataRepresentation representation);
#endif
-#if !_LIBUNWIND_ARM_EHABI
+#if !defined(_LIBUNWIND_ARM_EHABI)
extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
@@ -212,7 +225,7 @@ extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
-#else // _LIBUNWIND_ARM_EHABI
+#else // defined(_LIBUNWIND_ARM_EHABI)
#if defined(_LIBUNWIND_UNWIND_LEVEL1_EXTERNAL_LINKAGE)
#define _LIBUNWIND_EXPORT_UNWIND_LEVEL1 extern
@@ -251,7 +264,7 @@ void _Unwind_SetIP(struct _Unwind_Context *context, uintptr_t value) {
uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
_Unwind_SetGR(context, 15, value | thumb_bit);
}
-#endif // _LIBUNWIND_ARM_EHABI
+#endif // defined(_LIBUNWIND_ARM_EHABI)
extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
extern uintptr_t
@@ -321,7 +334,7 @@ extern void __deregister_frame(const void *fde);
// _Unwind_Find_FDE() will locate the FDE if the pc is in some function that has
// an associated FDE. Note, Mac OS X 10.6 and later, introduces "compact unwind
-// info" which the runtime uses in preference to dwarf unwind info. This
+// info" which the runtime uses in preference to DWARF unwind info. This
// function will only work if the target function has an FDE but no compact
// unwind info.
struct dwarf_eh_bases {
@@ -334,7 +347,7 @@ extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
// This function attempts to find the start (address of first instruction) of
// a function given an address inside the function. It only works if the
-// function has an FDE (dwarf unwind info).
+// function has an FDE (DWARF unwind info).
// This function is unimplemented on Mac OS X 10.6 and later. Instead, use
// _Unwind_Find_FDE() and look at the dwarf_eh_bases.func result.
extern void *_Unwind_FindEnclosingFunction(void *pc);
@@ -365,6 +378,22 @@ extern void *__deregister_frame_info(const void *fde)
extern void *__deregister_frame_info_bases(const void *fde)
LIBUNWIND_UNAVAIL;
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#ifndef _WIN32
+typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
+typedef struct _CONTEXT CONTEXT;
+typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
+#elif !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
+typedef struct _DISPATCHER_CONTEXT DISPATCHER_CONTEXT;
+#endif
+// This is the common wrapper for GCC-style personality functions with SEH.
+extern EXCEPTION_DISPOSITION _GCC_specific_handler(EXCEPTION_RECORD *exc,
+ void *frame,
+ CONTEXT *ctx,
+ DISPATCHER_CONTEXT *disp,
+ __personality_routine pers);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/src/AddressSpace.hpp b/src/AddressSpace.hpp
index da1b6a43e492..30ad35995aec 100644
--- a/src/AddressSpace.hpp
+++ b/src/AddressSpace.hpp
@@ -18,7 +18,15 @@
#include <stdlib.h>
#include <string.h>
-#ifndef _LIBUNWIND_IS_BAREMETAL
+#ifndef _LIBUNWIND_USE_DLADDR
+ #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
+ #define _LIBUNWIND_USE_DLADDR 1
+ #else
+ #define _LIBUNWIND_USE_DLADDR 0
+ #endif
+#endif
+
+#if _LIBUNWIND_USE_DLADDR
#include <dlfcn.h>
#endif
@@ -32,72 +40,137 @@ namespace libunwind {
#include "libunwind.h"
#include "config.h"
#include "dwarf2.h"
+#include "EHHeaderParser.hpp"
#include "Registers.hpp"
-#if _LIBUNWIND_ARM_EHABI
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#ifdef __APPLE__
-typedef void *_Unwind_Ptr;
+ 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
-#elif defined(__linux__)
+ // 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);
-typedef long unsigned int *_Unwind_Ptr;
-extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len);
+ if (!info->dwarf_section) {
+ info->dwarf_section_length = 0;
+ }
-// Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system.
-#define dl_unwind_find_exidx __gnu_Unwind_Find_exidx
+ if (!info->compact_unwind_section) {
+ info->compact_unwind_section_length = 0;
+ }
+
+ return true;
+ }
+ #endif
+
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
-#elif !defined(_LIBUNWIND_IS_BAREMETAL)
-#include <link.h>
-#else // !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.
-struct EHTEntry {
- uint32_t functionOffset;
- uint32_t unwindOpcodes;
-};
-extern EHTEntry __exidx_start;
-extern EHTEntry __exidx_end;
-#endif // !defined(_LIBUNWIND_IS_BAREMETAL)
-#endif // _LIBUNWIND_ARM_EHABI
-
-#if defined(__CloudABI__) || defined(__FreeBSD__) || defined(__linux__) || \
- defined(__NetBSD__)
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX
+
+// The following linker script may be used to produce the necessary sections and symbols.
+// Unless the --eh-frame-hdr linker option is provided, the section is not generated
+// and does not take space in the output file.
+//
+// .eh_frame :
+// {
+// __eh_frame_start = .;
+// KEEP(*(.eh_frame))
+// __eh_frame_end = .;
+// }
+//
+// .eh_frame_hdr :
+// {
+// KEEP(*(.eh_frame_hdr))
+// }
+//
+// __eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
+// __eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
+
+extern char __eh_frame_start;
+extern char __eh_frame_end;
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+extern char __eh_frame_hdr_start;
+extern char __eh_frame_hdr_end;
+#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>
-// Macro for machine-independent access to the ELF program headers. This
-// macro is not available on some systems (e.g., FreeBSD). On these
-// systems the data structures are just called Elf_XXX. Define ElfW()
-// locally.
+#else
+#include <windows.h>
+#include <psapi.h>
+#endif
#if !defined(ElfW)
#define ElfW(type) Elf_##type
#endif
-#include "EHHeaderParser.hpp"
-#endif
+
#endif
namespace libunwind {
/// Used by findUnwindSections() to return info about needed sections.
struct UnwindInfoSections {
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND || _LIBUNWIND_SUPPORT_DWARF_INDEX || \
- _LIBUNWIND_SUPPORT_COMPACT_UNWIND
- // No dso_base for ARM EHABI.
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) || defined(_LIBUNWIND_SUPPORT_DWARF_INDEX) || \
+ defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+ // No dso_base for SEH or ARM EHABI.
uintptr_t dso_base;
#endif
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
uintptr_t dwarf_section;
uintptr_t dwarf_section_length;
#endif
-#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
uintptr_t dwarf_index_section;
uintptr_t dwarf_index_section_length;
#endif
-#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
uintptr_t compact_unwind_section;
uintptr_t compact_unwind_section_length;
#endif
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
uintptr_t arm_section;
uintptr_t arm_section_length;
#endif
@@ -107,15 +180,10 @@ struct UnwindInfoSections {
/// LocalAddressSpace is used as a template parameter to UnwindCursor when
/// unwinding a thread in the same process. The wrappers compile away,
/// making local unwinds fast.
-class __attribute__((visibility("hidden"))) LocalAddressSpace {
+class _LIBUNWIND_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));
@@ -147,6 +215,7 @@ public:
return val;
}
uintptr_t getP(pint_t addr);
+ uint64_t getRegister(pint_t addr);
static uint64_t getULEB128(pint_t &addr, pint_t end);
static int64_t getSLEB128(pint_t &addr, pint_t end);
@@ -161,7 +230,15 @@ public:
};
inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
-#ifdef __LP64__
+#if __SIZEOF_POINTER__ == 8
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+}
+
+inline uint64_t LocalAddressSpace::getRegister(pint_t addr) {
+#if __SIZEOF_POINTER__ == 8 || defined(__mips64)
return get64(addr);
#else
return get32(addr);
@@ -209,7 +286,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;
}
@@ -306,55 +383,13 @@ 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.
- 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;
- const mach_header *mh = (const mach_header *)dlinfo.dli_saddr;
-
- // Find dwarf unwind section in that image.
- unsigned long size;
- const uint8_t *p = getsectiondata(mh, "__TEXT", "__eh_frame", &size);
- if (!p)
- return false;
-
- // Fill in return struct.
- info->mh = mh;
- info->dwarf_section = p;
- info->dwarf_section_length = size;
- info->compact_unwind_section = 0;
- info->compact_unwind_section_length = 0;
-
- return true;
- }
- #endif
-#endif
-
inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
UnwindInfoSections &info) {
#ifdef __APPLE__
dyld_unwind_sections dyldInfo;
if (_dyld_find_unwind_sections((void *)targetAddr, &dyldInfo)) {
info.dso_base = (uintptr_t)dyldInfo.mh;
- #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
info.dwarf_section_length = dyldInfo.dwarf_section_length;
#endif
@@ -362,23 +397,76 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
return true;
}
-#elif _LIBUNWIND_ARM_EHABI
- #ifdef _LIBUNWIND_IS_BAREMETAL
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
+ // Bare metal is statically linked, so no need to ask the dynamic loader
+ info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
+ info.dwarf_section = (uintptr_t)(&__eh_frame_start);
+ _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
+ (void *)info.dwarf_section, (void *)info.dwarf_section_length);
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+ info.dwarf_index_section = (uintptr_t)(&__eh_frame_hdr_start);
+ info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
+ _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
+ (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
+#endif
+ if (info.dwarf_section_length)
+ return true;
+#elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
// Bare metal is statically linked, so no need to ask the dynamic loader
info.arm_section = (uintptr_t)(&__exidx_start);
info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
- #else
+ _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
+ (void *)info.arm_section, (void *)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_SUPPORT_SEH_UNWIND) && defined(_WIN32)
+ // Don't even bother, since Windows has functions that do all this stuff
+ // for us.
+ return true;
+#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 =
+ (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
info.arm_section_length = (uintptr_t)length;
- #endif
- _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %X length %x\n",
- info.arm_section, info.arm_section_length);
if (info.arm_section && info.arm_section_length)
return true;
-#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
-#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+#elif defined(_LIBUNWIND_ARM_EHABI) || defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
struct dl_iterate_cb_data {
LocalAddressSpace *addressSpace;
UnwindInfoSections *sects;
@@ -389,7 +477,6 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
int found = dl_iterate_phdr(
[](struct dl_phdr_info *pinfo, size_t, void *data) -> int {
auto cbdata = static_cast<dl_iterate_cb_data *>(data);
- size_t object_length;
bool found_obj = false;
bool found_hdr = false;
@@ -406,11 +493,32 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
#if !defined(Elf_Phdr)
typedef ElfW(Phdr) Elf_Phdr;
#endif
+#if !defined(Elf_Addr) && defined(__ANDROID__)
+ typedef ElfW(Addr) Elf_Addr;
+#endif
+
+ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+ #if !defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+ #error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
+ #endif
+ size_t object_length;
+#if defined(__ANDROID__)
+ Elf_Addr image_base =
+ pinfo->dlpi_phnum
+ ? reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
+ reinterpret_cast<const Elf_Phdr *>(pinfo->dlpi_phdr)
+ ->p_offset
+ : 0;
+#endif
for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
if (phdr->p_type == PT_LOAD) {
uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
+#if defined(__ANDROID__)
+ if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
+ begin = begin + image_base;
+#endif
uintptr_t end = begin + phdr->p_memsz;
if (cbdata->targetAddr >= begin && cbdata->targetAddr < end) {
cbdata->sects->dso_base = begin;
@@ -420,6 +528,10 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
} else if (phdr->p_type == PT_GNU_EH_FRAME) {
EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
uintptr_t eh_frame_hdr_start = pinfo->dlpi_addr + phdr->p_vaddr;
+#if defined(__ANDROID__)
+ if (pinfo->dlpi_addr == 0 && phdr->p_vaddr < image_base)
+ eh_frame_hdr_start = eh_frame_hdr_start + image_base;
+#endif
cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
@@ -436,12 +548,26 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
} else {
return false;
}
+ #else // defined(_LIBUNWIND_ARM_EHABI)
+ for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
+ const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
+ if (phdr->p_type == PT_LOAD) {
+ uintptr_t begin = pinfo->dlpi_addr + phdr->p_vaddr;
+ uintptr_t end = begin + phdr->p_memsz;
+ if (cbdata->targetAddr >= begin && cbdata->targetAddr < end)
+ found_obj = true;
+ } else if (phdr->p_type == PT_ARM_EXIDX) {
+ uintptr_t exidx_start = pinfo->dlpi_addr + phdr->p_vaddr;
+ cbdata->sects->arm_section = exidx_start;
+ cbdata->sects->arm_section_length = phdr->p_memsz;
+ found_hdr = true;
+ }
+ }
+ return found_obj && found_hdr;
+ #endif
},
&cb_data);
return static_cast<bool>(found);
-#else
-#error "_LIBUNWIND_SUPPORT_DWARF_UNWIND requires _LIBUNWIND_SUPPORT_DWARF_INDEX on this platform."
-#endif
#endif
return false;
@@ -462,7 +588,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 _LIBUNWIND_USE_DLADDR
Dl_info dyldInfo;
if (dladdr((void *)addr, &dyldInfo)) {
if (dyldInfo.dli_sname != NULL) {
@@ -479,14 +605,14 @@ inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
#ifdef UNW_REMOTE
-/// OtherAddressSpace is used as a template parameter to UnwindCursor when
+/// RemoteAddressSpace is used as a template parameter to UnwindCursor when
/// unwinding a thread in the another process. The other process can be a
/// different endianness and a different pointer size which is handled by
/// the P template parameter.
template <typename P>
-class OtherAddressSpace {
+class RemoteAddressSpace {
public:
- OtherAddressSpace(task_t task) : fTask(task) {}
+ RemoteAddressSpace(task_t task) : fTask(task) {}
typedef typename P::uint_t pint_t;
@@ -495,6 +621,7 @@ public:
uint32_t get32(pint_t addr);
uint64_t get64(pint_t addr);
pint_t getP(pint_t addr);
+ uint64_t getRegister(pint_t addr);
uint64_t getULEB128(pint_t &addr, pint_t end);
int64_t getSLEB128(pint_t &addr, pint_t end);
pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
@@ -509,28 +636,33 @@ private:
task_t fTask;
};
-template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
+template <typename P> uint8_t RemoteAddressSpace<P>::get8(pint_t addr) {
return *((uint8_t *)localCopy(addr));
}
-template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
+template <typename P> uint16_t RemoteAddressSpace<P>::get16(pint_t addr) {
return P::E::get16(*(uint16_t *)localCopy(addr));
}
-template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
+template <typename P> uint32_t RemoteAddressSpace<P>::get32(pint_t addr) {
return P::E::get32(*(uint32_t *)localCopy(addr));
}
-template <typename P> uint64_t OtherAddressSpace<P>::get64(pint_t addr) {
+template <typename P> uint64_t RemoteAddressSpace<P>::get64(pint_t addr) {
return P::E::get64(*(uint64_t *)localCopy(addr));
}
template <typename P>
-typename P::uint_t OtherAddressSpace<P>::getP(pint_t addr) {
+typename P::uint_t RemoteAddressSpace<P>::getP(pint_t addr) {
return P::getP(*(uint64_t *)localCopy(addr));
}
template <typename P>
+typename P::uint_t OtherAddressSpace<P>::getRegister(pint_t addr) {
+ return P::getRegister(*(uint64_t *)localCopy(addr));
+}
+
+template <typename P>
uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
uintptr_t size = (end - addr);
LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
@@ -541,7 +673,7 @@ uint64_t OtherAddressSpace<P>::getULEB128(pint_t &addr, pint_t end) {
}
template <typename P>
-int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
+int64_t RemoteAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
uintptr_t size = (end - addr);
LocalAddressSpace::pint_t laddr = (LocalAddressSpace::pint_t) localCopy(addr);
LocalAddressSpace::pint_t sladdr = laddr;
@@ -550,13 +682,14 @@ int64_t OtherAddressSpace<P>::getSLEB128(pint_t &addr, pint_t end) {
return result;
}
-template <typename P> void *OtherAddressSpace<P>::localCopy(pint_t addr) {
+template <typename P> void *RemoteAddressSpace<P>::localCopy(pint_t addr) {
// FIX ME
}
template <typename P>
-bool OtherAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
- size_t bufLen, unw_word_t *offset) {
+bool RemoteAddressSpace<P>::findFunctionName(pint_t addr, char *buf,
+ size_t bufLen,
+ unw_word_t *offset) {
// FIX ME
}
@@ -572,7 +705,7 @@ struct unw_addr_space {
/// a 32-bit intel process.
struct unw_addr_space_i386 : public unw_addr_space {
unw_addr_space_i386(task_t task) : oas(task) {}
- OtherAddressSpace<Pointer32<LittleEndian> > oas;
+ RemoteAddressSpace<Pointer32<LittleEndian>> oas;
};
/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
@@ -580,7 +713,7 @@ struct unw_addr_space_i386 : public unw_addr_space {
/// a 64-bit intel process.
struct unw_addr_space_x86_64 : public unw_addr_space {
unw_addr_space_x86_64(task_t task) : oas(task) {}
- OtherAddressSpace<Pointer64<LittleEndian> > oas;
+ RemoteAddressSpace<Pointer64<LittleEndian>> oas;
};
/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
@@ -588,7 +721,14 @@ struct unw_addr_space_x86_64 : public unw_addr_space {
/// a 32-bit PowerPC process.
struct unw_addr_space_ppc : public unw_addr_space {
unw_addr_space_ppc(task_t task) : oas(task) {}
- OtherAddressSpace<Pointer32<BigEndian> > oas;
+ RemoteAddressSpace<Pointer32<BigEndian>> oas;
+};
+
+/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
+/// to when examining a 64-bit PowerPC process.
+struct unw_addr_space_ppc64 : public unw_addr_space {
+ unw_addr_space_ppc64(task_t task) : oas(task) {}
+ RemoteAddressSpace<Pointer64<LittleEndian>> oas;
};
#endif // UNW_REMOTE
diff --git a/src/CompactUnwinder.hpp b/src/CompactUnwinder.hpp
index f528fba984db..7b97bf84cebd 100644
--- a/src/CompactUnwinder.hpp
+++ b/src/CompactUnwinder.hpp
@@ -19,7 +19,6 @@
#include <libunwind.h>
#include <mach-o/compact_unwind_encoding.h>
-#include "AddressSpace.hpp"
#include "Registers.hpp"
#define EXTRACT_BITS(value, mask) \
@@ -105,7 +104,7 @@ int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
default:
(void)functionStart;
_LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
- "function starting at 0x%X\n",
+ "function starting at 0x%X",
compactEncoding, functionStart);
_LIBUNWIND_ABORT("invalid compact unwind encoding");
}
@@ -224,7 +223,7 @@ int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
break;
default:
_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
- "function starting at 0x%X\n",
+ "function starting at 0x%X",
encoding, functionStart);
_LIBUNWIND_ABORT("invalid compact unwind encoding");
}
@@ -336,7 +335,7 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
default:
(void)functionStart;
_LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
- "function starting at 0x%llX\n",
+ "function starting at 0x%llX",
compactEncoding, functionStart);
_LIBUNWIND_ABORT("invalid compact unwind encoding");
}
@@ -455,7 +454,7 @@ int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
break;
default:
_LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
- "function starting at 0x%llX\n",
+ "function starting at 0x%llX",
encoding, functionStart);
_LIBUNWIND_ABORT("invalid compact unwind encoding");
}
diff --git a/src/DwarfInstructions.hpp b/src/DwarfInstructions.hpp
index ce90aa05f534..ec70c0a11f70 100644
--- a/src/DwarfInstructions.hpp
+++ b/src/DwarfInstructions.hpp
@@ -6,7 +6,7 @@
// Source Licenses. See LICENSE.TXT for details.
//
//
-// Processor specific interpretation of dwarf unwind info.
+// Processor specific interpretation of DWARF unwind info.
//
//===----------------------------------------------------------------------===//
@@ -18,7 +18,6 @@
#include <stdlib.h>
#include "dwarf2.h"
-#include "AddressSpace.hpp"
#include "Registers.hpp"
#include "DwarfParser.hpp"
#include "config.h"
@@ -27,7 +26,7 @@
namespace libunwind {
-/// DwarfInstructions maps abtract dwarf unwind instructions to a particular
+/// DwarfInstructions maps abtract DWARF unwind instructions to a particular
/// architecture
template <typename A, typename R>
class DwarfInstructions {
@@ -83,10 +82,10 @@ typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
const RegisterLocation &savedReg) {
switch (savedReg.location) {
case CFI_Parser<A>::kRegisterInCFA:
- return addressSpace.getP(cfa + (pint_t)savedReg.value);
+ return addressSpace.getRegister(cfa + (pint_t)savedReg.value);
case CFI_Parser<A>::kRegisterAtExpression:
- return addressSpace.getP(
+ return addressSpace.getRegister(
evaluateExpression((pint_t)savedReg.value, addressSpace,
registers, cfa));
@@ -160,15 +159,15 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
&cieInfo) == NULL) {
PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
- &prolog)) {
+ R::getArch(), &prolog)) {
// get pointer to cfa (architecture specific)
pint_t cfa = getCFA(addressSpace, prolog, registers);
- // restore registers that dwarf says were saved
+ // restore registers that DWARF says were saved
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");
@@ -199,6 +198,42 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
// restoring SP means setting it to CFA.
newRegisters.setSP(cfa);
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ // If the target is aarch64 then the return address may have been signed
+ // using the v8.3 pointer authentication extensions. The original
+ // return address needs to be authenticated before the return address is
+ // restored. autia1716 is used instead of autia as autia1716 assembles
+ // to a NOP on pre-v8.3a architectures.
+ if ((R::getArch() == REGISTERS_ARM64) &&
+ prolog.savedRegisters[UNW_ARM64_RA_SIGN_STATE].value) {
+#if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
+ return UNW_ECROSSRASIGNING;
+#else
+ register unsigned long long x17 __asm("x17") = returnAddress;
+ register unsigned long long x16 __asm("x16") = cfa;
+
+ // These are the autia1716/autib1716 instructions. The hint instructions
+ // are used here as gcc does not assemble autia1716/autib1716 for pre
+ // armv8.3a targets.
+ if (cieInfo.addressesSignedWithBKey)
+ asm("hint 0xe" : "+r"(x17) : "r"(x16)); // autib1716
+ else
+ asm("hint 0xc" : "+r"(x17) : "r"(x16)); // autia1716
+ returnAddress = x17;
+#endif
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ if (R::getArch() == REGISTERS_SPARC) {
+ // Skip call site instruction and delay slot
+ returnAddress += 8;
+ // Skip unimp instruction if function returns a struct
+ if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
+ returnAddress += 4;
+ }
+#endif
+
// Return address is address after call site instruction, so setting IP to
// that does simualates a return.
newRegisters.setIP(returnAddress);
@@ -480,7 +515,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
case DW_OP_plus_uconst:
// pop stack, add uelb128 constant, push result
- *sp += addressSpace.getULEB128(p, expressionEnd);
+ *sp += static_cast<pint_t>(addressSpace.getULEB128(p, expressionEnd));
if (log)
fprintf(stderr, "add constant\n");
break;
@@ -744,7 +779,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
case DW_OP_call4:
case DW_OP_call_ref:
default:
- _LIBUNWIND_ABORT("dwarf opcode not implemented");
+ _LIBUNWIND_ABORT("DWARF opcode not implemented");
}
}
diff --git a/src/DwarfParser.hpp b/src/DwarfParser.hpp
index a19f0510a37b..a2c6d7f8db9f 100644
--- a/src/DwarfParser.hpp
+++ b/src/DwarfParser.hpp
@@ -20,13 +20,14 @@
#include "libunwind.h"
#include "dwarf2.h"
+#include "Registers.hpp"
-#include "AddressSpace.hpp"
+#include "config.h"
namespace libunwind {
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
-/// See Dwarf Spec for details:
+/// See DWARF Spec for details:
/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
///
template <typename A>
@@ -49,6 +50,9 @@ public:
bool isSignalFrame;
bool fdesHaveAugmentationData;
uint8_t returnAddressRegister;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ bool addressesSignedWithBKey;
+#endif
};
/// Information about an FDE (Frame Description Entry)
@@ -62,7 +66,7 @@ public:
};
enum {
- kMaxRegisterNumber = 120
+ kMaxRegisterNumber = _LIBUNWIND_HIGHEST_DWARF_REGISTER
};
enum RegisterSavedWhere {
kRegisterUnused,
@@ -77,7 +81,7 @@ public:
int64_t value;
};
/// Information about a frame layout and registers saved determined
- /// by "running" the dwarf FDE "instructions"
+ /// by "running" the DWARF FDE "instructions"
struct PrologInfo {
uint32_t cfaRegister;
int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
@@ -86,7 +90,7 @@ public:
uint32_t codeOffsetAtStackDecrement;
bool registersInOtherRegisters;
bool sameValueUsed;
- RegisterLocation savedRegisters[kMaxRegisterNumber];
+ RegisterLocation savedRegisters[kMaxRegisterNumber + 1];
};
struct PrologInfoStackEntry {
@@ -103,7 +107,7 @@ public:
FDE_Info *fdeInfo, CIE_Info *cieInfo);
static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
- PrologInfo *results);
+ int arch, PrologInfo *results);
static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
@@ -111,7 +115,7 @@ private:
static bool parseInstructions(A &addressSpace, pint_t instructions,
pint_t instructionsEnd, const CIE_Info &cieInfo,
pint_t pcoffset,
- PrologInfoStackEntry *&rememberStack,
+ PrologInfoStackEntry *&rememberStack, int arch,
PrologInfo *results);
};
@@ -138,23 +142,23 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
if (err != NULL)
return err;
p += 4;
- // parse pc begin and range
+ // Parse pc begin and range.
pint_t pcStart =
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
pint_t pcRange =
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding & 0x0F);
- // parse rest of info
+ // Parse rest of info.
fdeInfo->lsda = 0;
- // check for augmentation length
+ // Check for augmentation length.
if (cieInfo->fdesHaveAugmentationData) {
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
pint_t endOfAug = p + augLen;
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
- // peek at value (without indirection). Zero means no lsda
+ // Peek at value (without indirection). Zero means no LSDA.
pint_t lsdaStart = p;
if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
0) {
- // reset pointer and re-parse lsda address
+ // Reset pointer and re-parse LSDA address.
p = lsdaStart;
fdeInfo->lsda =
addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
@@ -192,23 +196,23 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
return false; // end marker
uint32_t id = addressSpace.get32(p);
if (id == 0) {
- // skip over CIEs
+ // Skip over CIEs.
p += cfiLength;
} else {
- // process FDE to see if it covers pc
+ // Process FDE to see if it covers pc.
pint_t nextCFI = p + cfiLength;
uint32_t ciePointer = addressSpace.get32(p);
pint_t cieStart = p - ciePointer;
- // validate pointer to CIE is within section
+ // Validate pointer to CIE is within section.
if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
p += 4;
- // parse pc begin and range
+ // Parse pc begin and range.
pint_t pcStart =
addressSpace.getEncodedP(p, nextCFI, cieInfo->pointerEncoding);
pint_t pcRange = addressSpace.getEncodedP(
p, nextCFI, cieInfo->pointerEncoding & 0x0F);
- // test if pc is within the function this FDE covers
+ // Test if pc is within the function this FDE covers.
if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
// parse rest of info
fdeInfo->lsda = 0;
@@ -217,11 +221,11 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
pint_t augLen = (pint_t)addressSpace.getULEB128(p, nextCFI);
pint_t endOfAug = p + augLen;
if (cieInfo->lsdaEncoding != DW_EH_PE_omit) {
- // peek at value (without indirection). Zero means no lsda
+ // Peek at value (without indirection). Zero means no LSDA.
pint_t lsdaStart = p;
if (addressSpace.getEncodedP(
p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
- // reset pointer and re-parse lsda address
+ // Reset pointer and re-parse LSDA address.
p = lsdaStart;
fdeInfo->lsda = addressSpace
.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
@@ -239,7 +243,7 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
// pc is not in begin/range, skip this FDE
}
} else {
- // malformed CIE, now augmentation describing pc range encoding
+ // Malformed CIE, now augmentation describing pc range encoding.
}
} else {
// malformed FDE. CIE is bad
@@ -263,6 +267,9 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
cieInfo->dataAlignFactor = 0;
cieInfo->isSignalFrame = false;
cieInfo->fdesHaveAugmentationData = false;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ cieInfo->addressesSignedWithBKey = false;
+#endif
cieInfo->cieStart = cie;
pint_t p = cie;
pint_t cieLength = (pint_t)addressSpace.get32(p);
@@ -326,6 +333,11 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
case 'S':
cieInfo->isSignalFrame = true;
break;
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ case 'B':
+ cieInfo->addressesSignedWithBKey = true;
+ break;
+#endif
default:
// ignore unknown letters
break;
@@ -338,12 +350,12 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
}
-/// "run" the dwarf instructions and create the abstact PrologInfo for an FDE
+/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
template <typename A>
bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
const FDE_Info &fdeInfo,
const CIE_Info &cieInfo, pint_t upToPC,
- PrologInfo *results) {
+ int arch, PrologInfo *results) {
// clear results
memset(results, '\0', sizeof(PrologInfo));
PrologInfoStackEntry *rememberStack = NULL;
@@ -351,28 +363,28 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
// parse CIE then FDE instructions
return parseInstructions(addressSpace, cieInfo.cieInstructions,
cieInfo.cieStart + cieInfo.cieLength, cieInfo,
- (pint_t)(-1), rememberStack, results) &&
+ (pint_t)(-1), rememberStack, arch, results) &&
parseInstructions(addressSpace, fdeInfo.fdeInstructions,
fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
- upToPC - fdeInfo.pcStart, rememberStack, results);
+ upToPC - fdeInfo.pcStart, rememberStack, arch,
+ results);
}
-/// "run" the dwarf instructions
+/// "run" the DWARF instructions
template <typename A>
bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
pint_t instructionsEnd,
const CIE_Info &cieInfo, pint_t pcoffset,
PrologInfoStackEntry *&rememberStack,
- PrologInfo *results) {
- const bool logDwarf = false;
+ int arch, PrologInfo *results) {
pint_t p = instructions;
pint_t codeOffset = 0;
PrologInfo initialState = *results;
- if (logDwarf)
- fprintf(stderr, "parseInstructions(instructions=0x%0" PRIx64 ")\n",
- (uint64_t)instructionsEnd);
- // see Dwarf Spec, section 6.4.2 for details on unwind opcodes
+ _LIBUNWIND_TRACE_DWARF("parseInstructions(instructions=0x%0" PRIx64 ")\n",
+ static_cast<uint64_t>(instructionsEnd));
+
+ // see DWARF Spec, section 6.4.2 for details on unwind opcodes
while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
uint64_t reg;
uint64_t reg2;
@@ -386,81 +398,71 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
++p;
switch (opcode) {
case DW_CFA_nop:
- if (logDwarf)
- fprintf(stderr, "DW_CFA_nop\n");
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_nop\n");
break;
case DW_CFA_set_loc:
codeOffset =
addressSpace.getEncodedP(p, instructionsEnd, cieInfo.pointerEncoding);
- if (logDwarf)
- fprintf(stderr, "DW_CFA_set_loc\n");
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_set_loc\n");
break;
case DW_CFA_advance_loc1:
codeOffset += (addressSpace.get8(p) * cieInfo.codeAlignFactor);
p += 1;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
- (uint64_t)codeOffset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc1: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
break;
case DW_CFA_advance_loc2:
codeOffset += (addressSpace.get16(p) * cieInfo.codeAlignFactor);
p += 2;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
- (uint64_t)codeOffset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc2: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
break;
case DW_CFA_advance_loc4:
codeOffset += (addressSpace.get32(p) * cieInfo.codeAlignFactor);
p += 4;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
- (uint64_t)codeOffset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc4: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
break;
case DW_CFA_offset_extended:
reg = addressSpace.getULEB128(p, instructionsEnd);
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor;
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_offset_extended dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_offset_extended DWARF unwind, reg too big");
return false;
}
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset;
- if (logDwarf)
- fprintf(stderr,
- "DW_CFA_offset_extended(reg=%" PRIu64 ", offset=%" PRId64 ")\n",
- reg, offset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended(reg=%" PRIu64 ", "
+ "offset=%" PRId64 ")\n",
+ reg, offset);
break;
case DW_CFA_restore_extended:
reg = addressSpace.getULEB128(p, instructionsEnd);
- ;
if (reg > kMaxRegisterNumber) {
- fprintf(
- stderr,
- "malformed DW_CFA_restore_extended dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_restore_extended DWARF unwind, reg too big");
return false;
}
results->savedRegisters[reg] = initialState.savedRegisters[reg];
- if (logDwarf)
- fprintf(stderr, "DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_extended(reg=%" PRIu64 ")\n", reg);
break;
case DW_CFA_undefined:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_undefined dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_undefined DWARF unwind, reg too big");
return false;
}
results->savedRegisters[reg].location = kRegisterUnused;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_undefined(reg=%" PRIu64 ")\n", reg);
break;
case DW_CFA_same_value:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_same_value dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_same_value DWARF unwind, reg too big");
return false;
}
// <rdar://problem/8456377> DW_CFA_same_value unsupported
@@ -470,29 +472,27 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
results->savedRegisters[reg].location = kRegisterUnused;
// set flag to disable conversion to compact unwind
results->sameValueUsed = true;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_same_value(reg=%" PRIu64 ")\n", reg);
break;
case DW_CFA_register:
reg = addressSpace.getULEB128(p, instructionsEnd);
reg2 = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_register dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_register DWARF unwind, reg too big");
return false;
}
if (reg2 > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_register DWARF unwind, reg2 too big");
return false;
}
results->savedRegisters[reg].location = kRegisterInRegister;
results->savedRegisters[reg].value = (int64_t)reg2;
// set flag to disable conversion to compact unwind
results->registersInOtherRegisters = true;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n",
- reg, reg2);
+ _LIBUNWIND_TRACE_DWARF(
+ "DW_CFA_register(reg=%" PRIu64 ", reg2=%" PRIu64 ")\n", reg, reg2);
break;
#if !defined(_LIBUNWIND_NO_HEAP)
case DW_CFA_remember_state:
@@ -505,8 +505,7 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
} else {
return false;
}
- if (logDwarf)
- fprintf(stderr, "DW_CFA_remember_state\n");
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_remember_state\n");
break;
case DW_CFA_restore_state:
if (rememberStack != NULL) {
@@ -517,202 +516,243 @@ bool CFI_Parser<A>::parseInstructions(A &addressSpace, pint_t instructions,
} else {
return false;
}
- if (logDwarf)
- fprintf(stderr, "DW_CFA_restore_state\n");
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_restore_state\n");
break;
#endif
case DW_CFA_def_cfa:
reg = addressSpace.getULEB128(p, instructionsEnd);
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr, "malformed DW_CFA_def_cfa dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0("malformed DW_CFA_def_cfa DWARF unwind, reg too big");
return false;
}
results->cfaRegister = (uint32_t)reg;
results->cfaRegisterOffset = (int32_t)offset;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n",
- reg, offset);
+ _LIBUNWIND_TRACE_DWARF(
+ "DW_CFA_def_cfa(reg=%" PRIu64 ", offset=%" PRIu64 ")\n", reg, offset);
break;
case DW_CFA_def_cfa_register:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(
- stderr,
- "malformed DW_CFA_def_cfa_register dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_def_cfa_register DWARF unwind, reg too big");
return false;
}
results->cfaRegister = (uint32_t)reg;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_register(%" PRIu64 ")\n", reg);
break;
case DW_CFA_def_cfa_offset:
results->cfaRegisterOffset = (int32_t)
addressSpace.getULEB128(p, instructionsEnd);
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_def_cfa_offset(%d)\n",
- results->cfaRegisterOffset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset(%d)\n",
+ results->cfaRegisterOffset);
break;
case DW_CFA_def_cfa_expression:
results->cfaRegister = 0;
results->cfaExpression = (int64_t)p;
length = addressSpace.getULEB128(p, instructionsEnd);
- p += length;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_def_cfa_expression(expression=0x%" PRIx64
- ", length=%" PRIu64 ")\n",
- results->cfaExpression, length);
+ assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+ p += static_cast<pint_t>(length);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_expression(expression=0x%" PRIx64
+ ", length=%" PRIu64 ")\n",
+ results->cfaExpression, length);
break;
case DW_CFA_expression:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_expression dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_expression DWARF unwind, reg too big");
return false;
}
results->savedRegisters[reg].location = kRegisterAtExpression;
results->savedRegisters[reg].value = (int64_t)p;
length = addressSpace.getULEB128(p, instructionsEnd);
- p += length;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_expression(reg=%" PRIu64
- ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
- reg, results->savedRegisters[reg].value, length);
+ assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+ p += static_cast<pint_t>(length);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_expression(reg=%" PRIu64 ", "
+ "expression=0x%" PRIx64 ", "
+ "length=%" PRIu64 ")\n",
+ reg, results->savedRegisters[reg].value, length);
break;
case DW_CFA_offset_extended_sf:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(
- stderr,
- "malformed DW_CFA_offset_extended_sf dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_offset_extended_sf DWARF unwind, reg too big");
return false;
}
offset =
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_offset_extended_sf(reg=%" PRIu64
- ", offset=%" PRId64 ")\n",
- reg, offset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_offset_extended_sf(reg=%" PRIu64 ", "
+ "offset=%" PRId64 ")\n",
+ reg, offset);
break;
case DW_CFA_def_cfa_sf:
reg = addressSpace.getULEB128(p, instructionsEnd);
offset =
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_def_cfa_sf dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_def_cfa_sf DWARF unwind, reg too big");
return false;
}
results->cfaRegister = (uint32_t)reg;
results->cfaRegisterOffset = (int32_t)offset;
- if (logDwarf)
- fprintf(stderr,
- "DW_CFA_def_cfa_sf(reg=%" PRIu64 ", offset=%" PRId64 ")\n", reg,
- offset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_sf(reg=%" PRIu64 ", "
+ "offset=%" PRId64 ")\n",
+ reg, offset);
break;
case DW_CFA_def_cfa_offset_sf:
results->cfaRegisterOffset = (int32_t)
(addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor);
results->codeOffsetAtStackDecrement = (uint32_t)codeOffset;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_def_cfa_offset_sf(%d)\n",
- results->cfaRegisterOffset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_def_cfa_offset_sf(%d)\n",
+ results->cfaRegisterOffset);
break;
case DW_CFA_val_offset:
reg = addressSpace.getULEB128(p, instructionsEnd);
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG(
+ "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;
results->savedRegisters[reg].value = offset;
- if (logDwarf)
- fprintf(stderr,
- "DW_CFA_val_offset(reg=%" PRIu64 ", offset=%" PRId64 "\n", reg,
- offset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset(reg=%" PRIu64 ", "
+ "offset=%" PRId64 "\n",
+ reg, offset);
break;
case DW_CFA_val_offset_sf:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_val_offset_sf dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_val_offset_sf DWARF unwind, reg too big");
return false;
}
offset =
addressSpace.getSLEB128(p, instructionsEnd) * cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterOffsetFromCFA;
results->savedRegisters[reg].value = offset;
- if (logDwarf)
- fprintf(stderr,
- "DW_CFA_val_offset_sf(reg=%" PRIu64 ", offset=%" PRId64 "\n",
- reg, offset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_val_offset_sf(reg=%" PRIu64 ", "
+ "offset=%" PRId64 "\n",
+ reg, offset);
break;
case DW_CFA_val_expression:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr,
- "malformed DW_CFA_val_expression dwarf unwind, reg too big\n");
+ _LIBUNWIND_LOG0(
+ "malformed DW_CFA_val_expression DWARF unwind, reg too big");
return false;
}
results->savedRegisters[reg].location = kRegisterIsExpression;
results->savedRegisters[reg].value = (int64_t)p;
length = addressSpace.getULEB128(p, instructionsEnd);
- p += length;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_val_expression(reg=%" PRIu64
- ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
- reg, results->savedRegisters[reg].value, length);
+ assert(length < static_cast<pint_t>(~0) && "pointer overflow");
+ p += static_cast<pint_t>(length);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", "
+ "expression=0x%" PRIx64 ", length=%" PRIu64 ")\n",
+ reg, results->savedRegisters[reg].value, length);
break;
case DW_CFA_GNU_args_size:
length = addressSpace.getULEB128(p, instructionsEnd);
results->spExtraArgSize = (uint32_t)length;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_args_size(%" PRIu64 ")\n", length);
break;
case DW_CFA_GNU_negative_offset_extended:
reg = addressSpace.getULEB128(p, instructionsEnd);
if (reg > kMaxRegisterNumber) {
- fprintf(stderr, "malformed DW_CFA_GNU_negative_offset_extended dwarf "
- "unwind, reg too big\n");
+ _LIBUNWIND_LOG0("malformed DW_CFA_GNU_negative_offset_extended DWARF "
+ "unwind, reg too big");
return false;
}
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = -offset;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n",
- offset);
+ _LIBUNWIND_TRACE_DWARF(
+ "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
+ break;
+
+#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
+ // The same constant is used to represent different instructions on
+ // AArch64 (negate_ra_state) and SPARC (window_save).
+ static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
+ "uses the same constant");
+ case DW_CFA_AARCH64_negate_ra_state:
+ switch (arch) {
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+ case REGISTERS_ARM64:
+ results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^= 0x1;
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
+ break;
+#endif
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ // case DW_CFA_GNU_window_save:
+ case REGISTERS_SPARC:
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
+ for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
+ results->savedRegisters[reg].location = kRegisterInRegister;
+ results->savedRegisters[reg].value =
+ ((int64_t)reg - UNW_SPARC_O0) + UNW_SPARC_I0;
+ }
+
+ for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+ results->savedRegisters[reg].location = kRegisterInCFA;
+ results->savedRegisters[reg].value =
+ ((int64_t)reg - UNW_SPARC_L0) * 4;
+ }
+ break;
+#endif
+ }
break;
+#else
+ (void)arch;
+#endif
+
default:
operand = opcode & 0x3F;
switch (opcode & 0xC0) {
case DW_CFA_offset:
reg = operand;
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG("malformed DW_CFA_offset DWARF unwind, reg (%" PRIu64
+ ") out of range",
+ reg);
+ return false;
+ }
offset = (int64_t)addressSpace.getULEB128(p, instructionsEnd)
* cieInfo.dataAlignFactor;
results->savedRegisters[reg].location = kRegisterInCFA;
results->savedRegisters[reg].value = offset;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
- operand, offset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_offset(reg=%d, offset=%" PRId64 ")\n",
+ operand, offset);
break;
case DW_CFA_advance_loc:
codeOffset += operand * cieInfo.codeAlignFactor;
- if (logDwarf)
- fprintf(stderr, "DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
- (uint64_t)codeOffset);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_advance_loc: new offset=%" PRIu64 "\n",
+ static_cast<uint64_t>(codeOffset));
break;
case DW_CFA_restore:
reg = operand;
+ if (reg > kMaxRegisterNumber) {
+ _LIBUNWIND_LOG("malformed DW_CFA_restore DWARF unwind, reg (%" PRIu64
+ ") out of range",
+ reg);
+ return false;
+ }
results->savedRegisters[reg] = initialState.savedRegisters[reg];
- if (logDwarf)
- fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg);
+ _LIBUNWIND_TRACE_DWARF("DW_CFA_restore(reg=%" PRIu64 ")\n",
+ static_cast<uint64_t>(operand));
break;
default:
- if (logDwarf)
- fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
+ _LIBUNWIND_TRACE_DWARF("unknown CFA opcode 0x%02X\n", opcode);
return false;
}
}
diff --git a/src/EHHeaderParser.hpp b/src/EHHeaderParser.hpp
index 7945c7ba2fb0..9bdaf5505ff0 100644
--- a/src/EHHeaderParser.hpp
+++ b/src/EHHeaderParser.hpp
@@ -15,7 +15,6 @@
#include "libunwind.h"
-#include "AddressSpace.hpp"
#include "DwarfParser.hpp"
namespace libunwind {
@@ -68,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;
}
@@ -85,7 +86,7 @@ bool EHHeaderParser<A>::decodeTableEntry(
const char *message =
CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
if (message != NULL) {
- _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s\n",
+ _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s",
message);
return false;
}
diff --git a/src/RWMutex.hpp b/src/RWMutex.hpp
new file mode 100644
index 000000000000..50a78a57b089
--- /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 ab8742840004..a4f5a85f2a7b 100644
--- a/src/Registers.hpp
+++ b/src/Registers.hpp
@@ -24,6 +24,18 @@ namespace libunwind {
// For emulating 128-bit registers
struct v128 { uint32_t vec[4]; };
+enum {
+ REGISTERS_X86,
+ REGISTERS_X86_64,
+ REGISTERS_PPC,
+ REGISTERS_PPC64,
+ REGISTERS_ARM64,
+ REGISTERS_ARM,
+ REGISTERS_OR1K,
+ REGISTERS_MIPS_O32,
+ REGISTERS_MIPS_NEWABI,
+ REGISTERS_SPARC,
+};
#if defined(_LIBUNWIND_TARGET_I386)
/// Registers_x86 holds the register state of a thread in a 32-bit intel
@@ -42,9 +54,10 @@ public:
bool validVectorRegister(int) const { return false; }
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
- const char *getRegisterName(int num);
+ static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 8; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
+ static int getArch() { return REGISTERS_X86; }
uint32_t getSP() const { return _registers.__esp; }
void setSP(uint32_t value) { _registers.__esp = value; }
@@ -122,9 +135,17 @@ inline uint32_t Registers_x86::getRegister(int regNum) const {
return _registers.__edx;
case UNW_X86_EBX:
return _registers.__ebx;
+#if !defined(__APPLE__)
+ case UNW_X86_ESP:
+#else
case UNW_X86_EBP:
+#endif
return _registers.__ebp;
+#if !defined(__APPLE__)
+ case UNW_X86_EBP:
+#else
case UNW_X86_ESP:
+#endif
return _registers.__esp;
case UNW_X86_ESI:
return _registers.__esi;
@@ -154,10 +175,18 @@ inline void Registers_x86::setRegister(int regNum, uint32_t value) {
case UNW_X86_EBX:
_registers.__ebx = value;
return;
+#if !defined(__APPLE__)
+ case UNW_X86_ESP:
+#else
case UNW_X86_EBP:
+#endif
_registers.__ebp = value;
return;
+#if !defined(__APPLE__)
+ case UNW_X86_EBP:
+#else
case UNW_X86_ESP:
+#endif
_registers.__esp = value;
return;
case UNW_X86_ESI:
@@ -229,12 +258,13 @@ 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);
+ static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 16; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
+ static int getArch() { return REGISTERS_X86_64; }
uint64_t getSP() const { return _registers.__rsp; }
void setSP(uint64_t value) { _registers.__rsp = value; }
@@ -276,8 +306,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) {
@@ -442,6 +478,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";
}
@@ -455,12 +523,37 @@ 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
+ (void)regNum; // suppress unused parameter warning
+ 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
+ (void)regNum; // suppress unused parameter warning
_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
+ (void)regNum; (void)value; // suppress unused parameter warnings
_LIBUNWIND_ABORT("no x86_64 vector registers");
+#endif
}
#endif // _LIBUNWIND_TARGET_X86_64
@@ -482,9 +575,10 @@ public:
bool validVectorRegister(int num) const;
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
- const char *getRegisterName(int num);
+ static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 112; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; }
+ static int getArch() { return REGISTERS_PPC; }
uint64_t getSP() const { return _registers.__r1; }
void setSP(uint32_t value) { _registers.__r1 = value; }
@@ -1030,6 +1124,648 @@ inline const char *Registers_ppc::getRegisterName(int regNum) {
}
#endif // _LIBUNWIND_TARGET_PPC
+#if defined(_LIBUNWIND_TARGET_PPC64)
+/// Registers_ppc64 holds the register state of a thread in a 64-bit PowerPC
+/// process.
+class _LIBUNWIND_HIDDEN Registers_ppc64 {
+public:
+ Registers_ppc64();
+ Registers_ppc64(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);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; }
+ static int getArch() { return REGISTERS_PPC64; }
+
+ uint64_t getSP() const { return _registers.__r1; }
+ void setSP(uint64_t value) { _registers.__r1 = value; }
+ uint64_t getIP() const { return _registers.__srr0; }
+ void setIP(uint64_t value) { _registers.__srr0 = value; }
+
+private:
+ struct ppc64_thread_state_t {
+ uint64_t __srr0; // Instruction address register (PC)
+ uint64_t __srr1; // Machine state register (supervisor)
+ uint64_t __r0;
+ uint64_t __r1;
+ uint64_t __r2;
+ uint64_t __r3;
+ uint64_t __r4;
+ uint64_t __r5;
+ uint64_t __r6;
+ uint64_t __r7;
+ uint64_t __r8;
+ uint64_t __r9;
+ uint64_t __r10;
+ uint64_t __r11;
+ uint64_t __r12;
+ uint64_t __r13;
+ uint64_t __r14;
+ uint64_t __r15;
+ uint64_t __r16;
+ uint64_t __r17;
+ uint64_t __r18;
+ uint64_t __r19;
+ uint64_t __r20;
+ uint64_t __r21;
+ uint64_t __r22;
+ uint64_t __r23;
+ uint64_t __r24;
+ uint64_t __r25;
+ uint64_t __r26;
+ uint64_t __r27;
+ uint64_t __r28;
+ uint64_t __r29;
+ uint64_t __r30;
+ uint64_t __r31;
+ uint64_t __cr; // Condition register
+ uint64_t __xer; // User's integer exception register
+ uint64_t __lr; // Link register
+ uint64_t __ctr; // Count register
+ uint64_t __vrsave; // Vector Save Register
+ };
+
+ union ppc64_vsr_t {
+ struct asfloat_s {
+ double f;
+ uint64_t v2;
+ } asfloat;
+ v128 v;
+ };
+
+ ppc64_thread_state_t _registers;
+ ppc64_vsr_t _vectorScalarRegisters[64];
+
+ static int getVectorRegNum(int num);
+};
+
+inline Registers_ppc64::Registers_ppc64(const void *registers) {
+ static_assert((check_fit<Registers_ppc64, unw_context_t>::does_fit),
+ "ppc64 registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast<const uint8_t *>(registers),
+ sizeof(_registers));
+ static_assert(sizeof(_registers) == 312,
+ "expected vector scalar register offset to be 312");
+ memcpy(&_vectorScalarRegisters,
+ static_cast<const uint8_t *>(registers) + sizeof(_registers),
+ sizeof(_vectorScalarRegisters));
+ static_assert(sizeof(_registers) +
+ sizeof(_vectorScalarRegisters) == 1336,
+ "expected vector register offset to be 1336 bytes");
+}
+
+inline Registers_ppc64::Registers_ppc64() {
+ memset(&_registers, 0, sizeof(_registers));
+ memset(&_vectorScalarRegisters, 0, sizeof(_vectorScalarRegisters));
+}
+
+inline bool Registers_ppc64::validRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ case UNW_REG_SP:
+ case UNW_PPC64_XER:
+ case UNW_PPC64_LR:
+ case UNW_PPC64_CTR:
+ case UNW_PPC64_VRSAVE:
+ return true;
+ }
+
+ if (regNum >= UNW_PPC64_R0 && regNum <= UNW_PPC64_R31)
+ return true;
+ if (regNum >= UNW_PPC64_CR0 && regNum <= UNW_PPC64_CR7)
+ return true;
+
+ return false;
+}
+
+inline uint64_t Registers_ppc64::getRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__srr0;
+ case UNW_PPC64_R0:
+ return _registers.__r0;
+ case UNW_PPC64_R1:
+ case UNW_REG_SP:
+ return _registers.__r1;
+ case UNW_PPC64_R2:
+ return _registers.__r2;
+ case UNW_PPC64_R3:
+ return _registers.__r3;
+ case UNW_PPC64_R4:
+ return _registers.__r4;
+ case UNW_PPC64_R5:
+ return _registers.__r5;
+ case UNW_PPC64_R6:
+ return _registers.__r6;
+ case UNW_PPC64_R7:
+ return _registers.__r7;
+ case UNW_PPC64_R8:
+ return _registers.__r8;
+ case UNW_PPC64_R9:
+ return _registers.__r9;
+ case UNW_PPC64_R10:
+ return _registers.__r10;
+ case UNW_PPC64_R11:
+ return _registers.__r11;
+ case UNW_PPC64_R12:
+ return _registers.__r12;
+ case UNW_PPC64_R13:
+ return _registers.__r13;
+ case UNW_PPC64_R14:
+ return _registers.__r14;
+ case UNW_PPC64_R15:
+ return _registers.__r15;
+ case UNW_PPC64_R16:
+ return _registers.__r16;
+ case UNW_PPC64_R17:
+ return _registers.__r17;
+ case UNW_PPC64_R18:
+ return _registers.__r18;
+ case UNW_PPC64_R19:
+ return _registers.__r19;
+ case UNW_PPC64_R20:
+ return _registers.__r20;
+ case UNW_PPC64_R21:
+ return _registers.__r21;
+ case UNW_PPC64_R22:
+ return _registers.__r22;
+ case UNW_PPC64_R23:
+ return _registers.__r23;
+ case UNW_PPC64_R24:
+ return _registers.__r24;
+ case UNW_PPC64_R25:
+ return _registers.__r25;
+ case UNW_PPC64_R26:
+ return _registers.__r26;
+ case UNW_PPC64_R27:
+ return _registers.__r27;
+ case UNW_PPC64_R28:
+ return _registers.__r28;
+ case UNW_PPC64_R29:
+ return _registers.__r29;
+ case UNW_PPC64_R30:
+ return _registers.__r30;
+ case UNW_PPC64_R31:
+ return _registers.__r31;
+ case UNW_PPC64_CR0:
+ return (_registers.__cr & 0xF0000000);
+ case UNW_PPC64_CR1:
+ return (_registers.__cr & 0x0F000000);
+ case UNW_PPC64_CR2:
+ return (_registers.__cr & 0x00F00000);
+ case UNW_PPC64_CR3:
+ return (_registers.__cr & 0x000F0000);
+ case UNW_PPC64_CR4:
+ return (_registers.__cr & 0x0000F000);
+ case UNW_PPC64_CR5:
+ return (_registers.__cr & 0x00000F00);
+ case UNW_PPC64_CR6:
+ return (_registers.__cr & 0x000000F0);
+ case UNW_PPC64_CR7:
+ return (_registers.__cr & 0x0000000F);
+ case UNW_PPC64_XER:
+ return _registers.__xer;
+ case UNW_PPC64_LR:
+ return _registers.__lr;
+ case UNW_PPC64_CTR:
+ return _registers.__ctr;
+ case UNW_PPC64_VRSAVE:
+ return _registers.__vrsave;
+ }
+ _LIBUNWIND_ABORT("unsupported ppc64 register");
+}
+
+inline void Registers_ppc64::setRegister(int regNum, uint64_t value) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__srr0 = value;
+ return;
+ case UNW_PPC64_R0:
+ _registers.__r0 = value;
+ return;
+ case UNW_PPC64_R1:
+ case UNW_REG_SP:
+ _registers.__r1 = value;
+ return;
+ case UNW_PPC64_R2:
+ _registers.__r2 = value;
+ return;
+ case UNW_PPC64_R3:
+ _registers.__r3 = value;
+ return;
+ case UNW_PPC64_R4:
+ _registers.__r4 = value;
+ return;
+ case UNW_PPC64_R5:
+ _registers.__r5 = value;
+ return;
+ case UNW_PPC64_R6:
+ _registers.__r6 = value;
+ return;
+ case UNW_PPC64_R7:
+ _registers.__r7 = value;
+ return;
+ case UNW_PPC64_R8:
+ _registers.__r8 = value;
+ return;
+ case UNW_PPC64_R9:
+ _registers.__r9 = value;
+ return;
+ case UNW_PPC64_R10:
+ _registers.__r10 = value;
+ return;
+ case UNW_PPC64_R11:
+ _registers.__r11 = value;
+ return;
+ case UNW_PPC64_R12:
+ _registers.__r12 = value;
+ return;
+ case UNW_PPC64_R13:
+ _registers.__r13 = value;
+ return;
+ case UNW_PPC64_R14:
+ _registers.__r14 = value;
+ return;
+ case UNW_PPC64_R15:
+ _registers.__r15 = value;
+ return;
+ case UNW_PPC64_R16:
+ _registers.__r16 = value;
+ return;
+ case UNW_PPC64_R17:
+ _registers.__r17 = value;
+ return;
+ case UNW_PPC64_R18:
+ _registers.__r18 = value;
+ return;
+ case UNW_PPC64_R19:
+ _registers.__r19 = value;
+ return;
+ case UNW_PPC64_R20:
+ _registers.__r20 = value;
+ return;
+ case UNW_PPC64_R21:
+ _registers.__r21 = value;
+ return;
+ case UNW_PPC64_R22:
+ _registers.__r22 = value;
+ return;
+ case UNW_PPC64_R23:
+ _registers.__r23 = value;
+ return;
+ case UNW_PPC64_R24:
+ _registers.__r24 = value;
+ return;
+ case UNW_PPC64_R25:
+ _registers.__r25 = value;
+ return;
+ case UNW_PPC64_R26:
+ _registers.__r26 = value;
+ return;
+ case UNW_PPC64_R27:
+ _registers.__r27 = value;
+ return;
+ case UNW_PPC64_R28:
+ _registers.__r28 = value;
+ return;
+ case UNW_PPC64_R29:
+ _registers.__r29 = value;
+ return;
+ case UNW_PPC64_R30:
+ _registers.__r30 = value;
+ return;
+ case UNW_PPC64_R31:
+ _registers.__r31 = value;
+ return;
+ case UNW_PPC64_CR0:
+ _registers.__cr &= 0x0FFFFFFF;
+ _registers.__cr |= (value & 0xF0000000);
+ return;
+ case UNW_PPC64_CR1:
+ _registers.__cr &= 0xF0FFFFFF;
+ _registers.__cr |= (value & 0x0F000000);
+ return;
+ case UNW_PPC64_CR2:
+ _registers.__cr &= 0xFF0FFFFF;
+ _registers.__cr |= (value & 0x00F00000);
+ return;
+ case UNW_PPC64_CR3:
+ _registers.__cr &= 0xFFF0FFFF;
+ _registers.__cr |= (value & 0x000F0000);
+ return;
+ case UNW_PPC64_CR4:
+ _registers.__cr &= 0xFFFF0FFF;
+ _registers.__cr |= (value & 0x0000F000);
+ return;
+ case UNW_PPC64_CR5:
+ _registers.__cr &= 0xFFFFF0FF;
+ _registers.__cr |= (value & 0x00000F00);
+ return;
+ case UNW_PPC64_CR6:
+ _registers.__cr &= 0xFFFFFF0F;
+ _registers.__cr |= (value & 0x000000F0);
+ return;
+ case UNW_PPC64_CR7:
+ _registers.__cr &= 0xFFFFFFF0;
+ _registers.__cr |= (value & 0x0000000F);
+ return;
+ case UNW_PPC64_XER:
+ _registers.__xer = value;
+ return;
+ case UNW_PPC64_LR:
+ _registers.__lr = value;
+ return;
+ case UNW_PPC64_CTR:
+ _registers.__ctr = value;
+ return;
+ case UNW_PPC64_VRSAVE:
+ _registers.__vrsave = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported ppc64 register");
+}
+
+inline bool Registers_ppc64::validFloatRegister(int regNum) const {
+ return regNum >= UNW_PPC64_F0 && regNum <= UNW_PPC64_F31;
+}
+
+inline double Registers_ppc64::getFloatRegister(int regNum) const {
+ assert(validFloatRegister(regNum));
+ return _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f;
+}
+
+inline void Registers_ppc64::setFloatRegister(int regNum, double value) {
+ assert(validFloatRegister(regNum));
+ _vectorScalarRegisters[regNum - UNW_PPC64_F0].asfloat.f = value;
+}
+
+inline bool Registers_ppc64::validVectorRegister(int regNum) const {
+#ifdef PPC64_HAS_VMX
+ if (regNum >= UNW_PPC64_VS0 && regNum <= UNW_PPC64_VS31)
+ return true;
+ if (regNum >= UNW_PPC64_VS32 && regNum <= UNW_PPC64_VS63)
+ return true;
+#else
+ if (regNum >= UNW_PPC64_V0 && regNum <= UNW_PPC64_V31)
+ return true;
+#endif
+ return false;
+}
+
+inline int Registers_ppc64::getVectorRegNum(int num)
+{
+ if (num >= UNW_PPC64_VS0 && num <= UNW_PPC64_VS31)
+ return num - UNW_PPC64_VS0;
+ else
+ return num - UNW_PPC64_VS32 + 32;
+}
+
+inline v128 Registers_ppc64::getVectorRegister(int regNum) const {
+ assert(validVectorRegister(regNum));
+ return _vectorScalarRegisters[getVectorRegNum(regNum)].v;
+}
+
+inline void Registers_ppc64::setVectorRegister(int regNum, v128 value) {
+ assert(validVectorRegister(regNum));
+ _vectorScalarRegisters[getVectorRegNum(regNum)].v = value;
+}
+
+inline const char *Registers_ppc64::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_PPC64_R0:
+ return "r0";
+ case UNW_PPC64_R1:
+ return "r1";
+ case UNW_PPC64_R2:
+ return "r2";
+ case UNW_PPC64_R3:
+ return "r3";
+ case UNW_PPC64_R4:
+ return "r4";
+ case UNW_PPC64_R5:
+ return "r5";
+ case UNW_PPC64_R6:
+ return "r6";
+ case UNW_PPC64_R7:
+ return "r7";
+ case UNW_PPC64_R8:
+ return "r8";
+ case UNW_PPC64_R9:
+ return "r9";
+ case UNW_PPC64_R10:
+ return "r10";
+ case UNW_PPC64_R11:
+ return "r11";
+ case UNW_PPC64_R12:
+ return "r12";
+ case UNW_PPC64_R13:
+ return "r13";
+ case UNW_PPC64_R14:
+ return "r14";
+ case UNW_PPC64_R15:
+ return "r15";
+ case UNW_PPC64_R16:
+ return "r16";
+ case UNW_PPC64_R17:
+ return "r17";
+ case UNW_PPC64_R18:
+ return "r18";
+ case UNW_PPC64_R19:
+ return "r19";
+ case UNW_PPC64_R20:
+ return "r20";
+ case UNW_PPC64_R21:
+ return "r21";
+ case UNW_PPC64_R22:
+ return "r22";
+ case UNW_PPC64_R23:
+ return "r23";
+ case UNW_PPC64_R24:
+ return "r24";
+ case UNW_PPC64_R25:
+ return "r25";
+ case UNW_PPC64_R26:
+ return "r26";
+ case UNW_PPC64_R27:
+ return "r27";
+ case UNW_PPC64_R28:
+ return "r28";
+ case UNW_PPC64_R29:
+ return "r29";
+ case UNW_PPC64_R30:
+ return "r30";
+ case UNW_PPC64_R31:
+ return "r31";
+ case UNW_PPC64_CR0:
+ return "cr0";
+ case UNW_PPC64_CR1:
+ return "cr1";
+ case UNW_PPC64_CR2:
+ return "cr2";
+ case UNW_PPC64_CR3:
+ return "cr3";
+ case UNW_PPC64_CR4:
+ return "cr4";
+ case UNW_PPC64_CR5:
+ return "cr5";
+ case UNW_PPC64_CR6:
+ return "cr6";
+ case UNW_PPC64_CR7:
+ return "cr7";
+ case UNW_PPC64_XER:
+ return "xer";
+ case UNW_PPC64_LR:
+ return "lr";
+ case UNW_PPC64_CTR:
+ return "ctr";
+ case UNW_PPC64_VRSAVE:
+ return "vrsave";
+ case UNW_PPC64_F0:
+ return "fp0";
+ case UNW_PPC64_F1:
+ return "fp1";
+ case UNW_PPC64_F2:
+ return "fp2";
+ case UNW_PPC64_F3:
+ return "fp3";
+ case UNW_PPC64_F4:
+ return "fp4";
+ case UNW_PPC64_F5:
+ return "fp5";
+ case UNW_PPC64_F6:
+ return "fp6";
+ case UNW_PPC64_F7:
+ return "fp7";
+ case UNW_PPC64_F8:
+ return "fp8";
+ case UNW_PPC64_F9:
+ return "fp9";
+ case UNW_PPC64_F10:
+ return "fp10";
+ case UNW_PPC64_F11:
+ return "fp11";
+ case UNW_PPC64_F12:
+ return "fp12";
+ case UNW_PPC64_F13:
+ return "fp13";
+ case UNW_PPC64_F14:
+ return "fp14";
+ case UNW_PPC64_F15:
+ return "fp15";
+ case UNW_PPC64_F16:
+ return "fp16";
+ case UNW_PPC64_F17:
+ return "fp17";
+ case UNW_PPC64_F18:
+ return "fp18";
+ case UNW_PPC64_F19:
+ return "fp19";
+ case UNW_PPC64_F20:
+ return "fp20";
+ case UNW_PPC64_F21:
+ return "fp21";
+ case UNW_PPC64_F22:
+ return "fp22";
+ case UNW_PPC64_F23:
+ return "fp23";
+ case UNW_PPC64_F24:
+ return "fp24";
+ case UNW_PPC64_F25:
+ return "fp25";
+ case UNW_PPC64_F26:
+ return "fp26";
+ case UNW_PPC64_F27:
+ return "fp27";
+ case UNW_PPC64_F28:
+ return "fp28";
+ case UNW_PPC64_F29:
+ return "fp29";
+ case UNW_PPC64_F30:
+ return "fp30";
+ case UNW_PPC64_F31:
+ return "fp31";
+ case UNW_PPC64_V0:
+ return "v0";
+ case UNW_PPC64_V1:
+ return "v1";
+ case UNW_PPC64_V2:
+ return "v2";
+ case UNW_PPC64_V3:
+ return "v3";
+ case UNW_PPC64_V4:
+ return "v4";
+ case UNW_PPC64_V5:
+ return "v5";
+ case UNW_PPC64_V6:
+ return "v6";
+ case UNW_PPC64_V7:
+ return "v7";
+ case UNW_PPC64_V8:
+ return "v8";
+ case UNW_PPC64_V9:
+ return "v9";
+ case UNW_PPC64_V10:
+ return "v10";
+ case UNW_PPC64_V11:
+ return "v11";
+ case UNW_PPC64_V12:
+ return "v12";
+ case UNW_PPC64_V13:
+ return "v13";
+ case UNW_PPC64_V14:
+ return "v14";
+ case UNW_PPC64_V15:
+ return "v15";
+ case UNW_PPC64_V16:
+ return "v16";
+ case UNW_PPC64_V17:
+ return "v17";
+ case UNW_PPC64_V18:
+ return "v18";
+ case UNW_PPC64_V19:
+ return "v19";
+ case UNW_PPC64_V20:
+ return "v20";
+ case UNW_PPC64_V21:
+ return "v21";
+ case UNW_PPC64_V22:
+ return "v22";
+ case UNW_PPC64_V23:
+ return "v23";
+ case UNW_PPC64_V24:
+ return "v24";
+ case UNW_PPC64_V25:
+ return "v25";
+ case UNW_PPC64_V26:
+ return "v26";
+ case UNW_PPC64_V27:
+ return "v27";
+ case UNW_PPC64_V28:
+ return "v28";
+ case UNW_PPC64_V29:
+ return "v29";
+ case UNW_PPC64_V30:
+ return "v30";
+ case UNW_PPC64_V31:
+ return "v31";
+ }
+ return "unknown register";
+}
+#endif // _LIBUNWIND_TARGET_PPC64
+
#if defined(_LIBUNWIND_TARGET_AARCH64)
/// Registers_arm64 holds the register state of a thread in a 64-bit arm
@@ -1048,9 +1784,10 @@ public:
bool validVectorRegister(int num) const;
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
- const char *getRegisterName(int num);
+ static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 95; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
+ static int getArch() { return REGISTERS_ARM64; }
uint64_t getSP() const { return _registers.__sp; }
void setSP(uint64_t value) { _registers.__sp = value; }
@@ -1066,7 +1803,7 @@ private:
uint64_t __lr; // Link register x30
uint64_t __sp; // Stack pointer x31
uint64_t __pc; // Program counter
- uint64_t padding; // 16-byte align
+ uint64_t __ra_sign_state; // RA sign state register
};
GPRs _registers;
@@ -1102,6 +1839,8 @@ inline bool Registers_arm64::validRegister(int regNum) const {
return false;
if (regNum > 95)
return false;
+ if (regNum == UNW_ARM64_RA_SIGN_STATE)
+ return true;
if ((regNum > 31) && (regNum < 64))
return false;
return true;
@@ -1112,6 +1851,8 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const {
return _registers.__pc;
if (regNum == UNW_REG_SP)
return _registers.__sp;
+ if (regNum == UNW_ARM64_RA_SIGN_STATE)
+ return _registers.__ra_sign_state;
if ((regNum >= 0) && (regNum < 32))
return _registers.__x[regNum];
_LIBUNWIND_ABORT("unsupported arm64 register");
@@ -1122,6 +1863,8 @@ inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
_registers.__pc = value;
else if (regNum == UNW_REG_SP)
_registers.__sp = value;
+ else if (regNum == UNW_ARM64_RA_SIGN_STATE)
+ _registers.__ra_sign_state = value;
else if ((regNum >= 0) && (regNum < 32))
_registers.__x[regNum] = value;
else
@@ -1310,7 +2053,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);
@@ -1318,11 +2061,13 @@ public:
bool validVectorRegister(int num) const;
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
- const char *getRegisterName(int num);
+ static const char *getRegisterName(int num);
void jumpto() {
restoreSavedFloatRegisters();
restoreCoreAndJumpTo();
}
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }
+ static int getArch() { return REGISTERS_ARM; }
uint32_t getSP() const { return _registers.__sp; }
void setSP(uint32_t value) { _registers.__sp = value; }
@@ -1343,10 +2088,12 @@ public:
}
if (_saved_vfp_d16_d31)
restoreVFPv3(_vfp_d16_d31);
+#if defined(__ARM_WMMX)
if (_saved_iwmmx)
restoreiWMMX(_iwmmx);
if (_saved_iwmmx_control)
restoreiWMMXControl(_iwmmx_control);
+#endif
}
private:
@@ -1360,13 +2107,15 @@ private:
static void saveVFPWithFSTMD(unw_fpreg_t*);
static void saveVFPWithFSTMX(unw_fpreg_t*);
static void saveVFPv3(unw_fpreg_t*);
- static void saveiWMMX(unw_fpreg_t*);
- static void saveiWMMXControl(uint32_t*);
static void restoreVFPWithFLDMD(unw_fpreg_t*);
static void restoreVFPWithFLDMX(unw_fpreg_t*);
static void restoreVFPv3(unw_fpreg_t*);
+#if defined(__ARM_WMMX)
+ static void saveiWMMX(unw_fpreg_t*);
+ static void saveiWMMXControl(uint32_t*);
static void restoreiWMMX(unw_fpreg_t*);
static void restoreiWMMXControl(uint32_t*);
+#endif
void restoreCoreAndJumpTo();
// ARM registers
@@ -1384,47 +2133,53 @@ private:
bool _saved_vfp_d0_d15;
// Whether VFPv3 D16-D31 are saved.
bool _saved_vfp_d16_d31;
- // Whether iWMMX data registers are saved.
- bool _saved_iwmmx;
- // Whether iWMMX control registers are saved.
- bool _saved_iwmmx_control;
// VFP registers D0-D15, + padding if saved using FSTMX
unw_fpreg_t _vfp_d0_d15_pad[17];
// VFPv3 registers D16-D31, always saved using FSTMD
unw_fpreg_t _vfp_d16_d31[16];
+#if defined(__ARM_WMMX)
+ // Whether iWMMX data registers are saved.
+ bool _saved_iwmmx;
+ // Whether iWMMX control registers are saved.
+ 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
};
inline Registers_arm::Registers_arm(const void *registers)
: _use_X_for_vfp_save(false),
_saved_vfp_d0_d15(false),
- _saved_vfp_d16_d31(false),
- _saved_iwmmx(false),
- _saved_iwmmx_control(false) {
+ _saved_vfp_d16_d31(false) {
static_assert((check_fit<Registers_arm, unw_context_t>::does_fit),
"arm registers do not fit into unw_context_t");
// See unw_getcontext() note about data.
memcpy(&_registers, registers, sizeof(_registers));
memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
+#if defined(__ARM_WMMX)
+ _saved_iwmmx = false;
+ _saved_iwmmx_control = false;
memset(&_iwmmx, 0, sizeof(_iwmmx));
memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+#endif
}
inline Registers_arm::Registers_arm()
: _use_X_for_vfp_save(false),
_saved_vfp_d0_d15(false),
- _saved_vfp_d16_d31(false),
- _saved_iwmmx(false),
- _saved_iwmmx_control(false) {
+ _saved_vfp_d16_d31(false) {
memset(&_registers, 0, sizeof(_registers));
memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
+#if defined(__ARM_WMMX)
+ _saved_iwmmx = false;
+ _saved_iwmmx_control = false;
memset(&_iwmmx, 0, sizeof(_iwmmx));
memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+#endif
}
inline bool Registers_arm::validRegister(int regNum) const {
@@ -1432,24 +2187,35 @@ inline bool Registers_arm::validRegister(int regNum) const {
// virtual register set (VRS).
if (regNum == UNW_REG_IP)
return true;
+
if (regNum == UNW_REG_SP)
return true;
+
if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15)
return true;
+
+#if defined(__ARM_WMMX)
if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3)
return true;
+#endif
+
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;
+
if (regNum == UNW_ARM_LR)
return _registers.__lr;
+
if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
return _registers.__pc;
+
if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
return _registers.__r[regNum];
+
+#if defined(__ARM_WMMX)
if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
if (!_saved_iwmmx_control) {
_saved_iwmmx_control = true;
@@ -1457,26 +2223,44 @@ inline uint32_t Registers_arm::getRegister(int regNum) {
}
return _iwmmx_control[regNum - UNW_ARM_WC0];
}
+#endif
+
_LIBUNWIND_ABORT("unsupported arm register");
}
inline void Registers_arm::setRegister(int regNum, uint32_t value) {
- if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+ if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP) {
_registers.__sp = value;
- else if (regNum == UNW_ARM_LR)
+ return;
+ }
+
+ if (regNum == UNW_ARM_LR) {
_registers.__lr = value;
- else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+ return;
+ }
+
+ if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP) {
_registers.__pc = value;
- else if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
+ return;
+ }
+
+ if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12) {
_registers.__r[regNum] = value;
- else if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+ return;
+ }
+
+#if defined(__ARM_WMMX)
+ if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
if (!_saved_iwmmx_control) {
_saved_iwmmx_control = true;
saveiWMMXControl(_iwmmx_control);
}
_iwmmx_control[regNum - UNW_ARM_WC0] = value;
- } else
- _LIBUNWIND_ABORT("unsupported arm register");
+ return;
+ }
+#endif
+
+ _LIBUNWIND_ABORT("unsupported arm register");
}
inline const char *Registers_arm::getRegisterName(int regNum) {
@@ -1652,7 +2436,10 @@ inline bool Registers_arm::validFloatRegister(int regNum) const {
// NOTE: Consider the intel MMX registers floating points so the
// unw_get_fpreg can be used to transmit the 64-bit data back.
return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31))
- || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15));
+#if defined(__ARM_WMMX)
+ || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15))
+#endif
+ ;
}
inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) {
@@ -1665,21 +2452,27 @@ inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) {
saveVFPWithFSTMD(_vfp_d0_d15_pad);
}
return _vfp_d0_d15_pad[regNum - UNW_ARM_D0];
- } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
+ }
+
+ if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
if (!_saved_vfp_d16_d31) {
_saved_vfp_d16_d31 = true;
saveVFPv3(_vfp_d16_d31);
}
return _vfp_d16_d31[regNum - UNW_ARM_D16];
- } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+ }
+
+#if defined(__ARM_WMMX)
+ if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
if (!_saved_iwmmx) {
_saved_iwmmx = true;
saveiWMMX(_iwmmx);
}
return _iwmmx[regNum - UNW_ARM_WR0];
- } else {
- _LIBUNWIND_ABORT("Unknown ARM float register");
}
+#endif
+
+ _LIBUNWIND_ABORT("Unknown ARM float register");
}
inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) {
@@ -1692,21 +2485,30 @@ inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) {
saveVFPWithFSTMD(_vfp_d0_d15_pad);
}
_vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value;
- } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
+ return;
+ }
+
+ if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
if (!_saved_vfp_d16_d31) {
_saved_vfp_d16_d31 = true;
saveVFPv3(_vfp_d16_d31);
}
_vfp_d16_d31[regNum - UNW_ARM_D16] = value;
- } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+ return;
+ }
+
+#if defined(__ARM_WMMX)
+ if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
if (!_saved_iwmmx) {
_saved_iwmmx = true;
saveiWMMX(_iwmmx);
}
_iwmmx[regNum - UNW_ARM_WR0] = value;
- } else {
- _LIBUNWIND_ABORT("Unknown ARM float register");
+ return;
}
+#endif
+
+ _LIBUNWIND_ABORT("Unknown ARM float register");
}
inline bool Registers_arm::validVectorRegister(int) const {
@@ -1740,18 +2542,21 @@ public:
bool validVectorRegister(int num) const;
v128 getVectorRegister(int num) const;
void setVectorRegister(int num, v128 value);
- const char *getRegisterName(int num);
+ static const char *getRegisterName(int num);
void jumpto();
- static int lastDwarfRegNum() { return 31; }
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; }
+ static int getArch() { return REGISTERS_OR1K; }
uint64_t getSP() const { return _registers.__r[1]; }
void setSP(uint32_t value) { _registers.__r[1] = value; }
- uint64_t getIP() const { return _registers.__r[9]; }
- void setIP(uint32_t value) { _registers.__r[9] = value; }
+ uint64_t getIP() const { return _registers.__pc; }
+ void setIP(uint32_t value) { _registers.__pc = value; }
private:
struct or1k_thread_state_t {
- unsigned int __r[32];
+ unsigned int __r[32]; // r0-r31
+ unsigned int __pc; // Program counter
+ unsigned int __epcr; // Program counter at exception
};
or1k_thread_state_t _registers;
@@ -1777,6 +2582,8 @@ inline bool Registers_or1k::validRegister(int regNum) const {
return false;
if (regNum <= UNW_OR1K_R31)
return true;
+ if (regNum == UNW_OR1K_EPCR)
+ return true;
return false;
}
@@ -1786,9 +2593,11 @@ inline uint32_t Registers_or1k::getRegister(int regNum) const {
switch (regNum) {
case UNW_REG_IP:
- return _registers.__r[9];
+ return _registers.__pc;
case UNW_REG_SP:
return _registers.__r[1];
+ case UNW_OR1K_EPCR:
+ return _registers.__epcr;
}
_LIBUNWIND_ABORT("unsupported or1k register");
}
@@ -1801,11 +2610,14 @@ inline void Registers_or1k::setRegister(int regNum, uint32_t value) {
switch (regNum) {
case UNW_REG_IP:
- _registers.__r[9] = value;
+ _registers.__pc = value;
return;
case UNW_REG_SP:
_registers.__r[1] = value;
return;
+ case UNW_OR1K_EPCR:
+ _registers.__epcr = value;
+ return;
}
_LIBUNWIND_ABORT("unsupported or1k register");
}
@@ -1901,12 +2713,811 @@ inline const char *Registers_or1k::getRegisterName(int regNum) {
return "r30";
case UNW_OR1K_R31:
return "r31";
+ case UNW_OR1K_EPCR:
+ return "EPCR";
default:
return "unknown register";
}
}
#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);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+ static int getArch() { return REGISTERS_MIPS_O32; }
+
+ 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;
+#ifdef __mips_hard_float
+ /// O32 with 32-bit floating point registers only uses half of this
+ /// space. However, using the same layout for 32-bit vs 64-bit
+ /// floating point registers results in a single context size for
+ /// O32 with hard float.
+ uint32_t _padding;
+ double _floats[32];
+#endif
+};
+
+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 __mips_isa_rev != 6
+ if (regNum == UNW_MIPS_HI)
+ return true;
+ if (regNum == UNW_MIPS_LO)
+ return true;
+#endif
+#if defined(__mips_hard_float) && __mips_fpr == 32
+ if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31)
+ return true;
+#endif
+ // FIXME: 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];
+#if defined(__mips_hard_float) && __mips_fpr == 32
+ if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) {
+ uint32_t *p;
+
+ if (regNum % 2 == 0)
+ p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0];
+ else
+ p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1;
+ return *p;
+ }
+#endif
+
+ 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;
+ }
+#if defined(__mips_hard_float) && __mips_fpr == 32
+ if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31) {
+ uint32_t *p;
+
+ if (regNum % 2 == 0)
+ p = (uint32_t *)&_floats[regNum - UNW_MIPS_F0];
+ else
+ p = (uint32_t *)&_floats[(regNum - 1) - UNW_MIPS_F0] + 1;
+ *p = value;
+ return;
+ }
+#endif
+
+ 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 {
+#if defined(__mips_hard_float) && __mips_fpr == 64
+ if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31)
+ return true;
+#endif
+ return false;
+}
+
+inline double Registers_mips_o32::getFloatRegister(int regNum) const {
+#if defined(__mips_hard_float) && __mips_fpr == 64
+ assert(validFloatRegister(regNum));
+ return _floats[regNum - UNW_MIPS_F0];
+#else
+ _LIBUNWIND_ABORT("mips_o32 float support not implemented");
+#endif
+}
+
+inline void Registers_mips_o32::setFloatRegister(int regNum,
+ double value) {
+#if defined(__mips_hard_float) && __mips_fpr == 64
+ assert(validFloatRegister(regNum));
+ _floats[regNum - UNW_MIPS_F0] = value;
+#else
+ _LIBUNWIND_ABORT("mips_o32 float support not implemented");
+#endif
+}
+
+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_F0:
+ return "$f0";
+ case UNW_MIPS_F1:
+ return "$f1";
+ case UNW_MIPS_F2:
+ return "$f2";
+ case UNW_MIPS_F3:
+ return "$f3";
+ case UNW_MIPS_F4:
+ return "$f4";
+ case UNW_MIPS_F5:
+ return "$f5";
+ case UNW_MIPS_F6:
+ return "$f6";
+ case UNW_MIPS_F7:
+ return "$f7";
+ case UNW_MIPS_F8:
+ return "$f8";
+ case UNW_MIPS_F9:
+ return "$f9";
+ case UNW_MIPS_F10:
+ return "$f10";
+ case UNW_MIPS_F11:
+ return "$f11";
+ case UNW_MIPS_F12:
+ return "$f12";
+ case UNW_MIPS_F13:
+ return "$f13";
+ case UNW_MIPS_F14:
+ return "$f14";
+ case UNW_MIPS_F15:
+ return "$f15";
+ case UNW_MIPS_F16:
+ return "$f16";
+ case UNW_MIPS_F17:
+ return "$f17";
+ case UNW_MIPS_F18:
+ return "$f18";
+ case UNW_MIPS_F19:
+ return "$f19";
+ case UNW_MIPS_F20:
+ return "$f20";
+ case UNW_MIPS_F21:
+ return "$f21";
+ case UNW_MIPS_F22:
+ return "$f22";
+ case UNW_MIPS_F23:
+ return "$f23";
+ case UNW_MIPS_F24:
+ return "$f24";
+ case UNW_MIPS_F25:
+ return "$f25";
+ case UNW_MIPS_F26:
+ return "$f26";
+ case UNW_MIPS_F27:
+ return "$f27";
+ case UNW_MIPS_F28:
+ return "$f28";
+ case UNW_MIPS_F29:
+ return "$f29";
+ case UNW_MIPS_F30:
+ return "$f30";
+ case UNW_MIPS_F31:
+ return "$f31";
+ 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_NEWABI)
+/// Registers_mips_newabi holds the register state of a thread in a
+/// MIPS process using NEWABI (the N32 or N64 ABIs).
+class _LIBUNWIND_HIDDEN Registers_mips_newabi {
+public:
+ Registers_mips_newabi();
+ Registers_mips_newabi(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);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+ static int getArch() { return REGISTERS_MIPS_NEWABI; }
+
+ 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_newabi_thread_state_t {
+ uint64_t __r[32];
+ uint64_t __pc;
+ uint64_t __hi;
+ uint64_t __lo;
+ };
+
+ mips_newabi_thread_state_t _registers;
+#ifdef __mips_hard_float
+ double _floats[32];
+#endif
+};
+
+inline Registers_mips_newabi::Registers_mips_newabi(const void *registers) {
+ static_assert((check_fit<Registers_mips_newabi, unw_context_t>::does_fit),
+ "mips_newabi registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast<const uint8_t *>(registers),
+ sizeof(_registers));
+}
+
+inline Registers_mips_newabi::Registers_mips_newabi() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_mips_newabi::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 __mips_isa_rev != 6
+ if (regNum == UNW_MIPS_HI)
+ return true;
+ if (regNum == UNW_MIPS_LO)
+ return true;
+#endif
+ // FIXME: Hard float, DSP accumulator registers, MSA registers
+ return false;
+}
+
+inline uint64_t Registers_mips_newabi::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_newabi register");
+}
+
+inline void Registers_mips_newabi::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_newabi register");
+}
+
+inline bool Registers_mips_newabi::validFloatRegister(int regNum) const {
+#ifdef __mips_hard_float
+ if (regNum >= UNW_MIPS_F0 && regNum <= UNW_MIPS_F31)
+ return true;
+#endif
+ return false;
+}
+
+inline double Registers_mips_newabi::getFloatRegister(int regNum) const {
+#ifdef __mips_hard_float
+ assert(validFloatRegister(regNum));
+ return _floats[regNum - UNW_MIPS_F0];
+#else
+ _LIBUNWIND_ABORT("mips_newabi float support not implemented");
+#endif
+}
+
+inline void Registers_mips_newabi::setFloatRegister(int regNum,
+ double value) {
+#ifdef __mips_hard_float
+ assert(validFloatRegister(regNum));
+ _floats[regNum - UNW_MIPS_F0] = value;
+#else
+ _LIBUNWIND_ABORT("mips_newabi float support not implemented");
+#endif
+}
+
+inline bool Registers_mips_newabi::validVectorRegister(int /* regNum */) const {
+ return false;
+}
+
+inline v128 Registers_mips_newabi::getVectorRegister(int /* regNum */) const {
+ _LIBUNWIND_ABORT("mips_newabi vector support not implemented");
+}
+
+inline void Registers_mips_newabi::setVectorRegister(int /* regNum */, v128 /* value */) {
+ _LIBUNWIND_ABORT("mips_newabi vector support not implemented");
+}
+
+inline const char *Registers_mips_newabi::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_F0:
+ return "$f0";
+ case UNW_MIPS_F1:
+ return "$f1";
+ case UNW_MIPS_F2:
+ return "$f2";
+ case UNW_MIPS_F3:
+ return "$f3";
+ case UNW_MIPS_F4:
+ return "$f4";
+ case UNW_MIPS_F5:
+ return "$f5";
+ case UNW_MIPS_F6:
+ return "$f6";
+ case UNW_MIPS_F7:
+ return "$f7";
+ case UNW_MIPS_F8:
+ return "$f8";
+ case UNW_MIPS_F9:
+ return "$f9";
+ case UNW_MIPS_F10:
+ return "$f10";
+ case UNW_MIPS_F11:
+ return "$f11";
+ case UNW_MIPS_F12:
+ return "$f12";
+ case UNW_MIPS_F13:
+ return "$f13";
+ case UNW_MIPS_F14:
+ return "$f14";
+ case UNW_MIPS_F15:
+ return "$f15";
+ case UNW_MIPS_F16:
+ return "$f16";
+ case UNW_MIPS_F17:
+ return "$f17";
+ case UNW_MIPS_F18:
+ return "$f18";
+ case UNW_MIPS_F19:
+ return "$f19";
+ case UNW_MIPS_F20:
+ return "$f20";
+ case UNW_MIPS_F21:
+ return "$f21";
+ case UNW_MIPS_F22:
+ return "$f22";
+ case UNW_MIPS_F23:
+ return "$f23";
+ case UNW_MIPS_F24:
+ return "$f24";
+ case UNW_MIPS_F25:
+ return "$f25";
+ case UNW_MIPS_F26:
+ return "$f26";
+ case UNW_MIPS_F27:
+ return "$f27";
+ case UNW_MIPS_F28:
+ return "$f28";
+ case UNW_MIPS_F29:
+ return "$f29";
+ case UNW_MIPS_F30:
+ return "$f30";
+ case UNW_MIPS_F31:
+ return "$f31";
+ case UNW_MIPS_HI:
+ return "$hi";
+ case UNW_MIPS_LO:
+ return "$lo";
+ default:
+ return "unknown register";
+ }
+}
+#endif // _LIBUNWIND_TARGET_MIPS_NEWABI
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+/// Registers_sparc holds the register state of a thread in a 32-bit Sparc
+/// process.
+class _LIBUNWIND_HIDDEN Registers_sparc {
+public:
+ Registers_sparc();
+ Registers_sparc(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);
+ static const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; }
+ static int getArch() { return REGISTERS_SPARC; }
+
+ uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6]; }
+ void setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; }
+ uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; }
+ void setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
+
+private:
+ struct sparc_thread_state_t {
+ unsigned int __regs[32];
+ };
+
+ sparc_thread_state_t _registers;
+};
+
+inline Registers_sparc::Registers_sparc(const void *registers) {
+ static_assert((check_fit<Registers_sparc, unw_context_t>::does_fit),
+ "sparc registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast<const uint8_t *>(registers),
+ sizeof(_registers));
+}
+
+inline Registers_sparc::Registers_sparc() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_sparc::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_SPARC_I7)
+ return true;
+ return false;
+}
+
+inline uint32_t Registers_sparc::getRegister(int regNum) const {
+ if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) {
+ return _registers.__regs[regNum];
+ }
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__regs[UNW_SPARC_O7];
+ case UNW_REG_SP:
+ return _registers.__regs[UNW_SPARC_O6];
+ }
+ _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline void Registers_sparc::setRegister(int regNum, uint32_t value) {
+ if ((UNW_SPARC_G0 <= regNum) && (regNum <= UNW_SPARC_I7)) {
+ _registers.__regs[regNum] = value;
+ return;
+ }
+
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__regs[UNW_SPARC_O7] = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__regs[UNW_SPARC_O6] = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline bool Registers_sparc::validFloatRegister(int) const { return false; }
+
+inline double Registers_sparc::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline void Registers_sparc::setFloatRegister(int, double) {
+ _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline bool Registers_sparc::validVectorRegister(int) const { return false; }
+
+inline v128 Registers_sparc::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline void Registers_sparc::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline const char *Registers_sparc::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "pc";
+ case UNW_SPARC_G0:
+ return "g0";
+ case UNW_SPARC_G1:
+ return "g1";
+ case UNW_SPARC_G2:
+ return "g2";
+ case UNW_SPARC_G3:
+ return "g3";
+ case UNW_SPARC_G4:
+ return "g4";
+ case UNW_SPARC_G5:
+ return "g5";
+ case UNW_SPARC_G6:
+ return "g6";
+ case UNW_SPARC_G7:
+ return "g7";
+ case UNW_SPARC_O0:
+ return "o0";
+ case UNW_SPARC_O1:
+ return "o1";
+ case UNW_SPARC_O2:
+ return "o2";
+ case UNW_SPARC_O3:
+ return "o3";
+ case UNW_SPARC_O4:
+ return "o4";
+ case UNW_SPARC_O5:
+ return "o5";
+ case UNW_REG_SP:
+ case UNW_SPARC_O6:
+ return "sp";
+ case UNW_SPARC_O7:
+ return "o7";
+ case UNW_SPARC_L0:
+ return "l0";
+ case UNW_SPARC_L1:
+ return "l1";
+ case UNW_SPARC_L2:
+ return "l2";
+ case UNW_SPARC_L3:
+ return "l3";
+ case UNW_SPARC_L4:
+ return "l4";
+ case UNW_SPARC_L5:
+ return "l5";
+ case UNW_SPARC_L6:
+ return "l6";
+ case UNW_SPARC_L7:
+ return "l7";
+ case UNW_SPARC_I0:
+ return "i0";
+ case UNW_SPARC_I1:
+ return "i1";
+ case UNW_SPARC_I2:
+ return "i2";
+ case UNW_SPARC_I3:
+ return "i3";
+ case UNW_SPARC_I4:
+ return "i4";
+ case UNW_SPARC_I5:
+ return "i5";
+ case UNW_SPARC_I6:
+ return "fp";
+ case UNW_SPARC_I7:
+ return "i7";
+ default:
+ return "unknown register";
+ }
+}
+#endif // _LIBUNWIND_TARGET_SPARC
+
} // namespace libunwind
#endif // __REGISTERS_HPP__
diff --git a/src/Unwind-EHABI.cpp b/src/Unwind-EHABI.cpp
index 5950c6902e38..f37732c6ac86 100644
--- a/src/Unwind-EHABI.cpp
+++ b/src/Unwind-EHABI.cpp
@@ -12,8 +12,9 @@
#include "Unwind-EHABI.h"
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
+#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
@@ -245,11 +246,9 @@ decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
return data;
}
-_Unwind_Reason_Code _Unwind_VRS_Interpret(
- _Unwind_Context* context,
- const uint32_t* data,
- size_t offset,
- size_t len) {
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
+ size_t offset, size_t len) {
bool wrotePC = false;
bool finish = false;
while (offset < len && !finish) {
@@ -351,6 +350,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
}
case 0xc0: {
switch (byte) {
+#if defined(__ARM_WMMX)
case 0xc0:
case 0xc1:
case 0xc2:
@@ -378,6 +378,7 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
_Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE);
break;
}
+#endif
case 0xc8:
case 0xc9: {
uint8_t v = getByte(data, offset++);
@@ -416,24 +417,21 @@ _Unwind_Reason_Code _Unwind_VRS_Interpret(
return _URC_CONTINUE_UNWIND;
}
-extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(
- _Unwind_State state,
- _Unwind_Control_Block *ucbp,
- _Unwind_Context *context) {
+extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
+__aeabi_unwind_cpp_pr0(_Unwind_State state, _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context) {
return unwindOneFrame(state, ucbp, context);
}
-extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(
- _Unwind_State state,
- _Unwind_Control_Block *ucbp,
- _Unwind_Context *context) {
+extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
+__aeabi_unwind_cpp_pr1(_Unwind_State state, _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context) {
return unwindOneFrame(state, ucbp, context);
}
-extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
- _Unwind_State state,
- _Unwind_Control_Block *ucbp,
- _Unwind_Context *context) {
+extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
+__aeabi_unwind_cpp_pr2(_Unwind_State state, _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context) {
return unwindOneFrame(state, ucbp, context);
}
@@ -454,7 +452,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_proc_info_t frameInfo;
if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info "
- "failed => _URC_FATAL_PHASE1_ERROR\n",
+ "failed => _URC_FATAL_PHASE1_ERROR",
static_cast<void *>(exception_object));
return _URC_FATAL_PHASE1_ERROR;
}
@@ -471,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\n",
- 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
@@ -484,7 +482,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
__personality_routine p =
(__personality_routine)(long)(frameInfo.handler);
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): calling personality function %p\n",
+ "unwind_phase1(ex_ojb=%p): calling personality function %p",
static_cast<void *>(exception_object),
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p)));
struct _Unwind_Context *context = (struct _Unwind_Context *)(cursor);
@@ -496,7 +494,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
(*p)(_US_VIRTUAL_UNWIND_FRAME, exception_object, context);
_LIBUNWIND_TRACE_UNWINDING(
"unwind_phase1(ex_ojb=%p): personality result %d start_ip %x ehtp %p "
- "additional %x\n",
+ "additional %x",
static_cast<void *>(exception_object), personalityResult,
exception_object->pr_cache.fnstart,
static_cast<void *>(exception_object->pr_cache.ehtp),
@@ -508,13 +506,13 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
handlerNotFound = false;
// p should have initialized barrier_cache. EHABI #7.3.5
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n",
+ "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",
static_cast<void *>(exception_object));
return _URC_NO_REASON;
case _URC_CONTINUE_UNWIND:
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
static_cast<void *>(exception_object));
// continue unwinding
break;
@@ -526,7 +524,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
default:
// something went wrong
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
static_cast<void *>(exception_object));
return _URC_FATAL_PHASE1_ERROR;
}
@@ -541,13 +539,13 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
// See comment at the start of unwind_phase1 regarding VRS integrity.
unw_init_local(cursor, uc);
- _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n",
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
static_cast<void *>(exception_object));
int frame_count = 0;
// Walk each frame until we reach where search phase said to stop.
while (true) {
- // Ask libuwind to get next frame (skip over first which is
+ // Ask libunwind to get next frame (skip over first which is
// _Unwind_RaiseException or _Unwind_Resume).
//
// Resume only ever makes sense for 1 frame.
@@ -572,7 +570,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
unw_get_reg(cursor, UNW_REG_SP, &sp);
if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info "
- "failed => _URC_FATAL_PHASE1_ERROR\n",
+ "failed => _URC_FATAL_PHASE2_ERROR",
static_cast<void *>(exception_object));
return _URC_FATAL_PHASE2_ERROR;
}
@@ -587,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\n",
- 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.
@@ -610,7 +608,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
case _URC_CONTINUE_UNWIND:
// Continue unwinding
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
static_cast<void *>(exception_object));
// EHABI #7.2
if (sp == exception_object->barrier_cache.sp) {
@@ -621,7 +619,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
break;
case _URC_INSTALL_CONTEXT:
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
+ "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",
static_cast<void *>(exception_object));
// Personality routine says to transfer control to landing pad.
// We may get control back if landing pad calls _Unwind_Resume().
@@ -630,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\n",
+ "user code with ip=0x%" PRIxPTR ", sp=0x%" PRIxPTR,
static_cast<void *>(exception_object),
- (long long)pc, (long long)sp);
+ pc, sp);
}
{
@@ -668,7 +666,7 @@ static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor
/// Called by __cxa_throw. Only returns if there is a fatal error.
_LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_RaiseException(_Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
static_cast<void *>(exception_object));
unw_context_t uc;
unw_cursor_t cursor;
@@ -706,7 +704,7 @@ _LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) {
/// in turn calls _Unwind_Resume_or_Rethrow().
_LIBUNWIND_EXPORT void
_Unwind_Resume(_Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)",
static_cast<void *>(exception_object));
unw_context_t uc;
unw_cursor_t cursor;
@@ -730,7 +728,7 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
result = (uintptr_t)frameInfo.lsda;
_LIBUNWIND_TRACE_API(
- "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx\n",
+ "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx",
static_cast<void *>(context), (long long)result);
return result;
}
@@ -753,12 +751,12 @@ static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,
return value;
}
-_Unwind_VRS_Result
+_LIBUNWIND_EXPORT _Unwind_VRS_Result
_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t regno, _Unwind_VRS_DataRepresentation representation,
void *valuep) {
_LIBUNWIND_TRACE_API("_Unwind_VRS_Set(context=%p, regclass=%d, reg=%d, "
- "rep=%d, value=0x%llX)\n",
+ "rep=%d, value=0x%llX)",
static_cast<void *>(context), regclass, regno,
representation,
ValueAsBitPattern(representation, valuep));
@@ -771,13 +769,6 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
*(unw_word_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
- case _UVRSC_WMMXC:
- if (representation != _UVRSD_UINT32 || regno > 3)
- return _UVRSR_FAILED;
- return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
- *(unw_word_t *)valuep) == UNW_ESUCCESS
- ? _UVRSR_OK
- : _UVRSR_FAILED;
case _UVRSC_VFP:
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED;
@@ -794,6 +785,14 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#if defined(__ARM_WMMX)
+ case _UVRSC_WMMXC:
+ if (representation != _UVRSD_UINT32 || regno > 3)
+ return _UVRSR_FAILED;
+ return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
+ *(unw_word_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
case _UVRSC_WMMXD:
if (representation != _UVRSD_DOUBLE || regno > 31)
return _UVRSR_FAILED;
@@ -801,6 +800,11 @@ _Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
*(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#else
+ case _UVRSC_WMMXC:
+ case _UVRSC_WMMXD:
+ break;
+#endif
}
_LIBUNWIND_ABORT("unsupported register class");
}
@@ -819,13 +823,6 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
(unw_word_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
- case _UVRSC_WMMXC:
- if (representation != _UVRSD_UINT32 || regno > 3)
- return _UVRSR_FAILED;
- return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
- (unw_word_t *)valuep) == UNW_ESUCCESS
- ? _UVRSR_OK
- : _UVRSR_FAILED;
case _UVRSC_VFP:
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED;
@@ -842,6 +839,14 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#if defined(__ARM_WMMX)
+ case _UVRSC_WMMXC:
+ if (representation != _UVRSD_UINT32 || regno > 3)
+ return _UVRSR_FAILED;
+ return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_WC0 + regno),
+ (unw_word_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
case _UVRSC_WMMXD:
if (representation != _UVRSD_DOUBLE || regno > 31)
return _UVRSR_FAILED;
@@ -849,21 +854,24 @@ _Unwind_VRS_Get_Internal(_Unwind_Context *context,
(unw_fpreg_t *)valuep) == UNW_ESUCCESS
? _UVRSR_OK
: _UVRSR_FAILED;
+#else
+ case _UVRSC_WMMXC:
+ case _UVRSC_WMMXD:
+ break;
+#endif
}
_LIBUNWIND_ABORT("unsupported register class");
}
-_Unwind_VRS_Result _Unwind_VRS_Get(
- _Unwind_Context *context,
- _Unwind_VRS_RegClass regclass,
- uint32_t regno,
- _Unwind_VRS_DataRepresentation representation,
- void *valuep) {
+_LIBUNWIND_EXPORT _Unwind_VRS_Result
+_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+ uint32_t regno, _Unwind_VRS_DataRepresentation representation,
+ void *valuep) {
_Unwind_VRS_Result result =
_Unwind_VRS_Get_Internal(context, regclass, regno, representation,
valuep);
_LIBUNWIND_TRACE_API("_Unwind_VRS_Get(context=%p, regclass=%d, reg=%d, "
- "rep=%d, value=0x%llX, result = %d)\n",
+ "rep=%d, value=0x%llX, result = %d)",
static_cast<void *>(context), regclass, regno,
representation,
ValueAsBitPattern(representation, valuep), result);
@@ -875,12 +883,15 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
uint32_t discriminator,
_Unwind_VRS_DataRepresentation representation) {
_LIBUNWIND_TRACE_API("_Unwind_VRS_Pop(context=%p, regclass=%d, "
- "discriminator=%d, representation=%d)\n",
+ "discriminator=%d, representation=%d)",
static_cast<void *>(context), regclass, discriminator,
representation);
switch (regclass) {
- case _UVRSC_CORE:
- case _UVRSC_WMMXC: {
+ case _UVRSC_WMMXC:
+#if !defined(__ARM_WMMX)
+ break;
+#endif
+ case _UVRSC_CORE: {
if (representation != _UVRSD_UINT32)
return _UVRSR_FAILED;
// When popping SP from the stack, we don't want to override it from the
@@ -908,8 +919,11 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
}
return _UVRSR_OK;
}
- case _UVRSC_VFP:
- case _UVRSC_WMMXD: {
+ case _UVRSC_WMMXD:
+#if !defined(__ARM_WMMX)
+ break;
+#endif
+ case _UVRSC_VFP: {
if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
return _UVRSR_FAILED;
uint32_t first = discriminator >> 16;
@@ -948,7 +962,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) {
uintptr_t result = 0;
if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
result = (uintptr_t)frameInfo.start_ip;
- _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX\n",
+ _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%llX",
static_cast<void *>(context), (long long)result);
return result;
}
@@ -958,7 +972,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) {
// is caught.
_LIBUNWIND_EXPORT void
_Unwind_DeleteException(_Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
static_cast<void *>(exception_object));
if (exception_object->exception_cleanup != NULL)
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
@@ -974,4 +988,4 @@ __gnu_unwind_frame(_Unwind_Exception *exception_object,
return _URC_OK;
}
-#endif // _LIBUNWIND_ARM_EHABI
+#endif // defined(_LIBUNWIND_ARM_EHABI)
diff --git a/src/Unwind-EHABI.h b/src/Unwind-EHABI.h
index a7c62df75132..fe164ff7be1e 100644
--- a/src/Unwind-EHABI.h
+++ b/src/Unwind-EHABI.h
@@ -13,7 +13,7 @@
#include <__libunwind_config.h>
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
#include <stdint.h>
#include <unwind.h>
@@ -46,6 +46,6 @@ extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
} // extern "C"
#endif
-#endif // _LIBUNWIND_ARM_EHABI
+#endif // defined(_LIBUNWIND_ARM_EHABI)
#endif // __UNWIND_EHABI_H__
diff --git a/src/Unwind-seh.cpp b/src/Unwind-seh.cpp
new file mode 100644
index 000000000000..c5cf7c47d40d
--- /dev/null
+++ b/src/Unwind-seh.cpp
@@ -0,0 +1,491 @@
+//===--------------------------- Unwind-seh.cpp ---------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements SEH-based Itanium C++ exceptions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "config.h"
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+
+#include <unwind.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <windef.h>
+#include <excpt.h>
+#include <winnt.h>
+#include <ntstatus.h>
+
+#include "libunwind_ext.h"
+#include "UnwindCursor.hpp"
+
+using namespace libunwind;
+
+#define STATUS_USER_DEFINED (1u << 29)
+
+#define STATUS_GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C')
+
+#define MAKE_CUSTOM_STATUS(s, c) \
+ ((NTSTATUS)(((s) << 30) | STATUS_USER_DEFINED | (c)))
+#define MAKE_GCC_EXCEPTION(c) \
+ MAKE_CUSTOM_STATUS(STATUS_SEVERITY_SUCCESS, STATUS_GCC_MAGIC | ((c) << 24))
+
+/// SEH exception raised by libunwind when the program calls
+/// \c _Unwind_RaiseException.
+#define STATUS_GCC_THROW MAKE_GCC_EXCEPTION(0) // 0x20474343
+/// SEH exception raised by libunwind to initiate phase 2 of exception
+/// handling.
+#define STATUS_GCC_UNWIND MAKE_GCC_EXCEPTION(1) // 0x21474343
+
+/// Class of foreign exceptions based on unrecognized SEH exceptions.
+static const uint64_t kSEHExceptionClass = 0x434C4E4753454800; // CLNGSEH\0
+
+/// Exception cleanup routine used by \c _GCC_specific_handler to
+/// free foreign exceptions.
+static void seh_exc_cleanup(_Unwind_Reason_Code urc, _Unwind_Exception *exc) {
+ if (exc->exception_class != kSEHExceptionClass)
+ _LIBUNWIND_ABORT("SEH cleanup called on non-SEH exception");
+ free(exc);
+}
+
+static int _unw_init_seh(unw_cursor_t *cursor, CONTEXT *ctx);
+static DISPATCHER_CONTEXT *_unw_seh_get_disp_ctx(unw_cursor_t *cursor);
+static void _unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp);
+
+/// Common implementation of SEH-style handler functions used by Itanium-
+/// style frames. Depending on how and why it was called, it may do one of:
+/// a) Delegate to the given Itanium-style personality function; or
+/// b) Initiate a collided unwind to halt unwinding.
+_LIBUNWIND_EXPORT EXCEPTION_DISPOSITION
+_GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
+ DISPATCHER_CONTEXT *disp, __personality_routine pers) {
+ unw_context_t uc;
+ unw_cursor_t cursor;
+ _Unwind_Exception *exc;
+ _Unwind_Action action;
+ struct _Unwind_Context *ctx = nullptr;
+ _Unwind_Reason_Code urc;
+ uintptr_t retval, target;
+ bool ours = false;
+
+ _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler(%#010x(%x), %p)", ms_exc->ExceptionCode, ms_exc->ExceptionFlags, frame);
+ if (ms_exc->ExceptionCode == STATUS_GCC_UNWIND) {
+ if (IS_TARGET_UNWIND(ms_exc->ExceptionFlags)) {
+ // Set up the upper return value (the lower one and the target PC
+ // were set in the call to RtlUnwindEx()) for the landing pad.
+#ifdef __x86_64__
+ disp->ContextRecord->Rdx = ms_exc->ExceptionInformation[3];
+#elif defined(__arm__)
+ disp->ContextRecord->R1 = ms_exc->ExceptionInformation[3];
+#elif defined(__aarch64__)
+ disp->ContextRecord->X1 = ms_exc->ExceptionInformation[3];
+#endif
+ }
+ // This is the collided unwind to the landing pad. Nothing to do.
+ return ExceptionContinueSearch;
+ }
+
+ if (ms_exc->ExceptionCode == STATUS_GCC_THROW) {
+ // This is (probably) a libunwind-controlled exception/unwind. Recover the
+ // parameters which we set below, and pass them to the personality function.
+ ours = true;
+ exc = (_Unwind_Exception *)ms_exc->ExceptionInformation[0];
+ if (!IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1) {
+ ctx = (struct _Unwind_Context *)ms_exc->ExceptionInformation[1];
+ action = (_Unwind_Action)ms_exc->ExceptionInformation[2];
+ }
+ } else {
+ // Foreign exception.
+ exc = (_Unwind_Exception *)malloc(sizeof(_Unwind_Exception));
+ exc->exception_class = kSEHExceptionClass;
+ exc->exception_cleanup = seh_exc_cleanup;
+ memset(exc->private_, 0, sizeof(exc->private_));
+ }
+ if (!ctx) {
+ _unw_init_seh(&cursor, disp->ContextRecord);
+ _unw_seh_set_disp_ctx(&cursor, disp);
+ unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc-1);
+ ctx = (struct _Unwind_Context *)&cursor;
+
+ if (!IS_UNWINDING(ms_exc->ExceptionFlags)) {
+ if (ours && ms_exc->NumberParameters > 1)
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_FORCE_UNWIND);
+ else
+ action = _UA_SEARCH_PHASE;
+ } else {
+ if (ours && ms_exc->ExceptionInformation[1] == (ULONG_PTR)frame)
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
+ else
+ action = _UA_CLEANUP_PHASE;
+ }
+ }
+
+ _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() calling personality function %p(1, %d, %llx, %p, %p)", pers, action, exc->exception_class, exc, ctx);
+ urc = pers(1, action, exc->exception_class, exc, ctx);
+ _LIBUNWIND_TRACE_UNWINDING("_GCC_specific_handler() personality returned %d", urc);
+ switch (urc) {
+ case _URC_CONTINUE_UNWIND:
+ // If we're in phase 2, and the personality routine said to continue
+ // at the target frame, we're in real trouble.
+ if (action & _UA_HANDLER_FRAME)
+ _LIBUNWIND_ABORT("Personality continued unwind at the target frame!");
+ return ExceptionContinueSearch;
+ case _URC_HANDLER_FOUND:
+ // If we were called by __libunwind_seh_personality(), indicate that
+ // a handler was found; otherwise, initiate phase 2 by unwinding.
+ if (ours && ms_exc->NumberParameters > 1)
+ return 4 /* ExecptionExecuteHandler in mingw */;
+ // This should never happen in phase 2.
+ if (IS_UNWINDING(ms_exc->ExceptionFlags))
+ _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!");
+ exc->private_[1] = (ULONG_PTR)frame;
+ if (ours) {
+ ms_exc->NumberParameters = 4;
+ ms_exc->ExceptionInformation[1] = (ULONG_PTR)frame;
+ }
+ // FIXME: Indicate target frame in foreign case!
+ // phase 2: the clean up phase
+ RtlUnwindEx(frame, (PVOID)disp->ControlPc, ms_exc, exc, ms_ctx, disp->HistoryTable);
+ _LIBUNWIND_ABORT("RtlUnwindEx() failed");
+ case _URC_INSTALL_CONTEXT: {
+ // If we were called by __libunwind_seh_personality(), indicate that
+ // a handler was found; otherwise, it's time to initiate a collided
+ // unwind to the target.
+ if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1)
+ return 4 /* ExecptionExecuteHandler in mingw */;
+ // This should never happen in phase 1.
+ if (!IS_UNWINDING(ms_exc->ExceptionFlags))
+ _LIBUNWIND_ABORT("Personality installed context during phase 1!");
+#ifdef __x86_64__
+ exc->private_[2] = disp->TargetIp;
+ unw_get_reg(&cursor, UNW_X86_64_RAX, &retval);
+ unw_get_reg(&cursor, UNW_X86_64_RDX, &exc->private_[3]);
+#elif defined(__arm__)
+ exc->private_[2] = disp->TargetPc;
+ unw_get_reg(&cursor, UNW_ARM_R0, &retval);
+ unw_get_reg(&cursor, UNW_ARM_R1, &exc->private_[3]);
+#elif defined(__aarch64__)
+ exc->private_[2] = disp->TargetPc;
+ unw_get_reg(&cursor, UNW_ARM64_X0, &retval);
+ unw_get_reg(&cursor, UNW_ARM64_X1, &exc->private_[3]);
+#endif
+ unw_get_reg(&cursor, UNW_REG_IP, &target);
+ ms_exc->ExceptionCode = STATUS_GCC_UNWIND;
+#ifdef __x86_64__
+ ms_exc->ExceptionInformation[2] = disp->TargetIp;
+#elif defined(__arm__) || defined(__aarch64__)
+ ms_exc->ExceptionInformation[2] = disp->TargetPc;
+#endif
+ ms_exc->ExceptionInformation[3] = exc->private_[3];
+ // Give NTRTL some scratch space to keep track of the collided unwind.
+ // Don't use the one that was passed in; we don't want to overwrite the
+ // context in the DISPATCHER_CONTEXT.
+ CONTEXT new_ctx;
+ RtlUnwindEx(frame, (PVOID)target, ms_exc, (PVOID)retval, &new_ctx, disp->HistoryTable);
+ _LIBUNWIND_ABORT("RtlUnwindEx() failed");
+ }
+ // Anything else indicates a serious problem.
+ default: return ExceptionContinueExecution;
+ }
+}
+
+/// Personality function returned by \c unw_get_proc_info() in SEH contexts.
+/// This is a wrapper that calls the real SEH handler function, which in
+/// turn (at least, for Itanium-style frames) calls the real Itanium
+/// personality function (see \c _GCC_specific_handler()).
+extern "C" _Unwind_Reason_Code
+__libunwind_seh_personality(int version, _Unwind_Action state,
+ uint64_t klass, _Unwind_Exception *exc,
+ struct _Unwind_Context *context) {
+ EXCEPTION_RECORD ms_exc;
+ bool phase2 = (state & (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)) == _UA_CLEANUP_PHASE;
+ ms_exc.ExceptionCode = STATUS_GCC_THROW;
+ ms_exc.ExceptionFlags = 0;
+ ms_exc.NumberParameters = 3;
+ ms_exc.ExceptionInformation[0] = (ULONG_PTR)exc;
+ ms_exc.ExceptionInformation[1] = (ULONG_PTR)context;
+ ms_exc.ExceptionInformation[2] = state;
+ DISPATCHER_CONTEXT *disp_ctx = _unw_seh_get_disp_ctx((unw_cursor_t *)context);
+ EXCEPTION_DISPOSITION ms_act = disp_ctx->LanguageHandler(&ms_exc,
+ (PVOID)disp_ctx->EstablisherFrame,
+ disp_ctx->ContextRecord,
+ disp_ctx);
+ switch (ms_act) {
+ case ExceptionContinueSearch: return _URC_CONTINUE_UNWIND;
+ case 4 /*ExceptionExecuteHandler*/:
+ return phase2 ? _URC_INSTALL_CONTEXT : _URC_HANDLER_FOUND;
+ default:
+ return phase2 ? _URC_FATAL_PHASE2_ERROR : _URC_FATAL_PHASE1_ERROR;
+ }
+}
+
+static _Unwind_Reason_Code
+unwind_phase2_forced(unw_context_t *uc,
+ _Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter) {
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ // Walk each frame until we reach where search phase said to stop
+ while (unw_step(&cursor2) > 0) {
+
+ // Update info about this frame.
+ unw_proc_info_t frameInfo;
+ if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step "
+ "failed => _URC_END_OF_STACK",
+ (void *)exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // When tracing, print state information.
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ char functionBuf[512];
+ const char *functionName = functionBuf;
+ unw_word_t offset;
+ if ((unw_get_proc_name(&cursor2, functionBuf, sizeof(functionBuf),
+ &offset) != UNW_ESUCCESS) ||
+ (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,
+ (void *)exception_object, frameInfo.start_ip, functionName,
+ frameInfo.lsda, frameInfo.handler);
+ }
+
+ // Call stop function at each frame.
+ _Unwind_Action action =
+ (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE);
+ _Unwind_Reason_Code stopResult =
+ (*stop)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2), stop_parameter);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
+ (void *)exception_object, stopResult);
+ if (stopResult != _URC_NO_REASON) {
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
+ (void *)exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // If there is a personality routine, tell it we are unwinding.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(intptr_t)(frameInfo.handler);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
+ (void *)exception_object, (void *)(uintptr_t)p);
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2));
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned "
+ "_URC_CONTINUE_UNWIND",
+ (void *)exception_object);
+ // Destructors called, continue unwinding
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned "
+ "_URC_INSTALL_CONTEXT",
+ (void *)exception_object);
+ // We may get control back if landing pad calls _Unwind_Resume().
+ unw_resume(&cursor2);
+ break;
+ default:
+ // Personality routine returned an unknown result code.
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned %d, "
+ "_URC_FATAL_PHASE2_ERROR",
+ (void *)exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // Call stop function one last time and tell it we've reached the end
+ // of the stack.
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
+ "function with _UA_END_OF_STACK",
+ (void *)exception_object);
+ _Unwind_Action lastAction =
+ (_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
+ (*stop)(1, lastAction, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2), stop_parameter);
+
+ // Clean up phase did not resume at the frame that the search phase said it
+ // would.
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+/// Called by \c __cxa_throw(). Only returns if there is a fatal error.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_RaiseException(_Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
+ (void *)exception_object);
+
+ // Mark that this is a non-forced unwind, so _Unwind_Resume()
+ // can do the right thing.
+ memset(exception_object->private_, 0, sizeof(exception_object->private_));
+
+ // phase 1: the search phase
+ // We'll let the system do that for us.
+ RaiseException(STATUS_GCC_THROW, 0, 1, (ULONG_PTR *)&exception_object);
+
+ // If we get here, either something went horribly wrong or we reached the
+ // top of the stack. Either way, let libc++abi call std::terminate().
+ return _URC_END_OF_STACK;
+}
+
+/// When \c _Unwind_RaiseException() is in phase2, it hands control
+/// to the personality function at each frame. The personality
+/// may force a jump to a landing pad in that function; the landing
+/// pad code may then call \c _Unwind_Resume() to continue with the
+/// unwinding. Note: the call to \c _Unwind_Resume() is from compiler
+/// geneated user code. All other \c _Unwind_* routines are called
+/// by the C++ runtime \c __cxa_* routines.
+///
+/// Note: re-throwing an exception (as opposed to continuing the unwind)
+/// is implemented by having the code call \c __cxa_rethrow() which
+/// in turn calls \c _Unwind_Resume_or_Rethrow().
+_LIBUNWIND_EXPORT void
+_Unwind_Resume(_Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
+
+ if (exception_object->private_[0] != 0) {
+ unw_context_t uc;
+
+ unw_getcontext(&uc);
+ unwind_phase2_forced(&uc, exception_object,
+ (_Unwind_Stop_Fn) exception_object->private_[0],
+ (void *)exception_object->private_[4]);
+ } else {
+ // Recover the parameters for the unwind from the exception object
+ // so we can start unwinding again.
+ EXCEPTION_RECORD ms_exc;
+ CONTEXT ms_ctx;
+ UNWIND_HISTORY_TABLE hist;
+
+ memset(&ms_exc, 0, sizeof(ms_exc));
+ memset(&hist, 0, sizeof(hist));
+ ms_exc.ExceptionCode = STATUS_GCC_THROW;
+ ms_exc.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
+ ms_exc.NumberParameters = 4;
+ ms_exc.ExceptionInformation[0] = (ULONG_PTR)exception_object;
+ ms_exc.ExceptionInformation[1] = exception_object->private_[1];
+ ms_exc.ExceptionInformation[2] = exception_object->private_[2];
+ ms_exc.ExceptionInformation[3] = exception_object->private_[3];
+ RtlUnwindEx((PVOID)exception_object->private_[1],
+ (PVOID)exception_object->private_[2], &ms_exc,
+ exception_object, &ms_ctx, &hist);
+ }
+
+ // Clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ _LIBUNWIND_ABORT("_Unwind_Resume() can't return");
+}
+
+/// Not used by C++.
+/// Unwinds stack, calling "stop" function at each frame.
+/// Could be used to implement \c longjmp().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter) {
+ _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
+ (void *)exception_object, (void *)(uintptr_t)stop);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // Mark that this is a forced unwind, so _Unwind_Resume() can do
+ // the right thing.
+ exception_object->private_[0] = (uintptr_t) stop;
+ exception_object->private_[4] = (uintptr_t) stop_parameter;
+
+ // do it
+ return unwind_phase2_forced(&uc, exception_object, stop, stop_parameter);
+}
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+ uintptr_t result = (uintptr_t)_unw_seh_get_disp_ctx((unw_cursor_t *)context)->HandlerData;
+ _LIBUNWIND_TRACE_API(
+ "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
+ (void *)context, result);
+ return result;
+}
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+ DISPATCHER_CONTEXT *disp = _unw_seh_get_disp_ctx((unw_cursor_t *)context);
+ uintptr_t result = (uintptr_t)disp->FunctionEntry->BeginAddress + disp->ImageBase;
+ _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
+ (void *)context, result);
+ return result;
+}
+
+static int
+_unw_init_seh(unw_cursor_t *cursor, CONTEXT *context) {
+#ifdef _LIBUNWIND_TARGET_X86_64
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>(
+ context, LocalAddressSpace::sThisAddressSpace);
+ auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
+ co->setInfoBasedOnIPRegister();
+ return UNW_ESUCCESS;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm>(
+ context, LocalAddressSpace::sThisAddressSpace);
+ auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
+ co->setInfoBasedOnIPRegister();
+ return UNW_ESUCCESS;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>(
+ context, LocalAddressSpace::sThisAddressSpace);
+ auto *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
+ co->setInfoBasedOnIPRegister();
+ return UNW_ESUCCESS;
+#else
+ return UNW_EINVAL;
+#endif
+}
+
+static DISPATCHER_CONTEXT *
+_unw_seh_get_disp_ctx(unw_cursor_t *cursor) {
+#ifdef _LIBUNWIND_TARGET_X86_64
+ return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->getDispatcherContext();
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->getDispatcherContext();
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ return reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->getDispatcherContext();
+#else
+ return nullptr;
+#endif
+}
+
+static void
+_unw_seh_set_disp_ctx(unw_cursor_t *cursor, DISPATCHER_CONTEXT *disp) {
+#ifdef _LIBUNWIND_TARGET_X86_64
+ reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_x86_64> *>(cursor)->setDispatcherContext(disp);
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm> *>(cursor)->setDispatcherContext(disp);
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ reinterpret_cast<UnwindCursor<LocalAddressSpace, Registers_arm64> *>(cursor)->setDispatcherContext(disp);
+#endif
+}
+
+#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
diff --git a/src/Unwind-sjlj.c b/src/Unwind-sjlj.c
index f9256b5a9260..90cac3f8c763 100644
--- a/src/Unwind-sjlj.c
+++ b/src/Unwind-sjlj.c
@@ -17,32 +17,26 @@
#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 _LIBUNWIND_BUILD_SJLJ_APIS
+#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
struct _Unwind_FunctionContext {
// next function in stack of handlers
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
@@ -72,7 +108,7 @@ _Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
static _Unwind_Reason_Code
unwind_phase1(struct _Unwind_Exception *exception_object) {
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
- _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p\n", c);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: initial function-context=%p", c);
// walk each frame looking for a place to stop
for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
@@ -80,17 +116,17 @@ unwind_phase1(struct _Unwind_Exception *exception_object) {
// check for no more frames
if (c == NULL) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
- "bottom => _URC_END_OF_STACK\n",
+ "bottom => _URC_END_OF_STACK",
exception_object);
return _URC_END_OF_STACK;
}
- _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p\n", c);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p", c);
// if there is a personality routine, ask it if it will want to stop at this
// frame
if (c->personality != NULL) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): calling "
- "personality function %p\n",
+ "personality function %p",
exception_object, c->personality);
_Unwind_Reason_Code personalityResult = (*c->personality)(
1, _UA_SEARCH_PHASE, exception_object->exception_class,
@@ -102,19 +138,19 @@ unwind_phase1(struct _Unwind_Exception *exception_object) {
handlerNotFound = false;
exception_object->private_2 = (uintptr_t) c;
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
- "_URC_HANDLER_FOUND\n", exception_object);
+ "_URC_HANDLER_FOUND", exception_object);
return _URC_NO_REASON;
case _URC_CONTINUE_UNWIND:
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
- "_URC_CONTINUE_UNWIND\n", exception_object);
+ "_URC_CONTINUE_UNWIND", exception_object);
// continue unwinding
break;
default:
// something went wrong
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
@@ -126,18 +162,18 @@ unwind_phase1(struct _Unwind_Exception *exception_object) {
static _Unwind_Reason_Code
unwind_phase2(struct _Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", exception_object);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)", exception_object);
// walk each frame until we reach where search phase said to stop
_Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
while (true) {
- _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p\n",
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2s(ex_ojb=%p): context=%p",
exception_object, c);
// check for no more frames
if (c == NULL) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
- "bottom => _URC_END_OF_STACK\n",
+ "bottom => _URC_END_OF_STACK",
exception_object);
return _URC_END_OF_STACK;
}
@@ -157,7 +193,7 @@ unwind_phase2(struct _Unwind_Exception *exception_object) {
case _URC_CONTINUE_UNWIND:
// continue unwinding
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
exception_object);
if ((uintptr_t) c == exception_object->private_2) {
// phase 1 said we would stop at this frame, but we did not...
@@ -168,7 +204,7 @@ unwind_phase2(struct _Unwind_Exception *exception_object) {
case _URC_INSTALL_CONTEXT:
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
"_URC_INSTALL_CONTEXT, will resume at "
- "landing pad %p\n",
+ "landing pad %p",
exception_object, c->jbuf[1]);
// personality routine says to transfer control to landing pad
// we may get control back if landing pad calls _Unwind_Resume()
@@ -202,7 +238,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object,
// get next frame (skip over first which is _Unwind_RaiseException)
if (c == NULL) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
- "bottom => _URC_END_OF_STACK\n",
+ "bottom => _URC_END_OF_STACK",
exception_object);
return _URC_END_OF_STACK;
}
@@ -214,11 +250,11 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object,
(*stop)(1, action, exception_object->exception_class, exception_object,
(struct _Unwind_Context *)c, stop_parameter);
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
- "stop function returned %d\n",
+ "stop function returned %d",
exception_object, stopResult);
if (stopResult != _URC_NO_REASON) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
- "stopped by stop function\n",
+ "stopped by stop function",
exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
@@ -227,7 +263,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object,
if (c->personality != NULL) {
__personality_routine p = (__personality_routine) c->personality;
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
- "calling personality function %p\n",
+ "calling personality function %p",
exception_object, p);
_Unwind_Reason_Code personalityResult =
(*p)(1, action, exception_object->exception_class, exception_object,
@@ -235,13 +271,13 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object,
switch (personalityResult) {
case _URC_CONTINUE_UNWIND:
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
- "personality returned _URC_CONTINUE_UNWIND\n",
+ "personality returned _URC_CONTINUE_UNWIND",
exception_object);
// destructors called, continue unwinding
break;
case _URC_INSTALL_CONTEXT:
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
- "personality returned _URC_INSTALL_CONTEXT\n",
+ "personality returned _URC_INSTALL_CONTEXT",
exception_object);
// we may get control back if landing pad calls _Unwind_Resume()
__Unwind_SjLj_SetTopOfFunctionStack(c);
@@ -251,7 +287,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object,
// something went wrong
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
"personality returned %d, "
- "_URC_FATAL_PHASE2_ERROR\n",
+ "_URC_FATAL_PHASE2_ERROR",
exception_object, personalityResult);
return _URC_FATAL_PHASE2_ERROR;
}
@@ -262,7 +298,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object,
// call stop function one last time and tell it we've reached the end of the
// stack
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
- "function with _UA_END_OF_STACK\n",
+ "function with _UA_END_OF_STACK",
exception_object);
_Unwind_Action lastAction =
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
@@ -278,7 +314,7 @@ unwind_phase2_forced(struct _Unwind_Exception *exception_object,
/// Called by __cxa_throw. Only returns if there is a fatal error
_LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)\n", exception_object);
+ _LIBUNWIND_TRACE_API("_Unwind_SjLj_RaiseException(ex_obj=%p)", exception_object);
// mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
// thing
@@ -308,7 +344,7 @@ _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
/// __cxa_rethrow() which in turn calls _Unwind_Resume_or_Rethrow()
_LIBUNWIND_EXPORT void
_Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)\n", exception_object);
+ _LIBUNWIND_TRACE_API("_Unwind_SjLj_Resume(ex_obj=%p)", exception_object);
if (exception_object->private_1 != 0)
unwind_phase2_forced(exception_object,
@@ -326,7 +362,7 @@ _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object) {
_LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
_LIBUNWIND_TRACE_API("__Unwind_SjLj_Resume_or_Rethrow(ex_obj=%p), "
- "private_1=%ld\n",
+ "private_1=%ld",
exception_object, exception_object->private_1);
// If this is non-forced and a stopping place was found, then this is a
// re-throw.
@@ -350,7 +386,7 @@ _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
_LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) "
- "=> 0x%0lX\n", context, ufc->lsda);
+ "=> 0x%0lX", context, ufc->lsda);
return ufc->lsda;
}
@@ -358,7 +394,7 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
/// Called by personality handler during phase 2 to get register values.
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
int index) {
- _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d)",
context, index);
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
return ufc->resumeParameters[index];
@@ -368,7 +404,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetGR(struct _Unwind_Context *context,
/// Called by personality handler during phase 2 to alter register values.
_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
uintptr_t new_value) {
- _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)\n"
+ _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0lX)"
, context, index, new_value);
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
ufc->resumeParameters[index] = new_value;
@@ -378,7 +414,7 @@ _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
/// Called by personality handler during phase 2 to get instruction pointer.
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
- _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%lX\n", context,
+ _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%lX", context,
ufc->resumeLocation + 1);
return ufc->resumeLocation + 1;
}
@@ -391,7 +427,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
int *ipBefore) {
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
*ipBefore = 0;
- _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX\n",
+ _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p, %p) => 0x%lX",
context, ipBefore, ufc->resumeLocation + 1);
return ufc->resumeLocation + 1;
}
@@ -400,7 +436,7 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
/// Called by personality handler during phase 2 to alter instruction pointer.
_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
uintptr_t new_value) {
- _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0lX)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0lX)",
context, new_value);
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
ufc->resumeLocation = new_value - 1;
@@ -413,7 +449,7 @@ _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetRegionStart(struct _Unwind_Context *context) {
// Not supported or needed for sjlj based unwinding
(void)context;
- _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)\n", context);
+ _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p)", context);
return 0;
}
@@ -422,7 +458,7 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) {
/// is caught.
_LIBUNWIND_EXPORT void
_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
exception_object);
if (exception_object->exception_cleanup != NULL)
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
@@ -437,7 +473,7 @@ _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
// Not supported or needed for sjlj based unwinding
(void)context;
- _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", context);
+ _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", context);
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
}
@@ -448,14 +484,14 @@ _LIBUNWIND_EXPORT uintptr_t
_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
// Not supported or needed for sjlj based unwinding
(void)context;
- _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", context);
+ _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", context);
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
}
/// Called by personality handler to get "Call Frame Area" for current frame.
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
- _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)\n", context);
+ _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p)", context);
if (context != NULL) {
_Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
// Setjmp/longjmp based exceptions don't have a true CFA.
@@ -465,4 +501,4 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
return 0;
}
-#endif // _LIBUNWIND_BUILD_SJLJ_APIS
+#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
diff --git a/src/UnwindCursor.hpp b/src/UnwindCursor.hpp
index 18a780919b11..52439f9b5453 100644
--- a/src/UnwindCursor.hpp
+++ b/src/UnwindCursor.hpp
@@ -6,7 +6,7 @@
// Source Licenses. See LICENSE.TXT for details.
//
//
-// C++ interface to lower levels of libuwind
+// C++ interface to lower levels of libunwind
//===----------------------------------------------------------------------===//
#ifndef __UNWINDCURSOR_HPP__
@@ -16,13 +16,53 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
-#include <pthread.h>
#include <unwind.h>
+#ifdef _WIN32
+ #include <windows.h>
+ #include <ntverp.h>
+#endif
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+// Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and
+// earlier) SDKs.
+// MinGW-w64 has always provided this struct.
+ #if defined(_WIN32) && defined(_LIBUNWIND_TARGET_X86_64) && \
+ !defined(__MINGW32__) && VER_PRODUCTBUILD < 8000
+struct _DISPATCHER_CONTEXT {
+ ULONG64 ControlPc;
+ ULONG64 ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG64 EstablisherFrame;
+ ULONG64 TargetIp;
+ PCONTEXT ContextRecord;
+ PEXCEPTION_ROUTINE LanguageHandler;
+ PVOID HandlerData;
+ PUNWIND_HISTORY_TABLE HistoryTable;
+ ULONG ScopeIndex;
+ ULONG Fill0;
+};
+ #endif
+
+struct UNWIND_INFO {
+ uint8_t Version : 3;
+ uint8_t Flags : 5;
+ uint8_t SizeOfProlog;
+ uint8_t CountOfCodes;
+ uint8_t FrameRegister : 4;
+ uint8_t FrameOffset : 4;
+ uint16_t UnwindCodes[2];
+};
+
+extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
+ int, _Unwind_Action, uint64_t, _Unwind_Exception *,
+ struct _Unwind_Context *);
+
+#endif
+
#include "config.h"
#include "AddressSpace.hpp"
@@ -32,11 +72,12 @@
#include "EHHeaderParser.hpp"
#include "libunwind.h"
#include "Registers.hpp"
+#include "RWMutex.hpp"
#include "Unwind-EHABI.h"
namespace libunwind {
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
/// Cache of recently found FDEs.
template <typename A>
class _LIBUNWIND_HIDDEN DwarfFDECache {
@@ -60,7 +101,7 @@ private:
// These fields are all static to avoid needing an initializer.
// There is only one instance of this class per process.
- static pthread_rwlock_t _lock;
+ static RWMutex _lock;
#ifdef __APPLE__
static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide);
static bool _registeredForDyldUnloads;
@@ -88,7 +129,7 @@ template <typename A>
typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64];
template <typename A>
-pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER;
+RWMutex DwarfFDECache<A>::_lock;
#ifdef __APPLE__
template <typename A>
@@ -98,7 +139,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)) {
@@ -107,7 +148,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;
}
@@ -115,7 +156,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;
@@ -139,13 +180,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) {
@@ -155,7 +196,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__
@@ -168,18 +209,18 @@ 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 // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
-#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
template <typename A> class UnwindSectionHeader {
public:
UnwindSectionHeader(A &addressSpace, typename A::pint_t addr)
@@ -367,7 +408,7 @@ private:
A &_addressSpace;
typename A::pint_t _addr;
};
-#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
public:
@@ -412,6 +453,419 @@ public:
#endif
};
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
+
+/// \c UnwindCursor contains all state (including all register values) during
+/// an unwind. This is normally stack-allocated inside a unw_cursor_t.
+template <typename A, typename R>
+class UnwindCursor : public AbstractUnwindCursor {
+ typedef typename A::pint_t pint_t;
+public:
+ UnwindCursor(unw_context_t *context, A &as);
+ UnwindCursor(CONTEXT *context, A &as);
+ UnwindCursor(A &as, void *threadArg);
+ virtual ~UnwindCursor() {}
+ virtual bool validReg(int);
+ virtual unw_word_t getReg(int);
+ virtual void setReg(int, unw_word_t);
+ virtual bool validFloatReg(int);
+ virtual unw_fpreg_t getFloatReg(int);
+ virtual void setFloatReg(int, unw_fpreg_t);
+ virtual int step();
+ virtual void getInfo(unw_proc_info_t *);
+ virtual void jumpto();
+ virtual bool isSignalFrame();
+ virtual bool getFunctionName(char *buf, size_t len, unw_word_t *off);
+ virtual void setInfoBasedOnIPRegister(bool isReturnAddress = false);
+ virtual const char *getRegisterName(int num);
+#ifdef __arm__
+ virtual void saveVFPAsX();
+#endif
+
+ DISPATCHER_CONTEXT *getDispatcherContext() { return &_dispContext; }
+ void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; }
+
+private:
+
+ pint_t getLastPC() const { return _dispContext.ControlPc; }
+ void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; }
+ RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) {
+ _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc,
+ &_dispContext.ImageBase,
+ _dispContext.HistoryTable);
+ *base = _dispContext.ImageBase;
+ return _dispContext.FunctionEntry;
+ }
+ bool getInfoFromSEH(pint_t pc);
+ int stepWithSEHData() {
+ _dispContext.LanguageHandler = RtlVirtualUnwind(UNW_FLAG_UHANDLER,
+ _dispContext.ImageBase,
+ _dispContext.ControlPc,
+ _dispContext.FunctionEntry,
+ _dispContext.ContextRecord,
+ &_dispContext.HandlerData,
+ &_dispContext.EstablisherFrame,
+ NULL);
+ // Update some fields of the unwind info now, since we have them.
+ _info.lsda = reinterpret_cast<unw_word_t>(_dispContext.HandlerData);
+ if (_dispContext.LanguageHandler) {
+ _info.handler = reinterpret_cast<unw_word_t>(__libunwind_seh_personality);
+ } else
+ _info.handler = 0;
+ return UNW_STEP_SUCCESS;
+ }
+
+ A &_addressSpace;
+ unw_proc_info_t _info;
+ DISPATCHER_CONTEXT _dispContext;
+ CONTEXT _msContext;
+ UNWIND_HISTORY_TABLE _histTable;
+ bool _unwindInfoMissing;
+};
+
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
+ : _addressSpace(as), _unwindInfoMissing(false) {
+ static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
+ "UnwindCursor<> does not fit in unw_cursor_t");
+ memset(&_info, 0, sizeof(_info));
+ memset(&_histTable, 0, sizeof(_histTable));
+ _dispContext.ContextRecord = &_msContext;
+ _dispContext.HistoryTable = &_histTable;
+ // Initialize MS context from ours.
+ R r(context);
+ _msContext.ContextFlags = CONTEXT_CONTROL|CONTEXT_INTEGER|CONTEXT_FLOATING_POINT;
+#if defined(_LIBUNWIND_TARGET_X86_64)
+ _msContext.Rax = r.getRegister(UNW_X86_64_RAX);
+ _msContext.Rcx = r.getRegister(UNW_X86_64_RCX);
+ _msContext.Rdx = r.getRegister(UNW_X86_64_RDX);
+ _msContext.Rbx = r.getRegister(UNW_X86_64_RBX);
+ _msContext.Rsp = r.getRegister(UNW_X86_64_RSP);
+ _msContext.Rbp = r.getRegister(UNW_X86_64_RBP);
+ _msContext.Rsi = r.getRegister(UNW_X86_64_RSI);
+ _msContext.Rdi = r.getRegister(UNW_X86_64_RDI);
+ _msContext.R8 = r.getRegister(UNW_X86_64_R8);
+ _msContext.R9 = r.getRegister(UNW_X86_64_R9);
+ _msContext.R10 = r.getRegister(UNW_X86_64_R10);
+ _msContext.R11 = r.getRegister(UNW_X86_64_R11);
+ _msContext.R12 = r.getRegister(UNW_X86_64_R12);
+ _msContext.R13 = r.getRegister(UNW_X86_64_R13);
+ _msContext.R14 = r.getRegister(UNW_X86_64_R14);
+ _msContext.R15 = r.getRegister(UNW_X86_64_R15);
+ _msContext.Rip = r.getRegister(UNW_REG_IP);
+ union {
+ v128 v;
+ M128A m;
+ } t;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM0);
+ _msContext.Xmm0 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM1);
+ _msContext.Xmm1 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM2);
+ _msContext.Xmm2 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM3);
+ _msContext.Xmm3 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM4);
+ _msContext.Xmm4 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM5);
+ _msContext.Xmm5 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM6);
+ _msContext.Xmm6 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM7);
+ _msContext.Xmm7 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM8);
+ _msContext.Xmm8 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM9);
+ _msContext.Xmm9 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM10);
+ _msContext.Xmm10 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM11);
+ _msContext.Xmm11 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM12);
+ _msContext.Xmm12 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM13);
+ _msContext.Xmm13 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM14);
+ _msContext.Xmm14 = t.m;
+ t.v = r.getVectorRegister(UNW_X86_64_XMM15);
+ _msContext.Xmm15 = t.m;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ _msContext.R0 = r.getRegister(UNW_ARM_R0);
+ _msContext.R1 = r.getRegister(UNW_ARM_R1);
+ _msContext.R2 = r.getRegister(UNW_ARM_R2);
+ _msContext.R3 = r.getRegister(UNW_ARM_R3);
+ _msContext.R4 = r.getRegister(UNW_ARM_R4);
+ _msContext.R5 = r.getRegister(UNW_ARM_R5);
+ _msContext.R6 = r.getRegister(UNW_ARM_R6);
+ _msContext.R7 = r.getRegister(UNW_ARM_R7);
+ _msContext.R8 = r.getRegister(UNW_ARM_R8);
+ _msContext.R9 = r.getRegister(UNW_ARM_R9);
+ _msContext.R10 = r.getRegister(UNW_ARM_R10);
+ _msContext.R11 = r.getRegister(UNW_ARM_R11);
+ _msContext.R12 = r.getRegister(UNW_ARM_R12);
+ _msContext.Sp = r.getRegister(UNW_ARM_SP);
+ _msContext.Lr = r.getRegister(UNW_ARM_LR);
+ _msContext.Pc = r.getRegister(UNW_ARM_IP);
+ for (int i = UNW_ARM_D0; i <= UNW_ARM_D31; ++i) {
+ union {
+ uint64_t w;
+ double d;
+ } d;
+ d.d = r.getFloatRegister(i);
+ _msContext.D[i - UNW_ARM_D0] = d.w;
+ }
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ for (int i = UNW_ARM64_X0; i <= UNW_ARM64_X30; ++i)
+ _msContext.X[i - UNW_ARM64_X0] = r.getRegister(i);
+ _msContext.Sp = r.getRegister(UNW_REG_SP);
+ _msContext.Pc = r.getRegister(UNW_REG_IP);
+ for (int i = UNW_ARM64_D0; i <= UNW_ARM64_D31; ++i)
+ _msContext.V[i - UNW_ARM64_D0].D[0] = r.getFloatRegister(i);
+#endif
+}
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(CONTEXT *context, A &as)
+ : _addressSpace(as), _unwindInfoMissing(false) {
+ static_assert((check_fit<UnwindCursor<A, R>, unw_cursor_t>::does_fit),
+ "UnwindCursor<> does not fit in unw_cursor_t");
+ memset(&_info, 0, sizeof(_info));
+ memset(&_histTable, 0, sizeof(_histTable));
+ _dispContext.ContextRecord = &_msContext;
+ _dispContext.HistoryTable = &_histTable;
+ _msContext = *context;
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validReg(int regNum) {
+ if (regNum == UNW_REG_IP || regNum == UNW_REG_SP) return true;
+#if defined(_LIBUNWIND_TARGET_X86_64)
+ if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ if (regNum >= UNW_ARM64_X0 && regNum <= UNW_ARM64_X30) return true;
+#endif
+ return false;
+}
+
+template <typename A, typename R>
+unw_word_t UnwindCursor<A, R>::getReg(int regNum) {
+ switch (regNum) {
+#if defined(_LIBUNWIND_TARGET_X86_64)
+ case UNW_REG_IP: return _msContext.Rip;
+ case UNW_X86_64_RAX: return _msContext.Rax;
+ case UNW_X86_64_RDX: return _msContext.Rdx;
+ case UNW_X86_64_RCX: return _msContext.Rcx;
+ case UNW_X86_64_RBX: return _msContext.Rbx;
+ case UNW_REG_SP:
+ case UNW_X86_64_RSP: return _msContext.Rsp;
+ case UNW_X86_64_RBP: return _msContext.Rbp;
+ case UNW_X86_64_RSI: return _msContext.Rsi;
+ case UNW_X86_64_RDI: return _msContext.Rdi;
+ case UNW_X86_64_R8: return _msContext.R8;
+ case UNW_X86_64_R9: return _msContext.R9;
+ case UNW_X86_64_R10: return _msContext.R10;
+ case UNW_X86_64_R11: return _msContext.R11;
+ case UNW_X86_64_R12: return _msContext.R12;
+ case UNW_X86_64_R13: return _msContext.R13;
+ case UNW_X86_64_R14: return _msContext.R14;
+ case UNW_X86_64_R15: return _msContext.R15;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ case UNW_ARM_R0: return _msContext.R0;
+ case UNW_ARM_R1: return _msContext.R1;
+ case UNW_ARM_R2: return _msContext.R2;
+ case UNW_ARM_R3: return _msContext.R3;
+ case UNW_ARM_R4: return _msContext.R4;
+ case UNW_ARM_R5: return _msContext.R5;
+ case UNW_ARM_R6: return _msContext.R6;
+ case UNW_ARM_R7: return _msContext.R7;
+ case UNW_ARM_R8: return _msContext.R8;
+ case UNW_ARM_R9: return _msContext.R9;
+ case UNW_ARM_R10: return _msContext.R10;
+ case UNW_ARM_R11: return _msContext.R11;
+ case UNW_ARM_R12: return _msContext.R12;
+ case UNW_REG_SP:
+ case UNW_ARM_SP: return _msContext.Sp;
+ case UNW_ARM_LR: return _msContext.Lr;
+ case UNW_REG_IP:
+ case UNW_ARM_IP: return _msContext.Pc;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ case UNW_REG_SP: return _msContext.Sp;
+ case UNW_REG_IP: return _msContext.Pc;
+ default: return _msContext.X[regNum - UNW_ARM64_X0];
+#endif
+ }
+ _LIBUNWIND_ABORT("unsupported register");
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) {
+ switch (regNum) {
+#if defined(_LIBUNWIND_TARGET_X86_64)
+ case UNW_REG_IP: _msContext.Rip = value; break;
+ case UNW_X86_64_RAX: _msContext.Rax = value; break;
+ case UNW_X86_64_RDX: _msContext.Rdx = value; break;
+ case UNW_X86_64_RCX: _msContext.Rcx = value; break;
+ case UNW_X86_64_RBX: _msContext.Rbx = value; break;
+ case UNW_REG_SP:
+ case UNW_X86_64_RSP: _msContext.Rsp = value; break;
+ case UNW_X86_64_RBP: _msContext.Rbp = value; break;
+ case UNW_X86_64_RSI: _msContext.Rsi = value; break;
+ case UNW_X86_64_RDI: _msContext.Rdi = value; break;
+ case UNW_X86_64_R8: _msContext.R8 = value; break;
+ case UNW_X86_64_R9: _msContext.R9 = value; break;
+ case UNW_X86_64_R10: _msContext.R10 = value; break;
+ case UNW_X86_64_R11: _msContext.R11 = value; break;
+ case UNW_X86_64_R12: _msContext.R12 = value; break;
+ case UNW_X86_64_R13: _msContext.R13 = value; break;
+ case UNW_X86_64_R14: _msContext.R14 = value; break;
+ case UNW_X86_64_R15: _msContext.R15 = value; break;
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ case UNW_ARM_R0: _msContext.R0 = value; break;
+ case UNW_ARM_R1: _msContext.R1 = value; break;
+ case UNW_ARM_R2: _msContext.R2 = value; break;
+ case UNW_ARM_R3: _msContext.R3 = value; break;
+ case UNW_ARM_R4: _msContext.R4 = value; break;
+ case UNW_ARM_R5: _msContext.R5 = value; break;
+ case UNW_ARM_R6: _msContext.R6 = value; break;
+ case UNW_ARM_R7: _msContext.R7 = value; break;
+ case UNW_ARM_R8: _msContext.R8 = value; break;
+ case UNW_ARM_R9: _msContext.R9 = value; break;
+ case UNW_ARM_R10: _msContext.R10 = value; break;
+ case UNW_ARM_R11: _msContext.R11 = value; break;
+ case UNW_ARM_R12: _msContext.R12 = value; break;
+ case UNW_REG_SP:
+ case UNW_ARM_SP: _msContext.Sp = value; break;
+ case UNW_ARM_LR: _msContext.Lr = value; break;
+ case UNW_REG_IP:
+ case UNW_ARM_IP: _msContext.Pc = value; break;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ case UNW_REG_SP: _msContext.Sp = value; break;
+ case UNW_REG_IP: _msContext.Pc = value; break;
+ case UNW_ARM64_X0:
+ case UNW_ARM64_X1:
+ case UNW_ARM64_X2:
+ case UNW_ARM64_X3:
+ case UNW_ARM64_X4:
+ case UNW_ARM64_X5:
+ case UNW_ARM64_X6:
+ case UNW_ARM64_X7:
+ case UNW_ARM64_X8:
+ case UNW_ARM64_X9:
+ case UNW_ARM64_X10:
+ case UNW_ARM64_X11:
+ case UNW_ARM64_X12:
+ case UNW_ARM64_X13:
+ case UNW_ARM64_X14:
+ case UNW_ARM64_X15:
+ case UNW_ARM64_X16:
+ case UNW_ARM64_X17:
+ case UNW_ARM64_X18:
+ case UNW_ARM64_X19:
+ case UNW_ARM64_X20:
+ case UNW_ARM64_X21:
+ case UNW_ARM64_X22:
+ case UNW_ARM64_X23:
+ case UNW_ARM64_X24:
+ case UNW_ARM64_X25:
+ case UNW_ARM64_X26:
+ case UNW_ARM64_X27:
+ case UNW_ARM64_X28:
+ case UNW_ARM64_FP:
+ case UNW_ARM64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break;
+#endif
+ default:
+ _LIBUNWIND_ABORT("unsupported register");
+ }
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validFloatReg(int regNum) {
+#if defined(_LIBUNWIND_TARGET_ARM)
+ if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true;
+ if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true;
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ if (regNum >= UNW_ARM64_D0 && regNum <= UNW_ARM64_D31) return true;
+#endif
+ return false;
+}
+
+template <typename A, typename R>
+unw_fpreg_t UnwindCursor<A, R>::getFloatReg(int regNum) {
+#if defined(_LIBUNWIND_TARGET_ARM)
+ if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) {
+ union {
+ uint32_t w;
+ float f;
+ } d;
+ d.w = _msContext.S[regNum - UNW_ARM_S0];
+ return d.f;
+ }
+ if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
+ union {
+ uint64_t w;
+ double d;
+ } d;
+ d.w = _msContext.D[regNum - UNW_ARM_D0];
+ return d.d;
+ }
+ _LIBUNWIND_ABORT("unsupported float register");
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ return _msContext.V[regNum - UNW_ARM64_D0].D[0];
+#else
+ _LIBUNWIND_ABORT("float registers unimplemented");
+#endif
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
+#if defined(_LIBUNWIND_TARGET_ARM)
+ if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) {
+ union {
+ uint32_t w;
+ float f;
+ } d;
+ d.f = value;
+ _msContext.S[regNum - UNW_ARM_S0] = d.w;
+ }
+ if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
+ union {
+ uint64_t w;
+ double d;
+ } d;
+ d.d = value;
+ _msContext.D[regNum - UNW_ARM_D0] = d.w;
+ }
+ _LIBUNWIND_ABORT("unsupported float register");
+#elif defined(_LIBUNWIND_TARGET_AARCH64)
+ _msContext.V[regNum - UNW_ARM64_D0].D[0] = value;
+#else
+ _LIBUNWIND_ABORT("float registers unimplemented");
+#endif
+}
+
+template <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
+ RtlRestoreContext(&_msContext, nullptr);
+}
+
+#ifdef __arm__
+template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {}
+#endif
+
+template <typename A, typename R>
+const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
+ return R::getRegisterName(regNum);
+}
+
+template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
+ return false;
+}
+
+#else // !defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) || !defined(_WIN32)
+
/// UnwindCursor contains all state (including all register values) during
/// an unwind. This is normally stack allocated inside a unw_cursor_t.
template <typename A, typename R>
@@ -440,7 +894,7 @@ public:
private:
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections &sects);
int stepWithEHABI() {
@@ -458,7 +912,7 @@ private:
}
#endif
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
uint32_t fdeSectionOffsetHint=0);
int stepWithDwarfFDE() {
@@ -469,11 +923,11 @@ private:
}
#endif
-#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
bool getInfoFromCompactEncodingSection(pint_t pc,
const UnwindInfoSections &sects);
int stepWithCompactEncoding() {
- #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
if ( compactSaysUseDwarf() )
return stepWithDwarfFDE();
#endif
@@ -501,6 +955,13 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_PPC64)
+ int stepWithCompactEncoding(Registers_ppc64 &) {
+ return UNW_EINVAL;
+ }
+#endif
+
+
#if defined(_LIBUNWIND_TARGET_AARCH64)
int stepWithCompactEncoding(Registers_arm64 &) {
return CompactUnwinder_arm64<A>::stepWithCompactEncoding(
@@ -508,6 +969,22 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+ int stepWithCompactEncoding(Registers_mips_o32 &) {
+ return UNW_EINVAL;
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI)
+ int stepWithCompactEncoding(Registers_mips_newabi &) {
+ return UNW_EINVAL;
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
+#endif
+
bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
R dummy;
return compactSaysUseDwarf(dummy, offset);
@@ -541,6 +1018,12 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_PPC64)
+ bool compactSaysUseDwarf(Registers_ppc64 &, uint32_t *) const {
+ return true;
+ }
+#endif
+
#if defined(_LIBUNWIND_TARGET_AARCH64)
bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const {
if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) {
@@ -551,9 +1034,26 @@ private:
return false;
}
#endif
-#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_TARGET_MIPS_O32)
+ bool compactSaysUseDwarf(Registers_mips_o32 &, uint32_t *) const {
+ return true;
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_MIPS_NEWABI)
+ bool compactSaysUseDwarf(Registers_mips_newabi &, uint32_t *) const {
+ return true;
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
+#endif
+
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
compact_unwind_encoding_t dwarfEncoding() const {
R dummy;
return dwarfEncoding(dummy);
@@ -577,18 +1077,61 @@ private:
}
#endif
+#if defined(_LIBUNWIND_TARGET_PPC64)
+ compact_unwind_encoding_t dwarfEncoding(Registers_ppc64 &) const {
+ return 0;
+ }
+#endif
+
#if defined(_LIBUNWIND_TARGET_AARCH64)
compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const {
return UNWIND_ARM64_MODE_DWARF;
}
#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
-#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+#if defined (_LIBUNWIND_TARGET_MIPS_O32)
+ compact_unwind_encoding_t dwarfEncoding(Registers_mips_o32 &) const {
+ return 0;
+ }
+#endif
+
+#if defined (_LIBUNWIND_TARGET_MIPS_NEWABI)
+ compact_unwind_encoding_t dwarfEncoding(Registers_mips_newabi &) const {
+ return 0;
+ }
+#endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+ compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
+#endif
+
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+ // For runtime environments using SEH unwind data without Windows runtime
+ // support.
+ pint_t getLastPC() const { /* FIXME: Implement */ return 0; }
+ void setLastPC(pint_t pc) { /* FIXME: Implement */ }
+ RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) {
+ /* FIXME: Implement */
+ *base = 0;
+ return nullptr;
+ }
+ bool getInfoFromSEH(pint_t pc);
+ int stepWithSEHData() { /* FIXME: Implement */ return 0; }
+#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
A &_addressSpace;
@@ -666,7 +1209,9 @@ template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
return _isSignalFrame;
}
-#if _LIBUNWIND_ARM_EHABI
+#endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+
+#if defined(_LIBUNWIND_ARM_EHABI)
struct EHABIIndexEntry {
uint32_t functionOffset;
uint32_t data;
@@ -687,7 +1232,8 @@ struct EHABISectionIterator {
return _Self(addressSpace, sects, 0);
}
static _Self end(A& addressSpace, const UnwindInfoSections& sects) {
- return _Self(addressSpace, sects, sects.arm_section_length);
+ return _Self(addressSpace, sects,
+ sects.arm_section_length / sizeof(EHABIIndexEntry));
}
EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i)
@@ -737,14 +1283,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)
@@ -861,7 +1414,7 @@ bool UnwindCursor<A, R>::getInfoFromEHABISection(
}
#endif
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
const UnwindInfoSections &sects,
@@ -877,7 +1430,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
sects.dwarf_section + fdeSectionOffsetHint,
&fdeInfo, &cieInfo);
}
-#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+#if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
if (!foundFDE && (sects.dwarf_index_section != 0)) {
foundFDE = EHHeaderParser<A>::findFDE(
_addressSpace, pc, sects.dwarf_index_section,
@@ -904,7 +1457,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
if (foundFDE) {
typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
- &prolog)) {
+ R::getArch(), &prolog)) {
// Save off parsed FDE info
_info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd;
@@ -920,7 +1473,7 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
// Add to cache (to make next lookup faster) if we had no hint
// and there was no index.
if (!foundInCache && (fdeSectionOffsetHint == 0)) {
- #if _LIBUNWIND_SUPPORT_DWARF_INDEX
+ #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
if (sects.dwarf_index_section == 0)
#endif
DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd,
@@ -929,13 +1482,13 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
return true;
}
}
- //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc);
+ //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX", (uint64_t)pc);
return false;
}
-#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
template <typename A, typename R>
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
const UnwindInfoSections &sects) {
@@ -1086,13 +1639,13 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base;
if (pc < funcStart) {
_LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second "
- "level compressed unwind table. funcStart=0x%llX\n",
+ "level compressed unwind table. funcStart=0x%llX",
(uint64_t) pc, (uint64_t) funcStart);
return false;
}
if (pc > funcEnd) {
_LIBUNWIND_DEBUG_LOG("malformed __unwind_info, pc=0x%llX not in second "
- "level compressed unwind table. funcEnd=0x%llX\n",
+ "level compressed unwind table. funcEnd=0x%llX",
(uint64_t) pc, (uint64_t) funcEnd);
return false;
}
@@ -1113,7 +1666,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
}
} else {
_LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second "
- "level page\n",
+ "level page",
(uint64_t) sects.compact_unwind_section);
return false;
}
@@ -1143,7 +1696,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
}
if (lsda == 0) {
_LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with HAS_LSDA bit set for "
- "pc=0x%0llX, but lsda table has no entry\n",
+ "pc=0x%0llX, but lsda table has no entry",
encoding, (uint64_t) pc);
return false;
}
@@ -1156,7 +1709,7 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
--personalityIndex; // change 1-based to zero-based index
if (personalityIndex > sectionHeader.personalityArrayCount()) {
_LIBUNWIND_DEBUG_LOG("found encoding 0x%08X with personality index %d, "
- "but personality table has only %d entires\n",
+ "but personality table has only %d entires",
encoding, personalityIndex,
sectionHeader.personalityArrayCount());
return false;
@@ -1189,13 +1742,62 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
_info.extra = sects.dso_base;
return true;
}
-#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
+ pint_t base;
+ RUNTIME_FUNCTION *unwindEntry = lookUpSEHUnwindInfo(pc, &base);
+ if (!unwindEntry) {
+ _LIBUNWIND_DEBUG_LOG("\tpc not in table, pc=0x%llX", (uint64_t) pc);
+ return false;
+ }
+ _info.gp = 0;
+ _info.flags = 0;
+ _info.format = 0;
+ _info.unwind_info_size = sizeof(RUNTIME_FUNCTION);
+ _info.unwind_info = reinterpret_cast<unw_word_t>(unwindEntry);
+ _info.extra = base;
+ _info.start_ip = base + unwindEntry->BeginAddress;
+#ifdef _LIBUNWIND_TARGET_X86_64
+ _info.end_ip = base + unwindEntry->EndAddress;
+ // Only fill in the handler and LSDA if they're stale.
+ if (pc != getLastPC()) {
+ UNWIND_INFO *xdata = reinterpret_cast<UNWIND_INFO *>(base + unwindEntry->UnwindData);
+ if (xdata->Flags & (UNW_FLAG_EHANDLER|UNW_FLAG_UHANDLER)) {
+ // The personality is given in the UNWIND_INFO itself. The LSDA immediately
+ // follows the UNWIND_INFO. (This follows how both Clang and MSVC emit
+ // these structures.)
+ // N.B. UNWIND_INFO structs are DWORD-aligned.
+ uint32_t lastcode = (xdata->CountOfCodes + 1) & ~1;
+ const uint32_t *handler = reinterpret_cast<uint32_t *>(&xdata->UnwindCodes[lastcode]);
+ _info.lsda = reinterpret_cast<unw_word_t>(handler+1);
+ if (*handler) {
+ _info.handler = reinterpret_cast<unw_word_t>(__libunwind_seh_personality);
+ } else
+ _info.handler = 0;
+ } else {
+ _info.lsda = 0;
+ _info.handler = 0;
+ }
+ }
+#elif defined(_LIBUNWIND_TARGET_ARM)
+ _info.end_ip = _info.start_ip + unwindEntry->FunctionLength;
+ _info.lsda = 0; // FIXME
+ _info.handler = 0; // FIXME
+#endif
+ setLastPC(pc);
+ return true;
+}
+#endif
template <typename A, typename R>
void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
pint_t pc = (pint_t)this->getReg(UNW_REG_IP);
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
// Remove the thumb bit so the IP represents the actual instruction address.
// This matches the behaviour of _Unwind_GetIP on arm.
pc &= (pint_t)~0x1;
@@ -1212,11 +1814,11 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// Ask address space object to find unwind sections for this pc.
UnwindInfoSections sects;
if (_addressSpace.findUnwindSections(pc, sects)) {
-#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
// If there is a compact unwind encoding table, look there first.
if (sects.compact_unwind_section != 0) {
if (this->getInfoFromCompactEncodingSection(pc, sects)) {
- #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
// Found info in table, done unless encoding says to use dwarf.
uint32_t dwarfOffset;
if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) {
@@ -1233,9 +1835,15 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
return;
}
}
-#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+ // If there is SEH unwind info, look there next.
+ if (this->getInfoFromSEH(pc))
+ return;
+#endif
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
// If there is dwarf unwind info, look there next.
if (sects.dwarf_section != 0) {
if (this->getInfoFromDwarfSection(pc, sects)) {
@@ -1245,14 +1853,14 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
}
#endif
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
// If there is ARM EHABI unwind info, look there next.
if (sects.arm_section != 0 && this->getInfoFromEHABISection(pc, sects))
return;
#endif
}
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
// There is no static unwind info for this pc. Look to see if an FDE was
// dynamically registered for it.
pint_t cachedFDE = DwarfFDECache<A>::findFDE(0, pc);
@@ -1264,7 +1872,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
if (msg == NULL) {
typename CFI_Parser<A>::PrologInfo prolog;
if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
- pc, &prolog)) {
+ pc, R::getArch(), &prolog)) {
// save off parsed FDE info
_info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd;
@@ -1293,8 +1901,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// Double check this FDE is for a function that includes the pc.
if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
typename CFI_Parser<A>::PrologInfo prolog;
- if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo,
- cieInfo, pc, &prolog)) {
+ if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
+ pc, R::getArch(), &prolog)) {
// save off parsed FDE info
_info.start_ip = fdeInfo.pcStart;
_info.end_ip = fdeInfo.pcEnd;
@@ -1311,7 +1919,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
}
}
}
-#endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
// no unwind info, flag that we can't reliably unwind
_unwindInfoMissing = true;
@@ -1325,14 +1933,17 @@ int UnwindCursor<A, R>::step() {
// Use unwinding info to modify register set as if function returned.
int result;
-#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
result = this->stepWithCompactEncoding();
-#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+ result = this->stepWithSEHData();
+#elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
result = this->stepWithDwarfFDE();
-#elif _LIBUNWIND_ARM_EHABI
+#elif defined(_LIBUNWIND_ARM_EHABI)
result = this->stepWithEHABI();
#else
#error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \
+ _LIBUNWIND_SUPPORT_SEH_UNWIND or \
_LIBUNWIND_SUPPORT_DWARF_UNWIND or \
_LIBUNWIND_ARM_EHABI
#endif
@@ -1342,8 +1953,6 @@ int UnwindCursor<A, R>::step() {
this->setInfoBasedOnIPRegister(true);
if (_unwindInfoMissing)
return UNW_STEP_END;
- if (_info.gp)
- setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp);
}
return result;
diff --git a/src/UnwindLevel1-gcc-ext.c b/src/UnwindLevel1-gcc-ext.c
index 28ba0928121f..1c6626585465 100644
--- a/src/UnwindLevel1-gcc-ext.c
+++ b/src/UnwindLevel1-gcc-ext.c
@@ -23,22 +23,26 @@
#include "Unwind-EHABI.h"
#include "unwind.h"
-#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
+
+#if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
+#define private_1 private_[0]
+#endif
/// Called by __cxa_rethrow().
_LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
-#if _LIBUNWIND_ARM_EHABI
- _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n",
+#if defined(_LIBUNWIND_ARM_EHABI)
+ _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld",
(void *)exception_object,
(long)exception_object->unwinder_cache.reserved1);
#else
- _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n",
+ _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%" PRIdPTR,
(void *)exception_object,
- (long)exception_object->private_1);
+ (intptr_t)exception_object->private_1);
#endif
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
// _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
// which is in the same position as private_1 below.
return _Unwind_RaiseException(exception_object);
@@ -66,7 +70,7 @@ _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
_LIBUNWIND_EXPORT uintptr_t
_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
(void)context;
- _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", (void *)context);
+ _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
_LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
}
@@ -76,7 +80,7 @@ _Unwind_GetDataRelBase(struct _Unwind_Context *context) {
_LIBUNWIND_EXPORT uintptr_t
_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
(void)context;
- _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", (void *)context);
+ _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)", (void *)context);
_LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
}
@@ -84,7 +88,7 @@ _Unwind_GetTextRelBase(struct _Unwind_Context *context) {
/// Scans unwind information to find the function that contains the
/// specified code address "pc".
_LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
- _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)\n", pc);
+ _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
// This is slow, but works.
// We create an unwind cursor then alter the IP to be pc
unw_cursor_t cursor;
@@ -92,9 +96,9 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
unw_proc_info_t info;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
- unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
+ unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc);
if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
- return (void *)(long) info.start_ip;
+ return (void *)(intptr_t) info.start_ip;
else
return NULL;
}
@@ -108,10 +112,10 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
- _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)",
(void *)(uintptr_t)callback);
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
// Create a mock exception object for force unwinding.
_Unwind_Exception ex;
memset(&ex, '\0', sizeof(ex));
@@ -122,12 +126,12 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
while (true) {
_Unwind_Reason_Code result;
-#if !_LIBUNWIND_ARM_EHABI
- // ask libuwind to get next frame (skip over first frame which is
+#if !defined(_LIBUNWIND_ARM_EHABI)
+ // ask libunwind to get next frame (skip over first frame which is
// _Unwind_Backtrace())
if (unw_step(&cursor) <= 0) {
_LIBUNWIND_TRACE_UNWINDING(" _backtrace: ended because cursor reached "
- "bottom of stack, returning %d\n",
+ "bottom of stack, returning %d",
_URC_END_OF_STACK);
return _URC_END_OF_STACK;
}
@@ -154,7 +158,7 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
_URC_CONTINUE_UNWIND) {
return _URC_END_OF_STACK;
}
-#endif // _LIBUNWIND_ARM_EHABI
+#endif // defined(_LIBUNWIND_ARM_EHABI)
// debugging
if (_LIBUNWIND_TRACING_UNWINDING) {
@@ -164,8 +168,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\n",
- (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);
}
@@ -173,14 +177,14 @@ _Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
if (result != _URC_NO_REASON) {
_LIBUNWIND_TRACE_UNWINDING(
- " _backtrace: ended because callback returned %d\n", result);
+ " _backtrace: ended because callback returned %d", result);
return result;
}
}
}
-/// Find dwarf unwind info for an address 'pc' in some function.
+/// Find DWARF unwind info for an address 'pc' in some function.
_LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
struct dwarf_eh_bases *bases) {
// This is slow, but works.
@@ -190,14 +194,14 @@ _LIBUNWIND_EXPORT const void *_Unwind_Find_FDE(const void *pc,
unw_proc_info_t info;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
- unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(long) pc);
+ unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)(intptr_t) pc);
unw_get_proc_info(&cursor, &info);
bases->tbase = (uintptr_t)info.extra;
bases->dbase = 0; // dbase not used on Mac OS X
bases->func = (uintptr_t)info.start_ip;
- _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p\n", pc,
- (void *)(long) info.unwind_info);
- return (void *)(long) info.unwind_info;
+ _LIBUNWIND_TRACE_API("_Unwind_Find_FDE(pc=%p) => %p", pc,
+ (void *)(intptr_t) info.unwind_info);
+ return (void *)(intptr_t) info.unwind_info;
}
/// Returns the CFA (call frame area, or stack pointer at start of function)
@@ -206,8 +210,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 "\n",
- (void *)context, (uint64_t)result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetCFA(context=%p) => 0x%" PRIxPTR,
+ (void *)context, result);
return (uintptr_t)result;
}
@@ -217,19 +221,19 @@ _LIBUNWIND_EXPORT uintptr_t _Unwind_GetCFA(struct _Unwind_Context *context) {
/// site address. Normally IP is the return address.
_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
int *ipBefore) {
- _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)\n", (void *)context);
+ _LIBUNWIND_TRACE_API("_Unwind_GetIPInfo(context=%p)", (void *)context);
*ipBefore = 0;
return _Unwind_GetIP(context);
}
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
/// Called by programs with dynamic code generators that want
/// to register a dynamically generated FDE.
/// This function has existed on Mac OS X since 10.4, but
/// was broken until 10.6.
_LIBUNWIND_EXPORT void __register_frame(const void *fde) {
- _LIBUNWIND_TRACE_API("__register_frame(%p)\n", fde);
+ _LIBUNWIND_TRACE_API("__register_frame(%p)", fde);
_unw_add_dynamic_fde((unw_word_t)(uintptr_t) fde);
}
@@ -239,7 +243,7 @@ _LIBUNWIND_EXPORT void __register_frame(const void *fde) {
/// This function has existed on Mac OS X since 10.4, but
/// was broken until 10.6.
_LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
- _LIBUNWIND_TRACE_API("__deregister_frame(%p)\n", fde);
+ _LIBUNWIND_TRACE_API("__deregister_frame(%p)", fde);
_unw_remove_dynamic_fde((unw_word_t)(uintptr_t) fde);
}
@@ -252,14 +256,14 @@ _LIBUNWIND_EXPORT void __deregister_frame(const void *fde) {
// applications working. We also add the not in 10.6 symbol so that nwe
// application won't be able to use them.
-#if _LIBUNWIND_SUPPORT_FRAME_APIS
+#if defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
_LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
void *tb, void *db) {
(void)fde;
(void)ob;
(void)tb;
(void)db;
- _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)\n",
+ _LIBUNWIND_TRACE_API("__register_frame_info_bases(%p,%p, %p, %p)",
fde, ob, tb, db);
// do nothing, this function never worked in Mac OS X
}
@@ -267,7 +271,7 @@ _LIBUNWIND_EXPORT void __register_frame_info_bases(const void *fde, void *ob,
_LIBUNWIND_EXPORT void __register_frame_info(const void *fde, void *ob) {
(void)fde;
(void)ob;
- _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)\n", fde, ob);
+ _LIBUNWIND_TRACE_API("__register_frame_info(%p, %p)", fde, ob);
// do nothing, this function never worked in Mac OS X
}
@@ -279,38 +283,38 @@ _LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,
(void)tb;
(void)db;
_LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
- "(%p,%p, %p, %p)\n", fde, ob, tb, db);
+ "(%p,%p, %p, %p)", fde, ob, tb, db);
// do nothing, this function never worked in Mac OS X
}
_LIBUNWIND_EXPORT void __register_frame_info_table(const void *fde, void *ob) {
(void)fde;
(void)ob;
- _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)\n", fde, ob);
+ _LIBUNWIND_TRACE_API("__register_frame_info_table(%p, %p)", fde, ob);
// do nothing, this function never worked in Mac OS X
}
_LIBUNWIND_EXPORT void __register_frame_table(const void *fde) {
(void)fde;
- _LIBUNWIND_TRACE_API("__register_frame_table(%p)\n", fde);
+ _LIBUNWIND_TRACE_API("__register_frame_table(%p)", fde);
// do nothing, this function never worked in Mac OS X
}
_LIBUNWIND_EXPORT void *__deregister_frame_info(const void *fde) {
(void)fde;
- _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)\n", fde);
+ _LIBUNWIND_TRACE_API("__deregister_frame_info(%p)", fde);
// do nothing, this function never worked in Mac OS X
return NULL;
}
_LIBUNWIND_EXPORT void *__deregister_frame_info_bases(const void *fde) {
(void)fde;
- _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)\n", fde);
+ _LIBUNWIND_TRACE_API("__deregister_frame_info_bases(%p)", fde);
// do nothing, this function never worked in Mac OS X
return NULL;
}
-#endif // _LIBUNWIND_SUPPORT_FRAME_APIS
+#endif // defined(_LIBUNWIND_SUPPORT_FRAME_APIS)
-#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
-#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
+#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
diff --git a/src/UnwindLevel1.c b/src/UnwindLevel1.c
index 7294f255407e..0a04438bba2f 100644
--- a/src/UnwindLevel1.c
+++ b/src/UnwindLevel1.c
@@ -30,7 +30,9 @@
#include "unwind.h"
#include "config.h"
-#if !_LIBUNWIND_ARM_EHABI
+#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
+
+#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND
static _Unwind_Reason_Code
unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
@@ -39,17 +41,17 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
// Walk each frame looking for a place to stop.
bool handlerNotFound = true;
while (handlerNotFound) {
- // Ask libuwind to get next frame (skip over first which is
+ // Ask libunwind to get next frame (skip over first which is
// _Unwind_RaiseException).
int stepResult = unw_step(cursor);
if (stepResult == 0) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached "
- "bottom => _URC_END_OF_STACK\n",
+ "bottom => _URC_END_OF_STACK",
(void *)exception_object);
return _URC_END_OF_STACK;
} else if (stepResult < 0) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step failed => "
- "_URC_FATAL_PHASE1_ERROR\n",
+ "_URC_FATAL_PHASE1_ERROR",
(void *)exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
@@ -59,7 +61,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_word_t sp;
if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info "
- "failed => _URC_FATAL_PHASE1_ERROR\n",
+ "failed => _URC_FATAL_PHASE1_ERROR",
(void *)exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
@@ -76,8 +78,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 "\n",
+ "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,9 +88,9 @@ 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\n",
+ "unwind_phase1(ex_ojb=%p): calling personality function %p",
(void *)exception_object, (void *)(uintptr_t)p);
_Unwind_Reason_Code personalityResult =
(*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
@@ -101,13 +103,13 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_get_reg(cursor, UNW_REG_SP, &sp);
exception_object->private_2 = (uintptr_t)sp;
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n",
+ "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",
(void *)exception_object);
return _URC_NO_REASON;
case _URC_CONTINUE_UNWIND:
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
(void *)exception_object);
// continue unwinding
break;
@@ -115,7 +117,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
default:
// something went wrong
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
(void *)exception_object);
return _URC_FATAL_PHASE1_ERROR;
}
@@ -129,23 +131,23 @@ static _Unwind_Reason_Code
unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
unw_init_local(cursor, uc);
- _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n",
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
(void *)exception_object);
// Walk each frame until we reach where search phase said to stop.
while (true) {
- // Ask libuwind to get next frame (skip over first which is
+ // Ask libunwind to get next frame (skip over first which is
// _Unwind_RaiseException).
int stepResult = unw_step(cursor);
if (stepResult == 0) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
- "bottom => _URC_END_OF_STACK\n",
+ "bottom => _URC_END_OF_STACK",
(void *)exception_object);
return _URC_END_OF_STACK;
} else if (stepResult < 0) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step failed => "
- "_URC_FATAL_PHASE1_ERROR\n",
+ "_URC_FATAL_PHASE1_ERROR",
(void *)exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
@@ -156,7 +158,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
unw_get_reg(cursor, UNW_REG_SP, &sp);
if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info "
- "failed => _URC_FATAL_PHASE1_ERROR\n",
+ "failed => _URC_FATAL_PHASE1_ERROR",
(void *)exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
@@ -170,9 +172,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 "\n",
+ _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 +183,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.
@@ -194,7 +196,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
case _URC_CONTINUE_UNWIND:
// Continue unwinding
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
(void *)exception_object);
if (sp == exception_object->private_2) {
// Phase 1 said we would stop at this frame, but we did not...
@@ -204,7 +206,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
break;
case _URC_INSTALL_CONTEXT:
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
+ "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",
(void *)exception_object);
// Personality routine says to transfer control to landing pad.
// We may get control back if landing pad calls _Unwind_Resume().
@@ -213,8 +215,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 "\n",
+ "user code with ip=0x%" PRIxPTR
+ ", sp=0x%" PRIxPTR,
(void *)exception_object, pc, sp);
}
unw_resume(cursor);
@@ -247,7 +249,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
unw_proc_info_t frameInfo;
if (unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): unw_step "
- "failed => _URC_END_OF_STACK\n",
+ "failed => _URC_END_OF_STACK",
(void *)exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
@@ -262,8 +264,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 "\n",
+ "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);
}
@@ -275,11 +277,11 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
(*stop)(1, action, exception_object->exception_class, exception_object,
(struct _Unwind_Context *)(cursor), stop_parameter);
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2_forced(ex_ojb=%p): stop function returned %d\n",
+ "unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
(void *)exception_object, stopResult);
if (stopResult != _URC_NO_REASON) {
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n",
+ "unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
(void *)exception_object);
return _URC_FATAL_PHASE2_ERROR;
}
@@ -287,9 +289,9 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
// 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)(intptr_t)(frameInfo.handler);
_LIBUNWIND_TRACE_UNWINDING(
- "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n",
+ "unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
(void *)exception_object, (void *)(uintptr_t)p);
_Unwind_Reason_Code personalityResult =
(*p)(1, action, exception_object->exception_class, exception_object,
@@ -298,14 +300,14 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
case _URC_CONTINUE_UNWIND:
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
"personality returned "
- "_URC_CONTINUE_UNWIND\n",
+ "_URC_CONTINUE_UNWIND",
(void *)exception_object);
// Destructors called, continue unwinding
break;
case _URC_INSTALL_CONTEXT:
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
"personality returned "
- "_URC_INSTALL_CONTEXT\n",
+ "_URC_INSTALL_CONTEXT",
(void *)exception_object);
// We may get control back if landing pad calls _Unwind_Resume().
unw_resume(cursor);
@@ -314,7 +316,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
// Personality routine returned an unknown result code.
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
"personality returned %d, "
- "_URC_FATAL_PHASE2_ERROR\n",
+ "_URC_FATAL_PHASE2_ERROR",
(void *)exception_object, personalityResult);
return _URC_FATAL_PHASE2_ERROR;
}
@@ -324,7 +326,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
// Call stop function one last time and tell it we've reached the end
// of the stack.
_LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
- "function with _UA_END_OF_STACK\n",
+ "function with _UA_END_OF_STACK",
(void *)exception_object);
_Unwind_Action lastAction =
(_Unwind_Action)(_UA_FORCE_UNWIND | _UA_CLEANUP_PHASE | _UA_END_OF_STACK);
@@ -340,7 +342,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
/// Called by __cxa_throw. Only returns if there is a fatal error.
_LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_RaiseException(_Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)",
(void *)exception_object);
unw_context_t uc;
unw_cursor_t cursor;
@@ -375,7 +377,7 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) {
/// in turn calls _Unwind_Resume_or_Rethrow().
_LIBUNWIND_EXPORT void
_Unwind_Resume(_Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", (void *)exception_object);
+ _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)", (void *)exception_object);
unw_context_t uc;
unw_cursor_t cursor;
unw_getcontext(&uc);
@@ -399,7 +401,7 @@ _Unwind_Resume(_Unwind_Exception *exception_object) {
_LIBUNWIND_EXPORT _Unwind_Reason_Code
_Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
_Unwind_Stop_Fn stop, void *stop_parameter) {
- _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)",
(void *)exception_object, (void *)(uintptr_t)stop);
unw_context_t uc;
unw_cursor_t cursor;
@@ -424,11 +426,11 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
result = (uintptr_t)frameInfo.lsda;
_LIBUNWIND_TRACE_API(
- "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR "\n",
+ "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
(void *)context, result);
if (result != 0) {
if (*((uint8_t *)result) != 0xFF)
- _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF\n",
+ _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",
result);
}
return result;
@@ -444,17 +446,18 @@ _Unwind_GetRegionStart(struct _Unwind_Context *context) {
uintptr_t result = 0;
if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
result = (uintptr_t)frameInfo.start_ip;
- _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR "\n",
+ _LIBUNWIND_TRACE_API("_Unwind_GetRegionStart(context=%p) => 0x%" PRIxPTR,
(void *)context, result);
return result;
}
+#endif // !_LIBUNWIND_SUPPORT_SEH_UNWIND
/// Called by personality handler during phase 2 if a foreign exception
// is caught.
_LIBUNWIND_EXPORT void
_Unwind_DeleteException(_Unwind_Exception *exception_object) {
- _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n",
+ _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
(void *)exception_object);
if (exception_object->exception_cleanup != NULL)
(*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
@@ -467,17 +470,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 "\n",
- (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
- ")\n",
- (void *)context, index, (uint64_t)value);
+ _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, value=0x%0" PRIxPTR
+ ")",
+ (void *)context, index, value);
unw_cursor_t *cursor = (unw_cursor_t *)context;
unw_set_reg(cursor, index, value);
}
@@ -487,8 +490,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 "\n",
- (void *)context, (uint64_t)result);
+ _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIxPTR,
+ (void *)context, result);
return (uintptr_t)result;
}
@@ -497,10 +500,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 ")\n",
- (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 // !_LIBUNWIND_ARM_EHABI
+#endif // !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__)
diff --git a/src/UnwindRegistersRestore.S b/src/UnwindRegistersRestore.S
index d5ecc6ed2acd..389db67579cd 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,11 +104,295 @@ 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
+#elif defined(__powerpc64__)
+
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
+//
+// void libunwind::Registers_ppc64::jumpto()
+//
+// On entry:
+// thread_state pointer is in r3
+//
+
+// load register (GPR)
+#define PPC64_LR(n) \
+ ld %r##n, (8 * (n + 2))(%r3)
+
+ // restore integral registers
+ // skip r0 for now
+ // skip r1 for now
+ PPC64_LR(2)
+ // skip r3 for now
+ // skip r4 for now
+ // skip r5 for now
+ PPC64_LR(6)
+ PPC64_LR(7)
+ PPC64_LR(8)
+ PPC64_LR(9)
+ PPC64_LR(10)
+ PPC64_LR(11)
+ PPC64_LR(12)
+ PPC64_LR(13)
+ PPC64_LR(14)
+ PPC64_LR(15)
+ PPC64_LR(16)
+ PPC64_LR(17)
+ PPC64_LR(18)
+ PPC64_LR(19)
+ PPC64_LR(20)
+ PPC64_LR(21)
+ PPC64_LR(22)
+ PPC64_LR(23)
+ PPC64_LR(24)
+ PPC64_LR(25)
+ PPC64_LR(26)
+ PPC64_LR(27)
+ PPC64_LR(28)
+ PPC64_LR(29)
+ PPC64_LR(30)
+ PPC64_LR(31)
+
+#ifdef PPC64_HAS_VMX
+
+ // restore VS registers
+ // (note that this also restores floating point registers and V registers,
+ // because part of VS is mapped to these registers)
+
+ addi %r4, %r3, PPC64_OFFS_FP
+
+// load VS register
+#define PPC64_LVS(n) \
+ lxvd2x %vs##n, 0, %r4 ;\
+ addi %r4, %r4, 16
+
+ // restore the first 32 VS regs (and also all floating point regs)
+ PPC64_LVS(0)
+ PPC64_LVS(1)
+ PPC64_LVS(2)
+ PPC64_LVS(3)
+ PPC64_LVS(4)
+ PPC64_LVS(5)
+ PPC64_LVS(6)
+ PPC64_LVS(7)
+ PPC64_LVS(8)
+ PPC64_LVS(9)
+ PPC64_LVS(10)
+ PPC64_LVS(11)
+ PPC64_LVS(12)
+ PPC64_LVS(13)
+ PPC64_LVS(14)
+ PPC64_LVS(15)
+ PPC64_LVS(16)
+ PPC64_LVS(17)
+ PPC64_LVS(18)
+ PPC64_LVS(19)
+ PPC64_LVS(20)
+ PPC64_LVS(21)
+ PPC64_LVS(22)
+ PPC64_LVS(23)
+ PPC64_LVS(24)
+ PPC64_LVS(25)
+ PPC64_LVS(26)
+ PPC64_LVS(27)
+ PPC64_LVS(28)
+ PPC64_LVS(29)
+ PPC64_LVS(30)
+ PPC64_LVS(31)
+
+ // use VRSAVE to conditionally restore the remaining VS regs,
+ // that are where the V regs are mapped
+
+ ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave
+ cmpwi %r5, 0
+ beq Lnovec
+
+// conditionally load VS
+#define PPC64_CLVS_BOTTOM(n) \
+ beq Ldone##n ;\
+ addi %r4, %r3, PPC64_OFFS_FP + n * 16 ;\
+ lxvd2x %vs##n, 0, %r4 ;\
+Ldone##n:
+
+#define PPC64_CLVSl(n) \
+ andis. %r0, %r5, (1<<(47-n)) ;\
+PPC64_CLVS_BOTTOM(n)
+
+#define PPC64_CLVSh(n) \
+ andi. %r0, %r5, (1<<(63-n)) ;\
+PPC64_CLVS_BOTTOM(n)
+
+ PPC64_CLVSl(32)
+ PPC64_CLVSl(33)
+ PPC64_CLVSl(34)
+ PPC64_CLVSl(35)
+ PPC64_CLVSl(36)
+ PPC64_CLVSl(37)
+ PPC64_CLVSl(38)
+ PPC64_CLVSl(39)
+ PPC64_CLVSl(40)
+ PPC64_CLVSl(41)
+ PPC64_CLVSl(42)
+ PPC64_CLVSl(43)
+ PPC64_CLVSl(44)
+ PPC64_CLVSl(45)
+ PPC64_CLVSl(46)
+ PPC64_CLVSl(47)
+ PPC64_CLVSh(48)
+ PPC64_CLVSh(49)
+ PPC64_CLVSh(50)
+ PPC64_CLVSh(51)
+ PPC64_CLVSh(52)
+ PPC64_CLVSh(53)
+ PPC64_CLVSh(54)
+ PPC64_CLVSh(55)
+ PPC64_CLVSh(56)
+ PPC64_CLVSh(57)
+ PPC64_CLVSh(58)
+ PPC64_CLVSh(59)
+ PPC64_CLVSh(60)
+ PPC64_CLVSh(61)
+ PPC64_CLVSh(62)
+ PPC64_CLVSh(63)
+
+#else
+
+// load FP register
+#define PPC64_LF(n) \
+ lfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3)
+
+ // restore float registers
+ PPC64_LF(0)
+ PPC64_LF(1)
+ PPC64_LF(2)
+ PPC64_LF(3)
+ PPC64_LF(4)
+ PPC64_LF(5)
+ PPC64_LF(6)
+ PPC64_LF(7)
+ PPC64_LF(8)
+ PPC64_LF(9)
+ PPC64_LF(10)
+ PPC64_LF(11)
+ PPC64_LF(12)
+ PPC64_LF(13)
+ PPC64_LF(14)
+ PPC64_LF(15)
+ PPC64_LF(16)
+ PPC64_LF(17)
+ PPC64_LF(18)
+ PPC64_LF(19)
+ PPC64_LF(20)
+ PPC64_LF(21)
+ PPC64_LF(22)
+ PPC64_LF(23)
+ PPC64_LF(24)
+ PPC64_LF(25)
+ PPC64_LF(26)
+ PPC64_LF(27)
+ PPC64_LF(28)
+ PPC64_LF(29)
+ PPC64_LF(30)
+ PPC64_LF(31)
+
+ // restore vector registers if any are in use
+ ld %r5, PPC64_OFFS_VRSAVE(%r3) // test VRsave
+ cmpwi %r5, 0
+ beq Lnovec
+
+ subi %r4, %r1, 16
+ // r4 is now a 16-byte aligned pointer into the red zone
+ // the _vectorScalarRegisters may not be 16-byte aligned
+ // so copy via red zone temp buffer
+
+#define PPC64_CLV_UNALIGNED_BOTTOM(n) \
+ beq Ldone##n ;\
+ ld %r0, (PPC64_OFFS_V + n * 16)(%r3) ;\
+ std %r0, 0(%r4) ;\
+ ld %r0, (PPC64_OFFS_V + n * 16 + 8)(%r3) ;\
+ std %r0, 8(%r4) ;\
+ lvx %v##n, 0, %r4 ;\
+Ldone ## n:
+
+#define PPC64_CLV_UNALIGNEDl(n) \
+ andis. %r0, %r5, (1<<(15-n)) ;\
+PPC64_CLV_UNALIGNED_BOTTOM(n)
+
+#define PPC64_CLV_UNALIGNEDh(n) \
+ andi. %r0, %r5, (1<<(31-n)) ;\
+PPC64_CLV_UNALIGNED_BOTTOM(n)
+
+ PPC64_CLV_UNALIGNEDl(0)
+ PPC64_CLV_UNALIGNEDl(1)
+ PPC64_CLV_UNALIGNEDl(2)
+ PPC64_CLV_UNALIGNEDl(3)
+ PPC64_CLV_UNALIGNEDl(4)
+ PPC64_CLV_UNALIGNEDl(5)
+ PPC64_CLV_UNALIGNEDl(6)
+ PPC64_CLV_UNALIGNEDl(7)
+ PPC64_CLV_UNALIGNEDl(8)
+ PPC64_CLV_UNALIGNEDl(9)
+ PPC64_CLV_UNALIGNEDl(10)
+ PPC64_CLV_UNALIGNEDl(11)
+ PPC64_CLV_UNALIGNEDl(12)
+ PPC64_CLV_UNALIGNEDl(13)
+ PPC64_CLV_UNALIGNEDl(14)
+ PPC64_CLV_UNALIGNEDl(15)
+ PPC64_CLV_UNALIGNEDh(16)
+ PPC64_CLV_UNALIGNEDh(17)
+ PPC64_CLV_UNALIGNEDh(18)
+ PPC64_CLV_UNALIGNEDh(19)
+ PPC64_CLV_UNALIGNEDh(20)
+ PPC64_CLV_UNALIGNEDh(21)
+ PPC64_CLV_UNALIGNEDh(22)
+ PPC64_CLV_UNALIGNEDh(23)
+ PPC64_CLV_UNALIGNEDh(24)
+ PPC64_CLV_UNALIGNEDh(25)
+ PPC64_CLV_UNALIGNEDh(26)
+ PPC64_CLV_UNALIGNEDh(27)
+ PPC64_CLV_UNALIGNEDh(28)
+ PPC64_CLV_UNALIGNEDh(29)
+ PPC64_CLV_UNALIGNEDh(30)
+ PPC64_CLV_UNALIGNEDh(31)
+
+#endif
+
+Lnovec:
+ ld %r0, PPC64_OFFS_CR(%r3)
+ mtcr %r0
+ ld %r0, PPC64_OFFS_SRR0(%r3)
+ mtctr %r0
+
+ PPC64_LR(0)
+ PPC64_LR(5)
+ PPC64_LR(4)
+ PPC64_LR(1)
+ PPC64_LR(3)
+ bctr
+
#elif defined(__ppc__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
@@ -322,9 +622,18 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
@
.p2align 2
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
-#if !defined(__ARM_ARCH_ISA_ARM)
- ldr r2, [r0, #52]
- ldr r3, [r0, #60]
+#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
+ @ r8-r11: ldm into r1-r4, then mov to r8-r11
+ adds r0, #0x20
+ ldm r0!, {r1-r4}
+ subs r0, #0x30
+ mov r8, r1
+ mov r9, r2
+ mov r10, r3
+ mov r11, r4
+ @ r12 does not need loading, it it the intra-procedure-call scratch register
+ ldr r2, [r0, #0x34]
+ ldr r3, [r0, #0x3c]
mov sp, r2
mov lr, r3 @ restore pc into lr
ldm r0, {r0-r7}
@@ -347,7 +656,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
@@ -366,7 +677,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)
@@ -378,11 +691,15 @@ 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)
+#if defined(__ARM_WMMX)
+
@
@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
@
@@ -390,8 +707,10 @@ 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)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
ldcl p1, cr0, [r0], #8 @ wldrd wR0, [r0], #8
ldcl p1, cr1, [r0], #8 @ wldrd wR1, [r0], #8
ldcl p1, cr2, [r0], #8 @ wldrd wR2, [r0], #8
@@ -408,7 +727,6 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreiWMMXEPy)
ldcl p1, cr13, [r0], #8 @ wldrd wR13, [r0], #8
ldcl p1, cr14, [r0], #8 @ wldrd wR14, [r0], #8
ldcl p1, cr15, [r0], #8 @ wldrd wR15, [r0], #8
-#endif
JMP(lr)
@
@@ -418,15 +736,18 @@ 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)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
ldc2 p1, cr8, [r0], #4 @ wldrw wCGR0, [r0], #4
ldc2 p1, cr9, [r0], #4 @ wldrw wCGR1, [r0], #4
ldc2 p1, cr10, [r0], #4 @ wldrw wCGR2, [r0], #4
ldc2 p1, cr11, [r0], #4 @ wldrw wCGR3, [r0], #4
-#endif
JMP(lr)
+#endif
+
#elif defined(__or1k__)
DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
@@ -437,7 +758,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
# thread_state pointer is in r3
#
- # restore integral registerrs
+ # restore integral registers
l.lwz r0, 0(r3)
l.lwz r1, 4(r3)
l.lwz r2, 8(r3)
@@ -447,7 +768,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
l.lwz r6, 24(r3)
l.lwz r7, 28(r3)
l.lwz r8, 32(r3)
- l.lwz r9, 36(r3)
+ # skip r9
l.lwz r10, 40(r3)
l.lwz r11, 44(r3)
l.lwz r12, 48(r3)
@@ -474,8 +795,236 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
# at last, restore r3
l.lwz r3, 12(r3)
+ # load new pc into ra
+ l.lwz r9, 128(r3)
# jump to pc
l.jr r9
l.nop
+#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
+
+//
+// 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
+#ifdef __mips_hard_float
+#if __mips_fpr != 64
+ ldc1 $f0, (4 * 36 + 8 * 0)($4)
+ ldc1 $f2, (4 * 36 + 8 * 2)($4)
+ ldc1 $f4, (4 * 36 + 8 * 4)($4)
+ ldc1 $f6, (4 * 36 + 8 * 6)($4)
+ ldc1 $f8, (4 * 36 + 8 * 8)($4)
+ ldc1 $f10, (4 * 36 + 8 * 10)($4)
+ ldc1 $f12, (4 * 36 + 8 * 12)($4)
+ ldc1 $f14, (4 * 36 + 8 * 14)($4)
+ ldc1 $f16, (4 * 36 + 8 * 16)($4)
+ ldc1 $f18, (4 * 36 + 8 * 18)($4)
+ ldc1 $f20, (4 * 36 + 8 * 20)($4)
+ ldc1 $f22, (4 * 36 + 8 * 22)($4)
+ ldc1 $f24, (4 * 36 + 8 * 24)($4)
+ ldc1 $f26, (4 * 36 + 8 * 26)($4)
+ ldc1 $f28, (4 * 36 + 8 * 28)($4)
+ ldc1 $f30, (4 * 36 + 8 * 30)($4)
+#else
+ ldc1 $f0, (4 * 36 + 8 * 0)($4)
+ ldc1 $f1, (4 * 36 + 8 * 1)($4)
+ ldc1 $f2, (4 * 36 + 8 * 2)($4)
+ ldc1 $f3, (4 * 36 + 8 * 3)($4)
+ ldc1 $f4, (4 * 36 + 8 * 4)($4)
+ ldc1 $f5, (4 * 36 + 8 * 5)($4)
+ ldc1 $f6, (4 * 36 + 8 * 6)($4)
+ ldc1 $f7, (4 * 36 + 8 * 7)($4)
+ ldc1 $f8, (4 * 36 + 8 * 8)($4)
+ ldc1 $f9, (4 * 36 + 8 * 9)($4)
+ ldc1 $f10, (4 * 36 + 8 * 10)($4)
+ ldc1 $f11, (4 * 36 + 8 * 11)($4)
+ ldc1 $f12, (4 * 36 + 8 * 12)($4)
+ ldc1 $f13, (4 * 36 + 8 * 13)($4)
+ ldc1 $f14, (4 * 36 + 8 * 14)($4)
+ ldc1 $f15, (4 * 36 + 8 * 15)($4)
+ ldc1 $f16, (4 * 36 + 8 * 16)($4)
+ ldc1 $f17, (4 * 36 + 8 * 17)($4)
+ ldc1 $f18, (4 * 36 + 8 * 18)($4)
+ ldc1 $f19, (4 * 36 + 8 * 19)($4)
+ ldc1 $f20, (4 * 36 + 8 * 20)($4)
+ ldc1 $f21, (4 * 36 + 8 * 21)($4)
+ ldc1 $f22, (4 * 36 + 8 * 22)($4)
+ ldc1 $f23, (4 * 36 + 8 * 23)($4)
+ ldc1 $f24, (4 * 36 + 8 * 24)($4)
+ ldc1 $f25, (4 * 36 + 8 * 25)($4)
+ ldc1 $f26, (4 * 36 + 8 * 26)($4)
+ ldc1 $f27, (4 * 36 + 8 * 27)($4)
+ ldc1 $f28, (4 * 36 + 8 * 28)($4)
+ ldc1 $f29, (4 * 36 + 8 * 29)($4)
+ ldc1 $f30, (4 * 36 + 8 * 30)($4)
+ ldc1 $f31, (4 * 36 + 8 * 31)($4)
#endif
+#endif
+ // 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(__mips64)
+
+//
+// void libunwind::Registers_mips_newabi::jumpto()
+//
+// On entry:
+// thread state pointer is in a0 ($4)
+//
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
+ .set push
+ .set noat
+ .set noreorder
+ .set nomacro
+#ifdef __mips_hard_float
+ ldc1 $f0, (8 * 35)($4)
+ ldc1 $f1, (8 * 36)($4)
+ ldc1 $f2, (8 * 37)($4)
+ ldc1 $f3, (8 * 38)($4)
+ ldc1 $f4, (8 * 39)($4)
+ ldc1 $f5, (8 * 40)($4)
+ ldc1 $f6, (8 * 41)($4)
+ ldc1 $f7, (8 * 42)($4)
+ ldc1 $f8, (8 * 43)($4)
+ ldc1 $f9, (8 * 44)($4)
+ ldc1 $f10, (8 * 45)($4)
+ ldc1 $f11, (8 * 46)($4)
+ ldc1 $f12, (8 * 47)($4)
+ ldc1 $f13, (8 * 48)($4)
+ ldc1 $f14, (8 * 49)($4)
+ ldc1 $f15, (8 * 50)($4)
+ ldc1 $f16, (8 * 51)($4)
+ ldc1 $f17, (8 * 52)($4)
+ ldc1 $f18, (8 * 53)($4)
+ ldc1 $f19, (8 * 54)($4)
+ ldc1 $f20, (8 * 55)($4)
+ ldc1 $f21, (8 * 56)($4)
+ ldc1 $f22, (8 * 57)($4)
+ ldc1 $f23, (8 * 58)($4)
+ ldc1 $f24, (8 * 59)($4)
+ ldc1 $f25, (8 * 60)($4)
+ ldc1 $f26, (8 * 61)($4)
+ ldc1 $f27, (8 * 62)($4)
+ ldc1 $f28, (8 * 63)($4)
+ ldc1 $f29, (8 * 64)($4)
+ ldc1 $f30, (8 * 65)($4)
+ ldc1 $f31, (8 * 66)($4)
+#endif
+ // 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
+
+#elif defined(__sparc__)
+
+//
+// void libunwind::Registers_sparc_o32::jumpto()
+//
+// On entry:
+// thread_state pointer is in o0
+//
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
+ ta 3
+ ldd [%o0 + 64], %l0
+ ldd [%o0 + 72], %l2
+ ldd [%o0 + 80], %l4
+ ldd [%o0 + 88], %l6
+ ldd [%o0 + 96], %i0
+ ldd [%o0 + 104], %i2
+ ldd [%o0 + 112], %i4
+ ldd [%o0 + 120], %i6
+ ld [%o0 + 60], %o7
+ jmp %o7
+ nop
+
+#endif
+
+#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/src/UnwindRegistersSave.S b/src/UnwindRegistersSave.S
index 82becffa0e45..48ecb0aec70f 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,258 @@ 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) && _MIPS_SIM == _ABIO32
+
+#
+# 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)
+#ifdef __mips_hard_float
+#if __mips_fpr != 64
+ sdc1 $f0, (4 * 36 + 8 * 0)($4)
+ sdc1 $f2, (4 * 36 + 8 * 2)($4)
+ sdc1 $f4, (4 * 36 + 8 * 4)($4)
+ sdc1 $f6, (4 * 36 + 8 * 6)($4)
+ sdc1 $f8, (4 * 36 + 8 * 8)($4)
+ sdc1 $f10, (4 * 36 + 8 * 10)($4)
+ sdc1 $f12, (4 * 36 + 8 * 12)($4)
+ sdc1 $f14, (4 * 36 + 8 * 14)($4)
+ sdc1 $f16, (4 * 36 + 8 * 16)($4)
+ sdc1 $f18, (4 * 36 + 8 * 18)($4)
+ sdc1 $f20, (4 * 36 + 8 * 20)($4)
+ sdc1 $f22, (4 * 36 + 8 * 22)($4)
+ sdc1 $f24, (4 * 36 + 8 * 24)($4)
+ sdc1 $f26, (4 * 36 + 8 * 26)($4)
+ sdc1 $f28, (4 * 36 + 8 * 28)($4)
+ sdc1 $f30, (4 * 36 + 8 * 30)($4)
+#else
+ sdc1 $f0, (4 * 36 + 8 * 0)($4)
+ sdc1 $f1, (4 * 36 + 8 * 1)($4)
+ sdc1 $f2, (4 * 36 + 8 * 2)($4)
+ sdc1 $f3, (4 * 36 + 8 * 3)($4)
+ sdc1 $f4, (4 * 36 + 8 * 4)($4)
+ sdc1 $f5, (4 * 36 + 8 * 5)($4)
+ sdc1 $f6, (4 * 36 + 8 * 6)($4)
+ sdc1 $f7, (4 * 36 + 8 * 7)($4)
+ sdc1 $f8, (4 * 36 + 8 * 8)($4)
+ sdc1 $f9, (4 * 36 + 8 * 9)($4)
+ sdc1 $f10, (4 * 36 + 8 * 10)($4)
+ sdc1 $f11, (4 * 36 + 8 * 11)($4)
+ sdc1 $f12, (4 * 36 + 8 * 12)($4)
+ sdc1 $f13, (4 * 36 + 8 * 13)($4)
+ sdc1 $f14, (4 * 36 + 8 * 14)($4)
+ sdc1 $f15, (4 * 36 + 8 * 15)($4)
+ sdc1 $f16, (4 * 36 + 8 * 16)($4)
+ sdc1 $f17, (4 * 36 + 8 * 17)($4)
+ sdc1 $f18, (4 * 36 + 8 * 18)($4)
+ sdc1 $f19, (4 * 36 + 8 * 19)($4)
+ sdc1 $f20, (4 * 36 + 8 * 20)($4)
+ sdc1 $f21, (4 * 36 + 8 * 21)($4)
+ sdc1 $f22, (4 * 36 + 8 * 22)($4)
+ sdc1 $f23, (4 * 36 + 8 * 23)($4)
+ sdc1 $f24, (4 * 36 + 8 * 24)($4)
+ sdc1 $f25, (4 * 36 + 8 * 25)($4)
+ sdc1 $f26, (4 * 36 + 8 * 26)($4)
+ sdc1 $f27, (4 * 36 + 8 * 27)($4)
+ sdc1 $f28, (4 * 36 + 8 * 28)($4)
+ sdc1 $f29, (4 * 36 + 8 * 29)($4)
+ sdc1 $f30, (4 * 36 + 8 * 30)($4)
+ sdc1 $f31, (4 * 36 + 8 * 31)($4)
+#endif
+#endif
+ jr $31
+ # return UNW_ESUCCESS
+ or $2, $0, $0
+ .set pop
+
+#elif defined(__mips64)
+
+#
+# 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)
+#ifdef __mips_hard_float
+ sdc1 $f0, (8 * 35)($4)
+ sdc1 $f1, (8 * 36)($4)
+ sdc1 $f2, (8 * 37)($4)
+ sdc1 $f3, (8 * 38)($4)
+ sdc1 $f4, (8 * 39)($4)
+ sdc1 $f5, (8 * 40)($4)
+ sdc1 $f6, (8 * 41)($4)
+ sdc1 $f7, (8 * 42)($4)
+ sdc1 $f8, (8 * 43)($4)
+ sdc1 $f9, (8 * 44)($4)
+ sdc1 $f10, (8 * 45)($4)
+ sdc1 $f11, (8 * 46)($4)
+ sdc1 $f12, (8 * 47)($4)
+ sdc1 $f13, (8 * 48)($4)
+ sdc1 $f14, (8 * 49)($4)
+ sdc1 $f15, (8 * 50)($4)
+ sdc1 $f16, (8 * 51)($4)
+ sdc1 $f17, (8 * 52)($4)
+ sdc1 $f18, (8 * 53)($4)
+ sdc1 $f19, (8 * 54)($4)
+ sdc1 $f20, (8 * 55)($4)
+ sdc1 $f21, (8 * 56)($4)
+ sdc1 $f22, (8 * 57)($4)
+ sdc1 $f23, (8 * 58)($4)
+ sdc1 $f24, (8 * 59)($4)
+ sdc1 $f25, (8 * 60)($4)
+ sdc1 $f26, (8 * 61)($4)
+ sdc1 $f27, (8 * 62)($4)
+ sdc1 $f28, (8 * 63)($4)
+ sdc1 $f29, (8 * 64)($4)
+ sdc1 $f30, (8 * 65)($4)
+ sdc1 $f31, (8 * 66)($4)
+#endif
+ jr $31
+ # return UNW_ESUCCESS
+ or $2, $0, $0
+ .set pop
+
# elif defined(__mips__)
#
@@ -96,6 +324,237 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
teq $0, $0
+#elif defined(__powerpc64__)
+
+//
+// extern int unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+// thread_state pointer is in r3
+//
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+
+// store register (GPR)
+#define PPC64_STR(n) \
+ std %r##n, (8 * (n + 2))(%r3)
+
+ // save GPRs
+ PPC64_STR(0)
+ mflr %r0
+ std %r0, PPC64_OFFS_SRR0(%r3) // store lr as ssr0
+ PPC64_STR(1)
+ PPC64_STR(2)
+ PPC64_STR(3)
+ PPC64_STR(4)
+ PPC64_STR(5)
+ PPC64_STR(6)
+ PPC64_STR(7)
+ PPC64_STR(8)
+ PPC64_STR(9)
+ PPC64_STR(10)
+ PPC64_STR(11)
+ PPC64_STR(12)
+ PPC64_STR(13)
+ PPC64_STR(14)
+ PPC64_STR(15)
+ PPC64_STR(16)
+ PPC64_STR(17)
+ PPC64_STR(18)
+ PPC64_STR(19)
+ PPC64_STR(20)
+ PPC64_STR(21)
+ PPC64_STR(22)
+ PPC64_STR(23)
+ PPC64_STR(24)
+ PPC64_STR(25)
+ PPC64_STR(26)
+ PPC64_STR(27)
+ PPC64_STR(28)
+ PPC64_STR(29)
+ PPC64_STR(30)
+ PPC64_STR(31)
+
+ mfcr %r0
+ std %r0, PPC64_OFFS_CR(%r3)
+ mfxer %r0
+ std %r0, PPC64_OFFS_XER(%r3)
+ mflr %r0
+ std %r0, PPC64_OFFS_LR(%r3)
+ mfctr %r0
+ std %r0, PPC64_OFFS_CTR(%r3)
+ mfvrsave %r0
+ std %r0, PPC64_OFFS_VRSAVE(%r3)
+
+#ifdef PPC64_HAS_VMX
+ // save VS registers
+ // (note that this also saves floating point registers and V registers,
+ // because part of VS is mapped to these registers)
+
+ addi %r4, %r3, PPC64_OFFS_FP
+
+// store VS register
+#define PPC64_STVS(n) \
+ stxvd2x %vs##n, 0, %r4 ;\
+ addi %r4, %r4, 16
+
+ PPC64_STVS(0)
+ PPC64_STVS(1)
+ PPC64_STVS(2)
+ PPC64_STVS(3)
+ PPC64_STVS(4)
+ PPC64_STVS(5)
+ PPC64_STVS(6)
+ PPC64_STVS(7)
+ PPC64_STVS(8)
+ PPC64_STVS(9)
+ PPC64_STVS(10)
+ PPC64_STVS(11)
+ PPC64_STVS(12)
+ PPC64_STVS(13)
+ PPC64_STVS(14)
+ PPC64_STVS(15)
+ PPC64_STVS(16)
+ PPC64_STVS(17)
+ PPC64_STVS(18)
+ PPC64_STVS(19)
+ PPC64_STVS(20)
+ PPC64_STVS(21)
+ PPC64_STVS(22)
+ PPC64_STVS(23)
+ PPC64_STVS(24)
+ PPC64_STVS(25)
+ PPC64_STVS(26)
+ PPC64_STVS(27)
+ PPC64_STVS(28)
+ PPC64_STVS(29)
+ PPC64_STVS(30)
+ PPC64_STVS(31)
+ PPC64_STVS(32)
+ PPC64_STVS(33)
+ PPC64_STVS(34)
+ PPC64_STVS(35)
+ PPC64_STVS(36)
+ PPC64_STVS(37)
+ PPC64_STVS(38)
+ PPC64_STVS(39)
+ PPC64_STVS(40)
+ PPC64_STVS(41)
+ PPC64_STVS(42)
+ PPC64_STVS(43)
+ PPC64_STVS(44)
+ PPC64_STVS(45)
+ PPC64_STVS(46)
+ PPC64_STVS(47)
+ PPC64_STVS(48)
+ PPC64_STVS(49)
+ PPC64_STVS(50)
+ PPC64_STVS(51)
+ PPC64_STVS(52)
+ PPC64_STVS(53)
+ PPC64_STVS(54)
+ PPC64_STVS(55)
+ PPC64_STVS(56)
+ PPC64_STVS(57)
+ PPC64_STVS(58)
+ PPC64_STVS(59)
+ PPC64_STVS(60)
+ PPC64_STVS(61)
+ PPC64_STVS(62)
+ PPC64_STVS(63)
+
+#else
+
+// store FP register
+#define PPC64_STF(n) \
+ stfd %f##n, (PPC64_OFFS_FP + n * 16)(%r3)
+
+ // save float registers
+ PPC64_STF(0)
+ PPC64_STF(1)
+ PPC64_STF(2)
+ PPC64_STF(3)
+ PPC64_STF(4)
+ PPC64_STF(5)
+ PPC64_STF(6)
+ PPC64_STF(7)
+ PPC64_STF(8)
+ PPC64_STF(9)
+ PPC64_STF(10)
+ PPC64_STF(11)
+ PPC64_STF(12)
+ PPC64_STF(13)
+ PPC64_STF(14)
+ PPC64_STF(15)
+ PPC64_STF(16)
+ PPC64_STF(17)
+ PPC64_STF(18)
+ PPC64_STF(19)
+ PPC64_STF(20)
+ PPC64_STF(21)
+ PPC64_STF(22)
+ PPC64_STF(23)
+ PPC64_STF(24)
+ PPC64_STF(25)
+ PPC64_STF(26)
+ PPC64_STF(27)
+ PPC64_STF(28)
+ PPC64_STF(29)
+ PPC64_STF(30)
+ PPC64_STF(31)
+
+ // save vector registers
+
+ // Use 16-bytes below the stack pointer as an
+ // aligned buffer to save each vector register.
+ // Note that the stack pointer is always 16-byte aligned.
+ subi %r4, %r1, 16
+
+#define PPC64_STV_UNALIGNED(n) \
+ stvx %v##n, 0, %r4 ;\
+ ld %r5, 0(%r4) ;\
+ std %r5, (PPC64_OFFS_V + n * 16)(%r3) ;\
+ ld %r5, 8(%r4) ;\
+ std %r5, (PPC64_OFFS_V + n * 16 + 8)(%r3)
+
+ PPC64_STV_UNALIGNED(0)
+ PPC64_STV_UNALIGNED(1)
+ PPC64_STV_UNALIGNED(2)
+ PPC64_STV_UNALIGNED(3)
+ PPC64_STV_UNALIGNED(4)
+ PPC64_STV_UNALIGNED(5)
+ PPC64_STV_UNALIGNED(6)
+ PPC64_STV_UNALIGNED(7)
+ PPC64_STV_UNALIGNED(8)
+ PPC64_STV_UNALIGNED(9)
+ PPC64_STV_UNALIGNED(10)
+ PPC64_STV_UNALIGNED(11)
+ PPC64_STV_UNALIGNED(12)
+ PPC64_STV_UNALIGNED(13)
+ PPC64_STV_UNALIGNED(14)
+ PPC64_STV_UNALIGNED(15)
+ PPC64_STV_UNALIGNED(16)
+ PPC64_STV_UNALIGNED(17)
+ PPC64_STV_UNALIGNED(18)
+ PPC64_STV_UNALIGNED(19)
+ PPC64_STV_UNALIGNED(20)
+ PPC64_STV_UNALIGNED(21)
+ PPC64_STV_UNALIGNED(22)
+ PPC64_STV_UNALIGNED(23)
+ PPC64_STV_UNALIGNED(24)
+ PPC64_STV_UNALIGNED(25)
+ PPC64_STV_UNALIGNED(26)
+ PPC64_STV_UNALIGNED(27)
+ PPC64_STV_UNALIGNED(28)
+ PPC64_STV_UNALIGNED(29)
+ PPC64_STV_UNALIGNED(30)
+ PPC64_STV_UNALIGNED(31)
+
+#endif
+
+ li %r3, 0 // return UNW_ESUCCESS
+ blr
+
+
#elif defined(__ppc__)
;
@@ -309,13 +768,24 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
@
.p2align 2
DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
-#if !defined(__ARM_ARCH_ISA_ARM)
- stm r0, {r0-r7}
+#if !defined(__ARM_ARCH_ISA_ARM) && __ARM_ARCH_ISA_THUMB == 1
+ stm r0!, {r0-r7}
+ mov r1, r8
+ mov r2, r9
+ mov r3, r10
+ stm r0!, {r1-r3}
+ mov r1, r11
mov r2, sp
mov r3, lr
- str r2, [r0, #52]
- str r3, [r0, #56]
- str r3, [r0, #60] @ store return address as pc
+ str r1, [r0, #0] @ r11
+ @ r12 does not need storing, it it the intra-procedure-call scratch register
+ str r2, [r0, #8] @ sp
+ str r3, [r0, #12] @ lr
+ str r3, [r0, #16] @ store return address as pc
+ @ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
+ @ It is safe to use here though because we are about to return, and cpsr is
+ @ not expected to be preserved.
+ movs r0, #0 @ return UNW_ESUCCESS
#else
@ 32bit thumb-2 restrictions for stm:
@ . the sp (r13) cannot be in the list
@@ -324,13 +794,6 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
str sp, [r0, #52]
str lr, [r0, #56]
str lr, [r0, #60] @ store return address as pc
-#endif
-#if __ARM_ARCH_ISA_THUMB == 1
- @ T1 does not have a non-cpsr-clobbering register-zeroing instruction.
- @ It is safe to use here though because we are about to return, and cpsr is
- @ not expected to be preserved.
- movs r0, #0 @ return UNW_ESUCCESS
-#else
mov r0, #0 @ return UNW_ESUCCESS
#endif
JMP(lr)
@@ -342,7 +805,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)
@@ -354,7 +819,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)
@@ -366,7 +833,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
@@ -378,6 +847,8 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveVFPv3EPy)
vstmia r0, {d16-d31}
JMP(lr)
+#if defined(_LIBUNWIND_ARM_WMMX)
+
@
@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
@
@@ -385,8 +856,10 @@ 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)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
stcl p1, cr0, [r0], #8 @ wstrd wR0, [r0], #8
stcl p1, cr1, [r0], #8 @ wstrd wR1, [r0], #8
stcl p1, cr2, [r0], #8 @ wstrd wR2, [r0], #8
@@ -403,7 +876,6 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm9saveiWMMXEPy)
stcl p1, cr13, [r0], #8 @ wstrd wR13, [r0], #8
stcl p1, cr14, [r0], #8 @ wstrd wR14, [r0], #8
stcl p1, cr15, [r0], #8 @ wstrd wR15, [r0], #8
-#endif
JMP(lr)
@
@@ -413,15 +885,18 @@ 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)
-#if (!defined(__ARM_ARCH_6M__) && !defined(__ARM_ARCH_6SM__)) || defined(__ARM_WMMX)
stc2 p1, cr8, [r0], #4 @ wstrw wCGR0, [r0], #4
stc2 p1, cr9, [r0], #4 @ wstrw wCGR1, [r0], #4
stc2 p1, cr10, [r0], #4 @ wstrw wCGR2, [r0], #4
stc2 p1, cr11, [r0], #4 @ wstrw wCGR3, [r0], #4
-#endif
JMP(lr)
+#endif
+
#elif defined(__or1k__)
#
@@ -463,4 +938,41 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
l.sw 116(r3), r29
l.sw 120(r3), r30
l.sw 124(r3), r31
+ # store ra to pc
+ l.sw 128(r3), r9
+ # zero epcr
+ l.sw 132(r3), r0
+
+#elif defined(__sparc__)
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# thread_state pointer is in o0
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ ta 3
+ add %o7, 8, %o7
+ std %g0, [%o0 + 0]
+ std %g2, [%o0 + 8]
+ std %g4, [%o0 + 16]
+ std %g6, [%o0 + 24]
+ std %o0, [%o0 + 32]
+ std %o2, [%o0 + 40]
+ std %o4, [%o0 + 48]
+ std %o6, [%o0 + 56]
+ std %l0, [%o0 + 64]
+ std %l2, [%o0 + 72]
+ std %l4, [%o0 + 80]
+ std %l6, [%o0 + 88]
+ std %i0, [%o0 + 96]
+ std %i2, [%o0 + 104]
+ std %i4, [%o0 + 112]
+ std %i6, [%o0 + 120]
+ jmp %o7
+ clr %o0 // return UNW_ESUCCESS
#endif
+#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
+
+NO_EXEC_STACK_DIRECTIVE
diff --git a/src/Unwind_AppleExtras.cpp b/src/Unwind_AppleExtras.cpp
index b8baef5fa76f..39f379c5298c 100644
--- a/src/Unwind_AppleExtras.cpp
+++ b/src/Unwind_AppleExtras.cpp
@@ -9,8 +9,8 @@
//===----------------------------------------------------------------------===//
#include "config.h"
+#include "AddressSpace.hpp"
#include "DwarfParser.hpp"
-#include "unwind_ext.h"
// private keymgr stuff
@@ -76,7 +76,7 @@ struct libgcc_object_info {
#endif
-#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+#if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
//
// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in
@@ -115,12 +115,12 @@ NEVER_HERE(__register_frame_table)
NEVER_HERE(__deregister_frame_info)
NEVER_HERE(__deregister_frame_info_bases)
-#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
+#endif // defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
-#if _LIBUNWIND_BUILD_SJLJ_APIS
+#if defined(_LIBUNWIND_BUILD_SJLJ_APIS)
//
// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in
// earlier versions
@@ -140,7 +140,7 @@ NOT_HERE_BEFORE_5_0(_Unwind_SjLj_RaiseException)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume_or_Rethrow)
NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Unregister)
-#endif // _LIBUNWIND_BUILD_SJLJ_APIS
+#endif // defined(_LIBUNWIND_BUILD_SJLJ_APIS)
namespace libunwind {
@@ -182,24 +182,3 @@ bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
}
-
-#if !defined(FOR_DYLD) && _LIBUNWIND_BUILD_SJLJ_APIS
-
-#include <System/pthread_machdep.h>
-
-// Accessors to get get/set linked list of frames for sjlj based execeptions.
-_LIBUNWIND_HIDDEN
-struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
- return (struct _Unwind_FunctionContext *)
- _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
-}
-
-_LIBUNWIND_HIDDEN
-void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
- _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
-}
-#endif
-
-
-
-
diff --git a/src/assembly.h b/src/assembly.h
index f46a24d0eed9..2df930214fae 100644
--- a/src/assembly.h
+++ b/src/assembly.h
@@ -16,7 +16,20 @@
#ifndef UNWIND_ASSEMBLY_H
#define UNWIND_ASSEMBLY_H
-#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#if defined(__powerpc64__)
+#define SEPARATOR ;
+#define PPC64_OFFS_SRR0 0
+#define PPC64_OFFS_CR 272
+#define PPC64_OFFS_XER 280
+#define PPC64_OFFS_LR 288
+#define PPC64_OFFS_CTR 296
+#define PPC64_OFFS_VRSAVE 304
+#define PPC64_OFFS_FP 312
+#define PPC64_OFFS_V 824
+#ifdef _ARCH_PWR8
+#define PPC64_HAS_VMX
+#endif
+#elif defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
#define SEPARATOR @
#elif defined(__arm64__)
#define SEPARATOR %%
@@ -24,40 +37,71 @@
#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)
#if defined(__APPLE__)
+
#define SYMBOL_IS_FUNC(name)
+#define EXPORT_SYMBOL(name)
+#define HIDDEN_SYMBOL(name) .private_extern name
+#define NO_EXEC_STACK_DIRECTIVE
+
#elif defined(__ELF__)
+
#if defined(__arm__)
#define SYMBOL_IS_FUNC(name) .type name,%function
#else
#define SYMBOL_IS_FUNC(name) .type name,@function
#endif
+#define EXPORT_SYMBOL(name)
+#define HIDDEN_SYMBOL(name) .hidden name
+
+#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
+
+#elif defined(_WIN32)
+
#define SYMBOL_IS_FUNC(name) \
.def name SEPARATOR \
.scl 2 SEPARATOR \
.type 32 SEPARATOR \
.endef
+#define EXPORT_SYMBOL2(name) \
+ .section .drectve,"yn" SEPARATOR \
+ .ascii "-export:", #name, "\0" SEPARATOR \
+ .text
+#if defined(_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS)
+#define EXPORT_SYMBOL(name)
+#else
+#define EXPORT_SYMBOL(name) EXPORT_SYMBOL2(name)
+#endif
+#define HIDDEN_SYMBOL(name)
+
+#define NO_EXEC_STACK_DIRECTIVE
+
+#elif defined(__sparc__)
+
+#else
+
+#error Unsupported target
+
#endif
#define DEFINE_LIBUNWIND_FUNCTION(name) \
.globl SYMBOL_NAME(name) SEPARATOR \
+ EXPORT_SYMBOL(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
SYMBOL_NAME(name):
#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 a50222f7c90d..fc7fd646707e 100644
--- a/src/config.h
+++ b/src/config.h
@@ -6,7 +6,7 @@
// Source Licenses. See LICENSE.TXT for details.
//
//
-// Defines macros used within libuwind project.
+// Defines macros used within libunwind project.
//
//===----------------------------------------------------------------------===//
@@ -16,6 +16,7 @@
#include <assert.h>
#include <stdio.h>
+#include <stdint.h>
#include <stdlib.h>
// Define static_assert() unless already defined by compiler.
@@ -31,51 +32,65 @@
// Platform specific configuration defines.
#ifdef __APPLE__
#if defined(FOR_DYLD)
- #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
- #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
- #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
#else
- #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
- #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
+ #endif
+#elif defined(_WIN32)
+ #ifdef __SEH__
+ #define _LIBUNWIND_SUPPORT_SEH_UNWIND 1
+ #else
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#endif
#else
#if defined(__ARM_DWARF_EH__) || !defined(__arm__)
- #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
#define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
#define _LIBUNWIND_SUPPORT_DWARF_INDEX 1
- #else
- #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
- #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
- #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
#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 1
-#else
-#define _LIBUNWIND_BUILD_SJLJ_APIS 0
+#define _LIBUNWIND_BUILD_SJLJ_APIS
#endif
-#if defined(__i386__) || defined(__x86_64__)
-#define _LIBUNWIND_SUPPORT_FRAME_APIS 1
-#else
-#define _LIBUNWIND_SUPPORT_FRAME_APIS 0
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
+#define _LIBUNWIND_SUPPORT_FRAME_APIS
#endif
#if defined(__i386__) || defined(__x86_64__) || \
+ defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) || \
(!defined(__APPLE__) && defined(__arm__)) || \
(defined(__arm64__) || defined(__aarch64__)) || \
- (defined(__APPLE__) && defined(__mips__))
-#define _LIBUNWIND_BUILD_ZERO_COST_APIS 1
-#else
-#define _LIBUNWIND_BUILD_ZERO_COST_APIS 0
+ defined(__mips__)
+#if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
+#define _LIBUNWIND_BUILD_ZERO_COST_APIS
+#endif
+#endif
+
+#if defined(__powerpc64__) && defined(_ARCH_PWR8)
+#define PPC64_HAS_VMX
#endif
+#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
+#define _LIBUNWIND_ABORT(msg) \
+ do { \
+ abort(); \
+ } while (0)
+#else
#define _LIBUNWIND_ABORT(msg) \
do { \
fprintf(stderr, "libunwind: %s %s:%d - %s\n", __func__, __FILE__, \
@@ -83,40 +98,65 @@
fflush(stderr); \
abort(); \
} while (0)
-#define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+#endif
+
+#if defined(NDEBUG) && defined(_LIBUNWIND_IS_BAREMETAL)
+#define _LIBUNWIND_LOG0(msg)
+#define _LIBUNWIND_LOG(msg, ...)
+#else
+#define _LIBUNWIND_LOG0(msg) \
+ fprintf(stderr, "libunwind: " msg "\n")
+#define _LIBUNWIND_LOG(msg, ...) \
+ fprintf(stderr, "libunwind: " msg "\n", __VA_ARGS__)
+#endif
+
+#if defined(NDEBUG)
+ #define _LIBUNWIND_LOG_IF_FALSE(x) x
+#else
+ #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
#ifdef NDEBUG
#define _LIBUNWIND_DEBUG_LOG(msg, ...)
#define _LIBUNWIND_TRACE_API(msg, ...)
- #define _LIBUNWIND_TRACING_UNWINDING 0
+ #define _LIBUNWIND_TRACING_UNWINDING (0)
+ #define _LIBUNWIND_TRACING_DWARF (0)
#define _LIBUNWIND_TRACE_UNWINDING(msg, ...)
- #define _LIBUNWIND_LOG_NON_ZERO(x) x
+ #define _LIBUNWIND_TRACE_DWARF(...)
#else
#ifdef __cplusplus
extern "C" {
#endif
extern bool logAPIs();
extern bool logUnwinding();
+ extern bool logDWARF();
#ifdef __cplusplus
}
#endif
#define _LIBUNWIND_DEBUG_LOG(msg, ...) _LIBUNWIND_LOG(msg, __VA_ARGS__)
- #define _LIBUNWIND_LOG_NON_ZERO(x) \
- do { \
- int _err = x; \
- if ( _err != 0 ) \
- _LIBUNWIND_LOG("" #x "=%d in %s", _err, __FUNCTION__); \
- } while (0)
- #define _LIBUNWIND_TRACE_API(msg, ...) \
- do { \
- if ( logAPIs() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \
- } while(0)
- #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \
- do { \
- if ( logUnwinding() ) _LIBUNWIND_LOG(msg, __VA_ARGS__); \
- } while(0)
+ #define _LIBUNWIND_TRACE_API(msg, ...) \
+ do { \
+ if (logAPIs()) \
+ _LIBUNWIND_LOG(msg, __VA_ARGS__); \
+ } while (0)
#define _LIBUNWIND_TRACING_UNWINDING logUnwinding()
+ #define _LIBUNWIND_TRACING_DWARF logDWARF()
+ #define _LIBUNWIND_TRACE_UNWINDING(msg, ...) \
+ do { \
+ if (logUnwinding()) \
+ _LIBUNWIND_LOG(msg, __VA_ARGS__); \
+ } while (0)
+ #define _LIBUNWIND_TRACE_DWARF(...) \
+ do { \
+ if (logDWARF()) \
+ fprintf(stderr, __VA_ARGS__); \
+ } while (0)
#endif
#ifdef __cplusplus
@@ -125,7 +165,7 @@
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
# define COMP_OP ==
#else
-# define COMP_OP <
+# define COMP_OP <=
#endif
template <typename _Type, typename _Mem>
struct check_fit {
diff --git a/src/dwarf2.h b/src/dwarf2.h
index 0dcd2ca99bab..58525eea044e 100644
--- a/src/dwarf2.h
+++ b/src/dwarf2.h
@@ -49,7 +49,10 @@ enum {
// GNU extensions
DW_CFA_GNU_window_save = 0x2D,
DW_CFA_GNU_args_size = 0x2E,
- DW_CFA_GNU_negative_offset_extended = 0x2F
+ DW_CFA_GNU_negative_offset_extended = 0x2F,
+
+ // AARCH64 extensions
+ DW_CFA_AARCH64_negate_ra_state = 0x2D
};
diff --git a/src/libunwind.cpp b/src/libunwind.cpp
index 95f2dc020dc4..f4d71a1863bf 100644
--- a/src/libunwind.cpp
+++ b/src/libunwind.cpp
@@ -1,4 +1,4 @@
-//===--------------------------- libuwind.cpp -----------------------------===//
+//===--------------------------- libunwind.cpp ----------------------------===//
//
// The LLVM Compiler Infrastructure
//
@@ -24,6 +24,8 @@
#include <stdlib.h>
+#if !defined(__USING_SJLJ_EXCEPTIONS__)
+#include "AddressSpace.hpp"
#include "UnwindCursor.hpp"
using namespace libunwind;
@@ -42,23 +44,31 @@ extern int unw_getcontext(unw_context_t *);
/// unw_getcontext().
_LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
unw_context_t *context) {
- _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n",
+ _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)",
static_cast<void *>(cursor),
static_cast<void *>(context));
#if defined(__i386__)
# define REGISTER_KIND Registers_x86
#elif defined(__x86_64__)
# define REGISTER_KIND Registers_x86_64
+#elif defined(__powerpc64__)
+# define REGISTER_KIND Registers_ppc64
#elif defined(__ppc__)
# define REGISTER_KIND Registers_ppc
#elif defined(__aarch64__)
# define REGISTER_KIND Registers_arm64
-#elif _LIBUNWIND_ARM_EHABI
+#elif defined(__arm__)
# define REGISTER_KIND Registers_arm
#elif defined(__or1k__)
# define REGISTER_KIND Registers_or1k
+#elif defined(__mips__) && defined(_ABIO32) && _MIPS_SIM == _ABIO32
+# define REGISTER_KIND Registers_mips_o32
+#elif defined(__mips64)
+# define REGISTER_KIND Registers_mips_newabi
#elif defined(__mips__)
-# warning The MIPS architecture is not supported.
+# warning The MIPS architecture is not supported with this ABI and environment!
+#elif defined(__sparc__)
+# define REGISTER_KIND Registers_sparc
#else
# error Architecture not supported
#endif
@@ -85,18 +95,18 @@ _LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
switch (as->cpuType) {
case CPU_TYPE_I386:
new ((void *)cursor)
- UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >,
+ UnwindCursor<RemoteAddressSpace<Pointer32<LittleEndian>>,
Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
break;
case CPU_TYPE_X86_64:
- new ((void *)cursor) UnwindCursor<
- OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(
- ((unw_addr_space_x86_64 *)as)->oas, arg);
+ new ((void *)cursor)
+ UnwindCursor<RemoteAddressSpace<Pointer64<LittleEndian>>,
+ Registers_x86_64>(((unw_addr_space_x86_64 *)as)->oas, arg);
break;
case CPU_TYPE_POWERPC:
new ((void *)cursor)
- UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>(
- ((unw_addr_space_ppc *)as)->oas, arg);
+ UnwindCursor<RemoteAddressSpace<Pointer32<BigEndian>>,
+ Registers_ppc>(((unw_addr_space_ppc *)as)->oas, arg);
break;
default:
return UNW_EUNSPEC;
@@ -157,7 +167,7 @@ _LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
/// Get value of specified register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_word_t *value) {
- _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n",
+ _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)",
static_cast<void *>(cursor), regNum,
static_cast<void *>(value));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
@@ -172,16 +182,28 @@ _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)\n",
- 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)) {
co->setReg(regNum, (pint_t)value);
// specical case altering IP to re-find info (being called by personality
// function)
- if (regNum == UNW_REG_IP)
+ if (regNum == UNW_REG_IP) {
+ unw_proc_info_t info;
+ // First, get the FDE for the old location and then update it.
+ co->getInfo(&info);
co->setInfoBasedOnIPRegister(false);
+ // If the original call expects stack adjustment, perform this now.
+ // Normal frame unwinding would have included the offset already in the
+ // CFA computation.
+ // Note: for PA-RISC and other platforms where the stack grows up,
+ // this should actually be - info.gp. LLVM doesn't currently support
+ // any such platforms and Clang doesn't export a macro for them.
+ if (info.gp)
+ co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + info.gp);
+ }
return UNW_ESUCCESS;
}
return UNW_EBADREG;
@@ -191,7 +213,7 @@ _LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
/// Get value of specified float register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_fpreg_t *value) {
- _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n",
+ _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)",
static_cast<void *>(cursor), regNum,
static_cast<void *>(value));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
@@ -206,11 +228,11 @@ _LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
/// Set value of specified float register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
unw_fpreg_t value) {
-#if _LIBUNWIND_ARM_EHABI
- _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)\n",
+#if defined(_LIBUNWIND_ARM_EHABI)
+ _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)",
static_cast<void *>(cursor), regNum, value);
#else
- _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n",
+ _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)",
static_cast<void *>(cursor), regNum, value);
#endif
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
@@ -224,7 +246,7 @@ _LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
/// Move cursor to next frame.
_LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
- _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", static_cast<void *>(cursor));
+ _LIBUNWIND_TRACE_API("unw_step(cursor=%p)", static_cast<void *>(cursor));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
return co->step();
}
@@ -233,7 +255,7 @@ _LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
/// Get unwind info at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
unw_proc_info_t *info) {
- _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n",
+ _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)",
static_cast<void *>(cursor), static_cast<void *>(info));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
co->getInfo(info);
@@ -246,7 +268,7 @@ _LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
/// Resume execution at cursor position (aka longjump).
_LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
- _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", static_cast<void *>(cursor));
+ _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)", static_cast<void *>(cursor));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
co->jumpto();
return UNW_EUNSPEC;
@@ -256,7 +278,7 @@ _LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
/// Get name of function at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
size_t bufLen, unw_word_t *offset) {
- _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)\n",
+ _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p, bufLen=%lu)",
static_cast<void *>(cursor), static_cast<void *>(buf),
static_cast<unsigned long>(bufLen));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
@@ -269,7 +291,7 @@ _LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
/// Checks if a register is a floating-point register.
_LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
- _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n",
+ _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)",
static_cast<void *>(cursor), regNum);
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
return co->validFloatReg(regNum);
@@ -279,7 +301,7 @@ _LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
/// Checks if a register is a floating-point register.
_LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
unw_regnum_t regNum) {
- _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n",
+ _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)",
static_cast<void *>(cursor), regNum);
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
return co->getRegisterName(regNum);
@@ -288,7 +310,7 @@ _LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
/// Checks if current frame is signal trampoline.
_LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
- _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n",
+ _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)",
static_cast<void *>(cursor));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
return co->isSignalFrame();
@@ -297,7 +319,7 @@ _LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
#ifdef __arm__
// Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD
_LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) {
- _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)\n",
+ _LIBUNWIND_TRACE_API("unw_fpreg_save_vfp_as_X(cursor=%p)",
static_cast<void *>(cursor));
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
return co->saveVFPAsX();
@@ -305,11 +327,11 @@ _LIBUNWIND_EXPORT void unw_save_vfp_as_X(unw_cursor_t *cursor) {
#endif
-#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
-/// SPI: walks cached dwarf entries
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+/// SPI: walks cached DWARF entries
_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
- _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n",
+ _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)",
reinterpret_cast<void *>(func));
DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
}
@@ -339,7 +361,8 @@ void _unw_remove_dynamic_fde(unw_word_t fde) {
// fde is own mh_group
DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
}
-#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+#endif // !defined(__USING_SJLJ_EXCEPTIONS__)
@@ -371,5 +394,17 @@ bool logUnwinding() {
return log;
}
+_LIBUNWIND_HIDDEN
+bool logDWARF() {
+ // do manual lock to avoid use of _cxa_guard_acquire or initializers
+ static bool checked = false;
+ static bool log = false;
+ if (!checked) {
+ log = (getenv("LIBUNWIND_PRINT_DWARF") != NULL);
+ checked = true;
+ }
+ return log;
+}
+
#endif // NDEBUG
diff --git a/src/libunwind_ext.h b/src/libunwind_ext.h
index 72dbf5851a8a..ec645a846739 100644
--- a/src/libunwind_ext.h
+++ b/src/libunwind_ext.h
@@ -33,7 +33,7 @@ extern void unw_iterate_dwarf_unwind_cache(void (*func)(unw_word_t ip_start,
extern void _unw_add_dynamic_fde(unw_word_t fde);
extern void _unw_remove_dynamic_fde(unw_word_t fde);
-#if _LIBUNWIND_ARM_EHABI
+#if defined(_LIBUNWIND_ARM_EHABI)
extern const uint32_t* decode_eht_entry(const uint32_t*, size_t*, size_t*);
extern _Unwind_Reason_Code _Unwind_VRS_Interpret(_Unwind_Context *context,
const uint32_t *data,
diff --git a/src/unwind_ext.h b/src/unwind_ext.h
deleted file mode 100644
index c40ce6a1610f..000000000000
--- 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__
-
-