summaryrefslogtreecommitdiff
path: root/libunwind
diff options
context:
space:
mode:
authorwhitequark <whitequark@whitequark.org>2018-05-16 19:09:41 +0000
committerwhitequark <whitequark@whitequark.org>2018-05-16 19:09:41 +0000
commit0bef15323814ab227b1ef3e120ab6f2fefb27bd1 (patch)
treea34b377642a677f1bd1283c7610d4b3824fc5ebc /libunwind
parent3f1b0d5711b6d40fde1aa2c5408fbf8cf2e652fe (diff)
[OR1K] Add a dedicated PC register to register state.
Before this commit, R9, the link register, was used as PC register. However, a stack frame may have R9 not set to PC on entry, either because it uses a custom calling convention, or, more likely, because this is a signal or exception stack frame. Using R9 as PC register made it impossible to unwind such frames. All other architectures similarly use a dedicated PC register.
Diffstat (limited to 'libunwind')
-rw-r--r--libunwind/src/Registers.hpp11
-rw-r--r--libunwind/src/UnwindRegistersRestore.S6
-rw-r--r--libunwind/src/UnwindRegistersSave.S2
3 files changed, 12 insertions, 7 deletions
diff --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 3817d82f583..f736ded9383 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -2521,12 +2521,13 @@ public:
uint64_t getSP() const { return _registers.__r[1]; }
void setSP(uint32_t value) { _registers.__r[1] = value; }
- uint64_t getIP() const { return _registers.__r[9]; }
- void setIP(uint32_t value) { _registers.__r[9] = value; }
+ uint64_t getIP() const { return _registers.__pc; }
+ void setIP(uint32_t value) { _registers.__pc = value; }
private:
struct or1k_thread_state_t {
- unsigned int __r[32];
+ unsigned int __r[32]; // r0-r31
+ unsigned int __pc; // Program counter
};
or1k_thread_state_t _registers;
@@ -2561,7 +2562,7 @@ inline uint32_t Registers_or1k::getRegister(int regNum) const {
switch (regNum) {
case UNW_REG_IP:
- return _registers.__r[9];
+ return _registers.__pc;
case UNW_REG_SP:
return _registers.__r[1];
}
@@ -2576,7 +2577,7 @@ inline void Registers_or1k::setRegister(int regNum, uint32_t value) {
switch (regNum) {
case UNW_REG_IP:
- _registers.__r[9] = value;
+ _registers.__pc = value;
return;
case UNW_REG_SP:
_registers.__r[1] = value;
diff --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index e0bf61e685d..d425d1c7d20 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -758,7 +758,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
# thread_state pointer is in r3
#
- # restore integral registerrs
+ # restore integral registers
l.lwz r0, 0(r3)
l.lwz r1, 4(r3)
l.lwz r2, 8(r3)
@@ -768,7 +768,7 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
l.lwz r6, 24(r3)
l.lwz r7, 28(r3)
l.lwz r8, 32(r3)
- l.lwz r9, 36(r3)
+ # skip r9
l.lwz r10, 40(r3)
l.lwz r11, 44(r3)
l.lwz r12, 48(r3)
@@ -795,6 +795,8 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
# at last, restore r3
l.lwz r3, 12(r3)
+ # load new pc into ra
+ l.lwz r9, 128(r3)
# jump to pc
l.jr r9
l.nop
diff --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index ac925d94c26..34f9205bfb0 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -938,6 +938,8 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
l.sw 116(r3), r29
l.sw 120(r3), r30
l.sw 124(r3), r31
+ # store ra to pc
+ l.sw 128(r3), r9
#endif
#endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */