Commit 1e7083d09c

Andrew Kelley <andrew@ziglang.org>
2023-01-26 21:24:30
update libunwind to llvm 16
1 parent e41b58d
lib/libcxx/include/__config
@@ -10,8 +10,6 @@
 #ifndef _LIBCPP___CONFIG
 #define _LIBCPP___CONFIG
 
-#include <__config_site>
-
 #if defined(_MSC_VER) && !defined(__clang__)
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #    define _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER
lib/libunwind/include/mach-o/compact_unwind_encoding.h
@@ -33,7 +33,7 @@
 
 
 //
-// The compact unwind endoding is a 32-bit value which encoded in an
+// The compact unwind encoding is a 32-bit value which encoded in an
 // architecture specific way, which registers to restore from where, and how
 // to unwind out of the function.
 //
@@ -116,7 +116,7 @@ enum {
 //    on the stack immediately after the return address.  The stack_size/4 is
 //    encoded in the UNWIND_X86_FRAMELESS_STACK_SIZE (max stack size is 1024).
 //    The number of registers saved is encoded in UNWIND_X86_FRAMELESS_STACK_REG_COUNT.
-//    UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+//    UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION contains which registers were
 //    saved and their order.
 // UNWIND_X86_MODE_STACK_IND:
 //    A "frameless" (EBP not used as frame pointer) function large constant 
@@ -250,7 +250,7 @@ enum {
 //    on the stack immediately after the return address.  The stack_size/8 is
 //    encoded in the UNWIND_X86_64_FRAMELESS_STACK_SIZE (max stack size is 2048).
 //    The number of registers saved is encoded in UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT.
-//    UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION constains which registers were
+//    UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION contains which registers were
 //    saved and their order.  
 // UNWIND_X86_64_MODE_STACK_IND:
 //    A "frameless" (RBP not used as frame pointer) function large constant 
lib/libunwind/include/__libunwind_config.h
@@ -30,6 +30,7 @@
 #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__)
@@ -166,6 +167,16 @@
 #  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
@@ -185,6 +196,7 @@
 # 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
lib/libunwind/include/libunwind.h
@@ -1023,6 +1023,16 @@ enum {
   UNW_RISCV_F29 = 61,
   UNW_RISCV_F30 = 62,
   UNW_RISCV_F31 = 63,
+  // 65-95 -- Reserved for future standard extensions
+  // 96-127 -- v0-v31 (Vector registers)
+  // 128-3071 -- Reserved for future standard extensions
+  // 3072-4095 -- Reserved for custom extensions
+  // 4096-8191 -- CSRs
+  //
+  // VLENB CSR number: 0xC22 -- defined by section 3 of v-spec:
+  // https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#3-vector-extension-programmers-model
+  // VLENB DWARF number: 0x1000 + 0xC22
+  UNW_RISCV_VLENB = 0x1C22,
 };
 
 // VE register numbers
@@ -1219,4 +1229,72 @@ enum {
   // 68-83 Vector Registers %v16-%v31
 };
 
+// LoongArch registers.
+enum {
+  UNW_LOONGARCH_R0 = 0,
+  UNW_LOONGARCH_R1 = 1,
+  UNW_LOONGARCH_R2 = 2,
+  UNW_LOONGARCH_R3 = 3,
+  UNW_LOONGARCH_R4 = 4,
+  UNW_LOONGARCH_R5 = 5,
+  UNW_LOONGARCH_R6 = 6,
+  UNW_LOONGARCH_R7 = 7,
+  UNW_LOONGARCH_R8 = 8,
+  UNW_LOONGARCH_R9 = 9,
+  UNW_LOONGARCH_R10 = 10,
+  UNW_LOONGARCH_R11 = 11,
+  UNW_LOONGARCH_R12 = 12,
+  UNW_LOONGARCH_R13 = 13,
+  UNW_LOONGARCH_R14 = 14,
+  UNW_LOONGARCH_R15 = 15,
+  UNW_LOONGARCH_R16 = 16,
+  UNW_LOONGARCH_R17 = 17,
+  UNW_LOONGARCH_R18 = 18,
+  UNW_LOONGARCH_R19 = 19,
+  UNW_LOONGARCH_R20 = 20,
+  UNW_LOONGARCH_R21 = 21,
+  UNW_LOONGARCH_R22 = 22,
+  UNW_LOONGARCH_R23 = 23,
+  UNW_LOONGARCH_R24 = 24,
+  UNW_LOONGARCH_R25 = 25,
+  UNW_LOONGARCH_R26 = 26,
+  UNW_LOONGARCH_R27 = 27,
+  UNW_LOONGARCH_R28 = 28,
+  UNW_LOONGARCH_R29 = 29,
+  UNW_LOONGARCH_R30 = 30,
+  UNW_LOONGARCH_R31 = 31,
+  UNW_LOONGARCH_F0 = 32,
+  UNW_LOONGARCH_F1 = 33,
+  UNW_LOONGARCH_F2 = 34,
+  UNW_LOONGARCH_F3 = 35,
+  UNW_LOONGARCH_F4 = 36,
+  UNW_LOONGARCH_F5 = 37,
+  UNW_LOONGARCH_F6 = 38,
+  UNW_LOONGARCH_F7 = 39,
+  UNW_LOONGARCH_F8 = 40,
+  UNW_LOONGARCH_F9 = 41,
+  UNW_LOONGARCH_F10 = 42,
+  UNW_LOONGARCH_F11 = 43,
+  UNW_LOONGARCH_F12 = 44,
+  UNW_LOONGARCH_F13 = 45,
+  UNW_LOONGARCH_F14 = 46,
+  UNW_LOONGARCH_F15 = 47,
+  UNW_LOONGARCH_F16 = 48,
+  UNW_LOONGARCH_F17 = 49,
+  UNW_LOONGARCH_F18 = 50,
+  UNW_LOONGARCH_F19 = 51,
+  UNW_LOONGARCH_F20 = 52,
+  UNW_LOONGARCH_F21 = 53,
+  UNW_LOONGARCH_F22 = 54,
+  UNW_LOONGARCH_F23 = 55,
+  UNW_LOONGARCH_F24 = 56,
+  UNW_LOONGARCH_F25 = 57,
+  UNW_LOONGARCH_F26 = 58,
+  UNW_LOONGARCH_F27 = 59,
+  UNW_LOONGARCH_F28 = 60,
+  UNW_LOONGARCH_F29 = 61,
+  UNW_LOONGARCH_F30 = 62,
+  UNW_LOONGARCH_F31 = 63,
+};
+
 #endif
lib/libunwind/include/unwind.h
@@ -93,7 +93,7 @@ extern void _Unwind_SjLj_Unregister(_Unwind_FunctionContext_t fc);
 #endif
 
 //
-// The following are semi-suppoted extensions to the C++ ABI
+// The following are semi-supported extensions to the C++ ABI
 //
 
 //
lib/libunwind/src/AddressSpace.hpp
@@ -246,7 +246,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 {
@@ -260,7 +260,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
@@ -373,28 +373,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;
@@ -468,7 +446,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
@@ -601,6 +579,56 @@ inline bool LocalAddressSpace::findUnwindSections(pint_t targetAddr,
   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);
lib/libunwind/src/CompactUnwinder.hpp
@@ -19,6 +19,7 @@
 #include <mach-o/compact_unwind_encoding.h>
 
 #include "Registers.hpp"
+#include "libunwind_ext.h"
 
 #define EXTRACT_BITS(value, mask)                                              \
   ((value >> __builtin_ctz(mask)) & (((1 << __builtin_popcount(mask))) - 1))
lib/libunwind/src/config.h
@@ -115,7 +115,7 @@
 #if defined(__i386__) || defined(__x86_64__) || defined(__powerpc__) ||        \
     (!defined(__APPLE__) && defined(__arm__)) || defined(__aarch64__) ||       \
     defined(__mips__) || defined(__riscv) || defined(__hexagon__) ||           \
-    defined(__sparc__) || defined(__s390x__)
+    defined(__sparc__) || defined(__s390x__) || defined(__loongarch__)
 #if !defined(_LIBUNWIND_BUILD_SJLJ_APIS)
 #define _LIBUNWIND_BUILD_ZERO_COST_APIS
 #endif
lib/libunwind/src/DwarfInstructions.hpp
@@ -16,16 +16,17 @@
 #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:
 
@@ -189,7 +190,7 @@ bool DwarfInstructions<A, R>::getRA_SIGN_STATE(A &addressSpace, R registers,
 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,
@@ -200,7 +201,38 @@ 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_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
@@ -241,7 +273,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);
         }
       }
@@ -331,7 +363,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.
@@ -635,7 +667,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:
lib/libunwind/src/DwarfParser.hpp
@@ -51,6 +51,7 @@ public:
     uint8_t   returnAddressRegister;
 #if defined(_LIBUNWIND_TARGET_AARCH64)
     bool      addressesSignedWithBKey;
+    bool      mteTaggedFrame;
 #endif
   };
 
