The open source OpenXR runtime
at main 1066 lines 31 kB view raw
1#include <limits> 2#include <new> 3#include <stdio.h> 4#include <string.h> 5#include "TracyCallstack.hpp" 6#include "TracyFastVector.hpp" 7#include "TracyStringHelpers.hpp" 8#include "../common/TracyAlloc.hpp" 9#include "TracyDebug.hpp" 10 11#ifdef TRACY_HAS_CALLSTACK 12 13#if TRACY_HAS_CALLSTACK == 1 14# ifndef NOMINMAX 15# define NOMINMAX 16# endif 17# include <windows.h> 18# include <psapi.h> 19# include <algorithm> 20# ifdef _MSC_VER 21# pragma warning( push ) 22# pragma warning( disable : 4091 ) 23# endif 24# include <dbghelp.h> 25# ifdef _MSC_VER 26# pragma warning( pop ) 27# endif 28#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6 29# include "../libbacktrace/backtrace.hpp" 30# include <algorithm> 31# include <dlfcn.h> 32# include <cxxabi.h> 33# include <stdlib.h> 34# include "TracyFastVector.hpp" 35#elif TRACY_HAS_CALLSTACK == 5 36# include <dlfcn.h> 37# include <cxxabi.h> 38#endif 39 40#ifdef TRACY_DBGHELP_LOCK 41# include "TracyProfiler.hpp" 42 43# define DBGHELP_INIT TracyConcat( TRACY_DBGHELP_LOCK, Init() ) 44# define DBGHELP_LOCK TracyConcat( TRACY_DBGHELP_LOCK, Lock() ); 45# define DBGHELP_UNLOCK TracyConcat( TRACY_DBGHELP_LOCK, Unlock() ); 46 47extern "C" 48{ 49 void DBGHELP_INIT; 50 void DBGHELP_LOCK; 51 void DBGHELP_UNLOCK; 52}; 53#endif 54 55#if TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 5 || TRACY_HAS_CALLSTACK == 6 56// If you want to use your own demangling functionality (e.g. for another language), 57// define TRACY_DEMANGLE and provide your own implementation of the __tracy_demangle 58// function. The input parameter is a function name. The demangle function must 59// identify whether this name is mangled, and fail if it is not. Failure is indicated 60// by returning nullptr. If demangling succeeds, a pointer to the C string containing 61// demangled function must be returned. The demangling function is responsible for 62// managing memory for this string. It is expected that it will be internally reused. 63// When a call to ___tracy_demangle is made, previous contents of the string memory 64// do not need to be preserved. Function may return string of any length, but the 65// profiler can choose to truncate it. 66extern "C" const char* ___tracy_demangle( const char* mangled ); 67 68#ifndef TRACY_DEMANGLE 69constexpr size_t ___tracy_demangle_buffer_len = 1024*1024; 70char* ___tracy_demangle_buffer; 71 72void ___tracy_init_demangle_buffer() 73{ 74 ___tracy_demangle_buffer = (char*)tracy::tracy_malloc( ___tracy_demangle_buffer_len ); 75} 76 77void ___tracy_free_demangle_buffer() 78{ 79 tracy::tracy_free( ___tracy_demangle_buffer ); 80} 81 82extern "C" const char* ___tracy_demangle( const char* mangled ) 83{ 84 if( !mangled || mangled[0] != '_' ) return nullptr; 85 if( strlen( mangled ) > ___tracy_demangle_buffer_len ) return nullptr; 86 int status; 87 size_t len = ___tracy_demangle_buffer_len; 88 return abi::__cxa_demangle( mangled, ___tracy_demangle_buffer, &len, &status ); 89} 90#endif 91#endif 92 93namespace tracy 94{ 95 96#if TRACY_HAS_CALLSTACK == 1 97 98enum { MaxCbTrace = 64 }; 99enum { MaxNameSize = 8*1024 }; 100 101int cb_num; 102CallstackEntry cb_data[MaxCbTrace]; 103 104extern "C" 105{ 106 typedef DWORD (__stdcall *t_SymAddrIncludeInlineTrace)( HANDLE hProcess, DWORD64 Address ); 107 typedef BOOL (__stdcall *t_SymQueryInlineTrace)( HANDLE hProcess, DWORD64 StartAddress, DWORD StartContext, DWORD64 StartRetAddress, DWORD64 CurAddress, LPDWORD CurContext, LPDWORD CurFrameIndex ); 108 typedef BOOL (__stdcall *t_SymFromInlineContext)( HANDLE hProcess, DWORD64 Address, ULONG InlineContext, PDWORD64 Displacement, PSYMBOL_INFO Symbol ); 109 typedef BOOL (__stdcall *t_SymGetLineFromInlineContext)( HANDLE hProcess, DWORD64 qwAddr, ULONG InlineContext, DWORD64 qwModuleBaseAddress, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64 ); 110 111 TRACY_API ___tracy_t_RtlWalkFrameChain ___tracy_RtlWalkFrameChain = 0; 112 t_SymAddrIncludeInlineTrace _SymAddrIncludeInlineTrace = 0; 113 t_SymQueryInlineTrace _SymQueryInlineTrace = 0; 114 t_SymFromInlineContext _SymFromInlineContext = 0; 115 t_SymGetLineFromInlineContext _SymGetLineFromInlineContext = 0; 116} 117 118 119struct ModuleCache 120{ 121 uint64_t start; 122 uint64_t end; 123 char* name; 124}; 125 126static FastVector<ModuleCache>* s_modCache; 127 128 129struct KernelDriver 130{ 131 uint64_t addr; 132 const char* mod; 133 const char* path; 134}; 135 136KernelDriver* s_krnlCache = nullptr; 137size_t s_krnlCacheCnt; 138 139 140void InitCallstackCritical() 141{ 142 ___tracy_RtlWalkFrameChain = (___tracy_t_RtlWalkFrameChain)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "RtlWalkFrameChain" ); 143} 144 145void InitCallstack() 146{ 147 _SymAddrIncludeInlineTrace = (t_SymAddrIncludeInlineTrace)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymAddrIncludeInlineTrace" ); 148 _SymQueryInlineTrace = (t_SymQueryInlineTrace)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymQueryInlineTrace" ); 149 _SymFromInlineContext = (t_SymFromInlineContext)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymFromInlineContext" ); 150 _SymGetLineFromInlineContext = (t_SymGetLineFromInlineContext)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymGetLineFromInlineContext" ); 151 152#ifdef TRACY_DBGHELP_LOCK 153 DBGHELP_INIT; 154 DBGHELP_LOCK; 155#endif 156 157 SymInitialize( GetCurrentProcess(), nullptr, true ); 158 SymSetOptions( SYMOPT_LOAD_LINES ); 159 160 DWORD needed; 161 LPVOID dev[4096]; 162 if( EnumDeviceDrivers( dev, sizeof(dev), &needed ) != 0 ) 163 { 164 char windir[MAX_PATH]; 165 if( !GetWindowsDirectoryA( windir, sizeof( windir ) ) ) memcpy( windir, "c:\\windows", 11 ); 166 const auto windirlen = strlen( windir ); 167 168 const auto sz = needed / sizeof( LPVOID ); 169 s_krnlCache = (KernelDriver*)tracy_malloc( sizeof(KernelDriver) * sz ); 170 int cnt = 0; 171 for( size_t i=0; i<sz; i++ ) 172 { 173 char fn[MAX_PATH]; 174 const auto len = GetDeviceDriverBaseNameA( dev[i], fn, sizeof( fn ) ); 175 if( len != 0 ) 176 { 177 auto buf = (char*)tracy_malloc_fast( len+3 ); 178 buf[0] = '<'; 179 memcpy( buf+1, fn, len ); 180 memcpy( buf+len+1, ">", 2 ); 181 s_krnlCache[cnt] = KernelDriver { (uint64_t)dev[i], buf }; 182 183 const auto len = GetDeviceDriverFileNameA( dev[i], fn, sizeof( fn ) ); 184 if( len != 0 ) 185 { 186 char full[MAX_PATH]; 187 char* path = fn; 188 189 if( memcmp( fn, "\\SystemRoot\\", 12 ) == 0 ) 190 { 191 memcpy( full, windir, windirlen ); 192 strcpy( full + windirlen, fn + 11 ); 193 path = full; 194 } 195 196 SymLoadModuleEx( GetCurrentProcess(), nullptr, path, nullptr, (DWORD64)dev[i], 0, nullptr, 0 ); 197 198 const auto psz = strlen( path ); 199 auto pptr = (char*)tracy_malloc_fast( psz+1 ); 200 memcpy( pptr, path, psz ); 201 pptr[psz] = '\0'; 202 s_krnlCache[cnt].path = pptr; 203 } 204 205 cnt++; 206 } 207 } 208 s_krnlCacheCnt = cnt; 209 std::sort( s_krnlCache, s_krnlCache + s_krnlCacheCnt, []( const KernelDriver& lhs, const KernelDriver& rhs ) { return lhs.addr > rhs.addr; } ); 210 } 211 212 s_modCache = (FastVector<ModuleCache>*)tracy_malloc( sizeof( FastVector<ModuleCache> ) ); 213 new(s_modCache) FastVector<ModuleCache>( 512 ); 214 215 HANDLE proc = GetCurrentProcess(); 216 HMODULE mod[1024]; 217 if( EnumProcessModules( proc, mod, sizeof( mod ), &needed ) != 0 ) 218 { 219 const auto sz = needed / sizeof( HMODULE ); 220 for( size_t i=0; i<sz; i++ ) 221 { 222 MODULEINFO info; 223 if( GetModuleInformation( proc, mod[i], &info, sizeof( info ) ) != 0 ) 224 { 225 const auto base = uint64_t( info.lpBaseOfDll ); 226 char name[1024]; 227 const auto res = GetModuleFileNameA( mod[i], name, 1021 ); 228 if( res > 0 ) 229 { 230 // This may be a new module loaded since our call to SymInitialize. 231 // Just in case, force DbgHelp to load its pdb ! 232 SymLoadModuleEx(proc, NULL, name, NULL, (DWORD64)info.lpBaseOfDll, info.SizeOfImage, NULL, 0); 233 234 auto ptr = name + res; 235 while( ptr > name && *ptr != '\\' && *ptr != '/' ) ptr--; 236 if( ptr > name ) ptr++; 237 const auto namelen = name + res - ptr; 238 auto cache = s_modCache->push_next(); 239 cache->start = base; 240 cache->end = base + info.SizeOfImage; 241 cache->name = (char*)tracy_malloc_fast( namelen+3 ); 242 cache->name[0] = '['; 243 memcpy( cache->name+1, ptr, namelen ); 244 cache->name[namelen+1] = ']'; 245 cache->name[namelen+2] = '\0'; 246 } 247 } 248 } 249 } 250 251#ifdef TRACY_DBGHELP_LOCK 252 DBGHELP_UNLOCK; 253#endif 254} 255 256void EndCallstack() 257{ 258} 259 260const char* DecodeCallstackPtrFast( uint64_t ptr ) 261{ 262 static char ret[MaxNameSize]; 263 const auto proc = GetCurrentProcess(); 264 265 char buf[sizeof( SYMBOL_INFO ) + MaxNameSize]; 266 auto si = (SYMBOL_INFO*)buf; 267 si->SizeOfStruct = sizeof( SYMBOL_INFO ); 268 si->MaxNameLen = MaxNameSize; 269 270#ifdef TRACY_DBGHELP_LOCK 271 DBGHELP_LOCK; 272#endif 273 if( SymFromAddr( proc, ptr, nullptr, si ) == 0 ) 274 { 275 *ret = '\0'; 276 } 277 else 278 { 279 memcpy( ret, si->Name, si->NameLen ); 280 ret[si->NameLen] = '\0'; 281 } 282#ifdef TRACY_DBGHELP_LOCK 283 DBGHELP_UNLOCK; 284#endif 285 return ret; 286} 287 288const char* GetKernelModulePath( uint64_t addr ) 289{ 290 assert( addr >> 63 != 0 ); 291 if( !s_krnlCache ) return nullptr; 292 auto it = std::lower_bound( s_krnlCache, s_krnlCache + s_krnlCacheCnt, addr, []( const KernelDriver& lhs, const uint64_t& rhs ) { return lhs.addr > rhs; } ); 293 if( it == s_krnlCache + s_krnlCacheCnt ) return nullptr; 294 return it->path; 295} 296 297static const char* GetModuleNameAndPrepareSymbols( uint64_t addr ) 298{ 299 if( ( addr >> 63 ) != 0 ) 300 { 301 if( s_krnlCache ) 302 { 303 auto it = std::lower_bound( s_krnlCache, s_krnlCache + s_krnlCacheCnt, addr, []( const KernelDriver& lhs, const uint64_t& rhs ) { return lhs.addr > rhs; } ); 304 if( it != s_krnlCache + s_krnlCacheCnt ) 305 { 306 return it->mod; 307 } 308 } 309 return "<kernel>"; 310 } 311 312 for( auto& v : *s_modCache ) 313 { 314 if( addr >= v.start && addr < v.end ) 315 { 316 return v.name; 317 } 318 } 319 320 HMODULE mod[1024]; 321 DWORD needed; 322 HANDLE proc = GetCurrentProcess(); 323 324 InitRpmalloc(); 325 if( EnumProcessModules( proc, mod, sizeof( mod ), &needed ) != 0 ) 326 { 327 const auto sz = needed / sizeof( HMODULE ); 328 for( size_t i=0; i<sz; i++ ) 329 { 330 MODULEINFO info; 331 if( GetModuleInformation( proc, mod[i], &info, sizeof( info ) ) != 0 ) 332 { 333 const auto base = uint64_t( info.lpBaseOfDll ); 334 if( addr >= base && addr < base + info.SizeOfImage ) 335 { 336 char name[1024]; 337 const auto res = GetModuleFileNameA( mod[i], name, 1021 ); 338 if( res > 0 ) 339 { 340 // since this is the first time we encounter this module, load its symbols (needed for modules loaded after SymInitialize) 341 SymLoadModuleEx(proc, NULL, name, NULL, (DWORD64)info.lpBaseOfDll, info.SizeOfImage, NULL, 0); 342 auto ptr = name + res; 343 while( ptr > name && *ptr != '\\' && *ptr != '/' ) ptr--; 344 if( ptr > name ) ptr++; 345 const auto namelen = name + res - ptr; 346 auto cache = s_modCache->push_next(); 347 cache->start = base; 348 cache->end = base + info.SizeOfImage; 349 cache->name = (char*)tracy_malloc_fast( namelen+3 ); 350 cache->name[0] = '['; 351 memcpy( cache->name+1, ptr, namelen ); 352 cache->name[namelen+1] = ']'; 353 cache->name[namelen+2] = '\0'; 354 return cache->name; 355 } 356 } 357 } 358 } 359 } 360 return "[unknown]"; 361} 362 363CallstackSymbolData DecodeSymbolAddress( uint64_t ptr ) 364{ 365 CallstackSymbolData sym; 366 IMAGEHLP_LINE64 line; 367 DWORD displacement = 0; 368 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 369#ifdef TRACY_DBGHELP_LOCK 370 DBGHELP_LOCK; 371#endif 372 const auto res = SymGetLineFromAddr64( GetCurrentProcess(), ptr, &displacement, &line ); 373 if( res == 0 || line.LineNumber >= 0xF00000 ) 374 { 375 sym.file = "[unknown]"; 376 sym.line = 0; 377 sym.needFree = false; 378 } 379 else 380 { 381 sym.file = CopyString( line.FileName ); 382 sym.line = line.LineNumber; 383 sym.needFree = true; 384 } 385#ifdef TRACY_DBGHELP_LOCK 386 DBGHELP_UNLOCK; 387#endif 388 return sym; 389} 390 391CallstackEntryData DecodeCallstackPtr( uint64_t ptr ) 392{ 393 int write; 394 const auto proc = GetCurrentProcess(); 395 InitRpmalloc(); 396 397#ifdef TRACY_DBGHELP_LOCK 398 DBGHELP_LOCK; 399#endif 400 401 const auto moduleName = GetModuleNameAndPrepareSymbols(ptr); 402 403#if !defined TRACY_NO_CALLSTACK_INLINES 404 BOOL doInline = FALSE; 405 DWORD ctx = 0; 406 DWORD inlineNum = 0; 407 if( _SymAddrIncludeInlineTrace ) 408 { 409 inlineNum = _SymAddrIncludeInlineTrace( proc, ptr ); 410 if( inlineNum > MaxCbTrace - 1 ) inlineNum = MaxCbTrace - 1; 411 DWORD idx; 412 if( inlineNum != 0 ) doInline = _SymQueryInlineTrace( proc, ptr, 0, ptr, ptr, &ctx, &idx ); 413 } 414 if( doInline ) 415 { 416 write = inlineNum; 417 cb_num = 1 + inlineNum; 418 } 419 else 420#endif 421 { 422 write = 0; 423 cb_num = 1; 424 } 425 426 char buf[sizeof( SYMBOL_INFO ) + MaxNameSize]; 427 auto si = (SYMBOL_INFO*)buf; 428 si->SizeOfStruct = sizeof( SYMBOL_INFO ); 429 si->MaxNameLen = MaxNameSize; 430 431 const auto symValid = SymFromAddr( proc, ptr, nullptr, si ) != 0; 432 433 IMAGEHLP_LINE64 line; 434 DWORD displacement = 0; 435 line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 436 437 { 438 const char* filename; 439 const auto res = SymGetLineFromAddr64( proc, ptr, &displacement, &line ); 440 if( res == 0 || line.LineNumber >= 0xF00000 ) 441 { 442 filename = "[unknown]"; 443 cb_data[write].line = 0; 444 } 445 else 446 { 447 filename = line.FileName; 448 cb_data[write].line = line.LineNumber; 449 } 450 451 cb_data[write].name = symValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleName ); 452 cb_data[write].file = CopyStringFast( filename ); 453 if( symValid ) 454 { 455 cb_data[write].symLen = si->Size; 456 cb_data[write].symAddr = si->Address; 457 } 458 else 459 { 460 cb_data[write].symLen = 0; 461 cb_data[write].symAddr = 0; 462 } 463 } 464 465#if !defined TRACY_NO_CALLSTACK_INLINES 466 if( doInline ) 467 { 468 for( DWORD i=0; i<inlineNum; i++ ) 469 { 470 auto& cb = cb_data[i]; 471 const auto symInlineValid = _SymFromInlineContext( proc, ptr, ctx, nullptr, si ) != 0; 472 const char* filename; 473 if( _SymGetLineFromInlineContext( proc, ptr, ctx, 0, &displacement, &line ) == 0 ) 474 { 475 filename = "[unknown]"; 476 cb.line = 0; 477 } 478 else 479 { 480 filename = line.FileName; 481 cb.line = line.LineNumber; 482 } 483 484 cb.name = symInlineValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleName ); 485 cb.file = CopyStringFast( filename ); 486 if( symInlineValid ) 487 { 488 cb.symLen = si->Size; 489 cb.symAddr = si->Address; 490 } 491 else 492 { 493 cb.symLen = 0; 494 cb.symAddr = 0; 495 } 496 497 ctx++; 498 } 499 } 500#endif 501#ifdef TRACY_DBGHELP_LOCK 502 DBGHELP_UNLOCK; 503#endif 504 505 return { cb_data, uint8_t( cb_num ), moduleName }; 506} 507 508#elif TRACY_HAS_CALLSTACK == 2 || TRACY_HAS_CALLSTACK == 3 || TRACY_HAS_CALLSTACK == 4 || TRACY_HAS_CALLSTACK == 6 509 510enum { MaxCbTrace = 64 }; 511 512struct backtrace_state* cb_bts; 513int cb_num; 514CallstackEntry cb_data[MaxCbTrace]; 515int cb_fixup; 516 517#ifdef TRACY_DEBUGINFOD 518debuginfod_client* s_debuginfod; 519 520struct DebugInfo 521{ 522 uint8_t* buildid; 523 size_t buildid_size; 524 char* filename; 525 int fd; 526}; 527 528FastVector<DebugInfo> s_di_known( 16 ); 529#endif 530 531#ifdef __linux 532struct KernelSymbol 533{ 534 uint64_t addr; 535 const char* name; 536 const char* mod; 537}; 538 539KernelSymbol* s_kernelSym = nullptr; 540size_t s_kernelSymCnt; 541 542static void InitKernelSymbols() 543{ 544 FILE* f = fopen( "/proc/kallsyms", "rb" ); 545 if( !f ) return; 546 tracy::FastVector<KernelSymbol> tmpSym( 1024 ); 547 size_t linelen = 16 * 1024; // linelen must be big enough to prevent reallocs in getline() 548 auto linebuf = (char*)tracy_malloc( linelen ); 549 ssize_t sz; 550 while( ( sz = getline( &linebuf, &linelen, f ) ) != -1 ) 551 { 552 auto ptr = linebuf; 553 uint64_t addr = 0; 554 while( *ptr != ' ' ) 555 { 556 auto v = *ptr; 557 if( v >= '0' && v <= '9' ) 558 { 559 v -= '0'; 560 } 561 else if( v >= 'a' && v <= 'f' ) 562 { 563 v -= 'a'; 564 v += 10; 565 } 566 else if( v >= 'A' && v <= 'F' ) 567 { 568 v -= 'A'; 569 v += 10; 570 } 571 else 572 { 573 assert( false ); 574 } 575 assert( ( v & ~0xF ) == 0 ); 576 addr <<= 4; 577 addr |= v; 578 ptr++; 579 } 580 if( addr == 0 ) continue; 581 ptr++; 582 if( *ptr != 'T' && *ptr != 't' ) continue; 583 ptr += 2; 584 const auto namestart = ptr; 585 while( *ptr != '\t' && *ptr != '\n' ) ptr++; 586 const auto nameend = ptr; 587 const char* modstart = nullptr; 588 const char* modend; 589 if( *ptr == '\t' ) 590 { 591 ptr += 2; 592 modstart = ptr; 593 while( *ptr != ']' ) ptr++; 594 modend = ptr; 595 } 596 597 auto strname = (char*)tracy_malloc_fast( nameend - namestart + 1 ); 598 memcpy( strname, namestart, nameend - namestart ); 599 strname[nameend-namestart] = '\0'; 600 601 char* strmod = nullptr; 602 if( modstart ) 603 { 604 strmod = (char*)tracy_malloc_fast( modend - modstart + 1 ); 605 memcpy( strmod, modstart, modend - modstart ); 606 strmod[modend-modstart] = '\0'; 607 } 608 609 auto sym = tmpSym.push_next(); 610 sym->addr = addr; 611 sym->name = strname; 612 sym->mod = strmod; 613 } 614 tracy_free_fast( linebuf ); 615 fclose( f ); 616 if( tmpSym.empty() ) return; 617 618 std::sort( tmpSym.begin(), tmpSym.end(), []( const KernelSymbol& lhs, const KernelSymbol& rhs ) { return lhs.addr > rhs.addr; } ); 619 s_kernelSymCnt = tmpSym.size(); 620 s_kernelSym = (KernelSymbol*)tracy_malloc_fast( sizeof( KernelSymbol ) * s_kernelSymCnt ); 621 memcpy( s_kernelSym, tmpSym.data(), sizeof( KernelSymbol ) * s_kernelSymCnt ); 622 TracyDebug( "Loaded %zu kernel symbols\n", s_kernelSymCnt ); 623} 624#endif 625 626char* NormalizePath( const char* path ) 627{ 628 if( path[0] != '/' ) return nullptr; 629 630 const char* ptr = path; 631 const char* end = path; 632 while( *end ) end++; 633 634 char* res = (char*)tracy_malloc( end - ptr + 1 ); 635 size_t rsz = 0; 636 637 while( ptr < end ) 638 { 639 const char* next = ptr; 640 while( next < end && *next != '/' ) next++; 641 size_t lsz = next - ptr; 642 switch( lsz ) 643 { 644 case 2: 645 if( memcmp( ptr, "..", 2 ) == 0 ) 646 { 647 const char* back = res + rsz - 1; 648 while( back > res && *back != '/' ) back--; 649 rsz = back - res; 650 ptr = next + 1; 651 continue; 652 } 653 break; 654 case 1: 655 if( *ptr == '.' ) 656 { 657 ptr = next + 1; 658 continue; 659 } 660 break; 661 case 0: 662 ptr = next + 1; 663 continue; 664 } 665 if( rsz != 1 ) res[rsz++] = '/'; 666 memcpy( res+rsz, ptr, lsz ); 667 rsz += lsz; 668 ptr = next + 1; 669 } 670 671 if( rsz == 0 ) 672 { 673 memcpy( res, "/", 2 ); 674 } 675 else 676 { 677 res[rsz] = '\0'; 678 } 679 return res; 680} 681 682void InitCallstackCritical() 683{ 684} 685 686void InitCallstack() 687{ 688 cb_bts = backtrace_create_state( nullptr, 0, nullptr, nullptr ); 689 ___tracy_init_demangle_buffer(); 690 691#ifdef __linux 692 InitKernelSymbols(); 693#endif 694#ifdef TRACY_DEBUGINFOD 695 s_debuginfod = debuginfod_begin(); 696#endif 697} 698 699#ifdef TRACY_DEBUGINFOD 700void ClearDebugInfoVector( FastVector<DebugInfo>& vec ) 701{ 702 for( auto& v : vec ) 703 { 704 tracy_free( v.buildid ); 705 tracy_free( v.filename ); 706 if( v.fd >= 0 ) close( v.fd ); 707 } 708 vec.clear(); 709} 710 711DebugInfo* FindDebugInfo( FastVector<DebugInfo>& vec, const uint8_t* buildid_data, size_t buildid_size ) 712{ 713 for( auto& v : vec ) 714 { 715 if( v.buildid_size == buildid_size && memcmp( v.buildid, buildid_data, buildid_size ) == 0 ) 716 { 717 return &v; 718 } 719 } 720 return nullptr; 721} 722 723int GetDebugInfoDescriptor( const char* buildid_data, size_t buildid_size, const char* filename ) 724{ 725 auto buildid = (uint8_t*)buildid_data; 726 auto it = FindDebugInfo( s_di_known, buildid, buildid_size ); 727 if( it ) return it->fd >= 0 ? dup( it->fd ) : -1; 728 729 int fd = debuginfod_find_debuginfo( s_debuginfod, buildid, buildid_size, nullptr ); 730 it = s_di_known.push_next(); 731 it->buildid_size = buildid_size; 732 it->buildid = (uint8_t*)tracy_malloc( buildid_size ); 733 memcpy( it->buildid, buildid, buildid_size ); 734 const auto fnsz = strlen( filename ) + 1; 735 it->filename = (char*)tracy_malloc( fnsz ); 736 memcpy( it->filename, filename, fnsz ); 737 it->fd = fd >= 0 ? fd : -1; 738 TracyDebug( "DebugInfo descriptor query: %i, fn: %s\n", fd, filename ); 739 return it->fd; 740} 741 742const uint8_t* GetBuildIdForImage( const char* image, size_t& size ) 743{ 744 assert( image ); 745 for( auto& v : s_di_known ) 746 { 747 if( strcmp( image, v.filename ) == 0 ) 748 { 749 size = v.buildid_size; 750 return v.buildid; 751 } 752 } 753 return nullptr; 754} 755 756debuginfod_client* GetDebuginfodClient() 757{ 758 return s_debuginfod; 759} 760#endif 761 762void EndCallstack() 763{ 764 ___tracy_free_demangle_buffer(); 765#ifdef TRACY_DEBUGINFOD 766 ClearDebugInfoVector( s_di_known ); 767 debuginfod_end( s_debuginfod ); 768#endif 769} 770 771const char* DecodeCallstackPtrFast( uint64_t ptr ) 772{ 773 static char ret[1024]; 774 auto vptr = (void*)ptr; 775 const char* symname = nullptr; 776 Dl_info dlinfo; 777 if( dladdr( vptr, &dlinfo ) && dlinfo.dli_sname ) 778 { 779 symname = dlinfo.dli_sname; 780 } 781 if( symname ) 782 { 783 strcpy( ret, symname ); 784 } 785 else 786 { 787 *ret = '\0'; 788 } 789 return ret; 790} 791 792static int SymbolAddressDataCb( void* data, uintptr_t pc, uintptr_t lowaddr, const char* fn, int lineno, const char* function ) 793{ 794 auto& sym = *(CallstackSymbolData*)data; 795 if( !fn ) 796 { 797 sym.file = "[unknown]"; 798 sym.line = 0; 799 sym.needFree = false; 800 } 801 else 802 { 803 sym.file = NormalizePath( fn ); 804 if( !sym.file ) sym.file = CopyString( fn ); 805 sym.line = lineno; 806 sym.needFree = true; 807 } 808 809 return 1; 810} 811 812static void SymbolAddressErrorCb( void* data, const char* /*msg*/, int /*errnum*/ ) 813{ 814 auto& sym = *(CallstackSymbolData*)data; 815 sym.file = "[unknown]"; 816 sym.line = 0; 817 sym.needFree = false; 818} 819 820CallstackSymbolData DecodeSymbolAddress( uint64_t ptr ) 821{ 822 CallstackSymbolData sym; 823 backtrace_pcinfo( cb_bts, ptr, SymbolAddressDataCb, SymbolAddressErrorCb, &sym ); 824 return sym; 825} 826 827static int CallstackDataCb( void* /*data*/, uintptr_t pc, uintptr_t lowaddr, const char* fn, int lineno, const char* function ) 828{ 829 cb_data[cb_num].symLen = 0; 830 cb_data[cb_num].symAddr = (uint64_t)lowaddr; 831 832 if( !fn && !function ) 833 { 834 const char* symname = nullptr; 835 auto vptr = (void*)pc; 836 ptrdiff_t symoff = 0; 837 838 Dl_info dlinfo; 839 if( dladdr( vptr, &dlinfo ) ) 840 { 841 symname = dlinfo.dli_sname; 842 symoff = (char*)pc - (char*)dlinfo.dli_saddr; 843 const char* demangled = ___tracy_demangle( symname ); 844 if( demangled ) symname = demangled; 845 } 846 847 if( !symname ) symname = "[unknown]"; 848 849 if( symoff == 0 ) 850 { 851 const auto len = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() ); 852 cb_data[cb_num].name = CopyStringFast( symname, len ); 853 } 854 else 855 { 856 char buf[32]; 857 const auto offlen = sprintf( buf, " + %td", symoff ); 858 const auto namelen = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() - offlen ); 859 auto name = (char*)tracy_malloc_fast( namelen + offlen + 1 ); 860 memcpy( name, symname, namelen ); 861 memcpy( name + namelen, buf, offlen ); 862 name[namelen + offlen] = '\0'; 863 cb_data[cb_num].name = name; 864 } 865 866 cb_data[cb_num].file = CopyStringFast( "[unknown]" ); 867 cb_data[cb_num].line = 0; 868 } 869 else 870 { 871 if( !fn ) fn = "[unknown]"; 872 if( !function ) 873 { 874 function = "[unknown]"; 875 } 876 else 877 { 878 const char* demangled = ___tracy_demangle( function ); 879 if( demangled ) function = demangled; 880 } 881 882 const auto len = std::min<size_t>( strlen( function ), std::numeric_limits<uint16_t>::max() ); 883 cb_data[cb_num].name = CopyStringFast( function, len ); 884 cb_data[cb_num].file = NormalizePath( fn ); 885 if( !cb_data[cb_num].file ) cb_data[cb_num].file = CopyStringFast( fn ); 886 cb_data[cb_num].line = lineno; 887 } 888 889 if( ++cb_num >= MaxCbTrace ) 890 { 891 return 1; 892 } 893 else 894 { 895 return 0; 896 } 897} 898 899static void CallstackErrorCb( void* /*data*/, const char* /*msg*/, int /*errnum*/ ) 900{ 901 for( int i=0; i<cb_num; i++ ) 902 { 903 tracy_free_fast( (void*)cb_data[i].name ); 904 tracy_free_fast( (void*)cb_data[i].file ); 905 } 906 907 cb_data[0].name = CopyStringFast( "[error]" ); 908 cb_data[0].file = CopyStringFast( "[error]" ); 909 cb_data[0].line = 0; 910 911 cb_num = 1; 912} 913 914void SymInfoCallback( void* /*data*/, uintptr_t pc, const char* symname, uintptr_t symval, uintptr_t symsize ) 915{ 916 cb_data[cb_num-1].symLen = (uint32_t)symsize; 917 cb_data[cb_num-1].symAddr = (uint64_t)symval; 918} 919 920void SymInfoError( void* /*data*/, const char* /*msg*/, int /*errnum*/ ) 921{ 922 cb_data[cb_num-1].symLen = 0; 923 cb_data[cb_num-1].symAddr = 0; 924} 925 926CallstackEntryData DecodeCallstackPtr( uint64_t ptr ) 927{ 928 InitRpmalloc(); 929 if( ptr >> 63 == 0 ) 930 { 931 cb_num = 0; 932 backtrace_pcinfo( cb_bts, ptr, CallstackDataCb, CallstackErrorCb, nullptr ); 933 assert( cb_num > 0 ); 934 935 backtrace_syminfo( cb_bts, ptr, SymInfoCallback, SymInfoError, nullptr ); 936 937 const char* symloc = nullptr; 938 Dl_info dlinfo; 939 if( dladdr( (void*)ptr, &dlinfo ) ) symloc = dlinfo.dli_fname; 940 941 return { cb_data, uint8_t( cb_num ), symloc ? symloc : "[unknown]" }; 942 } 943#ifdef __linux 944 else if( s_kernelSym ) 945 { 946 auto it = std::lower_bound( s_kernelSym, s_kernelSym + s_kernelSymCnt, ptr, []( const KernelSymbol& lhs, const uint64_t& rhs ) { return lhs.addr > rhs; } ); 947 if( it != s_kernelSym + s_kernelSymCnt ) 948 { 949 cb_data[0].name = CopyStringFast( it->name ); 950 cb_data[0].file = CopyStringFast( "<kernel>" ); 951 cb_data[0].line = 0; 952 cb_data[0].symLen = 0; 953 cb_data[0].symAddr = it->addr; 954 return { cb_data, 1, it->mod ? it->mod : "<kernel>" }; 955 } 956 } 957#endif 958 959 cb_data[0].name = CopyStringFast( "[unknown]" ); 960 cb_data[0].file = CopyStringFast( "<kernel>" ); 961 cb_data[0].line = 0; 962 cb_data[0].symLen = 0; 963 cb_data[0].symAddr = 0; 964 return { cb_data, 1, "<kernel>" }; 965} 966 967#elif TRACY_HAS_CALLSTACK == 5 968 969void InitCallstackCritical() 970{ 971} 972 973void InitCallstack() 974{ 975 ___tracy_init_demangle_buffer(); 976} 977 978void EndCallstack() 979{ 980 ___tracy_free_demangle_buffer(); 981} 982 983const char* DecodeCallstackPtrFast( uint64_t ptr ) 984{ 985 static char ret[1024]; 986 auto vptr = (void*)ptr; 987 const char* symname = nullptr; 988 Dl_info dlinfo; 989 if( dladdr( vptr, &dlinfo ) && dlinfo.dli_sname ) 990 { 991 symname = dlinfo.dli_sname; 992 } 993 if( symname ) 994 { 995 strcpy( ret, symname ); 996 } 997 else 998 { 999 *ret = '\0'; 1000 } 1001 return ret; 1002} 1003 1004CallstackSymbolData DecodeSymbolAddress( uint64_t ptr ) 1005{ 1006 const char* symloc = nullptr; 1007 Dl_info dlinfo; 1008 if( dladdr( (void*)ptr, &dlinfo ) ) symloc = dlinfo.dli_fname; 1009 if( !symloc ) symloc = "[unknown]"; 1010 return CallstackSymbolData { symloc, 0, false, 0 }; 1011} 1012 1013CallstackEntryData DecodeCallstackPtr( uint64_t ptr ) 1014{ 1015 static CallstackEntry cb; 1016 cb.line = 0; 1017 1018 const char* symname = nullptr; 1019 const char* symloc = nullptr; 1020 auto vptr = (void*)ptr; 1021 ptrdiff_t symoff = 0; 1022 void* symaddr = nullptr; 1023 1024 Dl_info dlinfo; 1025 if( dladdr( vptr, &dlinfo ) ) 1026 { 1027 symloc = dlinfo.dli_fname; 1028 symname = dlinfo.dli_sname; 1029 symoff = (char*)ptr - (char*)dlinfo.dli_saddr; 1030 symaddr = dlinfo.dli_saddr; 1031 const char* demangled = ___tracy_demangle( symname ); 1032 if( demangled ) symname = demangled; 1033 } 1034 1035 if( !symname ) symname = "[unknown]"; 1036 if( !symloc ) symloc = "[unknown]"; 1037 1038 if( symoff == 0 ) 1039 { 1040 const auto len = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() ); 1041 cb.name = CopyString( symname, len ); 1042 } 1043 else 1044 { 1045 char buf[32]; 1046 const auto offlen = sprintf( buf, " + %td", symoff ); 1047 const auto namelen = std::min<size_t>( strlen( symname ), std::numeric_limits<uint16_t>::max() - offlen ); 1048 auto name = (char*)tracy_malloc( namelen + offlen + 1 ); 1049 memcpy( name, symname, namelen ); 1050 memcpy( name + namelen, buf, offlen ); 1051 name[namelen + offlen] = '\0'; 1052 cb.name = name; 1053 } 1054 1055 cb.file = CopyString( "[unknown]" ); 1056 cb.symLen = 0; 1057 cb.symAddr = (uint64_t)symaddr; 1058 1059 return { &cb, 1, symloc }; 1060} 1061 1062#endif 1063 1064} 1065 1066#endif