RE: Call stack
"Daniel Vogel" <[email protected]> Wed, 9 Feb 2005 13:49:44 -0500
| Newsgroups | gmane.games.devel.windows |
|---|---|
| Message-ID | <[email protected]> |
> with the SP2 upgrade. StackWalk won't walk the whole stack - > it just gives up after returning 2 call stack frames. I've I attached the code of our stack walking implementation (sorry for the formatting, notepad didn't like our usage of tabs). It works fine for walking the stack after a crash as we have easy access to all the information we need to feed StackWalk64. > the stack. I have plenty of cases in the engine where I > capture a call stack for debugging later if something else IMO StackWalk64 is mostly useless for this case as you cannot call GetThreadContext on a running thread. http://msdn.microsoft.com/library/default.asp?url=/library/en-us/debug/b ase/getthreadcontext.asp I assume you're doing this as that's exactly what we did with our proxy malloc and it broke with SP2 as well. -- Daniel, Epic Games Inc.
stackwalk.txt
(text/plain, 3 KB)
INT CreateMiniDump( LPEXCEPTION_POINTERS ExceptionInfo )
{
// Try to create file for minidump.
HANDLE FileHandle = TCHAR_CALL_OS(
CreateFileW( MiniDumpFilenameW, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ),
CreateFileA( MiniDumpFilenameA, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )
);
// Write a minidump.
if( FileHandle )
{
MINIDUMP_EXCEPTION_INFORMATION DumpExceptionInfo;
DumpExceptionInfo.ThreadId = GetCurrentThreadId();
DumpExceptionInfo.ExceptionPointers = ExceptionInfo;
DumpExceptionInfo.ClientPointers = true;
MiniDumpWriteDump( GetCurrentProcess(), GetCurrentProcessId(), FileHandle, MiniDumpNormal, &DumpExceptionInfo, NULL, NULL );
CloseHandle( FileHandle );
}
// Walk the stack.
// Variables for stack walking.
HANDLE Process = GetCurrentProcess(),
Thread = GetCurrentThread();
DWORD64 Offset64 = 0;
DWORD Offset = 0,
SymOptions = SymGetOptions();
SYMBOL_INFO* Symbol = (SYMBOL_INFO*) appSystemMalloc( sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_LENGTH );
IMAGEHLP_LINE64 Line;
STACKFRAME64 StackFrame;
// Initialize stack frame.
memset( &StackFrame, 0, sizeof(StackFrame) );
StackFrame.AddrPC.Offset = ExceptionInfo->ContextRecord->Eip;
StackFrame.AddrPC.Mode = AddrModeFlat;
StackFrame.AddrFrame.Offset = ExceptionInfo->ContextRecord->Ebp;
StackFrame.AddrFrame.Mode = AddrModeFlat;
StackFrame.AddrStack.Offset = ExceptionInfo->ContextRecord->Esp;
StackFrame.AddrStack.Mode = AddrModeFlat;
StackFrame.AddrBStore.Mode = AddrModeFlat;
StackFrame.AddrReturn.Mode = AddrModeFlat;
// Set symbol options.
SymOptions |= SYMOPT_LOAD_LINES;
SymOptions |= SYMOPT_UNDNAME;
SymOptions |= SYMOPT_EXACT_SYMBOLS;
SymSetOptions( SymOptions );
// Initialize symbol.
memset( Symbol, 0, sizeof(SYMBOL_INFO) + MAX_SYMBOL_NAME_LENGTH );
Symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
Symbol->MaxNameLen = MAX_SYMBOL_NAME_LENGTH;
// Initialize line number info.
memset( &Line, 0, sizeof(Line) );
Line.SizeOfStruct = sizeof(Line);
// Load symbols.
SymInitialize( GetCurrentProcess(), ".", 1 );
while( 1 )
{
if( !StackWalk64( IMAGE_FILE_MACHINE_I386, Process, Thread, &StackFrame, ExceptionInfo->ContextRecord, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL ) )
break;
// Warning - ANSI_TO_TCHAR uses alloca which might not be safe during an exception handler - INVESTIGATE!
if( SymFromAddr( Process, StackFrame.AddrPC.Offset, &Offset64, Symbol ) && SymGetLineFromAddr64( Process, StackFrame.AddrPC.Offset, &Offset, &Line ) )
{
appStrncat( GErrorHist, *FString::Printf(TEXT("%s [Line %i] <- "),ANSI_TO_TCHAR(Symbol->Name), Line.LineNumber), ARRAY_COUNT(GErrorHist) );
debugf(TEXT("%45s Line %4i of %s"), ANSI_TO_TCHAR(Symbol->Name), Line.LineNumber, ANSI_TO_TCHAR(Line.FileName) );
}
}
SymCleanup( Process );
appSystemFree( Symbol );
return EXCEPTION_EXECUTE_HANDLER;
}