Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/llvm/llvm-project.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Weigand <ulrich.weigand@de.ibm.com>2022-05-02 15:35:29 +0300
committerUlrich Weigand <ulrich.weigand@de.ibm.com>2022-05-02 15:35:29 +0300
commit364c5023d2ce1617c706b185892ddfaa2fd4d166 (patch)
tree3c7c9302546a09f6323848c7470bf0df9d68cde6 /libunwind
parentc7662dc3e52801ec824d8473278fb976107d3e57 (diff)
[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
Diffstat (limited to 'libunwind')
-rw-r--r--libunwind/include/__libunwind_config.h7
-rw-r--r--libunwind/include/libunwind.h42
-rw-r--r--libunwind/src/Registers.hpp288
-rw-r--r--libunwind/src/UnwindCursor.hpp6
-rw-r--r--libunwind/src/UnwindRegistersRestore.S37
-rw-r--r--libunwind/src/UnwindRegistersSave.S43
-rw-r--r--libunwind/src/config.h2
-rw-r--r--libunwind/src/libunwind.cpp2
8 files changed, 426 insertions, 1 deletions
diff --git a/libunwind/include/__libunwind_config.h b/libunwind/include/__libunwind_config.h
index 30f5e0a23d08..e626567d4e59 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 a69e72fc132d..3d8fd2146ebb 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 32c13e6c9a24..28c617f34999 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 29ded5c4e78e..655e41d81d5e 100644
--- a/libunwind/src/UnwindCursor.hpp
+++ b/libunwind/src/UnwindCursor.hpp
@@ -1220,6 +1220,12 @@ private:
}
#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 b4843c912b0b..eeb64534966d 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 0cfc7b565863..f57dd637dd9d 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 e751860bd936..cc41b817acf6 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 21aa42680e5b..b8b41ff25e54 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