From 98759a63f627657185cc1b37bc7c17cb83dea761 Mon Sep 17 00:00:00 2001 From: Ivan Tustanivskyi Date: Mon, 22 Jun 2026 13:40:57 +0300 Subject: [PATCH] fix(win): resolve correct symbol names in client-side stack traces for multi-module apps --- snapshot/win/process_reader_win.cc | 37 ++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/snapshot/win/process_reader_win.cc b/snapshot/win/process_reader_win.cc index d203f6fd7..923dc07ae 100644 --- a/snapshot/win/process_reader_win.cc +++ b/snapshot/win/process_reader_win.cc @@ -486,8 +486,41 @@ void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) { #ifdef CLIENT_STACKTRACES_ENABLED DWORD options = SymGetOptions(); - SymSetOptions(options | SYMOPT_UNDNAME); - SymInitialize(process_, NULL, TRUE); + SymSetOptions(options | SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS + | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_NO_PROMPTS); + + // Build a dbghelp search path from every loaded module's directory so it + // can find each module's PDB next to its DLL and resolve symbols + std::wstring sym_search_path; + std::vector sym_modules; + if (process_info_.Modules(&sym_modules)) { + std::vector dirs; + for (const auto& module : sym_modules) { + const std::wstring& module_path = module.name; + size_t sep = module_path.find_last_of(L"\\/"); + if (sep == std::wstring::npos || sep == 0) + continue; + std::wstring dir = module_path.substr(0, sep); + bool dup = false; + for (const auto& existing : dirs) { + if (existing.size() == dir.size() + && _wcsicmp(existing.c_str(), dir.c_str()) == 0) { + dup = true; + break; + } + } + if (dup) + continue; + dirs.push_back(dir); + if (!sym_search_path.empty()) + sym_search_path.push_back(L';'); + sym_search_path.append(dir); + } + } + + SymInitializeW(process_, + sym_search_path.empty() ? nullptr : sym_search_path.c_str(), + TRUE); #endif for (unsigned long i = 0; i < process_information->NumberOfThreads; ++i) {