Commit 2f635c3ce9

Andrew Kelley <andrew@ziglang.org>
2022-08-05 03:09:10
update libunwind to LLVM 15
release/15.x commit 134fd359a5d884f16662a9edd22ab24feeb1498c
1 parent c0d9578
lib/libunwind/include/__libunwind_config.h
@@ -9,8 +9,10 @@
 #ifndef ____LIBUNWIND_CONFIG_H__
 #define ____LIBUNWIND_CONFIG_H__
 
+#define _LIBUNWIND_VERSION 15000
+
 #if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
-    !defined(__ARM_DWARF_EH__)
+    !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
 #define _LIBUNWIND_ARM_EHABI
 #endif
 
@@ -27,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__)
@@ -158,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
@@ -176,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
lib/libunwind/include/libunwind.h
@@ -81,7 +81,7 @@ typedef struct unw_addr_space *unw_addr_space_t;
 
 typedef int unw_regnum_t;
 typedef uintptr_t unw_word_t;
-#if defined(__arm__) && !defined(__ARM_DWARF_EH__)
+#if defined(__arm__) && !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
 typedef uint64_t unw_fpreg_t;
 #else
 typedef double unw_fpreg_t;
@@ -120,6 +120,9 @@ extern int unw_resume(unw_cursor_t *) LIBUNWIND_AVAIL;
 extern void unw_save_vfp_as_X(unw_cursor_t *) LIBUNWIND_AVAIL;
 #endif
 
+#ifdef _AIX
+extern uintptr_t unw_get_data_rel_base(unw_cursor_t *) LIBUNWIND_AVAIL;
+#endif
 
 extern const char *unw_regname(unw_cursor_t *, unw_regnum_t) LIBUNWIND_AVAIL;
 extern int unw_get_proc_info(unw_cursor_t *, unw_proc_info_t *) LIBUNWIND_AVAIL;
@@ -1174,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
lib/libunwind/include/unwind.h
@@ -160,7 +160,7 @@ extern const void *_Unwind_Find_FDE(const void *pc, struct dwarf_eh_bases *);
 extern void *_Unwind_FindEnclosingFunction(void *pc);
 
 // Mac OS X does not support text-rel and data-rel addressing so these functions
-// are unimplemented
+// are unimplemented.
 extern uintptr_t _Unwind_GetDataRelBase(struct _Unwind_Context *context)
     LIBUNWIND_UNAVAIL;
 extern uintptr_t _Unwind_GetTextRelBase(struct _Unwind_Context *context)
lib/libunwind/src/AddressSpace.hpp
@@ -24,7 +24,7 @@
 #include "Registers.hpp"
 
 #ifndef _LIBUNWIND_USE_DLADDR
-  #if !defined(_LIBUNWIND_IS_BAREMETAL) && !defined(_WIN32)
+  #if !(defined(_LIBUNWIND_IS_BAREMETAL) || defined(_WIN32) || defined(_AIX))
     #define _LIBUNWIND_USE_DLADDR 1
   #else
     #define _LIBUNWIND_USE_DLADDR 0
@@ -45,6 +45,13 @@ struct EHABIIndexEntry {
 };
 #endif
 
+#if defined(_AIX)
+namespace libunwind {
+char *getFuncNameFromTBTable(uintptr_t pc, uint16_t &NameLen,
+                             unw_word_t *offset);
+}
+#endif
+
 #ifdef __APPLE__
 
   struct dyld_unwind_sections
@@ -544,6 +551,7 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
     DWORD err = GetLastError();
     _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: EnumProcessModules failed, "
                                "returned error %d", (int)err);
+    (void)err;
     return false;
   }
 
@@ -580,6 +588,11 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
   (void)targetAddr;
   (void)info;
   return true;
+#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+  // The traceback table is used for unwinding.
+  (void)targetAddr;
+  (void)info;
+  return true;
 #elif defined(_LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX)
   int length = 0;
   info.arm_section =
@@ -596,7 +609,6 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
   return false;
 }
 
-
 inline bool LocalAddressSpace::findOtherFDE(pint_t targetAddr, pint_t &fde) {
   // TO DO: if OS has way to dynamically register FDEs, check that.
   (void)targetAddr;
@@ -616,6 +628,13 @@ inline bool LocalAddressSpace::findFunctionName(pint_t addr, char *buf,
       return true;
     }
   }
+#elif defined(_AIX)
+  uint16_t nameLen;
+  char *funcName = getFuncNameFromTBTable(addr, nameLen, offset);
+  if (funcName != NULL) {
+    snprintf(buf, bufLen, "%.*s", nameLen, funcName);
+    return true;
+  }
 #else
   (void)addr;
   (void)buf;
lib/libunwind/src/assembly.h
@@ -67,7 +67,8 @@
 #define SEPARATOR ;
 #endif
 
-#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1)
+#if defined(__powerpc64__) && (!defined(_CALL_ELF) || _CALL_ELF == 1) &&       \
+    !defined(_AIX)
 #define PPC64_OPD1 .section .opd,"aw",@progbits SEPARATOR
 #define PPC64_OPD2 SEPARATOR \
   .p2align 3 SEPARATOR \
@@ -203,12 +204,57 @@
 
 #elif defined(__sparc__)
 
+#elif defined(_AIX)
+
+#if defined(__powerpc64__)
+#define VBYTE_LEN 8
+#define CSECT_ALIGN 3
+#else
+#define VBYTE_LEN 4
+#define CSECT_ALIGN 2
+#endif
+
+// clang-format off
+#define DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(name, aliasname)              \
+  .csect .text[PR], 2 SEPARATOR                                                \
+  .csect .name[PR], 2 SEPARATOR                                                \
+  .globl name[DS] SEPARATOR                                                    \
+  .globl .name[PR] SEPARATOR                                                   \
+  .align 4 SEPARATOR                                                           \
+  .csect name[DS], CSECT_ALIGN SEPARATOR                                       \
+aliasname:                                                                     \
+  .vbyte VBYTE_LEN, .name[PR] SEPARATOR                                        \
+  .vbyte VBYTE_LEN, TOC[TC0] SEPARATOR                                         \
+  .vbyte VBYTE_LEN, 0 SEPARATOR                                                \
+  .weak  aliasname SEPARATOR                                                   \
+  .weak  .aliasname SEPARATOR                                                  \
+  .csect .name[PR], 2 SEPARATOR                                                \
+.aliasname:                                                                    \
+
+#define WEAK_ALIAS(name, aliasname)
+#define NO_EXEC_STACK_DIRECTIVE
+
+// clang-format on
 #else
 
 #error Unsupported target
 
 #endif
 
+#if defined(_AIX)
+  // clang-format off
+#define DEFINE_LIBUNWIND_FUNCTION(name)                                        \
+  .globl name[DS] SEPARATOR                                                    \
+  .globl .name SEPARATOR                                                       \
+  .align 4 SEPARATOR                                                           \
+  .csect name[DS], CSECT_ALIGN SEPARATOR                                       \
+  .vbyte VBYTE_LEN, .name SEPARATOR                                            \
+  .vbyte VBYTE_LEN, TOC[TC0] SEPARATOR                                         \
+  .vbyte VBYTE_LEN, 0 SEPARATOR                                                \
+  .csect .text[PR], 2 SEPARATOR                                                \
+.name:
+  // clang-format on
+#else
 #define DEFINE_LIBUNWIND_FUNCTION(name)                                        \
   .globl SYMBOL_NAME(name) SEPARATOR                                           \
   HIDDEN_SYMBOL(SYMBOL_NAME(name)) SEPARATOR                                   \
@@ -217,6 +263,7 @@
   SYMBOL_NAME(name):                                                           \
   PPC64_OPD2                                                                   \
   AARCH64_BTI
+#endif
 
 #if defined(__arm__)
 #if !defined(__ARM_ARCH)
lib/libunwind/src/cet_unwind.h
@@ -36,6 +36,6 @@
 #endif
 
 extern void *__libunwind_cet_get_registers(unw_cursor_t *);
-extern void *__libunwind_cet_get_jump_target();
+extern void *__libunwind_cet_get_jump_target(void);
 
 #endif
lib/libunwind/src/config.h
@@ -43,6 +43,9 @@
   // For ARM EHABI, Bionic didn't implement dl_iterate_phdr until API 21. After
   // API 21, dl_iterate_phdr exists, but dl_unwind_find_exidx is much faster.
   #define _LIBUNWIND_USE_DL_UNWIND_FIND_EXIDX 1
+#elif defined(_AIX)
+// The traceback table at the end of each function is used for unwinding.
+#define _LIBUNWIND_SUPPORT_TBTAB_UNWIND 1
 #else
   // Assume an ELF system with a dl_iterate_phdr function.
   #define _LIBUNWIND_USE_DL_ITERATE_PHDR 1
@@ -57,7 +60,7 @@
   #define _LIBUNWIND_EXPORT
   #define _LIBUNWIND_HIDDEN
 #else
-  #if !defined(__ELF__) && !defined(__MACH__)
+  #if !defined(__ELF__) && !defined(__MACH__) && !defined(_AIX)
     #define _LIBUNWIND_EXPORT __declspec(dllexport)
     #define _LIBUNWIND_HIDDEN
   #else
@@ -80,7 +83,7 @@
   __asm__(".globl " SYMBOL_NAME(aliasname));                                   \
   __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name));                     \
   _LIBUNWIND_ALIAS_VISIBILITY(SYMBOL_NAME(aliasname))
