[libunwind] r350705 - [Sparc] Add Sparc V8 support

Daniel Cederman via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 9 04:06:05 PST 2019


Author: dcederman
Date: Wed Jan  9 04:06:05 2019
New Revision: 350705

URL: http://llvm.org/viewvc/llvm-project?rev=350705&view=rev
Log:
[Sparc] Add Sparc V8 support

Summary:
Adds the register class implementation for Sparc.
Adds support for DW_CFA_GNU_window_save.
Adds save and restore context functionality.

On Sparc the return address is the address of the call instruction,
so an offset needs to be added when returning to skip the call instruction
and its delay slot. If the function returns a struct it is also necessary
to skip one extra instruction.

Reviewers: jyknight, mclow.lists, mstorsjo, compnerd

Reviewed By: compnerd

Subscribers: fedor.sergeev, JDevlieghere, ldionne, libcxx-commits

Differential Revision: https://reviews.llvm.org/D55763

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

Modified: libunwind/trunk/include/__libunwind_config.h
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/include/__libunwind_config.h?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/include/__libunwind_config.h (original)
+++ libunwind/trunk/include/__libunwind_config.h Wed Jan  9 04:06:05 2019
@@ -23,6 +23,7 @@
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM       287
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K      32
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS      65
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC     31
 
 #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
 # if defined(__i386__)
@@ -113,6 +114,11 @@
 #    error "Unsupported MIPS ABI and/or environment"
 #  endif
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
+# elif defined(__sparc__)
+  #define _LIBUNWIND_TARGET_SPARC 1
+  #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
+  #define _LIBUNWIND_CONTEXT_SIZE 16
+  #define _LIBUNWIND_CURSOR_SIZE 23
 # else
 #  error "Unsupported architecture."
 # endif
@@ -126,6 +132,7 @@
 # define _LIBUNWIND_TARGET_OR1K 1
 # define _LIBUNWIND_TARGET_MIPS_O32 1
 # define _LIBUNWIND_TARGET_MIPS_NEWABI 1
+# define _LIBUNWIND_TARGET_SPARC 1
 # define _LIBUNWIND_CONTEXT_SIZE 167
 # define _LIBUNWIND_CURSOR_SIZE 179
 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287

Modified: libunwind/trunk/include/libunwind.h
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/include/libunwind.h?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/include/libunwind.h (original)
+++ libunwind/trunk/include/libunwind.h Wed Jan  9 04:06:05 2019
@@ -823,4 +823,40 @@ enum {
   UNW_MIPS_LO = 65,
 };
 
+// SPARC registers
+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

Modified: libunwind/trunk/src/DwarfInstructions.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/DwarfInstructions.hpp?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/DwarfInstructions.hpp (original)
+++ libunwind/trunk/src/DwarfInstructions.hpp Wed Jan  9 04:06:05 2019
@@ -223,6 +223,14 @@ int DwarfInstructions<A, R>::stepWithDwa
       }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_SPARC)
+      // Skip call site instruction and delay slot
+      returnAddress += 8;
+      // Skip unimp instruction if function returns a struct
+      if ((addressSpace.get32(returnAddress) & 0xC1C00000) == 0)
+        returnAddress += 4;
+#endif
+
       // Return address is address after call site instruction, so setting IP to
       // that does simualates a return.
       newRegisters.setIP(returnAddress);