@@ -325,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;
@@ -353,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);
@@ -394,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
@@ -407,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,
lib/libunwind/src/libunwind.cpp
@@ -77,6 +77,8 @@ _LIBUNWIND_HIDDEN int __unw_init_local(unw_cursor_t *cursor,
 # 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
@@ -117,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;
@@ -181,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) {
lib/libunwind/src/Registers.hpp
@@ -40,6 +40,7 @@ enum {
   REGISTERS_RISCV,
   REGISTERS_VE,
   REGISTERS_S390X,
+  REGISTERS_LOONGARCH,
 };
 
 #if defined(_LIBUNWIND_TARGET_I386)
@@ -4003,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
@@ -4084,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;
@@ -4098,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");
 }
 
@@ -4249,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";
   }
@@ -5031,6 +5041,271 @@ inline const char *Registers_s390x::getRegisterName(int regNum) {
 }
 #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
 
lib/libunwind/src/Unwind-EHABI.cpp
@@ -235,7 +235,7 @@ decode_eht_entry(const uint32_t* data, size_t* off, size_t* len) {
   } else {
     // 6.3: ARM Compact Model
     //
-    // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeded
+    // EHT entries here correspond to the __aeabi_unwind_cpp_pr[012] PRs indeed
     // by format:
     Descriptor::Format format =
         static_cast<Descriptor::Format>((*data & 0x0f000000) >> 24);
@@ -845,7 +845,7 @@ _LIBUNWIND_EXPORT void _Unwind_Complete(_Unwind_Exception* exception_object) {
 /// may force a jump to a landing pad in that function, the landing
 /// pad code may then call _Unwind_Resume() to continue with the
 /// unwinding.  Note: the call to _Unwind_Resume() is from compiler
-/// geneated user code.  All other _Unwind_* routines are called
+/// generated user code.  All other _Unwind_* routines are called
 /// by the C++ runtime __cxa_* routines.
 ///
 /// Note: re-throwing an exception (as opposed to continuing the unwind)
lib/libunwind/src/Unwind-seh.cpp
@@ -137,7 +137,7 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
     // If we were called by __libunwind_seh_personality(), indicate that
     // a handler was found; otherwise, initiate phase 2 by unwinding.
     if (ours && ms_exc->NumberParameters > 1)
-      return 4 /* ExecptionExecuteHandler in mingw */;
+      return 4 /* ExceptionExecuteHandler in mingw */;
     // This should never happen in phase 2.
     if (IS_UNWINDING(ms_exc->ExceptionFlags))
       _LIBUNWIND_ABORT("Personality indicated exception handler in phase 2!");
@@ -155,7 +155,7 @@ _GCC_specific_handler(PEXCEPTION_RECORD ms_exc, PVOID frame, PCONTEXT ms_ctx,
     // a handler was found; otherwise, it's time to initiate a collided
     // unwind to the target.
     if (ours && !IS_UNWINDING(ms_exc->ExceptionFlags) && ms_exc->NumberParameters > 1)
-      return 4 /* ExecptionExecuteHandler in mingw */;
+      return 4 /* ExceptionExecuteHandler in mingw */;
     // This should never happen in phase 1.
     if (!IS_UNWINDING(ms_exc->ExceptionFlags))
       _LIBUNWIND_ABORT("Personality installed context during phase 1!");
@@ -354,7 +354,7 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) {
 /// may force a jump to a landing pad in that function; the landing
 /// pad code may then call \c _Unwind_Resume() to continue with the
 /// unwinding.  Note: the call to \c _Unwind_Resume() is from compiler
-/// geneated user code.  All other \c _Unwind_* routines are called
+/// generated user code.  All other \c _Unwind_* routines are called
 /// by the C++ runtime \c __cxa_* routines.
 ///
 /// Note: re-throwing an exception (as opposed to continuing the unwind)
lib/libunwind/src/Unwind-sjlj.c
@@ -33,7 +33,7 @@ struct _Unwind_FunctionContext {
   struct _Unwind_FunctionContext *prev;
 
 #if defined(__ve__)
-  // VE requires to store 64 bit pointers in the buffer for SjLj execption.
+  // VE requires to store 64 bit pointers in the buffer for SjLj exception.
   // We expand the size of values defined here.  This size must be matched
   // to the size returned by TargetMachine::getSjLjDataSize().
 
@@ -357,7 +357,7 @@ _Unwind_SjLj_RaiseException(struct _Unwind_Exception *exception_object) {
 /// may force a jump to a landing pad in that function, the landing
 /// pad code may then call _Unwind_Resume() to continue with the
 /// unwinding.  Note: the call to _Unwind_Resume() is from compiler
-/// geneated user code.  All other _Unwind_* routines are called
+/// generated user code.  All other _Unwind_* routines are called
 /// by the C++ runtime __cxa_* routines.
 ///
 /// Re-throwing an exception is implemented by having the code call
@@ -394,7 +394,7 @@ _Unwind_SjLj_Resume_or_Rethrow(struct _Unwind_Exception *exception_object) {
     // std::terminate()
   }
 
-  // Call through to _Unwind_Resume() which distiguishes between forced and
+  // Call through to _Unwind_Resume() which distinguishes between forced and
   // regular exceptions.
   _Unwind_SjLj_Resume(exception_object);
   _LIBUNWIND_ABORT("__Unwind_SjLj_Resume_or_Rethrow() called "
lib/libunwind/src/Unwind_AIXExtras.cpp
@@ -38,7 +38,7 @@ char *getFuncNameFromTBTable(uintptr_t Pc, uint16_t &NameLen,
   if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
     p++;
 
-  // If the tb_offset field exisits, get the offset from the start of
+  // If the tb_offset field exists, get the offset from the start of
   // the function to pc. Skip the field.
   if (TBTable->tb.has_tboff) {
     unw_word_t StartIp =
lib/libunwind/src/UnwindCursor.hpp
@@ -38,6 +38,17 @@
 #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
 // earlier) SDKs.
@@ -75,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 {
 
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
@@ -443,7 +442,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");
   }
@@ -495,7 +494,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();
@@ -510,7 +509,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:
@@ -926,7 +925,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();
@@ -946,7 +945,7 @@ public:
 #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:
@@ -1000,22 +999,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);
   }
@@ -1066,6 +1064,10 @@ 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
@@ -1142,6 +1144,12 @@ 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
@@ -1226,6 +1234,12 @@ 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
@@ -2106,6 +2120,11 @@ bool UnwindCursor<A, R>::getInfoFromTBTable(pint_t pc, R &registers) {
           // 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",
@@ -2119,6 +2138,7 @@ bool UnwindCursor<A, R>::getInfoFromTBTable(pint_t pc, R &registers) {
             assert(0 && "dlsym() failed");
           }
           dlclose(libHandle);
+          errno = saveErrno;
         }
       }
       xlcPersonalityV0InitLock.unlock();
@@ -2455,7 +2475,7 @@ int UnwindCursor<A, R>::stepWithTBTable(pint_t pc, tbtable *TBTable,
                              reinterpret_cast<void *>(pc));
 
   // The return address is the address after call site instruction, so
-  // setting IP to that simualates a return.
+  // 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.
@@ -2791,8 +2811,8 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_s390x &) {
 #endif // defined(_LIBUNWIND_CHECK_LINUX_SIGRETURN) &&
        // defined(_LIBUNWIND_TARGET_S390X)
 
-template <typename A, typename R>
-int UnwindCursor<A, R>::step() {
+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;
@@ -2806,13 +2826,13 @@ int UnwindCursor<A, R>::step() {
 #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
lib/libunwind/src/UnwindLevel1-gcc-ext.c
@@ -22,6 +22,10 @@
 #include "Unwind-EHABI.h"
 #include "unwind.h"
 
+#if defined(_AIX)
+#include <sys/debug.h>
+#endif
+
 #if defined(_LIBUNWIND_BUILD_ZERO_COST_APIS)
 
 #if defined(_LIBUNWIND_SUPPORT_SEH_UNWIND)
@@ -48,7 +52,7 @@ _Unwind_Resume_or_Rethrow(_Unwind_Exception *exception_object) {
     // std::terminate().
   }
 
-  // Call through to _Unwind_Resume() which distiguishes between forced and
+  // Call through to _Unwind_Resume() which distinguishes between forced and
   // regular exceptions.
   _Unwind_Resume(exception_object);
   _LIBUNWIND_ABORT("_Unwind_Resume_or_Rethrow() called _Unwind_RaiseException()"
@@ -82,6 +86,32 @@ _Unwind_GetTextRelBase(struct _Unwind_Context *context) {
 /// specified code address "pc".
 _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
   _LIBUNWIND_TRACE_API("_Unwind_FindEnclosingFunction(pc=%p)", pc);
+#if defined(_AIX)
+  if (pc == NULL)
+    return NULL;
+
+  // Get the start address of the enclosing function from the function's
+  // traceback table.
+  uint32_t *p = (uint32_t *)pc;
+
+  // Keep looking forward until a word of 0 is found. The traceback
+  // table starts at the following word.
+  while (*p)
+    ++p;
+  struct tbtable *TBTable = (struct tbtable *)(p + 1);
+
+  // Get the address of the traceback table extension.
+  p = (uint32_t *)&TBTable->tb_ext;
+
+  // Skip field parminfo if it exists.
+  if (TBTable->tb.fixedparms || TBTable->tb.floatparms)
+    ++p;
+
+  if (TBTable->tb.has_tboff)
+    // *p contains the offset from the function start to traceback table.
+    return (void *)((uintptr_t)TBTable - *p - sizeof(uint32_t));
+  return NULL;
+#else
   // This is slow, but works.
   // We create an unwind cursor then alter the IP to be pc
   unw_cursor_t cursor;
@@ -94,6 +124,7 @@ _LIBUNWIND_EXPORT void *_Unwind_FindEnclosingFunction(void *pc) {
     return (void *)(intptr_t) info.start_ip;
   else
     return NULL;
+#endif
 }
 
 /// Walk every frame and call trace function at each one.  If trace function
lib/libunwind/src/UnwindLevel1.c
@@ -41,7 +41,7 @@
 // In exception handing, some stack frames will be skipped before jumping to
 // landing pad and we must adjust CET shadow stack accordingly.
 // _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we
-// directly jump to __libunwind_Registerts_x86/x86_64_jumpto instead of using
+// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using
 // a regular function call to avoid pushing to CET shadow stack again.
 #if !defined(_LIBUNWIND_USE_CET)
 #define __unw_phase2_resume(cursor, fn)                                        \
@@ -50,6 +50,7 @@
     __unw_resume((cursor));                                                    \
   } while (0)
 #elif defined(_LIBUNWIND_TARGET_I386)
+#define __cet_ss_step_size 4
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
     _LIBUNWIND_POP_CET_SSP((fn));                                              \
@@ -61,6 +62,7 @@
                      "d"(cetJumpAddress));                                     \
   } while (0)
 #elif defined(_LIBUNWIND_TARGET_X86_64)
+#define __cet_ss_step_size 8
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
     _LIBUNWIND_POP_CET_SSP((fn));                                              \
@@ -82,13 +84,13 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
     int stepResult = __unw_step(cursor);
     if (stepResult == 0) {
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase1(ex_ojb=%p): __unw_step() reached "
+          "unwind_phase1(ex_obj=%p): __unw_step() reached "
           "bottom => _URC_END_OF_STACK",
           (void *)exception_object);
       return _URC_END_OF_STACK;
     } else if (stepResult < 0) {
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase1(ex_ojb=%p): __unw_step failed => "
+          "unwind_phase1(ex_obj=%p): __unw_step failed => "
           "_URC_FATAL_PHASE1_ERROR",
           (void *)exception_object);
       return _URC_FATAL_PHASE1_ERROR;
@@ -99,7 +101,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
     unw_word_t sp;
     if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase1(ex_ojb=%p): __unw_get_proc_info "
+          "unwind_phase1(ex_obj=%p): __unw_get_proc_info "
           "failed => _URC_FATAL_PHASE1_ERROR",
           (void *)exception_object);
       return _URC_FATAL_PHASE1_ERROR;
@@ -118,7 +120,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
       unw_word_t pc;
       __unw_get_reg(cursor, UNW_REG_IP, &pc);
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase1(ex_ojb=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
+          "unwind_phase1(ex_obj=%p): pc=0x%" PRIxPTR ", start_ip=0x%" PRIxPTR
           ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR "",
           (void *)exception_object, pc, frameInfo.start_ip, functionName,
           frameInfo.lsda, frameInfo.handler);
@@ -131,7 +133,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
       _Unwind_Personality_Fn p =
           (_Unwind_Personality_Fn)(uintptr_t)(frameInfo.handler);
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase1(ex_ojb=%p): calling personality function %p",
+          "unwind_phase1(ex_obj=%p): calling personality function %p",
           (void *)exception_object, (void *)(uintptr_t)p);
       _Unwind_Reason_Code personalityResult =
           (*p)(1, _UA_SEARCH_PHASE, exception_object->exception_class,
@@ -143,13 +145,13 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
         __unw_get_reg(cursor, UNW_REG_SP, &sp);
         exception_object->private_2 = (uintptr_t)sp;
         _LIBUNWIND_TRACE_UNWINDING(
-            "unwind_phase1(ex_ojb=%p): _URC_HANDLER_FOUND",
+            "unwind_phase1(ex_obj=%p): _URC_HANDLER_FOUND",
             (void *)exception_object);
         return _URC_NO_REASON;
 
       case _URC_CONTINUE_UNWIND:
         _LIBUNWIND_TRACE_UNWINDING(
-            "unwind_phase1(ex_ojb=%p): _URC_CONTINUE_UNWIND",
+            "unwind_phase1(ex_obj=%p): _URC_CONTINUE_UNWIND",
             (void *)exception_object);
         // continue unwinding
         break;
@@ -157,7 +159,7 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
       default:
         // something went wrong
         _LIBUNWIND_TRACE_UNWINDING(
-            "unwind_phase1(ex_ojb=%p): _URC_FATAL_PHASE1_ERROR",
+            "unwind_phase1(ex_obj=%p): _URC_FATAL_PHASE1_ERROR",
             (void *)exception_object);
         return _URC_FATAL_PHASE1_ERROR;
       }
@@ -165,33 +167,36 @@ unwind_phase1(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
   }
   return _URC_NO_REASON;
 }
-
+extern int __unw_step_stage2(unw_cursor_t *);
 
 static _Unwind_Reason_Code
 unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *exception_object) {
   __unw_init_local(cursor, uc);
 
-  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p)",
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p)",
                              (void *)exception_object);
 
   // uc is initialized by __unw_getcontext in the parent frame. The first stack
   // frame walked is unwind_phase2.
   unsigned framesWalked = 1;
