summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwhitequark <whitequark@whitequark.org>2018-05-16 19:09:48 +0000
committerwhitequark <whitequark@whitequark.org>2018-05-16 19:09:48 +0000
commit1e1c6b739595098ba5c466bfe9d58b993e646b48 (patch)
tree505e8d9327e6b69b62947fae659ca9639a5394bf
parent7549326b940948f617f3623c42299ee71b3027be (diff)
downloadlibunwind_llvm-1e1c6b739595098ba5c466bfe9d58b993e646b48.tar.gz
[OR1K] Add the EPCR special-purpose register to register state.
This makes it possible to unwind hardware exception stack frames, which necessarily save every register and so need an extra column for storing the return address. CFI for the exception handler could then look as follows: .globl exception_vector exception_vector: .cfi_startproc .cfi_signal_frame .cfi_return_column 32 l.addi r1, r1, -0x100 .cfi_def_cfa_offset 0x100 l.sw 0x00(r1), r2 .cfi_offset 2, 0x00-0x100 l.sw 0x04(r1), r3 .cfi_offset 3, 0x04-0x100 l.sw 0x08(r1), r4 .cfi_offset 4, 0x08-0x100 l.mfspr r3, r0, SPR_EPCR_BASE l.sw 0x78(r1), r3 .cfi_offset 32, 0x78-0x100 l.jal exception_handler l.nop l.lwz r2, 0x00(r1) l.lwz r3, 0x04(r1) l.lwz r4, 0x08(r1) l.jr r9 l.nop .cfi_endproc This register could, of course, also be accessed by the trace callback or personality function, if so desired. git-svn-id: https://llvm.org/svn/llvm-project/libunwind/trunk@332513 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/__libunwind_config.h2
-rw-r--r--include/libunwind.h1
-rw-r--r--src/Registers.hpp10
-rw-r--r--src/UnwindRegistersSave.S2
4 files changed, 14 insertions, 1 deletions
diff --git a/include/__libunwind_config.h b/include/__libunwind_config.h
index 584c570..5464e36 100644
--- a/include/__libunwind_config.h
+++ b/include/__libunwind_config.h
@@ -21,7 +21,7 @@
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64 116
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64 95
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM 287
-#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 31
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
#if defined(_LIBUNWIND_IS_NATIVE_ONLY)
diff --git a/include/libunwind.h b/include/libunwind.h
index 8e3d3fe..97d2b82 100644
--- a/include/libunwind.h
+++ b/include/libunwind.h
@@ -745,6 +745,7 @@ enum {
UNW_OR1K_R29 = 29,
UNW_OR1K_R30 = 30,
UNW_OR1K_R31 = 31,
+ UNW_OR1K_EPCR = 32,
};
// MIPS registers
diff --git a/src/Registers.hpp b/src/Registers.hpp
index f736ded..b20664a 100644
--- a/src/Registers.hpp
+++ b/src/Registers.hpp
@@ -2528,6 +2528,7 @@ private:
struct or1k_thread_state_t {
unsigned int __r[32]; // r0-r31
unsigned int __pc; // Program counter
+ unsigned int __epcr; // Program counter at exception
};
or1k_thread_state_t _registers;
@@ -2553,6 +2554,8 @@ inline bool Registers_or1k::validRegister(int regNum) const {
return false;
if (regNum <= UNW_OR1K_R31)
return true;
+ if (regNum == UNW_OR1K_EPCR)
+ return true;
return false;
}
@@ -2565,6 +2568,8 @@ inline uint32_t Registers_or1k::getRegister(int regNum) const {
return _registers.__pc;
case UNW_REG_SP:
return _registers.__r[1];
+ case UNW_OR1K_EPCR:
+ return _registers.__epcr;
}
_LIBUNWIND_ABORT("unsupported or1k register");
}
@@ -2582,6 +2587,9 @@ inline void Registers_or1k::setRegister(int regNum, uint32_t value) {
case UNW_REG_SP:
_registers.__r[1] = value;
return;
+ case UNW_OR1K_EPCR:
+ _registers.__epcr = value;
+ return;
}
_LIBUNWIND_ABORT("unsupported or1k register");
}
@@ -2677,6 +2685,8 @@ inline const char *Registers_or1k::getRegisterName(int regNum) {
return "r30";
case UNW_OR1K_R31:
return "r31";
+ case UNW_OR1K_EPCR:
+ return "EPCR";
default:
return "unknown register";
}
diff --git a/src/UnwindRegistersSave.S b/src/UnwindRegistersSave.S
index 34f9205..07db14b 100644
--- a/src/UnwindRegistersSave.S
+++ b/src/UnwindRegistersSave.S
@@ -940,6 +940,8 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
l.sw 124(r3), r31
# store ra to pc
l.sw 128(r3), r9
+ # zero epcr
+ l.sw 132(r3), r0
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */