Index: libunwind/include/__libunwind_config.h =================================================================== --- libunwind/include/__libunwind_config.h +++ libunwind/include/__libunwind_config.h @@ -51,6 +51,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 Index: libunwind/include/libunwind.h =================================================================== --- libunwind/include/libunwind.h +++ libunwind/include/libunwind.h @@ -547,4 +547,39 @@ UNW_OR1K_R31 = 31, }; +// SPARC register numbers +enum { + UNW_SPARC_G0 = 0, + UNW_SPARC_G1 = 1, + UNW_SPARC_G2 = 2, + UNW_SPARC_G3 = 3, + UNW_SPARC_G4 = 4, + UNW_SPARC_G5 = 5, + UNW_SPARC_G6 = 6, + UNW_SPARC_G7 = 7, + UNW_SPARC_O0 = 8, + UNW_SPARC_O1 = 9, + UNW_SPARC_O2 = 10, + UNW_SPARC_O3 = 11, + UNW_SPARC_O4 = 12, + UNW_SPARC_O5 = 13, + UNW_SPARC_O6 = 14, + UNW_SPARC_O7 = 15, + UNW_SPARC_L0 = 16, + UNW_SPARC_L1 = 17, + UNW_SPARC_L2 = 18, + UNW_SPARC_L3 = 19, + UNW_SPARC_L4 = 20, + UNW_SPARC_L5 = 21, + UNW_SPARC_L6 = 22, + UNW_SPARC_L7 = 23, + UNW_SPARC_I0 = 24, + UNW_SPARC_I1 = 25, + UNW_SPARC_I2 = 26, + UNW_SPARC_I3 = 27, + UNW_SPARC_I4 = 28, + UNW_SPARC_I5 = 29, + UNW_SPARC_I6 = 30, + UNW_SPARC_I7 = 31, +}; #endif Index: libunwind/src/DwarfInstructions.hpp =================================================================== --- libunwind/src/DwarfInstructions.hpp +++ libunwind/src/DwarfInstructions.hpp @@ -84,6 +84,10 @@ 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, @@ -121,6 +125,7 @@ case CFI_Parser::kRegisterUnused: case CFI_Parser::kRegisterOffsetFromCFA: case CFI_Parser::kRegisterInRegister: + case CFI_Parser::kRegisterInCFADecrypt: // FIX ME break; } @@ -144,6 +149,7 @@ case CFI_Parser::kRegisterUnused: case CFI_Parser::kRegisterOffsetFromCFA: case CFI_Parser::kRegisterInRegister: + case CFI_Parser::kRegisterInCFADecrypt: // FIX ME break; } Index: libunwind/src/DwarfParser.hpp =================================================================== --- libunwind/src/DwarfParser.hpp +++ libunwind/src/DwarfParser.hpp @@ -68,6 +68,7 @@ enum RegisterSavedWhere { kRegisterUnused, kRegisterInCFA, + kRegisterInCFADecrypt, kRegisterOffsetFromCFA, kRegisterInRegister, kRegisterAtExpression, @@ -643,6 +644,18 @@ _LIBUNWIND_TRACE_DWARF("DW_CFA_val_expression(reg=%" PRIu64 ", " "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 = + (int64_t)((reg - 16) * sizeof(pint_t)); + } + _LIBUNWIND_TRACE_DWARF("DW_CGA_GNU_window_save\n"); break; case DW_CFA_GNU_args_size: length = addressSpace.getULEB128(p, instructionsEnd); Index: libunwind/src/Registers.hpp =================================================================== --- libunwind/src/Registers.hpp +++ libunwind/src/Registers.hpp @@ -62,6 +62,7 @@ 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 { @@ -268,6 +269,7 @@ 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 { @@ -506,6 +508,7 @@ 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 { @@ -1074,6 +1077,7 @@ 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 { @@ -1344,6 +1348,7 @@ 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); @@ -1821,6 +1826,7 @@ 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 { @@ -1980,6 +1986,217 @@ } #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) { + switch (regNum) { + case UNW_SPARC_G0: + return "g0"; + case UNW_SPARC_G1: + return "g1"; + case UNW_SPARC_G2: + return "g2"; + case UNW_SPARC_G3: + return "g3"; + case UNW_SPARC_G4: + return "g4"; + case UNW_SPARC_G5: + return "g5"; + case UNW_SPARC_G6: + return "g6"; + case UNW_SPARC_G7: + return "g7"; + case UNW_SPARC_O0: + return "o0"; + case UNW_SPARC_O1: + return "o1"; + case UNW_SPARC_O2: + return "o2"; + case UNW_SPARC_O3: + return "o3"; + case UNW_SPARC_O4: + return "o4"; + case UNW_SPARC_O5: + return "o5"; + case UNW_SPARC_O6: + return "o6"; + case UNW_SPARC_O7: + return "o7"; + case UNW_SPARC_L0: + return "l0"; + case UNW_SPARC_L1: + return "l1"; + case UNW_SPARC_L2: + return "l2"; + case UNW_SPARC_L3: + return "l3"; + case UNW_SPARC_L4: + return "l4"; + case UNW_SPARC_L5: + return "l5"; + case UNW_SPARC_L6: + return "l6"; + case UNW_SPARC_L7: + return "l7"; + case UNW_SPARC_I0: + return "i0"; + case UNW_SPARC_I1: + return "i1"; + case UNW_SPARC_I2: + return "i2"; + case UNW_SPARC_I3: + return "i3"; + case UNW_SPARC_I4: + return "i4"; + case UNW_SPARC_I5: + return "i5"; + case UNW_SPARC_I6: + return "i6"; + case UNW_SPARC_I7: + return "i7"; + default: + return "unknown register"; + } +} + +#endif // _LIBUNWIND_TARGET_SPARC64 } // namespace libunwind #endif // __REGISTERS_HPP__ Index: libunwind/src/UnwindCursor.hpp =================================================================== --- libunwind/src/UnwindCursor.hpp +++ libunwind/src/UnwindCursor.hpp @@ -594,6 +594,12 @@ return 0; } #endif + +#if defined (_LIBUNWIND_TARGET_SPARC64) + compact_unwind_encoding_t dwarfEncoding(Registers_sparc64 &) const { + return 0; + } +#endif #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) Index: libunwind/src/UnwindRegistersRestore.S =================================================================== --- libunwind/src/UnwindRegistersRestore.S +++ libunwind/src/UnwindRegistersRestore.S @@ -489,6 +489,49 @@ 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 Index: libunwind/src/UnwindRegistersSave.S =================================================================== --- libunwind/src/UnwindRegistersSave.S +++ libunwind/src/UnwindRegistersSave.S @@ -469,6 +469,59 @@ 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 Index: libunwind/src/libunwind.cpp =================================================================== --- libunwind/src/libunwind.cpp +++ libunwind/src/libunwind.cpp @@ -58,6 +58,8 @@ # 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