+#ifdef _LIBUNWIND_USE_CET
+  unsigned long shadowStackTop = _get_ssp();
+#endif
   // Walk each frame until we reach where search phase said to stop.
   while (true) {
 
     // Ask libunwind to get next frame (skip over first which is
     // _Unwind_RaiseException).
-    int stepResult = __unw_step(cursor);
+    int stepResult = __unw_step_stage2(cursor);
     if (stepResult == 0) {
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase2(ex_ojb=%p): __unw_step() reached "
+          "unwind_phase2(ex_obj=%p): __unw_step_stage2() reached "
           "bottom => _URC_END_OF_STACK",
           (void *)exception_object);
       return _URC_END_OF_STACK;
     } else if (stepResult < 0) {
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase2(ex_ojb=%p): __unw_step failed => "
+          "unwind_phase2(ex_obj=%p): __unw_step_stage2 failed => "
           "_URC_FATAL_PHASE1_ERROR",
           (void *)exception_object);
       return _URC_FATAL_PHASE2_ERROR;
@@ -203,7 +208,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
     __unw_get_reg(cursor, UNW_REG_SP, &sp);
     if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase2(ex_ojb=%p): __unw_get_proc_info "
+          "unwind_phase2(ex_obj=%p): __unw_get_proc_info "
           "failed => _URC_FATAL_PHASE1_ERROR",
           (void *)exception_object);
       return _URC_FATAL_PHASE2_ERROR;
