Add support for offline symbol resolving by setting the "TRACY_SYMBOL_OFFLINE_RESOLVE=1" env var

- Add a tool "tracy-edit" that allows loading a tracy capture, patching symbols and recompress the result
- Add offline symbol resolvers for linux (using addr2line) and windows (using dbghelper)
This commit is contained in:
Tiago Rodrigues 2023-11-17 15:48:17 -05:00 committed by trodrigues
parent 906f73cab3
commit f4f75eac64
15 changed files with 1472 additions and 63 deletions

View File

@ -93,6 +93,14 @@ extern "C" const char* ___tracy_demangle( const char* mangled )
namespace tracy
{
// when "TRACY_SYMBOL_OFFLINE_RESOLVE" is set to "1", instead of fully resolving symbols at runtime,
// simply resolve the offset and image name (which will be enough the resolving to be done offline)
bool getDoOfflineSymbolResolve()
{
const char* symbolOfflineResolve = GetEnvVar( "TRACY_SYMBOL_OFFLINE_RESOLVE" );
return (symbolOfflineResolve && symbolOfflineResolve[0] == '1');
}
#if TRACY_HAS_CALLSTACK == 1
enum { MaxCbTrace = 64 };
@ -135,19 +143,24 @@ struct KernelDriver
KernelDriver* s_krnlCache = nullptr;
size_t s_krnlCacheCnt;
bool s_doOfflineSymbolResolve = false;
void InitCallstackCritical()
{
___tracy_RtlWalkFrameChain = (___tracy_t_RtlWalkFrameChain)GetProcAddress( GetModuleHandleA( "ntdll.dll" ), "RtlWalkFrameChain" );
}
void InitCallstack()
void dbgHelpInit()
{
_SymAddrIncludeInlineTrace = (t_SymAddrIncludeInlineTrace)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymAddrIncludeInlineTrace" );
_SymQueryInlineTrace = (t_SymQueryInlineTrace)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymQueryInlineTrace" );
_SymFromInlineContext = (t_SymFromInlineContext)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymFromInlineContext" );
_SymGetLineFromInlineContext = (t_SymGetLineFromInlineContext)GetProcAddress( GetModuleHandleA( "dbghelp.dll" ), "SymGetLineFromInlineContext" );
if( s_doOfflineSymbolResolve )
{
return;
}
_SymAddrIncludeInlineTrace = (t_SymAddrIncludeInlineTrace)GetProcAddress(GetModuleHandleA("dbghelp.dll"), "SymAddrIncludeInlineTrace");
_SymQueryInlineTrace = (t_SymQueryInlineTrace)GetProcAddress(GetModuleHandleA("dbghelp.dll"), "SymQueryInlineTrace");
_SymFromInlineContext = (t_SymFromInlineContext)GetProcAddress(GetModuleHandleA("dbghelp.dll"), "SymFromInlineContext");
_SymGetLineFromInlineContext = (t_SymGetLineFromInlineContext)GetProcAddress(GetModuleHandleA("dbghelp.dll"), "SymGetLineFromInlineContext");
#ifdef TRACY_DBGHELP_LOCK
DBGHELP_INIT;
@ -157,6 +170,65 @@ void InitCallstack()
SymInitialize( GetCurrentProcess(), nullptr, true );
SymSetOptions( SYMOPT_LOAD_LINES );
#ifdef TRACY_DBGHELP_LOCK
DBGHELP_UNLOCK;
#endif
}
DWORD64 dbgHelpLoadSymbolsForModule(PCSTR imageName, DWORD64 baseOfDll, DWORD bllSize)
{
if( !s_doOfflineSymbolResolve )
{
return SymLoadModuleEx( GetCurrentProcess(), nullptr, imageName, nullptr, baseOfDll, bllSize, nullptr, 0 );
}
return 0x0;
}
ModuleCache* dbgHelpLoadSymbolsForModuleAndCache(PCSTR imageName, DWORD imageNameLength, DWORD64 baseOfDll, DWORD dllSize)
{
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_doOfflineSymbolResolve )
{
cachedModule->name = (char*)tracy_malloc_fast(imageNameLength + 2);
memcpy(cachedModule->name, imageName, imageNameLength);
cachedModule->name[imageNameLength + 1] = '\0';
}
else
{
auto 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;
}
void InitCallstack()
{
s_doOfflineSymbolResolve = getDoOfflineSymbolResolve();
if( s_doOfflineSymbolResolve )
{
TracyDebug("TRACY: enabling offline symbol resolving!\n");
}
dbgHelpInit();
#ifdef TRACY_DBGHELP_LOCK
DBGHELP_LOCK;
#endif
// use TRACY_NO_DBHELP_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
@ -204,7 +276,7 @@ void InitCallstack()
path = full;
}
SymLoadModuleEx( GetCurrentProcess(), nullptr, path, nullptr, (DWORD64)dev[i], 0, nullptr, 0 );
dbgHelpLoadSymbolsForModule( path, (DWORD64)dev[i], 0 );
const auto psz = strlen( path );
auto pptr = (char*)tracy_malloc_fast( psz+1 );
@ -235,25 +307,12 @@ void InitCallstack()
{
const auto base = uint64_t( info.lpBaseOfDll );
char name[1024];
const auto res = GetModuleFileNameA( mod[i], name, 1021 );
if( res > 0 )
const auto nameLength = GetModuleFileNameA( mod[i], name, 1021 );
if( nameLength > 0 )
{
// This may be a new module loaded since our call to SymInitialize.
// Just in case, force DbgHelp to load its pdb !
SymLoadModuleEx(proc, NULL, name, NULL, (DWORD64)info.lpBaseOfDll, info.SizeOfImage, NULL, 0);
auto ptr = name + res;
while( ptr > name && *ptr != '\\' && *ptr != '/' ) ptr--;
if( ptr > name ) ptr++;
const auto namelen = name + res - ptr;
auto cache = s_modCache->push_next();
cache->start = base;
cache->end = base + info.SizeOfImage;
cache->name = (char*)tracy_malloc_fast( namelen+3 );
cache->name[0] = '[';
memcpy( cache->name+1, ptr, namelen );
cache->name[namelen+1] = ']';
cache->name[namelen+2] = '\0';
dbgHelpLoadSymbolsForModuleAndCache( name, nameLength, (DWORD64)info.lpBaseOfDll, info.SizeOfImage );
}
}
}
@ -270,6 +329,11 @@ void EndCallstack()
const char* DecodeCallstackPtrFast( uint64_t ptr )
{
if( s_doOfflineSymbolResolve )
{
return "[unresolved]";
}
static char ret[MaxNameSize];
const auto proc = GetCurrentProcess();
@ -305,7 +369,13 @@ const char* GetKernelModulePath( uint64_t addr )
return it->path;
}
static const char* GetModuleNameAndPrepareSymbols( uint64_t addr )
struct ModuleNameAndBaseAddress
{
const char* name;
uint64_t baseAddr;
};
ModuleNameAndBaseAddress GetModuleNameAndPrepareSymbols( uint64_t addr )
{
if( ( addr >> 63 ) != 0 )
{
@ -314,17 +384,17 @@ static const char* GetModuleNameAndPrepareSymbols( uint64_t addr )
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 it->mod;
return ModuleNameAndBaseAddress{ it->mod, it->addr };
}
}
return "<kernel>";
return ModuleNameAndBaseAddress{ "<kernel>", addr };
}
for( auto& v : *s_modCache )
{
if( addr >= v.start && addr < v.end )
{
return v.name;
return ModuleNameAndBaseAddress{ v.name, v.start };
}
}
@ -345,35 +415,33 @@ static const char* GetModuleNameAndPrepareSymbols( uint64_t addr )
if( addr >= base && addr < base + info.SizeOfImage )
{
char name[1024];
const auto res = GetModuleFileNameA( mod[i], name, 1021 );
if( res > 0 )
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)
SymLoadModuleEx(proc, NULL, name, NULL, (DWORD64)info.lpBaseOfDll, info.SizeOfImage, NULL, 0);
auto ptr = name + res;
while( ptr > name && *ptr != '\\' && *ptr != '/' ) ptr--;
if( ptr > name ) ptr++;
const auto namelen = name + res - ptr;
auto cache = s_modCache->push_next();
cache->start = base;
cache->end = base + info.SizeOfImage;
cache->name = (char*)tracy_malloc_fast( namelen+3 );
cache->name[0] = '[';
memcpy( cache->name+1, ptr, namelen );
cache->name[namelen+1] = ']';
cache->name[namelen+2] = '\0';
return cache->name;
ModuleCache* cachedModule = dbgHelpLoadSymbolsForModuleAndCache( name, nameLength, (DWORD64)info.lpBaseOfDll, info.SizeOfImage );
return ModuleNameAndBaseAddress{ cachedModule->name, cachedModule->start };
}
}
}
}
}
return "[unknown]";
return ModuleNameAndBaseAddress{ "[unknown]", 0x0 };
}
CallstackSymbolData DecodeSymbolAddress( uint64_t ptr )
{
CallstackSymbolData sym;
if( s_doOfflineSymbolResolve )
{
sym.file = "[unknown]";
sym.line = 0;
sym.needFree = false;
return sym;
}
IMAGEHLP_LINE64 line;
DWORD displacement = 0;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
@ -401,16 +469,29 @@ CallstackSymbolData DecodeSymbolAddress( uint64_t ptr )
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
{
InitRpmalloc();
const ModuleNameAndBaseAddress moduleNameAndAddress = GetModuleNameAndPrepareSymbols( ptr );
if( s_doOfflineSymbolResolve )
{
cb_data[0].symAddr = ptr - moduleNameAndAddress.baseAddr;
cb_data[0].symLen = 0;
cb_data[0].name = CopyStringFast("[unresolved]");
cb_data[0].file = CopyStringFast("[unknown]");
cb_data[0].line = 0;
return { cb_data, 1, moduleNameAndAddress.name };
}
int write;
const auto proc = GetCurrentProcess();
InitRpmalloc();
#ifdef TRACY_DBGHELP_LOCK
DBGHELP_LOCK;
#endif
const auto moduleName = GetModuleNameAndPrepareSymbols(ptr);
#if !defined TRACY_NO_CALLSTACK_INLINES
BOOL doInline = FALSE;
DWORD ctx = 0;
@ -459,7 +540,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
cb_data[write].line = line.LineNumber;
}
cb_data[write].name = symValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleName );
cb_data[write].name = symValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleNameAndAddress.name );
cb_data[write].file = CopyStringFast( filename );
if( symValid )
{
@ -492,7 +573,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
cb.line = line.LineNumber;
}
cb.name = symInlineValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleName );
cb.name = symInlineValid ? CopyStringFast( si->Name, si->NameLen ) : CopyStringFast( moduleNameAndAddress.name );
cb.file = CopyStringFast( filename );
if( symInlineValid )
{
@ -513,7 +594,7 @@ CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
DBGHELP_UNLOCK;
#endif
return { cb_data, uint8_t( cb_num ), moduleName };
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
@ -696,7 +777,16 @@ void InitCallstackCritical()
void InitCallstack()
{
cb_bts = backtrace_create_state( nullptr, 0, nullptr, nullptr );
if( getDoOfflineSymbolResolve() )
{
cb_bts = nullptr; // disable use of libbacktrace calls
TracyDebug("TRACY: enabling offline symbol resolving!\n");
}
else
{
cb_bts = backtrace_create_state( nullptr, 0, nullptr, nullptr );
}
#ifndef TRACY_DEMANGLE
___tracy_init_demangle_buffer();
#endif
@ -835,7 +925,15 @@ static void SymbolAddressErrorCb( void* data, const char* /*msg*/, int /*errnum*
CallstackSymbolData DecodeSymbolAddress( uint64_t ptr )
{
CallstackSymbolData sym;
backtrace_pcinfo( cb_bts, ptr, SymbolAddressDataCb, SymbolAddressErrorCb, &sym );
if( cb_bts )
{
backtrace_pcinfo( cb_bts, ptr, SymbolAddressDataCb, SymbolAddressErrorCb, &sym );
}
else
{
SymbolAddressErrorCb(&sym, nullptr, 0);
}
return sym;
}
@ -938,20 +1036,42 @@ void SymInfoError( void* /*data*/, const char* /*msg*/, int /*errnum*/ )
cb_data[cb_num-1].symAddr = 0;
}
void getSymbolForOfflineResolve(void* address, Dl_info& dlinfo, CallstackEntry& cbEntry)
{
// tagged with a string that we can identify as an unresolved symbol
cbEntry.name = CopyStringFast( "[unresolved]" );
// set .so relative offset so it can be resolved offline
cbEntry.symAddr = (uint64_t)address - (uint64_t)(dlinfo.dli_fbase);
cbEntry.symLen = 0x0;
cbEntry.file = CopyStringFast( "[unknown]" );
cbEntry.line = 0;
}
CallstackEntryData DecodeCallstackPtr( uint64_t ptr )
{
InitRpmalloc();
if( ptr >> 63 == 0 )
{
cb_num = 0;
backtrace_pcinfo( cb_bts, ptr, CallstackDataCb, CallstackErrorCb, nullptr );
assert( cb_num > 0 );
backtrace_syminfo( cb_bts, ptr, SymInfoCallback, SymInfoError, nullptr );
const char* symloc = nullptr;
Dl_info dlinfo;
if( dladdr( (void*)ptr, &dlinfo ) ) symloc = dlinfo.dli_fname;
if( dladdr( (void*)ptr, &dlinfo ) )
{
symloc = dlinfo.dli_fname;
}
if(cb_bts)
{
cb_num = 0;
backtrace_pcinfo( cb_bts, ptr, CallstackDataCb, CallstackErrorCb, nullptr );
assert( cb_num > 0 );
backtrace_syminfo( cb_bts, ptr, SymInfoCallback, SymInfoError, nullptr );
}
else
{
cb_num = 1;
getSymbolForOfflineResolve( (void*)ptr, dlinfo, cb_data[0] );
}
return { cb_data, uint8_t( cb_num ), symloc ? symloc : "[unknown]" };
}

View File

@ -553,11 +553,12 @@ Worker::Worker( const char* name, const char* program, const std::vector<ImportE
}
}
Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks )
Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks, bool allowStringModification)
: m_hasData( true )
, m_stream( nullptr )
, m_buffer( nullptr )
, m_inconsistentSamples( false )
, m_allowStringModification(allowStringModification)
{
auto loadStart = std::chrono::high_resolution_clock::now();
@ -707,7 +708,12 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks )
f.Read( sz );
m_data.stringMap.reserve( sz );
m_data.stringData.reserve_exact( sz, m_slab );
if( !m_allowStringModification )
{
m_data.stringData.reserve_exact( sz, m_slab );
}
for( uint64_t i=0; i<sz; i++ )
{
uint64_t ptr, ssz;
@ -716,7 +722,16 @@ Worker::Worker( FileRead& f, EventType::Type eventMask, bool bgTasks )
f.Read( dst, ssz );
dst[ssz] = '\0';
m_data.stringMap.emplace( charutil::StringKey { dst, size_t( ssz ) }, i );
m_data.stringData[i] = ( dst );
if( m_allowStringModification )
{
m_data.stringData.push_back( dst );
}
else
{
m_data.stringData[i] = ( dst );
}
pointerMap.emplace( ptr, dst );
}
@ -2411,6 +2426,19 @@ const char* Worker::GetString( const StringIdx& idx ) const
return m_data.stringData[idx.Idx()];
}
uint32_t Worker::AddNewString(const char* newString)
{
assert(m_allowStringModification);
uint64_t sz = strlen(newString);
auto ptr = m_slab.Alloc<char>( sz+1 );
memcpy( ptr, newString, sz );
ptr[sz] = '\0';
uint32_t idx = m_data.stringData.size();
m_data.stringMap.emplace( charutil::StringKey { ptr, sz }, idx );
m_data.stringData.push_back( ptr );
return idx;
}
static const char* BadExternalThreadNames[] = {
"ntdll.dll",
"???",

View File

@ -446,7 +446,7 @@ public:
Worker( const char* addr, uint16_t port );
Worker( const char* name, const char* program, const std::vector<ImportEventTimeline>& timeline, const std::vector<ImportEventMessages>& messages, const std::vector<ImportEventPlots>& plots, const std::unordered_map<uint64_t, std::string>& threadNames );
Worker( FileRead& f, EventType::Type eventMask = EventType::All, bool bgTasks = true );
Worker( FileRead& f, EventType::Type eventMask = EventType::All, bool bgTasks = true, bool allowStringModification = false);
~Worker();
const std::string& GetAddr() const { return m_addr; }
@ -549,6 +549,8 @@ public:
StringIdx GetLocationForAddress( uint64_t address, uint32_t& line ) const;
const uint64_t* GetInlineSymbolList( uint64_t sym, uint32_t len );
unordered_flat_map<CallstackFrameId, CallstackFrameData*, CallstackFrameIdHash, CallstackFrameIdCompare>& GetCallstackFrameMap() { return m_data.callstackFrameMap; }
#ifndef TRACY_NO_STATISTICS
const VarArray<CallstackFrameId>& GetParentCallstack( uint32_t idx ) const { return *m_data.parentCallstackPayload[idx]; }
const CallstackFrameData* GetParentCallstackFrame( const CallstackFrameId& ptr ) const;
@ -665,6 +667,8 @@ public:
void CacheSourceFiles();
uint32_t AddNewString(const char* newString);
private:
void Network();
void Exec();
@ -984,6 +988,7 @@ private:
bool m_combineSamples;
bool m_identifySamples = false;
bool m_inconsistentSamples;
bool m_allowStringModification = false;
short_ptr<GpuCtxData> m_gpuCtxMap[256];
uint32_t m_pendingCallstackId = 0;

View File

@ -0,0 +1,16 @@
all: release
debug:
@+make -f debug.mk all
release:
@+make -f release.mk all
clean:
@+make -f build.mk clean
db: clean
@bear -- $(MAKE) -f debug.mk all
@mv -f compile_commands.json ../../../
.PHONY: all clean debug release db

View File

@ -0,0 +1,13 @@
CFLAGS +=
CXXFLAGS := $(CFLAGS) -std=gnu++17
DEFINES += -DTRACY_NO_STATISTICS
INCLUDES := -I../../../capstone/include/capstone
LIBS += -lcapstone -lpthread
LDFLAGS := -L../../../capstone
PROJECT := tracy-edit
IMAGE := $(PROJECT)-$(BUILD)
FILTER :=
include ../../../common/src-from-vcxproj.mk
include ../../../common/unix.mk

View File

@ -0,0 +1,6 @@
CFLAGS := -g3 -Wall
DEFINES := -DDEBUG
BUILD := debug
include ../../../common/unix-debug.mk
include build.mk

View File

@ -0,0 +1,9 @@
CFLAGS := -O3
ifndef TRACY_NO_LTO
CFLAGS += -flto
endif
DEFINES := -DNDEBUG
BUILD := release
include ../../../common/unix-release.mk
include build.mk

View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30907.101
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tracy-edit", "tracy-edit.vcxproj", "{447D58BF-94CD-4469-BB90-549C05D03E00}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{447D58BF-94CD-4469-BB90-549C05D03E00}.Debug|x64.ActiveCfg = Debug|x64
{447D58BF-94CD-4469-BB90-549C05D03E00}.Debug|x64.Build.0 = Debug|x64
{447D58BF-94CD-4469-BB90-549C05D03E00}.Release|x64.ActiveCfg = Release|x64
{447D58BF-94CD-4469-BB90-549C05D03E00}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E51386C-43EA-44AC-9F24-AFAFE4D63ADE}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,210 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{447D58BF-94CD-4469-BB90-549C05D03E00}</ProjectGuid>
<RootNamespace>tracy-edit</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
<VcpkgTriplet>x64-windows-static</VcpkgTriplet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<PropertyGroup Label="Vcpkg">
<VcpkgEnableManifest>true</VcpkgEnableManifest>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>TRACY_NO_STATISTICS;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32_LEAN_AND_MEAN;NOMINMAX;_USE_MATH_DEFINES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\vcpkg_installed\$(VcpkgTriplet)\include;$(ProjectDir)..\..\..\vcpkg_installed\$(VcpkgTriplet)\include\capstone;$(VcpkgManifestRoot)\vcpkg_installed\$(VcpkgTriplet)\$(VcpkgTriplet)\include\capstone;$(VcpkgRoot)\installed\$(VcpkgTriplet)\include\capstone</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<AdditionalDependencies>ws2_32.lib;capstone.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\vcpkg_installed\$(VcpkgTriplet)\debug\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<PreprocessorDefinitions>TRACY_NO_STATISTICS;NDEBUG;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_DEPRECATE;WIN32_LEAN_AND_MEAN;NOMINMAX;_USE_MATH_DEFINES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<EnableEnhancedInstructionSet>AdvancedVectorExtensions2</EnableEnhancedInstructionSet>
<LanguageStandard>stdcpplatest</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)..\..\..\vcpkg_installed\$(VcpkgTriplet)\include;$(ProjectDir)..\..\..\vcpkg_installed\$(VcpkgTriplet)\include\capstone;$(VcpkgManifestRoot)\vcpkg_installed\$(VcpkgTriplet)\$(VcpkgTriplet)\include\capstone;$(VcpkgRoot)\installed\$(VcpkgTriplet)\include\capstone</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ws2_32.lib;capstone.lib;dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Console</SubSystem>
<AdditionalLibraryDirectories>$(ProjectDir)..\..\..\vcpkg_installed\$(VcpkgTriplet)\lib</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\..\public\common\TracySocket.cpp" />
<ClCompile Include="..\..\..\public\common\TracyStackFrames.cpp" />
<ClCompile Include="..\..\..\public\common\TracySystem.cpp" />
<ClCompile Include="..\..\..\public\common\tracy_lz4.cpp" />
<ClCompile Include="..\..\..\public\common\tracy_lz4hc.cpp" />
<ClCompile Include="..\..\..\server\TracyMemory.cpp" />
<ClCompile Include="..\..\..\server\TracyMmap.cpp" />
<ClCompile Include="..\..\..\server\TracyTaskDispatch.cpp" />
<ClCompile Include="..\..\..\server\TracyTextureCompression.cpp" />
<ClCompile Include="..\..\..\server\TracyThreadCompress.cpp" />
<ClCompile Include="..\..\..\server\TracyWorker.cpp" />
<ClCompile Include="..\..\..\zstd\common\debug.c" />
<ClCompile Include="..\..\..\zstd\common\entropy_common.c" />
<ClCompile Include="..\..\..\zstd\common\error_private.c" />
<ClCompile Include="..\..\..\zstd\common\fse_decompress.c" />
<ClCompile Include="..\..\..\zstd\common\pool.c" />
<ClCompile Include="..\..\..\zstd\common\threading.c" />
<ClCompile Include="..\..\..\zstd\common\xxhash.c" />
<ClCompile Include="..\..\..\zstd\common\zstd_common.c" />
<ClCompile Include="..\..\..\zstd\compress\fse_compress.c" />
<ClCompile Include="..\..\..\zstd\compress\hist.c" />
<ClCompile Include="..\..\..\zstd\compress\huf_compress.c" />
<ClCompile Include="..\..\..\zstd\compress\zstdmt_compress.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_compress.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_compress_literals.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_compress_sequences.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_compress_superblock.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_double_fast.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_fast.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_lazy.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_ldm.c" />
<ClCompile Include="..\..\..\zstd\compress\zstd_opt.c" />
<ClCompile Include="..\..\..\zstd\decompress\huf_decompress.c" />
<ClCompile Include="..\..\..\zstd\decompress\zstd_ddict.c" />
<ClCompile Include="..\..\..\zstd\decompress\zstd_decompress.c" />
<ClCompile Include="..\..\..\zstd\decompress\zstd_decompress_block.c" />
<ClCompile Include="..\..\..\zstd\dictBuilder\cover.c" />
<ClCompile Include="..\..\..\zstd\dictBuilder\divsufsort.c" />
<ClCompile Include="..\..\..\zstd\dictBuilder\fastcover.c" />
<ClCompile Include="..\..\..\zstd\dictBuilder\zdict.c" />
<ClCompile Include="..\..\src\OfflineSymbolResolver.cpp" />
<ClCompile Include="..\..\src\OfflineSymbolResolverAddr2Line.cpp" />
<ClCompile Include="..\..\src\OfflineSymbolResolverDbgHelper.cpp" />
<ClCompile Include="..\..\src\tracy-edit.cpp" />
<ClCompile Include="..\..\..\getopt\getopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\public\common\TracyAlign.hpp" />
<ClInclude Include="..\..\..\public\common\TracyAlloc.hpp" />
<ClInclude Include="..\..\..\public\common\TracyApi.h" />
<ClInclude Include="..\..\..\public\common\TracyColor.hpp" />
<ClInclude Include="..\..\..\public\common\TracyForceInline.hpp" />
<ClInclude Include="..\..\..\public\common\TracyMutex.hpp" />
<ClInclude Include="..\..\..\public\common\TracyProtocol.hpp" />
<ClInclude Include="..\..\..\public\common\TracyQueue.hpp" />
<ClInclude Include="..\..\..\public\common\TracySocket.hpp" />
<ClInclude Include="..\..\..\public\common\TracyStackFrames.hpp" />
<ClInclude Include="..\..\..\public\common\TracySystem.hpp" />
<ClInclude Include="..\..\..\public\common\TracyUwp.hpp" />
<ClInclude Include="..\..\..\public\common\TracyYield.hpp" />
<ClInclude Include="..\..\..\public\common\tracy_lz4.hpp" />
<ClInclude Include="..\..\..\public\common\tracy_lz4hc.hpp" />
<ClInclude Include="..\..\..\server\TracyCharUtil.hpp" />
<ClInclude Include="..\..\..\server\TracyEvent.hpp" />
<ClInclude Include="..\..\..\server\TracyFileRead.hpp" />
<ClInclude Include="..\..\..\server\TracyFileWrite.hpp" />
<ClInclude Include="..\..\..\server\TracyMemory.hpp" />
<ClInclude Include="..\..\..\server\TracyMmap.hpp" />
<ClInclude Include="..\..\..\server\TracyPopcnt.hpp" />
<ClInclude Include="..\..\..\server\TracySlab.hpp" />
<ClInclude Include="..\..\..\server\TracyTaskDispatch.hpp" />
<ClInclude Include="..\..\..\server\TracyTextureCompression.hpp" />
<ClInclude Include="..\..\..\server\TracyThreadCompress.hpp" />
<ClInclude Include="..\..\..\server\TracyVector.hpp" />
<ClInclude Include="..\..\..\server\TracyWorker.hpp" />
<ClInclude Include="..\..\..\zstd\common\bitstream.h" />
<ClInclude Include="..\..\..\zstd\common\compiler.h" />
<ClInclude Include="..\..\..\zstd\common\cpu.h" />
<ClInclude Include="..\..\..\zstd\common\debug.h" />
<ClInclude Include="..\..\..\zstd\common\error_private.h" />
<ClInclude Include="..\..\..\zstd\common\fse.h" />
<ClInclude Include="..\..\..\zstd\common\huf.h" />
<ClInclude Include="..\..\..\zstd\common\mem.h" />
<ClInclude Include="..\..\..\zstd\common\pool.h" />
<ClInclude Include="..\..\..\zstd\common\portability_macros.h" />
<ClInclude Include="..\..\..\zstd\common\threading.h" />
<ClInclude Include="..\..\..\zstd\common\xxhash.h" />
<ClInclude Include="..\..\..\zstd\common\zstd_deps.h" />
<ClInclude Include="..\..\..\zstd\common\zstd_internal.h" />
<ClInclude Include="..\..\..\zstd\common\zstd_trace.h" />
<ClInclude Include="..\..\..\zstd\compress\clevels.h" />
<ClInclude Include="..\..\..\zstd\compress\hist.h" />
<ClInclude Include="..\..\..\zstd\compress\zstdmt_compress.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_internal.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_literals.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_sequences.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_superblock.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_cwksp.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_double_fast.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_fast.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_lazy.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_ldm.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_ldm_geartab.h" />
<ClInclude Include="..\..\..\zstd\compress\zstd_opt.h" />
<ClInclude Include="..\..\..\zstd\decompress\zstd_ddict.h" />
<ClInclude Include="..\..\..\zstd\decompress\zstd_decompress_block.h" />
<ClInclude Include="..\..\..\zstd\decompress\zstd_decompress_internal.h" />
<ClInclude Include="..\..\..\zstd\dictBuilder\cover.h" />
<ClInclude Include="..\..\..\zstd\dictBuilder\divsufsort.h" />
<ClInclude Include="..\..\..\zstd\zdict.h" />
<ClInclude Include="..\..\..\zstd\zstd.h" />
<ClInclude Include="..\..\..\zstd\zstd_errors.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\zstd\decompress\huf_decompress_amd64.S" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,366 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="src">
<UniqueIdentifier>{729c80ee-4d26-4a5e-8f1f-6c075783eb56}</UniqueIdentifier>
</Filter>
<Filter Include="server">
<UniqueIdentifier>{cf23ef7b-7694-4154-830b-00cf053350ea}</UniqueIdentifier>
</Filter>
<Filter Include="common">
<UniqueIdentifier>{e39d3623-47cd-4752-8da9-3ea324f964c1}</UniqueIdentifier>
</Filter>
<Filter Include="zstd">
<UniqueIdentifier>{9ec18988-3ab7-4c05-a9d0-46c0a68037de}</UniqueIdentifier>
</Filter>
<Filter Include="zstd\common">
<UniqueIdentifier>{5ee9ba63-2914-4027-997e-e743a294bba6}</UniqueIdentifier>
</Filter>
<Filter Include="zstd\compress">
<UniqueIdentifier>{a166d032-7be0-4d07-9f85-a8199cc1ec7c}</UniqueIdentifier>
</Filter>
<Filter Include="zstd\decompress">
<UniqueIdentifier>{438fff23-197c-4b6f-91f0-74f8b3878571}</UniqueIdentifier>
</Filter>
<Filter Include="zstd\dictBuilder">
<UniqueIdentifier>{e5c7021a-e0e4-45c2-b461-e806bc036d5f}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\..\server\TracyMemory.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyWorker.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\src\tracy-edit.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyThreadCompress.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyTaskDispatch.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyMmap.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\..\server\TracyTextureCompression.cpp">
<Filter>server</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\debug.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\entropy_common.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\error_private.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\fse_decompress.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\pool.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\threading.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\xxhash.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\common\zstd_common.c">
<Filter>zstd\common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\fse_compress.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\hist.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\huf_compress.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_compress.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_compress_literals.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_compress_sequences.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_compress_superblock.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_double_fast.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_fast.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_lazy.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_ldm.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstd_opt.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\compress\zstdmt_compress.c">
<Filter>zstd\compress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\decompress\huf_decompress.c">
<Filter>zstd\decompress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\decompress\zstd_ddict.c">
<Filter>zstd\decompress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\decompress\zstd_decompress.c">
<Filter>zstd\decompress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\decompress\zstd_decompress_block.c">
<Filter>zstd\decompress</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\dictBuilder\cover.c">
<Filter>zstd\dictBuilder</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\dictBuilder\divsufsort.c">
<Filter>zstd\dictBuilder</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\dictBuilder\fastcover.c">
<Filter>zstd\dictBuilder</Filter>
</ClCompile>
<ClCompile Include="..\..\..\zstd\dictBuilder\zdict.c">
<Filter>zstd\dictBuilder</Filter>
</ClCompile>
<ClCompile Include="..\..\..\public\common\tracy_lz4.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\public\common\tracy_lz4hc.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\public\common\TracySocket.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\public\common\TracyStackFrames.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\..\public\common\TracySystem.cpp">
<Filter>common</Filter>
</ClCompile>
<ClCompile Include="..\..\src\OfflineSymbolResolver.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\OfflineSymbolResolverAddr2Line.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\src\OfflineSymbolResolverDbgHelper.cpp">
<Filter>src</Filter>
</ClCompile>
<ClCompile Include="..\..\..\getopt\getopt.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\server\TracyCharUtil.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyEvent.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyFileWrite.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyMemory.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyPopcnt.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracySlab.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyVector.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyWorker.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyThreadCompress.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyTaskDispatch.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyFileRead.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyMmap.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\server\TracyTextureCompression.hpp">
<Filter>server</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\zstd.h">
<Filter>zstd</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\zstd_errors.h">
<Filter>zstd</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\bitstream.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\compiler.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\cpu.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\debug.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\error_private.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\fse.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\huf.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\mem.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\pool.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\threading.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\xxhash.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\zstd_deps.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\zstd_internal.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\zstd_trace.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\hist.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_internal.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_literals.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_sequences.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_compress_superblock.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_cwksp.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_double_fast.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_fast.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_lazy.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_ldm.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_ldm_geartab.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstd_opt.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\zstdmt_compress.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\decompress\zstd_ddict.h">
<Filter>zstd\decompress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\decompress\zstd_decompress_block.h">
<Filter>zstd\decompress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\decompress\zstd_decompress_internal.h">
<Filter>zstd\decompress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\zdict.h">
<Filter>zstd</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\dictBuilder\cover.h">
<Filter>zstd\dictBuilder</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\dictBuilder\divsufsort.h">
<Filter>zstd\dictBuilder</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\common\portability_macros.h">
<Filter>zstd\common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\zstd\compress\clevels.h">
<Filter>zstd\compress</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\tracy_lz4.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\tracy_lz4hc.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyAlign.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyAlloc.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyApi.h">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyColor.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyForceInline.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyMutex.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyProtocol.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyQueue.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracySocket.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyStackFrames.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracySystem.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyUwp.hpp">
<Filter>common</Filter>
</ClInclude>
<ClInclude Include="..\..\..\public\common\TracyYield.hpp">
<Filter>common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\..\..\zstd\decompress\huf_decompress_amd64.S">
<Filter>zstd\decompress</Filter>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,123 @@
#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unordered_map>
#include "../../server/TracyWorker.hpp"
#include "../../zstd/zstd.h"
#include "OfflineSymbolResolver.h"
// TODO: use string hash map to reduce duplication or use some worker string internal hashing
tracy::StringIdx AddSymbolString(tracy::Worker& worker, const char* str)
{
uint32_t newStringIdx = worker.AddNewString( str );
return tracy::StringIdx( newStringIdx );
}
bool PatchSymbols(SymbolResolver* resolver, tracy::Worker& worker, bool verbose)
{
if( !resolver )
{
return false;
}
uint64_t callstackFrameCount = worker.GetCallstackFrameCount();
std::string relativeSoNameMatch = "[unresolved]";
std::cout << "Found '" << callstackFrameCount << "' callstack frames. Batching into image groups..." << std::endl;
// batch the symbol queries by .so so we issue the least amount of requests
using FrameEntriesPerImageIdx = std::unordered_map<uint32_t, FrameEntryList>;
FrameEntriesPerImageIdx entriesPerImageIdx;
auto& callstackFrameMap = worker.GetCallstackFrameMap();
for( auto it = callstackFrameMap.begin(); it != callstackFrameMap.end(); ++it )
{
tracy::CallstackFrameData* frameDataPtr = it->second;
if( !frameDataPtr )
{
continue;
}
tracy::CallstackFrameData& frameData = *frameDataPtr;
const char* imageName = worker.GetString( frameData.imageName );
const uint32_t imageNameIdx = frameData.imageName.Idx();
FrameEntryList& entries = entriesPerImageIdx[imageNameIdx];
for( uint8_t f = 0; f < frameData.size; f++ )
{
tracy::CallstackFrame& frame = frameData.data[f];
// TODO: use a better way to identify symbols that are unresolved
const char* nameStr = worker.GetString(frame.name);
if( strncmp( nameStr, relativeSoNameMatch.c_str(), relativeSoNameMatch.length() ) == 0 )
{
// when doing offline resolving we pass the offset from the start of the shared library in the "symAddr"
const uint64_t decodedOffset = frame.symAddr;
entries.push_back( {&frame, decodedOffset} );
}
}
}
std::cout << "Batched into '" << entriesPerImageIdx.size() << "' unique image groups" << std::endl;
// FIXME: the resolving of symbols here can be slow and could be done in parallel per "image"
// - be careful with string allocation though as that would be not safe to do in parallel
for( FrameEntriesPerImageIdx::iterator imageIt = entriesPerImageIdx.begin(),
imageItEnd = entriesPerImageIdx.end(); imageIt != imageItEnd; ++imageIt )
{
tracy::StringIdx imageIdx( imageIt->first );
const char* imageName = worker.GetString( imageIdx );
FrameEntryList& entries = imageIt->second;
std::cout << "Resolving " << entries.size() << " symbols for image: '" << imageName << "'" << std::endl;
if(!entries.size())
{
continue;
}
SymbolEntryList resolvedEntries;
ResolveSymbols( resolver, imageName, entries, resolvedEntries );
if( resolvedEntries.size() != entries.size() )
{
std::cerr << "ERROR: failed to resolve all entries! (got: " << resolvedEntries.size() << ")" << std::endl;
continue;
}
// finally patch the string with the resolved symbol data
for (size_t i = 0; i < resolvedEntries.size(); ++i)
{
FrameEntry& frameEntry = entries[i];
const SymbolEntry& symbolEntry = resolvedEntries[i];
tracy::CallstackFrame& frame = *frameEntry.frame;
if(!symbolEntry.name.length())
continue;
if(verbose)
{
const char* nameStr = worker.GetString(frame.name);
std::cout << "patching '" << nameStr << "' of '" << imageName << "' -> '" << symbolEntry.name << "'" << std::endl;
}
frame.name = AddSymbolString(worker, symbolEntry.name.c_str());
const char* newName = worker.GetString(frame.name);
if(symbolEntry.file.length())
{
frame.file = AddSymbolString(worker, symbolEntry.file.c_str());
frame.line = symbolEntry.line;
}
}
}
return true;
}

