test: chandler.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# chandler.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1990  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     chandler.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the C specific exception handler that provides
    00012     structured condition handling for the C language.
    00013
    00014 Author:
    00015
    00016     David N. Cutler (davec) 11-Sep-1990
    00017
    00018 Environment:
    00019
    00020     Any mode.
    00021
    00022 Revision History:
    00023
    00024     Thomas Van Baak (tvb) 29-Apr-1992
    00025
    00026         Adapted for Alpha AXP.
    00027
    00028 --*/
    00029
    00030 #include "nt.h"
    00031
    00032 //
    00033 // Define procedure prototypes for exception filter and termination handler
    00034 // execution routines defined in jmpuwind.s.
    00035 //
    00036
    00037 LONG
    00038 __C_ExecuteExceptionFilter (
    00039     PEXCEPTION_POINTERS ExceptionPointers,
    00040     EXCEPTION_FILTER ExceptionFilter,
    00041     ULONG_PTR EstablisherFrame
    00042     );
    00043
    00044 VOID
    00045 __C_ExecuteTerminationHandler (
    00046     BOOLEAN AbnormalTermination,
    00047     TERMINATION_HANDLER TerminationHandler,
    00048     ULONG_PTR EstablisherFrame
    00049     );
    00050
    00051 EXCEPTION_DISPOSITION
    00052 __C_specific_handler (
    00053     IN struct _EXCEPTION_RECORD *ExceptionRecord,
    00054     IN void *EstablisherFrame,
    00055     IN OUT struct _CONTEXT *ContextRecord,
    00056     IN OUT struct _DISPATCHER_CONTEXT *DispatcherContext
    00057     )
    00058
    00059 /*++
    00060
    00061 Routine Description:
    00062
    00063     This function scans the scope tables associated with the specified
    00064     procedure and calls exception and termination handlers as necessary.
    00065
    00066     This language specific exception handler function is called on a
    00067     per-frame basis and in two different cases:
    00068
    00069     First, the IS_DISPATCHING case, it is called by the exception
    00070     dispatcher, RtlDispatchException, via the short assembler routine,
    00071     __C_ExecuteHandlerForException, when trying to locate exception
    00072     filters within the given frame.
    00073
    00074     Second, the IS_UNWINDING case, it is called by the frame unwinder,
    00075     RtlUnwind, via the short assembler routine, __C_ExecuteHandlerForUnwind,
    00076     when unwinding the stack and trying to locate termination handlers
    00077     within the given frame.
    00078
    00079 Arguments:
    00080
    00081     ExceptionRecord - Supplies a pointer to an exception record.
    00082
    00083     EstablisherFrame - Supplies a pointer to frame of the establisher function.
    00084
    00085     ContextRecord - Supplies a pointer to a context record.
    00086
    00087     DispatcherContext - Supplies a pointer to the exception dispatcher or
    00088         unwind dispatcher context.
    00089
    00090 Return Value:
    00091
    00092     If the exception is handled by one of the exception filter routines, then
    00093     there is no return from this routine and RtlUnwind is called. Otherwise,
    00094     an exception disposition value of continue execution or continue search is
    00095     returned.
    00096
    00097 --*/
    00098
    00099 {
    00100
    00101     ULONG_PTR ControlPc;
    00102     EXCEPTION_FILTER ExceptionFilter;
    00103     EXCEPTION_POINTERS ExceptionPointers;
    00104     PRUNTIME_FUNCTION FunctionEntry;
    00105     ULONG Index;
    00106     PSCOPE_TABLE ScopeTable;
    00107     ULONG_PTR TargetPc;
    00108     TERMINATION_HANDLER TerminationHandler;
    00109     LONG Value;
    00110
    00111     //
    00112     // Get the address of where control left the establisher, the address of
    00113     // the function table entry that describes the function, and the address of
    00114     // the scope table.
    00115     //
    00116
    00117     ControlPc = DispatcherContext->ControlPc;
    00118     FunctionEntry = DispatcherContext->FunctionEntry;
    00119     ScopeTable = (PSCOPE_TABLE)(FunctionEntry->HandlerData);
    00120
    00121     //
    00122     // The scope table HandlerAddress is either the address of an exception
    00123     // filter or a termination handler. The C compiler wraps the code in the
    00124     // exception filter expression or the termination handler clause within
    00125     // an internal C function. The value of the scope table JumpTarget field
    00126     // is used to distinguish an exception filter function (JumpTarget non zero)
    00127     // from a termination handler function (JumpTarget is zero).
    00128     //
    00129
    00130     //
    00131     // If an unwind is not in progress, then scan the scope table and call
    00132     // the appropriate exception filter routines. Otherwise, scan the scope
    00133     // table and call the appropriate termination handlers using the target
    00134     // PC obtained from the context record.
    00135     //
    00136
    00137     if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) {
    00138
    00139         //
    00140         // Set up the ExceptionPointers structure that is passed as the argument
    00141         // to the exception filter. It is used by the compiler to implement the
    00142         // intrinsic functions exception_code() and exception_info().
    00143         //
    00144
    00145         ExceptionPointers.ExceptionRecord = ExceptionRecord;
    00146         ExceptionPointers.ContextRecord = ContextRecord;
    00147
    00148         //
    00149         // Scan the scope table and call the appropriate exception filter
    00150         // routines. The scope table entries are known to be sorted by
    00151         // increasing EndAddress order. Thus a linear scan will naturally
    00152         // hit inner scope exception clauses before outer scope clauses.
    00153         //
    00154
    00155         for (Index = 0; Index < ScopeTable->Count; Index += 1) {
    00156             if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
    00157                 (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) &&
    00158                 (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) {
    00159
    00160                 //
    00161                 // Call the exception filter routine.
    00162                 //
    00163
    00164                 ExceptionFilter =
    00165                     (EXCEPTION_FILTER)ScopeTable->ScopeRecord[Index].HandlerAddress;
    00166                 Value = __C_ExecuteExceptionFilter(&ExceptionPointers,
    00167                                                    ExceptionFilter,
    00168                                                    (ULONG_PTR)EstablisherFrame);
    00169
    00170                 //
    00171                 // If the return value is less than zero, then dismiss the
    00172                 // exception. Otherwise, if the value is greater than zero,
    00173                 // then unwind to the target exception handler corresponding
    00174                 // to the exception filter. Otherwise, continue the search for
    00175                 // an exception filter.
    00176                 //
    00177
    00178                 //
    00179                 // Exception filters will usually return one of the following
    00180                 // defines, although the decision below is made only by sign:
    00181                 //
    00182                 //  #define EXCEPTION_EXECUTE_HANDLER     1
    00183                 //  #define EXCEPTION_CONTINUE_SEARCH     0
    00184                 //  #define EXCEPTION_CONTINUE_EXECUTION -1
    00185                 //
    00186
    00187                 if (Value < 0) {
    00188                     return ExceptionContinueExecution;
    00189
    00190                 } else if (Value > 0) {
    00191
    00192                     //
    00193                     // Set the return value for the unwind to the exception
    00194                     // code so the exception handler clause can retrieve it
    00195                     // from v0. This is how GetExceptionCode() is implemented
    00196                     // in exception handler clauses.
    00197                     //
    00198
    00199                     RtlUnwind2(EstablisherFrame,
    00200                                (PVOID)ScopeTable->ScopeRecord[Index].JumpTarget,
    00201                                ExceptionRecord,
    00202                                ULongToPtr( ExceptionRecord->ExceptionCode ),
    00203                                ContextRecord);
    00204                 }
    00205             }
    00206         }
    00207
    00208     } else {
    00209
    00210         //
    00211         // Scan the scope table and call the appropriate termination handler
    00212         // routines.
    00213         //
    00214
    00215         TargetPc = (ULONG_PTR)ContextRecord->Fir;
    00216         for (Index = 0; Index < ScopeTable->Count; Index += 1) {
    00217             if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
    00218                 (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) {
    00219
    00220                 //
    00221                 // If the target PC is within the same scope the control PC
    00222                 // is within, then this is an uplevel goto out of an inner try
    00223                 // scope or a long jump back into a try scope. Terminate the
    00224                 // scan for termination handlers - because any other handlers
    00225                 // will be outside the scope of both the goto and its label.
    00226                 //
    00227                 // N.B. The target PC can be just beyond the end of the scope,
    00228                 //      in which case it is a leave from the scope.
    00229                 //
    00230
    00231                 if ((TargetPc >= ScopeTable->ScopeRecord[Index].BeginAddress) &&
    00232                     (TargetPc <= ScopeTable->ScopeRecord[Index].EndAddress)) {
    00233                     break;
    00234
    00235                 } else {
    00236
    00237                     //
    00238                     // If the scope table entry describes an exception filter
    00239                     // and the associated exception handler is the target of
    00240                     // the unwind, then terminate the scan for termination
    00241                     // handlers. Otherwise, if the scope table entry describes
    00242                     // a termination handler, then record the address of the
    00243                     // end of the scope as the new control PC address and call
    00244                     // the termination handler.
    00245                     //
    00246                     // Recording a new control PC is necessary to ensure that
    00247                     // termination handlers are called only once even when a
    00248                     // collided unwind occurs.
    00249                     //
    00250
    00251                     if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) {
    00252
    00253                         //
    00254                         // try/except - exception filter (JumpTarget != 0).
    00255                         // After the exception filter is called, the exception
    00256                         // handler clause is executed by the call to unwind
    00257                         // above. Having reached this point in the scan of the
    00258                         // scope tables, any other termination handlers will
    00259                         // be outside the scope of the try/except.
    00260                         //
    00261
    00262                         if (TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) {
    00263                             break;
    00264                         }
    00265
    00266                     } else {
    00267
    00268                         //
    00269                         // try/finally - termination handler (JumpTarget == 0).
    00270                         //
    00271
    00272                         //
    00273                         // Unless the termination handler results in a long
    00274                         // jump, execution will resume at the instruction after
    00275                         // the exception handler clause.
    00276                         //
    00277                         // ## tvb - I'm still suspicious of the +4 below.
    00278
    00279                         DispatcherContext->ControlPc =
    00280                                 ScopeTable->ScopeRecord[Index].EndAddress + 4;
    00281                         TerminationHandler =
    00282                             (TERMINATION_HANDLER)ScopeTable->ScopeRecord[Index].HandlerAddress;
    00283                         __C_ExecuteTerminationHandler(TRUE,
    00284                                                       TerminationHandler,
    00285                                                       (ULONG_PTR)EstablisherFrame);
    00286                     }
    00287                 }
    00288             }
    00289         }
    00290     }
    00291
    00292     //
    00293     // Continue search for exception filters or termination handlers.
    00294     //
    00295
    00296     return ExceptionContinueSearch;
    00297 }