-#elif defined(__ELF__)
+#elif defined(__ELF__) || defined(_AIX)
 #define _LIBUNWIND_WEAK_ALIAS(name, aliasname)                                 \
   extern "C" _LIBUNWIND_EXPORT __typeof(name) aliasname                        \
       __attribute__((weak, alias(#name)));
@@ -112,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
@@ -188,9 +191,9 @@
   #ifdef __cplusplus
     extern "C" {
   #endif
-    extern  bool logAPIs();
-    extern  bool logUnwinding();
-    extern  bool logDWARF();
+    extern  bool logAPIs(void);
+    extern  bool logUnwinding(void);
+    extern  bool logDWARF(void);
   #ifdef __cplusplus
     }
   #endif
lib/libunwind/src/DwarfInstructions.hpp
@@ -72,6 +72,10 @@ private:
     assert(0 && "getCFA(): unknown location");
     __builtin_unreachable();
   }
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+  static bool getRA_SIGN_STATE(A &addressSpace, R registers, pint_t cfa,
+                               PrologInfo &prolog);
+#endif
 };
 
 template <typename R>
@@ -166,6 +170,21 @@ v128 DwarfInstructions<A, R>::getSavedVectorRegister(
   }
   _LIBUNWIND_ABORT("unsupported restore location for vector register");
 }
+#if defined(_LIBUNWIND_TARGET_AARCH64)
+template <typename A, typename R>
+bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
+                                               pint_t cfa, PrologInfo &prolog) {
+  pint_t raSignState;
+  auto regloc = prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE];
+  if (regloc.location == CFI_Parser<A>::kRegisterUnused)
+    raSignState = static_cast<pint_t>(regloc.value);
+  else
+    raSignState = getSavedRegister(addressSpace, registers, cfa, regloc);
+
+  // Only bit[0] is meaningful.
+  return raSignState & 0x01;
+}
+#endif
 
 template <typename A, typename R>
 int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
@@ -194,9 +213,10 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
       newRegisters.setSP(cfa);
 
       pint_t returnAddress = 0;
-      const int lastReg = R::lastDwarfRegNum();
-      assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >= lastReg &&
-             "register range too large");
+      constexpr int lastReg = R::lastDwarfRegNum();
+      static_assert(static_cast<int>(CFI_Parser<A>::kMaxRegisterNumber) >=
+                        lastReg,
+                    "register range too large");
       assert(lastReg >= (int)cieInfo.returnAddressRegister &&
              "register range does not contain return address register");
       for (int i = 0; i <= lastReg; ++i) {
@@ -235,7 +255,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
       // restored. autia1716 is used instead of autia as autia1716 assembles
       // to a NOP on pre-v8.3a architectures.
       if ((R::getArch() == REGISTERS_ARM64) &&
-          prolog.savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value &&
+          getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
           returnAddress != 0) {
 #if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
         return UNW_ECROSSRASIGNING;
lib/libunwind/src/EHHeaderParser.hpp
@@ -57,7 +57,8 @@ bool EHHeaderParser<A>::decodeEHHdr(A &addressSpace, pint_t ehHdrStart,
   pint_t p = ehHdrStart;
   uint8_t version = addressSpace.get8(p++);
   if (version != 1) {
-    _LIBUNWIND_LOG0("Unsupported .eh_frame_hdr version");
+    _LIBUNWIND_LOG("unsupported .eh_frame_hdr version: %" PRIu8 " at %" PRIx64,
+                   version, static_cast<uint64_t>(ehHdrStart));
     return false;
   }
 
lib/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
@@ -247,6 +249,16 @@ _LIBUNWIND_HIDDEN int __unw_is_signal_frame(unw_cursor_t *cursor) {
 }
 _LIBUNWIND_WEAK_ALIAS(__unw_is_signal_frame, unw_is_signal_frame)
 
+#ifdef _AIX
+_LIBUNWIND_EXPORT uintptr_t __unw_get_data_rel_base(unw_cursor_t *cursor) {
+  _LIBUNWIND_TRACE_API("unw_get_data_rel_base(cursor=%p)",
+                       static_cast<void *>(cursor));
+  AbstractUnwindCursor *co = reinterpret_cast<AbstractUnwindCursor *>(cursor);
+  return co->getDataRelBase();
+}
+_LIBUNWIND_WEAK_ALIAS(__unw_get_data_rel_base, unw_get_data_rel_base)
+#endif
+
 #ifdef __arm__
 // Save VFP registers d0-d15 using FSTMIADX instead of FSTMIADD
 _LIBUNWIND_HIDDEN void __unw_save_vfp_as_X(unw_cursor_t *cursor) {
lib/libunwind/src/libunwind_ext.h
@@ -43,6 +43,10 @@ extern int __unw_is_fpreg(unw_cursor_t *, unw_regnum_t);
 extern int __unw_is_signal_frame(unw_cursor_t *);
 extern int __unw_get_proc_name(unw_cursor_t *, char *, size_t, unw_word_t *);
 
+#if defined(_AIX)
+extern uintptr_t __unw_get_data_rel_base(unw_cursor_t *);
+#endif
+
 // SPI
 extern void __unw_iterate_dwarf_unwind_cache(void (*func)(
     unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh));
lib/libunwind/src/Registers.hpp
@@ -39,6 +39,7 @@ enum {
   REGISTERS_HEXAGON,
   REGISTERS_RISCV,
   REGISTERS_VE,
+  REGISTERS_S390X,
 };
 
 #if defined(_LIBUNWIND_TARGET_I386)
@@ -69,7 +70,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto() { __libunwind_Registers_x86_jumpto(this); }
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86;
+  }
   static int  getArch() { return REGISTERS_X86; }
 
   uint32_t  getSP() const          { return _registers.__esp; }
@@ -285,7 +288,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto() { __libunwind_Registers_x86_64_jumpto(this); }
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_X86_64;
+  }
   static int  getArch() { return REGISTERS_X86_64; }
 
   uint64_t  getSP() const          { return _registers.__rsp; }
@@ -602,13 +607,17 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC;
+  }
   static int  getArch() { return REGISTERS_PPC; }
 
   uint64_t  getSP() const         { return _registers.__r1; }
   void      setSP(uint32_t value) { _registers.__r1 = value; }
   uint64_t  getIP() const         { return _registers.__srr0; }
   void      setIP(uint32_t value) { _registers.__srr0 = value; }
+  uint64_t  getCR() const         { return _registers.__cr; }
+  void      setCR(uint32_t value) { _registers.__cr = value; }
 
 private:
   struct ppc_thread_state_t {
@@ -1168,13 +1177,17 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64;
+  }
   static int  getArch() { return REGISTERS_PPC64; }
 
   uint64_t  getSP() const         { return _registers.__r1; }
   void      setSP(uint64_t value) { _registers.__r1 = value; }
   uint64_t  getIP() const         { return _registers.__srr0; }
   void      setIP(uint64_t value) { _registers.__srr0 = value; }
+  uint64_t  getCR() const         { return _registers.__cr; }
+  void      setCR(uint64_t value) { _registers.__cr = value; }
 
 private:
   struct ppc64_thread_state_t {
@@ -1813,7 +1826,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto() { __libunwind_Registers_arm64_jumpto(this); }
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64;
+  }
   static int  getArch() { return REGISTERS_ARM64; }
 
   uint64_t  getSP() const         { return _registers.__sp; }
@@ -2103,7 +2118,9 @@ public:
     restoreSavedFloatRegisters();
     restoreCoreAndJumpTo();
   }
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM;
+  }
   static int  getArch() { return REGISTERS_ARM; }
 
   uint32_t  getSP() const         { return _registers.__sp; }
@@ -2603,7 +2620,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K;
+  }
   static int  getArch() { return REGISTERS_OR1K; }
 
   uint64_t  getSP() const         { return _registers.__r[1]; }
@@ -2800,7 +2819,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS;
+  }
   static int  getArch() { return REGISTERS_MIPS_O32; }
 
   uint32_t  getSP() const         { return _registers.__r[29]; }
@@ -3127,7 +3148,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS;
+  }
   static int  getArch() { return REGISTERS_MIPS_NEWABI; }
 
   uint64_t  getSP() const         { return _registers.__r[29]; }
@@ -3422,7 +3445,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC;
+  }
   static int  getArch() { return REGISTERS_SPARC; }
 
   uint64_t  getSP() const         { return _registers.__regs[UNW_SPARC_O6]; }
@@ -3606,7 +3631,7 @@ public:
   void setVectorRegister(int num, v128 value);
   const char *getRegisterName(int num);
   void jumpto();
-  static int lastDwarfRegNum() {
+  static constexpr int lastDwarfRegNum() {
     return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64;
   }
   static int getArch() { return REGISTERS_SPARC64; }
@@ -3791,7 +3816,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON;
+  }
   static int  getArch() { return REGISTERS_HEXAGON; }
 
   uint32_t  getSP() const         { return _registers.__r[UNW_HEXAGON_R29]; }
@@ -4004,7 +4031,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV;
+  }
   static int  getArch() { return REGISTERS_RISCV; }
 
   reg_t       getSP() const { return _registers[2]; }
@@ -4290,7 +4319,9 @@ public:
   void        setVectorRegister(int num, v128 value);
   static const char *getRegisterName(int num);
   void        jumpto();
-  static int  lastDwarfRegNum() { return _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE; }
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE;
+  }
   static int  getArch() { return REGISTERS_VE; }
 
   uint64_t  getSP() const         { return _registers.__s[11]; }
