From 1f1d3ab856ffa4c1cd5b5cf1860e7e54887c8212 Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Sun, 30 Aug 2026 16:16:25 +0200 Subject: [PATCH] Resolve external callstacks to the full inline chain. The resolver previously captured only the first pcinfo result, so inline frames were lost, and reported ELF virtual addresses the server could never re-map to the target. Mirror the in-process pcinfo+syminfo flow, and report symAddr as the target VMA (loadBias + ELF vaddr) so the server's re-queries can resolve it. --- public/client/TracyCallstack.cpp | 214 +++++++++++++++---------------- 1 file changed, 103 insertions(+), 111 deletions(-) diff --git a/public/client/TracyCallstack.cpp b/public/client/TracyCallstack.cpp index 831118a9..33fb7c6c 100644 --- a/public/client/TracyCallstack.cpp +++ b/public/client/TracyCallstack.cpp @@ -618,36 +618,6 @@ static backtrace_state* GetExternalBtState( const ExternalImageEntry* entry ) return e->btState; } -struct ExternalResolveData -{ - const char* name; - const char* file; - uint32_t line; - int count; -}; - -static int ExternalPcInfoCb( void* data, uintptr_t pc, uintptr_t lowaddr, const char* filename, int lineno, const char* function ) -{ - auto& rd = *(ExternalResolveData*)data; - - if( rd.count > 0 ) return 1; - rd.count++; - - if( function ) - { - const char* demangled = ___tracy_demangle( function ); - rd.name = demangled ? demangled : function; - } - else - { - rd.name = nullptr; - } - - rd.file = filename; - rd.line = lineno; - - return 0; -} struct ExternalSymInfoData { @@ -1840,104 +1810,126 @@ void GetSymbolForOfflineResolve(void* address, uint64_t imageBaseAddress, Callst } #ifdef __linux__ -CallstackEntryData DecodeCallstackPtrExternal( uint64_t ptr ) +static int ExternalCallstackDataCb( void* data, uintptr_t /*pc*/, uintptr_t lowaddr, const char* fn, int lineno, const char* function ) { - const auto* extImg = FindExternalImageRefresh( ptr ); - if( extImg ) + auto* img = (const ExternalImageEntry*)data; + + cb_data[cb_num].symLen = 0; + cb_data[cb_num].symAddr = (uint64_t)img->loadBias + (uint64_t)lowaddr; + + if( !fn && !function ) { - const char* imageName = extImg->path; - - // Convert VMA (target process virtual address) to ELF virtual address. - // elf_vaddr = vma - load_bias - // libbacktrace indexes DWARF data by ELF virtual address when - // the backtrace_state is created from a file (base_address=0). - const auto elfVaddr = (uintptr_t)( ptr - extImg->loadBias ); - - auto* bts = GetExternalBtState( extImg ); - if( bts ) + // no symbol from pcinfo: name stays null, repaired from the symtab by ResolveExternalCallstack + cb_data[cb_num].name = nullptr; + cb_data[cb_num].file = nullptr; + cb_data[cb_num].line = 0; + } + else + { + if( !fn ) fn = "[unknown]"; + if( !function ) { - // Try DWARF-based resolution - ExternalResolveData rd = {}; - backtrace_pcinfo( bts, elfVaddr, ExternalPcInfoCb, ExternalBacktraceErrorCb, &rd ); + function = "[unknown]"; + } + else + { + const char* demangled = ___tracy_demangle( function ); + if( demangled ) function = demangled; + } - if( rd.name || rd.file ) - { - cb_num = 1; - if( rd.name ) - { - const auto len = std::min( strlen( rd.name ), std::numeric_limits::max() ); - cb_data[0].name = CopyStringFast( rd.name, len ); - } - else - { - cb_data[0].name = CopyStringFast( "[unknown]" ); - } - if( rd.file ) - { - cb_data[0].file = NormalizePath( rd.file ); - if( !cb_data[0].file ) cb_data[0].file = CopyStringFast( rd.file ); - } - else - { - cb_data[0].file = CopyStringFast( "[unknown]" ); - } - cb_data[0].line = rd.line; - cb_data[0].symLen = 0; - cb_data[0].symAddr = elfVaddr; + const auto len = std::min( strlen( function ), std::numeric_limits::max() ); + cb_data[cb_num].name = CopyStringFast( function, len ); + cb_data[cb_num].file = NormalizePath( fn ); + if( !cb_data[cb_num].file ) cb_data[cb_num].file = CopyStringFast( fn ); + cb_data[cb_num].line = lineno; + } - // Try to get symbol size info - ExternalSymInfoData sid = {}; - backtrace_syminfo( bts, elfVaddr, ExternalSymInfoCb, ExternalBacktraceErrorCb, &sid ); - if( sid.symsize > 0 ) - { - cb_data[0].symLen = (uint32_t)sid.symsize; - cb_data[0].symAddr = (uint64_t)sid.symval; - } + if( ++cb_num >= MaxCbTrace ) + { + return 1; + } + else + { + return 0; + } +} - // If DWARF gave us no function name, try the symbol table - if( !rd.name && sid.symname ) - { - tracy_free_fast( (void*)cb_data[0].name ); - const char* demangled = ___tracy_demangle( sid.symname ); - if( demangled ) - { - cb_data[0].name = CopyStringFast( demangled ); - } - else - { - cb_data[0].name = CopyStringFast( sid.symname ); - } - } +static void ExternalPcinfoErrorCb( void* /*data*/, const char* /*msg*/, int /*errnum*/ ) +{ + for( int i=0; ipath ? img->path : "[unknown]"; - // DWARF resolution failed; try symtab-only fallback + const auto elfVaddr = (uintptr_t)( vma - img->loadBias ); + auto* bts = GetExternalBtState( img ); + + if( bts ) + { + cb_num = 0; + backtrace_pcinfo( bts, elfVaddr, ExternalCallstackDataCb, ExternalPcinfoErrorCb, const_cast( img ) ); + + if( cb_num > 0 ) + { ExternalSymInfoData sid = {}; backtrace_syminfo( bts, elfVaddr, ExternalSymInfoCb, ExternalBacktraceErrorCb, &sid ); if( sid.symname ) { - cb_num = 1; - const char* demangled = ___tracy_demangle( sid.symname ); - cb_data[0].name = CopyStringFast( demangled ? demangled : sid.symname ); - cb_data[0].file = CopyStringFast( imageName ? imageName : "[unknown]" ); - cb_data[0].line = 0; - cb_data[0].symLen = (uint32_t)sid.symsize; - cb_data[0].symAddr = (uint64_t)sid.symval; - return { cb_data, 1, imageName ? imageName : "[unknown]" }; + cb_data[cb_num-1].symLen = (uint32_t)sid.symsize; + cb_data[cb_num-1].symAddr = (uint64_t)img->loadBias + (uint64_t)sid.symval; + if( !cb_data[cb_num-1].name ) + { + const char* demangled = ___tracy_demangle( sid.symname ); + cb_data[cb_num-1].name = CopyStringFast( demangled ? demangled : sid.symname ); + cb_data[cb_num-1].file = CopyStringFast( imageName ); + } } + else if( !cb_data[cb_num-1].name ) + { + cb_data[cb_num-1].name = CopyStringFast( "[unresolved]" ); + cb_data[cb_num-1].file = CopyStringFast( imageName ); + cb_data[cb_num-1].symLen = 0; + cb_data[cb_num-1].symAddr = vma; + } + return { cb_data, uint8_t( cb_num ), imageName }; } - // Fallback: return unresolved with offset - cb_num = 1; - cb_data[0].name = CopyStringFast( "[unresolved]" ); - cb_data[0].file = CopyStringFast( imageName ? imageName : "[unknown]" ); - cb_data[0].line = 0; - cb_data[0].symLen = 0; - cb_data[0].symAddr = elfVaddr; - return { cb_data, 1, imageName ? imageName : "[unknown]" }; + ExternalSymInfoData sid = {}; + backtrace_syminfo( bts, elfVaddr, ExternalSymInfoCb, ExternalBacktraceErrorCb, &sid ); + if( sid.symname ) + { + cb_num = 1; + const char* demangled = ___tracy_demangle( sid.symname ); + cb_data[0].name = CopyStringFast( demangled ? demangled : sid.symname ); + cb_data[0].file = CopyStringFast( imageName ); + cb_data[0].line = 0; + cb_data[0].symLen = (uint32_t)sid.symsize; + cb_data[0].symAddr = (uint64_t)img->loadBias + (uint64_t)sid.symval; + return { cb_data, 1, imageName }; + } } + cb_num = 1; + cb_data[0].name = CopyStringFast( "[unresolved]" ); + cb_data[0].file = CopyStringFast( imageName ); + cb_data[0].line = 0; + cb_data[0].symLen = 0; + cb_data[0].symAddr = vma; + return { cb_data, 1, imageName }; +} + +CallstackEntryData DecodeCallstackPtrExternal( uint64_t ptr ) +{ + const auto* extImg = FindExternalImageRefresh( ptr ); + if( extImg ) return ResolveExternalCallstack( extImg, ptr ); + // Address doesn't belong to any known mapping cb_num = 1; cb_data[0].name = CopyStringFast( "[unknown]" );