1 /*----------------------------------------------------------------------
\r
2 "Debugging Applications" (Microsoft Press)
\r
3 Copyright (c) 1997-2000 John Robbins -- All rights reserved.
\r
4 ------------------------------------------------------------------------
\r
5 This class is a paper-thin layer around the DBGHELP.DLL symbol engine.
\r
7 This class wraps only those functions that take the unique
\r
8 HANDLE value. Other DBGHELP.DLL symbol engine functions are global in
\r
9 scope, so I didn
\92t wrap them with this class.
\r
11 ------------------------------------------------------------------------
\r
12 Compilation Defines:
\r
14 DO_NOT_WORK_AROUND_SRCLINE_BUG - If defined, the class will NOT work
\r
15 around the SymGetLineFromAddr bug where
\r
16 PDB file lookups fail after the first
\r
18 USE_BUGSLAYERUTIL - If defined, the class will have another
\r
19 initialization method, BSUSymInitialize, which will
\r
20 use BSUSymInitialize from BUGSLAYERUTIL.DLL to
\r
21 initialize the symbol engine and allow the invade
\r
22 process flag to work for all Win32 operating systems.
\r
23 If you use this define, you must use
\r
24 BUGSLAYERUTIL.H to include this file.
\r
25 ----------------------------------------------------------------------*/
\r
27 #ifndef _SYMBOLENGINE_H
\r
28 #define _SYMBOLENGINE_H
\r
30 // You could include either IMAGEHLP.DLL or DBGHELP.DLL.
\r
31 #include "imagehlp.h"
\r
34 // Include these in case the user forgets to link against them.
\r
35 #pragma comment (lib,"dbghelp.lib")
\r
36 #pragma comment (lib,"version.lib")
\r
38 // The great Bugslayer idea of creating wrapper classes on structures
\r
39 // that have size fields came from fellow MSJ columnist, Paul DiLascia.
\r
42 // I didn
\92t wrap IMAGEHLP_SYMBOL because that is a variable-size
\r
45 // The IMAGEHLP_MODULE wrapper class
\r
46 struct CImageHlp_Module : public IMAGEHLP_MODULE
\r
48 CImageHlp_Module ( )
\r
50 memset ( this , NULL , sizeof ( IMAGEHLP_MODULE ) ) ;
\r
51 SizeOfStruct = sizeof ( IMAGEHLP_MODULE ) ;
\r
55 // The IMAGEHLP_LINE wrapper class
\r
56 struct CImageHlp_Line : public IMAGEHLP_LINE
\r
60 memset ( this , NULL , sizeof ( IMAGEHLP_LINE ) ) ;
\r
61 SizeOfStruct = sizeof ( IMAGEHLP_LINE ) ;
\r
65 // The symbol engine class
\r
68 /*----------------------------------------------------------------------
\r
69 Public Construction and Destruction
\r
70 ----------------------------------------------------------------------*/
\r
72 // To use this class, call the SymInitialize member function to
\r
73 // initialize the symbol engine and then use the other member
\r
74 // functions in place of their corresponding DBGHELP.DLL functions.
\r
75 CSymbolEngine ( void )
\r
79 virtual ~CSymbolEngine ( void )
\r
83 /*----------------------------------------------------------------------
\r
84 Public Helper Information Functions
\r
85 ----------------------------------------------------------------------*/
\r
88 // Returns the file version of DBGHELP.DLL being used.
\r
89 // To convert the return values into a readable format:
\r
90 // wsprintf ( szVer ,
\r
91 // ( "%d.%02d.%d.%d" ) ,
\r
92 // HIWORD ( dwMS ) ,
\r
93 // LOWORD ( dwMS ) ,
\r
94 // HIWORD ( dwLS ) ,
\r
95 // LOWORD ( dwLS ) ) ;
\r
96 // szVer will contain a string like: 5.00.1878.1
\r
97 BOOL GetImageHlpVersion ( DWORD & dwMS , DWORD & dwLS )
\r
99 return( GetInMemoryFileVersion ( ( "DBGHELP.DLL" ) ,
\r
104 BOOL GetDbgHelpVersion ( DWORD & dwMS , DWORD & dwLS )
\r
106 return( GetInMemoryFileVersion ( ( "DBGHELP.DLL" ) ,
\r
111 // Returns the file version of the PDB reading DLLs
\r
112 BOOL GetPDBReaderVersion ( DWORD & dwMS , DWORD & dwLS )
\r
114 // First try MSDBI.DLL.
\r
115 if ( TRUE == GetInMemoryFileVersion ( ( "MSDBI.DLL" ) ,
\r
121 else if ( TRUE == GetInMemoryFileVersion ( ( "MSPDB60.DLL" ),
\r
127 // Just fall down to MSPDB50.DLL.
\r
128 return ( GetInMemoryFileVersion ( ( "MSPDB50.DLL" ) ,
\r
133 // The worker function used by the previous two functions
\r
134 BOOL GetInMemoryFileVersion ( LPCTSTR szFile ,
\r
138 HMODULE hInstIH = GetModuleHandle ( szFile ) ;
\r
140 // Get the full filename of the loaded version.
\r
141 TCHAR szImageHlp[ MAX_PATH ] ;
\r
142 GetModuleFileName ( hInstIH , szImageHlp , MAX_PATH ) ;
\r
147 // Get the version information size.
\r
148 DWORD dwVerInfoHandle ;
\r
151 dwVerSize = GetFileVersionInfoSize ( szImageHlp ,
\r
152 &dwVerInfoHandle ) ;
\r
153 if ( 0 == dwVerSize )
\r
158 // Got the version size, now get the version information.
\r
159 LPVOID lpData = (LPVOID)new TCHAR [ dwVerSize ] ;
\r
160 if ( FALSE == GetFileVersionInfo ( szImageHlp ,
\r
169 VS_FIXEDFILEINFO * lpVerInfo ;
\r
171 BOOL bRet = VerQueryValue ( lpData ,
\r
173 (LPVOID*)&lpVerInfo ,
\r
175 if ( TRUE == bRet )
\r
177 dwMS = lpVerInfo->dwFileVersionMS ;
\r
178 dwLS = lpVerInfo->dwFileVersionLS ;
\r
186 /*----------------------------------------------------------------------
\r
187 Public Initialization and Cleanup
\r
188 ----------------------------------------------------------------------*/
\r
191 BOOL SymInitialize ( IN HANDLE hProcess ,
\r
192 IN LPSTR UserSearchPath ,
\r
193 IN BOOL fInvadeProcess )
\r
195 m_hProcess = hProcess ;
\r
196 return ( ::SymInitialize ( hProcess ,
\r
198 fInvadeProcess ) ) ;
\r
201 #ifdef USE_BUGSLAYERUTIL
\r
202 BOOL BSUSymInitialize ( DWORD dwPID ,
\r
204 PSTR UserSearchPath ,
\r
205 BOOL fInvadeProcess )
\r
207 m_hProcess = hProcess ;
\r
208 return ( ::BSUSymInitialize ( dwPID ,
\r
211 fInvadeProcess ) ) ;
\r
213 #endif // USE_BUGSLAYERUTIL
\r
214 BOOL SymCleanup ( void )
\r
216 return ( ::SymCleanup ( m_hProcess ) ) ;
\r
219 /*----------------------------------------------------------------------
\r
220 Public Module Manipulation
\r
221 ----------------------------------------------------------------------*/
\r
224 BOOL SymEnumerateModules ( IN PSYM_ENUMMODULES_CALLBACK
\r
225 EnumModulesCallback,
\r
226 IN PVOID UserContext )
\r
228 return ( ::SymEnumerateModules ( m_hProcess ,
\r
229 EnumModulesCallback ,
\r
233 BOOL SymLoadModule ( IN HANDLE hFile ,
\r
234 IN PSTR ImageName ,
\r
235 IN PSTR ModuleName ,
\r
236 IN DWORD_PTR BaseOfDll ,
\r
237 IN DWORD SizeOfDll )
\r
239 return ( ::SymLoadModule ( m_hProcess ,
\r
244 SizeOfDll ) != NULL) ;
\r
247 BOOL EnumerateLoadedModules ( IN PENUMLOADED_MODULES_CALLBACK
\r
248 EnumLoadedModulesCallback,
\r
249 IN PVOID UserContext )
\r
251 return ( ::EnumerateLoadedModules ( m_hProcess ,
\r
252 EnumLoadedModulesCallback ,
\r
256 BOOL SymUnloadModule ( IN DWORD_PTR BaseOfDll )
\r
258 return ( ::SymUnloadModule ( m_hProcess , BaseOfDll ) ) ;
\r
261 BOOL SymGetModuleInfo ( IN DWORD_PTR dwAddr ,
\r
262 OUT PIMAGEHLP_MODULE ModuleInfo )
\r
264 return ( ::SymGetModuleInfo ( m_hProcess ,
\r
269 DWORD SymGetModuleBase ( IN DWORD_PTR dwAddr )
\r
271 return ( ::SymGetModuleBase ( m_hProcess , dwAddr ) != NULL ) ;
\r
274 /*----------------------------------------------------------------------
\r
275 Public Symbol Manipulation
\r
276 ----------------------------------------------------------------------*/
\r
279 BOOL SymEnumerateSymbols (IN DWORD_PTR BaseOfDll,
\r
280 IN PSYM_ENUMSYMBOLS_CALLBACK
\r
281 EnumSymbolsCallback,
\r
282 IN PVOID UserContext )
\r
284 return ( ::SymEnumerateSymbols ( m_hProcess ,
\r
286 EnumSymbolsCallback ,
\r
290 BOOL SymGetSymFromAddr ( IN DWORD_PTR dwAddr ,
\r
291 OUT PDWORD_PTR pdwDisplacement ,
\r
292 OUT PIMAGEHLP_SYMBOL Symbol )
\r
294 return ( ::SymGetSymFromAddr ( m_hProcess ,
\r
300 BOOL SymGetSymFromName ( IN LPSTR Name ,
\r
301 OUT PIMAGEHLP_SYMBOL Symbol )
\r
303 return ( ::SymGetSymFromName ( m_hProcess ,
\r
308 BOOL SymGetSymNext ( IN OUT PIMAGEHLP_SYMBOL Symbol )
\r
310 return ( ::SymGetSymNext ( m_hProcess , Symbol ) ) ;
\r
313 BOOL SymGetSymPrev ( IN OUT PIMAGEHLP_SYMBOL Symbol )
\r
315 return ( ::SymGetSymPrev ( m_hProcess , Symbol ) ) ;
\r
318 /*----------------------------------------------------------------------
\r
319 Public Source Line Manipulation
\r
320 ----------------------------------------------------------------------*/
\r
323 BOOL SymGetLineFromAddr ( IN DWORD_PTR dwAddr ,
\r
324 OUT PDWORD pdwDisplacement ,
\r
325 OUT PIMAGEHLP_LINE Line )
\r
328 #ifdef DO_NOT_WORK_AROUND_SRCLINE_BUG
\r
329 // Just pass along the values returned by the main function.
\r
330 return ( ::SymGetLineFromAddr ( m_hProcess ,
\r
336 // The problem is that the symbol engine finds only those source
\r
337 // line addresses (after the first lookup) that fall exactly on
\r
338 // a zero displacement. I
\92ll walk backward 100 bytes to
\r
339 // find the line and return the proper displacement.
\r
340 DWORD dwTempDis = 0 ;
\r
341 while ( FALSE == ::SymGetLineFromAddr ( m_hProcess ,
\r
342 dwAddr - dwTempDis ,
\r
347 if ( 100 == dwTempDis )
\r
352 // I found it and the source line information is correct, so
\r
353 // change the displacement if I had to search backward to find
\r
354 // the source line.
\r
355 if ( 0 != dwTempDis )
\r
357 *pdwDisplacement = dwTempDis ;
\r
360 #endif // DO_NOT_WORK_AROUND_SRCLINE_BUG
\r
363 BOOL SymGetLineFromName ( IN LPSTR ModuleName ,
\r
364 IN LPSTR FileName ,
\r
365 IN DWORD dwLineNumber ,
\r
366 OUT PLONG plDisplacement ,
\r
367 IN OUT PIMAGEHLP_LINE Line )
\r
369 return ( ::SymGetLineFromName ( m_hProcess ,
\r
377 BOOL SymGetLineNext ( IN OUT PIMAGEHLP_LINE Line )
\r
379 return ( ::SymGetLineNext ( m_hProcess , Line ) ) ;
\r
382 BOOL SymGetLinePrev ( IN OUT PIMAGEHLP_LINE Line )
\r
384 return ( ::SymGetLinePrev ( m_hProcess , Line ) ) ;
\r
387 BOOL SymMatchFileName ( IN LPSTR FileName ,
\r
389 OUT LPSTR * FileNameStop ,
\r
390 OUT LPSTR * MatchStop )
\r
392 return ( ::SymMatchFileName ( FileName ,
\r
398 /*----------------------------------------------------------------------
\r
399 Public Miscellaneous Members
\r
400 ----------------------------------------------------------------------*/
\r
403 LPVOID SymFunctionTableAccess ( DWORD_PTR AddrBase )
\r
405 return ( ::SymFunctionTableAccess ( m_hProcess , AddrBase ) ) ;
\r
408 BOOL SymGetSearchPath ( OUT LPSTR SearchPath ,
\r
409 IN DWORD SearchPathLength )
\r
411 return ( ::SymGetSearchPath ( m_hProcess ,
\r
413 SearchPathLength ) ) ;
\r
416 BOOL SymSetSearchPath ( IN LPSTR SearchPath )
\r
418 return ( ::SymSetSearchPath ( m_hProcess , SearchPath ) ) ;
\r
421 /* BOOL SymRegisterCallback ( IN PSYMBOL_REGISTERED_CALLBACK
\r
423 IN DWORD_PTR UserContext )
\r
425 return ( ::SymRegisterCallback ( m_hProcess ,
\r
431 /*----------------------------------------------------------------------
\r
432 Protected Data Members
\r
433 ----------------------------------------------------------------------*/
\r
435 // The unique value that will be used for this instance of the
\r
436 // symbol engine. This value doesn
\92t have to be an actual
\r
437 // process value, just a unique value.
\r
438 HANDLE m_hProcess ;
\r
442 #endif // _SYMBOLENGINE_H
\r