diff options
author | whitequark <whitequark@whitequark.org> | 2018-05-16 19:09:41 +0000 |
---|---|---|
committer | whitequark <whitequark@whitequark.org> | 2018-05-16 19:09:41 +0000 |
commit | 3f948cd79de03e1256deea4ebaad63ca88ef8db8 (patch) | |
tree | 5c5858cba742d097a0488a78772ef1c017a17cdd /libunwind/src | |
parent | 4de94930c3ca2ebc4a680ac361cd07217714525d (diff) | |
download | bcm5719-llvm-3f948cd79de03e1256deea4ebaad63ca88ef8db8.tar.gz bcm5719-llvm-3f948cd79de03e1256deea4ebaad63ca88ef8db8.zip |
[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.
llvm-svn: 332512
Diffstat (limited to 'libunwind/src')
-rw-r--r-- | libunwind/src/Registers.hpp | 11 | ||||
-rw-r--r-- | libunwind/src/UnwindRegistersRestore.S | 6 | ||||
-rw-r--r-- | libunwind/src/UnwindRegistersSave.S | 2 |
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__) */ |