@@ -4712,6 +4743,295 @@ 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 constexpr 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__
lib/libunwind/src/Unwind-EHABI.cpp
@@ -432,10 +432,11 @@ _Unwind_VRS_Interpret(_Unwind_Context *context, const uint32_t *data,
       uint32_t sp;
       uint32_t pac;
       _Unwind_VRS_Get(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
-      _Unwind_VRS_Get(context, _UVRSC_PSEUDO, UNW_ARM_RA_AUTH_CODE,
-                      _UVRSD_UINT32, &pac);
+      _Unwind_VRS_Get(context, _UVRSC_PSEUDO, 0, _UVRSD_UINT32, &pac);
       __asm__ __volatile__("autg %0, %1, %2" : : "r"(pac), "r"(lr), "r"(sp) :);
     }
+#else
+    (void)hasReturnAddrAuthCode;
 #endif
     _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_IP, _UVRSD_UINT32, &lr);
   }
@@ -1136,8 +1137,7 @@ _Unwind_VRS_Pop(_Unwind_Context *context, _Unwind_VRS_RegClass regclass,
       }
       uint32_t pac = *sp++;
       _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_SP, _UVRSD_UINT32, &sp);
-      return _Unwind_VRS_Set(context, _UVRSC_CORE, UNW_ARM_RA_AUTH_CODE,
-                             _UVRSD_UINT32, &pac);
+      return _Unwind_VRS_Set(context, _UVRSC_PSEUDO, 0, _UVRSD_UINT32, &pac);
     }
   }
   _LIBUNWIND_ABORT("unsupported register class");
@@ -1193,6 +1193,7 @@ _Unwind_DeleteException(_Unwind_Exception *exception_object) {
 extern "C" _LIBUNWIND_EXPORT _Unwind_Reason_Code
 __gnu_unwind_frame(_Unwind_Exception *exception_object,
                    struct _Unwind_Context *context) {
+  (void)exception_object;
   unw_cursor_t *cursor = (unw_cursor_t *)context;
   switch (__unw_step(cursor)) {
   case UNW_STEP_SUCCESS:
lib/libunwind/src/Unwind-seh.cpp
@@ -104,7 +104,7 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
   if (!ctx) {
     __unw_init_seh(&cursor, disp->ContextRecord);
     __unw_seh_set_disp_ctx(&cursor, disp);
-    __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc - 1);
+    __unw_set_reg(&cursor, UNW_REG_IP, disp->ControlPc);
     ctx = (struct _Unwind_Context *)&cursor;
 
     if (!IS_UNWINDING(ms_exc->ExceptionFlags)) {
@@ -255,8 +255,8 @@ unwind_phase2_forced(unw_context_t *uc,
           (frameInfo.start_ip + offset > frameInfo.end_ip))
         functionName = ".anonymous.";
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIx64
-          ", func=%s, lsda=0x%" PRIx64 ", personality=0x%" PRIx64,
+          "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
+          ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
           (void *)exception_object, frameInfo.start_ip, functionName,
           frameInfo.lsda, frameInfo.handler);
     }
lib/libunwind/src/Unwind_AIXExtras.cpp
@@ -0,0 +1,63 @@
+//===--------------------- Unwind_AIXExtras.cpp -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//
+//===----------------------------------------------------------------------===//
+
+// This file is only used for AIX.
+#if defined(_AIX)
+
+#include "config.h"
+#include "libunwind_ext.h"
+#include <sys/debug.h>
+
+namespace libunwind {
+// getFuncNameFromTBTable
+// Get the function name from its traceback table.
+char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
+                             unw_word_t *Offset) {
+  uint32_t *p = reinterpret_cast<uint32_t *>(Pc);
+  *Offset = 0;
+
+  // Keep looking forward until a word of 0 is found. The traceback
+  // table starts at the following word.
+  while (*p)
+    p++;
+  tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
+
+  if (!TBTable->tb.name_present)
+    return NULL;
+
+  // Get to the name of the function.
+  p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
+
+  // Skip field parminfo if it exists.
+  if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
+    p++;
+
+  // If the tb_offset field exisits, get the offset from the start of
+  // the function to pc. Skip the field.
+  if (TBTable->tb.has_tboff) {
+    unw_word_t StartIp =
+        reinterpret_cast<uintptr_t>(TBTable) - *p - sizeof(uint32_t);
+    *Offset = Pc - StartIp;
+    p++;
+  }
+
+  // Skip field hand_mask if it exists.
+  if (TBTable->tb.int_hndl)
+    p++;
+
+  // Skip fields ctl_info and ctl_info_disp if they exist.
+  if (TBTable->tb.has_ctl) {
+    p += 1 + *p;
+  }
+
+  NameLen = *(reinterpret_cast<uint16_t *>(p));
+  return reinterpret_cast<char *>(p) + sizeof(uint16_t);
+}
+} // namespace libunwind
+#endif // defined(_AIX)
lib/libunwind/src/UnwindCursor.hpp
@@ -24,6 +24,19 @@
 #ifdef __APPLE__
   #include <mach-o/dyld.h>
 #endif
+#ifdef _AIX
+#include <dlfcn.h>
+#include <sys/debug.h>
+#include <sys/pseg.h>
+#endif
+
+#if defined(_LIBUNWIND_TARGET_LINUX) &&                                        \
+    (defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_S390X))
+#include <sys/syscall.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#define _LIBUNWIND_CHECK_LINUX_SIGRETURN 1
+#endif
 
 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
 // Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and
@@ -451,6 +464,12 @@ public:
   virtual void saveVFPAsX() { _LIBUNWIND_ABORT("saveVFPAsX not implemented"); }
 #endif
 
+#ifdef _AIX
+  virtual uintptr_t getDataRelBase() {
+    _LIBUNWIND_ABORT("getDataRelBase not implemented");
+  }
+#endif
+
 #if defined(_LIBUNWIND_USE_CET)
   virtual void *get_registers() {
     _LIBUNWIND_ABORT("get_registers not implemented");
@@ -499,6 +518,14 @@ private:
   pint_t getLastPC() const { return _dispContext.ControlPc; }
   void setLastPC(pint_t pc) { _dispContext.ControlPc = pc; }
   RUNTIME_FUNCTION *lookUpSEHUnwindInfo(pint_t pc, pint_t *base) {
+#ifdef __arm__
+    // Remove the thumb bit; FunctionEntry ranges don't include the thumb bit.
+    pc &= ~1U;
+#endif
+    // If pc points exactly at the end of the range, we might resolve the
+    // next function instead. Decrement pc by 1 to fit inside the current
+    // function.
+    pc -= 1;
     _dispContext.FunctionEntry = RtlLookupFunctionEntry(pc,
                                                         &_dispContext.ImageBase,
                                                         _dispContext.HistoryTable);
@@ -844,7 +871,7 @@ void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
       uint32_t w;
       float f;
     } d;
-    d.f = value;
+    d.f = (float)value;
     _msContext.S[regNum - UNW_ARM_S0] = d.w;
   }
   if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) {
@@ -910,9 +937,14 @@ public:
   virtual void        saveVFPAsX();
 #endif
 
+#ifdef _AIX
+  virtual uintptr_t getDataRelBase();
+#endif
+
 #if defined(_LIBUNWIND_USE_CET)
   virtual void *get_registers() { return &_registers; }
 #endif
+
   // libunwind does not and should not depend on C++ library which means that we
   // need our own defition of inline placement new.
   static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
@@ -937,7 +969,7 @@ private:
   }
 #endif
 
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
   bool setInfoForSigReturn() {
     R dummy;
     return setInfoForSigReturn(dummy);
@@ -946,8 +978,14 @@ private:
     R dummy;
     return stepThroughSigReturn(dummy);
   }
+#if defined(_LIBUNWIND_TARGET_AARCH64)
   bool setInfoForSigReturn(Registers_arm64 &);
   int stepThroughSigReturn(Registers_arm64 &);
+#endif
+#if defined(_LIBUNWIND_TARGET_S390X)
+  bool setInfoForSigReturn(Registers_s390x &);
+  int stepThroughSigReturn(Registers_s390x &);
+#endif
   template <typename Registers> bool setInfoForSigReturn(Registers &) {
     return false;
   }
@@ -1204,6 +1242,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)
@@ -1220,13 +1264,23 @@ private:
   int stepWithSEHData() { /* FIXME: Implement */ return 0; }
 #endif // defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
 
+#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+  bool getInfoFromTBTable(pint_t pc, R &registers);
+  int stepWithTBTable(pint_t pc, tbtable *TBTable, R &registers,
+                      bool &isSignalFrame);
+  int stepWithTBTableData() {
+    return stepWithTBTable(reinterpret_cast<pint_t>(this->getReg(UNW_REG_IP)),
+                           reinterpret_cast<tbtable *>(_info.unwind_info),
+                           _registers, _isSignalFrame);
+  }
+#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
 
   A               &_addressSpace;
   R                _registers;
   unw_proc_info_t  _info;
   bool             _unwindInfoMissing;
   bool             _isSignalFrame;
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
   bool             _isSigReturn = false;
 #endif
 };
@@ -1292,6 +1346,13 @@ template <typename A, typename R> void UnwindCursor<A, R>::saveVFPAsX() {
 }
 #endif
 
+#ifdef _AIX
+template <typename A, typename R>
+uintptr_t UnwindCursor<A, R>::getDataRelBase() {
+  return reinterpret_cast<uintptr_t>(_info.extra);
+}
+#endif
+
 template <typename A, typename R>
 const char *UnwindCursor<A, R>::getRegisterName(int regNum) {
   return _registers.getRegisterName(regNum);
@@ -1912,20 +1973,517 @@ bool UnwindCursor<A, R>::getInfoFromSEH(pint_t pc) {
       _info.handler = 0;
     }
   }