@@ -219,7 +224,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
                                &offset) != UNW_ESUCCESS) ||
           (frameInfo.start_ip + offset > frameInfo.end_ip))
         functionName = ".anonymous.";
-      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): start_ip=0x%" PRIxPTR
+      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p): start_ip=0x%" PRIxPTR
                                  ", func=%s, sp=0x%" PRIxPTR ", lsda=0x%" PRIxPTR
                                  ", personality=0x%" PRIxPTR,
                                  (void *)exception_object, frameInfo.start_ip,
@@ -228,6 +233,20 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
     }
 #endif
 
+// In CET enabled environment, we check return address stored in normal stack
+// against return address stored in CET shadow stack, if the 2 addresses don't
+// match, it means return address in normal stack has been corrupted, we return
+// _URC_FATAL_PHASE2_ERROR.
+#ifdef _LIBUNWIND_USE_CET
+    if (shadowStackTop != 0) {
+      unw_word_t retInNormalStack;
+      __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack);
+      unsigned long retInShadowStack = *(
+          unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked);
+      if (retInNormalStack != retInShadowStack)
+        return _URC_FATAL_PHASE2_ERROR;
+    }
+#endif
     ++framesWalked;
     // If there is a personality routine, tell it we are unwinding.
     if (frameInfo.handler != 0) {
@@ -245,7 +264,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
       case _URC_CONTINUE_UNWIND:
         // Continue unwinding
         _LIBUNWIND_TRACE_UNWINDING(
-            "unwind_phase2(ex_ojb=%p): _URC_CONTINUE_UNWIND",
+            "unwind_phase2(ex_obj=%p): _URC_CONTINUE_UNWIND",
             (void *)exception_object);
         if (sp == exception_object->private_2) {
           // Phase 1 said we would stop at this frame, but we did not...
@@ -255,7 +274,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
         break;
       case _URC_INSTALL_CONTEXT:
         _LIBUNWIND_TRACE_UNWINDING(
-            "unwind_phase2(ex_ojb=%p): _URC_INSTALL_CONTEXT",
+            "unwind_phase2(ex_obj=%p): _URC_INSTALL_CONTEXT",
             (void *)exception_object);
         // Personality routine says to transfer control to landing pad.
         // We may get control back if landing pad calls _Unwind_Resume().
@@ -263,7 +282,7 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
           unw_word_t pc;
           __unw_get_reg(cursor, UNW_REG_IP, &pc);
           __unw_get_reg(cursor, UNW_REG_SP, &sp);
-          _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_ojb=%p): re-entering "
+          _LIBUNWIND_TRACE_UNWINDING("unwind_phase2(ex_obj=%p): re-entering "
                                      "user code with ip=0x%" PRIxPTR
                                      ", sp=0x%" PRIxPTR,
                                      (void *)exception_object, pc, sp);
@@ -296,14 +315,15 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
   // frame walked is unwind_phase2_forced.
   unsigned framesWalked = 1;
   // Walk each frame until we reach where search phase said to stop
-  while (__unw_step(cursor) > 0) {
+  while (__unw_step_stage2(cursor) > 0) {
 
     // Update info about this frame.
     unw_proc_info_t frameInfo;
     if (__unw_get_proc_info(cursor, &frameInfo) != UNW_ESUCCESS) {
-      _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): __unw_step "
-                                 "failed => _URC_END_OF_STACK",
-                                 (void *)exception_object);
+      _LIBUNWIND_TRACE_UNWINDING(
+          "unwind_phase2_forced(ex_obj=%p): __unw_step_stage2 "
+          "failed => _URC_END_OF_STACK",
+          (void *)exception_object);
       return _URC_FATAL_PHASE2_ERROR;
     }
 
@@ -318,7 +338,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
           (frameInfo.start_ip + offset > frameInfo.end_ip))
         functionName = ".anonymous.";
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase2_forced(ex_ojb=%p): start_ip=0x%" PRIxPTR
+          "unwind_phase2_forced(ex_obj=%p): start_ip=0x%" PRIxPTR
           ", func=%s, lsda=0x%" PRIxPTR ", personality=0x%" PRIxPTR,
           (void *)exception_object, frameInfo.start_ip, functionName,
           frameInfo.lsda, frameInfo.handler);
