1010 *****************************************************************************/
1111
1212#include " StdInc.h"
13+ #include " StackTraceHelpers.h"
1314#include < SharedUtil.Misc.h>
1415#include < game/CGame.h>
1516#include < game/CPools.h>
3132#include < ctime>
3233#include < optional>
3334#include < utility>
35+ #include < mutex>
3436
3537static constexpr DWORD CRASH_EXIT_CODE = 3 ;
3638static constexpr std::size_t LOG_EVENT_SIZE = 200 ;
@@ -118,21 +120,35 @@ namespace
118120 static std::atomic_flag configured = ATOMIC_FLAG_INIT;
119121 if (!configured.test_and_set (std::memory_order_acq_rel))
120122 {
121- SymSetOptions (SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_FAIL_CRITICAL_ERRORS);
123+ SymSetOptions (SYMOPT_LOAD_LINES | SYMOPT_UNDNAME | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_DEFERRED_LOADS );
122124 }
123125 }
126+
127+ std::mutex& GetSymInitMutex () noexcept
128+ {
129+ static std::mutex symMutex;
130+ return symMutex;
131+ }
124132} // namespace
125133
126134class SymbolHandlerGuard
127135{
128136public:
129- explicit SymbolHandlerGuard (HANDLE process) noexcept : m_process(process), m_initialized(false )
137+ explicit SymbolHandlerGuard (HANDLE process, bool enableSymbols ) noexcept : m_process(process), m_initialized(false )
130138 {
139+ if (!enableSymbols)
140+ return ;
141+
131142 if (m_process != nullptr )
132143 {
144+ std::lock_guard<std::mutex> lock{GetSymInitMutex ()};
145+
133146 ConfigureDbgHelpOptions ();
147+
148+ const SString& processDir = SharedUtil::GetProcessBaseDir ();
149+ const char * searchPath = processDir.empty () ? nullptr : processDir.c_str ();
134150
135- if (SymInitialize (m_process, nullptr , TRUE ) != FALSE )
151+ if (SymInitialize (m_process, searchPath , TRUE ) != FALSE )
136152 m_initialized = true ;
137153 }
138154 }
@@ -516,6 +532,15 @@ static void AppendCrashDiagnostics(const SString& text)
516532 if (pException == nullptr || pException->ContextRecord == nullptr )
517533 return false ;
518534
535+ const bool hasSymbols = CrashHandler::ProcessHasLocalDebugSymbols ();
536+ if (!hasSymbols)
537+ {
538+ static std::once_flag logOnce;
539+ std::call_once (logOnce, [] {
540+ SAFE_DEBUG_OUTPUT (" CaptureStackTraceText: capturing without symbols (raw addresses only)\n " );
541+ });
542+ }
543+
519544 // For callback exceptions (0xC000041D), context and stack may be unreliable
520545 const bool isCallbackException = (pException->ExceptionRecord != nullptr &&
521546 pException->ExceptionRecord ->ExceptionCode == 0xC000041D );
@@ -548,9 +573,12 @@ static void AppendCrashDiagnostics(const SString& text)
548573 frame.AddrFrame .Mode = AddrModeFlat;
549574 frame.AddrStack .Mode = AddrModeFlat;
550575
551- SymbolHandlerGuard symbolGuard (hProcess);
552- if (!symbolGuard.IsInitialized ())
553- return false ;
576+ SymbolHandlerGuard symbolGuard (hProcess, hasSymbols);
577+
578+ const bool useDbgHelp = symbolGuard.IsInitialized ();
579+ const auto routines = useDbgHelp
580+ ? StackTraceHelpers::MakeStackWalkRoutines (true )
581+ : StackTraceHelpers::MakeStackWalkRoutines (false );
554582
555583 static_assert (MAX_SYM_NAME > 1 , " MAX_SYM_NAME must include room for a terminator" );
556584 constexpr DWORD kSymbolNameCapacity = MAX_SYM_NAME - 1 ;
@@ -564,8 +592,15 @@ static void AppendCrashDiagnostics(const SString& text)
564592
565593 for (std::size_t frameIndex = 0 ; frameIndex < MAX_FALLBACK_STACK_FRAMES; ++frameIndex)
566594 {
567- BOOL bWalked =
568- StackWalk64 (IMAGE_FILE_MACHINE_I386, hProcess, hThread, &frame, &context, nullptr , SymFunctionTableAccess64, SymGetModuleBase64, nullptr );
595+ BOOL bWalked = StackWalk64 (IMAGE_FILE_MACHINE_I386,
596+ hProcess,
597+ hThread,
598+ &frame,
599+ &context,
600+ routines.readMemory ,
601+ routines.functionTableAccess ,
602+ routines.moduleBase ,
603+ nullptr );
569604 if (bWalked == FALSE )
570605 break ;
571606
@@ -583,23 +618,29 @@ static void AppendCrashDiagnostics(const SString& text)
583618 visitedAddresses[visitedCount++] = address;
584619
585620 SString symbolName = SString (" 0x%llX" , static_cast <unsigned long long >(address));
586- if (SymFromAddr (hProcess, address, nullptr , pSymbol) != FALSE )
621+ if (useDbgHelp && SymFromAddr (hProcess, address, nullptr , pSymbol) != FALSE )
587622 {
588623 const auto terminatorIndex = static_cast <std::size_t >(pSymbol->MaxNameLen );
589624 if (terminatorIndex < MAX_SYM_NAME)
590625 pSymbol->Name [terminatorIndex] = ' \0 ' ;
591626 symbolName = pSymbol->Name ;
592627 }
593628
594- IMAGEHLP_LINE64 lineInfo{};
595- lineInfo.SizeOfStruct = sizeof (IMAGEHLP_LINE64);
629+ IMAGEHLP_LINE64 lineInfo{};
630+ lineInfo.SizeOfStruct = sizeof (IMAGEHLP_LINE64);
596631 DWORD lineDisplacement = 0 ;
597- SString lineDetail = " unknown" ;
598- if (SymGetLineFromAddr64 (hProcess, address, &lineDisplacement, &lineInfo) != FALSE )
632+ SString lineDetail;
633+
634+ if (useDbgHelp && SymGetLineFromAddr64 (hProcess, address, &lineDisplacement, &lineInfo) != FALSE )
599635 {
600636 const char * fileName = lineInfo.FileName != nullptr ? lineInfo.FileName : " unknown" ;
601637 lineDetail = SString (" %s:%lu" , fileName, static_cast <unsigned long >(lineInfo.LineNumber ));
602638 }
639+ else
640+ {
641+ const std::string formatted = StackTraceHelpers::FormatAddressWithModule (address);
642+ lineDetail = formatted.c_str ();
643+ }
603644
604645 outText += SString (" #%02u %s [0x%llX] (%s)\n " , static_cast <unsigned int >(frameIndex), symbolName.c_str (), static_cast <unsigned long long >(address),
605646 lineDetail.c_str ());
0 commit comments