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

ghandler.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1993 Digital Equipment Corporation 00004 00005 Module Name: 00006 00007 ghandler.c 00008 00009 Abstract: 00010 00011 This module implements the C specific exception handler that provides 00012 structured exception handling for code generated by the GEM compiler. 00013 00014 Author: 00015 00016 John Parks (parks) 12-Jan-1993 00017 Thomas Van Baak (tvb) 28-Jan-1993 00018 00019 Environment: 00020 00021 Any mode. 00022 00023 Revision History: 00024 00025 --*/ 00026 00027 #include "nt.h" 00028 00029 // 00030 // Define procedure prototypes for exception filter and termination handler 00031 // execution routines defined in jmpunwnd.s. 00032 // 00033 00034 LONG 00035 __C_ExecuteExceptionFilter ( 00036 PEXCEPTION_POINTERS ExceptionPointers, 00037 EXCEPTION_FILTER ExceptionFilter, 00038 ULONG_PTR EstablisherFrame 00039 ); 00040 00041 ULONG_PTR 00042 __C_ExecuteTerminationHandler ( 00043 BOOLEAN AbnormalTermination, 00044 TERMINATION_HANDLER TerminationHandler, 00045 ULONG_PTR EstablisherFrame 00046 ); 00047 00048 // 00049 // Define local procedure prototypes. 00050 // 00051 00052 EXCEPTION_DISPOSITION 00053 _OtsCSpecificHandler ( 00054 IN PEXCEPTION_RECORD ExceptionRecord, 00055 IN PVOID EstablisherFrame, 00056 IN OUT PCONTEXT ContextRecord, 00057 IN OUT PDISPATCHER_CONTEXT DispatcherContext 00058 ); 00059 00060 ULONG_PTR 00061 _OtsLocalFinallyUnwind ( 00062 IN PSEH_CONTEXT SehContext, 00063 IN PSEH_BLOCK TargetSeb, 00064 IN PVOID RealFramePointer 00065 ); 00066 00067 // 00068 // Define local macros. 00069 // 00070 00071 #define IS_EXCEPT(Seb) ((Seb)->JumpTarget != 0) 00072 #define IS_FINALLY(Seb) ((Seb)->JumpTarget == 0) 00073 00074 // 00075 // Initialize an exception record for the unwind with the SEB of the target 00076 // included as one information parameter. This is done so that the target 00077 // frame of the unwind may execute all the finally handlers necessary given 00078 // the SEB pointer at the unwind target. 00079 // 00080 00081 #define MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, Seb) { \ 00082 ExceptionRecord->ExceptionCode = STATUS_UNWIND; \ 00083 ExceptionRecord->ExceptionFlags = EXCEPTION_UNWINDING; \ 00084 ExceptionRecord->ExceptionRecord = NULL; \ 00085 ExceptionRecord->ExceptionAddress = 0; \ 00086 ExceptionRecord->NumberParameters = 1; \ 00087 ExceptionRecord->ExceptionInformation[0] = (ULONG_PTR)(Seb); \ 00088 } 00089 00090 EXCEPTION_DISPOSITION 00091 _OtsCSpecificHandler ( 00092 IN PEXCEPTION_RECORD ExceptionRecord, 00093 IN PVOID EstablisherFrame, 00094 IN OUT PCONTEXT ContextRecord, 00095 IN OUT PDISPATCHER_CONTEXT DispatcherContext 00096 ) 00097 00098 /*++ 00099 00100 Routine Description: 00101 00102 This function walks up the list of SEB's associated with the specified 00103 procedure and calls except filters and finally handlers as necessary. 00104 00105 It is called in two different contexts: 00106 (i) by the exception dispatcher after an exception is raised 00107 (ii) by the unwinder during an unwind operation 00108 00109 In the first case, is searches the SEB list for except filters to evaluate. 00110 In the second case, it searches for finally handlers to execute. 00111 00112 Arguments: 00113 00114 ExceptionRecord - Supplies a pointer to an exception record. 00115 00116 EstablisherFrame - Supplies a (virtual frame) pointer to the frame of the 00117 establisher function. 00118 00119 ContextRecord - Supplies a pointer to a context record. 00120 00121 DispatcherContext - Supplies a pointer to the exception dispatcher or 00122 unwind dispatcher context. 00123 00124 Return Value: 00125 00126 If the exception is handled by one of the exception filter routines, then 00127 there is no return from this routine and RtlUnwind is called. Otherwise, 00128 an exception disposition value of continue execution or continue search is 00129 returned. 00130 00131 Notes: 00132 In context (i) there are 3 possibilities: 00133 00134 (a) If an exception filter returns a value greater that 0 (meaning 00135 that the associated handler should be invoked) there is no 00136 return from this function. RtlUnwind is called to unwind the 00137 stack to the exception handler corresponding to that filter. 00138 00139 (b) If an exception filter returns a value less than 0 (meaning 00140 that the exception should be dismissed), this routine returns 00141 value ExceptionContinueExecution. 00142 00143 (c) If every filter returns value 0 (meaning that the search for a 00144 handler should continue elsewhere), this function returns 00145 ExceptionContinueSearch. 00146 00147 In context (ii) there are 2 possibilities: 00148 00149 (d) If no branches are detected out of finally handlers, this 00150 function returns ExceptionContinueSearch. 00151 00152 (e) If a branch is detected out of a finally handler, there is no 00153 return from this routine. RtlUnwind is called to unwind to the 00154 branch target (and cancel the current unwind). 00155 00156 There may be long jumps out of both except filters and finally handlers 00157 in which case this routine will be peeled off the stack without returning. 00158 00159 --*/ 00160 00161 { 00162 00163 ULONG_PTR ContinuationAddress; 00164 EXCEPTION_FILTER ExceptionFilter; 00165 PVOID ExceptionHandler; 00166 EXCEPTION_POINTERS ExceptionPointers; 00167 LONG FilterValue; 00168 ULONG_PTR RealFramePointer; 00169 PSEH_BLOCK Seb; 00170 PSEH_CONTEXT SehContext; 00171 PSEH_BLOCK TargetSeb; 00172 TERMINATION_HANDLER TerminationHandler; 00173 00174 // 00175 // Get the address of the SEH context which is at some negative offset 00176 // from the virtual frame pointer. For GEM, the handler data field of 00177 // the function entry contains that offset. The current SEB pointer and 00178 // the RFP (static link) are obtained from the SEH context. 00179 // 00180 00181 SehContext = (PSEH_CONTEXT)((ULONG_PTR)EstablisherFrame + 00182 (LONG_PTR)DispatcherContext->FunctionEntry->HandlerData); 00183 RealFramePointer = SehContext->RealFramePointer; 00184 00185 // 00186 // If this is a dispatching context, walk up the list of SEBs evaluating 00187 // except filters. 00188 // 00189 00190 if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) { 00191 00192 // 00193 // Set up the ExceptionPointers structure that is used by except 00194 // filters to obtain data for the GetExceptionInformation intrinsic 00195 // function. Copy the current SEB pointer into a local variable 00196 // because the real SEB pointer is only modified in unwind contexts. 00197 // 00198 00199 ExceptionPointers.ExceptionRecord = ExceptionRecord; 00200 ExceptionPointers.ContextRecord = ContextRecord; 00201 00202 for (Seb = SehContext->CurrentSeb; Seb != NULL; Seb = Seb->ParentSeb) { 00203 if (IS_EXCEPT(Seb)) { 00204 00205 // 00206 // This is an except filter. Get the addresses of the filter 00207 // and exception handler from the SEB, then call the except 00208 // filter. 00209 // 00210 00211 ExceptionFilter = (EXCEPTION_FILTER)Seb->HandlerAddress; 00212 ExceptionHandler = (PVOID)Seb->JumpTarget; 00213 00214 FilterValue = __C_ExecuteExceptionFilter(&ExceptionPointers, 00215 ExceptionFilter, 00216 RealFramePointer); 00217 00218 // 00219 // If the except filter < 0, dismiss the exception. If > 0, 00220 // store the exception code on the stack for the except 00221 // handler, modify the given ExceptionRecord so that finally 00222 // handlers will be called properly during the unwind, then 00223 // unwind down to the except handler. If = 0, resume the 00224 // search for except filters. 00225 // 00226 00227 if (FilterValue < 0) { 00228 return ExceptionContinueExecution; 00229 00230 } else if (FilterValue > 0) { 00231 SehContext->ExceptionCode = ExceptionRecord->ExceptionCode; 00232 MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, 00233 Seb->ParentSeb); 00234 RtlUnwind2(EstablisherFrame, 00235 ExceptionHandler, 00236 ExceptionRecord, 00237 0, 00238 ContextRecord); 00239 } 00240 } 00241 } 00242 00243 } else if (!IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags)) { 00244 00245 // 00246 // This is an unwind but is not the target frame. Since the function 00247 // is being terminated, finally handlers for all try bodies that are 00248 // presently in scope must be executed. Walk up the SEB list all the 00249 // way to the top executing finally handlers. This corresponds to 00250 // exiting all try bodies that are presently in scope. 00251 // 00252 00253 while (SehContext->CurrentSeb != NULL) { 00254 00255 // 00256 // Get the address of the SEB and then update the SEH context. 00257 // 00258 00259 Seb = SehContext->CurrentSeb; 00260 SehContext->CurrentSeb = Seb->ParentSeb; 00261 00262 if (IS_FINALLY(Seb)) { 00263 00264 // 00265 // This is a finally handler. Get the address of the handler 00266 // from the SEB and call the finally handler. 00267 // 00268 00269 TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress; 00270 ContinuationAddress = 00271 __C_ExecuteTerminationHandler(TRUE, 00272 TerminationHandler, 00273 RealFramePointer); 00274 00275 // 00276 // If the finally handler returns a non-zero result, there 00277 // was a branch out of the handler (to that address) and this 00278 // routine should unwind to that target. 00279 // 00280 00281 if (ContinuationAddress != 0) { 00282 MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, 00283 SehContext->CurrentSeb); 00284 RtlUnwind(EstablisherFrame, 00285 (PVOID)ContinuationAddress, 00286 ExceptionRecord, 00287 0); 00288 } 00289 } 00290 } 00291 00292 } else { 00293 00294 // 00295 // This is the target frame of an unwind. Since the target may be 00296 // in a different try scope than the one defined by the current SEB 00297 // pointer, finally handlers between the two scopes must execute. 00298 // Walk up the SEB list from the current SEB to the target SEB and 00299 // execute all finally handlers encountered. 00300 // 00301 00302 TargetSeb = (PSEH_BLOCK)ExceptionRecord->ExceptionInformation[0]; 00303 ContinuationAddress = _OtsLocalFinallyUnwind(SehContext, 00304 TargetSeb, 00305 (PVOID)RealFramePointer); 00306 if (ContinuationAddress != 0) { 00307 00308 // 00309 // A non-zero result indicates there was a branch out of a 00310 // finally handler that was being executed during the unwind. 00311 // This routine should unwind to that address. 00312 // 00313 00314 MODIFY_UNWIND_EXCEPTION_RECORD(ExceptionRecord, 00315 SehContext->CurrentSeb); 00316 RtlUnwind(EstablisherFrame, 00317 (PVOID)ContinuationAddress, 00318 ExceptionRecord, 00319 0); 00320 } 00321 } 00322 00323 // 00324 // Continue search for exception or termination handlers. 00325 // 00326 00327 return ExceptionContinueSearch; 00328 } 00329 00330 ULONG_PTR 00331 _OtsLocalFinallyUnwind ( 00332 IN PSEH_CONTEXT SehContext, 00333 IN PSEH_BLOCK TargetSeb, 00334 IN PVOID RealFramePointer 00335 ) 00336 00337 /*++ 00338 00339 Routine Description: 00340 00341 This function walks up the SEB tree of the current procedure from the 00342 current SEB to the target SEB and executes all the finally handlers it 00343 encounters. 00344 00345 Calls to this function are inserted into user code by the compiler when 00346 there are branches out of guarded regions that may require finally 00347 handlers to execute. 00348 00349 This function is also called from _OtsCSpecificHandler when the target 00350 frame is reached during an unwind operation. There may be finally handlers 00351 that should execute before resuming execution at the unwind target. 00352 00353 Arguments: 00354 00355 SehContext - Supplies the address of the SEH context structure which is 00356 located in the stack frame. 00357 00358 TargetSeb - Supplies the address of the SEB corresponding to the branch 00359 target address. 00360 00361 RealFramePointer - Supplies the (real frame) pointer of the establisher 00362 frame, which is the current stack frame. This is used to set up the 00363 static link if a finally handler is invoked. 00364 00365 Return Value: 00366 00367 If a branch out of a finally handler is detected, the function value is 00368 the address of the branch target. Otherwise, the function value is zero. 00369 00370 --*/ 00371 00372 { 00373 00374 ULONG_PTR ContinuationAddress; 00375 BOOLEAN Nested; 00376 PSEH_BLOCK Seb; 00377 TERMINATION_HANDLER TerminationHandler; 00378 00379 // 00380 // If the SEB pointers are the same, no finally handlers need to execute. 00381 // The branch is to a target location in the same guarded scope. 00382 // 00383 00384 if (SehContext->CurrentSeb == TargetSeb) { 00385 return 0; 00386 } 00387 00388 // 00389 // If the current SEB scope is not nested within the target SEB scope, no 00390 // finally handlers need to execute. Reset the current SEB pointer to the 00391 // target SEB pointer and return. 00392 // 00393 00394 Nested = FALSE; 00395 Seb = SehContext->CurrentSeb; 00396 00397 while (Seb != NULL) { 00398 Seb = Seb->ParentSeb; 00399 if (Seb == TargetSeb) { 00400 Nested = TRUE; 00401 break; 00402 } 00403 } 00404 if (Nested == FALSE) { 00405 SehContext->CurrentSeb = TargetSeb; 00406 return 0; 00407 } 00408 00409 // 00410 // Walk up the list of SEB blocks executing finally handlers. If a branch 00411 // out of a finally is encountered along the way, return the target 00412 // address, otherwise return 0. 00413 // 00414 00415 while (SehContext->CurrentSeb != TargetSeb) { 00416 00417 // 00418 // Get the address of the SEB and then update the SEH context. 00419 // 00420 00421 Seb = SehContext->CurrentSeb; 00422 SehContext->CurrentSeb = Seb->ParentSeb; 00423 00424 if (IS_FINALLY(Seb)) { 00425 TerminationHandler = (TERMINATION_HANDLER)Seb->HandlerAddress; 00426 ContinuationAddress = 00427 __C_ExecuteTerminationHandler(TRUE, 00428 TerminationHandler, 00429 (ULONG_PTR)RealFramePointer); 00430 if (ContinuationAddress != 0) { 00431 return ContinuationAddress; 00432 } 00433 } 00434 } 00435 return 0; 00436 }

Generated on Sat May 15 19:40:13 2004 for test by doxygen 1.3.7