Skip to content

Commit 2b9554b

Browse files
koachanMaskRay
authored andcommitted
[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
1 parent 527654d commit 2b9554b

File tree

8 files changed

+362
-1
lines changed

8 files changed

+362
-1
lines changed

libunwind/include/__libunwind_config.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K 32
2424
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS 65
2525
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC 31
26+
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64 31
2627
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON 34
2728
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV 64
2829
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE 143
@@ -125,6 +126,12 @@
125126
# error "Unsupported MIPS ABI and/or environment"
126127
# endif
127128
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
129+
#elif defined(__sparc__) && defined(__arch64__)
130+
#define _LIBUNWIND_TARGET_SPARC64 1
131+
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER \
132+
_LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64
133+
#define _LIBUNWIND_CONTEXT_SIZE 33
134+
#define _LIBUNWIND_CURSOR_SIZE 45
128135
# elif defined(__sparc__)
129136
#define _LIBUNWIND_TARGET_SPARC 1
130137
#define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
@@ -165,6 +172,7 @@
165172
# define _LIBUNWIND_TARGET_MIPS_O32 1
166173
# define _LIBUNWIND_TARGET_MIPS_NEWABI 1
167174
# define _LIBUNWIND_TARGET_SPARC 1
175+
# define _LIBUNWIND_TARGET_SPARC64 1
168176
# define _LIBUNWIND_TARGET_HEXAGON 1
169177
# define _LIBUNWIND_TARGET_RISCV 1
170178
# define _LIBUNWIND_TARGET_VE 1

libunwind/src/DwarfInstructions.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ class DwarfInstructions {
7474
}
7575
};
7676

77+
template <typename R>
78+
auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) {
79+
return r.getWCookie();
80+
}
81+
template <typename R> uint64_t getSparcWCookie(const R &, long) {
82+
return 0;
83+
}
7784

7885
template <typename A, typename R>
7986
typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
@@ -83,6 +90,10 @@ typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
8390
case CFI_Parser<A>::kRegisterInCFA:
8491
return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
8592

93+
case CFI_Parser<A>::kRegisterInCFADecrypt: // sparc64 specific
94+
return addressSpace.getP(cfa + (pint_t)savedReg.value) ^
95+
getSparcWCookie(registers, 0);
96+
8697
case CFI_Parser<A>::kRegisterAtExpression:
8798
return (pint_t)addressSpace.getRegister(evaluateExpression(
8899
(pint_t)savedReg.value, addressSpace, registers, cfa));
@@ -124,6 +135,7 @@ double DwarfInstructions<A, R>::getSavedFloatRegister(
124135
case CFI_Parser<A>::kRegisterIsExpression:
125136
case CFI_Parser<A>::kRegisterUnused:
126137
case CFI_Parser<A>::kRegisterOffsetFromCFA:
138+
case CFI_Parser<A>::kRegisterInCFADecrypt:
127139
// FIX ME
128140
break;
129141
}
@@ -148,6 +160,7 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
148160
case CFI_Parser<A>::kRegisterUndefined:
149161
case CFI_Parser<A>::kRegisterOffsetFromCFA:
150162
case CFI_Parser<A>::kRegisterInRegister:
163+
case CFI_Parser<A>::kRegisterInCFADecrypt:
151164
// FIX ME
152165
break;
153166
}
@@ -266,6 +279,12 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
266279
}
267280
#endif
268281

282+
#if defined(_LIBUNWIND_TARGET_SPARC64)
283+
// Skip call site instruction and delay slot.
284+
if (R::getArch() == REGISTERS_SPARC64)
285+
returnAddress += 8;
286+
#endif
287+
269288
#if defined(_LIBUNWIND_TARGET_PPC64)
270289
#define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
271290
#define PPC64_ELFV1_R2_OFFSET 40

libunwind/src/DwarfParser.hpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class CFI_Parser {
7171
kRegisterUnused,
7272
kRegisterUndefined,
7373
kRegisterInCFA,
74+
kRegisterInCFADecrypt, // sparc64 specific
7475
kRegisterOffsetFromCFA,
7576
kRegisterInRegister,
7677
kRegisterAtExpression,
@@ -733,7 +734,8 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
733734
"DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
734735
break;
735736

736-
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC)
737+
#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
738+
defined(_LIBUNWIND_TARGET_SPARC64)
737739
// The same constant is used to represent different instructions on
738740
// AArch64 (negate_ra_state) and SPARC (window_save).
739741
static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
@@ -767,8 +769,31 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
767769
}
768770
break;
769771
#endif
772+
773+
#if defined(_LIBUNWIND_TARGET_SPARC64)
774+
// case DW_CFA_GNU_window_save:
775+
case REGISTERS_SPARC64:
776+
// Don't save %o0-%o7 on sparc64.
777+
// https://reviews.llvm.org/D32450#736405
778+
779+
for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
780+
if (reg == UNW_SPARC_I7)
781+
results->setRegister(
782+
reg, kRegisterInCFADecrypt,
783+
static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
784+
initialState);
785+
else
786+
results->setRegister(
787+
reg, kRegisterInCFA,
788+
static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
789+
initialState);
790+
}
791+
_LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
792+
break;
793+
#endif
770794
}
771795
break;
796+
772797
#else
773798
(void)arch;
774799
#endif

