summaryrefslogtreecommitdiff
path: root/sys/lib/libunwind
diff options
context:
space:
mode:
authormatt <matt@NetBSD.org>2014-01-29 06:59:53 +0000
committermatt <matt@NetBSD.org>2014-01-29 06:59:53 +0000
commiteb98b3ccf715d74c845866a706eb78e2bdfd7d79 (patch)
tree924fef3de3c41c4a2958b3bdb46557f68b1301d4 /sys/lib/libunwind
parent1810d42d6506c46c1c5084ff7a2a4ccdfc4dfe49 (diff)
Add support for non-EABI (DWARF) ARM exception handling.
Diffstat (limited to 'sys/lib/libunwind')
-rw-r--r--sys/lib/libunwind/Registers.hpp72
-rw-r--r--sys/lib/libunwind/libunwind.cxx2
-rw-r--r--sys/lib/libunwind/unwind_registers.S20
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