From 3d8b5d8502c7507a822f4ad2aa0068586be028c9 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 17 Jan 2005 01:20:36 +0000 Subject: [PATCH] created a reusable interface to dbghelp API git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@31414 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/debughlp.h | 226 ++++++++++++ src/msw/debughlp.cpp | 716 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 942 insertions(+) create mode 100644 include/wx/msw/debughlp.h create mode 100644 src/msw/debughlp.cpp diff --git a/include/wx/msw/debughlp.h b/include/wx/msw/debughlp.h new file mode 100644 index 0000000000..10e32496a5 --- /dev/null +++ b/include/wx/msw/debughlp.h @@ -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 +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_MSW_DEBUGHLPH_H_ +#define _WX_MSW_DEBUGHLPH_H_ + +#include "wx/dynlib.h" + +#include "wx/msw/wrapwin.h" +#include +#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_ + diff --git a/src/msw/debughlp.cpp b/src/msw/debughlp.cpp new file mode 100644 index 0000000000..6e91403895 --- /dev/null +++ b/src/msw/debughlp.cpp @@ -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 +// 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 -- 2.45.2