Visual Studio unhandled exception stack trace

At work I've got the task to get a stacktrace to a thower of unhandled std exception. The first think I've tried was to print stacktrace from a terminate handler set with std::set_terminate. But I had no lack with this way because the stack is unwinded before std::terminate was called. The solution is to use windows API to get the result.

Three steps to get the stacktrace:



1. Detect unhandled exception

I've found a function SetUnhandledExceptionFilter which allowed me to get context of exception throw. In practice the context is just state of registers of a processor, but this is actually enough to do the thing.
Lets see the function takes a pointer to a handler of this format
The handler gets the struct _EXCEPTION_POINTERS, containing the context and exception signature, as input. It returns instruction what to do with this particular exception case. I return EXCEPTION_CONTINUE_SEARCH because looks like this is kinda default.

2. Get stacktrace as list of offsets in memory

The function with a healthy name "StackWalk" helps us in stepping though the stack. 
It expects a number of argument but don't be scared, in our case we use only 4 of them, the rest are NULL.

Use next function to get necessary information about current process:

MachineType = https://docs.microsoft.com/en-us/windows/desktop/api/wow64apiset/nf-wow64apiset-iswow64process2

hProcess = GetCurrentProcessId()

hThread = GetCurrentThread()

StackFrame = Not as easy
We have to fill this struct for the first frame of stack and this parameter will also be used as output for every next frame. 

Again we don't need every parameter. Take all values from _EXCEPTION_POINTERS structure passed to UnhandledExceptionFilter.
Just provide next 3 values:
AddrPc - from EIP for x86 or RIP for x64
AddrFrame - EBP for x86 or RBP for x64
AddrStack - ESP for x86 or RSP for x64

Fill the reset with default values (NULL or False)

Now call StackWalk in cycle until it return false and record AddrStack adresss every iteration. List of this values is actually a binary stacktrace.

There is also another option is to use "MiniDumpWriteDump"
This gives you a minidump file allowing to get stacktrace and even local variables. Minidump files are opened in visual studio and allows to reproduce error.

LONG WINAPI MyUnhandledExceptionFilter( _In_ struct _EXCEPTION_POINTERS *exceptionInfo ) {
 STACKFRAME64 stackFrame;
 stackFrame.AddrPC = ADDRESS64{ exceptionInfo->ContextRecord->Eip, 0, AddrModeFlat };
 stackFrame.AddrFrame = ADDRESS64{ exceptionInfo->ContextRecord->Ebp, 0, AddrModeFlat };
 stackFrame.AddrStack = ADDRESS64{ exceptionInfo->ContextRecord->Esp, 0, AddrModeFlat };
 stackFrame.FuncTableEntry = NULL;
 stackFrame.Params[0] = 0;
 stackFrame.Far = FALSE;
 stackFrame.Virtual = FALSE;
 stackFrame.Reserved[0] = 0;

 DAVA::Vector stackPointers;

 while (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(), &stackFrame, NULL, NULL, NULL, NULL, NULL)) {
  stackPointers.push_back(reinterpret_cast(stackFrame.AddrPC.Offset));
 }

 return EXCEPTION_EXECUTE_HANDLER;
}

3. Stringify

Didn't implemented yet.

Комментарии

Популярные сообщения из этого блога

Siege Up! Editor (beta)

Git и Yandex.Disk

STM32F4 и программный выход в DFU