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