@@ -332,11 +352,11 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
         (*stop)(1, action, exception_object->exception_class, exception_object,
                 (struct _Unwind_Context *)(cursor), stop_parameter);
     _LIBUNWIND_TRACE_UNWINDING(
-        "unwind_phase2_forced(ex_ojb=%p): stop function returned %d",
+        "unwind_phase2_forced(ex_obj=%p): stop function returned %d",
         (void *)exception_object, stopResult);
     if (stopResult != _URC_NO_REASON) {
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase2_forced(ex_ojb=%p): stopped by stop function",
+          "unwind_phase2_forced(ex_obj=%p): stopped by stop function",
           (void *)exception_object);
       return _URC_FATAL_PHASE2_ERROR;
     }
@@ -347,21 +367,21 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
       _Unwind_Personality_Fn p =
           (_Unwind_Personality_Fn)(intptr_t)(frameInfo.handler);
       _LIBUNWIND_TRACE_UNWINDING(
-          "unwind_phase2_forced(ex_ojb=%p): calling personality function %p",
+          "unwind_phase2_forced(ex_obj=%p): calling personality function %p",
           (void *)exception_object, (void *)(uintptr_t)p);
       _Unwind_Reason_Code personalityResult =
           (*p)(1, action, exception_object->exception_class, exception_object,
                (struct _Unwind_Context *)(cursor));
       switch (personalityResult) {
       case _URC_CONTINUE_UNWIND:
-        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): "
                                    "personality returned "
                                    "_URC_CONTINUE_UNWIND",
                                    (void *)exception_object);
         // Destructors called, continue unwinding
         break;
       case _URC_INSTALL_CONTEXT:
