diff --git a/tracy-edit/src/OfflineSymbolResolver.cpp b/tracy-edit/src/OfflineSymbolResolver.cpp index 3788e8b8..9ba7ce71 100644 --- a/tracy-edit/src/OfflineSymbolResolver.cpp +++ b/tracy-edit/src/OfflineSymbolResolver.cpp @@ -11,7 +11,7 @@ #include "OfflineSymbolResolver.h" -bool ApplyPathSubstitutions(std::string& path, const PathSubstitutionList& pathSubstituionlist) +bool ApplyPathSubstitutions( std::string& path, const PathSubstitutionList& pathSubstituionlist ) { for( const auto& substituion : pathSubstituionlist ) { @@ -24,21 +24,15 @@ bool ApplyPathSubstitutions(std::string& path, const PathSubstitutionList& pathS return false; } -// TODO: use string hash map to reduce duplication or use some worker string internal hashing -tracy::StringIdx AddSymbolString(tracy::Worker& worker, const char* str) +tracy::StringIdx AddSymbolString( tracy::Worker& worker, const std::string& str ) { - uint32_t newStringIdx = worker.AddNewString( str ); - return tracy::StringIdx( newStringIdx ); + // TODO: use string hash map to reduce potential string duplication? + tracy::StringLocation location = worker.StoreString( str.c_str(), str.length() ); + return tracy::StringIdx( location.idx ); } -bool PatchSymbols(SymbolResolver* resolver, tracy::Worker& worker, - const PathSubstitutionList& pathSubstituionlist, bool verbose) +bool PatchSymbols( tracy::Worker& worker, const PathSubstitutionList& pathSubstituionlist, bool verbose ) { - if( !resolver ) - { - return false; - } - uint64_t callstackFrameCount = worker.GetCallstackFrameCount(); std::string relativeSoNameMatch = "[unresolved]"; @@ -89,21 +83,19 @@ bool PatchSymbols(SymbolResolver* resolver, tracy::Worker& worker, std::string imagePath = worker.GetString( imageIdx ); FrameEntryList& entries = imageIt->second; - if (!entries.size()) - { - continue; - } + + if( !entries.size() ) continue; std::cout << "Resolving " << entries.size() << " symbols for image: '" << imagePath << "'" << std::endl; - const bool substituted = ApplyPathSubstitutions(imagePath, pathSubstituionlist); - if (substituted) + const bool substituted = ApplyPathSubstitutions( imagePath, pathSubstituionlist ); + if( substituted ) { std::cout << "\tPath substituted to: '" << imagePath << "'" << std::endl; } SymbolEntryList resolvedEntries; - ResolveSymbols( resolver, imagePath, entries, resolvedEntries ); + ResolveSymbols( imagePath, entries, resolvedEntries ); if( resolvedEntries.size() != entries.size() ) { @@ -119,10 +111,8 @@ bool PatchSymbols(SymbolResolver* resolver, tracy::Worker& worker, const SymbolEntry& symbolEntry = resolvedEntries[i]; tracy::CallstackFrame& frame = *frameEntry.frame; - if (!symbolEntry.name.length()) - { - continue; - } + + if( !symbolEntry.name.length() ) continue; if( verbose ) { @@ -131,12 +121,12 @@ bool PatchSymbols(SymbolResolver* resolver, tracy::Worker& worker, << "' -> '" << symbolEntry.name << "'" << std::endl; } - frame.name = AddSymbolString( worker, symbolEntry.name.c_str() ); - const char* newName = worker.GetString(frame.name); + frame.name = AddSymbolString( worker, symbolEntry.name ); + const char* newName = worker.GetString( frame.name ); if( symbolEntry.file.length() ) { - frame.file = AddSymbolString( worker, symbolEntry.file.c_str() ); + frame.file = AddSymbolString( worker, symbolEntry.file ); frame.line = symbolEntry.line; } } diff --git a/tracy-edit/src/OfflineSymbolResolver.h b/tracy-edit/src/OfflineSymbolResolver.h index 26d483a2..4ecc4db2 100644 --- a/tracy-edit/src/OfflineSymbolResolver.h +++ b/tracy-edit/src/OfflineSymbolResolver.h @@ -11,11 +11,6 @@ namespace tracy class Worker; } -class SymbolResolver; - -SymbolResolver* CreateResolver(); -void DestroySymbolResolver(SymbolResolver* resolver); - struct FrameEntry { tracy::CallstackFrame* frame = nullptr; @@ -33,13 +28,11 @@ struct SymbolEntry using SymbolEntryList = std::vector; -bool ResolveSymbols(SymbolResolver* resolver, const std::string& imagePath, - const FrameEntryList& inputEntryList, - SymbolEntryList& resolvedEntries); +bool ResolveSymbols( const std::string& imagePath, const FrameEntryList& inputEntryList, + SymbolEntryList& resolvedEntries ); using PathSubstitutionList = std::vector >; -bool PatchSymbols(SymbolResolver* resolver, tracy::Worker& worker, - const PathSubstitutionList& pathSubstituionlist, bool verbose = false); +bool PatchSymbols( tracy::Worker& worker, const PathSubstitutionList& pathSubstituionlist, bool verbose = false ); #endif // __SYMBOLRESOLVER_HPP__ \ No newline at end of file diff --git a/tracy-edit/src/OfflineSymbolResolverAddr2Line.cpp b/tracy-edit/src/OfflineSymbolResolverAddr2Line.cpp index b35b65b5..4fd0caa0 100644 --- a/tracy-edit/src/OfflineSymbolResolverAddr2Line.cpp +++ b/tracy-edit/src/OfflineSymbolResolverAddr2Line.cpp @@ -10,16 +10,16 @@ #include #include -std::string ExecShellCommand(const char* cmd) +std::string ExecShellCommand( const char* cmd ) { std::array buffer; std::string result; std::unique_ptr pipe(popen(cmd, "r"), pclose); - if (!pipe) + if( !pipe ) { return ""; } - while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) + while( fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr ) { result += buffer.data(); } @@ -29,13 +29,26 @@ std::string ExecShellCommand(const char* cmd) class SymbolResolver { public: - SymbolResolver(const std::string& addr2linePath) - : m_addr2LinePath(addr2linePath) - {} - - bool ResolveSymbols(const std::string& imagePath, const FrameEntryList& inputEntryList, - SymbolEntryList& resolvedEntries) + SymbolResolver( const std::string& addr2linePath ) { + std::stringstream result(ExecShellCommand("which addr2line")); + std::getline(result, m_addr2LinePath); + + if( !m_addr2LinePath.length() ) + { + std::cerr << "'addr2line' was not found in the system, please installed it" << std::endl; + } + else + { + std::cout << "Using 'addr2line' found at: '" << m_addr2LinePath.c_str() << "'" << std::endl; + } + } + + bool ResolveSymbols( const std::string& imagePath, const FrameEntryList& inputEntryList, + SymbolEntryList& resolvedEntries ) + { + if (!m_addr2LinePath.length()) return false; + // generate a single addr2line cmd line for all addresses in one invocation std::stringstream ss; ss << m_addr2LinePath << " -C -f -e " << imagePath << " -a "; @@ -91,34 +104,11 @@ private: std::string m_addr2LinePath; }; -SymbolResolver* CreateResolver() +bool ResolveSymbols( const std::string& imagePath, const FrameEntryList& inputEntryList, + SymbolEntryList& resolvedEntries ) { - 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}; + static SymbolResolver symbolResolver; + return symbolResolver.ResolveSymbols( imagePath, inputEntryList, resolvedEntries ); } -void DestroySymbolResolver(SymbolResolver* resolver) -{ - delete resolver; -} - -bool ResolveSymbols(SymbolResolver* resolver, const std::string& imagePath, - const FrameEntryList& inputEntryList, SymbolEntryList& resolvedEntries) -{ - if (resolver) - { - return resolver->ResolveSymbols( imagePath, inputEntryList, resolvedEntries ); - } - return false; -} - -#endif // #ifndef _WIN32 \ No newline at end of file +#endif // #ifndef _WIN32 diff --git a/tracy-edit/src/OfflineSymbolResolverDbgHelper.cpp b/tracy-edit/src/OfflineSymbolResolverDbgHelper.cpp index 7f5b7c04..20ed2f5e 100644 --- a/tracy-edit/src/OfflineSymbolResolverDbgHelper.cpp +++ b/tracy-edit/src/OfflineSymbolResolverDbgHelper.cpp @@ -23,14 +23,15 @@ public: { m_procHandle = GetCurrentProcess(); - if (!SymInitialize(m_procHandle, NULL, FALSE)) + 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; + const DWORD symopts = SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES; SymSetOptions( symopts ); + m_dbgHelpInitialized = true; } } @@ -39,18 +40,20 @@ public: SymCleanup( m_procHandle ); } - bool ResolveSymbolsForModule(const std::string& imagePath, const FrameEntryList& inputEntryList, - SymbolEntryList& resolvedEntries) + bool ResolveSymbolsForModule( const std::string& imagePath, const FrameEntryList& inputEntryList, + SymbolEntryList& resolvedEntries ) { - ULONG64 moduleBase = SymLoadModuleEx( m_procHandle, NULL, imagePath.c_str(), NULL, 0, 0, NULL, 0); - if (!moduleBase) + if( !m_dbgHelpInitialized ) return false; + + ULONG64 moduleBase = SymLoadModuleEx( m_procHandle, NULL, imagePath.c_str(), NULL, 0, 0, NULL, 0 ); + if( !moduleBase ) { std::cerr << "SymLoadModuleEx() failed for module " << imagePath << ": " << GetLastErrorString() << std::endl; return false; } - for (size_t i = 0; i < inputEntryList.size(); ++i) + for( size_t i = 0; i < inputEntryList.size(); ++i ) { uint64_t offset = inputEntryList[i].symbolOffset; DWORD64 address = moduleBase + offset; @@ -61,7 +64,7 @@ public: SymbolEntry newEntry; - if ( SymFromAddr( m_procHandle, address, NULL, symbolInfo ) ) + if( SymFromAddr( m_procHandle, address, NULL, symbolInfo ) ) { newEntry.name = symbolInfo->Name; //std::cout << "Resolved symbol to: '" << newEntry.name << "'" << std::endl; @@ -84,7 +87,7 @@ public: resolvedEntries.push_back(std::move(newEntry)); } - SymUnloadModule64(m_procHandle, moduleBase); + SymUnloadModule64( m_procHandle, moduleBase ); return true; } @@ -111,32 +114,17 @@ private: return message; } + bool m_dbgHelpInitialized = false; HANDLE m_procHandle = nullptr; }; char SymbolResolver::s_symbolResolutionBuffer[symbolResolutionBufferSize]; - -SymbolResolver* CreateResolver() +bool ResolveSymbols( const std::string& imagePath, const FrameEntryList& inputEntryList, + SymbolEntryList& resolvedEntries ) { - SymbolResolver* resolver = new SymbolResolver(); - return resolver; + static SymbolResolver resolver; + return resolver.ResolveSymbolsForModule( imagePath, inputEntryList, resolvedEntries ); } -void DestroySymbolResolver(SymbolResolver* resolver) -{ - delete resolver; -} - -bool ResolveSymbols(SymbolResolver* resolver, const std::string& imagePath, - const FrameEntryList& inputEntryList, - SymbolEntryList& resolvedEntries) -{ - if( resolver ) - { - return resolver->ResolveSymbolsForModule( imagePath, inputEntryList, resolvedEntries ); - } - return false; -} - -#endif // #ifdef _WIN32 \ No newline at end of file +#endif // #ifdef _WIN32 diff --git a/tracy-edit/src/tracy-edit.cpp b/tracy-edit/src/tracy-edit.cpp index de2e07a2..f79c5dab 100644 --- a/tracy-edit/src/tracy-edit.cpp +++ b/tracy-edit/src/tracy-edit.cpp @@ -177,15 +177,15 @@ int main( int argc, char** argv ) return 0; } -void PatchSymbols(tracy::Worker& worker, const Args& args) +void PatchSymbols( tracy::Worker& worker, const Args& args ) { std::cout << "Resolving and patching symbols..." << std::endl; PathSubstitutionList pathSubstitutionList; - for (const std::string& pathSubst : args.pathSubstitutions) + for( const std::string& pathSubst : args.pathSubstitutions ) { std::size_t pos = pathSubst.find(';'); - if (pos == std::string::npos) + if( pos == std::string::npos ) { std::cerr << "Ignoring invalid path substitution: '" << pathSubst << " '(please separate the regex of the string to replace with a ';')" << std::endl; @@ -194,11 +194,11 @@ void PatchSymbols(tracy::Worker& worker, const Args& args) try { - std::regex reg(pathSubst.substr(0, pos)); - std::string replacementStr(pathSubst.substr(pos + 1)); - pathSubstitutionList.push_back(std::pair(reg, replacementStr)); + std::regex reg( pathSubst.substr(0, pos) ); + std::string replacementStr( pathSubst.substr(pos + 1) ); + pathSubstitutionList.push_back( std::pair(reg, replacementStr) ); } - catch (std::exception& e) + catch( std::exception& e ) { std::cerr << "Ignoring invalid path substitution: '" << pathSubst << "' (" << e.what() << ")" << std::endl; @@ -206,15 +206,8 @@ void PatchSymbols(tracy::Worker& worker, const Args& args) } } - SymbolResolver* resolver = CreateResolver(); - if (resolver) + if( !PatchSymbols( worker, pathSubstitutionList, args.verbose ) ) { - PatchSymbols(resolver, worker, pathSubstitutionList, args.verbose); - - DestroySymbolResolver(resolver); - } - else - { - std::cerr << "Failed to create symbol resolver - skipping resolving" << std::endl; + std::cerr << "Failed to patch symbols" << std::endl; } }