diff options
| author | matt <matt@NetBSD.org> | 2014-01-29 06:59:53 +0000 |
|---|---|---|
| committer | matt <matt@NetBSD.org> | 2014-01-29 06:59:53 +0000 |
| commit | eb98b3ccf715d74c845866a706eb78e2bdfd7d79 (patch) | |
| tree | 924fef3de3c41c4a2958b3bdb46557f68b1301d4 /sys/lib/libunwind | |
| parent | 1810d42d6506c46c1c5084ff7a2a4ccdfc4dfe49 (diff) | |
Add support for non-EABI (DWARF) ARM exception handling.
Diffstat (limited to 'sys/lib/libunwind')
| -rw-r--r-- | sys/lib/libunwind/Registers.hpp | 72 | ||||
| -rw-r--r-- | sys/lib/libunwind/libunwind.cxx | 2 | ||||
| -rw-r--r-- | sys/lib/libunwind/unwind_registers.S | 20 |
3 files changed, 94 insertions, 0 deletions
diff --git a/sys/lib/libunwind/Registers.hpp b/sys/lib/libunwind/Registers.hpp index dc18d076bf3..4408ecaa48c 100644 --- a/sys/lib/libunwind/Registers.hpp +++ b/sys/lib/libunwind/Registers.hpp @@ -229,6 +229,78 @@ private: vecreg_t vecreg[64]; }; +enum { + DWARF_ARM32_R0 = 0, + DWARF_ARM32_R15 = 15, + DWARF_ARM32_SPSR = 128, + DWARF_ARM32_D0 = 256, // VFP-v3/Neon + DWARF_ARM32_D31 = 287, + REGNO_ARM32_R0 = 0, + REGNO_ARM32_SP = 13, + REGNO_ARM32_R15 = 15, + REGNO_ARM32_SPSR = 16, + REGNO_ARM32_D0 = 0, + REGNO_ARM32_D31 = 31, +}; + +class Registers_arm32 { +public: + enum { + LAST_RESTORE_REG = REGNO_ARM32_SPSR, + IP_PSEUDO_REG = REGNO_ARM32_SPSR, + LAST_REGISTER = REGNO_ARM32_D31, + }; + + __dso_hidden Registers_arm32(); + + static int dwarf2regno(int num) { + if (num >= DWARF_ARM32_R0 && num <= DWARF_ARM32_R15) + return REGNO_ARM32_R0 + (num - DWARF_ARM32_R0); + if (num >= DWARF_ARM32_D0 && num <= DWARF_ARM32_D31) + return REGNO_ARM32_D0 + (num - DWARF_ARM32_D0); + if (num == DWARF_ARM32_SPSR) + return REGNO_ARM32_SPSR; + return LAST_REGISTER + 1; + } + + bool validRegister(int num) const { + return num >= 0 && num <= LAST_RESTORE_REG; + } + + uint64_t getRegister(int num) const { + assert(validRegister(num)); + return reg[num]; + } + + void setRegister(int num, uint64_t value) { + assert(validRegister(num)); + reg[num] = value; + } + + uint64_t getIP() const { return reg[REGNO_ARM32_R15]; } + + void setIP(uint64_t value) { reg[REGNO_ARM32_R15] = value; } + + uint64_t getSP() const { return reg[REGNO_ARM32_SP]; } + + void setSP(uint64_t value) { reg[REGNO_ARM32_SP] = value; } + + bool validFloatVectorRegister(int num) const { + return (num >= REGNO_ARM32_D0 && num <= REGNO_ARM32_D31); + } + + void copyFloatVectorRegister(int num, uint64_t addr_) { + const void *addr = reinterpret_cast<const void *>(addr_); + memcpy(fpreg + (num - REGNO_ARM32_D0), addr, sizeof(fpreg[0])); + } + + __dso_hidden void jumpto() const __dead; + +private: + uint32_t reg[REGNO_ARM32_SPSR + 1]; + uint64_t fpreg[32]; +}; + } // namespace _Unwind #endif // __REGISTERS_HPP__ diff --git a/sys/lib/libunwind/libunwind.cxx b/sys/lib/libunwind/libunwind.cxx index 30f579e86f6..87a18cc119f 100644 --- a/sys/lib/libunwind/libunwind.cxx +++ b/sys/lib/libunwind/libunwind.cxx @@ -23,6 +23,8 @@ typedef Registers_x86 ThisUnwindRegisters; typedef Registers_x86_64 ThisUnwindRegisters; #elif __powerpc__ typedef Registers_ppc32 ThisUnwindRegisters; +#elif __arm__ && !defined(__ARM_EABI__) +typedef Registers_arm32 ThisUnwindRegisters; #else #error Unsupported architecture #endif diff --git a/sys/lib/libunwind/unwind_registers.S b/sys/lib/libunwind/unwind_registers.S index b87f1638015..b7fd0b02bfe 100644 --- a/sys/lib/libunwind/unwind_registers.S +++ b/sys/lib/libunwind/unwind_registers.S @@ -210,3 +210,23 @@ ENTRY(_ZNK7_Unwind15Registers_ppc326jumptoEv) lwz %r3,12(%r3) /* do r3 last */ bctr #endif + +#if defined(__arm__) && !defined(__ARM_EABI__) + .hidden _ZN7_Unwind15Registers_arm32C1Ev +ENTRY(_ZN7_Unwind15Registers_arm32C1Ev) + stmia r0, {r0-r14} + + str lr, [r0, #60] /* PC */ + mrs r1, cpsr + str r1, [r0, #64] /* CPSR */ + + RET +END(_ZN7_Unwind15Registers_arm32C1Ev) + + .hidden _ZNK7_Unwind15Registers_arm326jumptoEv +ENTRY(_ZNK7_Unwind15Registers_arm326jumptoEv) + ldr r1, [r0, #64] + msr cpsr_sxc, r1 + ldmia r0, {r0-r15} +END(_ZNK7_Unwind15Registers_arm326jumptoEv) +#endif |
