merge llvm libunwind 16.0.6
authorrobert <robert@openbsd.org>
Fri, 26 Jan 2024 11:41:32 +0000 (11:41 +0000)
committerrobert <robert@openbsd.org>
Fri, 26 Jan 2024 11:41:32 +0000 (11:41 +0000)
13 files changed:
gnu/llvm/libunwind/cmake/Modules/HandleCompilerRT.cmake [deleted file]
gnu/llvm/libunwind/include/__libunwind_config.h
gnu/llvm/libunwind/src/AddressSpace.hpp
gnu/llvm/libunwind/src/DwarfInstructions.hpp
gnu/llvm/libunwind/src/DwarfParser.hpp
gnu/llvm/libunwind/src/EHHeaderParser.hpp
gnu/llvm/libunwind/src/Registers.hpp
gnu/llvm/libunwind/src/UnwindCursor.hpp
gnu/llvm/libunwind/src/UnwindRegistersRestore.S
gnu/llvm/libunwind/src/UnwindRegistersSave.S
gnu/llvm/libunwind/src/assembly.h
gnu/llvm/libunwind/src/config.h
gnu/llvm/libunwind/src/libunwind.cpp

diff --git a/gnu/llvm/libunwind/cmake/Modules/HandleCompilerRT.cmake b/gnu/llvm/libunwind/cmake/Modules/HandleCompilerRT.cmake
deleted file mode 100644 (file)
index 77168e5..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-function(find_compiler_rt_library name dest)
-  if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
-    message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
-  endif()
-  set(dest "" PARENT_SCOPE)
-  set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
-      "--rtlib=compiler-rt" "--print-libgcc-file-name")
-  if (CMAKE_CXX_COMPILER_ID MATCHES Clang AND CMAKE_CXX_COMPILER_TARGET)
-    list(APPEND CLANG_COMMAND "--target=${CMAKE_CXX_COMPILER_TARGET}")
-  endif()
-  get_property(LIBUNWIND_CXX_FLAGS CACHE CMAKE_CXX_FLAGS PROPERTY VALUE)
-  string(REPLACE " " ";" LIBUNWIND_CXX_FLAGS "${LIBUNWIND_CXX_FLAGS}")
-  list(APPEND CLANG_COMMAND ${LIBUNWIND_CXX_FLAGS})
-  execute_process(
-      COMMAND ${CLANG_COMMAND}
-      RESULT_VARIABLE HAD_ERROR
-      OUTPUT_VARIABLE LIBRARY_FILE
-  )
-  string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
-  file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
-  string(REPLACE "builtins" "${name}" LIBRARY_FILE "${LIBRARY_FILE}")
-  if (NOT HAD_ERROR AND EXISTS "${LIBRARY_FILE}")
-    message(STATUS "Found compiler-rt library: ${LIBRARY_FILE}")
-    set(${dest} "${LIBRARY_FILE}" PARENT_SCOPE)
-  else()
-    message(STATUS "Failed to find compiler-rt library")
-  endif()
-endfunction()
-
-function(find_compiler_rt_dir dest)
-  if (NOT DEFINED LIBUNWIND_COMPILE_FLAGS)
-    message(FATAL_ERROR "LIBUNWIND_COMPILE_FLAGS must be defined when using this function")
-  endif()
-  set(dest "" PARENT_SCOPE)
-  if (APPLE)
-    set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
-        "-print-file-name=lib")
-    execute_process(
-        COMMAND ${CLANG_COMMAND}
-        RESULT_VARIABLE HAD_ERROR
-        OUTPUT_VARIABLE LIBRARY_DIR
-    )
-    string(STRIP "${LIBRARY_DIR}" LIBRARY_DIR)
-    file(TO_CMAKE_PATH "${LIBRARY_DIR}" LIBRARY_DIR)
-    set(LIBRARY_DIR "${LIBRARY_DIR}/darwin")
-  else()
-    set(CLANG_COMMAND ${CMAKE_CXX_COMPILER} ${LIBUNWIND_COMPILE_FLAGS}
-        "--rtlib=compiler-rt" "--print-libgcc-file-name")
-    execute_process(
-        COMMAND ${CLANG_COMMAND}
-        RESULT_VARIABLE HAD_ERROR
-        OUTPUT_VARIABLE LIBRARY_FILE
-    )
-    string(STRIP "${LIBRARY_FILE}" LIBRARY_FILE)
-    file(TO_CMAKE_PATH "${LIBRARY_FILE}" LIBRARY_FILE)
-    get_filename_component(LIBRARY_DIR "${LIBRARY_FILE}" DIRECTORY)
-  endif()
-  if (NOT HAD_ERROR AND EXISTS "${LIBRARY_DIR}")
-    message(STATUS "Found compiler-rt directory: ${LIBRARY_DIR}")
-    set(${dest} "${LIBRARY_DIR}" PARENT_SCOPE)
-  else()
-    message(STATUS "Failed to find compiler-rt directory")
-  endif()
-endfunction()
index 2acca1b..f69fe89 100644 (file)
@@ -1,4 +1,4 @@
-//===------------------------- __libunwind_config.h -----------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -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
 
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_OR1K      32
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS      65
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC     31
-#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64   32
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64   31
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_HEXAGON   34
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_RISCV     64
 #define _LIBUNWIND_HIGHEST_DWARF_REGISTER_VE        143
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_S390X     83
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH 64
 
 #if defined(_LIBUNWIND_IS_NATIVE_ONLY)
 # if defined(__linux__)
@@ -56,7 +60,7 @@
 #  define _LIBUNWIND_CONTEXT_SIZE 167
 #  define _LIBUNWIND_CURSOR_SIZE 179
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC64
-# elif defined(__ppc__)
+# elif defined(__powerpc__)
 #  define _LIBUNWIND_TARGET_PPC 1
 #  define _LIBUNWIND_CONTEXT_SIZE 117
 #  define _LIBUNWIND_CURSOR_SIZE 124
 #    error "Unsupported MIPS ABI and/or environment"
 #  endif
 #  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_MIPS
-# elif defined(__sparc__) && defined(__arch64__)
-#  define _LIBUNWIND_TARGET_SPARC64 1
-#  define _LIBUNWIND_CONTEXT_SIZE 33
-#  define _LIBUNWIND_CURSOR_SIZE 45
-#  define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64
+#elif defined(__sparc__) && defined(__arch64__)
+#define _LIBUNWIND_TARGET_SPARC64 1
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER                                      \
+  _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64
+#define _LIBUNWIND_CONTEXT_SIZE 33
+#define _LIBUNWIND_CURSOR_SIZE 45
 # elif defined(__sparc__)
   #define _LIBUNWIND_TARGET_SPARC 1
   #define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC
 #  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
+#elif defined(__loongarch__)
+#define _LIBUNWIND_TARGET_LOONGARCH 1
+#if __loongarch_grlen == 64
+#define _LIBUNWIND_CONTEXT_SIZE 65
+#define _LIBUNWIND_CURSOR_SIZE 77
+#else
+#error "Unsupported LoongArch ABI"
+#endif
+#define _LIBUNWIND_HIGHEST_DWARF_REGISTER                                      \
+  _LIBUNWIND_HIGHEST_DWARF_REGISTER_LOONGARCH
 # else
 #  error "Unsupported architecture."
 # endif
 # define _LIBUNWIND_TARGET_HEXAGON 1
 # define _LIBUNWIND_TARGET_RISCV 1
 # define _LIBUNWIND_TARGET_VE 1
+# define _LIBUNWIND_TARGET_S390X 1
+#define _LIBUNWIND_TARGET_LOONGARCH 1
 # define _LIBUNWIND_CONTEXT_SIZE 167
 # define _LIBUNWIND_CURSOR_SIZE 179
 # define _LIBUNWIND_HIGHEST_DWARF_REGISTER 287
index b99c21a..1df6950 100644 (file)
@@ -1,4 +1,4 @@
-//===------------------------- AddressSpace.hpp ---------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -25,7 +25,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
@@ -46,6 +46,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
@@ -122,23 +129,23 @@ struct UnwindInfoSections {
   uintptr_t       dso_base;
 #endif
 #if defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
-  uintptr_t       text_segment_length;
+  size_t          text_segment_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
   uintptr_t       dwarf_section;
-  uintptr_t       dwarf_section_length;
+  size_t          dwarf_section_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
   uintptr_t       dwarf_index_section;
-  uintptr_t       dwarf_index_section_length;
+  size_t          dwarf_index_section_length;
 #endif
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
   uintptr_t       compact_unwind_section;
-  uintptr_t       compact_unwind_section_length;
+  size_t          compact_unwind_section_length;
 #endif
 #if defined(_LIBUNWIND_ARM_EHABI)
   uintptr_t       arm_section;
-  uintptr_t       arm_section_length;
+  size_t          arm_section_length;
 #endif
 };
 
@@ -296,7 +303,7 @@ inline uint64_t LocalAddressSpace::getULEB128(pint_t &addr, pint_t end) {
 inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
   const uint8_t *p = (uint8_t *)addr;
   const uint8_t *pend = (uint8_t *)end;
-  int64_t result = 0;
+  uint64_t result = 0;
   int bit = 0;
   uint8_t byte;
   do {
@@ -310,7 +317,7 @@ inline int64_t LocalAddressSpace::getSLEB128(pint_t &addr, pint_t end) {
   if ((byte & 0x40) != 0 && bit < 64)
     result |= (-1ULL) << bit;
   addr = (pint_t) p;
-  return result;
+  return (int64_t)result;
 }
 
 inline LocalAddressSpace::pint_t
@@ -427,28 +434,6 @@ LocalAddressSpace::getEncodedP(pint_t &addr, pint_t end, uint8_t encoding,
   typedef ElfW(Addr) Elf_Addr;
 #endif
 
-static Elf_Addr calculateImageBase(struct dl_phdr_info *pinfo) {
-  Elf_Addr image_base = pinfo->dlpi_addr;
-#if defined(__ANDROID__) && __ANDROID_API__ < 18
-  if (image_base == 0) {
-    // Normally, an image base of 0 indicates a non-PIE executable. On
-    // versions of Android prior to API 18, the dynamic linker reported a
-    // dlpi_addr of 0 for PIE executables. Compute the true image base
-    // using the PT_PHDR segment.
-    // See https://github.com/android/ndk/issues/505.
-    for (Elf_Half i = 0; i < pinfo->dlpi_phnum; i++) {
-      const Elf_Phdr *phdr = &pinfo->dlpi_phdr[i];
-      if (phdr->p_type == PT_PHDR) {
-        image_base = reinterpret_cast<Elf_Addr>(pinfo->dlpi_phdr) -
-          phdr->p_vaddr;
-        break;
-      }
-    }
-  }
-#endif
-  return image_base;
-}
-
 struct _LIBUNWIND_HIDDEN dl_iterate_cb_data {
   LocalAddressSpace *addressSpace;
   UnwindInfoSections *sects;
@@ -491,7 +476,7 @@ static bool checkForUnwindInfoSegment(const Elf_Phdr *phdr, size_t image_base,
       // .eh_frame_hdr records the start of .eh_frame, but not its size.
       // Rely on a zero terminator to find the end of the section.
       cbdata->sects->dwarf_section = hdrInfo.eh_frame_ptr;
-      cbdata->sects->dwarf_section_length = UINTPTR_MAX;
+      cbdata->sects->dwarf_section_length = SIZE_MAX;
       return true;
     }
   }
@@ -522,7 +507,7 @@ static int findUnwindSectionsByPhdr(struct dl_phdr_info *pinfo,
   (void)pinfo_size;
 #endif
 
-  Elf_Addr image_base = calculateImageBase(pinfo);
+  Elf_Addr image_base = pinfo->dlpi_addr;
 
   // Most shared objects seen in this callback function likely don't contain the
   // target address, so optimize for that. Scan for a matching PT_LOAD segment
@@ -567,22 +552,22 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
     info.dso_base                      = (uintptr_t)dyldInfo.mh;
  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
     info.dwarf_section                 = (uintptr_t)dyldInfo.dwarf_section;
-    info.dwarf_section_length          = dyldInfo.dwarf_section_length;
+    info.dwarf_section_length          = (size_t)dyldInfo.dwarf_section_length;
  #endif
     info.compact_unwind_section        = (uintptr_t)dyldInfo.compact_unwind_section;
-    info.compact_unwind_section_length = dyldInfo.compact_unwind_section_length;
+    info.compact_unwind_section_length = (size_t)dyldInfo.compact_unwind_section_length;
     return true;
   }
 #elif defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND) && defined(_LIBUNWIND_IS_BAREMETAL)
   info.dso_base = 0;
   // Bare metal is statically linked, so no need to ask the dynamic loader
-  info.dwarf_section_length = (uintptr_t)(&__eh_frame_end - &__eh_frame_start);
+  info.dwarf_section_length = (size_t)(&__eh_frame_end - &__eh_frame_start);
   info.dwarf_section =        (uintptr_t)(&__eh_frame_start);
   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
                              (void *)info.dwarf_section, (void *)info.dwarf_section_length);
 #if defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
   info.dwarf_index_section =        (uintptr_t)(&__eh_frame_hdr_start);
-  info.dwarf_index_section_length = (uintptr_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
+  info.dwarf_index_section_length = (size_t)(&__eh_frame_hdr_end - &__eh_frame_hdr_start);
   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: index section %p length %p",
                              (void *)info.dwarf_index_section, (void *)info.dwarf_index_section_length);
 #endif
@@ -591,7 +576,7 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
 #elif defined(_LIBUNWIND_ARM_EHABI) && defined(_LIBUNWIND_IS_BAREMETAL)
   // Bare metal is statically linked, so no need to ask the dynamic loader
   info.arm_section =        (uintptr_t)(&__exidx_start);
-  info.arm_section_length = (uintptr_t)(&__exidx_end - &__exidx_start);
+  info.arm_section_length = (size_t)(&__exidx_end - &__exidx_start);
   _LIBUNWIND_TRACE_UNWINDING("findUnwindSections: section %p length %p",
                              (void *)info.arm_section, (void *)info.arm_section_length);
   if (info.arm_section && info.arm_section_length)
@@ -605,6 +590,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;
   }
 
@@ -641,14 +627,69 @@ 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 =
       (uintptr_t)dl_unwind_find_exidx((_Unwind_Ptr)targetAddr, &length);
-  info.arm_section_length = (uintptr_t)length * sizeof(EHABIIndexEntry);
+  info.arm_section_length = (size_t)length * sizeof(EHABIIndexEntry);
   if (info.arm_section && info.arm_section_length)
     return true;
 #elif defined(_LIBUNWIND_USE_DL_ITERATE_PHDR)
+  // Use DLFO_STRUCT_HAS_EH_DBASE to determine the existence of
+  // `_dl_find_object`. Use _LIBUNWIND_SUPPORT_DWARF_INDEX, because libunwind
+  // support for _dl_find_object on other unwind formats is not implemented,
+  // yet.
+#if defined(DLFO_STRUCT_HAS_EH_DBASE) & defined(_LIBUNWIND_SUPPORT_DWARF_INDEX)
+  // We expect `_dl_find_object` to return PT_GNU_EH_FRAME.
+#if DLFO_EH_SEGMENT_TYPE != PT_GNU_EH_FRAME
+#error _dl_find_object retrieves an unexpected section type
+#endif
+  // We look-up `dl_find_object` dynamically at runtime to ensure backwards
+  // compatibility with earlier version of glibc not yet providing it. On older
+  // systems, we gracefully fallback to `dl_iterate_phdr`. Cache the pointer
+  // so we only look it up once. Do manual lock to avoid _cxa_guard_acquire.
+  static decltype(_dl_find_object) *dlFindObject;
+  static bool dlFindObjectChecked = false;
+  if (!dlFindObjectChecked) {
+    dlFindObject = reinterpret_cast<decltype(_dl_find_object) *>(
+        dlsym(RTLD_DEFAULT, "_dl_find_object"));
+    dlFindObjectChecked = true;
+  }
+  // Try to find the unwind info using `dl_find_object`
+  dl_find_object findResult;
+  if (dlFindObject && dlFindObject((void *)targetAddr, &findResult) == 0) {
+    if (findResult.dlfo_eh_frame == nullptr) {
+      // Found an entry for `targetAddr`, but there is no unwind info.
+      return false;
+    }
+    info.dso_base = reinterpret_cast<uintptr_t>(findResult.dlfo_map_start);
+    info.text_segment_length = static_cast<size_t>(
+        (char *)findResult.dlfo_map_end - (char *)findResult.dlfo_map_start);
+
+    // Record the start of PT_GNU_EH_FRAME.
+    info.dwarf_index_section =
+        reinterpret_cast<uintptr_t>(findResult.dlfo_eh_frame);
+    // `_dl_find_object` does not give us the size of PT_GNU_EH_FRAME.
+    // Setting length to `SIZE_MAX` effectively disables all range checks.
+    info.dwarf_index_section_length = SIZE_MAX;
+    EHHeaderParser<LocalAddressSpace>::EHHeaderInfo hdrInfo;
+    if (!EHHeaderParser<LocalAddressSpace>::decodeEHHdr(
+            *this, info.dwarf_index_section, info.dwarf_index_section_length,
+            hdrInfo)) {
+      return false;
+    }
+    // Record the start of the FDE and use SIZE_MAX to indicate that we do
+    // not know the end address.
+    info.dwarf_section = hdrInfo.eh_frame_ptr;
+    info.dwarf_section_length = SIZE_MAX;
+    return true;
+  }
+#endif
   dl_iterate_cb_data cb_data = {this, &info, targetAddr};
   int found = dl_iterate_phdr(findUnwindSectionsByPhdr, &cb_data);
   return static_cast<bool>(found);
@@ -657,7 +698,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;
@@ -677,6 +717,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;
index 41569d4..9962c2f 100644 (file)
@@ -1,4 +1,4 @@
-//===-------------------------- DwarfInstructions.hpp ---------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "dwarf2.h"
-#include "Registers.hpp"
 #include "DwarfParser.hpp"
+#include "Registers.hpp"
 #include "config.h"
+#include "dwarf2.h"
+#include "libunwind_ext.h"
 
 
 namespace libunwind {
 
 
-/// DwarfInstructions maps abtract DWARF unwind instructions to a particular
+/// DwarfInstructions maps abstract DWARF unwind instructions to a particular
 /// architecture
 template <typename A, typename R>
 class DwarfInstructions {
@@ -34,7 +35,7 @@ public:
   typedef typename A::sint_t sint_t;
 
   static int stepWithDwarf(A &addressSpace, pint_t pc, pint_t fdeStart,
-                           R &registers, bool &isSignalFrame);
+                           R &registers, bool &isSignalFrame, bool stage2);
 
 private:
 
@@ -72,8 +73,19 @@ 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>
+auto getSparcWCookie(const R &r, int) -> decltype(r.getWCookie()) {
+  return r.getWCookie();
+}
+template <typename R> uint64_t getSparcWCookie(const R &, long) {
+  return 0;
+}
 
 template <typename A, typename R>
 typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
@@ -83,9 +95,9 @@ typename A::pint_t DwarfInstructions<A, R>::getSavedRegister(
   case CFI_Parser<A>::kRegisterInCFA:
     return (pint_t)addressSpace.getRegister(cfa + (pint_t)savedReg.value);
 
-  case CFI_Parser<A>::kRegisterInCFADecrypt:
-    return addressSpace.getP(
-       cfa + (pint_t)savedReg.value) ^ registers.getWCookie();
+  case CFI_Parser<A>::kRegisterInCFADecrypt: // sparc64 specific
+    return (pint_t)(addressSpace.getP(cfa + (pint_t)savedReg.value) ^
+           getSparcWCookie(registers, 0));
 
   case CFI_Parser<A>::kRegisterAtExpression:
     return (pint_t)addressSpace.getRegister(evaluateExpression(
@@ -119,12 +131,15 @@ double DwarfInstructions<A, R>::getSavedFloatRegister(
     return addressSpace.getDouble(
         evaluateExpression((pint_t)savedReg.value, addressSpace,
                             registers, cfa));
-
+  case CFI_Parser<A>::kRegisterUndefined:
+    return 0.0;
+  case CFI_Parser<A>::kRegisterInRegister:
+#ifndef _LIBUNWIND_TARGET_ARM
+    return registers.getFloatRegister((int)savedReg.value);
+#endif
   case CFI_Parser<A>::kRegisterIsExpression:
   case CFI_Parser<A>::kRegisterUnused:
-  case CFI_Parser<A>::kRegisterUndefined:
   case CFI_Parser<A>::kRegisterOffsetFromCFA:
-  case CFI_Parser<A>::kRegisterInRegister:
   case CFI_Parser<A>::kRegisterInCFADecrypt:
     // FIX ME
     break;
@@ -156,11 +171,26 @@ 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,
                                            pint_t fdeStart, R &registers,
-                                           bool &isSignalFrame) {
+                                           bool &isSignalFrame, bool stage2) {
   FDE_Info fdeInfo;
   CIE_Info cieInfo;
   if (CFI_Parser<A>::decodeFDE(addressSpace, fdeStart, &fdeInfo,
@@ -171,7 +201,39 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
       // get pointer to cfa (architecture specific)
       pint_t cfa = getCFA(addressSpace, prolog, registers);
 
-       // restore registers that DWARF says were saved
+      (void)stage2;
+      // __unw_step_stage2 is not used for cross unwinding, so we use
+      // __aarch64__ rather than LIBUNWIND_TARGET_AARCH64 to make sure we are
+      // building for AArch64 natively.
+#if defined(__aarch64__)
+      if (stage2 && cieInfo.mteTaggedFrame) {
+        pint_t sp = registers.getSP();
+        pint_t p = sp;
+        // AArch64 doesn't require the value of SP to be 16-byte aligned at
+        // all times, only at memory accesses and public interfaces [1]. Thus,
+        // a signal could arrive at a point where SP is not aligned properly.
+        // In that case, the kernel fixes up [2] the signal frame, but we
+        // still have a misaligned SP in the previous frame. If that signal
+        // handler caused stack unwinding, we would have an unaligned SP.
+        // We do not need to fix up the CFA, as that is the SP at a "public
+        // interface".
+        // [1]:
+        // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#622the-stack
+        // [2]:
+        // https://github.com/torvalds/linux/blob/1930a6e739c4b4a654a69164dbe39e554d228915/arch/arm64/kernel/signal.c#L718
+        p &= ~0xfULL;
+        // CFA is the bottom of the current stack frame.
+        for (; p < cfa; p += 16) {
+          __asm__ __volatile__(".arch armv8.5-a\n"
+                               ".arch_extension memtag\n"
+                               "stg %[Ptr], [%[Ptr]]\n"
+                               :
+                               : [Ptr] "r"(p)
+                               : "memory");
+        }
+      }
+#endif
+      // restore registers that DWARF says were saved
       R newRegisters = registers;
 
       // Typically, the CFA is the stack pointer at the call site in
@@ -184,9 +246,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) {
@@ -211,7 +274,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
             return UNW_EBADREG;
         } else if (i == (int)cieInfo.returnAddressRegister) {
             // Leaf function keeps the return address in register and there is no
-            // explicit intructions how to restore it.
+            // explicit instructions how to restore it.
             returnAddress = registers.getRegister(cieInfo.returnAddressRegister);
         }
       }
@@ -225,7 +288,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_ARM64_RA_SIGN_STATE].value &&
+          getRA_SIGN_STATE(addressSpace, registers, cfa, prolog) &&
           returnAddress != 0) {
 #if !defined(_LIBUNWIND_IS_NATIVE_ONLY)
         return UNW_ECROSSRASIGNING;
@@ -245,6 +308,20 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
       }
 #endif
 
+#if defined(_LIBUNWIND_IS_NATIVE_ONLY) && defined(_LIBUNWIND_TARGET_ARM) &&    \
+    defined(__ARM_FEATURE_PAUTH)
+      if ((R::getArch() == REGISTERS_ARM) &&
+          prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE].value) {
+        pint_t pac =
+            getSavedRegister(addressSpace, registers, cfa,
+                             prolog.savedRegisters[UNW_ARM_RA_AUTH_CODE]);
+        __asm__ __volatile__("autg %0, %1, %2"
+                             :
+                             : "r"(pac), "r"(returnAddress), "r"(cfa)
+                             :);
+      }
+#endif
+
 #if defined(_LIBUNWIND_TARGET_SPARC)
       if (R::getArch() == REGISTERS_SPARC) {
         // Skip call site instruction and delay slot
@@ -255,6 +332,12 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
       }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+      // Skip call site instruction and delay slot.
+      if (R::getArch() == REGISTERS_SPARC64)
+        returnAddress += 8;
+#endif
+
 #if defined(_LIBUNWIND_TARGET_PPC64)
 #define PPC64_ELFV1_R2_LOAD_INST_ENCODING 0xe8410028u // ld r2,40(r1)
 #define PPC64_ELFV1_R2_OFFSET 40
@@ -281,7 +364,7 @@ int DwarfInstructions<A, R>::stepWithDwarf(A &addressSpace, pint_t pc,
 #endif
 
       // Return address is address after call site instruction, so setting IP to
-      // that does simualates a return.
+      // that does simulates a return.
       newRegisters.setIP(returnAddress);
 
       // Simulate the step by replacing the register set with the new ones.
@@ -585,7 +668,7 @@ DwarfInstructions<A, R>::evaluateExpression(pint_t expression, A &addressSpace,
       svalue = (sint_t)*sp;
       *sp = (pint_t)(svalue >> value);
       if (log)
-        fprintf(stderr, "shift left arithmetric\n");
+        fprintf(stderr, "shift left arithmetic\n");
       break;
 
     case DW_OP_xor:
index b01937a..0682942 100644 (file)
@@ -1,4 +1,4 @@
-//===--------------------------- DwarfParser.hpp --------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -51,6 +51,7 @@ public:
     uint8_t   returnAddressRegister;
 #if defined(_LIBUNWIND_TARGET_AARCH64)
     bool      addressesSignedWithBKey;
+    bool      mteTaggedFrame;
 #endif
   };
 
@@ -71,7 +72,7 @@ public:
     kRegisterUnused,
     kRegisterUndefined,
     kRegisterInCFA,
-    kRegisterInCFADecrypt,
+    kRegisterInCFADecrypt, // sparc64 specific
     kRegisterOffsetFromCFA,
     kRegisterInRegister,
     kRegisterAtExpression,
@@ -152,10 +153,11 @@ public:
   };
 
   static bool findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
-                      uintptr_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
+                      size_t sectionLength, pint_t fdeHint, FDE_Info *fdeInfo,
                       CIE_Info *cieInfo);
   static const char *decodeFDE(A &addressSpace, pint_t fdeStart,
-                               FDE_Info *fdeInfo, CIE_Info *cieInfo);
+                               FDE_Info *fdeInfo, CIE_Info *cieInfo,
+                               bool useCIEInfo = false);
   static bool parseFDEInstructions(A &addressSpace, const FDE_Info &fdeInfo,
                                    const CIE_Info &cieInfo, pint_t upToPC,
                                    int arch, PrologInfo *results);
@@ -163,10 +165,14 @@ public:
   static const char *parseCIE(A &addressSpace, pint_t cie, CIE_Info *cieInfo);
 };
 
-/// Parse a FDE into a CIE_Info and an FDE_Info
+/// Parse a FDE into a CIE_Info and an FDE_Info. If useCIEInfo is
+/// true, treat cieInfo as already-parsed CIE_Info (whose start offset
+/// must match the one specified by the FDE) rather than parsing the
+/// one indicated within the FDE.
 template <typename A>
 const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
-                                     FDE_Info *fdeInfo, CIE_Info *cieInfo) {
+                                     FDE_Info *fdeInfo, CIE_Info *cieInfo,
+                                     bool useCIEInfo) {
   pint_t p = fdeStart;
   pint_t cfiLength = (pint_t)addressSpace.get32(p);
   p += 4;
@@ -182,9 +188,14 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
     return "FDE is really a CIE"; // this is a CIE not an FDE
   pint_t nextCFI = p + cfiLength;
   pint_t cieStart = p - ciePointer;
-  const char *err = parseCIE(addressSpace, cieStart, cieInfo);
-  if (err != NULL)
-    return err;
+  if (useCIEInfo) {
+    if (cieInfo->cieStart != cieStart)
+      return "CIE start does not match";
+  } else {
+    const char *err = parseCIE(addressSpace, cieStart, cieInfo);
+    if (err != NULL)
+      return err;
+  }
   p += 4;
   // Parse pc begin and range.
   pint_t pcStart =
@@ -221,11 +232,11 @@ const char *CFI_Parser<A>::decodeFDE(A &addressSpace, pint_t fdeStart,
 /// Scan an eh_frame section to find an FDE for a pc
 template <typename A>
 bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
-                            uintptr_t sectionLength, pint_t fdeHint,
+                            size_t sectionLength, pint_t fdeHint,
                             FDE_Info *fdeInfo, CIE_Info *cieInfo) {
   //fprintf(stderr, "findFDE(0x%llX)\n", (long long)pc);
   pint_t p = (fdeHint != 0) ? fdeHint : ehSectionStart;
-  const pint_t ehSectionEnd = (sectionLength == UINTPTR_MAX)
+  const pint_t ehSectionEnd = (sectionLength == SIZE_MAX)
                                   ? static_cast<pint_t>(-1)
                                   : (ehSectionStart + sectionLength);
   while (p < ehSectionEnd) {
@@ -315,6 +326,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
   cieInfo->fdesHaveAugmentationData = false;
 #if defined(_LIBUNWIND_TARGET_AARCH64)
   cieInfo->addressesSignedWithBKey = false;
+  cieInfo->mteTaggedFrame = false;
 #endif
   cieInfo->cieStart = cie;
   pint_t p = cie;
@@ -343,7 +355,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
   while (addressSpace.get8(p) != 0)
     ++p;
   ++p;
-  // parse code aligment factor
+  // parse code alignment factor
   cieInfo->codeAlignFactor = (uint32_t)addressSpace.getULEB128(p, cieContentEnd);
   // parse data alignment factor
   cieInfo->dataAlignFactor = (int)addressSpace.getSLEB128(p, cieContentEnd);
@@ -384,6 +396,9 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
       case 'B':
         cieInfo->addressesSignedWithBKey = true;
         break;
+      case 'G':
+        cieInfo->mteTaggedFrame = true;
+        break;
 #endif
       default:
         // ignore unknown letters
@@ -397,7 +412,7 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
 }
 
 
-/// "run" the DWARF instructions and create the abstact PrologInfo for an FDE
+/// "run" the DWARF instructions and create the abstract PrologInfo for an FDE
 template <typename A>
 bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
                                          const FDE_Info &fdeInfo,
@@ -724,8 +739,8 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
             "DW_CFA_GNU_negative_offset_extended(%" PRId64 ")\n", offset);
         break;
 
-#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) \
-        || defined(_LIBUNWIND_TARGET_SPARC64)
+#if defined(_LIBUNWIND_TARGET_AARCH64) || defined(_LIBUNWIND_TARGET_SPARC) || \
+    defined(_LIBUNWIND_TARGET_SPARC64)
         // The same constant is used to represent different instructions on
         // AArch64 (negate_ra_state) and SPARC (window_save).
         static_assert(DW_CFA_AARCH64_negate_ra_state == DW_CFA_GNU_window_save,
@@ -735,27 +750,13 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
 #if defined(_LIBUNWIND_TARGET_AARCH64)
         case REGISTERS_ARM64: {
           int64_t value =
-              results->savedRegisters[UNW_ARM64_RA_SIGN_STATE].value ^ 0x1;
-          results->setRegisterValue(UNW_ARM64_RA_SIGN_STATE, value,
+              results->savedRegisters[UNW_AARCH64_RA_SIGN_STATE].value ^ 0x1;
+          results->setRegisterValue(UNW_AARCH64_RA_SIGN_STATE, value,
                                     initialState);
           _LIBUNWIND_TRACE_DWARF("DW_CFA_AARCH64_negate_ra_state\n");
         } break;
 #endif
 
-#if defined(_LIBUNWIND_TARGET_SPARC64)
-      case REGISTERS_SPARC64:
-        // Hardcodes windowed registers for SPARC
-        for (reg = 16; reg < 32; reg++) {
-          if (reg == 31)
-            results->savedRegisters[reg].location = kRegisterInCFADecrypt;
-          else
-            results->savedRegisters[reg].location = kRegisterInCFA;
-          results->savedRegisters[reg].value = (reg - 16) * sizeof(pint_t);
-        }
-        _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save");
-        break;
-#endif
-
 #if defined(_LIBUNWIND_TARGET_SPARC)
         // case DW_CFA_GNU_window_save:
         case REGISTERS_SPARC:
@@ -773,8 +774,31 @@ bool CFI_Parser<A>::parseFDEInstructions(A &addressSpace,
           }
           break;
 #endif
+
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+        // case DW_CFA_GNU_window_save:
+        case REGISTERS_SPARC64:
+          // Don't save %o0-%o7 on sparc64.
+          // https://reviews.llvm.org/D32450#736405
+
+          for (reg = UNW_SPARC_L0; reg <= UNW_SPARC_I7; reg++) {
+            if (reg == UNW_SPARC_I7)
+              results->setRegister(
+                  reg, kRegisterInCFADecrypt,
+                  static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
+                  initialState);
+            else
+              results->setRegister(
+                  reg, kRegisterInCFA,
+                  static_cast<int64_t>((reg - UNW_SPARC_L0) * sizeof(pint_t)),
+                  initialState);
+          }
+          _LIBUNWIND_TRACE_DWARF("DW_CFA_GNU_window_save\n");
+          break;
+#endif
         }
         break;
+
 #else
         (void)arch;
 #endif
index d9902ed..fade6f6 100644 (file)
@@ -1,4 +1,4 @@
-//===------------------------- EHHeaderParser.hpp -------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -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;
   }
 
@@ -147,7 +148,6 @@ size_t EHHeaderParser<A>::getTableEntrySize(uint8_t tableEnc) {
   if (tableEnc == DW_EH_PE_omit) {
     return 0;
   }
-
   switch (tableEnc & 0x0f) {
   case DW_EH_PE_sdata2:
   case DW_EH_PE_udata2:
index 9e238f1..c7b875d 100644 (file)
@@ -1,4 +1,4 @@
-//===----------------------------- Registers.hpp --------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -15,8 +15,9 @@
 #include <stdint.h>
 #include <string.h>
 
-#include "libunwind.h"
+#include "cet_unwind.h"
 #include "config.h"
+#include "libunwind.h"
 
 namespace libunwind {
 
@@ -38,11 +39,20 @@ enum {
   REGISTERS_HEXAGON,
   REGISTERS_RISCV,
   REGISTERS_VE,
+  REGISTERS_S390X,
+  REGISTERS_LOONGARCH,
 };
 
 #if defined(_LIBUNWIND_TARGET_I386)
 class _LIBUNWIND_HIDDEN Registers_x86;
 extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);
+
+#if defined(_LIBUNWIND_USE_CET)
+extern "C" void *__libunwind_cet_get_jump_target() {
+  return reinterpret_cast<void *>(&__libunwind_Registers_x86_jumpto);
+}
+#endif
+
 /// Registers_x86 holds the register state of a thread in a 32-bit intel
 /// process.
 class _LIBUNWIND_HIDDEN Registers_x86 {
@@ -61,7 +71,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; }
@@ -80,7 +92,6 @@ public:
   void      setESI(uint32_t value) { _registers.__esi = value; }
   uint32_t  getEDI() const         { return _registers.__edi; }
   void      setEDI(uint32_t value) { _registers.__edi = value; }
-  uint32_t  getWCookie() const     { return 0; }
 
 private:
   struct GPRs {
@@ -255,6 +266,13 @@ inline void Registers_x86::setVectorRegister(int, v128) {
 /// process.
 class _LIBUNWIND_HIDDEN Registers_x86_64;
 extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);
+
+#if defined(_LIBUNWIND_USE_CET)
+extern "C" void *__libunwind_cet_get_jump_target() {
+  return reinterpret_cast<void *>(&__libunwind_Registers_x86_64_jumpto);
+}
+#endif
+
 class _LIBUNWIND_HIDDEN Registers_x86_64 {
 public:
   Registers_x86_64();
@@ -271,7 +289,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; }
@@ -290,7 +310,6 @@ public:
   void      setR14(uint64_t value) { _registers.__r14 = value; }
   uint64_t  getR15() const         { return _registers.__r15; }
   void      setR15(uint64_t value) { _registers.__r15 = value; }
-  uint64_t  getWCookie() const     { return 0; }
 
 private:
   struct GPRs {
@@ -342,7 +361,7 @@ inline bool Registers_x86_64::validRegister(int regNum) const {
     return true;
   if (regNum < 0)
     return false;
-  if (regNum > 15)
+  if (regNum > 16)
     return false;
   return true;
 }
@@ -350,6 +369,7 @@ inline bool Registers_x86_64::validRegister(int regNum) const {
 inline uint64_t Registers_x86_64::getRegister(int regNum) const {
   switch (regNum) {
   case UNW_REG_IP:
+  case UNW_X86_64_RIP:
     return _registers.__rip;
   case UNW_REG_SP:
     return _registers.__rsp;
@@ -392,6 +412,7 @@ inline uint64_t Registers_x86_64::getRegister(int regNum) const {
 inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
   switch (regNum) {
   case UNW_REG_IP:
+  case UNW_X86_64_RIP:
     _registers.__rip = value;
     return;
   case UNW_REG_SP:
@@ -452,6 +473,7 @@ inline void Registers_x86_64::setRegister(int regNum, uint64_t value) {
 inline const char *Registers_x86_64::getRegisterName(int regNum) {
   switch (regNum) {
   case UNW_REG_IP:
+  case UNW_X86_64_RIP:
     return "rip";
   case UNW_REG_SP:
     return "rsp";
@@ -586,14 +608,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  getWCookie() const    { return 0; }
+  uint64_t  getCR() const         { return _registers.__cr; }
+  void      setCR(uint32_t value) { _registers.__cr = value; }
 
 private:
   struct ppc_thread_state_t {
@@ -1153,14 +1178,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  getWCookie() const    { return 0; }
+  uint64_t  getCR() const         { return _registers.__cr; }
+  void      setCR(uint64_t value) { _registers.__cr = value; }
 
 private:
   struct ppc64_thread_state_t {
@@ -1799,7 +1827,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; }
@@ -1808,7 +1838,6 @@ public:
   void      setIP(uint64_t value) { _registers.__pc = value; }
   uint64_t  getFP() const         { return _registers.__fp; }
   void      setFP(uint64_t value) { _registers.__fp = value; }
-  uint64_t  getWCookie() const    { return 0; }
 
 private:
   struct GPRs {
@@ -1853,7 +1882,7 @@ inline bool Registers_arm64::validRegister(int regNum) const {
     return false;
   if (regNum > 95)
     return false;
-  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+  if (regNum == UNW_AARCH64_RA_SIGN_STATE)
     return true;
   if ((regNum > 32) && (regNum < 64))
     return false;
@@ -1861,15 +1890,15 @@ inline bool Registers_arm64::validRegister(int regNum) const {
 }
 
 inline uint64_t Registers_arm64::getRegister(int regNum) const {
-  if (regNum == UNW_REG_IP || regNum == UNW_ARM64_PC)
+  if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
     return _registers.__pc;
-  if (regNum == UNW_REG_SP || regNum == UNW_ARM64_SP)
+  if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
     return _registers.__sp;
-  if (regNum == UNW_ARM64_RA_SIGN_STATE)
+  if (regNum == UNW_AARCH64_RA_SIGN_STATE)
     return _registers.__ra_sign_state;
-  if (regNum == UNW_ARM64_FP)
+  if (regNum == UNW_AARCH64_FP)
     return _registers.__fp;
-  if (regNum == UNW_ARM64_LR)
+  if (regNum == UNW_AARCH64_LR)
     return _registers.__lr;
   if ((regNum >= 0) && (regNum < 29))
     return _registers.__x[regNum];
@@ -1877,15 +1906,15 @@ inline uint64_t Registers_arm64::getRegister(int regNum) const {
 }
 
 inline void Registers_arm64::setRegister(int regNum, uint64_t value) {
-  if (regNum == UNW_REG_IP || regNum == UNW_ARM64_PC)
+  if (regNum == UNW_REG_IP || regNum == UNW_AARCH64_PC)
     _registers.__pc = value;
-  else if (regNum == UNW_REG_SP || regNum == UNW_ARM64_SP)
+  else if (regNum == UNW_REG_SP || regNum == UNW_AARCH64_SP)
     _registers.__sp = value;
-  else if (regNum == UNW_ARM64_RA_SIGN_STATE)
+  else if (regNum == UNW_AARCH64_RA_SIGN_STATE)
     _registers.__ra_sign_state = value;
-  else if (regNum == UNW_ARM64_FP)
+  else if (regNum == UNW_AARCH64_FP)
     _registers.__fp = value;
-  else if (regNum == UNW_ARM64_LR)
+  else if (regNum == UNW_AARCH64_LR)
     _registers.__lr = value;
   else if ((regNum >= 0) && (regNum < 29))
     _registers.__x[regNum] = value;
@@ -1899,135 +1928,135 @@ inline const char *Registers_arm64::getRegisterName(int regNum) {
     return "pc";
   case UNW_REG_SP:
     return "sp";
-  case UNW_ARM64_X0:
+  case UNW_AARCH64_X0:
     return "x0";
-  case UNW_ARM64_X1:
+  case UNW_AARCH64_X1:
     return "x1";
-  case UNW_ARM64_X2:
+  case UNW_AARCH64_X2:
     return "x2";
-  case UNW_ARM64_X3:
+  case UNW_AARCH64_X3:
     return "x3";
-  case UNW_ARM64_X4:
+  case UNW_AARCH64_X4:
     return "x4";
-  case UNW_ARM64_X5:
+  case UNW_AARCH64_X5:
     return "x5";
-  case UNW_ARM64_X6:
+  case UNW_AARCH64_X6:
     return "x6";
-  case UNW_ARM64_X7:
+  case UNW_AARCH64_X7:
     return "x7";
-  case UNW_ARM64_X8:
+  case UNW_AARCH64_X8:
     return "x8";
-  case UNW_ARM64_X9:
+  case UNW_AARCH64_X9:
     return "x9";
-  case UNW_ARM64_X10:
+  case UNW_AARCH64_X10:
     return "x10";
-  case UNW_ARM64_X11:
+  case UNW_AARCH64_X11:
     return "x11";
-  case UNW_ARM64_X12:
+  case UNW_AARCH64_X12:
     return "x12";
-  case UNW_ARM64_X13:
+  case UNW_AARCH64_X13:
     return "x13";
-  case UNW_ARM64_X14:
+  case UNW_AARCH64_X14:
     return "x14";
-  case UNW_ARM64_X15:
+  case UNW_AARCH64_X15:
     return "x15";
-  case UNW_ARM64_X16:
+  case UNW_AARCH64_X16:
     return "x16";
-  case UNW_ARM64_X17:
+  case UNW_AARCH64_X17:
     return "x17";
-  case UNW_ARM64_X18:
+  case UNW_AARCH64_X18:
     return "x18";
-  case UNW_ARM64_X19:
+  case UNW_AARCH64_X19:
     return "x19";
-  case UNW_ARM64_X20:
+  case UNW_AARCH64_X20:
     return "x20";
-  case UNW_ARM64_X21:
+  case UNW_AARCH64_X21:
     return "x21";
-  case UNW_ARM64_X22:
+  case UNW_AARCH64_X22:
     return "x22";
-  case UNW_ARM64_X23:
+  case UNW_AARCH64_X23:
     return "x23";
-  case UNW_ARM64_X24:
+  case UNW_AARCH64_X24:
     return "x24";
-  case UNW_ARM64_X25:
+  case UNW_AARCH64_X25:
     return "x25";
-  case UNW_ARM64_X26:
+  case UNW_AARCH64_X26:
     return "x26";
-  case UNW_ARM64_X27:
+  case UNW_AARCH64_X27:
     return "x27";
-  case UNW_ARM64_X28:
+  case UNW_AARCH64_X28:
     return "x28";
-  case UNW_ARM64_FP:
+  case UNW_AARCH64_FP:
     return "fp";
-  case UNW_ARM64_LR:
+  case UNW_AARCH64_LR:
     return "lr";
-  case UNW_ARM64_SP:
+  case UNW_AARCH64_SP:
     return "sp";
-  case UNW_ARM64_PC:
+  case UNW_AARCH64_PC:
     return "pc";
-  case UNW_ARM64_D0:
+  case UNW_AARCH64_V0:
     return "d0";
-  case UNW_ARM64_D1:
+  case UNW_AARCH64_V1:
     return "d1";
-  case UNW_ARM64_D2:
+  case UNW_AARCH64_V2:
     return "d2";
-  case UNW_ARM64_D3:
+  case UNW_AARCH64_V3:
     return "d3";
-  case UNW_ARM64_D4:
+  case UNW_AARCH64_V4:
     return "d4";
-  case UNW_ARM64_D5:
+  case UNW_AARCH64_V5:
     return "d5";
-  case UNW_ARM64_D6:
+  case UNW_AARCH64_V6:
     return "d6";
-  case UNW_ARM64_D7:
+  case UNW_AARCH64_V7:
     return "d7";
-  case UNW_ARM64_D8:
+  case UNW_AARCH64_V8:
     return "d8";
-  case UNW_ARM64_D9:
+  case UNW_AARCH64_V9:
     return "d9";
-  case UNW_ARM64_D10:
+  case UNW_AARCH64_V10:
     return "d10";
-  case UNW_ARM64_D11:
+  case UNW_AARCH64_V11:
     return "d11";
-  case UNW_ARM64_D12:
+  case UNW_AARCH64_V12:
     return "d12";
-  case UNW_ARM64_D13:
+  case UNW_AARCH64_V13:
     return "d13";
-  case UNW_ARM64_D14:
+  case UNW_AARCH64_V14:
     return "d14";
-  case UNW_ARM64_D15:
+  case UNW_AARCH64_V15:
     return "d15";
-  case UNW_ARM64_D16:
+  case UNW_AARCH64_V16:
     return "d16";
-  case UNW_ARM64_D17:
+  case UNW_AARCH64_V17:
     return "d17";
-  case UNW_ARM64_D18:
+  case UNW_AARCH64_V18:
     return "d18";
-  case UNW_ARM64_D19:
+  case UNW_AARCH64_V19:
     return "d19";
-  case UNW_ARM64_D20:
+  case UNW_AARCH64_V20:
     return "d20";
-  case UNW_ARM64_D21:
+  case UNW_AARCH64_V21:
     return "d21";
-  case UNW_ARM64_D22:
+  case UNW_AARCH64_V22:
     return "d22";
-  case UNW_ARM64_D23:
+  case UNW_AARCH64_V23:
     return "d23";
-  case UNW_ARM64_D24:
+  case UNW_AARCH64_V24:
     return "d24";
-  case UNW_ARM64_D25:
+  case UNW_AARCH64_V25:
     return "d25";
-  case UNW_ARM64_D26:
+  case UNW_AARCH64_V26:
     return "d26";
-  case UNW_ARM64_D27:
+  case UNW_AARCH64_V27:
     return "d27";
-  case UNW_ARM64_D28:
+  case UNW_AARCH64_V28:
     return "d28";
-  case UNW_ARM64_D29:
+  case UNW_AARCH64_V29:
     return "d29";
-  case UNW_ARM64_D30:
+  case UNW_AARCH64_V30:
     return "d30";
-  case UNW_ARM64_D31:
+  case UNW_AARCH64_V31:
     return "d31";
   default:
     return "unknown register";
@@ -2035,21 +2064,21 @@ inline const char *Registers_arm64::getRegisterName(int regNum) {
 }
 
 inline bool Registers_arm64::validFloatRegister(int regNum) const {
-  if (regNum < UNW_ARM64_D0)
+  if (regNum < UNW_AARCH64_V0)
     return false;
-  if (regNum > UNW_ARM64_D31)
+  if (regNum > UNW_AARCH64_V31)
     return false;
   return true;
 }
 
 inline double Registers_arm64::getFloatRegister(int regNum) const {
   assert(validFloatRegister(regNum));
-  return _vectorHalfRegisters[regNum - UNW_ARM64_D0];
+  return _vectorHalfRegisters[regNum - UNW_AARCH64_V0];
 }
 
 inline void Registers_arm64::setFloatRegister(int regNum, double value) {
   assert(validFloatRegister(regNum));
-  _vectorHalfRegisters[regNum - UNW_ARM64_D0] = value;
+  _vectorHalfRegisters[regNum - UNW_AARCH64_V0] = value;
 }
 
 inline bool Registers_arm64::validVectorRegister(int) const {
@@ -2090,14 +2119,15 @@ 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; }
   void      setSP(uint32_t value) { _registers.__sp = value; }
   uint32_t  getIP() const         { return _registers.__pc; }
   void      setIP(uint32_t value) { _registers.__pc = value; }
-  uint64_t  getWCookie() const    { return 0; }
 
   void saveVFPAsX() {
     assert(_use_X_for_vfp_save || !_saved_vfp_d0_d15);
@@ -2129,6 +2159,10 @@ private:
     uint32_t __pc;    // Program counter r15
   };
 
+  struct PseudoRegisters {
+    uint32_t __pac; // Return Authentication Code (PAC)
+  };
+
   static void saveVFPWithFSTMD(void*);
   static void saveVFPWithFSTMX(void*);
   static void saveVFPv3(void*);
@@ -2145,6 +2179,7 @@ private:
 
   // ARM registers
   GPRs _registers;
+  PseudoRegisters _pseudo_registers;
 
   // We save floating point registers lazily because we can't know ahead of
   // time which ones are used. See EHABI #4.7.
@@ -2182,6 +2217,7 @@ inline Registers_arm::Registers_arm(const void *registers)
                 "arm registers do not fit into unw_context_t");
   // See __unw_getcontext() note about data.
   memcpy(&_registers, registers, sizeof(_registers));
+  memset(&_pseudo_registers, 0, sizeof(_pseudo_registers));
   memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
   memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
 #if defined(__ARM_WMMX)
@@ -2197,6 +2233,7 @@ inline Registers_arm::Registers_arm()
     _saved_vfp_d0_d15(false),
     _saved_vfp_d16_d31(false) {
   memset(&_registers, 0, sizeof(_registers));
+  memset(&_pseudo_registers, 0, sizeof(_pseudo_registers));
   memset(&_vfp_d0_d15_pad, 0, sizeof(_vfp_d0_d15_pad));
   memset(&_vfp_d16_d31, 0, sizeof(_vfp_d16_d31));
 #if defined(__ARM_WMMX)
@@ -2224,6 +2261,11 @@ inline bool Registers_arm::validRegister(int regNum) const {
     return true;
 #endif
 
+#ifdef __ARM_FEATURE_PAUTH
+  if (regNum == UNW_ARM_RA_AUTH_CODE)
+    return true;
+#endif
+
   return false;
 }
 
@@ -2250,6 +2292,11 @@ inline uint32_t Registers_arm::getRegister(int regNum) const {
   }
 #endif
 
+#ifdef __ARM_FEATURE_PAUTH
+  if (regNum == UNW_ARM_RA_AUTH_CODE)
+    return _pseudo_registers.__pac;
+#endif
+
   _LIBUNWIND_ABORT("unsupported arm register");
 }
 
@@ -2285,6 +2332,11 @@ inline void Registers_arm::setRegister(int regNum, uint32_t value) {
   }
 #endif
 
+  if (regNum == UNW_ARM_RA_AUTH_CODE) {
+    _pseudo_registers.__pac = value;
+    return;
+  }
+
   _LIBUNWIND_ABORT("unsupported arm register");
 }
 
@@ -2569,14 +2621,15 @@ 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]; }
   void      setSP(uint32_t value) { _registers.__r[1] = value; }
   uint64_t  getIP() const         { return _registers.__pc; }
   void      setIP(uint32_t value) { _registers.__pc = value; }
-  uint64_t  getWCookie() const    { return 0; }
 
 private:
   struct or1k_thread_state_t {
@@ -2748,150 +2801,6 @@ inline const char *Registers_or1k::getRegisterName(int regNum) {
 }
 #endif // _LIBUNWIND_TARGET_OR1K
 
-#if defined(_LIBUNWIND_TARGET_SPARC64)
-/// Registers_sparc64 holds the register state of a thread in a 64-bit
-/// sparc process.
-class _LIBUNWIND_HIDDEN Registers_sparc64 {
-public:
-  Registers_sparc64();
-  Registers_sparc64(const void *registers);
-
-  bool        validRegister(int num) const;
-  uint64_t    getRegister(int num) const;
-  void        setRegister(int num, uint64_t value);
-  bool        validFloatRegister(int num) const;
-  double      getFloatRegister(int num) const;
-  void        setFloatRegister(int num, double value);
-  bool        validVectorRegister(int num) const;
-  v128        getVectorRegister(int num) const;
-  void        setVectorRegister(int num, v128 value);
-  const char *getRegisterName(int num);
-  void        jumpto();
-  static int  lastDwarfRegNum() { return 31; }
-  static int  getArch() { return REGISTERS_SPARC64; }
-
-  uint64_t  getSP() const         { return _registers.__o[6] + 2047; }
-  void      setSP(uint64_t value) { _registers.__o[6] = value - 2047; }
-  uint64_t  getIP() const         { return _registers.__o[7]; }
-  void      setIP(uint64_t value) { _registers.__o[7] = value; }
-  uint64_t  getWCookie() const    { return _wcookie; }
-
-private:
-  struct GPRs {
-    uint64_t __g[8];
-    uint64_t __o[8];
-    uint64_t __l[8];
-    uint64_t __i[8];
-  };
-
-  GPRs _registers;
-  uint64_t _wcookie;
-};
-
-inline Registers_sparc64::Registers_sparc64(const void *registers) {
-  static_assert((check_fit<Registers_sparc64, unw_context_t>::does_fit),
-                "sparc64 registers do not fit into unw_context_t");
-  memcpy(&_registers, static_cast<const uint8_t *>(registers),
-         sizeof(_registers));
-  memcpy(&_wcookie, static_cast<const uint8_t *>(registers) + sizeof(GPRs),
-        sizeof(_wcookie));
-}
-
-inline Registers_sparc64::Registers_sparc64() {
-  memset(&_registers, 0, sizeof(_registers));
-  _wcookie = 0;
-}
-
-inline bool Registers_sparc64::validRegister(int regNum) const {
-  if (regNum == UNW_REG_IP)
-    return true;
-  if (regNum == UNW_REG_SP)
-    return true;
-  if (regNum < 0)
-    return false;
-  if (regNum <= 31)
-    return true;
-  return false;
-}
-
-inline uint64_t Registers_sparc64::getRegister(int regNum) const {
-  if (regNum >= 0 && regNum <= 7)
-    return _registers.__g[regNum - 0];
-  if (regNum >= 8 && regNum <= 15)
-    return _registers.__o[regNum - 8];
-  if (regNum >= 16 && regNum <= 23)
-    return _registers.__l[regNum - 16];
-  if (regNum >= 24 && regNum <= 31)
-    return _registers.__i[regNum - 24];
-
-  switch (regNum) {
-  case UNW_REG_IP:
-    return _registers.__o[7] + 8;
-  case UNW_REG_SP:
-    return _registers.__o[6] + 2047;
-  }
-  _LIBUNWIND_ABORT("unsupported sparc64 register");
-}
-
-inline void Registers_sparc64::setRegister(int regNum, uint64_t value) {
-  if (regNum >= 0 && regNum <= 7) {
-    _registers.__g[regNum - 0] = value;
-    return;
-  }
-  if (regNum >= 8 && regNum <= 15) {
-    _registers.__o[regNum - 8] = value;
-    return;
-  }
-  if (regNum >= 16 && regNum <= 23) {
-    _registers.__l[regNum - 16] = value;
-    return;
-  }
-  if (regNum >= 24 && regNum <= 31) {
-    _registers.__i[regNum - 24] = value;
-    return;
-  }
-
-  switch (regNum) {
-  case UNW_REG_IP:
-    _registers.__o[7] = value - 8;
-    return;
-  case UNW_REG_SP:
-    _registers.__o[6] = value - 2047;
-    return;
-  }
-  _LIBUNWIND_ABORT("unsupported sparc64 register");
-}
-
-inline bool Registers_sparc64::validFloatRegister(int) const {
-  return false;
-}
-
-inline double Registers_sparc64::getFloatRegister(int) const {
-  _LIBUNWIND_ABORT("no sparc64 float registers");
-}
-
-inline void Registers_sparc64::setFloatRegister(int, double) {
-  _LIBUNWIND_ABORT("no sparc64 float registers");
-}
-
-inline bool Registers_sparc64::validVectorRegister(int) const {
-  return false;
-}
-
-inline v128 Registers_sparc64::getVectorRegister(int) const {
-  _LIBUNWIND_ABORT("no sparc64 vector registers");
-}
-
-inline void Registers_sparc64::setVectorRegister(int, v128) {
-  _LIBUNWIND_ABORT("no sparc64 vector registers");
-}
-
-inline const char *Registers_sparc64::getRegisterName(int regNum) {
-  return "unknown register";
-}
-
-#endif // _LIBUNWIND_TARGET_SPARC64
-
 #if defined(_LIBUNWIND_TARGET_MIPS_O32)
 /// Registers_mips_o32 holds the register state of a thread in a 32-bit MIPS
 /// process.
@@ -2911,14 +2820,15 @@ 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]; }
   void      setSP(uint32_t value) { _registers.__r[29] = value; }
   uint32_t  getIP() const         { return _registers.__pc; }
   void      setIP(uint32_t value) { _registers.__pc = value; }
-  uint32_t  getWCookie() const    { return 0; }
 
 private:
   struct mips_o32_thread_state_t {
@@ -3239,14 +3149,15 @@ 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]; }
   void      setSP(uint64_t value) { _registers.__r[29] = value; }
   uint64_t  getIP() const         { return _registers.__pc; }
   void      setIP(uint64_t value) { _registers.__pc = value; }
-  uint32_t  getWCookie() const    { return 0; }
 
 private:
   struct mips_newabi_thread_state_t {
@@ -3535,7 +3446,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]; }
@@ -3700,6 +3613,191 @@ inline const char *Registers_sparc::getRegisterName(int regNum) {
 }
 #endif // _LIBUNWIND_TARGET_SPARC
 
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+/// Registers_sparc64 holds the register state of a thread in a 64-bit
+/// sparc process.
+class _LIBUNWIND_HIDDEN Registers_sparc64 {
+public:
+  Registers_sparc64() = default;
+  Registers_sparc64(const void *registers);
+
+  bool validRegister(int num) const;
+  uint64_t getRegister(int num) const;
+  void setRegister(int num, uint64_t value);
+  bool validFloatRegister(int num) const;
+  double getFloatRegister(int num) const;
+  void setFloatRegister(int num, double value);
+  bool validVectorRegister(int num) const;
+  v128 getVectorRegister(int num) const;
+  void setVectorRegister(int num, v128 value);
+  const char *getRegisterName(int num);
+  void jumpto();
+  static constexpr int lastDwarfRegNum() {
+    return _LIBUNWIND_HIGHEST_DWARF_REGISTER_SPARC64;
+  }
+  static int getArch() { return REGISTERS_SPARC64; }
+
+  uint64_t getSP() const { return _registers.__regs[UNW_SPARC_O6] + 2047; }
+  void setSP(uint64_t value) { _registers.__regs[UNW_SPARC_O6] = value - 2047; }
+  uint64_t getIP() const { return _registers.__regs[UNW_SPARC_O7]; }
+  void setIP(uint64_t value) { _registers.__regs[UNW_SPARC_O7] = value; }
+  uint64_t getWCookie() const { return _wcookie; }
+
+private:
+  struct sparc64_thread_state_t {
+    uint64_t __regs[32];
+  };
+
+  sparc64_thread_state_t _registers{};
+  uint64_t _wcookie = 0;
+};
+
+inline Registers_sparc64::Registers_sparc64(const void *registers) {
+  static_assert((check_fit<Registers_sparc64, unw_context_t>::does_fit),
+                "sparc64 registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+  memcpy(&_wcookie,
+         static_cast<const uint8_t *>(registers) + sizeof(_registers),
+         sizeof(_wcookie));
+}
+
+inline bool Registers_sparc64::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP)
+    return true;
+  if (regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0)
+    return false;
+  if (regNum <= UNW_SPARC_I7)
+    return true;
+  return false;
+}
+
+inline uint64_t Registers_sparc64::getRegister(int regNum) const {
+  if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7)
+    return _registers.__regs[regNum];
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    return _registers.__regs[UNW_SPARC_O7];
+  case UNW_REG_SP:
+    return _registers.__regs[UNW_SPARC_O6] + 2047;
+  }
+  _LIBUNWIND_ABORT("unsupported sparc64 register");
+}
+
+inline void Registers_sparc64::setRegister(int regNum, uint64_t value) {
+  if (regNum >= UNW_SPARC_G0 && regNum <= UNW_SPARC_I7) {
+    _registers.__regs[regNum] = value;
+    return;
+  }
+
+  switch (regNum) {
+  case UNW_REG_IP:
+    _registers.__regs[UNW_SPARC_O7] = value;
+    return;
+  case UNW_REG_SP:
+    _registers.__regs[UNW_SPARC_O6] = value - 2047;
+    return;
+  }
+  _LIBUNWIND_ABORT("unsupported sparc64 register");
+}
+
+inline bool Registers_sparc64::validFloatRegister(int) const { return false; }
+
+inline double Registers_sparc64::getFloatRegister(int) const {
+  _LIBUNWIND_ABORT("no sparc64 float registers");
+}
+
+inline void Registers_sparc64::setFloatRegister(int, double) {
+  _LIBUNWIND_ABORT("no sparc64 float registers");
+}
+
+inline bool Registers_sparc64::validVectorRegister(int) const { return false; }
+
+inline v128 Registers_sparc64::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("no sparc64 vector registers");
+}
+
+inline void Registers_sparc64::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("no sparc64 vector registers");
+}
+
+inline const char *Registers_sparc64::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "pc";
+  case UNW_SPARC_G0:
+    return "g0";
+  case UNW_SPARC_G1:
+    return "g1";
+  case UNW_SPARC_G2:
+    return "g2";
+  case UNW_SPARC_G3:
+    return "g3";
+  case UNW_SPARC_G4:
+    return "g4";
+  case UNW_SPARC_G5:
+    return "g5";
+  case UNW_SPARC_G6:
+    return "g6";
+  case UNW_SPARC_G7:
+    return "g7";
+  case UNW_SPARC_O0:
+    return "o0";
+  case UNW_SPARC_O1:
+    return "o1";
+  case UNW_SPARC_O2:
+    return "o2";
+  case UNW_SPARC_O3:
+    return "o3";
+  case UNW_SPARC_O4:
+    return "o4";
+  case UNW_SPARC_O5:
+    return "o5";
+  case UNW_REG_SP:
+  case UNW_SPARC_O6:
+    return "o6";
+  case UNW_SPARC_O7:
+    return "o7";
+  case UNW_SPARC_L0:
+    return "l0";
+  case UNW_SPARC_L1:
+    return "l1";
+  case UNW_SPARC_L2:
+    return "l2";
+  case UNW_SPARC_L3:
+    return "l3";
+  case UNW_SPARC_L4:
+    return "l4";
+  case UNW_SPARC_L5:
+    return "l5";
+  case UNW_SPARC_L6:
+    return "l6";
+  case UNW_SPARC_L7:
+    return "l7";
+  case UNW_SPARC_I0:
+    return "i0";
+  case UNW_SPARC_I1:
+    return "i1";
+  case UNW_SPARC_I2:
+    return "i2";
+  case UNW_SPARC_I3:
+    return "i3";
+  case UNW_SPARC_I4:
+    return "i4";
+  case UNW_SPARC_I5:
+    return "i5";
+  case UNW_SPARC_I6:
+    return "i6";
+  case UNW_SPARC_I7:
+    return "i7";
+  default:
+    return "unknown register";
+  }
+}
+#endif // _LIBUNWIND_TARGET_SPARC64
+
 #if defined(_LIBUNWIND_TARGET_HEXAGON)
 /// Registers_hexagon holds the register state of a thread in a Hexagon QDSP6
 /// process.
@@ -3719,7 +3817,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]; }
@@ -3904,7 +4004,7 @@ typedef float fp_t;
 #    error "Unsupported __riscv_flen"
 #   endif
 #  else
-// This is just for supressing undeclared error of fp_t.
+// This is just for suppressing undeclared error of fp_t.
 typedef double fp_t;
 #  endif
 # else
@@ -3932,14 +4032,15 @@ 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]; }
   void        setSP(reg_t value) { _registers[2] = value; }
   reg_t       getIP() const { return _registers[0]; }
   void        setIP(reg_t value) { _registers[0] = value; }
-  uint64_t    getWCookie() const     { return 0; }
 
 private:
   // _registers[0] holds the pc
@@ -3984,6 +4085,8 @@ inline bool Registers_riscv::validRegister(int regNum) const {
     return true;
   if (regNum < 0)
     return false;
+  if (regNum == UNW_RISCV_VLENB)
+    return true;
   if (regNum > UNW_RISCV_F31)
     return false;
   return true;
@@ -3998,6 +4101,11 @@ inline reg_t Registers_riscv::getRegister(int regNum) const {
     return 0;
   if ((regNum > 0) && (regNum < 32))
     return _registers[regNum];
+  if (regNum == UNW_RISCV_VLENB) {
+    reg_t vlenb;
+    __asm__("csrr %0, 0xC22" : "=r"(vlenb));
+    return vlenb;
+  }
   _LIBUNWIND_ABORT("unsupported riscv register");
 }
 
@@ -4149,6 +4257,8 @@ inline const char *Registers_riscv::getRegisterName(int regNum) {
     return "ft10";
   case UNW_RISCV_F31:
     return "ft11";
+  case UNW_RISCV_VLENB:
+    return "vlenb";
   default:
     return "unknown register";
   }
@@ -4219,7 +4329,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]; }
@@ -4641,6 +4753,560 @@ 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
+
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+/// Registers_loongarch holds the register state of a thread in a 64-bit
+/// LoongArch process.
+class _LIBUNWIND_HIDDEN Registers_loongarch {
+public:
+  Registers_loongarch();
+  Registers_loongarch(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_LOONGARCH;
+  }
+  static int getArch() { return REGISTERS_LOONGARCH; }
+
+  uint64_t getSP() const { return _registers.__r[3]; }
+  void setSP(uint64_t value) { _registers.__r[3] = value; }
+  uint64_t getIP() const { return _registers.__pc; }
+  void setIP(uint64_t value) { _registers.__pc = value; }
+
+private:
+  struct loongarch_thread_state_t {
+    uint64_t __r[32];
+    uint64_t __pc;
+  };
+
+  loongarch_thread_state_t _registers;
+#if __loongarch_frlen == 64
+  double _floats[32];
+#endif
+};
+
+inline Registers_loongarch::Registers_loongarch(const void *registers) {
+  static_assert((check_fit<Registers_loongarch, unw_context_t>::does_fit),
+                "loongarch registers do not fit into unw_context_t");
+  memcpy(&_registers, registers, sizeof(_registers));
+  static_assert(sizeof(_registers) == 0x108,
+                "expected float registers to be at offset 264");
+#if __loongarch_frlen == 64
+  memcpy(_floats, static_cast<const uint8_t *>(registers) + sizeof(_registers),
+         sizeof(_floats));
+#endif
+}
+
+inline Registers_loongarch::Registers_loongarch() {
+  memset(&_registers, 0, sizeof(_registers));
+#if __loongarch_frlen == 64
+  memset(&_floats, 0, sizeof(_floats));
+#endif
+}
+
+inline bool Registers_loongarch::validRegister(int regNum) const {
+  if (regNum == UNW_REG_IP || regNum == UNW_REG_SP)
+    return true;
+  if (regNum < 0 || regNum > UNW_LOONGARCH_F31)
+    return false;
+  return true;
+}
+
+inline uint64_t Registers_loongarch::getRegister(int regNum) const {
+  if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+    return _registers.__r[regNum - UNW_LOONGARCH_R0];
+
+  if (regNum == UNW_REG_IP)
+    return _registers.__pc;
+  if (regNum == UNW_REG_SP)
+    return _registers.__r[3];
+  _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline void Registers_loongarch::setRegister(int regNum, uint64_t value) {
+  if (regNum >= UNW_LOONGARCH_R0 && regNum <= UNW_LOONGARCH_R31)
+    _registers.__r[regNum - UNW_LOONGARCH_R0] = value;
+  else if (regNum == UNW_REG_IP)
+    _registers.__pc = value;
+  else if (regNum == UNW_REG_SP)
+    _registers.__r[3] = value;
+  else
+    _LIBUNWIND_ABORT("unsupported loongarch register");
+}
+
+inline const char *Registers_loongarch::getRegisterName(int regNum) {
+  switch (regNum) {
+  case UNW_REG_IP:
+    return "$pc";
+  case UNW_REG_SP:
+    return "$sp";
+  case UNW_LOONGARCH_R0:
+    return "$r0";
+  case UNW_LOONGARCH_R1:
+    return "$r1";
+  case UNW_LOONGARCH_R2:
+    return "$r2";
+  case UNW_LOONGARCH_R3:
+    return "$r3";
+  case UNW_LOONGARCH_R4:
+    return "$r4";
+  case UNW_LOONGARCH_R5:
+    return "$r5";
+  case UNW_LOONGARCH_R6:
+    return "$r6";
+  case UNW_LOONGARCH_R7:
+    return "$r7";
+  case UNW_LOONGARCH_R8:
+    return "$r8";
+  case UNW_LOONGARCH_R9:
+    return "$r9";
+  case UNW_LOONGARCH_R10:
+    return "$r10";
+  case UNW_LOONGARCH_R11:
+    return "$r11";
+  case UNW_LOONGARCH_R12:
+    return "$r12";
+  case UNW_LOONGARCH_R13:
+    return "$r13";
+  case UNW_LOONGARCH_R14:
+    return "$r14";
+  case UNW_LOONGARCH_R15:
+    return "$r15";
+  case UNW_LOONGARCH_R16:
+    return "$r16";
+  case UNW_LOONGARCH_R17:
+    return "$r17";
+  case UNW_LOONGARCH_R18:
+    return "$r18";
+  case UNW_LOONGARCH_R19:
+    return "$r19";
+  case UNW_LOONGARCH_R20:
+    return "$r20";
+  case UNW_LOONGARCH_R21:
+    return "$r21";
+  case UNW_LOONGARCH_R22:
+    return "$r22";
+  case UNW_LOONGARCH_R23:
+    return "$r23";
+  case UNW_LOONGARCH_R24:
+    return "$r24";
+  case UNW_LOONGARCH_R25:
+    return "$r25";
+  case UNW_LOONGARCH_R26:
+    return "$r26";
+  case UNW_LOONGARCH_R27:
+    return "$r27";
+  case UNW_LOONGARCH_R28:
+    return "$r28";
+  case UNW_LOONGARCH_R29:
+    return "$r29";
+  case UNW_LOONGARCH_R30:
+    return "$r30";
+  case UNW_LOONGARCH_R31:
+    return "$r31";
+  case UNW_LOONGARCH_F0:
+    return "$f0";
+  case UNW_LOONGARCH_F1:
+    return "$f1";
+  case UNW_LOONGARCH_F2:
+    return "$f2";
+  case UNW_LOONGARCH_F3:
+    return "$f3";
+  case UNW_LOONGARCH_F4:
+    return "$f4";
+  case UNW_LOONGARCH_F5:
+    return "$f5";
+  case UNW_LOONGARCH_F6:
+    return "$f6";
+  case UNW_LOONGARCH_F7:
+    return "$f7";
+  case UNW_LOONGARCH_F8:
+    return "$f8";
+  case UNW_LOONGARCH_F9:
+    return "$f9";
+  case UNW_LOONGARCH_F10:
+    return "$f10";
+  case UNW_LOONGARCH_F11:
+    return "$f11";
+  case UNW_LOONGARCH_F12:
+    return "$f12";
+  case UNW_LOONGARCH_F13:
+    return "$f13";
+  case UNW_LOONGARCH_F14:
+    return "$f14";
+  case UNW_LOONGARCH_F15:
+    return "$f15";
+  case UNW_LOONGARCH_F16:
+    return "$f16";
+  case UNW_LOONGARCH_F17:
+    return "$f17";
+  case UNW_LOONGARCH_F18:
+    return "$f18";
+  case UNW_LOONGARCH_F19:
+    return "$f19";
+  case UNW_LOONGARCH_F20:
+    return "$f20";
+  case UNW_LOONGARCH_F21:
+    return "$f21";
+  case UNW_LOONGARCH_F22:
+    return "$f22";
+  case UNW_LOONGARCH_F23:
+    return "$f23";
+  case UNW_LOONGARCH_F24:
+    return "$f24";
+  case UNW_LOONGARCH_F25:
+    return "$f25";
+  case UNW_LOONGARCH_F26:
+    return "$f26";
+  case UNW_LOONGARCH_F27:
+    return "$f27";
+  case UNW_LOONGARCH_F28:
+    return "$f28";
+  case UNW_LOONGARCH_F29:
+    return "$f29";
+  case UNW_LOONGARCH_F30:
+    return "$f30";
+  case UNW_LOONGARCH_F31:
+    return "$f31";
+  default:
+    return "unknown register";
+  }
+}
+
+inline bool Registers_loongarch::validFloatRegister(int regNum) const {
+  if (regNum < UNW_LOONGARCH_F0 || regNum > UNW_LOONGARCH_F31)
+    return false;
+  return true;
+}
+
+inline double Registers_loongarch::getFloatRegister(int regNum) const {
+#if __loongarch_frlen == 64
+  assert(validFloatRegister(regNum));
+  return _floats[regNum - UNW_LOONGARCH_F0];
+#else
+  _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline void Registers_loongarch::setFloatRegister(int regNum, double value) {
+#if __loongarch_frlen == 64
+  assert(validFloatRegister(regNum));
+  _floats[regNum - UNW_LOONGARCH_F0] = value;
+#else
+  _LIBUNWIND_ABORT("libunwind not built with float support");
+#endif
+}
+
+inline bool Registers_loongarch::validVectorRegister(int) const {
+  return false;
+}
+
+inline v128 Registers_loongarch::getVectorRegister(int) const {
+  _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+
+inline void Registers_loongarch::setVectorRegister(int, v128) {
+  _LIBUNWIND_ABORT("loongarch vector support not implemented");
+}
+#endif //_LIBUNWIND_TARGET_LOONGARCH
+
 } // namespace libunwind
 
 #endif // __REGISTERS_HPP__
index 28a7896..69a3ceb 100644 (file)
@@ -1,4 +1,4 @@
-//===------------------------- UnwindCursor.hpp ---------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -11,6 +11,7 @@
 #ifndef __UNWINDCURSOR_HPP__
 #define __UNWINDCURSOR_HPP__
 
+#include "cet_unwind.h"
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
 #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
+
+#include "AddressSpace.hpp"
+#include "CompactUnwinder.hpp"
+#include "config.h"
+#include "DwarfInstructions.hpp"
+#include "EHHeaderParser.hpp"
+#include "libunwind.h"
+#include "libunwind_ext.h"
+#include "Registers.hpp"
+#include "RWMutex.hpp"
+#include "Unwind-EHABI.h"
 
 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
 // Provide a definition for the DISPATCHER_CONTEXT struct for old (Win7 and
@@ -61,18 +86,6 @@ extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
 
 #endif
 
-#include "config.h"
-
-#include "AddressSpace.hpp"
-#include "CompactUnwinder.hpp"
-#include "config.h"
-#include "DwarfInstructions.hpp"
-#include "EHHeaderParser.hpp"
-#include "libunwind.h"
-#include "Registers.hpp"
-#include "RWMutex.hpp"
-#include "Unwind-EHABI.h"
-
 namespace libunwind {
 
 static thread_local UnwindInfoSectionsCache uwis_cache;
@@ -431,7 +444,7 @@ public:
   virtual void setFloatReg(int, unw_fpreg_t) {
     _LIBUNWIND_ABORT("setFloatReg not implemented");
   }
-  virtual int step() { _LIBUNWIND_ABORT("step not implemented"); }
+  virtual int step(bool = false) { _LIBUNWIND_ABORT("step not implemented"); }
   virtual void getInfo(unw_proc_info_t *) {
     _LIBUNWIND_ABORT("getInfo not implemented");
   }
@@ -451,6 +464,18 @@ public:
 #ifdef __arm__
   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");
+  }
+#endif
 };
 
 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND) && defined(_WIN32)
