update tracy from 11.0 to 13.1 and fix build with tracy enabled

This commit is contained in:
Sven Balzer
2026-05-01 18:24:04 +02:00
parent 7fa5294e02
commit 2adf75973a
304 changed files with 20579 additions and 170182 deletions
+272 -206
View File
@@ -24,15 +24,33 @@
# pragma warning( disable : 4091 )
# endif
# include <dbghelp.h>
# pragma comment( lib, "dbghelp.lib" )
# ifdef _MSC_VER
# pragma warning( pop )
# endif
#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6
#elif defined(TRACY_USE_LIBBACKTRACE)
# include "../libbacktrace/backtrace.hpp"
# include <algorithm>
# include <dlfcn.h>
# include <cxxabi.h>
# include <stdlib.h>
// Implementation files
# include "../libbacktrace/alloc.cpp"
# include "../libbacktrace/dwarf.cpp"
# include "../libbacktrace/fileline.cpp"
# include "../libbacktrace/mmapio.cpp"
# include "../libbacktrace/posix.cpp"
# include "../libbacktrace/sort.cpp"
# include "../libbacktrace/state.cpp"
# if TRACY_HAS_CALLSTACK == 4
# include "../libbacktrace/macho.cpp"
# else
# include "../libbacktrace/elf.cpp"
# endif
# include "../common/TracyStackFrames.cpp"
#elif TRACY_HAS_CALLSTACK == 5
# include <dlfcn.h>
# include <cxxabi.h>
@@ -53,7 +71,7 @@ extern "C"
};
#endif
#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 5 || TRACY_HAS_CALLSTACK == 6
#if defined(TRACY_USE_LIBBACKTRACE) || TRACY_HAS_CALLSTACK == 5
// If you want to use your own demangling functionality (e.g. for another language),
// define TRACY_DEMANGLE and provide your own implementation of the __tracy_demangle
// function. The input parameter is a function name. The demangle function must
@@ -91,94 +109,147 @@ extern "C" const char* ___tracy_demangle( const char* mangled )
#endif
#endif
#if TRACY_HAS_CALLSTACK == 3
# define TRACY_USE_IMAGE_CACHE
#if defined(TRACY_USE_LIBBACKTRACE) && TRACY_HAS_CALLSTACK != 4 // dl_iterate_phdr is required for the current image cache. Need to move it to libbacktrace?
# define TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
# include <link.h>
#endif
namespace tracy
{
#ifdef TRACY_USE_IMAGE_CACHE
// when we have access to dl_iterate_phdr(), we can build a cache of address ranges to image paths
// so we can quickly determine which image an address falls into.
// We refresh this cache only when we hit an address that doesn't fall into any known range.
static bool IsKernelAddress(uint64_t addr) {
return (addr >> 63) != 0;
}
void DestroyImageEntry( ImageEntry& entry )
{
tracy_free( entry.m_path );
tracy_free( entry.m_name );
}
class ImageCache
{
public:
struct ImageEntry
ImageCache( size_t imageCacheCapacity = 512 )
: m_images( imageCacheCapacity )
{
void* m_startAddress = nullptr;
void* m_endAddress = nullptr;
char* m_name = nullptr;
};
ImageCache()
: m_images( 512 )
{
Refresh();
}
~ImageCache()
{
Clear();
}
const ImageEntry* GetImageForAddress( void* address )
ImageEntry* AddEntry( const ImageEntry& entry )
{
const ImageEntry* entry = GetImageForAddressImpl( address );
if( m_sorted ) m_sorted = m_images.empty() || ( entry.m_startAddress < m_images.back().m_startAddress );
ImageEntry* newEntry = m_images.push_next();
*newEntry = entry;
return newEntry;
}
const ImageEntry* GetImageForAddress( uint64_t address )
{
Sort();
auto it = std::lower_bound( m_images.begin(), m_images.end(), address,
[]( const ImageEntry& lhs, const uint64_t rhs ) { return lhs.m_startAddress > rhs; } );
if( it != m_images.end() && address < it->m_endAddress )
{
return it;
}
return nullptr;
}
void Sort()
{
if( m_sorted ) return;
std::sort( m_images.begin(), m_images.end(),
[]( const ImageEntry& lhs, const ImageEntry& rhs ) { return lhs.m_startAddress > rhs.m_startAddress; } );
m_sorted = true;
}
void Clear()
{
for( ImageEntry& entry : m_images )
{
DestroyImageEntry( entry );
}
m_sorted = true;
m_images.clear();
}
bool ContainsImage( uint64_t startAddress ) const
{
return std::any_of( m_images.begin(), m_images.end(), [startAddress]( const ImageEntry& entry ) { return startAddress == entry.m_startAddress; } );
}
protected:
tracy::FastVector<ImageEntry> m_images;
bool m_sorted = true;
};
#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
// when we have access to dl_iterate_phdr(), we can build a cache of address ranges to image paths
// so we can quickly determine which image an address falls into.
// We refresh this cache only when we hit an address that doesn't fall into any known range.
class ImageCacheDlIteratePhdr : public ImageCache
{
public:
ImageCacheDlIteratePhdr()
{
Refresh();
}
~ImageCacheDlIteratePhdr()
{
}
const ImageEntry* GetImageForAddress( uint64_t address )
{
const ImageEntry* entry = ImageCache::GetImageForAddress( address );
if( !entry )
{
Refresh();
return GetImageForAddressImpl( address );
return ImageCache::GetImageForAddress( address );
}
return entry;
}
private:
tracy::FastVector<ImageEntry> m_images;
bool m_updated = false;
bool m_haveMainImageName = false;
static int Callback( struct dl_phdr_info* info, size_t size, void* data )
{
ImageCache* cache = reinterpret_cast<ImageCache*>( data );
ImageCacheDlIteratePhdr* cache = reinterpret_cast<ImageCacheDlIteratePhdr*>( data );
const auto startAddress = reinterpret_cast<void*>( info->dlpi_addr );
if( cache->Contains( startAddress ) ) return 0;
const auto startAddress = static_cast<uint64_t>( info->dlpi_addr );
if( cache->ContainsImage( startAddress ) ) return 0;
const uint32_t headerCount = info->dlpi_phnum;
assert( headerCount > 0);
const auto endAddress = reinterpret_cast<void*>( info->dlpi_addr +
const auto endAddress = static_cast<uint64_t>( info->dlpi_addr +
info->dlpi_phdr[info->dlpi_phnum - 1].p_vaddr + info->dlpi_phdr[info->dlpi_phnum - 1].p_memsz);
ImageEntry* image = cache->m_images.push_next();
image->m_startAddress = startAddress;
image->m_endAddress = endAddress;
ImageEntry image{};
image.m_startAddress = startAddress;
image.m_endAddress = endAddress;
// the base executable name isn't provided when iterating with dl_iterate_phdr,
// we will have to patch the executable image name outside this callback
if( info->dlpi_name && info->dlpi_name[0] != '\0' )
{
size_t sz = strlen( info->dlpi_name ) + 1;
image->m_name = (char*)tracy_malloc( sz );
memcpy( image->m_name, info->dlpi_name, sz );
}
else
{
image->m_name = nullptr;
}
image.m_name = info->dlpi_name && info->dlpi_name[0] != '\0' ? CopyStringFast( info->dlpi_name ) : nullptr;
cache->AddEntry( image );
cache->m_updated = true;
return 0;
}
bool Contains( void* startAddress ) const
{
return std::any_of( m_images.begin(), m_images.end(), [startAddress]( const ImageEntry& entry ) { return startAddress == entry.m_startAddress; } );
}
void Refresh()
{
m_updated = false;
@@ -186,9 +257,7 @@ private:
if( m_updated )
{
std::sort( m_images.begin(), m_images.end(),
[]( const ImageEntry& lhs, const ImageEntry& rhs ) { return lhs.m_startAddress > rhs.m_startAddress; } );
Sort();
// patch the main executable image name here, as calling dl_* functions inside the dl_iterate_phdr callback might cause deadlocks
UpdateMainImageName();
}
@@ -223,31 +292,45 @@ private:
m_haveMainImageName = true;
}
const ImageEntry* GetImageForAddressImpl( void* address ) const
{
auto it = std::lower_bound( m_images.begin(), m_images.end(), address,
[]( const ImageEntry& lhs, const void* rhs ) { return lhs.m_startAddress > rhs; } );
if( it != m_images.end() && address < it->m_endAddress )
{
return it;
}
return nullptr;
}
void Clear()
{
for( ImageEntry& entry : m_images )
{
tracy_free( entry.m_name );
}
m_images.clear();
ImageCache::Clear();
m_haveMainImageName = false;
}
};
#endif //#ifdef TRACY_USE_IMAGE_CACHE
using UserlandImageCache = ImageCacheDlIteratePhdr;
#else
using UserlandImageCache = ImageCache;
#endif //#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
static UserlandImageCache* s_imageCache;
static ImageCache* s_krnlCache;
void CreateImageCaches()
{
assert( s_imageCache == nullptr && s_krnlCache == nullptr );
s_imageCache = new ( tracy_malloc( sizeof( UserlandImageCache ) ) ) UserlandImageCache();
s_krnlCache = new ( tracy_malloc( sizeof( ImageCache ) ) ) ImageCache();
}
void DestroyImageCaches()
{
if( s_krnlCache != nullptr )
{
s_krnlCache->~ImageCache();
tracy_free( s_krnlCache );
s_krnlCache = nullptr;
}
if( s_imageCache != nullptr )
{
s_imageCache->~UserlandImageCache();
tracy_free( s_imageCache );
s_imageCache = nullptr;
}
}
// when "TRACY_SYMBOL_OFFLINE_RESOLVE" is set, instead of fully resolving symbols at runtime,
// simply resolve the offset and image name (which will be enough the resolving to be done offline)
@@ -282,32 +365,17 @@ extern "C"
t_SymFromInlineContext _SymFromInlineContext = 0;
t_SymGetLineFromInlineContext _SymGetLineFromInlineContext = 0;
TRACY_API ___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChain = 0;
typedef unsigned long (__stdcall *___tracy_t_RtlWalkFrameChain)( void**, unsigned long, unsigned long );
___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChainPtr = nullptr;
TRACY_API unsigned long ___tracy_RtlWalkFrameChain( void** callers, unsigned long count, unsigned long flags)
{
return ___tracy_RtlWalkFrameChainPtr(callers, count, flags);
}
}
struct ModuleCache
{
uint64_t start;
uint64_t end;
char* name;
};
static FastVector<ModuleCache>* s_modCache;
struct KernelDriver
{
uint64_t addr;
const char* mod;
const char* path;
};
KernelDriver* s_krnlCache = nullptr;
size_t s_krnlCacheCnt;
void InitCallstackCritical()
{
___tracy_RtlWalkFrameChain = (___tracy_t_RtlWalkFrameChain)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "RtlWalkFrameChain" );
___tracy_RtlWalkFrameChainPtr = (___tracy_t_RtlWalkFrameChain)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "RtlWalkFrameChain" );
}
void DbgHelpInit()
@@ -338,75 +406,57 @@ DWORD64 DbgHelpLoadSymbolsForModule( const char* imageName, uint64_t baseOfDll,
return SymLoadModuleEx( GetCurrentProcess(), nullptr, imageName, nullptr, baseOfDll, bllSize, nullptr, 0 );
}
ModuleCache* LoadSymbolsForModuleAndCache( const char* imageName, uint32_t imageNameLength, uint64_t baseOfDll, uint32_t dllSize )
char* FormatImageName( const char* imageName, uint32_t imageNameLength )
{
DbgHelpLoadSymbolsForModule( imageName, baseOfDll, dllSize );
ModuleCache* cachedModule = s_modCache->push_next();
cachedModule->start = baseOfDll;
cachedModule->end = baseOfDll + dllSize;
// when doing offline symbol resolution, we must store the full path of the dll for the resolving to work
if( s_shouldResolveSymbolsOffline )
{
cachedModule->name = (char*)tracy_malloc_fast(imageNameLength + 1);
memcpy(cachedModule->name, imageName, imageNameLength);
cachedModule->name[imageNameLength] = '\0';
return CopyStringFast( imageName, imageNameLength );
}
else
{
auto ptr = imageName + imageNameLength;
while (ptr > imageName && *ptr != '\\' && *ptr != '/') ptr--;
if (ptr > imageName) ptr++;
const char* ptr = imageName + imageNameLength;
while( ptr > imageName && *ptr != '\\' && *ptr != '/' ) ptr--;
if( ptr > imageName ) ptr++;
const auto namelen = imageName + imageNameLength - ptr;
cachedModule->name = (char*)tracy_malloc_fast(namelen + 3);
cachedModule->name[0] = '[';
memcpy(cachedModule->name + 1, ptr, namelen);
cachedModule->name[namelen + 1] = ']';
cachedModule->name[namelen + 2] = '\0';
}
return cachedModule;
char* alloc = (char*)tracy_malloc_fast( namelen + 3 );
alloc[0] = '[';
memcpy( alloc + 1, ptr, namelen );
alloc[namelen + 1] = ']';
alloc[namelen + 2] = '\0';
return alloc;
}
}
void InitCallstack()
ImageEntry* CacheModuleInfo( const char* imagePath, uint32_t imageNameLength, uint64_t baseOfDll, uint32_t dllSize )
{
#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
s_shouldResolveSymbolsOffline = ShouldResolveSymbolsOffline();
#endif //#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
if( s_shouldResolveSymbolsOffline )
{
TracyDebug("TRACY: enabling offline symbol resolving!\n");
}
ImageEntry moduleEntry = {};
moduleEntry.m_startAddress = baseOfDll;
moduleEntry.m_endAddress = baseOfDll + dllSize;
moduleEntry.m_path = CopyStringFast( imagePath, imageNameLength );
moduleEntry.m_name = FormatImageName( imagePath, imageNameLength );
DbgHelpInit();
return s_imageCache->AddEntry( moduleEntry );
}
#ifdef TRACY_DBGHELP_LOCK
DBGHELP_LOCK;
#endif
// use TRACY_NO_DBGHELP_INIT_LOAD=1 to disable preloading of driver
// and process module symbol loading at startup time - they will be loaded on demand later
// Sometimes this process can take a very long time and prevent resolving callstack frames
// symbols during that time.
const char* noInitLoadEnv = GetEnvVar( "TRACY_NO_DBGHELP_INIT_LOAD" );
const bool initTimeModuleLoad = !( noInitLoadEnv && noInitLoadEnv[0] == '1' );
if ( !initTimeModuleLoad )
{
TracyDebug("TRACY: skipping init time dbghelper module load\n");
}
ImageEntry* LoadSymbolsForModuleAndCache( const char* imagePath, uint32_t imageNameLength, uint64_t baseOfDll, uint32_t dllSize )
{
DbgHelpLoadSymbolsForModule( imagePath, baseOfDll, dllSize );
return CacheModuleInfo( imagePath, imageNameLength, baseOfDll, dllSize );
}
static void CacheProcessDrivers()
{
DWORD needed;
LPVOID dev[4096];
if( initTimeModuleLoad && EnumDeviceDrivers( dev, sizeof(dev), &needed ) != 0 )
if( EnumDeviceDrivers( dev, sizeof(dev), &needed ) != 0 )
{
char windir[MAX_PATH];
if( !GetWindowsDirectoryA( windir, sizeof( windir ) ) ) memcpy( windir, "c:\\windows", 11 );
const auto windirlen = strlen( windir );
const auto sz = needed / sizeof( LPVOID );
s_krnlCache = (KernelDriver*)tracy_malloc( sizeof(KernelDriver) * sz );
int cnt = 0;
for( size_t i=0; i<sz; i++ )
{
char fn[MAX_PATH];
@@ -417,7 +467,12 @@ void InitCallstack()
buf[0] = '<';
memcpy( buf+1, fn, len );
memcpy( buf+len+1, ">", 2 );
s_krnlCache[cnt] = KernelDriver { (uint64_t)dev[i], buf };
ImageEntry kernelDriver{};
kernelDriver.m_startAddress = (uint64_t)dev[i];
kernelDriver.m_endAddress = 0;
kernelDriver.m_name = buf;
kernelDriver.m_path = nullptr;
const auto len = GetDeviceDriverFileNameA( dev[i], fn, sizeof( fn ) );
if( len != 0 )
@@ -433,27 +488,23 @@ void InitCallstack()
}
DbgHelpLoadSymbolsForModule( path, (DWORD64)dev[i], 0 );
const auto psz = strlen( path );
auto pptr = (char*)tracy_malloc_fast( psz+1 );
memcpy( pptr, path, psz );
pptr[psz] = '\0';
s_krnlCache[cnt].path = pptr;
kernelDriver.m_path = CopyString( path );
}
cnt++;
s_krnlCache->AddEntry(kernelDriver);
}
}
s_krnlCacheCnt = cnt;
std::sort( s_krnlCache, s_krnlCache + s_krnlCacheCnt, []( const KernelDriver& lhs, const KernelDriver& rhs ) { return lhs.addr > rhs.addr; } );
s_krnlCache->Sort();
}
}
s_modCache = (FastVector<ModuleCache>*)tracy_malloc( sizeof( FastVector<ModuleCache> ) );
new(s_modCache) FastVector<ModuleCache>( 512 );
static void CacheProcessModules()
{
DWORD needed;
HANDLE proc = GetCurrentProcess();
HMODULE mod[1024];
if( initTimeModuleLoad && EnumProcessModules( proc, mod, sizeof( mod ), &needed ) != 0 )
if( EnumProcessModules( proc, mod, sizeof( mod ), &needed ) != 0 )
{
const auto sz = needed / sizeof( HMODULE );
for( size_t i=0; i<sz; i++ )
@@ -472,6 +523,41 @@ void InitCallstack()
}
}
}
}
void InitCallstack()
{
#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
s_shouldResolveSymbolsOffline = ShouldResolveSymbolsOffline();
#endif //#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
if( s_shouldResolveSymbolsOffline )
{
TracyDebug("TRACY: enabling offline symbol resolving!\n");
}
CreateImageCaches();
DbgHelpInit();
#ifdef TRACY_DBGHELP_LOCK
DBGHELP_LOCK;
#endif
// use TRACY_NO_DBGHELP_INIT_LOAD=1 to disable preloading of driver
// and process module symbol loading at startup time - they will be loaded on demand later
// Sometimes this process can take a very long time and prevent resolving callstack frames
// symbols during that time.
const char* noInitLoadEnv = GetEnvVar( "TRACY_NO_DBGHELP_INIT_LOAD" );
const bool initTimeModuleLoad = !( noInitLoadEnv && noInitLoadEnv[0] == '1' );
if ( !initTimeModuleLoad )
{
TracyDebug("TRACY: skipping init time dbghelper module load\n");
}
else
{
CacheProcessDrivers();
CacheProcessModules();
}
#ifdef TRACY_DBGHELP_LOCK
DBGHELP_UNLOCK;
@@ -480,6 +566,7 @@ void InitCallstack()
void EndCallstack()
{
DestroyImageCaches();
}
const char* DecodeCallstackPtrFast( uint64_t ptr )
@@ -514,11 +601,11 @@ const char* DecodeCallstackPtrFast( uint64_t ptr )
const char* GetKernelModulePath( uint64_t addr )
{
assert( addr >> 63 != 0 );
assert( IsKernelAddress( addr ) );
if( !s_krnlCache ) return nullptr;
auto it = std::lower_bound( s_krnlCache, s_krnlCache + s_krnlCacheCnt, addr, []( const KernelDriver& lhs, const uint64_t& rhs ) { return lhs.addr > rhs; } );
if( it == s_krnlCache + s_krnlCacheCnt ) return nullptr;
return it->path;
const ImageEntry* imageEntry = s_krnlCache->GetImageForAddress( addr );
if( imageEntry ) return imageEntry->m_path;
return nullptr;
}
struct ModuleNameAndBaseAddress
@@ -529,51 +616,38 @@ struct ModuleNameAndBaseAddress
ModuleNameAndBaseAddress GetModuleNameAndPrepareSymbols( uint64_t addr )
{
if( ( addr >> 63 ) != 0 )
if( IsKernelAddress( addr ) )
{
if( s_krnlCache )
{
auto it = std::lower_bound( s_krnlCache, s_krnlCache + s_krnlCacheCnt, addr, []( const KernelDriver& lhs, const uint64_t& rhs ) { return lhs.addr > rhs; } );
if( it != s_krnlCache + s_krnlCacheCnt )
{
return ModuleNameAndBaseAddress{ it->mod, it->addr };
}
}
const ImageEntry* entry = s_krnlCache->GetImageForAddress( addr );
if( entry != nullptr ) return ModuleNameAndBaseAddress{ entry->m_name, entry->m_startAddress };
return ModuleNameAndBaseAddress{ "<kernel>", addr };
}
for( auto& v : *s_modCache )
{
if( addr >= v.start && addr < v.end )
{
return ModuleNameAndBaseAddress{ v.name, v.start };
}
}
const ImageEntry* entry = s_imageCache->GetImageForAddress( addr );
if( entry != nullptr ) return ModuleNameAndBaseAddress{ entry->m_name, entry->m_startAddress };
HMODULE mod[1024];
DWORD needed;
HANDLE proc = GetCurrentProcess();
// Do not use FreeLibrary because we set the flag GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
// see https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexa to get more information
constexpr DWORD flag = GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
HMODULE mod = NULL;
InitRpmalloc();
if( EnumProcessModules( proc, mod, sizeof( mod ), &needed ) != 0 )
if( GetModuleHandleExA( flag, (char*)addr, &mod ) != 0 )
{
const auto sz = needed / sizeof( HMODULE );
for( size_t i=0; i<sz; i++ )
MODULEINFO info;
if( GetModuleInformation( proc, mod, &info, sizeof( info ) ) != 0 )
{
MODULEINFO info;
if( GetModuleInformation( proc, mod[i], &info, sizeof( info ) ) != 0 )
const auto base = uint64_t( info.lpBaseOfDll );
if( addr >= base && addr < ( base + info.SizeOfImage ) )
{
const auto base = uint64_t( info.lpBaseOfDll );
if( addr >= base && addr < base + info.SizeOfImage )
char name[1024];
const auto nameLength = GetModuleFileNameA( mod, name, sizeof( name ) );
if( nameLength > 0 )
{
char name[1024];
const auto nameLength = GetModuleFileNameA( mod[i], name, 1021 );
if( nameLength > 0 )
{
// since this is the first time we encounter this module, load its symbols (needed for modules loaded after SymInitialize)
ModuleCache* cachedModule = LoadSymbolsForModuleAndCache( name, nameLength, (DWORD64)info.lpBaseOfDll, info.SizeOfImage );
return ModuleNameAndBaseAddress{ cachedModule->name, cachedModule->start };
}
// since this is the first time we encounter this module, load its symbols (needed for modules loaded after SymInitialize)
ImageEntry* cachedModule = LoadSymbolsForModuleAndCache( name, nameLength, (DWORD64)info.lpBaseOfDll, info.SizeOfImage );
return ModuleNameAndBaseAddress{ cachedModule->m_name, cachedModule->m_startAddress };
}
}
}
@@ -753,7 +827,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
return { cb_data, uint8_t( cb_num ), moduleNameAndAddress.name };
}
#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6
#elif defined(TRACY_USE_LIBBACKTRACE)
enum { MaxCbTrace = 64 };
@@ -762,9 +836,6 @@ struct backtrace_state* cb_bts = nullptr;
int cb_num;
CallstackEntry cb_data[MaxCbTrace];
int cb_fixup;
#ifdef TRACY_USE_IMAGE_CACHE
static ImageCache* s_imageCache = nullptr;
#endif //#ifdef TRACY_USE_IMAGE_CACHE
#ifdef TRACY_DEBUGINFOD
debuginfod_client* s_debuginfod;
@@ -959,10 +1030,9 @@ void InitCallstack()
{
InitRpmalloc();
#ifdef TRACY_USE_IMAGE_CACHE
s_imageCache = (ImageCache*)tracy_malloc( sizeof( ImageCache ) );
new(s_imageCache) ImageCache();
#endif //#ifdef TRACY_USE_IMAGE_CACHE
#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
CreateImageCaches();
#endif //#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
#ifndef TRACY_SYMBOL_OFFLINE_RESOLVE
s_shouldResolveSymbolsOffline = ShouldResolveSymbolsOffline();
@@ -1056,13 +1126,9 @@ debuginfod_client* GetDebuginfodClient()
void EndCallstack()
{
#ifdef TRACY_USE_IMAGE_CACHE
if( s_imageCache )
{
s_imageCache->~ImageCache();
tracy_free( s_imageCache );
}
#endif //#ifdef TRACY_USE_IMAGE_CACHE
#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
DestroyImageCaches();
#endif //#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
#ifndef TRACY_DEMANGLE
___tracy_free_demangle_buffer();
#endif
@@ -1252,17 +1318,17 @@ void GetSymbolForOfflineResolve(void* address, uint64_t imageBaseAddress, Callst
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
{
InitRpmalloc();
if( ptr >> 63 == 0 )
if ( !IsKernelAddress( ptr ) )
{
const char* imageName = nullptr;
uint64_t imageBaseAddress = 0x0;
#ifdef TRACY_USE_IMAGE_CACHE
const auto* image = s_imageCache->GetImageForAddress((void*)ptr);
#ifdef TRACY_HAS_DL_ITERATE_PHDR_TO_REFRESH_IMAGE_CACHE
const auto* image = s_imageCache->GetImageForAddress( ptr );
if( image )
{
imageName = image->m_name;
imageBaseAddress = uint64_t(image->m_startAddress);
imageBaseAddress = uint64_t( image->m_startAddress );
}
#else
Dl_info dlinfo;