]> git.saurik.com Git - wxWidgets.git/blob - src/msw/debughlp.cpp
8a76027c76411d87ddc772519618b955a1281476
[wxWidgets.git] / src / msw / debughlp.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/debughlp.cpp
3 // Purpose: various Win32 debug helpers
4 // Author: Vadim Zeitlin
5 // Modified by: Suzumizaki-kimitaka 2013-04-10
6 // Created: 2005-01-08 (extracted from crashrpt.cpp)
7 // Copyright: (c) 2003-2005 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21 #ifdef __BORLANDC__
22 #pragma hdrstop
23 #endif
24
25 #include "wx/msw/debughlp.h"
26
27 #if wxUSE_DBGHELP && wxUSE_DYNLIB_CLASS
28
29 // ----------------------------------------------------------------------------
30 // constants
31 // ----------------------------------------------------------------------------
32
33 // to prevent recursion which could result from corrupted data we limit
34 // ourselves to that many levels of embedded fields inside structs
35 static const unsigned MAX_DUMP_DEPTH = 20;
36
37 // ----------------------------------------------------------------------------
38 // globals
39 // ----------------------------------------------------------------------------
40
41 // error message from Init()
42 static wxString gs_errMsg;
43
44 // ============================================================================
45 // wxDbgHelpDLL implementation
46 // ============================================================================
47
48 // ----------------------------------------------------------------------------
49 // static members
50 // ----------------------------------------------------------------------------
51
52 #define DEFINE_SYM_FUNCTION(func, name) \
53 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 */
66 bool wxDbgHelpDLL::BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
67 {
68 #define LOAD_SYM_FUNCTION(func, name) \
69 wxDbgHelpDLL::func = (wxDbgHelpDLL::func ## _t) \
70 dllDbgHelp.GetSymbol(wxT(#name)); \
71 if ( !wxDbgHelpDLL::func ) \
72 { \
73 gs_errMsg += wxT("Function ") wxT(#name) wxT("() not found.\n"); \
74 return false; \
75 }
76
77 wxDO_FOR_ALL_SYM_FUNCS_REQUIRED(LOAD_SYM_FUNCTION);
78
79 #undef LOAD_SYM_FUNCTION
80
81 #define LOAD_SYM_FUNCTION_OPTIONAL(func, name) \
82 if ( dllDbgHelp.HasSymbol(wxT(#name)) ) \
83 { \
84 wxDbgHelpDLL::func = (wxDbgHelpDLL::func ## _t) \
85 dllDbgHelp.GetSymbol(wxT(#name)); \
86 }
87
88 wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(LOAD_SYM_FUNCTION_OPTIONAL);
89
90 #undef LOAD_SYM_FUNCTION_CAN_FAIL
91
92 return true;
93 }
94
95 // called by Init() if we hadn't done this before
96 /* static */
97 bool wxDbgHelpDLL::DoInit()
98 {
99 wxDynamicLibrary dllDbgHelp(wxT("dbghelp.dll"), wxDL_VERBATIM);
100 if ( dllDbgHelp.IsLoaded() )
101 {
102 if ( BindDbgHelpFunctions(dllDbgHelp) )
103 {
104 // turn on default options
105 DWORD options = wxDbgHelpDLL::SymGetOptions();
106
107 options |= SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_DEBUG;
108
109 wxDbgHelpDLL::SymSetOptions(options);
110
111 dllDbgHelp.Detach();
112 return true;
113 }
114
115 gs_errMsg += wxT("\nPlease update your dbghelp.dll version, ")
116 wxT("at least version 5.1 is needed!\n")
117 wxT("(if you already have a new version, please ")
118 wxT("put it in the same directory where the program is.)\n");
119 }
120 else // failed to load dbghelp.dll
121 {
122 gs_errMsg += wxT("Please install dbghelp.dll available free of charge ")
123 wxT("from Microsoft to get more detailed crash information!");
124 }
125
126 gs_errMsg += wxT("\nLatest dbghelp.dll is available at ")
127 wxT("http://www.microsoft.com/whdc/ddk/debugging/\n");
128
129 return false;
130 }
131
132 /* static */
133 bool wxDbgHelpDLL::Init()
134 {
135 // this flag is -1 until Init() is called for the first time, then it's set
136 // to either false or true depending on whether we could load the functions
137 static int s_loaded = -1;
138
139 if ( s_loaded == -1 )
140 {
141 s_loaded = DoInit();
142 }
143
144 return s_loaded != 0;
145 }
146
147 // ----------------------------------------------------------------------------
148 // error handling
149 // ----------------------------------------------------------------------------
150
151 /* static */
152 const wxString& wxDbgHelpDLL::GetErrorMessage()
153 {
154 return gs_errMsg;
155 }
156
157 /* static */
158 void wxDbgHelpDLL::LogError(const wxChar *func)
159 {
160 ::OutputDebugString(wxString::Format(wxT("dbghelp: %s() failed: %s\r\n"),
161 func, wxSysErrorMsg(::GetLastError())).t_str());
162 }
163
164 // ----------------------------------------------------------------------------
165 // data dumping
166 // ----------------------------------------------------------------------------
167
168 static inline
169 bool
170 DoGetTypeInfo(DWORD64 base, ULONG ti, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc)
171 {
172 static HANDLE s_hProcess = ::GetCurrentProcess();
173
174 return wxDbgHelpDLL::SymGetTypeInfo
175 (
176 s_hProcess,
177 base,
178 ti,
179 type,
180 rc
181 ) != 0;
182 }
183
184 static inline
185 bool
186 DoGetTypeInfo(wxPSYMBOL_INFO pSym, IMAGEHLP_SYMBOL_TYPE_INFO type, void *rc)
187 {
188 return DoGetTypeInfo(pSym->ModBase, pSym->TypeIndex, type, rc);
189 }
190
191 static inline
192 wxDbgHelpDLL::BasicType GetBasicType(wxPSYMBOL_INFO pSym)
193 {
194 wxDbgHelpDLL::BasicType bt;
195 return DoGetTypeInfo(pSym, TI_GET_BASETYPE, &bt)
196 ? bt
197 : wxDbgHelpDLL::BASICTYPE_NOTYPE;
198 }
199
200 /* static */
201 wxString wxDbgHelpDLL::GetSymbolName(wxPSYMBOL_INFO pSym)
202 {
203 wxString s;
204
205 WCHAR *pwszTypeName;
206 if ( SymGetTypeInfo
207 (
208 GetCurrentProcess(),
209 pSym->ModBase,
210 pSym->TypeIndex,
211 TI_GET_SYMNAME,
212 &pwszTypeName
213 ) )
214 {
215 s = wxConvCurrent->cWC2WX(pwszTypeName);
216
217 ::LocalFree(pwszTypeName);
218 }
219
220 return s;
221 }
222
223 /* static */ wxString
224 wxDbgHelpDLL::DumpBaseType(BasicType bt, DWORD64 length, PVOID pAddress)
225 {
226 if ( !pAddress )
227 {
228 return wxT("null");
229 }
230
231 if ( ::IsBadReadPtr(pAddress, length) != 0 )
232 {
233 return wxT("BAD");
234 }
235
236
237 wxString s;
238 s.reserve(256);
239
240 if ( length == 1 )
241 {
242 const BYTE b = *(PBYTE)pAddress;
243
244 if ( bt == BASICTYPE_BOOL )
245 s = b ? wxT("true") : wxT("false");
246 else
247 s.Printf(wxT("%#04x"), b);
248 }
249 else if ( length == 2 )
250 {
251 s.Printf(bt == BASICTYPE_UINT ? wxT("%#06x") : wxT("%d"),
252 *(PWORD)pAddress);
253 }
254 else if ( length == 4 )
255 {
256 bool handled = false;
257
258 if ( bt == BASICTYPE_FLOAT )
259 {
260 s.Printf(wxT("%f"), *(PFLOAT)pAddress);
261
262 handled = true;
263 }
264 else if ( bt == BASICTYPE_CHAR )
265 {
266 // don't take more than 32 characters of a string
267 static const size_t NUM_CHARS = 64;
268
269 const char *pc = *(PSTR *)pAddress;
270 if ( ::IsBadStringPtrA(pc, NUM_CHARS) == 0 )
271 {
272 s += wxT('"');
273 for ( size_t n = 0; n < NUM_CHARS && *pc; n++, pc++ )
274 {
275 s += *pc;
276 }
277 s += wxT('"');
278
279 handled = true;
280 }
281 }
282
283 if ( !handled )
284 {
285 // treat just as an opaque DWORD
286 s.Printf(wxT("%#x"), *(PDWORD)pAddress);
287 }
288 }
289 else if ( length == 8 )
290 {
291 if ( bt == BASICTYPE_FLOAT )
292 {
293 s.Printf(wxT("%lf"), *(double *)pAddress);
294 }
295 else // opaque 64 bit value
296 {
297 s.Printf("%#" wxLongLongFmtSpec "x", *(wxLongLong_t *)pAddress);
298 }
299 }
300
301 return s;
302 }
303
304 wxString
305 wxDbgHelpDLL::DumpField(wxPSYMBOL_INFO pSym, void *pVariable, unsigned level)
306 {
307 wxString s;
308
309 // avoid infinite recursion
310 if ( level > MAX_DUMP_DEPTH )
311 {
312 return s;
313 }
314
315 SymbolTag tag = SYMBOL_TAG_NULL;
316 if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) )
317 {
318 return s;
319 }
320
321 switch ( tag )
322 {
323 case SYMBOL_TAG_UDT:
324 case SYMBOL_TAG_BASE_CLASS:
325 s = DumpUDT(pSym, pVariable, level);
326 break;
327
328 case SYMBOL_TAG_DATA:
329 if ( !pVariable )
330 {
331 s = wxT("NULL");
332 }
333 else // valid location
334 {
335 wxDbgHelpDLL::DataKind kind;
336 if ( !DoGetTypeInfo(pSym, TI_GET_DATAKIND, &kind) ||
337 kind != DATA_MEMBER )
338 {
339 // maybe it's a static member? we're not interested in them...
340 break;
341 }
342
343 // get the offset of the child member, relative to its parent
344 DWORD ofs = 0;
345 if ( !DoGetTypeInfo(pSym, TI_GET_OFFSET, &ofs) )
346 break;
347
348 pVariable = (void *)((DWORD_PTR)pVariable + ofs);
349
350
351 // now pass to the type representing the type of this member
352 wxSYMBOL_INFO sym = *pSym;
353 if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &sym.TypeIndex) )
354 break;
355
356 ULONG64 size;
357 DoGetTypeInfo(&sym, TI_GET_LENGTH, &size);
358
359 switch ( DereferenceSymbol(&sym, &pVariable) )
360 {
361 case SYMBOL_TAG_BASE_TYPE:
362 {
363 BasicType bt = GetBasicType(&sym);
364 if ( bt )
365 {
366 s = DumpBaseType(bt, size, pVariable);
367 }
368 }
369 break;
370
371 case SYMBOL_TAG_UDT:
372 case SYMBOL_TAG_BASE_CLASS:
373 s = DumpUDT(&sym, pVariable, level);
374 break;
375
376 default:
377 // Suppress gcc warnings about unhandled enum values.
378 break;
379 }
380 }
381
382 if ( !s.empty() )
383 {
384 s = GetSymbolName(pSym) + wxT(" = ") + s;
385 }
386 break;
387
388 default:
389 // Suppress gcc warnings about unhandled enum values, don't assert
390 // to avoid problems during fatal crash generation.
391 break;
392 }
393
394 if ( !s.empty() )
395 {
396 s = wxString(wxT('\t'), level + 1) + s + wxT('\n');
397 }
398
399 return s;
400 }
401
402 /* static */ wxString
403 wxDbgHelpDLL::DumpUDT(wxPSYMBOL_INFO pSym, void *pVariable, unsigned level)
404 {
405 wxString s;
406
407 // we have to limit the depth of UDT dumping as otherwise we get in
408 // infinite loops trying to dump linked lists... 10 levels seems quite
409 // reasonable, full information is in minidump file anyhow
410 if ( level > 10 )
411 return s;
412
413 s.reserve(512);
414 s = GetSymbolName(pSym);
415
416 #if !wxUSE_STD_STRING
417 // special handling for ubiquitous wxString: although the code below works
418 // for it as well, it shows the wxStringBase class and takes 4 lines
419 // instead of only one as this branch
420 if ( s == wxT("wxString") )
421 {
422 wxString *ps = (wxString *)pVariable;
423
424 // we can't just dump wxString directly as it could be corrupted or
425 // invalid and it could also be locked for writing (i.e. if we're
426 // between GetWriteBuf() and UngetWriteBuf() calls) and assert when we
427 // try to access it contents using public methods, so instead use our
428 // knowledge of its internals
429 const wxChar *p = NULL;
430 if ( !::IsBadReadPtr(ps, sizeof(wxString)) )
431 {
432 p = ps->data();
433 wxStringData *data = (wxStringData *)p - 1;
434 if ( ::IsBadReadPtr(data, sizeof(wxStringData)) ||
435 ::IsBadReadPtr(p, sizeof(wxChar *)*data->nAllocLength) )
436 {
437 p = NULL; // don't touch this pointer with 10 feet pole
438 }
439 }
440
441 s << wxT("(\"") << (p ? p : wxT("???")) << wxT(")\"");
442 }
443 else // any other UDT
444 #endif // !wxUSE_STD_STRING
445 {
446 // Determine how many children this type has.
447 DWORD dwChildrenCount = 0;
448 DoGetTypeInfo(pSym, TI_GET_CHILDRENCOUNT, &dwChildrenCount);
449
450 // Prepare to get an array of "TypeIds", representing each of the children.
451 TI_FINDCHILDREN_PARAMS *children = (TI_FINDCHILDREN_PARAMS *)
452 malloc(sizeof(TI_FINDCHILDREN_PARAMS) +
453 (dwChildrenCount - 1)*sizeof(ULONG));
454 if ( !children )
455 return s;
456
457 children->Count = dwChildrenCount;
458 children->Start = 0;
459
460 // Get the array of TypeIds, one for each child type
461 if ( !DoGetTypeInfo(pSym, TI_FINDCHILDREN, children) )
462 {
463 free(children);
464 return s;
465 }
466
467 s << wxT(" {\n");
468
469 // Iterate through all children
470 wxSYMBOL_INFO sym;
471 wxZeroMemory(sym);
472 sym.ModBase = pSym->ModBase;
473 for ( unsigned i = 0; i < dwChildrenCount; i++ )
474 {
475 sym.TypeIndex = children->ChildId[i];
476
477 // children here are in lexicographic sense, i.e. we get all our nested
478 // classes and not only our member fields, but we can't get the values
479 // for the members of the nested classes, of course!
480 DWORD nested;
481 if ( DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) && nested )
482 continue;
483
484 // avoid infinite recursion: this does seem to happen sometimes with
485 // complex typedefs...
486 if ( sym.TypeIndex == pSym->TypeIndex )
487 continue;
488
489 s += DumpField(&sym, pVariable, level + 1);
490 }
491
492 free(children);
493
494 s << wxString(wxT('\t'), level + 1) << wxT('}');
495 }
496
497 return s;
498 }
499
500 /* static */
501 wxDbgHelpDLL::SymbolTag
502 wxDbgHelpDLL::DereferenceSymbol(wxPSYMBOL_INFO pSym, void **ppData)
503 {
504 SymbolTag tag = SYMBOL_TAG_NULL;
505 for ( ;; )
506 {
507 if ( !DoGetTypeInfo(pSym, TI_GET_SYMTAG, &tag) )
508 break;
509
510 if ( tag != SYMBOL_TAG_POINTER_TYPE )
511 break;
512
513 ULONG tiNew;
514 if ( !DoGetTypeInfo(pSym, TI_GET_TYPEID, &tiNew) ||
515 tiNew == pSym->TypeIndex )
516 break;
517
518 pSym->TypeIndex = tiNew;
519
520 // remove one level of indirection except for the char strings: we want
521 // to dump "char *" and not a single "char" for them
522 if ( ppData && *ppData && GetBasicType(pSym) != BASICTYPE_CHAR )
523 {
524 DWORD_PTR *pData = (DWORD_PTR *)*ppData;
525
526 if ( ::IsBadReadPtr(pData, sizeof(DWORD_PTR *)) )
527 {
528 break;
529 }
530
531 *ppData = (void *)*pData;
532 }
533 }
534
535 return tag;
536 }
537
538 /* static */ wxString
539 wxDbgHelpDLL::DumpSymbol(wxPSYMBOL_INFO pSym, void *pVariable)
540 {
541 wxString s;
542 wxSYMBOL_INFO symDeref = *pSym;
543 switch ( DereferenceSymbol(&symDeref, &pVariable) )
544 {
545 default:
546 // Suppress gcc warnings about unhandled enum values, don't assert
547 // to avoid problems during fatal crash generation.
548 break;
549
550 case SYMBOL_TAG_UDT:
551 // show UDT recursively
552 s = DumpUDT(&symDeref, pVariable);
553 break;
554
555 case SYMBOL_TAG_BASE_TYPE:
556 // variable of simple type, show directly
557 BasicType bt = GetBasicType(&symDeref);
558 if ( bt )
559 {
560 s = DumpBaseType(bt, pSym->Size, pVariable);
561 }
562 break;
563 }
564
565 return s;
566 }
567
568 // ----------------------------------------------------------------------------
569 // do the best functions and structures
570 // ----------------------------------------------------------------------------
571
572 struct wxMswEnmLddMdlsHelperStruct
573 {
574 public:
575 wxMswEnmLddMdlsHelperStruct(wxPENUMLOADED_MODULES_CALLBACK64 ptr, PVOID content)
576 : m_pointer_to_callback(ptr), m_user_content(content)
577 { }
578 wxPENUMLOADED_MODULES_CALLBACK64 m_pointer_to_callback;
579 PVOID m_user_content;
580 };
581
582 #ifdef UNICODE
583
584 static BOOL CALLBACK wxMswEnmLddMdlsCallback1(
585 PCSTR ModuleName, DWORD64 ModuleBase, ULONG ModuleSize, PVOID UserContext)
586 {
587 wxMswEnmLddMdlsHelperStruct& alternate =
588 *(wxMswEnmLddMdlsHelperStruct*)(UserContext);
589
590 const wxWCharBuffer buf = wxConvLocal.cMB2WC(ModuleName, wxNO_LEN, NULL);
591 return (*alternate.m_pointer_to_callback)
592 (buf.data(), ModuleBase, ModuleSize, alternate.m_user_content);
593 }
594
595 static BOOL CALLBACK wxMswEnmLddMdlsCallback2(
596 PCSTR ModuleName, DWORD_PTR ModuleBase, ULONG ModuleSize, PVOID UserContext)
597 {
598 wxMswEnmLddMdlsHelperStruct& alternate =
599 *(wxMswEnmLddMdlsHelperStruct*)(UserContext);
600
601 const wxWCharBuffer buf = wxConvLocal.cMB2WC(ModuleName, wxNO_LEN, NULL);
602 return (*alternate.m_pointer_to_callback)
603 (buf.data(), ModuleBase, ModuleSize, alternate.m_user_content);
604 }
605
606 #else
607
608 static BOOL CALLBACK wxMswEnmLddMdlsCallback(
609 PCSTR ModuleName, DWORD_PTR ModuleBase, ULONG ModuleSize, PVOID UserContext)
610 {
611 wxMswEnmLddMdlsHelperStruct& alternate =
612 *(wxMswEnmLddMdlsHelperStruct*)(UserContext);
613
614 return (*alternate.m_pointer_to_callback)
615 (ModuleName, ModuleBase, ModuleSize, alternate.m_user_content);
616 }
617
618 #endif // UNICODE
619
620 /* static */
621 BOOL wxDbgHelpDLL::EnumerateLoadedModulesT(
622 HANDLE handle, wxPENUMLOADED_MODULES_CALLBACK64 callback, PVOID pvoid)
623 {
624 #ifdef UNICODE
625 if (EnumerateLoadedModulesW64)
626 {
627 const BOOL retVal = (*EnumerateLoadedModulesW64)(handle, callback, pvoid);
628 if (retVal)
629 return retVal;
630 }
631 if (EnumerateLoadedModules64)
632 {
633 wxMswEnmLddMdlsHelperStruct p(callback, pvoid);
634 const BOOL retVal =
635 (*EnumerateLoadedModules64)
636 (handle, &wxMswEnmLddMdlsCallback1, (PVOID)(&p));
637 if (retVal)
638 return retVal;
639 }
640 if (EnumerateLoadedModules)
641 {
642 wxMswEnmLddMdlsHelperStruct p(callback, pvoid);
643 const BOOL retVal =
644 (*EnumerateLoadedModules)
645 (handle, &wxMswEnmLddMdlsCallback2, (PVOID)(&p));
646 if (retVal)
647 return retVal;
648 }
649 return FALSE;
650 #else
651 if (EnumerateLoadedModules64)
652 {
653 const BOOL retVal = (*EnumerateLoadedModules64)(handle, callback, pvoid);
654 if (retVal)
655 return retVal;
656 }
657 if (EnumerateLoadedModules)
658 {
659 wxMswEnmLddMdlsHelperStruct p(callback, pvoid);
660 const BOOL retVal =
661 (*EnumerateLoadedModules)
662 (handle, &wxMswEnmLddMdlsCallback, (PVOID)(&p));
663 if (retVal)
664 return retVal;
665 }
666 return FALSE;
667 #endif
668 }
669
670 /* static */
671 BOOL wxDbgHelpDLL::SymInitializeT(HANDLE hProcess, LPCTSTR UserSearchPath, BOOL fInvadeProcess)
672 {
673 #ifdef UNICODE
674 if (SymInitializeW)
675 {
676 const BOOL retVal = (*SymInitializeW)(hProcess, UserSearchPath, fInvadeProcess);
677 if (retVal)
678 return retVal;
679 }
680 if (SymInitialize)
681 {
682 BOOL retVal;
683 if (UserSearchPath)
684 {
685 const wxCharBuffer buf = wxConvLocal.cWC2MB(UserSearchPath, wxNO_LEN, NULL);
686 retVal = (*SymInitialize)(hProcess, buf.data(), fInvadeProcess);
687 }
688 else
689 {
690 retVal = (*SymInitialize)(hProcess, NULL, fInvadeProcess);
691 }
692 return retVal;
693 }
694 return FALSE;
695 #else
696 if (SymInitialize)
697 {
698 return (*SymInitialize)(hProcess, UserSearchPath, fInvadeProcess);
699 }
700 return FALSE;
701 #endif
702 }
703
704 /* static */
705 BOOL wxDbgHelpDLL::SymFromAddrT(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, wxPSYMBOL_INFO Symbol)
706 {
707 #ifdef UNICODE
708 if (SymFromAddrW)
709 {
710 const BOOL retVal = (*SymFromAddrW)(hProcess, Address, Displacement, Symbol);
711 if (retVal)
712 return retVal;
713 }
714 if (SymFromAddr)
715 {
716 BYTE* symbolBuffer = new BYTE[sizeof(SYMBOL_INFO) + Symbol->MaxNameLen*sizeof(CHAR)];
717 PSYMBOL_INFO data = (SYMBOL_INFO*)(symbolBuffer);
718 wxZeroMemory(*data);
719 data->SizeOfStruct = sizeof(SYMBOL_INFO);
720 data->MaxNameLen = Symbol->MaxNameLen;
721 if (! (*SymFromAddr)(hProcess, Address, Displacement, data))
722 {
723 delete [] symbolBuffer;
724 return FALSE;
725 }
726
727 // We can't refer data->NameLen. It seems to be unmodified.
728 const wxWCharBuffer buf = wxConvLocal.cMB2WC(data->Name, wxNO_LEN, NULL);
729
730 // FIXME: I know too brute but some header names SYMBOL_INFO::Index
731 // and the other one defines it as SYMBOL_INFO::info.
732 const ULONG dstSize = Symbol->SizeOfStruct;
733 CopyMemory(Symbol, data, sizeof(SYMBOL_INFO)-sizeof(CHAR));
734 Symbol->SizeOfStruct = dstSize;
735 Symbol->NameLen = buf.length();
736 wxStrncpy(Symbol->Name, buf.data(), Symbol->MaxNameLen);
737 delete [] symbolBuffer;
738 return TRUE;
739 }
740 return FALSE;
741 #else
742 if (SymFromAddr)
743 {
744 return (*SymFromAddr)(hProcess, Address, Displacement, Symbol);
745 }
746 return FALSE;
747 #endif
748 }
749
750 /* static */
751 BOOL wxDbgHelpDLL::SymGetLineFromAddrT(HANDLE hProcess, DWORD64 dwAddr, PDWORD pdrDisplacement, wxPIMAGEHLP_LINE Line)
752 {
753 #ifdef UNICODE
754 if (SymGetLineFromAddrW64)
755 {
756 const BOOL retVal = (*SymGetLineFromAddrW64)(hProcess, dwAddr, pdrDisplacement, Line);
757 if (retVal)
758 return retVal;
759 // TODO: seems always fail with GetLastError() returns 487 with 32bit binary on 64 bit Windows.
760 }
761 static WCHAR staticBuf[MAX_PATH];
762 if (SymGetLineFromAddr64)
763 {
764 IMAGEHLP_LINE64 LineAlternate;
765 LineAlternate.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
766 if ((*SymGetLineFromAddr64)(hProcess, dwAddr, pdrDisplacement, &LineAlternate))
767 {
768 const wxWCharBuffer ConvBuf =
769 wxConvLocal.cMB2WC(LineAlternate.FileName, wxNO_LEN, NULL);
770 wxStrncpy(staticBuf, ConvBuf.data(), MAX_PATH);
771 Line->Key = LineAlternate.Key;
772 Line->LineNumber = LineAlternate.LineNumber;
773 Line->FileName = staticBuf;
774 Line->Address = LineAlternate.Address;
775 return TRUE;
776 }
777 }
778 if (SymGetLineFromAddr)
779 {
780 IMAGEHLP_LINE LineAlternate;
781 LineAlternate.SizeOfStruct = sizeof(IMAGEHLP_LINE);
782 if ((*SymGetLineFromAddr)(hProcess, dwAddr, pdrDisplacement, &LineAlternate))
783 {
784 const wxWCharBuffer ConvBuf =
785 wxConvLocal.cMB2WC(LineAlternate.FileName, wxNO_LEN, NULL);
786 wxStrncpy(staticBuf, ConvBuf.data(), MAX_PATH);
787 Line->Key = LineAlternate.Key;
788 Line->LineNumber = LineAlternate.LineNumber;
789 Line->FileName = staticBuf;
790 Line->Address = LineAlternate.Address;
791 return TRUE;
792 }
793 }
794 return FALSE;
795 #else
796 if (SymGetLineFromAddr64)
797 {
798 return (*SymGetLineFromAddr64)(hProcess, dwAddr, pdrDisplacement, Line);
799 }
800 if (SymGetLineFromAddr)
801 {
802 IMAGEHLP_LINE LineAlternate;
803 LineAlternate.SizeOfStruct = sizeof(IMAGEHLP_LINE);
804 if ((*SymGetLineFromAddr)(hProcess, dwAddr, pdrDisplacement, &LineAlternate))
805 {
806 Line->Key = LineAlternate.Key;
807 Line->LineNumber = LineAlternate.LineNumber;
808 Line->FileName = LineAlternate.FileName;
809 Line->Address = LineAlternate.Address;
810 return TRUE;
811 }
812 }
813 return FALSE;
814 #endif
815 }
816
817 struct wxMswSymEnumSymbolsHelperStruct
818 {
819 public:
820 wxMswSymEnumSymbolsHelperStruct(PSYM_ENUMERATESYMBOLS_CALLBACKW ptr, PVOID content)
821 : m_pointer_to_callback(ptr), m_user_content(content)
822 { }
823 PSYM_ENUMERATESYMBOLS_CALLBACKW m_pointer_to_callback;
824 PVOID m_user_content;
825 };
826
827 #ifdef UNICODE
828
829 static BOOL CALLBACK wxMswSymEnumSymbolsHelperCallback(
830 PSYMBOL_INFO pSymInfo, ULONG SymbolSize, PVOID UserContext)
831 {
832 wxMswSymEnumSymbolsHelperStruct& alternate =
833 *(wxMswSymEnumSymbolsHelperStruct*)(UserContext);
834 const wxWCharBuffer buf = wxConvLocal.cMB2WC(pSymInfo->Name, pSymInfo->MaxNameLen, NULL);
835 BYTE* symbolBuffer = new BYTE[sizeof(SYMBOL_INFOW) + buf.length()*sizeof(WCHAR)];
836 SYMBOL_INFOW* data = (SYMBOL_INFOW*)(symbolBuffer);
837
838 // FIXME: I know too brute but some header names SYMBOL_INFO::Index
839 // and the other one defines it as SYMBOL_INFO::info.
840 CopyMemory(data, pSymInfo, sizeof(SYMBOL_INFO)-sizeof(CHAR));
841 data->SizeOfStruct = sizeof(SYMBOL_INFOW);
842 wxStrncpy(data->Name, buf.data(), buf.length());
843 BOOL retVal = (*alternate.m_pointer_to_callback)(data, SymbolSize, alternate.m_user_content);
844 delete [] symbolBuffer;
845 return retVal;
846 }
847
848 #endif // UNICODE
849
850 /* static */
851 BOOL wxDbgHelpDLL::SymEnumSymbolsT(HANDLE hProcess, ULONG64 baseOfDll, PCTSTR Mask,
852 wxPSYM_ENUMERATESYMBOLS_CALLBACK EnumSymbolsCallback, const PVOID UserContext)
853 {
854 #ifdef UNICODE
855 if (SymEnumSymbolsW)
856 {
857 const BOOL retVal = (*SymEnumSymbolsW)(hProcess, baseOfDll, Mask, EnumSymbolsCallback, UserContext);
858 if (retVal)
859 return retVal;
860 }
861 if (SymEnumSymbols)
862 {
863 wxMswSymEnumSymbolsHelperStruct p(EnumSymbolsCallback, UserContext);
864 const wxCharBuffer buf = wxConvLocal.cWC2MB(Mask ? Mask : L"", wxNO_LEN, NULL);
865 return (*SymEnumSymbols)(hProcess, baseOfDll, buf.data(),
866 wxMswSymEnumSymbolsHelperCallback, (PVOID)(&p));
867 }
868 return FALSE;
869 #else
870 if (SymEnumSymbols)
871 {
872 return (*SymEnumSymbols)(hProcess, baseOfDll, Mask, EnumSymbolsCallback, UserContext);
873 }
874 return FALSE;
875 #endif
876 }
877
878 // ----------------------------------------------------------------------------
879 // debugging helpers
880 // ----------------------------------------------------------------------------
881
882 // this code is very useful when debugging debughlp.dll-related code but
883 // probably not worth having compiled in normally, please do not remove it!
884 #if 0 // ndef NDEBUG
885
886 static wxString TagString(wxDbgHelpDLL::SymbolTag tag)
887 {
888 static const wxChar *tags[] =
889 {
890 wxT("null"),
891 wxT("exe"),
892 wxT("compiland"),
893 wxT("compiland details"),
894 wxT("compiland env"),
895 wxT("function"),
896 wxT("block"),
897 wxT("data"),
898 wxT("annotation"),
899 wxT("label"),
900 wxT("public symbol"),
901 wxT("udt"),
902 wxT("enum"),
903 wxT("function type"),
904 wxT("pointer type"),
905 wxT("array type"),
906 wxT("base type"),
907 wxT("typedef"),
908 wxT("base class"),
909 wxT("friend"),
910 wxT("function arg type"),
911 wxT("func debug start"),
912 wxT("func debug end"),
913 wxT("using namespace"),
914 wxT("vtable shape"),
915 wxT("vtable"),
916 wxT("custom"),
917 wxT("thunk"),
918 wxT("custom type"),
919 wxT("managed type"),
920 wxT("dimension"),
921 };
922
923 wxCOMPILE_TIME_ASSERT( WXSIZEOF(tags) == wxDbgHelpDLL::SYMBOL_TAG_MAX,
924 SymbolTagStringMismatch );
925
926 wxString s;
927 if ( tag < WXSIZEOF(tags) )
928 s = tags[tag];
929 else
930 s.Printf(wxT("unrecognized tag (%d)"), tag);
931
932 return s;
933 }
934
935 static wxString KindString(wxDbgHelpDLL::DataKind kind)
936 {
937 static const wxChar *kinds[] =
938 {
939 wxT("unknown"),
940 wxT("local"),
941 wxT("static local"),
942 wxT("param"),
943 wxT("object ptr"),
944 wxT("file static"),
945 wxT("global"),
946 wxT("member"),
947 wxT("static member"),
948 wxT("constant"),
949 };
950
951 wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::DATA_MAX,
952 DataKindStringMismatch );
953
954 wxString s;
955 if ( kind < WXSIZEOF(kinds) )
956 s = kinds[kind];
957 else
958 s.Printf(wxT("unrecognized kind (%d)"), kind);
959
960 return s;
961 }
962
963 static wxString UdtKindString(wxDbgHelpDLL::UdtKind kind)
964 {
965 static const wxChar *kinds[] =
966 {
967 wxT("struct"),
968 wxT("class"),
969 wxT("union"),
970 };
971
972 wxCOMPILE_TIME_ASSERT( WXSIZEOF(kinds) == wxDbgHelpDLL::UDT_MAX,
973 UDTKindStringMismatch );
974
975 wxString s;
976 if ( kind < WXSIZEOF(kinds) )
977 s = kinds[kind];
978 else
979 s.Printf(wxT("unrecognized UDT (%d)"), kind);
980
981 return s;
982 }
983
984 static wxString TypeString(wxDbgHelpDLL::BasicType bt)
985 {
986 static const wxChar *types[] =
987 {
988 wxT("no type"),
989 wxT("void"),
990 wxT("char"),
991 wxT("wchar"),
992 wxT(""),
993 wxT(""),
994 wxT("int"),
995 wxT("uint"),
996 wxT("float"),
997 wxT("bcd"),
998 wxT("bool"),
999 wxT(""),
1000 wxT(""),
1001 wxT("long"),
1002 wxT("ulong"),
1003 wxT(""),
1004 wxT(""),
1005 wxT(""),
1006 wxT(""),
1007 wxT(""),
1008 wxT(""),
1009 wxT(""),
1010 wxT(""),
1011 wxT(""),
1012 wxT(""),
1013 wxT("CURRENCY"),
1014 wxT("DATE"),
1015 wxT("VARIANT"),
1016 wxT("complex"),
1017 wxT("bit"),
1018 wxT("BSTR"),
1019 wxT("HRESULT"),
1020 };
1021
1022 wxCOMPILE_TIME_ASSERT( WXSIZEOF(types) == wxDbgHelpDLL::BASICTYPE_MAX,
1023 BasicTypeStringMismatch );
1024
1025 wxString s;
1026 if ( bt < WXSIZEOF(types) )
1027 s = types[bt];
1028
1029 if ( s.empty() )
1030 s.Printf(wxT("unrecognized type (%d)"), bt);
1031
1032 return s;
1033 }
1034
1035 // this function is meant to be called from under debugger to see the
1036 // proprieties of the given type id
1037 extern "C" void DumpTI(ULONG ti)
1038 {
1039 SYMBOL_INFO sym = { sizeof(SYMBOL_INFO) };
1040 sym.ModBase = 0x400000; // it's a constant under Win32
1041 sym.TypeIndex = ti;
1042
1043 wxDbgHelpDLL::SymbolTag tag = wxDbgHelpDLL::SYMBOL_TAG_NULL;
1044 DoGetTypeInfo(&sym, TI_GET_SYMTAG, &tag);
1045 DoGetTypeInfo(&sym, TI_GET_TYPEID, &ti);
1046
1047 OutputDebugString(wxString::Format(wxT("Type 0x%x: "), sym.TypeIndex));
1048 wxString name = wxDbgHelpDLL::GetSymbolName(&sym);
1049 if ( !name.empty() )
1050 {
1051 OutputDebugString(wxString::Format(wxT("name=\"%s\", "), name.c_str()));
1052 }
1053
1054 DWORD nested;
1055 if ( !DoGetTypeInfo(&sym, TI_GET_NESTED, &nested) )
1056 {
1057 nested = FALSE;
1058 }
1059
1060 OutputDebugString(wxString::Format(wxT("tag=%s%s"),
1061 nested ? wxT("nested ") : wxEmptyString,
1062 TagString(tag).c_str()));
1063 if ( tag == wxDbgHelpDLL::SYMBOL_TAG_UDT )
1064 {
1065 wxDbgHelpDLL::UdtKind udtKind;
1066 if ( DoGetTypeInfo(&sym, TI_GET_UDTKIND, &udtKind) )
1067 {
1068 OutputDebugString(wxT(" (") + UdtKindString(udtKind) + wxT(')'));
1069 }
1070 }
1071
1072 wxDbgHelpDLL::DataKind kind = wxDbgHelpDLL::DATA_UNKNOWN;
1073 if ( DoGetTypeInfo(&sym, TI_GET_DATAKIND, &kind) )
1074 {
1075 OutputDebugString(wxString::Format(
1076 wxT(", kind=%s"), KindString(kind).c_str()));
1077 if ( kind == wxDbgHelpDLL::DATA_MEMBER )
1078 {
1079 DWORD ofs = 0;
1080 if ( DoGetTypeInfo(&sym, TI_GET_OFFSET, &ofs) )
1081 {
1082 OutputDebugString(wxString::Format(wxT(" (ofs=0x%x)"), ofs));
1083 }
1084 }
1085 }
1086
1087 wxDbgHelpDLL::BasicType bt = GetBasicType(&sym);
1088 if ( bt )
1089 {
1090 OutputDebugString(wxString::Format(wxT(", type=%s"),
1091 TypeString(bt).c_str()));
1092 }
1093
1094 if ( ti != sym.TypeIndex )
1095 {
1096 OutputDebugString(wxString::Format(wxT(", next ti=0x%x"), ti));
1097 }
1098
1099 OutputDebugString(wxT("\r\n"));
1100 }
1101
1102 #endif // NDEBUG
1103
1104 #endif // wxUSE_DBGHELP