Update diff del rename ignore document.
[TortoiseGit.git] / src / crashrpt / StackTrace.cpp
blob2ef3877034b9e37ae809802142aa63c17c645a6d
1 /*----------------------------------------------------------------------
2 John Robbins - Microsoft Systems Journal Bugslayer Column - Feb 99
3 ----------------------------------------------------------------------*/
4 #include <stdafx.h>
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)
13 #include <map>
14 #pragma warning(pop)
16 /*//////////////////////////////////////////////////////////////////////
17 File Scope Globals
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;
24 #pragma warning(pop)
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) {
32 CSymbolEngine cSym;
33 HANDLE hProcess = GetCurrentProcess ( ) ;
34 DWORD dwOpts = SymGetOptions ( ) ;
36 // Turn on load lines.
37 SymSetOptions ( dwOpts |
38 SYMOPT_LOAD_LINES ) ;
39 iter = g_cSymMap.insert(iter, std::make_pair(CurrProcessId, CSymbolEngine()));
40 if ( FALSE == iter->second.SymInitialize ( hProcess ,
41 NULL ,
42 TRUE ) )
44 OutputDebugString ( "DiagAssert : Unable to initialize the "
45 "symbol engine!!!\n" ) ;
47 #ifdef _DEBUG
48 DebugBreak ( ) ;
49 #endif
52 return iter->second;
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 ) ;
68 else
70 // Let's go fishing.
71 MEMORY_BASIC_INFORMATION stMBI ;
73 if ( 0 != VirtualQueryEx ( hProcess ,
74 (LPCVOID)dwAddr ,
75 &stMBI ,
76 sizeof ( stMBI ) ) )
78 // Try and load it.
79 DWORD dwNameLen = 0 ;
80 TCHAR szFile[ MAX_PATH ] ;
81 szFile[0] = '\0';
82 dwNameLen = GetModuleFileName ( (HINSTANCE)
83 stMBI.AllocationBase ,
84 szFile ,
85 MAX_PATH );
86 HANDLE hFile = NULL ;
88 if ( 0 != dwNameLen )
90 hFile = CreateFile ( szFile ,
91 GENERIC_READ ,
92 FILE_SHARE_READ ,
93 NULL ,
94 OPEN_EXISTING ,
95 0 ,
96 0 ) ;
98 #ifdef NOTDEF_DEBUG
99 DWORD dwRet =
100 #endif
101 cSym.SymLoadModule ( hFile ,
102 ( dwNameLen ? szFile : NULL ) ,
103 NULL ,
104 (DWORD)stMBI.AllocationBase ,
105 0 );
106 ::CloseHandle(hFile);
108 #ifdef NOTDEF_DEBUG
109 if ( 0 == dwRet )
111 ATLTRACE ( "SymLoadModule failed : 0x%08X\n" ,
112 GetLastError ( ) ) ;
114 #endif // _DEBUG
115 return ( (DWORD)stMBI.AllocationBase ) ;
118 return ( 0 ) ;
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 ) {
134 szName++ ;
135 } else {
136 szName = const_cast<char *>(ImageName) ;
138 pCurrPos += _snprintf ( pCurrPos , sizeof buffer - (pCurrPos - buffer), ( "%s: " ) , szName ) ;
139 } else {
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);
145 } else {
146 pCurrPos += _snprintf ( pCurrPos , sizeof buffer - (pCurrPos - buffer),
147 ( "%s + %d bytes" ) ,
148 FunctionName ,
149 functionDisp ) ;
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);
155 pCurrPos = buffer;
156 pCurrPos += _snprintf ( pCurrPos , sizeof buffer - (pCurrPos - buffer),
157 ( "\t\t%s, Line %d" ) ,
158 Filename ,
159 LineNumber ) ;
160 if ( 0 != lineDisp )
162 pCurrPos += _snprintf ( pCurrPos , sizeof buffer - (pCurrPos - buffer),
163 ( " + %d bytes" ) ,
164 lineDisp ) ;
167 } else {
168 pCurrPos += _snprintf ( pCurrPos , sizeof buffer - (pCurrPos - buffer), ( "<unknown symbol>" ) ) ;
170 // Tack on a CRLF.
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 ));
205 // Get the function.
206 DWORD_PTR dwFuncDisp=0 ;
207 DWORD dwLineDisp=0;
208 if ( 0 != cSym.SymGetSymFromAddr ( dwAddr , &dwFuncDisp , pIHS ) )
210 haveFunction = true;
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 ,
219 &dwLineDisp ,
220 &stIHL );
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,
227 data);
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.
242 CONTEXT stCtx ;
243 if (pContext == NULL) {
245 stCtx.ContextFlags = CONTEXT_FULL ;
247 if ( GetThreadContext ( GetCurrentThread ( ) , &stCtx ) )
249 pContext = &stCtx;
252 if (pContext != NULL) {
253 STACKFRAME stFrame ;
254 DWORD dwMachine ;
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 ;
279 #else
280 #error ( "Unknown machine!" )
281 #endif
283 // Loop for the first <depth> stack elements.
284 for ( int i = 0 ; i < depth ; i++ )
286 if ( FALSE == StackWalk ( dwMachine ,
287 hProcess ,
288 //hProcess ,
289 GetCurrentThread(),
290 &stFrame ,
291 pContext ,
292 NULL ,
293 SymFunctionTableAccess ,
294 GetModBase ,
295 NULL ) )
297 break ;
299 if ( i >= numSkip )
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 ) ;