libunwind/src/Registers.hpp

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum {
3535
REGISTERS_MIPS_O32,
3636
REGISTERS_MIPS_NEWABI,
3737
REGISTERS_SPARC,
38+
REGISTERS_SPARC64,
3839
REGISTERS_HEXAGON,
3940
REGISTERS_RISCV,
4041
REGISTERS_VE,
@@ -3586,6 +3587,191 @@ inline const char *Registers_sparc::getRegisterName(int regNum) {
35863587
}
35873588
#endif // _LIBUNWIND_TARGET_SPARC
35883589

3590+
#if defined(_LIBUNWIND_TARGET_SPARC64)
3591+
/// Registers_sparc64 holds the register state of a thread in a 64-bit
3592+
/// sparc process.
3593+
class _LIBUNWIND_HIDDEN Registers_sparc64 {
3594+
public:
3595+
Registers_sparc64() = default;
3596+
Registers_sparc64(const void *registers);
3597+
3598+
bool validRegister(int num) const;
3599+
uint64_t getRegister(int num) const;
3600+
void setRegister(int num, uint64_t value);
3601+
bool validFloatRegister(int num) const;
3602+
double getFloatRegister(int num) const;
3603+
void setFloatRegister(int num, double value);
3604+
bool validVectorRegister(int num) const;
3605+
v128 getVectorRegister(int num) const;
3606+
void setVectorRegister(int num, v128 value);
3607+
const char *getRegisterName(int num);
3608+
void jumpto();
3609+
static int lastDwarfRegNum() {
3610+
return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64;
3611+
}
3612+
static int getArch() { return REGISTERS_SPARC64; }
3613+
3614+
uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6] + 2047; }
3615+
void setSP(uint64_t value) { _registers.__regs[UNW_SPARC_O6] = value - 2047; }
3616+
uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; }
3617+
void setIP(uint64_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
3618+
uint64_t getWCookie() const { return _wcookie; }
3619+
3620+
private:
3621+
struct sparc64_thread_state_t {
3622+
uint64_t __regs[32];
3623+
};
3624+
3625+
sparc64_thread_state_t _registers{};
3626+
uint64_t _wcookie = 0;
3627+
};
3628+
3629+
inline Registers_sparc64::Registers_sparc64(const void *registers) {
3630+
static_assert((check_fit<Registers_sparc64, unw_context_t>::does_fit),
3631+
"sparc64 registers do not fit into unw_context_t");
3632+
memcpy(&_registers, registers, sizeof(_registers));
3633+
memcpy(&_wcookie,
3634+
static_cast<const uint8_t *>(registers) + sizeof(_registers),
3635+
sizeof(_wcookie));
3636+
}
3637+
3638+
inline bool Registers_sparc64::validRegister(int regNum) const {
3639+
if (regNum == UNW_REG_IP)
3640+
return true;
3641+
if (regNum == UNW_REG_SP)
3642+
return true;
3643+
if (regNum < 0)
3644+
return false;
3645+
if (regNum <= UNW_SPARC_I7)
3646+
return true;
3647+
return false;
3648+
}
3649+
3650+
inline uint64_t Registers_sparc64::getRegister(int regNum) const {
3651+
if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7)
3652+
return _registers.__regs[regNum];
3653+
3654+
switch (regNum) {
3655+
case UNW_REG_IP:
3656+
return _registers.__regs[UNW_SPARC_O7];
3657+
case UNW_REG_SP:
3658+
return _registers.__regs[UNW_SPARC_O6] + 2047;
3659+
}
3660+
_LIBUNWIND_ABORT("unsupported sparc64 register");
3661+
}
3662+
3663+
inline void Registers_sparc64::setRegister(int regNum, uint64_t value) {
3664+
if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7) {
3665+
_registers.__regs[regNum] = value;
3666+
return;
3667+
}
3668+
3669+
switch (regNum) {
3670+
case UNW_REG_IP:
3671+
_registers.__regs[UNW_SPARC_O7] = value;
3672+
return;
3673+
case UNW_REG_SP:
3674+
_registers.__regs[UNW_SPARC_O6] = value - 2047;
3675+
return;
3676+
}
3677+
_LIBUNWIND_ABORT("unsupported sparc64 register");
3678+
}
3679+
3680+
inline bool Registers_sparc64::validFloatRegister(int) const { return false; }
3681+
3682+
inline double Registers_sparc64::getFloatRegister(int) const {
3683+
_LIBUNWIND_ABORT("no sparc64 float registers");
3684+
}
3685+
3686+
inline void Registers_sparc64::setFloatRegister(int, double) {
3687+
_LIBUNWIND_ABORT("no sparc64 float registers");
3688+
}
3689+
3690+
inline bool Registers_sparc64::validVectorRegister(int) const { return false; }
3691+
3692+
inline v128 Registers_sparc64::getVectorRegister(int) const {
3693+
_LIBUNWIND_ABORT("no sparc64 vector registers");
3694+
}
3695+
3696+
inline void Registers_sparc64::setVectorRegister(int, v128) {
3697+
_LIBUNWIND_ABORT("no sparc64 vector registers");
3698+
}
3699+
3700+
inline const char *Registers_sparc64::getRegisterName(int regNum) {
3701+
switch (regNum) {
3702+
case UNW_REG_IP:
3703+
return "pc";
3704+
case UNW_SPARC_G0:
3705+
return "g0";
3706+
case UNW_SPARC_G1:
3707+
return "g1";
3708+
case UNW_SPARC_G2:
3709+
return "g2";
3710+
case UNW_SPARC_G3:
3711+
return "g3";
3712+
case UNW_SPARC_G4:
3713+
return "g4";
3714+
case UNW_SPARC_G5:
3715+
return "g5";
3716+
case UNW_SPARC_G6:
3717+
return "g6";
3718+
case UNW_SPARC_G7:
3719+
return "g7";
3720+
case UNW_SPARC_O0:
3721+
return "o0";
3722+
case UNW_SPARC_O1:
3723+
return "o1";
3724+
case UNW_SPARC_O2:
3725+
return "o2";
3726+
case UNW_SPARC_O3:
3727+
return "o3";
3728+
case UNW_SPARC_O4:
3729+
return "o4";
3730+
case UNW_SPARC_O5:
3731+
return "o5";
3732+
case UNW_REG_SP:
3733+
case UNW_SPARC_O6:
3734+
return "o6";
3735+
case UNW_SPARC_O7:
3736+
return "o7";
3737+
case UNW_SPARC_L0:
3738+
return "l0";
3739+
case UNW_SPARC_L1:
3740+
return "l1";
3741+
case UNW_SPARC_L2:
3742+
return "l2";
3743+
case UNW_SPARC_L3:
3744+
return "l3";
3745+
case UNW_SPARC_L4:
3746+
return "l4";
3747+
case UNW_SPARC_L5:
3748+
return "l5";
3749+
case UNW_SPARC_L6:
3750+
return "l6";
3751+
case UNW_SPARC_L7:
3752+
return "l7";
3753+
case UNW_SPARC_I0:
3754+
return "i0";
3755+
case UNW_SPARC_I1:
3756+
return "i1";
3757+
case UNW_SPARC_I2:
3758+
return "i2";
3759+
case UNW_SPARC_I3:
3760+
return "i3";
3761+
case UNW_SPARC_I4:
3762+
return "i4";
3763+
case UNW_SPARC_I5:
3764+
return "i5";
3765+
case UNW_SPARC_I6:
3766+
return "i6";
3767+
case UNW_SPARC_I7:
3768+
return "i7";
3769+
default:
3770+
return "unknown register";
3771+
}
3772+
}
3773+
#endif // _LIBUNWIND_TARGET_SPARC64
3774+
35893775
#if defined(_LIBUNWIND_TARGET_HEXAGON)
35903776
/// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6
35913777
/// process.

