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

chandler.c File Reference

#include "nt.h"

Go to the source code of this file.

Functions

LONG __C_ExecuteExceptionFilter (PEXCEPTION_POINTERS ExceptionPointers, EXCEPTION_FILTER ExceptionFilter, ULONG_PTR EstablisherFrame)
VOID __C_ExecuteTerminationHandler (BOOLEAN AbnormalTermination, TERMINATION_HANDLER TerminationHandler, ULONG_PTR EstablisherFrame)
EXCEPTION_DISPOSITION __C_specific_handler (IN struct _EXCEPTION_RECORD *ExceptionRecord, IN void *EstablisherFrame, IN OUT struct _CONTEXT *ContextRecord, IN OUT struct _DISPATCHER_CONTEXT *DispatcherContext)


Function Documentation

LONG __C_ExecuteExceptionFilter PEXCEPTION_POINTERS  ExceptionPointers,
EXCEPTION_FILTER  ExceptionFilter,
ULONG_PTR  EstablisherFrame
 

VOID __C_ExecuteTerminationHandler BOOLEAN  AbnormalTermination,
TERMINATION_HANDLER  TerminationHandler,
ULONG_PTR  EstablisherFrame
 

EXCEPTION_DISPOSITION __C_specific_handler IN struct _EXCEPTION_RECORD *  ExceptionRecord,
IN void *  EstablisherFrame,
IN OUT struct _CONTEXT *  ContextRecord,
IN OUT struct _DISPATCHER_CONTEXT DispatcherContext
 

Definition at line 52 of file alpha/chandler.c.

References __C_ExecuteExceptionFilter(), __C_ExecuteTerminationHandler(), ExceptionContinueExecution, ExceptionContinueSearch, Index, RtlUnwind2(), and TRUE.

00061 : 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 } }


Generated on Sat May 15 19:43:03 2004 for test by doxygen 1.3.7