forked from OSchip/llvm-project
[libunwind] [sparc] Add SPARCv9 support
Adds libunwind support for SPARCv9 (aka sparc64). This is a rebase of @kettenis' patch D32450, which I created (with his permission) because the original review has become inactive. The changes are of a cosmetic nature to make it fit better with the new code style, and to reuse the existing SPARCv8 code, whenever possible. Please let me know if I posted this on the wrong place. Also, the summary of the original review is reproduced below: > This adds unwinder support for 64-bit SPARC (aka SPARCv9). The implementation was done on OpenBSD/sparc64, so it takes StackGhost into account: > > https://www.usenix.org/legacy/publications/library/proceedings/sec01/full_papers/frantzen/frantzen_html/index.html > > Since StackGhost xor's return addresses with a random cookie before storing them on the stack, the unwinder has to do some extra work to recover those. This is done by introducing a new kRegisterInCFADecrypt "location" type that is used to implement the DW_CFA_GNU_window_save opcode. That implementation is SPARC-specific, but should work for 32-bit SPARC as well. DW_CFA_GNU_window_save is only ever generated on SPARC as far as I know. Co-authored-by: Mark Kettenis Reviewed By: #libunwind, thesamesam, MaskRay, Arfrever Differential Revision: https://reviews.llvm.org/D116857
This commit is contained in:
parent
527654dceb
commit
2b9554b885
|
@ -23,6 +23,7 @@
|
|||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64 31
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON 34
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE 143
|
||||
|
@ -125,6 +126,12 @@
|
|||
# error "Unsupported MIPS ABI and/or environment"
|
||||
# endif
|
||||
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
|
||||
#elif defined(__sparc__) && defined(__arch64__)
|
||||
#define _LIBUNWIND_TARGET_SPARC64 1
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER \
|
||||
_LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64
|
||||
#define _LIBUNWIND_CONTEXT_SIZE 33
|
||||
#define _LIBUNWIND_CURSOR_SIZE 45
|
||||
# elif defined(__sparc__)
|
||||
#define _LIBUNWIND_TARGET_SPARC 1
|
||||
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
|
||||
|
@ -165,6 +172,7 @@
|
|||
# define _LIBUNWIND_TARGET_MIPS_O32 1
|
||||
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
|
||||
# define _LIBUNWIND_TARGET_SPARC 1
|
||||
# define _LIBUNWIND_TARGET_SPARC64 1
|
||||
# define _LIBUNWIND_TARGET_HEXAGON 1
|
||||
# define _LIBUNWIND_TARGET_RISCV 1
|
||||
# define _LIBUNWIND_TARGET_VE 1
|
||||
|
|
|
@ -74,6 +74,13 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) {
|
||||
return r.getWCookie();
|
||||
}
|
||||
template <typename R> uint64_t getSparcWCookie(const R &, long) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename A, typename R>
|
||||
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
|
||||
|
@ -83,6 +90,10 @@ typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
|
|||
case CFI_Parser<A>::kRegisterInCFA:
|
||||
return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
|
||||
|
||||
case CFI_Parser<A>::kRegisterInCFADecrypt: // sparc64 specific
|
||||
return addressSpace.getP(cfa + (pint_t)savedReg.value) ^
|
||||
getSparcWCookie(registers, 0);
|
||||
|
||||
case CFI_Parser<A>::kRegisterAtExpression:
|
||||
return (pint_t)addressSpace.getRegister(evaluateExpression(
|
||||
(pint_t)savedReg.value, addressSpace, registers, cfa));
|
||||
|
@ -124,6 +135,7 @@ double DwarfInstructions<A, R>::getSavedFloatRegister(
|
|||
case CFI_Parser<A>::kRegisterIsExpression:
|
||||
case CFI_Parser<A>::kRegisterUnused:
|
||||
case CFI_Parser<A>::kRegisterOffsetFromCFA:
|
||||
case CFI_Parser<A>::kRegisterInCFADecrypt:
|
||||
// FIX ME
|
||||
break;
|
||||
}
|
||||
|
@ -148,6 +160,7 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
|
|||
case CFI_Parser<A>::kRegisterUndefined:
|
||||
case CFI_Parser<A>::kRegisterOffsetFromCFA:
|
||||
case CFI_Parser<A>::kRegisterInRegister:
|
||||
case CFI_Parser<A>::kRegisterInCFADecrypt:
|
||||
// FIX ME
|
||||
break;
|
||||
}
|
||||
|
@ -266,6 +279,12 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC64)
|
||||
// Skip call site instruction and delay slot.
|
||||
if (R::getArch() == REGISTERS_SPARC64)
|
||||
returnAddress += 8;
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_PPC64)
|
||||
#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
|
||||
#define PPC64_ELFV1_R2_OFFSET 40
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
kRegisterUnused,
|
||||
kRegisterUndefined,
|
||||
kRegisterInCFA,
|
||||
kRegisterInCFADecrypt, // sparc64 specific
|
||||
kRegisterOffsetFromCFA,
|
||||
kRegisterInRegister,
|
||||
kRegisterAtExpression,
|
||||
|
@ -733,7 +734,8 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
|
|||
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
|
||||
break;
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
|
||||
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
|
||||
defined(_LIBUNWIND_TARGET_SPARC64)
|
||||
// The same constant is used to represent different instructions on
|
||||
// AArch64 (negate_ra_state) and SPARC (window_save).
|
||||
static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
|
||||
|
@ -767,8 +769,31 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
|
|||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC64)
|
||||
// case DW_CFA_GNU_window_save:
|
||||
case REGISTERS_SPARC64:
|
||||
// Don't save %o0-%o7 on sparc64.
|
||||
// https://reviews.llvm.org/D32450#736405
|
||||
|
||||
for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
|
||||
if (reg == UNW_SPARC_I7)
|
||||
results->setRegister(
|
||||
reg, kRegisterInCFADecrypt,
|
||||
static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
|
||||
initialState);
|
||||
else
|
||||
results->setRegister(
|
||||
reg, kRegisterInCFA,
|
||||
static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
|
||||
initialState);
|
||||
}
|
||||
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
#else
|
||||
(void)arch;
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,7 @@ enum {
|
|||
REGISTERS_MIPS_O32,
|
||||
REGISTERS_MIPS_NEWABI,
|
||||
REGISTERS_SPARC,
|
||||
REGISTERS_SPARC64,
|
||||
REGISTERS_HEXAGON,
|
||||
REGISTERS_RISCV,
|
||||
REGISTERS_VE,
|
||||
|
@ -3586,6 +3587,191 @@ inline const char *Registers_sparc::getRegisterName(int regNum) {
|
|||
}
|
||||
#endif // _LIBUNWIND_TARGET_SPARC
|
||||
|
||||
#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() = default;
|
||||
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 _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64;
|
||||
}
|
||||
static int getArch() { return REGISTERS_SPARC64; }
|
||||
|
||||
uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6] + 2047; }
|
||||
void setSP(uint64_t value) { _registers.__regs[UNW_SPARC_O6] = value - 2047; }
|
||||
uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; }
|
||||
void setIP(uint64_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
|
||||
uint64_t getWCookie() const { return _wcookie; }
|
||||
|
||||
private:
|
||||
struct sparc64_thread_state_t {
|
||||
uint64_t __regs[32];
|
||||
};
|
||||
|
||||
sparc64_thread_state_t _registers{};
|
||||
uint64_t _wcookie = 0;
|
||||
};
|
||||
|
||||
inline Registers_sparc64::Registers_sparc64(const void *registers) {
|
||||
static_assert((check_fit<Registers_sparc64, unw_context_t>::does_fit),
|
||||
"sparc64 registers do not fit into unw_context_t");
|
||||
memcpy(&_registers, registers, sizeof(_registers));
|
||||
memcpy(&_wcookie,
|
||||
static_cast<const uint8_t *>(registers) + sizeof(_registers),
|
||||
sizeof(_wcookie));
|
||||
}
|
||||
|
||||
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 <= UNW_SPARC_I7)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline uint64_t Registers_sparc64::getRegister(int regNum) const {
|
||||
if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7)
|
||||
return _registers.__regs[regNum];
|
||||
|
||||
switch (regNum) {
|
||||
case UNW_REG_IP:
|
||||
return _registers.__regs[UNW_SPARC_O7];
|
||||
case UNW_REG_SP:
|
||||
return _registers.__regs[UNW_SPARC_O6] + 2047;
|
||||
}
|
||||
_LIBUNWIND_ABORT("unsupported sparc64 register");
|
||||
}
|
||||
|
||||
inline void Registers_sparc64::setRegister(int regNum, uint64_t value) {
|
||||
if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7) {
|
||||
_registers.__regs[regNum] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (regNum) {
|
||||
case UNW_REG_IP:
|
||||
_registers.__regs[UNW_SPARC_O7] = value;
|
||||
return;
|
||||
case UNW_REG_SP:
|
||||
_registers.__regs[UNW_SPARC_O6] = 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_REG_IP:
|
||||
return "pc";
|
||||
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_REG_SP:
|
||||
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
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_HEXAGON)
|
||||
/// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6
|
||||
/// process.
|
||||
|
|
|
@ -1032,6 +1032,10 @@ private:
|
|||
int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC64)
|
||||
int stepWithCompactEncoding(Registers_sparc64 &) { return UNW_EINVAL; }
|
||||
#endif
|
||||
|
||||
#if defined (_LIBUNWIND_TARGET_RISCV)
|
||||
int stepWithCompactEncoding(Registers_riscv &) {
|
||||
return UNW_EINVAL;
|
||||
|
@ -1104,6 +1108,12 @@ private:
|
|||
bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC64)
|
||||
bool compactSaysUseDwarf(Registers_sparc64 &, uint32_t *) const {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (_LIBUNWIND_TARGET_RISCV)
|
||||
bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const {
|
||||
return true;
|
||||
|
@ -1182,6 +1192,12 @@ private:
|
|||
compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
|
||||
#endif
|
||||
|
||||
#if defined(_LIBUNWIND_TARGET_SPARC64)
|
||||
compact_unwind_encoding_t dwarfEncoding(Registers_sparc64 &) const {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (_LIBUNWIND_TARGET_RISCV)
|
||||
compact_unwind_encoding_t dwarfEncoding(Registers_riscv &) const {
|
||||
return 0;
|
||||
|
|
|
@ -1062,6 +1062,53 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
|
|||
ld $4, (8 * 4)($4)
|
||||
.set pop
|
||||
|
||||
#elif defined(__sparc__) && defined(__arch64__)
|
||||
|
||||
DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv)
|
||||
//
|
||||
// void libunwind::Registers_sparc64::jumpto()
|
||||
//
|
||||
// On entry:
|
||||
// thread_state pointer is in %o0
|
||||
//
|
||||
.register %g2, #scratch
|
||||
.register %g3, #scratch
|
||||
.register %g6, #scratch
|
||||
.register %g7, #scratch
|
||||
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
|
||||
jmp %o7
|
||||
ldx [%o0 + 0x40], %o0
|
||||
|
||||
#elif defined(__sparc__)
|
||||
|
||||
//
|
||||
|
|
|
@ -999,6 +999,64 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
|
|||
|
||||
jumpr 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)
|
||||
.register %g2, #scratch
|
||||
.register %g3, #scratch
|
||||
.register %g6, #scratch
|
||||
.register %g7, #scratch
|
||||
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
|
||||
mov %i7, %g4
|
||||
save %sp, -176, %sp
|
||||
# register window flush necessary even without StackGhost
|
||||
flushw
|
||||
restore
|
||||
ldx [%sp + 2047 + 0x78], %g5
|
||||
xor %g4, %g5, %g4
|
||||
stx %g4, [%o0 + 0x100]
|
||||
retl
|
||||
# return UNW_ESUCCESS
|
||||
clr %o0
|
||||
|
||||
#elif defined(__sparc__)
|
||||
|
||||
#
|
||||
|
|
|
@ -67,6 +67,8 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
|
|||
# define REGISTER_KIND Registers_mips_newabi
|
||||
#elif defined(__mips__)
|
||||
# warning The MIPS architecture is not supported with this ABI and environment!
|
||||
#elif defined(__sparc__) && defined(__arch64__)
|
||||
#define REGISTER_KIND Registers_sparc64
|
||||
#elif defined(__sparc__)
|
||||
# define REGISTER_KIND Registers_sparc
|
||||
#elif defined(__riscv)
|
||||
|
|
Loading…
Reference in New Issue