Index: src/Unwind/Registers.hpp
===================================================================
--- src/Unwind/Registers.hpp	(revision 196555)
+++ src/Unwind/Registers.hpp	(working copy)
@@ -1050,10 +1050,6 @@
 
   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) {
@@ -1273,6 +1269,340 @@
   _LIBUNWIND_ABORT("no arm64 vector register support yet");
 }
 
+/// Registers_arm holds the register state of a thread in a 32-bit arm
+/// process.
+///
+/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit,
+/// this uses more memory than required.
+///
+/// FIXME: Support MMX Data Registers, Control registers, and load/stores
+/// for different representations in the VFP registers as listed in
+/// Table 1 of EHABI #7.5.2
+class _LIBUNWIND_HIDDEN Registers_arm {
+public:
+  Registers_arm();
+  Registers_arm(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  // FIXME: Due to ARM VRS's support for reading/writing different
+  // reperesentations into the VFP registers this set of accessors seem wrong.
+  // If {get,set}FloatRegister() is the backing store for
+  // _Unwind_VRS_{Get,Set} then it might be best to return a tagged union
+  // with types for each representation in _Unwind_VRS_DataRepresentation.
+  // Similarly, unw_{get,set}_fpreg in the public libunwind API may want to
+  // use a similar tagged union to back the unw_fpreg_t output parameter type.
+  bool        validFloatRegister(int num) const;
+  unw_fpreg_t getFloatRegister(int num) const;
+  void        setFloatRegister(int num, unw_fpreg_t value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto();
+
+  uint32_t  getSP() const         { return _registers.__sp; }
+  void      setSP(uint32_t value) { _registers.__sp = value; }
+  uint32_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint32_t value) { _registers.__pc = value; }
+
+private:
+  struct GPRs {
+    uint32_t __r[13]; // r0-r12
+    uint32_t __sp;    // Stack pointer r13
+    uint32_t __lr;    // Link register r14
+    uint32_t __pc;    // Program counter r15
+  };
+
+  GPRs    _registers;
+  // VFP defines overlapping registers. So S0 & S1 comprise the high and
+  // low word of D0. Furthermore, these registers can be loaded from/stored
+  // to using various data representation formats. Use a raw byte buffer so
+  // the representation can be more clearly manipulated.
+  //
+  // Per EHABI spec, the VRS only needs to store data for D0-D31.
+  uint8_t _vfpRegisterData[sizeof(double) * 32];
+  uint8_t _wmmxData[sizeof(uint64_t) * 16];
+  uint8_t _wmmxControl[sizeof(uint32_t) * 4];
+};
+
+inline Registers_arm::Registers_arm(const void *registers) {
+  static_assert(sizeof(Registers_arm) < sizeof(unw_context_t),
+                    "arm registers do not fit into unw_context_t");
+  // See unw_getcontext() note about data.
+  memcpy(&_registers, registers, sizeof(_registers));
+  bzero(_vfpRegisterData, sizeof(_vfpRegisterData));
+  bzero(_wmmxData, sizeof(_wmmxData));
+  bzero(_wmmxControl, sizeof(_wmmxControl));
+}
+
+inline Registers_arm::Registers_arm() {
+  bzero(&_registers, sizeof(_registers));
+  bzero(_vfpRegisterData, sizeof(_vfpRegisterData));
+  bzero(_wmmxData, sizeof(_wmmxData));
+  bzero(_wmmxControl, sizeof(_wmmxControl));
+}
+
+inline bool Registers_arm::validRegister(int regNum) const {
+  // Returns true for all non-VFP registers supported by the EHABI
+  // virtual register set (VRS).
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R15))
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_arm::getRegister(int regNum) const {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    return _registers.__sp;
+  if (regNum == UNW_ARM_LR)
+    return _registers.__lr;
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    return _registers.__pc;
+  if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12))
+    return _registers.__r[regNum];
+  _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline void Registers_arm::setRegister(int regNum, uint32_t value) {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    _registers.__sp = value;
+  else if (regNum == UNW_ARM_LR)
+    _registers.__lr = value;
+  else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    _registers.__pc = value;
+  else if ((regNum >= UNW_ARM_R0) && (regNum <= UNW_ARM_R12))
+    _registers.__r[regNum] = value;
+  else
+    _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline const char *Registers_arm::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+  case UNW_ARM_IP: // UNW_ARM_R15 is alias
+    return "pc";
+  case UNW_ARM_LR: // UNW_ARM_R14 is alias
+    return "lr";
+  case UNW_REG_SP:
+  case UNW_ARM_SP: // UNW_ARM_R13 is alias
+    return "sp";
+  case UNW_ARM_R0:
+    return "r0";
+  case UNW_ARM_R1:
+    return "r1";
+  case UNW_ARM_R2:
+    return "r2";
+  case UNW_ARM_R3:
+    return "r3";
+  case UNW_ARM_R4:
+    return "r4";
+  case UNW_ARM_R5:
+    return "r5";
+  case UNW_ARM_R6:
+    return "r6";
+  case UNW_ARM_R7:
+    return "r7";
+  case UNW_ARM_R8:
+    return "r8";
+  case UNW_ARM_R9:
+    return "r9";
+  case UNW_ARM_R10:
+    return "r10";
+  case UNW_ARM_R11:
+    return "r11";
+  case UNW_ARM_R12:
+    return "r12";
+  case UNW_ARM_S0:
+    return "s0";
+  case UNW_ARM_S1:
+    return "s1";
+  case UNW_ARM_S2:
+    return "s2";
+  case UNW_ARM_S3:
+    return "s3";
+  case UNW_ARM_S4:
+    return "s4";
+  case UNW_ARM_S5:
+    return "s5";
+  case UNW_ARM_S6:
+    return "s6";
+  case UNW_ARM_S7:
+    return "s7";
+  case UNW_ARM_S8:
+    return "s8";
+  case UNW_ARM_S9:
+    return "s9";
+  case UNW_ARM_S10:
+    return "s10";
+  case UNW_ARM_S11:
+    return "s11";
+  case UNW_ARM_S12:
+    return "s12";
+  case UNW_ARM_S13:
+    return "s13";
+  case UNW_ARM_S14:
+    return "s14";
+  case UNW_ARM_S15:
+    return "s15";
+  case UNW_ARM_S16:
+    return "s16";
+  case UNW_ARM_S17:
+    return "s17";
+  case UNW_ARM_S18:
+    return "s18";
+  case UNW_ARM_S19:
+    return "s19";
+  case UNW_ARM_S20:
+    return "s20";
+  case UNW_ARM_S21:
+    return "s21";
+  case UNW_ARM_S22:
+    return "s22";
+  case UNW_ARM_S23:
+    return "s23";
+  case UNW_ARM_S24:
+    return "s24";
+  case UNW_ARM_S25:
+    return "s25";
+  case UNW_ARM_S26:
+    return "s26";
+  case UNW_ARM_S27:
+    return "s27";
+  case UNW_ARM_S28:
+    return "s28";
+  case UNW_ARM_S29:
+    return "s29";
+  case UNW_ARM_S30:
+    return "s30";
+  case UNW_ARM_S31:
+    return "s31";
+  case UNW_ARM_D0:
+    return "d0";
+  case UNW_ARM_D1:
+    return "d1";
+  case UNW_ARM_D2:
+    return "d2";
+  case UNW_ARM_D3:
+    return "d3";
+  case UNW_ARM_D4:
+    return "d4";
+  case UNW_ARM_D5:
+    return "d5";
+  case UNW_ARM_D6:
+    return "d6";
+  case UNW_ARM_D7:
+    return "d7";
+  case UNW_ARM_D8:
+    return "d8";
+  case UNW_ARM_D9:
+    return "d9";
+  case UNW_ARM_D10:
+    return "d10";
+  case UNW_ARM_D11:
+    return "d11";
+  case UNW_ARM_D12:
+    return "d12";
+  case UNW_ARM_D13:
+    return "d13";
+  case UNW_ARM_D14:
+    return "d14";
+  case UNW_ARM_D15:
+    return "d15";
+  case UNW_ARM_D16:
+    return "d16";
+  case UNW_ARM_D17:
+    return "d17";
+  case UNW_ARM_D18:
+    return "d18";
+  case UNW_ARM_D19:
+    return "d19";
+  case UNW_ARM_D20:
+    return "d20";
+  case UNW_ARM_D21:
+    return "d21";
+  case UNW_ARM_D22:
+    return "d22";
+  case UNW_ARM_D23:
+    return "d23";
+  case UNW_ARM_D24:
+    return "d24";
+  case UNW_ARM_D25:
+    return "d25";
+  case UNW_ARM_D26:
+    return "d26";
+  case UNW_ARM_D27:
+    return "d27";
+  case UNW_ARM_D28:
+    return "d28";
+  case UNW_ARM_D29:
+    return "d29";
+  case UNW_ARM_D30:
+    return "d30";
+  case UNW_ARM_D31:
+    return "d31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_arm::validFloatRegister(int regNum) const {
+  // NOTE: Consider the indel MMX registers floating points so the
+  // unw_get_fpreg can be used to transmit the 64-bit data back.
+  return ((regNum >= UNW_ARM_S0) && (regNum <= UNW_ARM_S31))
+      || ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31))
+      || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15))
+      || ((regNum >= UNW_ARM_WC0) && (regNum <= UNW_ARM_WC3));
+}
+
+inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) const {
+  assert(validFloatRegister(regNum));
+  unw_fpreg_t value;
+  if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_S0);
+    memcpy(&value, &_vfpRegisterData[index * sizeof(float)],
+           sizeof(float));
+  } else if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_D0);
+    memcpy(&value, &_vfpRegisterData[index * sizeof(double)],
+           sizeof(double));
+  } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_WR0);
+    memcpy(&value, &_wmmxData[index * sizeof(uint64_t)],
+           sizeof(uint64_t));
+  } else if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_WC0);
+    memcpy(&value, &_wmmxControl[index * sizeof(uint32_t)],
+           sizeof(uint32_t));
+  }
+  return value;
+}
+
+inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) {
+  assert(validFloatRegister(regNum));
+  if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_S0);
+    memcpy(&_vfpRegisterData[index * sizeof(float)], &value,
+           sizeof(float));
+  } else if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_D0);
+    memcpy(&_vfpRegisterData[index * sizeof(double)], &value,
+           sizeof(double));
+  } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_WR0);
+    memcpy(&_wmmxData[index * sizeof(uint64_t)], &value,
+           sizeof(uint64_t));
+  } else if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+    unsigned index = (unsigned)(regNum - UNW_ARM_WC0);
+    memcpy(&_wmmxControl[index * sizeof(uint32_t)], &value,
+           sizeof(uint32_t));
+  }
+}
+
 } // namespace libunwind
 
 #endif // __REGISTERS_HPP__
