X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e84ba59e3e52c3a24f40bc23e69d5e9b7d86fdd4..404b319a85dadd7decf7a5a5331020520031a41c:/src/msw/debughlp.cpp?ds=inline diff --git a/src/msw/debughlp.cpp b/src/msw/debughlp.cpp index 98b35f06e0..927c293a86 100644 --- a/src/msw/debughlp.cpp +++ b/src/msw/debughlp.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: msw/debughlp.cpp +// Name: src/msw/debughlp.cpp // Purpose: various Win32 debug helpers // Author: Vadim Zeitlin // Modified by: @@ -25,7 +25,15 @@ #include "wx/msw/debughlp.h" -#if wxUSE_DBGHELP +#if wxUSE_DBGHELP && wxUSE_DYNLIB_CLASS + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// to prevent recursion which could result from corrupted data we limit +// ourselves to that many levels of embedded fields inside structs +static const unsigned MAX_DUMP_DEPTH = 20; // ---------------------------------------------------------------------------- // globals @@ -42,7 +50,8 @@ static wxString gs_errMsg; // static members // ---------------------------------------------------------------------------- -#define DEFINE_SYM_FUNCTION(func) wxDbgHelpDLL::func ## _t wxDbgHelpDLL::func = 0 +#define DEFINE_SYM_FUNCTION(func, name) \ + wxDbgHelpDLL::func ## _t wxDbgHelpDLL::func = 0 wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION); @@ -56,12 +65,12 @@ wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION); static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp) { - #define LOAD_SYM_FUNCTION(name) \ - wxDbgHelpDLL::name = (wxDbgHelpDLL::name ## _t) \ - dllDbgHelp.GetSymbol(_T(#name)); \ - if ( !wxDbgHelpDLL::name ) \ + #define LOAD_SYM_FUNCTION(func, name) \ + wxDbgHelpDLL::func = (wxDbgHelpDLL::func ## _t) \ + dllDbgHelp.GetSymbol(wxT(#name)); \ + if ( !wxDbgHelpDLL::func ) \ { \ - gs_errMsg += _T("Function ") _T(#name) _T("() not found.\n"); \ + gs_errMsg += wxT("Function ") wxT(#name) wxT("() not found.\n"); \ return false; \ } @@ -75,7 +84,7 @@ static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp) // called by Init() if we hadn't done this before static bool DoInit() { - wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM); + wxDynamicLibrary dllDbgHelp(wxT("dbghelp.dll"), wxDL_VERBATIM); if ( dllDbgHelp.IsLoaded() ) { if ( BindDbgHelpFunctions(dllDbgHelp) ) @@ -91,19 +100,19 @@ static bool DoInit() 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"); + gs_errMsg += wxT("\nPlease update your dbghelp.dll version, ") + wxT("at least version 5.1 is needed!\n") + wxT("(if you already have a new version, please ") + wxT("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 += wxT("Please install dbghelp.dll available free of charge ") + wxT("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"); + gs_errMsg += wxT("\nLatest dbghelp.dll is available at ") + wxT("http://www.microsoft.com/whdc/ddk/debugging/\n"); return false; } @@ -136,8 +145,8 @@ const wxString& wxDbgHelpDLL::GetErrorMessage() /* static */ void wxDbgHelpDLL::LogError(const wxChar *func) { - ::OutputDebugString(wxString::Format(_T("dbghelp: %s() failed: %s\r\n"), - func, wxSysErrorMsg(::GetLastError()))); + ::OutputDebugString(wxString::Format(wxT("dbghelp: %s() failed: %s\r\n"), + func, wxSysErrorMsg(::GetLastError())).t_str()); } // ---------------------------------------------------------------------------- @@ -204,12 +213,12 @@ wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress) { if ( !pAddress ) { - return _T("null"); + return wxT("null"); } if ( ::IsBadReadPtr(pAddress, length) != 0 ) { - return _T("BAD"); + return wxT("BAD"); } @@ -221,13 +230,13 @@ wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress) const BYTE b = *(PBYTE)pAddress; if ( bt == BASICTYPE_BOOL ) - s = b ? _T("true") : _T("false"); + s = b ? wxT("true") : wxT("false"); else - s.Printf(_T("%#04x"), b); + s.Printf(wxT("%#04x"), b); } else if ( length == 2 ) { - s.Printf(bt == BASICTYPE_UINT ? _T("%#06x") : _T("%d"), + s.Printf(bt == BASICTYPE_UINT ? wxT("%#06x") : wxT("%d"), *(PWORD)pAddress); } else if ( length == 4 ) @@ -236,7 +245,7 @@ wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress) if ( bt == BASICTYPE_FLOAT ) { - s.Printf(_T("%f"), *(PFLOAT)pAddress); + s.Printf(wxT("%f"), *(PFLOAT)pAddress); handled = true; } @@ -248,12 +257,12 @@ wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress) const char *pc = *(PSTR *)pAddress; if ( ::IsBadStringPtrA(pc, NUM_CHARS) == 0 ) { - s += _T('"'); + s += wxT('"'); for ( size_t n = 0; n < NUM_CHARS && *pc; n++, pc++ ) { s += *pc; } - s += _T('"'); + s += wxT('"'); handled = true; } @@ -262,18 +271,18 @@ wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress) if ( !handled ) { // treat just as an opaque DWORD - s.Printf(_T("%#x"), *(PDWORD)pAddress); + s.Printf(wxT("%#x"), *(PDWORD)pAddress); } } else if ( length == 8 ) { if ( bt == BASICTYPE_FLOAT ) { - s.Printf(_T("%lf"), *(double *)pAddress); + s.Printf(wxT("%lf"), *(double *)pAddress); } else // opaque 64 bit value { - s.Printf(_T("%#" wxLongLongFmtSpec _T("x")), *(PDWORD *)pAddress); + s.Printf("%#" wxLongLongFmtSpec "x", *(wxLongLong_t *)pAddress); } } @@ -286,7 +295,7 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) wxString s; // avoid infinite recursion - if ( level > 100 ) + if ( level > MAX_DUMP_DEPTH ) { return s; } @@ -305,58 +314,74 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) break; case SYMBOL_TAG_DATA: - wxDbgHelpDLL::DataKind kind; - if ( !DoGetTypeInfo(pSym, TI_GET_DATAKIND, &kind) || - kind != DATA_MEMBER ) + if ( !pVariable ) { - // maybe it's a static member? we're not interested in them... - break; + s = wxT("NULL"); } + else // valid location + { + 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; + // 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); + 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; + // 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); + ULONG64 size; + DoGetTypeInfo(&sym, TI_GET_LENGTH, &size); - switch ( DereferenceSymbol(&sym, &pVariable) ) - { - case SYMBOL_TAG_BASE_TYPE: - { - BasicType bt = GetBasicType(&sym); - if ( bt ) + switch ( DereferenceSymbol(&sym, &pVariable) ) + { + case SYMBOL_TAG_BASE_TYPE: { - s = DumpBaseType(bt, size, pVariable); + BasicType bt = GetBasicType(&sym); + if ( bt ) + { + s = DumpBaseType(bt, size, pVariable); + } } - } - break; + break; - case SYMBOL_TAG_UDT: - case SYMBOL_TAG_BASE_CLASS: - s = DumpUDT(&sym, pVariable, level); - break; + case SYMBOL_TAG_UDT: + case SYMBOL_TAG_BASE_CLASS: + s = DumpUDT(&sym, pVariable, level); + break; + + default: + // Suppress gcc warnings about unhandled enum values. + break; + } } if ( !s.empty() ) { - s = GetSymbolName(pSym) + _T(" = ") + s; + s = GetSymbolName(pSym) + wxT(" = ") + s; } break; + + default: + // Suppress gcc warnings about unhandled enum values, don't assert + // to avoid problems during fatal crash generation. + break; } if ( !s.empty() ) { - s = wxString(_T('\t'), level + 1) + s + _T('\n'); + s = wxString(wxT('\t'), level + 1) + s + wxT('\n'); } return s; @@ -366,20 +391,45 @@ wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level) wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level) { wxString s; + + // we have to limit the depth of UDT dumping as otherwise we get in + // infinite loops trying to dump linked lists... 10 levels seems quite + // reasonable, full information is in minidump file anyhow + if ( level > 10 ) + return s; + s.reserve(512); s = GetSymbolName(pSym); -#if !wxUSE_STL +#if !wxUSE_STD_STRING // 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") ) + if ( s == wxT("wxString") ) { wxString *ps = (wxString *)pVariable; - s << _T("(\"") << *ps << _T(")\""); + + // we can't just dump wxString directly as it could be corrupted or + // invalid and it could also be locked for writing (i.e. if we're + // between GetWriteBuf() and UngetWriteBuf() calls) and assert when we + // try to access it contents using public methods, so instead use our + // knowledge of its internals + const wxChar *p = NULL; + if ( !::IsBadReadPtr(ps, sizeof(wxString)) ) + { + p = ps->data(); + wxStringData *data = (wxStringData *)p - 1; + if ( ::IsBadReadPtr(data, sizeof(wxStringData)) || + ::IsBadReadPtr(p, sizeof(wxChar *)*data->nAllocLength) ) + { + p = NULL; // don't touch this pointer with 10 feet pole + } + } + + s << wxT("(\"") << (p ? p : wxT("???")) << wxT(")\""); } else // any other UDT -#endif // !wxUSE_STL +#endif // !wxUSE_STD_STRING { // Determine how many children this type has. DWORD dwChildrenCount = 0; @@ -402,7 +452,7 @@ wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level) return s; } - s << _T(" {\n"); + s << wxT(" {\n"); // Iterate through all children SYMBOL_INFO sym; @@ -429,7 +479,7 @@ wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level) free(children); - s << wxString(_T('\t'), level + 1) << _T('}'); + s << wxString(wxT('\t'), level + 1) << wxT('}'); } return s; @@ -458,7 +508,16 @@ wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym, void **ppData) // 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); + { + DWORD_PTR *pData = (DWORD_PTR *)*ppData; + + if ( ::IsBadReadPtr(pData, sizeof(DWORD_PTR *)) ) + { + break; + } + + *ppData = (void *)*pData; + } } return tag; @@ -471,6 +530,11 @@ wxDbgHelpDLL::DumpSymbol(PSYMBOL_INFO pSym, void *pVariable) SYMBOL_INFO symDeref = *pSym; switch ( DereferenceSymbol(&symDeref, &pVariable) ) { + default: + // Suppress gcc warnings about unhandled enum values, don't assert + // to avoid problems during fatal crash generation. + break; + case SYMBOL_TAG_UDT: // show UDT recursively s = DumpUDT(&symDeref, pVariable); @@ -501,37 +565,37 @@ 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"), + wxT("null"), + wxT("exe"), + wxT("compiland"), + wxT("compiland details"), + wxT("compiland env"), + wxT("function"), + wxT("block"), + wxT("data"), + wxT("annotation"), + wxT("label"), + wxT("public symbol"), + wxT("udt"), + wxT("enum"), + wxT("function type"), + wxT("pointer type"), + wxT("array type"), + wxT("base type"), + wxT("typedef"), + wxT("base class"), + wxT("friend"), + wxT("function arg type"), + wxT("func debug start"), + wxT("func debug end"), + wxT("using namespace"), + wxT("vtable shape"), + wxT("vtable"), + wxT("custom"), + wxT("thunk"), + wxT("custom type"), + wxT("managed type"), + wxT("dimension"), }; wxCOMPILE_TIME_ASSERT( WXSIZEOF(tags) == wxDbgHelpDLL::SYMBOL_TAG_MAX, @@ -541,7 +605,7 @@ static wxString TagString(wxDbgHelpDLL::SymbolTag tag) if ( tag < WXSIZEOF(tags) ) s = tags[tag]; else - s.Printf(_T("unrecognized tag (%d)"), tag); + s.Printf(wxT("unrecognized tag (%d)"), tag); return s; } @@ -550,16 +614,16 @@ 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"), + wxT("unknown"), + wxT("local"), + wxT("static local"), + wxT("param"), + wxT("object ptr"), + wxT("file static"), + wxT("global"), + wxT("member"), + wxT("static member"), + wxT("constant"), }; wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::DATA_MAX, @@ -569,7 +633,7 @@ static wxString KindString(wxDbgHelpDLL::DataKind kind) if ( kind < WXSIZEOF(kinds) ) s = kinds[kind]; else - s.Printf(_T("unrecognized kind (%d)"), kind); + s.Printf(wxT("unrecognized kind (%d)"), kind); return s; } @@ -578,9 +642,9 @@ static wxString UdtKindString(wxDbgHelpDLL::UdtKind kind) { static const wxChar *kinds[] = { - _T("struct"), - _T("class"), - _T("union"), + wxT("struct"), + wxT("class"), + wxT("union"), }; wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::UDT_MAX, @@ -590,7 +654,7 @@ static wxString UdtKindString(wxDbgHelpDLL::UdtKind kind) if ( kind < WXSIZEOF(kinds) ) s = kinds[kind]; else - s.Printf(_T("unrecognized UDT (%d)"), kind); + s.Printf(wxT("unrecognized UDT (%d)"), kind); return s; } @@ -599,38 +663,38 @@ 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"), + wxT("no type"), + wxT("void"), + wxT("char"), + wxT("wchar"), + wxT(""), + wxT(""), + wxT("int"), + wxT("uint"), + wxT("float"), + wxT("bcd"), + wxT("bool"), + wxT(""), + wxT(""), + wxT("long"), + wxT("ulong"), + wxT(""), + wxT(""), + wxT(""), + wxT(""), + wxT(""), + wxT(""), + wxT(""), + wxT(""), + wxT(""), + wxT(""), + wxT("CURRENCY"), + wxT("DATE"), + wxT("VARIANT"), + wxT("complex"), + wxT("bit"), + wxT("BSTR"), + wxT("HRESULT"), }; wxCOMPILE_TIME_ASSERT( WXSIZEOF(types) == wxDbgHelpDLL::BASICTYPE_MAX, @@ -641,7 +705,7 @@ static wxString TypeString(wxDbgHelpDLL::BasicType bt) s = types[bt]; if ( s.empty() ) - s.Printf(_T("unrecognized type (%d)"), bt); + s.Printf(wxT("unrecognized type (%d)"), bt); return s; } @@ -658,11 +722,11 @@ extern "C" void DumpTI(ULONG ti) DoGetTypeInfo(&sym, TI_GET_SYMTAG, &tag); DoGetTypeInfo(&sym, TI_GET_TYPEID, &ti); - OutputDebugString(wxString::Format(_T("Type 0x%x: "), sym.TypeIndex)); + OutputDebugString(wxString::Format(wxT("Type 0x%x: "), sym.TypeIndex)); wxString name = wxDbgHelpDLL::GetSymbolName(&sym); if ( !name.empty() ) { - OutputDebugString(wxString::Format(_T("name=\"%s\", "), name.c_str())); + OutputDebugString(wxString::Format(wxT("name=\"%s\", "), name.c_str())); } DWORD nested; @@ -671,15 +735,15 @@ extern "C" void DumpTI(ULONG ti) nested = FALSE; } - OutputDebugString(wxString::Format(_T("tag=%s%s"), - nested ? _T("nested ") : _T(""), + OutputDebugString(wxString::Format(wxT("tag=%s%s"), + nested ? wxT("nested ") : wxEmptyString, 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(')')); + OutputDebugString(wxT(" (") + UdtKindString(udtKind) + wxT(')')); } } @@ -687,13 +751,13 @@ extern "C" void DumpTI(ULONG ti) if ( DoGetTypeInfo(&sym, TI_GET_DATAKIND, &kind) ) { OutputDebugString(wxString::Format( - _T(", kind=%s"), KindString(kind).c_str())); + wxT(", 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)); + OutputDebugString(wxString::Format(wxT(" (ofs=0x%x)"), ofs)); } } } @@ -701,16 +765,16 @@ extern "C" void DumpTI(ULONG ti) wxDbgHelpDLL::BasicType bt = GetBasicType(&sym); if ( bt ) { - OutputDebugString(wxString::Format(_T(", type=%s"), + OutputDebugString(wxString::Format(wxT(", type=%s"), TypeString(bt).c_str())); } if ( ti != sym.TypeIndex ) { - OutputDebugString(wxString::Format(_T(", next ti=0x%x"), ti)); + OutputDebugString(wxString::Format(wxT(", next ti=0x%x"), ti)); } - OutputDebugString(_T("\r\n")); + OutputDebugString(wxT("\r\n")); } #endif // NDEBUG