[libcxxabi] r192136 - libcxxabi contains the runtime support for C++. But, as some folks have

Nick Kledzik kledzik at apple.com
Mon Oct 7 14:39:41 PDT 2013


Author: kledzik
Date: Mon Oct  7 16:39:41 2013
New Revision: 192136

URL: http://llvm.org/viewvc/llvm-project?rev=192136&view=rev
Log:

libcxxabi contains the runtime support for C++.  But, as some folks have 
realized, it is not complete.  It relies on some _Unwind_* functions to be
supplied by the OS. That means it cannot be ported to platforms that don’t 
already have an unwinder.  

Years ago Apple wrote its own unwinder for MacOSX and iOS.  To make libcxxabi 
complete, Apple has decided the source code for its unwinder can be contributed
to the open source LLVM libcxxabi project, with a dual licensed under LLVM 
and MIT license.

So, I’ve spent some time cleaning up the sources to make them conform with 
LLVM style and to conditionalize the sources in a way that should make it 
easier to port to other platforms.  The sources are in a separate "Unwind" 
directory under "src" in libcxxabi.  

Background:
Most architectures now use "zero cost" exceptions for C++.  The zero cost means
there are no extra instructions executed if no exceptions are thrown.  But if 
an exception is thrown, the runtime must consult side tables and figure out how
to restore registers and "unwind" from the current stack frame to the catch 
clause.  That ability to modify the stack frames and cause the thread to resume 
in a catch clause with all registers restored properly is the main purpose 
of the unwinder.

This unwinder has two levels of API.  The high level APIs are the _Unwind_* 
functions which the cxa_* exception functions in libcxxabi require.  The low 
level APIs are the unw_* functions which are an interface defined by the the 
old HP libunwind project (which shares no code with this unwinder).

Added:
    libcxxabi/trunk/include/libunwind.h
    libcxxabi/trunk/include/mach-o/
    libcxxabi/trunk/include/mach-o/compact_unwind_encoding.h
    libcxxabi/trunk/include/unwind.h
    libcxxabi/trunk/src/Unwind/
    libcxxabi/trunk/src/Unwind/AddressSpace.hpp
    libcxxabi/trunk/src/Unwind/CompactUnwinder.hpp
    libcxxabi/trunk/src/Unwind/DwarfInstructions.hpp
    libcxxabi/trunk/src/Unwind/DwarfParser.hpp
    libcxxabi/trunk/src/Unwind/Registers.hpp
    libcxxabi/trunk/src/Unwind/Unwind-sjlj.c
    libcxxabi/trunk/src/Unwind/UnwindCursor.hpp
    libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c
    libcxxabi/trunk/src/Unwind/UnwindLevel1.c
    libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.s
    libcxxabi/trunk/src/Unwind/UnwindRegistersSave.s
    libcxxabi/trunk/src/Unwind/Unwind_AppleExtras.cpp
    libcxxabi/trunk/src/Unwind/config.h
    libcxxabi/trunk/src/Unwind/dwarf2.h
    libcxxabi/trunk/src/Unwind/libunwind.cpp
    libcxxabi/trunk/src/Unwind/libunwind_ext.h
    libcxxabi/trunk/src/Unwind/unwind_ext.h

Added: libcxxabi/trunk/include/libunwind.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/include/libunwind.h?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/include/libunwind.h (added)
+++ libcxxabi/trunk/include/libunwind.h Mon Oct  7 16:39:41 2013
@@ -0,0 +1,356 @@
+//===---------------------------- 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,
+};
+
+#endif

Added: libcxxabi/trunk/include/mach-o/compact_unwind_encoding.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/include/mach-o/compact_unwind_encoding.h?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/include/mach-o/compact_unwind_encoding.h (added)
+++ libcxxabi/trunk/include/mach-o/compact_unwind_encoding.h Mon Oct  7 16:39:41 2013
@@ -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
+