Index: src/Unwind/UnwindRegistersRestore.S
===================================================================
--- src/Unwind/UnwindRegistersRestore.S	(revision 196555)
+++ src/Unwind/UnwindRegistersRestore.S	(working copy)
@@ -7,12 +7,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "assembly.h"
 
+  .text
+
 #if __i386__
-  .text
-  .globl __ZN9libunwind13Registers_x866jumptoEv
-  .private_extern __ZN9libunwind13Registers_x866jumptoEv
-__ZN9libunwind13Registers_x866jumptoEv:
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_x866jumptoEv)
 #
 # void libunwind::Registers_x86::jumpto()
 #
@@ -54,10 +54,7 @@
 
 #elif __x86_64__
 
-  .text
-  .globl __ZN9libunwind16Registers_x86_646jumptoEv
-  .private_extern __ZN9libunwind16Registers_x86_646jumptoEv
-__ZN9libunwind16Registers_x86_646jumptoEv:
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind16Registers_x86_646jumptoEv)
 #
 # void libunwind::Registers_x86_64::jumpto()
 #
@@ -98,10 +95,7 @@
 
 #elif __ppc__
 
-  .text
-  .globl __ZN9libunwind13Registers_ppc6jumptoEv
-  .private_extern __ZN9libunwind13Registers_ppc6jumptoEv
-__ZN9libunwind13Registers_ppc6jumptoEv:
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
 ;
 ; void libunwind::Registers_ppc::jumpto()
 ;