-#elif defined(_LIBUNWIND_TARGET_ARM)
-  _info.end_ip = _info.start_ip + unwindEntry->FunctionLength;
-  _info.lsda = 0; // FIXME
-  _info.handler = 0; // FIXME
 #endif
   setLastPC(pc);
   return true;
 }
 #endif
 
+#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+// Masks for traceback table field xtbtable.
+enum xTBTableMask : uint8_t {
+  reservedBit = 0x02, // The traceback table was incorrectly generated if set
+                      // (see comments in function getInfoFromTBTable().
+  ehInfoBit = 0x08    // Exception handling info is present if set
+};
+
+enum frameType : unw_word_t {
+  frameWithXLEHStateTable = 0,
+  frameWithEHInfo = 1
+};
+
+extern "C" {
+typedef _Unwind_Reason_Code __xlcxx_personality_v0_t(int, _Unwind_Action,
+                                                     uint64_t,
+                                                     _Unwind_Exception *,
+                                                     struct _Unwind_Context *);
+__attribute__((__weak__)) __xlcxx_personality_v0_t __xlcxx_personality_v0;
+}
+
+static __xlcxx_personality_v0_t *xlcPersonalityV0;
+static RWMutex xlcPersonalityV0InitLock;
+
+template <typename A, typename R>
+bool UnwindCursor<A, R>::getInfoFromTBTable(pint_t pc, R &registers) {
+  uint32_t *p = reinterpret_cast<uint32_t *>(pc);
+
+  // Keep looking forward until a word of 0 is found. The traceback
+  // table starts at the following word.
+  while (*p)
+    ++p;
+  tbtable *TBTable = reinterpret_cast<tbtable *>(p + 1);
+
+  if (_LIBUNWIND_TRACING_UNWINDING) {
+    char functionBuf[512];
+    const char *functionName = functionBuf;
+    unw_word_t offset;
+    if (!getFunctionName(functionBuf, sizeof(functionBuf), &offset)) {
+      functionName = ".anonymous.";
+    }
+    _LIBUNWIND_TRACE_UNWINDING("%s: Look up traceback table of func=%s at %p",
+                               __func__, functionName,
+                               reinterpret_cast<void *>(TBTable));
+  }
+
+  // If the traceback table does not contain necessary info, bypass this frame.
+  if (!TBTable->tb.has_tboff)
+    return false;
+
+  // Structure tbtable_ext contains important data we are looking for.
+  p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
+
+  // Skip field parminfo if it exists.
+  if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
+    ++p;
+
+  // p now points to tb_offset, the offset from start of function to TB table.
+  unw_word_t start_ip =
+      reinterpret_cast<unw_word_t>(TBTable) - *p - sizeof(uint32_t);
+  unw_word_t end_ip = reinterpret_cast<unw_word_t>(TBTable);
+  ++p;
+
+  _LIBUNWIND_TRACE_UNWINDING("start_ip=%p, end_ip=%p\n",
+                             reinterpret_cast<void *>(start_ip),
+                             reinterpret_cast<void *>(end_ip));
+
+  // Skip field hand_mask if it exists.
+  if (TBTable->tb.int_hndl)
+    ++p;
+
+  unw_word_t lsda = 0;
+  unw_word_t handler = 0;
+  unw_word_t flags = frameType::frameWithXLEHStateTable;
+
+  if (TBTable->tb.lang == TB_CPLUSPLUS && TBTable->tb.has_ctl) {
+    // State table info is available. The ctl_info field indicates the
+    // number of CTL anchors. There should be only one entry for the C++
+    // state table.
+    assert(*p == 1 && "libunwind: there must be only one ctl_info entry");
+    ++p;
+    // p points to the offset of the state table into the stack.
+    pint_t stateTableOffset = *p++;
+
+    int framePointerReg;
+
+    // Skip fields name_len and name if exist.
+    if (TBTable->tb.name_present) {
+      const uint16_t name_len = *(reinterpret_cast<uint16_t *>(p));
+      p = reinterpret_cast<uint32_t *>(reinterpret_cast<char *>(p) + name_len +
+                                       sizeof(uint16_t));
+    }
+
+    if (TBTable->tb.uses_alloca)
+      framePointerReg = *(reinterpret_cast<char *>(p));
+    else
+      framePointerReg = 1; // default frame pointer == SP
+
+    _LIBUNWIND_TRACE_UNWINDING(
+        "framePointerReg=%d, framePointer=%p, "
+        "stateTableOffset=%#lx\n",
+        framePointerReg,
+        reinterpret_cast<void *>(_registers.getRegister(framePointerReg)),
+        stateTableOffset);
+    lsda = _registers.getRegister(framePointerReg) + stateTableOffset;
+
+    // Since the traceback table generated by the legacy XLC++ does not
+    // provide the location of the personality for the state table,
+    // function __xlcxx_personality_v0(), which is the personality for the state
+    // table and is exported from libc++abi, is directly assigned as the
+    // handler here. When a legacy XLC++ frame is encountered, the symbol
+    // is resolved dynamically using dlopen() to avoid hard dependency from
+    // libunwind on libc++abi.
+
+    // Resolve the function pointer to the state table personality if it has
+    // not already.
+    if (xlcPersonalityV0 == NULL) {
+      xlcPersonalityV0InitLock.lock();
+      if (xlcPersonalityV0 == NULL) {
+        // If libc++abi is statically linked in, symbol __xlcxx_personality_v0
+        // has been resolved at the link time.
+        xlcPersonalityV0 = &__xlcxx_personality_v0;
+        if (xlcPersonalityV0 == NULL) {
+          // libc++abi is dynamically linked. Resolve __xlcxx_personality_v0
+          // using dlopen().
+          const char libcxxabi[] = "libc++abi.a(libc++abi.so.1)";
+          void *libHandle;
+          libHandle = dlopen(libcxxabi, RTLD_MEMBER | RTLD_NOW);
+          if (libHandle == NULL) {
+            _LIBUNWIND_TRACE_UNWINDING("dlopen() failed with errno=%d\n",
+                                       errno);
+            assert(0 && "dlopen() failed");
+          }
+          xlcPersonalityV0 = reinterpret_cast<__xlcxx_personality_v0_t *>(
+              dlsym(libHandle, "__xlcxx_personality_v0"));
+          if (xlcPersonalityV0 == NULL) {
+            _LIBUNWIND_TRACE_UNWINDING("dlsym() failed with errno=%d\n", errno);
+            assert(0 && "dlsym() failed");
+          }
+          dlclose(libHandle);
+        }
+      }
+      xlcPersonalityV0InitLock.unlock();
+    }
+    handler = reinterpret_cast<unw_word_t>(xlcPersonalityV0);
+    _LIBUNWIND_TRACE_UNWINDING("State table: LSDA=%p, Personality=%p\n",
+                               reinterpret_cast<void *>(lsda),
+                               reinterpret_cast<void *>(handler));
+  } else if (TBTable->tb.longtbtable) {
+    // This frame has the traceback table extension. Possible cases are
+    // 1) a C++ frame that has the 'eh_info' structure; 2) a C++ frame that
+    // is not EH aware; or, 3) a frame of other languages. We need to figure out
+    // if the traceback table extension contains the 'eh_info' structure.
+    //
+    // We also need to deal with the complexity arising from some XL compiler
+    // versions use the wrong ordering of 'longtbtable' and 'has_vec' bits
+    // where the 'longtbtable' bit is meant to be the 'has_vec' bit and vice
+    // versa. For frames of code generated by those compilers, the 'longtbtable'
+    // bit may be set but there isn't really a traceback table extension.
+    //
+    // In </usr/include/sys/debug.h>, there is the following definition of
+    // 'struct tbtable_ext'. It is not really a structure but a dummy to
+    // collect the description of optional parts of the traceback table.
+    //
+    // struct tbtable_ext {
+    //   ...
+    //   char alloca_reg;        /* Register for alloca automatic storage */
+    //   struct vec_ext vec_ext; /* Vector extension (if has_vec is set) */
+    //   unsigned char xtbtable; /* More tbtable fields, if longtbtable is set*/
+    // };
+    //
+    // Depending on how the 'has_vec'/'longtbtable' bit is interpreted, the data
+    // following 'alloca_reg' can be treated either as 'struct vec_ext' or
+    // 'unsigned char xtbtable'. 'xtbtable' bits are defined in
+    // </usr/include/sys/debug.h> as flags. The 7th bit '0x02' is currently
+    // unused and should not be set. 'struct vec_ext' is defined in
+    // </usr/include/sys/debug.h> as follows:
+    //
+    // struct vec_ext {
+    //   unsigned vr_saved:6;      /* Number of non-volatile vector regs saved
+    //   */
+    //                             /* first register saved is assumed to be */
+    //                             /* 32 - vr_saved                         */
+    //   unsigned saves_vrsave:1;  /* Set if vrsave is saved on the stack */
+    //   unsigned has_varargs:1;
+    //   ...
+    // };
+    //
+    // Here, the 7th bit is used as 'saves_vrsave'. To determine whether it
+    // is 'struct vec_ext' or 'xtbtable' that follows 'alloca_reg',
+    // we checks if the 7th bit is set or not because 'xtbtable' should
+    // never have the 7th bit set. The 7th bit of 'xtbtable' will be reserved
+    // in the future to make sure the mitigation works. This mitigation
+    // is not 100% bullet proof because 'struct vec_ext' may not always have
+    // 'saves_vrsave' bit set.
+    //
+    // 'reservedBit' is defined in enum 'xTBTableMask' above as the mask for
+    // checking the 7th bit.
+
+    // p points to field name len.
+    uint8_t *charPtr = reinterpret_cast<uint8_t *>(p);
+
+    // Skip fields name_len and name if they exist.
+    if (TBTable->tb.name_present) {
+      const uint16_t name_len = *(reinterpret_cast<uint16_t *>(charPtr));
+      charPtr = charPtr + name_len + sizeof(uint16_t);
+    }
+
+    // Skip field alloc_reg if it exists.
+    if (TBTable->tb.uses_alloca)
+      ++charPtr;
+
+    // Check traceback table bit has_vec. Skip struct vec_ext if it exists.
+    if (TBTable->tb.has_vec)
+      // Note struct vec_ext does exist at this point because whether the
+      // ordering of longtbtable and has_vec bits is correct or not, both
+      // are set.
+      charPtr += sizeof(struct vec_ext);
+
+    // charPtr points to field 'xtbtable'. Check if the EH info is available.
+    // Also check if the reserved bit of the extended traceback table field
+    // 'xtbtable' is set. If it is, the traceback table was incorrectly
+    // generated by an XL compiler that uses the wrong ordering of 'longtbtable'
+    // and 'has_vec' bits and this is in fact 'struct vec_ext'. So skip the
+    // frame.
+    if ((*charPtr & xTBTableMask::ehInfoBit) &&
+        !(*charPtr & xTBTableMask::reservedBit)) {
+      // Mark this frame has the new EH info.
+      flags = frameType::frameWithEHInfo;
+
+      // eh_info is available.
+      charPtr++;
+      // The pointer is 4-byte aligned.
+      if (reinterpret_cast<uintptr_t>(charPtr) % 4)
+        charPtr += 4 - reinterpret_cast<uintptr_t>(charPtr) % 4;
+      uintptr_t *ehInfo =
+          reinterpret_cast<uintptr_t *>(*(reinterpret_cast<uintptr_t *>(
+              registers.getRegister(2) +
+              *(reinterpret_cast<uintptr_t *>(charPtr)))));
+
+      // ehInfo points to structure en_info. The first member is version.
+      // Only version 0 is currently supported.
+      assert(*(reinterpret_cast<uint32_t *>(ehInfo)) == 0 &&
+             "libunwind: ehInfo version other than 0 is not supported");
+
+      // Increment ehInfo to point to member lsda.
+      ++ehInfo;
+      lsda = *ehInfo++;
+
+      // enInfo now points to member personality.
+      handler = *ehInfo;
+
+      _LIBUNWIND_TRACE_UNWINDING("Range table: LSDA=%#lx, Personality=%#lx\n",
+                                 lsda, handler);
+    }
+  }
+
+  _info.start_ip = start_ip;
+  _info.end_ip = end_ip;
+  _info.lsda = lsda;
+  _info.handler = handler;
+  _info.gp = 0;
+  _info.flags = flags;
+  _info.format = 0;
+  _info.unwind_info = reinterpret_cast<unw_word_t>(TBTable);
+  _info.unwind_info_size = 0;
+  _info.extra = registers.getRegister(2);
+
+  return true;
+}
+
+// Step back up the stack following the frame back link.
+template <typename A, typename R>
+int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
+                                        R &registers, bool &isSignalFrame) {
+  if (_LIBUNWIND_TRACING_UNWINDING) {
+    char functionBuf[512];
+    const char *functionName = functionBuf;
+    unw_word_t offset;
+    if (!getFunctionName(functionBuf, sizeof(functionBuf), &offset)) {
+      functionName = ".anonymous.";
+    }
+    _LIBUNWIND_TRACE_UNWINDING("%s: Look up traceback table of func=%s at %p",
+                               __func__, functionName,
+                               reinterpret_cast<void *>(TBTable));
+  }
+
+#if defined(__powerpc64__)
+  // Instruction to reload TOC register "l r2,40(r1)"
+  const uint32_t loadTOCRegInst = 0xe8410028;
+  const int32_t unwPPCF0Index = UNW_PPC64_F0;
+  const int32_t unwPPCV0Index = UNW_PPC64_V0;
+#else
+  // Instruction to reload TOC register "l r2,20(r1)"
+  const uint32_t loadTOCRegInst = 0x80410014;
+  const int32_t unwPPCF0Index = UNW_PPC_F0;
+  const int32_t unwPPCV0Index = UNW_PPC_V0;
+#endif
+
+  R newRegisters = registers;
+
+  // lastStack points to the stack frame of the next routine up.
+  pint_t lastStack = *(reinterpret_cast<pint_t *>(registers.getSP()));
+
+  // Return address is the address after call site instruction.
+  pint_t returnAddress;
+
+  if (isSignalFrame) {
+    _LIBUNWIND_TRACE_UNWINDING("Possible signal handler frame: lastStack=%p",
+                               reinterpret_cast<void *>(lastStack));
+
+    sigcontext *sigContext = reinterpret_cast<sigcontext *>(
+        reinterpret_cast<char *>(lastStack) + STKMIN);
+    returnAddress = sigContext->sc_jmpbuf.jmp_context.iar;
+
+    _LIBUNWIND_TRACE_UNWINDING("From sigContext=%p, returnAddress=%p\n",
+                               reinterpret_cast<void *>(sigContext),
+                               reinterpret_cast<void *>(returnAddress));
+
+    if (returnAddress < 0x10000000) {
+      // Try again using STKMINALIGN
+      sigContext = reinterpret_cast<sigcontext *>(
+          reinterpret_cast<char *>(lastStack) + STKMINALIGN);
+      returnAddress = sigContext->sc_jmpbuf.jmp_context.iar;
+      if (returnAddress < 0x10000000) {
+        _LIBUNWIND_TRACE_UNWINDING("Bad returnAddress=%p\n",
+                                   reinterpret_cast<void *>(returnAddress));
+        return UNW_EBADFRAME;
+      } else {
+        _LIBUNWIND_TRACE_UNWINDING("Tried again using STKMINALIGN: "
+                                   "sigContext=%p, returnAddress=%p. "
+                                   "Seems to be a valid address\n",
+                                   reinterpret_cast<void *>(sigContext),
+                                   reinterpret_cast<void *>(returnAddress));
+      }
+    }
+    // Restore the condition register from sigcontext.
+    newRegisters.setCR(sigContext->sc_jmpbuf.jmp_context.cr);
+
+    // Restore GPRs from sigcontext.
+    for (int i = 0; i < 32; ++i)
+      newRegisters.setRegister(i, sigContext->sc_jmpbuf.jmp_context.gpr[i]);
+
+    // Restore FPRs from sigcontext.
+    for (int i = 0; i < 32; ++i)
+      newRegisters.setFloatRegister(i + unwPPCF0Index,
+                                    sigContext->sc_jmpbuf.jmp_context.fpr[i]);
+
+    // Restore vector registers if there is an associated extended context
+    // structure.
+    if (sigContext->sc_jmpbuf.jmp_context.msr & __EXTCTX) {
+      ucontext_t *uContext = reinterpret_cast<ucontext_t *>(sigContext);
+      if (uContext->__extctx->__extctx_magic == __EXTCTX_MAGIC) {
+        for (int i = 0; i < 32; ++i)
+          newRegisters.setVectorRegister(
+              i + unwPPCV0Index, *(reinterpret_cast<v128 *>(
+                                     &(uContext->__extctx->__vmx.__vr[i]))));
+      }
+    }
+  } else {
+    // Step up a normal frame.
+    returnAddress = reinterpret_cast<pint_t *>(lastStack)[2];
+
+    _LIBUNWIND_TRACE_UNWINDING("Extract info from lastStack=%p, "
+                               "returnAddress=%p\n",
+                               reinterpret_cast<void *>(lastStack),
+                               reinterpret_cast<void *>(returnAddress));
+    _LIBUNWIND_TRACE_UNWINDING("fpr_regs=%d, gpr_regs=%d, saves_cr=%d\n",
+                               TBTable->tb.fpr_saved, TBTable->tb.gpr_saved,
+                               TBTable->tb.saves_cr);
+
+    // Restore FP registers.
+    char *ptrToRegs = reinterpret_cast<char *>(lastStack);
+    double *FPRegs = reinterpret_cast<double *>(
+        ptrToRegs - (TBTable->tb.fpr_saved * sizeof(double)));
+    for (int i = 0; i < TBTable->tb.fpr_saved; ++i)
+      newRegisters.setFloatRegister(
+          32 - TBTable->tb.fpr_saved + i + unwPPCF0Index, FPRegs[i]);
+
+    // Restore GP registers.
+    ptrToRegs = reinterpret_cast<char *>(FPRegs);
+    uintptr_t *GPRegs = reinterpret_cast<uintptr_t *>(
+        ptrToRegs - (TBTable->tb.gpr_saved * sizeof(uintptr_t)));
+    for (int i = 0; i < TBTable->tb.gpr_saved; ++i)
+      newRegisters.setRegister(32 - TBTable->tb.gpr_saved + i, GPRegs[i]);
+
+    // Restore Vector registers.
+    ptrToRegs = reinterpret_cast<char *>(GPRegs);
+
+    // Restore vector registers only if this is a Clang frame. Also
+    // check if traceback table bit has_vec is set. If it is, structure
+    // vec_ext is available.
+    if (_info.flags == frameType::frameWithEHInfo && TBTable->tb.has_vec) {
+
+      // Get to the vec_ext structure to check if vector registers are saved.
+      uint32_t *p = reinterpret_cast<uint32_t *>(&TBTable->tb_ext);
+
+      // Skip field parminfo if exists.
+      if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
+        ++p;
+
+      // Skip field tb_offset if exists.
+      if (TBTable->tb.has_tboff)
+        ++p;
+
+      // Skip field hand_mask if exists.
+      if (TBTable->tb.int_hndl)
+        ++p;
+
+      // Skip fields ctl_info and ctl_info_disp if exist.
+      if (TBTable->tb.has_ctl) {
+        // Skip field ctl_info.
+        ++p;
+        // Skip field ctl_info_disp.
+        ++p;
+      }
+
+      // Skip fields name_len and name if exist.
+      // p is supposed to point to field name_len now.
+      uint8_t *charPtr = reinterpret_cast<uint8_t *>(p);
+      if (TBTable->tb.name_present) {
+        const uint16_t name_len = *(reinterpret_cast<uint16_t *>(charPtr));
+        charPtr = charPtr + name_len + sizeof(uint16_t);
+      }
+
+      // Skip field alloc_reg if it exists.
+      if (TBTable->tb.uses_alloca)
+        ++charPtr;
+
+      struct vec_ext *vec_ext = reinterpret_cast<struct vec_ext *>(charPtr);
+
+      _LIBUNWIND_TRACE_UNWINDING("vr_saved=%d\n", vec_ext->vr_saved);
+
+      // Restore vector register(s) if saved on the stack.
+      if (vec_ext->vr_saved) {
+        // Saved vector registers are 16-byte aligned.
+        if (reinterpret_cast<uintptr_t>(ptrToRegs) % 16)
+          ptrToRegs -= reinterpret_cast<uintptr_t>(ptrToRegs) % 16;
+        v128 *VecRegs = reinterpret_cast<v128 *>(ptrToRegs - vec_ext->vr_saved *
+                                                                 sizeof(v128));
+        for (int i = 0; i < vec_ext->vr_saved; ++i) {
+          newRegisters.setVectorRegister(
+              32 - vec_ext->vr_saved + i + unwPPCV0Index, VecRegs[i]);
+        }
+      }
+    }
+    if (TBTable->tb.saves_cr) {
+      // Get the saved condition register. The condition register is only
+      // a single word.
+      newRegisters.setCR(
+          *(reinterpret_cast<uint32_t *>(lastStack + sizeof(uintptr_t))));
+    }
+
+    // Restore the SP.
+    newRegisters.setSP(lastStack);
+
+    // The first instruction after return.
+    uint32_t firstInstruction = *(reinterpret_cast<uint32_t *>(returnAddress));
+
+    // Do we need to set the TOC register?
+    _LIBUNWIND_TRACE_UNWINDING(
+        "Current gpr2=%p\n",
+        reinterpret_cast<void *>(newRegisters.getRegister(2)));
+    if (firstInstruction == loadTOCRegInst) {
+      _LIBUNWIND_TRACE_UNWINDING(
+          "Set gpr2=%p from frame\n",
+          reinterpret_cast<void *>(reinterpret_cast<pint_t *>(lastStack)[5]));
+      newRegisters.setRegister(2, reinterpret_cast<pint_t *>(lastStack)[5]);
+    }
+  }
+  _LIBUNWIND_TRACE_UNWINDING("lastStack=%p, returnAddress=%p, pc=%p\n",
+                             reinterpret_cast<void *>(lastStack),
+                             reinterpret_cast<void *>(returnAddress),
+                             reinterpret_cast<void *>(pc));
+
+  // The return address is the address after call site instruction, so
+  // setting IP to that simualates a return.
+  newRegisters.setIP(reinterpret_cast<uintptr_t>(returnAddress));
+
+  // Simulate the step by replacing the register set with the new ones.
+  registers = newRegisters;
+
+  // Check if the next frame is a signal frame.
+  pint_t nextStack = *(reinterpret_cast<pint_t *>(registers.getSP()));
+
+  // Return address is the address after call site instruction.
+  pint_t nextReturnAddress = reinterpret_cast<pint_t *>(nextStack)[2];
+
+  if (nextReturnAddress > 0x01 && nextReturnAddress < 0x10000) {
+    _LIBUNWIND_TRACE_UNWINDING("The next is a signal handler frame: "
+                               "nextStack=%p, next return address=%p\n",
+                               reinterpret_cast<void *>(nextStack),
+                               reinterpret_cast<void *>(nextReturnAddress));
+    isSignalFrame = true;
+  } else {
+    isSignalFrame = false;
+  }
+
+  return UNW_STEP_SUCCESS;
+}
+#endif // defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
 
 template <typename A, typename R>
 void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
   _isSigReturn = false;
 #endif
 
