__try
{
}
__except(FilterFunction())
{
}
Let's start to find out what are the inner details of exceptions. How does windows carry out exception dispatching.
We are completely focusing on X86 exception dispatching. Amd64 has a little difference in the way exceptions are handled and I will try to cover them later.
As soon as the processor sees an exception during the execution of an instruction, it first checks which ring it is executing in(i.e. whether its user mode or kernel mode). lets consider first User Mode. if it is user mode it first switches to kernel mode stack. Kernel mode stack can be retrieved from the task state register of the task. However how processor switches back to kernel mode is not a topic of this blog.
So once the processor switches back to kernel mode it pushes some of the registers on the stack before it actually calls the interrupt handler(each type of interrupt/exception has a different interrup handler for example for divide by zero the interrupt handler is nt!kiTrap00). These registers are:
Push SS //this is 23 for i386 User Mode
Push esp
Push Eflags
Push cs //this is 1b for i386 User mode
Push eip
Push ErrorCode
The purpose of these register is to remember the state and instruction which caused the exception.
However these does not save complete state of the execution context, so right after saving this processor dispatches to interrupt handler. Interrupt handler saves a few other registers/addresses on the stack and this complete saved structure is called the trap frame.
The interrupt hadnler creates a EXCEPTION_RECORD and calls the kernel routine that dispatches the exceptions. This routine checks if a debugger was attached to the process then it sends a message to break in and this is what we call a first chance exception. If debugger handles the exception the interrupt handler uses the trap frame to resume the instruction that caused exception.
But if debugger doesn't handle the exception the kernel mode exception dispatching api needs to call user mode exception dispatcher which finally searches for all exception handlers registerd by program and operating system. However before dispatching to user mode exception dispatcher the kernel mode dispatcher copies the EXCEPTION_POINTER structure to user mode. Once this is done we are again in user mode with exception information already copied to user space and the control is at User mode exception dispatcher.
The user mode exception dispatcher function searches for all the exception handler in the call chain. If any of the handler provided by the program returns EXCEPTION_CONTINUE_EXECUTION. The execution is contiuned.
If the handler provided by the program returns EXCEPTION_EXECUTE_HANDLER then the code under the catch block is executed.
However if none of the program defined exception handler handles the exception then system provided UnhandledExceptionFilter is called. it again checks if the process is under debugger or not.
if it is, the debugger is sent again the break in command and this is what we know as second chance exception.
if the debugger is not attached this function searches for WER settings and if that is set the WER message is popped( the familiar message box saying the program stopped working)
If there is no WER, then UnhandledExceptionFilter returns the EXCEPTION_EXCEUTE_HANDLER which in turn the causes the very first catch block(provided by system) to execute and this simply terminates the process.
No comments:
Post a Comment