From 60f9c91b81c4e318101a49794c0f84f0961bd10a Mon Sep 17 00:00:00 2001 From: kettenis Date: Tue, 18 Apr 2017 15:35:24 +0000 Subject: [PATCH] Add sparc64 support. --- lib/libunwind/include/__libunwind_config.h | 5 + lib/libunwind/src/DwarfInstructions.hpp | 6 + lib/libunwind/src/DwarfParser.hpp | 13 ++ lib/libunwind/src/Registers.hpp | 150 +++++++++++++++++++++ lib/libunwind/src/UnwindCursor.hpp | 6 + lib/libunwind/src/UnwindRegistersRestore.S | 43 ++++++ lib/libunwind/src/UnwindRegistersSave.S | 53 ++++++++ lib/libunwind/src/libunwind.cpp | 2 + 8 files changed, 278 insertions(+) diff --git a/lib/libunwind/include/__libunwind_config.h b/lib/libunwind/include/__libunwind_config.h index a9d9958be05..112ff25fca5 100644 --- a/lib/libunwind/include/__libunwind_config.h +++ b/lib/libunwind/include/__libunwind_config.h @@ -53,6 +53,11 @@ # define _LIBUNWIND_CONTEXT_SIZE 16 # define _LIBUNWIND_CURSOR_SIZE 28 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 32 +# elif defined(__sparc__) && defined(__arch64__) +# define _LIBUNWIND_TARGET_SPARC64 1 +# define _LIBUNWIND_CONTEXT_SIZE 33 +# define _LIBUNWIND_CURSOR_SIZE 45 +# define _LIBUNWIND_HIGHEST_DWARF_REGISTER 32 # else # error "Unsupported architecture." # endif diff --git a/lib/libunwind/src/DwarfInstructions.hpp b/lib/libunwind/src/DwarfInstructions.hpp index ce90aa05f53..7fa62cd7bba 100644 --- a/lib/libunwind/src/DwarfInstructions.hpp +++ b/lib/libunwind/src/DwarfInstructions.hpp @@ -85,6 +85,10 @@ typename A::pint_t DwarfInstructions::getSavedRegister( case CFI_Parser::kRegisterInCFA: return addressSpace.getP(cfa + (pint_t)savedReg.value); + case CFI_Parser::kRegisterInCFADecrypt: + return addressSpace.getP( + cfa + (pint_t)savedReg.value) ^ registers.getWCookie(); + case CFI_Parser::kRegisterAtExpression: return addressSpace.getP( evaluateExpression((pint_t)savedReg.value, addressSpace, @@ -122,6 +126,7 @@ double DwarfInstructions::getSavedFloatRegister( case CFI_Parser::kRegisterUnused: case CFI_Parser::kRegisterOffsetFromCFA: case CFI_Parser::kRegisterInRegister: + case CFI_Parser::kRegisterInCFADecrypt: // FIX ME break; } @@ -145,6 +150,7 @@ v128 DwarfInstructions::getSavedVectorRegister( case CFI_Parser::kRegisterUnused: case CFI_Parser::kRegisterOffsetFromCFA: case CFI_Parser::kRegisterInRegister: + case CFI_Parser::kRegisterInCFADecrypt: // FIX ME break; } diff --git a/lib/libunwind/src/DwarfParser.hpp b/lib/libunwind/src/DwarfParser.hpp index 9618b116aef..2f8c2c6d1f9 100644 --- a/lib/libunwind/src/DwarfParser.hpp +++ b/lib/libunwind/src/DwarfParser.hpp @@ -67,6 +67,7 @@ public: enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, + kRegisterInCFADecrypt, kRegisterOffsetFromCFA, kRegisterInRegister, kRegisterAtExpression, @@ -664,6 +665,18 @@ bool CFI_Parser::parseInstructions(A &addressSpace, pint_t instructions, ", expression=0x%" PRIx64 ", length=%" PRIu64 ")\n", reg, results->savedRegisters[reg].value, length); break; + case DW_CFA_GNU_window_save: + // Hardcodes windowed registers for SPARC + for (reg = 16; reg < 32; reg++) { + if (reg == 31) + results->savedRegisters[reg].location = kRegisterInCFADecrypt; + else + results->savedRegisters[reg].location = kRegisterInCFA; + results->savedRegisters[reg].value = (reg - 16) * sizeof(pint_t); + } + if (logDwarf) + fprintf(stderr, "DW_CGA_GNU_window_save\n"); + break; case DW_CFA_GNU_args_size: length = addressSpace.getULEB128(p, instructionsEnd); results->spExtraArgSize = (uint32_t)length; diff --git a/lib/libunwind/src/Registers.hpp b/lib/libunwind/src/Registers.hpp index 8066b808c63..1a98d929e10 100644 --- a/lib/libunwind/src/Registers.hpp +++ b/lib/libunwind/src/Registers.hpp @@ -62,6 +62,7 @@ public: void setESI(uint32_t value) { _registers.__esi = value; } uint32_t getEDI() const { return _registers.__edi; } void setEDI(uint32_t value) { _registers.__edi = value; } + uint32_t getWCookie() const { return 0; } private: struct GPRs { @@ -252,6 +253,7 @@ public: void setR14(uint64_t value) { _registers.__r14 = value; } uint64_t getR15() const { return _registers.__r15; } void setR15(uint64_t value) { _registers.__r15 = value; } + uint64_t getWCookie() const { return 0; } private: struct GPRs { @@ -490,6 +492,7 @@ public: void setSP(uint32_t value) { _registers.__r1 = value; } uint64_t getIP() const { return _registers.__srr0; } void setIP(uint32_t value) { _registers.__srr0 = value; } + uint64_t getWCookie() const { return 0; } private: struct ppc_thread_state_t { @@ -1058,6 +1061,7 @@ public: void setIP(uint64_t value) { _registers.__pc = value; } uint64_t getFP() const { return _registers.__fp; } void setFP(uint64_t value) { _registers.__fp = value; } + uint64_t getWCookie() const { return 0; } private: struct GPRs { @@ -1328,6 +1332,7 @@ public: void setSP(uint32_t value) { _registers.__sp = value; } uint32_t getIP() const { return _registers.__pc; } void setIP(uint32_t value) { _registers.__pc = value; } + uint64_t getWCookie() const { return 0; } void saveVFPAsX() { assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15); @@ -1805,6 +1810,7 @@ public: 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 getWCookie() const { return 0; } private: struct or1k_thread_state_t { @@ -1964,6 +1970,150 @@ inline const char *Registers_or1k::getRegisterName(int regNum) { } #endif // _LIBUNWIND_TARGET_OR1K + + +#if defined(_LIBUNWIND_TARGET_SPARC64) +/// Registers_sparc64 holds the register state of a thread in a 64-bit +/// sparc process. +class _LIBUNWIND_HIDDEN Registers_sparc64 { +public: + Registers_sparc64(); + Registers_sparc64(const void *registers); + + bool validRegister(int num) const; + uint64_t getRegister(int num) const; + void setRegister(int num, uint64_t value); + bool validFloatRegister(int num) const; + double getFloatRegister(int num) const; + void setFloatRegister(int num, double value); + bool validVectorRegister(int num) const; + v128 getVectorRegister(int num) const; + void setVectorRegister(int num, v128 value); + const char *getRegisterName(int num); + void jumpto(); + static int lastDwarfRegNum() { return 31; } + + uint64_t getSP() const { return _registers.__o[6] + 2047; } + void setSP(uint64_t value) { _registers.__o[6] = value - 2047; } + uint64_t getIP() const { return _registers.__o[7]; } + void setIP(uint64_t value) { _registers.__o[7] = value; } + uint64_t getWCookie() const { return _wcookie; } + +private: + struct GPRs { + uint64_t __g[8]; + uint64_t __o[8]; + uint64_t __l[8]; + uint64_t __i[8]; + }; + + GPRs _registers; + uint64_t _wcookie; +}; + +inline Registers_sparc64::Registers_sparc64(const void *registers) { + static_assert((check_fit::does_fit), + "sparc64 registers do not fit into unw_context_t"); + memcpy(&_registers, static_cast(registers), + sizeof(_registers)); + memcpy(&_wcookie, static_cast(registers) + sizeof(GPRs), + sizeof(_wcookie)); +} + +inline Registers_sparc64::Registers_sparc64() { + memset(&_registers, 0, sizeof(_registers)); + _wcookie = 0; +} + +inline bool Registers_sparc64::validRegister(int regNum) const { + if (regNum == UNW_REG_IP) + return true; + if (regNum == UNW_REG_SP) + return true; + if (regNum < 0) + return false; + if (regNum <= 31) + return true; + return false; +} + +inline uint64_t Registers_sparc64::getRegister(int regNum) const { + if (regNum >= 0 && regNum <= 7) + return _registers.__g[regNum - 0]; + if (regNum >= 8 && regNum <= 15) + return _registers.__o[regNum - 8]; + if (regNum >= 16 && regNum <= 23) + return _registers.__l[regNum - 16]; + if (regNum >= 24 && regNum <= 31) + return _registers.__i[regNum - 24]; + + switch (regNum) { + case UNW_REG_IP: + return _registers.__o[7]; + case UNW_REG_SP: + return _registers.__o[6] + 2047; + } + _LIBUNWIND_ABORT("unsupported sparc64 register"); +} + +inline void Registers_sparc64::setRegister(int regNum, uint64_t value) { + if (regNum >= 0 && regNum <= 7) { + _registers.__g[regNum - 0] = value; + return; + } + if (regNum >= 8 && regNum <= 15) { + _registers.__o[regNum - 8] = value; + return; + } + if (regNum >= 16 && regNum <= 23) { + _registers.__l[regNum - 16] = value; + return; + } + if (regNum >= 24 && regNum <= 31) { + _registers.__i[regNum - 24] = value; + return; + } + + switch (regNum) { + case UNW_REG_IP: + _registers.__o[7] = value; + return; + case UNW_REG_SP: + _registers.__o[6] = value - 2047; + return; + } + _LIBUNWIND_ABORT("unsupported sparc64 register"); +} + +inline bool Registers_sparc64::validFloatRegister(int) const { + return false; +} + +inline double Registers_sparc64::getFloatRegister(int) const { + _LIBUNWIND_ABORT("no sparc64 float registers"); +} + +inline void Registers_sparc64::setFloatRegister(int, double) { + _LIBUNWIND_ABORT("no sparc64 float registers"); +} + +inline bool Registers_sparc64::validVectorRegister(int) const { + return false; +} + +inline v128 Registers_sparc64::getVectorRegister(int) const { + _LIBUNWIND_ABORT("no sparc64 vector registers"); +} + +inline void Registers_sparc64::setVectorRegister(int, v128) { + _LIBUNWIND_ABORT("no sparc64 vector registers"); +} + +inline const char *Registers_sparc64::getRegisterName(int regNum) { + return "unknown register"; +} + +#endif // _LIBUNWIND_TARGET_SPARC64 } // namespace libunwind #endif // __REGISTERS_HPP__ diff --git a/lib/libunwind/src/UnwindCursor.hpp b/lib/libunwind/src/UnwindCursor.hpp index 18a780919b1..52f3347eb3e 100644 --- a/lib/libunwind/src/UnwindCursor.hpp +++ b/lib/libunwind/src/UnwindCursor.hpp @@ -588,6 +588,12 @@ private: return 0; } #endif + +#if defined (_LIBUNWIND_TARGET_SPARC64) + compact_unwind_encoding_t dwarfEncoding(Registers_sparc64 &) const { + return 0; + } +#endif #endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND diff --git a/lib/libunwind/src/UnwindRegistersRestore.S b/lib/libunwind/src/UnwindRegistersRestore.S index b2f6914a79f..3b185aa3e10 100644 --- a/lib/libunwind/src/UnwindRegistersRestore.S +++ b/lib/libunwind/src/UnwindRegistersRestore.S @@ -478,6 +478,49 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv) l.jr r9 l.nop +#elif defined(__sparc__) && defined(__arch64__) + +DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv) +# +# void libunwind::Registers_sparc64::jumpto() +# +# On entry: +# thread_state pointer is in %o0 +# + flushw + ldx [%o0 + 0x08], %g1 + ldx [%o0 + 0x10], %g2 + ldx [%o0 + 0x18], %g3 + ldx [%o0 + 0x20], %g4 + ldx [%o0 + 0x28], %g5 + ldx [%o0 + 0x30], %g6 + ldx [%o0 + 0x38], %g7 + ldx [%o0 + 0x48], %o1 + ldx [%o0 + 0x50], %o2 + ldx [%o0 + 0x58], %o3 + ldx [%o0 + 0x60], %o4 + ldx [%o0 + 0x68], %o5 + ldx [%o0 + 0x70], %o6 + ldx [%o0 + 0x78], %o7 + ldx [%o0 + 0x80], %l0 + ldx [%o0 + 0x88], %l1 + ldx [%o0 + 0x90], %l2 + ldx [%o0 + 0x98], %l3 + ldx [%o0 + 0xa0], %l4 + ldx [%o0 + 0xa8], %l5 + ldx [%o0 + 0xb0], %l6 + ldx [%o0 + 0xb8], %l7 + ldx [%o0 + 0xc0], %i0 + ldx [%o0 + 0xc8], %i1 + ldx [%o0 + 0xd0], %i2 + ldx [%o0 + 0xd8], %i3 + ldx [%o0 + 0xe0], %i4 + ldx [%o0 + 0xe8], %i5 + ldx [%o0 + 0xf0], %i6 + ldx [%o0 + 0xf8], %i7 + jmpl %o7, %g0 + ldx [%o0 + 0x40], %o0 + #endif NO_EXEC_STACK_DIRECTIVE diff --git a/lib/libunwind/src/UnwindRegistersSave.S b/lib/libunwind/src/UnwindRegistersSave.S index 6425bf6bfd0..f24c5398cbb 100644 --- a/lib/libunwind/src/UnwindRegistersSave.S +++ b/lib/libunwind/src/UnwindRegistersSave.S @@ -463,6 +463,59 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) l.sw 116(r3), r29 l.sw 120(r3), r30 l.sw 124(r3), r31 + +#elif defined(__sparc__) && defined(__arch64__) + +# +# extern int unw_getcontext(unw_context_t* thread_state) +# +# On entry: +# thread_state pointer is in %o0 +# +DEFINE_LIBUNWIND_FUNCTION(unw_getcontext) + stx %g1, [%o0 + 0x08] + stx %g2, [%o0 + 0x10] + stx %g3, [%o0 + 0x18] + stx %g4, [%o0 + 0x20] + stx %g5, [%o0 + 0x28] + stx %g6, [%o0 + 0x30] + stx %g7, [%o0 + 0x38] + stx %o0, [%o0 + 0x40] + stx %o1, [%o0 + 0x48] + stx %o2, [%o0 + 0x50] + stx %o3, [%o0 + 0x58] + stx %o4, [%o0 + 0x60] + stx %o5, [%o0 + 0x68] + stx %o6, [%o0 + 0x70] + stx %o7, [%o0 + 0x78] + stx %l0, [%o0 + 0x80] + stx %l1, [%o0 + 0x88] + stx %l2, [%o0 + 0x90] + stx %l3, [%o0 + 0x98] + stx %l4, [%o0 + 0xa0] + stx %l5, [%o0 + 0xa8] + stx %l6, [%o0 + 0xb0] + stx %l7, [%o0 + 0xb8] + stx %i0, [%o0 + 0xc0] + stx %i1, [%o0 + 0xc8] + stx %i2, [%o0 + 0xd0] + stx %i3, [%o0 + 0xd8] + stx %i4, [%o0 + 0xe0] + stx %i5, [%o0 + 0xe8] + stx %i6, [%o0 + 0xf0] + stx %i7, [%o0 + 0xf8] + + # save StackGhost cookie + add %i7, %g0, %g4 + save %sp, -176, %sp + # register window flush necessary even without StackGhost + flushw + restore + ldx [%sp + 2047 + 0x78], %g5 + xor %g4, %g5, %g4 + retl + stx %g4, [%o0 + 0x100] + #endif NO_EXEC_STACK_DIRECTIVE diff --git a/lib/libunwind/src/libunwind.cpp b/lib/libunwind/src/libunwind.cpp index 95f2dc020dc..46b26fedc28 100644 --- a/lib/libunwind/src/libunwind.cpp +++ b/lib/libunwind/src/libunwind.cpp @@ -57,6 +57,8 @@ _LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor, # define REGISTER_KIND Registers_arm #elif defined(__or1k__) # define REGISTER_KIND Registers_or1k +#elif defined(__sparc__) && defined(__arch64__) +# define REGISTER_KIND Registers_sparc64 #elif defined(__mips__) # warning The MIPS architecture is not supported. #else -- 2.20.1