1 /*----------------------------------------------------------------------
2 John Robbins - Microsoft Systems Journal Bugslayer Column - Feb 99
3 ----------------------------------------------------------------------*/
6 #include "StackTrace.h"
7 #include "SymbolEngine.h"
9 // 4710: inline function not inlined
10 #pragma warning(disable: 4710)
11 #pragma warning(disable: 4786)
12 #pragma warning(push, 3)
16 /*//////////////////////////////////////////////////////////////////////
18 //////////////////////////////////////////////////////////////////////*/
20 // The symbol engine. Indexed by process-id so there is no collision between processes.
21 #pragma warning(push, 3)
22 typedef std::map
<DWORD
, CSymbolEngine
> TSymbolEngineMap
;
23 static TSymbolEngineMap g_cSymMap
;
26 static CSymbolEngine
& GetSymbolEngine()
28 DWORD CurrProcessId
= GetCurrentProcessId();
29 TSymbolEngineMap::iterator iter
;
30 iter
= g_cSymMap
.lower_bound(CurrProcessId
);
31 if (iter
== g_cSymMap
.end() || iter
->first
!= CurrProcessId
) {
33 HANDLE hProcess
= GetCurrentProcess ( ) ;
34 DWORD dwOpts
= SymGetOptions ( ) ;
36 // Turn on load lines.
37 SymSetOptions ( dwOpts
|
39 iter
= g_cSymMap
.insert(iter
, std::make_pair(CurrProcessId
, CSymbolEngine()));
40 if ( FALSE
== iter
->second
.SymInitialize ( hProcess
,
44 OutputDebugString ( "DiagAssert : Unable to initialize the "
45 "symbol engine!!!\n" ) ;
55 static DWORD_PTR __stdcall
GetModBase ( HANDLE hProcess
, DWORD_PTR dwAddr
)
57 // Check in the symbol engine first.
58 IMAGEHLP_MODULE stIHM
;
59 CSymbolEngine
& cSym
= GetSymbolEngine();
60 // This is what the MFC stack trace routines forgot to do so their
61 // code will not get the info out of the symbol engine.
62 stIHM
.SizeOfStruct
= sizeof ( IMAGEHLP_MODULE
) ;
64 if ( cSym
.SymGetModuleInfo ( dwAddr
, &stIHM
) )
66 return ( stIHM
.BaseOfImage
) ;
71 MEMORY_BASIC_INFORMATION stMBI
;
73 if ( 0 != VirtualQueryEx ( hProcess
,
80 TCHAR szFile
[ MAX_PATH
] ;
82 dwNameLen
= GetModuleFileName ( (HINSTANCE
)
83 stMBI
.AllocationBase
,
90 hFile
= CreateFile ( szFile
,
101 cSym
.SymLoadModule ( hFile
,
102 ( dwNameLen
? szFile
: NULL
) ,
104 (DWORD
)stMBI
.AllocationBase
,
106 ::CloseHandle(hFile
);
111 ATLTRACE ( "SymLoadModule failed : 0x%08X\n" ,
115 return ( (DWORD
)stMBI
.AllocationBase
) ;
121 static void PrintAddress (DWORD_PTR address
, const char *ImageName
,
122 const char *FunctionName
, DWORD_PTR functionDisp
,
123 const char *Filename
, DWORD LineNumber
, DWORD lineDisp
,
124 void * /* data, unused */ )
126 static char buffer
[ MAX_PATH
*2 + 512 ];
127 LPTSTR pCurrPos
= buffer
;
128 // Always stick the address in first.
129 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
), addressFormat
, address
) ;
131 if (ImageName
!= NULL
) {
132 LPCTSTR szName
= strchr ( ImageName
, ( '\\' ) ) ;
133 if ( NULL
!= szName
) {
136 szName
= const_cast<char *>(ImageName
) ;
138 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
), ( "%s: " ) , szName
) ;
140 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
), ( "<unknown module>: " ) );
142 if (FunctionName
!= NULL
) {
143 if ( 0 == functionDisp
) {
144 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
), ( "%s" ) , FunctionName
);
146 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
),
147 ( "%s + %d bytes" ) ,
151 if (Filename
!= NULL
) {
152 // Put this on the next line and indented a bit.
153 pCurrPos
+= _snprintf( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
), "-\n");
154 OutputDebugString(buffer
);
156 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
),
157 ( "\t\t%s, Line %d" ) ,
162 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
),
168 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
), ( "<unknown symbol>" ) ) ;
171 pCurrPos
+= _snprintf ( pCurrPos
, sizeof buffer
- (pCurrPos
- buffer
), ( "\n" ) ) ;
172 OutputDebugString ( buffer
);
176 void AddressToSymbol(DWORD_PTR dwAddr
, TraceCallbackFunction pFunction
, LPVOID data
)
178 char szTemp
[ MAX_PATH
+ sizeof ( IMAGEHLP_SYMBOL
) ] ;
180 PIMAGEHLP_SYMBOL pIHS
= (PIMAGEHLP_SYMBOL
)&szTemp
;
182 IMAGEHLP_MODULE stIHM
;
183 IMAGEHLP_LINE stIHL
;
185 bool haveModule
= false;
186 bool haveFunction
= false;
187 bool haveLine
= false;
189 CSymbolEngine
& cSym
= GetSymbolEngine();
191 SecureZeroMemory ( pIHS
, MAX_PATH
+ sizeof ( IMAGEHLP_SYMBOL
) ) ;
192 SecureZeroMemory ( &stIHM
, sizeof ( IMAGEHLP_MODULE
) ) ;
193 SecureZeroMemory ( &stIHL
, sizeof ( IMAGEHLP_LINE
) ) ;
195 pIHS
->SizeOfStruct
= sizeof ( IMAGEHLP_SYMBOL
) ;
196 pIHS
->Address
= dwAddr
;
197 pIHS
->MaxNameLength
= MAX_PATH
;
199 stIHM
.SizeOfStruct
= sizeof ( IMAGEHLP_MODULE
) ;
202 // Get the module name.
203 haveModule
= (0 != cSym
.SymGetModuleInfo ( dwAddr
, &stIHM
));
206 DWORD_PTR dwFuncDisp
=0 ;
208 if ( 0 != cSym
.SymGetSymFromAddr ( dwAddr
, &dwFuncDisp
, pIHS
) )
213 // If I got a symbol, give the source and line a whirl.
216 stIHL
.SizeOfStruct
= sizeof ( IMAGEHLP_LINE
) ;
218 haveLine
= 0 != cSym
.SymGetLineFromAddr ( dwAddr
,
222 if (pFunction
!= NULL
) {
224 pFunction(dwAddr
, haveModule
? stIHM
.ImageName
: NULL
,
225 haveFunction
? pIHS
->Name
: NULL
, dwFuncDisp
,
226 haveLine
? stIHL
.FileName
: NULL
, haveLine
? stIHL
.LineNumber
: 0, dwLineDisp
,
231 void DoStackTrace ( int numSkip
, int depth
, TraceCallbackFunction pFunction
, CONTEXT
*pContext
, LPVOID data
)
233 HANDLE hProcess
= GetCurrentProcess ( ) ;
235 if (pFunction
== NULL
) {
236 pFunction
= PrintAddress
;
239 // The symbol engine is initialized so do the stack walk.
241 // The thread information - if not supplied.
243 if (pContext
== NULL
) {
245 stCtx
.ContextFlags
= CONTEXT_FULL
;
247 if ( GetThreadContext ( GetCurrentThread ( ) , &stCtx
) )
252 if (pContext
!= NULL
) {
256 SecureZeroMemory ( &stFrame
, sizeof ( STACKFRAME
) ) ;
258 stFrame
.AddrPC
.Mode
= AddrModeFlat
;
260 #if defined (_M_IX86)
261 dwMachine
= IMAGE_FILE_MACHINE_I386
;
262 stFrame
.AddrPC
.Offset
= pContext
->Eip
;
263 stFrame
.AddrStack
.Offset
= pContext
->Esp
;
264 stFrame
.AddrStack
.Mode
= AddrModeFlat
;
265 stFrame
.AddrFrame
.Offset
= pContext
->Ebp
;
266 stFrame
.AddrFrame
.Mode
= AddrModeFlat
;
268 #elif defined (_M_AMD64)
269 dwMachine
= IMAGE_FILE_MACHINE_AMD64
;
270 stFrame
.AddrPC
.Offset
= pContext
->Rip
;
271 stFrame
.AddrStack
.Offset
= pContext
->Rsp
;
272 stFrame
.AddrStack
.Mode
= AddrModeFlat
;
273 stFrame
.AddrFrame
.Offset
= pContext
->Rbp
;
274 stFrame
.AddrFrame
.Mode
= AddrModeFlat
;
276 #elif defined (_M_ALPHA)
277 dwMachine
= IMAGE_FILE_MACHINE_ALPHA
;
278 stFrame
.AddrPC
.Offset
= (unsigned long)pContext
->Fir
;
280 #error ( "Unknown machine!" )
283 // Loop for the first <depth> stack elements.
284 for ( int i
= 0 ; i
< depth
; i
++ )
286 if ( FALSE
== StackWalk ( dwMachine
,
293 SymFunctionTableAccess
,
301 // Also check that the address is not zero. Sometimes
302 // StackWalk returns TRUE with a frame of zero.
303 if ( 0 != stFrame
.AddrPC
.Offset
)
305 AddressToSymbol ( stFrame
.AddrPC
.Offset
, pFunction
, data
) ;