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