[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
NOKEYCHECK=True
GitOrigin-RevId: 2b9554b8850192bdd86c02eb671de1d866df8d87
diff --git a/src/DwarfInstructions.hpp b/src/DwarfInstructions.hpp
index 1c50941..c1a241c 100644
--- a/src/DwarfInstructions.hpp
+++ b/src/DwarfInstructions.hpp
@@ -74,6 +74,13 @@
}
};
+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 @@
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 @@
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 @@
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 @@
}
#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