@@ -471,7 +496,7 @@ public:
   virtual bool        validFloatReg(int);
   virtual unw_fpreg_t getFloatReg(int);
   virtual void        setFloatReg(int, unw_fpreg_t);
-  virtual int         step();
+  virtual int         step(bool = false);
   virtual void        getInfo(unw_proc_info_t *);
   virtual void        jumpto();
   virtual bool        isSignalFrame();
@@ -486,7 +511,7 @@ public:
   void setDispatcherContext(DISPATCHER_CONTEXT *disp) { _dispContext = *disp; }
 
   // libunwind does not and should not depend on C++ library which means that we
-  // need our own defition of inline placement new.
+  // need our own definition of inline placement new.
   static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
 
 private:
@@ -494,6 +519,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);
@@ -622,12 +655,12 @@ UnwindCursor<A, R>::UnwindCursor(unw_context_t *context, A &as)
     _msContext.D[i - UNW_ARM_D0] = d.w;
   }
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
-  for (int i = UNW_ARM64_X0; i <= UNW_ARM64_X30; ++i)
-    _msContext.X[i - UNW_ARM64_X0] = r.getRegister(i);
+  for (int i = UNW_AARCH64_X0; i <= UNW_ARM64_X30; ++i)
+    _msContext.X[i - UNW_AARCH64_X0] = r.getRegister(i);
   _msContext.Sp = r.getRegister(UNW_REG_SP);
   _msContext.Pc = r.getRegister(UNW_REG_IP);
-  for (int i = UNW_ARM64_D0; i <= UNW_ARM64_D31; ++i)
-    _msContext.V[i - UNW_ARM64_D0].D[0] = r.getFloatRegister(i);
+  for (int i = UNW_AARCH64_V0; i <= UNW_ARM64_D31; ++i)
+    _msContext.V[i - UNW_AARCH64_V0].D[0] = r.getFloatRegister(i);
 #endif
 }
 
@@ -650,9 +683,11 @@ bool UnwindCursor<A, R>::validReg(int regNum) {
 #if defined(_LIBUNWIND_TARGET_X86_64)
   if (regNum >= UNW_X86_64_RAX && regNum <= UNW_X86_64_R15) return true;
 #elif defined(_LIBUNWIND_TARGET_ARM)
-  if (regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) return true;
+  if ((regNum >= UNW_ARM_R0 && regNum <= UNW_ARM_R15) ||
+      regNum == UNW_ARM_RA_AUTH_CODE)
+    return true;
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
-  if (regNum >= UNW_ARM64_X0 && regNum <= UNW_ARM64_X30) return true;
+  if (regNum >= UNW_AARCH64_X0 && regNum <= UNW_ARM64_X30) return true;
 #endif
   return false;
 }