@@ -1948,7 +2506,14 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
   // To disambiguate this, back up the pc when we know it is a return
   // address.
   if (isReturnAddress)
+#if defined(_AIX)
+    // PC needs to be a 4-byte aligned address to be able to look for a
+    // word of 0 that indicates the start of the traceback table at the end
+    // of a function on AIX.
+    pc -= 4;
+#else
     --pc;
+#endif
 
   // Ask address space object to find unwind sections for this pc.
   UnwindInfoSections sects;
@@ -1982,6 +2547,12 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
       return;
 #endif
 
+#if defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+    // If there is unwind info in the traceback table, look there next.
+    if (this->getInfoFromTBTable(pc, _registers))
+      return;
+#endif
+
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
     // If there is dwarf unwind info, look there next.
     if (sects.dwarf_section != 0) {
@@ -2027,7 +2598,7 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
   }
 #endif // #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
 
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
   if (setInfoForSigReturn())
     return;
 #endif
@@ -2036,7 +2607,8 @@ void UnwindCursor<A, R>::setInfoBasedOnIPRegister(bool isReturnAddress) {
   _unwindInfoMissing = true;
 }
 
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&                               \
+    defined(_LIBUNWIND_TARGET_AARCH64)
 template <typename A, typename R>
 bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
   // Look for the sigreturn trampoline. The trampoline's body is two