View File

@ -0,0 +1,41 @@
#ifndef __SYMBOLRESOLVER_HPP__
#define __SYMBOLRESOLVER_HPP__
#include <string>
#include <vector>
namespace tracy
{
struct CallstackFrame;
class Worker;
}
class SymbolResolver;
SymbolResolver* CreateResolver();
void DestroySymbolResolver(SymbolResolver* resolver);
struct FrameEntry
{
tracy::CallstackFrame* frame = nullptr;
uint64_t symbolOffset = 0;
};
using FrameEntryList = std::vector<FrameEntry>;
struct SymbolEntry
{
std::string name;
std::string file;
int line = 0;
};
using SymbolEntryList = std::vector<SymbolEntry>;
bool ResolveSymbols(SymbolResolver* resolver, const char* imageName,
const FrameEntryList& inputEntryList,
SymbolEntryList& resolvedEntries);
bool PatchSymbols(SymbolResolver* resolver, tracy::Worker& worker, bool verbose = false);
#endif // __SYMBOLRESOLVER_HPP__

View File

@ -0,0 +1,124 @@
#ifdef __linux
#include "OfflineSymbolResolver.h"
#include <fstream>
#include <iostream>
#include <string>
#include <array>
#include <sstream>
#include <memory>
#include <stdio.h>
std::string ExecShellCommand(const char* cmd)
{
std::array<char, 128> buffer;
std::string result;
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe)
{
return "";
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
result += buffer.data();
}
return result;
}
class SymbolResolver
{
public:
SymbolResolver(const std::string& addr2linePath)
: m_addr2LinePath(addr2linePath)
{}
bool ResolveSymbols(const char* imageName, const FrameEntryList& inputEntryList,
SymbolEntryList& resolvedEntries)
{
// generate a single addr2line cmd line for all addresses in one invocation
std::stringstream ss;
ss << m_addr2LinePath << " -C -f -e " << imageName << " -a ";
for (const FrameEntry& entry : inputEntryList)
{
ss << " 0x" << std::hex << entry.symbolOffset;
}
std::string resultStr = ExecShellCommand(ss.str().c_str());
std::stringstream result(resultStr);
//printf("executing: '%s' got '%s'\n", ss.str().c_str(), result.str().c_str());
// The output is 2 lines per entry with the following contents:
// hex_address_of_symbol
// symbol_name
// file:line
for (size_t i = 0; i < inputEntryList.size(); ++i)
{
const FrameEntry& inputEntry = inputEntryList[i];
SymbolEntry newEntry;
std::string addr;
std::getline(result, addr);
std::getline(result, newEntry.name);
if (newEntry.name == "??")
{
newEntry.name = "[unknown] + " + std::to_string(inputEntry.symbolOffset);
}
std::string fileLine;
std::getline(result, fileLine);
if (fileLine != "??:?")
{
size_t pos = fileLine.find_last_of(':');
if (pos != std::string::npos)
{
newEntry.file = fileLine.substr(0, pos);
std::string lineStr = fileLine.substr(pos + 1);
char* after = nullptr;
newEntry.line = strtol(lineStr.c_str(), &after, 10);
}
}
resolvedEntries.push_back(std::move(newEntry));
}
return true;
}
private:
std::string m_addr2LinePath;
};
SymbolResolver* CreateResolver()
{
std::stringstream result(ExecShellCommand("which addr2line"));
std::string addr2LinePath;
std::getline(result, addr2LinePath);
if(!addr2LinePath.length())
{
std::cerr << "'addr2line' was not found in the system, please installed it" << std::endl;
return nullptr;
}
std::cout << "Using 'addr2line' found at: '" << addr2LinePath.c_str() << "'" << std::endl;
return new SymbolResolver{addr2LinePath};
}
void DestroySymbolResolver(SymbolResolver* resolver)
{
delete resolver;
}
bool ResolveSymbols(SymbolResolver* resolver, const char* imageName,
const FrameEntryList& inputEntryList, SymbolEntryList& resolvedEntries)
{
if (resolver)
{
return resolver->ResolveSymbols(imageName, inputEntryList, resolvedEntries);
}
return false;
}
#endif // #ifdef __linux

View File

@ -0,0 +1,142 @@
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <dbghelp.h>
#include <cstdio>
#include <iostream>
#include <stdint.h>
#include <stdlib.h>
#include <windows.h>
#include <string>
#include "OfflineSymbolResolver.h"
class SymbolResolver
{
public:
SymbolResolver()
{
m_procHandle = GetCurrentProcess();
if (!SymInitialize(m_procHandle, NULL, FALSE))
{
std::cerr << "SymInitialize() failed with: " << GetLastErrorString() << std::endl;
}
else
{
const DWORD symopts = SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_DEBUG | SYMOPT_LOAD_LINES;
SymSetOptions( symopts );
}
}
~SymbolResolver()
{
SymCleanup( m_procHandle );
}
bool ResolveSymbolsForModule(const char* fileName, const FrameEntryList& inputEntryList,
SymbolEntryList& resolvedEntries)
{
ULONG64 moduleBase = SymLoadModuleEx( m_procHandle, NULL, fileName, NULL, 0, 0, NULL, 0 );
if (!moduleBase)
{
std::cerr << "SymLoadModuleEx() failed for module " << fileName
<< ": " << GetLastErrorString() << std::endl;
return false;
}
for (size_t i = 0; i < inputEntryList.size(); ++i)
{
uint64_t offset = inputEntryList[i].symbolOffset;
DWORD64 address = moduleBase + offset;
SYMBOL_INFO* symbolInfo = (SYMBOL_INFO*)s_symbolResolutionBuffer;
symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
symbolInfo->MaxNameLen = MAX_SYM_NAME;
SymbolEntry newEntry;
if ( SymFromAddr( m_procHandle, address, NULL, symbolInfo ) )
{
newEntry.name = symbolInfo->Name;
//std::cout << "Resolved symbol to: '" << newEntry.name << "'" << std::endl;
}
else
{
newEntry.name = "[unknown] + " + std::to_string(offset);
}
IMAGEHLP_LINE lineInfo = { 0 };
lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD displaceMent = 0;
if ( SymGetLineFromAddr64( m_procHandle, address, &displaceMent, &lineInfo ) )
{
newEntry.file = lineInfo.FileName;
newEntry.line = int(lineInfo.LineNumber);
///std::cout << "\tline_file: " lineInfo.FileName << ":" << int(lineInfo.LineNumber) << std::endl;
}
resolvedEntries.push_back(std::move(newEntry));
}
SymUnloadModule64(m_procHandle, moduleBase);
return true;
}
private:
static const size_t symbolResolutionBufferSize = sizeof(SYMBOL_INFO) + MAX_SYM_NAME;
static char s_symbolResolutionBuffer[symbolResolutionBufferSize];
std::string GetLastErrorString()
{
DWORD error = GetLastError();
if (error == 0)
{
return "";
}
LPSTR messageBuffer = nullptr;
DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
size_t size = FormatMessageA( dwFlags, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&messageBuffer, 0, NULL );
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
return message;
}
HANDLE m_procHandle = nullptr;
};
char SymbolResolver::s_symbolResolutionBuffer[symbolResolutionBufferSize];
SymbolResolver* CreateResolver()
{
SymbolResolver* resolver = new SymbolResolver();
return resolver;
}
void DestroySymbolResolver(SymbolResolver* resolver)
{
delete resolver;
}
bool ResolveSymbols(SymbolResolver* resolver, const char* imageName,
const FrameEntryList& inputEntryList,
SymbolEntryList& resolvedEntries)
{
if( resolver )
{
return resolver->ResolveSymbolsForModule( imageName, inputEntryList, resolvedEntries );
}
return false;
}
#endif // #ifdef _WIN32