@@ -701,7 +736,7 @@ unw_word_t UnwindCursor<A, R>::getReg(int regNum) {
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
   case UNW_REG_SP: return _msContext.Sp;
   case UNW_REG_IP: return _msContext.Pc;
-  default: return _msContext.X[regNum - UNW_ARM64_X0];
+  default: return _msContext.X[regNum - UNW_AARCH64_X0];
 #endif
   }
   _LIBUNWIND_ABORT("unsupported register");
@@ -751,37 +786,37 @@ void UnwindCursor<A, R>::setReg(int regNum, unw_word_t value) {
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
   case UNW_REG_SP: _msContext.Sp = value; break;
   case UNW_REG_IP: _msContext.Pc = value; break;
-  case UNW_ARM64_X0:
-  case UNW_ARM64_X1:
-  case UNW_ARM64_X2:
-  case UNW_ARM64_X3:
-  case UNW_ARM64_X4:
-  case UNW_ARM64_X5:
-  case UNW_ARM64_X6:
-  case UNW_ARM64_X7:
-  case UNW_ARM64_X8:
-  case UNW_ARM64_X9:
-  case UNW_ARM64_X10:
-  case UNW_ARM64_X11:
-  case UNW_ARM64_X12:
-  case UNW_ARM64_X13:
-  case UNW_ARM64_X14:
-  case UNW_ARM64_X15:
-  case UNW_ARM64_X16:
-  case UNW_ARM64_X17:
-  case UNW_ARM64_X18:
-  case UNW_ARM64_X19:
-  case UNW_ARM64_X20:
-  case UNW_ARM64_X21:
-  case UNW_ARM64_X22:
-  case UNW_ARM64_X23:
-  case UNW_ARM64_X24:
-  case UNW_ARM64_X25:
-  case UNW_ARM64_X26:
-  case UNW_ARM64_X27:
-  case UNW_ARM64_X28:
-  case UNW_ARM64_FP:
-  case UNW_ARM64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break;
+  case UNW_AARCH64_X0:
+  case UNW_AARCH64_X1:
+  case UNW_AARCH64_X2:
+  case UNW_AARCH64_X3:
+  case UNW_AARCH64_X4:
+  case UNW_AARCH64_X5:
+  case UNW_AARCH64_X6:
+  case UNW_AARCH64_X7:
+  case UNW_AARCH64_X8:
+  case UNW_AARCH64_X9:
+  case UNW_AARCH64_X10:
+  case UNW_AARCH64_X11:
+  case UNW_AARCH64_X12:
+  case UNW_AARCH64_X13:
+  case UNW_AARCH64_X14:
+  case UNW_AARCH64_X15:
+  case UNW_AARCH64_X16:
+  case UNW_AARCH64_X17:
+  case UNW_AARCH64_X18:
+  case UNW_AARCH64_X19:
+  case UNW_AARCH64_X20:
+  case UNW_AARCH64_X21:
+  case UNW_AARCH64_X22:
+  case UNW_AARCH64_X23:
+  case UNW_AARCH64_X24:
+  case UNW_AARCH64_X25:
+  case UNW_AARCH64_X26:
+  case UNW_AARCH64_X27:
+  case UNW_AARCH64_X28:
+  case UNW_AARCH64_FP:
+  case UNW_AARCH64_LR: _msContext.X[regNum - UNW_ARM64_X0] = value; break;
 #endif
   default:
     _LIBUNWIND_ABORT("unsupported register");
@@ -794,7 +829,7 @@ bool UnwindCursor<A, R>::validFloatReg(int regNum) {
   if (regNum >= UNW_ARM_S0 && regNum <= UNW_ARM_S31) return true;
   if (regNum >= UNW_ARM_D0 && regNum <= UNW_ARM_D31) return true;
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
-  if (regNum >= UNW_ARM64_D0 && regNum <= UNW_ARM64_D31) return true;
+  if (regNum >= UNW_AARCH64_V0 && regNum <= UNW_ARM64_D31) return true;
 #else
   (void)regNum;
 #endif
@@ -822,7 +857,7 @@ unw_fpreg_t UnwindCursor<A, R>::getFloatReg(int regNum) {
   }
   _LIBUNWIND_ABORT("unsupported float register");
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
-  return _msContext.V[regNum - UNW_ARM64_D0].D[0];
+  return _msContext.V[regNum - UNW_AARCH64_V0].D[0];
 #else
   (void)regNum;
   _LIBUNWIND_ABORT("float registers unimplemented");
@@ -837,7 +872,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) {
@@ -850,7 +885,7 @@ void UnwindCursor<A, R>::setFloatReg(int regNum, unw_fpreg_t value) {
   }
   _LIBUNWIND_ABORT("unsupported float register");
 #elif defined(_LIBUNWIND_TARGET_AARCH64)
-  _msContext.V[regNum - UNW_ARM64_D0].D[0] = value;
+  _msContext.V[regNum - UNW_AARCH64_V0].D[0] = value;
 #else
   (void)regNum;
   (void)value;
@@ -892,7 +927,7 @@ public:
   virtual bool        validFloatReg(int);
   virtual unw_fpreg_t getFloatReg(int);
   virtual void        setFloatReg(int, unw_fpreg_t);
-  virtual int         step();
+  virtual int         step(bool stage2 = false);
   virtual void        getInfo(unw_proc_info_t *);
   virtual void        jumpto();
   virtual bool        isSignalFrame();
@@ -903,8 +938,16 @@ 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.
+  // need our own definition of inline placement new.
   static void *operator new(size_t, UnwindCursor<A, R> *p) { return p; }
 
 private:
@@ -927,7 +970,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);
@@ -936,8 +979,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;
   }
@@ -952,22 +1001,21 @@ private:
                          pint_t pc, uintptr_t dso_base);
   bool getInfoFromDwarfSection(pint_t pc, const UnwindInfoSections &sects,
                                             uint32_t fdeSectionOffsetHint=0);
-  int stepWithDwarfFDE() {
-    return DwarfInstructions<A, R>::stepWithDwarf(_addressSpace,
-                                              (pint_t)this->getReg(UNW_REG_IP),
-                                              (pint_t)_info.unwind_info,
-                                              _registers, _isSignalFrame);
+  int stepWithDwarfFDE(bool stage2) {
+    return DwarfInstructions<A, R>::stepWithDwarf(
+        _addressSpace, (pint_t)this->getReg(UNW_REG_IP),
+        (pint_t)_info.unwind_info, _registers, _isSignalFrame, stage2);
   }
 #endif
 
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
   bool getInfoFromCompactEncodingSection(pint_t pc,
                                             const UnwindInfoSections &sects);
-  int stepWithCompactEncoding() {
-  #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
+  int stepWithCompactEncoding(bool stage2 = false) {
+#if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
     if ( compactSaysUseDwarf() )
-      return stepWithDwarfFDE();
-  #endif
+      return stepWithDwarfFDE(stage2);
+#endif
     R dummy;
     return stepWithCompactEncoding(dummy);
   }
@@ -1018,10 +1066,18 @@ private:
   }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+  int stepWithCompactEncoding(Registers_loongarch &) { return UNW_EINVAL; }
+#endif
+
 #if defined(_LIBUNWIND_TARGET_SPARC)
   int stepWithCompactEncoding(Registers_sparc &) { return UNW_EINVAL; }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+  int stepWithCompactEncoding(Registers_sparc64 &) { return UNW_EINVAL; }
+#endif
+
 #if defined (_LIBUNWIND_TARGET_RISCV)
   int stepWithCompactEncoding(Registers_riscv &) {
     return UNW_EINVAL;
@@ -1090,10 +1146,22 @@ private:
   }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+  bool compactSaysUseDwarf(Registers_loongarch &, uint32_t *) const {
+    return true;
+  }
+#endif
+
 #if defined(_LIBUNWIND_TARGET_SPARC)
   bool compactSaysUseDwarf(Registers_sparc &, uint32_t *) const { return true; }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_SPARC64)
+  bool compactSaysUseDwarf(Registers_sparc64 &, uint32_t *) const {
+    return true;
+  }
+#endif
+
 #if defined (_LIBUNWIND_TARGET_RISCV)
   bool compactSaysUseDwarf(Registers_riscv &, uint32_t *) const {
     return true;
@@ -1168,11 +1236,17 @@ private:
   }
 #endif
 
+#if defined(_LIBUNWIND_TARGET_LOONGARCH)
+  compact_unwind_encoding_t dwarfEncoding(Registers_loongarch &) const {
+    return 0;
+  }
+#endif
+
 #if defined(_LIBUNWIND_TARGET_SPARC)
   compact_unwind_encoding_t dwarfEncoding(Registers_sparc &) const { return 0; }
 #endif
 
-#if defined (_LIBUNWIND_TARGET_SPARC64)
+#if defined(_LIBUNWIND_TARGET_SPARC64)
   compact_unwind_encoding_t dwarfEncoding(Registers_sparc64 &) const {
     return 0;
   }
@@ -1184,6 +1258,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)
@@ -1200,13 +1280,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
 };
@@ -1272,6 +1362,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);
@@ -1892,20 +1989,523 @@ 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;
+          // The AIX dlopen() sets errno to 0 when it is successful, which
+          // clobbers the value of errno from the user code. This is an AIX
+          // bug because according to POSIX it should not set errno to 0. To
+          // workaround before AIX fixes the bug, errno is saved and restored.
+          int saveErrno = errno;
+          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);
+          errno = saveErrno;
+        }
+      }
+      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 simulates 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
 
@@ -1928,7 +2528,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;
@@ -1969,6 +2576,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) {
@@ -2014,7 +2627,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
@@ -2023,7 +2636,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
@@ -2042,14 +2656,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>
@@ -2076,35 +2704,144 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
   for (int i = 0; i <= 30; ++i) {
     uint64_t value = _addressSpace.get64(sigctx + kOffsetGprs +
                                          static_cast<pint_t>(i * 8));
-    _registers.setRegister(UNW_ARM64_X0 + i, value);
+    _registers.setRegister(UNW_AARCH64_X0 + i, value);
   }
   _registers.setSP(_addressSpace.get64(sigctx + kOffsetSp));
   _registers.setIP(_addressSpace.get64(sigctx + kOffsetPc));
   _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>::step() {
+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(bool stage2) {
+  (void)stage2;
   // Bottom of stack is defined is when unwind info cannot be found.
   if (_unwindInfoMissing)
     return UNW_STEP_END;
 
   // 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
 #endif
   {
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
-    result = this->stepWithCompactEncoding();
+    result = this->stepWithCompactEncoding(stage2);
 #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();
+    result = this->stepWithDwarfFDE(stage2);
 #elif defined(_LIBUNWIND_ARM_EHABI)
     result = this->stepWithEHABI();
 #else
@@ -2140,6 +2877,12 @@ bool UnwindCursor<A, R>::getFunctionName(char *buf, size_t bufLen,
                                          buf, bufLen, offset);
 }
 
+#if defined(_LIBUNWIND_USE_CET)
+extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) {
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->get_registers();
+}
+#endif
 } // namespace libunwind
 
 #endif // __UNWINDCURSOR_HPP__
index 3d4ceed..951189e 100644 (file)
@@ -1,4 +1,4 @@
-//===-------------------- UnwindRegistersRestore.S ------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -8,7 +8,17 @@
 
 #include "assembly.h"
 
+#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+#define FROM_16_TO_31 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+
+#define FROM_0_TO_31 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+#define FROM_32_TO_63 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
+
+#if defined(_AIX)
+  .toc
+#else
   .text
+#endif
 
 #if !defined(__USING_SJLJ_EXCEPTIONS__)
 
@@ -25,6 +35,8 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
 #  + return address        +
 #  +-----------------------+   <-- SP
 #  +                       +
+
+  _LIBUNWIND_CET_ENDBR
   movl   4(%esp), %eax
   # set up eax and ret on new stack location
   movl  28(%eax), %edx # edx holds new stack pointer
@@ -46,7 +58,8 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_jumpto)
   # skip ss
   # skip eflags
   pop    %eax  # eax was already pushed on new stack
-  ret        # eip was already pushed on new stack
+  pop    %ecx
+  jmp    *%ecx
   # skip cs
   # skip ds
   # skip es
@@ -70,6 +83,7 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
 # On entry, thread_state pointer is in rdi
 #endif
 
+  _LIBUNWIND_CET_ENDBR
   movq  56(%rdi), %rax # rax holds new stack pointer
   subq  $16, %rax
   movq  %rax, 56(%rdi)
@@ -119,7 +133,8 @@ DEFINE_LIBUNWIND_FUNCTION(__libunwind_Registers_x86_64_jumpto)
 #endif
   movq  56(%rdi), %rsp  # cut back rsp to new location
   pop    %rdi      # rdi was saved here earlier
-  ret            # rip was saved here
+  pop    %rcx
+  jmpq   *%rcx
 
 
 #elif defined(__powerpc64__)
@@ -179,9 +194,20 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_ppc646jumptoEv)
   addi  4, 3, PPC64_OFFS_FP
 
 // load VS register
+#ifdef __LITTLE_ENDIAN__
+// For little-endian targets, we need a swap since lxvd2x will load the register
+// in the incorrect doubleword order.
+// FIXME: when supporting targets older than Power9 on LE is no longer required,
+//        this can be changed to simply `lxv n, (16 * n)(4)`.
 #define PPC64_LVS(n)         \
   lxvd2x  n, 0, 4           ;\
+  xxswapd n, n              ;\
   addi    4, 4, 16
+#else
+#define PPC64_LVS(n)         \
+  lxvd2x  n, 0, 4           ;\
+  addi    4, 4, 16
+#endif
 
   // restore the first 32 VS regs (and also all floating point regs)
   PPC64_LVS(0)
@@ -217,27 +243,43 @@ 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
+#ifdef __LITTLE_ENDIAN__
+#define PPC64_CLVS_RESTORE(n)                    \
+  addi   4, 3, PPC64_OFFS_FP + n * 16           ;\
+  lxvd2x n, 0, 4                                ;\
+  xxswapd n, n
+#else
+#define PPC64_CLVS_RESTORE(n)                    \
+  addi   4, 3, PPC64_OFFS_FP + n * 16           ;\
+  lxvd2x n, 0, 4
+#endif
 
+#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_CLVSh(n)                           \
+  andi.  0, 5, (1 PPC_LEFT_SHIFT(63-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)
+#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)
@@ -313,32 +355,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)
 
-#define PPC64_CLV_UNALIGNEDh(n)                \
-  andi.  0, 5, (1 PPC_LEFT_SHIFT(31-n))       ;\
-PPC64_CLV_UNALIGNED_BOTTOM(n)
+#endif // !defined(_AIX)
+
+  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)
@@ -382,14 +436,26 @@ 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(__ppc__)
+#elif defined(__powerpc__)
 
 DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
 //
@@ -399,7 +465,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_ppc6jumptoEv)
 //  thread_state pointer is in r3
 //
 
-  // restore integral registerrs
+  // restore integral registers
   // skip r0 for now
   // skip r1 for now
   lwz     2,  16(3)