@@ -2055,14 +2627,28 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
   //
   // [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
   const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  // The PC might contain an invalid address if the unwind info is bad, so
+  // directly accessing it could cause a segfault. Use process_vm_readv to read
+  // the memory safely instead. process_vm_readv was added in Linux 3.2, and
+  // AArch64 supported was added in Linux 3.7, so the syscall is guaranteed to
+  // be present. Unfortunately, there are Linux AArch64 environments where the
+  // libc wrapper for the syscall might not be present (e.g. Android 5), so call
+  // the syscall directly instead.
+  uint32_t instructions[2];
+  struct iovec local_iov = {&instructions, sizeof instructions};
+  struct iovec remote_iov = {reinterpret_cast<void *>(pc), sizeof instructions};
+  long bytesRead =
+      syscall(SYS_process_vm_readv, getpid(), &local_iov, 1, &remote_iov, 1, 0);
   // Look for instructions: mov x8, #0x8b; svc #0x0
-  if (_addressSpace.get32(pc) == 0xd2801168 &&
-      _addressSpace.get32(pc + 4) == 0xd4000001) {
-    _info = {};
-    _isSigReturn = true;
-    return true;
-  }
-  return false;
+  if (bytesRead != sizeof instructions || instructions[0] != 0xd2801168 ||
+      instructions[1] != 0xd4000001)
+    return false;
+
+  _info = {};
+  _info.start_ip = pc;
+  _info.end_ip = pc + 4;
+  _isSigReturn = true;
+  return true;
 }
 
 template <typename A, typename R>
@@ -2096,7 +2682,114 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
   _isSignalFrame = true;
   return UNW_STEP_SUCCESS;
 }
