unwind: move src/Unwind, include/, and test/ unwind content

This moves the majority of the unwind sources into the new project layout for
libunwind.  This was previously discussed on llvmdev at [1].  This is a
purely movement related change, with the build infrastructure currently still
residing in the libc++abi repository.

[1] http://lists.cs.uiuc.edu/pipermail/llvmdev/2015-January/081507.html



git-svn-id: https://llvm.org/svn/llvm-project/libunwind/trunk@235758 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/src/Registers.hpp b/src/Registers.hpp
new file mode 100644
index 0000000..4a441b7
--- /dev/null
+++ b/src/Registers.hpp
@@ -0,0 +1,1718 @@
+//===----------------------------- Registers.hpp --------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//
+//  Models register sets for supported processors.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __REGISTERS_HPP__
+#define __REGISTERS_HPP__
+
+#include <stdint.h>
+#include <strings.h>
+#include <string.h>
+
+#include "libunwind.h"
+#include "config.h"
+
+namespace libunwind {
+
+// For emulating 128-bit registers
+struct v128 { uint32_t vec[4]; };
+
+
+/// Registers_x86 holds the register state of a thread in a 32-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86 {
+public:
+  Registers_x86();
+  Registers_x86(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int) const { return false; }
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int) const { return false; }
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return 8; }
+
+  uint32_t  getSP() const          { return _registers.__esp; }
+  void      setSP(uint32_t value)  { _registers.__esp = value; }
+  uint32_t  getIP() const          { return _registers.__eip; }
+  void      setIP(uint32_t value)  { _registers.__eip = value; }
+  uint32_t  getEBP() const         { return _registers.__ebp; }
+  void      setEBP(uint32_t value) { _registers.__ebp = value; }
+  uint32_t  getEBX() const         { return _registers.__ebx; }
+  void      setEBX(uint32_t value) { _registers.__ebx = value; }
+  uint32_t  getECX() const         { return _registers.__ecx; }
+  void      setECX(uint32_t value) { _registers.__ecx = value; }
+  uint32_t  getEDX() const         { return _registers.__edx; }
+  void      setEDX(uint32_t value) { _registers.__edx = value; }
+  uint32_t  getESI() const         { return _registers.__esi; }
+  void      setESI(uint32_t value) { _registers.__esi = value; }
+  uint32_t  getEDI() const         { return _registers.__edi; }
+  void      setEDI(uint32_t value) { _registers.__edi = value; }
+
+private:
+  struct GPRs {
+    unsigned int __eax;
+    unsigned int __ebx;
+    unsigned int __ecx;
+    unsigned int __edx;
+    unsigned int __edi;
+    unsigned int __esi;
+    unsigned int __ebp;
+    unsigned int __esp;
+    unsigned int __ss;
+    unsigned int __eflags;
+    unsigned int __eip;
+    unsigned int __cs;
+    unsigned int __ds;
+    unsigned int __es;
+    unsigned int __fs;
+    unsigned int __gs;
+  };
+
+  GPRs _registers;
+};
+
+inline Registers_x86::Registers_x86(const void *registers) {
+  static_assert(sizeof(Registers_x86) < sizeof(unw_context_t),
+                    "x86 registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_x86::Registers_x86() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_x86::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum > 7)
+    return false;
+  return true;
+}
+
+inline uint32_t Registers_x86::getRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__eip;
+  case UNW_REG_SP:
+    return _registers.__esp;
+  case UNW_X86_EAX:
+    return _registers.__eax;
+  case UNW_X86_ECX:
+    return _registers.__ecx;
+  case UNW_X86_EDX:
+    return _registers.__edx;
+  case UNW_X86_EBX:
+    return _registers.__ebx;
+  case UNW_X86_EBP:
+    return _registers.__ebp;
+  case UNW_X86_ESP:
+    return _registers.__esp;
+  case UNW_X86_ESI:
+    return _registers.__esi;
+  case UNW_X86_EDI:
+    return _registers.__edi;
+  }
+  _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline void Registers_x86::setRegister(int regNum, uint32_t value) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__eip = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__esp = value;
+    return;
+  case UNW_X86_EAX:
+    _registers.__eax = value;
+    return;
+  case UNW_X86_ECX:
+    _registers.__ecx = value;
+    return;
+  case UNW_X86_EDX:
+    _registers.__edx = value;
+    return;
+  case UNW_X86_EBX:
+    _registers.__ebx = value;
+    return;
+  case UNW_X86_EBP:
+    _registers.__ebp = value;
+    return;
+  case UNW_X86_ESP:
+    _registers.__esp = value;
+    return;
+  case UNW_X86_ESI:
+    _registers.__esi = value;
+    return;
+  case UNW_X86_EDI:
+    _registers.__edi = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported x86 register");
+}
+
+inline const char *Registers_x86::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "ip";
+  case UNW_REG_SP:
+    return "esp";
+  case UNW_X86_EAX:
+    return "eax";
+  case UNW_X86_ECX:
+    return "ecx";
+  case UNW_X86_EDX:
+    return "edx";
+  case UNW_X86_EBX:
+    return "ebx";
+  case UNW_X86_EBP:
+    return "ebp";
+  case UNW_X86_ESP:
+    return "esp";
+  case UNW_X86_ESI:
+    return "esi";
+  case UNW_X86_EDI:
+    return "edi";
+  default:
+    return "unknown register";
+  }
+}
+
+inline double Registers_x86::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline void Registers_x86::setFloatRegister(int, double) {
+  _LIBUNWIND_ABORT("no x86 float registers");
+}
+
+inline v128 Registers_x86::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no x86 vector registers");
+}
+
+inline void Registers_x86::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no x86 vector registers");
+}
+
+
+/// Registers_x86_64  holds the register state of a thread in a 64-bit intel
+/// process.
+class _LIBUNWIND_HIDDEN Registers_x86_64 {
+public:
+  Registers_x86_64();
+  Registers_x86_64(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint64_t    getRegister(int num) const;
+  void        setRegister(int num, uint64_t value);
+  bool        validFloatRegister(int) const { return false; }
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int) const { return false; }
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return 16; }
+
+  uint64_t  getSP() const          { return _registers.__rsp; }
+  void      setSP(uint64_t value)  { _registers.__rsp = value; }
+  uint64_t  getIP() const          { return _registers.__rip; }
+  void      setIP(uint64_t value)  { _registers.__rip = value; }
+  uint64_t  getRBP() const         { return _registers.__rbp; }
+  void      setRBP(uint64_t value) { _registers.__rbp = value; }
+  uint64_t  getRBX() const         { return _registers.__rbx; }
+  void      setRBX(uint64_t value) { _registers.__rbx = value; }
+  uint64_t  getR12() const         { return _registers.__r12; }
+  void      setR12(uint64_t value) { _registers.__r12 = value; }
+  uint64_t  getR13() const         { return _registers.__r13; }
+  void      setR13(uint64_t value) { _registers.__r13 = value; }
+  uint64_t  getR14() const         { return _registers.__r14; }
+  void      setR14(uint64_t value) { _registers.__r14 = value; }
+  uint64_t  getR15() const         { return _registers.__r15; }
+  void      setR15(uint64_t value) { _registers.__r15 = value; }
+
+private:
+  struct GPRs {
+    uint64_t __rax;
+    uint64_t __rbx;
+    uint64_t __rcx;
+    uint64_t __rdx;
+    uint64_t __rdi;
+    uint64_t __rsi;
+    uint64_t __rbp;
+    uint64_t __rsp;
+    uint64_t __r8;
+    uint64_t __r9;
+    uint64_t __r10;
+    uint64_t __r11;
+    uint64_t __r12;
+    uint64_t __r13;
+    uint64_t __r14;
+    uint64_t __r15;
+    uint64_t __rip;
+    uint64_t __rflags;
+    uint64_t __cs;
+    uint64_t __fs;
+    uint64_t __gs;
+  };
+  GPRs _registers;
+};
+
+inline Registers_x86_64::Registers_x86_64(const void *registers) {
+  static_assert(sizeof(Registers_x86_64) < sizeof(unw_context_t),
+                    "x86_64 registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+}
+
+inline Registers_x86_64::Registers_x86_64() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_x86_64::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum > 15)
+    return false;
+  return true;
+}
+
+inline uint64_t Registers_x86_64::getRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__rip;
+  case UNW_REG_SP:
+    return _registers.__rsp;
+  case UNW_X86_64_RAX:
+    return _registers.__rax;
+  case UNW_X86_64_RDX:
+    return _registers.__rdx;
+  case UNW_X86_64_RCX:
+    return _registers.__rcx;
+  case UNW_X86_64_RBX:
+    return _registers.__rbx;
+  case UNW_X86_64_RSI:
+    return _registers.__rsi;
+  case UNW_X86_64_RDI:
+    return _registers.__rdi;
+  case UNW_X86_64_RBP:
+    return _registers.__rbp;
+  case UNW_X86_64_RSP:
+    return _registers.__rsp;
+  case UNW_X86_64_R8:
+    return _registers.__r8;
+  case UNW_X86_64_R9:
+    return _registers.__r9;
+  case UNW_X86_64_R10:
+    return _registers.__r10;
+  case UNW_X86_64_R11:
+    return _registers.__r11;
+  case UNW_X86_64_R12:
+    return _registers.__r12;
+  case UNW_X86_64_R13:
+    return _registers.__r13;
+  case UNW_X86_64_R14:
+    return _registers.__r14;
+  case UNW_X86_64_R15:
+    return _registers.__r15;
+  }
+  _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__rip = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__rsp = value;
+    return;
+  case UNW_X86_64_RAX:
+    _registers.__rax = value;
+    return;
+  case UNW_X86_64_RDX:
+    _registers.__rdx = value;
+    return;
+  case UNW_X86_64_RCX:
+    _registers.__rcx = value;
+    return;
+  case UNW_X86_64_RBX:
+    _registers.__rbx = value;
+    return;
+  case UNW_X86_64_RSI:
+    _registers.__rsi = value;
+    return;
+  case UNW_X86_64_RDI:
+    _registers.__rdi = value;
+    return;
+  case UNW_X86_64_RBP:
+    _registers.__rbp = value;
+    return;
+  case UNW_X86_64_RSP:
+    _registers.__rsp = value;
+    return;
+  case UNW_X86_64_R8:
+    _registers.__r8 = value;
+    return;
+  case UNW_X86_64_R9:
+    _registers.__r9 = value;
+    return;
+  case UNW_X86_64_R10:
+    _registers.__r10 = value;
+    return;
+  case UNW_X86_64_R11:
+    _registers.__r11 = value;
+    return;
+  case UNW_X86_64_R12:
+    _registers.__r12 = value;
+    return;
+  case UNW_X86_64_R13:
+    _registers.__r13 = value;
+    return;
+  case UNW_X86_64_R14:
+    _registers.__r14 = value;
+    return;
+  case UNW_X86_64_R15:
+    _registers.__r15 = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported x86_64 register");
+}
+
+inline const char *Registers_x86_64::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "rip";
+  case UNW_REG_SP:
+    return "rsp";
+  case UNW_X86_64_RAX:
+    return "rax";
+  case UNW_X86_64_RDX:
+    return "rdx";
+  case UNW_X86_64_RCX:
+    return "rcx";
+  case UNW_X86_64_RBX:
+    return "rbx";
+  case UNW_X86_64_RSI:
+    return "rsi";
+  case UNW_X86_64_RDI:
+    return "rdi";
+  case UNW_X86_64_RBP:
+    return "rbp";
+  case UNW_X86_64_RSP:
+    return "rsp";
+  case UNW_X86_64_R8:
+    return "r8";
+  case UNW_X86_64_R9:
+    return "r9";
+  case UNW_X86_64_R10:
+    return "r10";
+  case UNW_X86_64_R11:
+    return "r11";
+  case UNW_X86_64_R12:
+    return "r12";
+  case UNW_X86_64_R13:
+    return "r13";
+  case UNW_X86_64_R14:
+    return "r14";
+  case UNW_X86_64_R15:
+    return "r15";
+  default:
+    return "unknown register";
+  }
+}
+
+inline double Registers_x86_64::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline void Registers_x86_64::setFloatRegister(int, double) {
+  _LIBUNWIND_ABORT("no x86_64 float registers");
+}
+
+inline v128 Registers_x86_64::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no x86_64 vector registers");
+}
+
+inline void Registers_x86_64::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no x86_64 vector registers");
+}
+
+
+/// Registers_ppc holds the register state of a thread in a 32-bit PowerPC
+/// process.
+class _LIBUNWIND_HIDDEN Registers_ppc {
+public:
+  Registers_ppc();
+  Registers_ppc(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return 112; }
+
+  uint64_t  getSP() const         { return _registers.__r1; }
+  void      setSP(uint32_t value) { _registers.__r1 = value; }
+  uint64_t  getIP() const         { return _registers.__srr0; }
+  void      setIP(uint32_t value) { _registers.__srr0 = value; }
+
+private:
+  struct ppc_thread_state_t {
+    unsigned int __srr0; /* Instruction address register (PC) */
+    unsigned int __srr1; /* Machine state register (supervisor) */
+    unsigned int __r0;
+    unsigned int __r1;
+    unsigned int __r2;
+    unsigned int __r3;
+    unsigned int __r4;
+    unsigned int __r5;
+    unsigned int __r6;
+    unsigned int __r7;
+    unsigned int __r8;
+    unsigned int __r9;
+    unsigned int __r10;
+    unsigned int __r11;
+    unsigned int __r12;
+    unsigned int __r13;
+    unsigned int __r14;
+    unsigned int __r15;
+    unsigned int __r16;
+    unsigned int __r17;
+    unsigned int __r18;
+    unsigned int __r19;
+    unsigned int __r20;
+    unsigned int __r21;
+    unsigned int __r22;
+    unsigned int __r23;
+    unsigned int __r24;
+    unsigned int __r25;
+    unsigned int __r26;
+    unsigned int __r27;
+    unsigned int __r28;
+    unsigned int __r29;
+    unsigned int __r30;
+    unsigned int __r31;
+    unsigned int __cr;     /* Condition register */
+    unsigned int __xer;    /* User's integer exception register */
+    unsigned int __lr;     /* Link register */
+    unsigned int __ctr;    /* Count register */
+    unsigned int __mq;     /* MQ register (601 only) */
+    unsigned int __vrsave; /* Vector Save Register */
+  };
+
+  struct ppc_float_state_t {
+    double __fpregs[32];
+
+    unsigned int __fpscr_pad; /* fpscr is 64 bits, 32 bits of rubbish */
+    unsigned int __fpscr;     /* floating point status register */
+  };
+
+  ppc_thread_state_t _registers;
+  ppc_float_state_t  _floatRegisters;
+  v128               _vectorRegisters[32]; // offset 424
+};
+
+inline Registers_ppc::Registers_ppc(const void *registers) {
+  static_assert(sizeof(Registers_ppc) < sizeof(unw_context_t),
+                    "ppc registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+  static_assert(sizeof(ppc_thread_state_t) == 160,
+                "expected float register offset to be 160");
+  memcpy(&_floatRegisters,
+         static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t),
+         sizeof(_floatRegisters));
+  static_assert(sizeof(ppc_thread_state_t) + sizeof(ppc_float_state_t) == 424,
+                "expected vector register offset to be 424 bytes");
+  memcpy(_vectorRegisters,
+         static_cast<const uint8_t *>(registers) + sizeof(ppc_thread_state_t) +
+             sizeof(ppc_float_state_t),
+         sizeof(_vectorRegisters));
+}
+
+inline Registers_ppc::Registers_ppc() {
+  memset(&_registers, 0, sizeof(_registers));
+  memset(&_floatRegisters, 0, sizeof(_floatRegisters));
+  memset(&_vectorRegisters, 0, sizeof(_vectorRegisters));
+}
+
+inline bool Registers_ppc::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum == UNW_PPC_VRSAVE)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum <= UNW_PPC_R31)
+    return true;
+  if (regNum == UNW_PPC_MQ)
+    return true;
+  if (regNum == UNW_PPC_LR)
+    return true;
+  if (regNum == UNW_PPC_CTR)
+    return true;
+  if ((UNW_PPC_CR0 <= regNum) && (regNum <= UNW_PPC_CR7))
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_ppc::getRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__srr0;
+  case UNW_REG_SP:
+    return _registers.__r1;
+  case UNW_PPC_R0:
+    return _registers.__r0;
+  case UNW_PPC_R1:
+    return _registers.__r1;
+  case UNW_PPC_R2:
+    return _registers.__r2;
+  case UNW_PPC_R3:
+    return _registers.__r3;
+  case UNW_PPC_R4:
+    return _registers.__r4;
+  case UNW_PPC_R5:
+    return _registers.__r5;
+  case UNW_PPC_R6:
+    return _registers.__r6;
+  case UNW_PPC_R7:
+    return _registers.__r7;
+  case UNW_PPC_R8:
+    return _registers.__r8;
+  case UNW_PPC_R9:
+    return _registers.__r9;
+  case UNW_PPC_R10:
+    return _registers.__r10;
+  case UNW_PPC_R11:
+    return _registers.__r11;
+  case UNW_PPC_R12:
+    return _registers.__r12;
+  case UNW_PPC_R13:
+    return _registers.__r13;
+  case UNW_PPC_R14:
+    return _registers.__r14;
+  case UNW_PPC_R15:
+    return _registers.__r15;
+  case UNW_PPC_R16:
+    return _registers.__r16;
+  case UNW_PPC_R17:
+    return _registers.__r17;
+  case UNW_PPC_R18:
+    return _registers.__r18;
+  case UNW_PPC_R19:
+    return _registers.__r19;
+  case UNW_PPC_R20:
+    return _registers.__r20;
+  case UNW_PPC_R21:
+    return _registers.__r21;
+  case UNW_PPC_R22:
+    return _registers.__r22;
+  case UNW_PPC_R23:
+    return _registers.__r23;
+  case UNW_PPC_R24:
+    return _registers.__r24;
+  case UNW_PPC_R25:
+    return _registers.__r25;
+  case UNW_PPC_R26:
+    return _registers.__r26;
+  case UNW_PPC_R27:
+    return _registers.__r27;
+  case UNW_PPC_R28:
+    return _registers.__r28;
+  case UNW_PPC_R29:
+    return _registers.__r29;
+  case UNW_PPC_R30:
+    return _registers.__r30;
+  case UNW_PPC_R31:
+    return _registers.__r31;
+  case UNW_PPC_LR:
+    return _registers.__lr;
+  case UNW_PPC_CR0:
+    return (_registers.__cr & 0xF0000000);
+  case UNW_PPC_CR1:
+    return (_registers.__cr & 0x0F000000);
+  case UNW_PPC_CR2:
+    return (_registers.__cr & 0x00F00000);
+  case UNW_PPC_CR3:
+    return (_registers.__cr & 0x000F0000);
+  case UNW_PPC_CR4:
+    return (_registers.__cr & 0x0000F000);
+  case UNW_PPC_CR5:
+    return (_registers.__cr & 0x00000F00);
+  case UNW_PPC_CR6:
+    return (_registers.__cr & 0x000000F0);
+  case UNW_PPC_CR7:
+    return (_registers.__cr & 0x0000000F);
+  case UNW_PPC_VRSAVE:
+    return _registers.__vrsave;
+  }
+  _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline void Registers_ppc::setRegister(int regNum, uint32_t value) {
+  //fprintf(stderr, "Registers_ppc::setRegister(%d, 0x%08X)\n", regNum, value);
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__srr0 = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__r1 = value;
+    return;
+  case UNW_PPC_R0:
+    _registers.__r0 = value;
+    return;
+  case UNW_PPC_R1:
+    _registers.__r1 = value;
+    return;
+  case UNW_PPC_R2:
+    _registers.__r2 = value;
+    return;
+  case UNW_PPC_R3:
+    _registers.__r3 = value;
+    return;
+  case UNW_PPC_R4:
+    _registers.__r4 = value;
+    return;
+  case UNW_PPC_R5:
+    _registers.__r5 = value;
+    return;
+  case UNW_PPC_R6:
+    _registers.__r6 = value;
+    return;
+  case UNW_PPC_R7:
+    _registers.__r7 = value;
+    return;
+  case UNW_PPC_R8:
+    _registers.__r8 = value;
+    return;
+  case UNW_PPC_R9:
+    _registers.__r9 = value;
+    return;
+  case UNW_PPC_R10:
+    _registers.__r10 = value;
+    return;
+  case UNW_PPC_R11:
+    _registers.__r11 = value;
+    return;
+  case UNW_PPC_R12:
+    _registers.__r12 = value;
+    return;
+  case UNW_PPC_R13:
+    _registers.__r13 = value;
+    return;
+  case UNW_PPC_R14:
+    _registers.__r14 = value;
+    return;
+  case UNW_PPC_R15:
+    _registers.__r15 = value;
+    return;
+  case UNW_PPC_R16:
+    _registers.__r16 = value;
+    return;
+  case UNW_PPC_R17:
+    _registers.__r17 = value;
+    return;
+  case UNW_PPC_R18:
+    _registers.__r18 = value;
+    return;
+  case UNW_PPC_R19:
+    _registers.__r19 = value;
+    return;
+  case UNW_PPC_R20:
+    _registers.__r20 = value;
+    return;
+  case UNW_PPC_R21:
+    _registers.__r21 = value;
+    return;
+  case UNW_PPC_R22:
+    _registers.__r22 = value;
+    return;
+  case UNW_PPC_R23:
+    _registers.__r23 = value;
+    return;
+  case UNW_PPC_R24:
+    _registers.__r24 = value;
+    return;
+  case UNW_PPC_R25:
+    _registers.__r25 = value;
+    return;
+  case UNW_PPC_R26:
+    _registers.__r26 = value;
+    return;
+  case UNW_PPC_R27:
+    _registers.__r27 = value;
+    return;
+  case UNW_PPC_R28:
+    _registers.__r28 = value;
+    return;
+  case UNW_PPC_R29:
+    _registers.__r29 = value;
+    return;
+  case UNW_PPC_R30:
+    _registers.__r30 = value;
+    return;
+  case UNW_PPC_R31:
+    _registers.__r31 = value;
+    return;
+  case UNW_PPC_MQ:
+    _registers.__mq = value;
+    return;
+  case UNW_PPC_LR:
+    _registers.__lr = value;
+    return;
+  case UNW_PPC_CTR:
+    _registers.__ctr = value;
+    return;
+  case UNW_PPC_CR0:
+    _registers.__cr &= 0x0FFFFFFF;
+    _registers.__cr |= (value & 0xF0000000);
+    return;
+  case UNW_PPC_CR1:
+    _registers.__cr &= 0xF0FFFFFF;
+    _registers.__cr |= (value & 0x0F000000);
+    return;
+  case UNW_PPC_CR2:
+    _registers.__cr &= 0xFF0FFFFF;
+    _registers.__cr |= (value & 0x00F00000);
+    return;
+  case UNW_PPC_CR3:
+    _registers.__cr &= 0xFFF0FFFF;
+    _registers.__cr |= (value & 0x000F0000);
+    return;
+  case UNW_PPC_CR4:
+    _registers.__cr &= 0xFFFF0FFF;
+    _registers.__cr |= (value & 0x0000F000);
+    return;
+  case UNW_PPC_CR5:
+    _registers.__cr &= 0xFFFFF0FF;
+    _registers.__cr |= (value & 0x00000F00);
+    return;
+  case UNW_PPC_CR6:
+    _registers.__cr &= 0xFFFFFF0F;
+    _registers.__cr |= (value & 0x000000F0);
+    return;
+  case UNW_PPC_CR7:
+    _registers.__cr &= 0xFFFFFFF0;
+    _registers.__cr |= (value & 0x0000000F);
+    return;
+  case UNW_PPC_VRSAVE:
+    _registers.__vrsave = value;
+    return;
+    // not saved
+    return;
+  case UNW_PPC_XER:
+    _registers.__xer = value;
+    return;
+  case UNW_PPC_AP:
+  case UNW_PPC_VSCR:
+  case UNW_PPC_SPEFSCR:
+    // not saved
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported ppc register");
+}
+
+inline bool Registers_ppc::validFloatRegister(int regNum) const {
+  if (regNum < UNW_PPC_F0)
+    return false;
+  if (regNum > UNW_PPC_F31)
+    return false;
+  return true;
+}
+
+inline double Registers_ppc::getFloatRegister(int regNum) const {
+  assert(validFloatRegister(regNum));
+  return _floatRegisters.__fpregs[regNum - UNW_PPC_F0];
+}
+
+inline void Registers_ppc::setFloatRegister(int regNum, double value) {
+  assert(validFloatRegister(regNum));
+  _floatRegisters.__fpregs[regNum - UNW_PPC_F0] = value;
+}
+
+inline bool Registers_ppc::validVectorRegister(int regNum) const {
+  if (regNum < UNW_PPC_V0)
+    return false;
+  if (regNum > UNW_PPC_V31)
+    return false;
+  return true;
+}
+
+inline v128 Registers_ppc::getVectorRegister(int regNum) const {
+  assert(validVectorRegister(regNum));
+  v128 result = _vectorRegisters[regNum - UNW_PPC_V0];
+  return result;
+}
+
+inline void Registers_ppc::setVectorRegister(int regNum, v128 value) {
+  assert(validVectorRegister(regNum));
+  _vectorRegisters[regNum - UNW_PPC_V0] = value;
+}
+
+inline const char *Registers_ppc::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "ip";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_PPC_R0:
+    return "r0";
+  case UNW_PPC_R1:
+    return "r1";
+  case UNW_PPC_R2:
+    return "r2";
+  case UNW_PPC_R3:
+    return "r3";
+  case UNW_PPC_R4:
+    return "r4";
+  case UNW_PPC_R5:
+    return "r5";
+  case UNW_PPC_R6:
+    return "r6";
+  case UNW_PPC_R7:
+    return "r7";
+  case UNW_PPC_R8:
+    return "r8";
+  case UNW_PPC_R9:
+    return "r9";
+  case UNW_PPC_R10:
+    return "r10";
+  case UNW_PPC_R11:
+    return "r11";
+  case UNW_PPC_R12:
+    return "r12";
+  case UNW_PPC_R13:
+    return "r13";
+  case UNW_PPC_R14:
+    return "r14";
+  case UNW_PPC_R15:
+    return "r15";
+  case UNW_PPC_R16:
+    return "r16";
+  case UNW_PPC_R17:
+    return "r17";
+  case UNW_PPC_R18:
+    return "r18";
+  case UNW_PPC_R19:
+    return "r19";
+  case UNW_PPC_R20:
+    return "r20";
+  case UNW_PPC_R21:
+    return "r21";
+  case UNW_PPC_R22:
+    return "r22";
+  case UNW_PPC_R23:
+    return "r23";
+  case UNW_PPC_R24:
+    return "r24";
+  case UNW_PPC_R25:
+    return "r25";
+  case UNW_PPC_R26:
+    return "r26";
+  case UNW_PPC_R27:
+    return "r27";
+  case UNW_PPC_R28:
+    return "r28";
+  case UNW_PPC_R29:
+    return "r29";
+  case UNW_PPC_R30:
+    return "r30";
+  case UNW_PPC_R31:
+    return "r31";
+  case UNW_PPC_F0:
+    return "fp0";
+  case UNW_PPC_F1:
+    return "fp1";
+  case UNW_PPC_F2:
+    return "fp2";
+  case UNW_PPC_F3:
+    return "fp3";
+  case UNW_PPC_F4:
+    return "fp4";
+  case UNW_PPC_F5:
+    return "fp5";
+  case UNW_PPC_F6:
+    return "fp6";
+  case UNW_PPC_F7:
+    return "fp7";
+  case UNW_PPC_F8:
+    return "fp8";
+  case UNW_PPC_F9:
+    return "fp9";
+  case UNW_PPC_F10:
+    return "fp10";
+  case UNW_PPC_F11:
+    return "fp11";
+  case UNW_PPC_F12:
+    return "fp12";
+  case UNW_PPC_F13:
+    return "fp13";
+  case UNW_PPC_F14:
+    return "fp14";
+  case UNW_PPC_F15:
+    return "fp15";
+  case UNW_PPC_F16:
+    return "fp16";
+  case UNW_PPC_F17:
+    return "fp17";
+  case UNW_PPC_F18:
+    return "fp18";
+  case UNW_PPC_F19:
+    return "fp19";
+  case UNW_PPC_F20:
+    return "fp20";
+  case UNW_PPC_F21:
+    return "fp21";
+  case UNW_PPC_F22:
+    return "fp22";
+  case UNW_PPC_F23:
+    return "fp23";
+  case UNW_PPC_F24:
+    return "fp24";
+  case UNW_PPC_F25:
+    return "fp25";
+  case UNW_PPC_F26:
+    return "fp26";
+  case UNW_PPC_F27:
+    return "fp27";
+  case UNW_PPC_F28:
+    return "fp28";
+  case UNW_PPC_F29:
+    return "fp29";
+  case UNW_PPC_F30:
+    return "fp30";
+  case UNW_PPC_F31:
+    return "fp31";
+  case UNW_PPC_LR:
+    return "lr";
+  default:
+    return "unknown register";
+  }
+
+}
+
+
+/// Registers_arm64  holds the register state of a thread in a 64-bit arm
+/// process.
+class _LIBUNWIND_HIDDEN Registers_arm64 {
+public:
+  Registers_arm64();
+  Registers_arm64(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint64_t    getRegister(int num) const;
+  void        setRegister(int num, uint64_t value);
+  bool        validFloatRegister(int num) const;
+  double      getFloatRegister(int num) const;
+  void        setFloatRegister(int num, double value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return 95; }
+
+  uint64_t  getSP() const         { return _registers.__sp; }
+  void      setSP(uint64_t value) { _registers.__sp = value; }
+  uint64_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint64_t value) { _registers.__pc = value; }
+  uint64_t  getFP() const         { return _registers.__fp; }
+  void      setFP(uint64_t value) { _registers.__fp = value; }
+
+private:
+  struct GPRs {
+    uint64_t __x[29]; // x0-x28
+    uint64_t __fp;    // Frame pointer x29
+    uint64_t __lr;    // Link register x30
+    uint64_t __sp;    // Stack pointer x31
+    uint64_t __pc;    // Program counter
+    uint64_t padding; // 16-byte align
+  };
+
+  GPRs    _registers;
+  double  _vectorHalfRegisters[32];
+  // Currently only the lower double in 128-bit vectore registers
+  // is perserved during unwinding.  We could define new register
+  // numbers (> 96) which mean whole vector registers, then this
+  // struct would need to change to contain whole vector registers.
+};
+
+inline Registers_arm64::Registers_arm64(const void *registers) {
+  static_assert(sizeof(Registers_arm64) < sizeof(unw_context_t),
+                    "arm64 registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+  static_assert(sizeof(GPRs) == 0x110,
+                "expected VFP registers to be at offset 272");
+  memcpy(_vectorHalfRegisters,
+         static_cast<const uint8_t *>(registers) + sizeof(GPRs),
+         sizeof(_vectorHalfRegisters));
+}
+
+inline Registers_arm64::Registers_arm64() {
+  memset(&_registers, 0, sizeof(_registers));
+  memset(&_vectorHalfRegisters, 0, sizeof(_vectorHalfRegisters));
+}
+
+inline bool Registers_arm64::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum > 95)
+    return false;
+  if ((regNum > 31) && (regNum < 64))
+    return false;
+  return true;
+}
+
+inline uint64_t Registers_arm64::getRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return _registers.__pc;
+  if (regNum == UNW_REG_SP)
+    return _registers.__sp;
+  if ((regNum >= 0) && (regNum < 32))
+    return _registers.__x[regNum];
+  _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
+  if (regNum == UNW_REG_IP)
+    _registers.__pc = value;
+  else if (regNum == UNW_REG_SP)
+    _registers.__sp = value;
+  else if ((regNum >= 0) && (regNum < 32))
+    _registers.__x[regNum] = value;
+  else
+    _LIBUNWIND_ABORT("unsupported arm64 register");
+}
+
+inline const char *Registers_arm64::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "pc";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_ARM64_X0:
+    return "x0";
+  case UNW_ARM64_X1:
+    return "x1";
+  case UNW_ARM64_X2:
+    return "x2";
+  case UNW_ARM64_X3:
+    return "x3";
+  case UNW_ARM64_X4:
+    return "x4";
+  case UNW_ARM64_X5:
+    return "x5";
+  case UNW_ARM64_X6:
+    return "x6";
+  case UNW_ARM64_X7:
+    return "x7";
+  case UNW_ARM64_X8:
+    return "x8";
+  case UNW_ARM64_X9:
+    return "x9";
+  case UNW_ARM64_X10:
+    return "x10";
+  case UNW_ARM64_X11:
+    return "x11";
+  case UNW_ARM64_X12:
+    return "x12";
+  case UNW_ARM64_X13:
+    return "x13";
+  case UNW_ARM64_X14:
+    return "x14";
+  case UNW_ARM64_X15:
+    return "x15";
+  case UNW_ARM64_X16:
+    return "x16";
+  case UNW_ARM64_X17:
+    return "x17";
+  case UNW_ARM64_X18:
+    return "x18";
+  case UNW_ARM64_X19:
+    return "x19";
+  case UNW_ARM64_X20:
+    return "x20";
+  case UNW_ARM64_X21:
+    return "x21";
+  case UNW_ARM64_X22:
+    return "x22";
+  case UNW_ARM64_X23:
+    return "x23";
+  case UNW_ARM64_X24:
+    return "x24";
+  case UNW_ARM64_X25:
+    return "x25";
+  case UNW_ARM64_X26:
+    return "x26";
+  case UNW_ARM64_X27:
+    return "x27";
+  case UNW_ARM64_X28:
+    return "x28";
+  case UNW_ARM64_X29:
+    return "fp";
+  case UNW_ARM64_X30:
+    return "lr";
+  case UNW_ARM64_X31:
+    return "sp";
+  case UNW_ARM64_D0:
+    return "d0";
+  case UNW_ARM64_D1:
+    return "d1";
+  case UNW_ARM64_D2:
+    return "d2";
+  case UNW_ARM64_D3:
+    return "d3";
+  case UNW_ARM64_D4:
+    return "d4";
+  case UNW_ARM64_D5:
+    return "d5";
+  case UNW_ARM64_D6:
+    return "d6";
+  case UNW_ARM64_D7:
+    return "d7";
+  case UNW_ARM64_D8:
+    return "d8";
+  case UNW_ARM64_D9:
+    return "d9";
+  case UNW_ARM64_D10:
+    return "d10";
+  case UNW_ARM64_D11:
+    return "d11";
+  case UNW_ARM64_D12:
+    return "d12";
+  case UNW_ARM64_D13:
+    return "d13";
+  case UNW_ARM64_D14:
+    return "d14";
+  case UNW_ARM64_D15:
+    return "d15";
+  case UNW_ARM64_D16:
+    return "d16";
+  case UNW_ARM64_D17:
+    return "d17";
+  case UNW_ARM64_D18:
+    return "d18";
+  case UNW_ARM64_D19:
+    return "d19";
+  case UNW_ARM64_D20:
+    return "d20";
+  case UNW_ARM64_D21:
+    return "d21";
+  case UNW_ARM64_D22:
+    return "d22";
+  case UNW_ARM64_D23:
+    return "d23";
+  case UNW_ARM64_D24:
+    return "d24";
+  case UNW_ARM64_D25:
+    return "d25";
+  case UNW_ARM64_D26:
+    return "d26";
+  case UNW_ARM64_D27:
+    return "d27";
+  case UNW_ARM64_D28:
+    return "d28";
+  case UNW_ARM64_D29:
+    return "d29";
+  case UNW_ARM64_D30:
+    return "d30";
+  case UNW_ARM64_D31:
+    return "d31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_arm64::validFloatRegister(int regNum) const {
+  if (regNum < UNW_ARM64_D0)
+    return false;
+  if (regNum > UNW_ARM64_D31)
+    return false;
+  return true;
+}
+
+inline double Registers_arm64::getFloatRegister(int regNum) const {
+  assert(validFloatRegister(regNum));
+  return _vectorHalfRegisters[regNum - UNW_ARM64_D0];
+}
+
+inline void Registers_arm64::setFloatRegister(int regNum, double value) {
+  assert(validFloatRegister(regNum));
+  _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value;
+}
+
+inline bool Registers_arm64::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_arm64::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+
+inline void Registers_arm64::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no arm64 vector register support yet");
+}
+
+/// Registers_arm holds the register state of a thread in a 32-bit arm
+/// process.
+///
+/// NOTE: Assumes VFPv3. On ARM processors without a floating point unit,
+/// this uses more memory than required.
+class _LIBUNWIND_HIDDEN Registers_arm {
+public:
+  Registers_arm();
+  Registers_arm(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num);
+  void        setRegister(int num, uint32_t value);
+  bool        validFloatRegister(int num) const;
+  unw_fpreg_t getFloatRegister(int num);
+  void        setFloatRegister(int num, unw_fpreg_t value);
+  bool        validVectorRegister(int num) const;
+  v128        getVectorRegister(int num) const;
+  void        setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void        jumpto() {
+    restoreSavedFloatRegisters();
+    restoreCoreAndJumpTo();
+  }
+
+  uint32_t  getSP() const         { return _registers.__sp; }
+  void      setSP(uint32_t value) { _registers.__sp = value; }
+  uint32_t  getIP() const         { return _registers.__pc; }
+  void      setIP(uint32_t value) { _registers.__pc = value; }
+
+  void saveVFPAsX() {
+    assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
+    _use_X_for_vfp_save = true;
+  }
+
+  void restoreSavedFloatRegisters() {
+    if (_saved_vfp_d0_d15) {
+      if (_use_X_for_vfp_save)
+        restoreVFPWithFLDMX(_vfp_d0_d15_pad);
+      else
+        restoreVFPWithFLDMD(_vfp_d0_d15_pad);
+    }
+    if (_saved_vfp_d16_d31)
+      restoreVFPv3(_vfp_d16_d31);
+    if (_saved_iwmmx)
+      restoreiWMMX(_iwmmx);
+    if (_saved_iwmmx_control)
+      restoreiWMMXControl(_iwmmx_control);
+  }
+
+private:
+  struct GPRs {
+    uint32_t __r[13]; // r0-r12
+    uint32_t __sp;    // Stack pointer r13
+    uint32_t __lr;    // Link register r14
+    uint32_t __pc;    // Program counter r15
+  };
+
+  static void saveVFPWithFSTMD(unw_fpreg_t*);
+  static void saveVFPWithFSTMX(unw_fpreg_t*);
+  static void saveVFPv3(unw_fpreg_t*);
+  static void saveiWMMX(unw_fpreg_t*);
+  static void saveiWMMXControl(uint32_t*);
+  static void restoreVFPWithFLDMD(unw_fpreg_t*);
+  static void restoreVFPWithFLDMX(unw_fpreg_t*);
+  static void restoreVFPv3(unw_fpreg_t*);
+  static void restoreiWMMX(unw_fpreg_t*);
+  static void restoreiWMMXControl(uint32_t*);
+  void restoreCoreAndJumpTo();
+
+  // ARM registers
+  GPRs _registers;
+
+  // We save floating point registers lazily because we can't know ahead of
+  // time which ones are used. See EHABI #4.7.
+
+  // Whether D0-D15 are saved in the FTSMX instead of FSTMD format.
+  //
+  // See EHABI #7.5 that explains how matching instruction sequences for load
+  // and store need to be used to correctly restore the exact register bits.
+  bool _use_X_for_vfp_save;
+  // Whether VFP D0-D15 are saved.
+  bool _saved_vfp_d0_d15;
+  // Whether VFPv3 D16-D31 are saved.
+  bool _saved_vfp_d16_d31;
+  // Whether iWMMX data registers are saved.
+  bool _saved_iwmmx;
+  // Whether iWMMX control registers are saved.
+  bool _saved_iwmmx_control;
+  // VFP registers D0-D15, + padding if saved using FSTMX
+  unw_fpreg_t _vfp_d0_d15_pad[17];
+  // VFPv3 registers D16-D31, always saved using FSTMD
+  unw_fpreg_t _vfp_d16_d31[16];
+  // iWMMX registers
+  unw_fpreg_t _iwmmx[16];
+  // iWMMX control registers
+  uint32_t _iwmmx_control[4];
+};
+
+inline Registers_arm::Registers_arm(const void *registers)
+  : _use_X_for_vfp_save(false),
+    _saved_vfp_d0_d15(false),
+    _saved_vfp_d16_d31(false),
+    _saved_iwmmx(false),
+    _saved_iwmmx_control(false) {
+  static_assert(sizeof(Registers_arm) < sizeof(unw_context_t),
+                    "arm registers do not fit into unw_context_t");
+  // See unw_getcontext() note about data.
+  memcpy(&_registers, registers, sizeof(_registers));
+  memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
+  memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
+  memset(&_iwmmx, 0, sizeof(_iwmmx));
+  memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+}
+
+inline Registers_arm::Registers_arm()
+  : _use_X_for_vfp_save(false),
+    _saved_vfp_d0_d15(false),
+    _saved_vfp_d16_d31(false),
+    _saved_iwmmx(false),
+    _saved_iwmmx_control(false) {
+  memset(&_registers, 0, sizeof(_registers));
+  memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
+  memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
+  memset(&_iwmmx, 0, sizeof(_iwmmx));
+  memset(&_iwmmx_control, 0, sizeof(_iwmmx_control));
+}
+
+inline bool Registers_arm::validRegister(int regNum) const {
+  // Returns true for all non-VFP registers supported by the EHABI
+  // virtual register set (VRS).
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15)
+    return true;
+  if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3)
+    return true;
+  return false;
+}
+
+inline uint32_t Registers_arm::getRegister(int regNum) {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    return _registers.__sp;
+  if (regNum == UNW_ARM_LR)
+    return _registers.__lr;
+  if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    return _registers.__pc;
+  if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
+    return _registers.__r[regNum];
+  if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+    if (!_saved_iwmmx_control) {
+      _saved_iwmmx_control = true;
+      saveiWMMXControl(_iwmmx_control);
+    }
+    return _iwmmx_control[regNum - UNW_ARM_WC0];
+  }
+  _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline void Registers_arm::setRegister(int regNum, uint32_t value) {
+  if (regNum == UNW_REG_SP || regNum == UNW_ARM_SP)
+    _registers.__sp = value;
+  else if (regNum == UNW_ARM_LR)
+    _registers.__lr = value;
+  else if (regNum == UNW_REG_IP || regNum == UNW_ARM_IP)
+    _registers.__pc = value;
+  else if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R12)
+    _registers.__r[regNum] = value;
+  else if (regNum >= UNW_ARM_WC0 && regNum <= UNW_ARM_WC3) {
+    if (!_saved_iwmmx_control) {
+      _saved_iwmmx_control = true;
+      saveiWMMXControl(_iwmmx_control);
+    }
+    _iwmmx_control[regNum - UNW_ARM_WC0] = value;
+  } else
+    _LIBUNWIND_ABORT("unsupported arm register");
+}
+
+inline const char *Registers_arm::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+  case UNW_ARM_IP: // UNW_ARM_R15 is alias
+    return "pc";
+  case UNW_ARM_LR: // UNW_ARM_R14 is alias
+    return "lr";
+  case UNW_REG_SP:
+  case UNW_ARM_SP: // UNW_ARM_R13 is alias
+    return "sp";
+  case UNW_ARM_R0:
+    return "r0";
+  case UNW_ARM_R1:
+    return "r1";
+  case UNW_ARM_R2:
+    return "r2";
+  case UNW_ARM_R3:
+    return "r3";
+  case UNW_ARM_R4:
+    return "r4";
+  case UNW_ARM_R5:
+    return "r5";
+  case UNW_ARM_R6:
+    return "r6";
+  case UNW_ARM_R7:
+    return "r7";
+  case UNW_ARM_R8:
+    return "r8";
+  case UNW_ARM_R9:
+    return "r9";
+  case UNW_ARM_R10:
+    return "r10";
+  case UNW_ARM_R11:
+    return "r11";
+  case UNW_ARM_R12:
+    return "r12";
+  case UNW_ARM_S0:
+    return "s0";
+  case UNW_ARM_S1:
+    return "s1";
+  case UNW_ARM_S2:
+    return "s2";
+  case UNW_ARM_S3:
+    return "s3";
+  case UNW_ARM_S4:
+    return "s4";
+  case UNW_ARM_S5:
+    return "s5";
+  case UNW_ARM_S6:
+    return "s6";
+  case UNW_ARM_S7:
+    return "s7";
+  case UNW_ARM_S8:
+    return "s8";
+  case UNW_ARM_S9:
+    return "s9";
+  case UNW_ARM_S10:
+    return "s10";
+  case UNW_ARM_S11:
+    return "s11";
+  case UNW_ARM_S12:
+    return "s12";
+  case UNW_ARM_S13:
+    return "s13";
+  case UNW_ARM_S14:
+    return "s14";
+  case UNW_ARM_S15:
+    return "s15";
+  case UNW_ARM_S16:
+    return "s16";
+  case UNW_ARM_S17:
+    return "s17";
+  case UNW_ARM_S18:
+    return "s18";
+  case UNW_ARM_S19:
+    return "s19";
+  case UNW_ARM_S20:
+    return "s20";
+  case UNW_ARM_S21:
+    return "s21";
+  case UNW_ARM_S22:
+    return "s22";
+  case UNW_ARM_S23:
+    return "s23";
+  case UNW_ARM_S24:
+    return "s24";
+  case UNW_ARM_S25:
+    return "s25";
+  case UNW_ARM_S26:
+    return "s26";
+  case UNW_ARM_S27:
+    return "s27";
+  case UNW_ARM_S28:
+    return "s28";
+  case UNW_ARM_S29:
+    return "s29";
+  case UNW_ARM_S30:
+    return "s30";
+  case UNW_ARM_S31:
+    return "s31";
+  case UNW_ARM_D0:
+    return "d0";
+  case UNW_ARM_D1:
+    return "d1";
+  case UNW_ARM_D2:
+    return "d2";
+  case UNW_ARM_D3:
+    return "d3";
+  case UNW_ARM_D4:
+    return "d4";
+  case UNW_ARM_D5:
+    return "d5";
+  case UNW_ARM_D6:
+    return "d6";
+  case UNW_ARM_D7:
+    return "d7";
+  case UNW_ARM_D8:
+    return "d8";
+  case UNW_ARM_D9:
+    return "d9";
+  case UNW_ARM_D10:
+    return "d10";
+  case UNW_ARM_D11:
+    return "d11";
+  case UNW_ARM_D12:
+    return "d12";
+  case UNW_ARM_D13:
+    return "d13";
+  case UNW_ARM_D14:
+    return "d14";
+  case UNW_ARM_D15:
+    return "d15";
+  case UNW_ARM_D16:
+    return "d16";
+  case UNW_ARM_D17:
+    return "d17";
+  case UNW_ARM_D18:
+    return "d18";
+  case UNW_ARM_D19:
+    return "d19";
+  case UNW_ARM_D20:
+    return "d20";
+  case UNW_ARM_D21:
+    return "d21";
+  case UNW_ARM_D22:
+    return "d22";
+  case UNW_ARM_D23:
+    return "d23";
+  case UNW_ARM_D24:
+    return "d24";
+  case UNW_ARM_D25:
+    return "d25";
+  case UNW_ARM_D26:
+    return "d26";
+  case UNW_ARM_D27:
+    return "d27";
+  case UNW_ARM_D28:
+    return "d28";
+  case UNW_ARM_D29:
+    return "d29";
+  case UNW_ARM_D30:
+    return "d30";
+  case UNW_ARM_D31:
+    return "d31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_arm::validFloatRegister(int regNum) const {
+  // NOTE: Consider the intel MMX registers floating points so the
+  // unw_get_fpreg can be used to transmit the 64-bit data back.
+  return ((regNum >= UNW_ARM_D0) && (regNum <= UNW_ARM_D31))
+      || ((regNum >= UNW_ARM_WR0) && (regNum <= UNW_ARM_WR15));
+}
+
+inline unw_fpreg_t Registers_arm::getFloatRegister(int regNum) {
+  if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) {
+    if (!_saved_vfp_d0_d15) {
+      _saved_vfp_d0_d15 = true;
+      if (_use_X_for_vfp_save)
+        saveVFPWithFSTMX(_vfp_d0_d15_pad);
+      else
+        saveVFPWithFSTMD(_vfp_d0_d15_pad);
+    }
+    return _vfp_d0_d15_pad[regNum - UNW_ARM_D0];
+  } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
+    if (!_saved_vfp_d16_d31) {
+      _saved_vfp_d16_d31 = true;
+      saveVFPv3(_vfp_d16_d31);
+    }
+    return _vfp_d16_d31[regNum - UNW_ARM_D16];
+  } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+    if (!_saved_iwmmx) {
+      _saved_iwmmx = true;
+      saveiWMMX(_iwmmx);
+    }
+    return _iwmmx[regNum - UNW_ARM_WR0];
+  } else {
+    _LIBUNWIND_ABORT("Unknown ARM float register");
+  }
+}
+
+inline void Registers_arm::setFloatRegister(int regNum, unw_fpreg_t value) {
+  if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D15) {
+    if (!_saved_vfp_d0_d15) {
+      _saved_vfp_d0_d15 = true;
+      if (_use_X_for_vfp_save)
+        saveVFPWithFSTMX(_vfp_d0_d15_pad);
+      else
+        saveVFPWithFSTMD(_vfp_d0_d15_pad);
+    }
+    _vfp_d0_d15_pad[regNum - UNW_ARM_D0] = value;
+  } else if (regNum >= UNW_ARM_D16 && regNum <= UNW_ARM_D31) {
+    if (!_saved_vfp_d16_d31) {
+      _saved_vfp_d16_d31 = true;
+      saveVFPv3(_vfp_d16_d31);
+    }
+    _vfp_d16_d31[regNum - UNW_ARM_D0] = value;
+  } else if (regNum >= UNW_ARM_WR0 && regNum <= UNW_ARM_WR15) {
+    if (!_saved_iwmmx) {
+      _saved_iwmmx = true;
+      saveiWMMX(_iwmmx);
+    }
+    _iwmmx[regNum - UNW_ARM_WR0] = value;
+  } else {
+    _LIBUNWIND_ABORT("Unknown ARM float register");
+  }
+}
+
+inline bool Registers_arm::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_arm::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+inline void Registers_arm::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("ARM vector support not implemented");
+}
+
+} // namespace libunwind
+
+#endif // __REGISTERS_HPP__