24.1.2 Exception Architecture

The overall exception architecture of Win32 encompasses the process creation primitives, the Microsoft calling standards, and system routines that raise, dispatch, and unwind exceptions.

When an exception is initiated, an attempt is made to notify the process' debugger. If the process is not being debugged, or if the associated debugger does not handle the exception, then a search of the current thread's call frames is conducted in an attempt to locate an exception handler. If no frame-based handler can be found, or none of the frame-based handlers handle the exception, then another attempt is made to notify the process' debugger. If there is no debugger, or the associated debugger does not handle the exception then the system provides default handling based on the exception type.

Thus the search hierarchy is:

Debugger first chance

Frame-based handlers

Debugger second chance

24.1.2.1 Frame-Based Exception Handlers

An exception handler can be associated with each call frame in the procedure call hierarchy of a program. This requires that each procedure or function that either saves nonvolatile registers or establishes an associated exception handler, have a call frame.

Microsoft compilers for Win32 adhere to a standard calling convention for the construction of a call frame.

24.1.2.2 Exception Dispatching

When a hardware exception occurs, the Win32 trap handling software gets control and saves the hardware state of the current thread in a context record. The reason for the trap is determined, and an exception record is constructed which describes the exception and any pertinent parameters. Executive software is then called to dispatch the exception.

If the previous processor mode was kernel, then the exception dispatcher is called to search the kernel stack call frames in an attempt to locate an exception handler. If a frame-based handler cannot be located, or no frame-based handler handles the exception, then the system is shut down as in ExitWindows. Unhandled exceptions emanating from within privileged software are considered fatal bugs.

If the previous processor mode was user, then an attempt is made to notify the process' debugger. This notification includes the exception record and the identification of the thread. The debugger may handle the exception (e.g., breakpoint or single step) and modify the thread state as appropriate, or not handle the exception and defer to any frame-based exception handlers found on the user stack.

If the debugger indicates that it has handled the exception, then the machine state is restored and thread execution is continued. Otherwise, if the debugger indicates that it has not handled the exception, or there is no debugger, then the exception dispatcher is invoked to search for frame-based exception handlers.

If a frame-based handler handles the exception, then thread execution is continued. Otherwise, if no frame-based handler is found, or no frame-based handler handles the exception, then the debugger (if present) is given a second chance to handle the exception. If the exception remains unhandled, the system default action is taken. For most exceptions, the default action is to call ExitProcess.

24.1.2.3 Exception Handling and Unwind

During the dispatching of an exception, each frame-based handler is called specifying the associated exception and context records as parameters. The exception handler can handle the exception and continue execution, not handle the exception and continue the search for an exception handler, or handle the exception and initiate an unwind operation.

Handling an exception may be as simple as noting an error and setting a flag that will be examined later, printing a warning or error message, or taking some other overt action. If execution can be continued, then it may be necessary to change the machine state by modifying the context record (e.g., advance the continuation instruction address).

If execution can be continued, then the exception handler returns to the exception dispatcher with a status code that specifies that execution should be continued. Continuing execution causes the exception dispatcher to stop its search for an exception handler. The machine state from the context record is restored and execution is continued accordingly.

If execution of the thread cannot be continued, then the exception handler usually initiates an unwind operation by calling a system supplied function specifying a target call frame and a continuation address. The unwind function walks the stack backwards searching for the target call frame. As it walks the stack, the unwind function calls each exception handler that is encountered to allow it to perform any cleanup actions that may be necessary (e.g., release a semaphore, etc.). When the target call frame is reached, the machine state is restored and execution is continued at the specified address.