-#endif // defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
+       // defined(_LIBUNWIND_TARGET_AARCH64)
+
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&                               \
+    defined(_LIBUNWIND_TARGET_S390X)
+template <typename A, typename R>
+bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_s390x &) {
+  // Look for the sigreturn trampoline. The trampoline's body is a
+  // specific instruction (see below). Typically the trampoline comes from the
+  // vDSO (i.e. the __kernel_[rt_]sigreturn function). A libc might provide its
+  // own restorer function, though, or user-mode QEMU might write a trampoline
+  // onto the stack.
+  const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  // The PC might contain an invalid address if the unwind info is bad, so
+  // directly accessing it could cause a segfault. Use process_vm_readv to
+  // read the memory safely instead.
+  uint16_t inst;
+  struct iovec local_iov = {&inst, sizeof inst};
+  struct iovec remote_iov = {reinterpret_cast<void *>(pc), sizeof inst};
+  long bytesRead = process_vm_readv(getpid(), &local_iov, 1, &remote_iov, 1, 0);
+  if (bytesRead == sizeof inst && (inst == 0x0a77 || inst == 0x0aad)) {
+    _info = {};
+    _info.start_ip = pc;
+    _info.end_ip = pc + 2;
+    _isSigReturn = true;
+    return true;
+  }
+  return false;
+}
+
+template <typename A, typename R>
+int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
+  // Determine current SP.
+  const pint_t sp = static_cast<pint_t>(this->getReg(UNW_REG_SP));
+  // According to the s390x ABI, the CFA is at (incoming) SP + 160.
+  const pint_t cfa = sp + 160;
+
+  // Determine current PC and instruction there (this must be either
+  // a "svc __NR_sigreturn" or "svc __NR_rt_sigreturn").
+  const pint_t pc = static_cast<pint_t>(this->getReg(UNW_REG_IP));
+  const uint16_t inst = _addressSpace.get16(pc);
+
+  // Find the addresses of the signo and sigcontext in the frame.
+  pint_t pSigctx = 0;
+  pint_t pSigno = 0;
+
+  // "svc __NR_sigreturn" uses a non-RT signal trampoline frame.
+  if (inst == 0x0a77) {
+    // Layout of a non-RT signal trampoline frame, starting at the CFA:
+    //  - 8-byte signal mask
+    //  - 8-byte pointer to sigcontext, followed by signo
+    //  - 4-byte signo
+    pSigctx = _addressSpace.get64(cfa + 8);
+    pSigno = pSigctx + 344;
+  }
+
+  // "svc __NR_rt_sigreturn" uses a RT signal trampoline frame.
+  if (inst == 0x0aad) {
+    // Layout of a RT signal trampoline frame, starting at the CFA:
+    //  - 8-byte retcode (+ alignment)
+    //  - 128-byte siginfo struct (starts with signo)
+    //  - ucontext struct:
+    //     - 8-byte long (uc_flags)
+    //     - 8-byte pointer (uc_link)
+    //     - 24-byte stack_t
+    //     - 8 bytes of padding because sigcontext has 16-byte alignment
+    //     - sigcontext/mcontext_t
+    pSigctx = cfa + 8 + 128 + 8 + 8 + 24 + 8;
+    pSigno = cfa + 8;
+  }
+
+  assert(pSigctx != 0);
+  assert(pSigno != 0);
+
+  // Offsets from sigcontext to each register.
+  const pint_t kOffsetPc = 8;
+  const pint_t kOffsetGprs = 16;
+  const pint_t kOffsetFprs = 216;
+
+  // Restore all registers.
+  for (int i = 0; i < 16; ++i) {
+    uint64_t value = _addressSpace.get64(pSigctx + kOffsetGprs +
+                                         static_cast<pint_t>(i * 8));
+    _registers.setRegister(UNW_S390X_R0 + i, value);
+  }
+  for (int i = 0; i < 16; ++i) {
+    static const int fpr[16] = {
+      UNW_S390X_F0, UNW_S390X_F1, UNW_S390X_F2, UNW_S390X_F3,
+      UNW_S390X_F4, UNW_S390X_F5, UNW_S390X_F6, UNW_S390X_F7,
+      UNW_S390X_F8, UNW_S390X_F9, UNW_S390X_F10, UNW_S390X_F11,
+      UNW_S390X_F12, UNW_S390X_F13, UNW_S390X_F14, UNW_S390X_F15
+    };
+    double value = _addressSpace.getDouble(pSigctx + kOffsetFprs +
+                                           static_cast<pint_t>(i * 8));
+    _registers.setFloatRegister(fpr[i], value);
+  }
+  _registers.setIP(_addressSpace.get64(pSigctx + kOffsetPc));
+
+  // SIGILL, SIGFPE and SIGTRAP are delivered with psw_addr
+  // after the faulting instruction rather than before it.
+  // Do not set _isSignalFrame in that case.
+  uint32_t signo = _addressSpace.get32(pSigno);
+  _isSignalFrame = (signo != 4 && signo != 5 && signo != 8);
+
+  return UNW_STEP_SUCCESS;
+}
+#endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
+       // defined(_LIBUNWIND_TARGET_S390X)
 
 template <typename A, typename R>
 int UnwindCursor<A, R>::step() {
@@ -2106,7 +2799,7 @@ int UnwindCursor<A, R>::step() {
 
   // Use unwinding info to modify register set as if function returned.
   int result;
-#if defined(_LIBUNWIND_TARGET_LINUX) && defined(_LIBUNWIND_TARGET_AARCH64)
+#if defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN)
   if (_isSigReturn) {
     result = this->stepThroughSigReturn();
   } else
@@ -2116,6 +2809,8 @@ int UnwindCursor<A, R>::step() {
     result = this->stepWithCompactEncoding();
 #elif defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
     result = this->stepWithSEHData();
+#elif defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
+    result = this->stepWithTBTableData();
 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
     result = this->stepWithDwarfFDE();
 #elif defined(_LIBUNWIND_ARM_EHABI)
lib/libunwind/src/UnwindLevel1-gcc-ext.c
@@ -59,12 +59,15 @@ _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
 /// relative encodings.
 _LIBUNWIND_EXPORT uintptr_t
 _Unwind_GetDataRelBase(struct _Unwind_Context *context) {
-  (void)context;
   _LIBUNWIND_TRACE_API("_Unwind_GetDataRelBase(context=%p)", (void *)context);
+#if defined(_AIX)
+  return unw_get_data_rel_base((unw_cursor_t *)context);
+#else
+  (void)context;
   _LIBUNWIND_ABORT("_Unwind_GetDataRelBase() not implemented");
+#endif
 }
 
-
 /// Called by personality handler during phase 2 to get base address for text
 /// relative encodings.
 _LIBUNWIND_EXPORT uintptr_t
lib/libunwind/src/UnwindLevel1.c
@@ -44,7 +44,11 @@
 // directly jump to __libunwind_Registerts_x86/x86_64_jumpto instead of using
 // a regular function call to avoid pushing to CET shadow stack again.
 #if !defined(_LIBUNWIND_USE_CET)
-#define __unw_phase2_resume(cursor, fn) __unw_resume((cursor))
+#define __unw_phase2_resume(cursor, fn)                                        \
+  do {                                                                         \
+    (void)fn;                                                                  \
+    __unw_resume((cursor));                                                    \
+  } while (0)
 #elif defined(_LIBUNWIND_TARGET_I386)
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
@@ -480,11 +484,13 @@ _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
   _LIBUNWIND_TRACE_API(
       "_Unwind_GetLanguageSpecificData(context=%p) => 0x%" PRIxPTR,
       (void *)context, result);
+#if !defined(_LIBUNWIND_SUPPORT_TBTAB_UNWIND)
   if (result != 0) {
     if (*((uint8_t *)result) != 0xFF)
       _LIBUNWIND_DEBUG_LOG("lsda at 0x%" PRIxPTR " does not start with 0xFF",
                            result);
   }
+#endif
   return result;
 }
 
lib/libunwind/src/UnwindRegistersRestore.S
@@ -8,7 +8,11 @@
 
 #include "assembly.h"
 
+#if defined(_AIX)
+  .toc
+#else
   .text
+#endif
 
 #if !defined(__USING_SJLJ_EXCEPTIONS__)
 
@@ -222,27 +226,36 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
   PPC64_LVS(30)
   PPC64_LVS(31)
 
-  // use VRSAVE to conditionally restore the remaining VS regs,
-  // that are where the V regs are mapped
+#define PPC64_CLVS_RESTORE(n)                    \
+  addi   4, 3, PPC64_OFFS_FP + n * 16           ;\
+  lxvd2x n, 0, 4
 
+#if !defined(_AIX)
+  // use VRSAVE to conditionally restore the remaining VS regs, that are
+  // where the V regs are mapped. In the AIX ABI, VRSAVE is not used.
   ld    5, PPC64_OFFS_VRSAVE(3)   // test VRsave
   cmpwi 5, 0
   beq   Lnovec
 
 // conditionally load VS
-#define PPC64_CLVS_BOTTOM(n)               \
-  beq    Ldone##n                         ;\
-  addi   4, 3, PPC64_OFFS_FP + n * 16     ;\
-  lxvd2x n, 0, 4                          ;\
+#define PPC64_CLVSl(n)                           \
+  andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n))         ;\
+  beq    Ldone##n                               ;\
+  PPC64_CLVS_RESTORE(n)                         ;\
 Ldone##n:
 
-#define PPC64_CLVSl(n)                    \
-  andis. 0, 5, (1 PPC_LEFT_SHIFT(47-n))  ;\
-PPC64_CLVS_BOTTOM(n)
+#define PPC64_CLVSh(n)                           \
+  andi.  0, 5, (1 PPC_LEFT_SHIFT(63-n))         ;\
+  beq    Ldone##n                               ;\
+  PPC64_CLVS_RESTORE(n)                         ;\
+Ldone##n:
+
+#else
 
-#define PPC64_CLVSh(n)                    \
-  andi.  0, 5, (1 PPC_LEFT_SHIFT(63-n))  ;\
-PPC64_CLVS_BOTTOM(n)
+#define PPC64_CLVSl(n) PPC64_CLVS_RESTORE(n)
+#define PPC64_CLVSh(n) PPC64_CLVS_RESTORE(n)
+
+#endif // !defined(_AIX)
 
   PPC64_CLVSl(32)
   PPC64_CLVSl(33)
@@ -318,32 +331,44 @@ PPC64_CLVS_BOTTOM(n)
   PPC64_LF(31)
 
 #if defined(__ALTIVEC__)
-  // restore vector registers if any are in use
+
+#define PPC64_CLV_UNALIGNED_RESTORE(n)       \
+  ld     0, (PPC64_OFFS_V + n * 16)(3)      ;\
+  std    0, 0(4)                            ;\
+  ld     0, (PPC64_OFFS_V + n * 16 + 8)(3)  ;\
+  std    0, 8(4)                            ;\
+  lvx    n, 0, 4
+
+#if !defined(_AIX)
+  // restore vector registers if any are in use. In the AIX ABI, VRSAVE is
+  // not used.
   ld    5, PPC64_OFFS_VRSAVE(3)   // test VRsave
   cmpwi 5, 0
   beq   Lnovec
 