Added: libcxxabi/trunk/include/unwind.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/include/unwind.h?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/include/unwind.h (added)
+++ libcxxabi/trunk/include/unwind.h Mon Oct  7 16:39:41 2013
@@ -0,0 +1,211 @@
+//===------------------------------- 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>
+
+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)
+    __attribute__((unavailable));
+extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
+    __attribute__((unavailable));
+
+// 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) __attribute__((unavailable));
+extern void __register_frame_info(const void *fde, void *ob)
+    __attribute__((unavailable));
+extern void __register_frame_info_table_bases(const void *fde, void *ob,
+                                              void *tb, void *db)
+    __attribute__((unavailable));
+extern void __register_frame_info_table(const void *fde, void *ob)
+    __attribute__((unavailable));
+extern void __register_frame_table(const void *fde)
+    __attribute__((unavailable));
+extern void *__deregister_frame_info(const void *fde)
+    __attribute__((unavailable));
+extern void *__deregister_frame_info_bases(const void *fde)
+    __attribute__((unavailable));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __UNWIND_H__

Added: libcxxabi/trunk/src/Unwind/AddressSpace.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/AddressSpace.hpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/AddressSpace.hpp (added)
+++ libcxxabi/trunk/src/Unwind/AddressSpace.hpp Mon Oct  7 16:39:41 2013
@@ -0,0 +1,389 @@
+//===------------------------- 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/dyld_priv.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;
+}
+
+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__

Added: libcxxabi/trunk/src/Unwind/CompactUnwinder.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/CompactUnwinder.hpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/CompactUnwinder.hpp (added)
+++ libcxxabi/trunk/src/Unwind/CompactUnwinder.hpp Mon Oct  7 16:39:41 2013
@@ -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__

Added: libcxxabi/trunk/src/Unwind/DwarfInstructions.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/DwarfInstructions.hpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/DwarfInstructions.hpp (added)
+++ libcxxabi/trunk/src/Unwind/DwarfInstructions.hpp Mon Oct  7 16:39:41 2013
@@ -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__

Added: libcxxabi/trunk/src/Unwind/DwarfParser.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/DwarfParser.hpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/DwarfParser.hpp (added)
+++ libcxxabi/trunk/src/Unwind/DwarfParser.hpp Mon Oct  7 16:39:41 2013
@@ -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__

Added: libcxxabi/trunk/src/Unwind/Registers.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/Registers.hpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/Registers.hpp (added)
+++ libcxxabi/trunk/src/Unwind/Registers.hpp Mon Oct  7 16:39:41 2013
@@ -0,0 +1,1277 @@
+//===----------------------------- 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 "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(&_registers, 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");
+}
+
+} // namespace libunwind
+
+#endif // __REGISTERS_HPP__

Added: libcxxabi/trunk/src/Unwind/Unwind-sjlj.c
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/Unwind-sjlj.c?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/Unwind-sjlj.c (added)
+++ libcxxabi/trunk/src/Unwind/Unwind-sjlj.c Mon Oct  7 16:39:41 2013
@@ -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

Added: libcxxabi/trunk/src/Unwind/UnwindCursor.hpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindCursor.hpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindCursor.hpp (added)
+++ libcxxabi/trunk/src/Unwind/UnwindCursor.hpp Mon Oct  7 16:39:41 2013
@@ -0,0 +1,1058 @@
+//===------------------------- 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>
+
+#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, thread_t thread);
+  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, thread_t )
+    : _addressSpace(as), _unwindInfoMissing(false), _isSignalFrame(false) {
+  bzero(&_info, sizeof(_info));
+  // FIXME
+  // fill in _registers from thread
+}
+
+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__

Added: libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c (added)
+++ libcxxabi/trunk/src/Unwind/UnwindLevel1-gcc-ext.c Mon Oct  7 16:39:41 2013
@@ -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

Added: libcxxabi/trunk/src/Unwind/UnwindLevel1.c
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindLevel1.c?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindLevel1.c (added)
+++ libcxxabi/trunk/src/Unwind/UnwindLevel1.c Mon Oct  7 16:39:41 2013
@@ -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

Added: libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.s
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.s?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.s (added)
+++ libcxxabi/trunk/src/Unwind/UnwindRegistersRestore.s Mon Oct  7 16:39:41 2013
@@ -0,0 +1,286 @@
+//===-------------------- 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.
+//
+//===----------------------------------------------------------------------===//
+
+
+    .text
+
+#if __i386__
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#   +                       +
+#   +-----------------------+
+#   + thread_state pointer  +
+#   +-----------------------+
+#   + return address        +
+#   +-----------------------+   <-- SP
+#   +                       +
+#
+  .globl _unw_getcontext
+_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
+#
+  .globl _unw_getcontext
+_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
+;
+  .globl _unw_getcontext
+_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
+;
+  .globl _unw_getcontext
+_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
+
+#endif
+

