| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #ifndef __FRAMEHEADER_CACHE_HPP__ |
| | #define __FRAMEHEADER_CACHE_HPP__ |
| |
|
| | #include "config.h" |
| | #include <limits.h> |
| |
|
| | #ifdef _LIBUNWIND_DEBUG_FRAMEHEADER_CACHE |
| | #define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) _LIBUNWIND_LOG0(x) |
| | #define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) \ |
| | _LIBUNWIND_LOG(msg, __VA_ARGS__) |
| | #else |
| | #define _LIBUNWIND_FRAMEHEADERCACHE_TRACE0(x) |
| | #define _LIBUNWIND_FRAMEHEADERCACHE_TRACE(msg, ...) |
| | #endif |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | class _LIBUNWIND_HIDDEN FrameHeaderCache { |
| | struct CacheEntry { |
| | uintptr_t LowPC() { return Info.dso_base; }; |
| | uintptr_t HighPC() { return Info.dso_base + Info.text_segment_length; }; |
| | UnwindInfoSections Info; |
| | CacheEntry *Next; |
| | }; |
| |
|
| | static const size_t kCacheEntryCount = 8; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | CacheEntry Entries[kCacheEntryCount]; |
| | CacheEntry *MostRecentlyUsed; |
| | CacheEntry *Unused; |
| |
|
| | void resetCache() { |
| | _LIBUNWIND_FRAMEHEADERCACHE_TRACE0("FrameHeaderCache reset"); |
| | MostRecentlyUsed = nullptr; |
| | Unused = &Entries[0]; |
| | for (size_t i = 0; i < kCacheEntryCount - 1; i++) { |
| | Entries[i].Next = &Entries[i + 1]; |
| | } |
| | Entries[kCacheEntryCount - 1].Next = nullptr; |
| | } |
| |
|
| | bool cacheNeedsReset(dl_phdr_info *PInfo) { |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | static unsigned long long LastAdds = ULLONG_MAX; |
| | static unsigned long long LastSubs = ULLONG_MAX; |
| | if (PInfo->dlpi_adds != LastAdds || PInfo->dlpi_subs != LastSubs) { |
| | |
| | |
| | |
| | LastAdds = PInfo->dlpi_adds; |
| | LastSubs = PInfo->dlpi_subs; |
| | resetCache(); |
| | return true; |
| | } |
| | return false; |
| | } |
| |
|
| | public: |
| | bool find(dl_phdr_info *PInfo, size_t, void *data) { |
| | if (cacheNeedsReset(PInfo) || MostRecentlyUsed == nullptr) |
| | return false; |
| |
|
| | auto *CBData = static_cast<dl_iterate_cb_data *>(data); |
| | CacheEntry *Current = MostRecentlyUsed; |
| | CacheEntry *Previous = nullptr; |
| | while (Current != nullptr) { |
| | _LIBUNWIND_FRAMEHEADERCACHE_TRACE( |
| | "FrameHeaderCache check %lx in [%lx - %lx)", CBData->targetAddr, |
| | Current->LowPC(), Current->HighPC()); |
| | if (Current->LowPC() <= CBData->targetAddr && |
| | CBData->targetAddr < Current->HighPC()) { |
| | _LIBUNWIND_FRAMEHEADERCACHE_TRACE( |
| | "FrameHeaderCache hit %lx in [%lx - %lx)", CBData->targetAddr, |
| | Current->LowPC(), Current->HighPC()); |
| | if (Previous) { |
| | |
| | |
| | Previous->Next = Current->Next; |
| | Current->Next = MostRecentlyUsed; |
| | MostRecentlyUsed = Current; |
| | } |
| | *CBData->sects = Current->Info; |
| | return true; |
| | } |
| | Previous = Current; |
| | Current = Current->Next; |
| | } |
| | _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache miss for address %lx", |
| | CBData->targetAddr); |
| | return false; |
| | } |
| |
|
| | void add(const UnwindInfoSections *UIS) { |
| | CacheEntry *Current = nullptr; |
| |
|
| | if (Unused != nullptr) { |
| | Current = Unused; |
| | Unused = Unused->Next; |
| | } else { |
| | Current = MostRecentlyUsed; |
| | CacheEntry *Previous = nullptr; |
| | while (Current->Next != nullptr) { |
| | Previous = Current; |
| | Current = Current->Next; |
| | } |
| | Previous->Next = nullptr; |
| | _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache evict [%lx - %lx)", |
| | Current->LowPC(), Current->HighPC()); |
| | } |
| |
|
| | Current->Info = *UIS; |
| | Current->Next = MostRecentlyUsed; |
| | MostRecentlyUsed = Current; |
| | _LIBUNWIND_FRAMEHEADERCACHE_TRACE("FrameHeaderCache add [%lx - %lx)", |
| | MostRecentlyUsed->LowPC(), |
| | MostRecentlyUsed->HighPC()); |
| | } |
| | }; |
| |
|
| | #endif |
| |
|