-  subi  4, 1, 16
-  // r4 is now a 16-byte aligned pointer into the red zone
-  // the _vectorScalarRegisters may not be 16-byte aligned
-  // so copy via red zone temp buffer
+#define PPC64_CLV_UNALIGNEDl(n)              \
+  andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n))     ;\
+  beq    Ldone##n                           ;\
+  PPC64_CLV_UNALIGNED_RESTORE(n)            ;\
+Ldone  ## n:
 
-#define PPC64_CLV_UNALIGNED_BOTTOM(n)            \
-  beq    Ldone##n                               ;\
-  ld     0, (PPC64_OFFS_V + n * 16)(3)          ;\
-  std    0, 0(4)                                ;\
-  ld     0, (PPC64_OFFS_V + n * 16 + 8)(3)      ;\
-  std    0, 8(4)                                ;\
-  lvx    n, 0, 4                                ;\
+#define PPC64_CLV_UNALIGNEDh(n)              \
+  andi.  0, 5, (1 PPC_LEFT_SHIFT(31-n))     ;\
+  beq    Ldone##n                           ;\
+  PPC64_CLV_UNALIGNED_RESTORE(n)            ;\
 Ldone  ## n:
 
-#define PPC64_CLV_UNALIGNEDl(n)                 \
-  andis. 0, 5, (1 PPC_LEFT_SHIFT(15-n))        ;\
-PPC64_CLV_UNALIGNED_BOTTOM(n)
+#else
+
+#define PPC64_CLV_UNALIGNEDl(n) PPC64_CLV_UNALIGNED_RESTORE(n)
+#define PPC64_CLV_UNALIGNEDh(n) PPC64_CLV_UNALIGNED_RESTORE(n)
+
+#endif // !defined(_AIX)
 
-#define PPC64_CLV_UNALIGNEDh(n)                \
-  andi.  0, 5, (1 PPC_LEFT_SHIFT(31-n))       ;\
-PPC64_CLV_UNALIGNED_BOTTOM(n)
+  subi  4, 1, 16
+  // r4 is now a 16-byte aligned pointer into the red zone
+  // the _vectorScalarRegisters may not be 16-byte aligned
+  // so copy via red zone temp buffer
 
   PPC64_CLV_UNALIGNEDl(0)
   PPC64_CLV_UNALIGNEDl(1)
@@ -387,11 +412,23 @@ Lnovec:
   ld    0, PPC64_OFFS_SRR0(3)
   mtctr 0
 
+#if defined(_AIX)
+  // After setting GPR1 to a higher address, AIX wipes out the original
+  // stack space below that address invalidated by the new GPR1 value. Use
+  // GPR0 to save the value of GPR3 in the context before it is wiped out.
+  // This compromises the content of GPR0 which is a volatile register.
+  ld 0, (8 * (3 + 2))(3)
+#else
   PPC64_LR(0)
+#endif
   PPC64_LR(5)
   PPC64_LR(4)
   PPC64_LR(1)
+#if defined(_AIX)
+  mr 3, 0
+#else
   PPC64_LR(3)
+#endif
   bctr
 
 #elif defined(__powerpc__)
@@ -475,45 +512,48 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
 #endif
 
 #if defined(__ALTIVEC__)
-  // restore vector registers if any are in use
+
+#define LOAD_VECTOR_RESTORE(_index)                 \
+  lwz     0, 424+_index*16(3)             SEPARATOR \
+  stw     0, 0(4)                         SEPARATOR \
+  lwz     0, 424+_index*16+4(3)           SEPARATOR \
+  stw     0, 4(4)                         SEPARATOR \
+  lwz     0, 424+_index*16+8(3)           SEPARATOR \
+  stw     0, 8(4)                         SEPARATOR \
+  lwz     0, 424+_index*16+12(3)          SEPARATOR \
+  stw     0, 12(4)                        SEPARATOR \
+  lvx     _index, 0, 4
+
+#if !defined(_AIX)
+  // restore vector registers if any are in use. In the AIX ABI, VRSAVE
+  // is not used.
   lwz     5, 156(3)       // test VRsave
   cmpwi   5, 0
   beq     Lnovec
 
-  subi    4, 1, 16
-  rlwinm  4, 4, 0, 0, 27  // mask low 4-bits
-  // r4 is now a 16-byte aligned pointer into the red zone
-  // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
-
-
-#define LOAD_VECTOR_UNALIGNEDl(_index)          \
-  andis.  0, 5, (1 PPC_LEFT_SHIFT(15-_index)) SEPARATOR \
-  beq     Ldone ## _index             SEPARATOR \
-  lwz     0, 424+_index*16(3)         SEPARATOR \
-  stw     0, 0(%r4)                   SEPARATOR \
-  lwz     0, 424+_index*16+4(%r3)     SEPARATOR \
-  stw     0, 4(%r4)                   SEPARATOR \
-  lwz     0, 424+_index*16+8(%r3)     SEPARATOR \
-  stw     0, 8(%r4)                   SEPARATOR \
-  lwz     0, 424+_index*16+12(%r3)    SEPARATOR \
-  stw     0, 12(%r4)                  SEPARATOR \
-  lvx     _index, 0, 4                SEPARATOR \
+#define LOAD_VECTOR_UNALIGNEDl(_index)                   \
+  andis.  0, 5, (1 PPC_LEFT_SHIFT(15-_index))  SEPARATOR \
+  beq     Ldone ## _index                      SEPARATOR \
+  LOAD_VECTOR_RESTORE(_index)                  SEPARATOR \
   Ldone ## _index:
 
-#define LOAD_VECTOR_UNALIGNEDh(_index)          \
-  andi.   0, 5, (1 PPC_LEFT_SHIFT(31-_index)) SEPARATOR \
-  beq     Ldone ## _index             SEPARATOR \
-  lwz     0, 424+_index*16(3)         SEPARATOR \
-  stw     0, 0(4)                     SEPARATOR \
-  lwz     0, 424+_index*16+4(3)       SEPARATOR \
-  stw     0, 4(4)                     SEPARATOR \
-  lwz     0, 424+_index*16+8(3)       SEPARATOR \
-  stw     0, 8(%r4)                   SEPARATOR \
-  lwz     0, 424+_index*16+12(3)      SEPARATOR \
-  stw     0, 12(4)                    SEPARATOR \
-  lvx     _index, 0, 4                SEPARATOR \
+#define LOAD_VECTOR_UNALIGNEDh(_index)                   \
+  andi.   0, 5, (1 PPC_LEFT_SHIFT(31-_index))  SEPARATOR \
+  beq     Ldone ## _index                      SEPARATOR \
+  LOAD_VECTOR_RESTORE(_index)                  SEPARATOR \
   Ldone ## _index:
 
+#else
+
+#define LOAD_VECTOR_UNALIGNEDl(_index) LOAD_VECTOR_RESTORE(_index)
+#define LOAD_VECTOR_UNALIGNEDh(_index) LOAD_VECTOR_RESTORE(_index)
+
+#endif // !defined(_AIX)
+
+  subi    4, 1, 16
+  rlwinm  4, 4, 0, 0, 27  // mask low 4-bits
+  // r4 is now a 16-byte aligned pointer into the red zone
+  // the _vectorRegisters may not be 16-byte aligned so copy via red zone temp buffer
 
   LOAD_VECTOR_UNALIGNEDl(0)
   LOAD_VECTOR_UNALIGNEDl(1)
@@ -1212,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__) */
lib/libunwind/src/UnwindRegistersSave.S
@@ -8,7 +8,11 @@
 
 #include "assembly.h"
 
+#if defined(_AIX)
+    .toc
+#else
     .text
+#endif
 
 #if !defined(__USING_SJLJ_EXCEPTIONS__)
 
@@ -334,8 +338,11 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 // On entry:
 //  thread_state pointer is in r3
 //
+#if defined(_AIX)
+DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(__unw_getcontext, unw_getcontext)
+#else
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
-
+#endif
 // store register (GPR)
 #define PPC64_STR(n) \
   std   n, (8 * (n + 2))(3)
@@ -567,7 +574,11 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 // On entry:
 //  thread_state pointer is in r3
 //
+#if defined(_AIX)
+DEFINE_LIBUNWIND_FUNCTION_AND_WEAK_ALIAS(__unw_getcontext, unw_getcontext)
+#else
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+#endif
   stw     0,   8(3)
   mflr    0
   stw     0,   0(3) // store lr as ssr0
@@ -1168,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)
src/libunwind.zig
@@ -33,17 +33,6 @@ pub fn buildStaticLib(comp: *Compilation) !void {
         .directory = null, // Put it in the cache directory.
         .basename = basename,
     };
-    const unwind_src_list = [_][]const u8{
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "libunwind.cpp",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-EHABI.cpp",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-seh.cpp",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1.c",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1-gcc-ext.c",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-sjlj.c",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S",
-        "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c",
-    };
     var c_source_files: [unwind_src_list.len]Compilation.CSourceFile = undefined;
     for (unwind_src_list) |unwind_src, i| {
         var cflags = std.ArrayList([]const u8).init(arena);
@@ -150,3 +139,16 @@ pub fn buildStaticLib(comp: *Compilation) !void {
         .lock = sub_compilation.bin_file.toOwnedLock(),
     };
 }
+
+const unwind_src_list = [_][]const u8{
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "libunwind.cpp",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-EHABI.cpp",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-seh.cpp",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1.c",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindLevel1-gcc-ext.c",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind-sjlj.c",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersRestore.S",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "UnwindRegistersSave.S",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "Unwind_AIXExtras.cpp",
+    "libunwind" ++ path.sep_str ++ "src" ++ path.sep_str ++ "gcc_personality_v0.c",
+};