@@ -470,45 +536,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)
@@ -655,7 +724,13 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind13Registers_arm20restoreCoreAndJumpToEv)
   ldr sp, [lr, #52]
   ldr lr, [lr, #60]  @ restore pc into lr
 #endif
+#if defined(__ARM_FEATURE_BTI_DEFAULT) && !defined(__ARM_ARCH_ISA_ARM)
+  // 'bx' is not BTI setting when used with lr, therefore r12 is used instead
+  mov r12, lr
+  JMP(r12)
+#else
   JMP(lr)
+#endif
 
 @
 @ static void libunwind::Registers_arm::restoreVFPWithFLDMD(unw_fpreg_t* values)
@@ -800,11 +875,12 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind14Registers_or1k6jumptoEv)
   l.lwz    r30,120(r3)
   l.lwz    r31,124(r3)
 
+  # load new pc into ra
+  l.lwz    r9, 128(r3)
+
   # at last, restore r3
   l.lwz    r3,  12(r3)
 
-  # load new pc into ra
-  l.lwz    r9, 128(r3)
   # jump to pc
   l.jr     r9
    l.nop
@@ -974,38 +1050,9 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
   .set noreorder
   .set nomacro
 #ifdef __mips_hard_float
-  ldc1  $f0, (8 * 35)($4)
-  ldc1  $f1, (8 * 36)($4)
-  ldc1  $f2, (8 * 37)($4)
-  ldc1  $f3, (8 * 38)($4)
-  ldc1  $f4, (8 * 39)($4)
-  ldc1  $f5, (8 * 40)($4)
-  ldc1  $f6, (8 * 41)($4)
-  ldc1  $f7, (8 * 42)($4)
-  ldc1  $f8, (8 * 43)($4)
-  ldc1  $f9, (8 * 44)($4)
-  ldc1  $f10, (8 * 45)($4)
-  ldc1  $f11, (8 * 46)($4)
-  ldc1  $f12, (8 * 47)($4)
-  ldc1  $f13, (8 * 48)($4)
-  ldc1  $f14, (8 * 49)($4)
-  ldc1  $f15, (8 * 50)($4)
-  ldc1  $f16, (8 * 51)($4)
-  ldc1  $f17, (8 * 52)($4)
-  ldc1  $f18, (8 * 53)($4)
-  ldc1  $f19, (8 * 54)($4)
-  ldc1  $f20, (8 * 55)($4)
-  ldc1  $f21, (8 * 56)($4)
-  ldc1  $f22, (8 * 57)($4)
-  ldc1  $f23, (8 * 58)($4)
-  ldc1  $f24, (8 * 59)($4)
-  ldc1  $f25, (8 * 60)($4)
-  ldc1  $f26, (8 * 61)($4)
-  ldc1  $f27, (8 * 62)($4)
-  ldc1  $f28, (8 * 63)($4)
-  ldc1  $f29, (8 * 64)($4)
-  ldc1  $f30, (8 * 65)($4)
-  ldc1  $f31, (8 * 66)($4)
+  .irp i,FROM_0_TO_31
+    ldc1 $f\i, (280+8*\i)($4)
+  .endr
 #endif
   // restore hi and lo
   ld    $8, (8 * 33)($4)
@@ -1017,32 +1064,9 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
   ld    $2, (8 * 2)($4)
   ld    $3, (8 * 3)($4)
   // skip a0 for now
-  ld    $5, (8 * 5)($4)
-  ld    $6, (8 * 6)($4)
-  ld    $7, (8 * 7)($4)
-  ld    $8, (8 * 8)($4)
-  ld    $9, (8 * 9)($4)
-  ld    $10, (8 * 10)($4)
-  ld    $11, (8 * 11)($4)
-  ld    $12, (8 * 12)($4)
-  ld    $13, (8 * 13)($4)
-  ld    $14, (8 * 14)($4)
-  ld    $15, (8 * 15)($4)
-  ld    $16, (8 * 16)($4)
-  ld    $17, (8 * 17)($4)
-  ld    $18, (8 * 18)($4)
-  ld    $19, (8 * 19)($4)
-  ld    $20, (8 * 20)($4)
-  ld    $21, (8 * 21)($4)
-  ld    $22, (8 * 22)($4)
-  ld    $23, (8 * 23)($4)
-  ld    $24, (8 * 24)($4)
-  ld    $25, (8 * 25)($4)
-  ld    $26, (8 * 26)($4)
-  ld    $27, (8 * 27)($4)
-  ld    $28, (8 * 28)($4)
-  ld    $29, (8 * 29)($4)
-  ld    $30, (8 * 30)($4)
+  .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30
+    ld $\i, (8 * \i)($4)
+  .endr
   // load new pc into ra
   ld    $31, (8 * 32)($4)
   // jump to ra, load a0 in the delay slot
@@ -1053,12 +1077,16 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind21Registers_mips_newabi6jumptoEv)
 #elif defined(__sparc__) && defined(__arch64__)
 
 DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv)
-#
-# void libunwind::Registers_sparc64::jumpto()
-#
-# On entry:
-#  thread_state pointer is in %o0
-#
+//
+// void libunwind::Registers_sparc64::jumpto()
+//
+// On entry:
+//  thread_state pointer is in %o0
+//
+  .register %g2, #scratch
+  .register %g3, #scratch
+  .register %g6, #scratch
+  .register %g7, #scratch
   flushw
   ldx  [%o0 + 0x08], %g1
   ldx  [%o0 + 0x10], %g2
@@ -1090,7 +1118,7 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind17Registers_sparc646jumptoEv)
   ldx  [%o0 + 0xe8], %i5
   ldx  [%o0 + 0xf0], %i6
   ldx  [%o0 + 0xf8], %i7
-  jmpl %o7 + 8, %g0
+  jmp  %o7
    ldx [%o0 + 0x40], %o0
 
 #elif defined(__sparc__)
@@ -1126,76 +1154,78 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_sparc6jumptoEv)
   .p2align 2
 DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_riscv6jumptoEv)
 # if defined(__riscv_flen)
-  FLOAD    f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0)
-  FLOAD    f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0)
-  FLOAD    f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0)
-  FLOAD    f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0)
-  FLOAD    f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0)
-  FLOAD    f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0)
-  FLOAD    f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0)
-  FLOAD    f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0)
-  FLOAD    f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0)
-  FLOAD    f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0)
-  FLOAD    f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0)
-  FLOAD    f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0)
-  FLOAD    f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0)
-  FLOAD    f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0)
-  FLOAD    f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0)
-  FLOAD    f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0)
-  FLOAD    f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0)
-  FLOAD    f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0)
-  FLOAD    f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0)
-  FLOAD    f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0)
-  FLOAD    f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0)
-  FLOAD    f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0)
-  FLOAD    f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0)
-  FLOAD    f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0)
-  FLOAD    f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0)
-  FLOAD    f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0)
-  FLOAD    f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0)
-  FLOAD    f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0)
-  FLOAD    f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0)
-  FLOAD    f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0)
-  FLOAD    f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0)
-  FLOAD    f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0)
+  .irp i,FROM_0_TO_31
+    FLOAD f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
+  .endr
 # endif
 
   // x0 is zero
   ILOAD    x1, (RISCV_ISIZE * 0)(a0) // restore pc into ra
-  ILOAD    x2, (RISCV_ISIZE * 2)(a0)
-  ILOAD    x3, (RISCV_ISIZE * 3)(a0)
-  ILOAD    x4, (RISCV_ISIZE * 4)(a0)
-  ILOAD    x5, (RISCV_ISIZE * 5)(a0)
-  ILOAD    x6, (RISCV_ISIZE * 6)(a0)
-  ILOAD    x7, (RISCV_ISIZE * 7)(a0)
-  ILOAD    x8, (RISCV_ISIZE * 8)(a0)
-  ILOAD    x9, (RISCV_ISIZE * 9)(a0)
+  .irp i,2,3,4,5,6,7,8,9
+    ILOAD x\i, (RISCV_ISIZE * \i)(a0)
+  .endr
   // skip a0 for now
-  ILOAD    x11, (RISCV_ISIZE * 11)(a0)
-  ILOAD    x12, (RISCV_ISIZE * 12)(a0)
-  ILOAD    x13, (RISCV_ISIZE * 13)(a0)
-  ILOAD    x14, (RISCV_ISIZE * 14)(a0)
-  ILOAD    x15, (RISCV_ISIZE * 15)(a0)
-  ILOAD    x16, (RISCV_ISIZE * 16)(a0)
-  ILOAD    x17, (RISCV_ISIZE * 17)(a0)
-  ILOAD    x18, (RISCV_ISIZE * 18)(a0)
-  ILOAD    x19, (RISCV_ISIZE * 19)(a0)
-  ILOAD    x20, (RISCV_ISIZE * 20)(a0)
-  ILOAD    x21, (RISCV_ISIZE * 21)(a0)
-  ILOAD    x22, (RISCV_ISIZE * 22)(a0)
-  ILOAD    x23, (RISCV_ISIZE * 23)(a0)
-  ILOAD    x24, (RISCV_ISIZE * 24)(a0)
-  ILOAD    x25, (RISCV_ISIZE * 25)(a0)
-  ILOAD    x26, (RISCV_ISIZE * 26)(a0)
-  ILOAD    x27, (RISCV_ISIZE * 27)(a0)
-  ILOAD    x28, (RISCV_ISIZE * 28)(a0)
-  ILOAD    x29, (RISCV_ISIZE * 29)(a0)
-  ILOAD    x30, (RISCV_ISIZE * 30)(a0)
-  ILOAD    x31, (RISCV_ISIZE * 31)(a0)
+  .irp i,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+    ILOAD x\i, (RISCV_ISIZE * \i)(a0)
+  .endr
   ILOAD    x10, (RISCV_ISIZE * 10)(a0)   // restore a0
 
   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
+  .irp i,FROM_0_TO_15
+    ld %f\i, (144+8*\i)(%r2)
+  .endr
+
+  // Restore GPRs - skipping %r0 and %r1
+  lmg  %r2, %r15, 32(%r2)
+
+  // Return to PSWA (was loaded into %r1 above)
+  br %r1
+
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+//
+// void libunwind::Registers_loongarch::jumpto()
+//
+// On entry:
+//  thread_state pointer is in $a0($r4)
+//
+  .p2align 2
+DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind19Registers_loongarch6jumptoEv)
+# if __loongarch_frlen == 64
+  .irp i,FROM_0_TO_31
+    fld.d $f\i, $a0, (8 * 33 + 8 * \i)
+  .endr
+# endif
+
+  // $r0 is zero
+  .irp i,1,2,3
+    ld.d $r\i, $a0, (8 * \i)
+  .endr
+  // skip $a0 for now
+  .irp i,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+    ld.d $r\i, $a0, (8 * \i)
+  .endr
+
+  ld.d    $ra,  $a0, (8 * 32)  // load new pc into $ra
+  ld.d    $a0,  $a0, (8 * 4)   // restore $a0 last
+
+  jr      $ra
+
 #endif
 
 #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
index fdbceea..79f5696 100644 (file)
@@ -1,4 +1,4 @@
-//===------------------------ UnwindRegistersSave.S -----------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -8,7 +8,17 @@
 
 #include "assembly.h"
 
+#define FROM_0_TO_15 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
+#define FROM_16_TO_31 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+
+#define FROM_0_TO_31 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+#define FROM_32_TO_63 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63
+
+#if defined(_AIX)
+    .toc
+#else
     .text
+#endif
 
 #if !defined(__USING_SJLJ_EXCEPTIONS__)
 
@@ -27,6 +37,8 @@
 #   +                       +
 #
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+
+  _LIBUNWIND_CET_ENDBR
   push  %eax
   movl  8(%esp), %eax
   movl  %ebx,  4(%eax)
@@ -70,6 +82,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 #define TMP %rsi
 #endif
 
+  _LIBUNWIND_CET_ENDBR
   movq  %rax,   (PTR)
   movq  %rbx,  8(PTR)
   movq  %rcx, 16(PTR)
@@ -237,37 +250,9 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   .set noat
   .set noreorder
   .set nomacro
-  sd    $1, (8 * 1)($4)
-  sd    $2, (8 * 2)($4)
-  sd    $3, (8 * 3)($4)
-  sd    $4, (8 * 4)($4)
-  sd    $5, (8 * 5)($4)
-  sd    $6, (8 * 6)($4)
-  sd    $7, (8 * 7)($4)
-  sd    $8, (8 * 8)($4)
-  sd    $9, (8 * 9)($4)
-  sd    $10, (8 * 10)($4)
-  sd    $11, (8 * 11)($4)
-  sd    $12, (8 * 12)($4)
-  sd    $13, (8 * 13)($4)
-  sd    $14, (8 * 14)($4)
-  sd    $15, (8 * 15)($4)
-  sd    $16, (8 * 16)($4)
-  sd    $17, (8 * 17)($4)
-  sd    $18, (8 * 18)($4)
-  sd    $19, (8 * 19)($4)
-  sd    $20, (8 * 20)($4)
-  sd    $21, (8 * 21)($4)
-  sd    $22, (8 * 22)($4)
-  sd    $23, (8 * 23)($4)
-  sd    $24, (8 * 24)($4)
-  sd    $25, (8 * 25)($4)
-  sd    $26, (8 * 26)($4)
-  sd    $27, (8 * 27)($4)
-  sd    $28, (8 * 28)($4)
-  sd    $29, (8 * 29)($4)
-  sd    $30, (8 * 30)($4)
-  sd    $31, (8 * 31)($4)
+  .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+    sd $\i, (8 * \i)($4)
+  .endr
   # Store return address to pc
   sd    $31, (8 * 32)($4)
   # hi and lo
@@ -276,38 +261,9 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   mflo  $8
   sd    $8,  (8 * 34)($4)
 #ifdef __mips_hard_float
-  sdc1  $f0, (8 * 35)($4)
-  sdc1  $f1, (8 * 36)($4)
-  sdc1  $f2, (8 * 37)($4)
-  sdc1  $f3, (8 * 38)($4)
-  sdc1  $f4, (8 * 39)($4)
-  sdc1  $f5, (8 * 40)($4)
-  sdc1  $f6, (8 * 41)($4)
-  sdc1  $f7, (8 * 42)($4)
-  sdc1  $f8, (8 * 43)($4)
-  sdc1  $f9, (8 * 44)($4)
-  sdc1  $f10, (8 * 45)($4)
-  sdc1  $f11, (8 * 46)($4)
-  sdc1  $f12, (8 * 47)($4)
-  sdc1  $f13, (8 * 48)($4)
-  sdc1  $f14, (8 * 49)($4)
-  sdc1  $f15, (8 * 50)($4)
-  sdc1  $f16, (8 * 51)($4)
-  sdc1  $f17, (8 * 52)($4)
-  sdc1  $f18, (8 * 53)($4)
-  sdc1  $f19, (8 * 54)($4)
-  sdc1  $f20, (8 * 55)($4)
-  sdc1  $f21, (8 * 56)($4)
-  sdc1  $f22, (8 * 57)($4)
-  sdc1  $f23, (8 * 58)($4)
-  sdc1  $f24, (8 * 59)($4)
-  sdc1  $f25, (8 * 60)($4)
-  sdc1  $f26, (8 * 61)($4)
-  sdc1  $f27, (8 * 62)($4)
-  sdc1  $f28, (8 * 63)($4)
-  sdc1  $f29, (8 * 64)($4)
-  sdc1  $f30, (8 * 65)($4)
-  sdc1  $f31, (8 * 66)($4)
+  .irp i,FROM_0_TO_31
+    sdc1 $f\i, (280+8*\i)($4)
+  .endr
 #endif
   jr   $31
   # return UNW_ESUCCESS
@@ -331,8 +287,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)
@@ -392,9 +351,20 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   addi  4, 3, PPC64_OFFS_FP
 
 // store VS register
+#ifdef __LITTLE_ENDIAN__
+// For little-endian targets, we need a swap since stxvd2x will store the
+// register in the incorrect doubleword order.
+// FIXME: when supporting targets older than Power9 on LE is no longer required
+//        this can be changed to simply `stxv n, 16 * n(4)`.
+#define PPC64_STVS(n)      \
+  xxswapd n, n            ;\
+  stxvd2x n, 0, 4         ;\
+  addi    4, 4, 16
+#else
 #define PPC64_STVS(n)      \
   stxvd2x n, 0, 4         ;\
   addi    4, 4, 16
+#endif
 
   PPC64_STVS(0)
   PPC64_STVS(1)
@@ -556,7 +526,7 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   blr
 
 
-#elif defined(__ppc__)
+#elif defined(__powerpc__)
 
 //
 // extern int unw_getcontext(unw_context_t* thread_state)
