1
0
mirror of https://github.com/openbsd/src.git synced 2026-06-19 07:43:34 +02:00

take 2: re-apply two commits that were lost while merging the 19.1.7 update

Reintroduce a tweaked version of the IP-based caching implementation.
Implementing a custom "new" operator has the two following desirable
properties:
- make the code more standalone, not depending on "new" from libcxx.
- teach this allocator to return nullptr on memory shortage ("noexcept")
  so it can fail gracefully. If we can't allocate an item, we just don't
  cache it.
That should be more resilient to memory shortages and thus more usable
from libexecinfo.

ok rsadowski@ robert@
This commit is contained in:
jca
2025-11-04 13:09:23 +00:00
parent dd6358cb0c
commit d387f9c1e6
2 changed files with 77 additions and 1 deletions
+67
View File
@@ -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,
+10 -1
View File
@@ -90,6 +90,8 @@ extern "C" _Unwind_Reason_Code __libunwind_seh_personality(
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>::setInfoBasedOnIPRegister(bool isReturnAddress) {
// 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) {