Modified: libunwind/trunk/src/DwarfParser.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/DwarfParser.hpp?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/DwarfParser.hpp (original)
+++ libunwind/trunk/src/DwarfParser.hpp Wed Jan  9 04:06:05 2019
@@ -685,6 +685,22 @@ bool CFI_Parser<A>::parseInstructions(A
       break;
 #endif
 
+#if defined(_LIBUNWIND_TARGET_SPARC)
+    case DW_CFA_GNU_window_save:
+      _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save()\n");
+      for (reg = UNW_SPARC_O0; reg <= UNW_SPARC_O7; reg++) {
+        results->savedRegisters[reg].location = kRegisterInRegister;
+        results->savedRegisters[reg].value =
+            (reg - UNW_SPARC_O0) + UNW_SPARC_I0;
+      }
+
+      for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+        results->savedRegisters[reg].location = kRegisterInCFA;
+        results->savedRegisters[reg].value = (reg - UNW_SPARC_L0) * 4;
+      }
+      break;
+#endif
+
     default:
       operand = opcode & 0x3F;
       switch (opcode & 0xC0) {

Modified: libunwind/trunk/src/Registers.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/Registers.hpp?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/Registers.hpp (original)
+++ libunwind/trunk/src/Registers.hpp Wed Jan  9 04:06:05 2019
@@ -3312,6 +3312,194 @@ inline const char *Registers_mips_newabi
   }
 }
 #endif // _LIBUNWIND_TARGET_MIPS_NEWABI
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+/// Registers_sparc holds the register state of a thread in a 32-bit Sparc
+/// process.
+class _LIBUNWIND_HIDDEN Registers_sparc {
+public:
+  Registers_sparc();
+  Registers_sparc(const void *registers);
+
+  bool        validRegister(int num) const;
+  uint32_t    getRegister(int num) const;
+  void        setRegister(int num, uint32_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);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; }
+
+  uint64_t  getSP() const         { return _registers.__regs[UNW_SPARC_O6]; }
+  void      setSP(uint32_t value) { _registers.__regs[UNW_SPARC_O6] = value; }
+  uint64_t  getIP() const         { return _registers.__regs[UNW_SPARC_O7]; }
+  void      setIP(uint32_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
+
+private:
+  struct sparc_thread_state_t {
+    unsigned int __regs[32];
+  };
+
+  sparc_thread_state_t _registers;
+};
+
+inline Registers_sparc::Registers_sparc(const void *registers) {
+  static_assert((check_fit<Registers_sparc, unw_context_t>::does_fit),
+                "sparc registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_sparc::Registers_sparc() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_sparc::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 uint32_t Registers_sparc::getRegister(int regNum) const {
+  if ((UNW_SPARC_G0 <= regNum) && (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];
+  }
+  _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline void Registers_sparc::setRegister(int regNum, uint32_t value) {
+  if ((UNW_SPARC_G0 <= regNum) && (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;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported sparc register");
+}
+
+inline bool Registers_sparc::validFloatRegister(int regNum) const {
+  return false;
+}
+
+inline double Registers_sparc::getFloatRegister(int regNum) const {
+  _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline void Registers_sparc::setFloatRegister(int regNum, double value) {
+  _LIBUNWIND_ABORT("no Sparc float registers");
+}
+
+inline bool Registers_sparc::validVectorRegister(int regNum) const {
+  return false;
+}
+
+inline v128 Registers_sparc::getVectorRegister(int regNum) const {
+  _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline void Registers_sparc::setVectorRegister(int regNum, v128 value) {
+  _LIBUNWIND_ABORT("no Sparc vector registers");
+}
+
+inline const char *Registers_sparc::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 "sp";
+  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 "fp";
+  case UNW_SPARC_I7:
+    return "i7";
+  default:
+    return "unknown register";
+  }
+}
+#endif // _LIBUNWIND_TARGET_SPARC
+
 } // namespace libunwind
 
 #endif // __REGISTERS_HPP__

Modified: libunwind/trunk/src/UnwindCursor.hpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/UnwindCursor.hpp?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/UnwindCursor.hpp (original)
+++ libunwind/trunk/src/UnwindCursor.hpp Wed Jan  9 04:06:05 2019
@@ -981,6 +981,10 @@ private:
   }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_SPARC)
+  int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
+#endif
+
   bool compactSaysUseDwarf(uint32_t *offset=NULL) const {
     R dummy;
     return compactSaysUseDwarf(dummy, offset);
@@ -1042,6 +1046,11 @@ private:
     return true;
   }
 #endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+  bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
+#endif
+
 #endif // defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
 
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -1103,6 +1112,11 @@ private:
     return 0;
   }
 #endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC)
