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