-        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): "
                                    "personality returned "
                                    "_URC_INSTALL_CONTEXT",
                                    (void *)exception_object);
@@ -370,7 +390,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
         break;
       default:
         // Personality routine returned an unknown result code.
-        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): "
+        _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): "
                                    "personality returned %d, "
                                    "_URC_FATAL_PHASE2_ERROR",
                                    (void *)exception_object, personalityResult);
@@ -381,7 +401,7 @@ unwind_phase2_forced(unw_context_t *uc, unw_cursor_t *cursor,
 
   // Call stop function one last time and tell it we've reached the end
   // of the stack.
-  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_ojb=%p): calling stop "
+  _LIBUNWIND_TRACE_UNWINDING("unwind_phase2_forced(ex_obj=%p): calling stop "
                              "function with _UA_END_OF_STACK",
                              (void *)exception_object);
   _Unwind_Action lastAction =
@@ -425,7 +445,7 @@ _Unwind_RaiseException(_Unwind_Exception *exception_object) {
 /// may force a jump to a landing pad in that function, the landing
 /// pad code may then call _Unwind_Resume() to continue with the
 /// unwinding.  Note: the call to _Unwind_Resume() is from compiler
-/// geneated user code.  All other _Unwind_* routines are called
+/// generated user code.  All other _Unwind_* routines are called
 /// by the C++ runtime __cxa_* routines.
 ///
 /// Note: re-throwing an exception (as opposed to continuing the unwind)
lib/libunwind/src/UnwindRegistersRestore.S
@@ -8,6 +8,12 @@
 
 #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
@@ -441,7 +447,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)
@@ -1026,38 +1032,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)
@@ -1069,32 +1046,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
@@ -1182,72 +1136,20 @@ 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
@@ -1266,22 +1168,9 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
   lg %r1, 8(%r2)
 
   // Restore FPRs
