created a reusable interface to dbghelp API
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@31414 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
226
include/wx/msw/debughlp.h
Normal file
226
include/wx/msw/debughlp.h
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: wx/msw/wrapdbgh.h
|
||||||
|
// Purpose: wraps dbghelp.h standard file
|
||||||
|
// Author: Vadim Zeitlin
|
||||||
|
// Modified by:
|
||||||
|
// Created: 2005-01-08 (extracted from msw/crashrpt.cpp)
|
||||||
|
// RCS-ID: $Id$
|
||||||
|
// Copyright: (c) 2003-2005 Vadim Zeitlin <vadim@wxwindows.org>
|
||||||
|
// Licence: wxWindows licence
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#ifndef _WX_MSW_DEBUGHLPH_H_
|
||||||
|
#define _WX_MSW_DEBUGHLPH_H_
|
||||||
|
|
||||||
|
#include "wx/dynlib.h"
|
||||||
|
|
||||||
|
#include "wx/msw/wrapwin.h"
|
||||||
|
#include <imagehlp.h>
|
||||||
|
#include "wx/msw/private.h"
|
||||||
|
|
||||||
|
// we need to determine whether we have the declarations for the function in
|
||||||
|
// debughlp.dll version 5.81 (at least) and we check for DBHLPAPI to test this
|
||||||
|
//
|
||||||
|
// reasons:
|
||||||
|
// - VC6 version of imagehlp.h doesn't define it
|
||||||
|
// - VC7 one does
|
||||||
|
// - testing for compiler version doesn't work as you can install and use
|
||||||
|
// the new SDK headers with VC6
|
||||||
|
//
|
||||||
|
// in any case, the user may override by defining wxUSE_DBGHELP himself
|
||||||
|
#ifndef wxUSE_DBGHELP
|
||||||
|
#ifdef DBHLPAPI
|
||||||
|
#define wxUSE_DBGHELP 1
|
||||||
|
#else
|
||||||
|
#define wxUSE_DBGHELP 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if wxUSE_DBGHELP
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxDbgHelpDLL: dynamically load dbghelp.dll functions
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// wrapper for some functions from dbghelp.dll
|
||||||
|
//
|
||||||
|
// MT note: this class is not MT safe and should be only used from a single
|
||||||
|
// thread at a time (this is so because dbghelp.dll is not MT-safe
|
||||||
|
// itself anyhow)
|
||||||
|
class wxDbgHelpDLL
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// some useful constants not present in debughlp.h (stolen from DIA SDK)
|
||||||
|
enum BasicType
|
||||||
|
{
|
||||||
|
BASICTYPE_NOTYPE = 0,
|
||||||
|
BASICTYPE_VOID = 1,
|
||||||
|
BASICTYPE_CHAR = 2,
|
||||||
|
BASICTYPE_WCHAR = 3,
|
||||||
|
BASICTYPE_INT = 6,
|
||||||
|
BASICTYPE_UINT = 7,
|
||||||
|
BASICTYPE_FLOAT = 8,
|
||||||
|
BASICTYPE_BCD = 9,
|
||||||
|
BASICTYPE_BOOL = 10,
|
||||||
|
BASICTYPE_LONG = 13,
|
||||||
|
BASICTYPE_ULONG = 14,
|
||||||
|
BASICTYPE_CURRENCY = 25,
|
||||||
|
BASICTYPE_DATE = 26,
|
||||||
|
BASICTYPE_VARIANT = 27,
|
||||||
|
BASICTYPE_COMPLEX = 28,
|
||||||
|
BASICTYPE_BIT = 29,
|
||||||
|
BASICTYPE_BSTR = 30,
|
||||||
|
BASICTYPE_HRESULT = 31,
|
||||||
|
BASICTYPE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SymbolTag
|
||||||
|
{
|
||||||
|
SYMBOL_TAG_NULL,
|
||||||
|
SYMBOL_TAG_EXE,
|
||||||
|
SYMBOL_TAG_COMPILAND,
|
||||||
|
SYMBOL_TAG_COMPILAND_DETAILS,
|
||||||
|
SYMBOL_TAG_COMPILAND_ENV,
|
||||||
|
SYMBOL_TAG_FUNCTION,
|
||||||
|
SYMBOL_TAG_BLOCK,
|
||||||
|
SYMBOL_TAG_DATA,
|
||||||
|
SYMBOL_TAG_ANNOTATION,
|
||||||
|
SYMBOL_TAG_LABEL,
|
||||||
|
SYMBOL_TAG_PUBLIC_SYMBOL,
|
||||||
|
SYMBOL_TAG_UDT,
|
||||||
|
SYMBOL_TAG_ENUM,
|
||||||
|
SYMBOL_TAG_FUNCTION_TYPE,
|
||||||
|
SYMBOL_TAG_POINTER_TYPE,
|
||||||
|
SYMBOL_TAG_ARRAY_TYPE,
|
||||||
|
SYMBOL_TAG_BASE_TYPE,
|
||||||
|
SYMBOL_TAG_TYPEDEF,
|
||||||
|
SYMBOL_TAG_BASE_CLASS,
|
||||||
|
SYMBOL_TAG_FRIEND,
|
||||||
|
SYMBOL_TAG_FUNCTION_ARG_TYPE,
|
||||||
|
SYMBOL_TAG_FUNC_DEBUG_START,
|
||||||
|
SYMBOL_TAG_FUNC_DEBUG_END,
|
||||||
|
SYMBOL_TAG_USING_NAMESPACE,
|
||||||
|
SYMBOL_TAG_VTABLE_SHAPE,
|
||||||
|
SYMBOL_TAG_VTABLE,
|
||||||
|
SYMBOL_TAG_CUSTOM,
|
||||||
|
SYMBOL_TAG_THUNK,
|
||||||
|
SYMBOL_TAG_CUSTOM_TYPE,
|
||||||
|
SYMBOL_TAG_MANAGED_TYPE,
|
||||||
|
SYMBOL_TAG_DIMENSION,
|
||||||
|
SYMBOL_TAG_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum DataKind
|
||||||
|
{
|
||||||
|
DATA_UNKNOWN,
|
||||||
|
DATA_LOCAL,
|
||||||
|
DATA_STATIC_LOCAL,
|
||||||
|
DATA_PARAM,
|
||||||
|
DATA_OBJECT_PTR, // "this" pointer
|
||||||
|
DATA_FILE_STATIC,
|
||||||
|
DATA_GLOBAL,
|
||||||
|
DATA_MEMBER,
|
||||||
|
DATA_STATIC_MEMBER,
|
||||||
|
DATA_CONSTANT,
|
||||||
|
DATA_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
enum UdtKind
|
||||||
|
{
|
||||||
|
UDT_STRUCT,
|
||||||
|
UDT_CLASS,
|
||||||
|
UDT_UNION,
|
||||||
|
UDT_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// function types
|
||||||
|
typedef DWORD (WINAPI *SymGetOptions_t)();
|
||||||
|
typedef DWORD (WINAPI *SymSetOptions_t)(DWORD);
|
||||||
|
typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL);
|
||||||
|
typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME,
|
||||||
|
LPVOID, PREAD_PROCESS_MEMORY_ROUTINE,
|
||||||
|
PFUNCTION_TABLE_ACCESS_ROUTINE,
|
||||||
|
PGET_MODULE_BASE_ROUTINE,
|
||||||
|
PTRANSLATE_ADDRESS_ROUTINE);
|
||||||
|
typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
|
||||||
|
typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD);
|
||||||
|
typedef DWORD (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD);
|
||||||
|
typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD,
|
||||||
|
PDWORD, PIMAGEHLP_LINE);
|
||||||
|
typedef BOOL (WINAPI *SymSetContext_t)(HANDLE, PIMAGEHLP_STACK_FRAME,
|
||||||
|
PIMAGEHLP_CONTEXT);
|
||||||
|
typedef BOOL (WINAPI *SymEnumSymbols_t)(HANDLE, ULONG64, PCSTR,
|
||||||
|
PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
|
||||||
|
typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG,
|
||||||
|
IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
|
||||||
|
typedef BOOL (WINAPI *SymCleanup_t)(HANDLE);
|
||||||
|
typedef BOOL (WINAPI *EnumerateLoadedModules_t)(HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID);
|
||||||
|
typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE,
|
||||||
|
MINIDUMP_TYPE,
|
||||||
|
CONST PMINIDUMP_EXCEPTION_INFORMATION,
|
||||||
|
CONST PMINIDUMP_USER_STREAM_INFORMATION,
|
||||||
|
CONST PMINIDUMP_CALLBACK_INFORMATION);
|
||||||
|
|
||||||
|
#define wxDO_FOR_ALL_SYM_FUNCS(what) \
|
||||||
|
what(SymGetOptions); \
|
||||||
|
what(SymSetOptions); \
|
||||||
|
what(SymInitialize); \
|
||||||
|
what(StackWalk); \
|
||||||
|
what(SymFromAddr); \
|
||||||
|
what(SymFunctionTableAccess); \
|
||||||
|
what(SymGetModuleBase); \
|
||||||
|
what(SymGetLineFromAddr); \
|
||||||
|
what(SymSetContext); \
|
||||||
|
what(SymEnumSymbols); \
|
||||||
|
what(SymGetTypeInfo); \
|
||||||
|
what(SymCleanup); \
|
||||||
|
what(EnumerateLoadedModules); \
|
||||||
|
what(MiniDumpWriteDump)
|
||||||
|
|
||||||
|
#define wxDECLARE_SYM_FUNCTION(func) static func ## _t func
|
||||||
|
|
||||||
|
wxDO_FOR_ALL_SYM_FUNCS(wxDECLARE_SYM_FUNCTION);
|
||||||
|
|
||||||
|
#undef wxDECLARE_SYM_FUNCTION
|
||||||
|
|
||||||
|
// load all functions from DLL, return true if ok
|
||||||
|
static bool Init();
|
||||||
|
|
||||||
|
// return the string with the error message explaining why Init() failed
|
||||||
|
static const wxString& GetErrorMessage();
|
||||||
|
|
||||||
|
// log error returned by the given function to debug output
|
||||||
|
static void LogError(const wxChar *func);
|
||||||
|
|
||||||
|
// return textual representation of the value of given symbol
|
||||||
|
static wxString DumpSymbol(PSYMBOL_INFO pSymInfo, void *pVariable);
|
||||||
|
|
||||||
|
// return the name of the symbol with given type index
|
||||||
|
static wxString GetSymbolName(PSYMBOL_INFO pSymInfo);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// dereference the given symbol, i.e. return symbol which is not a
|
||||||
|
// pointer/reference any more
|
||||||
|
//
|
||||||
|
// if ppData != NULL, dereference the pointer as many times as we
|
||||||
|
// dereferenced the symbol
|
||||||
|
//
|
||||||
|
// return the tag of the dereferenced symbol
|
||||||
|
static SymbolTag DereferenceSymbol(PSYMBOL_INFO pSymInfo, void **ppData);
|
||||||
|
|
||||||
|
static wxString DumpField(PSYMBOL_INFO pSymInfo,
|
||||||
|
void *pVariable,
|
||||||
|
unsigned level);
|
||||||
|
|
||||||
|
static wxString DumpBaseType(BasicType bt, DWORD64 length, void *pVariable);
|
||||||
|
|
||||||
|
static wxString DumpUDT(PSYMBOL_INFO pSymInfo,
|
||||||
|
void *pVariable,
|
||||||
|
unsigned level = 0);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // wxUSE_DBGHELP
|
||||||
|
|
||||||
|
#endif // _WX_MSW_DEBUGHLPH_H_
|
||||||
|
|
716
src/msw/debughlp.cpp
Normal file
716
src/msw/debughlp.cpp
Normal file
@@ -0,0 +1,716 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Name: msw/debughlp.cpp
|
||||||
|
// Purpose: various Win32 debug helpers
|
||||||
|
// Author: Vadim Zeitlin
|
||||||
|
// Modified by:
|
||||||
|
// Created: 2005-01-08 (extracted from crashrpt.cpp)
|
||||||
|
// RCS-ID: $Id$
|
||||||
|
// Copyright: (c) 2003-2005 Vadim Zeitlin <vadim@wxwindows.org>
|
||||||
|
// Licence: wxWindows licence
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// declarations
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// headers
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include "wx/wxprec.h"
|
||||||
|
|
||||||
|
#ifdef __BORLANDC__
|
||||||
|
#pragma hdrstop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "wx/msw/debughlp.h"
|
||||||
|
|
||||||
|
#if wxUSE_DBGHELP
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// globals
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// error message from Init()
|
||||||
|
static wxString gs_errMsg;
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// wxDbgHelpDLL implementation
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// static members
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define DEFINE_SYM_FUNCTION(func) wxDbgHelpDLL::func ## _t wxDbgHelpDLL::func = 0
|
||||||
|
|
||||||
|
wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION);
|
||||||
|
|
||||||
|
#undef DEFINE_SYM_FUNCTION
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// initialization methods
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// load all function we need from the DLL
|
||||||
|
|
||||||
|
static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
|
||||||
|
{
|
||||||
|
#define LOAD_SYM_FUNCTION(name) \
|
||||||
|
wxDbgHelpDLL::name = (wxDbgHelpDLL::name ## _t) \
|
||||||
|
dllDbgHelp.GetSymbol(_T(#name)); \
|
||||||
|
if ( !wxDbgHelpDLL::name ) \
|
||||||
|
{ \
|
||||||
|
gs_errMsg += _T("Function ") _T(#name) _T("() not found.\n"); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDO_FOR_ALL_SYM_FUNCS(LOAD_SYM_FUNCTION);
|
||||||
|
|
||||||
|
#undef LOAD_SYM_FUNCTION
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// called by Init() if we hadn't done this before
|
||||||
|
static bool DoInit()
|
||||||
|
{
|
||||||
|
wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM);
|
||||||
|
if ( dllDbgHelp.IsLoaded() )
|
||||||
|
{
|
||||||
|
if ( BindDbgHelpFunctions(dllDbgHelp) )
|
||||||
|
{
|
||||||
|
// turn on default options
|
||||||
|
DWORD options = wxDbgHelpDLL::SymGetOptions();
|
||||||
|
|
||||||
|
options |= SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_DEBUG;
|
||||||
|
|
||||||
|
wxDbgHelpDLL::SymSetOptions(options);
|
||||||
|
|
||||||
|
dllDbgHelp.Detach();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
gs_errMsg += _T("\nPlease update your dbghelp.dll version, ")
|
||||||
|
_T("at least version 5.1 is needed!\n")
|
||||||
|
_T("(if you already have a new version, please ")
|
||||||
|
_T("put it in the same directory where the program is.)\n");
|
||||||
|
}
|
||||||
|
else // failed to load dbghelp.dll
|
||||||
|
{
|
||||||
|
gs_errMsg += _T("Please install dbghelp.dll available free of charge ")
|
||||||
|
_T("from Microsoft to get more detailed crash information!");
|
||||||
|
}
|
||||||
|
|
||||||
|
gs_errMsg += _T("\nLatest dbghelp.dll is available at ")
|
||||||
|
_T("http://www.microsoft.com/whdc/ddk/debugging/\n");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
if ( s_loaded == -1 )
|
||||||
|
{
|
||||||
|
s_loaded = DoInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_loaded != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// error handling
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
const wxString& wxDbgHelpDLL::GetErrorMessage()
|
||||||
|
{
|
||||||
|
return gs_errMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
void wxDbgHelpDLL::LogError(const wxChar *func)
|
||||||
|
{
|
||||||
|
::OutputDebugString(wxString::Format(_T("dbghelp: %s() failed: %s\r\n"),
|
||||||
|
func, wxSysErrorMsg(::GetLastError())));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// data dumping
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static inline
|
||||||
|
bool
|
||||||
|
DoGetTypeInfo(DWORD64 base, ULONG ti, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc)
|
||||||
|
{
|
||||||
|
static HANDLE s_hProcess = ::GetCurrentProcess();
|
||||||
|
|
||||||
|
return wxDbgHelpDLL::SymGetTypeInfo
|
||||||
|
(
|
||||||
|
s_hProcess,
|
||||||
|
base,
|
||||||
|
ti,
|
||||||
|
type,
|
||||||
|
rc
|
||||||
|
) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
bool
|
||||||
|
DoGetTypeInfo(PSYMBOL_INFO pSym, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc)
|
||||||
|
{
|
||||||
|
return DoGetTypeInfo(pSym->ModBase, pSym->TypeIndex, type, rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
wxDbgHelpDLL::BasicType GetBasicType(PSYMBOL_INFO pSym)
|
||||||
|
{
|
||||||
|
wxDbgHelpDLL::BasicType bt;
|
||||||
|
return DoGetTypeInfo(pSym, TI_GET_BASETYPE, &bt)
|
||||||
|
? bt
|
||||||
|
: wxDbgHelpDLL::BASICTYPE_NOTYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
wxString wxDbgHelpDLL::GetSymbolName(PSYMBOL_INFO pSym)
|
||||||
|
{
|
||||||
|
wxString s;
|
||||||
|
|
||||||
|
WCHAR *pwszTypeName;
|
||||||
|
if ( SymGetTypeInfo
|
||||||
|
(
|
||||||
|
GetCurrentProcess(),
|
||||||
|
pSym->ModBase,
|
||||||
|
pSym->TypeIndex,
|
||||||
|
TI_GET_SYMNAME,
|
||||||
|
&pwszTypeName
|
||||||
|
) )
|
||||||
|
{
|
||||||
|
s = wxConvCurrent->cWC2WX(pwszTypeName);
|
||||||
|
|
||||||
|
::LocalFree(pwszTypeName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ wxString
|
||||||
|
wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress)
|
||||||
|
{
|
||||||
|
if ( !pAddress )
|
||||||
|
{
|
||||||
|
return _T("null");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ::IsBadReadPtr(pAddress, length) != 0 )
|
||||||
|
{
|
||||||
|
return _T("BAD");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
wxString s;
|
||||||
|
s.reserve(256);
|
||||||
|
|
||||||
|
if ( length == 1 )
|
||||||
|
{
|
||||||
|
const BYTE b = *(PBYTE)pAddress;
|
||||||
|
|
||||||
|
if ( bt == BASICTYPE_BOOL )
|
||||||
|
s = b ? _T("true") : _T("false");
|
||||||
|
else
|
||||||
|
s.Printf(_T("%#04x"), b);
|
||||||
|
}
|
||||||
|
else if ( length == 2 )
|
||||||
|
{
|
||||||
|
s.Printf(bt == BASICTYPE_UINT ? _T("%#06x") : _T("%d"),
|
||||||
|
*(PWORD)pAddress);
|
||||||
|
}
|
||||||
|
else if ( length == 4 )
|
||||||
|
{
|
||||||
|
bool handled = false;
|
||||||
|
|
||||||
|
if ( bt == BASICTYPE_FLOAT )
|
||||||
|
{
|
||||||
|
s.Printf(_T("%f"), *(PFLOAT)pAddress);
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
else if ( bt == BASICTYPE_CHAR )
|
||||||
|
{
|
||||||
|
// don't take more than 32 characters of a string
|
||||||
|
static const size_t NUM_CHARS = 64;
|
||||||
|
|
||||||
|
const char *pc = *(PSTR *)pAddress;
|
||||||
|
if ( ::IsBadStringPtrA(pc, NUM_CHARS) == 0 )
|
||||||
|
{
|
||||||
|
s += _T('"');
|
||||||
|
for ( size_t n = 0; n < NUM_CHARS && *pc; n++, pc++ )
|
||||||
|
{
|
||||||
|
s += *pc;
|
||||||
|
}
|
||||||
|
s += _T('"');
|
||||||
|
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !handled )
|
||||||
|
{
|
||||||
|
// treat just as an opaque DWORD
|
||||||
|
s.Printf(_T("%#x"), *(PDWORD)pAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( length == 8 )
|
||||||
|
{
|
||||||
|
if ( bt == BASICTYPE_FLOAT )
|
||||||
|
{
|
||||||
|
s.Printf(_T("%lf"), *(double *)pAddress);
|
||||||
|
}
|
||||||
|
else // opaque 64 bit value
|
||||||
|
{
|
||||||
|
s.Printf(_T("%#" wxLongLongFmtSpec _T("x")), *(PDWORD *)pAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString
|
||||||
|
wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level)
|
||||||
|
{
|
||||||
|
wxString s;
|
||||||
|
|
||||||
|
// avoid infinite recursion
|
||||||
|
if ( level > 100 )
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
SymbolTag tag = SYMBOL_TAG_NULL;
|
||||||
|
if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) )
|
||||||
|
{
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ( tag )
|
||||||
|
{
|
||||||
|
case SYMBOL_TAG_UDT:
|
||||||
|
case SYMBOL_TAG_BASE_CLASS:
|
||||||
|
s = DumpUDT(pSym, pVariable, level);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYMBOL_TAG_DATA:
|
||||||
|
wxDbgHelpDLL::DataKind kind;
|
||||||
|
if ( !DoGetTypeInfo(pSym, TI_GET_DATAKIND, &kind) ||
|
||||||
|
kind != DATA_MEMBER )
|
||||||
|
{
|
||||||
|
// maybe it's a static member? we're not interested in them...
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the offset of the child member, relative to its parent
|
||||||
|
DWORD ofs = 0;
|
||||||
|
if ( !DoGetTypeInfo(pSym, TI_GET_OFFSET, &ofs) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
pVariable = (void *)((DWORD_PTR)pVariable + ofs);
|
||||||
|
|
||||||
|
|
||||||
|
// now pass to the type representing the type of this member
|
||||||
|
SYMBOL_INFO sym = *pSym;
|
||||||
|
if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &sym.TypeIndex) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
ULONG64 size;
|
||||||
|
DoGetTypeInfo(&sym, TI_GET_LENGTH, &size);
|
||||||
|
|
||||||
|
switch ( DereferenceSymbol(&sym, &pVariable) )
|
||||||
|
{
|
||||||
|
case SYMBOL_TAG_BASE_TYPE:
|
||||||
|
{
|
||||||
|
BasicType bt = GetBasicType(&sym);
|
||||||
|
if ( bt )
|
||||||
|
{
|
||||||
|
s = DumpBaseType(bt, size, pVariable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYMBOL_TAG_UDT:
|
||||||
|
case SYMBOL_TAG_BASE_CLASS:
|
||||||
|
s = DumpUDT(&sym, pVariable, level);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !s.empty() )
|
||||||
|
{
|
||||||
|
s = GetSymbolName(pSym) + _T(" = ") + s;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !s.empty() )
|
||||||
|
{
|
||||||
|
s = wxString(_T('\t'), level + 1) + s + _T('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ wxString
|
||||||
|
wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level)
|
||||||
|
{
|
||||||
|
wxString s;
|
||||||
|
s.reserve(512);
|
||||||
|
s = GetSymbolName(pSym);
|
||||||
|
|
||||||
|
#if !wxUSE_STL
|
||||||
|
// special handling for ubiquitous wxString: although the code below works
|
||||||
|
// for it as well, it shows the wxStringBase class and takes 4 lines
|
||||||
|
// instead of only one as this branch
|
||||||
|
if ( s == _T("wxString") )
|
||||||
|
{
|
||||||
|
wxString *ps = (wxString *)pVariable;
|
||||||
|
s << _T("(\"") << *ps << _T(")\"");
|
||||||
|
}
|
||||||
|
else // any other UDT
|
||||||
|
#endif // !wxUSE_STL
|
||||||
|
{
|
||||||
|
// Determine how many children this type has.
|
||||||
|
DWORD dwChildrenCount = 0;
|
||||||
|
DoGetTypeInfo(pSym, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
|
||||||
|
|
||||||
|
// Prepare to get an array of "TypeIds", representing each of the children.
|
||||||
|
TI_FINDCHILDREN_PARAMS *children = (TI_FINDCHILDREN_PARAMS *)
|
||||||
|
malloc(sizeof(TI_FINDCHILDREN_PARAMS) +
|
||||||
|
(dwChildrenCount - 1)*sizeof(ULONG));
|
||||||
|
if ( !children )
|
||||||
|
return s;
|
||||||
|
|
||||||
|
children->Count = dwChildrenCount;
|
||||||
|
children->Start = 0;
|
||||||
|
|
||||||
|
// Get the array of TypeIds, one for each child type
|
||||||
|
if ( !DoGetTypeInfo(pSym, TI_FINDCHILDREN, children) )
|
||||||
|
{
|
||||||
|
free(children);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
s << _T(" {\n");
|
||||||
|
|
||||||
|
// Iterate through all children
|
||||||
|
SYMBOL_INFO sym;
|
||||||
|
wxZeroMemory(sym);
|
||||||
|
sym.ModBase = pSym->ModBase;
|
||||||
|
for ( unsigned i = 0; i < dwChildrenCount; i++ )
|
||||||
|
{
|
||||||
|
sym.TypeIndex = children->ChildId[i];
|
||||||
|
|
||||||
|
// children here are in lexicographic sense, i.e. we get all our nested
|
||||||
|
// classes and not only our member fields, but we can't get the values
|
||||||
|
// for the members of the nested classes, of course!
|
||||||
|
DWORD nested;
|
||||||
|
if ( DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) && nested )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// avoid infinite recursion: this does seem to happen sometimes with
|
||||||
|
// complex typedefs...
|
||||||
|
if ( sym.TypeIndex == pSym->TypeIndex )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s += DumpField(&sym, pVariable, level + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(children);
|
||||||
|
|
||||||
|
s << wxString(_T('\t'), level + 1) << _T('}');
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */
|
||||||
|
wxDbgHelpDLL::SymbolTag
|
||||||
|
wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym, void **ppData)
|
||||||
|
{
|
||||||
|
SymbolTag tag = SYMBOL_TAG_NULL;
|
||||||
|
for ( ;; )
|
||||||
|
{
|
||||||
|
if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( tag != SYMBOL_TAG_POINTER_TYPE )
|
||||||
|
break;
|
||||||
|
|
||||||
|
ULONG tiNew;
|
||||||
|
if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &tiNew) ||
|
||||||
|
tiNew == pSym->TypeIndex )
|
||||||
|
break;
|
||||||
|
|
||||||
|
pSym->TypeIndex = tiNew;
|
||||||
|
|
||||||
|
// remove one level of indirection except for the char strings: we want
|
||||||
|
// to dump "char *" and not a single "char" for them
|
||||||
|
if ( ppData && *ppData && GetBasicType(pSym) != BASICTYPE_CHAR )
|
||||||
|
*ppData = (void *)*((DWORD_PTR *)*ppData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ wxString
|
||||||
|
wxDbgHelpDLL::DumpSymbol(PSYMBOL_INFO pSym, void *pVariable)
|
||||||
|
{
|
||||||
|
wxString s;
|
||||||
|
SYMBOL_INFO symDeref = *pSym;
|
||||||
|
switch ( DereferenceSymbol(&symDeref, &pVariable) )
|
||||||
|
{
|
||||||
|
case SYMBOL_TAG_UDT:
|
||||||
|
// show UDT recursively
|
||||||
|
s = DumpUDT(&symDeref, pVariable);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SYMBOL_TAG_BASE_TYPE:
|
||||||
|
// variable of simple type, show directly
|
||||||
|
BasicType bt = GetBasicType(&symDeref);
|
||||||
|
if ( bt )
|
||||||
|
{
|
||||||
|
s = DumpBaseType(bt, pSym->Size, pVariable);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// debugging helpers
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
|
||||||
|
static wxString TagString(wxDbgHelpDLL::SymbolTag tag)
|
||||||
|
{
|
||||||
|
static const wxChar *tags[] =
|
||||||
|
{
|
||||||
|
_T("null"),
|
||||||
|
_T("exe"),
|
||||||
|
_T("compiland"),
|
||||||
|
_T("compiland details"),
|
||||||
|
_T("compiland env"),
|
||||||
|
_T("function"),
|
||||||
|
_T("block"),
|
||||||
|
_T("data"),
|
||||||
|
_T("annotation"),
|
||||||
|
_T("label"),
|
||||||
|
_T("public symbol"),
|
||||||
|
_T("udt"),
|
||||||
|
_T("enum"),
|
||||||
|
_T("function type"),
|
||||||
|
_T("pointer type"),
|
||||||
|
_T("array type"),
|
||||||
|
_T("base type"),
|
||||||
|
_T("typedef"),
|
||||||
|
_T("base class"),
|
||||||
|
_T("friend"),
|
||||||
|
_T("function arg type"),
|
||||||
|
_T("func debug start"),
|
||||||
|
_T("func debug end"),
|
||||||
|
_T("using namespace"),
|
||||||
|
_T("vtable shape"),
|
||||||
|
_T("vtable"),
|
||||||
|
_T("custom"),
|
||||||
|
_T("thunk"),
|
||||||
|
_T("custom type"),
|
||||||
|
_T("managed type"),
|
||||||
|
_T("dimension"),
|
||||||
|
};
|
||||||
|
|
||||||
|
wxCOMPILE_TIME_ASSERT( WXSIZEOF(tags) == wxDbgHelpDLL::SYMBOL_TAG_MAX,
|
||||||
|
SymbolTagStringMismatch );
|
||||||
|
|
||||||
|
wxString s;
|
||||||
|
if ( tag < WXSIZEOF(tags) )
|
||||||
|
s = tags[tag];
|
||||||
|
else
|
||||||
|
s.Printf(_T("unrecognized tag (%d)"), tag);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static wxString KindString(wxDbgHelpDLL::DataKind kind)
|
||||||
|
{
|
||||||
|
static const wxChar *kinds[] =
|
||||||
|
{
|
||||||
|
_T("unknown"),
|
||||||
|
_T("local"),
|
||||||
|
_T("static local"),
|
||||||
|
_T("param"),
|
||||||
|
_T("object ptr"),
|
||||||
|
_T("file static"),
|
||||||
|
_T("global"),
|
||||||
|
_T("member"),
|
||||||
|
_T("static member"),
|
||||||
|
_T("constant"),
|
||||||
|
};
|
||||||
|
|
||||||
|
wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::DATA_MAX,
|
||||||
|
DataKindStringMismatch );
|
||||||
|
|
||||||
|
wxString s;
|
||||||
|
if ( kind < WXSIZEOF(kinds) )
|
||||||
|
s = kinds[kind];
|
||||||
|
else
|
||||||
|
s.Printf(_T("unrecognized kind (%d)"), kind);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static wxString UdtKindString(wxDbgHelpDLL::UdtKind kind)
|
||||||
|
{
|
||||||
|
static const wxChar *kinds[] =
|
||||||
|
{
|
||||||
|
_T("struct"),
|
||||||
|
_T("class"),
|
||||||
|
_T("union"),
|
||||||
|
};
|
||||||
|
|
||||||
|
wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::UDT_MAX,
|
||||||
|
UDTKindStringMismatch );
|
||||||
|
|
||||||
|
wxString s;
|
||||||
|
if ( kind < WXSIZEOF(kinds) )
|
||||||
|
s = kinds[kind];
|
||||||
|
else
|
||||||
|
s.Printf(_T("unrecognized UDT (%d)"), kind);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
static wxString TypeString(wxDbgHelpDLL::BasicType bt)
|
||||||
|
{
|
||||||
|
static const wxChar *types[] =
|
||||||
|
{
|
||||||
|
_T("no type"),
|
||||||
|
_T("void"),
|
||||||
|
_T("char"),
|
||||||
|
_T("wchar"),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T("int"),
|
||||||
|
_T("uint"),
|
||||||
|
_T("float"),
|
||||||
|
_T("bcd"),
|
||||||
|
_T("bool"),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T("long"),
|
||||||
|
_T("ulong"),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T(""),
|
||||||
|
_T("CURRENCY"),
|
||||||
|
_T("DATE"),
|
||||||
|
_T("VARIANT"),
|
||||||
|
_T("complex"),
|
||||||
|
_T("bit"),
|
||||||
|
_T("BSTR"),
|
||||||
|
_T("HRESULT"),
|
||||||
|
};
|
||||||
|
|
||||||
|
wxCOMPILE_TIME_ASSERT( WXSIZEOF(types) == wxDbgHelpDLL::BASICTYPE_MAX,
|
||||||
|
BasicTypeStringMismatch );
|
||||||
|
|
||||||
|
wxString s;
|
||||||
|
if ( bt < WXSIZEOF(types) )
|
||||||
|
s = types[bt];
|
||||||
|
|
||||||
|
if ( s.empty() )
|
||||||
|
s.Printf(_T("unrecognized type (%d)"), bt);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function is meant to be called from under debugger to see the
|
||||||
|
// proprieties of the given type id
|
||||||
|
extern "C" void DumpTI(ULONG ti)
|
||||||
|
{
|
||||||
|
SYMBOL_INFO sym = { sizeof(SYMBOL_INFO) };
|
||||||
|
sym.ModBase = 0x400000; // it's a constant under Win32
|
||||||
|
sym.TypeIndex = ti;
|
||||||
|
|
||||||
|
wxDbgHelpDLL::SymbolTag tag = wxDbgHelpDLL::SYMBOL_TAG_NULL;
|
||||||
|
DoGetTypeInfo(&sym, TI_GET_SYMTAG, &tag);
|
||||||
|
DoGetTypeInfo(&sym, TI_GET_TYPEID, &ti);
|
||||||
|
|
||||||
|
OutputDebugString(wxString::Format(_T("Type 0x%x: "), sym.TypeIndex));
|
||||||
|
wxString name = wxDbgHelpDLL::GetSymbolName(&sym);
|
||||||
|
if ( !name.empty() )
|
||||||
|
{
|
||||||
|
OutputDebugString(wxString::Format(_T("name=\"%s\", "), name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD nested;
|
||||||
|
if ( !DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) )
|
||||||
|
{
|
||||||
|
nested = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputDebugString(wxString::Format(_T("tag=%s%s"),
|
||||||
|
nested ? _T("nested ") : _T(""),
|
||||||
|
TagString(tag).c_str()));
|
||||||
|
if ( tag == wxDbgHelpDLL::SYMBOL_TAG_UDT )
|
||||||
|
{
|
||||||
|
wxDbgHelpDLL::UdtKind udtKind;
|
||||||
|
if ( DoGetTypeInfo(&sym, TI_GET_UDTKIND, &udtKind) )
|
||||||
|
{
|
||||||
|
OutputDebugString(_T(" (") + UdtKindString(udtKind) + _T(')'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDbgHelpDLL::DataKind kind = wxDbgHelpDLL::DATA_UNKNOWN;
|
||||||
|
if ( DoGetTypeInfo(&sym, TI_GET_DATAKIND, &kind) )
|
||||||
|
{
|
||||||
|
OutputDebugString(wxString::Format(
|
||||||
|
_T(", kind=%s"), KindString(kind).c_str()));
|
||||||
|
if ( kind == wxDbgHelpDLL::DATA_MEMBER )
|
||||||
|
{
|
||||||
|
DWORD ofs = 0;
|
||||||
|
if ( DoGetTypeInfo(&sym, TI_GET_OFFSET, &ofs) )
|
||||||
|
{
|
||||||
|
OutputDebugString(wxString::Format(_T(" (ofs=0x%x)"), ofs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDbgHelpDLL::BasicType bt = GetBasicType(&sym);
|
||||||
|
if ( bt )
|
||||||
|
{
|
||||||
|
OutputDebugString(wxString::Format(_T(", type=%s"),
|
||||||
|
TypeString(bt).c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ti != sym.TypeIndex )
|
||||||
|
{
|
||||||
|
OutputDebugString(wxString::Format(_T(", next ti=0x%x"), ti));
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputDebugString("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
#endif // wxUSE_DBGHELP
|
Reference in New Issue
Block a user