[libunwind] 364c502 - [libunwind] Add SystemZ support

Ulrich Weigand via cfe-commits cfe-commits at lists.llvm.org
Mon May 2 05:38:10 PDT 2022


Author: Ulrich Weigand
Date: 2022-05-02T14:35:29+02:00
New Revision: 364c5023d2ce1617c706b185892ddfaa2fd4d166

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

LOG: [libunwind] Add SystemZ support

Add support for the SystemZ (s390x) architecture to libunwind.

Support should be feature-complete with the exception of
unwinding from signal handlers (to be added later).

Reviewed by: MaskRay

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

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 30f5e0a23d08e..e626567d4e594 100644
--- a/libunwind/include/__libunwind_config.h
+++ b/libunwind/include/__libunwind_config.h
@@ -29,6 +29,7 @@
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON   34
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV     64
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE        143
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X     83
 
 #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
 # if defined(__linux__)
@@ -160,6 +161,11 @@
 #  define _LIBUNWIND_CONTEXT_SIZE 67
 #  define _LIBUNWIND_CURSOR_SIZE 79
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE
+# elif defined(__s390x__)
+#  define _LIBUNWIND_TARGET_S390X 1
+#  define _LIBUNWIND_CONTEXT_SIZE 34
+#  define _LIBUNWIND_CURSOR_SIZE 46
+#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X
 # else
 #  error "Unsupported architecture."
 # endif
@@ -178,6 +184,7 @@
 # define _LIBUNWIND_TARGET_HEXAGON 1
 # define _LIBUNWIND_TARGET_RISCV 1
 # define _LIBUNWIND_TARGET_VE 1
+# define _LIBUNWIND_TARGET_S390X 1
 # define _LIBUNWIND_CONTEXT_SIZE 167
 # define _LIBUNWIND_CURSOR_SIZE 179
 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287

diff  --git a/libunwind/include/libunwind.h b/libunwind/include/libunwind.h
index a69e72fc132df..3d8fd2146ebbd 100644
--- a/libunwind/include/libunwind.h
+++ b/libunwind/include/libunwind.h
@@ -1177,4 +1177,46 @@ enum {
   UNW_VE_VL   = 145,
 };
 
+// s390x register numbers
+enum {
+  UNW_S390X_R0      = 0,
+  UNW_S390X_R1      = 1,
+  UNW_S390X_R2      = 2,
+  UNW_S390X_R3      = 3,
+  UNW_S390X_R4      = 4,
+  UNW_S390X_R5      = 5,
+  UNW_S390X_R6      = 6,
+  UNW_S390X_R7      = 7,
+  UNW_S390X_R8      = 8,
+  UNW_S390X_R9      = 9,
+  UNW_S390X_R10     = 10,
+  UNW_S390X_R11     = 11,
+  UNW_S390X_R12     = 12,
+  UNW_S390X_R13     = 13,
+  UNW_S390X_R14     = 14,
+  UNW_S390X_R15     = 15,
+  UNW_S390X_F0      = 16,
+  UNW_S390X_F2      = 17,
+  UNW_S390X_F4      = 18,
+  UNW_S390X_F6      = 19,
+  UNW_S390X_F1      = 20,
+  UNW_S390X_F3      = 21,
+  UNW_S390X_F5      = 22,
+  UNW_S390X_F7      = 23,
+  UNW_S390X_F8      = 24,
+  UNW_S390X_F10     = 25,
+  UNW_S390X_F12     = 26,
+  UNW_S390X_F14     = 27,
+  UNW_S390X_F9      = 28,
+  UNW_S390X_F11     = 29,
+  UNW_S390X_F13     = 30,
+  UNW_S390X_F15     = 31,
+  // 32-47 Control Registers
+  // 48-63 Access Registers
+  UNW_S390X_PSWM    = 64,
+  UNW_S390X_PSWA    = 65,
+  // 66-67 Reserved
+  // 68-83 Vector Registers %v16-%v31
+};
+
 #endif

diff  --git a/libunwind/src/Registers.hpp b/libunwind/src/Registers.hpp
index 32c13e6c9a248..28c617f34999b 100644
--- a/libunwind/src/Registers.hpp
+++ b/libunwind/src/Registers.hpp
@@ -39,6 +39,7 @@ enum {
   REGISTERS_HEXAGON,
   REGISTERS_RISCV,
   REGISTERS_VE,
+  REGISTERS_S390X,
 };
 
 #if defined(_LIBUNWIND_TARGET_I386)
@@ -4716,6 +4717,293 @@ inline const char *Registers_ve::getRegisterName(int regNum) {
 }
 #endif // _LIBUNWIND_TARGET_VE
 