@@ -564,7 +534,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
@@ -953,7 +927,6 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   l.sw     132(r3), r0
 
 #elif defined(__hexagon__)
-
 #
 # extern int unw_getcontext(unw_context_t* thread_state)
 #
@@ -1002,12 +975,16 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 #elif defined(__sparc__) && defined(__arch64__)
 
 #
-# extern int unw_getcontext(unw_context_t* thread_state)
+# extern int __unw_getcontext(unw_context_t* thread_state)
 #
 # On entry:
 #  thread_state pointer is in %o0
 #
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  .register %g2, #scratch
+  .register %g3, #scratch
+  .register %g6, #scratch
+  .register %g7, #scratch
   stx  %g1, [%o0 + 0x08]
   stx  %g2, [%o0 + 0x10]
   stx  %g3, [%o0 + 0x18]
@@ -1041,15 +1018,17 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   stx  %i7, [%o0 + 0xf8]
 
   # save StackGhost cookie
-  add  %i7, %g0, %g4
+  mov  %i7, %g4
   save %sp, -176, %sp
   # register window flush necessary even without StackGhost
   flushw
   restore
   ldx  [%sp + 2047 + 0x78], %g5
   xor  %g4, %g5, %g4
+  stx  %g4, [%o0 + 0x100]
   retl
-   stx %g4, [%o0 + 0x100]
+  # return UNW_ESUCCESS
+   clr %o0
 
 #elif defined(__sparc__)
 
@@ -1091,75 +1070,71 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
 #
 DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   ISTORE    x1, (RISCV_ISIZE * 0)(a0) // store ra as pc
-  ISTORE    x1, (RISCV_ISIZE * 1)(a0)
-  ISTORE    x2, (RISCV_ISIZE * 2)(a0)
-  ISTORE    x3, (RISCV_ISIZE * 3)(a0)
-  ISTORE    x4, (RISCV_ISIZE * 4)(a0)
-  ISTORE    x5, (RISCV_ISIZE * 5)(a0)
-  ISTORE    x6, (RISCV_ISIZE * 6)(a0)
-  ISTORE    x7, (RISCV_ISIZE * 7)(a0)
-  ISTORE    x8, (RISCV_ISIZE * 8)(a0)
-  ISTORE    x9, (RISCV_ISIZE * 9)(a0)
-  ISTORE    x10, (RISCV_ISIZE * 10)(a0)
-  ISTORE    x11, (RISCV_ISIZE * 11)(a0)
-  ISTORE    x12, (RISCV_ISIZE * 12)(a0)
-  ISTORE    x13, (RISCV_ISIZE * 13)(a0)
-  ISTORE    x14, (RISCV_ISIZE * 14)(a0)
-  ISTORE    x15, (RISCV_ISIZE * 15)(a0)
-  ISTORE    x16, (RISCV_ISIZE * 16)(a0)
-  ISTORE    x17, (RISCV_ISIZE * 17)(a0)
-  ISTORE    x18, (RISCV_ISIZE * 18)(a0)
-  ISTORE    x19, (RISCV_ISIZE * 19)(a0)
-  ISTORE    x20, (RISCV_ISIZE * 20)(a0)
-  ISTORE    x21, (RISCV_ISIZE * 21)(a0)
-  ISTORE    x22, (RISCV_ISIZE * 22)(a0)
-  ISTORE    x23, (RISCV_ISIZE * 23)(a0)
-  ISTORE    x24, (RISCV_ISIZE * 24)(a0)
-  ISTORE    x25, (RISCV_ISIZE * 25)(a0)
-  ISTORE    x26, (RISCV_ISIZE * 26)(a0)
-  ISTORE    x27, (RISCV_ISIZE * 27)(a0)
-  ISTORE    x28, (RISCV_ISIZE * 28)(a0)
-  ISTORE    x29, (RISCV_ISIZE * 29)(a0)
-  ISTORE    x30, (RISCV_ISIZE * 30)(a0)
-  ISTORE    x31, (RISCV_ISIZE * 31)(a0)
+  .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+    ISTORE x\i, (RISCV_ISIZE * \i)(a0)
+  .endr
 
 # if defined(__riscv_flen)
-  FSTORE    f0, (RISCV_FOFFSET + RISCV_FSIZE * 0)(a0)
-  FSTORE    f1, (RISCV_FOFFSET + RISCV_FSIZE * 1)(a0)
-  FSTORE    f2, (RISCV_FOFFSET + RISCV_FSIZE * 2)(a0)
-  FSTORE    f3, (RISCV_FOFFSET + RISCV_FSIZE * 3)(a0)
-  FSTORE    f4, (RISCV_FOFFSET + RISCV_FSIZE * 4)(a0)
-  FSTORE    f5, (RISCV_FOFFSET + RISCV_FSIZE * 5)(a0)
-  FSTORE    f6, (RISCV_FOFFSET + RISCV_FSIZE * 6)(a0)
-  FSTORE    f7, (RISCV_FOFFSET + RISCV_FSIZE * 7)(a0)
-  FSTORE    f8, (RISCV_FOFFSET + RISCV_FSIZE * 8)(a0)
-  FSTORE    f9, (RISCV_FOFFSET + RISCV_FSIZE * 9)(a0)
-  FSTORE    f10, (RISCV_FOFFSET + RISCV_FSIZE * 10)(a0)
-  FSTORE    f11, (RISCV_FOFFSET + RISCV_FSIZE * 11)(a0)
-  FSTORE    f12, (RISCV_FOFFSET + RISCV_FSIZE * 12)(a0)
-  FSTORE    f13, (RISCV_FOFFSET + RISCV_FSIZE * 13)(a0)
-  FSTORE    f14, (RISCV_FOFFSET + RISCV_FSIZE * 14)(a0)
-  FSTORE    f15, (RISCV_FOFFSET + RISCV_FSIZE * 15)(a0)
-  FSTORE    f16, (RISCV_FOFFSET + RISCV_FSIZE * 16)(a0)
-  FSTORE    f17, (RISCV_FOFFSET + RISCV_FSIZE * 17)(a0)
-  FSTORE    f18, (RISCV_FOFFSET + RISCV_FSIZE * 18)(a0)
-  FSTORE    f19, (RISCV_FOFFSET + RISCV_FSIZE * 19)(a0)
-  FSTORE    f20, (RISCV_FOFFSET + RISCV_FSIZE * 20)(a0)
-  FSTORE    f21, (RISCV_FOFFSET + RISCV_FSIZE * 21)(a0)
-  FSTORE    f22, (RISCV_FOFFSET + RISCV_FSIZE * 22)(a0)
-  FSTORE    f23, (RISCV_FOFFSET + RISCV_FSIZE * 23)(a0)
-  FSTORE    f24, (RISCV_FOFFSET + RISCV_FSIZE * 24)(a0)
-  FSTORE    f25, (RISCV_FOFFSET + RISCV_FSIZE * 25)(a0)
-  FSTORE    f26, (RISCV_FOFFSET + RISCV_FSIZE * 26)(a0)
-  FSTORE    f27, (RISCV_FOFFSET + RISCV_FSIZE * 27)(a0)
-  FSTORE    f28, (RISCV_FOFFSET + RISCV_FSIZE * 28)(a0)
-  FSTORE    f29, (RISCV_FOFFSET + RISCV_FSIZE * 29)(a0)
-  FSTORE    f30, (RISCV_FOFFSET + RISCV_FSIZE * 30)(a0)
-  FSTORE    f31, (RISCV_FOFFSET + RISCV_FSIZE * 31)(a0)
+  .irp i,FROM_0_TO_31
+    FSTORE f\i, (RISCV_FOFFSET + RISCV_FSIZE * \i)(a0)
+  .endr
 # endif
 
   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
+  .irp i,FROM_0_TO_15
+    std %f\i, (144+8*\i)(%r2)
+  .endr
+
+  // Return UNW_ESUCCESS
+  lghi %r2, 0
+  br %r14
+
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+
+#
+# extern int __unw_getcontext(unw_context_t* thread_state)
+#
+# On entry:
+#  thread_state pointer is in $a0($r4)
+#
+DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
+  .irp i,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
+    st.d $r\i, $a0, (8*\i)
+  .endr
+  st.d    $r1,  $a0, (8 * 32) // store $ra to pc
+
+# if __loongarch_frlen == 64
+  .irp i,FROM_0_TO_31
+    fst.d $f\i, $a0, (8 * 33 + 8 * \i)
+  .endr
+# endif
+
+  move     $a0, $zero  // UNW_ESUCCESS
+  jr       $ra
+
 #endif
 
   WEAK_ALIAS(__unw_getcontext, unw_getcontext)
index 76ef825..fb07d04 100644 (file)
 #ifndef UNWIND_ASSEMBLY_H
 #define UNWIND_ASSEMBLY_H
 
+#if defined(__linux__) && defined(__CET__)
+#include <cet.h>
+#define _LIBUNWIND_CET_ENDBR _CET_ENDBR
+#else
+#define _LIBUNWIND_CET_ENDBR
+#endif
+
 #if defined(__powerpc64__)
 #define SEPARATOR ;
 #define PPC64_OFFS_SRR0   0
@@ -60,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 \
@@ -74,7 +82,7 @@
 #define PPC64_OPD2
 #endif
 
-#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#if defined(__aarch64__) && defined(__ARM_FEATURE_BTI_DEFAULT)
   .pushsection ".note.gnu.property", "a" SEPARATOR                             \
   .balign 8 SEPARATOR                                                          \
   .long 4 SEPARATOR                                                            \
 #define AARCH64_BTI
 #endif
 
+#if !defined(__aarch64__)
+#ifdef __ARM_FEATURE_PAC_DEFAULT
+  .eabi_attribute Tag_PAC_extension, 2
+  .eabi_attribute Tag_PACRET_use, 1
+#endif
+#ifdef __ARM_FEATURE_BTI_DEFAULT
+  .eabi_attribute Tag_BTI_extension, 1
+  .eabi_attribute Tag_BTI_use, 1
+#endif
+#endif
+
 #define GLUE2(a, b) a ## b
 #define GLUE(a, b) GLUE2(a, b)
 #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
 
 #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                                   \
   SYMBOL_NAME(name):                                                           \
   PPC64_OPD2                                                                   \
   AARCH64_BTI
+#endif
 
 #if defined(__arm__)
 #if !defined(__ARM_ARCH)
 #endif
 #endif /* __arm__ */
 
-#if defined(__ppc__) || defined(__powerpc64__)
+#if defined(__powerpc__)
 #define PPC_LEFT_SHIFT(index) << (index)
 #endif
 
index 1c8e7db..4bbac95 100644 (file)
@@ -1,4 +1,4 @@
-//===----------------------------- config.h -------------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -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)));
 #define _LIBUNWIND_BUILD_SJLJ_APIS
 #endif
 
-#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__)
 #define _LIBUNWIND_SUPPORT_FRAME_APIS
 #endif
 
-#if defined(__i386__) || defined(__x86_64__) ||                                \
-    defined(__ppc__) || defined(__ppc64__) || defined(__powerpc64__) ||        \
-    (!defined(__APPLE__) && defined(__arm__)) ||                               \
-    defined(__aarch64__) ||                                                    \
-    defined(__mips__) ||                                                       \
-    defined(__riscv) ||                                                        \
-    defined(__sparc64__) ||                                                    \
-    defined(__hexagon__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) ||        \
+    (!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) ||       \
+    defined(__mips__) || defined(__riscv) || defined(__hexagon__) ||           \
+    defined(__sparc__) || defined(__s390x__) || defined(__loongarch__)
 #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
 #define _LIBUNWIND_BUILD_ZERO_COST_APIS
 #endif
   #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
index 005c042..0faea2b 100644 (file)
@@ -1,4 +1,4 @@
-//===--------------------------- libunwind.cpp ----------------------------===//
+//===----------------------------------------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -11,8 +11,8 @@
 
 #include <libunwind.h>
 
-#include "libunwind_ext.h"
 #include "config.h"
+#include "libunwind_ext.h"
 
 #include <stdlib.h>
 
@@ -51,7 +51,7 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
 # define REGISTER_KIND Registers_x86_64
 #elif defined(__powerpc64__)
 # define REGISTER_KIND Registers_ppc64
-#elif defined(__ppc__)
+#elif defined(__powerpc__)
 # define REGISTER_KIND Registers_ppc
 #elif defined(__aarch64__)
 # define REGISTER_KIND Registers_arm64
@@ -68,13 +68,17 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
 #elif defined(__mips__)
 # warning The MIPS architecture is not supported with this ABI and environment!
 #elif defined(__sparc__) && defined(__arch64__)
-# define REGISTER_KIND Registers_sparc64
+#define REGISTER_KIND Registers_sparc64
 #elif defined(__sparc__)
 # define REGISTER_KIND Registers_sparc
 #elif defined(__riscv)
 # define REGISTER_KIND Registers_riscv
 #elif defined(__ve__)
 # define REGISTER_KIND Registers_ve
+#elif defined(__s390x__)
+# define REGISTER_KIND Registers_s390x
+#elif defined(__loongarch__) && __loongarch_grlen == 64
+#define REGISTER_KIND Registers_loongarch
 #else
 # error Architecture not supported
 #endif
@@ -115,7 +119,7 @@ _LIBUNWIND_HIDDEN int __unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
   AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
   if (co->validReg(regNum)) {
     co->setReg(regNum, (pint_t)value);
-    // specical case altering IP to re-find info (being called by personality
+    // special case altering IP to re-find info (being called by personality
     // function)
     if (regNum == UNW_REG_IP) {
       unw_proc_info_t info;
@@ -179,6 +183,15 @@ _LIBUNWIND_HIDDEN int __unw_step(unw_cursor_t *cursor) {
 }
 _LIBUNWIND_WEAK_ALIAS(__unw_step, unw_step)
 
+// Move cursor to next frame and for stage2 of unwinding.
+// This resets MTE tags of tagged frames to zero.
+extern "C" _LIBUNWIND_HIDDEN int __unw_step_stage2(unw_cursor_t *cursor) {
+  _LIBUNWIND_TRACE_API("__unw_step_stage2(cursor=%p)",
+                       static_cast<void *>(cursor));
+  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
+  return co->step(true);
+}
+
 /// Get unwind info at cursor position in stack frame.
 _LIBUNWIND_HIDDEN int __unw_get_proc_info(unw_cursor_t *cursor,
                                           unw_proc_info_t *info) {
@@ -247,6 +260,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) {
@@ -294,6 +317,35 @@ void __unw_remove_dynamic_fde(unw_word_t fde) {
   // fde is own mh_group
   DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
 }
+
+void __unw_add_dynamic_eh_frame_section(unw_word_t eh_frame_start) {
+  // The eh_frame section start serves as the mh_group
+  unw_word_t mh_group = eh_frame_start;
+  CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
+  CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
+  auto p = (LocalAddressSpace::pint_t)eh_frame_start;
+  while (true) {
+    if (CFI_Parser<LocalAddressSpace>::decodeFDE(
+            LocalAddressSpace::sThisAddressSpace, p, &fdeInfo, &cieInfo,
+            true) == NULL) {
+      DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
+                                            fdeInfo.pcStart, fdeInfo.pcEnd,
+                                            fdeInfo.fdeStart);
+      p += fdeInfo.fdeLength;
+    } else if (CFI_Parser<LocalAddressSpace>::parseCIE(
+                   LocalAddressSpace::sThisAddressSpace, p, &cieInfo) == NULL) {
+      p += cieInfo.cieLength;
+    } else
+      return;
+  }
+}
+
+void __unw_remove_dynamic_eh_frame_section(unw_word_t eh_frame_start) {
+  // The eh_frame section start serves as the mh_group
+  DwarfFDECache<LocalAddressSpace>::removeAllIn(
+      (LocalAddressSpace::pint_t)eh_frame_start);
+}
+
 #endif // defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
 #endif // !defined(__USING_SJLJ_EXCEPTIONS__)