Merge remote-tracking branch 'upstream/master' into HEAD
diff --git a/LICENSE.TXT b/LICENSE.TXT
index b04ba2c..17969ae 100644
--- a/LICENSE.TXT
+++ b/LICENSE.TXT
@@ -14,7 +14,7 @@
 University of Illinois/NCSA
 Open Source License
 
-Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
 
 All rights reserved.
 
@@ -55,7 +55,7 @@
 
 ==============================================================================
 
-Copyright (c) 2009-2013 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2014 by the contributors listed in CREDITS.TXT
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/include/libunwind.h b/include/libunwind.h
new file mode 100644
index 0000000..eaeab39
--- /dev/null
+++ b/include/libunwind.h
@@ -0,0 +1,486 @@
+//===---------------------------- 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>
+
+#if __APPLE__
+  #include <Availability.h>
+    #if __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;
+typedef uint64_t unw_word_t;
+typedef double unw_fpreg_t;
+
+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;
+
+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*);
+
+#if UNW_REMOTE
+/*
+ * Mac OS X "remote" API for unwinding other processes on same machine
+ *
+ */
+extern unw_addr_space_t unw_local_addr_space;
+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
+
+/*
+ * 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/include/mach-o/compact_unwind_encoding.h b/include/mach-o/compact_unwind_encoding.h
new file mode 100644
index 0000000..6110688
--- /dev/null
+++ b/include/mach-o/compact_unwind_encoding.h
@@ -0,0 +1,487 @@
+//===------------------ 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 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-1020.  The offset/4 
+//    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/4 is
+//    encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 1024).
+//    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.
+//
+
+
+#ifndef __OPEN_SOURCE__
+
+// ARM64
+//
+// 1-bit: start
+// 1-bit: has lsda
+// 2-bit: personality index
+//
+// 4-bits: 4=frame-based, 2=frameless, 3=dwarf
+//  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_FRAME_X21_X22_PAIR_OLD        = 0x00000001,
+    UNWIND_ARM64_FRAME_X23_X24_PAIR_OLD        = 0x00000002,
+    UNWIND_ARM64_FRAME_X25_X26_PAIR_OLD        = 0x00000004,
+    UNWIND_ARM64_FRAME_X27_X28_PAIR_OLD        = 0x00000008,
+    UNWIND_ARM64_FRAME_D8_D9_PAIR_OLD          = 0x00000010,
+    UNWIND_ARM64_FRAME_D10_D11_PAIR_OLD        = 0x00000020,
+    UNWIND_ARM64_FRAME_D12_D13_PAIR_OLD        = 0x00000040,
+    UNWIND_ARM64_FRAME_D14_D15_PAIR_OLD        = 0x00000080,
+
+    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.
+//
+
+#endif // __OPEN_SOURCE__
+
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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[]
+    // uintptr_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/include/unwind.h b/include/unwind.h
new file mode 100644
index 0000000..c5acd93
--- /dev/null
+++ b/include/unwind.h
@@ -0,0 +1,217 @@
+//===------------------------------- 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
+
+typedef enum {
+  _URC_NO_REASON = 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
+} _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;
+
+struct _Unwind_Context;   // opaque
+struct _Unwind_Exception; // forward declaration
+
+struct _Unwind_Exception {
+  uint64_t exception_class;
+  void (*exception_cleanup)(_Unwind_Reason_Code reason,
+                            struct _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
+#if !__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,
+     struct _Unwind_Exception* exceptionObject,
+     struct _Unwind_Context* context,
+     void* stop_parameter );
+
+typedef _Unwind_Reason_Code (*__personality_routine)
+      (int version,
+       _Unwind_Action actions,
+       uint64_t exceptionClass,
+       struct _Unwind_Exception* exceptionObject,
+       struct _Unwind_Context* context);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//
+// The following are the base functions documented by the C++ ABI
+//
+#if __arm__
+extern _Unwind_Reason_Code
+    _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object);
+extern void _Unwind_SjLj_Resume(struct _Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+    _Unwind_RaiseException(struct _Unwind_Exception *exception_object);
+extern void _Unwind_Resume(struct _Unwind_Exception *exception_object);
+#endif
+extern void _Unwind_DeleteException(struct _Unwind_Exception *exception_object);
+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);
+#if __arm__
+extern _Unwind_Reason_Code
+    _Unwind_SjLj_ForcedUnwind(struct _Unwind_Exception *exception_object,
+                              _Unwind_Stop_Fn stop, void *stop_parameter);
+#else
+extern _Unwind_Reason_Code
+    _Unwind_ForcedUnwind(struct _Unwind_Exception *exception_object,
+                         _Unwind_Stop_Fn stop, void *stop_parameter);
+#endif
+
+#if __arm__
+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().
+//
+#if __arm__
+extern _Unwind_Reason_Code
+    _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object);
+#else
+extern _Unwind_Reason_Code
+    _Unwind_Resume_or_Rethrow(struct _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/lib/buildit b/lib/buildit
index b18491d..5a4a710 100755
--- a/lib/buildit
+++ b/lib/buildit
@@ -82,12 +82,12 @@
 set -x
 
 for FILE in ../src/*.cpp; do
-	$CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE
+	$CXX -c -g -O3 $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE
 done
 case $TRIPLE in
   *-*-mingw*)
   for FILE in ../src/support/win32/*.cpp; do
-    $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $FILE
+    $CXX -c -g -Os $RC_CFLAGS $EXTRA_FLAGS -I../include $OPTIONS $FILE
   done
   ;;
 esac
diff --git a/src/Unwind/AddressSpace.hpp b/src/Unwind/AddressSpace.hpp
new file mode 100644
index 0000000..67b0973
--- /dev/null
+++ b/src/Unwind/AddressSpace.hpp
@@ -0,0 +1,430 @@
+//===------------------------- 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 <dlfcn.h>
+
+#if __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"
+
+namespace libunwind {
+
+/// Used by findUnwindSections() to return info about needed sections.
+struct UnwindInfoSections {
+  uintptr_t        dso_base;
+#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
+};
+
+
+/// 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:
+#if __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)      { return *((uint8_t *)addr); }
+  uint16_t        get16(pint_t addr)     { return *((uint16_t *)addr); }
+  uint32_t        get32(pint_t addr)     { return *((uint32_t *)addr); }
+  uint64_t        get64(pint_t addr)     { return *((uint64_t *)addr); }
+  double          getDouble(pint_t addr) { return *((double *)addr); }
+  v128            getVector(pint_t addr) { return *((v128 *)addr); }
+  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);
+  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) {
+#if __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 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:
+    result = (uint16_t)get16(addr);
+    p += 2;
+    addr = (pint_t) p;
+    break;
+  case DW_EH_PE_sdata4:
+    result = (uint32_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:
+    _LIBUNWIND_ABORT("DW_EH_PE_datarel pointer encoding not supported");
+    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;
+}
+
+#if __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)
+    // 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) {
+#if __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;
+  }
+#else
+  // TO DO
+
+#endif
+
+  return false;
+}
+
+
+inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
+#if __APPLE__
+  return checkKeyMgrRegisteredFDEs(targetAddr, *((void**)&fde));
+#else
+  // TO DO: if OS has way to dynamically register FDEs, check that.
+  return false;
+#endif
+}
+
+inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
+                                                size_t bufLen,
+                                                unw_word_t *offset) {
+  dl_info dyldInfo;
+  if (dladdr((void *)addr, &dyldInfo)) {
+    if (dyldInfo.dli_sname != NULL) {
+      strlcpy(buf, dyldInfo.dli_sname, bufLen);
+      *offset = (addr - (pint_t) dyldInfo.dli_saddr);
+      return true;
+    }
+  }
+  return false;
+}
+
+
+
+#if 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);
+  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/src/Unwind/CompactUnwinder.hpp b/src/Unwind/CompactUnwinder.hpp
new file mode 100644
index 0000000..0dc187f
--- /dev/null
+++ b/src/Unwind/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/src/Unwind/DwarfInstructions.hpp b/src/Unwind/DwarfInstructions.hpp
new file mode 100644
index 0000000..158bad8
--- /dev/null
+++ b/src/Unwind/DwarfInstructions.hpp
@@ -0,0 +1,888 @@
+//===-------------------------- 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);
+
+  // x86 specific variants
+  static int lastRestoreReg(const Registers_x86 &);
+  static bool isReturnAddressRegister(int regNum, const Registers_x86 &);
+  static pint_t getCFA(A &addressSpace, const PrologInfo &prolog,
+                       const Registers_x86 &);
+
+  // x86_64 specific variants
+  static int lastRestoreReg(const Registers_x86_64 &);
+  static bool isReturnAddressRegister(int regNum, const Registers_x86_64 &);
+  static pint_t getCFA(A &addressSpace,
+                       const PrologInfo &prolog,
+                       const Registers_x86_64 &);
+
+  // ppc specific variants
+  static int lastRestoreReg(const Registers_ppc &);
+  static bool isReturnAddressRegister(int regNum, const Registers_ppc &);
+  static pint_t getCFA(A &addressSpace,
+                       const PrologInfo &prolog,
+                       const Registers_ppc &);
+
+  // arm64 specific variants
+  static bool isReturnAddressRegister(int regNum, const Registers_arm64 &);
+  static int lastRestoreReg(const Registers_arm64 &);
+  static pint_t getCFA(A &addressSpace,
+                       const PrologInfo &prolog,
+                       const Registers_arm64 &);
+
+};
+
+
+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)) {
+      R newRegisters = registers;
+
+      // get pointer to cfa (architecture specific)
+      pint_t cfa = getCFA(addressSpace, prolog, registers);
+
+      // restore registers that dwarf says were saved
+      pint_t returnAddress = 0;
+      for (int i = 0; i <= lastRestoreReg(newRegisters); ++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 (isReturnAddressRegister(i, registers))
+            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=%llu\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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%llX\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 %lld\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 %lld\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 = opcode - DW_OP_lit0;
+      *(++sp) = value;
+      if (log)
+        fprintf(stderr, "push literal 0x%llX\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 = opcode - DW_OP_reg0;
+      *(++sp) = registers.getRegister((int)reg);
+      if (log)
+        fprintf(stderr, "push reg %d\n", reg);
+      break;
+
+    case DW_OP_regx:
+      reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd);
+      *(++sp) = registers.getRegister((int)reg);
+      if (log)
+        fprintf(stderr, "push reg %d + 0x%llX\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 = opcode - DW_OP_breg0;
+      svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+      svalue += registers.getRegister((int)reg);
+      *(++sp) = (pint_t)(svalue);
+      if (log)
+        fprintf(stderr, "push reg %d + 0x%llX\n", reg, (uint64_t) svalue);
+      break;
+
+    case DW_OP_bregx:
+      reg = (uint32_t)addressSpace.getULEB128(p, expressionEnd);
+      svalue = (sint_t)addressSpace.getSLEB128(p, expressionEnd);
+      svalue += registers.getRegister((int)reg);
+      *(++sp) = (pint_t)(svalue);
+      if (log)
+        fprintf(stderr, "push reg %d + 0x%llX\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%llX\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%llX\n", (uint64_t) * sp);
+  return *sp;
+}
+
+//
+//  x86_64 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_x86_64 &) {
+  static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+              > (int)DW_X86_64_RET_ADDR, "register number out of range");
+  return DW_X86_64_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool
+DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+                                                 const Registers_x86_64 &) {
+  return (regNum == DW_X86_64_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(
+    A &addressSpace, const PrologInfo &prolog,
+    const Registers_x86_64 &registers) {
+  if (prolog.cfaRegister != 0)
+    return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister)
+                                                    + prolog.cfaRegisterOffset);
+  else if (prolog.cfaExpression != 0)
+    return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace, registers, 0);
+  else
+    _LIBUNWIND_ABORT("getCFA(): unknown location for x86_64 cfa");
+}
+
+
+//
+//  x86 specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_x86 &) {
+  static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+              > (int)DW_X86_RET_ADDR, "register number out of range");
+  return DW_X86_RET_ADDR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+                                                      const Registers_x86 &) {
+  return (regNum == DW_X86_RET_ADDR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(
+    A &addressSpace, const PrologInfo &prolog,
+    const Registers_x86 &registers) {
+  if (prolog.cfaRegister != 0)
+    return (pint_t)((sint_t)registers.getRegister((int)prolog.cfaRegister)
+                                                    + prolog.cfaRegisterOffset);
+  else if (prolog.cfaExpression != 0)
+    return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
+                                                                  registers, 0);
+  else
+    _LIBUNWIND_ABORT("getCFA(): unknown location for x86 cfa");
+}
+
+
+//
+//  ppc specific functions
+//
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_ppc &) {
+  static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+              > (int)UNW_PPC_SPEFSCR, "register number out of range");
+  return UNW_PPC_SPEFSCR;
+}
+
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+                                                      const Registers_ppc &) {
+  return (regNum == UNW_PPC_LR);
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(
+    A &addressSpace, const PrologInfo &prolog,
+    const Registers_ppc &registers) {
+  if (prolog.cfaRegister != 0)
+    return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+  else if (prolog.cfaExpression != 0)
+    return evaluateExpression((pint_t)prolog.cfaExpression, addressSpace,
+                                                                  registers, 0);
+  else
+    _LIBUNWIND_ABORT("getCFA(): unknown location for ppc cfa");
+}
+
+
+
+//
+// arm64 specific functions
+//
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::isReturnAddressRegister(int regNum,
+                                                      const Registers_arm64 &) {
+  return (regNum == UNW_ARM64_LR);
+}
+
+template <typename A, typename R>
+int DwarfInstructions<A, R>::lastRestoreReg(const Registers_arm64 &) {
+  static_assert((int)CFI_Parser<A>::kMaxRegisterNumber
+              > (int)UNW_ARM64_D31, "register number out of range");
+  return UNW_ARM64_D31;
+}
+
+template <typename A, typename R>
+typename A::pint_t DwarfInstructions<A, R>::getCFA(A&, const PrologInfo &prolog,
+                                             const Registers_arm64 &registers) {
+  if (prolog.cfaRegister != 0)
+    return registers.getRegister(prolog.cfaRegister) + prolog.cfaRegisterOffset;
+  else
+    _LIBUNWIND_ABORT("getCFA(): unsupported location for arm64 cfa");
+}
+
+
+} // namespace libunwind
+
+#endif // __DWARF_INSTRUCTIONS_HPP__
diff --git a/src/Unwind/DwarfParser.hpp b/src/Unwind/DwarfParser.hpp
new file mode 100644
index 0000000..152baab
--- /dev/null
+++ b/src/Unwind/DwarfParser.hpp
@@ -0,0 +1,713 @@
+//===--------------------------- 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 <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;
+  };
+
+  /// 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 != 0) {
+      // 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 != 0) {
+                // 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 = 0;
+  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
+  addressSpace.getULEB128(p, cieContentEnd);
+  // 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
+  bzero(results, 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%0llX)\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=%llu\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=%llu\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=%llu\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=%lld, offset=%lld)\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=%lld)\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=%lld)\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=%lld)\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=%lld, reg2=%lld)\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=%lld, offset=%lld)\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(%lld)\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%llX, length=%llu)\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=%lld, expression=0x%llX, length=%llu)\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=%lld, offset=%lld)\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=%lld, offset=%lld)\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=%lld, offset=%lld\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=%lld, offset=%lld\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=%lld, expression=0x%llX, length=%lld)\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(%lld)\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(%lld)\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=%lld)\n", operand,
+                  offset);
+        break;
+      case DW_CFA_advance_loc:
+        codeOffset += operand * cieInfo.codeAlignFactor;
+        if (logDwarf)
+          fprintf(stderr, "DW_CFA_advance_loc: new offset=%llu\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=%lld)\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/src/Unwind/Registers.hpp b/src/Unwind/Registers.hpp
new file mode 100644
index 0000000..584e449
--- /dev/null
+++ b/src/Unwind/Registers.hpp
@@ -0,0 +1,1568 @@
+//===----------------------------- 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 "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();
+
+  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");
+  _registers = *((GPRs *)registers);
+}
+
+inline Registers_x86::Registers_x86() {
+  bzero(&_registers, 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();
+
+  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");
+  _registers = *((GPRs *)registers);
+}
+
+inline Registers_x86_64::Registers_x86_64() {
+  bzero(&_registers, 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();
+
+  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");
+  _registers = *((ppc_thread_state_t *)registers);
+  _floatRegisters = *((ppc_float_state_t *)((char *)registers + 160));
+  memcpy(_vectorRegisters, ((char *)registers + 424), sizeof(_vectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc() {
+  bzero(&_registers, sizeof(_registers));
+  bzero(&_floatRegisters, sizeof(_floatRegisters));
+  bzero(&_vectorRegisters, 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();
+
+  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));
+  memcpy(_vectorHalfRegisters, (((char *)registers) + 0x110),
+         sizeof(_vectorHalfRegisters));
+}
+
+inline Registers_arm64::Registers_arm64() {
+  bzero(&_registers, sizeof(_registers));
+  bzero(&_vectorHalfRegisters, 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.
+///
+/// FIXME: Support MMX Data Registers, Control registers, and load/stores
+/// for different representations in the VFP registers as listed in
+/// Table 1 of EHABI #7.5.2
+class _LIBUNWIND_HIDDEN Registers_arm {
+public:
+  Registers_arm();
+  Registers_arm(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  // FIXME: Due to ARM VRS's support for reading/writing different
+  // representations into the VFP registers this set of accessors seem wrong.
+  // If {get,set}FloatRegister() is the backing store for
+  // _Unwind_VRS_{Get,Set} then it might be best to return a tagged union
+  // with types for each representation in _Unwind_VRS_DataRepresentation.
+  // Similarly, unw_{get,set}_fpreg in the public libunwind API may want to
+  // use a similar tagged union to back the unw_fpreg_t output parameter type.
+  bool        validFloatRegister(int num) const;
+  unw_fpreg_t getFloatRegister(int num) const;
+  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();
+
+  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; }
+
+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
+  };
+
+  GPRs    _registers;
+};
+
+inline Registers_arm::Registers_arm(const void *registers) {
+  static_assert(sizeof(Registers_arm) < sizeof(unw_context_t),
+                    "arm registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_arm::Registers_arm() {
+  bzero(&_registers, sizeof(_registers));
+}
+
+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;
+  return false;
+}
+
+inline uint32_t Registers_arm::getRegister(int regNum) const {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    return _registers.__sp;
+  if (regNum == UNW_ARM_LR)
+    return _registers.__lr;
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    return _registers.__pc;
+  if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12))
+    return _registers.__r[regNum];
+  _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
+    _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) const {
+  // FIXME: Implement float register support.
+  return false;
+}
+
+inline unw_fpreg_t Registers_arm::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("ARM float register support not yet implemented");
+}
+
+inline void Registers_arm::setFloatRegister(int, unw_fpreg_t) {
+  _LIBUNWIND_ABORT("ARM float register support not yet implemented");
+}
+
+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/src/Unwind/Unwind-sjlj.c b/src/Unwind/Unwind-sjlj.c
new file mode 100644
index 0000000..f9256b5
--- /dev/null
+++ b/src/Unwind/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/src/Unwind/UnwindCursor.hpp b/src/Unwind/UnwindCursor.hpp
new file mode 100644
index 0000000..256a72d
--- /dev/null
+++ b/src/Unwind/UnwindCursor.hpp
@@ -0,0 +1,1063 @@
+//===------------------------- 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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#if __APPLE__
+  #include <mach-o/dyld.h>
+#endif
+
+#include "libunwind.h"
+
+#include "AddressSpace.hpp"
+#include "Registers.hpp"
+#include "DwarfInstructions.hpp"
+#include "CompactUnwinder.hpp"
+#include "config.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;
+#if __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;
+
+#if __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;
+#if __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));
+}
+
+template <typename A>
+void DwarfFDECache<A>::dyldUnloadHook(const struct mach_header *mh, intptr_t ) {
+  removeAllIn((pint_t) mh);
+}
+
+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:
+  virtual bool        validReg(int) = 0;
+  virtual unw_word_t  getReg(int) = 0;
+  virtual void        setReg(int, unw_word_t) = 0;
+  virtual bool        validFloatReg(int) = 0;
+  virtual double      getFloatReg(int) = 0;
+  virtual void        setFloatReg(int, double) = 0;
+  virtual int         step() = 0;
+  virtual void        getInfo(unw_proc_info_t *) = 0;
+  virtual void        jumpto() = 0;
+  virtual bool        isSignalFrame() = 0;
+  virtual bool        getFunctionName(char *bf, size_t ln, unw_word_t *off) = 0;
+  virtual void        setInfoBasedOnIPRegister(bool isReturnAddr = false) = 0;
+  virtual const char *getRegisterName(int num) = 0;
+};
+
+
+/// 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 double      getFloatReg(int);
+  virtual void        setFloatReg(int, double);
+  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);
+
+  void            operator delete(void *, size_t) {}
+
+private:
+
+#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;
+  }
+
+  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_COMPACT_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");
+
+  bzero(&_info, sizeof(_info));
+}
+
+template <typename A, typename R>
+UnwindCursor<A, R>::UnwindCursor(A &as, void *)
+    : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
+  bzero(&_info, 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>
+double UnwindCursor<A, R>::getFloatReg(int regNum) {
+  return _registers.getFloatRegister(regNum);
+}
+
+template <typename A, typename R>
+void UnwindCursor<A, R>::setFloatReg(int regNum, double value) {
+  _registers.setFloatRegister(regNum, value);
+}
+
+template <typename A, typename R> void UnwindCursor<A, R>::jumpto() {
+  _registers.jumpto();
+}
+
+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 _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)) {
+    // Have eh_frame_hdr section which is index into dwarf section.
+    // TO DO: implement index search
+  }
+#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;
+    }
+    uint32_t personalityDelta = _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 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 _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 no 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();
+#else
+  #error Need _LIBUNWIND_SUPPORT_COMPACT_UNWIND or _LIBUNWIND_SUPPORT_DWARF_UNWIND
+#endif
+
+  // update info based on new PC
+  if (result == UNW_STEP_SUCCESS) {
+    this->setInfoBasedOnIPRegister(true);
+    if (_unwindInfoMissing)
+      return UNW_STEP_END;
+  }
+
+  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/src/Unwind/UnwindLevel1-gcc-ext.c b/src/Unwind/UnwindLevel1-gcc-ext.c
new file mode 100644
index 0000000..c84db76
--- /dev/null
+++ b/src/Unwind/UnwindLevel1-gcc-ext.c
@@ -0,0 +1,268 @@
+//===--------------------- 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 <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "libunwind_ext.h"
+#include "config.h"
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+///  Called by __cxa_rethrow().
+_LIBUNWIND_EXPORT _Unwind_Reason_Code
+_Unwind_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_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_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");
+}
+
+
+/// 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", 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", 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", callback);
+
+  // walk each frame
+  while (true) {
+
+    // 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;
+    }
+
+    // debugging
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionName[512];
+      unw_proc_info_t frameInfo;
+      unw_word_t offset;
+      unw_get_proc_name(&cursor, functionName, 512, &offset);
+      unw_get_proc_info(&cursor, &frameInfo);
+      _LIBUNWIND_TRACE_UNWINDING(
+          " _backtrace: start_ip=0x%llX, func=%s, lsda=0x%llX, context=%p\n",
+          frameInfo.start_ip, functionName, frameInfo.lsda, &cursor);
+    }
+
+    // call trace function with this frame
+    _Unwind_Reason_Code 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%llX\n", 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", 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/src/Unwind/UnwindLevel1.c b/src/Unwind/UnwindLevel1.c
new file mode 100644
index 0000000..b2e93c7
--- /dev/null
+++ b/src/Unwind/UnwindLevel1.c
@@ -0,0 +1,495 @@
+//===------------------------- 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 <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "unwind.h"
+#include "config.h"
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+static _Unwind_Reason_Code
+unwind_phase1(unw_context_t *uc, struct _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",
+                            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",
+                            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",
+                            exception_object);
+      return _URC_FATAL_PHASE1_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionName[512];
+      unw_word_t offset;
+      if ((unw_get_proc_name(&cursor1, functionName, 512, &offset) !=
+           UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
+        strcpy(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",
+          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",
+          exception_object, 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",
+                                   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(unw_context_t *uc, struct _Unwind_Exception *exception_object) {
+  unw_cursor_t cursor2;
+  unw_init_local(&cursor2, uc);
+
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)\n", 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",
+                            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",
+                            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",
+                            exception_object);
+      return _URC_FATAL_PHASE2_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionName[512];
+      unw_word_t offset;
+      if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
+           UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
+        strcpy(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",
+          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",
+            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 if phase2 it did not stop here");
+        }
+        break;
+      case _URC_INSTALL_CONTEXT:
+        _LIBUNWIND_TRACE_UNWINDING(
+            "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT\n",
+            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",
+                                    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,
+                     struct _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",
+                                 exception_object);
+      return _URC_FATAL_PHASE1_ERROR;
+    }
+
+    // When tracing, print state information.
+    if (_LIBUNWIND_TRACING_UNWINDING) {
+      char functionName[512];
+      unw_word_t offset;
+      if ((unw_get_proc_name(&cursor2, functionName, 512, &offset) !=
+           UNW_ESUCCESS) || (frameInfo.start_ip + offset > frameInfo.end_ip))
+        strcpy(functionName, ".anonymous.");
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p):  "
+                                 "start_ip=0x%llX, func=%s, lsda=0x%llX, "
+                                 " personality=0x%llX\n",
+                                 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",
+        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 (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",
+          exception_object, 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",
+                                 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().
+        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",
+                                   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",
+                        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(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_RaiseException(ex_obj=%p)\n",
+                             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(struct _Unwind_Exception *exception_object) {
+  _LIBUNWIND_TRACE_API("_Unwind_Resume(ex_obj=%p)\n", 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(struct _Unwind_Exception *exception_object,
+                     _Unwind_Stop_Fn stop, void *stop_parameter) {
+  _LIBUNWIND_TRACE_API("_Unwind_ForcedUnwind(ex_obj=%p, stop=%p)\n",
+                  exception_object, 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%lX\n", context, result);
+  if (result != 0) {
+    if (*((uint8_t *)result) != 0xFF)
+      _LIBUNWIND_DEBUG_LOG("lsda at 0x%lX does not start with 0xFF\n", result);
+  }
+  return result;
+}
+
+
+
+/// 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%llX\n",
+    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 new_value) {
+  _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, reg=%d, "
+                             "value=0x%0llX)\n", context,
+                             index, (uint64_t) new_value);
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_set_reg(cursor, index, new_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%llX\n", 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 new_value) {
+  _LIBUNWIND_TRACE_API("_Unwind_SetIP(context=%p, value=0x%0llX)\n",
+                             context, (uint64_t) new_value);
+  unw_cursor_t *cursor = (unw_cursor_t *)context;
+  unw_set_reg(cursor, UNW_REG_IP, new_value);
+}
+
+
+/// 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%lX\n",
+                             context, result);
+  return result;
+}
+
+
+/// 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);
+}
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
diff --git a/src/Unwind/UnwindRegistersRestore.S b/src/Unwind/UnwindRegistersRestore.S
new file mode 100644
index 0000000..15e2072
--- /dev/null
+++ b/src/Unwind/UnwindRegistersRestore.S
@@ -0,0 +1,329 @@
+//===-------------------- 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 __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 __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 __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 __arm64__
+
+;
+; void libunwind::Registers_arm64::jumpto()
+;
+; On entry:
+;  thread_state pointer is in x0
+;
+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 __arm__
+
+@
+@ void libunwind::Registers_arm::jumpto()
+@
+@ On entry:
+@  thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm6jumptoEv)
+  @ 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
+  mov pc, lr
+
+#endif
diff --git a/src/Unwind/UnwindRegistersSave.S b/src/Unwind/UnwindRegistersSave.S
new file mode 100644
index 0000000..6f19f6c
--- /dev/null
+++ b/src/Unwind/UnwindRegistersSave.S
@@ -0,0 +1,301 @@
+//===------------------------ 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 __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 __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 __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 __arm64__
+
+;
+; extern int unw_getcontext(unw_context_t* thread_state)
+;
+; On entry:
+;  thread_state pointer is in x0
+;
+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 __arm__ && !__APPLE__
+
+@
+@ extern int unw_getcontext(unw_context_t* thread_state)
+@
+@ On entry:
+@  thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+  @ 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
+  mov r0, #0      @ return UNW_ESUCCESS
+  mov pc, lr
+
+#endif
diff --git a/src/Unwind/Unwind_AppleExtras.cpp b/src/Unwind/Unwind_AppleExtras.cpp
new file mode 100644
index 0000000..6d02a66
--- /dev/null
+++ b/src/Unwind/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 __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 __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 !FOR_DYLD && _LIBUNWIND_BUILD_SJLJ_APIS
+
+#include <System/pthread_machdep.h>
+
+// Accessors to get get/set linked list of frames for sjlj based execeptions.
+_LIBUNWIND_HIDDEN
+struct _Unwind_FunctionContext *__Unwind_SjLj_GetTopOfFunctionStack() {
+  return (struct _Unwind_FunctionContext *)
+    _pthread_getspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key);
+}
+
+_LIBUNWIND_HIDDEN
+void __Unwind_SjLj_SetTopOfFunctionStack(struct _Unwind_FunctionContext *fc) {
+  _pthread_setspecific_direct(__PTK_LIBC_DYLD_Unwind_SjLj_Key, fc);
+}
+#endif
+
+
+
+
diff --git a/src/Unwind/assembly.h b/src/Unwind/assembly.h
new file mode 100644
index 0000000..d282de8
--- /dev/null
+++ b/src/Unwind/assembly.h
@@ -0,0 +1,44 @@
+/* ===-- 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 @
+#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)
+
+#define DEFINE_LIBUNWIND_FUNCTION(name)                   \
+  .globl 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_NAME(name):
+
+#endif /* UNWIND_ASSEMBLY_H */
diff --git a/src/Unwind/config.h b/src/Unwind/config.h
new file mode 100644
index 0000000..2b92464
--- /dev/null
+++ b/src/Unwind/config.h
@@ -0,0 +1,108 @@
+//===----------------------------- 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>
+
+// Define static_assert() unless already defined by compiler.
+#ifndef __has_feature
+  #define __has_feature(__x) 0
+#endif
+#if !(__has_feature(cxx_static_assert))
+  #define static_assert(__b, __m) \
+      extern int compile_time_assert_failed[ ( __b ) ? 1 : -1 ]  \
+                                                  __attribute__( ( unused ) );
+#endif
+
+// Platform specific configuration defines.
+#if __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 (__i386__ || __x86_64__ || __arm64__)
+  #define _LIBUNWIND_BUILD_SJLJ_APIS      (__arm__)
+  #define _LIBUNWIND_SUPPORT_FRAME_APIS   (__i386__ || __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 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
+  // #define _LIBUNWIND_BUILD_ZERO_COST_APIS
+  // #define _LIBUNWIND_BUILD_SJLJ_APIS
+  // #define _LIBUNWIND_SUPPORT_FRAME_APIS
+  // #define _LIBUNWIND_EXPORT
+  // #define _LIBUNWIND_HIDDEN
+  // #define _LIBUNWIND_LOG()
+  // #define _LIBUNWIND_ABORT()
+  // #define _LIBUNWIND_SUPPORT_COMPACT_UNWIND
+  // #define _LIBUNWIND_SUPPORT_DWARF_UNWIND
+  // #define _LIBUNWIND_SUPPORT_DWARF_INDEX
+#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/src/Unwind/dwarf2.h b/src/Unwind/dwarf2.h
new file mode 100644
index 0000000..0dcd2ca
--- /dev/null
+++ b/src/Unwind/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/src/Unwind/libunwind.cpp b/src/Unwind/libunwind.cpp
new file mode 100644
index 0000000..2043ac2
--- /dev/null
+++ b/src/Unwind/libunwind.cpp
@@ -0,0 +1,353 @@
+//===--------------------------- 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>
+
+#include <new>
+
+#include "libunwind_ext.h"
+#include "config.h"
+
+
+#if _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+#include "UnwindCursor.hpp"
+
+using namespace libunwind;
+
+/// internal object to represent this processes address space
+LocalAddressSpace 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",
+                              cursor, context);
+  // Use "placement new" to allocate UnwindCursor in the cursor buffer.
+#if __i386__
+  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86>(
+                                 context, LocalAddressSpace::sThisAddressSpace);
+#elif __x86_64__
+  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>(
+                                 context, LocalAddressSpace::sThisAddressSpace);
+#elif __ppc__
+  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_ppc>(
+                                 context, LocalAddressSpace::sThisAddressSpace);
+#elif __arm64__
+  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>(
+                                 context, LocalAddressSpace::sThisAddressSpace);
+#endif
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  co->setInfoBasedOnIPRegister();
+
+  return UNW_ESUCCESS;
+}
+
+#if UNW_REMOTE
+
+_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
+    (unw_addr_space_t) & sThisAddressSpace;
+
+/// 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) & 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",
+                              cursor, regNum, 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",
+                             cursor, regNum, value);
+  typedef LocalAddressSpace::pint_t pint_t;
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  if (co->validReg(regNum)) {
+    co->setReg(regNum, (pint_t)value);
+    // specical case altering IP to re-find info (being called by personality
+    // function)
+    if (regNum == UNW_REG_IP) {
+      unw_proc_info_t info;
+      co->getInfo(&info);
+      pint_t orgArgSize = (pint_t)info.gp;
+      uint64_t orgFuncStart = info.start_ip;
+      co->setInfoBasedOnIPRegister(false);
+      // and adjust REG_SP if there was a DW_CFA_GNU_args_size
+      if ((orgFuncStart == info.start_ip) && (orgArgSize != 0))
+        co->setReg(UNW_REG_SP, co->getReg(UNW_REG_SP) + orgArgSize);
+    }
+    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",
+                             cursor, regNum, 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) {
+  _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n",
+                             cursor, regNum, value);
+  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", 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",
+                             cursor, 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", 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=%ld)\n", cursor, buf, 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",
+                             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",
+                             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", cursor);
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->isSignalFrame();
+}
+
+
+#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", 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
+
+#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS
+
+
+
+// Add logging hooks in Debug builds only
+#ifndef NDEBUG
+
+_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/src/Unwind/libunwind_ext.h b/src/Unwind/libunwind_ext.h
new file mode 100644
index 0000000..38d71cc
--- /dev/null
+++ b/src/Unwind/libunwind_ext.h
@@ -0,0 +1,38 @@
+//===------------------------ 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 <libunwind.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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LIBUNWIND_EXT__
diff --git a/src/Unwind/unwind_ext.h b/src/Unwind/unwind_ext.h
new file mode 100644
index 0000000..c40ce6a
--- /dev/null
+++ b/src/Unwind/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/src/cxa_demangle.cpp b/src/cxa_demangle.cpp
index 671d79c..39b6f3e 100644
--- a/src/cxa_demangle.cpp
+++ b/src/cxa_demangle.cpp
@@ -539,6 +539,8 @@
         {
             if (first[1] == '_')
             {
+                if (db.template_param.empty())
+                    return first;
                 if (!db.template_param.back().empty())
                 {
                     for (auto& t : db.template_param.back().front())
@@ -561,7 +563,7 @@
                     sub *= 10;
                     sub += static_cast<size_t>(*t - '0');
                 }
-                if (t == last || *t != '_')
+                if (t == last || *t != '_' || db.template_param.empty())
                     return first;
                 ++sub;
                 if (sub < db.template_param.back().size())
@@ -596,6 +598,8 @@
             const char* t1 = parse_expression(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto expr = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back() = "const_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -620,6 +624,8 @@
             const char* t1 = parse_expression(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto expr = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back() = "dynamic_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -644,6 +650,8 @@
             const char* t1 = parse_expression(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto expr = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back() = "reinterpret_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -668,6 +676,8 @@
             const char* t1 = parse_expression(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto expr = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back() = "static_cast<" + db.names.back().move_full() + ">(" + expr + ")";
@@ -704,6 +714,8 @@
         const char* t = parse_type(first+2, last, db);
         if (t != first+2)
         {
+            if (db.names.empty())
+                return first;
             db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
             first = t;
         }
@@ -722,6 +734,8 @@
         const char* t = parse_expression(first+2, last, db);
         if (t != first+2)
         {
+            if (db.names.empty())
+                return first;
             db.names.back() = "sizeof (" + db.names.back().move_full() + ")";
             first = t;
         }
@@ -813,6 +827,8 @@
         const char* t = parse_function_param(first+2, last, db);
         if (t != first+2)
         {
+            if (db.names.empty())
+                return first;
             db.names.back() = "sizeof...(" + db.names.back().move_full() + ")";
             first = t;
         }
@@ -836,6 +852,8 @@
             t = parse_type(first+2, last, db);
         if (t != first+2)
         {
+            if (db.names.empty())
+                return first;
             db.names.back() = "typeid(" + db.names.back().move_full() + ")";
             first = t;
         }
@@ -854,6 +872,8 @@
         const char* t = parse_expression(first+2, last, db);
         if (t != first+2)
         {
+            if (db.names.empty())
+                return first;
             db.names.back() = "throw " + db.names.back().move_full();
             first = t;
         }
@@ -875,6 +895,8 @@
             const char* t1 = parse_expression(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto expr = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back().first += ".*" + expr;
@@ -899,6 +921,8 @@
             const char* t1 = parse_template_args(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto args = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back().first += std::move(args);
@@ -945,6 +969,8 @@
             t = parse_decltype(first, last, db);
             if (t != first)
             {
+                if (db.names.empty())
+                    return first;
                 db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                 first = t;
             }
@@ -960,6 +986,8 @@
                     t = parse_unqualified_name(first+2, last, db);
                     if (t != first+2)
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back().first.insert(0, "std::");
                         db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                         first = t;
@@ -986,6 +1014,8 @@
             t = parse_simple_id(first, last, db);
         if (t != first)
         {
+            if (db.names.empty())
+                return first;
             db.names.back().first.insert(0, "~");
             first = t;
         }
@@ -1017,6 +1047,8 @@
                     first = parse_template_args(t, last, db);
                     if (first != t)
                     {
+                        if (db.names.size() < 2)
+                            return first;
                         auto args = db.names.back().move_full();
                         db.names.pop_back();
                         db.names.back().first += std::move(args);
@@ -1041,6 +1073,8 @@
                     first = parse_template_args(t, last, db);
                     if (first != t)
                     {
+                        if (db.names.size() < 2)
+                            return first;
                         auto args = db.names.back().move_full();
                         db.names.pop_back();
                         db.names.back().first += std::move(args);
@@ -1090,7 +1124,11 @@
         if (t2 != t)
         {
             if (global)
+            {
+                if (db.names.empty())
+                    return first;
                 db.names.back().first.insert(0, "::");
+            }
             first = t2;
         }
         else if (last - t > 2 && t[0] == 's' && t[1] == 'r')
@@ -1105,6 +1143,8 @@
                 t1 = parse_template_args(t, last, db);
                 if (t1 != t)
                 {
+                    if (db.names.size() < 2)
+                        return first;
                     auto args = db.names.back().move_full();
                     db.names.pop_back();
                     db.names.back().first += std::move(args);
@@ -1118,7 +1158,7 @@
                 while (*t != 'E')
                 {
                     t1 = parse_unresolved_qualifier_level(t, last, db);
-                    if (t1 == t || t1 == last)
+                    if (t1 == t || t1 == last || db.names.size() < 2)
                         return first;
                     auto s = db.names.back().move_full();
                     db.names.pop_back();
@@ -1129,9 +1169,12 @@
                 t1 = parse_base_unresolved_name(t, last, db);
                 if (t1 == t)
                 {
-                    db.names.pop_back();
+                    if (!db.names.empty())
+                        db.names.pop_back();
                     return first;
                 }
+                if (db.names.size() < 2)
+                    return first;
                 auto s = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back().first += "::" + std::move(s);
@@ -1147,6 +1190,8 @@
                     t1 = parse_template_args(t, last, db);
                     if (t1 != t)
                     {
+                        if (db.names.size() < 2)
+                            return first;
                         auto args = db.names.back().move_full();
                         db.names.pop_back();
                         db.names.back().first += std::move(args);
@@ -1155,9 +1200,12 @@
                     t1 = parse_base_unresolved_name(t, last, db);
                     if (t1 == t)
                     {
-                        db.names.pop_back();
+                        if (!db.names.empty())
+                            db.names.pop_back();
                         return first;
                     }
+                    if (db.names.size() < 2)
+                        return first;
                     auto s = db.names.back().move_full();
                     db.names.pop_back();
                     db.names.back().first += "::" + std::move(s);
@@ -1170,11 +1218,15 @@
                         return first;
                     t = t1;
                     if (global)
+                    {
+                        if (db.names.empty())
+                            return first;
                         db.names.back().first.insert(0, "::");
+                    }
                     while (*t != 'E')
                     {
                         t1 = parse_unresolved_qualifier_level(t, last, db);
-                        if (t1 == t || t1 == last)
+                        if (t1 == t || t1 == last || db.names.size() < 2)
                             return first;
                         auto s = db.names.back().move_full();
                         db.names.pop_back();
@@ -1185,9 +1237,12 @@
                     t1 = parse_base_unresolved_name(t, last, db);
                     if (t1 == t)
                     {
-                        db.names.pop_back();
+                        if (!db.names.empty())
+                            db.names.pop_back();
                         return first;
                     }
+                    if (db.names.size() < 2)
+                        return first;
                     auto s = db.names.back().move_full();
                     db.names.pop_back();
                     db.names.back().first += "::" + std::move(s);
@@ -1213,6 +1268,8 @@
             const char* t1 = parse_unresolved_name(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto name = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back().first += "." + name;
@@ -1236,6 +1293,8 @@
         {
             if (t == last)
                 return first;
+            if (db.names.empty())
+                return first;
             db.names.back().first += db.names.back().second;
             db.names.back().second = typename C::String();
             db.names.back().first.append("(");
@@ -1245,10 +1304,14 @@
                 const char* t1 = parse_expression(t, last, db);
                 if (t1 == t || t1 == last)
                     return first;
+                if (db.names.empty())
+                    return first;
                 auto tmp = db.names.back().move_full();
                 db.names.pop_back();
                 if (!tmp.empty())
                 {
+                    if (db.names.empty())
+                        return first;
                     if (!first_expr)
                     {
                         db.names.back().first.append(", ");
@@ -1259,6 +1322,8 @@
                 t = t1;
             }
             ++t;
+            if (db.names.empty())
+                return first;
             db.names.back().first.append(")");
             first = t;
         }
@@ -1301,10 +1366,14 @@
                 has_expr_list = true;
                 if (!first_expr)
                 {
+                    if (db.names.empty())
+                        return first;
                     auto tmp = db.names.back().move_full();
                     db.names.pop_back();
                     if (!tmp.empty())
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back().first.append(", ");
                         db.names.back().first.append(tmp);
                         first_expr = false;
@@ -1330,10 +1399,14 @@
                         return first;
                     if (!first_expr)
                     {
+                        if (db.names.empty())
+                            return first;
                         auto tmp = db.names.back().move_full();
                         db.names.pop_back();
                         if (!tmp.empty())
                         {
+                            if (db.names.empty())
+                                return first;
                             db.names.back().first.append(", ");
                             db.names.back().first.append(tmp);
                             first_expr = false;
@@ -1347,14 +1420,20 @@
             typename C::String init_list;
             if (has_init)
             {
+                if (db.names.empty())
+                    return first;
                 init_list = db.names.back().move_full();
                 db.names.pop_back();
             }
+            if (db.names.empty())
+                return first;
             auto type = db.names.back().move_full();
             db.names.pop_back();
             typename C::String expr_list;
             if (has_expr_list)
             {
+                if (db.names.empty())
+                    return first;
                 expr_list = db.names.back().move_full();
                 db.names.pop_back();
             }
@@ -1416,10 +1495,14 @@
                             return first;
                         if (!first_expr)
                         {
+                            if (db.names.empty())
+                                return first;
                             auto tmp = db.names.back().move_full();
                             db.names.pop_back();
                             if (!tmp.empty())
                             {
+                                if (db.names.empty())
+                                    return first;
                                 db.names.back().first.append(", ");
                                 db.names.back().first.append(tmp);
                                 first_expr = false;
@@ -1430,6 +1513,8 @@
                 }
                 ++t;
             }
+            if (db.names.size() < 2)
+                return first;
             auto tmp = db.names.back().move_full();
             db.names.pop_back();
             db.names.back() = "(" + db.names.back().move_full() + ")(" + tmp + ")";
@@ -1453,6 +1538,8 @@
             const char* t1 = parse_expression(t, last, db);
             if (t1 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto tmp = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back().first += "->";
@@ -1545,6 +1632,8 @@
                     sig += " &&";
                     break;
                 }
+                if (db.names.empty())
+                    return first;
                 db.names.back().first += " ";
                 db.names.back().second.insert(0, sig);
                 first = t;
@@ -1568,6 +1657,8 @@
             const char* t2 = parse_type(t, last, db);
             if (t2 != t)
             {
+                if (db.names.size() < 2)
+                    return first;
                 auto func = std::move(db.names.back());
                 db.names.pop_back();
                 auto class_type = std::move(db.names.back());
@@ -1602,6 +1693,8 @@
             const char* t = parse_type(first+2, last, db);
             if (t != first+2)
             {
+                if (db.names.empty())
+                    return first;
                 if (db.names.back().second.substr(0, 2) == " [")
                     db.names.back().second.erase(0, 1);
                 db.names.back().second.insert(0, " []");
@@ -1616,6 +1709,8 @@
                 const char* t2 = parse_type(t+1, last, db);
                 if (t2 != t+1)
                 {
+                    if (db.names.empty())
+                        return first;
                     if (db.names.back().second.substr(0, 2) == " [")
                         db.names.back().second.erase(0, 1);
                     db.names.back().second.insert(0, " [" + typename C::String(first+1, t) + "]");
@@ -1631,6 +1726,8 @@
                 const char* t2 = parse_type(++t, last, db);
                 if (t2 != t)
                 {
+                    if (db.names.size() < 2)
+                        return first;
                     auto type = std::move(db.names.back());
                     db.names.pop_back();
                     auto expr = std::move(db.names.back());
@@ -1663,6 +1760,8 @@
                 const char* t = parse_expression(first+2, last, db);
                 if (t != first+2 && t != last && *t == 'E')
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back() = "decltype(" + db.names.back().move_full() + ")";
                     first = t+1;
                 }
@@ -1700,6 +1799,8 @@
                     const char* t1 = parse_type(t, last, db);
                     if (t1 != t)
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back().first += " vector[" + typename C::String(num, sz) + "]";
                         first = t1;
                     }
@@ -1721,6 +1822,8 @@
                 const char* t = parse_expression(t1, last, db);
                 if (t != t1)
                 {
+                    if (db.names.empty())
+                        return first;
                     num = db.names.back().move_full();
                     db.names.pop_back();
                     t1 = t;
@@ -1731,6 +1834,8 @@
                 const char* t = parse_type(t1, last, db);
                 if (t != t1)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first += " vector[" + num + "]";
                     first = t;
                 }
@@ -1841,6 +1946,8 @@
                         t = parse_array_type(first, last, db);
                         if (t != first)
                         {
+                            if (db.names.empty())
+                                return first;
                             first = t;
                             db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                         }
@@ -1849,6 +1956,8 @@
                         t = parse_type(first+1, last, db);
                         if (t != first+1)
                         {
+                            if (db.names.empty())
+                                return first;
                             db.names.back().first.append(" complex");
                             first = t;
                             db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
@@ -1858,6 +1967,8 @@
                         t = parse_function_type(first, last, db);
                         if (t != first)
                         {
+                            if (db.names.empty())
+                                return first;
                             first = t;
                             db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                         }
@@ -1866,6 +1977,8 @@
                         t = parse_type(first+1, last, db);
                         if (t != first+1)
                         {
+                            if (db.names.empty())
+                                return first;
                             db.names.back().first.append(" imaginary");
                             first = t;
                             db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
@@ -1875,6 +1988,8 @@
                         t = parse_pointer_to_member_type(first, last, db);
                         if (t != first)
                         {
+                            if (db.names.empty())
+                                return first;
                             first = t;
                             db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                         }
@@ -2002,6 +2117,8 @@
                                 const char* t2 = parse_type(t, last, db);
                                 if (t2 != t)
                                 {
+                                    if (db.names.size() < 2)
+                                        return first;
                                     auto type = db.names.back().move_full();
                                     db.names.pop_back();
                                     if (db.names.back().first.substr(0, 9) != "objcproto")
@@ -2034,6 +2151,8 @@
                             t = parse_name(first, last, db);
                             if (t != first)
                             {
+                                if (db.names.empty())
+                                    return first;
                                 db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                                 first = t;
                             }
@@ -2049,6 +2168,8 @@
                                 t = parse_template_args(first, last, db);
                                 if (t != first)
                                 {
+                                    if (db.names.size() < 2)
+                                        return first;
                                     auto template_args = db.names.back().move_full();
                                     db.names.pop_back();
                                     db.names.back().first += template_args;
@@ -2084,6 +2205,8 @@
                                 t = parse_decltype(first, last, db);
                                 if (t != first)
                                 {
+                                    if (db.names.empty())
+                                        return first;
                                     db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                                     first = t;
                                     return first;
@@ -2093,6 +2216,8 @@
                                 t = parse_vector_type(first, last, db);
                                 if (t != first)
                                 {
+                                    if (db.names.empty())
+                                        return first;
                                     db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                                     first = t;
                                     return first;
@@ -2114,6 +2239,8 @@
                             t = parse_name(first, last, db);
                             if (t != first)
                             {
+                                if (db.names.empty())
+                                    return first;
                                 db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                                 first = t;
                             }
@@ -2150,6 +2277,7 @@
 //                   ::= gt    # >             
 //                   ::= ix    # []            
 //                   ::= le    # <=            
+//                   ::= li <source-name>  # operator ""
 //                   ::= ls    # <<            
 //                   ::= lS    # <<=           
 //                   ::= lt    # <             
@@ -2232,6 +2360,8 @@
                     db.try_to_parse_template_args = try_to_parse_template_args;
                     if (t != first+2)
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back().first.insert(0, "operator ");
                         db.parsed_ctor_dtor_cv = true;
                         first = t;
@@ -2309,6 +2439,18 @@
                 db.names.push_back("operator<=");
                 first += 2;
                 break;
+            case 'i':
+                {
+                    const char* t = parse_source_name(first+2, last, db);
+                    if (t != first+2)
+                    {
+                        if (db.names.empty())
+                            return first;
+                        db.names.back().first.insert(0, "operator\"\" ");
+                        first = t;
+                    }
+                }
+                break;
             case 's':
                 db.names.push_back("operator<<");
                 first += 2;
@@ -2453,6 +2595,8 @@
                 const char* t = parse_source_name(first+2, last, db);
                 if (t != first+2)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "operator ");
                     first = t;
                 }
@@ -2662,6 +2806,8 @@
                             ;
                         if (n != t && n != last && *n == 'E')
                         {
+                            if (db.names.empty())
+                                return first;
                             db.names.back() = "(" + db.names.back().move_full() + ")" + typename C::String(t, n);
                             first = n+1;
                             break;
@@ -2762,6 +2908,8 @@
             case '2':
             case '3':
             case '5':
+                if (db.names.empty())
+                    return first;
                 db.names.push_back(base_name(db.names.back().first));
                 first += 2;
                 db.parsed_ctor_dtor_cv = true;
@@ -2775,6 +2923,8 @@
             case '1':
             case '2':
             case '5':
+                if (db.names.empty())
+                    return first;
                 db.names.push_back("~" + base_name(db.names.back().first));
                 first += 2;
                 db.parsed_ctor_dtor_cv = true;
@@ -2845,6 +2995,8 @@
                     db.names.pop_back();
                     return first;
                 }
+                if (db.names.size() < 2)
+                    return first;
                 auto tmp = db.names.back().move_full();
                 db.names.pop_back();
                 db.names.back().first.append(tmp);
@@ -2854,6 +3006,8 @@
                     t1 = parse_type(t0, last, db);
                     if (t1 == t0)
                         break;
+                    if (db.names.size() < 2)
+                        return first;
                     tmp = db.names.back().move_full();
                     db.names.pop_back();
                     if (!tmp.empty())
@@ -2968,7 +3122,11 @@
         if (t1 != t0)
         {
             if (St)
+            {
+                if (db.names.empty())
+                    return first;
                 db.names.back().first.insert(0, "std::");
+            }
             first = t1;
         }
     }
@@ -2986,6 +3144,8 @@
         const char* t = parse_type(first+2, last, db);
         if (t != first+2)
         {
+            if (db.names.empty())
+                return first;
             db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
             first = t;
         }
@@ -3004,6 +3164,8 @@
         const char* t = parse_expression(first+2, last, db);
         if (t != first+2)
         {
+            if (db.names.empty())
+                return first;
             db.names.back().first = "alignof (" + db.names.back().move_full() + ")";
             first = t;
         }
@@ -3018,6 +3180,8 @@
     const char* t1 = parse_expression(first, last, db);
     if (t1 != first)
     {
+        if (db.names.empty())
+            return first;
         db.names.back().first =  "noexcept (" + db.names.back().move_full() + ")";
         first = t1;
     }
@@ -3031,6 +3195,8 @@
     const char* t1 = parse_expression(first, last, db);
     if (t1 != first)
     {
+        if (db.names.empty())
+            return first;
         db.names.back().first =  op + "(" + db.names.back().move_full() + ")";
         first = t1;
     }
@@ -3047,6 +3213,8 @@
         const char* t2 = parse_expression(t1, last, db);
         if (t2 != t1)
         {
+            if (db.names.size() < 2)
+                return first;
             auto op2 = db.names.back().move_full();
             db.names.pop_back();
             auto op1 = db.names.back().move_full();
@@ -3197,6 +3365,8 @@
                     const char* t1 = parse_expression(t+2, last, db);
                     if (t1 != t+2)
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
                                           "delete[] " + db.names.back().move_full();
                         first = t1;
@@ -3216,6 +3386,8 @@
                     const char* t1 = parse_expression(t+2, last, db);
                     if (t1 != t+2)
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back().first = (parsed_gs ? typename C::String("::") : typename C::String()) +
                                           "delete " + db.names.back().move_full();
                         first = t1;
@@ -3286,6 +3458,8 @@
                     const char* t2 = parse_expression(t1, last, db);
                     if (t2 != t1)
                     {
+                        if (db.names.size() < 2)
+                            return first;
                         auto op2 = db.names.back().move_full();
                         db.names.pop_back();
                         auto op1 = db.names.back().move_full();
@@ -3357,6 +3531,8 @@
                     const char* t1 = parse_expression(first+2, last, db);
                     if (t1 != first+2)
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back() = "(" + db.names.back().move_full() + ")--";
                         first = t1;
                     }
@@ -3445,6 +3621,8 @@
                     const char* t1 = parse_expression(first+2, last, db);
                     if (t1 != first+2)
                     {
+                        if (db.names.empty())
+                            return first;
                         db.names.back() = "(" + db.names.back().move_full() + ")++";
                         first = t1;
                     }
@@ -3472,6 +3650,8 @@
                         const char* t3 = parse_expression(t2, last, db);
                         if (t3 != t2)
                         {
+                            if (db.names.size() < 3)
+                                return first;
                             auto op3 = db.names.back().move_full();
                             db.names.pop_back();
                             auto op2 = db.names.back().move_full();
@@ -3899,6 +4079,8 @@
             {
             case 's':
                 first = parse_discriminator(t+1, last);
+                if (db.names.empty())
+                    return first;
                 db.names.back().first.append("::string literal");
                 break;
             case 'd':
@@ -3911,6 +4093,8 @@
                         t1 = parse_name(t, last, db);
                         if (t1 != t)
                         {
+                            if (db.names.size() < 2)
+                                return first;
                             auto name = db.names.back().move_full();
                             db.names.pop_back();
                             db.names.back().first.append("::");
@@ -3929,6 +4113,8 @@
                     {
                         // parse but ignore discriminator
                         first = parse_discriminator(t1, last);
+                        if (db.names.size() < 2)
+                            return first;
                         auto name = db.names.back().move_full();
                         db.names.pop_back();
                         db.names.back().first.append("::");
@@ -3985,11 +4171,15 @@
             {
                 if (t1 != last && *t1 == 'I')  // <unscoped-template-name> <template-args>
                 {
+                    if (db.names.empty())
+                        return first;
                     db.subs.push_back(typename C::sub_type(1, db.names.back(), db.names.get_allocator()));
                     t0 = t1;
                     t1 = parse_template_args(t0, last, db);
                     if (t1 != t0)
                     {
+                        if (db.names.size() < 2)
+                            return first;
                         auto tmp = db.names.back().move_full();
                         db.names.pop_back();
                         db.names.back().first += tmp;
@@ -4008,6 +4198,8 @@
                     t1 = parse_template_args(t0, last, db);
                     if (t1 != t0)
                     {
+                        if (db.names.size() < 2)
+                            return first;
                         auto tmp = db.names.back().move_full();
                         db.names.pop_back();
                         db.names.back().first += tmp;
@@ -4093,6 +4285,8 @@
                 t = parse_type(first+2, last, db);
                 if (t != first+2)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "vtable for ");
                     first = t;
                 }
@@ -4102,6 +4296,8 @@
                 t = parse_type(first+2, last, db);
                 if (t != first+2)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "VTT for ");
                     first = t;
                 }
@@ -4111,6 +4307,8 @@
                 t = parse_type(first+2, last, db);
                 if (t != first+2)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "typeinfo for ");
                     first = t;
                 }
@@ -4120,6 +4318,8 @@
                 t = parse_type(first+2, last, db);
                 if (t != first+2)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "typeinfo name for ");
                     first = t;
                 }
@@ -4136,6 +4336,8 @@
                 t = parse_encoding(t1, last, db);
                 if (t != t1)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "covariant return thunk to ");
                     first = t;
                 }
@@ -4152,6 +4354,8 @@
                         const char* t1 = parse_type(++t0, last, db);
                         if (t1 != t0)
                         {
+                            if (db.names.size() < 2)
+                                return first;
                             auto left = db.names.back().move_full();
                             db.names.pop_back();
                             db.names.back().first = "construction vtable for " +
@@ -4171,6 +4375,8 @@
                 t = parse_encoding(t0, last, db);
                 if (t != t0)
                 {
+                    if (db.names.empty())
+                        return first;
                     if (first[2] == 'v')
                     {
                         db.names.back().first.insert(0, "virtual thunk to ");
@@ -4194,6 +4400,8 @@
                 t = parse_name(first+2, last, db);
                 if (t != first+2)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "guard variable for ");
                     first = t;
                 }
@@ -4203,6 +4411,8 @@
                 t = parse_name(first+2, last, db);
                 if (t != first+2)
                 {
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first.insert(0, "reference temporary for ");
                     first = t;
                 }
@@ -4214,6 +4424,26 @@
     return first;
 }
 
+template <class T>
+class save_value
+{
+    T& restore_;
+    T original_value_;
+public:
+    save_value(T& restore)
+        : restore_(restore),
+          original_value_(restore)
+        {}
+
+    ~save_value()
+    {
+        restore_ = std::move(original_value_);
+    }
+
+    save_value(const save_value&) = delete;
+    save_value& operator=(const save_value&) = delete;
+};
+
 // <encoding> ::= <function name> <bare-function-type>
 //            ::= <data name>
 //            ::= <special-name>
@@ -4224,6 +4454,11 @@
 {
     if (first != last)
     {
+        save_value<decltype(db.encoding_depth)> su(db.encoding_depth);
+        ++db.encoding_depth;
+        save_value<decltype(db.tag_templates)> sb(db.tag_templates);
+        if (db.encoding_depth > 1)
+            db.tag_templates = true;
         switch (*first)
         {
         case 'G':
@@ -4239,17 +4474,23 @@
             {
                 if (t != last && *t != 'E' && *t != '.')
                 {
-                    bool tag_templates = db.tag_templates;
+                    save_value<bool> sb2(db.tag_templates);
                     db.tag_templates = false;
                     const char* t2;
                     typename C::String ret2;
+                    if (db.names.empty())
+                        return first;
                     const typename C::String& nm = db.names.back().first;
+                    if (nm.empty())
+                        return first;
                     if (!db.parsed_ctor_dtor_cv && nm.back() == '>' && nm[nm.size()-2] != '-'
                                                                     && nm[nm.size()-2] != '>')
                     {
                         t2 = parse_type(t, last, db);
                         if (t2 == t)
                             return first;
+                        if (db.names.size() < 2)
+                            return first;
                         auto ret1 = std::move(db.names.back().first);
                         ret2 = std::move(db.names.back().second);
                         if (ret2.empty())
@@ -4286,6 +4527,8 @@
                                     db.names.pop_back();
                                 if (!tmp.empty())
                                 {
+                                    if (db.names.empty())
+                                        return first;
                                     if (!first_arg)
                                         db.names.back().first += ", ";
                                     else
@@ -4296,6 +4539,8 @@
                             t = t2;
                         }
                     }
+                    if (db.names.empty())
+                        return first;
                     db.names.back().first += ')';
                     if (cv & 1)
                         db.names.back().first.append(" const");
@@ -4309,7 +4554,6 @@
                         db.names.back().first.append(" &&");
                     db.names.back().first += ret2;
                     first = t;
-                    db.tag_templates = tag_templates;
                 }
                 else
                     first = t;
@@ -4351,6 +4595,8 @@
             while (t != last && isdigit(*t))
                 ++t;
         }
+        if (db.names.empty())
+            return first;
         db.names.back().first.insert(0, "invocation function for block in ");
         first = t;
     }
@@ -4366,6 +4612,8 @@
 {
     if (first != last && *first == '.')
     {
+        if (db.names.empty())
+            return first;
         db.names.back().first += " (" + typename C::String(first, last) + ")";
         first = last;
     }
@@ -4591,6 +4839,30 @@
     String move_full() {return std::move(first) + std::move(second);}
 };
 
+struct Db
+{
+    typedef String String;
+    typedef Vector<string_pair> sub_type;
+    typedef Vector<sub_type> template_param_type;
+    Vector<string_pair> names;
+    Vector<sub_type> subs;
+    Vector<template_param_type> template_param;
+    unsigned cv;
+    unsigned ref;
+    unsigned encoding_depth;
+    bool parsed_ctor_dtor_cv;
+    bool tag_templates;
+    bool fix_forward_references;
+    bool try_to_parse_template_args;
+
+    template <size_t N>
+    Db(arena<N>& ar) :
+        names(ar),
+        subs(0, names, ar),
+        template_param(0, subs, ar)
+    {}
+};
+
 }  // unnamed namespace
 
 __attribute__ ((__visibility__("default")))
@@ -4616,31 +4888,10 @@
     // @LOCALMOD-END
     size_t internal_size = buf != nullptr ? *n : 0;
     arena<bs> a;
-    struct Db
-    {
-        typedef String String;
-        typedef Vector<string_pair> sub_type;
-        typedef Vector<sub_type> template_param_type;
-        Vector<string_pair> names;
-        Vector<sub_type> subs;
-        Vector<template_param_type> template_param;
-        unsigned cv;
-        unsigned ref;
-        bool parsed_ctor_dtor_cv;
-        bool tag_templates;
-        bool fix_forward_references;
-        bool try_to_parse_template_args;
-
-        template <size_t N>
-        Db(arena<N>& ar) :
-            names(ar),
-            subs(0, names, ar),
-            template_param(0, subs, ar)
-        {}
-    };
     Db db(a);
     db.cv = 0;
     db.ref = 0;
+    db.encoding_depth = 0;
     db.parsed_ctor_dtor_cv = false;
     db.tag_templates = true;
     db.template_param.emplace_back(a);
diff --git a/src/cxa_exception.hpp b/src/cxa_exception.hpp
index 66f05c4..22c4da3 100644
--- a/src/cxa_exception.hpp
+++ b/src/cxa_exception.hpp
@@ -41,19 +41,19 @@
         std::unexpected_handler unexpectedHandler;
         std::terminate_handler  terminateHandler;
         
-         __cxa_exception *nextException;
+        __cxa_exception *nextException;
         
-         int handlerCount;
+        int handlerCount;
     
 #ifdef __ARM_EABI_UNWINDER__
-         __cxa_exception* nextPropagatingException;
-         int propagationCount;
+        __cxa_exception* nextPropagatingException;
+        int propagationCount;
 #else
-         int handlerSwitchValue;
-         const unsigned char *actionRecord;
-         const unsigned char *languageSpecificData;
-         void *catchTemp;
-         void *adjustedPtr;
+        int handlerSwitchValue;
+        const unsigned char *actionRecord;
+        const unsigned char *languageSpecificData;
+        void *catchTemp;
+        void *adjustedPtr;
 #endif
 
 #if !__LP64__
diff --git a/src/cxa_new_delete.cpp b/src/cxa_new_delete.cpp
index 6352001..25a5454 100644
--- a/src/cxa_new_delete.cpp
+++ b/src/cxa_new_delete.cpp
@@ -9,6 +9,8 @@
 // This file implements the new and delete operators.
 //===----------------------------------------------------------------------===//
 
+#define _LIBCPP_BUILDING_NEW
+
 #include <new>
 #include <cstdlib>
 
@@ -228,4 +230,33 @@
     return "bad_array_new_length";
 }
 
+// bad_array_length
+
+#ifndef _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
+
+class _LIBCPP_EXCEPTION_ABI bad_array_length
+    : public bad_alloc
+{
+public:
+    bad_array_length() _NOEXCEPT;
+    virtual ~bad_array_length() _NOEXCEPT;
+    virtual const char* what() const _NOEXCEPT;
+};
+
+#endif  // _LIBCPP_BAD_ARRAY_LENGTH_DEFINED
+
+bad_array_length::bad_array_length() _NOEXCEPT
+{
+}
+
+bad_array_length::~bad_array_length() _NOEXCEPT
+{
+}
+
+const char*
+bad_array_length::what() const _NOEXCEPT
+{
+    return "bad_array_length";
+}
+
 }  // std
diff --git a/src/private_typeinfo.cpp b/src/private_typeinfo.cpp
index 640ff8c..52326a3 100644
--- a/src/private_typeinfo.cpp
+++ b/src/private_typeinfo.cpp
@@ -27,7 +27,7 @@
 // The current implementation of _LIBCXX_DYNAMIC_FALLBACK requires a
 // printf-like function called syslog:
 // 
-//     void syslog(const char* format, ...);
+//     void syslog(int facility_priority, const char* format, ...);
 // 
 // If you want this functionality but your platform doesn't have syslog,
 // just implement it in terms of fprintf(stderr, ...).
@@ -40,6 +40,18 @@
 #include <sys/syslog.h>
 #endif
 
+// On Windows, typeids are different between DLLs and EXEs, so comparing
+// type_info* will work for typeids from the same compiled file but fail
+// for typeids from a DLL and an executable. Among other things, exceptions
+// are not caught by handlers since can_catch() returns false.
+//
+// Defining _LIBCXX_DYNAMIC_FALLBACK does not help since can_catch() calls 
+// is_equal() with use_strcmp=false so the string names are not compared.
+
+#ifdef _WIN32
+#include <string.h>
+#endif
+
 namespace __cxxabiv1
 {
 
@@ -62,7 +74,11 @@
 bool
 is_equal(const std::type_info* x, const std::type_info* y, bool)
 {
+#ifndef _WIN32
     return x == y;
+#else
+    return (x == y) || (strcmp(x->name(), y->name()) == 0);
+#endif    
 }
 
 #endif  // _LIBCXX_DYNAMIC_FALLBACK
diff --git a/src/stdexcept.cpp b/src/stdexcept.cpp
index 076f474..246eea4 100644
--- a/src/stdexcept.cpp
+++ b/src/stdexcept.cpp
@@ -47,7 +47,7 @@
 #if __APPLE__
     static
     const void*
-    compute_gcc_empty_string_storage() _LIBCPP_CANTTHROW
+    compute_gcc_empty_string_storage() _NOEXCEPT
     {
         void* handle = dlopen("/usr/lib/libstdc++.6.dylib", RTLD_NOLOAD);
         if (handle == 0)
@@ -57,7 +57,7 @@
     
     static
     const void*
-    get_gcc_empty_string_storage() _LIBCPP_CANTTHROW
+    get_gcc_empty_string_storage() _NOEXCEPT
     {
         static const void* p = compute_gcc_empty_string_storage();
         return p;
diff --git a/test/catch_const_pointer_nullptr.cpp b/test/catch_const_pointer_nullptr.cpp
index c9d5acf..417a2aa 100644
--- a/test/catch_const_pointer_nullptr.cpp
+++ b/test/catch_const_pointer_nullptr.cpp
@@ -1,4 +1,4 @@
-//===--------------------- catch_const_pointer_nullptr.cpp ----------------------===//
+//===--------------------- catch_const_pointer_nullptr.cpp ----------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -53,7 +53,7 @@
         throw nullptr;
         assert(false);
     }
-    catch (const A const*)
+    catch (const A* const)
     {
     }
     catch (A*)
@@ -72,7 +72,7 @@
     catch (A*)
     {
     }
-    catch (const A const*)
+    catch (const A* const)
     {
         assert(false);
     }
diff --git a/test/test_demangle.cpp b/test/test_demangle.cpp
index 0b582d3..2d9dd55 100644
--- a/test/test_demangle.cpp
+++ b/test/test_demangle.cpp
@@ -29583,6 +29583,8 @@
     {"_Z1fPU11objcproto1A11objc_object", "f(id<A>)"},
     {"_Z1fPKU11objcproto1A7NSArray", "f(NSArray<A> const*)"},
     {"_ZNK1AIJ1Z1Y1XEEcv1BIJDpPT_EEIJS2_S1_S0_EEEv", "A<Z, Y, X>::operator B<X*, Y*, Z*><X, Y, Z>() const"},
+    {"_ZNK3Ncr6Silver7Utility6detail12CallOnThreadIZ53-[DeploymentSetupController handleManualServerEntry:]E3$_5EclIJEEEDTclclL_ZNS2_4getTIS4_EERT_vEEspclsr3stdE7forwardIT_Efp_EEEDpOSA_", "decltype(-[DeploymentSetupController handleManualServerEntry:]::$_5& Ncr::Silver::Utility::detail::getT<-[DeploymentSetupController handleManualServerEntry:]::$_5>()()(std::forward<-[DeploymentSetupController handleManualServerEntry:]::$_5>(fp))) Ncr::Silver::Utility::detail::CallOnThread<-[DeploymentSetupController handleManualServerEntry:]::$_5>::operator()<>(-[DeploymentSetupController handleManualServerEntry:]::$_5&&) const"},
+    {"_Zli2_xy", "operator\"\" _x(unsigned long long)"},
 };
 
 const unsigned N = sizeof(cases) / sizeof(cases[0]);
@@ -29663,7 +29665,9 @@
     std::string input;
     while (std::cin)
     {
-        std::cin >> input;
+        std::getline(std::cin, input);
+        if (std::cin.fail())
+            break;
         std::size_t len = 0;
         int status;
         len = 0;