+#if defined(_LIBUNWIND_TARGET_S390X)
+/// Registers_s390x holds the register state of a thread in a
+/// 64-bit Linux on IBM zSystems process.
+class _LIBUNWIND_HIDDEN Registers_s390x {
+public:
+  Registers_s390x();
+  Registers_s390x(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);
+  static const char *getRegisterName(int num);
+  void        jumpto();
+  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X; }
+  static int  getArch() { return REGISTERS_S390X; }
+
+  uint64_t  getSP() const         { return _registers.__gpr[15]; }
+  void      setSP(uint64_t value) { _registers.__gpr[15] = value; }
+  uint64_t  getIP() const         { return _registers.__pswa; }
+  void      setIP(uint64_t value) { _registers.__pswa = value; }
+
+private:
+  struct s390x_thread_state_t {
+    uint64_t __pswm;    // Problem Status Word: Mask
+    uint64_t __pswa;    // Problem Status Word: Address (PC)
+    uint64_t __gpr[16]; // General Purpose Registers
+    double __fpr[16];   // Floating-Point Registers
+  };
+
+  s390x_thread_state_t _registers;
+};
+
+inline Registers_s390x::Registers_s390x(const void *registers) {
+  static_assert((check_fit<Registers_s390x, unw_context_t>::does_fit),
+                "s390x registers do not fit into unw_context_t");
+  memcpy(&_registers, static_cast<const uint8_t *>(registers),
+         sizeof(_registers));
+}
+
+inline Registers_s390x::Registers_s390x() {
+  memset(&_registers, 0, sizeof(_registers));
+}
+
+inline bool Registers_s390x::validRegister(int regNum) const {
+  switch (regNum) {
+  case UNW_S390X_PSWM:
+  case UNW_S390X_PSWA:
+  case UNW_REG_IP:
+  case UNW_REG_SP:
+      return true;
+  }
+
+  if (regNum >= UNW_S390X_R0 && regNum <= UNW_S390X_R15)
+    return true;
+
+  return false;
+}
+
+inline uint64_t Registers_s390x::getRegister(int regNum) const {
+  if (regNum >= UNW_S390X_R0 && regNum <= UNW_S390X_R15)
+    return _registers.__gpr[regNum - UNW_S390X_R0];
+
+  switch (regNum) {
+  case UNW_S390X_PSWM:
+    return _registers.__pswm;
+  case UNW_S390X_PSWA:
+  case UNW_REG_IP:
+    return _registers.__pswa;
+  case UNW_REG_SP:
+    return _registers.__gpr[15];
+  }
+  _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline void Registers_s390x::setRegister(int regNum, uint64_t value) {
+  if (regNum >= UNW_S390X_R0 && regNum <= UNW_S390X_R15) {
+    _registers.__gpr[regNum - UNW_S390X_R0] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_S390X_PSWM:
+    _registers.__pswm = value;
+    return;
+  case UNW_S390X_PSWA:
+  case UNW_REG_IP:
+    _registers.__pswa = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__gpr[15] = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline bool Registers_s390x::validFloatRegister(int regNum) const {
+  return regNum >= UNW_S390X_F0 && regNum <= UNW_S390X_F15;
+}
+
+inline double Registers_s390x::getFloatRegister(int regNum) const {
+  // NOTE: FPR DWARF register numbers are not consecutive.
+  switch (regNum) {
+  case UNW_S390X_F0:
+    return _registers.__fpr[0];
+  case UNW_S390X_F1:
+    return _registers.__fpr[1];
+  case UNW_S390X_F2:
+    return _registers.__fpr[2];
+  case UNW_S390X_F3:
+    return _registers.__fpr[3];
+  case UNW_S390X_F4:
+    return _registers.__fpr[4];
+  case UNW_S390X_F5:
+    return _registers.__fpr[5];
+  case UNW_S390X_F6:
+    return _registers.__fpr[6];
+  case UNW_S390X_F7:
+    return _registers.__fpr[7];
+  case UNW_S390X_F8:
+    return _registers.__fpr[8];
+  case UNW_S390X_F9:
+    return _registers.__fpr[9];
+  case UNW_S390X_F10:
+    return _registers.__fpr[10];
+  case UNW_S390X_F11:
+    return _registers.__fpr[11];
+  case UNW_S390X_F12:
+    return _registers.__fpr[12];
+  case UNW_S390X_F13:
+    return _registers.__fpr[13];
+  case UNW_S390X_F14:
+    return _registers.__fpr[14];
+  case UNW_S390X_F15:
+    return _registers.__fpr[15];
+  }
+  _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline void Registers_s390x::setFloatRegister(int regNum, double value) {
+  // NOTE: FPR DWARF register numbers are not consecutive.
+  switch (regNum) {
+  case UNW_S390X_F0:
+    _registers.__fpr[0] = value;
+    return;
+  case UNW_S390X_F1:
+    _registers.__fpr[1] = value;
+    return;
+  case UNW_S390X_F2:
+    _registers.__fpr[2] = value;
+    return;
+  case UNW_S390X_F3:
+    _registers.__fpr[3] = value;
+    return;
+  case UNW_S390X_F4:
+    _registers.__fpr[4] = value;
+    return;
+  case UNW_S390X_F5:
+    _registers.__fpr[5] = value;
+    return;
+  case UNW_S390X_F6:
+    _registers.__fpr[6] = value;
+    return;
+  case UNW_S390X_F7:
+    _registers.__fpr[7] = value;
+    return;
+  case UNW_S390X_F8:
+    _registers.__fpr[8] = value;
+    return;
+  case UNW_S390X_F9:
+    _registers.__fpr[9] = value;
+    return;
+  case UNW_S390X_F10:
+    _registers.__fpr[10] = value;
+    return;
+  case UNW_S390X_F11:
+    _registers.__fpr[11] = value;
+    return;
+  case UNW_S390X_F12:
+    _registers.__fpr[12] = value;
+    return;
+  case UNW_S390X_F13:
+    _registers.__fpr[13] = value;
+    return;
+  case UNW_S390X_F14:
+    _registers.__fpr[14] = value;
+    return;
+  case UNW_S390X_F15:
+    _registers.__fpr[15] = value;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported s390x register");
+}
+
+inline bool Registers_s390x::validVectorRegister(int /*regNum*/) const {
+  return false;
+}
+
+inline v128 Registers_s390x::getVectorRegister(int /*regNum*/) const {
+  _LIBUNWIND_ABORT("s390x vector support not implemented");
+}
+
+inline void Registers_s390x::setVectorRegister(int /*regNum*/, v128 /*value*/) {
+  _LIBUNWIND_ABORT("s390x vector support not implemented");
+}
+
+inline const char *Registers_s390x::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "ip";
+  case UNW_REG_SP:
+    return "sp";
+  case UNW_S390X_R0:
+    return "r0";
+  case UNW_S390X_R1:
+    return "r1";
+  case UNW_S390X_R2:
+    return "r2";
+  case UNW_S390X_R3:
+    return "r3";
+  case UNW_S390X_R4:
+    return "r4";
+  case UNW_S390X_R5:
+    return "r5";
+  case UNW_S390X_R6:
+    return "r6";
+  case UNW_S390X_R7:
+    return "r7";
+  case UNW_S390X_R8:
+    return "r8";
+  case UNW_S390X_R9:
+    return "r9";
+  case UNW_S390X_R10:
+    return "r10";
+  case UNW_S390X_R11:
+    return "r11";
+  case UNW_S390X_R12:
+    return "r12";
+  case UNW_S390X_R13:
+    return "r13";
+  case UNW_S390X_R14:
+    return "r14";
+  case UNW_S390X_R15:
+    return "r15";
+  case UNW_S390X_F0:
+    return "f0";
+  case UNW_S390X_F1:
+    return "f1";
+  case UNW_S390X_F2:
+    return "f2";
+  case UNW_S390X_F3:
+    return "f3";
+  case UNW_S390X_F4:
+    return "f4";
+  case UNW_S390X_F5:
+    return "f5";
+  case UNW_S390X_F6:
+    return "f6";
+  case UNW_S390X_F7:
+    return "f7";
+  case UNW_S390X_F8:
+    return "f8";
+  case UNW_S390X_F9:
+    return "f9";
+  case UNW_S390X_F10:
+    return "f10";
+  case UNW_S390X_F11:
+    return "f11";
+  case UNW_S390X_F12:
+    return "f12";
+  case UNW_S390X_F13:
+    return "f13";
+  case UNW_S390X_F14:
+    return "f14";
+  case UNW_S390X_F15:
+    return "f15";
+  }
+  return "unknown register";
+}
+#endif // _LIBUNWIND_TARGET_S390X
+
+
 } // namespace libunwind
 
 #endif // __REGISTERS_HPP__

diff  --git a/libunwind/src/UnwindCursor.hpp b/libunwind/src/UnwindCursor.hpp
index 29ded5c4e78ed..655e41d81d5eb 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1220,6 +1220,12 @@ class UnwindCursor : public AbstractUnwindCursor{
   }
 #endif
 
+#if defined (_LIBUNWIND_TARGET_S390X)
+  compact_unwind_encoding_t dwarfEncoding(Registers_s390x &) const {
+    return 0;
+  }
+#endif
+
 #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
 
 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)

diff  --git a/libunwind/src/UnwindRegistersRestore.S b/libunwind/src/UnwindRegistersRestore.S
index b4843c912b0bd..eeb64534966df 100644
--- a/libunwind/src/UnwindRegistersRestore.S
+++ b/libunwind/src/UnwindRegistersRestore.S
@@ -1252,6 +1252,43 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
 
   ret                       // jump to ra
 
+#elif defined(__s390x__)
+
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
+//
+// void libunwind::Registers_s390x::jumpto()
+//
+// On entry:
+//  thread_state pointer is in r2
+//
+
+  // Skip PSWM, but load PSWA into r1
+  lg %r1, 8(%r2)
+
+  // Restore FPRs
+  ld %f0, 144(%r2)
+  ld %f1, 152(%r2)
+  ld %f2, 160(%r2)
+  ld %f3, 168(%r2)
+  ld %f4, 176(%r2)
+  ld %f5, 184(%r2)
+  ld %f6, 192(%r2)
+  ld %f7, 200(%r2)
+  ld %f8, 208(%r2)
+  ld %f9, 216(%r2)
+  ld %f10, 224(%r2)
+  ld %f11, 232(%r2)
+  ld %f12, 240(%r2)
+  ld %f13, 248(%r2)
+  ld %f14, 256(%r2)
+  ld %f15, 264(%r2)
+
+  // Restore GPRs - skipping %r0 and %r1
+  lmg  %r2, %r15, 32(%r2)
+
+  // Return to PSWA (was loaded into %r1 above)
+  br %r1
+
 #endif
 
 #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */

diff  --git a/libunwind/src/UnwindRegistersSave.S b/libunwind/src/UnwindRegistersSave.S
index 0cfc7b565863e..f57dd637dd9d8 100644
--- a/libunwind/src/UnwindRegistersSave.S
+++ b/libunwind/src/UnwindRegistersSave.S
@@ -1179,6 +1179,49 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 
   li     a0, 0  // return UNW_ESUCCESS
   ret           // jump to ra
+
+#elif defined(__s390x__)
+
+//
+// extern int __unw_getcontext(unw_context_t* thread_state)
+//
+// On entry:
+//  thread_state pointer is in r2
+//
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+
+  // Save GPRs
+  stmg %r0, %r15, 16(%r2)
+
+  // Save PSWM
+  epsw %r0, %r1
+  stm %r0, %r1, 0(%r2)
+
+  // Store return address as PSWA
+  stg %r14, 8(%r2)
+
+  // Save FPRs
+  std %f0, 144(%r2)
+  std %f1, 152(%r2)
+  std %f2, 160(%r2)
+  std %f3, 168(%r2)
+  std %f4, 176(%r2)
+  std %f5, 184(%r2)
+  std %f6, 192(%r2)
+  std %f7, 200(%r2)
+  std %f8, 208(%r2)
+  std %f9, 216(%r2)
+  std %f10, 224(%r2)
+  std %f11, 232(%r2)
+  std %f12, 240(%r2)
+  std %f13, 248(%r2)
+  std %f14, 256(%r2)
+  std %f15, 264(%r2)
+
+  // Return UNW_ESUCCESS
+  lghi %r2, 0
+  br %r14
+
 #endif
 
   WEAK_ALIAS(__unw_getcontext, unw_getcontext)

diff  --git a/libunwind/src/config.h b/libunwind/src/config.h
index e751860bd936e..cc41b817acf60 100644
--- a/libunwind/src/config.h
+++ b/libunwind/src/config.h
@@ -115,7 +115,7 @@
 #if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) ||        \
     (!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) ||       \
     defined(__mips__) || defined(__riscv) || defined(__hexagon__) ||           \
-    defined(__sparc__)
+    defined(__sparc__) || defined(__s390x__)
 #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
 #define _LIBUNWIND_BUILD_ZERO_COST_APIS
 #endif

diff  --git a/libunwind/src/libunwind.cpp b/libunwind/src/libunwind.cpp
index 21aa42680e5b7..b8b41ff25e54f 100644
--- a/libunwind/src/libunwind.cpp
+++ b/libunwind/src/libunwind.cpp
@@ -75,6 +75,8 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
 # define REGISTER_KIND Registers_riscv
 #elif defined(__ve__)
 # define REGISTER_KIND Registers_ve
+#elif defined(__s390x__)
+# define REGISTER_KIND Registers_s390x
 #else
 # error Architecture not supported
 #endif


        


More information about the cfe-commits mailing list