mirror of https://github.com/PCSX2/pcsx2.git
wxWidgets/Win32:
* Fixed a bug that caused all but the first stackframe walk to fail with an error. * Improved thread safety of stack walking. DevNotes: When walking stackframes multiple times from the same process, only the first stackframe walk would work and all others would fail with an error because of calling SymInitialize multiple times. So now SymInitialize is only called once and SymRefreshModuleList is used prior to walking, if available. (only available in winDbgHlp.dll v6.5 or later) git-svn-id: http://pcsx2.googlecode.com/svn/trunk@3546 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
915983cc71
commit
9c22dc4f73
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Reference in New Issue