/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/msw/debughlp.cpp
ViewVC logotype

Contents of /trunk/3rdparty/wxWidgets/src/msw/debughlp.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22