-  ld %f0, 144(%r2)
-  ld %f1, 152(%r2)
-  ld %f2, 160(%r2)
-  ld %f3, 168(%r2)
-  ld %f4, 176(%r2)
-  ld %f5, 184(%r2)
-  ld %f6, 192(%r2)
-  ld %f7, 200(%r2)
-  ld %f8, 208(%r2)
-  ld %f9, 216(%r2)
-  ld %f10, 224(%r2)
-  ld %f11, 232(%r2)
-  ld %f12, 240(%r2)
-  ld %f13, 248(%r2)
-  ld %f14, 256(%r2)
-  ld %f15, 264(%r2)
+  .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)
@@ -1289,6 +1178,36 @@ DEFINE_LIBUNWIND_FUNCTION(_ZN9libunwind15Registers_s390x6jumptoEv)
   // 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    $r4,  $a0, (8 * 4)   // restore $a0 last
+  ld.d    $r1,  $a0, (8 * 32)  // load new pc into $ra
+
+  jr      $ra
+
 #endif
 
 #endif /* !defined(__USING_SJLJ_EXCEPTIONS__) */
lib/libunwind/src/UnwindRegistersSave.S
@@ -8,6 +8,12 @@
 
 #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
@@ -244,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
@@ -283,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
@@ -1110,71 +1059,14 @@ 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
@@ -1201,27 +1093,37 @@ DEFINE_LIBUNWIND_FUNCTION(__unw_getcontext)
   stg %r14, 8(%r2)
 
   // Save FPRs
-  std %f0, 144(%r2)
-  std %f1, 152(%r2)
-  std %f2, 160(%r2)
-  std %f3, 168(%r2)
-  std %f4, 176(%r2)
-  std %f5, 184(%r2)
-  std %f6, 192(%r2)
-  std %f7, 200(%r2)
-  std %f8, 208(%r2)
-  std %f9, 216(%r2)
-  std %f10, 224(%r2)
-  std %f11, 232(%r2)
-  std %f12, 240(%r2)
-  std %f13, 248(%r2)
-  std %f14, 256(%r2)
-  std %f15, 264(%r2)
+  .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)