Original Post
Hi everyone. At the moment I'm writing exception handling code that should show a message box on a crash to the user along with a backtrace of where the program has been up till the crash. I was originally intending on doing a stack trace manually by putting in appropriate code at the beginning and end of each function, but I figured this would be time consuming ( I have 70k lines of code in this project ) and also error prone so I looked for a better way of doing it. So, I found out about the Win32 StackWalk() function and I've been trying ( unsuccessfully ) to get it working. It is displaying a stack trace at the moment, but it's not the correct stack trace. I stuck in a simple line of code in my main() function that tried to manipulate a null pointer and got the following stack trace: 1 - 0x004086fc 2 - 0x004010ab 3 - 0x7c862cd3 UnhandledExceptionFilter 4 - 0x7c843622 FindAtomW Running the debugger and allowing it to capture the exception I get the following: 1 - 0x0043ede5 WinMain (Main.cpp:96) 2 - 0x00496e3a main (C:/Program Files/CodeBlocks/bin/../lib/gcc/mingw32/3.4.4/../../../../include/c++/3.4.4/bits/stl_algobase.h:150) Clearly something is going wrong.. I'm not even getting the right addresses or the right amount of calls. Here's the code I'm using to find the stack trace: Can anyone spot anything I'm missing or anything that is wrong ? Thanks for your help.
/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Name: Errors::appendCallTrace()
Purpose: Appends a list of the last 8 functions called to the given error string.
Params: String to append the list of functions called to.
Returns: none
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/
void Errors::appendCallTrace( string & errorMessage )
{
// Store the names of all the functions called here:
list<string> functionNames;
// Initialise the symbol table to get function names:
SymInitialize
(
GetCurrentProcess(), // Process to get symbol table for
0, // Where to search for symbol files: dont care
true // Get symbols for all dll's etc. attached to process
);
// Store the current stack frame here:
STACKFRAME frame = { 0 };
// Get processor information for the current thread:
CONTEXT context; memset( & context , 0 , sizeof( CONTEXT ) );
context.ContextFlags = CONTEXT_FULL;
// Load the RTLCapture context function:
HINSTANCE kernel32 = LoadLibrary("Kernel32.dll");
typedef void ( * RtlCaptureContextFunc ) ( CONTEXT * ContextRecord );
RtlCaptureContextFunc rtlCaptureContext = (RtlCaptureContextFunc) GetProcAddress( kernel32, "RtlCaptureContext" );
// Capture the thread context
rtlCaptureContext( & context );
// Use this to fill the frame structure:
frame.AddrPC.Offset = context.Eip; // Current location in program
frame.AddrPC.Mode = AddrModeFlat; // Address mode for this pointer: flat 32 bit addressing
frame.AddrStack.Offset = context.Esp; // Stack pointers current value
frame.AddrStack.Mode = AddrModeFlat; // Address mode for this pointer: flat 32 bit addressing
frame.AddrFrame.Offset = context.Ebp; // Value of register used to access local function variables.
frame.AddrFrame.Mode = AddrModeFlat; // Address mode for this pointer: flat 32 bit addressing
// Keep getting stack frames from windows till there are no more left:
while
(
StackWalk
(
IMAGE_FILE_MACHINE_I386 , // MachineType - x86
GetCurrentProcess() , // Process to get stack trace for
GetCurrentThread() , // Thread to get stack trace for
& frame , // Where to store next stack frame
& context , // Pointer to processor context record
0 , // Routine to read process memory: use the default ReadProcessMemory
SymFunctionTableAccess , // Routine to access the modules symbol table
SymGetModuleBase , // Routine to access the modules base address
0 // Something to do with 16-bit code. Not needed.
)
)
{
//------------------------------------------------------------------
// Declare an image help symbol structure to hold symbol info and
// name up to 256 chars This struct is of variable lenght though so
// it must be declared as a raw byte buffer.
//------------------------------------------------------------------
static char symbolBuffer[ sizeof(IMAGEHLP_SYMBOL) + 255 ];
memset( symbolBuffer , 0 , sizeof(IMAGEHLP_SYMBOL) + 255 );
// Cast it to a symbol struct:
IMAGEHLP_SYMBOL * symbol = (IMAGEHLP_SYMBOL*) symbolBuffer;
// Need to set the first two fields of this symbol before obtaining name info:
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL) + 255;
symbol->MaxNameLength = 254;
// The displacement from the beginning of the symbol is stored here: pretty useless
unsigned displacement = 0;
// Get the symbol information from the address of the instruction pointer register:
if
(
SymGetSymFromAddr
(
GetCurrentProcess() , // Process to get symbol information for
frame.AddrPC.Offset , // Address to get symbol for: instruction pointer register
(DWORD*) & displacement , // Displacement from the beginning of the symbol: whats this for ?
symbol // Where to save the symbol
)
)
{
// Add the name of the function to the function list:
char buffer[2048]; sprintf( buffer , "0x%08x %s" , frame.AddrPC.Offset , symbol->Name );
functionNames.push_back(buffer);
}
else
{
// Print an unknown location:
// functionNames.push_back("unknown location");
char buffer[64]; sprintf( buffer , "0x%08x" , frame.AddrPC.Offset );
functionNames.push_back(buffer);
}
}
// Cleanup the symbol table:
SymCleanup( GetCurrentProcess() );
//--------------------------------------------------------------------------
// Print the names of all the functions called
//--------------------------------------------------------------------------
{
errorMessage += "\nBacktrace of locations visited by program: \n";
// Store the number of functions printed here:
unsigned count = 1;
// Run through the list of function names
list<string>::iterator i = functionNames.begin();
list<string>::iterator e = functionNames.end();
while ( i != e && count < 17 )
{
// Get this function name:
string & name = * i; i++;
// Add it to the error message
errorMessage += "\n";
static char buffer[8]; itoa(count,buffer,10); errorMessage += buffer;
errorMessage += " - ";
errorMessage += name;
// Increment the number of functions printed
count++;
}
}
}