From 61ee58ba70d9321435f37ca97948131b634e0ea4 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Tue, 5 May 2026 20:00:40 +0200 Subject: [PATCH] Enable resolving plugin symbols in OBS crash reports --- lib/win/advanced-scene-switcher-win.cpp | 82 +++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/lib/win/advanced-scene-switcher-win.cpp b/lib/win/advanced-scene-switcher-win.cpp index 2ba00294..530a3c05 100644 --- a/lib/win/advanced-scene-switcher-win.cpp +++ b/lib/win/advanced-scene-switcher-win.cpp @@ -1,10 +1,12 @@ #include "platform-funcs.hpp" +#include "plugin-state-helpers.hpp" #include #include #include #include #include +#include #include #include #include @@ -16,6 +18,9 @@ #include #include +#define ADVSS_WIDEN_(x) L##x +#define ADVSS_WIDEN(x) ADVSS_WIDEN_(x) + namespace advss { #define MAX_SEARCH 1000 @@ -500,9 +505,86 @@ int SecondsSinceLastInput() return (getTime() - getLastInputTime()) / 1000; } +static void addPluginFolderToSymbolPath() +{ + // This runs after OBS_FRONTEND_EVENT_FINISHED_LOADING, which fires after + // obs_load_all_modules() completes. By that point OBS has already called + // reset_win32_symbol_paths() -> SymInitializeW(), so DbgHelp is + // initialized and we can append our plugins subfolder (where the PDB + // files live) to the existing search path. + HMODULE dbghelp = LoadLibraryW(L"DbgHelp"); + if (!dbghelp) { + return; + } + + typedef BOOL(WINAPI * SymGetSearchPathW_t)(HANDLE, PWSTR, DWORD); + typedef BOOL(WINAPI * SymSetSearchPathW_t)(HANDLE, PCWSTR); + typedef BOOL(WINAPI * SymRefreshModuleList_t)(HANDLE); + + auto symGetSearchPathW = reinterpret_cast( + GetProcAddress(dbghelp, "SymGetSearchPathW")); + auto symSetSearchPathW = reinterpret_cast( + GetProcAddress(dbghelp, "SymSetSearchPathW")); + auto symRefreshModuleList = reinterpret_cast( + GetProcAddress(dbghelp, "SymRefreshModuleList")); + + if (!symGetSearchPathW || !symSetSearchPathW || !symRefreshModuleList) { + FreeLibrary(dbghelp); + return; + } + + HMODULE hModule = NULL; + if (!GetModuleHandleExW( + GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(addPluginFolderToSymbolPath), + &hModule)) { + FreeLibrary(dbghelp); + return; + } + + wchar_t dllDir[MAX_PATH]; + if (!GetModuleFileNameW(hModule, dllDir, MAX_PATH)) { + FreeLibrary(dbghelp); + return; + } + + wchar_t *lastSep = wcsrchr(dllDir, L'\\'); + if (!lastSep) { + FreeLibrary(dbghelp); + return; + } + *lastSep = L'\0'; + + wchar_t pluginsPath[MAX_PATH]; + wcsncpy_s(pluginsPath, MAX_PATH, dllDir, _TRUNCATE); + wcsncat_s(pluginsPath, MAX_PATH, L"\\" ADVSS_WIDEN(ADVSS_PLUGIN_FOLDER), + _TRUNCATE); + + constexpr DWORD currentPathLen = 4096; + constexpr DWORD newPathLen = 8192; + auto currentPath = std::make_unique(currentPathLen); + auto newPath = std::make_unique(newPathLen); + + symGetSearchPathW(GetCurrentProcess(), currentPath.get(), + currentPathLen); + + if (currentPath[0] != L'\0') { + _snwprintf_s(newPath.get(), newPathLen, _TRUNCATE, L"%s;%s", + currentPath.get(), pluginsPath); + } else { + wcsncpy_s(newPath.get(), newPathLen, pluginsPath, _TRUNCATE); + } + + symSetSearchPathW(GetCurrentProcess(), newPath.get()); + symRefreshModuleList(GetCurrentProcess()); + FreeLibrary(dbghelp); +} + void PlatformInit() { CoInitialize(NULL); + AddFinishedLoadingStep(addPluginFolderToSymbolPath); } void PlatformCleanup()