[llvm-branch-commits] [libunwind] ec05ccb - [libunwind] [sparc] Add SPARCv9 support

Fangrui Song via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Mon Feb 7 11:32:03 PST 2022


Author: Koakuma
Date: 2022-02-07T11:13:22-08:00
New Revision: ec05ccbc47156314217916b963d8bd9f664c37f8

URL: https://github.com/llvm/llvm-project/commit/ec05ccbc47156314217916b963d8bd9f664c37f8
DIFF: https://github.com/llvm/llvm-project/commit/ec05ccbc47156314217916b963d8bd9f664c37f8.diff

LOG: [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

(cherry picked from commit 2b9554b8850192bdd86c02eb671de1d866df8d87)

Added: 
    

Modified: 
    libunwind/include/__libunwind_config.h
    libunwind/src/DwarfInstructions.hpp
    libunwind/src/DwarfParser.hpp
    libunwind/src/Registers.hpp
    libunwind/src/UnwindCursor.hpp
    libunwind/src/UnwindRegistersRestore.S
    libunwind/src/UnwindRegistersSave.S
    libunwind/src/libunwind.cpp

Removed: 
    


################################################################################
diff  --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 67527d9da4042..e87bcf40034f3 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -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

diff  --git a/libunwind/src/DwarfInstructions.hpp b/libunwind/src/DwarfInstructions.hpp
index 1c50941680b33..c1a241c55ce66 100644
--- a/libunwind/src/DwarfInstructions.hpp
+++ b/libunwind/src/DwarfInstructions.hpp
@@ -74,6 +74,13 @@ class DwarfInstructions {
   }
 };
 
+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

diff  --git a/libunwind/src/DwarfParser.hpp b/libunwind/src/DwarfParser.hpp
index 8630178777e34..b5a53166fc3f6 100644
--- a/libunwind/src/DwarfParser.hpp
+++ b/libunwind/src/DwarfParser.hpp
@@ -71,6 +71,7 @@ class CFI_Parser {
     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 
diff erent 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

diff  --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 373d9e49018e0..cbc3876d672e1 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -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.

diff  --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index c400fdf33d8a9..1ca842f33aa51 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1032,6 +1032,10 @@ class UnwindCursor : public AbstractUnwindCursor{
   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 @@ class UnwindCursor : public AbstractUnwindCursor{
   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 @@ class UnwindCursor : public AbstractUnwindCursor{
   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;

diff  --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index f3d9dd31683e4..1df97f5fc41c4 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -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__)
 
 //

diff  --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index 7af5c9d154fb3..9566bb0335fee 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -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__)
 
 #

diff  --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index ef48cbe860c7d..03f8b75b5bba4 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -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)


        


More information about the llvm-branch-commits mailing list