@@ -266,16 +260,13 @@
 
 #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
 ;
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_arm646jumptoEv)
   ; skip restore of x0,x1 for now
   ldp    x2, x3,  [x0, #0x010]
   ldp    x4, x5,  [x0, #0x020]
@@ -316,8 +307,23 @@
   ldp    x0, x1,  [x0, #0x000]  ; restore x0,x1
   ret    lr            ; jump to pc
 
+#elif __arm__
 
+@
+@ void libunwind::Registers_arm::jumpto()
+@
+@ On entry:
+@  thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind13Registers_arm6jumptoEv)
+  @ Use lr as base so that r0 can be restored.
+  mov lr, r0
+  @ 32bit thumb-2 restrictions for ldm:
+  @ . the sp (r13) cannot be in the list
+  @ . the pc (r15) and lr (r14) cannot both be in the list in an LDM instruction
+  ldm lr, {r0-r12}
+  ldr sp, [lr, #52]
+  ldr lr, [lr, #60]  @ restore pc into lr
+  mov pc, lr
 
-
 #endif
-
Index: src/Unwind/UnwindRegistersSave.S
===================================================================
--- src/Unwind/UnwindRegistersSave.S	(revision 196555)
+++ src/Unwind/UnwindRegistersSave.S	(working copy)
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "assembly.h"
 
     .text
 
@@ -24,8 +25,7 @@
 #   +-----------------------+   <-- SP
 #   +                       +
 #
-  .globl _unw_getcontext
-_unw_getcontext:
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
   push  %eax
   movl  8(%esp), %eax
   movl  %ebx,  4(%eax)
@@ -60,8 +60,7 @@
 # On entry:
 #  thread_state pointer is in rdi
 #
-  .globl _unw_getcontext
-_unw_getcontext:
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
   movq  %rax,   (%rdi)
   movq  %rbx,  8(%rdi)
   movq  %rcx, 16(%rdi)
@@ -96,8 +95,7 @@
 ; On entry:
 ;  thread_state pointer is in r3
 ;
-  .globl _unw_getcontext
-_unw_getcontext:
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
   stw    r0,  8(r3)
   mflr  r0
   stw    r0,  0(r3)  ; store lr as ssr0
@@ -240,8 +238,7 @@
 ; On entry:
 ;  thread_state pointer is in x0
 ;
-  .globl _unw_getcontext
-_unw_getcontext:
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
   stp    x0, x1,  [x0, #0x000]
   stp    x2, x3,  [x0, #0x010]
   stp    x4, x5,  [x0, #0x020]
@@ -282,5 +279,24 @@
   ldr    x0, #0      ; return UNW_ESUCCESS
   ret
 
+#elif __arm__ && !__APPLE__
+
+@
+@ extern int unw_getcontext(unw_context_t* thread_state)
+@
+@ On entry:
+@  thread_state pointer is in r0
+@
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+  @ 32bit thumb-2 restrictions for stm:
+  @ . the sp (r13) cannot be in the list
+  @ . the pc (r15) cannot be in the list in an STM instruction
+  stm r0, {r0-r12}
+  str sp, [r0, #52]
+  str lr, [r0, #56]
+  str lr, [r0, #60]  @ store return address as pc
+  mov r0, #0      @ return UNW_ESUCCESS
+  mov pc, lr
+  @ FIXME: VFP registers
+
 #endif
-
Index: src/Unwind/assembly.h
===================================================================
--- src/Unwind/assembly.h	(revision 0)
+++ src/Unwind/assembly.h	(working copy)
@@ -0,0 +1,45 @@
+/* ===-- assembly.h - libUnwind assembler support macros -------------------===
+ *
+ *                     The LLVM Compiler Infrastructure
+ *
+ * This file is dual licensed under the MIT and the University of Illinois Open
+ * Source Licenses. See LICENSE.TXT for details.
+ *
+ * ===----------------------------------------------------------------------===
+ *
+ * This file defines macros for use in libUnwind assembler source.
+ * This file is not part of the interface of this library.
+ *
+ * ===----------------------------------------------------------------------===
+ */
+
+#ifndef UNWIND_ASSEMBLY_H
+#define UNWIND_ASSEMBLY_H
+
+#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
+#define SEPARATOR @
+#else
+#define SEPARATOR ;
+#endif
+
+#if defined(__APPLE__)
+#define HIDDEN_DIRECTIVE .private_extern
+#else
+#define HIDDEN_DIRECTIVE .hidden
+#endif
+
+#define GLUE2(a, b) a ## b
+#define GLUE(a, b) GLUE2(a, b)
+#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
+
+#define DEFINE_LIBUNWIND_FUNCTION(name)                   \
+  .globl SYMBOL_NAME(name) SEPARATOR                      \
+  SYMBOL_NAME(name):
+
+#define DEFINE_LIBUNWIND_PRIVATE_FUNCTION(name)           \
+  .globl SYMBOL_NAME(name) SEPARATOR                      \
+  HIDDEN_DIRECTIVE SYMBOL_NAME(name) SEPARATOR            \
+  SYMBOL_NAME(name):
+
+#endif /* UNWIND_ASSEMBLY_H */
+
Index: include/libunwind.h
===================================================================
--- include/libunwind.h	(revision 196555)
+++ include/libunwind.h	(working copy)
@@ -57,6 +57,7 @@
 
 typedef int unw_regnum_t;
 typedef uint64_t unw_word_t;
+
 typedef double unw_fpreg_t;
 
 struct unw_proc_info_t {
@@ -353,4 +354,134 @@
   UNW_ARM64_D31 = 95,
 };
 
+// 32-bit ARM registers. Numbers match DWARF for ARM spec #3.1 Table 1.
+// Naming scheme uses recommendations given in Note 4 for VFP-v2 and VFP-v3.
+// In this scheme, even though the 64-bit floating point registers D0-D31
+// overlap physically with the 32-bit floating pointer registers S0-S31,
+// they are given a non-overlapping range of register numbers.
+//
+// Commented out ranges are not preserved during unwinding.
+enum {
+  UNW_ARM_R0  = 0,
+  UNW_ARM_R1  = 1,
+  UNW_ARM_R2  = 2,
+  UNW_ARM_R3  = 3,
+  UNW_ARM_R4  = 4,
+  UNW_ARM_R5  = 5,
+  UNW_ARM_R6  = 6,
+  UNW_ARM_R7  = 7,
+  UNW_ARM_R8  = 8,
+  UNW_ARM_R9  = 9,
+  UNW_ARM_R10 = 10,
+  UNW_ARM_R11 = 11,
+  UNW_ARM_R12 = 12,
+  UNW_ARM_SP  = 13,  // Logical alias for UNW_REG_SP
+  UNW_ARM_R13 = 13,
+  UNW_ARM_LR  = 14,
+  UNW_ARM_R14 = 14,
+  UNW_ARM_IP  = 15,  // Logical alias for UNW_REG_IP
+  UNW_ARM_R15 = 15,
+  // 16-63 -- OBSOLETE. Used in VFP1 to represent both S0-S31 and D0-D31.
+  UNW_ARM_S0  = 64,
+  UNW_ARM_S1  = 65,
+  UNW_ARM_S2  = 66,
+  UNW_ARM_S3  = 67,
+  UNW_ARM_S4  = 68,
+  UNW_ARM_S5  = 69,
+  UNW_ARM_S6  = 70,
+  UNW_ARM_S7  = 71,
+  UNW_ARM_S8  = 72,
+  UNW_ARM_S9  = 73,
+  UNW_ARM_S10 = 74,
+  UNW_ARM_S11 = 75,
+  UNW_ARM_S12 = 76,
+  UNW_ARM_S13 = 77,
+  UNW_ARM_S14 = 78,
+  UNW_ARM_S15 = 79,
+  UNW_ARM_S16 = 80,
+  UNW_ARM_S17 = 81,
+  UNW_ARM_S18 = 82,
+  UNW_ARM_S19 = 83,
+  UNW_ARM_S20 = 84,
+  UNW_ARM_S21 = 85,
+  UNW_ARM_S22 = 86,
+  UNW_ARM_S23 = 87,
+  UNW_ARM_S24 = 88,
+  UNW_ARM_S25 = 89,
+  UNW_ARM_S26 = 90,
+  UNW_ARM_S27 = 91,
+  UNW_ARM_S28 = 92,
+  UNW_ARM_S29 = 93,
+  UNW_ARM_S30 = 94,
+  UNW_ARM_S31 = 95,
+  //  96-103 -- OBSOLETE. F0-F7. Used by the FPA system. Superceded by VFP.
+  // 104-111 -- wCGR0-wCGR7, ACC0-ACC7 (Intel wireless MMX)
+  UNW_ARM_WR0 = 112,
+  UNW_ARM_WR1 = 113,
+  UNW_ARM_WR2 = 114,
+  UNW_ARM_WR3 = 115,
+  UNW_ARM_WR4 = 116,
+  UNW_ARM_WR5 = 117,
+  UNW_ARM_WR6 = 118,
+  UNW_ARM_WR7 = 119,
+  UNW_ARM_WR8 = 120,
+  UNW_ARM_WR9 = 121,
+  UNW_ARM_WR10 = 122,
+  UNW_ARM_WR11 = 123,
+  UNW_ARM_WR12 = 124,
+  UNW_ARM_WR13 = 125,
+  UNW_ARM_WR14 = 126,
+  UNW_ARM_WR15 = 127,
+  // 128-133 -- SPSR, SPSR_{FIQ|IRQ|ABT|UND|SVC}
+  // 134-143 -- Reserved
+  // 144-150 -- R8_USR–R14_USR
+  // 151-157 -- R8_FIQ–R14_FIQ
+  // 158-159 -- R13_IRQ–R14_IRQ
+  // 160-161 -- R13_ABT–R14_ABT
+  // 162-163 -- R13_UND–R14_UND
+  // 164-165 -- R13_SVC–R14_SVC
+  // 166-191 -- Reserved
+  UNW_ARM_WC0 = 192,
+  UNW_ARM_WC1 = 193,
+  UNW_ARM_WC2 = 194,
+  UNW_ARM_WC3 = 195,
+  // 196-199 -- wC4-wC7 (Intel wireless MMX control)
+  // 200-255 -- Reserved
+  UNW_ARM_D0  = 256,
+  UNW_ARM_D1  = 257,
+  UNW_ARM_D2  = 258,
+  UNW_ARM_D3  = 259,
+  UNW_ARM_D4  = 260,
+  UNW_ARM_D5  = 261,
+  UNW_ARM_D6  = 262,
+  UNW_ARM_D7  = 263,
+  UNW_ARM_D8  = 264,
+  UNW_ARM_D9  = 265,
+  UNW_ARM_D10 = 266,
+  UNW_ARM_D11 = 267,
+  UNW_ARM_D12 = 268,
+  UNW_ARM_D13 = 269,
+  UNW_ARM_D14 = 270,
+  UNW_ARM_D15 = 271,
+  UNW_ARM_D16 = 272,
+  UNW_ARM_D17 = 273,
+  UNW_ARM_D18 = 274,
+  UNW_ARM_D19 = 275,
+  UNW_ARM_D20 = 276,
+  UNW_ARM_D21 = 277,
+  UNW_ARM_D22 = 278,
+  UNW_ARM_D23 = 279,
+  UNW_ARM_D24 = 280,
+  UNW_ARM_D25 = 281,
+  UNW_ARM_D26 = 282,
+  UNW_ARM_D27 = 283,
+  UNW_ARM_D28 = 284,
+  UNW_ARM_D29 = 285,
+  UNW_ARM_D30 = 286,
+  UNW_ARM_D31 = 287,
+  // 288-319 -- Reserved for VFP/Neon
+  // 320-8191 -- Reserved
+  // 8192-16383 -- Unspecified vendor co-processor register.
+};
+
 #endif