Added: libcxxabi/trunk/src/Unwind/UnwindRegistersSave.s
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/UnwindRegistersSave.s?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/UnwindRegistersSave.s (added)
+++ libcxxabi/trunk/src/Unwind/UnwindRegistersSave.s Mon Oct  7 16:39:41 2013
@@ -0,0 +1,323 @@
+//===------------------------ 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.
+//
+//===----------------------------------------------------------------------===//
+
+
+#if __i386__
+  .text
+  .globl __ZN9libunwind13Registers_x866jumptoEv
+  .private_extern __ZN9libunwind13Registers_x866jumptoEv
+__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__
+
+  .text
+  .globl __ZN9libunwind16Registers_x86_646jumptoEv
+  .private_extern __ZN9libunwind16Registers_x86_646jumptoEv
+__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__
+
+  .text
+  .globl __ZN9libunwind13Registers_ppc6jumptoEv
+  .private_extern __ZN9libunwind13Registers_ppc6jumptoEv
+__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__
+
+  .text
+  .globl __ZN9libunwind15Registers_arm646jumptoEv
+  .private_extern __ZN9libunwind15Registers_arm646jumptoEv
+__ZN9libunwind15Registers_arm646jumptoEv:
+;
+; void libunwind::Registers_arm64::jumpto()
+;
+; On entry:
+;  thread_state pointer is in x0
+;
+  ; 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
+
+
+
+
+#endif
+

Added: libcxxabi/trunk/src/Unwind/Unwind_AppleExtras.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/Unwind_AppleExtras.cpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/Unwind_AppleExtras.cpp (added)
+++ libcxxabi/trunk/src/Unwind/Unwind_AppleExtras.cpp Mon Oct  7 16:39:41 2013
@@ -0,0 +1,204 @@
+//===--------------------- 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
+
+#include <System/pthread_machdep.h>
+
+_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
+
+
+
+

Added: libcxxabi/trunk/src/Unwind/config.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/config.h?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/config.h (added)
+++ libcxxabi/trunk/src/Unwind/config.h Mon Oct  7 16:39:41 2013
@@ -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

Added: libcxxabi/trunk/src/Unwind/dwarf2.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/dwarf2.h?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/dwarf2.h (added)
+++ libcxxabi/trunk/src/Unwind/dwarf2.h Mon Oct  7 16:39:41 2013
@@ -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 compiler
+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

Added: libcxxabi/trunk/src/Unwind/libunwind.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/libunwind.cpp?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/libunwind.cpp (added)
+++ libcxxabi/trunk/src/Unwind/libunwind.cpp Mon Oct  7 16:39:41 2013
@@ -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,
+                                             thread_t thread) {
+  // 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, thread);
+    break;
+  case CPU_TYPE_X86_64:
+    new ((void *)cursor) UnwindCursor<
+        OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(
+        ((unw_addr_space_x86_64 *)as)->oas, thread);
+    break;
+  case CPU_TYPE_POWERPC:
+    new ((void *)cursor)
+        UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>(
+            ((unw_addr_space_ppc *)as)->oas, thread);
+    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
+

Added: libcxxabi/trunk/src/Unwind/libunwind_ext.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/libunwind_ext.h?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/libunwind_ext.h (added)
+++ libcxxabi/trunk/src/Unwind/libunwind_ext.h Mon Oct  7 16:39:41 2013
@@ -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__

Added: libcxxabi/trunk/src/Unwind/unwind_ext.h
URL: http://llvm.org/viewvc/llvm-project/libcxxabi/trunk/src/Unwind/unwind_ext.h?rev=192136&view=auto
==============================================================================
--- libcxxabi/trunk/src/Unwind/unwind_ext.h (added)
+++ libcxxabi/trunk/src/Unwind/unwind_ext.h Mon Oct  7 16:39:41 2013
@@ -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__
+
+





More information about the cfe-commits mailing list