+  compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
+#endif
+
 #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
 
 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)

Modified: libunwind/trunk/src/UnwindRegistersRestore.S
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/UnwindRegistersRestore.S?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/UnwindRegistersRestore.S (original)
+++ libunwind/trunk/src/UnwindRegistersRestore.S Wed Jan  9 04:06:05 2019
@@ -1000,6 +1000,28 @@ DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9li
   ld    $4, (8 * 4)($4)
   .set pop
 
+#elif defined(__sparc__)
+
+//
+// void libunwind::Registers_sparc_o32::jumpto()
+//
+// On entry:
+//  thread_state pointer is in o0
+//
+DEFINE_LIBUNWIND_PRIVATE_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
+  ta 3
+  ldd [%o0 + 64],  %l0
+  ldd [%o0 + 72],  %l2
+  ldd [%o0 + 80],  %l4
+  ldd [%o0 + 88],  %l6
+  ldd [%o0 + 96],  %i0
+  ldd [%o0 + 104], %i2
+  ldd [%o0 + 112], %i4
+  ldd [%o0 + 120], %i6
+  ld  [%o0 + 60],  %o7
+  jmp %o7
+   nop
+
 #endif
 
 #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */

Modified: libunwind/trunk/src/UnwindRegistersSave.S
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/UnwindRegistersSave.S?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/UnwindRegistersSave.S (original)
+++ libunwind/trunk/src/UnwindRegistersSave.S Wed Jan  9 04:06:05 2019
@@ -942,9 +942,37 @@ DEFINE_LIBUNWIND_FUNCTION(unw_getcontext
   l.sw     128(r3), r9
   # zero epcr
   l.sw     132(r3), r0
-#endif
 
+#elif defined(__sparc__)
+
+#
+# extern int unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in o0
+#
+DEFINE_LIBUNWIND_FUNCTION(unw_getcontext)
+  ta 3
+  add %o7, 8, %o7
+  std %g0, [%o0 +   0]
+  std %g2, [%o0 +   8]
+  std %g4, [%o0 +  16]
+  std %g6, [%o0 +  24]
+  std %o0, [%o0 +  32]
+  std %o2, [%o0 +  40]
+  std %o4, [%o0 +  48]
+  std %o6, [%o0 +  56]
+  std %l0, [%o0 +  64]
+  std %l2, [%o0 +  72]
+  std %l4, [%o0 +  80]
+  std %l6, [%o0 +  88]
+  std %i0, [%o0 +  96]
+  std %i2, [%o0 + 104]
+  std %i4, [%o0 + 112]
+  std %i6, [%o0 + 120]
+  jmp %o7
+   clr %o0                   // return UNW_ESUCCESS
+#endif
 #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
 
 NO_EXEC_STACK_DIRECTIVE
-

Modified: libunwind/trunk/src/assembly.h
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/assembly.h?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/assembly.h (original)
+++ libunwind/trunk/src/assembly.h Wed Jan  9 04:06:05 2019
@@ -85,6 +85,8 @@
 
 #define NO_EXEC_STACK_DIRECTIVE
 
+#elif defined(__sparc__)
+
 #else
 
 #error Unsupported target

Modified: libunwind/trunk/src/libunwind.cpp
URL: http://llvm.org/viewvc/llvm-project/libunwind/trunk/src/libunwind.cpp?rev=350705&r1=350704&r2=350705&view=diff
==============================================================================
--- libunwind/trunk/src/libunwind.cpp (original)
+++ libunwind/trunk/src/libunwind.cpp Wed Jan  9 04:06:05 2019
@@ -67,6 +67,8 @@ _LIBUNWIND_EXPORT int unw_init_local(unw
 # define REGISTER_KIND Registers_mips_newabi
 #elif defined(__mips__)
 # warning The MIPS architecture is not supported with this ABI and environment!
+#elif defined(__sparc__)
+# define REGISTER_KIND Registers_sparc
 #else
 # error Architecture not supported
 #endif




More information about the cfe-commits mailing list