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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (hide annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 11 months ago) by william
File size: 21407 byte(s)
committing r3113 initial commit again...
1 william 31 /////////////////////////////////////////////////////////////////////////////
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     // ============================================================================
46     // wxDbgHelpDLL implementation
47     // ============================================================================
48    
49     // ----------------------------------------------------------------------------
50     // static members
51     // ----------------------------------------------------------------------------
52    
53     #define DEFINE_SYM_FUNCTION(func) wxDbgHelpDLL::func ## _t wxDbgHelpDLL::func = 0
54    
55     wxDO_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    
65     static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
66     {
67     #define LOAD_SYM_FUNCTION(name) \
68     wxDbgHelpDLL::name = (wxDbgHelpDLL::name ## _t) \
69     dllDbgHelp.GetSymbol(_T(#name)); \
70     if ( !wxDbgHelpDLL::name ) \
71     { \
72     gs_errMsg += _T("Function ") _T(#name) _T("() not found.\n"); \
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
84     static bool DoInit()
85     {
86     wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM);
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    
102     gs_errMsg += _T("\nPlease update your dbghelp.dll version, ")
103     _T("at least version 5.1 is needed!\n")
104     _T("(if you already have a new version, please ")
105     _T("put it in the same directory where the program is.)\n");
106     }
107     else // failed to load dbghelp.dll
108     {
109     gs_errMsg += _T("Please install dbghelp.dll available free of charge ")
110     _T("from Microsoft to get more detailed crash information!");
111     }
112    
113     gs_errMsg += _T("\nLatest dbghelp.dll is available at ")
114     _T("http://www.microsoft.com/whdc/ddk/debugging/\n");
115    
116     return false;
117     }
118    
119     /* static */
120     bool 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 */
139     const wxString& wxDbgHelpDLL::GetErrorMessage()
140     {
141     return gs_errMsg;
142     }
143    
144     /* static */
145     void wxDbgHelpDLL::LogError(const wxChar *func)
146     {
147     ::OutputDebugString(wxString::Format(_T("dbghelp: %s() failed: %s\r\n"),
148     func, wxSysErrorMsg(::GetLastError())));
149     }
150    
151     // ----------------------------------------------------------------------------
152     // data dumping
153     // ----------------------------------------------------------------------------
154    
155     static inline
156     bool
157     DoGetTypeInfo(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    
171     static inline
172     bool
173     DoGetTypeInfo(PSYMBOL_INFO pSym, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc)
174     {
175     return DoGetTypeInfo(pSym->ModBase, pSym->TypeIndex, type, rc);
176     }
177    
178     static inline
179     wxDbgHelpDLL::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 */
188     wxString 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
211     wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress)
212     {
213     if ( !pAddress )
214     {
215     return _T("null");
216     }
217    
218     if ( ::IsBadReadPtr(pAddress, length) != 0 )
219     {
220     return _T("BAD");
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 )
232     s = b ? _T("true") : _T("false");
233     else
234     s.Printf(_T("%#04x"), b);
235     }
236     else if ( length == 2 )
237     {
238     s.Printf(bt == BASICTYPE_UINT ? _T("%#06x") : _T("%d"),
239     *(PWORD)pAddress);
240     }
241     else if ( length == 4 )
242     {
243     bool handled = false;
244    
245     if ( bt == BASICTYPE_FLOAT )
246     {
247     s.Printf(_T("%f"), *(PFLOAT)pAddress);
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     {
259     s += _T('"');
260     for ( size_t n = 0; n < NUM_CHARS && *pc; n++, pc++ )
261     {
262     s += *pc;
263     }
264     s += _T('"');
265    
266     handled = true;
267     }
268     }
269    
270     if ( !handled )
271     {
272     // treat just as an opaque DWORD
273     s.Printf(_T("%#x"), *(PDWORD)pAddress);
274     }
275     }
276     else if ( length == 8 )
277     {
278     if ( bt == BASICTYPE_FLOAT )
279     {
280     s.Printf(_T("%lf"), *(double *)pAddress);
281     }
282     else // opaque 64 bit value
283     {
284     s.Printf(_T("%#" wxLongLongFmtSpec _T("x")), *(PDWORD *)pAddress);
285     }
286     }
287    
288     return s;
289     }
290    
291     wxString
292     wxDbgHelpDLL::DumpField(PSYMBOL_INFO pSym, void *pVariable, unsigned level)
293     {
294     wxString s;
295    
296     // avoid infinite recursion
297     if ( level > MAX_DUMP_DEPTH )
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:
316     if ( !pVariable )
317     {
318     s = _T("NULL");
319     }
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     }
329    
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;
334    
335     pVariable = (void *)((DWORD_PTR)pVariable + ofs);
336    
337    
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;
342    
343     ULONG64 size;
344     DoGetTypeInfo(&sym, TI_GET_LENGTH, &size);
345    
346     switch ( DereferenceSymbol(&sym, &pVariable) )
347     {
348     case SYMBOL_TAG_BASE_TYPE:
349     {
350     BasicType bt = GetBasicType(&sym);
351     if ( bt )
352     {
353     s = DumpBaseType(bt, size, pVariable);
354     }
355     }
356     break;
357    
358     case SYMBOL_TAG_UDT:
359     case SYMBOL_TAG_BASE_CLASS:
360     s = DumpUDT(&sym, pVariable, level);
361     break;
362     }
363     }
364    
365     if ( !s.empty() )
366     {
367     s = GetSymbolName(pSym) + _T(" = ") + s;
368     }
369     break;
370     }
371    
372     if ( !s.empty() )
373     {
374     s = wxString(_T('\t'), level + 1) + s + _T('\n');
375     }
376    
377     return s;
378     }
379    
380     /* static */ wxString
381     wxDbgHelpDLL::DumpUDT(PSYMBOL_INFO pSym, void *pVariable, unsigned level)
382     {
383     wxString s;
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    
391     s.reserve(512);
392     s = GetSymbolName(pSym);
393    
394     #if !wxUSE_STL
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
398     if ( s == _T("wxString") )
399     {
400     wxString *ps = (wxString *)pVariable;
401    
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
407     const wxChar *p = NULL;
408     if ( !::IsBadReadPtr(ps, sizeof(wxString)) )
409     {
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     }
417     }
418    
419     s << _T("(\"") << (p ? p : _T("???")) << _T(")\"");
420     }
421     else // any other UDT
422     #endif // !wxUSE_STL
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    
445     s << _T(" {\n");
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    
472     s << wxString(_T('\t'), level + 1) << _T('}');
473     }
474    
475     return s;
476     }
477    
478     /* static */
479     wxDbgHelpDLL::SymbolTag
480     wxDbgHelpDLL::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 )
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     }
511     }
512    
513     return tag;
514     }
515    
516     /* static */ wxString
517     wxDbgHelpDLL::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    
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
548    
549     static wxString TagString(wxDbgHelpDLL::SymbolTag tag)
550     {
551     static const wxChar *tags[] =
552     {
553     _T("null"),
554     _T("exe"),
555     _T("compiland"),
556     _T("compiland details"),
557     _T("compiland env"),
558     _T("function"),
559     _T("block"),
560     _T("data"),
561     _T("annotation"),
562     _T("label"),
563     _T("public symbol"),
564     _T("udt"),
565     _T("enum"),
566     _T("function type"),
567     _T("pointer type"),
568     _T("array type"),
569     _T("base type"),
570     _T("typedef"),
571     _T("base class"),
572     _T("friend"),
573     _T("function arg type"),
574     _T("func debug start"),
575     _T("func debug end"),
576     _T("using namespace"),
577     _T("vtable shape"),
578     _T("vtable"),
579     _T("custom"),
580     _T("thunk"),
581     _T("custom type"),
582     _T("managed type"),
583     _T("dimension"),
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
593     s.Printf(_T("unrecognized tag (%d)"), tag);
594    
595     return s;
596     }
597    
598     static wxString KindString(wxDbgHelpDLL::DataKind kind)
599     {
600     static const wxChar *kinds[] =
601     {
602     _T("unknown"),
603     _T("local"),
604     _T("static local"),
605     _T("param"),
606     _T("object ptr"),
607     _T("file static"),
608     _T("global"),
609     _T("member"),
610     _T("static member"),
611     _T("constant"),
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
621     s.Printf(_T("unrecognized kind (%d)"), kind);
622    
623     return s;
624     }
625    
626     static wxString UdtKindString(wxDbgHelpDLL::UdtKind kind)
627     {
628     static const wxChar *kinds[] =
629     {
630     _T("struct"),
631     _T("class"),
632     _T("union"),
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
642     s.Printf(_T("unrecognized UDT (%d)"), kind);
643    
644     return s;
645     }
646    
647     static wxString TypeString(wxDbgHelpDLL::BasicType bt)
648     {
649     static const wxChar *types[] =
650     {
651     _T("no type"),
652     _T("void"),
653     _T("char"),
654     _T("wchar"),
655     _T(""),
656     _T(""),
657     _T("int"),
658     _T("uint"),
659     _T("float"),
660     _T("bcd"),
661     _T("bool"),
662     _T(""),
663     _T(""),
664     _T("long"),
665     _T("ulong"),
666     _T(""),
667     _T(""),
668     _T(""),
669     _T(""),
670     _T(""),
671     _T(""),
672     _T(""),
673     _T(""),
674     _T(""),
675     _T(""),
676     _T("CURRENCY"),
677     _T("DATE"),
678     _T("VARIANT"),
679     _T("complex"),
680     _T("bit"),
681     _T("BSTR"),
682     _T("HRESULT"),
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() )
693     s.Printf(_T("unrecognized type (%d)"), bt);
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
700     extern "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    
710     OutputDebugString(wxString::Format(_T("Type 0x%x: "), sym.TypeIndex));
711     wxString name = wxDbgHelpDLL::GetSymbolName(&sym);
712     if ( !name.empty() )
713     {
714     OutputDebugString(wxString::Format(_T("name=\"%s\", "), name.c_str()));
715     }
716    
717     DWORD nested;
718     if ( !DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) )
719     {
720     nested = FALSE;
721     }
722    
723     OutputDebugString(wxString::Format(_T("tag=%s%s"),
724     nested ? _T("nested ") : wxEmptyString,
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     {
731     OutputDebugString(_T(" (") + UdtKindString(udtKind) + _T(')'));
732     }
733     }
734    
735     wxDbgHelpDLL::DataKind kind = wxDbgHelpDLL::DATA_UNKNOWN;
736     if ( DoGetTypeInfo(&sym, TI_GET_DATAKIND, &kind) )
737     {
738     OutputDebugString(wxString::Format(
739     _T(", kind=%s"), KindString(kind).c_str()));
740     if ( kind == wxDbgHelpDLL::DATA_MEMBER )
741     {
742     DWORD ofs = 0;
743     if ( DoGetTypeInfo(&sym, TI_GET_OFFSET, &ofs) )
744     {
745     OutputDebugString(wxString::Format(_T(" (ofs=0x%x)"), ofs));
746     }
747     }
748     }
749    
750     wxDbgHelpDLL::BasicType bt = GetBasicType(&sym);
751     if ( bt )
752     {
753     OutputDebugString(wxString::Format(_T(", type=%s"),
754     TypeString(bt).c_str()));
755     }
756    
757     if ( ti != sym.TypeIndex )
758     {
759     OutputDebugString(wxString::Format(_T(", next ti=0x%x"), ti));
760     }
761    
762     OutputDebugString(_T("\r\n"));
763     }
764    
765     #endif // NDEBUG
766    
767     #endif // wxUSE_DBGHELP

  ViewVC Help
Powered by ViewVC 1.1.22