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__