diff --git a/3rdparty/wxWidgets/include/wx/msw/debughlp.h b/3rdparty/wxWidgets/include/wx/msw/debughlp.h index 0728c44f21..133c452b1b 100644 --- a/3rdparty/wxWidgets/include/wx/msw/debughlp.h +++ b/3rdparty/wxWidgets/include/wx/msw/debughlp.h @@ -140,6 +140,7 @@ public: typedef DWORD (WINAPI *SymGetOptions_t)(); typedef DWORD (WINAPI *SymSetOptions_t)(DWORD); typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL); + typedef BOOL (WINAPI *SymRefreshModuleList_t)(HANDLE); typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, LPVOID, PREAD_PROCESS_MEMORY_ROUTINE, PFUNCTION_TABLE_ACCESS_ROUTINE, @@ -184,11 +185,13 @@ public: wxDO_FOR_ALL_SYM_FUNCS(wxDECLARE_SYM_FUNCTION); - #undef wxDECLARE_SYM_FUNCTION - // load all functions from DLL, return true if ok static bool Init(); + // *PCSX2* Should be called before performing a stack trace, as apps may load/unload plugins during + // program execution. + static bool RefreshModuleList(HANDLE hProcess); + // return the string with the error message explaining why Init() failed static const wxString& GetErrorMessage(); @@ -202,6 +205,14 @@ public: static wxString GetSymbolName(PSYMBOL_INFO pSymInfo); private: + // Declared separately since it requires an especially new version of WinDbgHlp + // (v6.5 or later). + wxDECLARE_SYM_FUNCTION(SymRefreshModuleList); + + static bool DoInit(); + + static bool BindFunctions(const wxDynamicLibrary& dllDbgHelp); + // dereference the given symbol, i.e. return symbol which is not a // pointer/reference any more // @@ -222,6 +233,8 @@ private: unsigned level = 0); }; +#undef wxDECLARE_SYM_FUNCTION + #endif // wxUSE_DBGHELP #endif // _WX_MSW_DEBUGHLPH_H_ diff --git a/3rdparty/wxWidgets/src/msw/debughlp.cpp b/3rdparty/wxWidgets/src/msw/debughlp.cpp index c725ef3705..20915c3050 100644 --- a/3rdparty/wxWidgets/src/msw/debughlp.cpp +++ b/3rdparty/wxWidgets/src/msw/debughlp.cpp @@ -42,6 +42,10 @@ static const unsigned MAX_DUMP_DEPTH = 20; // error message from Init() static wxString gs_errMsg; +#if wxUSE_THREADS +wxMutex s_mtx_DbgHelp; +#endif + // ============================================================================ // wxDbgHelpDLL implementation // ============================================================================ @@ -53,6 +57,7 @@ static wxString gs_errMsg; #define DEFINE_SYM_FUNCTION(func) wxDbgHelpDLL::func ## _t wxDbgHelpDLL::func = 0 wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION); +DEFINE_SYM_FUNCTION(SymRefreshModuleList); #undef DEFINE_SYM_FUNCTION @@ -62,12 +67,11 @@ wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION); // load all function we need from the DLL -static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp) +bool wxDbgHelpDLL::BindFunctions(const wxDynamicLibrary& dllDbgHelp) { #define LOAD_SYM_FUNCTION(name) \ - wxDbgHelpDLL::name = (wxDbgHelpDLL::name ## _t) \ - dllDbgHelp.GetSymbol(_T(#name)); \ - if ( !wxDbgHelpDLL::name ) \ + name = (name ## _t)dllDbgHelp.GetSymbol(_T(#name)); \ + if ( !name ) \ { \ gs_errMsg += _T("Function ") _T(#name) _T("() not found.\n"); \ return false; \ @@ -75,25 +79,31 @@ static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp) wxDO_FOR_ALL_SYM_FUNCS(LOAD_SYM_FUNCTION); - #undef LOAD_SYM_FUNCTION + #undef LOAD_SYM_FUNCTION + + // SymRefreshModuleList is bound separately since it requires an especially new version + // of WinDbgHlp (v6.5 or later). If it binds as NULL, that's ok. Its only needed in + // order to reload symbols for apps that dynamically unload/reload plugins. + + SymRefreshModuleList = (SymRefreshModuleList_t)dllDbgHelp.GetSymbol(_T("SymRefreshModuleList")); return true; } // called by Init() if we hadn't done this before -static bool DoInit() +bool wxDbgHelpDLL::DoInit() { wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM); if ( dllDbgHelp.IsLoaded() ) { - if ( BindDbgHelpFunctions(dllDbgHelp) ) + if ( BindFunctions(dllDbgHelp) ) { // turn on default options - DWORD options = wxDbgHelpDLL::SymGetOptions(); + DWORD options = SymGetOptions(); options |= SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_DEBUG; - wxDbgHelpDLL::SymSetOptions(options); + SymSetOptions(options); dllDbgHelp.Detach(); return true; @@ -119,9 +129,13 @@ static bool DoInit() /* static */ bool wxDbgHelpDLL::Init() { - // this flag is -1 until Init() is called for the first time, then it's set - // to either false or true depending on whether we could load the functions - static int s_loaded = -1; + // this flag is -1 until Init() is called for the first time, then it's set + // to either false or true depending on whether we could load the functions + static int s_loaded = -1; + +#if wxUSE_THREADS + wxMutexLocker lock(s_mtx_DbgHelp); +#endif if ( s_loaded == -1 ) { @@ -131,6 +145,42 @@ bool wxDbgHelpDLL::Init() return s_loaded != 0; } +bool wxDbgHelpDLL::RefreshModuleList( HANDLE hProcess ) +{ + static bool s_syms_initialized = false; + +#if wxUSE_THREADS + wxMutexLocker lock(s_mtx_DbgHelp); +#endif + + if ( !s_syms_initialized ) + { + if ( !SymInitialize( + hProcess, + NULL, // use default symbol search path + TRUE // load symbols for all loaded modules + ) ) + { + wxDbgHelpDLL::LogError(_T("SymInitialize")); + return false; + } + + s_syms_initialized = true; + } + else if ( SymRefreshModuleList && !SymRefreshModuleList( hProcess ) ) + { + // If winDbgHlp v6.5 or newer, we can use this to reload symbols on-the-fly. + // If not, then the app could have outdated or unloaded symbols if it dynamically + // loads and unloads modules *and* performs multiple stack traces during the course + // of program execution. + + wxDbgHelpDLL::LogError(_T("SymRefreshModuleList")); + return false; + } + + return true; +} + // ---------------------------------------------------------------------------- // error handling // ---------------------------------------------------------------------------- diff --git a/3rdparty/wxWidgets/src/msw/stackwalk.cpp b/3rdparty/wxWidgets/src/msw/stackwalk.cpp index f6784717d0..96aad0b1cf 100644 --- a/3rdparty/wxWidgets/src/msw/stackwalk.cpp +++ b/3rdparty/wxWidgets/src/msw/stackwalk.cpp @@ -209,6 +209,9 @@ void wxStackFrame::OnGetParam() } } +#if wxUSE_THREADS +static wxMutex s_mtx_StackWalker; +#endif // ---------------------------------------------------------------------------- // wxStackWalker @@ -216,6 +219,14 @@ void wxStackFrame::OnGetParam() void wxStackWalker::WalkFrom(const CONTEXT *pCtx, size_t skip) { +#if wxUSE_THREADS + // wxDbgHelpDLL has its own mutex locks for some critical functions, but really it + // should have locks on ALL its functions. So until it gets fixed, we'll use a + // mutex here for stackframe walking. --air + + wxMutexLocker lock(s_mtx_StackWalker); +#endif + if ( !wxDbgHelpDLL::Init() ) { // don't log a user-visible error message here because the stack trace @@ -233,17 +244,7 @@ void wxStackWalker::WalkFrom(const CONTEXT *pCtx, size_t skip) // below which should be a real handle... so this is what we use const HANDLE hProcess = ::GetCurrentProcess(); - if ( !wxDbgHelpDLL::SymInitialize - ( - hProcess, - NULL, // use default symbol search path - TRUE // load symbols for all loaded modules - ) ) - { - wxDbgHelpDLL::LogError(_T("SymInitialize")); - - return; - } + if ( !wxDbgHelpDLL::RefreshModuleList(hProcess) ) return; CONTEXT ctx = *pCtx; // will be modified by StackWalk()