9 #if defined(PDB_DEBUGGING)
20 #pragma comment( lib, "dbghelp.lib" )
22 HRESULT SCP_DumpStack( SCP_IDumpHandler* pISH );
23 BOOL SCP_mspdbcs_ResolveSymbol(
HANDLE hProcess, UINT_PTR dwAddress, SCP_mspdbcs_SDumpStackSymbolInfo& siSymbol );
25 DWORD64
__stdcall SCP_mspdbcs_GetModuleBase(
HANDLE hProcess, DWORD64 returnAddress );
30 static bool SCP_mspdbcs_initialised =
false;
33 BOOL SCP_mspdbcs_ResolveSymbol(
HANDLE hProcess, UINT_PTR dwAddress, SCP_mspdbcs_SDumpStackSymbolInfo& siSymbol )
37 char szUndec[ SCP_MSPDBCS_MAX_SYMBOL_LENGTH ];
38 char szWithOffset[ SCP_MSPDBCS_MAX_SYMBOL_LENGTH ];
39 char* pszSymbol = NULL;
42 memset( &siSymbol, 0,
sizeof( SCP_mspdbcs_SDumpStackSymbolInfo ) );
43 mi.SizeOfStruct =
sizeof( IMAGEHLP_MODULE64 );
45 siSymbol.dwAddress = dwAddress;
47 if ( !SymGetModuleInfo64( hProcess, dwAddress, &mi ) )
51 strcpy_s( siSymbol.szModule,
"<no module>" );
55 char* pszLastModule = strchr( mi.ImageName,
'\\' );
57 if ( pszLastModule == NULL )
58 pszLastModule = mi.ImageName;
62 strncpy_s( siSymbol.szModule, pszLastModule, _TRUNCATE );
69 CHAR rgchSymbol[
sizeof(IMAGEHLP_SYMBOL64) + SCP_MSPDBCS_MAX_SYMBOL_LENGTH ];
70 IMAGEHLP_SYMBOL64 sym;
73 memset( &sym.sym, 0,
sizeof( sym.sym ) );
74 sym.sym.SizeOfStruct =
sizeof( IMAGEHLP_SYMBOL64 );
77 sym.sym.Address = dwAddress;
79 sym.sym.Address = (
DWORD)dwAddress;
81 sym.sym.MaxNameLength = SCP_MSPDBCS_MAX_SYMBOL_LENGTH;
84 if ( SymGetSymFromAddr64( hProcess, dwAddress, &(siSymbol.dwOffset), &sym.sym ) )
86 if ( SymGetSymFromAddr64( hProcess, (
DWORD)dwAddress, &(siSymbol.dwOffset), &sym.sym ) )
89 pszSymbol = sym.sym.Name;
91 if ( UnDecorateSymbolName( sym.sym.Name, szUndec,
sizeof( szUndec )/
sizeof( szUndec[0] ),
92 UNDNAME_NO_MS_KEYWORDS | UNDNAME_NO_ACCESS_SPECIFIERS ) )
96 else if ( SymUnDName64( &sym.sym, szUndec,
sizeof( szUndec )/
sizeof( szUndec[0] ) ) )
101 if ( siSymbol.dwOffset != 0 )
103 sprintf_s( szWithOffset, SCP_MSPDBCS_MAX_SYMBOL_LENGTH,
"%s + %d bytes", pszSymbol, siSymbol.dwOffset );
104 szWithOffset[ SCP_MSPDBCS_MAX_SYMBOL_LENGTH - 1 ] =
'\0';
105 pszSymbol = szWithOffset;
109 pszSymbol =
"<no symbol>";
111 __except( EXCEPTION_ACCESS_VIOLATION == GetExceptionCode( ) )
113 pszSymbol =
"<EX: no symbol>";
114 siSymbol.dwOffset = dwAddress - mi.BaseOfImage;
117 strncpy_s( siSymbol.szSymbol, pszSymbol, _TRUNCATE );
124 return SymFunctionTableAccess64( hProcess, dwPCAddress );
127 DWORD64
__stdcall SCP_mspdbcs_GetModuleBase(
HANDLE hProcess, DWORD64 returnAddress )
129 IMAGEHLP_MODULE moduleInfo;
130 moduleInfo.SizeOfStruct =
sizeof( IMAGEHLP_MODULE );
134 if ( SymGetModuleInfo( hProcess, returnAddress, &moduleInfo ) )
136 if ( SymGetModuleInfo( hProcess, (ULONG)returnAddress, &moduleInfo ) )
139 return moduleInfo.BaseOfImage;
143 MEMORY_BASIC_INFORMATION memoryBasicInfo;
145 if ( VirtualQueryEx( hProcess, (
LPVOID)returnAddress,
146 &memoryBasicInfo,
sizeof( MEMORY_BASIC_INFORMATION ) ) )
150 cch = GetModuleFileNameA( (
HINSTANCE)memoryBasicInfo.AllocationBase, szFile,
MAX_PATH );
151 SymLoadModule( hProcess, NULL, ((cch)?szFile:NULL),
153 NULL, (DWORD_PTR)memoryBasicInfo.AllocationBase, 0 );
155 NULL, (
DWORD)(DWORD_PTR)memoryBasicInfo.AllocationBase, 0 );
157 return (DWORD_PTR)memoryBasicInfo.AllocationBase;
167 memset( &context, 0,
sizeof( CONTEXT ) );
168 context.ContextFlags = CONTEXT_FULL;
169 SCP_mspdbcs_SDumpStackThreadInfo* pdsti =
170 reinterpret_cast< SCP_mspdbcs_SDumpStackThreadInfo*
>( pv );
175 SuspendThread( pdsti->hThread );
177 pdsti->pIDS->OnBegin( );
180 GetThreadContext( pdsti->hThread, &context );
183 DWORD dw = SymGetOptions( );
184 dw = dw & ~SYMOPT_UNDNAME;
188 STACKFRAME64 stackFrame;
189 memset( &stackFrame, 0,
sizeof( STACKFRAME64 ) );
190 stackFrame.AddrPC.Mode = AddrModeFlat;
191 stackFrame.AddrFrame.Mode = AddrModeFlat;
192 stackFrame.AddrStack.Mode = AddrModeFlat;
193 stackFrame.AddrReturn.Mode = AddrModeFlat;
194 stackFrame.AddrBStore.Mode = AddrModeFlat;
205 dwMachType = IMAGE_FILE_MACHINE_I386;
206 stackFrame.AddrPC.Offset = context.Eip;
207 stackFrame.AddrStack.Offset = context.Esp;
208 stackFrame.AddrFrame.Offset = context.Ebp;
209 #elif defined(_M_AMD64)
210 dwMachType = IMAGE_FILE_MACHINE_AMD64;
211 stackFrame.AddrPC.Offset = context.Rip;
212 stackFrame.AddrStack = context.Rsp;
214 # error UNKNOWN ARCHITECTURE
221 for (
int currFrame = 0; currFrame < SCP_MSPDBCS_MAX_STACK_FRAMES; currFrame++ )
223 if ( !StackWalk64( dwMachType, pdsti->hProcess, pdsti->hThread,
224 &stackFrame, &context, NULL,
225 SCP_mspdbcs_FunctionTableAccess, SCP_mspdbcs_GetModuleBase, NULL ) )
231 if ( stackFrame.AddrPC.Offset != 0 )
233 if ( pdsti->pIDS->ResolveSymbols( ) )
234 addresses.push_back( (
void*)(DWORD_PTR)stackFrame.AddrPC.Offset );
236 pdsti->pIDS->OnEntry( (
void*)(DWORD_PTR)stackFrame.AddrPC.Offset, NULL, NULL );
240 if ( pdsti->pIDS->ResolveSymbols( ) )
243 for (
size_t i = 0;
i < addresses.size( );
i++ )
245 SCP_mspdbcs_SDumpStackSymbolInfo info;
246 const char* szModule = NULL;
247 const char* szSymbol = NULL;
249 if ( SCP_mspdbcs_ResolveSymbol( pdsti->hProcess, (UINT_PTR)addresses[
i ], info ) )
251 szModule = info.szModule;
252 szSymbol = info.szSymbol;
255 pdsti->pIDS->OnEntry( addresses[ i ], szModule, szSymbol );
259 pdsti->pIDS->OnEnd( );
260 ResumeThread( pdsti->hThread );
266 HRESULT SCP_DumpStack( SCP_IDumpHandler* pIDH )
272 HANDLE hPseudoThread = GetCurrentThread( );
273 HANDLE hPseudoProcess = GetCurrentProcess( );
277 if ( !DuplicateHandle( hPseudoProcess, hPseudoThread,
278 hPseudoProcess, &hThread,
279 0,
FALSE, DUPLICATE_SAME_ACCESS ) )
280 return HRESULT_FROM_WIN32( GetLastError( ) );
284 SCP_mspdbcs_SDumpStackThreadInfo info;
285 info.hProcess = hPseudoProcess;
286 info.hThread = hThread;
290 EnterCriticalSection( &SCP_mspdbcs_cs );
294 if ( !SCP_mspdbcs_initialised )
296 LeaveCriticalSection( &SCP_mspdbcs_cs );
297 mprintf( (
"Symbols not initialised\n") );
301 HANDLE workerThread = CreateThread( NULL, 0, SCP_mspdbcs_DumpStackThread,
304 LeaveCriticalSection( &SCP_mspdbcs_cs );
306 if ( workerThread == NULL )
307 return HRESULT_FROM_WIN32( GetLastError( ) );
309 while ( WaitForSingleObject( workerThread, 0 ) != WAIT_OBJECT_0 );
311 CloseHandle( workerThread );
315 #endif // PDB_DEBUGGING
320 HANDLE hPseudoProcess = GetCurrentProcess( );
321 if ( !SymInitialize( hPseudoProcess, NULL,
TRUE ) )
323 mprintf( (
"Could not initialise symbols - callstacks will fail: %x\n", HRESULT_FROM_WIN32( GetLastError( ) ) ) );
327 InitializeCriticalSection( &SCP_mspdbcs_cs );
328 SCP_mspdbcs_initialised =
true;
340 EnterCriticalSection( &SCP_mspdbcs_cs );
341 SCP_mspdbcs_initialised =
false;
342 LeaveCriticalSection( &SCP_mspdbcs_cs );
344 DeleteCriticalSection( &SCP_mspdbcs_cs );
346 HANDLE hPseudoProcess = GetCurrentProcess( );
347 SymCleanup( hPseudoProcess );
SDL_mutex * CRITICAL_SECTION
void SCP_mspdbcs_Initialise()
void SCP_mspdbcs_Cleanup()