| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #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 |
|
|