View File

@ -0,0 +1,181 @@
#ifdef _WIN32
# include <windows.h>
#endif
#include <fstream>
#include <iostream>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../../server/TracyFileRead.hpp"
#include "../../server/TracyFileWrite.hpp"
#include "../../server/TracyWorker.hpp"
#include "../../getopt/getopt.h"
#include "OfflineSymbolResolver.h"
struct Args
{
const char* inputTracyPath = nullptr;
const char* outputTracyPath = nullptr;
bool verbose = false;
bool resolveSymbols = false;
tracy::FileWrite::Compression compressionType = tracy::FileWrite::Compression::Zstd;
int compressionLevel = 5;
};
void PrintUsageAndExit()
{
std::cerr << "Modify a tracy file" << std::endl;
std::cerr << "Usage:" << std::endl;
std::cerr << " extract [OPTION...] <input trace file> <output tracy file>" << std::endl;
std::cerr << std::endl;
std::cerr << " -h, --help Print usage" << std::endl;
std::cerr << " -v, --verbose Enable verbose logging" << std::endl;
std::cerr << " -r, --resolveSymbols Resolve symbols and patch callstack frames" << std::endl;
std::cerr << " -c, --compression arg Compress output with the given compression algo" << std::endl;
std::cerr << " -l, --compressesionLevel arg Level of compression" << std::endl;
exit( 1 );
}
static const char* compressionTypeStr[]
{
"Fast",
"Slow",
"Extreme",
"Zstd"
};
static_assert( uint32_t(tracy::FileWrite::Compression::Zstd)+1 == sizeof(compressionTypeStr)/sizeof(compressionTypeStr[0]));
tracy::FileWrite::Compression getCompressionFromString(const char* str)
{
for( uint32_t i = 0; i < sizeof(compressionTypeStr)/sizeof(compressionTypeStr[0]); ++i )
{
if( strcmp( compressionTypeStr[i], str ) == 0 )
{
return tracy::FileWrite::Compression( i );
}
}
return tracy::FileWrite::Compression::Zstd;
}
Args ParseArgs( int argc, char** argv )
{
if ( argc < 3 )
{
PrintUsageAndExit();
}
Args args;
struct option long_opts[] =
{
{ "help", no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' },
{ "resolveSymbols", no_argument, NULL, 'r' },
{ "compression", required_argument, NULL, 'c' },
{ "compressesionLevel", required_argument, NULL, 'l' },
{ NULL, 0, NULL, 0 }
};
int c;
while ( (c = getopt_long( argc, argv, "hvrc:l:", long_opts, NULL )) != -1 )
{
switch (c)
{
case 'h':
PrintUsageAndExit();
break;
case 'v':
args.verbose = true;
break;
case 'r':
args.resolveSymbols = true;
break;
case 'c':
args.compressionType = getCompressionFromString( optarg );
break;
case 'l':
args.compressionLevel = atoi( optarg );
break;
default:
PrintUsageAndExit();
break;
}
}
if (argc != optind + 2)
{
PrintUsageAndExit();
}
args.inputTracyPath = argv[optind + 0];
args.outputTracyPath = argv[optind + 1];
return args;
}
int main( int argc, char** argv )
{
#ifdef _WIN32
if( !AttachConsole( ATTACH_PARENT_PROCESS ) )
{
AllocConsole();
SetConsoleMode( GetStdHandle( STD_OUTPUT_HANDLE ), 0x07 );
}
#endif // #ifdef _WIN32
Args args = ParseArgs( argc, argv );
// load input tracy file
auto f = std::unique_ptr<tracy::FileRead>(tracy::FileRead::Open( args.inputTracyPath ));
if (!f)
{
std::cerr << "Could not open file: " << args.inputTracyPath;
return 1;
}
std::cout << "Reading ..." << std::endl;
const bool allowBgThreads = false;
bool allowStringModification = true;
tracy::Worker worker( *f, tracy::EventType::All, allowBgThreads, allowStringModification );
std::cout << "Loaded." << std::endl;
// attempt to resolve symbols only if requested
if(args.resolveSymbols)
{
std::cout << "Resolving and patching symbols..." << std::endl;
SymbolResolver* resolver = CreateResolver();
if(!resolver)
{
std::cerr << "Failed to create symbol resolver - skipping resolving" << std::endl;
}
else
{
PatchSymbols(resolver, worker);
DestroySymbolResolver(resolver);
}
}
// save out capture file with new compression options
std::cout << "Saving (using '" << compressionTypeStr[uint32_t(args.compressionType)]
<< "', level: " << args.compressionLevel << ") ..." << std::endl;
auto w = std::unique_ptr<tracy::FileWrite>(
tracy::FileWrite::Open( args.outputTracyPath, args.compressionType, args.compressionLevel) );
if( !w )
{
std::cerr << "Cannot open output file: '" << args.outputTracyPath << "'" << std::endl;
exit( 1 );
}
worker.Write( *w, false );
std::cout << "Cleanup..." << std::endl;
return 0;
}