summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaleem Abdulrasool <compnerd@compnerd.org>2015-04-24 19:39:17 +0000
committerSaleem Abdulrasool <compnerd@compnerd.org>2015-04-24 19:39:17 +0000
commitb1b1911777d3516fab27ce1461fdc39fe372bf6f (patch)
tree08e05b7d3cac64b47f40748770e11abaf6fef95b
parentcb6b6f7e20bc169cdf6d768f740f8efae66edc8b (diff)
downloadbcm5719-llvm-b1b1911777d3516fab27ce1461fdc39fe372bf6f.tar.gz
bcm5719-llvm-b1b1911777d3516fab27ce1461fdc39fe372bf6f.zip
unwind: move src/Unwind, include/, and test/ unwind content
This moves the majority of the unwind sources into the new project layout for libunwind. This was previously discussed on llvmdev at [1]. This is a purely movement related change, with the build infrastructure currently still residing in the libc++abi repository. [1] http://lists.cs.uiuc.edu/pipermail/llvmdev/2015-January/081507.html llvm-svn: 235758
-rw-r--r--libunwind/include/libunwind.h500
-rw-r--r--libunwind/include/mach-o/compact_unwind_encoding.h478
-rw-r--r--libunwind/include/unwind.h329
-rw-r--r--libunwind/src/AddressSpace.hpp579
-rw-r--r--libunwind/src/CMakeLists.txt118
-rw-r--r--libunwind/src/CompactUnwinder.hpp693
-rw-r--r--libunwind/src/DwarfInstructions.hpp760
-rw-r--r--libunwind/src/DwarfParser.hpp724
-rw-r--r--libunwind/src/EHHeaderParser.hpp161
-rw-r--r--libunwind/src/Registers.hpp1718
-rw-r--r--libunwind/src/Unwind-EHABI.cpp994
-rw-r--r--libunwind/src/Unwind-EHABI.h51
-rw-r--r--libunwind/src/Unwind-sjlj.c468
-rw-r--r--libunwind/src/UnwindCursor.hpp1317
-rw-r--r--libunwind/src/UnwindLevel1-gcc-ext.c327
-rw-r--r--libunwind/src/UnwindLevel1.c534
-rw-r--r--libunwind/src/UnwindRegistersRestore.S430
-rw-r--r--libunwind/src/UnwindRegistersSave.S416
-rw-r--r--libunwind/src/Unwind_AppleExtras.cpp205
-rw-r--r--libunwind/src/assembly.h80
-rw-r--r--libunwind/src/config.h126
-rw-r--r--libunwind/src/dwarf2.h237
-rw-r--r--libunwind/src/libunwind.cpp373
-rw-r--r--libunwind/src/libunwind_ext.h47
-rw-r--r--libunwind/src/unwind_ext.h37
-rw-r--r--libunwind/test/unwind_01.pass.cpp96
-rw-r--r--libunwind/test/unwind_02.pass.cpp96
-rw-r--r--libunwind/test/unwind_03.pass.cpp102
-rw-r--r--libunwind/test/unwind_04.pass.cpp108
-rw-r--r--libunwind/test/unwind_05.pass.cpp112
-rw-r--r--libunwind/test/unwind_06.pass.cpp257
31 files changed, 12473 insertions, 0 deletions
diff --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
new file mode 100644
index 00000000000..e2396e4ab7c
--- /dev/null
+++ b/libunwind/include/libunwind.h
@@ -0,0 +1,500 @@
+//===---------------------------- libunwind.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.
+//
+//
+// Compatible with libuwind API documented at:
+// http://www.nongnu.org/libunwind/man/libunwind(3).html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND__
+#define __LIBUNWIND__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#include <__cxxabi_config.h>
+
+#ifdef __APPLE__
+ #include <Availability.h>
+ #ifdef __arm__
+ #define LIBUNWIND_AVAIL __attribute__((unavailable))
+ #else
+ #define LIBUNWIND_AVAIL __OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_5_0)
+ #endif
+#else
+ #define LIBUNWIND_AVAIL
+#endif
+
+/* error codes */
+enum {
+ UNW_ESUCCESS = 0, /* no error */
+ UNW_EUNSPEC = -6540, /* unspecified (general) error */
+ UNW_ENOMEM = -6541, /* out of memory */
+ UNW_EBADREG = -6542, /* bad register number */
+ UNW_EREADONLYREG = -6543, /* attempt to write read-only register */
+ UNW_ESTOPUNWIND = -6544, /* stop unwinding */
+ UNW_EINVALIDIP = -6545, /* invalid IP */
+ UNW_EBADFRAME = -6546, /* bad frame */
+ UNW_EINVAL = -6547, /* unsupported operation or bad value */
+ UNW_EBADVERSION = -6548, /* unwind info has unsupported version */
+ UNW_ENOINFO = -6549 /* no unwind info found */
+};
+
+struct unw_context_t {
+ uint64_t data[128];
+};
+typedef struct unw_context_t unw_context_t;
+
+struct unw_cursor_t {
+ uint64_t data[140];
+};
+typedef struct unw_cursor_t unw_cursor_t;
+
+typedef struct unw_addr_space *unw_addr_space_t;
+
+typedef int unw_regnum_t;
+#if LIBCXXABI_ARM_EHABI
+typedef uint32_t unw_word_t;
+typedef uint64_t unw_fpreg_t;
+#else
+typedef uint64_t unw_word_t;
+typedef double unw_fpreg_t;
+#endif
+
+struct unw_proc_info_t {
+ unw_word_t start_ip; /* start address of function */
+ unw_word_t end_ip; /* address after end of function */
+ unw_word_t lsda; /* address of language specific data area, */
+ /* or zero if not used */
+ unw_word_t handler; /* personality routine, or zero if not used */
+ 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 */
+ unw_word_t extra; /* mach_header of mach-o image containing func */
+};
+typedef struct unw_proc_info_t unw_proc_info_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int unw_getcontext(unw_context_t *) LIBUNWIND_AVAIL;
+extern int unw_init_local(unw_cursor_t *, unw_context_t *) LIBUNWIND_AVAIL;
+extern int unw_step(unw_cursor_t *) LIBUNWIND_AVAIL;
+extern int unw_get_reg(unw_cursor_t *, unw_regnum_t, unw_word_t *) LIBUNWIND_AVAIL;
+extern int unw_get_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t *) LIBUNWIND_AVAIL;
+extern int unw_set_reg(unw_cursor_t *, unw_regnum_t, unw_word_t) LIBUNWIND_AVAIL;
+extern int unw_set_fpreg(unw_cursor_t *, unw_regnum_t, unw_fpreg_t) LIBUNWIND_AVAIL;
+extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;
+
+#ifdef __arm__
+/* Save VFP registers in FSTMX format (instead of FSTMD). */
+extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL;
+#endif
+
+
+extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
+extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL;
+extern int unw_is_fpreg(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
+extern int unw_is_signal_frame(unw_cursor_t *) LIBUNWIND_AVAIL;
+extern int unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *) LIBUNWIND_AVAIL;
+//extern int unw_get_save_loc(unw_cursor_t*, int, unw_save_loc_t*);
+
+extern unw_addr_space_t unw_local_addr_space;
+
+#ifdef UNW_REMOTE
+/*
+ * Mac OS X "remote" API for unwinding other processes on same machine
+ *
+ */
+extern unw_addr_space_t unw_create_addr_space_for_task(task_t);
+extern void unw_destroy_addr_space(unw_addr_space_t);
+extern int unw_init_remote_thread(unw_cursor_t *, unw_addr_space_t, thread_t *);
+#endif /* UNW_REMOTE */
+
+/*
+ * traditional libuwind "remote" API
+ * NOT IMPLEMENTED on Mac OS X
+ *
+ * extern int unw_init_remote(unw_cursor_t*, unw_addr_space_t,
+ * thread_t*);
+ * extern unw_accessors_t unw_get_accessors(unw_addr_space_t);
+ * extern unw_addr_space_t unw_create_addr_space(unw_accessors_t, int);
+ * extern void unw_flush_cache(unw_addr_space_t, unw_word_t,
+ * unw_word_t);
+ * extern int unw_set_caching_policy(unw_addr_space_t,
+ * unw_caching_policy_t);
+ * extern void _U_dyn_register(unw_dyn_info_t*);
+ * extern void _U_dyn_cancel(unw_dyn_info_t*);
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+// architecture independent register numbers
+enum {
+ UNW_REG_IP = -1, // instruction pointer
+ UNW_REG_SP = -2, // stack pointer
+};
+
+// 32-bit x86 registers
+enum {
+ UNW_X86_EAX = 0,
+ UNW_X86_ECX = 1,
+ UNW_X86_EDX = 2,
+ UNW_X86_EBX = 3,
+ UNW_X86_EBP = 4,
+ UNW_X86_ESP = 5,
+ UNW_X86_ESI = 6,
+ UNW_X86_EDI = 7
+};
+
+// 64-bit x86_64 registers
+enum {
+ UNW_X86_64_RAX = 0,
+ UNW_X86_64_RDX = 1,
+ UNW_X86_64_RCX = 2,
+ UNW_X86_64_RBX = 3,
+ UNW_X86_64_RSI = 4,
+ UNW_X86_64_RDI = 5,
+ UNW_X86_64_RBP = 6,
+ UNW_X86_64_RSP = 7,
+ UNW_X86_64_R8 = 8,
+ UNW_X86_64_R9 = 9,
+ UNW_X86_64_R10 = 10,
+ UNW_X86_64_R11 = 11,
+ UNW_X86_64_R12 = 12,
+ UNW_X86_64_R13 = 13,
+ UNW_X86_64_R14 = 14,
+ UNW_X86_64_R15 = 15
+};
+
+
+// 32-bit ppc register numbers
+enum {
+ UNW_PPC_R0 = 0,
+ UNW_PPC_R1 = 1,
+ UNW_PPC_R2 = 2,
+ UNW_PPC_R3 = 3,
+ UNW_PPC_R4 = 4,
+ UNW_PPC_R5 = 5,
+ UNW_PPC_R6 = 6,
+ UNW_PPC_R7 = 7,
+ UNW_PPC_R8 = 8,
+ UNW_PPC_R9 = 9,
+ UNW_PPC_R10 = 10,
+ UNW_PPC_R11 = 11,
+ UNW_PPC_R12 = 12,
+ UNW_PPC_R13 = 13,
+ UNW_PPC_R14 = 14,
+ UNW_PPC_R15 = 15,
+ UNW_PPC_R16 = 16,
+ UNW_PPC_R17 = 17,
+ UNW_PPC_R18 = 18,
+ UNW_PPC_R19 = 19,
+ UNW_PPC_R20 = 20,
+ UNW_PPC_R21 = 21,
+ UNW_PPC_R22 = 22,
+ UNW_PPC_R23 = 23,
+ UNW_PPC_R24 = 24,
+ UNW_PPC_R25 = 25,
+ UNW_PPC_R26 = 26,
+ UNW_PPC_R27 = 27,
+ UNW_PPC_R28 = 28,
+ UNW_PPC_R29 = 29,
+ UNW_PPC_R30 = 30,
+ UNW_PPC_R31 = 31,
+ UNW_PPC_F0 = 32,
+ UNW_PPC_F1 = 33,
+ UNW_PPC_F2 = 34,
+ UNW_PPC_F3 = 35,
+ UNW_PPC_F4 = 36,
+ UNW_PPC_F5 = 37,
+ UNW_PPC_F6 = 38,
+ UNW_PPC_F7 = 39,
+ UNW_PPC_F8 = 40,
+ UNW_PPC_F9 = 41,
+ UNW_PPC_F10 = 42,
+ UNW_PPC_F11 = 43,
+ UNW_PPC_F12 = 44,
+ UNW_PPC_F13 = 45,
+ UNW_PPC_F14 = 46,
+ UNW_PPC_F15 = 47,
+ UNW_PPC_F16 = 48,
+ UNW_PPC_F17 = 49,
+ UNW_PPC_F18 = 50,
+ UNW_PPC_F19 = 51,
+ UNW_PPC_F20 = 52,
+ UNW_PPC_F21 = 53,
+ UNW_PPC_F22 = 54,
+ UNW_PPC_F23 = 55,
+ UNW_PPC_F24 = 56,
+ UNW_PPC_F25 = 57,
+ UNW_PPC_F26 = 58,
+ UNW_PPC_F27 = 59,
+ UNW_PPC_F28 = 60,
+ UNW_PPC_F29 = 61,
+ UNW_PPC_F30 = 62,
+ UNW_PPC_F31 = 63,
+ UNW_PPC_MQ = 64,
+ UNW_PPC_LR = 65,
+ UNW_PPC_CTR = 66,
+ UNW_PPC_AP = 67,
+ UNW_PPC_CR0 = 68,
+ UNW_PPC_CR1 = 69,
+ UNW_PPC_CR2 = 70,
+ UNW_PPC_CR3 = 71,
+ UNW_PPC_CR4 = 72,
+ UNW_PPC_CR5 = 73,
+ UNW_PPC_CR6 = 74,
+ UNW_PPC_CR7 = 75,
+ UNW_PPC_XER = 76,
+ UNW_PPC_V0 = 77,
+ UNW_PPC_V1 = 78,
+ UNW_PPC_V2 = 79,
+ UNW_PPC_V3 = 80,
+ UNW_PPC_V4 = 81,
+ UNW_PPC_V5 = 82,
+ UNW_PPC_V6 = 83,
+ UNW_PPC_V7 = 84,
+ UNW_PPC_V8 = 85,
+ UNW_PPC_V9 = 86,
+ UNW_PPC_V10 = 87,
+ UNW_PPC_V11 = 88,
+ UNW_PPC_V12 = 89,
+ UNW_PPC_V13 = 90,
+ UNW_PPC_V14 = 91,
+ UNW_PPC_V15 = 92,
+ UNW_PPC_V16 = 93,
+ UNW_PPC_V17 = 94,
+ UNW_PPC_V18 = 95,
+ UNW_PPC_V19 = 96,
+ UNW_PPC_V20 = 97,
+ UNW_PPC_V21 = 98,
+ UNW_PPC_V22 = 99,
+ UNW_PPC_V23 = 100,
+ UNW_PPC_V24 = 101,
+ UNW_PPC_V25 = 102,
+ UNW_PPC_V26 = 103,
+ UNW_PPC_V27 = 104,
+ UNW_PPC_V28 = 105,
+ UNW_PPC_V29 = 106,
+ UNW_PPC_V30 = 107,
+ UNW_PPC_V31 = 108,
+ UNW_PPC_VRSAVE = 109,
+ UNW_PPC_VSCR = 110,
+ UNW_PPC_SPE_ACC = 111,
+ UNW_PPC_SPEFSCR = 112
+};
+
+// 64-bit ARM64 registers
+enum {
+ UNW_ARM64_X0 = 0,
+ UNW_ARM64_X1 = 1,
+ UNW_ARM64_X2 = 2,
+ UNW_ARM64_X3 = 3,
+ UNW_ARM64_X4 = 4,
+ UNW_ARM64_X5 = 5,
+ UNW_ARM64_X6 = 6,
+ UNW_ARM64_X7 = 7,
+ UNW_ARM64_X8 = 8,
+ UNW_ARM64_X9 = 9,
+ UNW_ARM64_X10 = 10,
+ UNW_ARM64_X11 = 11,
+ UNW_ARM64_X12 = 12,
+ UNW_ARM64_X13 = 13,
+ UNW_ARM64_X14 = 14,
+ UNW_ARM64_X15 = 15,
+ UNW_ARM64_X16 = 16,
+ UNW_ARM64_X17 = 17,
+ UNW_ARM64_X18 = 18,
+ UNW_ARM64_X19 = 19,
+ UNW_ARM64_X20 = 20,
+ UNW_ARM64_X21 = 21,
+ UNW_ARM64_X22 = 22,
+ UNW_ARM64_X23 = 23,
+ UNW_ARM64_X24 = 24,
+ UNW_ARM64_X25 = 25,
+ UNW_ARM64_X26 = 26,
+ UNW_ARM64_X27 = 27,
+ UNW_ARM64_X28 = 28,
+ UNW_ARM64_X29 = 29,
+ UNW_ARM64_FP = 29,
+ UNW_ARM64_X30 = 30,
+ UNW_ARM64_LR = 30,
+ UNW_ARM64_X31 = 31,
+ UNW_ARM64_SP = 31,
+ // reserved block
+ UNW_ARM64_D0 = 64,
+ UNW_ARM64_D1 = 65,
+ UNW_ARM64_D2 = 66,
+ UNW_ARM64_D3 = 67,
+ UNW_ARM64_D4 = 68,
+ UNW_ARM64_D5 = 69,
+ UNW_ARM64_D6 = 70,
+ UNW_ARM64_D7 = 71,
+ UNW_ARM64_D8 = 72,
+ UNW_ARM64_D9 = 73,
+ UNW_ARM64_D10 = 74,
+ UNW_ARM64_D11 = 75,
+ UNW_ARM64_D12 = 76,
+ UNW_ARM64_D13 = 77,
+ UNW_ARM64_D14 = 78,
+ UNW_ARM64_D15 = 79,
+ UNW_ARM64_D16 = 80,
+ UNW_ARM64_D17 = 81,
+ UNW_ARM64_D18 = 82,
+ UNW_ARM64_D19 = 83,
+ UNW_ARM64_D20 = 84,
+ UNW_ARM64_D21 = 85,
+ UNW_ARM64_D22 = 86,
+ UNW_ARM64_D23 = 87,
+ UNW_ARM64_D24 = 88,
+ UNW_ARM64_D25 = 89,
+ UNW_ARM64_D26 = 90,
+ UNW_ARM64_D27 = 91,
+ UNW_ARM64_D28 = 92,
+ UNW_ARM64_D29 = 93,
+ UNW_ARM64_D30 = 94,
+ UNW_ARM64_D31 = 95,
+};
+
+// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1.
+// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3.
+// In this scheme, even though the 64-bit floating point registers D0-D31
+// overlap physically with the 32-bit floating pointer registers S0-S31,
+// they are given a non-overlapping range of register numbers.
+//
+// Commented out ranges are not preserved during unwinding.
+enum {
+ UNW_ARM_R0 = 0,
+ UNW_ARM_R1 = 1,
+ UNW_ARM_R2 = 2,
+ UNW_ARM_R3 = 3,
+ UNW_ARM_R4 = 4,
+ UNW_ARM_R5 = 5,
+ UNW_ARM_R6 = 6,
+ UNW_ARM_R7 = 7,
+ UNW_ARM_R8 = 8,
+ UNW_ARM_R9 = 9,
+ UNW_ARM_R10 = 10,
+ UNW_ARM_R11 = 11,
+ UNW_ARM_R12 = 12,
+ UNW_ARM_SP = 13, // Logical alias for UNW_REG_SP
+ UNW_ARM_R13 = 13,
+ UNW_ARM_LR = 14,
+ UNW_ARM_R14 = 14,
+ UNW_ARM_IP = 15, // Logical alias for UNW_REG_IP
+ UNW_ARM_R15 = 15,
+ // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31.
+ UNW_ARM_S0 = 64,
+ UNW_ARM_S1 = 65,
+ UNW_ARM_S2 = 66,
+ UNW_ARM_S3 = 67,
+ UNW_ARM_S4 = 68,
+ UNW_ARM_S5 = 69,
+ UNW_ARM_S6 = 70,
+ UNW_ARM_S7 = 71,
+ UNW_ARM_S8 = 72,
+ UNW_ARM_S9 = 73,
+ UNW_ARM_S10 = 74,
+ UNW_ARM_S11 = 75,
+ UNW_ARM_S12 = 76,
+ UNW_ARM_S13 = 77,
+ UNW_ARM_S14 = 78,
+ UNW_ARM_S15 = 79,
+ UNW_ARM_S16 = 80,
+ UNW_ARM_S17 = 81,
+ UNW_ARM_S18 = 82,
+ UNW_ARM_S19 = 83,
+ UNW_ARM_S20 = 84,
+ UNW_ARM_S21 = 85,
+ UNW_ARM_S22 = 86,
+ UNW_ARM_S23 = 87,
+ UNW_ARM_S24 = 88,
+ UNW_ARM_S25 = 89,
+ UNW_ARM_S26 = 90,
+ UNW_ARM_S27 = 91,
+ UNW_ARM_S28 = 92,
+ UNW_ARM_S29 = 93,
+ UNW_ARM_S30 = 94,
+ UNW_ARM_S31 = 95,
+ // 96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superseded by VFP.
+ // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX)
+ UNW_ARM_WR0 = 112,
+ UNW_ARM_WR1 = 113,
+ UNW_ARM_WR2 = 114,
+ UNW_ARM_WR3 = 115,
+ UNW_ARM_WR4 = 116,
+ UNW_ARM_WR5 = 117,
+ UNW_ARM_WR6 = 118,
+ UNW_ARM_WR7 = 119,
+ UNW_ARM_WR8 = 120,
+ UNW_ARM_WR9 = 121,
+ UNW_ARM_WR10 = 122,
+ UNW_ARM_WR11 = 123,
+ UNW_ARM_WR12 = 124,
+ UNW_ARM_WR13 = 125,
+ UNW_ARM_WR14 = 126,
+ UNW_ARM_WR15 = 127,
+ // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC}
+ // 134-143 -- Reserved
+ // 144-150 -- R8_USR-R14_USR
+ // 151-157 -- R8_FIQ-R14_FIQ
+ // 158-159 -- R13_IRQ-R14_IRQ
+ // 160-161 -- R13_ABT-R14_ABT
+ // 162-163 -- R13_UND-R14_UND
+ // 164-165 -- R13_SVC-R14_SVC
+ // 166-191 -- Reserved
+ UNW_ARM_WC0 = 192,
+ UNW_ARM_WC1 = 193,
+ UNW_ARM_WC2 = 194,
+ UNW_ARM_WC3 = 195,
+ // 196-199 -- wC4-wC7 (Intel wireless MMX control)
+ // 200-255 -- Reserved
+ UNW_ARM_D0 = 256,
+ UNW_ARM_D1 = 257,
+ UNW_ARM_D2 = 258,
+ UNW_ARM_D3 = 259,
+ UNW_ARM_D4 = 260,
+ UNW_ARM_D5 = 261,
+ UNW_ARM_D6 = 262,
+ UNW_ARM_D7 = 263,
+ UNW_ARM_D8 = 264,
+ UNW_ARM_D9 = 265,
+ UNW_ARM_D10 = 266,
+ UNW_ARM_D11 = 267,
+ UNW_ARM_D12 = 268,
+ UNW_ARM_D13 = 269,
+ UNW_ARM_D14 = 270,
+ UNW_ARM_D15 = 271,
+ UNW_ARM_D16 = 272,
+ UNW_ARM_D17 = 273,
+ UNW_ARM_D18 = 274,
+ UNW_ARM_D19 = 275,
+ UNW_ARM_D20 = 276,
+ UNW_ARM_D21 = 277,
+ UNW_ARM_D22 = 278,
+ UNW_ARM_D23 = 279,
+ UNW_ARM_D24 = 280,
+ UNW_ARM_D25 = 281,
+ UNW_ARM_D26 = 282,
+ UNW_ARM_D27 = 283,
+ UNW_ARM_D28 = 284,
+ UNW_ARM_D29 = 285,
+ UNW_ARM_D30 = 286,
+ UNW_ARM_D31 = 287,
+ // 288-319 -- Reserved for VFP/Neon
+ // 320-8191 -- Reserved
+ // 8192-16383 -- Unspecified vendor co-processor register.
+};
+
+#endif
diff --git a/libunwind/include/mach-o/compact_unwind_encoding.h b/libunwind/include/mach-o/compact_unwind_encoding.h
new file mode 100644
index 00000000000..b71c2c8f5b7
--- /dev/null
+++ b/libunwind/include/mach-o/compact_unwind_encoding.h
@@ -0,0 +1,478 @@
+//===------------------ mach-o/compact_unwind_encoding.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.
+//
+//
+// Darwin's alternative to dwarf based unwind encodings.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef __COMPACT_UNWIND_ENCODING__
+#define __COMPACT_UNWIND_ENCODING__
+
+#include <stdint.h>
+
+//
+// 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.
+//
+// When the linker creates a final linked image, it will create a
+// __TEXT,__unwind_info section. This section is a small and fast way for the
+// 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
+// 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
+// compact unwind info. But that is fragile and no longer done.
+
+
+//
+// The compact unwind endoding is a 32-bit value which encoded in an
+// architecture specific way, which registers to restore from where, and how
+// to unwind out of the function.
+//
+typedef uint32_t compact_unwind_encoding_t;
+
+
+// architecture independent bits
+enum {
+ UNWIND_IS_NOT_FUNCTION_START = 0x80000000,
+ UNWIND_HAS_LSDA = 0x40000000,
+ UNWIND_PERSONALITY_MASK = 0x30000000,
+};
+
+
+
+
+//
+// x86
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 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
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_MODE_MASK = 0x0F000000,
+ UNWIND_X86_MODE_EBP_FRAME = 0x01000000,
+ UNWIND_X86_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_EBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_EBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_REG_NONE = 0,
+ UNWIND_X86_REG_EBX = 1,
+ UNWIND_X86_REG_ECX = 2,
+ UNWIND_X86_REG_EDX = 3,
+ UNWIND_X86_REG_EDI = 4,
+ UNWIND_X86_REG_ESI = 5,
+ UNWIND_X86_REG_EBP = 6,
+};
+
+//
+// For x86 there are four modes for the compact unwind encoding:
+// UNWIND_X86_MODE_EBP_FRAME:
+// EBP based frame where EBP is push on stack immediately after return address,
+// then ESP is moved to EBP. Thus, to unwind ESP is restored with the current
+// EPB value, then EBP is restored by popping off the stack, and the return
+// is done by popping the stack once more into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// in a small range in the stack that starts EBP-4 to EBP-1020. The offset/4
+// is encoded in the UNWIND_X86_EBP_FRAME_OFFSET bits. The registers saved
+// are encoded in the UNWIND_X86_EBP_FRAME_REGISTERS bits as five 3-bit entries.
+// Each entry contains which register to restore.
+// UNWIND_X86_MODE_STACK_IMMD:
+// A "frameless" (EBP not used as frame pointer) function with a small
+// constant stack size. To return, a constant (encoded in the compact
+// unwind encoding) is added to the ESP. Then the return is done by
+// popping the stack into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// on the stack immediately after the return address. The stack_size/4 is
+// encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
+// The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
+// UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+// saved and their order.
+// UNWIND_X86_MODE_STACK_IND:
+// A "frameless" (EBP not used as frame pointer) function large constant
+// stack size. This case is like the previous, except the stack size is too
+// large to encode in the compact unwind encoding. Instead it requires that
+// the function contains "subl $nnnnnnnn,ESP" in its prolog. The compact
+// encoding contains the offset to the nnnnnnnn value in the function in
+// 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.
+// 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
+// function.
+//
+// The permutation encoding is a Lehmer code sequence encoded into a
+// single variable-base number so we can encode the ordering of up to
+// six registers in a 10-bit space.
+//
+// The following is the algorithm used to create the permutation encoding used
+// with frameless stacks. It is passed the number of registers to be saved and
+// an array of the register numbers saved.
+//
+//uint32_t permute_encode(uint32_t registerCount, const uint32_t registers[6])
+//{
+// uint32_t renumregs[6];
+// for (int i=6-registerCount; i < 6; ++i) {
+// int countless = 0;
+// for (int j=6-registerCount; j < i; ++j) {
+// if ( registers[j] < registers[i] )
+// ++countless;
+// }
+// renumregs[i] = registers[i] - countless -1;
+// }
+// uint32_t permutationEncoding = 0;
+// switch ( registerCount ) {
+// case 6:
+// permutationEncoding |= (120*renumregs[0] + 24*renumregs[1]
+// + 6*renumregs[2] + 2*renumregs[3]
+// + renumregs[4]);
+// break;
+// case 5:
+// permutationEncoding |= (120*renumregs[1] + 24*renumregs[2]
+// + 6*renumregs[3] + 2*renumregs[4]
+// + renumregs[5]);
+// break;
+// case 4:
+// permutationEncoding |= (60*renumregs[2] + 12*renumregs[3]
+// + 3*renumregs[4] + renumregs[5]);
+// break;
+// case 3:
+// permutationEncoding |= (20*renumregs[3] + 4*renumregs[4]
+// + renumregs[5]);
+// break;
+// case 2:
+// permutationEncoding |= (5*renumregs[4] + renumregs[5]);
+// break;
+// case 1:
+// permutationEncoding |= (renumregs[5]);
+// break;
+// }
+// return permutationEncoding;
+//}
+//
+
+
+
+
+//
+// x86_64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 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
+// frameless:
+// 8-bits stack size
+// 3-bits stack adjust
+// 3-bits register count
+// 10-bits register permutation
+//
+enum {
+ UNWIND_X86_64_MODE_MASK = 0x0F000000,
+ UNWIND_X86_64_MODE_RBP_FRAME = 0x01000000,
+ UNWIND_X86_64_MODE_STACK_IMMD = 0x02000000,
+ UNWIND_X86_64_MODE_STACK_IND = 0x03000000,
+ UNWIND_X86_64_MODE_DWARF = 0x04000000,
+
+ UNWIND_X86_64_RBP_FRAME_REGISTERS = 0x00007FFF,
+ UNWIND_X86_64_RBP_FRAME_OFFSET = 0x00FF0000,
+
+ UNWIND_X86_64_FRAMELESS_STACK_SIZE = 0x00FF0000,
+ UNWIND_X86_64_FRAMELESS_STACK_ADJUST = 0x0000E000,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT = 0x00001C00,
+ UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION = 0x000003FF,
+
+ UNWIND_X86_64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+
+enum {
+ UNWIND_X86_64_REG_NONE = 0,
+ UNWIND_X86_64_REG_RBX = 1,
+ UNWIND_X86_64_REG_R12 = 2,
+ UNWIND_X86_64_REG_R13 = 3,
+ UNWIND_X86_64_REG_R14 = 4,
+ UNWIND_X86_64_REG_R15 = 5,
+ UNWIND_X86_64_REG_RBP = 6,
+};
+//
+// For x86_64 there are four modes for the compact unwind encoding:
+// UNWIND_X86_64_MODE_RBP_FRAME:
+// RBP based frame where RBP is push on stack immediately after return address,
+// then RSP is moved to RBP. Thus, to unwind RSP is restored with the current
+// EPB value, then RBP is restored by popping off the stack, and the return
+// is done by popping the stack once more into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// in a small range in the stack that starts RBP-8 to RBP-2040. The offset/8
+// is encoded in the UNWIND_X86_64_RBP_FRAME_OFFSET bits. The registers saved
+// are encoded in the UNWIND_X86_64_RBP_FRAME_REGISTERS bits as five 3-bit entries.
+// Each entry contains which register to restore.
+// UNWIND_X86_64_MODE_STACK_IMMD:
+// A "frameless" (RBP not used as frame pointer) function with a small
+// constant stack size. To return, a constant (encoded in the compact
+// unwind encoding) is added to the RSP. Then the return is done by
+// popping the stack into the pc.
+// All non-volatile registers that need to be restored must have been saved
+// on the stack immediately after the return address. The stack_size/8 is
+// encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048).
+// The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
+// UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+// saved and their order.
+// UNWIND_X86_64_MODE_STACK_IND:
+// A "frameless" (RBP not used as frame pointer) function large constant
+// stack size. This case is like the previous, except the stack size is too
+// large to encode in the compact unwind encoding. Instead it requires that
+// the function contains "subq $nnnnnnnn,RSP" in its prolog. The compact
+// encoding contains the offset to the nnnnnnnn value in the function in
+// 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.
+// 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
+// function.
+//
+
+
+// ARM64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 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
+//
+enum {
+ UNWIND_ARM64_MODE_MASK = 0x0F000000,
+ UNWIND_ARM64_MODE_FRAMELESS = 0x02000000,
+ UNWIND_ARM64_MODE_DWARF = 0x03000000,
+ UNWIND_ARM64_MODE_FRAME = 0x04000000,
+
+ UNWIND_ARM64_FRAME_X19_X20_PAIR = 0x00000001,
+ UNWIND_ARM64_FRAME_X21_X22_PAIR = 0x00000002,
+ UNWIND_ARM64_FRAME_X23_X24_PAIR = 0x00000004,
+ UNWIND_ARM64_FRAME_X25_X26_PAIR = 0x00000008,
+ UNWIND_ARM64_FRAME_X27_X28_PAIR = 0x00000010,
+ UNWIND_ARM64_FRAME_D8_D9_PAIR = 0x00000100,
+ UNWIND_ARM64_FRAME_D10_D11_PAIR = 0x00000200,
+ UNWIND_ARM64_FRAME_D12_D13_PAIR = 0x00000400,
+ UNWIND_ARM64_FRAME_D14_D15_PAIR = 0x00000800,
+
+ UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK = 0x00FFF000,
+ UNWIND_ARM64_DWARF_SECTION_OFFSET = 0x00FFFFFF,
+};
+// For arm64 there are three modes for the compact unwind encoding:
+// UNWIND_ARM64_MODE_FRAME:
+// This is a standard arm64 prolog where FP/LR are immediately pushed on the
+// stack, then SP is copied to FP. If there are any non-volatile registers
+// saved, then are copied into the stack frame in pairs in a contiguous
+// range right below the saved FP/LR pair. Any subset of the five X pairs
+// and four D pairs can be saved, but the memory layout must be in register
+// number order.
+// UNWIND_ARM64_MODE_FRAMELESS:
+// A "frameless" leaf function, where FP/LR are not saved. The return address
+// remains in LR throughout the function. If any non-volatile registers
+// are saved, they must be pushed onto the stack before any stack space is
+// allocated for local variables. The stack sized (including any saved
+// non-volatile registers) divided by 16 is encoded in the bits
+// 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.
+// 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
+// function.
+//
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Relocatable Object Files: __LD,__compact_unwind
+//
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// A compiler can generated compact unwind information for a function by adding
+// a "row" to the __LD,__compact_unwind section. This section has the
+// S_ATTR_DEBUG bit set, so the section will be ignored by older linkers.
+// It is removed by the new linker, so never ends up in final executables.
+// This section is a table, initially with one row per function (that needs
+// unwind info). The table columns and some conceptual entries are:
+//
+// range-start pointer to start of function/range
+// range-length
+// compact-unwind-encoding 32-bit encoding
+// personality-function or zero if no personality function
+// lsda or zero if no LSDA data
+//
+// The length and encoding fields are 32-bits. The other are all pointer sized.
+//
+// In x86_64 assembly, these entry would look like:
+//
+// .section __LD,__compact_unwind,regular,debug
+//
+// #compact unwind for _foo
+// .quad _foo
+// .set L1,LfooEnd-_foo
+// .long L1
+// .long 0x01010001
+// .quad 0
+// .quad 0
+//
+// #compact unwind for _bar
+// .quad _bar
+// .set L2,LbarEnd-_bar
+// .long L2
+// .long 0x01020011
+// .quad __gxx_personality
+// .quad except_tab1
+//
+//
+// Notes: There is no need for any labels in the the __compact_unwind section.
+// The use of the .set directive is to force the evaluation of the
+// range-length at assembly time, instead of generating relocations.
+//
+// To support future compiler optimizations where which non-volatile registers
+// are saved changes within a function (e.g. delay saving non-volatiles until
+// necessary), there can by multiple lines in the __compact_unwind table for one
+// function, each with a different (non-overlapping) range and each with
+// different compact unwind encodings that correspond to the non-volatiles
+// 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.
+// The runtime will use which ever is available.
+//
+// Runtime support for compact unwind encodings are only available on 10.6
+// and later. So, the compiler should not generate it when targeting pre-10.6.
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Final Linked Images: __TEXT,__unwind_info
+//
+////////////////////////////////////////////////////////////////////////////////
+
+//
+// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
+// The header of the section contains a coarse index that maps function address
+// to the page (4096 byte block) containing the unwind info for that function.
+//
+
+#define UNWIND_SECTION_VERSION 1
+struct unwind_info_section_header
+{
+ uint32_t version; // UNWIND_SECTION_VERSION
+ uint32_t commonEncodingsArraySectionOffset;
+ uint32_t commonEncodingsArrayCount;
+ uint32_t personalityArraySectionOffset;
+ uint32_t personalityArrayCount;
+ uint32_t indexSectionOffset;
+ uint32_t indexCount;
+ // compact_unwind_encoding_t[]
+ // uint32_t personalities[]
+ // unwind_info_section_header_index_entry[]
+ // unwind_info_section_header_lsda_index_entry[]
+};
+
+struct unwind_info_section_header_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t secondLevelPagesSectionOffset; // section offset to start of regular or compress page
+ uint32_t lsdaIndexArraySectionOffset; // section offset to start of lsda_index array for this range
+};
+
+struct unwind_info_section_header_lsda_index_entry
+{
+ uint32_t functionOffset;
+ uint32_t lsdaOffset;
+};
+
+//
+// There are two kinds of second level index pages: regular and compressed.
+// A compressed page can hold up to 1021 entries, but it cannot be used
+// if too many different encoding types are used. The regular page holds
+// 511 entries.
+//
+
+struct unwind_info_regular_second_level_entry
+{
+ uint32_t functionOffset;
+ compact_unwind_encoding_t encoding;
+};
+
+#define UNWIND_SECOND_LEVEL_REGULAR 2
+struct unwind_info_regular_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_REGULAR
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ // entry array
+};
+
+#define UNWIND_SECOND_LEVEL_COMPRESSED 3
+struct unwind_info_compressed_second_level_page_header
+{
+ uint32_t kind; // UNWIND_SECOND_LEVEL_COMPRESSED
+ uint16_t entryPageOffset;
+ uint16_t entryCount;
+ uint16_t encodingsPageOffset;
+ uint16_t encodingsCount;
+ // 32-bit entry array
+ // encodings array
+};
+
+#define UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) (entry & 0x00FFFFFF)
+#define UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry) ((entry >> 24) & 0xFF)
+
+
+
+#endif
+
diff --git a/libunwind/include/unwind.h b/libunwind/include/unwind.h
new file mode 100644
index 00000000000..86001bbb563
--- /dev/null
+++ b/libunwind/include/unwind.h
@@ -0,0 +1,329 @@
+//===------------------------------- unwind.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.
+//
+//
+// C++ ABI Level 1 ABI documented at:
+// http://mentorembedded.github.io/cxx-abi/abi-eh.html
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_H__
+#define __UNWIND_H__
+
+#include <stdint.h>
+#include <stddef.h>
+
+#if defined(__APPLE__)
+#define LIBUNWIND_UNAVAIL __attribute__ (( unavailable ))
+#else
+#define LIBUNWIND_UNAVAIL
+#endif
+
+#include <__cxxabi_config.h>
+
+typedef enum {
+ _URC_NO_REASON = 0,
+ _URC_OK = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8,
+#if LIBCXXABI_ARM_EHABI
+ _URC_FAILURE = 9
+#endif
+} _Unwind_Reason_Code;
+
+typedef enum {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ _UA_END_OF_STACK = 16 // gcc extension to C++ ABI
+} _Unwind_Action;
+
+typedef struct _Unwind_Context _Unwind_Context; // opaque
+
+#if LIBCXXABI_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;
+/* Undocumented flag for force unwinding. */
+static const _Unwind_State _US_FORCE_UNWIND = 8;
+
+typedef uint32_t _Unwind_EHT_Header;
+
+struct _Unwind_Control_Block;
+typedef struct _Unwind_Control_Block _Unwind_Control_Block;
+typedef struct _Unwind_Control_Block _Unwind_Exception; /* Alias */
+
+struct _Unwind_Control_Block {
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code, _Unwind_Control_Block*);
+
+ /* Unwinder cache, private fields for the unwinder's use */
+ struct {
+ uint32_t reserved1; /* init reserved1 to 0, then don't touch */
+ uint32_t reserved2;
+ uint32_t reserved3;
+ uint32_t reserved4;
+ uint32_t reserved5;
+ } unwinder_cache;
+
+ /* Propagation barrier cache (valid after phase 1): */
+ struct {
+ uint32_t sp;
+ uint32_t bitpattern[5];
+ } barrier_cache;
+
+ /* Cleanup cache (preserved over cleanup): */
+ struct {
+ uint32_t bitpattern[4];
+ } cleanup_cache;
+
+ /* Pr cache (for pr's benefit): */
+ struct {
+ uint32_t fnstart; /* function start address */
+ _Unwind_EHT_Header* ehtp; /* pointer to EHT entry header word */
+ uint32_t additional;
+ uint32_t reserved1;
+ } pr_cache;
+
+ long long int :0; /* Enforce the 8-byte alignment */
+};
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+ (_Unwind_State state,
+ _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context);
+
+typedef _Unwind_Reason_Code (*__personality_routine)
+ (_Unwind_State state,
+ _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context);
+#else
+struct _Unwind_Context; // opaque
+struct _Unwind_Exception; // forward declaration
+typedef struct _Unwind_Exception _Unwind_Exception;
+
+struct _Unwind_Exception {
+ uint64_t exception_class;
+ void (*exception_cleanup)(_Unwind_Reason_Code reason,
+ _Unwind_Exception *exc);
+ uintptr_t private_1; // non-zero means forced unwind
+ uintptr_t private_2; // holds sp that phase1 found for phase2 to use
+#ifndef __LP64__
+ // 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.
+ uint32_t reserved[3];
+#endif
+};
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context,
+ void* stop_parameter );
+
+typedef _Unwind_Reason_Code (*__personality_routine)
+ (int version,
+ _Unwind_Action actions,
+ uint64_t exceptionClass,
+ _Unwind_Exception* exceptionObject,
+ struct _Unwind_Context* context);
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// The following are the base functions documented by the C++ ABI
+//
+#ifdef __USING_SJLJ_EXCEPTIONS__
+extern _Unwind_Reason_Code
+ _Unwind_SjLj_RaiseException(_Unwind_Exception *exception_object);
+extern void _Unwind_SjLj_Resume(_Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+ _Unwind_RaiseException(_Unwind_Exception *exception_object);
+extern void _Unwind_Resume(_Unwind_Exception *exception_object);
+#endif
+extern void _Unwind_DeleteException(_Unwind_Exception *exception_object);
+
+#if LIBCXXABI_ARM_EHABI
+typedef enum {
+ _UVRSC_CORE = 0, /* integer register */
+ _UVRSC_VFP = 1, /* vfp */
+ _UVRSC_WMMXD = 3, /* Intel WMMX data register */
+ _UVRSC_WMMXC = 4 /* Intel WMMX control register */
+} _Unwind_VRS_RegClass;
+
+typedef enum {
+ _UVRSD_UINT32 = 0,
+ _UVRSD_VFPX = 1,
+ _UVRSD_UINT64 = 3,
+ _UVRSD_FLOAT = 4,
+ _UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+typedef enum {
+ _UVRSR_OK = 0,
+ _UVRSR_NOT_IMPLEMENTED = 1,
+ _UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+
+extern void _Unwind_Complete(_Unwind_Exception* exception_object);
+
+extern _Unwind_VRS_Result
+_Unwind_VRS_Get(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+ uint32_t regno, _Unwind_VRS_DataRepresentation representation,
+ void *valuep);
+
+extern _Unwind_VRS_Result
+_Unwind_VRS_Set(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+ uint32_t regno, _Unwind_VRS_DataRepresentation representation,
+ void *valuep);
+
+extern _Unwind_VRS_Result
+_Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
+ uint32_t discriminator,
+ _Unwind_VRS_DataRepresentation representation);
+#endif
+
+extern uintptr_t _Unwind_GetGR(struct _Unwind_Context *context, int index);
+extern void _Unwind_SetGR(struct _Unwind_Context *context, int index,
+ uintptr_t new_value);
+extern uintptr_t _Unwind_GetIP(struct _Unwind_Context *context);
+extern void _Unwind_SetIP(struct _Unwind_Context *, uintptr_t new_value);
+
+extern uintptr_t _Unwind_GetRegionStart(struct _Unwind_Context *context);
+extern uintptr_t
+ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context);
+#ifdef __USING_SJLJ_EXCEPTIONS__
+extern _Unwind_Reason_Code
+ _Unwind_SjLj_ForcedUnwind(_Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter);
+#else
+extern _Unwind_Reason_Code
+ _Unwind_ForcedUnwind(_Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter);
+#endif
+
+#ifdef __USING_SJLJ_EXCEPTIONS__
+typedef struct _Unwind_FunctionContext *_Unwind_FunctionContext_t;
+extern void _Unwind_SjLj_Register(_Unwind_FunctionContext_t fc);
+extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
+#endif
+
+//
+// The following are semi-suppoted extensions to the C++ ABI
+//
+
+//
+// called by __cxa_rethrow().
+//
+#ifdef __USING_SJLJ_EXCEPTIONS__
+extern _Unwind_Reason_Code
+ _Unwind_SjLj_Resume_or_Rethrow(_Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+ _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object);
+#endif
+
+// _Unwind_Backtrace() is a gcc extension that walks the stack and calls the
+// _Unwind_Trace_Fn once per frame until it reaches the bottom of the stack
+// or the _Unwind_Trace_Fn function returns something other than _URC_NO_REASON.
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *,
+ void *);
+extern _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *);
+
+// _Unwind_GetCFA is a gcc extension that can be called from within a
+// personality handler to get the CFA (stack pointer before call) of
+// current frame.
+extern uintptr_t _Unwind_GetCFA(struct _Unwind_Context *);
+
+
+// _Unwind_GetIPInfo is a gcc extension that can be called from within a
+// personality handler. Similar to _Unwind_GetIP() but also returns in
+// *ipBefore a non-zero value if the instruction pointer is at or before the
+// instruction causing the unwind. Normally, in a function call, the IP returned
+// is the return address which is after the call instruction and may be past the
+// end of the function containing the call instruction.
+extern uintptr_t _Unwind_GetIPInfo(struct _Unwind_Context *context,
+ int *ipBefore);
+
+
+// __register_frame() is used with dynamically generated code to register the
+// FDE for a generated (JIT) code. The FDE must use pc-rel addressing to point
+// to its function and optional LSDA.
+// __register_frame() has existed in all versions of Mac OS X, but in 10.4 and
+// 10.5 it was buggy and did not actually register the FDE with the unwinder.
+// In 10.6 and later it does register properly.
+extern void __register_frame(const void *fde);
+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
+// function will only work if the target function has an FDE but no compact
+// unwind info.
+struct dwarf_eh_bases {
+ uintptr_t tbase;
+ uintptr_t dbase;
+ uintptr_t func;
+};
+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).
+// 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);
+
+// Mac OS X does not support text-rel and data-rel addressing so these functions
+// are unimplemented
+extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context)
+ LIBUNWIND_UNAVAIL;
+extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
+ LIBUNWIND_UNAVAIL;
+
+// Mac OS X 10.4 and 10.5 had implementations of these functions in
+// libgcc_s.dylib, but they never worked.
+/// These functions are no longer available on Mac OS X.
+extern void __register_frame_info_bases(const void *fde, void *ob, void *tb,
+ void *db) LIBUNWIND_UNAVAIL;
+extern void __register_frame_info(const void *fde, void *ob)
+ LIBUNWIND_UNAVAIL;
+extern void __register_frame_info_table_bases(const void *fde, void *ob,
+ void *tb, void *db)
+ LIBUNWIND_UNAVAIL;
+extern void __register_frame_info_table(const void *fde, void *ob)
+ LIBUNWIND_UNAVAIL;
+extern void __register_frame_table(const void *fde)
+ LIBUNWIND_UNAVAIL;
+extern void *__deregister_frame_info(const void *fde)
+ LIBUNWIND_UNAVAIL;
+extern void *__deregister_frame_info_bases(const void *fde)
+ LIBUNWIND_UNAVAIL;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UNWIND_H__
diff --git a/libunwind/src/AddressSpace.hpp b/libunwind/src/AddressSpace.hpp
new file mode 100644
index 00000000000..9c659a85655
--- /dev/null
+++ b/libunwind/src/AddressSpace.hpp
@@ -0,0 +1,579 @@
+//===------------------------- AddressSpace.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.
+//
+//
+// Abstracts accessing local vs remote address spaces.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ADDRESSSPACE_HPP__
+#define __ADDRESSSPACE_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef _LIBUNWIND_IS_BAREMETAL
+#include <dlfcn.h>
+#endif
+
+#ifdef __APPLE__
+#include <mach-o/getsect.h>
+namespace libunwind {
+ bool checkKeyMgrRegisteredFDEs(uintptr_t targetAddr, void *&fde);
+}
+#endif
+
+#include "libunwind.h"
+#include "config.h"
+#include "dwarf2.h"
+#include "Registers.hpp"
+
+#if LIBCXXABI_ARM_EHABI
+#ifdef __linux__
+
+typedef long unsigned int *_Unwind_Ptr;
+extern "C" _Unwind_Ptr __gnu_Unwind_Find_exidx(_Unwind_Ptr addr, int *len);
+
+// Emulate the BSD dl_unwind_find_exidx API when on a GNU libdl system.
+#define dl_unwind_find_exidx __gnu_Unwind_Find_exidx
+
+#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 // LIBCXXABI_ARM_EHABI
+
+#if defined(__CloudABI__) || defined(__linux__)
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND && _LIBUNWIND_SUPPORT_DWARF_INDEX
+#include <link.h>
+#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.
+ uintptr_t dso_base;
+#endif
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ uintptr_t dwarf_section;
+ uintptr_t dwarf_section_length;
+#endif
+#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+ uintptr_t dwarf_index_section;
+ uintptr_t dwarf_index_section_length;
+#endif
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ uintptr_t compact_unwind_section;
+ uintptr_t compact_unwind_section_length;
+#endif
+#if LIBCXXABI_ARM_EHABI
+ uintptr_t arm_section;
+ uintptr_t arm_section_length;
+#endif
+};
+
+
+/// 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 {
+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
+ uint8_t get8(pint_t addr) {
+ uint8_t val;
+ memcpy(&val, (void *)addr, sizeof(val));
+ return val;
+ }
+ uint16_t get16(pint_t addr) {
+ uint16_t val;
+ memcpy(&val, (void *)addr, sizeof(val));
+ return val;
+ }
+ uint32_t get32(pint_t addr) {
+ uint32_t val;
+ memcpy(&val, (void *)addr, sizeof(val));
+ return val;
+ }
+ uint64_t get64(pint_t addr) {
+ uint64_t val;
+ memcpy(&val, (void *)addr, sizeof(val));
+ return val;
+ }
+ double getDouble(pint_t addr) {
+ double val;
+ memcpy(&val, (void *)addr, sizeof(val));
+ return val;
+ }
+ v128 getVector(pint_t addr) {
+ v128 val;
+ memcpy(&val, (void *)addr, sizeof(val));
+ return val;
+ }
+ uintptr_t getP(pint_t addr);
+ static uint64_t getULEB128(pint_t &addr, pint_t end);
+ static int64_t getSLEB128(pint_t &addr, pint_t end);
+
+ pint_t getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
+ pint_t datarelBase = 0);
+ bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
+ unw_word_t *offset);
+ bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
+ bool findOtherFDE(pint_t targetAddr, pint_t &fde);
+
+ static LocalAddressSpace sThisAddressSpace;
+};
+
+inline uintptr_t LocalAddressSpace::getP(pint_t addr) {
+#ifdef __LP64__
+ return get64(addr);
+#else
+ return get32(addr);
+#endif
+}
+
+/// Read a ULEB128 into a 64-bit word.
+inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
+ const uint8_t *p = (uint8_t *)addr;
+ const uint8_t *pend = (uint8_t *)end;
+ uint64_t result = 0;
+ int bit = 0;
+ do {
+ uint64_t b;
+
+ if (p == pend)
+ _LIBUNWIND_ABORT("truncated uleb128 expression");
+
+ b = *p & 0x7f;
+
+ if (bit >= 64 || b << bit >> bit != b) {
+ _LIBUNWIND_ABORT("malformed uleb128 expression");
+ } else {
+ result |= b << bit;
+ bit += 7;
+ }
+ } while (*p++ >= 0x80);
+ addr = (pint_t) p;
+ return result;
+}
+
+/// Read a SLEB128 into a 64-bit word.
+inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
+ const uint8_t *p = (uint8_t *)addr;
+ const uint8_t *pend = (uint8_t *)end;
+ int64_t result = 0;
+ int bit = 0;
+ uint8_t byte;
+ do {
+ if (p == pend)
+ _LIBUNWIND_ABORT("truncated sleb128 expression");
+ byte = *p++;
+ result |= ((byte & 0x7f) << bit);
+ bit += 7;
+ } while (byte & 0x80);
+ // sign extend negative numbers
+ if ((byte & 0x40) != 0)
+ result |= (-1LL) << bit;
+ addr = (pint_t) p;
+ return result;
+}
+
+inline LocalAddressSpace::pint_t
+LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
+ pint_t datarelBase) {
+ pint_t startAddr = addr;
+ const uint8_t *p = (uint8_t *)addr;
+ pint_t result;
+
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_ptr:
+ result = getP(addr);
+ p += sizeof(pint_t);
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_uleb128:
+ result = (pint_t)getULEB128(addr, end);
+ break;
+ case DW_EH_PE_udata2:
+ result = get16(addr);
+ p += 2;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_udata4:
+ result = get32(addr);
+ p += 4;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_udata8:
+ result = (pint_t)get64(addr);
+ p += 8;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_sleb128:
+ result = (pint_t)getSLEB128(addr, end);
+ break;
+ case DW_EH_PE_sdata2:
+ // Sign extend from signed 16-bit value.
+ result = (pint_t)(int16_t)get16(addr);
+ p += 2;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_sdata4:
+ // Sign extend from signed 32-bit value.
+ result = (pint_t)(int32_t)get32(addr);
+ p += 4;
+ addr = (pint_t) p;
+ break;
+ case DW_EH_PE_sdata8:
+ result = (pint_t)get64(addr);
+ p += 8;
+ addr = (pint_t) p;
+ break;
+ default:
+ _LIBUNWIND_ABORT("unknown pointer encoding");
+ }
+
+ // then add relative offset
+ switch (encoding & 0x70) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += startAddr;
+ break;
+ case DW_EH_PE_textrel:
+ _LIBUNWIND_ABORT("DW_EH_PE_textrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_datarel:
+ // DW_EH_PE_datarel is only valid in a few places, so the parameter has a
+ // default value of 0, and we abort in the event that someone calls this
+ // function with a datarelBase of 0 and DW_EH_PE_datarel encoding.
+ if (datarelBase == 0)
+ _LIBUNWIND_ABORT("DW_EH_PE_datarel is invalid with a datarelBase of 0");
+ result += datarelBase;
+ break;
+ case DW_EH_PE_funcrel:
+ _LIBUNWIND_ABORT("DW_EH_PE_funcrel pointer encoding not supported");
+ break;
+ case DW_EH_PE_aligned:
+ _LIBUNWIND_ABORT("DW_EH_PE_aligned pointer encoding not supported");
+ break;
+ default:
+ _LIBUNWIND_ABORT("unknown pointer encoding");
+ break;
+ }
+
+ if (encoding & DW_EH_PE_indirect)
+ result = getP(result);
+
+ 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
+ info.dwarf_section = (uintptr_t)dyldInfo.dwarf_section;
+ info.dwarf_section_length = dyldInfo.dwarf_section_length;
+ #endif
+ info.compact_unwind_section = (uintptr_t)dyldInfo.compact_unwind_section;
+ info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
+ return true;
+ }
+#elif LIBCXXABI_ARM_EHABI
+ #ifdef _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
+ int length = 0;
+ 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
+ struct dl_iterate_cb_data {
+ LocalAddressSpace *addressSpace;
+ UnwindInfoSections *sects;
+ uintptr_t targetAddr;
+ };
+
+ dl_iterate_cb_data cb_data = {this, &info, 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;
+
+ assert(cbdata);
+ assert(cbdata->sects);
+
+ if (cbdata->targetAddr < pinfo->dlpi_addr) {
+ return false;
+ }
+
+ for (ElfW(Half) i = 0; i < pinfo->dlpi_phnum; i++) {
+ const ElfW(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) {
+ cbdata->sects->dso_base = begin;
+ object_length = phdr->p_memsz;
+ found_obj = true;
+ }
+ } 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;
+ cbdata->sects->dwarf_index_section = eh_frame_hdr_start;
+ cbdata->sects->dwarf_index_section_length = phdr->p_memsz;
+ EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
+ *cbdata->addressSpace, eh_frame_hdr_start, phdr->p_memsz,
+ hdrInfo);
+ cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
+ found_hdr = true;
+ }
+ }
+
+ if (found_obj && found_hdr) {
+ cbdata->sects->dwarf_section_length = object_length;
+ return true;
+ } else {
+ return false;
+ }
+ },
+ &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;
+}
+
+
+inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
+#ifdef __APPLE__
+ return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
+#else
+ // TO DO: if OS has way to dynamically register FDEs, check that.
+ (void)targetAddr;
+ (void)fde;
+ return false;
+#endif
+}
+
+inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
+ size_t bufLen,
+ unw_word_t *offset) {
+#ifndef _LIBUNWIND_IS_BAREMETAL
+ Dl_info dyldInfo;
+ if (dladdr((void *)addr, &dyldInfo)) {
+ if (dyldInfo.dli_sname != NULL) {
+ snprintf(buf, bufLen, "%s", dyldInfo.dli_sname);
+ *offset = (addr - (pint_t) dyldInfo.dli_saddr);
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+
+
+
+#ifdef UNW_REMOTE
+
+/// OtherAddressSpace 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 {
+public:
+ OtherAddressSpace(task_t task) : fTask(task) {}
+
+ typedef typename P::uint_t pint_t;
+
+ uint8_t get8(pint_t addr);
+ uint16_t get16(pint_t addr);
+ uint32_t get32(pint_t addr);
+ uint64_t get64(pint_t addr);
+ pint_t getP(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,
+ pint_t datarelBase = 0);
+ bool findFunctionName(pint_t addr, char *buf, size_t bufLen,
+ unw_word_t *offset);
+ bool findUnwindSections(pint_t targetAddr, UnwindInfoSections &info);
+ bool findOtherFDE(pint_t targetAddr, pint_t &fde);
+private:
+ void *localCopy(pint_t addr);
+
+ task_t fTask;
+};
+
+template <typename P> uint8_t OtherAddressSpace<P>::get8(pint_t addr) {
+ return *((uint8_t *)localCopy(addr));
+}
+
+template <typename P> uint16_t OtherAddressSpace<P>::get16(pint_t addr) {
+ return P::E::get16(*(uint16_t *)localCopy(addr));
+}
+
+template <typename P> uint32_t OtherAddressSpace<P>::get32(pint_t addr) {
+ return P::E::get32(*(uint32_t *)localCopy(addr));
+}
+
+template <typename P> uint64_t OtherAddressSpace<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) {
+ return P::getP(*(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);
+ LocalAddressSpace::pint_t sladdr = laddr;
+ uint64_t result = LocalAddressSpace::getULEB128(laddr, laddr + size);
+ addr += (laddr - sladdr);
+ return result;
+}
+
+template <typename P>
+int64_t OtherAddressSpace<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;
+ uint64_t result = LocalAddressSpace::getSLEB128(laddr, laddr + size);
+ addr += (laddr - sladdr);
+ return result;
+}
+
+template <typename P> void *OtherAddressSpace<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) {
+ // FIX ME
+}
+
+/// unw_addr_space is the base class that abstract unw_addr_space_t type in
+/// libunwind.h points to.
+struct unw_addr_space {
+ cpu_type_t cpuType;
+ task_t taskPort;
+};
+
+/// unw_addr_space_i386 is the concrete instance that a unw_addr_space_t points
+/// to when examining
+/// 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;
+};
+
+/// unw_addr_space_x86_64 is the concrete instance that a unw_addr_space_t
+/// points to when examining
+/// 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;
+};
+
+/// unw_addr_space_ppc is the concrete instance that a unw_addr_space_t points
+/// to when examining
+/// 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;
+};
+
+#endif // UNW_REMOTE
+
+} // namespace libunwind
+
+#endif // __ADDRESSSPACE_HPP__
diff --git a/libunwind/src/CMakeLists.txt b/libunwind/src/CMakeLists.txt
new file mode 100644
index 00000000000..e10ae75e8ec
--- /dev/null
+++ b/libunwind/src/CMakeLists.txt
@@ -0,0 +1,118 @@
+# Get sources
+
+set(LIBUNWIND_CXX_SOURCES
+ libunwind.cpp
+ Unwind-EHABI.cpp)
+append_if(LIBUNWIND_CXX_SOURCES APPLE Unwind_AppleExtras.cpp)
+
+set(LIBUNWIND_C_SOURCES
+ UnwindLevel1.c
+ UnwindLevel1-gcc-ext.c
+ Unwind-sjlj.c)
+set_source_files_properties(${LIBUNWIND_C_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "-std=c99")
+
+set(LIBUNWIND_ASM_SOURCES
+ UnwindRegistersRestore.S
+ UnwindRegistersSave.S)
+set_source_files_properties(${LIBUNWIND_ASM_SOURCES}
+ PROPERTIES
+ LANGUAGE C)
+
+set(LIBUNWIND_HEADERS
+ AddressSpace.hpp
+ assembly.h
+ CompactUnwinder.hpp
+ config.h
+ dwarf2.h
+ DwarfInstructions.hpp
+ DwarfParser.hpp
+ libunwind_ext.h
+ Registers.hpp
+ UnwindCursor.hpp
+ unwind_ext.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include/libunwind.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/../include/unwind.h
+)
+
+append_if(LIBCXXABI_HEADERS APPLE
+ "${CMAKE_CURRENT_SOURCE_DIR}/../include/mach-o/compact_unwind_encoding.h")
+
+if (MSVC_IDE)
+ # Force them all into the headers dir on MSVC, otherwise they end up at
+ # project scope because they don't have extensions.
+ source_group("Header Files" FILES ${LIBUNWIND_HEADERS})
+endif()
+
+set(LIBUNWIND_SOURCES
+ ${LIBUNWIND_CXX_SOURCES}
+ ${LIBUNWIND_C_SOURCES}
+ ${LIBUNWIND_ASM_SOURCES})
+
+if (LIBUNWIND_ENABLE_SHARED)
+ add_library(unwind SHARED ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS})
+else()
+ add_library(unwind STATIC ${LIBUNWIND_SOURCES} ${LIBUNWIND_HEADERS})
+endif()
+
+include_directories("${LIBCXXABI_LIBCXX_INCLUDES}")
+
+# Generate library list.
+set(libraries ${LIBCXXABI_CXX_ABI_LIBRARIES})
+append_if(libraries LIBCXXABI_HAS_C_LIB c)
+append_if(libraries LIBCXXABI_HAS_DL_LIB dl)
+append_if(libraries LIBCXXABI_HAS_PTHREAD_LIB pthread)
+
+target_link_libraries(unwind ${libraries})
+
+# Setup flags.
+append_if(LIBCXXABI_COMPILE_FLAGS LIBCXXABI_HAS_FPIC_FLAG -fPIC)
+append_if(LIBCXXABI_LINK_FLAGS LIBCXXABI_HAS_NODEFAULTLIBS_FLAG -nodefaultlibs)
+
+set(LIBUNWIND_COMPILE_FLAGS)
+append_if(LIBUNWIND_COMPILE_FLAGS LIBCXXABI_HAS_NO_RTTI_FLAG -fno-rtti)
+if ( LIBCXXABI_HAS_NO_EXCEPTIONS_FLAG AND LIBCXXABI_HAS_FUNWIND_TABLES )
+ list(APPEND LIBUNWIND_COMPILE_FLAGS -fno-exceptions)
+ list(APPEND LIBUNWIND_COMPILE_FLAGS -funwind-tables)
+elseif( LIBUNWIND_ENABLE_SHARED )
+ message(FATAL_ERROR "Compiler doesn't support generation of unwind tables "
+ "if exception support is disabled. Building libunwind "
+ "DSO with runtime dependency on libcxxabi is not "
+ "supported.")
+endif()
+
+set(LIBCXXABI_UNWINDER_NAME "unwind")
+
+if ( APPLE )
+ if ( CMAKE_OSX_DEPLOYMENT_TARGET STREQUAL "10.6" )
+ list(APPEND LIBCXXABI_COMPILE_FLAGS "-U__STRICT_ANSI__")
+ list(APPEND LIBCXXABI_LINK_FLAGS
+ "-compatibility_version 1"
+ "-current_version ${LIBCXXABI_VERSION}"
+ "-install_name /usr/lib/lib${LIBCXXABI_UNWINDER_NAME}.1.dylib"
+ "/usr/lib/libSystem.B.dylib")
+ else()
+ list(APPEND LIBCXXABI_LINK_FLAGS
+ "-compatibility_version 1"
+ "-install_name /usr/lib/lib${LIBCXXABI_UNWINDER_NAME}.1.dylib")
+ endif()
+endif()
+
+string(REPLACE ";" " " LIBCXXABI_COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS}")
+string(REPLACE ";" " " LIBUNWIND_COMPILE_FLAGS "${LIBUNWIND_COMPILE_FLAGS}")
+string(REPLACE ";" " " LIBCXXABI_LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}")
+
+set_target_properties(unwind
+ PROPERTIES
+ COMPILE_FLAGS "${LIBCXXABI_COMPILE_FLAGS} ${LIBUNWIND_COMPILE_FLAGS}"
+ LINK_FLAGS "${LIBCXXABI_LINK_FLAGS}"
+ OUTPUT_NAME "${LIBCXXABI_UNWINDER_NAME}"
+ VERSION "1.0"
+ SOVERSION "1"
+ )
+
+install(TARGETS unwind
+ LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+ ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+ )
diff --git a/libunwind/src/CompactUnwinder.hpp b/libunwind/src/CompactUnwinder.hpp
new file mode 100644
index 00000000000..cd9ce3e5ecd
--- /dev/null
+++ b/libunwind/src/CompactUnwinder.hpp
@@ -0,0 +1,693 @@
+//===-------------------------- CompactUnwinder.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.
+//
+//
+// Does runtime stack unwinding using compact unwind encodings.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __COMPACT_UNWINDER_HPP__
+#define __COMPACT_UNWINDER_HPP__
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <libunwind.h>
+#include <mach-o/compact_unwind_encoding.h>
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+
+#define EXTRACT_BITS(value, mask) \
+ ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
+
+namespace libunwind {
+
+/// CompactUnwinder_x86 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_x86 register set
+template <typename A>
+class CompactUnwinder_x86 {
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t info,
+ uint32_t functionStart, A &addressSpace,
+ Registers_x86 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A &addressSpace, Registers_x86 &registers);
+ static void framelessUnwind(A &addressSpace,
+ typename A::pint_t returnAddressLocation,
+ Registers_x86 &registers);
+ static int
+ stepWithCompactEncodingEBPFrame(compact_unwind_encoding_t compactEncoding,
+ uint32_t functionStart, A &addressSpace,
+ Registers_x86 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers) {
+ switch (compactEncoding & UNWIND_X86_MODE_MASK) {
+ case UNWIND_X86_MODE_EBP_FRAME:
+ return stepWithCompactEncodingEBPFrame(compactEncoding, functionStart,
+ addressSpace, registers);
+ case UNWIND_X86_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, false);
+ case UNWIND_X86_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, true);
+ }
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingEBPFrame(
+ compact_unwind_encoding_t compactEncoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers) {
+ uint32_t savedRegistersOffset =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_EBP_FRAME_REGISTERS);
+
+ uint32_t savedRegisters = registers.getEBP() - 4 * savedRegistersOffset;
+ for (int i = 0; i < 5; ++i) {
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ (void)functionStart;
+ _LIBUNWIND_DEBUG_LOG("bad register for EBP frame, encoding=%08X for "
+ "function starting at 0x%X\n",
+ compactEncoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_x86<A>::stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t encoding, uint32_t functionStart,
+ A &addressSpace, Registers_x86 &registers, bool indirectStackSize) {
+ uint32_t stackSizeEncoded =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation =
+ EXTRACT_BITS(encoding, UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded * 4;
+ if (indirectStackSize) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
+ stackSize = subl + 4 * stackAdjust;
+ }
+ // decompress permutation
+ uint32_t permunreg[6];
+ switch (regCount) {
+ case 6:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation / 60;
+ permutation -= (permunreg[0] * 60);
+ permunreg[1] = permutation / 12;
+ permutation -= (permunreg[1] * 12);
+ permunreg[2] = permutation / 3;
+ permutation -= (permunreg[2] * 3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation / 20;
+ permutation -= (permunreg[0] * 20);
+ permunreg[1] = permutation / 4;
+ permutation -= (permunreg[1] * 4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation / 5;
+ permutation -= (permunreg[0] * 5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i = 0; i < regCount; ++i) {
+ uint32_t renum = 0;
+ for (int u = 1; u < 7; ++u) {
+ if (!used[u]) {
+ if (renum == permunreg[i]) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint32_t savedRegisters = registers.getSP() + stackSize - 4 - 4 * regCount;
+ for (uint32_t i = 0; i < regCount; ++i) {
+ switch (registersSaved[i]) {
+ case UNWIND_X86_REG_EBX:
+ registers.setEBX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ECX:
+ registers.setECX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDX:
+ registers.setEDX(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EDI:
+ registers.setEDI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_ESI:
+ registers.setESI(addressSpace.get32(savedRegisters));
+ break;
+ case UNWIND_X86_REG_EBP:
+ registers.setEBP(addressSpace.get32(savedRegisters));
+ break;
+ default:
+ _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
+ "function starting at 0x%X\n",
+ encoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 4;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+void CompactUnwinder_x86<A>::frameUnwind(A &addressSpace,
+ Registers_x86 &registers) {
+ typename A::pint_t bp = registers.getEBP();
+ // ebp points to old ebp
+ registers.setEBP(addressSpace.get32(bp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP((uint32_t)bp + 8);
+ // pop return address into eip
+ registers.setIP(addressSpace.get32(bp + 4));
+}
+
+template <typename A>
+void CompactUnwinder_x86<A>::framelessUnwind(
+ A &addressSpace, typename A::pint_t returnAddressLocation,
+ Registers_x86 &registers) {
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get32(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP((uint32_t)returnAddressLocation + 4);
+}
+
+
+/// CompactUnwinder_x86_64 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_x86_64 register set
+template <typename A>
+class CompactUnwinder_x86_64 {
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_x86_64 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static void frameUnwind(A &addressSpace, Registers_x86_64 &registers);
+ static void framelessUnwind(A &addressSpace, uint64_t returnAddressLocation,
+ Registers_x86_64 &registers);
+ static int
+ stepWithCompactEncodingRBPFrame(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_x86_64 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers, bool indirectStackSize);
+};
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers) {
+ switch (compactEncoding & UNWIND_X86_64_MODE_MASK) {
+ case UNWIND_X86_64_MODE_RBP_FRAME:
+ return stepWithCompactEncodingRBPFrame(compactEncoding, functionStart,
+ addressSpace, registers);
+ case UNWIND_X86_64_MODE_STACK_IMMD:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, false);
+ case UNWIND_X86_64_MODE_STACK_IND:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers, true);
+ }
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingRBPFrame(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_x86_64 &registers) {
+ uint32_t savedRegistersOffset =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_OFFSET);
+ uint32_t savedRegistersLocations =
+ EXTRACT_BITS(compactEncoding, UNWIND_X86_64_RBP_FRAME_REGISTERS);
+
+ uint64_t savedRegisters = registers.getRBP() - 8 * savedRegistersOffset;
+ for (int i = 0; i < 5; ++i) {
+ switch (savedRegistersLocations & 0x7) {
+ case UNWIND_X86_64_REG_NONE:
+ // no register saved in this slot
+ break;
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters));
+ break;
+ default:
+ (void)functionStart;
+ _LIBUNWIND_DEBUG_LOG("bad register for RBP frame, encoding=%08X for "
+ "function starting at 0x%llX\n",
+ compactEncoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 8;
+ savedRegistersLocations = (savedRegistersLocations >> 3);
+ }
+ frameUnwind(addressSpace, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_x86_64<A>::stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t encoding, uint64_t functionStart, A &addressSpace,
+ Registers_x86_64 &registers, bool indirectStackSize) {
+ uint32_t stackSizeEncoded =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_SIZE);
+ uint32_t stackAdjust =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_ADJUST);
+ uint32_t regCount =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT);
+ uint32_t permutation =
+ EXTRACT_BITS(encoding, UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION);
+ uint32_t stackSize = stackSizeEncoded * 8;
+ if (indirectStackSize) {
+ // stack size is encoded in subl $xxx,%esp instruction
+ uint32_t subl = addressSpace.get32(functionStart + stackSizeEncoded);
+ stackSize = subl + 8 * stackAdjust;
+ }
+ // decompress permutation
+ uint32_t permunreg[6];
+ switch (regCount) {
+ case 6:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ permunreg[5] = 0;
+ break;
+ case 5:
+ permunreg[0] = permutation / 120;
+ permutation -= (permunreg[0] * 120);
+ permunreg[1] = permutation / 24;
+ permutation -= (permunreg[1] * 24);
+ permunreg[2] = permutation / 6;
+ permutation -= (permunreg[2] * 6);
+ permunreg[3] = permutation / 2;
+ permutation -= (permunreg[3] * 2);
+ permunreg[4] = permutation;
+ break;
+ case 4:
+ permunreg[0] = permutation / 60;
+ permutation -= (permunreg[0] * 60);
+ permunreg[1] = permutation / 12;
+ permutation -= (permunreg[1] * 12);
+ permunreg[2] = permutation / 3;
+ permutation -= (permunreg[2] * 3);
+ permunreg[3] = permutation;
+ break;
+ case 3:
+ permunreg[0] = permutation / 20;
+ permutation -= (permunreg[0] * 20);
+ permunreg[1] = permutation / 4;
+ permutation -= (permunreg[1] * 4);
+ permunreg[2] = permutation;
+ break;
+ case 2:
+ permunreg[0] = permutation / 5;
+ permutation -= (permunreg[0] * 5);
+ permunreg[1] = permutation;
+ break;
+ case 1:
+ permunreg[0] = permutation;
+ break;
+ }
+ // re-number registers back to standard numbers
+ int registersSaved[6];
+ bool used[7] = { false, false, false, false, false, false, false };
+ for (uint32_t i = 0; i < regCount; ++i) {
+ uint32_t renum = 0;
+ for (int u = 1; u < 7; ++u) {
+ if (!used[u]) {
+ if (renum == permunreg[i]) {
+ registersSaved[i] = u;
+ used[u] = true;
+ break;
+ }
+ ++renum;
+ }
+ }
+ }
+ uint64_t savedRegisters = registers.getSP() + stackSize - 8 - 8 * regCount;
+ for (uint32_t i = 0; i < regCount; ++i) {
+ switch (registersSaved[i]) {
+ case UNWIND_X86_64_REG_RBX:
+ registers.setRBX(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R12:
+ registers.setR12(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R13:
+ registers.setR13(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R14:
+ registers.setR14(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_R15:
+ registers.setR15(addressSpace.get64(savedRegisters));
+ break;
+ case UNWIND_X86_64_REG_RBP:
+ registers.setRBP(addressSpace.get64(savedRegisters));
+ break;
+ default:
+ _LIBUNWIND_DEBUG_LOG("bad register for frameless, encoding=%08X for "
+ "function starting at 0x%llX\n",
+ encoding, functionStart);
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+ }
+ savedRegisters += 8;
+ }
+ framelessUnwind(addressSpace, savedRegisters, registers);
+ return UNW_STEP_SUCCESS;
+}
+
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::frameUnwind(A &addressSpace,
+ Registers_x86_64 &registers) {
+ uint64_t rbp = registers.getRBP();
+ // ebp points to old ebp
+ registers.setRBP(addressSpace.get64(rbp));
+ // old esp is ebp less saved ebp and return address
+ registers.setSP(rbp + 16);
+ // pop return address into eip
+ registers.setIP(addressSpace.get64(rbp + 8));
+}
+
+template <typename A>
+void CompactUnwinder_x86_64<A>::framelessUnwind(A &addressSpace,
+ uint64_t returnAddressLocation,
+ Registers_x86_64 &registers) {
+ // return address is on stack after last saved register
+ registers.setIP(addressSpace.get64(returnAddressLocation));
+ // old esp is before return address
+ registers.setSP(returnAddressLocation + 8);
+}
+
+
+
+/// CompactUnwinder_arm64 uses a compact unwind info to virtually "step" (aka
+/// unwind) by modifying a Registers_arm64 register set
+template <typename A>
+class CompactUnwinder_arm64 {
+public:
+
+ static int stepWithCompactEncoding(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_arm64 &registers);
+
+private:
+ typename A::pint_t pint_t;
+
+ static int
+ stepWithCompactEncodingFrame(compact_unwind_encoding_t compactEncoding,
+ uint64_t functionStart, A &addressSpace,
+ Registers_arm64 &registers);
+ static int stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_arm64 &registers);
+};
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncoding(
+ compact_unwind_encoding_t compactEncoding, uint64_t functionStart,
+ A &addressSpace, Registers_arm64 &registers) {
+ switch (compactEncoding & UNWIND_ARM64_MODE_MASK) {
+ case UNWIND_ARM64_MODE_FRAME:
+ return stepWithCompactEncodingFrame(compactEncoding, functionStart,
+ addressSpace, registers);
+ case UNWIND_ARM64_MODE_FRAMELESS:
+ return stepWithCompactEncodingFrameless(compactEncoding, functionStart,
+ addressSpace, registers);
+ }
+ _LIBUNWIND_ABORT("invalid compact unwind encoding");
+}
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
+ compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
+ Registers_arm64 &registers) {
+ uint32_t stackSize =
+ 16 * EXTRACT_BITS(encoding, UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK);
+
+ uint64_t savedRegisterLoc = registers.getSP() + stackSize;
+
+ if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
+ registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
+ registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
+ registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
+ registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
+ registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D8,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D9,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D10,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D11,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D12,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D13,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D14,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D15,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ // subtract stack size off of sp
+ registers.setSP(savedRegisterLoc);
+
+ // set pc to be value in lr
+ registers.setIP(registers.getRegister(UNW_ARM64_LR));
+
+ return UNW_STEP_SUCCESS;
+}
+
+template <typename A>
+int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
+ compact_unwind_encoding_t encoding, uint64_t, A &addressSpace,
+ Registers_arm64 &registers) {
+ uint64_t savedRegisterLoc = registers.getFP() - 8;
+
+ if (encoding & UNWIND_ARM64_FRAME_X19_X20_PAIR) {
+ registers.setRegister(UNW_ARM64_X19, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X20, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X21_X22_PAIR) {
+ registers.setRegister(UNW_ARM64_X21, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X22, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X23_X24_PAIR) {
+ registers.setRegister(UNW_ARM64_X23, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X24, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X25_X26_PAIR) {
+ registers.setRegister(UNW_ARM64_X25, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X26, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_X27_X28_PAIR) {
+ registers.setRegister(UNW_ARM64_X27, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setRegister(UNW_ARM64_X28, addressSpace.get64(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ if (encoding & UNWIND_ARM64_FRAME_D8_D9_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D8,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D9,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D10_D11_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D10,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D11,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D12_D13_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D12,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D13,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+ if (encoding & UNWIND_ARM64_FRAME_D14_D15_PAIR) {
+ registers.setFloatRegister(UNW_ARM64_D14,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ registers.setFloatRegister(UNW_ARM64_D15,
+ addressSpace.getDouble(savedRegisterLoc));
+ savedRegisterLoc -= 8;
+ }
+
+ uint64_t fp = registers.getFP();
+ // fp points to old fp
+ registers.setFP(addressSpace.get64(fp));
+ // old sp is fp less saved fp and lr
+ registers.setSP(fp + 16);
+ // pop return address into pc
+ registers.setIP(addressSpace.get64(fp + 8));
+
+ return UNW_STEP_SUCCESS;
+}
+
+
+} // namespace libunwind
+
+#endif // __COMPACT_UNWINDER_HPP__
diff --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
new file mode 100644
index 00000000000..99737e0b66c
--- /dev/null
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -0,0 +1,760 @@
+//===-------------------------- DwarfInstructions.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.
+//
+//
+// Processor specific interpretation of dwarf unwind info.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DWARF_INSTRUCTIONS_HPP__
+#define __DWARF_INSTRUCTIONS_HPP__
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dwarf2.h"
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfParser.hpp"
+#include "config.h"
+
+
+namespace libunwind {
+
+
+/// DwarfInstructions maps abtract dwarf unwind instructions to a particular
+/// architecture
+template <typename A, typename R>
+class DwarfInstructions {
+public:
+ typedef typename A::pint_t pint_t;
+ typedef typename A::sint_t sint_t;
+
+ static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
+ R &registers);
+
+private:
+
+ enum {
+ DW_X86_64_RET_ADDR = 16
+ };
+
+ enum {
+ DW_X86_RET_ADDR = 8
+ };
+
+ typedef typename CFI_Parser<A>::RegisterLocation RegisterLocation;
+ typedef typename CFI_Parser<A>::PrologInfo PrologInfo;
+ typedef typename CFI_Parser<A>::FDE_Info FDE_Info;
+ typedef typename CFI_Parser<A>::CIE_Info CIE_Info;
+
+ static pint_t evaluateExpression(pint_t expression, A &addressSpace,
+ const R &registers,
+ pint_t initialStackValue);
+ static pint_t getSavedRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+ static double getSavedFloatRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+ static v128 getSavedVectorRegister(A &addressSpace, const R &registers,
+ pint_t cfa, const RegisterLocation &savedReg);
+
+ static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
+ const R &registers) {
+ if (prolog.cfaRegister != 0)
+ return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister) +
+ prolog.cfaRegisterOffset);
+ if (prolog.cfaExpression != 0)
+ return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
+ registers, 0);
+ assert(0 && "getCFA(): unknown location");
+ __builtin_unreachable();
+ }
+};
+
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
+ A &addressSpace, const R &registers, pint_t cfa,
+ const RegisterLocation &savedReg) {
+ switch (savedReg.location) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getP(cfa + (pint_t)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getP(
+ evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ return evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa);
+
+ case CFI_Parser<A>::kRegisterInRegister:
+ return registers.getRegister((int)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ // FIX ME
+ break;
+ }
+ _LIBUNWIND_ABORT("unsupported restore location for register");
+}
+
+template <typename A, typename R>
+double DwarfInstructions<A, R>::getSavedFloatRegister(
+ A &addressSpace, const R &registers, pint_t cfa,
+ const RegisterLocation &savedReg) {
+ switch (savedReg.location) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getDouble(cfa + (pint_t)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getDouble(
+ evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ _LIBUNWIND_ABORT("unsupported restore location for float register");
+}
+
+template <typename A, typename R>
+v128 DwarfInstructions<A, R>::getSavedVectorRegister(
+ A &addressSpace, const R &registers, pint_t cfa,
+ const RegisterLocation &savedReg) {
+ switch (savedReg.location) {
+ case CFI_Parser<A>::kRegisterInCFA:
+ return addressSpace.getVector(cfa + (pint_t)savedReg.value);
+
+ case CFI_Parser<A>::kRegisterAtExpression:
+ return addressSpace.getVector(
+ evaluateExpression((pint_t)savedReg.value, addressSpace,
+ registers, cfa));
+
+ case CFI_Parser<A>::kRegisterIsExpression:
+ case CFI_Parser<A>::kRegisterUnused:
+ case CFI_Parser<A>::kRegisterOffsetFromCFA:
+ case CFI_Parser<A>::kRegisterInRegister:
+ // FIX ME
+ break;
+ }
+ _LIBUNWIND_ABORT("unsupported restore location for vector register");
+}
+
+template <typename A, typename R>
+int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
+ pint_t fdeStart, R &registers) {
+ FDE_Info fdeInfo;
+ CIE_Info cieInfo;
+ if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
+ &cieInfo) == NULL) {
+ PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(addressSpace, fdeInfo, cieInfo, pc,
+ &prolog)) {
+ // get pointer to cfa (architecture specific)
+ pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+ // 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 &&
+ "register range too large");
+ assert(lastReg <= (int)cieInfo.returnAddressRegister &&
+ "register range does not contain return address register");
+ for (int i = 0; i <= lastReg; ++i) {
+ if (prolog.savedRegisters[i].location !=
+ CFI_Parser<A>::kRegisterUnused) {
+ if (registers.validFloatRegister(i))
+ newRegisters.setFloatRegister(
+ i, getSavedFloatRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]));
+ else if (registers.validVectorRegister(i))
+ newRegisters.setVectorRegister(
+ i, getSavedVectorRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]));
+ else if (i == (int)cieInfo.returnAddressRegister)
+ returnAddress = getSavedRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]);
+ else if (registers.validRegister(i))
+ newRegisters.setRegister(
+ i, getSavedRegister(addressSpace, registers, cfa,
+ prolog.savedRegisters[i]));
+ else
+ return UNW_EBADREG;
+ }
+ }
+
+ // By definition, the CFA is the stack pointer at the call site, so
+ // restoring SP means setting it to CFA.
+ newRegisters.setSP(cfa);
+
+ // Return address is address after call site instruction, so setting IP to
+ // that does simualates a return.
+ newRegisters.setIP(returnAddress);
+
+ // Simulate the step by replacing the register set with the new ones.
+ registers = newRegisters;
+
+ return UNW_STEP_SUCCESS;
+ }
+ }
+ return UNW_EBADFRAME;
+}
+
+template <typename A, typename R>
+typename A::pint_t
+DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
+ const R &registers,
+ pint_t initialStackValue) {
+ const bool log = false;
+ pint_t p = expression;
+ pint_t expressionEnd = expression + 20; // temp, until len read
+ pint_t length = (pint_t)addressSpace.getULEB128(p, expressionEnd);
+ expressionEnd = p + length;
+ if (log)
+ fprintf(stderr, "evaluateExpression(): length=%" PRIu64 "\n",
+ (uint64_t)length);
+ pint_t stack[100];
+ pint_t *sp = stack;
+ *(++sp) = initialStackValue;
+
+ while (p < expressionEnd) {
+ if (log) {
+ for (pint_t *t = sp; t > stack; --t) {
+ fprintf(stderr, "sp[] = 0x%" PRIx64 "\n", (uint64_t)(*t));
+ }
+ }
+ uint8_t opcode = addressSpace.get8(p++);
+ sint_t svalue, svalue2;
+ pint_t value;
+ uint32_t reg;
+ switch (opcode) {
+ case DW_OP_addr:
+ // push immediate address sized value
+ value = addressSpace.getP(p);
+ p += sizeof(pint_t);
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_deref:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *(++sp) = addressSpace.getP(value);
+ if (log)
+ fprintf(stderr, "dereference 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1u:
+ // push immediate 1 byte value
+ value = addressSpace.get8(p);
+ p += 1;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const1s:
+ // push immediate 1 byte signed value
+ svalue = (int8_t) addressSpace.get8(p);
+ p += 1;
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const2u:
+ // push immediate 2 byte value
+ value = addressSpace.get16(p);
+ p += 2;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const2s:
+ // push immediate 2 byte signed value
+ svalue = (int16_t) addressSpace.get16(p);
+ p += 2;
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const4u:
+ // push immediate 4 byte value
+ value = addressSpace.get32(p);
+ p += 4;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const4s:
+ // push immediate 4 byte signed value
+ svalue = (int32_t)addressSpace.get32(p);
+ p += 4;
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_const8u:
+ // push immediate 8 byte value
+ value = (pint_t)addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_const8s:
+ // push immediate 8 byte signed value
+ value = (pint_t)addressSpace.get64(p);
+ p += 8;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_constu:
+ // push immediate ULEB128 value
+ value = (pint_t)addressSpace.getULEB128(p, expressionEnd);
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_consts:
+ // push immediate SLEB128 value
+ svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+ *(++sp) = (pint_t)svalue;
+ if (log)
+ fprintf(stderr, "push 0x%" PRIx64 "\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_dup:
+ // push top of stack
+ value = *sp;
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "duplicate top of stack\n");
+ break;
+
+ case DW_OP_drop:
+ // pop
+ --sp;
+ if (log)
+ fprintf(stderr, "pop top of stack\n");
+ break;
+
+ case DW_OP_over:
+ // dup second
+ value = sp[-1];
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "duplicate second in stack\n");
+ break;
+
+ case DW_OP_pick:
+ // pick from
+ reg = addressSpace.get8(p);
+ p += 1;
+ value = sp[-reg];
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "duplicate %d in stack\n", reg);
+ break;
+
+ case DW_OP_swap:
+ // swap top two
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = value;
+ if (log)
+ fprintf(stderr, "swap top of stack\n");
+ break;
+
+ case DW_OP_rot:
+ // rotate top three
+ value = sp[0];
+ sp[0] = sp[-1];
+ sp[-1] = sp[-2];
+ sp[-2] = value;
+ if (log)
+ fprintf(stderr, "rotate top three of stack\n");
+ break;
+
+ case DW_OP_xderef:
+ // pop stack, dereference, push result
+ value = *sp--;
+ *sp = *((pint_t*)value);
+ if (log)
+ fprintf(stderr, "x-dereference 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_abs:
+ svalue = (sint_t)*sp;
+ if (svalue < 0)
+ *sp = (pint_t)(-svalue);
+ if (log)
+ fprintf(stderr, "abs\n");
+ break;
+
+ case DW_OP_and:
+ value = *sp--;
+ *sp &= value;
+ if (log)
+ fprintf(stderr, "and\n");
+ break;
+
+ case DW_OP_div:
+ svalue = (sint_t)(*sp--);
+ svalue2 = (sint_t)*sp;
+ *sp = (pint_t)(svalue2 / svalue);
+ if (log)
+ fprintf(stderr, "div\n");
+ break;
+
+ case DW_OP_minus:
+ value = *sp--;
+ *sp = *sp - value;
+ if (log)
+ fprintf(stderr, "minus\n");
+ break;
+
+ case DW_OP_mod:
+ svalue = (sint_t)(*sp--);
+ svalue2 = (sint_t)*sp;
+ *sp = (pint_t)(svalue2 % svalue);
+ if (log)
+ fprintf(stderr, "module\n");
+ break;
+
+ case DW_OP_mul:
+ svalue = (sint_t)(*sp--);
+ svalue2 = (sint_t)*sp;
+ *sp = (pint_t)(svalue2 * svalue);
+ if (log)
+ fprintf(stderr, "mul\n");
+ break;
+
+ case DW_OP_neg:
+ *sp = 0 - *sp;
+ if (log)
+ fprintf(stderr, "neg\n");
+ break;
+
+ case DW_OP_not:
+ svalue = (sint_t)(*sp);
+ *sp = (pint_t)(~svalue);
+ if (log)
+ fprintf(stderr, "not\n");
+ break;
+
+ case DW_OP_or:
+ value = *sp--;
+ *sp |= value;
+ if (log)
+ fprintf(stderr, "or\n");
+ break;
+
+ case DW_OP_plus:
+ value = *sp--;
+ *sp += value;
+ if (log)
+ fprintf(stderr, "plus\n");
+ break;
+
+ case DW_OP_plus_uconst:
+ // pop stack, add uelb128 constant, push result
+ *sp += addressSpace.getULEB128(p, expressionEnd);
+ if (log)
+ fprintf(stderr, "add constant\n");
+ break;
+
+ case DW_OP_shl:
+ value = *sp--;
+ *sp = *sp << value;
+ if (log)
+ fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shr:
+ value = *sp--;
+ *sp = *sp >> value;
+ if (log)
+ fprintf(stderr, "shift left\n");
+ break;
+
+ case DW_OP_shra:
+ value = *sp--;
+ svalue = (sint_t)*sp;
+ *sp = (pint_t)(svalue >> value);
+ if (log)
+ fprintf(stderr, "shift left arithmetric\n");
+ break;
+
+ case DW_OP_xor:
+ value = *sp--;
+ *sp ^= value;
+ if (log)
+ fprintf(stderr, "xor\n");
+ break;
+
+ case DW_OP_skip:
+ svalue = (int16_t) addressSpace.get16(p);
+ p += 2;
+ p = (pint_t)((sint_t)p + svalue);
+ if (log)
+ fprintf(stderr, "skip %" PRIu64 "\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_bra:
+ svalue = (int16_t) addressSpace.get16(p);
+ p += 2;
+ if (*sp--)
+ p = (pint_t)((sint_t)p + svalue);
+ if (log)
+ fprintf(stderr, "bra %" PRIu64 "\n", (uint64_t)svalue);
+ break;
+
+ case DW_OP_eq:
+ value = *sp--;
+ *sp = (*sp == value);
+ if (log)
+ fprintf(stderr, "eq\n");
+ break;
+
+ case DW_OP_ge:
+ value = *sp--;
+ *sp = (*sp >= value);
+ if (log)
+ fprintf(stderr, "ge\n");
+ break;
+
+ case DW_OP_gt:
+ value = *sp--;
+ *sp = (*sp > value);
+ if (log)
+ fprintf(stderr, "gt\n");
+ break;
+
+ case DW_OP_le:
+ value = *sp--;
+ *sp = (*sp <= value);
+ if (log)
+ fprintf(stderr, "le\n");
+ break;
+
+ case DW_OP_lt:
+ value = *sp--;
+ *sp = (*sp < value);
+ if (log)
+ fprintf(stderr, "lt\n");
+ break;
+
+ case DW_OP_ne:
+ value = *sp--;
+ *sp = (*sp != value);
+ if (log)
+ fprintf(stderr, "ne\n");
+ break;
+
+ case DW_OP_lit0:
+ case DW_OP_lit1:
+ case DW_OP_lit2:
+ case DW_OP_lit3:
+ case DW_OP_lit4:
+ case DW_OP_lit5:
+ case DW_OP_lit6:
+ case DW_OP_lit7:
+ case DW_OP_lit8:
+ case DW_OP_lit9:
+ case DW_OP_lit10:
+ case DW_OP_lit11:
+ case DW_OP_lit12:
+ case DW_OP_lit13:
+ case DW_OP_lit14:
+ case DW_OP_lit15:
+ case DW_OP_lit16:
+ case DW_OP_lit17:
+ case DW_OP_lit18:
+ case DW_OP_lit19:
+ case DW_OP_lit20:
+ case DW_OP_lit21:
+ case DW_OP_lit22:
+ case DW_OP_lit23:
+ case DW_OP_lit24:
+ case DW_OP_lit25:
+ case DW_OP_lit26:
+ case DW_OP_lit27:
+ case DW_OP_lit28:
+ case DW_OP_lit29:
+ case DW_OP_lit30:
+ case DW_OP_lit31:
+ value = static_cast<pint_t>(opcode - DW_OP_lit0);
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "push literal 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_reg0:
+ case DW_OP_reg1:
+ case DW_OP_reg2:
+ case DW_OP_reg3:
+ case DW_OP_reg4:
+ case DW_OP_reg5:
+ case DW_OP_reg6:
+ case DW_OP_reg7:
+ case DW_OP_reg8:
+ case DW_OP_reg9:
+ case DW_OP_reg10:
+ case DW_OP_reg11:
+ case DW_OP_reg12:
+ case DW_OP_reg13:
+ case DW_OP_reg14:
+ case DW_OP_reg15:
+ case DW_OP_reg16:
+ case DW_OP_reg17:
+ case DW_OP_reg18:
+ case DW_OP_reg19:
+ case DW_OP_reg20:
+ case DW_OP_reg21:
+ case DW_OP_reg22:
+ case DW_OP_reg23:
+ case DW_OP_reg24:
+ case DW_OP_reg25:
+ case DW_OP_reg26:
+ case DW_OP_reg27:
+ case DW_OP_reg28:
+ case DW_OP_reg29:
+ case DW_OP_reg30:
+ case DW_OP_reg31:
+ reg = static_cast<uint32_t>(opcode - DW_OP_reg0);
+ *(++sp) = registers.getRegister((int)reg);
+ if (log)
+ fprintf(stderr, "push reg %d\n", reg);
+ break;
+
+ case DW_OP_regx:
+ reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
+ *(++sp) = registers.getRegister((int)reg);
+ if (log)
+ fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ reg = static_cast<uint32_t>(opcode - DW_OP_breg0);
+ svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+ svalue += static_cast<sint_t>(registers.getRegister((int)reg));
+ *(++sp) = (pint_t)(svalue);
+ if (log)
+ fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_bregx:
+ reg = static_cast<uint32_t>(addressSpace.getULEB128(p, expressionEnd));
+ svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+ svalue += static_cast<sint_t>(registers.getRegister((int)reg));
+ *(++sp) = (pint_t)(svalue);
+ if (log)
+ fprintf(stderr, "push reg %d + 0x%" PRIx64 "\n", reg, (uint64_t)svalue);
+ break;
+
+ case DW_OP_fbreg:
+ _LIBUNWIND_ABORT("DW_OP_fbreg not implemented");
+ break;
+
+ case DW_OP_piece:
+ _LIBUNWIND_ABORT("DW_OP_piece not implemented");
+ break;
+
+ case DW_OP_deref_size:
+ // pop stack, dereference, push result
+ value = *sp--;
+ switch (addressSpace.get8(p++)) {
+ case 1:
+ value = addressSpace.get8(value);
+ break;
+ case 2:
+ value = addressSpace.get16(value);
+ break;
+ case 4:
+ value = addressSpace.get32(value);
+ break;
+ case 8:
+ value = (pint_t)addressSpace.get64(value);
+ break;
+ default:
+ _LIBUNWIND_ABORT("DW_OP_deref_size with bad size");
+ }
+ *(++sp) = value;
+ if (log)
+ fprintf(stderr, "sized dereference 0x%" PRIx64 "\n", (uint64_t)value);
+ break;
+
+ case DW_OP_xderef_size:
+ case DW_OP_nop:
+ case DW_OP_push_object_addres:
+ case DW_OP_call2:
+ case DW_OP_call4:
+ case DW_OP_call_ref:
+ default:
+ _LIBUNWIND_ABORT("dwarf opcode not implemented");
+ }
+
+ }
+ if (log)
+ fprintf(stderr, "expression evaluates to 0x%" PRIx64 "\n", (uint64_t)*sp);
+ return *sp;
+}
+
+
+
+} // namespace libunwind
+
+#endif // __DWARF_INSTRUCTIONS_HPP__
diff --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
new file mode 100644
index 00000000000..f6ef738c471
--- /dev/null
+++ b/libunwind/src/DwarfParser.hpp
@@ -0,0 +1,724 @@
+//===--------------------------- DwarfParser.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.
+//
+//
+// Parses DWARF CFIs (FDEs and CIEs).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __DWARF_PARSER_HPP__
+#define __DWARF_PARSER_HPP__
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <vector>
+
+#include "libunwind.h"
+#include "dwarf2.h"
+
+#include "AddressSpace.hpp"
+
+namespace libunwind {
+
+/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
+/// See Dwarf Spec for details:
+/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A>
+class CFI_Parser {
+public:
+ typedef typename A::pint_t pint_t;
+
+ /// Information encoded in a CIE (Common Information Entry)
+ struct CIE_Info {
+ pint_t cieStart;
+ pint_t cieLength;
+ pint_t cieInstructions;
+ uint8_t pointerEncoding;
+ uint8_t lsdaEncoding;
+ uint8_t personalityEncoding;
+ uint8_t personalityOffsetInCIE;
+ pint_t personality;
+ uint32_t codeAlignFactor;
+ int dataAlignFactor;
+ bool isSignalFrame;
+ bool fdesHaveAugmentationData;
+ uint8_t returnAddressRegister;
+ };
+
+ /// Information about an FDE (Frame Description Entry)
+ struct FDE_Info {
+ pint_t fdeStart;
+ pint_t fdeLength;
+ pint_t fdeInstructions;
+ pint_t pcStart;
+ pint_t pcEnd;
+ pint_t lsda;
+ };
+
+ enum {
+ kMaxRegisterNumber = 120
+ };
+ enum RegisterSavedWhere {
+ kRegisterUnused,
+ kRegisterInCFA,
+ kRegisterOffsetFromCFA,
+ kRegisterInRegister,
+ kRegisterAtExpression,
+ kRegisterIsExpression
+ };
+ struct RegisterLocation {
+ RegisterSavedWhere location;
+ int64_t value;
+ };
+ /// Information about a frame layout and registers saved determined
+ /// by "running" the dwarf FDE "instructions"
+ struct PrologInfo {
+ uint32_t cfaRegister;
+ int32_t cfaRegisterOffset; // CFA = (cfaRegister)+cfaRegisterOffset
+ int64_t cfaExpression; // CFA = expression
+ uint32_t spExtraArgSize;
+ uint32_t codeOffsetAtStackDecrement;
+ bool registersInOtherRegisters;
+ bool sameValueUsed;
+ RegisterLocation savedRegisters[kMaxRegisterNumber];
+ };
+
+ struct PrologInfoStackEntry {
+ PrologInfoStackEntry(PrologInfoStackEntry *n, const PrologInfo &i)
+ : next(n), info(i) {}
+ PrologInfoStackEntry *next;
+ PrologInfo info;
+ };
+
+ static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
+ uint32_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+ CIE_Info *cieInfo);
+ static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
+ FDE_Info *fdeInfo, CIE_Info *cieInfo);
+ static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
+ const CIE_Info &cieInfo, pint_t upToPC,
+ PrologInfo *results);
+
+ static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
+
+private:
+ static bool parseInstructions(A &addressSpace, pint_t instructions,
+ pint_t instructionsEnd, const CIE_Info &cieInfo,
+ pint_t pcoffset,
+ PrologInfoStackEntry *&rememberStack,
+ PrologInfo *results);
+};
+
+/// Parse a FDE into a CIE_Info and an FDE_Info
+template <typename A>
+const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
+ FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+ pint_t p = fdeStart;
+ pint_t cfiLength = (pint_t)addressSpace.get32(p);
+ p += 4;
+ if (cfiLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = (pint_t)addressSpace.get64(p);
+ p += 8;
+ }
+ if (cfiLength == 0)
+ return "FDE has zero length"; // end marker
+ uint32_t ciePointer = addressSpace.get32(p);
+ if (ciePointer == 0)
+ return "FDE is really a CIE"; // this is a CIE not an FDE
+ pint_t nextCFI = p + cfiLength;
+ pint_t cieStart = p - ciePointer;
+ const char *err = parseCIE(addressSpace, cieStart, cieInfo);
+ if (err != NULL)
+ return err;
+ p += 4;
+ // 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
+ fdeInfo->lsda = 0;
+ // 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
+ pint_t lsdaStart = p;
+ if (addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding & 0x0F) !=
+ 0) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda =
+ addressSpace.getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = fdeStart;
+ fdeInfo->fdeLength = nextCFI - fdeStart;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart + pcRange;
+ return NULL; // success
+}
+
+/// Scan an eh_frame section to find an FDE for a pc
+template <typename A>
+bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
+ uint32_t sectionLength, pint_t fdeHint,
+ FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+ //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
+ pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
+ const pint_t ehSectionEnd = p + sectionLength;
+ while (p < ehSectionEnd) {
+ pint_t currentCFI = p;
+ //fprintf(stderr, "findFDE() CFI at 0x%llX\n", (long long)p);
+ pint_t cfiLength = addressSpace.get32(p);
+ p += 4;
+ if (cfiLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cfiLength = (pint_t)addressSpace.get64(p);
+ p += 8;
+ }
+ if (cfiLength == 0)
+ return false; // end marker
+ uint32_t id = addressSpace.get32(p);
+ if (id == 0) {
+ // skip over CIEs
+ p += cfiLength;
+ } else {
+ // 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
+ if ((ehSectionStart <= cieStart) && (cieStart < ehSectionEnd)) {
+ if (parseCIE(addressSpace, cieStart, cieInfo) == NULL) {
+ p += 4;
+ // 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
+ if ((pcStart < pc) && (pc <= pcStart + pcRange)) {
+ // parse rest of info
+ fdeInfo->lsda = 0;
+ // 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
+ pint_t lsdaStart = p;
+ if (addressSpace.getEncodedP(
+ p, nextCFI, cieInfo->lsdaEncoding & 0x0F) != 0) {
+ // reset pointer and re-parse lsda address
+ p = lsdaStart;
+ fdeInfo->lsda = addressSpace
+ .getEncodedP(p, nextCFI, cieInfo->lsdaEncoding);
+ }
+ }
+ p = endOfAug;
+ }
+ fdeInfo->fdeStart = currentCFI;
+ fdeInfo->fdeLength = nextCFI - currentCFI;
+ fdeInfo->fdeInstructions = p;
+ fdeInfo->pcStart = pcStart;
+ fdeInfo->pcEnd = pcStart + pcRange;
+ return true;
+ } else {
+ // pc is not in begin/range, skip this FDE
+ }
+ } else {
+ // malformed CIE, now augmentation describing pc range encoding
+ }
+ } else {
+ // malformed FDE. CIE is bad
+ }
+ p = nextCFI;
+ }
+ }
+ return false;
+}
+
+/// Extract info from a CIE
+template <typename A>
+const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
+ CIE_Info *cieInfo) {
+ cieInfo->pointerEncoding = 0;
+ cieInfo->lsdaEncoding = DW_EH_PE_omit;
+ cieInfo->personalityEncoding = 0;
+ cieInfo->personalityOffsetInCIE = 0;
+ cieInfo->personality = 0;
+ cieInfo->codeAlignFactor = 0;
+ cieInfo->dataAlignFactor = 0;
+ cieInfo->isSignalFrame = false;
+ cieInfo->fdesHaveAugmentationData = false;
+ cieInfo->cieStart = cie;
+ pint_t p = cie;
+ pint_t cieLength = (pint_t)addressSpace.get32(p);
+ p += 4;
+ pint_t cieContentEnd = p + cieLength;
+ if (cieLength == 0xffffffff) {
+ // 0xffffffff means length is really next 8 bytes
+ cieLength = (pint_t)addressSpace.get64(p);
+ p += 8;
+ cieContentEnd = p + cieLength;
+ }
+ if (cieLength == 0)
+ return NULL;
+ // CIE ID is always 0
+ if (addressSpace.get32(p) != 0)
+ return "CIE ID is not zero";
+ p += 4;
+ // Version is always 1 or 3
+ uint8_t version = addressSpace.get8(p);
+ if ((version != 1) && (version != 3))
+ return "CIE version is not 1 or 3";
+ ++p;
+ // save start of augmentation string and find end
+ pint_t strStart = p;
+ while (addressSpace.get8(p) != 0)
+ ++p;
+ ++p;
+ // parse code aligment factor
+ cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
+ // parse data alignment factor
+ cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
+ // parse return address register
+ uint64_t raReg = addressSpace.getULEB128(p, cieContentEnd);
+ assert(raReg < 255 && "return address register too large");
+ cieInfo->returnAddressRegister = (uint8_t)raReg;
+ // parse augmentation data based on augmentation string
+ const char *result = NULL;
+ if (addressSpace.get8(strStart) == 'z') {
+ // parse augmentation data length
+ addressSpace.getULEB128(p, cieContentEnd);
+ for (pint_t s = strStart; addressSpace.get8(s) != '\0'; ++s) {
+ switch (addressSpace.get8(s)) {
+ case 'z':
+ cieInfo->fdesHaveAugmentationData = true;
+ break;
+ case 'P':
+ cieInfo->personalityEncoding = addressSpace.get8(p);
+ ++p;
+ cieInfo->personalityOffsetInCIE = (uint8_t)(p - cie);
+ cieInfo->personality = addressSpace
+ .getEncodedP(p, cieContentEnd, cieInfo->personalityEncoding);
+ break;
+ case 'L':
+ cieInfo->lsdaEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'R':
+ cieInfo->pointerEncoding = addressSpace.get8(p);
+ ++p;
+ break;
+ case 'S':
+ cieInfo->isSignalFrame = true;
+ break;
+ default:
+ // ignore unknown letters
+ break;
+ }
+ }
+ }
+ cieInfo->cieLength = cieContentEnd - cieInfo->cieStart;
+ cieInfo->cieInstructions = p;
+ return result;
+}
+
+
+/// "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) {
+ // clear results
+ memset(results, '\0', sizeof(PrologInfo));
+ PrologInfoStackEntry *rememberStack = NULL;
+
+ // parse CIE then FDE instructions
+ return parseInstructions(addressSpace, cieInfo.cieInstructions,
+ cieInfo.cieStart + cieInfo.cieLength, cieInfo,
+ (pint_t)(-1), rememberStack, results) &&
+ parseInstructions(addressSpace, fdeInfo.fdeInstructions,
+ fdeInfo.fdeStart + fdeInfo.fdeLength, cieInfo,
+ upToPC - fdeInfo.pcStart, rememberStack, results);
+}
+
+/// "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;
+ 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
+ while ((p < instructionsEnd) && (codeOffset < pcoffset)) {
+ uint64_t reg;
+ uint64_t reg2;
+ int64_t offset;
+ uint64_t length;
+ uint8_t opcode = addressSpace.get8(p);
+ uint8_t operand;
+ PrologInfoStackEntry *entry;
+ ++p;
+ switch (opcode) {
+ case DW_CFA_nop:
+ if (logDwarf)
+ fprintf(stderr, "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");
+ 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);
+ 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);
+ 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);
+ 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");
+ 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);
+ 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");
+ return false;
+ }
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if (logDwarf)
+ fprintf(stderr, "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");
+ return false;
+ }
+ results->savedRegisters[reg].location = kRegisterUnused;
+ if (logDwarf)
+ fprintf(stderr, "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");
+ return false;
+ }
+ // <rdar://problem/8456377> DW_CFA_same_value unsupported
+ // "same value" means register was stored in frame, but its current
+ // value has not changed, so no need to restore from frame.
+ // We model this as if the register was never saved.
+ 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);
+ 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");
+ return false;
+ }
+ if (reg2 > kMaxRegisterNumber) {
+ fprintf(stderr,
+ "malformed DW_CFA_register dwarf unwind, reg2 too big\n");
+ 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);
+ break;
+ case DW_CFA_remember_state:
+ // avoid operator new, because that would be an upward dependency
+ entry = (PrologInfoStackEntry *)malloc(sizeof(PrologInfoStackEntry));
+ if (entry != NULL) {
+ entry->next = rememberStack;
+ entry->info = *results;
+ rememberStack = entry;
+ } else {
+ return false;
+ }
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_remember_state\n");
+ break;
+ case DW_CFA_restore_state:
+ if (rememberStack != NULL) {
+ PrologInfoStackEntry *top = rememberStack;
+ *results = top->info;
+ rememberStack = top->next;
+ free((char *)top);
+ } else {
+ return false;
+ }
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_restore_state\n");
+ break;
+ 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");
+ 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);
+ 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");
+ return false;
+ }
+ results->cfaRegister = (uint32_t)reg;
+ if (logDwarf)
+ fprintf(stderr, "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);
+ 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);
+ 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");
+ 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);
+ 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");
+ 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);
+ 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");
+ 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);
+ 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);
+ break;
+ case DW_CFA_val_offset:
+ reg = addressSpace.getULEB128(p, instructionsEnd);
+ 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);
+ 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");
+ 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);
+ 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");
+ 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);
+ 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);
+ 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");
+ 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);
+ break;
+ default:
+ operand = opcode & 0x3F;
+ switch (opcode & 0xC0) {
+ case DW_CFA_offset:
+ reg = operand;
+ 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);
+ 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);
+ break;
+ case DW_CFA_restore:
+ reg = operand;
+ results->savedRegisters[reg] = initialState.savedRegisters[reg];
+ if (logDwarf)
+ fprintf(stderr, "DW_CFA_restore(reg=%" PRIu64 ")\n", reg);
+ break;
+ default:
+ if (logDwarf)
+ fprintf(stderr, "unknown CFA opcode 0x%02X\n", opcode);
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace libunwind
+
+#endif // __DWARF_PARSER_HPP__
diff --git a/libunwind/src/EHHeaderParser.hpp b/libunwind/src/EHHeaderParser.hpp
new file mode 100644
index 00000000000..7945c7ba2fb
--- /dev/null
+++ b/libunwind/src/EHHeaderParser.hpp
@@ -0,0 +1,161 @@
+//===------------------------- EHHeaderParser.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.
+//
+//
+// Parses ELF .eh_frame_hdr sections.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __EHHEADERPARSER_HPP__
+#define __EHHEADERPARSER_HPP__
+
+#include "libunwind.h"
+
+#include "AddressSpace.hpp"
+#include "DwarfParser.hpp"
+
+namespace libunwind {
+
+/// \brief EHHeaderParser does basic parsing of an ELF .eh_frame_hdr section.
+///
+/// See DWARF spec for details:
+/// http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+///
+template <typename A> class EHHeaderParser {
+public:
+ typedef typename A::pint_t pint_t;
+
+ /// Information encoded in the EH frame header.
+ struct EHHeaderInfo {
+ pint_t eh_frame_ptr;
+ size_t fde_count;
+ pint_t table;
+ uint8_t table_enc;
+ };
+
+ static void decodeEHHdr(A &addressSpace, pint_t ehHdrStart, pint_t ehHdrEnd,
+ EHHeaderInfo &ehHdrInfo);
+ static bool findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
+ uint32_t sectionLength,
+ typename CFI_Parser<A>::FDE_Info *fdeInfo,
+ typename CFI_Parser<A>::CIE_Info *cieInfo);
+
+private:
+ static bool decodeTableEntry(A &addressSpace, pint_t &tableEntry,
+ pint_t ehHdrStart, pint_t ehHdrEnd,
+ uint8_t tableEnc,
+ typename CFI_Parser<A>::FDE_Info *fdeInfo,
+ typename CFI_Parser<A>::CIE_Info *cieInfo);
+ static size_t getTableEntrySize(uint8_t tableEnc);
+};
+
+template <typename A>
+void EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
+ pint_t ehHdrEnd, EHHeaderInfo &ehHdrInfo) {
+ pint_t p = ehHdrStart;
+ uint8_t version = addressSpace.get8(p++);
+ if (version != 1)
+ _LIBUNWIND_ABORT("Unsupported .eh_frame_hdr version");
+
+ uint8_t eh_frame_ptr_enc = addressSpace.get8(p++);
+ uint8_t fde_count_enc = addressSpace.get8(p++);
+ ehHdrInfo.table_enc = addressSpace.get8(p++);
+
+ ehHdrInfo.eh_frame_ptr =
+ addressSpace.getEncodedP(p, ehHdrEnd, eh_frame_ptr_enc, ehHdrStart);
+ ehHdrInfo.fde_count =
+ addressSpace.getEncodedP(p, ehHdrEnd, fde_count_enc, ehHdrStart);
+ ehHdrInfo.table = p;
+}
+
+template <typename A>
+bool EHHeaderParser<A>::decodeTableEntry(
+ A &addressSpace, pint_t &tableEntry, pint_t ehHdrStart, pint_t ehHdrEnd,
+ uint8_t tableEnc, typename CFI_Parser<A>::FDE_Info *fdeInfo,
+ typename CFI_Parser<A>::CIE_Info *cieInfo) {
+ // Have to decode the whole FDE for the PC range anyway, so just throw away
+ // the PC start.
+ addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
+ pint_t fde =
+ addressSpace.getEncodedP(tableEntry, ehHdrEnd, tableEnc, ehHdrStart);
+ const char *message =
+ CFI_Parser<A>::decodeFDE(addressSpace, fde, fdeInfo, cieInfo);
+ if (message != NULL) {
+ _LIBUNWIND_DEBUG_LOG("EHHeaderParser::decodeTableEntry: bad fde: %s\n",
+ message);
+ return false;
+ }
+
+ return true;
+}
+
+template <typename A>
+bool EHHeaderParser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehHdrStart,
+ uint32_t sectionLength,
+ typename CFI_Parser<A>::FDE_Info *fdeInfo,
+ typename CFI_Parser<A>::CIE_Info *cieInfo) {
+ pint_t ehHdrEnd = ehHdrStart + sectionLength;
+
+ EHHeaderParser<A>::EHHeaderInfo hdrInfo;
+ EHHeaderParser<A>::decodeEHHdr(addressSpace, ehHdrStart, ehHdrEnd, hdrInfo);
+
+ size_t tableEntrySize = getTableEntrySize(hdrInfo.table_enc);
+ pint_t tableEntry;
+
+ size_t low = 0;
+ for (size_t len = hdrInfo.fde_count; len > 1;) {
+ size_t mid = low + (len / 2);
+ tableEntry = hdrInfo.table + mid * tableEntrySize;
+ pint_t start = addressSpace.getEncodedP(tableEntry, ehHdrEnd,
+ hdrInfo.table_enc, ehHdrStart);
+
+ if (start == pc) {
+ low = mid;
+ break;
+ } else if (start < pc) {
+ low = mid;
+ len -= (len / 2);
+ } else {
+ len /= 2;
+ }
+ }
+
+ tableEntry = hdrInfo.table + low * tableEntrySize;
+ if (decodeTableEntry(addressSpace, tableEntry, ehHdrStart, ehHdrEnd,
+ hdrInfo.table_enc, fdeInfo, cieInfo)) {
+ if (pc >= fdeInfo->pcStart && pc < fdeInfo->pcEnd)
+ return true;
+ }
+
+ return false;
+}
+
+template <typename A>
+size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) {
+ switch (tableEnc & 0x0f) {
+ case DW_EH_PE_sdata2:
+ case DW_EH_PE_udata2:
+ return 4;
+ case DW_EH_PE_sdata4:
+ case DW_EH_PE_udata4:
+ return 8;
+ case DW_EH_PE_sdata8:
+ case DW_EH_PE_udata8:
+ return 16;
+ case DW_EH_PE_sleb128:
+ case DW_EH_PE_uleb128:
+ _LIBUNWIND_ABORT("Can't binary search on variable length encoded data.");
+ case DW_EH_PE_omit:
+ return 0;
+ default:
+ _LIBUNWIND_ABORT("Unknown DWARF encoding for search table.");
+ }
+}
+
+}
+
+#endif
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
new file mode 100644
index 00000000000..4a441b70e4b
--- /dev/null
+++ b/libunwind/src/Registers.hpp
@@ -0,0 +1,1718 @@
+//===----------------------------- 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.
+//
+//
+// Models register sets for supported processors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <strings.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "config.h"
+
+namespace libunwind {
+
+// For emulating 128-bit registers
+struct v128 { uint32_t vec[4]; };
+
+
+/// Registers_x86 holds the register state of a thread in a 32-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86 {
+public:
+ Registers_x86();
+ Registers_x86(const void *registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int) const { return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return 8; }
+
+ uint32_t getSP() const { return _registers.__esp; }
+ void setSP(uint32_t value) { _registers.__esp = value; }
+ uint32_t getIP() const { return _registers.__eip; }
+ void setIP(uint32_t value) { _registers.__eip = value; }
+ uint32_t getEBP() const { return _registers.__ebp; }
+ void setEBP(uint32_t value) { _registers.__ebp = value; }
+ uint32_t getEBX() const { return _registers.__ebx; }
+ void setEBX(uint32_t value) { _registers.__ebx = value; }
+ uint32_t getECX() const { return _registers.__ecx; }
+ void setECX(uint32_t value) { _registers.__ecx = value; }
+ uint32_t getEDX() const { return _registers.__edx; }
+ void setEDX(uint32_t value) { _registers.__edx = value; }
+ uint32_t getESI() const { return _registers.__esi; }
+ void setESI(uint32_t value) { _registers.__esi = value; }
+ uint32_t getEDI() const { return _registers.__edi; }
+ void setEDI(uint32_t value) { _registers.__edi = value; }
+
+private:
+ struct GPRs {
+ unsigned int __eax;
+ unsigned int __ebx;
+ unsigned int __ecx;
+ unsigned int __edx;
+ unsigned int __edi;
+ unsigned int __esi;
+ unsigned int __ebp;
+ unsigned int __esp;
+ unsigned int __ss;
+ unsigned int __eflags;
+ unsigned int __eip;
+ unsigned int __cs;
+ unsigned int __ds;
+ unsigned int __es;
+ unsigned int __fs;
+ unsigned int __gs;
+ };
+
+ GPRs _registers;
+};
+
+inline Registers_x86::Registers_x86(const void *registers) {
+ static_assert(sizeof(Registers_x86) < sizeof(unw_context_t),
+ "x86 registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_x86::Registers_x86() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_x86::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 > 7)
+ return false;
+ return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__eip;
+ case UNW_REG_SP:
+ return _registers.__esp;
+ case UNW_X86_EAX:
+ return _registers.__eax;
+ case UNW_X86_ECX:
+ return _registers.__ecx;
+ case UNW_X86_EDX:
+ return _registers.__edx;
+ case UNW_X86_EBX:
+ return _registers.__ebx;
+ case UNW_X86_EBP:
+ return _registers.__ebp;
+ case UNW_X86_ESP:
+ return _registers.__esp;
+ case UNW_X86_ESI:
+ return _registers.__esi;
+ case UNW_X86_EDI:
+ return _registers.__edi;
+ }
+ _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__eip = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__esp = value;
+ return;
+ case UNW_X86_EAX:
+ _registers.__eax = value;
+ return;
+ case UNW_X86_ECX:
+ _registers.__ecx = value;
+ return;
+ case UNW_X86_EDX:
+ _registers.__edx = value;
+ return;
+ case UNW_X86_EBX:
+ _registers.__ebx = value;
+ return;
+ case UNW_X86_EBP:
+ _registers.__ebp = value;
+ return;
+ case UNW_X86_ESP:
+ _registers.__esp = value;
+ return;
+ case UNW_X86_ESI:
+ _registers.__esi = value;
+ return;
+ case UNW_X86_EDI:
+ _registers.__edi = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline const char *Registers_x86::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "esp";
+ case UNW_X86_EAX:
+ return "eax";
+ case UNW_X86_ECX:
+ return "ecx";
+ case UNW_X86_EDX:
+ return "edx";
+ case UNW_X86_EBX:
+ return "ebx";
+ case UNW_X86_EBP:
+ return "ebp";
+ case UNW_X86_ESP:
+ return "esp";
+ case UNW_X86_ESI:
+ return "esi";
+ case UNW_X86_EDI:
+ return "edi";
+ default:
+ return "unknown register";
+ }
+}
+
+inline double Registers_x86::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int, double) {
+ _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no x86 vector registers");
+}
+
+
+/// Registers_x86_64 holds the register state of a thread in a 64-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86_64 {
+public:
+ Registers_x86_64();
+ Registers_x86_64(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int) const { return false; }
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int) const { return false; }
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return 16; }
+
+ uint64_t getSP() const { return _registers.__rsp; }
+ void setSP(uint64_t value) { _registers.__rsp = value; }
+ uint64_t getIP() const { return _registers.__rip; }
+ void setIP(uint64_t value) { _registers.__rip = value; }
+ uint64_t getRBP() const { return _registers.__rbp; }
+ void setRBP(uint64_t value) { _registers.__rbp = value; }
+ uint64_t getRBX() const { return _registers.__rbx; }
+ void setRBX(uint64_t value) { _registers.__rbx = value; }
+ uint64_t getR12() const { return _registers.__r12; }
+ void setR12(uint64_t value) { _registers.__r12 = value; }
+ uint64_t getR13() const { return _registers.__r13; }
+ void setR13(uint64_t value) { _registers.__r13 = value; }
+ uint64_t getR14() const { return _registers.__r14; }
+ void setR14(uint64_t value) { _registers.__r14 = value; }
+ uint64_t getR15() const { return _registers.__r15; }
+ void setR15(uint64_t value) { _registers.__r15 = value; }
+
+private:
+ struct GPRs {
+ uint64_t __rax;
+ uint64_t __rbx;
+ uint64_t __rcx;
+ uint64_t __rdx;
+ uint64_t __rdi;
+ uint64_t __rsi;
+ uint64_t __rbp;
+ uint64_t __rsp;
+ 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 __rip;
+ uint64_t __rflags;
+ uint64_t __cs;
+ uint64_t __fs;
+ uint64_t __gs;
+ };
+ GPRs _registers;
+};
+
+inline Registers_x86_64::Registers_x86_64(const void *registers) {
+ static_assert(sizeof(Registers_x86_64) < sizeof(unw_context_t),
+ "x86_64 registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_x86_64::Registers_x86_64() {
+ memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_x86_64::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 > 15)
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__rip;
+ case UNW_REG_SP:
+ return _registers.__rsp;
+ case UNW_X86_64_RAX:
+ return _registers.__rax;
+ case UNW_X86_64_RDX:
+ return _registers.__rdx;
+ case UNW_X86_64_RCX:
+ return _registers.__rcx;
+ case UNW_X86_64_RBX:
+ return _registers.__rbx;
+ case UNW_X86_64_RSI:
+ return _registers.__rsi;
+ case UNW_X86_64_RDI:
+ return _registers.__rdi;
+ case UNW_X86_64_RBP:
+ return _registers.__rbp;
+ case UNW_X86_64_RSP:
+ return _registers.__rsp;
+ case UNW_X86_64_R8:
+ return _registers.__r8;
+ case UNW_X86_64_R9:
+ return _registers.__r9;
+ case UNW_X86_64_R10:
+ return _registers.__r10;
+ case UNW_X86_64_R11:
+ return _registers.__r11;
+ case UNW_X86_64_R12:
+ return _registers.__r12;
+ case UNW_X86_64_R13:
+ return _registers.__r13;
+ case UNW_X86_64_R14:
+ return _registers.__r14;
+ case UNW_X86_64_R15:
+ return _registers.__r15;
+ }
+ _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__rip = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__rsp = value;
+ return;
+ case UNW_X86_64_RAX:
+ _registers.__rax = value;
+ return;
+ case UNW_X86_64_RDX:
+ _registers.__rdx = value;
+ return;
+ case UNW_X86_64_RCX:
+ _registers.__rcx = value;
+ return;
+ case UNW_X86_64_RBX:
+ _registers.__rbx = value;
+ return;
+ case UNW_X86_64_RSI:
+ _registers.__rsi = value;
+ return;
+ case UNW_X86_64_RDI:
+ _registers.__rdi = value;
+ return;
+ case UNW_X86_64_RBP:
+ _registers.__rbp = value;
+ return;
+ case UNW_X86_64_RSP:
+ _registers.__rsp = value;
+ return;
+ case UNW_X86_64_R8:
+ _registers.__r8 = value;
+ return;
+ case UNW_X86_64_R9:
+ _registers.__r9 = value;
+ return;
+ case UNW_X86_64_R10:
+ _registers.__r10 = value;
+ return;
+ case UNW_X86_64_R11:
+ _registers.__r11 = value;
+ return;
+ case UNW_X86_64_R12:
+ _registers.__r12 = value;
+ return;
+ case UNW_X86_64_R13:
+ _registers.__r13 = value;
+ return;
+ case UNW_X86_64_R14:
+ _registers.__r14 = value;
+ return;
+ case UNW_X86_64_R15:
+ _registers.__r15 = value;
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline const char *Registers_x86_64::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "rip";
+ case UNW_REG_SP:
+ return "rsp";
+ case UNW_X86_64_RAX:
+ return "rax";
+ case UNW_X86_64_RDX:
+ return "rdx";
+ case UNW_X86_64_RCX:
+ return "rcx";
+ case UNW_X86_64_RBX:
+ return "rbx";
+ case UNW_X86_64_RSI:
+ return "rsi";
+ case UNW_X86_64_RDI:
+ return "rdi";
+ case UNW_X86_64_RBP:
+ return "rbp";
+ case UNW_X86_64_RSP:
+ return "rsp";
+ case UNW_X86_64_R8:
+ return "r8";
+ case UNW_X86_64_R9:
+ return "r9";
+ case UNW_X86_64_R10:
+ return "r10";
+ case UNW_X86_64_R11:
+ return "r11";
+ case UNW_X86_64_R12:
+ return "r12";
+ case UNW_X86_64_R13:
+ return "r13";
+ case UNW_X86_64_R14:
+ return "r14";
+ case UNW_X86_64_R15:
+ return "r15";
+ default:
+ return "unknown register";
+ }
+}
+
+inline double Registers_x86_64::getFloatRegister(int) const {
+ _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline void Registers_x86_64::setFloatRegister(int, double) {
+ _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no x86_64 vector registers");
+}
+
+inline void Registers_x86_64::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no x86_64 vector registers");
+}
+
+
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC
+/// process.
+class _LIBUNWIND_HIDDEN Registers_ppc {
+public:
+ Registers_ppc();
+ Registers_ppc(const void *registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num) const;
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return 112; }
+
+ uint64_t getSP() const { return _registers.__r1; }
+ void setSP(uint32_t value) { _registers.__r1 = value; }
+ uint64_t getIP() const { return _registers.__srr0; }
+ void setIP(uint32_t value) { _registers.__srr0 = value; }
+
+private:
+ struct ppc_thread_state_t {
+ unsigned int __srr0; /* Instruction address register (PC) */
+ unsigned int __srr1; /* Machine state register (supervisor) */
+ unsigned int __r0;
+ unsigned int __r1;
+ unsigned int __r2;
+ unsigned int __r3;
+ unsigned int __r4;
+ unsigned int __r5;
+ unsigned int __r6;
+ unsigned int __r7;
+ unsigned int __r8;
+ unsigned int __r9;
+ unsigned int __r10;
+ unsigned int __r11;
+ unsigned int __r12;
+ unsigned int __r13;
+ unsigned int __r14;
+ unsigned int __r15;
+ unsigned int __r16;
+ unsigned int __r17;
+ unsigned int __r18;
+ unsigned int __r19;
+ unsigned int __r20;
+ unsigned int __r21;
+ unsigned int __r22;
+ unsigned int __r23;
+ unsigned int __r24;
+ unsigned int __r25;
+ unsigned int __r26;
+ unsigned int __r27;
+ unsigned int __r28;
+ unsigned int __r29;
+ unsigned int __r30;
+ unsigned int __r31;
+ unsigned int __cr; /* Condition register */
+ unsigned int __xer; /* User's integer exception register */
+ unsigned int __lr; /* Link register */
+ unsigned int __ctr; /* Count register */
+ unsigned int __mq; /* MQ register (601 only) */
+ unsigned int __vrsave; /* Vector Save Register */
+ };
+
+ struct ppc_float_state_t {
+ double __fpregs[32];
+
+ unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
+ unsigned int __fpscr; /* floating point status register */
+ };
+
+ ppc_thread_state_t _registers;
+ ppc_float_state_t _floatRegisters;
+ v128 _vectorRegisters[32]; // offset 424
+};
+
+inline Registers_ppc::Registers_ppc(const void *registers) {
+ static_assert(sizeof(Registers_ppc) < sizeof(unw_context_t),
+ "ppc registers do not fit into unw_context_t");
+ memcpy(&_registers, static_cast<const uint8_t *>(registers),
+ sizeof(_registers));
+ static_assert(sizeof(ppc_thread_state_t) == 160,
+ "expected float register offset to be 160");
+ memcpy(&_floatRegisters,
+ static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t),
+ sizeof(_floatRegisters));
+ static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424,
+ "expected vector register offset to be 424 bytes");
+ memcpy(_vectorRegisters,
+ static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t) +
+ sizeof(ppc_float_state_t),
+ sizeof(_vectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc() {
+ memset(&_registers, 0, sizeof(_registers));
+ memset(&_floatRegisters, 0, sizeof(_floatRegisters));
+ memset(&_vectorRegisters, 0, sizeof(_vectorRegisters));
+}
+
+inline bool Registers_ppc::validRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return true;
+ if (regNum == UNW_REG_SP)
+ return true;
+ if (regNum == UNW_PPC_VRSAVE)
+ return true;
+ if (regNum < 0)
+ return false;
+ if (regNum <= UNW_PPC_R31)
+ return true;
+ if (regNum == UNW_PPC_MQ)
+ return true;
+ if (regNum == UNW_PPC_LR)
+ return true;
+ if (regNum == UNW_PPC_CTR)
+ return true;
+ if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7))
+ return true;
+ return false;
+}
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return _registers.__srr0;
+ case UNW_REG_SP:
+ return _registers.__r1;
+ case UNW_PPC_R0:
+ return _registers.__r0;
+ case UNW_PPC_R1:
+ return _registers.__r1;
+ case UNW_PPC_R2:
+ return _registers.__r2;
+ case UNW_PPC_R3:
+ return _registers.__r3;
+ case UNW_PPC_R4:
+ return _registers.__r4;
+ case UNW_PPC_R5:
+ return _registers.__r5;
+ case UNW_PPC_R6:
+ return _registers.__r6;
+ case UNW_PPC_R7:
+ return _registers.__r7;
+ case UNW_PPC_R8:
+ return _registers.__r8;
+ case UNW_PPC_R9:
+ return _registers.__r9;
+ case UNW_PPC_R10:
+ return _registers.__r10;
+ case UNW_PPC_R11:
+ return _registers.__r11;
+ case UNW_PPC_R12:
+ return _registers.__r12;
+ case UNW_PPC_R13:
+ return _registers.__r13;
+ case UNW_PPC_R14:
+ return _registers.__r14;
+ case UNW_PPC_R15:
+ return _registers.__r15;
+ case UNW_PPC_R16:
+ return _registers.__r16;
+ case UNW_PPC_R17:
+ return _registers.__r17;
+ case UNW_PPC_R18:
+ return _registers.__r18;
+ case UNW_PPC_R19:
+ return _registers.__r19;
+ case UNW_PPC_R20:
+ return _registers.__r20;
+ case UNW_PPC_R21:
+ return _registers.__r21;
+ case UNW_PPC_R22:
+ return _registers.__r22;
+ case UNW_PPC_R23:
+ return _registers.__r23;
+ case UNW_PPC_R24:
+ return _registers.__r24;
+ case UNW_PPC_R25:
+ return _registers.__r25;
+ case UNW_PPC_R26:
+ return _registers.__r26;
+ case UNW_PPC_R27:
+ return _registers.__r27;
+ case UNW_PPC_R28:
+ return _registers.__r28;
+ case UNW_PPC_R29:
+ return _registers.__r29;
+ case UNW_PPC_R30:
+ return _registers.__r30;
+ case UNW_PPC_R31:
+ return _registers.__r31;
+ case UNW_PPC_LR:
+ return _registers.__lr;
+ case UNW_PPC_CR0:
+ return (_registers.__cr & 0xF0000000);
+ case UNW_PPC_CR1:
+ return (_registers.__cr & 0x0F000000);
+ case UNW_PPC_CR2:
+ return (_registers.__cr & 0x00F00000);
+ case UNW_PPC_CR3:
+ return (_registers.__cr & 0x000F0000);
+ case UNW_PPC_CR4:
+ return (_registers.__cr & 0x0000F000);
+ case UNW_PPC_CR5:
+ return (_registers.__cr & 0x00000F00);
+ case UNW_PPC_CR6:
+ return (_registers.__cr & 0x000000F0);
+ case UNW_PPC_CR7:
+ return (_registers.__cr & 0x0000000F);
+ case UNW_PPC_VRSAVE:
+ return _registers.__vrsave;
+ }
+ _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value) {
+ //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
+ switch (regNum) {
+ case UNW_REG_IP:
+ _registers.__srr0 = value;
+ return;
+ case UNW_REG_SP:
+ _registers.__r1 = value;
+ return;
+ case UNW_PPC_R0:
+ _registers.__r0 = value;
+ return;
+ case UNW_PPC_R1:
+ _registers.__r1 = value;
+ return;
+ case UNW_PPC_R2:
+ _registers.__r2 = value;
+ return;
+ case UNW_PPC_R3:
+ _registers.__r3 = value;
+ return;
+ case UNW_PPC_R4:
+ _registers.__r4 = value;
+ return;
+ case UNW_PPC_R5:
+ _registers.__r5 = value;
+ return;
+ case UNW_PPC_R6:
+ _registers.__r6 = value;
+ return;
+ case UNW_PPC_R7:
+ _registers.__r7 = value;
+ return;
+ case UNW_PPC_R8:
+ _registers.__r8 = value;
+ return;
+ case UNW_PPC_R9:
+ _registers.__r9 = value;
+ return;
+ case UNW_PPC_R10:
+ _registers.__r10 = value;
+ return;
+ case UNW_PPC_R11:
+ _registers.__r11 = value;
+ return;
+ case UNW_PPC_R12:
+ _registers.__r12 = value;
+ return;
+ case UNW_PPC_R13:
+ _registers.__r13 = value;
+ return;
+ case UNW_PPC_R14:
+ _registers.__r14 = value;
+ return;
+ case UNW_PPC_R15:
+ _registers.__r15 = value;
+ return;
+ case UNW_PPC_R16:
+ _registers.__r16 = value;
+ return;
+ case UNW_PPC_R17:
+ _registers.__r17 = value;
+ return;
+ case UNW_PPC_R18:
+ _registers.__r18 = value;
+ return;
+ case UNW_PPC_R19:
+ _registers.__r19 = value;
+ return;
+ case UNW_PPC_R20:
+ _registers.__r20 = value;
+ return;
+ case UNW_PPC_R21:
+ _registers.__r21 = value;
+ return;
+ case UNW_PPC_R22:
+ _registers.__r22 = value;
+ return;
+ case UNW_PPC_R23:
+ _registers.__r23 = value;
+ return;
+ case UNW_PPC_R24:
+ _registers.__r24 = value;
+ return;
+ case UNW_PPC_R25:
+ _registers.__r25 = value;
+ return;
+ case UNW_PPC_R26:
+ _registers.__r26 = value;
+ return;
+ case UNW_PPC_R27:
+ _registers.__r27 = value;
+ return;
+ case UNW_PPC_R28:
+ _registers.__r28 = value;
+ return;
+ case UNW_PPC_R29:
+ _registers.__r29 = value;
+ return;
+ case UNW_PPC_R30:
+ _registers.__r30 = value;
+ return;
+ case UNW_PPC_R31:
+ _registers.__r31 = value;
+ return;
+ case UNW_PPC_MQ:
+ _registers.__mq = value;
+ return;
+ case UNW_PPC_LR:
+ _registers.__lr = value;
+ return;
+ case UNW_PPC_CTR:
+ _registers.__ctr = value;
+ return;
+ case UNW_PPC_CR0:
+ _registers.__cr &= 0x0FFFFFFF;
+ _registers.__cr |= (value & 0xF0000000);
+ return;
+ case UNW_PPC_CR1:
+ _registers.__cr &= 0xF0FFFFFF;
+ _registers.__cr |= (value & 0x0F000000);
+ return;
+ case UNW_PPC_CR2:
+ _registers.__cr &= 0xFF0FFFFF;
+ _registers.__cr |= (value & 0x00F00000);
+ return;
+ case UNW_PPC_CR3:
+ _registers.__cr &= 0xFFF0FFFF;
+ _registers.__cr |= (value & 0x000F0000);
+ return;
+ case UNW_PPC_CR4:
+ _registers.__cr &= 0xFFFF0FFF;
+ _registers.__cr |= (value & 0x0000F000);
+ return;
+ case UNW_PPC_CR5:
+ _registers.__cr &= 0xFFFFF0FF;
+ _registers.__cr |= (value & 0x00000F00);
+ return;
+ case UNW_PPC_CR6:
+ _registers.__cr &= 0xFFFFFF0F;
+ _registers.__cr |= (value & 0x000000F0);
+ return;
+ case UNW_PPC_CR7:
+ _registers.__cr &= 0xFFFFFFF0;
+ _registers.__cr |= (value & 0x0000000F);
+ return;
+ case UNW_PPC_VRSAVE:
+ _registers.__vrsave = value;
+ return;
+ // not saved
+ return;
+ case UNW_PPC_XER:
+ _registers.__xer = value;
+ return;
+ case UNW_PPC_AP:
+ case UNW_PPC_VSCR:
+ case UNW_PPC_SPEFSCR:
+ // not saved
+ return;
+ }
+ _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const {
+ if (regNum < UNW_PPC_F0)
+ return false;
+ if (regNum > UNW_PPC_F31)
+ return false;
+ return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const {
+ assert(validFloatRegister(regNum));
+ return _floatRegisters.__fpregs[regNum - UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value) {
+ assert(validFloatRegister(regNum));
+ _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value;
+}
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const {
+ if (regNum < UNW_PPC_V0)
+ return false;
+ if (regNum > UNW_PPC_V31)
+ return false;
+ return true;
+}
+
+inline v128 Registers_ppc::getVectorRegister(int regNum) const {
+ assert(validVectorRegister(regNum));
+ v128 result = _vectorRegisters[regNum - UNW_PPC_V0];
+ return result;
+}
+
+inline void Registers_ppc::setVectorRegister(int regNum, v128 value) {
+ assert(validVectorRegister(regNum));
+ _vectorRegisters[regNum - UNW_PPC_V0] = value;
+}
+
+inline const char *Registers_ppc::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "ip";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_PPC_R0:
+ return "r0";
+ case UNW_PPC_R1:
+ return "r1";
+ case UNW_PPC_R2:
+ return "r2";
+ case UNW_PPC_R3:
+ return "r3";
+ case UNW_PPC_R4:
+ return "r4";
+ case UNW_PPC_R5:
+ return "r5";
+ case UNW_PPC_R6:
+ return "r6";
+ case UNW_PPC_R7:
+ return "r7";
+ case UNW_PPC_R8:
+ return "r8";
+ case UNW_PPC_R9:
+ return "r9";
+ case UNW_PPC_R10:
+ return "r10";
+ case UNW_PPC_R11:
+ return "r11";
+ case UNW_PPC_R12:
+ return "r12";
+ case UNW_PPC_R13:
+ return "r13";
+ case UNW_PPC_R14:
+ return "r14";
+ case UNW_PPC_R15:
+ return "r15";
+ case UNW_PPC_R16:
+ return "r16";
+ case UNW_PPC_R17:
+ return "r17";
+ case UNW_PPC_R18:
+ return "r18";
+ case UNW_PPC_R19:
+ return "r19";
+ case UNW_PPC_R20:
+ return "r20";
+ case UNW_PPC_R21:
+ return "r21";
+ case UNW_PPC_R22:
+ return "r22";
+ case UNW_PPC_R23:
+ return "r23";
+ case UNW_PPC_R24:
+ return "r24";
+ case UNW_PPC_R25:
+ return "r25";
+ case UNW_PPC_R26:
+ return "r26";
+ case UNW_PPC_R27:
+ return "r27";
+ case UNW_PPC_R28:
+ return "r28";
+ case UNW_PPC_R29:
+ return "r29";
+ case UNW_PPC_R30:
+ return "r30";
+ case UNW_PPC_R31:
+ return "r31";
+ case UNW_PPC_F0:
+ return "fp0";
+ case UNW_PPC_F1:
+ return "fp1";
+ case UNW_PPC_F2:
+ return "fp2";
+ case UNW_PPC_F3:
+ return "fp3";
+ case UNW_PPC_F4:
+ return "fp4";
+ case UNW_PPC_F5:
+ return "fp5";
+ case UNW_PPC_F6:
+ return "fp6";
+ case UNW_PPC_F7:
+ return "fp7";
+ case UNW_PPC_F8:
+ return "fp8";
+ case UNW_PPC_F9:
+ return "fp9";
+ case UNW_PPC_F10:
+ return "fp10";
+ case UNW_PPC_F11:
+ return "fp11";
+ case UNW_PPC_F12:
+ return "fp12";
+ case UNW_PPC_F13:
+ return "fp13";
+ case UNW_PPC_F14:
+ return "fp14";
+ case UNW_PPC_F15:
+ return "fp15";
+ case UNW_PPC_F16:
+ return "fp16";
+ case UNW_PPC_F17:
+ return "fp17";
+ case UNW_PPC_F18:
+ return "fp18";
+ case UNW_PPC_F19:
+ return "fp19";
+ case UNW_PPC_F20:
+ return "fp20";
+ case UNW_PPC_F21:
+ return "fp21";
+ case UNW_PPC_F22:
+ return "fp22";
+ case UNW_PPC_F23:
+ return "fp23";
+ case UNW_PPC_F24:
+ return "fp24";
+ case UNW_PPC_F25:
+ return "fp25";
+ case UNW_PPC_F26:
+ return "fp26";
+ case UNW_PPC_F27:
+ return "fp27";
+ case UNW_PPC_F28:
+ return "fp28";
+ case UNW_PPC_F29:
+ return "fp29";
+ case UNW_PPC_F30:
+ return "fp30";
+ case UNW_PPC_F31:
+ return "fp31";
+ case UNW_PPC_LR:
+ return "lr";
+ default:
+ return "unknown register";
+ }
+
+}
+
+
+/// Registers_arm64 holds the register state of a thread in a 64-bit arm
+/// process.
+class _LIBUNWIND_HIDDEN Registers_arm64 {
+public:
+ Registers_arm64();
+ Registers_arm64(const void *registers);
+
+ bool validRegister(int num) const;
+ uint64_t getRegister(int num) const;
+ void setRegister(int num, uint64_t value);
+ bool validFloatRegister(int num) const;
+ double getFloatRegister(int num) const;
+ void setFloatRegister(int num, double value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto();
+ static int lastDwarfRegNum() { return 95; }
+
+ uint64_t getSP() const { return _registers.__sp; }
+ void setSP(uint64_t value) { _registers.__sp = value; }
+ uint64_t getIP() const { return _registers.__pc; }
+ void setIP(uint64_t value) { _registers.__pc = value; }
+ uint64_t getFP() const { return _registers.__fp; }
+ void setFP(uint64_t value) { _registers.__fp = value; }
+
+private:
+ struct GPRs {
+ uint64_t __x[29]; // x0-x28
+ uint64_t __fp; // Frame pointer x29
+ uint64_t __lr; // Link register x30
+ uint64_t __sp; // Stack pointer x31
+ uint64_t __pc; // Program counter
+ uint64_t padding; // 16-byte align
+ };
+
+ GPRs _registers;
+ double _vectorHalfRegisters[32];
+ // Currently only the lower double in 128-bit vectore registers
+ // is perserved during unwinding. We could define new register
+ // numbers (> 96) which mean whole vector registers, then this
+ // struct would need to change to contain whole vector registers.
+};
+
+inline Registers_arm64::Registers_arm64(const void *registers) {
+ static_assert(sizeof(Registers_arm64) < sizeof(unw_context_t),
+ "arm64 registers do not fit into unw_context_t");
+ memcpy(&_registers, registers, sizeof(_registers));
+ static_assert(sizeof(GPRs) == 0x110,
+ "expected VFP registers to be at offset 272");
+ memcpy(_vectorHalfRegisters,
+ static_cast<const uint8_t *>(registers) + sizeof(GPRs),
+ sizeof(_vectorHalfRegisters));
+}
+
+inline Registers_arm64::Registers_arm64() {
+ memset(&_registers, 0, sizeof(_registers));
+ memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters));
+}
+
+inline bool Registers_arm64::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 > 95)
+ return false;
+ if ((regNum > 31) && (regNum < 64))
+ return false;
+ return true;
+}
+
+inline uint64_t Registers_arm64::getRegister(int regNum) const {
+ if (regNum == UNW_REG_IP)
+ return _registers.__pc;
+ if (regNum == UNW_REG_SP)
+ return _registers.__sp;
+ if ((regNum >= 0) && (regNum < 32))
+ return _registers.__x[regNum];
+ _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
+ if (regNum == UNW_REG_IP)
+ _registers.__pc = value;
+ else if (regNum == UNW_REG_SP)
+ _registers.__sp = value;
+ else if ((regNum >= 0) && (regNum < 32))
+ _registers.__x[regNum] = value;
+ else
+ _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline const char *Registers_arm64::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ return "pc";
+ case UNW_REG_SP:
+ return "sp";
+ case UNW_ARM64_X0:
+ return "x0";
+ case UNW_ARM64_X1:
+ return "x1";
+ case UNW_ARM64_X2:
+ return "x2";
+ case UNW_ARM64_X3:
+ return "x3";
+ case UNW_ARM64_X4:
+ return "x4";
+ case UNW_ARM64_X5:
+ return "x5";
+ case UNW_ARM64_X6:
+ return "x6";
+ case UNW_ARM64_X7:
+ return "x7";
+ case UNW_ARM64_X8:
+ return "x8";
+ case UNW_ARM64_X9:
+ return "x9";
+ case UNW_ARM64_X10:
+ return "x10";
+ case UNW_ARM64_X11:
+ return "x11";
+ case UNW_ARM64_X12:
+ return "x12";
+ case UNW_ARM64_X13:
+ return "x13";
+ case UNW_ARM64_X14:
+ return "x14";
+ case UNW_ARM64_X15:
+ return "x15";
+ case UNW_ARM64_X16:
+ return "x16";
+ case UNW_ARM64_X17:
+ return "x17";
+ case UNW_ARM64_X18:
+ return "x18";
+ case UNW_ARM64_X19:
+ return "x19";
+ case UNW_ARM64_X20:
+ return "x20";
+ case UNW_ARM64_X21:
+ return "x21";
+ case UNW_ARM64_X22:
+ return "x22";
+ case UNW_ARM64_X23:
+ return "x23";
+ case UNW_ARM64_X24:
+ return "x24";
+ case UNW_ARM64_X25:
+ return "x25";
+ case UNW_ARM64_X26:
+ return "x26";
+ case UNW_ARM64_X27:
+ return "x27";
+ case UNW_ARM64_X28:
+ return "x28";
+ case UNW_ARM64_X29:
+ return "fp";
+ case UNW_ARM64_X30:
+ return "lr";
+ case UNW_ARM64_X31:
+ return "sp";
+ case UNW_ARM64_D0:
+ return "d0";
+ case UNW_ARM64_D1:
+ return "d1";
+ case UNW_ARM64_D2:
+ return "d2";
+ case UNW_ARM64_D3:
+ return "d3";
+ case UNW_ARM64_D4:
+ return "d4";
+ case UNW_ARM64_D5:
+ return "d5";
+ case UNW_ARM64_D6:
+ return "d6";
+ case UNW_ARM64_D7:
+ return "d7";
+ case UNW_ARM64_D8:
+ return "d8";
+ case UNW_ARM64_D9:
+ return "d9";
+ case UNW_ARM64_D10:
+ return "d10";
+ case UNW_ARM64_D11:
+ return "d11";
+ case UNW_ARM64_D12:
+ return "d12";
+ case UNW_ARM64_D13:
+ return "d13";
+ case UNW_ARM64_D14:
+ return "d14";
+ case UNW_ARM64_D15:
+ return "d15";
+ case UNW_ARM64_D16:
+ return "d16";
+ case UNW_ARM64_D17:
+ return "d17";
+ case UNW_ARM64_D18:
+ return "d18";
+ case UNW_ARM64_D19:
+ return "d19";
+ case UNW_ARM64_D20:
+ return "d20";
+ case UNW_ARM64_D21:
+ return "d21";
+ case UNW_ARM64_D22:
+ return "d22";
+ case UNW_ARM64_D23:
+ return "d23";
+ case UNW_ARM64_D24:
+ return "d24";
+ case UNW_ARM64_D25:
+ return "d25";
+ case UNW_ARM64_D26:
+ return "d26";
+ case UNW_ARM64_D27:
+ return "d27";
+ case UNW_ARM64_D28:
+ return "d28";
+ case UNW_ARM64_D29:
+ return "d29";
+ case UNW_ARM64_D30:
+ return "d30";
+ case UNW_ARM64_D31:
+ return "d31";
+ default:
+ return "unknown register";
+ }
+}
+
+inline bool Registers_arm64::validFloatRegister(int regNum) const {
+ if (regNum < UNW_ARM64_D0)
+ return false;
+ if (regNum > UNW_ARM64_D31)
+ return false;
+ return true;
+}
+
+inline double Registers_arm64::getFloatRegister(int regNum) const {
+ assert(validFloatRegister(regNum));
+ return _vectorHalfRegisters[regNum - UNW_ARM64_D0];
+}
+
+inline void Registers_arm64::setFloatRegister(int regNum, double value) {
+ assert(validFloatRegister(regNum));
+ _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value;
+}
+
+inline bool Registers_arm64::validVectorRegister(int) const {
+ return false;
+}
+
+inline v128 Registers_arm64::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+
+inline void Registers_arm64::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+
+/// Registers_arm holds the register state of a thread in a 32-bit arm
+/// process.
+///
+/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit,
+/// this uses more memory than required.
+class _LIBUNWIND_HIDDEN Registers_arm {
+public:
+ Registers_arm();
+ Registers_arm(const void *registers);
+
+ bool validRegister(int num) const;
+ uint32_t getRegister(int num);
+ void setRegister(int num, uint32_t value);
+ bool validFloatRegister(int num) const;
+ unw_fpreg_t getFloatRegister(int num);
+ void setFloatRegister(int num, unw_fpreg_t value);
+ bool validVectorRegister(int num) const;
+ v128 getVectorRegister(int num) const;
+ void setVectorRegister(int num, v128 value);
+ const char *getRegisterName(int num);
+ void jumpto() {
+ restoreSavedFloatRegisters();
+ restoreCoreAndJumpTo();
+ }
+
+ uint32_t getSP() const { return _registers.__sp; }
+ void setSP(uint32_t value) { _registers.__sp = value; }
+ uint32_t getIP() const { return _registers.__pc; }
+ void setIP(uint32_t value) { _registers.__pc = value; }
+
+ void saveVFPAsX() {
+ assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
+ _use_X_for_vfp_save = true;
+ }
+
+ void restoreSavedFloatRegisters() {
+ if (_saved_vfp_d0_d15) {
+ if (_use_X_for_vfp_save)
+ restoreVFPWithFLDMX(_vfp_d0_d15_pad);
+ else
+ restoreVFPWithFLDMD(_vfp_d0_d15_pad);
+ }
+ if (_saved_vfp_d16_d31)
+ restoreVFPv3(_vfp_d16_d31);
+ if (_saved_iwmmx)
+ restoreiWMMX(_iwmmx);
+ if (_saved_iwmmx_control)
+ restoreiWMMXControl(_iwmmx_control);
+ }
+
+private:
+ struct GPRs {
+ uint32_t __r[13]; // r0-r12
+ uint32_t __sp; // Stack pointer r13
+ uint32_t __lr; // Link register r14
+ uint32_t __pc; // Program counter r15
+ };
+
+ 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*);
+ static void restoreiWMMX(unw_fpreg_t*);
+ static void restoreiWMMXControl(uint32_t*);
+ void restoreCoreAndJumpTo();
+
+ // ARM registers
+ GPRs _registers;
+
+ // We save floating point registers lazily because we can't know ahead of
+ // time which ones are used. See EHABI #4.7.
+
+ // Whether D0-D15 are saved in the FTSMX instead of FSTMD format.
+ //
+ // See EHABI #7.5 that explains how matching instruction sequences for load
+ // and store need to be used to correctly restore the exact register bits.
+ bool _use_X_for_vfp_save;
+ // Whether VFP D0-D15 are saved.
+ 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];
+ // iWMMX registers
+ unw_fpreg_t _iwmmx[16];
+ // iWMMX control registers
+ uint32_t _iwmmx_control[4];
+};
+
+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) {
+ static_assert(sizeof(Registers_arm) < sizeof(unw_context_t),
+ "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));
+ memset(&_iwmmx, 0, sizeof(_iwmmx));
+ memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+}
+
+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) {
+ 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));
+ memset(&_iwmmx, 0, sizeof(_iwmmx));
+ memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+}
+
+inline bool Registers_arm::validRegister(int regNum) const {
+ // Returns true for all non-VFP registers supported by the EHABI
+ // 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 (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3)
+ return true;
+ return false;
+}
+
+inline uint32_t Registers_arm::getRegister(int regNum) {
+ 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 (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+ if (!_saved_iwmmx_control) {
+ _saved_iwmmx_control = true;
+ saveiWMMXControl(_iwmmx_control);
+ }
+ return _iwmmx_control[regNum - UNW_ARM_WC0];
+ }
+ _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline void Registers_arm::setRegister(int regNum, uint32_t value) {
+ if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+ _registers.__sp = value;
+ else if (regNum == UNW_ARM_LR)
+ _registers.__lr = value;
+ else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+ _registers.__pc = value;
+ else if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
+ _registers.__r[regNum] = value;
+ else 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");
+}
+
+inline const char *Registers_arm::getRegisterName(int regNum) {
+ switch (regNum) {
+ case UNW_REG_IP:
+ case UNW_ARM_IP: // UNW_ARM_R15 is alias
+ return "pc";
+ case UNW_ARM_LR: // UNW_ARM_R14 is alias
+ return "lr";
+ case UNW_REG_SP:
+ case UNW_ARM_SP: // UNW_ARM_R13 is alias
+ return "sp";
+ case UNW_ARM_R0:
+ return "r0";
+ case UNW_ARM_R1:
+ return "r1";
+ case UNW_ARM_R2:
+ return "r2";
+ case UNW_ARM_R3:
+ return "r3";
+ case UNW_ARM_R4:
+ return "r4";
+ case UNW_ARM_R5:
+ return "r5";
+ case UNW_ARM_R6:
+ return "r6";
+ case UNW_ARM_R7:
+ return "r7";
+ case UNW_ARM_R8:
+ return "r8";
+ case UNW_ARM_R9:
+ return "r9";
+ case UNW_ARM_R10:
+ return "r10";
+ case UNW_ARM_R11:
+ return "r11";
+ case UNW_ARM_R12:
+ return "r12";
+ case UNW_ARM_S0:
+ return "s0";
+ case UNW_ARM_S1:
+ return "s1";
+ case UNW_ARM_S2:
+ return "s2";
+ case UNW_ARM_S3:
+ return "s3";
+ case UNW_ARM_S4:
+ return "s4";
+ case UNW_ARM_S5:
+ return "s5";
+ case UNW_ARM_S6:
+ return "s6";
+ case UNW_ARM_S7:
+ return "s7";
+ case UNW_ARM_S8:
+ return "s8";
+ case UNW_ARM_S9:
+ return "s9";
+ case UNW_ARM_S10:
+ return "s10";
+ case UNW_ARM_S11:
+ return "s11";
+ case UNW_ARM_S12:
+ return "s12";
+ case UNW_ARM_S13:
+ return "s13";
+ case UNW_ARM_S14:
+ return "s14";
+ case UNW_ARM_S15:
+ return "s15";
+ case UNW_ARM_S16:
+ return "s16";
+ case UNW_ARM_S17:
+ return "s17";
+ case UNW_ARM_S18:
+ return "s18";
+ case UNW_ARM_S19:
+ return "s19";
+ case UNW_ARM_S20:
+ return "s20";
+ case UNW_ARM_S21:
+ return "s21";
+ case UNW_ARM_S22:
+ return "s22";
+ case UNW_ARM_S23:
+ return "s23";
+ case UNW_ARM_S24:
+ return "s24";
+ case UNW_ARM_S25:
+ return "s25";
+ case UNW_ARM_S26:
+ return "s26";
+ case UNW_ARM_S27:
+ return "s27";
+ case UNW_ARM_S28:
+ return "s28";
+ case UNW_ARM_S29:
+ return "s29";
+ case UNW_ARM_S30:
+ return "s30";
+ case UNW_ARM_S31:
+ return "s31";
+ case UNW_ARM_D0:
+ return "d0";
+ case UNW_ARM_D1:
+ return "d1";
+ case UNW_ARM_D2:
+ return "d2";
+ case UNW_ARM_D3:
+ return "d3";
+ case UNW_ARM_D4:
+ return "d4";
+ case UNW_ARM_D5:
+ return "d5";
+ case UNW_ARM_D6:
+ return "d6";
+ case UNW_ARM_D7:
+ return "d7";
+ case UNW_ARM_D8:
+ return "d8";
+ case UNW_ARM_D9:
+ return "d9";
+ case UNW_ARM_D10:
+ return "d10";
+ case UNW_ARM_D11:
+ return "d11";
+ case UNW_ARM_D12:
+ return "d12";
+ case UNW_ARM_D13:
+ return "d13";
+ case UNW_ARM_D14:
+ return "d14";
+ case UNW_ARM_D15:
+ return "d15";
+ case UNW_ARM_D16:
+ return "d16";
+ case UNW_ARM_D17:
+ return "d17";
+ case UNW_ARM_D18:
+ return "d18";
+ case UNW_ARM_D19:
+ return "d19";
+ case UNW_ARM_D20:
+ return "d20";
+ case UNW_ARM_D21:
+ return "d21";
+ case UNW_ARM_D22:
+ return "d22";
+ case UNW_ARM_D23:
+ return "d23";
+ case UNW_ARM_D24:
+ return "d24";
+ case UNW_ARM_D25:
+ return "d25";
+ case UNW_ARM_D26:
+ return "d26";
+ case UNW_ARM_D27:
+ return "d27";
+ case UNW_ARM_D28:
+ return "d28";
+ case UNW_ARM_D29:
+ return "d29";
+ case UNW_ARM_D30:
+ return "d30";
+ case UNW_ARM_D31:
+ return "d31";
+ default:
+ return "unknown register";
+ }
+}
+
+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));
+}
+
+inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) {
+ if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) {
+ if (!_saved_vfp_d0_d15) {
+ _saved_vfp_d0_d15 = true;
+ if (_use_X_for_vfp_save)
+ saveVFPWithFSTMX(_vfp_d0_d15_pad);
+ else
+ 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 (!_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 (!_saved_iwmmx) {
+ _saved_iwmmx = true;
+ saveiWMMX(_iwmmx);
+ }
+ return _iwmmx[regNum - UNW_ARM_WR0];
+ } else {
+ _LIBUNWIND_ABORT("Unknown ARM float register");
+ }
+}
+
+inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) {
+ if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) {
+ if (!_saved_vfp_d0_d15) {
+ _saved_vfp_d0_d15 = true;
+ if (_use_X_for_vfp_save)
+ saveVFPWithFSTMX(_vfp_d0_d15_pad);
+ else
+ saveVFPWithFSTMD(_vfp_d0_d15_pad);
+ }
+ _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value;
+ } else 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_D0] = value;
+ } else 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");
+ }
+}
+
+inline bool Registers_arm::validVectorRegister(int) const {
+ return false;
+}
+
+inline v128 Registers_arm::getVectorRegister(int) const {
+ _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+inline void Registers_arm::setVectorRegister(int, v128) {
+ _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+} // namespace libunwind
+
+#endif // __REGISTERS_HPP__
diff --git a/libunwind/src/Unwind-EHABI.cpp b/libunwind/src/Unwind-EHABI.cpp
new file mode 100644
index 00000000000..7ebba67fbcb
--- /dev/null
+++ b/libunwind/src/Unwind-EHABI.cpp
@@ -0,0 +1,994 @@
+//===--------------------------- Unwind-EHABI.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 ARM zero-cost C++ exceptions
+//
+//===----------------------------------------------------------------------===//
+
+#include "Unwind-EHABI.h"
+
+#if LIBCXXABI_ARM_EHABI
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <type_traits>
+
+#include "config.h"
+#include "libunwind.h"
+#include "libunwind_ext.h"
+#include "unwind.h"
+#include "../private_typeinfo.h"
+
+namespace {
+
+// Strange order: take words in order, but inside word, take from most to least
+// signinficant byte.
+uint8_t getByte(const uint32_t* data, size_t offset) {
+ const uint8_t* byteData = reinterpret_cast<const uint8_t*>(data);
+ return byteData[(offset & ~(size_t)0x03) + (3 - (offset & (size_t)0x03))];
+}
+
+const char* getNextWord(const char* data, uint32_t* out) {
+ *out = *reinterpret_cast<const uint32_t*>(data);
+ return data + 4;
+}
+
+const char* getNextNibble(const char* data, uint32_t* out) {
+ *out = *reinterpret_cast<const uint16_t*>(data);
+ return data + 2;
+}
+
+struct Descriptor {
+ // See # 9.2
+ typedef enum {
+ SU16 = 0, // Short descriptor, 16-bit entries
+ LU16 = 1, // Long descriptor, 16-bit entries
+ LU32 = 3, // Long descriptor, 32-bit entries
+ RESERVED0 = 4, RESERVED1 = 5, RESERVED2 = 6, RESERVED3 = 7,
+ RESERVED4 = 8, RESERVED5 = 9, RESERVED6 = 10, RESERVED7 = 11,
+ RESERVED8 = 12, RESERVED9 = 13, RESERVED10 = 14, RESERVED11 = 15
+ } Format;
+
+ // See # 9.2
+ typedef enum {
+ CLEANUP = 0x0,
+ FUNC = 0x1,
+ CATCH = 0x2,
+ INVALID = 0x4
+ } Kind;
+};
+
+_Unwind_Reason_Code ProcessDescriptors(
+ _Unwind_State state,
+ _Unwind_Control_Block* ucbp,
+ struct _Unwind_Context* context,
+ Descriptor::Format format,
+ const char* descriptorStart,
+ uint32_t flags) {
+
+ // EHT is inlined in the index using compact form. No descriptors. #5
+ if (flags & 0x1)
+ return _URC_CONTINUE_UNWIND;
+
+ // TODO: We should check the state here, and determine whether we need to
+ // perform phase1 or phase2 unwinding.
+ (void)state;
+
+ const char* descriptor = descriptorStart;
+ uint32_t descriptorWord;
+ getNextWord(descriptor, &descriptorWord);
+ while (descriptorWord) {
+ // Read descriptor based on # 9.2.
+ uint32_t length;
+ uint32_t offset;
+ switch (format) {
+ case Descriptor::LU32:
+ descriptor = getNextWord(descriptor, &length);
+ descriptor = getNextWord(descriptor, &offset);
+ case Descriptor::LU16:
+ descriptor = getNextNibble(descriptor, &length);
+ descriptor = getNextNibble(descriptor, &offset);
+ default:
+ assert(false);
+ return _URC_FAILURE;
+ }
+
+ // See # 9.2 table for decoding the kind of descriptor. It's a 2-bit value.
+ Descriptor::Kind kind =
+ static_cast<Descriptor::Kind>((length & 0x1) | ((offset & 0x1) << 1));
+
+ // Clear off flag from last bit.
+ length &= ~1u;
+ offset &= ~1u;
+ uintptr_t scopeStart = ucbp->pr_cache.fnstart + offset;
+ uintptr_t scopeEnd = scopeStart + length;
+ uintptr_t pc = _Unwind_GetIP(context);
+ bool isInScope = (scopeStart <= pc) && (pc < scopeEnd);
+
+ switch (kind) {
+ case Descriptor::CLEANUP: {
+ // TODO(ajwong): Handle cleanup descriptors.
+ break;
+ }
+ case Descriptor::FUNC: {
+ // TODO(ajwong): Handle function descriptors.
+ break;
+ }
+ case Descriptor::CATCH: {
+ // Catch descriptors require gobbling one more word.
+ uint32_t landing_pad;
+ descriptor = getNextWord(descriptor, &landing_pad);
+
+ if (isInScope) {
+ // TODO(ajwong): This is only phase1 compatible logic. Implement
+ // phase2.
+ landing_pad = signExtendPrel31(landing_pad & ~0x80000000);
+ if (landing_pad == 0xffffffff) {
+ return _URC_HANDLER_FOUND;
+ } else if (landing_pad == 0xfffffffe) {
+ return _URC_FAILURE;
+ } else {
+ /*
+ bool is_reference_type = landing_pad & 0x80000000;
+ void* matched_object;
+ if (__cxxabiv1::__cxa_type_match(
+ ucbp, reinterpret_cast<const std::type_info *>(landing_pad),
+ is_reference_type,
+ &matched_object) != __cxxabiv1::ctm_failed)
+ return _URC_HANDLER_FOUND;
+ */
+ _LIBUNWIND_ABORT("Type matching not implemented");
+ }
+ }
+ break;
+ }
+ default:
+ _LIBUNWIND_ABORT("Invalid descriptor kind found.");
+ }
+
+ getNextWord(descriptor, &descriptorWord);
+ }
+
+ return _URC_CONTINUE_UNWIND;
+}
+
+static _Unwind_Reason_Code unwindOneFrame(_Unwind_State state,
+ _Unwind_Control_Block* ucbp,
+ struct _Unwind_Context* context) {
+ // Read the compact model EHT entry's header # 6.3
+ const uint32_t* unwindingData = ucbp->pr_cache.ehtp;
+ assert((*unwindingData & 0xf0000000) == 0x80000000 && "Must be a compact entry");
+ Descriptor::Format format =
+ static_cast<Descriptor::Format>((*unwindingData & 0x0f000000) >> 24);
+ size_t len = 0;
+ size_t off = 0;
+ unwindingData = decode_eht_entry(unwindingData, &off, &len);
+ if (unwindingData == nullptr) {
+ return _URC_FAILURE;
+ }
+
+ // Handle descriptors before unwinding so they are processed in the context
+ // of the correct stack frame.
+ _Unwind_Reason_Code result =
+ ProcessDescriptors(
+ state, ucbp, context, format,
+ reinterpret_cast<const char*>(ucbp->pr_cache.ehtp) + len,
+ ucbp->pr_cache.additional);
+
+ if (result != _URC_CONTINUE_UNWIND)
+ return result;
+
+ return _Unwind_VRS_Interpret(context, unwindingData, off, len);
+}
+
+// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_CORE /
+// _UVRSD_UINT32.
+uint32_t RegisterMask(uint8_t start, uint8_t count_minus_one) {
+ return ((1U << (count_minus_one + 1)) - 1) << start;
+}
+
+// Generates mask discriminator for _Unwind_VRS_Pop, e.g. for _UVRSC_VFP /
+// _UVRSD_DOUBLE.
+uint32_t RegisterRange(uint8_t start, uint8_t count_minus_one) {
+ return ((uint32_t)start << 16) | ((uint32_t)count_minus_one + 1);
+}
+
+} // end anonymous namespace
+
+/**
+ * Decodes an EHT entry.
+ *
+ * @param data Pointer to EHT.
+ * @param[out] off Offset from return value (in bytes) to begin interpretation.
+ * @param[out] len Number of bytes in unwind code.
+ * @return Pointer to beginning of unwind code.
+ */
+extern "C" const uint32_t*
+decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
+ assert((*data & 0x80000000) != 0 &&
+ "decode_eht_entry() does not support user-defined personality");
+
+ // 6.3: ARM Compact Model
+ // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded
+ // by format:
+ Descriptor::Format format =
+ static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);
+ switch (format) {
+ case Descriptor::SU16:
+ *len = 4;
+ *off = 1;
+ break;
+ case Descriptor::LU16:
+ case Descriptor::LU32:
+ *len = 4 + 4 * ((*data & 0x00ff0000) >> 16);
+ *off = 2;
+ break;
+ default:
+ return nullptr;
+ }
+ return data;
+}
+
+_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) {
+ uint8_t byte = getByte(data, offset++);
+ if ((byte & 0x80) == 0) {
+ uint32_t sp;
+ _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
+ if (byte & 0x40)
+ sp -= (((uint32_t)byte & 0x3f) << 2) + 4;
+ else
+ sp += ((uint32_t)byte << 2) + 4;
+ _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
+ } else {
+ switch (byte & 0xf0) {
+ case 0x80: {
+ if (offset >= len)
+ return _URC_FAILURE;
+ uint32_t registers =
+ (((uint32_t)byte & 0x0f) << 12) |
+ (((uint32_t)getByte(data, offset++)) << 4);
+ if (!registers)
+ return _URC_FAILURE;
+ if (registers & (1 << 15))
+ wrotePC = true;
+ _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);
+ break;
+ }
+ case 0x90: {
+ uint8_t reg = byte & 0x0f;
+ if (reg == 13 || reg == 15)
+ return _URC_FAILURE;
+ uint32_t sp;
+ _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_R0 + reg,
+ _UVRSD_UINT32, &sp);
+ _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+ &sp);
+ break;
+ }
+ case 0xa0: {
+ uint32_t registers = RegisterMask(4, byte & 0x07);
+ if (byte & 0x08)
+ registers |= 1 << 14;
+ _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);
+ break;
+ }
+ case 0xb0: {
+ switch (byte) {
+ case 0xb0:
+ finish = true;
+ break;
+ case 0xb1: {
+ if (offset >= len)
+ return _URC_FAILURE;
+ uint8_t registers = getByte(data, offset++);
+ if (registers & 0xf0 || !registers)
+ return _URC_FAILURE;
+ _Unwind_VRS_Pop(context, _UVRSC_CORE, registers, _UVRSD_UINT32);
+ break;
+ }
+ case 0xb2: {
+ uint32_t addend = 0;
+ uint32_t shift = 0;
+ // This decodes a uleb128 value.
+ while (true) {
+ if (offset >= len)
+ return _URC_FAILURE;
+ uint32_t v = getByte(data, offset++);
+ addend |= (v & 0x7f) << shift;
+ if ((v & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ uint32_t sp;
+ _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+ &sp);
+ sp += 0x204 + (addend << 2);
+ _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+ &sp);
+ break;
+ }
+ case 0xb3: {
+ uint8_t v = getByte(data, offset++);
+ _Unwind_VRS_Pop(context, _UVRSC_VFP,
+ RegisterRange(static_cast<uint8_t>(v >> 4),
+ v & 0x0f), _UVRSD_VFPX);
+ break;
+ }
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ return _URC_FAILURE;
+ default:
+ _Unwind_VRS_Pop(context, _UVRSC_VFP,
+ RegisterRange(8, byte & 0x07), _UVRSD_VFPX);
+ break;
+ }
+ break;
+ }
+ case 0xc0: {
+ switch (byte) {
+ case 0xc0:
+ case 0xc1:
+ case 0xc2:
+ case 0xc3:
+ case 0xc4:
+ case 0xc5:
+ _Unwind_VRS_Pop(context, _UVRSC_WMMXD,
+ RegisterRange(10, byte & 0x7), _UVRSD_DOUBLE);
+ break;
+ case 0xc6: {
+ uint8_t v = getByte(data, offset++);
+ uint8_t start = static_cast<uint8_t>(v >> 4);
+ uint8_t count_minus_one = v & 0xf;
+ if (start + count_minus_one >= 16)
+ return _URC_FAILURE;
+ _Unwind_VRS_Pop(context, _UVRSC_WMMXD,
+ RegisterRange(start, count_minus_one),
+ _UVRSD_DOUBLE);
+ break;
+ }
+ case 0xc7: {
+ uint8_t v = getByte(data, offset++);
+ if (!v || v & 0xf0)
+ return _URC_FAILURE;
+ _Unwind_VRS_Pop(context, _UVRSC_WMMXC, v, _UVRSD_DOUBLE);
+ break;
+ }
+ case 0xc8:
+ case 0xc9: {
+ uint8_t v = getByte(data, offset++);
+ uint8_t start =
+ static_cast<uint8_t>(((byte == 0xc8) ? 16 : 0) + (v >> 4));
+ uint8_t count_minus_one = v & 0xf;
+ if (start + count_minus_one >= 32)
+ return _URC_FAILURE;
+ _Unwind_VRS_Pop(context, _UVRSC_VFP,
+ RegisterRange(start, count_minus_one),
+ _UVRSD_DOUBLE);
+ break;
+ }
+ default:
+ return _URC_FAILURE;
+ }
+ break;
+ }
+ case 0xd0: {
+ if (byte & 0x08)
+ return _URC_FAILURE;
+ _Unwind_VRS_Pop(context, _UVRSC_VFP, RegisterRange(8, byte & 0x7),
+ _UVRSD_DOUBLE);
+ break;
+ }
+ default:
+ return _URC_FAILURE;
+ }
+ }
+ }
+ if (!wrotePC) {
+ uint32_t lr;
+ _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_LR, _UVRSD_UINT32, &lr);
+ _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr);
+ }
+ return _URC_CONTINUE_UNWIND;
+}
+
+extern "C" _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) {
+ return unwindOneFrame(state, ucbp, context);
+}
+
+extern "C" _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
+ _Unwind_State state,
+ _Unwind_Control_Block *ucbp,
+ _Unwind_Context *context) {
+ return unwindOneFrame(state, ucbp, context);
+}
+
+static _Unwind_Reason_Code
+unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) {
+ // EHABI #7.3 discusses preserving the VRS in a "temporary VRS" during
+ // phase 1 and then restoring it to the "primary VRS" for phase 2. The
+ // effect is phase 2 doesn't see any of the VRS manipulations from phase 1.
+ // In this implementation, the phases don't share the VRS backing store.
+ // Instead, they are passed the original |uc| and they create a new VRS
+ // from scratch thus achieving the same effect.
+ unw_cursor_t cursor1;
+ unw_init_local(&cursor1, uc);
+
+ // Walk each frame looking for a place to stop.
+ for (bool handlerNotFound = true; handlerNotFound;) {
+
+ // Ask libuwind to get next frame (skip over first which is
+ // _Unwind_RaiseException).
+ int stepResult = unw_step(&cursor1);
+ if (stepResult == 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ static_cast<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",
+ static_cast<void *>(exception_object));
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // See if frame has code to run (has personality routine).
+ unw_proc_info_t frameInfo;
+ if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info "
+ "failed => _URC_FATAL_PHASE1_ERROR\n",
+ static_cast<void *>(exception_object));
+ return _URC_FATAL_PHASE1_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(&cursor1, functionBuf, sizeof(functionBuf),
+ &offset) != UNW_ESUCCESS) ||
+ (frameInfo.start_ip + offset > frameInfo.end_ip))
+ functionName = ".anonymous.";
+ unw_word_t pc;
+ unw_get_reg(&cursor1, 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);
+ }
+
+ // If there is a personality routine, ask it if it will want to stop at
+ // this frame.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(long)(frameInfo.handler);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): calling personality function %p\n",
+ static_cast<void *>(exception_object),
+ reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p)));
+ struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor1);
+ exception_object->pr_cache.fnstart = frameInfo.start_ip;
+ exception_object->pr_cache.ehtp =
+ (_Unwind_EHT_Header *)frameInfo.unwind_info;
+ exception_object->pr_cache.additional = frameInfo.flags;
+ _Unwind_Reason_Code personalityResult =
+ (*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",
+ static_cast<void *>(exception_object), personalityResult,
+ exception_object->pr_cache.fnstart,
+ static_cast<void *>(exception_object->pr_cache.ehtp),
+ exception_object->pr_cache.additional);
+ switch (personalityResult) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember stack pointer at the frame
+ handlerNotFound = false;
+ // p should have initialized barrier_cache. EHABI #7.3.5
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n",
+ 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",
+ static_cast<void *>(exception_object));
+ // continue unwinding
+ break;
+
+ // EHABI #7.3.3
+ case _URC_FAILURE:
+ return _URC_FAILURE;
+
+ default:
+ // something went wrong
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ static_cast<void *>(exception_object));
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+static _Unwind_Reason_Code unwind_phase2(unw_context_t *uc,
+ _Unwind_Exception *exception_object,
+ bool resume) {
+ // See comment at the start of unwind_phase1 regarding VRS integrity.
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n",
+ 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
+ // _Unwind_RaiseException or _Unwind_Resume).
+ //
+ // Resume only ever makes sense for 1 frame.
+ _Unwind_State state =
+ resume ? _US_UNWIND_FRAME_RESUME : _US_UNWIND_FRAME_STARTING;
+ if (resume && frame_count == 1) {
+ // On a resume, first unwind the _Unwind_Resume() frame. The next frame
+ // is now the landing pad for the cleanup from a previous execution of
+ // phase2. To continue unwindingly correctly, replace VRS[15] with the
+ // IP of the frame that the previous run of phase2 installed the context
+ // for. After this, continue unwinding as if normal.
+ //
+ // See #7.4.6 for details.
+ unw_set_reg(&cursor2, UNW_REG_IP,
+ exception_object->unwinder_cache.reserved2);
+ resume = false;
+ }
+
+ int stepResult = unw_step(&cursor2);
+ if (stepResult == 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ static_cast<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",
+ static_cast<void *>(exception_object));
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // Get info about this frame.
+ unw_word_t sp;
+ unw_proc_info_t frameInfo;
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info "
+ "failed => _URC_FATAL_PHASE1_ERROR\n",
+ static_cast<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(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);
+ }
+
+ // If there is a personality routine, tell it we are unwinding.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(long)(frameInfo.handler);
+ struct _Unwind_Context *context = (struct _Unwind_Context *)(&cursor2);
+ // EHABI #7.2
+ exception_object->pr_cache.fnstart = frameInfo.start_ip;
+ exception_object->pr_cache.ehtp =
+ (_Unwind_EHT_Header *)frameInfo.unwind_info;
+ exception_object->pr_cache.additional = frameInfo.flags;
+ _Unwind_Reason_Code personalityResult =
+ (*p)(state, exception_object, context);
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ // Continue unwinding
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ static_cast<void *>(exception_object));
+ // EHABI #7.2
+ if (sp == exception_object->barrier_cache.sp) {
+ // Phase 1 said we would stop at this frame, but we did not...
+ _LIBUNWIND_ABORT("during phase1 personality function said it would "
+ "stop here, but now in phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
+ 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().
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ unw_word_t pc;
+ unw_get_reg(&cursor2, UNW_REG_IP, &pc);
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
+ "user code with ip=0x%llX, sp=0x%llX\n",
+ static_cast<void *>(exception_object),
+ (long long)pc, (long long)sp);
+ }
+
+ {
+ // EHABI #7.4.1 says we need to preserve pc for when _Unwind_Resume
+ // is called back, to find this same frame.
+ unw_word_t pc;
+ unw_get_reg(&cursor2, UNW_REG_IP, &pc);
+ exception_object->unwinder_cache.reserved2 = (uint32_t)pc;
+ }
+ unw_resume(&cursor2);
+ // unw_resume() only returns if there was an error.
+ return _URC_FATAL_PHASE2_ERROR;
+
+ // # EHABI #7.4.3
+ case _URC_FAILURE:
+ abort();
+
+ default:
+ // Personality routine returned an unknown result code.
+ _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+ personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ frame_count++;
+ }
+
+ // Clean up phase did not resume at the frame that the search phase
+ // said it would...
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+/// 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",
+ static_cast<void *>(exception_object));
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // This field for is for compatibility with GCC to say this isn't a forced
+ // unwind. EHABI #7.2
+ exception_object->unwinder_cache.reserved1 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object);
+ if (phase1 != _URC_NO_REASON)
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(&uc, exception_object, false);
+}
+
+_LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) {
+ // This is to be called when exception handling completes to give us a chance
+ // to perform any housekeeping. EHABI #7.2. But we have nothing to do here.
+ (void)exception_object;
+}
+
+/// When _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 _Unwind_Resume() to continue with the
+/// unwinding. Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code. All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Note: re-throwing an exception (as opposed to continuing the unwind)
+/// is implemented by having the code call __cxa_rethrow() which
+/// 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",
+ static_cast<void *>(exception_object));
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // _Unwind_RaiseException on EHABI will always set the reserved1 field to 0,
+ // which is in the same position as private_1 below.
+ // TODO(ajwong): Who wronte the above? Why is it true?
+ unwind_phase2(&uc, exception_object, true);
+
+ // Clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ _LIBUNWIND_ABORT("_Unwind_Resume() can't return");
+}
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+ result = (uintptr_t)frameInfo.lsda;
+ _LIBUNWIND_TRACE_API(
+ "_Unwind_GetLanguageSpecificData(context=%p) => 0x%llx\n",
+ static_cast<void *>(context), (long long)result);
+ if (result != 0) {
+ if (*((uint8_t *)result) != 0xFF)
+ _LIBUNWIND_DEBUG_LOG("lsda at 0x%llx does not start with 0xFF\n",
+ (long long)result);
+ }
+ return result;
+}
+
+static uint64_t ValueAsBitPattern(_Unwind_VRS_DataRepresentation representation,
+ void* valuep) {
+ uint64_t value = 0;
+ switch (representation) {
+ case _UVRSD_UINT32:
+ case _UVRSD_FLOAT:
+ memcpy(&value, valuep, sizeof(uint32_t));
+ break;
+
+ case _UVRSD_VFPX:
+ case _UVRSD_UINT64:
+ case _UVRSD_DOUBLE:
+ memcpy(&value, valuep, sizeof(uint64_t));
+ break;
+ }
+ return value;
+}
+
+_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",
+ static_cast<void *>(context), regclass, regno,
+ representation,
+ ValueAsBitPattern(representation, valuep));
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ switch (regclass) {
+ case _UVRSC_CORE:
+ if (representation != _UVRSD_UINT32 || regno > 15)
+ return _UVRSR_FAILED;
+ return unw_set_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),
+ *(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;
+ if (representation == _UVRSD_VFPX) {
+ // Can only touch d0-15 with FSTMFDX.
+ if (regno > 15)
+ return _UVRSR_FAILED;
+ unw_save_vfp_as_X(cursor);
+ } else {
+ if (regno > 31)
+ return _UVRSR_FAILED;
+ }
+ return unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno),
+ *(unw_fpreg_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
+ case _UVRSC_WMMXD:
+ if (representation != _UVRSD_DOUBLE || regno > 31)
+ return _UVRSR_FAILED;
+ return unw_set_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno),
+ *(unw_fpreg_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
+ }
+ _LIBUNWIND_ABORT("unsupported register class");
+}
+
+static _Unwind_VRS_Result
+_Unwind_VRS_Get_Internal(_Unwind_Context *context,
+ _Unwind_VRS_RegClass regclass, uint32_t regno,
+ _Unwind_VRS_DataRepresentation representation,
+ void *valuep) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ switch (regclass) {
+ case _UVRSC_CORE:
+ if (representation != _UVRSD_UINT32 || regno > 15)
+ return _UVRSR_FAILED;
+ return unw_get_reg(cursor, (unw_regnum_t)(UNW_ARM_R0 + regno),
+ (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;
+ if (representation == _UVRSD_VFPX) {
+ // Can only touch d0-15 with FSTMFDX.
+ if (regno > 15)
+ return _UVRSR_FAILED;
+ unw_save_vfp_as_X(cursor);
+ } else {
+ if (regno > 31)
+ return _UVRSR_FAILED;
+ }
+ return unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_D0 + regno),
+ (unw_fpreg_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
+ case _UVRSC_WMMXD:
+ if (representation != _UVRSD_DOUBLE || regno > 31)
+ return _UVRSR_FAILED;
+ return unw_get_fpreg(cursor, (unw_regnum_t)(UNW_ARM_WR0 + regno),
+ (unw_fpreg_t *)valuep) == UNW_ESUCCESS
+ ? _UVRSR_OK
+ : _UVRSR_FAILED;
+ }
+ _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) {
+ _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",
+ static_cast<void *>(context), regclass, regno,
+ representation,
+ ValueAsBitPattern(representation, valuep), result);
+ return result;
+}
+
+_Unwind_VRS_Result
+_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",
+ static_cast<void *>(context), regclass, discriminator,
+ representation);
+ switch (regclass) {
+ case _UVRSC_CORE:
+ case _UVRSC_WMMXC: {
+ if (representation != _UVRSD_UINT32)
+ return _UVRSR_FAILED;
+ // When popping SP from the stack, we don't want to override it from the
+ // computed new stack location. See EHABI #7.5.4 table 3.
+ bool poppedSP = false;
+ uint32_t* sp;
+ if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,
+ _UVRSD_UINT32, &sp) != _UVRSR_OK) {
+ return _UVRSR_FAILED;
+ }
+ for (uint32_t i = 0; i < 16; ++i) {
+ if (!(discriminator & static_cast<uint32_t>(1 << i)))
+ continue;
+ uint32_t value = *sp++;
+ if (regclass == _UVRSC_CORE && i == 13)
+ poppedSP = true;
+ if (_Unwind_VRS_Set(context, regclass, i,
+ _UVRSD_UINT32, &value) != _UVRSR_OK) {
+ return _UVRSR_FAILED;
+ }
+ }
+ if (!poppedSP) {
+ return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP,
+ _UVRSD_UINT32, &sp);
+ }
+ return _UVRSR_OK;
+ }
+ case _UVRSC_VFP:
+ case _UVRSC_WMMXD: {
+ if (representation != _UVRSD_VFPX && representation != _UVRSD_DOUBLE)
+ return _UVRSR_FAILED;
+ uint32_t first = discriminator >> 16;
+ uint32_t count = discriminator & 0xffff;
+ uint32_t end = first+count;
+ uint32_t* sp;
+ if (_Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP,
+ _UVRSD_UINT32, &sp) != _UVRSR_OK) {
+ return _UVRSR_FAILED;
+ }
+ // For _UVRSD_VFPX, we're assuming the data is stored in FSTMX "standard
+ // format 1", which is equivalent to FSTMD + a padding word.
+ for (uint32_t i = first; i < end; ++i) {
+ // SP is only 32-bit aligned so don't copy 64-bit at a time.
+ uint64_t value = *sp++;
+ value |= ((uint64_t)(*sp++)) << 32;
+ if (_Unwind_VRS_Set(context, regclass, i, representation, &value) !=
+ _UVRSR_OK)
+ return _UVRSR_FAILED;
+ }
+ if (representation == _UVRSD_VFPX)
+ ++sp;
+ return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32,
+ &sp);
+ }
+ }
+ _LIBUNWIND_ABORT("unsupported register class");
+}
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetRegionStart(struct _Unwind_Context *context) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_proc_info_t frameInfo;
+ 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",
+ static_cast<void *>(context), (long long)result);
+ return result;
+}
+
+
+/// 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",
+ static_cast<void *>(exception_object));
+ if (exception_object->exception_cleanup != NULL)
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+ exception_object);
+}
+
+#endif // LIBCXXABI_ARM_EHABI
diff --git a/libunwind/src/Unwind-EHABI.h b/libunwind/src/Unwind-EHABI.h
new file mode 100644
index 00000000000..ebd56a10d03
--- /dev/null
+++ b/libunwind/src/Unwind-EHABI.h
@@ -0,0 +1,51 @@
+//===------------------------- Unwind-EHABI.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.
+//
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_EHABI_H__
+#define __UNWIND_EHABI_H__
+
+#include <__cxxabi_config.h>
+
+#if LIBCXXABI_ARM_EHABI
+
+#include <stdint.h>
+#include <unwind.h>
+
+// Unable to unwind in the ARM index table (section 5 EHABI).
+#define UNW_EXIDX_CANTUNWIND 0x1
+
+static inline uint32_t signExtendPrel31(uint32_t data) {
+ return data | ((data & 0x40000000u) << 1);
+}
+
+static inline uint32_t readPrel31(const uint32_t *data) {
+ return (((uint32_t)(uintptr_t)data) + signExtendPrel31(*data));
+}
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr0(
+ _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr1(
+ _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+extern _Unwind_Reason_Code __aeabi_unwind_cpp_pr2(
+ _Unwind_State state, _Unwind_Control_Block *ucbp, _Unwind_Context *context);
+
+#if defined(__cplusplus)
+} // extern "C"
+#endif
+
+#endif // LIBCXXABI_ARM_EHABI
+
+#endif // __UNWIND_EHABI_H__
diff --git a/libunwind/src/Unwind-sjlj.c b/libunwind/src/Unwind-sjlj.c
new file mode 100644
index 00000000000..f9256b5a926
--- /dev/null
+++ b/libunwind/src/Unwind-sjlj.c
@@ -0,0 +1,468 @@
+//===--------------------------- Unwind-sjlj.c ----------------------------===//
+//
+// 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 setjump-longjump based C++ exceptions
+//
+//===----------------------------------------------------------------------===//
+
+#include <unwind.h>
+
+#include <stdint.h>
+#include <stdbool.h>
+#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.
+//
+
+#if _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;
+
+ // set by personality handler to be parameters passed to landing pad function
+ uintptr_t resumeParameters[4];
+
+ // set by calling function before registering
+ __personality_routine personality; // arm offset=24
+ uintptr_t lsda; // arm offset=28
+
+ // variable length array, contains registers to restore
+ // 0 = r7, 1 = pc, 2 = sp
+ void *jbuf[];
+};
+
+
+/// Called at start of each function that catches exceptions
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Register(struct _Unwind_FunctionContext *fc) {
+ fc->prev = __Unwind_SjLj_GetTopOfFunctionStack();
+ __Unwind_SjLj_SetTopOfFunctionStack(fc);
+}
+
+
+/// Called at end of each function that catches exceptions
+_LIBUNWIND_EXPORT void
+_Unwind_SjLj_Unregister(struct _Unwind_FunctionContext *fc) {
+ __Unwind_SjLj_SetTopOfFunctionStack(fc->prev);
+}
+
+
+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);
+
+ // walk each frame looking for a place to stop
+ for (bool handlerNotFound = true; handlerNotFound; c = c->prev) {
+
+ // check for no more frames
+ if (c == NULL) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): reached "
+ "bottom => _URC_END_OF_STACK\n",
+ exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1: function-context=%p\n", 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",
+ exception_object, c->personality);
+ _Unwind_Reason_Code personalityResult = (*c->personality)(
+ 1, _UA_SEARCH_PHASE, exception_object->exception_class,
+ exception_object, (struct _Unwind_Context *)c);
+ switch (personalityResult) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember function context
+ handlerNotFound = false;
+ exception_object->private_2 = (uintptr_t) c;
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
+ "_URC_HANDLER_FOUND\n", exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): "
+ "_URC_CONTINUE_UNWIND\n", exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", 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",
+ 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",
+ exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ if (c->personality != NULL) {
+ _Unwind_Action action = _UA_CLEANUP_PHASE;
+ if ((uintptr_t) c == exception_object->private_2)
+ action = (_Unwind_Action)(
+ _UA_CLEANUP_PHASE |
+ _UA_HANDLER_FRAME); // tell personality this was the frame it marked
+ // in phase 1
+ _Unwind_Reason_Code personalityResult =
+ (*c->personality)(1, action, exception_object->exception_class,
+ exception_object, (struct _Unwind_Context *)c);
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ // continue unwinding
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ exception_object);
+ if ((uintptr_t) c == exception_object->private_2) {
+ // phase 1 said we would stop at this frame, but we did not...
+ _LIBUNWIND_ABORT("during phase1 personality function said it would "
+ "stop here, but now if phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): "
+ "_URC_INSTALL_CONTEXT, will resume at "
+ "landing pad %p\n",
+ 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()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ // unw_resume() only returns if there was an error
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // something went wrong
+ _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+ personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // clean up phase did not resume at the frame that the search phase said it
+ // would
+ return _URC_FATAL_PHASE2_ERROR;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2_forced(struct _Unwind_Exception *exception_object,
+ _Unwind_Stop_Fn stop, void *stop_parameter) {
+ // walk each frame until we reach where search phase said to stop
+ _Unwind_FunctionContext_t c = __Unwind_SjLj_GetTopOfFunctionStack();
+ while (true) {
+
+ // 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",
+ exception_object);
+ return _URC_END_OF_STACK;
+ }
+
+ // 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 *)c, stop_parameter);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "stop function returned %d\n",
+ exception_object, stopResult);
+ if (stopResult != _URC_NO_REASON) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "stopped by stop function\n",
+ exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // if there is a personality routine, tell it we are unwinding
+ 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",
+ exception_object, p);
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)c);
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned _URC_CONTINUE_UNWIND\n",
+ 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",
+ exception_object);
+ // we may get control back if landing pad calls _Unwind_Resume()
+ __Unwind_SjLj_SetTopOfFunctionStack(c);
+ __builtin_longjmp(c->jbuf, 1);
+ break;
+ default:
+ // something went wrong
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+ "personality returned %d, "
+ "_URC_FATAL_PHASE2_ERROR\n",
+ exception_object, personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ c = c->prev;
+ }
+
+ // 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",
+ 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 *)c, 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 __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);
+
+ // mark that this is a non-forced unwind, so _Unwind_Resume() can do the right
+ // thing
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(exception_object);
+ if (phase1 != _URC_NO_REASON)
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(exception_object);
+}
+
+
+
+/// When _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 _Unwind_Resume() to continue with the
+/// unwinding. Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code. All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Re-throwing an exception is implemented by having the code call
+/// __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);
+
+ if (exception_object->private_1 != 0)
+ unwind_phase2_forced(exception_object,
+ (_Unwind_Stop_Fn) exception_object->private_1,
+ (void *)exception_object->private_2);
+ else
+ unwind_phase2(exception_object);
+
+ // clients assume _Unwind_Resume() does not return, so all we can do is abort.
+ _LIBUNWIND_ABORT("_Unwind_SjLj_Resume() can't return");
+}
+
+
+/// Called by __cxa_rethrow().
+_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",
+ exception_object, exception_object->private_1);
+ // If this is non-forced and a stopping place was found, then this is a
+ // re-throw.
+ // Call _Unwind_RaiseException() as if this was a new exception.
+ if (exception_object->private_1 == 0) {
+ return _Unwind_SjLj_RaiseException(exception_object);
+ // should return if there is no catch clause, so that __cxa_rethrow can call
+ // std::terminate()
+ }
+
+ // Call through to _Unwind_Resume() which distiguishes between forced and
+ // regular exceptions.
+ _Unwind_SjLj_Resume(exception_object);
+ _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
+ "_Unwind_SjLj_Resume() which unexpectedly returned");
+}
+
+
+/// Called by personality handler during phase 2 to get LSDA for current frame.
+_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);
+ return ufc->lsda;
+}
+
+
+/// 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",
+ context, index);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ return ufc->resumeParameters[index];
+}
+
+
+/// 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"
+ , context, index, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ ufc->resumeParameters[index] = new_value;
+}
+
+
+/// 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,
+ ufc->resumeLocation + 1);
+ return ufc->resumeLocation + 1;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+/// ipBefore is a boolean that says if IP is already adjusted to be the call
+/// site address. Normally IP is the return address.
+_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",
+ context, ipBefore, ufc->resumeLocation + 1);
+ return ufc->resumeLocation + 1;
+}
+
+
+/// 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",
+ context, new_value);
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ ufc->resumeLocation = new_value - 1;
+}
+
+
+/// Called by personality handler during phase 2 to find the start of the
+/// function.
+_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);
+ return 0;
+}
+
+
+/// Called by personality handler during phase 2 if a foreign exception
+/// is caught.
+_LIBUNWIND_EXPORT void
+_Unwind_DeleteException(struct _Unwind_Exception *exception_object) {
+ _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)\n",
+ exception_object);
+ if (exception_object->exception_cleanup != NULL)
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+ exception_object);
+}
+
+
+
+/// Called by personality handler during phase 2 to get base address for data
+/// relative encodings.
+_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_ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+/// Called by personality handler during phase 2 to get base address for text
+/// relative encodings.
+_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_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);
+ if (context != NULL) {
+ _Unwind_FunctionContext_t ufc = (_Unwind_FunctionContext_t) context;
+ // Setjmp/longjmp based exceptions don't have a true CFA.
+ // Instead, the SP in the jmpbuf is the closest approximation.
+ return (uintptr_t) ufc->jbuf[2];
+ }
+ return 0;
+}
+
+#endif // _LIBUNWIND_BUILD_SJLJ_APIS
diff --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
new file mode 100644
index 00000000000..b4d413f4f32
--- /dev/null
+++ b/libunwind/src/UnwindCursor.hpp
@@ -0,0 +1,1317 @@
+//===------------------------- UnwindCursor.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.
+//
+//
+// C++ interface to lower levels of libuwind
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWINDCURSOR_HPP__
+#define __UNWINDCURSOR_HPP__
+
+#include <algorithm>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unwind.h>
+
+#ifdef __APPLE__
+ #include <mach-o/dyld.h>
+#endif
+
+#include "config.h"
+
+#include "AddressSpace.hpp"
+#include "CompactUnwinder.hpp"
+#include "config.h"
+#include "DwarfInstructions.hpp"
+#include "EHHeaderParser.hpp"
+#include "libunwind.h"
+#include "Registers.hpp"
+#include "Unwind-EHABI.h"
+
+namespace libunwind {
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+/// Cache of recently found FDEs.
+template <typename A>
+class _LIBUNWIND_HIDDEN DwarfFDECache {
+ typedef typename A::pint_t pint_t;
+public:
+ static pint_t findFDE(pint_t mh, pint_t pc);
+ static void add(pint_t mh, pint_t ip_start, pint_t ip_end, pint_t fde);
+ static void removeAllIn(pint_t mh);
+ static void iterateCacheEntries(void (*func)(unw_word_t ip_start,
+ unw_word_t ip_end,
+ unw_word_t fde, unw_word_t mh));
+
+private:
+
+ struct entry {
+ pint_t mh;
+ pint_t ip_start;
+ pint_t ip_end;
+ pint_t fde;
+ };
+
+ // 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;
+#ifdef __APPLE__
+ static void dyldUnloadHook(const struct mach_header *mh, intptr_t slide);
+ static bool _registeredForDyldUnloads;
+#endif
+ // Can't use std::vector<> here because this code is below libc++.
+ static entry *_buffer;
+ static entry *_bufferUsed;
+ static entry *_bufferEnd;
+ static entry _initialBuffer[64];
+};
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_buffer = _initialBuffer;
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_bufferUsed = _initialBuffer;
+
+template <typename A>
+typename DwarfFDECache<A>::entry *
+DwarfFDECache<A>::_bufferEnd = &_initialBuffer[64];
+
+template <typename A>
+typename DwarfFDECache<A>::entry DwarfFDECache<A>::_initialBuffer[64];
+
+template <typename A>
+pthread_rwlock_t DwarfFDECache<A>::_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+#ifdef __APPLE__
+template <typename A>
+bool DwarfFDECache<A>::_registeredForDyldUnloads = false;
+#endif
+
+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));
+ for (entry *p = _buffer; p < _bufferUsed; ++p) {
+ if ((mh == p->mh) || (mh == 0)) {
+ if ((p->ip_start <= pc) && (pc < p->ip_end)) {
+ result = p->fde;
+ break;
+ }
+ }
+ }
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+ return result;
+}
+
+template <typename A>
+void DwarfFDECache<A>::add(pint_t mh, pint_t ip_start, pint_t ip_end,
+ pint_t fde) {
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ if (_bufferUsed >= _bufferEnd) {
+ size_t oldSize = (size_t)(_bufferEnd - _buffer);
+ size_t newSize = oldSize * 4;
+ // Can't use operator new (we are below it).
+ entry *newBuffer = (entry *)malloc(newSize * sizeof(entry));
+ memcpy(newBuffer, _buffer, oldSize * sizeof(entry));
+ if (_buffer != _initialBuffer)
+ free(_buffer);
+ _buffer = newBuffer;
+ _bufferUsed = &newBuffer[oldSize];
+ _bufferEnd = &newBuffer[newSize];
+ }
+ _bufferUsed->mh = mh;
+ _bufferUsed->ip_start = ip_start;
+ _bufferUsed->ip_end = ip_end;
+ _bufferUsed->fde = fde;
+ ++_bufferUsed;
+#ifdef __APPLE__
+ if (!_registeredForDyldUnloads) {
+ _dyld_register_func_for_remove_image(&dyldUnloadHook);
+ _registeredForDyldUnloads = true;
+ }
+#endif
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+}
+
+template <typename A>
+void DwarfFDECache<A>::removeAllIn(pint_t mh) {
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_wrlock(&_lock));
+ entry *d = _buffer;
+ for (const entry *s = _buffer; s < _bufferUsed; ++s) {
+ if (s->mh != mh) {
+ if (d != s)
+ *d = *s;
+ ++d;
+ }
+ }
+ _bufferUsed = d;
+ _LIBUNWIND_LOG_NON_ZERO(::pthread_rwlock_unlock(&_lock));
+}
+
+#ifdef __APPLE__
+template <typename A>
+void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) {
+ removeAllIn((pint_t) mh);
+}
+#endif
+
+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));
+ 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));
+}
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+
+#define arrayoffsetof(type, index, field) ((size_t)(&((type *)0)[index].field))
+
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+template <typename A> class UnwindSectionHeader {
+public:
+ UnwindSectionHeader(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t version() const {
+ return _addressSpace.get32(_addr +
+ offsetof(unwind_info_section_header, version));
+ }
+ uint32_t commonEncodingsArraySectionOffset() const {
+ return _addressSpace.get32(_addr +
+ offsetof(unwind_info_section_header,
+ commonEncodingsArraySectionOffset));
+ }
+ uint32_t commonEncodingsArrayCount() const {
+ return _addressSpace.get32(_addr + offsetof(unwind_info_section_header,
+ commonEncodingsArrayCount));
+ }
+ uint32_t personalityArraySectionOffset() const {
+ return _addressSpace.get32(_addr + offsetof(unwind_info_section_header,
+ personalityArraySectionOffset));
+ }
+ uint32_t personalityArrayCount() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_section_header, personalityArrayCount));
+ }
+ uint32_t indexSectionOffset() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_section_header, indexSectionOffset));
+ }
+ uint32_t indexCount() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_section_header, indexCount));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionIndexArray {
+public:
+ UnwindSectionIndexArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+ functionOffset));
+ }
+ uint32_t secondLevelPagesSectionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+ secondLevelPagesSectionOffset));
+ }
+ uint32_t lsdaIndexArraySectionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_index_entry, index,
+ lsdaIndexArraySectionOffset));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionRegularPageHeader {
+public:
+ UnwindSectionRegularPageHeader(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t kind() const {
+ return _addressSpace.get32(
+ _addr + offsetof(unwind_info_regular_second_level_page_header, kind));
+ }
+ uint16_t entryPageOffset() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_regular_second_level_page_header,
+ entryPageOffset));
+ }
+ uint16_t entryCount() const {
+ return _addressSpace.get16(
+ _addr +
+ offsetof(unwind_info_regular_second_level_page_header, entryCount));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionRegularArray {
+public:
+ UnwindSectionRegularArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_regular_second_level_entry, index,
+ functionOffset));
+ }
+ uint32_t encoding(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr +
+ arrayoffsetof(unwind_info_regular_second_level_entry, index, encoding));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionCompressedPageHeader {
+public:
+ UnwindSectionCompressedPageHeader(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t kind() const {
+ return _addressSpace.get32(
+ _addr +
+ offsetof(unwind_info_compressed_second_level_page_header, kind));
+ }
+ uint16_t entryPageOffset() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_compressed_second_level_page_header,
+ entryPageOffset));
+ }
+ uint16_t entryCount() const {
+ return _addressSpace.get16(
+ _addr +
+ offsetof(unwind_info_compressed_second_level_page_header, entryCount));
+ }
+ uint16_t encodingsPageOffset() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_compressed_second_level_page_header,
+ encodingsPageOffset));
+ }
+ uint16_t encodingsCount() const {
+ return _addressSpace.get16(
+ _addr + offsetof(unwind_info_compressed_second_level_page_header,
+ encodingsCount));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionCompressedArray {
+public:
+ UnwindSectionCompressedArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(
+ _addressSpace.get32(_addr + index * sizeof(uint32_t)));
+ }
+ uint16_t encodingIndex(uint32_t index) const {
+ return UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(
+ _addressSpace.get32(_addr + index * sizeof(uint32_t)));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+
+template <typename A> class UnwindSectionLsdaArray {
+public:
+ UnwindSectionLsdaArray(A &addressSpace, typename A::pint_t addr)
+ : _addressSpace(addressSpace), _addr(addr) {}
+
+ uint32_t functionOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry,
+ index, functionOffset));
+ }
+ uint32_t lsdaOffset(uint32_t index) const {
+ return _addressSpace.get32(
+ _addr + arrayoffsetof(unwind_info_section_header_lsda_index_entry,
+ index, lsdaOffset));
+ }
+
+private:
+ A &_addressSpace;
+ typename A::pint_t _addr;
+};
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+class _LIBUNWIND_HIDDEN AbstractUnwindCursor {
+public:
+ // NOTE: provide a class specific placement deallocation function (S5.3.4 p20)
+ // This avoids an unnecessary dependency to libc++abi.
+ void operator delete(void *, size_t) {}
+
+ virtual ~AbstractUnwindCursor() {}
+ virtual bool validReg(int) { _LIBUNWIND_ABORT("validReg not implemented"); }
+ virtual unw_word_t getReg(int) { _LIBUNWIND_ABORT("getReg not implemented"); }
+ virtual void setReg(int, unw_word_t) {
+ _LIBUNWIND_ABORT("setReg not implemented");
+ }
+ virtual bool validFloatReg(int) {
+ _LIBUNWIND_ABORT("validFloatReg not implemented");
+ }
+ virtual unw_fpreg_t getFloatReg(int) {
+ _LIBUNWIND_ABORT("getFloatReg not implemented");
+ }
+ virtual void setFloatReg(int, unw_fpreg_t) {
+ _LIBUNWIND_ABORT("setFloatReg not implemented");
+ }
+ virtual int step() { _LIBUNWIND_ABORT("step not implemented"); }
+ virtual void getInfo(unw_proc_info_t *) {
+ _LIBUNWIND_ABORT("getInfo not implemented");
+ }
+ virtual void jumpto() { _LIBUNWIND_ABORT("jumpto not implemented"); }
+ virtual bool isSignalFrame() {
+ _LIBUNWIND_ABORT("isSignalFrame not implemented");
+ }
+ virtual bool getFunctionName(char *, size_t, unw_word_t *) {
+ _LIBUNWIND_ABORT("getFunctionName not implemented");
+ }
+ virtual void setInfoBasedOnIPRegister(bool = false) {
+ _LIBUNWIND_ABORT("setInfoBasedOnIPRegister not implemented");
+ }
+ virtual const char *getRegisterName(int) {
+ _LIBUNWIND_ABORT("getRegisterName not implemented");
+ }
+#ifdef __arm__
+ virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); }
+#endif
+};
+
+/// 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(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
+
+private:
+
+#if LIBCXXABI_ARM_EHABI
+ bool getInfoFromEHABISection(pint_t pc, const UnwindInfoSections &sects);
+#endif
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
+ uint32_t fdeSectionOffsetHint=0);
+ int stepWithDwarfFDE() {
+ return DwarfInstructions<A, R>::stepWithDwarf(_addressSpace,
+ (pint_t)this->getReg(UNW_REG_IP),
+ (pint_t)_info.unwind_info,
+ _registers);
+ }
+#endif
+
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ bool getInfoFromCompactEncodingSection(pint_t pc,
+ const UnwindInfoSections &sects);
+ int stepWithCompactEncoding() {
+ #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ if ( compactSaysUseDwarf() )
+ return stepWithDwarfFDE();
+ #endif
+ R dummy;
+ return stepWithCompactEncoding(dummy);
+ }
+
+ int stepWithCompactEncoding(Registers_x86_64 &) {
+ return CompactUnwinder_x86_64<A>::stepWithCompactEncoding(
+ _info.format, _info.start_ip, _addressSpace, _registers);
+ }
+
+ int stepWithCompactEncoding(Registers_x86 &) {
+ return CompactUnwinder_x86<A>::stepWithCompactEncoding(
+ _info.format, (uint32_t)_info.start_ip, _addressSpace, _registers);
+ }
+
+ int stepWithCompactEncoding(Registers_ppc &) {
+ return UNW_EINVAL;
+ }
+
+ int stepWithCompactEncoding(Registers_arm64 &) {
+ return CompactUnwinder_arm64<A>::stepWithCompactEncoding(
+ _info.format, _info.start_ip, _addressSpace, _registers);
+ }
+
+ bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
+ R dummy;
+ return compactSaysUseDwarf(dummy, offset);
+ }
+
+ bool compactSaysUseDwarf(Registers_x86_64 &, uint32_t *offset) const {
+ if ((_info.format & UNWIND_X86_64_MODE_MASK) == UNWIND_X86_64_MODE_DWARF) {
+ if (offset)
+ *offset = (_info.format & UNWIND_X86_64_DWARF_SECTION_OFFSET);
+ return true;
+ }
+ return false;
+ }
+
+ bool compactSaysUseDwarf(Registers_x86 &, uint32_t *offset) const {
+ if ((_info.format & UNWIND_X86_MODE_MASK) == UNWIND_X86_MODE_DWARF) {
+ if (offset)
+ *offset = (_info.format & UNWIND_X86_DWARF_SECTION_OFFSET);
+ return true;
+ }
+ return false;
+ }
+
+ bool compactSaysUseDwarf(Registers_ppc &, uint32_t *) const {
+ return true;
+ }
+
+ bool compactSaysUseDwarf(Registers_arm64 &, uint32_t *offset) const {
+ if ((_info.format & UNWIND_ARM64_MODE_MASK) == UNWIND_ARM64_MODE_DWARF) {
+ if (offset)
+ *offset = (_info.format & UNWIND_ARM64_DWARF_SECTION_OFFSET);
+ return true;
+ }
+ return false;
+ }
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ compact_unwind_encoding_t dwarfEncoding() const {
+ R dummy;
+ return dwarfEncoding(dummy);
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_x86_64 &) const {
+ return UNWIND_X86_64_MODE_DWARF;
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_x86 &) const {
+ return UNWIND_X86_MODE_DWARF;
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_ppc &) const {
+ return 0;
+ }
+
+ compact_unwind_encoding_t dwarfEncoding(Registers_arm64 &) const {
+ return UNWIND_ARM64_MODE_DWARF;
+ }
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+
+ A &_addressSpace;
+ R _registers;
+ unw_proc_info_t _info;
+ bool _unwindInfoMissing;
+ bool _isSignalFrame;
+};
+
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
+ : _addressSpace(as), _registers(context), _unwindInfoMissing(false),
+ _isSignalFrame(false) {
+ static_assert(sizeof(UnwindCursor<A, R>) < sizeof(unw_cursor_t),
+ "UnwindCursor<> does not fit in unw_cursor_t");
+ memset(&_info, 0, sizeof(_info));
+}
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(A &as, void *)
+ : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
+ memset(&_info, 0, sizeof(_info));
+ // FIXME
+ // fill in _registers from thread arg
+}
+
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validReg(int regNum) {
+ return _registers.validRegister(regNum);
+}
+
+template <typename A, typename R>
+unw_word_t UnwindCursor<A, R>::getReg(int regNum) {
+ return _registers.getRegister(regNum);
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) {
+ _registers.setRegister(regNum, (typename A::pint_t)value);
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::validFloatReg(int regNum) {
+ return _registers.validFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+unw_fpreg_t UnwindCursor<A, R>::getFloatReg(int regNum) {
+ return _registers.getFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
+ _registers.setFloatRegister(regNum, value);
+}
+
+template <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
+ _registers.jumpto();
+}
+
+#ifdef __arm__
+template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {
+ _registers.saveVFPAsX();
+}
+#endif
+
+template <typename A, typename R>
+const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
+ return _registers.getRegisterName(regNum);
+}
+
+template <typename A, typename R> bool UnwindCursor<A, R>::isSignalFrame() {
+ return _isSignalFrame;
+}
+
+#if LIBCXXABI_ARM_EHABI
+struct EHABIIndexEntry {
+ uint32_t functionOffset;
+ uint32_t data;
+};
+
+template<typename A>
+struct EHABISectionIterator {
+ typedef EHABISectionIterator _Self;
+
+ typedef std::random_access_iterator_tag iterator_category;
+ typedef typename A::pint_t value_type;
+ typedef typename A::pint_t* pointer;
+ typedef typename A::pint_t& reference;
+ typedef size_t size_type;
+ typedef size_t difference_type;
+
+ static _Self begin(A& addressSpace, const UnwindInfoSections& sects) {
+ return _Self(addressSpace, sects, 0);
+ }
+ static _Self end(A& addressSpace, const UnwindInfoSections& sects) {
+ return _Self(addressSpace, sects, sects.arm_section_length);
+ }
+
+ EHABISectionIterator(A& addressSpace, const UnwindInfoSections& sects, size_t i)
+ : _i(i), _addressSpace(&addressSpace), _sects(&sects) {}
+
+ _Self& operator++() { ++_i; return *this; }
+ _Self& operator+=(size_t a) { _i += a; return *this; }
+ _Self& operator--() { assert(_i > 0); --_i; return *this; }
+ _Self& operator-=(size_t a) { assert(_i >= a); _i -= a; return *this; }
+
+ _Self operator+(size_t a) { _Self out = *this; out._i += a; return out; }
+ _Self operator-(size_t a) { assert(_i >= a); _Self out = *this; out._i -= a; return out; }
+
+ size_t operator-(const _Self& other) { return _i - other._i; }
+
+ bool operator==(const _Self& other) const {
+ assert(_addressSpace == other._addressSpace);
+ assert(_sects == other._sects);
+ return _i == other._i;
+ }
+
+ typename A::pint_t operator*() const { return functionAddress(); }
+
+ typename A::pint_t functionAddress() const {
+ typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof(
+ EHABIIndexEntry, _i, functionOffset);
+ return indexAddr + signExtendPrel31(_addressSpace->get32(indexAddr));
+ }
+
+ typename A::pint_t dataAddress() {
+ typename A::pint_t indexAddr = _sects->arm_section + arrayoffsetof(
+ EHABIIndexEntry, _i, data);
+ return indexAddr;
+ }
+
+ private:
+ size_t _i;
+ A* _addressSpace;
+ const UnwindInfoSections* _sects;
+};
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromEHABISection(
+ pint_t pc,
+ const UnwindInfoSections &sects) {
+ EHABISectionIterator<A> begin =
+ EHABISectionIterator<A>::begin(_addressSpace, sects);
+ EHABISectionIterator<A> end =
+ EHABISectionIterator<A>::end(_addressSpace, sects);
+
+ EHABISectionIterator<A> itNextPC = std::upper_bound(begin, end, pc);
+ if (itNextPC == begin || itNextPC == end)
+ return false;
+ EHABISectionIterator<A> itThisPC = itNextPC - 1;
+
+ pint_t thisPC = itThisPC.functionAddress();
+ pint_t nextPC = itNextPC.functionAddress();
+ pint_t indexDataAddr = itThisPC.dataAddress();
+
+ if (indexDataAddr == 0)
+ return false;
+
+ uint32_t indexData = _addressSpace.get32(indexDataAddr);
+ if (indexData == UNW_EXIDX_CANTUNWIND)
+ return false;
+
+ // If the high bit is set, the exception handling table entry is inline inside
+ // the index table entry on the second word (aka |indexDataAddr|). Otherwise,
+ // the table points at an offset in the exception handling table (section 5 EHABI).
+ pint_t exceptionTableAddr;
+ uint32_t exceptionTableData;
+ bool isSingleWordEHT;
+ if (indexData & 0x80000000) {
+ exceptionTableAddr = indexDataAddr;
+ // TODO(ajwong): Should this data be 0?
+ exceptionTableData = indexData;
+ isSingleWordEHT = true;
+ } else {
+ exceptionTableAddr = indexDataAddr + signExtendPrel31(indexData);
+ exceptionTableData = _addressSpace.get32(exceptionTableAddr);
+ isSingleWordEHT = false;
+ }
+
+ // Now we know the 3 things:
+ // exceptionTableAddr -- exception handler table entry.
+ // exceptionTableData -- the data inside the first word of the eht entry.
+ // isSingleWordEHT -- whether the entry is in the index.
+ unw_word_t personalityRoutine = 0xbadf00d;
+ bool scope32 = false;
+ uintptr_t lsda = 0xbadf00d;
+
+ // If the high bit in the exception handling table entry is set, the entry is
+ // in compact form (section 6.3 EHABI).
+ if (exceptionTableData & 0x80000000) {
+ // Grab the index of the personality routine from the compact form.
+ uint32_t choice = (exceptionTableData & 0x0f000000) >> 24;
+ uint32_t extraWords = 0;
+ switch (choice) {
+ case 0:
+ personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr0;
+ extraWords = 0;
+ scope32 = false;
+ break;
+ case 1:
+ personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr1;
+ extraWords = (exceptionTableData & 0x00ff0000) >> 16;
+ scope32 = false;
+ break;
+ case 2:
+ personalityRoutine = (unw_word_t) &__aeabi_unwind_cpp_pr2;
+ extraWords = (exceptionTableData & 0x00ff0000) >> 16;
+ scope32 = true;
+ break;
+ default:
+ _LIBUNWIND_ABORT("unknown personality routine");
+ return false;
+ }
+
+ if (isSingleWordEHT) {
+ if (extraWords != 0) {
+ _LIBUNWIND_ABORT("index inlined table detected but pr function "
+ "requires extra words");
+ return false;
+ }
+ }
+ } else {
+ pint_t personalityAddr =
+ exceptionTableAddr + signExtendPrel31(exceptionTableData);
+ personalityRoutine = personalityAddr;
+
+ // ARM EHABI # 6.2, # 9.2
+ //
+ // +---- ehtp
+ // v
+ // +--------------------------------------+
+ // | +--------+--------+--------+-------+ |
+ // | |0| prel31 to personalityRoutine | |
+ // | +--------+--------+--------+-------+ |
+ // | | N | unwind opcodes | | <-- UnwindData
+ // | +--------+--------+--------+-------+ |
+ // | | Word 2 unwind opcodes | |
+ // | +--------+--------+--------+-------+ |
+ // | ... |
+ // | +--------+--------+--------+-------+ |
+ // | | Word N unwind opcodes | |
+ // | +--------+--------+--------+-------+ |
+ // | | LSDA | | <-- lsda
+ // | | ... | |
+ // | +--------+--------+--------+-------+ |
+ // +--------------------------------------+
+
+ uint32_t *UnwindData = reinterpret_cast<uint32_t*>(exceptionTableAddr) + 1;
+ uint32_t FirstDataWord = *UnwindData;
+ size_t N = ((FirstDataWord >> 24) & 0xff);
+ size_t NDataWords = N + 1;
+ lsda = reinterpret_cast<uintptr_t>(UnwindData + NDataWords);
+ }
+
+ _info.start_ip = thisPC;
+ _info.end_ip = nextPC;
+ _info.handler = personalityRoutine;
+ _info.unwind_info = exceptionTableAddr;
+ _info.lsda = lsda;
+ // flags is pr_cache.additional. See EHABI #7.2 for definition of bit 0.
+ _info.flags = isSingleWordEHT ? 1 : 0 | scope32 ? 0x2 : 0; // Use enum?
+
+ return true;
+}
+#endif
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromDwarfSection(pint_t pc,
+ const UnwindInfoSections &sects,
+ uint32_t fdeSectionOffsetHint) {
+ typename CFI_Parser<A>::FDE_Info fdeInfo;
+ typename CFI_Parser<A>::CIE_Info cieInfo;
+ bool foundFDE = false;
+ bool foundInCache = false;
+ // If compact encoding table gave offset into dwarf section, go directly there
+ if (fdeSectionOffsetHint != 0) {
+ foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+ (uint32_t)sects.dwarf_section_length,
+ sects.dwarf_section + fdeSectionOffsetHint,
+ &fdeInfo, &cieInfo);
+ }
+#if _LIBUNWIND_SUPPORT_DWARF_INDEX
+ if (!foundFDE && (sects.dwarf_index_section != 0)) {
+ foundFDE = EHHeaderParser<A>::findFDE(
+ _addressSpace, pc, sects.dwarf_index_section,
+ (uint32_t)sects.dwarf_index_section_length, &fdeInfo, &cieInfo);
+ }
+#endif
+ if (!foundFDE) {
+ // otherwise, search cache of previously found FDEs.
+ pint_t cachedFDE = DwarfFDECache<A>::findFDE(sects.dso_base, pc);
+ if (cachedFDE != 0) {
+ foundFDE =
+ CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+ (uint32_t)sects.dwarf_section_length,
+ cachedFDE, &fdeInfo, &cieInfo);
+ foundInCache = foundFDE;
+ }
+ }
+ if (!foundFDE) {
+ // Still not found, do full scan of __eh_frame section.
+ foundFDE = CFI_Parser<A>::findFDE(_addressSpace, pc, sects.dwarf_section,
+ (uint32_t)sects.dwarf_section_length, 0,
+ &fdeInfo, &cieInfo);
+ }
+ if (foundFDE) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo, pc,
+ &prolog)) {
+ // Save off parsed FDE info
+ _info.start_ip = fdeInfo.pcStart;
+ _info.end_ip = fdeInfo.pcEnd;
+ _info.lsda = fdeInfo.lsda;
+ _info.handler = cieInfo.personality;
+ _info.gp = prolog.spExtraArgSize;
+ _info.flags = 0;
+ _info.format = dwarfEncoding();
+ _info.unwind_info = fdeInfo.fdeStart;
+ _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
+ _info.extra = (unw_word_t) sects.dso_base;
+
+ // 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 (sects.dwarf_index_section == 0)
+ #endif
+ DwarfFDECache<A>::add(sects.dso_base, fdeInfo.pcStart, fdeInfo.pcEnd,
+ fdeInfo.fdeStart);
+ }
+ return true;
+ }
+ }
+ //_LIBUNWIND_DEBUG_LOG("can't find/use FDE for pc=0x%llX\n", (uint64_t)pc);
+ return false;
+}
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(pint_t pc,
+ const UnwindInfoSections &sects) {
+ const bool log = false;
+ if (log)
+ fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX, mh=0x%llX)\n",
+ (uint64_t)pc, (uint64_t)sects.dso_base);
+
+ const UnwindSectionHeader<A> sectionHeader(_addressSpace,
+ sects.compact_unwind_section);
+ if (sectionHeader.version() != UNWIND_SECTION_VERSION)
+ return false;
+
+ // do a binary search of top level index to find page with unwind info
+ pint_t targetFunctionOffset = pc - sects.dso_base;
+ const UnwindSectionIndexArray<A> topIndex(_addressSpace,
+ sects.compact_unwind_section
+ + sectionHeader.indexSectionOffset());
+ uint32_t low = 0;
+ uint32_t high = sectionHeader.indexCount();
+ uint32_t last = high - 1;
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ //if ( log ) fprintf(stderr, "\tmid=%d, low=%d, high=%d, *mid=0x%08X\n",
+ //mid, low, high, topIndex.functionOffset(mid));
+ if (topIndex.functionOffset(mid) <= targetFunctionOffset) {
+ if ((mid == last) ||
+ (topIndex.functionOffset(mid + 1) > targetFunctionOffset)) {
+ low = mid;
+ break;
+ } else {
+ low = mid + 1;
+ }
+ } else {
+ high = mid;
+ }
+ }
+ const uint32_t firstLevelFunctionOffset = topIndex.functionOffset(low);
+ const uint32_t firstLevelNextPageFunctionOffset =
+ topIndex.functionOffset(low + 1);
+ const pint_t secondLevelAddr =
+ sects.compact_unwind_section + topIndex.secondLevelPagesSectionOffset(low);
+ const pint_t lsdaArrayStartAddr =
+ sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low);
+ const pint_t lsdaArrayEndAddr =
+ sects.compact_unwind_section + topIndex.lsdaIndexArraySectionOffset(low+1);
+ if (log)
+ fprintf(stderr, "\tfirst level search for result index=%d "
+ "to secondLevelAddr=0x%llX\n",
+ low, (uint64_t) secondLevelAddr);
+ // do a binary search of second level page index
+ uint32_t encoding = 0;
+ pint_t funcStart = 0;
+ pint_t funcEnd = 0;
+ pint_t lsda = 0;
+ pint_t personality = 0;
+ uint32_t pageKind = _addressSpace.get32(secondLevelAddr);
+ if (pageKind == UNWIND_SECOND_LEVEL_REGULAR) {
+ // regular page
+ UnwindSectionRegularPageHeader<A> pageHeader(_addressSpace,
+ secondLevelAddr);
+ UnwindSectionRegularArray<A> pageIndex(
+ _addressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ // binary search looks for entry with e where index[e].offset <= pc <
+ // index[e+1].offset
+ if (log)
+ fprintf(stderr, "\tbinary search for targetFunctionOffset=0x%08llX in "
+ "regular page starting at secondLevelAddr=0x%llX\n",
+ (uint64_t) targetFunctionOffset, (uint64_t) secondLevelAddr);
+ low = 0;
+ high = pageHeader.entryCount();
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ if (pageIndex.functionOffset(mid) <= targetFunctionOffset) {
+ if (mid == (uint32_t)(pageHeader.entryCount() - 1)) {
+ // at end of table
+ low = mid;
+ funcEnd = firstLevelNextPageFunctionOffset + sects.dso_base;
+ break;
+ } else if (pageIndex.functionOffset(mid + 1) > targetFunctionOffset) {
+ // next is too big, so we found it
+ low = mid;
+ funcEnd = pageIndex.functionOffset(low + 1) + sects.dso_base;
+ break;
+ } else {
+ low = mid + 1;
+ }
+ } else {
+ high = mid;
+ }
+ }
+ encoding = pageIndex.encoding(low);
+ funcStart = pageIndex.functionOffset(low) + sects.dso_base;
+ if (pc < funcStart) {
+ if (log)
+ fprintf(
+ stderr,
+ "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n",
+ (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd);
+ return false;
+ }
+ if (pc > funcEnd) {
+ if (log)
+ fprintf(
+ stderr,
+ "\tpc not in table, pc=0x%llX, funcStart=0x%llX, funcEnd=0x%llX\n",
+ (uint64_t) pc, (uint64_t) funcStart, (uint64_t) funcEnd);
+ return false;
+ }
+ } else if (pageKind == UNWIND_SECOND_LEVEL_COMPRESSED) {
+ // compressed page
+ UnwindSectionCompressedPageHeader<A> pageHeader(_addressSpace,
+ secondLevelAddr);
+ UnwindSectionCompressedArray<A> pageIndex(
+ _addressSpace, secondLevelAddr + pageHeader.entryPageOffset());
+ const uint32_t targetFunctionPageOffset =
+ (uint32_t)(targetFunctionOffset - firstLevelFunctionOffset);
+ // binary search looks for entry with e where index[e].offset <= pc <
+ // index[e+1].offset
+ if (log)
+ fprintf(stderr, "\tbinary search of compressed page starting at "
+ "secondLevelAddr=0x%llX\n",
+ (uint64_t) secondLevelAddr);
+ low = 0;
+ last = pageHeader.entryCount() - 1;
+ high = pageHeader.entryCount();
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ if (pageIndex.functionOffset(mid) <= targetFunctionPageOffset) {
+ if ((mid == last) ||
+ (pageIndex.functionOffset(mid + 1) > targetFunctionPageOffset)) {
+ low = mid;
+ break;
+ } else {
+ low = mid + 1;
+ }
+ } else {
+ high = mid;
+ }
+ }
+ funcStart = pageIndex.functionOffset(low) + firstLevelFunctionOffset
+ + sects.dso_base;
+ if (low < last)
+ funcEnd =
+ pageIndex.functionOffset(low + 1) + firstLevelFunctionOffset
+ + sects.dso_base;
+ else
+ 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",
+ (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",
+ (uint64_t) pc, (uint64_t) funcEnd);
+ return false;
+ }
+ uint16_t encodingIndex = pageIndex.encodingIndex(low);
+ if (encodingIndex < sectionHeader.commonEncodingsArrayCount()) {
+ // encoding is in common table in section header
+ encoding = _addressSpace.get32(
+ sects.compact_unwind_section +
+ sectionHeader.commonEncodingsArraySectionOffset() +
+ encodingIndex * sizeof(uint32_t));
+ } else {
+ // encoding is in page specific table
+ uint16_t pageEncodingIndex =
+ encodingIndex - (uint16_t)sectionHeader.commonEncodingsArrayCount();
+ encoding = _addressSpace.get32(secondLevelAddr +
+ pageHeader.encodingsPageOffset() +
+ pageEncodingIndex * sizeof(uint32_t));
+ }
+ } else {
+ _LIBUNWIND_DEBUG_LOG("malformed __unwind_info at 0x%0llX bad second "
+ "level page\n",
+ (uint64_t) sects.compact_unwind_section);
+ return false;
+ }
+
+ // look up LSDA, if encoding says function has one
+ if (encoding & UNWIND_HAS_LSDA) {
+ UnwindSectionLsdaArray<A> lsdaIndex(_addressSpace, lsdaArrayStartAddr);
+ uint32_t funcStartOffset = (uint32_t)(funcStart - sects.dso_base);
+ low = 0;
+ high = (uint32_t)(lsdaArrayEndAddr - lsdaArrayStartAddr) /
+ sizeof(unwind_info_section_header_lsda_index_entry);
+ // binary search looks for entry with exact match for functionOffset
+ if (log)
+ fprintf(stderr,
+ "\tbinary search of lsda table for targetFunctionOffset=0x%08X\n",
+ funcStartOffset);
+ while (low < high) {
+ uint32_t mid = (low + high) / 2;
+ if (lsdaIndex.functionOffset(mid) == funcStartOffset) {
+ lsda = lsdaIndex.lsdaOffset(mid) + sects.dso_base;
+ break;
+ } else if (lsdaIndex.functionOffset(mid) < funcStartOffset) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ 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",
+ encoding, (uint64_t) pc);
+ return false;
+ }
+ }
+
+ // extact personality routine, if encoding says function has one
+ uint32_t personalityIndex = (encoding & UNWIND_PERSONALITY_MASK) >>
+ (__builtin_ctz(UNWIND_PERSONALITY_MASK));
+ if (personalityIndex != 0) {
+ --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",
+ encoding, personalityIndex,
+ sectionHeader.personalityArrayCount());
+ return false;
+ }
+ int32_t personalityDelta = (int32_t)_addressSpace.get32(
+ sects.compact_unwind_section +
+ sectionHeader.personalityArraySectionOffset() +
+ personalityIndex * sizeof(uint32_t));
+ pint_t personalityPointer = sects.dso_base + (pint_t)personalityDelta;
+ personality = _addressSpace.getP(personalityPointer);
+ if (log)
+ fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
+ "personalityDelta=0x%08X, personality=0x%08llX\n",
+ (uint64_t) pc, personalityDelta, (uint64_t) personality);
+ }
+
+ if (log)
+ fprintf(stderr, "getInfoFromCompactEncodingSection(pc=0x%llX), "
+ "encoding=0x%08X, lsda=0x%08llX for funcStart=0x%llX\n",
+ (uint64_t) pc, encoding, (uint64_t) lsda, (uint64_t) funcStart);
+ _info.start_ip = funcStart;
+ _info.end_ip = funcEnd;
+ _info.lsda = lsda;
+ _info.handler = personality;
+ _info.gp = 0;
+ _info.flags = 0;
+ _info.format = encoding;
+ _info.unwind_info = 0;
+ _info.unwind_info_size = 0;
+ _info.extra = sects.dso_base;
+ return true;
+}
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
+ pint_t pc = (pint_t)this->getReg(UNW_REG_IP);
+#if LIBCXXABI_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;
+#endif
+
+ // If the last line of a function is a "throw" the compiler sometimes
+ // emits no instructions after the call to __cxa_throw. This means
+ // the return address is actually the start of the next function.
+ // To disambiguate this, back up the pc when we know it is a return
+ // address.
+ if (isReturnAddress)
+ --pc;
+
+ // Ask address space object to find unwind sections for this pc.
+ UnwindInfoSections sects;
+ if (_addressSpace.findUnwindSections(pc, sects)) {
+#if _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
+ // Found info in table, done unless encoding says to use dwarf.
+ uint32_t dwarfOffset;
+ if ((sects.dwarf_section != 0) && compactSaysUseDwarf(&dwarfOffset)) {
+ if (this->getInfoFromDwarfSection(pc, sects, dwarfOffset)) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+ #endif
+ // If unwind table has entry, but entry says there is no unwind info,
+ // record that we have no unwind info.
+ if (_info.format == 0)
+ _unwindInfoMissing = true;
+ return;
+ }
+ }
+#endif // _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+
+#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ // If there is dwarf unwind info, look there next.
+ if (sects.dwarf_section != 0) {
+ if (this->getInfoFromDwarfSection(pc, sects)) {
+ // found info in dwarf, done
+ return;
+ }
+ }
+#endif
+
+#if LIBCXXABI_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
+ // 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);
+ if (cachedFDE != 0) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char *msg = CFI_Parser<A>::decodeFDE(_addressSpace,
+ cachedFDE, &fdeInfo, &cieInfo);
+ if (msg == NULL) {
+ typename CFI_Parser<A>::PrologInfo prolog;
+ if (CFI_Parser<A>::parseFDEInstructions(_addressSpace, fdeInfo, cieInfo,
+ pc, &prolog)) {
+ // save off parsed FDE info
+ _info.start_ip = fdeInfo.pcStart;
+ _info.end_ip = fdeInfo.pcEnd;
+ _info.lsda = fdeInfo.lsda;
+ _info.handler = cieInfo.personality;
+ _info.gp = prolog.spExtraArgSize;
+ // Some frameless functions need SP
+ // altered when resuming in function.
+ _info.flags = 0;
+ _info.format = dwarfEncoding();
+ _info.unwind_info = fdeInfo.fdeStart;
+ _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
+ _info.extra = 0;
+ return;
+ }
+ }
+ }
+
+ // Lastly, ask AddressSpace object about platform specific ways to locate
+ // other FDEs.
+ pint_t fde;
+ if (_addressSpace.findOtherFDE(pc, fde)) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ if (!CFI_Parser<A>::decodeFDE(_addressSpace, fde, &fdeInfo, &cieInfo)) {
+ // 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)) {
+ // save off parsed FDE info
+ _info.start_ip = fdeInfo.pcStart;
+ _info.end_ip = fdeInfo.pcEnd;
+ _info.lsda = fdeInfo.lsda;
+ _info.handler = cieInfo.personality;
+ _info.gp = prolog.spExtraArgSize;
+ _info.flags = 0;
+ _info.format = dwarfEncoding();
+ _info.unwind_info = fdeInfo.fdeStart;
+ _info.unwind_info_size = (uint32_t)fdeInfo.fdeLength;
+ _info.extra = 0;
+ return;
+ }
+ }
+ }
+ }
+#endif // #if _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+ // no unwind info, flag that we can't reliably unwind
+ _unwindInfoMissing = true;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A, R>::step() {
+ // Bottom of stack is defined is when unwind info cannot be found.
+ if (_unwindInfoMissing)
+ return UNW_STEP_END;
+
+ // Use unwinding info to modify register set as if function returned.
+ int result;
+#if _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+ result = this->stepWithCompactEncoding();
+#elif _LIBUNWIND_SUPPORT_DWARF_UNWIND
+ result = this->stepWithDwarfFDE();
+#elif LIBCXXABI_ARM_EHABI
+ result = UNW_STEP_SUCCESS;
+#else
+ #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or \
+ _LIBUNWIND_SUPPORT_DWARF_UNWIND or \
+ LIBCXXABI_ARM_EHABI
+#endif
+
+ // update info based on new PC
+ if (result == UNW_STEP_SUCCESS) {
+ this->setInfoBasedOnIPRegister(true);
+ if (_unwindInfoMissing)
+ return UNW_STEP_END;
+ if (_info.gp)
+ setReg(UNW_REG_SP, getReg(UNW_REG_SP) + _info.gp);
+ }
+
+ return result;
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::getInfo(unw_proc_info_t *info) {
+ *info = _info;
+}
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
+ unw_word_t *offset) {
+ return _addressSpace.findFunctionName((pint_t)this->getReg(UNW_REG_IP),
+ buf, bufLen, offset);
+}
+
+} // namespace libunwind
+
+#endif // __UNWINDCURSOR_HPP__
diff --git a/libunwind/src/UnwindLevel1-gcc-ext.c b/libunwind/src/UnwindLevel1-gcc-ext.c
new file mode 100644
index 00000000000..b1e3f777f6c
--- /dev/null
+++ b/libunwind/src/UnwindLevel1-gcc-ext.c
@@ -0,0 +1,327 @@
+//===--------------------- UnwindLevel1-gcc-ext.c -------------------------===//
+//
+// 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 gcc extensions to the C++ ABI Exception Handling Level 1.
+//
+//===----------------------------------------------------------------------===//
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "libunwind_ext.h"
+#include "libunwind.h"
+#include "Unwind-EHABI.h"
+#include "unwind.h"
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+/// Called by __cxa_rethrow().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
+#if LIBCXXABI_ARM_EHABI
+ _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n",
+ (void *)exception_object,
+ (long)exception_object->unwinder_cache.reserved1);
+#else
+ _LIBUNWIND_TRACE_API("_Unwind_Resume_or_Rethrow(ex_obj=%p), private_1=%ld\n",
+ (void *)exception_object,
+ (long)exception_object->private_1);
+#endif
+
+#if LIBCXXABI_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);
+#else
+ // If this is non-forced and a stopping place was found, then this is a
+ // re-throw.
+ // Call _Unwind_RaiseException() as if this was a new exception
+ if (exception_object->private_1 == 0) {
+ return _Unwind_RaiseException(exception_object);
+ // Will return if there is no catch clause, so that __cxa_rethrow can call
+ // std::terminate().
+ }
+
+ // Call through to _Unwind_Resume() which distiguishes between forced and
+ // regular exceptions.
+ _Unwind_Resume(exception_object);
+ _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
+ " which unexpectedly returned");
+#endif
+}
+
+
+/// Called by personality handler during phase 2 to get base address for data
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetDataRelBase(struct _Unwind_Context *context) {
+ (void)context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)\n", (void *)context);
+ _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
+}
+
+
+/// Called by personality handler during phase 2 to get base address for text
+/// relative encodings.
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetTextRelBase(struct _Unwind_Context *context) {
+ (void)context;
+ _LIBUNWIND_TRACE_API("_Unwind_GetTextRelBase(context=%p)\n", (void *)context);
+ _LIBUNWIND_ABORT("_Unwind_GetTextRelBase() not implemented");
+}
+
+
+/// 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);
+ // This is slow, but works.
+ // We create an unwind cursor then alter the IP to be pc
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ 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);
+ if (unw_get_proc_info(&cursor, &info) == UNW_ESUCCESS)
+ return (void *)(long) info.start_ip;
+ else
+ return NULL;
+}
+
+/// Walk every frame and call trace function at each one. If trace function
+/// returns anything other than _URC_NO_REASON, then walk is terminated.
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_Backtrace(_Unwind_Trace_Fn callback, void *ref) {
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+
+ _LIBUNWIND_TRACE_API("_Unwind_Backtrace(callback=%p)\n",
+ (void *)(uintptr_t)callback);
+
+ // walk each frame
+ while (true) {
+ _Unwind_Reason_Code result;
+
+ // ask libuwind 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",
+ _URC_END_OF_STACK);
+ return _URC_END_OF_STACK;
+ }
+
+#if LIBCXXABI_ARM_EHABI
+ // Get the information for this frame.
+ unw_proc_info_t frameInfo;
+ if (unw_get_proc_info(&cursor, &frameInfo) != UNW_ESUCCESS) {
+ return _URC_END_OF_STACK;
+ }
+
+ struct _Unwind_Context *context = (struct _Unwind_Context *)&cursor;
+ const uint32_t* unwindInfo = (uint32_t *) frameInfo.unwind_info;
+ if ((*unwindInfo & 0x80000000) == 0) {
+ // 6.2: Generic Model
+ // EHT entry is a prel31 pointing to the PR, followed by data understood
+ // only by the personality routine. Since EHABI doesn't guarantee the
+ // location or availability of the unwind opcodes in the generic model,
+ // we have to call personality functions with (_US_VIRTUAL_UNWIND_FRAME |
+ // _US_FORCE_UNWIND) state.
+
+ // Create a mock exception object for force unwinding.
+ _Unwind_Exception ex;
+ ex.exception_class = 0x434C4E47554E5700; // CLNGUNW\0
+ ex.pr_cache.fnstart = frameInfo.start_ip;
+ ex.pr_cache.ehtp = (_Unwind_EHT_Header *) unwindInfo;
+ ex.pr_cache.additional= frameInfo.flags;
+
+ // Get and call the personality function to unwind the frame.
+ __personality_routine pr = (__personality_routine) readPrel31(unwindInfo);
+ if (pr(_US_VIRTUAL_UNWIND_FRAME | _US_FORCE_UNWIND, &ex, context) !=
+ _URC_CONTINUE_UNWIND) {
+ return _URC_END_OF_STACK;
+ }
+ } else {
+ size_t off, len;
+ unwindInfo = decode_eht_entry(unwindInfo, &off, &len);
+ if (unwindInfo == NULL) {
+ return _URC_FAILURE;
+ }
+
+ result = _Unwind_VRS_Interpret(context, unwindInfo, off, len);
+ if (result != _URC_CONTINUE_UNWIND) {
+ return _URC_END_OF_STACK;
+ }
+ }
+#endif // LIBCXXABI_ARM_EHABI
+
+ // debugging
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ char functionName[512];
+ unw_proc_info_t frame;
+ unw_word_t offset;
+ 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,
+ (void *)&cursor);
+ }
+
+ // call trace function with this frame
+ result = (*callback)((struct _Unwind_Context *)(&cursor), ref);
+ if (result != _URC_NO_REASON) {
+ _LIBUNWIND_TRACE_UNWINDING(
+ " _backtrace: ended because callback returned %d\n", result);
+ return result;
+ }
+ }
+}
+
+
+/// 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.
+ // We create an unwind cursor then alter the IP to be pc
+ unw_cursor_t cursor;
+ unw_context_t uc;
+ 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_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;
+}
+
+/// Returns the CFA (call frame area, or stack pointer at start of function)
+/// for the current context.
+_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);
+ return (uintptr_t)result;
+}
+
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+/// ipBefore is a boolean that says if IP is already adjusted to be the call
+/// 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);
+ *ipBefore = 0;
+ return _Unwind_GetIP(context);
+}
+
+#if _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);
+ _unw_add_dynamic_fde((unw_word_t)(uintptr_t) fde);
+}
+
+
+/// Called by programs with dynamic code generators that want
+/// to unregister a dynamically generated 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);
+ _unw_remove_dynamic_fde((unw_word_t)(uintptr_t) fde);
+}
+
+
+// The following register/deregister functions are gcc extensions.
+// They have existed on Mac OS X, but have never worked because Mac OS X
+// before 10.6 used keymgr to track known FDEs, but these functions
+// never got updated to use keymgr.
+// For now, we implement these as do-nothing functions to keep any existing
+// 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
+_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",
+ fde, ob, tb, db);
+ // do nothing, this function never worked in Mac OS X
+}
+
+_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);
+ // do nothing, this function never worked in Mac OS X
+}
+
+_LIBUNWIND_EXPORT void __register_frame_info_table_bases(const void *fde,
+ void *ob, void *tb,
+ void *db) {
+ (void)fde;
+ (void)ob;
+ (void)tb;
+ (void)db;
+ _LIBUNWIND_TRACE_API("__register_frame_info_table_bases"
+ "(%p,%p, %p, %p)\n", 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);
+ // 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);
+ // 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);
+ // 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);
+ // do nothing, this function never worked in Mac OS X
+ return NULL;
+}
+#endif // _LIBUNWIND_SUPPORT_FRAME_APIS
+
+#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
diff --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
new file mode 100644
index 00000000000..84627c253b0
--- /dev/null
+++ b/libunwind/src/UnwindLevel1.c
@@ -0,0 +1,534 @@
+//===------------------------- UnwindLevel1.c -----------------------------===//
+//
+// 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 C++ ABI Exception Handling Level 1 as documented at:
+// http://mentorembedded.github.io/cxx-abi/abi-eh.html
+// using libunwind
+//
+//===----------------------------------------------------------------------===//
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "config.h"
+
+#if !LIBCXXABI_ARM_EHABI
+
+static _Unwind_Reason_Code
+unwind_phase1(unw_context_t *uc, _Unwind_Exception *exception_object) {
+ unw_cursor_t cursor1;
+ unw_init_local(&cursor1, uc);
+
+ // Walk each frame looking for a place to stop.
+ for (bool handlerNotFound = true; handlerNotFound;) {
+
+ // Ask libuwind to get next frame (skip over first which is
+ // _Unwind_RaiseException).
+ int stepResult = unw_step(&cursor1);
+ if (stepResult == 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ (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",
+ (void *)exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+
+ // See if frame has code to run (has personality routine).
+ unw_proc_info_t frameInfo;
+ unw_word_t sp;
+ if (unw_get_proc_info(&cursor1, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase1(ex_ojb=%p): unw_get_proc_info "
+ "failed => _URC_FATAL_PHASE1_ERROR\n",
+ (void *)exception_object);
+ return _URC_FATAL_PHASE1_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(&cursor1, functionBuf, sizeof(functionBuf),
+ &offset) != UNW_ESUCCESS) ||
+ (frameInfo.start_ip + offset > frameInfo.end_ip))
+ functionName = ".anonymous.";
+ unw_word_t pc;
+ unw_get_reg(&cursor1, 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",
+ (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
+ // this frame.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(long)(frameInfo.handler);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): calling personality function %p\n",
+ (void *)exception_object, (void *)(uintptr_t)p);
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
+ exception_object, (struct _Unwind_Context *)(&cursor1));
+ switch (personalityResult) {
+ case _URC_HANDLER_FOUND:
+ // found a catch clause or locals that need destructing in this frame
+ // stop search and remember stack pointer at the frame
+ handlerNotFound = false;
+ unw_get_reg(&cursor1, UNW_REG_SP, &sp);
+ exception_object->private_2 = (uintptr_t)sp;
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND \n",
+ (void *)exception_object);
+ return _URC_NO_REASON;
+
+ case _URC_CONTINUE_UNWIND:
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ (void *)exception_object);
+ // continue unwinding
+ break;
+
+ default:
+ // something went wrong
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR\n",
+ (void *)exception_object);
+ return _URC_FATAL_PHASE1_ERROR;
+ }
+ }
+ }
+ return _URC_NO_REASON;
+}
+
+
+static _Unwind_Reason_Code
+unwind_phase2(unw_context_t *uc, _Unwind_Exception *exception_object) {
+ unw_cursor_t cursor2;
+ unw_init_local(&cursor2, uc);
+
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n",
+ (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
+ // _Unwind_RaiseException).
+ int stepResult = unw_step(&cursor2);
+ if (stepResult == 0) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_step() reached "
+ "bottom => _URC_END_OF_STACK\n",
+ (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",
+ (void *)exception_object);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+
+ // Get info about this frame.
+ unw_word_t sp;
+ unw_proc_info_t frameInfo;
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ if (unw_get_proc_info(&cursor2, &frameInfo) != UNW_ESUCCESS) {
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): unw_get_proc_info "
+ "failed => _URC_FATAL_PHASE1_ERROR\n",
+ (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(ex_ojb=%p): start_ip=0x%" PRIx64
+ ", func=%s, sp=0x%" PRIx64 ", lsda=0x%" PRIx64
+ ", personality=0x%" PRIx64 "\n",
+ (void *)exception_object, frameInfo.start_ip,
+ functionName, sp, frameInfo.lsda,
+ frameInfo.handler);
+ }
+
+ // If there is a personality routine, tell it we are unwinding.
+ if (frameInfo.handler != 0) {
+ __personality_routine p =
+ (__personality_routine)(long)(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.
+ action = (_Unwind_Action)(_UA_CLEANUP_PHASE | _UA_HANDLER_FRAME);
+ }
+ _Unwind_Reason_Code personalityResult =
+ (*p)(1, action, exception_object->exception_class, exception_object,
+ (struct _Unwind_Context *)(&cursor2));
+ switch (personalityResult) {
+ case _URC_CONTINUE_UNWIND:
+ // Continue unwinding
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND\n",
+ (void *)exception_object);
+ if (sp == exception_object->private_2) {
+ // Phase 1 said we would stop at this frame, but we did not...
+ _LIBUNWIND_ABORT("during phase1 personality function said it would "
+ "stop here, but now in phase2 it did not stop here");
+ }
+ break;
+ case _URC_INSTALL_CONTEXT:
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
+ (void *)exception_object);
+ // Personality routine says to transfer control to landing pad.
+ // We may get control back if landing pad calls _Unwind_Resume().
+ if (_LIBUNWIND_TRACING_UNWINDING) {
+ unw_word_t pc;
+ unw_get_reg(&cursor2, UNW_REG_IP, &pc);
+ unw_get_reg(&cursor2, UNW_REG_SP, &sp);
+ _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
+ "user code with ip=0x%" PRIx64
+ ", sp=0x%" PRIx64 "\n",
+ (void *)exception_object, pc, sp);
+ }
+ unw_resume(&cursor2);
+ // unw_resume() only returns if there was an error.
+ return _URC_FATAL_PHASE2_ERROR;
+ default:
+ // Personality routine returned an unknown result code.
+ _LIBUNWIND_DEBUG_LOG("personality function returned unknown result %d",
+ personalityResult);
+ return _URC_FATAL_PHASE2_ERROR;
+ }
+ }
+ }
+
+ // Clean up phase did not resume at the frame that the search phase
+ // said it would...
+ return _URC_FATAL_PHASE2_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\n",
+ (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 "\n",
+ (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\n",
+ (void *)exception_object, stopResult);
+ if (stopResult != _URC_NO_REASON) {
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): stopped by stop function\n",
+ (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)(long)(frameInfo.handler);
+ _LIBUNWIND_TRACE_UNWINDING(
+ "unwind_phase2_forced(ex_ojb=%p): calling personality function %p\n",
+ (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\n",
+ (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",
+ (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\n",
+ (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\n",
+ (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 __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",
+ (void *)exception_object);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ // Mark that this is a non-forced unwind, so _Unwind_Resume()
+ // can do the right thing.
+ exception_object->private_1 = 0;
+ exception_object->private_2 = 0;
+
+ // phase 1: the search phase
+ _Unwind_Reason_Code phase1 = unwind_phase1(&uc, exception_object);
+ if (phase1 != _URC_NO_REASON)
+ return phase1;
+
+ // phase 2: the clean up phase
+ return unwind_phase2(&uc, exception_object);
+}
+
+
+
+/// When _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 _Unwind_Resume() to continue with the
+/// unwinding. Note: the call to _Unwind_Resume() is from compiler
+/// geneated user code. All other _Unwind_* routines are called
+/// by the C++ runtime __cxa_* routines.
+///
+/// Note: re-throwing an exception (as opposed to continuing the unwind)
+/// is implemented by having the code call __cxa_rethrow() which
+/// 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);
+ unw_context_t uc;
+ unw_getcontext(&uc);
+
+ if (exception_object->private_1 != 0)
+ unwind_phase2_forced(&uc, exception_object,
+ (_Unwind_Stop_Fn) exception_object->private_1,
+ (void *)exception_object->private_2);
+ else
+ unwind_phase2(&uc, exception_object);
+
+ // 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 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)\n",
+ (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_1 = (uintptr_t) stop;
+ exception_object->private_2 = (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) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_proc_info_t frameInfo;
+ uintptr_t result = 0;
+ if (unw_get_proc_info(cursor, &frameInfo) == UNW_ESUCCESS)
+ result = (uintptr_t)frameInfo.lsda;
+ _LIBUNWIND_TRACE_API(
+ "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR "\n",
+ (void *)context, result);
+ if (result != 0) {
+ if (*((uint8_t *)result) != 0xFF)
+ _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF\n",
+ 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) {
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_proc_info_t frameInfo;
+ 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",
+ (void *)context, result);
+ return result;
+}
+
+
+/// 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",
+ (void *)exception_object);
+ if (exception_object->exception_cleanup != NULL)
+ (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
+ exception_object);
+}
+
+/// Called by personality handler during phase 2 to get register values.
+_LIBUNWIND_EXPORT uintptr_t
+_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);
+ 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);
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_set_reg(cursor, index, value);
+}
+
+/// Called by personality handler during phase 2 to get instruction pointer.
+_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);
+ return (uintptr_t)result;
+}
+
+/// Called by personality handler during phase 2 to alter instruction pointer,
+/// such as setting where the landing pad is, so _Unwind_Resume() will
+/// 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);
+ unw_cursor_t *cursor = (unw_cursor_t *)context;
+ unw_set_reg(cursor, UNW_REG_IP, value);
+}
+
+#else
+
+_LIBUNWIND_EXPORT uintptr_t
+_Unwind_GetGR(struct _Unwind_Context *context, int index) {
+ uintptr_t value = 0;
+ _Unwind_VRS_Get(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
+ _LIBUNWIND_TRACE_API("_Unwind_GetGR(context=%p, reg=%d) => 0x%" PRIx64 "\n",
+ (void *)context, index, (uint64_t)value);
+ return value;
+}
+
+_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);
+ _Unwind_VRS_Set(context, _UVRSC_CORE, (uint32_t)index, _UVRSD_UINT32, &value);
+}
+
+_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
+ // remove the thumb-bit before returning
+ uintptr_t value = _Unwind_GetGR(context, 15) & (~(uintptr_t)0x1);
+ _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => 0x%" PRIx64 "\n",
+ (void *)context, (uint64_t)value);
+ return value;
+}
+
+_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);
+ uintptr_t thumb_bit = _Unwind_GetGR(context, 15) & ((uintptr_t)0x1);
+ _Unwind_SetGR(context, 15, value | thumb_bit);
+}
+
+#endif // !LIBCXXABI_ARM_EHABI
+
diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
new file mode 100644
index 00000000000..7d21953999f
--- /dev/null
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -0,0 +1,430 @@
+//===-------------------- UnwindRegistersRestore.S ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "assembly.h"
+
+ .text
+
+#if defined(__i386__)
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
+#
+# void libunwind::Registers_x86::jumpto()
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+ movl 4(%esp), %eax
+ # set up eax and ret on new stack location
+ movl 28(%eax), %edx # edx holds new stack pointer
+ subl $8,%edx
+ movl %edx, 28(%eax)
+ movl 0(%eax), %ebx
+ movl %ebx, 0(%edx)
+ movl 40(%eax), %ebx
+ movl %ebx, 4(%edx)
+ # we now have ret and eax pushed onto where new stack will be
+ # restore all registers
+ movl 4(%eax), %ebx
+ movl 8(%eax), %ecx
+ movl 12(%eax), %edx
+ movl 16(%eax), %edi
+ movl 20(%eax), %esi
+ movl 24(%eax), %ebp
+ movl 28(%eax), %esp
+ # skip ss
+ # skip eflags
+ pop %eax # eax was already pushed on new stack
+ ret # eip was already pushed on new stack
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+
+#elif defined(__x86_64__)
+
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
+#
+# void libunwind::Registers_x86_64::jumpto()
+#
+# On entry, thread_state pointer is in rdi
+
+ movq 56(%rdi), %rax # rax holds new stack pointer
+ subq $16, %rax
+ movq %rax, 56(%rdi)
+ movq 32(%rdi), %rbx # store new rdi on new stack
+ movq %rbx, 0(%rax)
+ movq 128(%rdi), %rbx # store new rip on new stack
+ movq %rbx, 8(%rax)
+ # restore all registers
+ movq 0(%rdi), %rax
+ movq 8(%rdi), %rbx
+ movq 16(%rdi), %rcx
+ movq 24(%rdi), %rdx
+ # restore rdi later
+ movq 40(%rdi), %rsi
+ movq 48(%rdi), %rbp
+ # restore rsp later
+ movq 64(%rdi), %r8
+ movq 72(%rdi), %r9
+ movq 80(%rdi), %r10
+ movq 88(%rdi), %r11
+ movq 96(%rdi), %r12
+ movq 104(%rdi), %r13
+ movq 112(%rdi), %r14
+ movq 120(%rdi), %r15
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ movq 56(%rdi), %rsp # cut back rsp to new location
+ pop %rdi # rdi was saved here earlier
+ ret # rip was saved here
+
+
+#elif defined(__ppc__)
+
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
+;
+; void libunwind::Registers_ppc::jumpto()
+;
+; On entry:
+; thread_state pointer is in r3
+;
+
+ ; restore integral registerrs
+ ; skip r0 for now
+ ; skip r1 for now
+ lwz r2, 16(r3)
+ ; skip r3 for now
+ ; skip r4 for now
+ ; skip r5 for now
+ lwz r6, 32(r3)
+ lwz r7, 36(r3)
+ lwz r8, 40(r3)
+ lwz r9, 44(r3)
+ lwz r10, 48(r3)
+ lwz r11, 52(r3)
+ lwz r12, 56(r3)
+ lwz r13, 60(r3)
+ lwz r14, 64(r3)
+ lwz r15, 68(r3)
+ lwz r16, 72(r3)
+ lwz r17, 76(r3)
+ lwz r18, 80(r3)
+ lwz r19, 84(r3)
+ lwz r20, 88(r3)
+ lwz r21, 92(r3)
+ lwz r22, 96(r3)
+ lwz r23,100(r3)
+ lwz r24,104(r3)
+ lwz r25,108(r3)
+ lwz r26,112(r3)
+ lwz r27,116(r3)
+ lwz r28,120(r3)
+ lwz r29,124(r3)
+ lwz r30,128(r3)
+ lwz r31,132(r3)
+
+ ; restore float registers
+ lfd f0, 160(r3)
+ lfd f1, 168(r3)
+ lfd f2, 176(r3)
+ lfd f3, 184(r3)
+ lfd f4, 192(r3)
+ lfd f5, 200(r3)
+ lfd f6, 208(r3)
+ lfd f7, 216(r3)
+ lfd f8, 224(r3)
+ lfd f9, 232(r3)
+ lfd f10,240(r3)
+ lfd f11,248(r3)
+ lfd f12,256(r3)
+ lfd f13,264(r3)
+ lfd f14,272(r3)
+ lfd f15,280(r3)
+ lfd f16,288(r3)
+ lfd f17,296(r3)
+ lfd f18,304(r3)
+ lfd f19,312(r3)
+ lfd f20,320(r3)
+ lfd f21,328(r3)
+ lfd f22,336(r3)
+ lfd f23,344(r3)
+ lfd f24,352(r3)
+ lfd f25,360(r3)
+ lfd f26,368(r3)
+ lfd f27,376(r3)
+ lfd f28,384(r3)
+ lfd f29,392(r3)
+ lfd f30,400(r3)
+ lfd f31,408(r3)
+
+ ; restore vector registers if any are in use
+ lwz r5,156(r3) ; test VRsave
+ cmpwi r5,0
+ beq Lnovec
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+ ; the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
+
+
+#define LOAD_VECTOR_UNALIGNEDl(_index) \
+ andis. r0,r5,(1<<(15-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+Ldone ## _index:
+
+#define LOAD_VECTOR_UNALIGNEDh(_index) \
+ andi. r0,r5,(1<<(31-_index)) @\
+ beq Ldone ## _index @\
+ lwz r0, 424+_index*16(r3) @\
+ stw r0, 0(r4) @\
+ lwz r0, 424+_index*16+4(r3) @\
+ stw r0, 4(r4) @\
+ lwz r0, 424+_index*16+8(r3) @\
+ stw r0, 8(r4) @\
+ lwz r0, 424+_index*16+12(r3)@\
+ stw r0, 12(r4) @\
+ lvx v ## _index,0,r4 @\
+ Ldone ## _index:
+
+
+ LOAD_VECTOR_UNALIGNEDl(0)
+ LOAD_VECTOR_UNALIGNEDl(1)
+ LOAD_VECTOR_UNALIGNEDl(2)
+ LOAD_VECTOR_UNALIGNEDl(3)
+ LOAD_VECTOR_UNALIGNEDl(4)
+ LOAD_VECTOR_UNALIGNEDl(5)
+ LOAD_VECTOR_UNALIGNEDl(6)
+ LOAD_VECTOR_UNALIGNEDl(7)
+ LOAD_VECTOR_UNALIGNEDl(8)
+ LOAD_VECTOR_UNALIGNEDl(9)
+ LOAD_VECTOR_UNALIGNEDl(10)
+ LOAD_VECTOR_UNALIGNEDl(11)
+ LOAD_VECTOR_UNALIGNEDl(12)
+ LOAD_VECTOR_UNALIGNEDl(13)
+ LOAD_VECTOR_UNALIGNEDl(14)
+ LOAD_VECTOR_UNALIGNEDl(15)
+ LOAD_VECTOR_UNALIGNEDh(16)
+ LOAD_VECTOR_UNALIGNEDh(17)
+ LOAD_VECTOR_UNALIGNEDh(18)
+ LOAD_VECTOR_UNALIGNEDh(19)
+ LOAD_VECTOR_UNALIGNEDh(20)
+ LOAD_VECTOR_UNALIGNEDh(21)
+ LOAD_VECTOR_UNALIGNEDh(22)
+ LOAD_VECTOR_UNALIGNEDh(23)
+ LOAD_VECTOR_UNALIGNEDh(24)
+ LOAD_VECTOR_UNALIGNEDh(25)
+ LOAD_VECTOR_UNALIGNEDh(26)
+ LOAD_VECTOR_UNALIGNEDh(27)
+ LOAD_VECTOR_UNALIGNEDh(28)
+ LOAD_VECTOR_UNALIGNEDh(29)
+ LOAD_VECTOR_UNALIGNEDh(30)
+ LOAD_VECTOR_UNALIGNEDh(31)
+
+Lnovec:
+ lwz r0, 136(r3) ; __cr
+ mtocrf 255,r0
+ lwz r0, 148(r3) ; __ctr
+ mtctr r0
+ lwz r0, 0(r3) ; __ssr0
+ mtctr r0
+ lwz r0, 8(r3) ; do r0 now
+ lwz r5,28(r3) ; do r5 now
+ lwz r4,24(r3) ; do r4 now
+ lwz r1,12(r3) ; do sp now
+ lwz r3,20(r3) ; do r3 last
+ bctr
+
+#elif defined(__arm64__) || defined(__aarch64__)
+
+//
+// void libunwind::Registers_arm64::jumpto()
+//
+// On entry:
+// thread_state pointer is in x0
+//
+ .p2align 2
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
+ // skip restore of x0,x1 for now
+ ldp x2, x3, [x0, #0x010]
+ ldp x4, x5, [x0, #0x020]
+ ldp x6, x7, [x0, #0x030]
+ ldp x8, x9, [x0, #0x040]
+ ldp x10,x11, [x0, #0x050]
+ ldp x12,x13, [x0, #0x060]
+ ldp x14,x15, [x0, #0x070]
+ ldp x16,x17, [x0, #0x080]
+ ldp x18,x19, [x0, #0x090]
+ ldp x20,x21, [x0, #0x0A0]
+ ldp x22,x23, [x0, #0x0B0]
+ ldp x24,x25, [x0, #0x0C0]
+ ldp x26,x27, [x0, #0x0D0]
+ ldp x28,fp, [x0, #0x0E0]
+ ldr lr, [x0, #0x100] // restore pc into lr
+ ldr x1, [x0, #0x0F8]
+ mov sp,x1 // restore sp
+
+ ldp d0, d1, [x0, #0x110]
+ ldp d2, d3, [x0, #0x120]
+ ldp d4, d5, [x0, #0x130]
+ ldp d6, d7, [x0, #0x140]
+ ldp d8, d9, [x0, #0x150]
+ ldp d10,d11, [x0, #0x160]
+ ldp d12,d13, [x0, #0x170]
+ ldp d14,d15, [x0, #0x180]
+ ldp d16,d17, [x0, #0x190]
+ ldp d18,d19, [x0, #0x1A0]
+ ldp d20,d21, [x0, #0x1B0]
+ ldp d22,d23, [x0, #0x1C0]
+ ldp d24,d25, [x0, #0x1D0]
+ ldp d26,d27, [x0, #0x1E0]
+ ldp d28,d29, [x0, #0x1F0]
+ ldr d30, [x0, #0x200]
+ ldr d31, [x0, #0x208]
+
+ ldp x0, x1, [x0, #0x000] // restore x0,x1
+ ret lr // jump to pc
+
+#elif defined(__arm__) && !defined(__APPLE__)
+
+#if !defined(__ARM_ARCH_ISA_ARM)
+ .thumb
+#endif
+
+@
+@ void libunwind::Registers_arm::restoreCoreAndJumpTo()
+@
+@ On entry:
+@ thread_state pointer is in r0
+@
+ .p2align 2
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
+#if !defined(__ARM_ARCH_ISA_ARM)
+ ldr r2, [r0, #52]
+ ldr r3, [r0, #60]
+ mov sp, r2
+ mov lr, r3 @ restore pc into lr
+ ldm r0, {r0-r7}
+#else
+ @ Use lr as base so that r0 can be restored.
+ mov lr, r0
+ @ 32bit thumb-2 restrictions for ldm:
+ @ . the sp (r13) cannot be in the list
+ @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
+ ldm lr, {r0-r12}
+ ldr sp, [lr, #52]
+ ldr lr, [lr, #60] @ restore pc into lr
+#endif
+ JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+ .fpu vfpv3-d16
+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
+ @ want the compiler to generate instructions that access those) but this is
+ @ only accessed if the personality routine needs these registers. Use of
+ @ these registers implies they are, actually, available on the target, so
+ @ it's ok to execute.
+ @ So, generate the instruction using the corresponding coprocessor mnemonic.
+ vldmia r0, {d0-d15}
+ JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreVFPWithFLDMX(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+ .fpu vfpv3-d16
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm19restoreVFPWithFLDMXEPy)
+ vldmia r0, {d0-d15} @ fldmiax is deprecated in ARMv7+ and now behaves like vldmia
+ JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreVFPv3(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+ .fpu vfpv3
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm12restoreVFPv3EPy)
+ vldmia r0, {d16-d31}
+ JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::restoreiWMMX(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+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
+ ldcl p1, cr3, [r0], #8 @ wldrd wR3, [r0], #8
+ ldcl p1, cr4, [r0], #8 @ wldrd wR4, [r0], #8
+ ldcl p1, cr5, [r0], #8 @ wldrd wR5, [r0], #8
+ ldcl p1, cr6, [r0], #8 @ wldrd wR6, [r0], #8
+ ldcl p1, cr7, [r0], #8 @ wldrd wR7, [r0], #8
+ ldcl p1, cr8, [r0], #8 @ wldrd wR8, [r0], #8
+ ldcl p1, cr9, [r0], #8 @ wldrd wR9, [r0], #8
+ ldcl p1, cr10, [r0], #8 @ wldrd wR10, [r0], #8
+ ldcl p1, cr11, [r0], #8 @ wldrd wR11, [r0], #8
+ ldcl p1, cr12, [r0], #8 @ wldrd wR12, [r0], #8
+ 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)
+
+@
+@ static void libunwind::Registers_arm::restoreiWMMXControl(unw_uint32_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+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
diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
new file mode 100644
index 00000000000..3d457216d6f
--- /dev/null
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -0,0 +1,416 @@
+//===------------------------ UnwindRegistersSave.S -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "assembly.h"
+
+ .text
+
+#if defined(__i386__)
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# + +
+# +-----------------------+
+# + thread_state pointer +
+# +-----------------------+
+# + return address +
+# +-----------------------+ <-- SP
+# + +
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ push %eax
+ movl 8(%esp), %eax
+ movl %ebx, 4(%eax)
+ movl %ecx, 8(%eax)
+ movl %edx, 12(%eax)
+ movl %edi, 16(%eax)
+ movl %esi, 20(%eax)
+ movl %ebp, 24(%eax)
+ movl %esp, %edx
+ addl $8, %edx
+ movl %edx, 28(%eax) # store what sp was at call site as esp
+ # skip ss
+ # skip eflags
+ movl 4(%esp), %edx
+ movl %edx, 40(%eax) # store return address as eip
+ # skip cs
+ # skip ds
+ # skip es
+ # skip fs
+ # skip gs
+ movl (%esp), %edx
+ movl %edx, (%eax) # store original eax
+ popl %eax
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif defined(__x86_64__)
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+# 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
+ # skip rflags
+ # skip cs
+ # skip fs
+ # skip gs
+ xorl %eax, %eax # return UNW_ESUCCESS
+ ret
+
+#elif defined(__ppc__)
+
+;
+; extern int unw_getcontext(unw_context_t* thread_state)
+;
+; On entry:
+; thread_state pointer is in r3
+;
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ stw r0, 8(r3)
+ mflr r0
+ stw r0, 0(r3) ; store lr as ssr0
+ stw r1, 12(r3)
+ stw r2, 16(r3)
+ stw r3, 20(r3)
+ stw r4, 24(r3)
+ stw r5, 28(r3)
+ stw r6, 32(r3)
+ stw r7, 36(r3)
+ stw r8, 40(r3)
+ stw r9, 44(r3)
+ stw r10, 48(r3)
+ stw r11, 52(r3)
+ stw r12, 56(r3)
+ stw r13, 60(r3)
+ stw r14, 64(r3)
+ stw r15, 68(r3)
+ stw r16, 72(r3)
+ stw r17, 76(r3)
+ stw r18, 80(r3)
+ stw r19, 84(r3)
+ stw r20, 88(r3)
+ stw r21, 92(r3)
+ stw r22, 96(r3)
+ stw r23,100(r3)
+ stw r24,104(r3)
+ stw r25,108(r3)
+ stw r26,112(r3)
+ stw r27,116(r3)
+ stw r28,120(r3)
+ stw r29,124(r3)
+ stw r30,128(r3)
+ stw r31,132(r3)
+
+ ; save VRSave register
+ mfspr r0,256
+ stw r0,156(r3)
+ ; save CR registers
+ mfcr r0
+ stw r0,136(r3)
+ ; save CTR register
+ mfctr r0
+ stw r0,148(r3)
+
+ ; save float registers
+ stfd f0, 160(r3)
+ stfd f1, 168(r3)
+ stfd f2, 176(r3)
+ stfd f3, 184(r3)
+ stfd f4, 192(r3)
+ stfd f5, 200(r3)
+ stfd f6, 208(r3)
+ stfd f7, 216(r3)
+ stfd f8, 224(r3)
+ stfd f9, 232(r3)
+ stfd f10,240(r3)
+ stfd f11,248(r3)
+ stfd f12,256(r3)
+ stfd f13,264(r3)
+ stfd f14,272(r3)
+ stfd f15,280(r3)
+ stfd f16,288(r3)
+ stfd f17,296(r3)
+ stfd f18,304(r3)
+ stfd f19,312(r3)
+ stfd f20,320(r3)
+ stfd f21,328(r3)
+ stfd f22,336(r3)
+ stfd f23,344(r3)
+ stfd f24,352(r3)
+ stfd f25,360(r3)
+ stfd f26,368(r3)
+ stfd f27,376(r3)
+ stfd f28,384(r3)
+ stfd f29,392(r3)
+ stfd f30,400(r3)
+ stfd f31,408(r3)
+
+
+ ; save vector registers
+
+ subi r4,r1,16
+ rlwinm r4,r4,0,0,27 ; mask low 4-bits
+ ; r4 is now a 16-byte aligned pointer into the red zone
+
+#define SAVE_VECTOR_UNALIGNED(_vec, _offset) \
+ stvx _vec,0,r4 @\
+ lwz r5, 0(r4) @\
+ stw r5, _offset(r3) @\
+ lwz r5, 4(r4) @\
+ stw r5, _offset+4(r3) @\
+ lwz r5, 8(r4) @\
+ stw r5, _offset+8(r3) @\
+ lwz r5, 12(r4) @\
+ stw r5, _offset+12(r3)
+
+ SAVE_VECTOR_UNALIGNED( v0, 424+0x000)
+ SAVE_VECTOR_UNALIGNED( v1, 424+0x010)
+ SAVE_VECTOR_UNALIGNED( v2, 424+0x020)
+ SAVE_VECTOR_UNALIGNED( v3, 424+0x030)
+ SAVE_VECTOR_UNALIGNED( v4, 424+0x040)
+ SAVE_VECTOR_UNALIGNED( v5, 424+0x050)
+ SAVE_VECTOR_UNALIGNED( v6, 424+0x060)
+ SAVE_VECTOR_UNALIGNED( v7, 424+0x070)
+ SAVE_VECTOR_UNALIGNED( v8, 424+0x080)
+ SAVE_VECTOR_UNALIGNED( v9, 424+0x090)
+ SAVE_VECTOR_UNALIGNED(v10, 424+0x0A0)
+ SAVE_VECTOR_UNALIGNED(v11, 424+0x0B0)
+ SAVE_VECTOR_UNALIGNED(v12, 424+0x0C0)
+ SAVE_VECTOR_UNALIGNED(v13, 424+0x0D0)
+ SAVE_VECTOR_UNALIGNED(v14, 424+0x0E0)
+ SAVE_VECTOR_UNALIGNED(v15, 424+0x0F0)
+ SAVE_VECTOR_UNALIGNED(v16, 424+0x100)
+ SAVE_VECTOR_UNALIGNED(v17, 424+0x110)
+ SAVE_VECTOR_UNALIGNED(v18, 424+0x120)
+ SAVE_VECTOR_UNALIGNED(v19, 424+0x130)
+ SAVE_VECTOR_UNALIGNED(v20, 424+0x140)
+ SAVE_VECTOR_UNALIGNED(v21, 424+0x150)
+ SAVE_VECTOR_UNALIGNED(v22, 424+0x160)
+ SAVE_VECTOR_UNALIGNED(v23, 424+0x170)
+ SAVE_VECTOR_UNALIGNED(v24, 424+0x180)
+ SAVE_VECTOR_UNALIGNED(v25, 424+0x190)
+ SAVE_VECTOR_UNALIGNED(v26, 424+0x1A0)
+ SAVE_VECTOR_UNALIGNED(v27, 424+0x1B0)
+ SAVE_VECTOR_UNALIGNED(v28, 424+0x1C0)
+ SAVE_VECTOR_UNALIGNED(v29, 424+0x1D0)
+ SAVE_VECTOR_UNALIGNED(v30, 424+0x1E0)
+ SAVE_VECTOR_UNALIGNED(v31, 424+0x1F0)
+
+ li r3, 0 ; return UNW_ESUCCESS
+ blr
+
+
+#elif defined(__arm64__) || defined(__aarch64__)
+
+//
+// extern int unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+// thread_state pointer is in x0
+//
+ .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+ stp x0, x1, [x0, #0x000]
+ stp x2, x3, [x0, #0x010]
+ stp x4, x5, [x0, #0x020]
+ stp x6, x7, [x0, #0x030]
+ stp x8, x9, [x0, #0x040]
+ stp x10,x11, [x0, #0x050]
+ stp x12,x13, [x0, #0x060]
+ stp x14,x15, [x0, #0x070]
+ stp x16,x17, [x0, #0x080]
+ stp x18,x19, [x0, #0x090]
+ stp x20,x21, [x0, #0x0A0]
+ stp x22,x23, [x0, #0x0B0]
+ stp x24,x25, [x0, #0x0C0]
+ stp x26,x27, [x0, #0x0D0]
+ stp x28,fp, [x0, #0x0E0]
+ str lr, [x0, #0x0F0]
+ mov x1,sp
+ str x1, [x0, #0x0F8]
+ str lr, [x0, #0x100] // store return address as pc
+ // skip cpsr
+ stp d0, d1, [x0, #0x110]
+ stp d2, d3, [x0, #0x120]
+ stp d4, d5, [x0, #0x130]
+ stp d6, d7, [x0, #0x140]
+ stp d8, d9, [x0, #0x150]
+ stp d10,d11, [x0, #0x160]
+ stp d12,d13, [x0, #0x170]
+ stp d14,d15, [x0, #0x180]
+ stp d16,d17, [x0, #0x190]
+ stp d18,d19, [x0, #0x1A0]
+ stp d20,d21, [x0, #0x1B0]
+ stp d22,d23, [x0, #0x1C0]
+ stp d24,d25, [x0, #0x1D0]
+ stp d26,d27, [x0, #0x1E0]
+ stp d28,d29, [x0, #0x1F0]
+ str d30, [x0, #0x200]
+ str d31, [x0, #0x208]
+ ldr x0, #0 // return UNW_ESUCCESS
+ ret
+
+#elif defined(__arm__) && !defined(__APPLE__)
+
+#if !defined(__ARM_ARCH_ISA_ARM)
+ .thumb
+#endif
+
+@
+@ extern int unw_getcontext(unw_context_t* thread_state)
+@
+@ On entry:
+@ thread_state pointer is in r0
+@
+@ Per EHABI #4.7 this only saves the core integer registers.
+@ EHABI #7.4.5 notes that in general all VRS registers should be restored
+@ however this is very hard to do for VFP registers because it is unknown
+@ to the library how many registers are implemented by the architecture.
+@ Instead, VFP registers are demand saved by logic external to unw_getcontext.
+@
+ .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+#if !defined(__ARM_ARCH_ISA_ARM)
+ stm r0!, {r0-r7}
+ mov r2, sp
+ mov r3, lr
+ str r2, [r0, #52]
+ str r3, [r0, #56]
+ str r3, [r0, #60] @ store return address as pc
+#else
+ @ 32bit thumb-2 restrictions for stm:
+ @ . the sp (r13) cannot be in the list
+ @ . the pc (r15) cannot be in the list in an STM instruction
+ stm r0, {r0-r12}
+ 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)
+
+@
+@ static void libunwind::Registers_arm::saveVFPWithFSTMD(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+ .fpu vfpv3-d16
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMDEPy)
+ vstmia r0, {d0-d15}
+ JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::saveVFPWithFSTMX(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+ .fpu vfpv3-d16
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm16saveVFPWithFSTMXEPy)
+ vstmia r0, {d0-d15} @ fstmiax is deprecated in ARMv7+ and now behaves like vstmia
+ JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::saveVFPv3(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+ .fpu vfpv3
+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
+ @ want the compiler to generate instructions that access those) but this is
+ @ only accessed if the personality routine needs these registers. Use of
+ @ these registers implies they are, actually, available on the target, so
+ @ it's ok to execute.
+ @ So, generate the instructions using the corresponding coprocessor mnemonic.
+ vstmia r0, {d16-d31}
+ JMP(lr)
+
+@
+@ static void libunwind::Registers_arm::saveiWMMX(unw_fpreg_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+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
+ stcl p1, cr3, [r0], #8 @ wstrd wR3, [r0], #8
+ stcl p1, cr4, [r0], #8 @ wstrd wR4, [r0], #8
+ stcl p1, cr5, [r0], #8 @ wstrd wR5, [r0], #8
+ stcl p1, cr6, [r0], #8 @ wstrd wR6, [r0], #8
+ stcl p1, cr7, [r0], #8 @ wstrd wR7, [r0], #8
+ stcl p1, cr8, [r0], #8 @ wstrd wR8, [r0], #8
+ stcl p1, cr9, [r0], #8 @ wstrd wR9, [r0], #8
+ stcl p1, cr10, [r0], #8 @ wstrd wR10, [r0], #8
+ stcl p1, cr11, [r0], #8 @ wstrd wR11, [r0], #8
+ stcl p1, cr12, [r0], #8 @ wstrd wR12, [r0], #8
+ 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)
+
+@
+@ static void libunwind::Registers_arm::saveiWMMXControl(unw_uint32_t* values)
+@
+@ On entry:
+@ values pointer is in r0
+@
+ .p2align 2
+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
diff --git a/libunwind/src/Unwind_AppleExtras.cpp b/libunwind/src/Unwind_AppleExtras.cpp
new file mode 100644
index 00000000000..b8baef5fa76
--- /dev/null
+++ b/libunwind/src/Unwind_AppleExtras.cpp
@@ -0,0 +1,205 @@
+//===--------------------- Unwind_AppleExtras.cpp -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "config.h"
+#include "DwarfParser.hpp"
+#include "unwind_ext.h"
+
+
+// private keymgr stuff
+#define KEYMGR_GCC3_DW2_OBJ_LIST 302
+extern "C" {
+ extern void _keymgr_set_and_unlock_processwide_ptr(int key, void *ptr);
+ extern void *_keymgr_get_and_lock_processwide_ptr(int key);
+}
+
+// undocumented libgcc "struct object"
+struct libgcc_object {
+ void *start;
+ void *unused1;
+ void *unused2;
+ void *fde;
+ unsigned long encoding;
+ void *fde_end;
+ libgcc_object *next;
+};
+
+// undocumented libgcc "struct km_object_info" referenced by
+// KEYMGR_GCC3_DW2_OBJ_LIST
+struct libgcc_object_info {
+ libgcc_object *seen_objects;
+ libgcc_object *unseen_objects;
+ unsigned spare[2];
+};
+
+
+// static linker symbols to prevent wrong two level namespace for _Unwind symbols
+#if defined(__arm__)
+ #define NOT_HERE_BEFORE_5_0(sym) \
+ extern const char sym##_tmp30 __asm("$ld$hide$os3.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp30 = 0; \
+ extern const char sym##_tmp31 __asm("$ld$hide$os3.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp31 = 0; \
+ extern const char sym##_tmp32 __asm("$ld$hide$os3.2$_" #sym );\
+ __attribute__((visibility("default"))) const char sym##_tmp32 = 0; \
+ extern const char sym##_tmp40 __asm("$ld$hide$os4.0$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp40 = 0; \
+ extern const char sym##_tmp41 __asm("$ld$hide$os4.1$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp41 = 0; \
+ extern const char sym##_tmp42 __asm("$ld$hide$os4.2$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp42 = 0; \
+ extern const char sym##_tmp43 __asm("$ld$hide$os4.3$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp43 = 0;
+#elif defined(__arm64__)
+ #define NOT_HERE_BEFORE_10_6(sym)
+ #define NEVER_HERE(sym)
+#else
+ #define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+ #define NEVER_HERE(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
+
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+//
+// symbols in libSystem.dylib in 10.6 and later, but are in libgcc_s.dylib in
+// earlier versions
+//
+NOT_HERE_BEFORE_10_6(_Unwind_DeleteException)
+NOT_HERE_BEFORE_10_6(_Unwind_Find_FDE)
+NOT_HERE_BEFORE_10_6(_Unwind_ForcedUnwind)
+NOT_HERE_BEFORE_10_6(_Unwind_GetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_10_6(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_10_6(_Unwind_RaiseException)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume)
+NOT_HERE_BEFORE_10_6(_Unwind_SetGR)
+NOT_HERE_BEFORE_10_6(_Unwind_SetIP)
+NOT_HERE_BEFORE_10_6(_Unwind_Backtrace)
+NOT_HERE_BEFORE_10_6(_Unwind_FindEnclosingFunction)
+NOT_HERE_BEFORE_10_6(_Unwind_GetCFA)
+NOT_HERE_BEFORE_10_6(_Unwind_GetDataRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_GetTextRelBase)
+NOT_HERE_BEFORE_10_6(_Unwind_Resume_or_Rethrow)
+NOT_HERE_BEFORE_10_6(_Unwind_GetIPInfo)
+NOT_HERE_BEFORE_10_6(__register_frame)
+NOT_HERE_BEFORE_10_6(__deregister_frame)
+
+//
+// symbols in libSystem.dylib for compatibility, but we don't want any new code
+// using them
+//
+NEVER_HERE(__register_frame_info_bases)
+NEVER_HERE(__register_frame_info)
+NEVER_HERE(__register_frame_info_table_bases)
+NEVER_HERE(__register_frame_info_table)
+NEVER_HERE(__register_frame_table)
+NEVER_HERE(__deregister_frame_info)
+NEVER_HERE(__deregister_frame_info_bases)
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+
+
+
+#if _LIBUNWIND_BUILD_SJLJ_APIS
+//
+// symbols in libSystem.dylib in iOS 5.0 and later, but are in libgcc_s.dylib in
+// earlier versions
+//
+NOT_HERE_BEFORE_5_0(_Unwind_GetLanguageSpecificData)
+NOT_HERE_BEFORE_5_0(_Unwind_GetRegionStart)
+NOT_HERE_BEFORE_5_0(_Unwind_GetIP)
+NOT_HERE_BEFORE_5_0(_Unwind_SetGR)
+NOT_HERE_BEFORE_5_0(_Unwind_SetIP)
+NOT_HERE_BEFORE_5_0(_Unwind_DeleteException)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Register)
+NOT_HERE_BEFORE_5_0(_Unwind_GetGR)
+NOT_HERE_BEFORE_5_0(_Unwind_GetIPInfo)
+NOT_HERE_BEFORE_5_0(_Unwind_GetCFA)
+NOT_HERE_BEFORE_5_0(_Unwind_SjLj_Resume)
+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
+
+
+namespace libunwind {
+
+_LIBUNWIND_HIDDEN
+bool checkKeyMgrRegisteredFDEs(uintptr_t pc, void *&fde) {
+#if __MAC_OS_X_VERSION_MIN_REQUIRED
+ // lastly check for old style keymgr registration of dynamically generated
+ // FDEs acquire exclusive access to libgcc_object_info
+ libgcc_object_info *head = (libgcc_object_info *)
+ _keymgr_get_and_lock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST);
+ if (head != NULL) {
+ // look at each FDE in keymgr
+ for (libgcc_object *ob = head->unseen_objects; ob != NULL; ob = ob->next) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char *msg = CFI_Parser<LocalAddressSpace>::decodeFDE(
+ LocalAddressSpace::sThisAddressSpace,
+ (uintptr_t)ob->fde, &fdeInfo, &cieInfo);
+ if (msg == NULL) {
+ // Check if this FDE is for a function that includes the pc
+ if ((fdeInfo.pcStart <= pc) && (pc < fdeInfo.pcEnd)) {
+ fde = (void*)fdeInfo.pcStart;
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST,
+ head);
+ return true;
+ }
+ }
+ }
+ }
+ // release libgcc_object_info
+ _keymgr_set_and_unlock_processwide_ptr(KEYMGR_GCC3_DW2_OBJ_LIST, head);
+#else
+ (void)pc;
+ (void)fde;
+#endif
+ return false;
+}
+
+}
+
+
+#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/libunwind/src/assembly.h b/libunwind/src/assembly.h
new file mode 100644
index 00000000000..f46a24d0eed
--- /dev/null
+++ b/libunwind/src/assembly.h
@@ -0,0 +1,80 @@
+/* ===-- assembly.h - libUnwind assembler support macros -------------------===
+ *
+ * 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.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file defines macros for use in libUnwind assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef UNWIND_ASSEMBLY_H
+#define UNWIND_ASSEMBLY_H
+
+#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#define SEPARATOR @
+#elif defined(__arm64__)
+#define SEPARATOR %%
+#else
+#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)
+#elif defined(__ELF__)
+#if defined(__arm__)
+#define SYMBOL_IS_FUNC(name) .type name,%function
+#else
+#define SYMBOL_IS_FUNC(name) .type name,@function
+#endif
+#else
+#define SYMBOL_IS_FUNC(name) \
+ .def name SEPARATOR \
+ .scl 2 SEPARATOR \
+ .type 32 SEPARATOR \
+ .endef
+#endif
+
+#define DEFINE_LIBUNWIND_FUNCTION(name) \
+ .globl SYMBOL_NAME(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 \
+ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ SYMBOL_NAME(name):
+
+#if defined(__arm__)
+#if !defined(__ARM_ARCH)
+#define __ARM_ARCH 4
+#endif
+
+#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
+#define ARM_HAS_BX
+#endif
+
+#ifdef ARM_HAS_BX
+#define JMP(r) bx r
+#else
+#define JMP(r) mov pc, r
+#endif
+#endif /* __arm__ */
+
+#endif /* UNWIND_ASSEMBLY_H */
diff --git a/libunwind/src/config.h b/libunwind/src/config.h
new file mode 100644
index 00000000000..c9ec087a7ea
--- /dev/null
+++ b/libunwind/src/config.h
@@ -0,0 +1,126 @@
+//===----------------------------- config.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.
+//
+//
+// Defines macros used within libuwind project.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LIBUNWIND_CONFIG_H
+#define LIBUNWIND_CONFIG_H
+
+#include <assert.h>
+#include <stdio.h>
+
+// Define static_assert() unless already defined by compiler.
+#ifndef __has_feature
+ #define __has_feature(__x) 0
+#endif
+#if !(__has_feature(cxx_static_assert)) && !defined(static_assert)
+ #define static_assert(__b, __m) \
+ extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ] \
+ __attribute__( ( unused ) );
+#endif
+
+// Platform specific configuration defines.
+#ifdef __APPLE__
+ #include <Availability.h>
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ void __assert_rtn(const char *, const char *, int, const char *)
+ __attribute__((noreturn));
+ #ifdef __cplusplus
+ }
+ #endif
+
+ #define _LIBUNWIND_BUILD_ZERO_COST_APIS (defined(__i386__) || \
+ defined(__x86_64__) || \
+ defined(__arm64__))
+ #define _LIBUNWIND_BUILD_SJLJ_APIS defined(__arm__)
+ #define _LIBUNWIND_SUPPORT_FRAME_APIS (defined(__i386__) || \
+ defined(__x86_64__))
+ #define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
+ #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
+ #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+ #define _LIBUNWIND_ABORT(msg) __assert_rtn(__func__, __FILE__, __LINE__, msg)
+
+ #if defined(FOR_DYLD)
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 0
+ #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
+ #else
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND 1
+ #define _LIBUNWIND_SUPPORT_DWARF_INDEX 0
+ #endif
+
+#else
+ #include <stdlib.h>
+
+ static inline void assert_rtn(const char* func, const char* file, int line, const char* msg) __attribute__ ((noreturn));
+ static inline void assert_rtn(const char* func, const char* file, int line, const char* msg) {
+ fprintf(stderr, "libunwind: %s %s:%d - %s\n", func, file, line, msg);
+ assert(false);
+ abort();
+ }
+
+ #define _LIBUNWIND_BUILD_ZERO_COST_APIS (defined(__i386__) || \
+ defined(__x86_64__) || \
+ defined(__arm__))
+ #define _LIBUNWIND_BUILD_SJLJ_APIS 0
+ #define _LIBUNWIND_SUPPORT_FRAME_APIS (defined(__i386__) || \
+ defined(__x86_64__))
+ #define _LIBUNWIND_EXPORT __attribute__((visibility("default")))
+ #define _LIBUNWIND_HIDDEN __attribute__((visibility("hidden")))
+ #define _LIBUNWIND_LOG(msg, ...) fprintf(stderr, "libuwind: " msg, __VA_ARGS__)
+ #define _LIBUNWIND_ABORT(msg) assert_rtn(__func__, __FILE__, __LINE__, msg)
+
+ #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND 0
+ #define _LIBUNWIND_SUPPORT_DWARF_UNWIND !defined(__arm__) || \
+ defined(__ARM_DWARF_EH__)
+ #define _LIBUNWIND_SUPPORT_DWARF_INDEX _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#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_TRACE_UNWINDING(msg, ...)
+ #define _LIBUNWIND_LOG_NON_ZERO(x) x
+#else
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ extern bool logAPIs();
+ extern bool logUnwinding();
+ #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_TRACING_UNWINDING logUnwinding()
+#endif
+
+
+#endif // LIBUNWIND_CONFIG_H
diff --git a/libunwind/src/dwarf2.h b/libunwind/src/dwarf2.h
new file mode 100644
index 00000000000..0dcd2ca99ba
--- /dev/null
+++ b/libunwind/src/dwarf2.h
@@ -0,0 +1,237 @@
+//===------------------------------- dwarf2.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.
+//
+//===----------------------------------------------------------------------===//
+
+
+/*
+ These constants were taken from version 3 of the DWARF standard,
+ which is Copyright (c) 2005 Free Standards Group, and
+ Copyright (c) 1992, 1993 UNIX International, Inc.
+*/
+
+#ifndef __DWARF2__
+#define __DWARF2__
+
+// DWARF unwind instructions
+enum {
+ DW_CFA_nop = 0x0,
+ DW_CFA_set_loc = 0x1,
+ DW_CFA_advance_loc1 = 0x2,
+ DW_CFA_advance_loc2 = 0x3,
+ DW_CFA_advance_loc4 = 0x4,
+ DW_CFA_offset_extended = 0x5,
+ DW_CFA_restore_extended = 0x6,
+ DW_CFA_undefined = 0x7,
+ DW_CFA_same_value = 0x8,
+ DW_CFA_register = 0x9,
+ DW_CFA_remember_state = 0xA,
+ DW_CFA_restore_state = 0xB,
+ DW_CFA_def_cfa = 0xC,
+ DW_CFA_def_cfa_register = 0xD,
+ DW_CFA_def_cfa_offset = 0xE,
+ DW_CFA_def_cfa_expression = 0xF,
+ DW_CFA_expression = 0x10,
+ DW_CFA_offset_extended_sf = 0x11,
+ DW_CFA_def_cfa_sf = 0x12,
+ DW_CFA_def_cfa_offset_sf = 0x13,
+ DW_CFA_val_offset = 0x14,
+ DW_CFA_val_offset_sf = 0x15,
+ DW_CFA_val_expression = 0x16,
+ DW_CFA_advance_loc = 0x40, // high 2 bits are 0x1, lower 6 bits are delta
+ DW_CFA_offset = 0x80, // high 2 bits are 0x2, lower 6 bits are register
+ DW_CFA_restore = 0xC0, // high 2 bits are 0x3, lower 6 bits are register
+
+ // GNU extensions
+ DW_CFA_GNU_window_save = 0x2D,
+ DW_CFA_GNU_args_size = 0x2E,
+ DW_CFA_GNU_negative_offset_extended = 0x2F
+};
+
+
+// FSF exception handling Pointer-Encoding constants
+// Used in CFI augmentation by GCC
+enum {
+ DW_EH_PE_ptr = 0x00,
+ DW_EH_PE_uleb128 = 0x01,
+ DW_EH_PE_udata2 = 0x02,
+ DW_EH_PE_udata4 = 0x03,
+ DW_EH_PE_udata8 = 0x04,
+ DW_EH_PE_signed = 0x08,
+ DW_EH_PE_sleb128 = 0x09,
+ DW_EH_PE_sdata2 = 0x0A,
+ DW_EH_PE_sdata4 = 0x0B,
+ DW_EH_PE_sdata8 = 0x0C,
+ DW_EH_PE_absptr = 0x00,
+ DW_EH_PE_pcrel = 0x10,
+ DW_EH_PE_textrel = 0x20,
+ DW_EH_PE_datarel = 0x30,
+ DW_EH_PE_funcrel = 0x40,
+ DW_EH_PE_aligned = 0x50,
+ DW_EH_PE_indirect = 0x80,
+ DW_EH_PE_omit = 0xFF
+};
+
+
+// DWARF expressions
+enum {
+ DW_OP_addr = 0x03, // constant address (size target specific)
+ DW_OP_deref = 0x06,
+ DW_OP_const1u = 0x08, // 1-byte constant
+ DW_OP_const1s = 0x09, // 1-byte constant
+ DW_OP_const2u = 0x0A, // 2-byte constant
+ DW_OP_const2s = 0x0B, // 2-byte constant
+ DW_OP_const4u = 0x0C, // 4-byte constant
+ DW_OP_const4s = 0x0D, // 4-byte constant
+ DW_OP_const8u = 0x0E, // 8-byte constant
+ DW_OP_const8s = 0x0F, // 8-byte constant
+ DW_OP_constu = 0x10, // ULEB128 constant
+ DW_OP_consts = 0x11, // SLEB128 constant
+ DW_OP_dup = 0x12,
+ DW_OP_drop = 0x13,
+ DW_OP_over = 0x14,
+ DW_OP_pick = 0x15, // 1-byte stack index
+ DW_OP_swap = 0x16,
+ DW_OP_rot = 0x17,
+ DW_OP_xderef = 0x18,
+ DW_OP_abs = 0x19,
+ DW_OP_and = 0x1A,
+ DW_OP_div = 0x1B,
+ DW_OP_minus = 0x1C,
+ DW_OP_mod = 0x1D,
+ DW_OP_mul = 0x1E,
+ DW_OP_neg = 0x1F,
+ DW_OP_not = 0x20,
+ DW_OP_or = 0x21,
+ DW_OP_plus = 0x22,
+ DW_OP_plus_uconst = 0x23, // ULEB128 addend
+ DW_OP_shl = 0x24,
+ DW_OP_shr = 0x25,
+ DW_OP_shra = 0x26,
+ DW_OP_xor = 0x27,
+ DW_OP_skip = 0x2F, // signed 2-byte constant
+ DW_OP_bra = 0x28, // signed 2-byte constant
+ DW_OP_eq = 0x29,
+ DW_OP_ge = 0x2A,
+ DW_OP_gt = 0x2B,
+ DW_OP_le = 0x2C,
+ DW_OP_lt = 0x2D,
+ DW_OP_ne = 0x2E,
+ DW_OP_lit0 = 0x30, // Literal 0
+ DW_OP_lit1 = 0x31, // Literal 1
+ DW_OP_lit2 = 0x32, // Literal 2
+ DW_OP_lit3 = 0x33, // Literal 3
+ DW_OP_lit4 = 0x34, // Literal 4
+ DW_OP_lit5 = 0x35, // Literal 5
+ DW_OP_lit6 = 0x36, // Literal 6
+ DW_OP_lit7 = 0x37, // Literal 7
+ DW_OP_lit8 = 0x38, // Literal 8
+ DW_OP_lit9 = 0x39, // Literal 9
+ DW_OP_lit10 = 0x3A, // Literal 10
+ DW_OP_lit11 = 0x3B, // Literal 11
+ DW_OP_lit12 = 0x3C, // Literal 12
+ DW_OP_lit13 = 0x3D, // Literal 13
+ DW_OP_lit14 = 0x3E, // Literal 14
+ DW_OP_lit15 = 0x3F, // Literal 15
+ DW_OP_lit16 = 0x40, // Literal 16
+ DW_OP_lit17 = 0x41, // Literal 17
+ DW_OP_lit18 = 0x42, // Literal 18
+ DW_OP_lit19 = 0x43, // Literal 19
+ DW_OP_lit20 = 0x44, // Literal 20
+ DW_OP_lit21 = 0x45, // Literal 21
+ DW_OP_lit22 = 0x46, // Literal 22
+ DW_OP_lit23 = 0x47, // Literal 23
+ DW_OP_lit24 = 0x48, // Literal 24
+ DW_OP_lit25 = 0x49, // Literal 25
+ DW_OP_lit26 = 0x4A, // Literal 26
+ DW_OP_lit27 = 0x4B, // Literal 27
+ DW_OP_lit28 = 0x4C, // Literal 28
+ DW_OP_lit29 = 0x4D, // Literal 29
+ DW_OP_lit30 = 0x4E, // Literal 30
+ DW_OP_lit31 = 0x4F, // Literal 31
+ DW_OP_reg0 = 0x50, // Contents of reg0
+ DW_OP_reg1 = 0x51, // Contents of reg1
+ DW_OP_reg2 = 0x52, // Contents of reg2
+ DW_OP_reg3 = 0x53, // Contents of reg3
+ DW_OP_reg4 = 0x54, // Contents of reg4
+ DW_OP_reg5 = 0x55, // Contents of reg5
+ DW_OP_reg6 = 0x56, // Contents of reg6
+ DW_OP_reg7 = 0x57, // Contents of reg7
+ DW_OP_reg8 = 0x58, // Contents of reg8
+ DW_OP_reg9 = 0x59, // Contents of reg9
+ DW_OP_reg10 = 0x5A, // Contents of reg10
+ DW_OP_reg11 = 0x5B, // Contents of reg11
+ DW_OP_reg12 = 0x5C, // Contents of reg12
+ DW_OP_reg13 = 0x5D, // Contents of reg13
+ DW_OP_reg14 = 0x5E, // Contents of reg14
+ DW_OP_reg15 = 0x5F, // Contents of reg15
+ DW_OP_reg16 = 0x60, // Contents of reg16
+ DW_OP_reg17 = 0x61, // Contents of reg17
+ DW_OP_reg18 = 0x62, // Contents of reg18
+ DW_OP_reg19 = 0x63, // Contents of reg19
+ DW_OP_reg20 = 0x64, // Contents of reg20
+ DW_OP_reg21 = 0x65, // Contents of reg21
+ DW_OP_reg22 = 0x66, // Contents of reg22
+ DW_OP_reg23 = 0x67, // Contents of reg23
+ DW_OP_reg24 = 0x68, // Contents of reg24
+ DW_OP_reg25 = 0x69, // Contents of reg25
+ DW_OP_reg26 = 0x6A, // Contents of reg26
+ DW_OP_reg27 = 0x6B, // Contents of reg27
+ DW_OP_reg28 = 0x6C, // Contents of reg28
+ DW_OP_reg29 = 0x6D, // Contents of reg29
+ DW_OP_reg30 = 0x6E, // Contents of reg30
+ DW_OP_reg31 = 0x6F, // Contents of reg31
+ DW_OP_breg0 = 0x70, // base register 0 + SLEB128 offset
+ DW_OP_breg1 = 0x71, // base register 1 + SLEB128 offset
+ DW_OP_breg2 = 0x72, // base register 2 + SLEB128 offset
+ DW_OP_breg3 = 0x73, // base register 3 + SLEB128 offset
+ DW_OP_breg4 = 0x74, // base register 4 + SLEB128 offset
+ DW_OP_breg5 = 0x75, // base register 5 + SLEB128 offset
+ DW_OP_breg6 = 0x76, // base register 6 + SLEB128 offset
+ DW_OP_breg7 = 0x77, // base register 7 + SLEB128 offset
+ DW_OP_breg8 = 0x78, // base register 8 + SLEB128 offset
+ DW_OP_breg9 = 0x79, // base register 9 + SLEB128 offset
+ DW_OP_breg10 = 0x7A, // base register 10 + SLEB128 offset
+ DW_OP_breg11 = 0x7B, // base register 11 + SLEB128 offset
+ DW_OP_breg12 = 0x7C, // base register 12 + SLEB128 offset
+ DW_OP_breg13 = 0x7D, // base register 13 + SLEB128 offset
+ DW_OP_breg14 = 0x7E, // base register 14 + SLEB128 offset
+ DW_OP_breg15 = 0x7F, // base register 15 + SLEB128 offset
+ DW_OP_breg16 = 0x80, // base register 16 + SLEB128 offset
+ DW_OP_breg17 = 0x81, // base register 17 + SLEB128 offset
+ DW_OP_breg18 = 0x82, // base register 18 + SLEB128 offset
+ DW_OP_breg19 = 0x83, // base register 19 + SLEB128 offset
+ DW_OP_breg20 = 0x84, // base register 20 + SLEB128 offset
+ DW_OP_breg21 = 0x85, // base register 21 + SLEB128 offset
+ DW_OP_breg22 = 0x86, // base register 22 + SLEB128 offset
+ DW_OP_breg23 = 0x87, // base register 23 + SLEB128 offset
+ DW_OP_breg24 = 0x88, // base register 24 + SLEB128 offset
+ DW_OP_breg25 = 0x89, // base register 25 + SLEB128 offset
+ DW_OP_breg26 = 0x8A, // base register 26 + SLEB128 offset
+ DW_OP_breg27 = 0x8B, // base register 27 + SLEB128 offset
+ DW_OP_breg28 = 0x8C, // base register 28 + SLEB128 offset
+ DW_OP_breg29 = 0x8D, // base register 29 + SLEB128 offset
+ DW_OP_breg30 = 0x8E, // base register 30 + SLEB128 offset
+ DW_OP_breg31 = 0x8F, // base register 31 + SLEB128 offset
+ DW_OP_regx = 0x90, // ULEB128 register
+ DW_OP_fbreg = 0x91, // SLEB128 offset
+ DW_OP_bregx = 0x92, // ULEB128 register followed by SLEB128 offset
+ DW_OP_piece = 0x93, // ULEB128 size of piece addressed
+ DW_OP_deref_size = 0x94, // 1-byte size of data retrieved
+ DW_OP_xderef_size = 0x95, // 1-byte size of data retrieved
+ DW_OP_nop = 0x96,
+ DW_OP_push_object_addres = 0x97,
+ DW_OP_call2 = 0x98, // 2-byte offset of DIE
+ DW_OP_call4 = 0x99, // 4-byte offset of DIE
+ DW_OP_call_ref = 0x9A, // 4- or 8-byte offset of DIE
+ DW_OP_lo_user = 0xE0,
+ DW_OP_APPLE_uninit = 0xF0,
+ DW_OP_hi_user = 0xFF
+};
+
+
+#endif
diff --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
new file mode 100644
index 00000000000..031ecce90d7
--- /dev/null
+++ b/libunwind/src/libunwind.cpp
@@ -0,0 +1,373 @@
+//===--------------------------- libuwind.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 unw_* functions from <libunwind.h>
+//
+//===----------------------------------------------------------------------===//
+
+#include <libunwind.h>
+
+#ifndef NDEBUG
+#include <cstdlib> // getenv
+#endif
+#include <new>
+#include <tuple>
+#include <memory>
+#include <vector>
+
+#include "libunwind_ext.h"
+#include "config.h"
+
+#include <stdlib.h>
+
+
+#include "UnwindCursor.hpp"
+
+using namespace libunwind;
+
+/// internal object to represent this processes address space
+LocalAddressSpace LocalAddressSpace::sThisAddressSpace;
+
+_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
+ (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace;
+
+/// record the registers and stack position of the caller
+extern int unw_getcontext(unw_context_t *);
+// note: unw_getcontext() implemented in assembly
+
+/// Create a cursor of a thread in this process given 'context' recorded by
+/// 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",
+ static_cast<void *>(cursor),
+ static_cast<void *>(context));
+ // Use "placement new" to allocate UnwindCursor in the cursor buffer.
+#if defined(__i386__)
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#elif defined(__x86_64__)
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#elif defined(__ppc__)
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_ppc>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#elif defined(__arm64__)
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#elif LIBCXXABI_ARM_EHABI
+ new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm>(
+ context, LocalAddressSpace::sThisAddressSpace);
+#endif
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ co->setInfoBasedOnIPRegister();
+
+ return UNW_ESUCCESS;
+}
+
+#ifdef UNW_REMOTE
+/// Create a cursor into a thread in another process.
+_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
+ unw_addr_space_t as,
+ void *arg) {
+ // special case: unw_init_remote(xx, unw_local_addr_space, xx)
+ if (as == (unw_addr_space_t)&LocalAddressSpace::sThisAddressSpace)
+ return unw_init_local(cursor, NULL); //FIXME
+
+ // use "placement new" to allocate UnwindCursor in the cursor buffer
+ switch (as->cpuType) {
+ case CPU_TYPE_I386:
+ new ((void *)cursor)
+ UnwindCursor<OtherAddressSpace<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);
+ break;
+ case CPU_TYPE_POWERPC:
+ new ((void *)cursor)
+ UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>(
+ ((unw_addr_space_ppc *)as)->oas, arg);
+ break;
+ default:
+ return UNW_EUNSPEC;
+ }
+ return UNW_ESUCCESS;
+}
+
+
+static bool is64bit(task_t task) {
+ return false; // FIXME
+}
+
+/// Create an address_space object for use in examining another task.
+_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) {
+#if __i386__
+ if (is64bit(task)) {
+ unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task);
+ as->taskPort = task;
+ as->cpuType = CPU_TYPE_X86_64;
+ //as->oas
+ } else {
+ unw_addr_space_i386 *as = new unw_addr_space_i386(task);
+ as->taskPort = task;
+ as->cpuType = CPU_TYPE_I386;
+ //as->oas
+ }
+#else
+// FIXME
+#endif
+}
+
+
+/// Delete an address_space object.
+_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
+ switch (asp->cpuType) {
+#if __i386__ || __x86_64__
+ case CPU_TYPE_I386: {
+ unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp;
+ delete as;
+ }
+ break;
+ case CPU_TYPE_X86_64: {
+ unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp;
+ delete as;
+ }
+ break;
+#endif
+ case CPU_TYPE_POWERPC: {
+ unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp;
+ delete as;
+ }
+ break;
+ }
+}
+#endif // UNW_REMOTE
+
+
+/// 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",
+ static_cast<void *>(cursor), regNum,
+ static_cast<void *>(value));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->validReg(regNum)) {
+ *value = co->getReg(regNum);
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// 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);
+ 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)
+ co->setInfoBasedOnIPRegister(false);
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// 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",
+ static_cast<void *>(cursor), regNum,
+ static_cast<void *>(value));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->validFloatReg(regNum)) {
+ *value = co->getFloatReg(regNum);
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// 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 LIBCXXABI_ARM_EHABI
+ _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%llX)\n",
+ static_cast<void *>(cursor), regNum, value);
+#else
+ _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n",
+ static_cast<void *>(cursor), regNum, value);
+#endif
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->validFloatReg(regNum)) {
+ co->setFloatReg(regNum, value);
+ return UNW_ESUCCESS;
+ }
+ return UNW_EBADREG;
+}
+
+
+/// 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));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->step();
+}
+
+
+/// 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",
+ static_cast<void *>(cursor), static_cast<void *>(info));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ co->getInfo(info);
+ if (info->end_ip == 0)
+ return UNW_ENOINFO;
+ else
+ return UNW_ESUCCESS;
+}
+
+
+/// 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));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ co->jumpto();
+ return UNW_EUNSPEC;
+}
+
+
+/// 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",
+ static_cast<void *>(cursor), static_cast<void *>(buf),
+ static_cast<unsigned long>(bufLen));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ if (co->getFunctionName(buf, bufLen, offset))
+ return UNW_ESUCCESS;
+ else
+ return UNW_EUNSPEC;
+}
+
+
+/// 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",
+ static_cast<void *>(cursor), regNum);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->validFloatReg(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",
+ static_cast<void *>(cursor), regNum);
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->getRegisterName(regNum);
+}
+
+
+/// 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",
+ static_cast<void *>(cursor));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->isSignalFrame();
+}
+
+#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",
+ static_cast<void *>(cursor));
+ AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+ return co->saveVFPAsX();
+}
+#endif
+
+
+#if _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",
+ reinterpret_cast<void *>(func));
+ DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
+}
+
+
+/// IPI: for __register_frame()
+void _unw_add_dynamic_fde(unw_word_t fde) {
+ CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+ CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+ const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
+ LocalAddressSpace::sThisAddressSpace,
+ (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
+ if (message == NULL) {
+ // dynamically registered FDEs don't have a mach_header group they are in.
+ // Use fde as mh_group
+ unw_word_t mh_group = fdeInfo.fdeStart;
+ DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
+ fdeInfo.pcStart, fdeInfo.pcEnd,
+ fdeInfo.fdeStart);
+ } else {
+ _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message);
+ }
+}
+
+/// IPI: for __deregister_frame()
+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
+
+
+
+// Add logging hooks in Debug builds only
+#ifndef NDEBUG
+#include <stdlib.h>
+
+_LIBUNWIND_HIDDEN
+bool logAPIs() {
+ // 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_APIS") != NULL);
+ checked = true;
+ }
+ return log;
+}
+
+_LIBUNWIND_HIDDEN
+bool logUnwinding() {
+ // 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_UNWINDING") != NULL);
+ checked = true;
+ }
+ return log;
+}
+
+#endif // NDEBUG
+
diff --git a/libunwind/src/libunwind_ext.h b/libunwind/src/libunwind_ext.h
new file mode 100644
index 00000000000..5eb0e877302
--- /dev/null
+++ b/libunwind/src/libunwind_ext.h
@@ -0,0 +1,47 @@
+//===------------------------ libunwind_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 libunwind API.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LIBUNWIND_EXT__
+#define __LIBUNWIND_EXT__
+
+#include "config.h"
+#include <libunwind.h>
+#include <unwind.h>
+
+#define UNW_STEP_SUCCESS 1
+#define UNW_STEP_END 0
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// SPI
+extern 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));
+
+// IPI
+extern void _unw_add_dynamic_fde(unw_word_t fde);
+extern void _unw_remove_dynamic_fde(unw_word_t fde);
+
+#if LIBCXXABI_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,
+ size_t offset, size_t len);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LIBUNWIND_EXT__
diff --git a/libunwind/src/unwind_ext.h b/libunwind/src/unwind_ext.h
new file mode 100644
index 00000000000..c40ce6a1610
--- /dev/null
+++ b/libunwind/src/unwind_ext.h
@@ -0,0 +1,37 @@
+//===-------------------------- unwind_ext.h ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+// Extensions to unwind API.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __UNWIND_EXT__
+#define __UNWIND_EXT__
+
+#include "unwind.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// These platform specific functions to get and set the top context are
+// implemented elsewhere.
+
+extern struct _Unwind_FunctionContext *
+__Unwind_SjLj_GetTopOfFunctionStack();
+
+extern void
+__Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UNWIND_EXT__
+
+
diff --git a/libunwind/test/unwind_01.pass.cpp b/libunwind/test/unwind_01.pass.cpp
new file mode 100644
index 00000000000..9d237f89446
--- /dev/null
+++ b/libunwind/test/unwind_01.pass.cpp
@@ -0,0 +1,96 @@
+//===------------------------- unwind_01.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+
+struct A
+{
+ static int count;
+ int id_;
+ A() : id_(++count) {}
+ ~A() {assert(id_ == count--);}
+
+private:
+ A(const A&);
+ A& operator=(const A&);
+};
+
+int A::count = 0;
+
+struct B
+{
+ static int count;
+ int id_;
+ B() : id_(++count) {}
+ ~B() {assert(id_ == count--);}
+
+private:
+ B(const B&);
+ B& operator=(const B&);
+};
+
+int B::count = 0;
+
+struct C
+{
+ static int count;
+ int id_;
+ C() : id_(++count) {}
+ ~C() {assert(id_ == count--);}
+
+private:
+ C(const C&);
+ C& operator=(const C&);
+};
+
+int C::count = 0;
+
+void f2()
+{
+ C c;
+ A a;
+ throw 55;
+ B b;
+}
+
+void f1()
+{
+ A a;
+ B b;
+ f2();
+ C c;
+}
+
+int main()
+{
+ try
+ {
+ f1();
+ assert(false);
+ }
+ catch (int* i)
+ {
+ assert(false);
+ }
+ catch (long i)
+ {
+ assert(false);
+ }
+ catch (int i)
+ {
+ assert(i == 55);
+ }
+ catch (...)
+ {
+ assert(false);
+ }
+ assert(A::count == 0);
+ assert(B::count == 0);
+ assert(C::count == 0);
+}
diff --git a/libunwind/test/unwind_02.pass.cpp b/libunwind/test/unwind_02.pass.cpp
new file mode 100644
index 00000000000..94d53adc416
--- /dev/null
+++ b/libunwind/test/unwind_02.pass.cpp
@@ -0,0 +1,96 @@
+//===------------------------- unwind_02.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+
+struct A
+{
+ static int count;
+ int id_;
+ A() : id_(++count) {}
+ ~A() {assert(id_ == count--);}
+
+private:
+ A(const A&);
+ A& operator=(const A&);
+};
+
+int A::count = 0;
+
+struct B
+{
+ static int count;
+ int id_;
+ B() : id_(++count) {}
+ ~B() {assert(id_ == count--);}
+
+private:
+ B(const B&);
+ B& operator=(const B&);
+};
+
+int B::count = 0;
+
+struct C
+{
+ static int count;
+ int id_;
+ C() : id_(++count) {}
+ ~C() {assert(id_ == count--);}
+
+private:
+ C(const C&);
+ C& operator=(const C&);
+};
+
+int C::count = 0;
+
+void f2()
+{
+ C c;
+ A a;
+ throw 55;
+ B b;
+}
+
+void f1() throw (long, char, int, double)
+{
+ A a;
+ B b;
+ f2();
+ C c;
+}
+
+int main()
+{
+ try
+ {
+ f1();
+ assert(false);
+ }
+ catch (int* i)
+ {
+ assert(false);
+ }
+ catch (long i)
+ {
+ assert(false);
+ }
+ catch (int i)
+ {
+ assert(i == 55);
+ }
+ catch (...)
+ {
+ assert(false);
+ }
+ assert(A::count == 0);
+ assert(B::count == 0);
+ assert(C::count == 0);
+}
diff --git a/libunwind/test/unwind_03.pass.cpp b/libunwind/test/unwind_03.pass.cpp
new file mode 100644
index 00000000000..8af1d2b3fd6
--- /dev/null
+++ b/libunwind/test/unwind_03.pass.cpp
@@ -0,0 +1,102 @@
+//===------------------------- unwind_03.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+#include <stdlib.h>
+#include <assert.h>
+
+struct A
+{
+ static int count;
+ int id_;
+ A() : id_(++count) {}
+ ~A() {assert(id_ == count--);}
+
+private:
+ A(const A&);
+ A& operator=(const A&);
+};
+
+int A::count = 0;
+
+struct B
+{
+ static int count;
+ int id_;
+ B() : id_(++count) {}
+ ~B() {assert(id_ == count--);}
+
+private:
+ B(const B&);
+ B& operator=(const B&);
+};
+
+int B::count = 0;
+
+struct C
+{
+ static int count;
+ int id_;
+ C() : id_(++count) {}
+ ~C() {assert(id_ == count--);}
+
+private:
+ C(const C&);
+ C& operator=(const C&);
+};
+
+int C::count = 0;
+
+void f2()
+{
+ C c;
+ A a;
+ throw 55;
+ B b;
+}
+
+void f1() throw (long, char, double)
+{
+ A a;
+ B b;
+ f2();
+ C c;
+}
+
+void u_handler()
+{
+ exit(0);
+}
+
+int main()
+{
+ std::set_unexpected(u_handler);
+ try
+ {
+ f1();
+ assert(false);
+ }
+ catch (int* i)
+ {
+ assert(false);
+ }
+ catch (long i)
+ {
+ assert(false);
+ }
+ catch (int i)
+ {
+ assert(i == 55);
+ }
+ catch (...)
+ {
+ assert(false);
+ }
+ assert(false);
+}
diff --git a/libunwind/test/unwind_04.pass.cpp b/libunwind/test/unwind_04.pass.cpp
new file mode 100644
index 00000000000..0fc6587e823
--- /dev/null
+++ b/libunwind/test/unwind_04.pass.cpp
@@ -0,0 +1,108 @@
+//===------------------------- unwind_04.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+#include <stdlib.h>
+#include <assert.h>
+
+struct A
+{
+ static int count;
+ int id_;
+ A() : id_(++count) {}
+ ~A() {assert(id_ == count--);}
+
+private:
+ A(const A&);
+ A& operator=(const A&);
+};
+
+int A::count = 0;
+
+struct B
+{
+ static int count;
+ int id_;
+ B() : id_(++count) {}
+ ~B() {assert(id_ == count--);}
+
+private:
+ B(const B&);
+ B& operator=(const B&);
+};
+
+int B::count = 0;
+
+struct C
+{
+ static int count;
+ int id_;
+ C() : id_(++count) {}
+ ~C() {assert(id_ == count--);}
+
+private:
+ C(const C&);
+ C& operator=(const C&);
+};
+
+int C::count = 0;
+
+void f2()
+{
+ C c;
+ A a;
+ throw 55;
+ B b;
+}
+
+void f1() throw (long, char, double)
+{
+ A a;
+ B b;
+ f2();
+ C c;
+}
+
+void u_handler()
+{
+ throw 'a';
+}
+
+int main()
+{
+ std::set_unexpected(u_handler);
+ try
+ {
+ f1();
+ assert(false);
+ }
+ catch (int* i)
+ {
+ assert(false);
+ }
+ catch (long i)
+ {
+ assert(false);
+ }
+ catch (int i)
+ {
+ assert(false);
+ }
+ catch (char c)
+ {
+ assert(c == 'a');
+ }
+ catch (...)
+ {
+ assert(false);
+ }
+ assert(A::count == 0);
+ assert(B::count == 0);
+ assert(C::count == 0);
+}
diff --git a/libunwind/test/unwind_05.pass.cpp b/libunwind/test/unwind_05.pass.cpp
new file mode 100644
index 00000000000..b994c19939d
--- /dev/null
+++ b/libunwind/test/unwind_05.pass.cpp
@@ -0,0 +1,112 @@
+//===------------------------- unwind_05.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+#include <stdlib.h>
+#include <assert.h>
+
+struct A
+{
+ static int count;
+ int id_;
+ A() : id_(++count) {}
+ ~A() {assert(id_ == count--);}
+
+private:
+ A(const A&);
+ A& operator=(const A&);
+};
+
+int A::count = 0;
+
+struct B
+{
+ static int count;
+ int id_;
+ B() : id_(++count) {}
+ ~B() {assert(id_ == count--);}
+
+private:
+ B(const B&);
+ B& operator=(const B&);
+};
+
+int B::count = 0;
+
+struct C
+{
+ static int count;
+ int id_;
+ C() : id_(++count) {}
+ ~C() {assert(id_ == count--);}
+
+private:
+ C(const C&);
+ C& operator=(const C&);
+};
+
+int C::count = 0;
+
+void f2()
+{
+ C c;
+ A a;
+ throw 55;
+ B b;
+}
+
+void f1() throw (long, char, double, std::bad_exception)
+{
+ A a;
+ B b;
+ f2();
+ C c;
+}
+
+void u_handler()
+{
+ throw;
+}
+
+int main()
+{
+ std::set_unexpected(u_handler);
+ try
+ {
+ f1();
+ assert(false);
+ }
+ catch (int* i)
+ {
+ assert(false);
+ }
+ catch (long i)
+ {
+ assert(false);
+ }
+ catch (int i)
+ {
+ assert(false);
+ }
+ catch (char c)
+ {
+ assert(false);
+ }
+ catch (const std::bad_exception& e)
+ {
+ assert(true);
+ }
+ catch (...)
+ {
+ assert(false);
+ }
+ assert(A::count == 0);
+ assert(B::count == 0);
+ assert(C::count == 0);
+}
diff --git a/libunwind/test/unwind_06.pass.cpp b/libunwind/test/unwind_06.pass.cpp
new file mode 100644
index 00000000000..dd505c8e92a
--- /dev/null
+++ b/libunwind/test/unwind_06.pass.cpp
@@ -0,0 +1,257 @@
+//===------------------------- unwind_06.cpp ------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <exception>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+// Compile with -Os to get compiler uses float registers to hold float variables
+
+double get_(int x) { return (double)x; }
+
+double (* volatile get)(int) = get_;
+
+volatile int counter;
+
+double try1(bool v) {
+ double a = get(0);
+ double b = get(1);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b;
+ if (v) throw 10;
+ return get(0)+a+b;
+}
+
+double try2(bool v) {
+ double a = get(0);
+ double b = get(1);
+ double c = get(2);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b + c;
+ if (v) throw 10;
+ return get(0)+a+b+c;
+}
+
+double try3(bool v) {
+ double a = get(0);
+ double b = get(1);
+ double c = get(2);
+ double d = get(3);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b + c + d;
+ if (v) throw 10;
+ return get(0)+a+b+c+d;
+}
+
+double try4(bool v) {
+ double a = get(0);
+ double b = get(0);
+ double c = get(0);
+ double d = get(0);
+ double e = get(0);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b+c+d+e;
+ if (v) throw 10;
+ return get(0)+a+b+c+d+e;
+}
+
+double try5(bool v) {
+ double a = get(0);
+ double b = get(0);
+ double c = get(0);
+ double d = get(0);
+ double e = get(0);
+ double f = get(0);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b+c+d+e+f;
+ if (v) throw 10;
+ return get(0)+a+b+c+d+e+f;
+}
+
+double try6(bool v) {
+ double a = get(0);
+ double b = get(0);
+ double c = get(0);
+ double d = get(0);
+ double e = get(0);
+ double f = get(0);
+ double g = get(0);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b+c+d+e+f+g;
+ if (v) throw 10;
+ return get(0)+a+b+c+d+e+f+g;
+}
+
+double try7(bool v) {
+ double a = get(0);
+ double b = get(0);
+ double c = get(0);
+ double d = get(0);
+ double e = get(0);
+ double f = get(0);
+ double g = get(0);
+ double h = get(0);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b+c+d+e+f+g;
+ if (v) throw 10;
+ return get(0)+a+b+c+d+e+f+g;
+}
+
+double try8(bool v) {
+ double a = get(0);
+ double b = get(0);
+ double c = get(0);
+ double d = get(0);
+ double e = get(0);
+ double f = get(0);
+ double g = get(0);
+ double h = get(0);
+ double i = get(0);
+ for (counter = 100; counter; --counter)
+ a += get(1) + b+c+d+e+f+g+i;
+ if (v) throw 10;
+ return get(0)+a+b+c+d+e+f+g+i;
+}
+
+
+
+
+
+double foo()
+{
+ double a = get(1);
+ double b = get(2);
+ double c = get(3);
+ double d = get(4);
+ double e = get(5);
+ double f = get(6);
+ double g = get(7);
+ double h = get(8);
+ try {
+ try1(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ try {
+ try2(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ try {
+ try3(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ try {
+ try4(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ try {
+ try5(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ try {
+ try6(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ try {
+ try7(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ try {
+ try8(true);
+ }
+ catch (int e) {
+ }
+ assert(a == get(1));
+ assert(b == get(2));
+ assert(c == get(3));
+ assert(d == get(4));
+ assert(e == get(5));
+ assert(f == get(6));
+ assert(g == get(7));
+ assert(h == get(8));
+
+ return a+b+c+d+e+f+g+h;
+}
+
+
+
+int main()
+{
+ foo();
+}
OpenPOWER on IntegriCloud