libunwind/src/UnwindCursor.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,10 @@ class UnwindCursor : public AbstractUnwindCursor{
10321032
int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
10331033
#endif
10341034

1035+
#if defined(_LIBUNWIND_TARGET_SPARC64)
1036+
int stepWithCompactEncoding(Registers_sparc64 &) { return UNW_EINVAL; }
1037+
#endif
1038+
10351039
#if defined (_LIBUNWIND_TARGET_RISCV)
10361040
int stepWithCompactEncoding(Registers_riscv &) {
10371041
return UNW_EINVAL;
@@ -1104,6 +1108,12 @@ class UnwindCursor : public AbstractUnwindCursor{
11041108
bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
11051109
#endif
11061110

1111+
#if defined(_LIBUNWIND_TARGET_SPARC64)
1112+
bool compactSaysUseDwarf(Registers_sparc64 &, uint32_t *) const {
1113+
return true;
1114+
}
1115+
#endif
1116+
11071117
#if defined (_LIBUNWIND_TARGET_RISCV)
11081118
bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const {
11091119
return true;
@@ -1182,6 +1192,12 @@ class UnwindCursor : public AbstractUnwindCursor{
11821192
compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
11831193
#endif
11841194

1195+
#if defined(_LIBUNWIND_TARGET_SPARC64)
1196+
compact_unwind_encoding_t dwarfEncoding(Registers_sparc64 &) const {
1197+
return 0;
1198+
}
1199+
#endif
1200+
11851201
#if defined (_LIBUNWIND_TARGET_RISCV)
11861202
compact_unwind_encoding_t dwarfEncoding(Registers_riscv &) const {
11871203
return 0;

0 commit comments

Comments
 (0)