/////////////////////////////////////////////////////////////////////////////
-// Name: msw/debughlp.cpp
+// Name: src/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
/////////////////////////////////////////////////////////////////////////////
#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
// 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);
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; \
}
// 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) )
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;
}
/* 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());
}
// ----------------------------------------------------------------------------
{
if ( !pAddress )
{
- return _T("null");
+ return wxT("null");
}
if ( ::IsBadReadPtr(pAddress, length) != 0 )
{
- return _T("BAD");
+ return wxT("BAD");
}
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 )
if ( bt == BASICTYPE_FLOAT )
{
- s.Printf(_T("%f"), *(PFLOAT)pAddress);
+ s.Printf(wxT("%f"), *(PFLOAT)pAddress);
handled = true;
}
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;
}
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);
}
}
wxString s;
// avoid infinite recursion
- if ( level > 100 )
+ if ( level > MAX_DUMP_DEPTH )
{
return s;
}
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;
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;
return s;
}
- s << _T(" {\n");
+ s << wxT(" {\n");
// Iterate through all children
SYMBOL_INFO sym;
free(children);
- s << wxString(_T('\t'), level + 1) << _T('}');
+ s << wxString(wxT('\t'), level + 1) << wxT('}');
}
return s;
// 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;
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);
{
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,
if ( tag < WXSIZEOF(tags) )
s = tags[tag];
else
- s.Printf(_T("unrecognized tag (%d)"), tag);
+ s.Printf(wxT("unrecognized tag (%d)"), tag);
return s;
}
{
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,
if ( kind < WXSIZEOF(kinds) )
s = kinds[kind];
else
- s.Printf(_T("unrecognized kind (%d)"), kind);
+ s.Printf(wxT("unrecognized kind (%d)"), kind);
return s;
}
{
static const wxChar *kinds[] =
{
- _T("struct"),
- _T("class"),
- _T("union"),
+ wxT("struct"),
+ wxT("class"),
+ wxT("union"),
};
wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::UDT_MAX,
if ( kind < WXSIZEOF(kinds) )
s = kinds[kind];
else
- s.Printf(_T("unrecognized UDT (%d)"), kind);
+ s.Printf(wxT("unrecognized UDT (%d)"), kind);
return s;
}
{
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,
s = types[bt];
if ( s.empty() )
- s.Printf(_T("unrecognized type (%d)"), bt);
+ s.Printf(wxT("unrecognized type (%d)"), bt);
return s;
}
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;
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(')'));
}
}
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));
}
}
}
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