5.1.9 Invocation of Exception Handlers

The search for an exception handler begins with the program counter value that indicates the address at which the exception was raised. As a general rule, a program counter value is associated with a procedure descriptor that provides information needed to identify the procedure that contains the code and to interpret those parts of the stack frame that are needed to walk the procedure call chain. (See also Procedure Invocations and Call Chains.)

If a null frame procedure or other fragment of code does not have an associated procedure descriptor, then it is assumed that an appropriate initial program counter value is located in the normal return address register (R26). If there is a procedure descriptor associated with this address, then the search for an exception handler begins using that address. Otherwise, a fatal exception is raised (and the executing thread is terminated).

Order of Invocation

When an exception is raised, established exception handlers are invoked in a specific order.

Any frame-based handlers are invoked in order from that established by the most current procedure invocation to the oldest predecessor in the invocation chain.

If no frame-based handlers have been established, or if all reraise the exception, then the system last-chance handler is invoked.

Nested Exceptions

A nested exception occurs if an exception is raised while an exception handler is active.

When a nested exception occurs, the structure of the procedure invocation chain, from the most recent procedure invocation to the oldest predecessor, is as follows:

  1. The procedure invocation within which the nested exception was raised.

  2. Zero or more procedures invoked indirectly or directly by the most recently invoked (most current) handler.

  3. The most current handler.

    This is the same invocation as item 1 (that in which the nested exception was raised) if there are zero invocations in item 2. In this case, items 1 and 3 count as just one invocation.

  4. The procedure invocation within which the active exception that immediately preceded the nested exception was raised; that is, the invocation in which the exception was raised for which the most current handler was invoked.

  5. Zero or more procedure invocations, all established handlers that were invoked for the exception that immediately preceded the nested exception, and all of which reraised.

  6. The establisher of the most current handler.

    This is the same as item 4 (the invocation in which the exception that immediately preceded the nested exception was raised) if there are zero invocations in item 5.

  7. Zero or more procedure invocations for which no established handlers have yet been invoked.

Established handlers are invoked in reverse order with respect to that in which their establishers were invoked; that is, the search of stack frames for procedure invocations that have established handlers is in order from 1 to 7.

If further nested exceptions occur, this procedure invocation chain structure is repeated for those further nested exceptions, and frame-based handlers are invoked according to the above rules, in order from those established by the most current procedure to those established by the oldest predecessor.

Steps for Locating and Invoking Handlers for Exceptions

When an exception is raised, the steps that implement the above explanation are detailed in the following. (Note that these steps cover only the search of stack frames for a handler proper and do not address the mapping of a POSIX signal to an exception.)

  1. Let current_invocation be the procedure invocation in which the exception was raised.

  2. [loop]: If current_invocation does not establish a handler, go to step [check-begin] below.

  3. Invoke the handler established by current_invocation.

  4. If the handler returns ExceptionContinueExecution or initiates an unwind, exit these steps.

  5. [check-begin]: If current_invocation is the beginning of the procedure invocation chain, go to step [last-chance] below.

  6. If current_invocation is an active handler, let current_invocation be the invocation in which the exception was raised that invoked this active handler, and go to step [loop] above.

  7. Let current_invocation be the procedure invocation that invoked current_invocation.

  8. Go to step [loop] above.

  9. [last-chance]: Invoke the system last chance handler.

Invalid Thread Stack

If, during the search for and invocation of frame-based handlers, the exception dispatcher detects that the thread's stack is corrupt, then the following steps take place:

  1. The EXCEPTION_STACK_INVALID flag is set to 1.

  2. The search for handlers immediately proceeds to the system last-chance handler.

Handler Invocation and Arguments

Every exception handler is invoked as a function that returns a status value. The function call is defined as follows:

(*ExceptionHandler)( ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext )

Arguments

ExceptionRecord  

The address of a primary exception record.

EstablisherFrame  

Virtual frame pointer of the establisher.

ContextRecord  

Address of an invocation context block containing the saved original context at the point where the exception occurred. During an unwind, this is the address of the invocation context block for the establisher.

DispatcherContext  

Address of a control record for the exception dispatcher (see below).

Function Value

Status  

A value indicating the action to be taken upon handler return. The valid values are ExceptionContinueExecution and ExceptionContinueSearch.

Note   The exception dispatcher allows additional return values from its own exception handlers.

Remarks

The control record pointed to by DispatcherContext provides communication between the handler and the exception dispatcher (the system routine that actually invokes the handler). This record provides information about the establisher. Of the fields listed below, all but ControlPC are read-only to exception handlers (except for handlers for the exception dispatcher itself).

ControlPC contains the PC where control left the establisher of the exception handler; i.e., the PC of the call instruction or the instruction that caused the exception. This field may be updated by a handler. If a nested exception occurs during unwinding while the handler is still active, then the value of the PC used for the establisher will be the updated value of ControlPC. This mechanism can be employed to retire nested exception-handling scopes local to a procedure to ensure that each is executed at most once (even in the presence of a nested exception within such a handler). The ControlPC value, however, must always be an address within the procedure whose handler is executing.

FunctionEntry contains a pointer to the primary procedure descriptor for the establisher.