]> git.saurik.com Git - wxWidgets.git/blame - src/msw/debughlp.cpp
Add comments explaining the workaround for mingw 3.2.3
[wxWidgets.git] / src / msw / debughlp.cpp
CommitLineData
3d8b5d85
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: msw/debughlp.cpp
3// Purpose: various Win32 debug helpers
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 2005-01-08 (extracted from crashrpt.cpp)
7// RCS-ID: $Id$
8// Copyright: (c) 2003-2005 Vadim Zeitlin <vadim@wxwindows.org>
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23 #pragma hdrstop
24#endif
25
26#include "wx/msw/debughlp.h"
27
28#if wxUSE_DBGHELP
29
30// ----------------------------------------------------------------------------
31// globals
32// ----------------------------------------------------------------------------
33
34// error message from Init()
35static wxString gs_errMsg;
36
37// ============================================================================
38// wxDbgHelpDLL implementation
39// ============================================================================
40
41// ----------------------------------------------------------------------------
42// static members
43// ----------------------------------------------------------------------------
44
45#define DEFINE_SYM_FUNCTION(func) wxDbgHelpDLL::func ## _t wxDbgHelpDLL::func = 0
46
47wxDO_FOR_ALL_SYM_FUNCS(DEFINE_SYM_FUNCTION);
48
49#undef DEFINE_SYM_FUNCTION
50
51// ----------------------------------------------------------------------------
52// initialization methods
53// ----------------------------------------------------------------------------
54
55// load all function we need from the DLL
56
57static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
58{
59 #define LOAD_SYM_FUNCTION(name) \
60 wxDbgHelpDLL::name = (wxDbgHelpDLL::name ## _t) \
61 dllDbgHelp.GetSymbol(_T(#name)); \
62 if ( !wxDbgHelpDLL::name ) \
63 { \
64 gs_errMsg += _T("Function ") _T(#name) _T("() not found.\n"); \
65 return false; \
66 }
67
68 wxDO_FOR_ALL_SYM_FUNCS(LOAD_SYM_FUNCTION);
69
70 #undef LOAD_SYM_FUNCTION
71
72 return true;
73}
74
75// called by Init() if we hadn't done this before
76static bool DoInit()
77{
78 wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM);
79 if ( dllDbgHelp.IsLoaded() )
80 {
81 if ( BindDbgHelpFunctions(dllDbgHelp) )
82 {
83 // turn on default options
84 DWORD options = wxDbgHelpDLL::SymGetOptions();
85
86 options |= SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_DEBUG;
87
88 wxDbgHelpDLL::SymSetOptions(options);
89
90 dllDbgHelp.Detach();
91 return true;
92 }
93
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");
98 }
99 else // failed to load dbghelp.dll
100 {
101 gs_errMsg += _T("Please install dbghelp.dll available free of charge ")
102 _T("from Microsoft to get more detailed crash information!");
103 }
104
105 gs_errMsg += _T("\nLatest dbghelp.dll is available at ")
106 _T("http://www.microsoft.com/whdc/ddk/debugging/\n");
107
108 return false;
109}
110
111/* static */
112bool wxDbgHelpDLL::Init()
113{
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;
117
118 if ( s_loaded == -1 )
119 {
120 s_loaded = DoInit();
121 }
122
123 return s_loaded != 0;
124}
125
126// ----------------------------------------------------------------------------
127// error handling
128// ----------------------------------------------------------------------------
129
130/* static */
131const wxString& wxDbgHelpDLL::GetErrorMessage()
132{
133 return gs_errMsg;
134}
135
136/* static */
137void wxDbgHelpDLL::LogError(const wxChar *func)
138{
139 ::OutputDebugString(wxString::Format(_T("dbghelp: %s() failed: %s\r\n"),
140 func, wxSysErrorMsg(::GetLastError())));
141}
142
143// ----------------------------------------------------------------------------
144// data dumping
145// ----------------------------------------------------------------------------
146
147static inline
148bool
149DoGetTypeInfo(DWORD64 base, ULONG ti, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc)
150{
151 static HANDLE s_hProcess = ::GetCurrentProcess();
152
153 return wxDbgHelpDLL::SymGetTypeInfo
154 (
155 s_hProcess,
156 base,
157 ti,
158 type,
159 rc
160 ) != 0;
161}
162
163static inline
164bool
165DoGetTypeInfo(PSYMBOL_INFO pSym, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc)
166{
167 return DoGetTypeInfo(pSym->ModBase, pSym->TypeIndex, type, rc);
168}
169
170static inline
171wxDbgHelpDLL::BasicType GetBasicType(PSYMBOL_INFO pSym)
172{
173 wxDbgHelpDLL::BasicType bt;
174 return DoGetTypeInfo(pSym, TI_GET_BASETYPE, &bt)
175 ? bt
176 : wxDbgHelpDLL::BASICTYPE_NOTYPE;
177}
178
179/* static */
180wxString wxDbgHelpDLL::GetSymbolName(PSYMBOL_INFO pSym)
181{
182 wxString s;
183
184 WCHAR *pwszTypeName;
185 if ( SymGetTypeInfo
186 (
187 GetCurrentProcess(),
188 pSym->ModBase,
189 pSym->TypeIndex,
190 TI_GET_SYMNAME,
191 &pwszTypeName
192 ) )
193 {
194 s = wxConvCurrent->cWC2WX(pwszTypeName);
195
196 ::LocalFree(pwszTypeName);
197 }
198
199 return s;
200}
201
202/* static */ wxString
203wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress)
204{
205 if ( !pAddress )
206 {
207 return _T("null");
208 }
209
210 if ( ::IsBadReadPtr(pAddress, length) != 0 )
211 {
212 return _T("BAD");
213 }
214
215
216 wxString s;
217 s.reserve(256);
218
219 if ( length == 1 )
220 {
221 const BYTE b = *(PBYTE)pAddress;
222
223 if ( bt == BASICTYPE_BOOL )
224 s = b ? _T("true") : _T("false");
225 else
226 s.Printf(_T("%#04x"), b);
227 }
228 else if ( length == 2 )
229 {
230 s.Printf(bt == BASICTYPE_UINT ? _T("%#06x") : _T("%d"),
231 *(PWORD)pAddress);
232 }
233 else if ( length == 4 )
234 {
235 bool handled = false;
236
237 if ( bt == BASICTYPE_FLOAT )
238 {
239 s.Printf(_T("%f"), *(PFLOAT)pAddress);
240
241 handled = true;
242 }
243 else if ( bt == BASICTYPE_CHAR )
244 {
245 // don't take more than 32 characters of a string
246 static const size_t NUM_CHARS = 64;
247
248 const char *pc = *(PSTR *)pAddress;
249 if ( ::IsBadStringPtrA(pc, NUM_CHARS) == 0 )
250 {
251 s += _T('"');
252 for ( size_t n = 0; n < NUM_CHARS && *pc; n++, pc++ )
253 {
254 s += *pc;
255 }
256 s += _T('"');
257
258 handled = true;
259 }
260 }
261
262 if ( !handled )
263 {
264 // treat just as an opaque DWORD
265 s.Printf(_T("%#x"), *(PDWORD)pAddress);
266 }
267 }
268 else if ( length == 8 )
269 {
270 if ( bt == BASICTYPE_FLOAT )
271 {
272 s.Printf(_T("%lf"), *(double *)pAddress);
273 }
274 else // opaque 64 bit value
275 {
276 s.Printf(_T("%#" wxLongLongFmtSpec _T("x")), *(PDWORD *)pAddress);
277 }
278 }
279
280 return s;
281}
282
283wxString
284wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level)
285{
286 wxString s;
287
288 // avoid infinite recursion
289 if ( level > 100 )
290 {
291 return s;
292 }
293
294 SymbolTag tag = SYMBOL_TAG_NULL;
295 if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) )
296 {
297 return s;
298 }
299
300 switch ( tag )
301 {
302 case SYMBOL_TAG_UDT:
303 case SYMBOL_TAG_BASE_CLASS:
304 s = DumpUDT(pSym, pVariable, level);
305 break;
306
307 case SYMBOL_TAG_DATA:
120678ee 308 if ( !pVariable )
3d8b5d85 309 {
120678ee 310 s = _T("NULL");
3d8b5d85 311 }
120678ee
VZ
312 else // valid location
313 {
314 wxDbgHelpDLL::DataKind kind;
315 if ( !DoGetTypeInfo(pSym, TI_GET_DATAKIND, &kind) ||
316 kind != DATA_MEMBER )
317 {
318 // maybe it's a static member? we're not interested in them...
319 break;
320 }
3d8b5d85 321
120678ee
VZ
322 // get the offset of the child member, relative to its parent
323 DWORD ofs = 0;
324 if ( !DoGetTypeInfo(pSym, TI_GET_OFFSET, &ofs) )
325 break;
3d8b5d85 326
120678ee 327 pVariable = (void *)((DWORD_PTR)pVariable + ofs);
3d8b5d85
VZ
328
329
120678ee
VZ
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) )
333 break;
3d8b5d85 334
120678ee
VZ
335 ULONG64 size;
336 DoGetTypeInfo(&sym, TI_GET_LENGTH, &size);
3d8b5d85 337
120678ee
VZ
338 switch ( DereferenceSymbol(&sym, &pVariable) )
339 {
340 case SYMBOL_TAG_BASE_TYPE:
3d8b5d85 341 {
120678ee
VZ
342 BasicType bt = GetBasicType(&sym);
343 if ( bt )
344 {
345 s = DumpBaseType(bt, size, pVariable);
346 }
3d8b5d85 347 }
120678ee 348 break;
3d8b5d85 349
120678ee
VZ
350 case SYMBOL_TAG_UDT:
351 case SYMBOL_TAG_BASE_CLASS:
352 s = DumpUDT(&sym, pVariable, level);
353 break;
354 }
3d8b5d85
VZ
355 }
356
357 if ( !s.empty() )
358 {
359 s = GetSymbolName(pSym) + _T(" = ") + s;
360 }
361 break;
362 }
363
364 if ( !s.empty() )
365 {
366 s = wxString(_T('\t'), level + 1) + s + _T('\n');
367 }
368
369 return s;
370}
371
372/* static */ wxString
373wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level)
374{
375 wxString s;
376 s.reserve(512);
377 s = GetSymbolName(pSym);
378
379#if !wxUSE_STL
380 // special handling for ubiquitous wxString: although the code below works
381 // for it as well, it shows the wxStringBase class and takes 4 lines
382 // instead of only one as this branch
383 if ( s == _T("wxString") )
384 {
385 wxString *ps = (wxString *)pVariable;
386 s << _T("(\"") << *ps << _T(")\"");
387 }
388 else // any other UDT
389#endif // !wxUSE_STL
390 {
391 // Determine how many children this type has.
392 DWORD dwChildrenCount = 0;
393 DoGetTypeInfo(pSym, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
394
395 // Prepare to get an array of "TypeIds", representing each of the children.
396 TI_FINDCHILDREN_PARAMS *children = (TI_FINDCHILDREN_PARAMS *)
397 malloc(sizeof(TI_FINDCHILDREN_PARAMS) +
398 (dwChildrenCount - 1)*sizeof(ULONG));
399 if ( !children )
400 return s;
401
402 children->Count = dwChildrenCount;
403 children->Start = 0;
404
405 // Get the array of TypeIds, one for each child type
406 if ( !DoGetTypeInfo(pSym, TI_FINDCHILDREN, children) )
407 {
408 free(children);
409 return s;
410 }
411
412 s << _T(" {\n");
413
414 // Iterate through all children
415 SYMBOL_INFO sym;
416 wxZeroMemory(sym);
417 sym.ModBase = pSym->ModBase;
418 for ( unsigned i = 0; i < dwChildrenCount; i++ )
419 {
420 sym.TypeIndex = children->ChildId[i];
421
422 // children here are in lexicographic sense, i.e. we get all our nested
423 // classes and not only our member fields, but we can't get the values
424 // for the members of the nested classes, of course!
425 DWORD nested;
426 if ( DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) && nested )
427 continue;
428
429 // avoid infinite recursion: this does seem to happen sometimes with
430 // complex typedefs...
431 if ( sym.TypeIndex == pSym->TypeIndex )
432 continue;
433
434 s += DumpField(&sym, pVariable, level + 1);
435 }
436
437 free(children);
438
439 s << wxString(_T('\t'), level + 1) << _T('}');
440 }
441
442 return s;
443}
444
445/* static */
446wxDbgHelpDLL::SymbolTag
447wxDbgHelpDLL::DereferenceSymbol(PSYMBOL_INFO pSym, void **ppData)
448{
449 SymbolTag tag = SYMBOL_TAG_NULL;
450 for ( ;; )
451 {
452 if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) )
453 break;
454
455 if ( tag != SYMBOL_TAG_POINTER_TYPE )
456 break;
457
458 ULONG tiNew;
459 if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &tiNew) ||
460 tiNew == pSym->TypeIndex )
461 break;
462
463 pSym->TypeIndex = tiNew;
464
465 // remove one level of indirection except for the char strings: we want
466 // to dump "char *" and not a single "char" for them
467 if ( ppData && *ppData && GetBasicType(pSym) != BASICTYPE_CHAR )
120678ee
VZ
468 {
469 DWORD_PTR *pData = (DWORD_PTR *)*ppData;
470
471 if ( ::IsBadReadPtr(pData, sizeof(DWORD_PTR *)) )
472 {
473 break;
474 }
475
476 *ppData = (void *)*pData;
477 }
3d8b5d85
VZ
478 }
479
480 return tag;
481}
482
483/* static */ wxString
484wxDbgHelpDLL::DumpSymbol(PSYMBOL_INFO pSym, void *pVariable)
485{
486 wxString s;
487 SYMBOL_INFO symDeref = *pSym;
488 switch ( DereferenceSymbol(&symDeref, &pVariable) )
489 {
490 case SYMBOL_TAG_UDT:
491 // show UDT recursively
492 s = DumpUDT(&symDeref, pVariable);
493 break;
494
495 case SYMBOL_TAG_BASE_TYPE:
496 // variable of simple type, show directly
497 BasicType bt = GetBasicType(&symDeref);
498 if ( bt )
499 {
500 s = DumpBaseType(bt, pSym->Size, pVariable);
501 }
502 break;
503 }
504
505 return s;
506}
507
508// ----------------------------------------------------------------------------
509// debugging helpers
510// ----------------------------------------------------------------------------
511
e84ba59e
VZ
512// this code is very useful when debugging debughlp.dll-related code but
513// probably not worth having compiled in normally, please do not remove it!
514#if 0 // ndef NDEBUG
3d8b5d85
VZ
515
516static wxString TagString(wxDbgHelpDLL::SymbolTag tag)
517{
518 static const wxChar *tags[] =
519 {
520 _T("null"),
521 _T("exe"),
522 _T("compiland"),
523 _T("compiland details"),
524 _T("compiland env"),
525 _T("function"),
526 _T("block"),
527 _T("data"),
528 _T("annotation"),
529 _T("label"),
530 _T("public symbol"),
531 _T("udt"),
532 _T("enum"),
533 _T("function type"),
534 _T("pointer type"),
535 _T("array type"),
536 _T("base type"),
537 _T("typedef"),
538 _T("base class"),
539 _T("friend"),
540 _T("function arg type"),
541 _T("func debug start"),
542 _T("func debug end"),
543 _T("using namespace"),
544 _T("vtable shape"),
545 _T("vtable"),
546 _T("custom"),
547 _T("thunk"),
548 _T("custom type"),
549 _T("managed type"),
550 _T("dimension"),
551 };
552
553 wxCOMPILE_TIME_ASSERT( WXSIZEOF(tags) == wxDbgHelpDLL::SYMBOL_TAG_MAX,
554 SymbolTagStringMismatch );
555
556 wxString s;
557 if ( tag < WXSIZEOF(tags) )
558 s = tags[tag];
559 else
560 s.Printf(_T("unrecognized tag (%d)"), tag);
561
562 return s;
563}
564
565static wxString KindString(wxDbgHelpDLL::DataKind kind)
566{
567 static const wxChar *kinds[] =
568 {
569 _T("unknown"),
570 _T("local"),
571 _T("static local"),
572 _T("param"),
573 _T("object ptr"),
574 _T("file static"),
575 _T("global"),
576 _T("member"),
577 _T("static member"),
578 _T("constant"),
579 };
580
581 wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::DATA_MAX,
582 DataKindStringMismatch );
583
584 wxString s;
585 if ( kind < WXSIZEOF(kinds) )
586 s = kinds[kind];
587 else
588 s.Printf(_T("unrecognized kind (%d)"), kind);
589
590 return s;
591}
592
593static wxString UdtKindString(wxDbgHelpDLL::UdtKind kind)
594{
595 static const wxChar *kinds[] =
596 {
597 _T("struct"),
598 _T("class"),
599 _T("union"),
600 };
601
602 wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::UDT_MAX,
603 UDTKindStringMismatch );
604
605 wxString s;
606 if ( kind < WXSIZEOF(kinds) )
607 s = kinds[kind];
608 else
609 s.Printf(_T("unrecognized UDT (%d)"), kind);
610
611 return s;
612}
613
614static wxString TypeString(wxDbgHelpDLL::BasicType bt)
615{
616 static const wxChar *types[] =
617 {
618 _T("no type"),
619 _T("void"),
620 _T("char"),
621 _T("wchar"),
622 _T(""),
623 _T(""),
624 _T("int"),
625 _T("uint"),
626 _T("float"),
627 _T("bcd"),
628 _T("bool"),
629 _T(""),
630 _T(""),
631 _T("long"),
632 _T("ulong"),
633 _T(""),
634 _T(""),
635 _T(""),
636 _T(""),
637 _T(""),
638 _T(""),
639 _T(""),
640 _T(""),
641 _T(""),
642 _T(""),
643 _T("CURRENCY"),
644 _T("DATE"),
645 _T("VARIANT"),
646 _T("complex"),
647 _T("bit"),
648 _T("BSTR"),
649 _T("HRESULT"),
650 };
651
652 wxCOMPILE_TIME_ASSERT( WXSIZEOF(types) == wxDbgHelpDLL::BASICTYPE_MAX,
653 BasicTypeStringMismatch );
654
655 wxString s;
656 if ( bt < WXSIZEOF(types) )
657 s = types[bt];
658
659 if ( s.empty() )
660 s.Printf(_T("unrecognized type (%d)"), bt);
661
662 return s;
663}
664
665// this function is meant to be called from under debugger to see the
666// proprieties of the given type id
667extern "C" void DumpTI(ULONG ti)
668{
669 SYMBOL_INFO sym = { sizeof(SYMBOL_INFO) };
670 sym.ModBase = 0x400000; // it's a constant under Win32
671 sym.TypeIndex = ti;
672
673 wxDbgHelpDLL::SymbolTag tag = wxDbgHelpDLL::SYMBOL_TAG_NULL;
674 DoGetTypeInfo(&sym, TI_GET_SYMTAG, &tag);
675 DoGetTypeInfo(&sym, TI_GET_TYPEID, &ti);
676
677 OutputDebugString(wxString::Format(_T("Type 0x%x: "), sym.TypeIndex));
678 wxString name = wxDbgHelpDLL::GetSymbolName(&sym);
679 if ( !name.empty() )
680 {
681 OutputDebugString(wxString::Format(_T("name=\"%s\", "), name.c_str()));
682 }
683
684 DWORD nested;
685 if ( !DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) )
686 {
687 nested = FALSE;
688 }
689
690 OutputDebugString(wxString::Format(_T("tag=%s%s"),
f31a4098 691 nested ? _T("nested ") : wxEmptyString,
3d8b5d85
VZ
692 TagString(tag).c_str()));
693 if ( tag == wxDbgHelpDLL::SYMBOL_TAG_UDT )
694 {
695 wxDbgHelpDLL::UdtKind udtKind;
696 if ( DoGetTypeInfo(&sym, TI_GET_UDTKIND, &udtKind) )
697 {
698 OutputDebugString(_T(" (") + UdtKindString(udtKind) + _T(')'));
699 }
700 }
701
702 wxDbgHelpDLL::DataKind kind = wxDbgHelpDLL::DATA_UNKNOWN;
703 if ( DoGetTypeInfo(&sym, TI_GET_DATAKIND, &kind) )
704 {
705 OutputDebugString(wxString::Format(
706 _T(", kind=%s"), KindString(kind).c_str()));
707 if ( kind == wxDbgHelpDLL::DATA_MEMBER )
708 {
709 DWORD ofs = 0;
710 if ( DoGetTypeInfo(&sym, TI_GET_OFFSET, &ofs) )
711 {
712 OutputDebugString(wxString::Format(_T(" (ofs=0x%x)"), ofs));
713 }
714 }
715 }
716
717 wxDbgHelpDLL::BasicType bt = GetBasicType(&sym);
718 if ( bt )
719 {
720 OutputDebugString(wxString::Format(_T(", type=%s"),
721 TypeString(bt).c_str()));
722 }
723
724 if ( ti != sym.TypeIndex )
725 {
726 OutputDebugString(wxString::Format(_T(", next ti=0x%x"), ti));
727 }
728
e84ba59e 729 OutputDebugString(_T("\r\n"));
3d8b5d85
VZ
730}
731
732#endif // NDEBUG
733
734#endif // wxUSE_DBGHELP