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

  ViewVC Help
Powered by ViewVC 1.1.22