untrusted comment: verify with openbsd-78-base.pub
RWS3/nvFmk4SWe4Ipy1XcKaskB0EO5kWuGLjVNXU9fzqyhGsxwkR6s35FTNkH/O8IUD9xN4FqMGpYnoYATr9kVcoZIU7Ie0VRgk=

OpenBSD 7.8 errata 006, November 17, 2025:

Missing modifications to libunwind after the LLVM 19.1.7 update can
cause performance regressions and missing endbr instructions.

Apply by doing:
    signify -Vep /etc/signify/openbsd-78-base.pub -x 006_libunwind.patch.sig \
        -m - | (cd /usr/src && patch -p0)

And then rebuild and install libcxxabi and libexecinfo
    cd /usr/src/gnu/lib/libcxxabi
    make obj
    make
    make install
    cd /usr/src/gnu/lib/libexecinfo
    make obj
    make
    make install

Index: gnu/llvm/libunwind/src/AddressSpace.hpp
===================================================================
RCS file: /cvs/src/gnu/llvm/libunwind/src/AddressSpace.hpp,v
diff -u -p -u -r1.5 AddressSpace.hpp
--- gnu/llvm/libunwind/src/AddressSpace.hpp	21 Aug 2025 14:54:43 -0000	1.5
+++ gnu/llvm/libunwind/src/AddressSpace.hpp	5 Nov 2025 08:32:10 -0000
@@ -16,6 +16,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/tree.h>
 
 #include "libunwind.h"
 #include "config.h"
@@ -152,6 +153,72 @@ struct UnwindInfoSections {
 #endif
 };
 
+class UnwindInfoSectionsCache {
+public:
+
+  struct CacheItem {
+    /*
+     * Implement new operator to avoid depending on libcxx.  By declaring
+     * it noexcept we can let it return nullptr under memory shortage.
+     */
+    void *operator new(size_t sz) noexcept {
+      return malloc(sz);
+    }
+
+    CacheItem(UnwindInfoSections &uis, uintptr_t pc)
+      : m_uis(uis), m_pc(pc) {
+    }
+    CacheItem(uintptr_t pc)
+      : m_pc(pc) {
+    }
+
+    UnwindInfoSections m_uis;
+    uintptr_t m_pc;
+
+    RB_ENTRY(CacheItem) entry;
+  };
+
+  typedef uintptr_t CacheItemKey;
+
+  int CacheCmp(struct CacheItem *c1, struct CacheItem *c2) {
+    return (c1->m_pc < c2->m_pc ? -1 : c1->m_pc > c2->m_pc);
+  }
+
+  UnwindInfoSectionsCache() {
+    m_head = RB_INITIALIZER(&head);
+  }
+
+  bool getUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) {
+    UnwindInfoSections *result = nullptr;
+    if (m_prev_req_item && m_prev_req_item->m_pc == key)
+      result = &m_prev_req_item->m_uis;
+    else {
+      struct CacheItem find(key), *res;
+      res = RB_FIND(CacheTree, &m_head, &find);
+      if (res) {
+        m_prev_req_item = res;
+        result = &res->m_uis;
+      }
+    }
+    if (result) {
+      uis = *result;
+      return true;
+    }
+    return false;
+  }
+
+  void setUnwindInfoSectionsForPC(CacheItemKey key, UnwindInfoSections &uis) {
+    CacheItem *p_item = new CacheItem(uis, key);
+    if (p_item == nullptr)
+      return;
+    RB_INSERT(CacheTree, &m_head, p_item);
+  }
+
+private:
+  CacheItem *m_prev_req_item = nullptr;
+  RB_HEAD(CacheTree, CacheItem) m_head;
+  RB_GENERATE(CacheTree, CacheItem, entry, CacheCmp);
+};
 
 /// LocalAddressSpace is used as a template parameter to UnwindCursor when
 /// unwinding a thread in the same process.  The wrappers compile away,
Index: gnu/llvm/libunwind/src/UnwindCursor.hpp
===================================================================
RCS file: /cvs/src/gnu/llvm/libunwind/src/UnwindCursor.hpp,v
diff -u -p -u -r1.6 UnwindCursor.hpp
--- gnu/llvm/libunwind/src/UnwindCursor.hpp	21 Aug 2025 14:54:43 -0000	1.6
+++ gnu/llvm/libunwind/src/UnwindCursor.hpp	5 Nov 2025 08:32:10 -0000
@@ -90,6 +90,8 @@ extern "C" _Unwind_Reason_Code __libunwi
 
 namespace libunwind {
 
+static thread_local UnwindInfoSectionsCache uwis_cache;
+
 #if defined(_LIBUNWIND_SUPPORT_DWARF_UNWIND)
 /// Cache of recently found FDEs.
 template <typename A>
@@ -2600,7 +2602,14 @@ void UnwindCursor<A, R>::setInfoBasedOnI
 
   // Ask address space object to find unwind sections for this pc.
   UnwindInfoSections sects;
-  if (_addressSpace.findUnwindSections(pc, sects)) {
+  bool have_sects = false;
+  if (uwis_cache.getUnwindInfoSectionsForPC(pc, sects))
+    have_sects = true;
+  else if (_addressSpace.findUnwindSections(pc, sects)) {
+    uwis_cache.setUnwindInfoSectionsForPC(pc, sects);
+    have_sects = true;
+  }
+  if (have_sects) {
 #if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
     // If there is a compact unwind encoding table, look there first.
     if (sects.compact_unwind_section != 0) {
Index: gnu/llvm/libunwind/src/assembly.h
===================================================================
RCS file: /cvs/src/gnu/llvm/libunwind/src/assembly.h,v
diff -u -p -u -r1.7 assembly.h
--- gnu/llvm/libunwind/src/assembly.h	21 Aug 2025 14:54:43 -0000	1.7
+++ gnu/llvm/libunwind/src/assembly.h	5 Nov 2025 08:32:10 -0000
@@ -15,7 +15,7 @@
 #ifndef UNWIND_ASSEMBLY_H
 #define UNWIND_ASSEMBLY_H
 
-#if defined(__linux__) && defined(__CET__)
+#if defined(__CET__)
 #include <cet.h>
 #define _LIBUNWIND_CET_ENDBR _CET_ENDBR
 #else
