1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/debughlp.cpp
3 // Purpose: various Win32 debug helpers
4 // Author: Vadim Zeitlin
6 // Created: 2005-01-08 (extracted from crashrpt.cpp)
8 // Copyright: (c) 2003-2005 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #include "wx/wxprec.h"
26 #include "wx/msw/debughlp.h"
30 // ----------------------------------------------------------------------------
32 // ----------------------------------------------------------------------------
34 // error message from Init()
35 static wxString gs_errMsg
;
37 // ============================================================================
38 // wxDbgHelpDLL implementation
39 // ============================================================================
41 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 #define DEFINE_SYM_FUNCTION(func) wxDbgHelpDLL::func ## _t wxDbgHelpDLL::func = 0
47 wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION
);
49 #undef DEFINE_SYM_FUNCTION
51 // ----------------------------------------------------------------------------
52 // initialization methods
53 // ----------------------------------------------------------------------------
55 // load all function we need from the DLL
57 static bool BindDbgHelpFunctions(const wxDynamicLibrary
& dllDbgHelp
)
59 #define LOAD_SYM_FUNCTION(name) \
60 wxDbgHelpDLL::name = (wxDbgHelpDLL::name ## _t) \
61 dllDbgHelp.GetSymbol(_T(#name)); \
62 if ( !wxDbgHelpDLL::name ) \
64 gs_errMsg += _T("Function ") _T(#name) _T("() not found.\n"); \
68 wxDO_FOR_ALL_SYM_FUNCS(LOAD_SYM_FUNCTION
);
70 #undef LOAD_SYM_FUNCTION
75 // called by Init() if we hadn't done this before
78 wxDynamicLibrary
dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM
);
79 if ( dllDbgHelp
.IsLoaded() )
81 if ( BindDbgHelpFunctions(dllDbgHelp
) )
83 // turn on default options
84 DWORD options
= wxDbgHelpDLL::SymGetOptions();
86 options
|= SYMOPT_DEFERRED_LOADS
| SYMOPT_UNDNAME
| SYMOPT_DEBUG
;
88 wxDbgHelpDLL::SymSetOptions(options
);
94 gs_errMsg
+= _T("\nPlease update your dbghelp.dll version, ")
95 _T("at least version 5.1 is needed!\n")
96 _T("(if you already have a new version, please ")
97 _T("put it in the same directory where the program is.)\n");
99 else // failed to load dbghelp.dll
101 gs_errMsg
+= _T("Please install dbghelp.dll available free of charge ")
102 _T("from Microsoft to get more detailed crash information!");
105 gs_errMsg
+= _T("\nLatest dbghelp.dll is available at ")
106 _T("http://www.microsoft.com/whdc/ddk/debugging/\n");
112 bool wxDbgHelpDLL::Init()
114 // this flag is -1 until Init() is called for the first time, then it's set
115 // to either false or true depending on whether we could load the functions
116 static int s_loaded
= -1;
118 if ( s_loaded
== -1 )
123 return s_loaded
!= 0;
126 // ----------------------------------------------------------------------------
128 // ----------------------------------------------------------------------------
131 const wxString
& wxDbgHelpDLL::GetErrorMessage()
137 void wxDbgHelpDLL::LogError(const wxChar
*func
)
139 ::OutputDebugString(wxString::Format(_T("dbghelp: %s() failed: %s\r\n"),
140 func
, wxSysErrorMsg(::GetLastError())));
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
149 DoGetTypeInfo(DWORD64 base
, ULONG ti
, IMAGEHLP_SYMBOL_TYPE_INFO type
, void *rc
)
151 static HANDLE s_hProcess
= ::GetCurrentProcess();
153 return wxDbgHelpDLL::SymGetTypeInfo
165 DoGetTypeInfo(PSYMBOL_INFO pSym
, IMAGEHLP_SYMBOL_TYPE_INFO type
, void *rc
)
167 return DoGetTypeInfo(pSym
->ModBase
, pSym
->TypeIndex
, type
, rc
);
171 wxDbgHelpDLL::BasicType
GetBasicType(PSYMBOL_INFO pSym
)
173 wxDbgHelpDLL::BasicType bt
;
174 return DoGetTypeInfo(pSym
, TI_GET_BASETYPE
, &bt
)
176 : wxDbgHelpDLL::BASICTYPE_NOTYPE
;
180 wxString
wxDbgHelpDLL::GetSymbolName(PSYMBOL_INFO pSym
)
194 s
= wxConvCurrent
->cWC2WX(pwszTypeName
);
196 ::LocalFree(pwszTypeName
);
202 /* static */ wxString
203 wxDbgHelpDLL::DumpBaseType(BasicType bt
, DWORD64 length
, PVOID pAddress
)
210 if ( ::IsBadReadPtr(pAddress
, length
) != 0 )
221 const BYTE b
= *(PBYTE
)pAddress
;
223 if ( bt
== BASICTYPE_BOOL
)
224 s
= b
? _T("true") : _T("false");
226 s
.Printf(_T("%#04x"), b
);
228 else if ( length
== 2 )
230 s
.Printf(bt
== BASICTYPE_UINT
? _T("%#06x") : _T("%d"),
233 else if ( length
== 4 )
235 bool handled
= false;
237 if ( bt
== BASICTYPE_FLOAT
)
239 s
.Printf(_T("%f"), *(PFLOAT
)pAddress
);
243 else if ( bt
== BASICTYPE_CHAR
)
245 // don't take more than 32 characters of a string
246 static const size_t NUM_CHARS
= 64;
248 const char *pc
= *(PSTR
*)pAddress
;
249 if ( ::IsBadStringPtrA(pc
, NUM_CHARS
) == 0 )
252 for ( size_t n
= 0; n
< NUM_CHARS
&& *pc
; n
++, pc
++ )
264 // treat just as an opaque DWORD
265 s
.Printf(_T("%#x"), *(PDWORD
)pAddress
);
268 else if ( length
== 8 )
270 if ( bt
== BASICTYPE_FLOAT
)
272 s
.Printf(_T("%lf"), *(double *)pAddress
);
274 else // opaque 64 bit value
276 s
.Printf(_T("%#" wxLongLongFmtSpec
_T("x")), *(PDWORD
*)pAddress
);
284 wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym
, void *pVariable
, unsigned level
)
288 // avoid infinite recursion
294 SymbolTag tag
= SYMBOL_TAG_NULL
;
295 if ( !DoGetTypeInfo(pSym
, TI_GET_SYMTAG
, &tag
) )
303 case SYMBOL_TAG_BASE_CLASS
:
304 s
= DumpUDT(pSym
, pVariable
, level
);
307 case SYMBOL_TAG_DATA
:
312 else // valid location
314 wxDbgHelpDLL::DataKind kind
;
315 if ( !DoGetTypeInfo(pSym
, TI_GET_DATAKIND
, &kind
) ||
316 kind
!= DATA_MEMBER
)
318 // maybe it's a static member? we're not interested in them...
322 // get the offset of the child member, relative to its parent
324 if ( !DoGetTypeInfo(pSym
, TI_GET_OFFSET
, &ofs
) )
327 pVariable
= (void *)((DWORD_PTR
)pVariable
+ ofs
);
330 // now pass to the type representing the type of this member
331 SYMBOL_INFO sym
= *pSym
;
332 if ( !DoGetTypeInfo(pSym
, TI_GET_TYPEID
, &sym
.TypeIndex
) )
336 DoGetTypeInfo(&sym
, TI_GET_LENGTH
, &size
);
338 switch ( DereferenceSymbol(&sym
, &pVariable
) )
340 case SYMBOL_TAG_BASE_TYPE
:
342 BasicType bt
= GetBasicType(&sym
);
345 s
= DumpBaseType(bt
, size
, pVariable
);
351 case SYMBOL_TAG_BASE_CLASS
:
352 s
= DumpUDT(&sym
, pVariable
, level
);
359 s
= GetSymbolName(pSym
) + _T(" = ") + s
;
366 s
= wxString(_T('\t'), level
+ 1) + s
+ _T('\n');
372 /* static */ wxString
373 wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym
, void *pVariable
, unsigned level
)
377 // we have to limit the depth of UDT dumping as otherwise we get in
378 // infinite loops trying to dump linked lists... 10 levels seems quite
379 // reasonable, full information is in minidump file anyhow
384 s
= GetSymbolName(pSym
);
387 // special handling for ubiquitous wxString: although the code below works
388 // for it as well, it shows the wxStringBase class and takes 4 lines
389 // instead of only one as this branch
390 if ( s
== _T("wxString") )
392 wxString
*ps
= (wxString
*)pVariable
;
393 s
<< _T("(\"") << *ps
<< _T(")\"");
395 else // any other UDT
398 // Determine how many children this type has.
399 DWORD dwChildrenCount
= 0;
400 DoGetTypeInfo(pSym
, TI_GET_CHILDRENCOUNT
, &dwChildrenCount
);
402 // Prepare to get an array of "TypeIds", representing each of the children.
403 TI_FINDCHILDREN_PARAMS
*children
= (TI_FINDCHILDREN_PARAMS
*)
404 malloc(sizeof(TI_FINDCHILDREN_PARAMS
) +
405 (dwChildrenCount
- 1)*sizeof(ULONG
));
409 children
->Count
= dwChildrenCount
;
412 // Get the array of TypeIds, one for each child type
413 if ( !DoGetTypeInfo(pSym
, TI_FINDCHILDREN
, children
) )
421 // Iterate through all children
424 sym
.ModBase
= pSym
->ModBase
;
425 for ( unsigned i
= 0; i
< dwChildrenCount
; i
++ )
427 sym
.TypeIndex
= children
->ChildId
[i
];
429 // children here are in lexicographic sense, i.e. we get all our nested
430 // classes and not only our member fields, but we can't get the values
431 // for the members of the nested classes, of course!
433 if ( DoGetTypeInfo(&sym
, TI_GET_NESTED
, &nested
) && nested
)
436 // avoid infinite recursion: this does seem to happen sometimes with
437 // complex typedefs...
438 if ( sym
.TypeIndex
== pSym
->TypeIndex
)
441 s
+= DumpField(&sym
, pVariable
, level
+ 1);
446 s
<< wxString(_T('\t'), level
+ 1) << _T('}');
453 wxDbgHelpDLL::SymbolTag
454 wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym
, void **ppData
)
456 SymbolTag tag
= SYMBOL_TAG_NULL
;
459 if ( !DoGetTypeInfo(pSym
, TI_GET_SYMTAG
, &tag
) )
462 if ( tag
!= SYMBOL_TAG_POINTER_TYPE
)
466 if ( !DoGetTypeInfo(pSym
, TI_GET_TYPEID
, &tiNew
) ||
467 tiNew
== pSym
->TypeIndex
)
470 pSym
->TypeIndex
= tiNew
;
472 // remove one level of indirection except for the char strings: we want
473 // to dump "char *" and not a single "char" for them
474 if ( ppData
&& *ppData
&& GetBasicType(pSym
) != BASICTYPE_CHAR
)
476 DWORD_PTR
*pData
= (DWORD_PTR
*)*ppData
;
478 if ( ::IsBadReadPtr(pData
, sizeof(DWORD_PTR
*)) )
483 *ppData
= (void *)*pData
;
490 /* static */ wxString
491 wxDbgHelpDLL::DumpSymbol(PSYMBOL_INFO pSym
, void *pVariable
)
494 SYMBOL_INFO symDeref
= *pSym
;
495 switch ( DereferenceSymbol(&symDeref
, &pVariable
) )
498 // show UDT recursively
499 s
= DumpUDT(&symDeref
, pVariable
);
502 case SYMBOL_TAG_BASE_TYPE
:
503 // variable of simple type, show directly
504 BasicType bt
= GetBasicType(&symDeref
);
507 s
= DumpBaseType(bt
, pSym
->Size
, pVariable
);
515 // ----------------------------------------------------------------------------
517 // ----------------------------------------------------------------------------
519 // this code is very useful when debugging debughlp.dll-related code but
520 // probably not worth having compiled in normally, please do not remove it!
523 static wxString
TagString(wxDbgHelpDLL::SymbolTag tag
)
525 static const wxChar
*tags
[] =
530 _T("compiland details"),
547 _T("function arg type"),
548 _T("func debug start"),
549 _T("func debug end"),
550 _T("using namespace"),
560 wxCOMPILE_TIME_ASSERT( WXSIZEOF(tags
) == wxDbgHelpDLL::SYMBOL_TAG_MAX
,
561 SymbolTagStringMismatch
);
564 if ( tag
< WXSIZEOF(tags
) )
567 s
.Printf(_T("unrecognized tag (%d)"), tag
);
572 static wxString
KindString(wxDbgHelpDLL::DataKind kind
)
574 static const wxChar
*kinds
[] =
588 wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds
) == wxDbgHelpDLL::DATA_MAX
,
589 DataKindStringMismatch
);
592 if ( kind
< WXSIZEOF(kinds
) )
595 s
.Printf(_T("unrecognized kind (%d)"), kind
);
600 static wxString
UdtKindString(wxDbgHelpDLL::UdtKind kind
)
602 static const wxChar
*kinds
[] =
609 wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds
) == wxDbgHelpDLL::UDT_MAX
,
610 UDTKindStringMismatch
);
613 if ( kind
< WXSIZEOF(kinds
) )
616 s
.Printf(_T("unrecognized UDT (%d)"), kind
);
621 static wxString
TypeString(wxDbgHelpDLL::BasicType bt
)
623 static const wxChar
*types
[] =
659 wxCOMPILE_TIME_ASSERT( WXSIZEOF(types
) == wxDbgHelpDLL::BASICTYPE_MAX
,
660 BasicTypeStringMismatch
);
663 if ( bt
< WXSIZEOF(types
) )
667 s
.Printf(_T("unrecognized type (%d)"), bt
);
672 // this function is meant to be called from under debugger to see the
673 // proprieties of the given type id
674 extern "C" void DumpTI(ULONG ti
)
676 SYMBOL_INFO sym
= { sizeof(SYMBOL_INFO
) };
677 sym
.ModBase
= 0x400000; // it's a constant under Win32
680 wxDbgHelpDLL::SymbolTag tag
= wxDbgHelpDLL::SYMBOL_TAG_NULL
;
681 DoGetTypeInfo(&sym
, TI_GET_SYMTAG
, &tag
);
682 DoGetTypeInfo(&sym
, TI_GET_TYPEID
, &ti
);
684 OutputDebugString(wxString::Format(_T("Type 0x%x: "), sym
.TypeIndex
));
685 wxString name
= wxDbgHelpDLL::GetSymbolName(&sym
);
688 OutputDebugString(wxString::Format(_T("name=\"%s\", "), name
.c_str()));
692 if ( !DoGetTypeInfo(&sym
, TI_GET_NESTED
, &nested
) )
697 OutputDebugString(wxString::Format(_T("tag=%s%s"),
698 nested
? _T("nested ") : wxEmptyString
,
699 TagString(tag
).c_str()));
700 if ( tag
== wxDbgHelpDLL::SYMBOL_TAG_UDT
)
702 wxDbgHelpDLL::UdtKind udtKind
;
703 if ( DoGetTypeInfo(&sym
, TI_GET_UDTKIND
, &udtKind
) )
705 OutputDebugString(_T(" (") + UdtKindString(udtKind
) + _T(')'));
709 wxDbgHelpDLL::DataKind kind
= wxDbgHelpDLL::DATA_UNKNOWN
;
710 if ( DoGetTypeInfo(&sym
, TI_GET_DATAKIND
, &kind
) )
712 OutputDebugString(wxString::Format(
713 _T(", kind=%s"), KindString(kind
).c_str()));
714 if ( kind
== wxDbgHelpDLL::DATA_MEMBER
)
717 if ( DoGetTypeInfo(&sym
, TI_GET_OFFSET
, &ofs
) )
719 OutputDebugString(wxString::Format(_T(" (ofs=0x%x)"), ofs
));
724 wxDbgHelpDLL::BasicType bt
= GetBasicType(&sym
);
727 OutputDebugString(wxString::Format(_T(", type=%s"),
728 TypeString(bt
).c_str()));
731 if ( ti
!= sym
.TypeIndex
)
733 OutputDebugString(wxString::Format(_T(", next ti=0x%x"), ti
));
736 OutputDebugString(_T("\r\n"));
741 #endif // wxUSE_DBGHELP