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

exdsptch.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1990 Microsoft Corporation 00004 Copyright (c) 1993 Digital Equipment Corporation 00005 00006 Module Name: 00007 00008 exdsptch.c 00009 00010 Abstract: 00011 00012 This module implements the dispatching of exceptions and the unwinding of 00013 procedure call frames. 00014 00015 Author: 00016 00017 David N. Cutler (davec) 11-Sep-1990 00018 00019 Environment: 00020 00021 Any mode. 00022 00023 Revision History: 00024 00025 Thomas Van Baak (tvb) 13-May-1992 00026 00027 Adapted for Alpha AXP. 00028 00029 Florence Lee (Digital) 10-Apr-1997 00030 00031 Add support for dynamic function tables (user mode only) 00032 1) Modify RtlLookupFunctionEntry to search dynamic function tables 00033 2) Add RtlAddFunctionTable: Add an array of RUNTIME_FUNCTION entries 00034 to the dynamic function table list. 00035 3) Add RtlDeleteFunctionTable: Remove dynamic from table the 00036 dynamic function table list. 00037 00038 Monty VanderBilt (Digital) 16-Jun-1997 00039 00040 1) Use macros defined in ntalpha.h to access RUNTIME_FUNCTION 00041 fields without low order bits used for other information 00042 2) Modify RtlLookupFunctionEntry() and RtlVirtualUnwind() to 00043 handle the variations of secondary function entry types. 00044 00045 Monty VanderBilt (Compaq) 10-Aug-1999 00046 00047 ECO (Engineering Change Order) numbers refer to Alpha NT calling standard changes 00048 ECO 11: Support for compiler optimizations: tail calls, floating return sequences, shrinkwrap. 00049 ECO 12: Minor change to ECO 11 moving StackAllocation field from the 3rd to 4th longword 00050 in the secondary function entry. 00051 ECO 14: Fixed return function entries to support (among other uses) exception handling in 00052 instrumentation code. 00053 00054 --*/ 00055 00056 #include "ntrtlp.h" 00057 int __cdecl sprintf(char *, const char *, ...); 00058 00059 // 00060 // Define local macros. 00061 // 00062 // Raise noncontinuable exception with associated exception record. 00063 // 00064 00065 #define RAISE_EXCEPTION(Status, ExceptionRecordt) { \ 00066 EXCEPTION_RECORD ExceptionRecordn; \ 00067 \ 00068 ExceptionRecordn.ExceptionCode = Status; \ 00069 ExceptionRecordn.ExceptionFlags = EXCEPTION_NONCONTINUABLE; \ 00070 ExceptionRecordn.ExceptionRecord = ExceptionRecordt; \ 00071 ExceptionRecordn.NumberParameters = 0; \ 00072 RtlRaiseException(&ExceptionRecordn); \ 00073 } 00074 00075 // 00076 // Determine if ExceptionHandler is defined 00077 // 00078 00079 #define IS_HANDLER_DEFINED(FunctionEntry) \ 00080 (RF_EXCEPTION_HANDLER(FunctionEntry) != 0) 00081 00082 #if DBG 00083 00084 // 00085 // Maintain a short history of PC's for malformed function table errors. 00086 // 00087 00088 #define PC_HISTORY_DEPTH 4 00089 00090 // 00091 // Definition of global flag to debug/validate exception handling. 00092 // See ntrtlalp.h for the bit definitions in this flag word. 00093 // 00094 00095 ULONG RtlDebugFlags = 0; 00096 00097 void 00098 ShowRuntimeFunction( 00099 PRUNTIME_FUNCTION FunctionEntry, 00100 PSTR Label 00101 ); 00102 00103 #endif 00104 00105 #define Virtual VirtualFramePointer 00106 #define Real RealFramePointer 00107 00108 // 00109 // Define private function prototypes. 00110 // 00111 00112 VOID 00113 RtlpRaiseException ( 00114 IN PEXCEPTION_RECORD ExceptionRecord 00115 ); 00116 00117 VOID 00118 RtlpRaiseStatus ( 00119 IN NTSTATUS Status 00120 ); 00121 00122 ULONG_PTR 00123 RtlpVirtualUnwind ( 00124 IN ULONG_PTR ControlPc, 00125 IN PRUNTIME_FUNCTION FunctionEntry, 00126 IN PCONTEXT ContextRecord, 00127 OUT PBOOLEAN InFunction, 00128 OUT PFRAME_POINTERS EstablisherFrame 00129 ); 00130 00131 #if !defined(NTOS_KERNEL_RUNTIME) 00132 00133 // 00134 // List head for DYNAMIC_FUNCTION_TABLE entries. 00135 // 00136 00137 LIST_ENTRY DynamicFunctionTable; 00138 00139 PRUNTIME_FUNCTION 00140 RtlLookupDynamicFunctionEntry( 00141 IN ULONG_PTR ControlPc 00142 ); 00143 00144 #endif 00145 00146 PRUNTIME_FUNCTION 00147 RtlLookupStaticFunctionEntry( 00148 IN ULONG_PTR ControlPc, 00149 OUT PBOOLEAN InImage 00150 ); 00151 00152 VOID 00153 RtlGetUnwindFunctionEntry( 00154 IN ULONG_PTR ControlPc, 00155 IN PRUNTIME_FUNCTION FunctionEntry, 00156 OUT PRUNTIME_FUNCTION UnwindFunctionEntry, 00157 OUT PULONG StackAdjust, 00158 OUT PULONG_PTR FixedReturn 00159 ); 00160 00161 BOOLEAN 00162 RtlDispatchException ( 00163 IN PEXCEPTION_RECORD ExceptionRecord, 00164 IN PCONTEXT ContextRecord 00165 ) 00166 00167 /*++ 00168 00169 Routine Description: 00170 00171 This function attempts to dispatch an exception to a frame based 00172 handler by searching backwards through the stack based call frames. 00173 The search begins with the frame specified in the context record and 00174 continues backward until either a handler is found that handles the 00175 exception, the stack is found to be invalid (i.e., out of limits or 00176 unaligned), or the end of the call hierarchy is reached. 00177 00178 As each frame is encountered, the PC where control left the corresponding 00179 function is determined and used to lookup exception handler information 00180 in the runtime function table built by the linker. If the respective 00181 routine has an exception handler, then the handler is called. If the 00182 handler does not handle the exception, then the prologue of the routine 00183 is executed backwards to "unwind" the effect of the prologue and then 00184 the next frame is examined. 00185 00186 Arguments: 00187 00188 ExceptionRecord - Supplies a pointer to an exception record. 00189 00190 ContextRecord - Supplies a pointer to a context record. 00191 00192 Return Value: 00193 00194 If the exception is handled by one of the frame based handlers, then 00195 a value of TRUE is returned. Otherwise a value of FALSE is returned. 00196 00197 --*/ 00198 00199 { 00200 00201 CONTEXT ContextRecord1; 00202 ULONG_PTR ControlPc; 00203 #if DBG 00204 ULONG_PTR ControlPcHistory[PC_HISTORY_DEPTH]; 00205 ULONG ControlPcHistoryIndex = 0; 00206 #endif 00207 DISPATCHER_CONTEXT DispatcherContext; 00208 EXCEPTION_DISPOSITION Disposition; 00209 FRAME_POINTERS EstablisherFrame; 00210 ULONG ExceptionFlags; 00211 #if DBG 00212 LONG FrameDepth = 0; 00213 #endif 00214 PRUNTIME_FUNCTION FunctionEntry; 00215 ULONG_PTR HighLimit; 00216 BOOLEAN InFunction; 00217 ULONG_PTR LowLimit; 00218 ULONG_PTR NestedFrame; 00219 ULONG_PTR NextPc; 00220 00221 // 00222 // Get current stack limits, copy the context record, get the initial 00223 // PC value, capture the exception flags, and set the nested exception 00224 // frame pointer. 00225 // 00226 // The initial PC value is obtained from ExceptionAddress rather than 00227 // from ContextRecord.Fir since some Alpha exceptions are asynchronous. 00228 // 00229 00230 RtlpGetStackLimits(&LowLimit, &HighLimit); 00231 RtlMoveMemory(&ContextRecord1, ContextRecord, sizeof(CONTEXT)); 00232 ControlPc = (ULONG_PTR)ExceptionRecord->ExceptionAddress; 00233 00234 #if DBG 00235 if ((ULONG_PTR)ExceptionRecord->ExceptionAddress != (ULONG_PTR)ContextRecord->Fir) { 00236 DbgPrint("RtlDispatchException: ExceptionAddress = %p, Fir = %p\n", 00237 ExceptionRecord->ExceptionAddress, (ULONG_PTR)ContextRecord->Fir); 00238 } 00239 #endif 00240 00241 ExceptionFlags = ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE; 00242 NestedFrame = 0; 00243 00244 #if DBG 00245 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION) { 00246 DbgPrint("\nRtlDispatchException(ExceptionRecord = %p, ContextRecord = %p)\n", 00247 ExceptionRecord, ContextRecord); 00248 DbgPrint("RtlDispatchException: ControlPc = %p, ExceptionRecord->ExceptionCode = %lx\n", 00249 ControlPc, ExceptionRecord->ExceptionCode); 00250 } 00251 #endif 00252 00253 // 00254 // Start with the frame specified by the context record and search 00255 // backwards through the call frame hierarchy attempting to find an 00256 // exception handler that will handle the exception. 00257 // 00258 00259 do { 00260 #if DBG 00261 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { 00262 DbgPrint("RtlDispatchException: Loop: FrameDepth = %d, sp = %p, ControlPc = %p\n", 00263 FrameDepth, (ULONG_PTR)ContextRecord1.IntSp, ControlPc); 00264 FrameDepth -= 1; 00265 } 00266 #endif 00267 00268 // 00269 // Lookup the function table entry using the point at which control 00270 // left the procedure. 00271 // 00272 00273 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00274 00275 // 00276 // If there is a function table entry for the routine, then virtually 00277 // unwind to the caller of the current routine to obtain the virtual 00278 // frame pointer of the establisher and check if there is an exception 00279 // handler for the frame. 00280 // 00281 00282 if (FunctionEntry != NULL) { 00283 NextPc = RtlVirtualUnwind(ControlPc, 00284 FunctionEntry, 00285 &ContextRecord1, 00286 &InFunction, 00287 &EstablisherFrame, 00288 NULL); 00289 00290 // 00291 // If the virtual frame pointer is not within the specified stack 00292 // limits or the virtual frame pointer is unaligned, then set the 00293 // stack invalid flag in the exception record and return exception 00294 // not handled. Otherwise, check if the current routine has an 00295 // exception handler. 00296 // 00297 00298 if ((EstablisherFrame.Virtual < LowLimit) || 00299 (EstablisherFrame.Virtual > HighLimit) || 00300 ((EstablisherFrame.Virtual & 0xF) != 0)) { 00301 00302 #if DBG 00303 DbgPrint("\n****** Warning - stack invalid (exception).\n"); 00304 DbgPrint(" EstablisherFrame.Virtual = %p, EstablisherFrame.Real = %p\n", 00305 EstablisherFrame.Virtual, EstablisherFrame.Real); 00306 DbgPrint(" LowLimit = %p, HighLimit = %p\n", 00307 LowLimit, HighLimit); 00308 DbgPrint(" NextPc = %p, ControlPc = %p\n", 00309 NextPc, ControlPc); 00310 DbgPrint(" Now setting EXCEPTION_STACK_INVALID flag.\n"); 00311 #endif 00312 00313 ExceptionFlags |= EXCEPTION_STACK_INVALID; 00314 break; 00315 00316 } else if (IS_HANDLER_DEFINED(FunctionEntry) && InFunction) { 00317 00318 ULONG Index; 00319 00320 #if DBG 00321 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { 00322 DbgPrint("RtlDispatchException: ExceptionHandler = %p, HandlerData = %p\n", 00323 FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData); 00324 } 00325 #endif 00326 00327 // 00328 // The frame has an exception handler. The handler must be 00329 // executed by calling another routine that is written in 00330 // assembler. This is required because up level addressing 00331 // of the handler information is required when a nested 00332 // exception is encountered. 00333 // 00334 00335 DispatcherContext.ControlPc = ControlPc; 00336 DispatcherContext.FunctionEntry = FunctionEntry; 00337 DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual; 00338 DispatcherContext.ContextRecord = ContextRecord; 00339 ExceptionRecord->ExceptionFlags = ExceptionFlags; 00340 00341 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) { 00342 Index = RtlpLogExceptionHandler( 00343 ExceptionRecord, 00344 ContextRecord, 00345 ControlPc, 00346 FunctionEntry, 00347 sizeof(RUNTIME_FUNCTION)); 00348 } 00349 00350 #if DBG 00351 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { 00352 DbgPrint("RtlDispatchException: calling RtlpExecuteHandlerForException, ControlPc = %lx Handler = %lx\n", 00353 ControlPc, RF_EXCEPTION_HANDLER(FunctionEntry) ); 00354 } 00355 #endif 00356 Disposition = 00357 RtlpExecuteHandlerForException(ExceptionRecord, 00358 EstablisherFrame.Virtual, 00359 ContextRecord, 00360 &DispatcherContext, 00361 RF_EXCEPTION_HANDLER(FunctionEntry)); 00362 #if DBG 00363 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { 00364 DbgPrint("RtlDispatchException: RtlpExecuteHandlerForException returned Disposition = %lx\n", Disposition); 00365 } 00366 #endif 00367 00368 if (NtGlobalFlag & FLG_ENABLE_EXCEPTION_LOGGING) { 00369 RtlpLogLastExceptionDisposition(Index, Disposition); 00370 } 00371 00372 ExceptionFlags |= 00373 (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE); 00374 00375 // 00376 // If the current scan is within a nested context and the frame 00377 // just examined is the end of the nested region, then clear 00378 // the nested context frame and the nested exception flag in 00379 // the exception flags. 00380 // 00381 00382 if (NestedFrame == EstablisherFrame.Virtual) { 00383 ExceptionFlags &= (~EXCEPTION_NESTED_CALL); 00384 NestedFrame = 0; 00385 } 00386 00387 // 00388 // Case on the handler disposition. 00389 // 00390 00391 switch (Disposition) { 00392 00393 // 00394 // The disposition is to continue execution. 00395 // 00396 // If the exception is not continuable, then raise the 00397 // exception STATUS_NONCONTINUABLE_EXCEPTION. Otherwise 00398 // return exception handled. 00399 // 00400 00401 case ExceptionContinueExecution : 00402 if ((ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) { 00403 RAISE_EXCEPTION(STATUS_NONCONTINUABLE_EXCEPTION, ExceptionRecord); 00404 00405 } else { 00406 #if DBG 00407 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION) { 00408 DbgPrint("RtlDispatchException: returning TRUE\n"); 00409 } 00410 #endif 00411 return TRUE; 00412 } 00413 00414 // 00415 // The disposition is to continue the search. 00416 // 00417 // Get next frame address and continue the search. 00418 // 00419 00420 case ExceptionContinueSearch : 00421 break; 00422 00423 // 00424 // The disposition is nested exception. 00425 // 00426 // Set the nested context frame to the establisher frame 00427 // address and set the nested exception flag in the 00428 // exception flags. 00429 // 00430 00431 case ExceptionNestedException : 00432 ExceptionFlags |= EXCEPTION_NESTED_CALL; 00433 if (DispatcherContext.EstablisherFrame > NestedFrame) { 00434 NestedFrame = DispatcherContext.EstablisherFrame; 00435 } 00436 00437 break; 00438 00439 // 00440 // All other disposition values are invalid. 00441 // 00442 // Raise invalid disposition exception. 00443 // 00444 00445 default : 00446 RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord); 00447 } 00448 } 00449 00450 } else { 00451 00452 // 00453 // Set point at which control left the previous routine. 00454 // 00455 00456 NextPc = (ULONG_PTR)ContextRecord1.IntRa - 4; 00457 00458 // 00459 // If the next control PC is the same as the old control PC, then 00460 // the function table is not correctly formed. 00461 // 00462 00463 if (NextPc == ControlPc) { 00464 #if DBG 00465 ULONG Count; 00466 DbgPrint("\n****** Warning - malformed function table (exception).\n"); 00467 DbgPrint("ControlPc = %p, NextPc %p", NextPc, ControlPc); 00468 for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) { 00469 if (ControlPcHistoryIndex > 0) { 00470 ControlPcHistoryIndex -= 1; 00471 ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH]; 00472 DbgPrint(", %p", ControlPc); 00473 } 00474 } 00475 DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n"); 00476 #endif 00477 break; 00478 } 00479 } 00480 00481 // 00482 // Set point at which control left the previous routine. 00483 // 00484 00485 #if DBG 00486 ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc; 00487 ControlPcHistoryIndex += 1; 00488 #endif 00489 ControlPc = NextPc; 00490 00491 } while ((ULONG_PTR)ContextRecord1.IntSp < HighLimit); 00492 00493 // 00494 // Set final exception flags and return exception not handled. 00495 // 00496 00497 ExceptionRecord->ExceptionFlags = ExceptionFlags; 00498 #if DBG 00499 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION) { 00500 DbgPrint("RtlDispatchException: returning FALSE\n"); 00501 } 00502 #endif 00503 return FALSE; 00504 } 00505 00506 PRUNTIME_FUNCTION 00507 RtlLookupFunctionEntry ( 00508 IN ULONG_PTR ControlPc 00509 ) 00510 00511 /*++ 00512 00513 Routine Description: 00514 00515 This function searches the currently active function tables (static and dynamic) 00516 for an entry that corresponds to the specified PC value. If the entry is for a 00517 secondary function entry then the primary function table entry is obtained 00518 via an indirection through the PrologEndAddress. RtlLookupDirectFunctionEntry() 00519 performs the same function without the indirection to the primary function table. 00520 Because RtlLookupFunctionEntry() always returns the primary function entry, it 00521 has the property such that 00522 00523 RtlLookupFunctionEntry(Pc1) == RtlLookupFunctionEntry(Pc2) 00524 00525 implies 00526 00527 Pc1 and Pc2 are in the same procedure. 00528 00529 Arguments: 00530 00531 ControlPc - Supplies the address of an instruction within the specified 00532 function. 00533 00534 Return Value: 00535 00536 If there is no entry in the function table for the specified PC, then 00537 NULL is returned. Otherwise, the address of the primary function table 00538 entry that corresponds to the specified PC is returned. 00539 00540 --*/ 00541 00542 { 00543 PRUNTIME_FUNCTION FunctionEntry; 00544 00545 // Look for a static or dynamic function entry 00546 00547 FunctionEntry = RtlLookupDirectFunctionEntry( ControlPc ); 00548 00549 if (FunctionEntry != NULL) { 00550 00551 // 00552 // The capability exists for more than one function entry 00553 // to map to the same function. This permits a function to 00554 // have discontiguous code segments described by separate 00555 // function table entries. If the ending prologue address 00556 // is not within the limits of the begining and ending 00557 // address of the function able entry, then the prologue 00558 // ending address is the address of the primary function 00559 // table entry that accurately describes the ending prologue 00560 // address. 00561 // 00562 00563 if ((RF_PROLOG_END_ADDRESS(FunctionEntry) < RF_BEGIN_ADDRESS(FunctionEntry)) || 00564 (RF_PROLOG_END_ADDRESS(FunctionEntry) >= RF_END_ADDRESS(FunctionEntry))) { 00565 #if DBG 00566 ShowRuntimeFunction(FunctionEntry, "RtlLookupFunctionEntry: secondary entry" ); 00567 #endif 00568 // Officially the PrologEndAddress field in secondary function entries 00569 // doesn't have the exception mode bits there have been some versions 00570 // of alpha tools that put them there. Strip them off to be safe. 00571 00572 FunctionEntry = (PRUNTIME_FUNCTION)RF_PROLOG_END_ADDRESS(FunctionEntry); 00573 } else if (RF_IS_FIXED_RETURN(FunctionEntry)) { 00574 ULONG_PTR FixedReturn = RF_FIXED_RETURN(FunctionEntry); 00575 00576 #if DBG 00577 ShowRuntimeFunction(FunctionEntry, "LookupFunctionEntry: fixed return entry"); 00578 #endif 00579 // Recursively call LookupFunctionEntry to ensure we get a primary function entry here. 00580 // Check for incorrectly formed function entry where the fixed return points to itself. 00581 00582 if ((FixedReturn < RF_BEGIN_ADDRESS(FunctionEntry)) || 00583 (FixedReturn >= RF_END_ADDRESS(FunctionEntry))) { 00584 FunctionEntry = RtlLookupFunctionEntry( RF_FIXED_RETURN(FunctionEntry) ); 00585 } 00586 } 00587 #if DBG 00588 else { 00589 ShowRuntimeFunction(FunctionEntry, "RtlLookupFunctionEntry: primary entry" ); 00590 } 00591 #endif 00592 } 00593 00594 #if DBG 00595 if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) { 00596 DbgPrint("RtlLookupFunctionEntry: returning FunctionEntry = %lx\n", FunctionEntry); 00597 } 00598 #endif 00599 return FunctionEntry; 00600 } 00601 00602 VOID 00603 RtlRaiseException ( 00604 IN PEXCEPTION_RECORD ExceptionRecord 00605 ) 00606 00607 /*++ 00608 00609 Routine Description: 00610 00611 This function raises a software exception by building a context record 00612 and calling the raise exception system service. 00613 00614 N.B. This routine is a shell routine that simply calls another routine 00615 to do the real work. The reason this is done is to avoid a problem 00616 in try/finally scopes where the last statement in the scope is a 00617 call to raise an exception. 00618 00619 Arguments: 00620 00621 ExceptionRecord - Supplies a pointer to an exception record. 00622 00623 Return Value: 00624 00625 None. 00626 00627 --*/ 00628 00629 { 00630 00631 #if DBG 00632 if (RtlDebugFlags & RTL_DBG_RAISE_EXCEPTION) { 00633 DbgPrint("RtlRaiseException(ExceptionRecord = %p) Status = %lx\n", 00634 ExceptionRecord, ExceptionRecord->ExceptionCode); 00635 } 00636 #endif 00637 00638 RtlpRaiseException(ExceptionRecord); 00639 return; 00640 } 00641 00642 VOID 00643 RtlpRaiseException ( 00644 IN PEXCEPTION_RECORD ExceptionRecord 00645 ) 00646 00647 /*++ 00648 00649 Routine Description: 00650 00651 This function raises a software exception by building a context record 00652 and calling the raise exception system service. 00653 00654 Arguments: 00655 00656 ExceptionRecord - Supplies a pointer to an exception record. 00657 00658 Return Value: 00659 00660 None. 00661 00662 --*/ 00663 00664 { 00665 00666 ULONG_PTR ControlPc; 00667 CONTEXT ContextRecord; 00668 FRAME_POINTERS EstablisherFrame; 00669 PRUNTIME_FUNCTION FunctionEntry; 00670 BOOLEAN InFunction; 00671 ULONG_PTR NextPc; 00672 NTSTATUS Status; 00673 00674 // 00675 // Capture the current context, virtually unwind to the caller of this 00676 // routine, set the fault instruction address to that of the caller, and 00677 // call the raise exception system service. 00678 // 00679 00680 RtlCaptureContext(&ContextRecord); 00681 ControlPc = (ULONG_PTR)ContextRecord.IntRa - 4; 00682 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00683 NextPc = RtlVirtualUnwind(ControlPc, 00684 FunctionEntry, 00685 &ContextRecord, 00686 &InFunction, 00687 &EstablisherFrame, 00688 NULL); 00689 00690 ContextRecord.Fir = (ULONGLONG)(LONG_PTR)NextPc + 4; 00691 ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Fir; 00692 Status = ZwRaiseException(ExceptionRecord, &ContextRecord, TRUE); 00693 00694 // 00695 // There should never be a return from this system service unless 00696 // there is a problem with the argument list itself. Raise another 00697 // exception specifying the status value returned. 00698 // 00699 00700 RtlRaiseStatus(Status); 00701 return; 00702 } 00703 00704 VOID 00705 RtlRaiseStatus ( 00706 IN NTSTATUS Status 00707 ) 00708 00709 /*++ 00710 00711 Routine Description: 00712 00713 This function raises an exception with the specified status value. The 00714 exception is marked as noncontinuable with no parameters. 00715 00716 N.B. This routine is a shell routine that simply calls another routine 00717 to do the real work. The reason this is done is to avoid a problem 00718 in try/finally scopes where the last statement in the scope is a 00719 call to raise an exception. 00720 00721 Arguments: 00722 00723 Status - Supplies the status value to be used as the exception code 00724 for the exception that is to be raised. 00725 00726 Return Value: 00727 00728 None. 00729 00730 --*/ 00731 00732 { 00733 00734 #if DBG 00735 if (RtlDebugFlags & RTL_DBG_RAISE_EXCEPTION) { 00736 DbgPrint("RtlRaiseStatus(Status = %lx)\n", Status); 00737 } 00738 #endif 00739 00740 RtlpRaiseStatus(Status); 00741 return; 00742 } 00743 00744 VOID 00745 RtlpRaiseStatus ( 00746 IN NTSTATUS Status 00747 ) 00748 00749 /*++ 00750 00751 Routine Description: 00752 00753 This function raises an exception with the specified status value. The 00754 exception is marked as noncontinuable with no parameters. 00755 00756 Arguments: 00757 00758 Status - Supplies the status value to be used as the exception code 00759 for the exception that is to be raised. 00760 00761 Return Value: 00762 00763 None. 00764 00765 --*/ 00766 00767 { 00768 00769 ULONG_PTR ControlPc; 00770 CONTEXT ContextRecord; 00771 FRAME_POINTERS EstablisherFrame; 00772 EXCEPTION_RECORD ExceptionRecord; 00773 PRUNTIME_FUNCTION FunctionEntry; 00774 BOOLEAN InFunction; 00775 ULONG_PTR NextPc; 00776 00777 // 00778 // Construct an exception record. 00779 // 00780 00781 ExceptionRecord.ExceptionCode = Status; 00782 ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL; 00783 ExceptionRecord.NumberParameters = 0; 00784 ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; 00785 00786 // 00787 // Capture the current context, virtually unwind to the caller of this 00788 // routine, set the fault instruction address to that of the caller, and 00789 // call the raise exception system service. 00790 // 00791 00792 RtlCaptureContext(&ContextRecord); 00793 ControlPc = (ULONG_PTR)ContextRecord.IntRa - 4; 00794 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00795 NextPc = RtlVirtualUnwind(ControlPc, 00796 FunctionEntry, 00797 &ContextRecord, 00798 &InFunction, 00799 &EstablisherFrame, 00800 NULL); 00801 00802 ContextRecord.Fir = (ULONGLONG)(LONG_PTR)NextPc + 4; 00803 ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Fir; 00804 Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, TRUE); 00805 00806 // 00807 // There should never be a return from this system service unless 00808 // there is a problem with the argument list itself. Raise another 00809 // exception specifying the status value returned. 00810 // 00811 00812 RtlRaiseStatus(Status); 00813 return; 00814 } 00815 00816 VOID 00817 RtlUnwind ( 00818 IN PVOID TargetFrame OPTIONAL, 00819 IN PVOID TargetIp OPTIONAL, 00820 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, 00821 IN PVOID ReturnValue 00822 ) 00823 00824 /*++ 00825 00826 Routine Description: 00827 00828 This function initiates an unwind of procedure call frames. The machine 00829 state at the time of the call to unwind is captured in a context record 00830 and the unwinding flag is set in the exception flags of the exception 00831 record. If the TargetFrame parameter is not specified, then the exit unwind 00832 flag is also set in the exception flags of the exception record. A backward 00833 scan through the procedure call frames is then performed to find the target 00834 of the unwind operation. 00835 00836 As each frame is encounter, the PC where control left the corresponding 00837 function is determined and used to lookup exception handler information 00838 in the runtime function table built by the linker. If the respective 00839 routine has an exception handler, then the handler is called. 00840 00841 N.B. This routine is provided for backward compatibility with release 1. 00842 00843 Arguments: 00844 00845 TargetFrame - Supplies an optional pointer to the call frame that is the 00846 target of the unwind. If this parameter is not specified, then an exit 00847 unwind is performed. 00848 00849 TargetIp - Supplies an optional instruction address that specifies the 00850 continuation address of the unwind. This address is ignored if the 00851 target frame parameter is not specified. 00852 00853 ExceptionRecord - Supplies an optional pointer to an exception record. 00854 00855 ReturnValue - Supplies a value that is to be placed in the integer 00856 function return register just before continuing execution. 00857 00858 Return Value: 00859 00860 None. 00861 00862 --*/ 00863 00864 { 00865 CONTEXT ContextRecord; 00866 00867 00868 // 00869 // Call real unwind routine specifying a context record as an 00870 // extra argument. 00871 // 00872 00873 RtlUnwind2(TargetFrame, 00874 TargetIp, 00875 ExceptionRecord, 00876 ReturnValue, 00877 &ContextRecord); 00878 00879 return; 00880 } 00881 00882 VOID 00883 RtlUnwind2 ( 00884 IN PVOID TargetFrame OPTIONAL, 00885 IN PVOID TargetIp OPTIONAL, 00886 IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, 00887 IN PVOID ReturnValue, 00888 IN PCONTEXT ContextRecord 00889 ) 00890 00891 /*++ 00892 00893 Routine Description: 00894 00895 This function initiates an unwind of procedure call frames. The machine 00896 state at the time of the call to unwind is captured in a context record 00897 and the unwinding flag is set in the exception flags of the exception 00898 record. If the TargetFrame parameter is not specified, then the exit unwind 00899 flag is also set in the exception flags of the exception record. A backward 00900 scan through the procedure call frames is then performed to find the target 00901 of the unwind operation. 00902 00903 As each frame is encounter, the PC where control left the corresponding 00904 function is determined and used to lookup exception handler information 00905 in the runtime function table built by the linker. If the respective 00906 routine has an exception handler, then the handler is called. 00907 00908 N.B. This routine is provided for backward compatibility with release 1. 00909 00910 Arguments: 00911 00912 TargetFrame - Supplies an optional pointer to the call frame that is the 00913 target of the unwind. If this parameter is not specified, then an exit 00914 unwind is performed. 00915 00916 TargetIp - Supplies an optional instruction address that specifies the 00917 continuation address of the unwind. This address is ignored if the 00918 target frame parameter is not specified. 00919 00920 ExceptionRecord - Supplies an optional pointer to an exception record. 00921 00922 ReturnValue - Supplies a value that is to be placed in the integer 00923 function return register just before continuing execution. 00924 00925 Return Value: 00926 00927 None. 00928 00929 --*/ 00930 00931 { 00932 ULONG_PTR ControlPc; 00933 #if DBG 00934 ULONG_PTR ControlPcHistory[PC_HISTORY_DEPTH]; 00935 ULONG ControlPcHistoryIndex = 0; 00936 #endif 00937 DISPATCHER_CONTEXT DispatcherContext; 00938 EXCEPTION_DISPOSITION Disposition; 00939 FRAME_POINTERS EstablisherFrame; 00940 ULONG ExceptionFlags; 00941 EXCEPTION_RECORD ExceptionRecord1; 00942 #if DBG 00943 LONG FrameDepth = 0; 00944 #endif 00945 PRUNTIME_FUNCTION FunctionEntry; 00946 ULONG_PTR HighLimit; 00947 BOOLEAN InFunction; 00948 ULONG_PTR LowLimit; 00949 ULONG_PTR NextPc; 00950 00951 #if DBG 00952 if (RtlDebugFlags & RTL_DBG_UNWIND) { 00953 DbgPrint("\nRtlUnwind(TargetFrame = %p, TargetIp = %p,, ReturnValue = %lx)\n", 00954 TargetFrame, TargetIp, ReturnValue); 00955 } 00956 #endif 00957 00958 // 00959 // Get current stack limits, capture the current context, virtually 00960 // unwind to the caller of this routine, get the initial PC value, and 00961 // set the unwind target address. 00962 // 00963 00964 RtlpGetStackLimits(&LowLimit, &HighLimit); 00965 RtlCaptureContext(ContextRecord); 00966 ControlPc = (ULONG_PTR)ContextRecord->IntRa - 4; 00967 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00968 NextPc = RtlVirtualUnwind(ControlPc, 00969 FunctionEntry, 00970 ContextRecord, 00971 &InFunction, 00972 &EstablisherFrame, 00973 NULL); 00974 00975 ControlPc = NextPc; 00976 ContextRecord->Fir = (ULONGLONG)(LONG_PTR)TargetIp; 00977 00978 // 00979 // If an exception record is not specified, then build a local exception 00980 // record for use in calling exception handlers during the unwind operation. 00981 // 00982 00983 if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) { 00984 ExceptionRecord = &ExceptionRecord1; 00985 ExceptionRecord1.ExceptionCode = STATUS_UNWIND; 00986 ExceptionRecord1.ExceptionRecord = NULL; 00987 ExceptionRecord1.ExceptionAddress = (PVOID)ControlPc; 00988 ExceptionRecord1.NumberParameters = 0; 00989 } 00990 00991 // 00992 // If the target frame of the unwind is specified, then a normal unwind 00993 // is being performed. Otherwise, an exit unwind is being performed. 00994 // 00995 00996 ExceptionFlags = EXCEPTION_UNWINDING; 00997 if (ARGUMENT_PRESENT(TargetFrame) == FALSE) { 00998 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND; 00999 } 01000 01001 // 01002 // Scan backward through the call frame hierarchy and call exception 01003 // handlers until the target frame of the unwind is reached. 01004 // 01005 01006 do { 01007 01008 #if DBG 01009 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 01010 DbgPrint("RtlUnwind: Loop: FrameDepth = %d, sp = %p, ControlPc = %p\n", 01011 FrameDepth, (ULONG_PTR)ContextRecord->IntSp, ControlPc); 01012 FrameDepth -= 1; 01013 } 01014 #endif 01015 01016 // 01017 // Lookup the function table entry using the point at which control 01018 // left the procedure. 01019 // 01020 01021 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 01022 01023 // 01024 // If there is a function table entry for the routine, then virtually 01025 // unwind to the caller of the routine to obtain the virtual frame 01026 // pointer of the establisher, but don't update the context record. 01027 // 01028 01029 if (FunctionEntry != NULL) { 01030 NextPc = RtlpVirtualUnwind(ControlPc, 01031 FunctionEntry, 01032 ContextRecord, 01033 &InFunction, 01034 &EstablisherFrame); 01035 01036 // 01037 // If the virtual frame pointer is not within the specified stack 01038 // limits, the virtual frame pointer is unaligned, or the target 01039 // frame is below the virtual frame and an exit unwind is not being 01040 // performed, then raise the exception STATUS_BAD_STACK. Otherwise, 01041 // check to determine if the current routine has an exception 01042 // handler. 01043 // 01044 01045 if ((EstablisherFrame.Virtual < LowLimit) || 01046 (EstablisherFrame.Virtual > HighLimit) || 01047 ((ARGUMENT_PRESENT(TargetFrame) != FALSE) && 01048 ((ULONG_PTR)TargetFrame < EstablisherFrame.Virtual)) || 01049 ((EstablisherFrame.Virtual & 0xF) != 0)) { 01050 01051 #if DBG 01052 DbgPrint("\n****** Warning - bad stack or target frame (unwind).\n"); 01053 DbgPrint(" EstablisherFrame Virtual = %p, Real = %p\n", 01054 EstablisherFrame.Virtual, EstablisherFrame.Real); 01055 DbgPrint(" TargetFrame = %p\n", TargetFrame); 01056 if ((ARGUMENT_PRESENT(TargetFrame) != FALSE) && 01057 ((ULONG_PTR)TargetFrame < EstablisherFrame.Virtual)) { 01058 DbgPrint(" TargetFrame is below EstablisherFrame!\n"); 01059 } 01060 DbgPrint(" Previous EstablisherFrame (sp) = %p\n", 01061 (ULONG_PTR)ContextRecord->IntSp); 01062 DbgPrint(" LowLimit = %p, HighLimit = %p\n", 01063 LowLimit, HighLimit); 01064 DbgPrint(" NextPc = %p, ControlPc = %p\n", 01065 NextPc, ControlPc); 01066 DbgPrint(" Now raising STATUS_BAD_STACK exception.\n"); 01067 #endif 01068 01069 RAISE_EXCEPTION(STATUS_BAD_STACK, ExceptionRecord); 01070 01071 } else if (IS_HANDLER_DEFINED(FunctionEntry) && InFunction) { 01072 01073 #if DBG 01074 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { 01075 DbgPrint("RtlUnwind: ExceptionHandler = %p, HandlerData = %p\n", 01076 FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData); 01077 } 01078 #endif 01079 01080 // 01081 // The frame has an exception handler. 01082 // 01083 // The control PC, establisher frame pointer, the address 01084 // of the function table entry, and the address of the 01085 // context record are all stored in the dispatcher context. 01086 // This information is used by the unwind linkage routine 01087 // and can be used by the exception handler itself. 01088 // 01089 // A linkage routine written in assembler is used to actually 01090 // call the actual exception handler. This is required by the 01091 // exception handler that is associated with the linkage 01092 // routine so it can have access to two sets of dispatcher 01093 // context when it is called. 01094 // 01095 01096 DispatcherContext.ControlPc = ControlPc; 01097 DispatcherContext.FunctionEntry = FunctionEntry; 01098 DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual; 01099 DispatcherContext.ContextRecord = ContextRecord; 01100 01101 // 01102 // Call the exception handler. 01103 // 01104 01105 do { 01106 01107 // 01108 // If the establisher frame is the target of the unwind 01109 // operation, then set the target unwind flag. 01110 // 01111 01112 if ((ULONG_PTR)TargetFrame == EstablisherFrame.Virtual) { 01113 ExceptionFlags |= EXCEPTION_TARGET_UNWIND; 01114 } 01115 01116 ExceptionRecord->ExceptionFlags = ExceptionFlags; 01117 01118 // 01119 // Set the specified return value in case the exception 01120 // handler directly continues execution. 01121 // 01122 01123 ContextRecord->IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue; 01124 #if DBG 01125 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 01126 DbgPrint("RtlUnwind: calling RtlpExecuteHandlerForUnwind, ControlPc = %p\n", ControlPc); 01127 } 01128 #endif 01129 Disposition = 01130 RtlpExecuteHandlerForUnwind(ExceptionRecord, 01131 EstablisherFrame.Virtual, 01132 ContextRecord, 01133 &DispatcherContext, 01134 RF_EXCEPTION_HANDLER(FunctionEntry)); 01135 #if DBG 01136 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 01137 DbgPrint("RtlUnwind: RtlpExecuteHandlerForUnwind returned Disposition = %lx\n", Disposition); 01138 } 01139 #endif 01140 01141 // 01142 // Clear target unwind and collided unwind flags. 01143 // 01144 01145 ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND | 01146 EXCEPTION_TARGET_UNWIND); 01147 01148 // 01149 // Case on the handler disposition. 01150 // 01151 01152 switch (Disposition) { 01153 01154 // 01155 // The disposition is to continue the search. 01156 // 01157 // If the target frame has not been reached, then 01158 // virtually unwind to the caller of the current 01159 // routine, update the context record, and continue 01160 // the search for a handler. 01161 // 01162 01163 case ExceptionContinueSearch : 01164 if (EstablisherFrame.Virtual != (ULONG_PTR)TargetFrame) { 01165 NextPc = RtlVirtualUnwind(ControlPc, 01166 FunctionEntry, 01167 ContextRecord, 01168 &InFunction, 01169 &EstablisherFrame, 01170 NULL); 01171 } 01172 01173 break; 01174 01175 // 01176 // The disposition is collided unwind. 01177 // 01178 // Set the target of the current unwind to the context 01179 // record of the previous unwind, and reexecute the 01180 // exception handler from the collided frame with the 01181 // collided unwind flag set in the exception record. 01182 // 01183 01184 case ExceptionCollidedUnwind : 01185 ControlPc = DispatcherContext.ControlPc; 01186 FunctionEntry = DispatcherContext.FunctionEntry; 01187 ContextRecord = DispatcherContext.ContextRecord; 01188 ContextRecord->Fir = (ULONGLONG)(LONG_PTR)TargetIp; 01189 ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND; 01190 EstablisherFrame.Virtual = DispatcherContext.EstablisherFrame; 01191 break; 01192 01193 // 01194 // All other disposition values are invalid. 01195 // 01196 // Raise invalid disposition exception. 01197 // 01198 01199 default : 01200 RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord); 01201 } 01202 01203 } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0); 01204 } else { 01205 01206 // 01207 // Virtually unwind to the caller of the current routine and 01208 // update the context record. 01209 // 01210 01211 if (EstablisherFrame.Virtual != (ULONG_PTR)TargetFrame) { 01212 NextPc = RtlVirtualUnwind(ControlPc, 01213 FunctionEntry, 01214 ContextRecord, 01215 &InFunction, 01216 &EstablisherFrame, 01217 NULL); 01218 } 01219 } 01220 01221 } else { 01222 01223 // 01224 // Set point at which control left the previous routine. 01225 // 01226 01227 NextPc = (ULONG_PTR)ContextRecord->IntRa - 4; 01228 01229 // 01230 // If the next control PC is the same as the old control PC, then 01231 // the function table is not correctly formed. 01232 // 01233 01234 if (NextPc == ControlPc) { 01235 #if DBG 01236 ULONG Count; 01237 DbgPrint("\n****** Warning - malformed function table (unwind).\n"); 01238 DbgPrint("ControlPc = %p, %p", NextPc, ControlPc); 01239 for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) { 01240 if (ControlPcHistoryIndex > 0) { 01241 ControlPcHistoryIndex -= 1; 01242 ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH]; 01243 DbgPrint(", %p", ControlPc); 01244 } 01245 } 01246 DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n"); 01247 DbgPrint(" Now raising STATUS_BAD_FUNCTION_TABLE exception.\n"); 01248 #endif 01249 RtlRaiseStatus(STATUS_BAD_FUNCTION_TABLE); 01250 } 01251 } 01252 01253 // 01254 // Set point at which control left the previous routine. 01255 // 01256 01257 #if DBG 01258 ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc; 01259 ControlPcHistoryIndex += 1; 01260 #endif 01261 ControlPc = NextPc; 01262 01263 } while ((EstablisherFrame.Virtual < HighLimit) && 01264 (EstablisherFrame.Virtual != (ULONG_PTR)TargetFrame)); 01265 01266 // 01267 // If the establisher stack pointer is equal to the target frame 01268 // pointer, then continue execution. Otherwise, an exit unwind was 01269 // performed or the target of the unwind did not exist and the 01270 // debugger and subsystem are given a second chance to handle the 01271 // unwind. 01272 // 01273 01274 if (EstablisherFrame.Virtual == (ULONG_PTR)TargetFrame) { 01275 ContextRecord->IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue; 01276 01277 #if DBG 01278 if (RtlDebugFlags & RTL_DBG_UNWIND) { 01279 DbgPrint("RtlUnwind: finished unwinding, and calling RtlpRestoreContext(%lx)\n",ContextRecord); 01280 } 01281 #endif 01282 01283 RtlpRestoreContext(ContextRecord); 01284 01285 } else { 01286 01287 #if DBG 01288 if (RtlDebugFlags & RTL_DBG_UNWIND) { 01289 DbgPrint("RtlUnwind: finished unwinding, but calling ZwRaiseException\n"); 01290 } 01291 #endif 01292 01293 ZwRaiseException(ExceptionRecord, ContextRecord, FALSE); 01294 } 01295 01296 } 01297 01298 #if DBG 01299 // 01300 // Define an array of symbolic names for the integer registers. 01301 // 01302 01303 PCHAR RtlpIntegerRegisterNames[32] = { 01304 "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6", // 0 - 7 01305 "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp", // 8 - 15 01306 "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9", // 16 - 23 01307 "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero", // 24 - 31 01308 }; 01309 01310 // 01311 // This function disassembles the instruction at the given address. It is 01312 // only used for debugging and recognizes only those few instructions that 01313 // are relevant during reverse execution of the prologue by virtual unwind. 01314 // 01315 01316 VOID 01317 _RtlpDebugDisassemble ( 01318 IN ULONG_PTR ControlPc, 01319 IN PCONTEXT ContextRecord 01320 ) 01321 01322 { 01323 UCHAR Comments[50]; 01324 PULONGLONG FloatingRegister; 01325 ULONG Function; 01326 ULONG Hint; 01327 ULONG Literal8; 01328 ALPHA_INSTRUCTION Instruction; 01329 PULONGLONG IntegerRegister; 01330 LONG Offset16; 01331 UCHAR Operands[20]; 01332 ULONG Opcode; 01333 PCHAR OpName; 01334 ULONG Ra; 01335 ULONG Rb; 01336 ULONG Rc; 01337 PCHAR RaName; 01338 PCHAR RbName; 01339 PCHAR RcName; 01340 01341 if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND_DETAIL) { 01342 Instruction.Long = *((PULONG)ControlPc); 01343 Hint = Instruction.Jump.Hint; 01344 Literal8 = Instruction.OpLit.Literal; 01345 Offset16 = Instruction.Memory.MemDisp; 01346 Opcode = Instruction.Memory.Opcode; 01347 Ra = Instruction.OpReg.Ra; 01348 RaName = RtlpIntegerRegisterNames[Ra]; 01349 Rb = Instruction.OpReg.Rb; 01350 RbName = RtlpIntegerRegisterNames[Rb]; 01351 Rc = Instruction.OpReg.Rc; 01352 RcName = RtlpIntegerRegisterNames[Rc]; 01353 01354 IntegerRegister = &ContextRecord->IntV0; 01355 FloatingRegister = &ContextRecord->FltF0; 01356 01357 OpName = NULL; 01358 switch (Opcode) { 01359 case JMP_OP : 01360 if (Instruction.Jump.Function == RET_FUNC) { 01361 OpName = "ret"; 01362 sprintf(Operands, "%s, (%s), %04lx", RaName, RbName, Hint); 01363 sprintf(Comments, "%s = %Lx", RbName, IntegerRegister[Rb]); 01364 } 01365 break; 01366 01367 case LDAH_OP : 01368 case LDA_OP : 01369 case STQ_OP : 01370 if (Opcode == LDA_OP) { 01371 OpName = "lda"; 01372 01373 } else if (Opcode == LDAH_OP) { 01374 OpName = "ldah"; 01375 01376 } else if (Opcode == STQ_OP) { 01377 OpName = "stq"; 01378 } 01379 sprintf(Operands, "%s, $%d(%s)", RaName, Offset16, RbName); 01380 sprintf(Comments, "%s = %Lx", RaName, IntegerRegister[Ra]); 01381 break; 01382 01383 case ARITH_OP : 01384 case BIT_OP : 01385 Function = Instruction.OpReg.Function; 01386 if ((Opcode == ARITH_OP) && (Function == ADDQ_FUNC)) { 01387 OpName = "addq"; 01388 01389 } else if ((Opcode == ARITH_OP) && (Function == SUBQ_FUNC)) { 01390 OpName = "subq"; 01391 01392 } else if ((Opcode == BIT_OP) && (Function == BIS_FUNC)) { 01393 OpName = "bis"; 01394 01395 } else { 01396 break; 01397 } 01398 if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) { 01399 sprintf(Operands, "%s, %s, %s", RaName, RbName, RcName); 01400 01401 } else { 01402 sprintf(Operands, "%s, $%d, %s", RaName, Literal8, RcName); 01403 } 01404 sprintf(Comments, "%s = %Lx", RcName, IntegerRegister[Rc]); 01405 break; 01406 01407 case FPOP_OP : 01408 if (Instruction.FpOp.Function == CPYS_FUNC) { 01409 OpName = "cpys"; 01410 sprintf(Operands, "f%d, f%d, f%d", Ra, Rb, Rc); 01411 sprintf(Comments, "f%d = %Lx", Rc, FloatingRegister[Rc]); 01412 } 01413 break; 01414 01415 case STT_OP : 01416 OpName = "stt"; 01417 sprintf(Operands, "f%d, $%d(%s)", Ra, Offset16, RbName); 01418 sprintf(Comments, "f%d = %Lx", Ra, FloatingRegister[Ra]); 01419 break; 01420 } 01421 if (OpName == NULL) { 01422 OpName = "???"; 01423 sprintf(Operands, "..."); 01424 sprintf(Comments, "Unknown to virtual unwind."); 01425 } 01426 DbgPrint(" %p: %08lx %-5s %-16s // %s\n", 01427 ControlPc, Instruction.Long, OpName, Operands, Comments); 01428 } 01429 return; 01430 } 01431 01432 #define _RtlpFoundTrapFrame(NextPc) \ 01433 if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND) { \ 01434 DbgPrint(" *** Looks like a trap frame (fake prologue), Fir = %lx\n", \ 01435 NextPc); \ 01436 } 01437 01438 #define _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame) \ 01439 if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND) { \ 01440 DbgPrint("RtlVirtualUnwind: EstablisherFrame Virtual = %08lx, Real = %08lx\n", \ 01441 (EstablisherFrame)->Virtual, (EstablisherFrame)->Real); \ 01442 DbgPrint("RtlVirtualUnwind: returning NextPc = %p, sp = %p\n\n", \ 01443 NextPc, (ULONG_PTR)ContextRecord->IntSp); \ 01444 } 01445 01446 #else 01447 01448 #define _RtlpDebugDisassemble(ControlPc, ContextRecord) 01449 #define _RtlpFoundTrapFrame(NextPc) 01450 #define _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame) 01451 01452 #endif 01453 01454 ULONG_PTR 01455 RtlVirtualUnwind ( 01456 IN ULONG_PTR ControlPc, 01457 IN PRUNTIME_FUNCTION FunctionEntry, 01458 IN OUT PCONTEXT ContextRecord, 01459 OUT PBOOLEAN InFunction, 01460 OUT PFRAME_POINTERS EstablisherFrame, 01461 IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers OPTIONAL 01462 ) 01463 01464 /*++ 01465 01466 Routine Description: 01467 01468 This function virtually unwinds the specified function by executing its 01469 prologue code backwards. Given the current context and the instructions 01470 that preserve registers in the prologue, it is possible to recreate the 01471 nonvolatile context at the point the function was called. 01472 01473 If the function is a leaf function, then the address where control left 01474 the previous frame is obtained from the context record. If the function 01475 is a nested function, but not an exception or interrupt frame, then the 01476 prologue code is executed backwards and the address where control left 01477 the previous frame is obtained from the updated context record. 01478 01479 Otherwise, an exception or interrupt entry to the system is being unwound 01480 and a specially coded prologue restores the return address twice. Once 01481 from the fault instruction address and once from the saved return address 01482 register. The first restore is returned as the function value and the 01483 second restore is placed in the updated context record. 01484 01485 During the unwind, the virtual and real frame pointers for the function 01486 are calculated and returned in the given frame pointers structure. 01487 01488 If a context pointers record is specified, then the address where each 01489 register is restored from is recorded in the appropriate element of the 01490 context pointers record. 01491 01492 Arguments: 01493 01494 ControlPc - Supplies the address where control left the specified 01495 function. 01496 01497 FunctionEntry - Supplies the address of the function table entry for the 01498 specified function. 01499 01500 ContextRecord - Supplies the address of a context record. 01501 01502 InFunction - Supplies a pointer to a variable that receives whether the 01503 control PC is within the current function. 01504 01505 EstablisherFrame - Supplies a pointer to a frame pointers structure 01506 that will receive the values for the virtual frame pointer and the 01507 real frame pointer. The value of the real frame pointer is reliable 01508 only when InFunction is TRUE. 01509 01510 ContextPointers - Supplies an optional pointer to a context pointers 01511 record. 01512 01513 Return Value: 01514 01515 The address where control left the previous frame is returned as the 01516 function value. 01517 01518 Implementation Notes: 01519 01520 N.B. "where control left" is not the "return address" of the call in the 01521 previous frame. For normal frames, NextPc points to the last instruction 01522 that completed in the previous frame (the JSR/BSR). The difference between 01523 NextPc and NextPc + 4 (return address) is important for correct behavior 01524 in boundary cases of exception addresses and scope tables. 01525 01526 For exception and interrupt frames, NextPc is obtained from the trap frame 01527 contination address (Fir). For faults and synchronous traps, NextPc is both 01528 the last instruction to execute in the previous frame and the next 01529 instruction to execute if the function were to return. For asynchronous 01530 traps, NextPc is the continuation address. It is the responsibility of the 01531 compiler to insert TRAPB instructions to insure asynchronous traps do not 01532 occur outside the scope from the instruction(s) that caused them. 01533 01534 N.B. in this and other files where RtlVirtualUnwind is used, the variable 01535 named NextPc is perhaps more accurately, LastPc - the last PC value in 01536 the previous frame, or CallPc - the address of the call instruction, or 01537 ControlPc - the address where control left the previous frame. Instead 01538 think of NextPc as the next PC to use in another call to virtual unwind. 01539 01540 The Alpha version of virtual unwind is similar in design, but slightly 01541 more complex than the Mips version. This is because Alpha compilers 01542 are given more flexibility to optimize generated code and instruction 01543 sequences, including within procedure prologues. In addition, because of 01544 the current inability of the GEM compiler to materialize virtual frame 01545 pointers, this function must manage both virtual and real frame pointers. 01546 01547 --*/ 01548 01549 { 01550 01551 ULONG_PTR Address; 01552 ULONG DecrementOffset; 01553 ULONG DecrementRegister; 01554 ALPHA_INSTRUCTION FollowingInstruction; 01555 PULONGLONG FloatingRegister; 01556 ULONG_PTR FrameSize; 01557 ULONG Function; 01558 ALPHA_INSTRUCTION Instruction; 01559 PULONGLONG IntegerRegister; 01560 ULONG Literal8; 01561 ULONG_PTR NextPc; 01562 LONG Offset16; 01563 ULONG Opcode; 01564 ULONG Ra; 01565 ULONG Rb; 01566 ULONG Rc; 01567 BOOLEAN RestoredRa; 01568 BOOLEAN RestoredSp; 01569 RUNTIME_FUNCTION UnwindFunctionEntry; 01570 ULONG StackAdjust; 01571 ULONG_PTR FixedReturn; 01572 01573 #if DBG 01574 if (RtlDebugFlags & RTL_DBG_VIRTUAL_UNWIND) { 01575 DbgPrint("\nRtlVirtualUnwind(ControlPc = %p, FunctionEntry = %p,) sp = %p\n", 01576 ControlPc, FunctionEntry, (ULONG_PTR)ContextRecord->IntSp); 01577 } 01578 #endif 01579 01580 // Construct a function entry suitable for unwinding from ControlPc 01581 01582 RtlGetUnwindFunctionEntry( ControlPc, FunctionEntry, &UnwindFunctionEntry, &StackAdjust, &FixedReturn ); 01583 01584 #if DBG 01585 ShowRuntimeFunction(&UnwindFunctionEntry, "RtlVirtualUnwind: unwind function entry" ); 01586 #endif 01587 // 01588 // Set the base address of the integer and floating register arrays within 01589 // the context record. Each set of 32 registers is known to be contiguous. 01590 // 01591 01592 IntegerRegister = &ContextRecord->IntV0; 01593 FloatingRegister = &ContextRecord->FltF0; 01594 01595 // 01596 // Handle the epilogue case where the next instruction is a return. 01597 // 01598 // Exception handlers cannot be called if the ControlPc is within the 01599 // epilogue because exception handlers expect to operate with a current 01600 // stack frame. The value of SP is not current within the epilogue. 01601 // 01602 01603 Instruction.Long = *((PULONG)ControlPc); 01604 if (IS_RETURN_0001_INSTRUCTION(Instruction.Long)) { 01605 Rb = Instruction.Jump.Rb; 01606 NextPc = (ULONG_PTR)IntegerRegister[Rb] - 4; 01607 01608 // 01609 // The instruction at the point where control left the specified 01610 // function is a return, so any saved registers have already been 01611 // restored, and the stack pointer has already been adjusted. The 01612 // stack does not need to be unwound in this case and the saved 01613 // return address register is returned as the function value. 01614 // 01615 // In fact, reverse execution of the prologue is not possible in 01616 // this case: the stack pointer has already been incremented and 01617 // so, for this frame, neither a valid stack pointer nor frame 01618 // pointer exists from which to begin reverse execution of the 01619 // prologue. In addition, the integrity of any data on the stack 01620 // below the stack pointer is never guaranteed (due to interrupts 01621 // and exceptions). 01622 // 01623 // The epilogue instruction sequence is: 01624 // 01625 // ==> ret zero, (Ra), 1 // return 01626 // or 01627 // 01628 // mov ra, Rx // save return address 01629 // ... 01630 // ==> ret zero, (Rx), 1 // return 01631 // 01632 01633 EstablisherFrame->Real = 0; 01634 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp; 01635 *InFunction = FALSE; 01636 _RtlpDebugDisassemble(ControlPc, ContextRecord); 01637 _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame); 01638 return NextPc; 01639 } 01640 01641 // 01642 // Handle the epilogue case where the next two instructions are a stack 01643 // frame deallocation and a return. 01644 // 01645 01646 FollowingInstruction.Long = *((PULONG)(ControlPc + 4)); 01647 if (IS_RETURN_0001_INSTRUCTION(FollowingInstruction.Long)) { 01648 Rb = FollowingInstruction.Jump.Rb; 01649 NextPc = (ULONG_PTR)IntegerRegister[Rb] - 4; 01650 01651 // 01652 // The second instruction following the point where control 01653 // left the specified function is a return. If the instruction 01654 // before the return is a stack increment instruction, then all 01655 // saved registers have already been restored except for SP. 01656 // The value of the stack pointer register cannot be recovered 01657 // through reverse execution of the prologue because in order 01658 // to begin reverse execution either the stack pointer or the 01659 // frame pointer (if any) must still be valid. 01660 // 01661 // Instead, the effect that the stack increment instruction 01662 // would have had on the context is manually applied to the 01663 // current context. This is forward execution of the epilogue 01664 // rather than reverse execution of the prologue. 01665 // 01666 // In an epilogue, as in a prologue, the stack pointer is always 01667 // adjusted with a single instruction: either an immediate-value 01668 // (lda) or a register-value (addq) add instruction. 01669 // 01670 01671 Function = Instruction.OpReg.Function; 01672 Offset16 = Instruction.Memory.MemDisp; 01673 Opcode = Instruction.OpReg.Opcode; 01674 Ra = Instruction.OpReg.Ra; 01675 Rb = Instruction.OpReg.Rb; 01676 Rc = Instruction.OpReg.Rc; 01677 01678 if ((Opcode == LDA_OP) && (Ra == SP_REG)) { 01679 01680 // 01681 // Load Address instruction. 01682 // 01683 // Since the destination (Ra) register is SP, an immediate- 01684 // value stack deallocation operation is being performed. The 01685 // displacement value should be added to SP. The displacement 01686 // value is assumed to be positive. The amount of stack 01687 // deallocation possible using this instruction ranges from 01688 // 16 to 32752 (32768 - 16) bytes. The base register (Rb) is 01689 // usually SP, but may be another register. 01690 // 01691 // The epilogue instruction sequence is: 01692 // 01693 // ==> lda sp, +N(sp) // deallocate stack frame 01694 // ret zero, (ra) // return 01695 // or 01696 // 01697 // ==> lda sp, +N(Rx) // restore SP and deallocate frame 01698 // ret zero, (ra) // return 01699 // 01700 01701 ContextRecord->IntSp = Offset16 + IntegerRegister[Rb]; 01702 EstablisherFrame->Real = 0; 01703 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp; 01704 *InFunction = FALSE; 01705 _RtlpDebugDisassemble(ControlPc, ContextRecord); 01706 _RtlpDebugDisassemble(ControlPc + 4, ContextRecord); 01707 _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame); 01708 return NextPc; 01709 01710 } else if ((Opcode == ARITH_OP) && (Function == ADDQ_FUNC) && 01711 (Rc == SP_REG) && 01712 (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) { 01713 01714 // 01715 // Add Quadword instruction. 01716 // 01717 // Since both source operands are registers, and the 01718 // destination register is SP, a register-value stack 01719 // deallocation is being performed. The value of the two 01720 // source registers should be added and this is the new 01721 // value of SP. One of the source registers is usually SP, 01722 // but may be another register. 01723 // 01724 // The epilogue instruction sequence is: 01725 // 01726 // ldiq Rx, N // set [large] frame size 01727 // ... 01728 // ==> addq sp, Rx, sp // deallocate stack frame 01729 // ret zero, (ra) // return 01730 // or 01731 // 01732 // ==> addq Rx, Ry, sp // restore SP and deallocate frame 01733 // ret zero, (ra) // return 01734 // 01735 01736 ContextRecord->IntSp = IntegerRegister[Ra] + IntegerRegister[Rb]; 01737 EstablisherFrame->Real = 0; 01738 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp; 01739 *InFunction = FALSE; 01740 _RtlpDebugDisassemble(ControlPc, ContextRecord); 01741 _RtlpDebugDisassemble(ControlPc + 4, ContextRecord); 01742 _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame); 01743 return NextPc; 01744 } 01745 } 01746 01747 // 01748 // By default set the frame pointers to the current value of SP. 01749 // 01750 // When a procedure is called, the value of SP before the stack 01751 // allocation instruction is the virtual frame pointer. When reverse 01752 // executing instructions in the prologue, the value of SP before the 01753 // stack allocation instruction is encountered is the real frame 01754 // pointer. This is the current value of SP unless the procedure uses 01755 // a frame pointer (e.g., FP_REG). 01756 // 01757 01758 EstablisherFrame->Real = (ULONG_PTR)ContextRecord->IntSp; 01759 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp; 01760 01761 // 01762 // If the address where control left the specified function is beyond 01763 // the end of the prologue, then the control PC is considered to be 01764 // within the function and the control address is set to the end of 01765 // the prologue. Otherwise, the control PC is not considered to be 01766 // within the function (i.e., the prologue). 01767 // 01768 // N.B. PrologEndAddress is equal to BeginAddress for a leaf function. 01769 // 01770 // The low-order two bits of PrologEndAddress are reserved for the IEEE 01771 // exception mode and so must be masked out. 01772 // 01773 01774 if ((ControlPc < UnwindFunctionEntry.BeginAddress) || 01775 (ControlPc >= UnwindFunctionEntry.PrologEndAddress)) { 01776 *InFunction = TRUE; 01777 ControlPc = (UnwindFunctionEntry.PrologEndAddress & (~(UINT_PTR)0x3)); 01778 01779 } else { 01780 *InFunction = FALSE; 01781 } 01782 01783 // 01784 // Scan backward through the prologue to reload callee saved registers 01785 // that were stored or copied and to increment the stack pointer if it 01786 // was decremented. 01787 // 01788 01789 DecrementRegister = ZERO_REG; 01790 NextPc = (ULONG_PTR)ContextRecord->IntRa - 4; 01791 RestoredRa = FALSE; 01792 RestoredSp = FALSE; 01793 while (ControlPc > UnwindFunctionEntry.BeginAddress) { 01794 01795 // 01796 // Get instruction value, decode fields, case on opcode value, and 01797 // reverse register store and stack decrement operations. 01798 // N.B. The location of Opcode, Ra, Rb, and Rc is the same across 01799 // all opcode formats. The same is not true for Function. 01800 // 01801 01802 ControlPc -= 4; 01803 Instruction.Long = *((PULONG)ControlPc); 01804 Function = Instruction.OpReg.Function; 01805 Literal8 = Instruction.OpLit.Literal; 01806 Offset16 = Instruction.Memory.MemDisp; 01807 Opcode = Instruction.OpReg.Opcode; 01808 Ra = Instruction.OpReg.Ra; 01809 Rb = Instruction.OpReg.Rb; 01810 Rc = Instruction.OpReg.Rc; 01811 01812 // 01813 // Compare against each instruction type that will affect the context 01814 // and that is allowed in a prologue. Any other instructions found 01815 // in the prologue will be ignored since they are assumed to have no 01816 // effect on the context. 01817 // 01818 01819 switch (Opcode) { 01820 01821 case STQ_OP : 01822 01823 // 01824 // Store Quad instruction. 01825 // 01826 // If the base register is SP, then reload the source register 01827 // value from the value stored on the stack. 01828 // 01829 // The prologue instruction sequence is: 01830 // 01831 // ==> stq Rx, N(sp) // save integer register Rx 01832 // 01833 01834 if ((Rb == SP_REG) && (Ra != ZERO_REG)) { 01835 01836 // 01837 // Reload the register by retrieving the value previously 01838 // stored on the stack. 01839 // 01840 01841 Address = Offset16 + (LONG_PTR)ContextRecord->IntSp; 01842 IntegerRegister[Ra] = *((PULONGLONG)Address); 01843 01844 // 01845 // If the destination register is RA and this is the first 01846 // time that RA is being restored, then set the address of 01847 // where control left the previous frame. Otherwise, if this 01848 // is the second time RA is being restored, then the first 01849 // one was an interrupt or exception address and the return 01850 // PC should not have been biased by 4. 01851 // 01852 01853 if (Ra == RA_REG) { 01854 if (RestoredRa == FALSE) { 01855 NextPc = (ULONG_PTR)ContextRecord->IntRa - 4; 01856 RestoredRa = TRUE; 01857 01858 } else { 01859 NextPc += 4; 01860 _RtlpFoundTrapFrame(NextPc); 01861 } 01862 01863 // 01864 // Otherwise, if the destination register is SP and this is 01865 // the first time that SP is being restored, then set the 01866 // establisher frame pointers. 01867 // 01868 01869 } else if ((Ra == SP_REG) && (RestoredSp == FALSE)) { 01870 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp; 01871 EstablisherFrame->Real = (ULONG_PTR)ContextRecord->IntSp; 01872 RestoredSp = TRUE; 01873 } 01874 01875 // 01876 // If a context pointer record is specified, then record 01877 // the address where the destination register contents 01878 // are stored. 01879 // 01880 01881 if (ARGUMENT_PRESENT(ContextPointers)) { 01882 ContextPointers->IntegerContext[Ra] = (PULONGLONG)Address; 01883 } 01884 _RtlpDebugDisassemble(ControlPc, ContextRecord); 01885 } 01886 break; 01887 01888 case LDAH_OP : 01889 Offset16 <<= 16; 01890 01891 case LDA_OP : 01892 01893 // 01894 // Load Address High, Load Address instruction. 01895 // 01896 // There are several cases where the lda and/or ldah instructions 01897 // are used: one to decrement the stack pointer directly, and the 01898 // others to load immediate values into another register and that 01899 // register is then used to decrement the stack pointer. 01900 // 01901 // In the examples below, as a single instructions or as a pair, 01902 // a lda may be substituted for a ldah and visa-versa. 01903 // 01904 01905 if (Ra == SP_REG) { 01906 if (Rb == SP_REG) { 01907 01908 // 01909 // If both the destination (Ra) and base (Rb) registers 01910 // are SP, then a standard stack allocation was performed 01911 // and the negated displacement value is the stack frame 01912 // size. The amount of stack allocation possible using 01913 // the lda instruction ranges from 16 to 32768 bytes and 01914 // the amount of stack allocation possible using the ldah 01915 // instruction ranges from 65536 to 2GB in multiples of 01916 // 65536 bytes. It is rare for the ldah instruction to be 01917 // used in this manner. 01918 // 01919 // The prologue instruction sequence is: 01920 // 01921 // ==> lda sp, -N(sp) // allocate stack frame 01922 // 01923 01924 FrameSize = -Offset16; 01925 goto StackAllocation; 01926 01927 } else { 01928 01929 // 01930 // The destination register is SP and the base register 01931 // is not SP, so this instruction must be the second 01932 // half of an instruction pair to allocate a large size 01933 // (>32768 bytes) stack frame. Save the displacement value 01934 // as the partial decrement value and postpone adjusting 01935 // the value of SP until the first instruction of the pair 01936 // is encountered. 01937 // 01938 // The prologue instruction sequence is: 01939 // 01940 // ldah Rx, -N(sp) // prepare new SP (upper) 01941 // ==> lda sp, sN(Rx) // allocate stack frame 01942 // 01943 01944 DecrementRegister = Rb; 01945 DecrementOffset = Offset16; 01946 _RtlpDebugDisassemble(ControlPc, ContextRecord); 01947 } 01948 01949 } else if (Ra == DecrementRegister) { 01950 if (Rb == DecrementRegister) { 01951 01952 // 01953 // Both the destination and base registers are the 01954 // decrement register, so this instruction exists as the 01955 // second half of a two instruction pair to load a 01956 // 31-bit immediate value into the decrement register. 01957 // Save the displacement value as the partial decrement 01958 // value. 01959 // 01960 // The prologue instruction sequence is: 01961 // 01962 // ldah Rx, +N(zero) // set frame size (upper) 01963 // ==> lda Rx, sN(Rx) // set frame size (+lower) 01964 // ... 01965 // subq sp, Rx, sp // allocate stack frame 01966 // 01967 01968 DecrementOffset += Offset16; 01969 _RtlpDebugDisassemble(ControlPc, ContextRecord); 01970 01971 } else if (Rb == ZERO_REG) { 01972 01973 // 01974 // The destination register is the decrement register and 01975 // the base register is zero, so this instruction exists 01976 // to load an immediate value into the decrement register. 01977 // The stack frame size is the new displacement value added 01978 // to the previous displacement value, if any. 01979 // 01980 // The prologue instruction sequence is: 01981 // 01982 // ==> lda Rx, +N(zero) // set frame size 01983 // ... 01984 // subq sp, Rx, sp // allocate stack frame 01985 // or 01986 // 01987 // ==> ldah Rx, +N(zero) // set frame size (upper) 01988 // lda Rx, sN(Rx) // set frame size (+lower) 01989 // ... 01990 // subq sp, Rx, sp // allocate stack frame 01991 // 01992 01993 FrameSize = (Offset16 + DecrementOffset); 01994 goto StackAllocation; 01995 01996 } else if (Rb == SP_REG) { 01997 01998 // 01999 // The destination (Ra) register is SP and the base (Rb) 02000 // register is the decrement register, so a two 02001 // instruction, large size (>32768 bytes) stack frame 02002 // allocation was performed. Add the new displacement 02003 // value to the previous displacement value. The negated 02004 // displacement value is the stack frame size. 02005 // 02006 // The prologue instruction sequence is: 02007 // 02008 // ==> ldah Rx, -N(sp) // prepare new SP (upper) 02009 // lda sp, sN(Rx) // allocate stack frame 02010 // 02011 02012 FrameSize = -(Offset16 + (LONG)DecrementOffset); 02013 goto StackAllocation; 02014 } 02015 } 02016 break; 02017 02018 case ARITH_OP : 02019 02020 if ((Function == ADDQ_FUNC) && 02021 (Instruction.OpReg.RbvType != RBV_REGISTER_FORMAT)) { 02022 02023 // 02024 // Add Quadword (immediate) instruction. 02025 // 02026 // If the first source register is zero, and the second 02027 // operand is a literal, and the destination register is 02028 // the decrement register, then the instruction exists 02029 // to load an unsigned immediate value less than 256 into 02030 // the decrement register. The immediate value is the stack 02031 // frame size. 02032 // 02033 // The prologue instruction sequence is: 02034 // 02035 // ==> addq zero, N, Rx // set frame size 02036 // ... 02037 // subq sp, Rx, sp // allocate stack frame 02038 // 02039 02040 if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) { 02041 FrameSize = Literal8; 02042 goto StackAllocation; 02043 } 02044 02045 } else if ((Function == SUBQ_FUNC) && 02046 (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT)) { 02047 02048 // 02049 // Subtract Quadword (register) instruction. 02050 // 02051 // If both source operands are registers and the first 02052 // source (minuend) register and the destination 02053 // (difference) register are both SP, then a register value 02054 // stack allocation was performed and the second source 02055 // (subtrahend) register value will be added to SP when its 02056 // value is known. Until that time save the register number of 02057 // this decrement register. 02058 // 02059 // The prologue instruction sequence is: 02060 // 02061 // ldiq Rx, N // set frame size 02062 // ... 02063 // ==> subq sp, Rx, sp // allocate stack frame 02064 // 02065 02066 if ((Ra == SP_REG) && (Rc == SP_REG)) { 02067 DecrementRegister = Rb; 02068 DecrementOffset = 0; 02069 _RtlpDebugDisassemble(ControlPc, ContextRecord); 02070 } 02071 } 02072 break; 02073 02074 case BIT_OP : 02075 02076 // 02077 // If the second operand is a register the bit set instruction 02078 // may be a register move instruction, otherwise if the second 02079 // operand is a literal, the bit set instruction may be a load 02080 // immediate value instruction. 02081 // 02082 02083 if ((Function == BIS_FUNC) && (Rc != ZERO_REG)) { 02084 if (Instruction.OpReg.RbvType == RBV_REGISTER_FORMAT) { 02085 02086 // 02087 // Bit Set (register move) instruction. 02088 // 02089 // If both source registers are the same register, or 02090 // one of the source registers is zero, then this is a 02091 // register move operation. Restore the value of the 02092 // source register by copying the current destination 02093 // register value back to the source register. 02094 // 02095 // The prologue instruction sequence is: 02096 // 02097 // ==> bis Rx, Rx, Ry // copy register Rx 02098 // or 02099 // 02100 // ==> bis Rx, zero, Ry // copy register Rx 02101 // or 02102 // 02103 // ==> bis zero, Rx, Ry // copy register Rx 02104 // 02105 02106 if (Ra == ZERO_REG) { 02107 02108 // 02109 // Map the third case above to the first case. 02110 // 02111 02112 Ra = Rb; 02113 02114 } else if (Rb == ZERO_REG) { 02115 02116 // 02117 // Map the second case above to the first case. 02118 // 02119 02120 Rb = Ra; 02121 } 02122 02123 if ((Ra == Rb) && (Ra != ZERO_REG)) { 02124 IntegerRegister[Ra] = IntegerRegister[Rc]; 02125 02126 // 02127 // If the destination register is RA and this is the 02128 // first time that RA is being restored, then set the 02129 // address of where control left the previous frame. 02130 // Otherwise, if this is the second time RA is being 02131 // restored, then the first one was an interrupt or 02132 // exception address and the return PC should not 02133 // have been biased by 4. 02134 // 02135 02136 if (Ra == RA_REG) { 02137 if (RestoredRa == FALSE) { 02138 NextPc = (ULONG_PTR)ContextRecord->IntRa - 4; 02139 RestoredRa = TRUE; 02140 02141 } else { 02142 NextPc += 4; 02143 _RtlpFoundTrapFrame(NextPc); 02144 } 02145 02146 // 02147 // If the source register is SP and this is the first 02148 // time SP is set, then this is a frame pointer set 02149 // instruction. Reset the frame pointers to this new 02150 // value of SP. 02151 // 02152 02153 } else if ((Ra == SP_REG) && (RestoredSp == FALSE)) { 02154 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp; 02155 EstablisherFrame->Real = (ULONG_PTR)ContextRecord->IntSp; 02156 RestoredSp = TRUE; 02157 } 02158 02159 _RtlpDebugDisassemble(ControlPc, ContextRecord); 02160 } 02161 02162 } else { 02163 02164 // 02165 // Bit Set (load immediate) instruction. 02166 // 02167 // If the first source register is zero, and the second 02168 // operand is a literal, and the destination register is 02169 // the decrement register, then this instruction exists 02170 // to load an unsigned immediate value less than 256 into 02171 // the decrement register. The decrement register value is 02172 // the stack frame size. 02173 // 02174 // The prologue instruction sequence is: 02175 // 02176 // ==> bis zero, N, Rx // set frame size 02177 // ... 02178 // subq sp, Rx, sp // allocate stack frame 02179 // 02180 02181 if ((Ra == ZERO_REG) && (Rc == DecrementRegister)) { 02182 FrameSize = Literal8; 02183 StackAllocation: 02184 // 02185 // Add the frame size to SP to reverse the stack frame 02186 // allocation, leave the real frame pointer as is, set 02187 // the virtual frame pointer with the updated SP value, 02188 // and clear the decrement register. 02189 // 02190 02191 ContextRecord->IntSp += FrameSize; 02192 EstablisherFrame->Virtual = (ULONG_PTR)ContextRecord->IntSp; 02193 DecrementRegister = ZERO_REG; 02194 _RtlpDebugDisassemble(ControlPc, ContextRecord); 02195 } 02196 } 02197 } 02198 break; 02199 02200 case STT_OP : 02201 02202 // 02203 // Store T-Floating (quadword integer) instruction. 02204 // 02205 // If the base register is SP, then reload the source register 02206 // value from the value stored on the stack. 02207 // 02208 // The prologue instruction sequence is: 02209 // 02210 // ==> stt Fx, N(sp) // save floating register Fx 02211 // 02212 02213 if ((Rb == SP_REG) && (Ra != FZERO_REG)) { 02214 02215 // 02216 // Reload the register by retrieving the value previously 02217 // stored on the stack. 02218 // 02219 02220 Address = Offset16 + (LONG_PTR)ContextRecord->IntSp; 02221 FloatingRegister[Ra] = *((PULONGLONG)Address); 02222 02223 // 02224 // If a context pointer record is specified, then record 02225 // the address where the destination register contents are 02226 // stored. 02227 // 02228 02229 if (ARGUMENT_PRESENT(ContextPointers)) { 02230 ContextPointers->FloatingContext[Ra] = (PULONGLONG)Address; 02231 } 02232 _RtlpDebugDisassemble(ControlPc, ContextRecord); 02233 } 02234 break; 02235 02236 case FPOP_OP : 02237 02238 // 02239 // N.B. The floating operate function field is not the same as 02240 // the integer operate nor the jump function fields. 02241 // 02242 02243 if (Instruction.FpOp.Function == CPYS_FUNC) { 02244 02245 // 02246 // Copy Sign (floating-point move) instruction. 02247 // 02248 // If both source registers are the same register, then this is 02249 // a floating-point register move operation. Restore the value 02250 // of the source register by copying the current destination 02251 // register value to the source register. 02252 // 02253 // The prologue instruction sequence is: 02254 // 02255 // ==> cpys Fx, Fx, Fy // copy floating register Fx 02256 // 02257 02258 if ((Ra == Rb) && (Ra != FZERO_REG)) { 02259 FloatingRegister[Ra] = FloatingRegister[Rc]; 02260 _RtlpDebugDisassemble(ControlPc, ContextRecord); 02261 } 02262 } 02263 02264 default : 02265 break; 02266 } 02267 } 02268 02269 // Check for exlicit stack adjust amount 02270 02271 if (StackAdjust) { 02272 ContextRecord->IntSp += StackAdjust; 02273 } 02274 02275 if (FixedReturn != 0) { 02276 NextPc = FixedReturn; 02277 } 02278 02279 _RtlpVirtualUnwindExit(NextPc, ContextRecord, EstablisherFrame); 02280 return NextPc; 02281 } 02282 02283 ULONG_PTR 02284 RtlpVirtualUnwind ( 02285 IN ULONG_PTR ControlPc, 02286 IN PRUNTIME_FUNCTION FunctionEntry, 02287 IN PCONTEXT ContextRecord, 02288 OUT PBOOLEAN InFunction, 02289 OUT PFRAME_POINTERS EstablisherFrame 02290 ) 02291 02292 /*++ 02293 02294 Routine Description: 02295 02296 This function virtually unwinds the specfified function by executing its 02297 prologue code backwards. 02298 02299 If the function is a leaf function, then the address where control left 02300 the previous frame is obtained from the context record. If the function 02301 is a nested function, but not an exception or interrupt frame, then the 02302 prologue code is executed backwards and the address where control left 02303 the previous frame is obtained from the updated context record. 02304 02305 Otherwise, an exception or interrupt entry to the system is being unwound 02306 and a specially coded prologue restores the return address twice. Once 02307 from the fault instruction address and once from the saved return address 02308 register. The first restore is returned as the function value and the 02309 second restore is place in the updated context record. 02310 02311 If a context pointers record is specified, then the address where each 02312 nonvolatile registers is restored from is recorded in the appropriate 02313 element of the context pointers record. 02314 02315 N.B. This function copies the specified context record and only computes 02316 the establisher frame and whether control is actually in a function. 02317 02318 Arguments: 02319 02320 ControlPc - Supplies the address where control left the specified 02321 function. 02322 02323 FunctionEntry - Supplies the address of the function table entry for the 02324 specified function. 02325 02326 ContextRecord - Supplies the address of a context record. 02327 02328 InFunction - Supplies a pointer to a variable that receives whether the 02329 control PC is within the current function. 02330 02331 EstablisherFrame - Supplies a pointer to a variable that receives the 02332 the establisher frame pointer value. 02333 02334 ContextPointers - Supplies an optional pointer to a context pointers 02335 record. 02336 02337 Return Value: 02338 02339 The address where control left the previous frame is returned as the 02340 function value. 02341 02342 --*/ 02343 02344 { 02345 02346 CONTEXT LocalContext; 02347 02348 // 02349 // Copy the context record so updates will not be reflected in the 02350 // original copy and then virtually unwind to the caller of the 02351 // specified control point. 02352 // 02353 02354 RtlMoveMemory((PVOID)&LocalContext, ContextRecord, sizeof(CONTEXT)); 02355 return RtlVirtualUnwind(ControlPc, 02356 FunctionEntry, 02357 &LocalContext, 02358 InFunction, 02359 EstablisherFrame, 02360 NULL); 02361 } 02362 02363 PRUNTIME_FUNCTION 02364 RtlLookupDirectFunctionEntry ( 02365 IN ULONG_PTR ControlPc 02366 ) 02367 02368 /*++ 02369 02370 Routine Description: 02371 02372 This function searches the currently active function tables (static and dynamic) 02373 for an entry that corresponds to the specified PC value. 02374 02375 Arguments: 02376 02377 ControlPc - Supplies the address of an instruction within the specified 02378 function. 02379 02380 Return Value: 02381 02382 If there is no entry in the function table for the specified PC, then 02383 NULL is returned. Otherwise, the address of the function table entry 02384 that corresponds to the specified PC is returned. 02385 02386 --*/ 02387 02388 { 02389 PRUNTIME_FUNCTION FunctionEntry; 02390 BOOLEAN InImage; 02391 02392 // 02393 // look for function entry in static function tables 02394 // 02395 02396 FunctionEntry = RtlLookupStaticFunctionEntry( ControlPc, &InImage ); 02397 02398 #if !defined(NTOS_KERNEL_RUNTIME) 02399 // 02400 // If not in static image range and no static function entry 02401 // found then look for a dynamic function entry 02402 // 02403 02404 if (FunctionEntry == NULL && !InImage) { 02405 02406 FunctionEntry = RtlLookupDynamicFunctionEntry( ControlPc ); 02407 02408 } 02409 #endif 02410 02411 #if DBG 02412 if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) { 02413 DbgPrint("RtlLookupDirectFunctionEntry: returning FunctionEntry = %p\n", FunctionEntry); 02414 } 02415 #endif 02416 02417 return FunctionEntry; 02418 } 02419 02420 PRUNTIME_FUNCTION 02421 RtlLookupStaticFunctionEntry( 02422 IN ULONG_PTR ControlPc, 02423 OUT PBOOLEAN InImage 02424 ) 02425 02426 /*++ 02427 02428 Routine Description: 02429 02430 This function searches the currently active static function tables for an 02431 entry that corresponds to the specified PC value. 02432 02433 Arguments: 02434 02435 ControlPc - Supplies the address of an instruction within the specified 02436 function. 02437 02438 InImage - Address to recieve a flag indicating whether the ControlPc 02439 was in the range of a static function table 02440 02441 Return Value: 02442 02443 If there is no entry in the static function tables for the specified PC, 02444 then NULL is returned. Otherwise, the address of the function table entry 02445 that corresponds to the specified PC is returned. 02446 02447 --*/ 02448 02449 { 02450 PRUNTIME_FUNCTION FunctionEntry; 02451 PRUNTIME_FUNCTION FunctionTable; 02452 ULONG SizeOfExceptionTable; 02453 LONG High; 02454 PVOID ImageBase; 02455 LONG Low; 02456 LONG Middle; 02457 02458 // 02459 // Search for the image that includes the specified PC value. 02460 // 02461 02462 ImageBase = RtlPcToFileHeader((PVOID)ControlPc, &ImageBase); 02463 02464 #if DBG 02465 if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) { 02466 DbgPrint("RtlLookupStaticFunctionEntry(ControlPc = %p) ImageBase = %p\n", 02467 ControlPc, ImageBase); 02468 } 02469 #endif 02470 02471 // 02472 // If an image is found that includes the specified PC, then locate the 02473 // function table for the image. 02474 // 02475 02476 *InImage = (ImageBase != NULL); 02477 FunctionEntry = NULL; 02478 if (ImageBase != NULL) { 02479 FunctionTable = (PRUNTIME_FUNCTION)RtlImageDirectoryEntryToData( 02480 ImageBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, 02481 &SizeOfExceptionTable); 02482 #if DBG 02483 if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY_DETAIL) { 02484 DbgPrint("RtlLookupStaticFunctionEntry: FunctionTable = %p, SizeOfExceptionTable = %lx\n", 02485 FunctionTable, SizeOfExceptionTable); 02486 } 02487 #endif 02488 02489 // 02490 // If a function table is located, then search the function table 02491 // for a function table entry for the specified PC. 02492 // 02493 02494 if (FunctionTable != NULL) { 02495 02496 // 02497 // Initialize search indicies. 02498 // 02499 02500 Low = 0; 02501 High = (SizeOfExceptionTable / sizeof(RUNTIME_FUNCTION)) - 1; 02502 02503 // 02504 // Perform binary search on the function table for a function table 02505 // entry that subsumes the specified PC. 02506 // 02507 02508 while (High >= Low) { 02509 02510 // 02511 // Compute next probe index and test entry. If the specified PC 02512 // is greater than of equal to the beginning address and less 02513 // than the ending address of the function table entry, then 02514 // return the address of the function table entry. Otherwise, 02515 // continue the search. 02516 // 02517 02518 Middle = (Low + High) >> 1; 02519 FunctionEntry = &FunctionTable[Middle]; 02520 if (ControlPc < RF_BEGIN_ADDRESS(FunctionEntry)) { 02521 High = Middle - 1; 02522 02523 } else if (ControlPc >= RF_END_ADDRESS(FunctionEntry)) { 02524 Low = Middle + 1; 02525 02526 } else { 02527 return FunctionEntry; 02528 } 02529 } // while (High >= Low) 02530 } // FunctionTable != NULL 02531 } // ImageBase != NULL 02532 return NULL; 02533 } 02534 02535 VOID 02536 RtlGetUnwindFunctionEntry( 02537 IN ULONG_PTR ControlPc, 02538 IN PRUNTIME_FUNCTION FunctionEntry, 02539 OUT PRUNTIME_FUNCTION UnwindFunctionEntry, 02540 OUT PULONG StackAdjust, 02541 OUT PULONG_PTR FixedReturn 02542 ) 02543 /*++ 02544 02545 Routine Description: 02546 02547 This function returns a function entry (RUNTIME_FUNCTION) suitable 02548 for unwinding from ControlPc. It encapsulates the handling of primary 02549 and secondary function entries so that this processing is not duplicated 02550 in RtlVirtualUnwind and other similar functions. 02551 02552 Arguments: 02553 02554 ControlPc - Supplies the address where control left the specified 02555 function. 02556 02557 FunctionEntry - Supplies the address of the function table entry for the 02558 specified function. 02559 02560 UnwindFunctionEntry - Supplies the address of a function table entry which 02561 will be setup with appropriate fields for unwinding from ControlPc 02562 02563 StackAdjust - Receives the optional stack adjustment amount specified 02564 in RF_NULL_CONTEXT type secondary function entries. Will be zero 02565 if no null-context stack adjustment is required. 02566 02567 FixedReturn - Receives the return address specified by fixed-return functin 02568 entries. Will be zero if a fixed return address was not specified. 02569 02570 Return Value: 02571 02572 None. 02573 02574 --*/ 02575 02576 { 02577 ULONG EntryType = 0; 02578 PRUNTIME_FUNCTION SecondaryFunctionEntry = NULL; 02579 ULONG_PTR AlternateProlog; 02580 02581 *FixedReturn = 0; 02582 *StackAdjust = 0; 02583 02584 // FunctionEntry should never be null, but if it is create one that 02585 // looks like a leaf entry for ControlPc 02586 02587 if (FunctionEntry == NULL) { 02588 #if DBG 02589 DbgPrint("\n****** Warning - Null function table entry for unwinding.\n"); 02590 #endif 02591 UnwindFunctionEntry->BeginAddress = ControlPc; 02592 UnwindFunctionEntry->EndAddress = ControlPc+4; 02593 UnwindFunctionEntry->ExceptionHandler = NULL; 02594 UnwindFunctionEntry->HandlerData = 0; 02595 UnwindFunctionEntry->PrologEndAddress = ControlPc; 02596 return; 02597 } 02598 02599 // 02600 // Because of the secondary-to-primary function entry indirection applied by 02601 // RtlLookupFunctionEntry() ControlPc may not be within the range described 02602 // by the supplied function entry. Call RtlLookupDirectFunctionEntry() 02603 // to recover the actual (secondary) function entry. If we don't get a 02604 // valid associated function entry then process the unwind with the one 02605 // supplied, trusting that the caller has supplied the given entry intentionally. 02606 // 02607 // A secondary function entry is a RUNTIME_FUNCTION entry where 02608 // PrologEndAddress is not in the range of BeginAddress to EndAddress. 02609 // There are three types of secondary function entries. They are 02610 // distinquished by the Entry Type field (2 bits): 02611 // 02612 // RF_NOT_CONTIGUOUS - discontiguous code 02613 // RF_ALT_ENT_PROLOG - alternate entry point prologue 02614 // RF_NULL_CONTEXT - null-context code 02615 // 02616 02617 if ((ControlPc < RF_BEGIN_ADDRESS(FunctionEntry)) || 02618 (ControlPc >= RF_END_ADDRESS(FunctionEntry))) { 02619 02620 // ControlPC is not in the range of the supplied function entry. 02621 // Get the actual function entry which is expected to be the 02622 // associated secondary function entry. 02623 02624 #if DBG 02625 if (RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY) { 02626 DbgPrint("\nGetUnwindFunctionEntry:RtlLookupDirectFunctionEntry(ControlPc=%lx)\n", ControlPc); 02627 } 02628 #endif 02629 SecondaryFunctionEntry = RtlLookupDirectFunctionEntry( ControlPc ); 02630 02631 if (SecondaryFunctionEntry) { 02632 02633 #if DBG 02634 ShowRuntimeFunction(SecondaryFunctionEntry, "GetUnwindFunctionEntry: LookupDirectFunctionEntry"); 02635 #endif 02636 02637 // If this is a null-context tail region then unwind with a null-context-like descriptor 02638 02639 if ((ControlPc >= RF_END_ADDRESS(SecondaryFunctionEntry)-(RF_NULL_CONTEXT_COUNT(SecondaryFunctionEntry)*4)) && 02640 (ControlPc < RF_END_ADDRESS(SecondaryFunctionEntry))) { 02641 02642 // Use the secondary function entry with PrologEndAddress = BeginAddress. 02643 // This ensures that the prologue is not reverse executed. 02644 02645 UnwindFunctionEntry->BeginAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry); 02646 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(SecondaryFunctionEntry); 02647 UnwindFunctionEntry->ExceptionHandler = 0; 02648 UnwindFunctionEntry->HandlerData = 0; 02649 UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry); 02650 return; 02651 } 02652 02653 if ((SecondaryFunctionEntry->PrologEndAddress < RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) || 02654 (SecondaryFunctionEntry->PrologEndAddress > RF_END_ADDRESS(SecondaryFunctionEntry))) { 02655 02656 // Got a secondary function entry as expected. But if indirection doesn't point 02657 // to FunctionEntry then ignore it and use the caller supplied FunctionEntry. 02658 02659 if (RF_PROLOG_END_ADDRESS(SecondaryFunctionEntry) != (ULONG_PTR)FunctionEntry) { 02660 #if DBG 02661 DbgPrint("RtlGetUnwindFunctionEntry: unexpected secondary function entry from RtlLookupDirectFunctionEntry\n"); 02662 #endif 02663 SecondaryFunctionEntry = NULL; 02664 } 02665 } else { 02666 02667 // Got a primary function entry. The only valid type is a 02668 // Fixed Return Function Entry, which if present gets processed 02669 // at the end. Even if it is not a fixed return function entry, 02670 // use it, since its prolog matches up with the control PC. 02671 02672 FunctionEntry = SecondaryFunctionEntry; 02673 SecondaryFunctionEntry = NULL; 02674 02675 #if DBG 02676 if (!RF_FIXED_RETURN(FunctionEntry)) { 02677 DbgPrint("RtlGetUnwindFunctionEntry: unexpected primary function entry from RtlLookupDirectFunctionEntry\n"); 02678 } 02679 #endif 02680 } 02681 #if DBG 02682 } else { 02683 DbgPrint("GetUnwindFunctionEntry: LookupDirectFunctionEntry returned NULL\n"); 02684 #endif 02685 } 02686 02687 } else { 02688 02689 // ControlPC is in the range of the supplied function entry. 02690 // Check if it is a secondary function entry. If so, get the 02691 // associated primary function entry. 02692 02693 // If this is a null-context tail region then unwind with a null-context-like descriptor 02694 02695 if ((ControlPc >= RF_END_ADDRESS(FunctionEntry)-(RF_NULL_CONTEXT_COUNT(FunctionEntry)*4)) && 02696 (ControlPc < RF_END_ADDRESS(FunctionEntry))) { 02697 02698 // Create the unwind function entry with PrologEndAddress = BeginAddress. 02699 // This ensures that the prologue is not reverse executed. 02700 02701 UnwindFunctionEntry->BeginAddress = RF_BEGIN_ADDRESS(FunctionEntry); 02702 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(FunctionEntry); 02703 UnwindFunctionEntry->ExceptionHandler = 0; 02704 UnwindFunctionEntry->HandlerData = 0; 02705 UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(FunctionEntry); 02706 return; 02707 } 02708 02709 if ((FunctionEntry->PrologEndAddress < RF_BEGIN_ADDRESS(FunctionEntry)) || 02710 (FunctionEntry->PrologEndAddress > RF_END_ADDRESS(FunctionEntry))) { 02711 02712 SecondaryFunctionEntry = FunctionEntry; 02713 FunctionEntry = (PRUNTIME_FUNCTION)RF_PROLOG_END_ADDRESS(SecondaryFunctionEntry); 02714 #if DBG 02715 DbgPrint("RtlGetUnwindFunctionEntry: received secondary function entry\n"); 02716 #endif 02717 } 02718 } 02719 02720 #if DBG 02721 if (ControlPc & 0x3) { 02722 DbgPrint("RtlGetUnwindFunctionEntry: Warning - Invalid ControlPc %lx for unwinding.\n", ControlPc); 02723 } else if (RF_BEGIN_ADDRESS(FunctionEntry) >= RF_END_ADDRESS(FunctionEntry)) { 02724 ShowRuntimeFunction(FunctionEntry, "RtlGetUnwindFunctionEntry: Warning - BeginAddress < EndAddress."); 02725 } else if (FunctionEntry->PrologEndAddress < RF_BEGIN_ADDRESS(FunctionEntry)) { 02726 ShowRuntimeFunction(FunctionEntry, "RtlGetUnwindFunctionEntry: Warning - PrologEndAddress < BeginAddress."); 02727 } else if (FunctionEntry->PrologEndAddress > RF_END_ADDRESS(FunctionEntry)) { 02728 ShowRuntimeFunction(FunctionEntry, "RtlGetUnwindFunctionEntry: Warning - PrologEndAddress > EndAddress."); 02729 } 02730 #endif 02731 02732 // FunctionEntry is now the primary function entry and if SecondaryFunctionEntry is 02733 // not NULL then it is the secondary function entry that contains the ControlPC. Setup a 02734 // copy of the FunctionEntry suitable for unwinding. By default use the supplied FunctionEntry. 02735 02736 if (SecondaryFunctionEntry) { 02737 02738 // Extract the secondary function entry type. 02739 02740 EntryType = RF_ENTRY_TYPE(SecondaryFunctionEntry); 02741 02742 if (EntryType == RF_NOT_CONTIGUOUS) { 02743 // The exception happened in the body of the procedure but in a non-contiguous 02744 // section of code. Regardless of what entry point was used, it is normally valid 02745 // to unwind using the primary entry point prologue. The only exception is when an 02746 // alternate prologue is specified However, there may be an 02747 // alternate prologue end addresss specified in which case unwind using this 02748 // block as though it were the primary. 02749 02750 AlternateProlog = RF_ALT_PROLOG(SecondaryFunctionEntry); 02751 02752 if ((AlternateProlog >= RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) && 02753 (AlternateProlog < RF_END_ADDRESS(SecondaryFunctionEntry))) { 02754 02755 // If the control PC is in the alternate prologue, use the secondary. 02756 // The control Pc is not in procedure context. 02757 02758 if ((ControlPc >= RF_BEGIN_ADDRESS(SecondaryFunctionEntry)) && 02759 (ControlPc < AlternateProlog)) { 02760 02761 UnwindFunctionEntry->BeginAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry); 02762 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(SecondaryFunctionEntry); 02763 UnwindFunctionEntry->ExceptionHandler = 0; 02764 UnwindFunctionEntry->HandlerData = 0; 02765 UnwindFunctionEntry->PrologEndAddress = AlternateProlog; 02766 return; 02767 } 02768 } 02769 02770 // Fall out of the if statement to pick up the primary function entry below. 02771 // This code is in-procedure-context and subject to the primary's prologue 02772 // and exception handlers. 02773 02774 02775 } else if (EntryType == RF_ALT_ENT_PROLOG) { 02776 02777 // Exception occured in an alternate entry point prologue. 02778 // Use the secondary function entry with a fixed-up PrologEndAddress. 02779 02780 UnwindFunctionEntry->BeginAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry); 02781 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(SecondaryFunctionEntry); 02782 UnwindFunctionEntry->ExceptionHandler = 0; 02783 UnwindFunctionEntry->HandlerData = 0; 02784 UnwindFunctionEntry->PrologEndAddress = RF_END_ADDRESS(UnwindFunctionEntry); 02785 02786 // Check for an alternate prologue. 02787 02788 AlternateProlog = RF_ALT_PROLOG(SecondaryFunctionEntry); 02789 if (AlternateProlog >= UnwindFunctionEntry->BeginAddress && 02790 AlternateProlog < UnwindFunctionEntry->EndAddress ) { 02791 // The prologue is only part of the procedure 02792 UnwindFunctionEntry->PrologEndAddress = AlternateProlog; 02793 } 02794 02795 return; 02796 02797 } else if (EntryType == RF_NULL_CONTEXT) { 02798 02799 // Exception occured in null-context code associated with a primary function. 02800 // Use the secondary function entry with a PrologEndAddress = BeginAddress. 02801 // There is no prologue for null-context code. 02802 02803 *StackAdjust = RF_STACK_ADJUST(SecondaryFunctionEntry); 02804 UnwindFunctionEntry->BeginAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry); 02805 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(SecondaryFunctionEntry); 02806 UnwindFunctionEntry->ExceptionHandler = 0; 02807 UnwindFunctionEntry->HandlerData = 0; 02808 UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(SecondaryFunctionEntry); 02809 return; 02810 } 02811 02812 } 02813 02814 // Use the primary function entry 02815 02816 *UnwindFunctionEntry = *FunctionEntry; 02817 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(UnwindFunctionEntry); // Remove null-context count 02818 02819 // If the primary has a fixed return address, pull that out now. 02820 02821 if (RF_IS_FIXED_RETURN(FunctionEntry)) { 02822 *FixedReturn = RF_FIXED_RETURN(FunctionEntry); 02823 UnwindFunctionEntry->ExceptionHandler = 0; 02824 UnwindFunctionEntry->HandlerData = 0; 02825 } 02826 02827 // If the ControlPc is in the primary Null context, return null context. 02828 // Otherwise, remove Null context count 02829 02830 if ((ControlPc >= RF_END_ADDRESS(FunctionEntry)-(RF_NULL_CONTEXT_COUNT(FunctionEntry)*4)) && 02831 (ControlPc < RF_END_ADDRESS(FunctionEntry))) { 02832 02833 // Exception occured in null-context code associated with a primary function. 02834 // Create the unwind function entry with a PrologEndAddress = BeginAddress. 02835 // This ensures that the prologue is not reverse executed. 02836 02837 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(FunctionEntry); 02838 UnwindFunctionEntry->ExceptionHandler = 0; 02839 UnwindFunctionEntry->HandlerData = 0; 02840 UnwindFunctionEntry->PrologEndAddress = RF_BEGIN_ADDRESS(FunctionEntry); 02841 } 02842 else { 02843 UnwindFunctionEntry->EndAddress = RF_END_ADDRESS(FunctionEntry); 02844 } 02845 } 02846 #if !defined(NTOS_KERNEL_RUNTIME) 02847 02848 PLIST_ENTRY 02849 RtlGetFunctionTableListHead ( 02850 VOID 02851 ) 02852 02853 /*++ 02854 02855 Routine Description: 02856 02857 Return the address of the dynamic function table list head. 02858 02859 Return value: 02860 02861 Address of dynamic function table list head. 02862 02863 --*/ 02864 { 02865 return &DynamicFunctionTable; 02866 } 02867 02868 BOOLEAN 02869 RtlAddFunctionTable( 02870 IN PRUNTIME_FUNCTION FunctionTable, 02871 IN ULONG EntryCount 02872 ) 02873 02874 /*++ 02875 02876 Routine Description: 02877 02878 Add a dynamic function table to the dynamic function table list. Dynamic 02879 function tables describe code generated at run-time. The dynamic function 02880 tables are searched via a call to RtlLookupDynamicFunctionEntry(). 02881 Normally this is only invoked via calls to RtlLookupFunctionEntry(). 02882 02883 The FunctionTable entries need not be sorted in any particular order. The 02884 list is scanned for a Min and Max address range and whether or not it is 02885 sorted. If the latter RtlLookupDynamicFunctionEntry() uses a binary 02886 search, otherwise it uses a linear search. 02887 02888 The dynamic function entries will be searched only after a search 02889 through the static function entries associated with all current 02890 process images has failed. 02891 02892 Arguments: 02893 02894 FunctionTable Address of an array of function entries where 02895 each element is of type RUNTIME_FUNCTION. 02896 02897 EntryCount The number of function entries in the array 02898 02899 Return value: 02900 02901 TRUE if RtlAddFunctionTable completed successfully 02902 FALSE if RtlAddFunctionTable completed unsuccessfully 02903 02904 --*/ 02905 { 02906 PDYNAMIC_FUNCTION_TABLE pNew; 02907 PRUNTIME_FUNCTION FunctionEntry; 02908 ULONG i; 02909 02910 if (EntryCount == 0) 02911 return FALSE; 02912 02913 // 02914 // Make sure the link list is initialized; 02915 // 02916 02917 if (DynamicFunctionTable.Flink == NULL) { 02918 InitializeListHead(&DynamicFunctionTable); 02919 } 02920 02921 // 02922 // Allocate memory for this link list entry 02923 // 02924 02925 pNew = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof(DYNAMIC_FUNCTION_TABLE) ); 02926 02927 if (pNew != NULL) { 02928 pNew->FunctionTable = FunctionTable; 02929 pNew->EntryCount = EntryCount; 02930 NtQuerySystemTime( &pNew->TimeStamp ); 02931 02932 // 02933 // Scan the function table for Minimum/Maximum and to determine 02934 // if it is sorted. If the latter, we can perform a binary search. 02935 // 02936 02937 FunctionEntry = FunctionTable; 02938 pNew->MinimumAddress = RF_BEGIN_ADDRESS(FunctionEntry); 02939 pNew->MaximumAddress = RF_END_ADDRESS(FunctionEntry); 02940 pNew->Sorted = TRUE; 02941 FunctionEntry++; 02942 02943 for (i = 1; i < EntryCount; FunctionEntry++, i++) { 02944 if (pNew->Sorted && FunctionEntry->BeginAddress < FunctionTable[i-1].BeginAddress) { 02945 pNew->Sorted = FALSE; 02946 } 02947 if (FunctionEntry->BeginAddress < pNew->MinimumAddress) { 02948 pNew->MinimumAddress = RF_BEGIN_ADDRESS(FunctionEntry); 02949 } 02950 if (FunctionEntry->EndAddress > pNew->MaximumAddress) { 02951 pNew->MaximumAddress = RF_END_ADDRESS(FunctionEntry); 02952 } 02953 } 02954 02955 // 02956 // Insert the new entry in the dynamic function table list. 02957 // Protect the insertion with the loader lock. 02958 // 02959 02960 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 02961 InsertTailList((PLIST_ENTRY)&DynamicFunctionTable, (PLIST_ENTRY)pNew); 02962 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 02963 02964 return TRUE; 02965 } else { 02966 return FALSE; 02967 } 02968 } 02969 02970 BOOLEAN 02971 RtlDeleteFunctionTable ( 02972 IN PRUNTIME_FUNCTION FunctionTable 02973 ) 02974 { 02975 02976 /*++ 02977 02978 Routine Description: 02979 02980 Remove a dynamic function table from the dynamic function table list. 02981 02982 Arguments: 02983 02984 FunctionTable Address of an array of function entries that 02985 was passed in a previous call to RtlAddFunctionTable 02986 02987 Return Value 02988 02989 TRUE - If function completed successfully 02990 FALSE - If function completed unsuccessfully 02991 02992 --*/ 02993 02994 PDYNAMIC_FUNCTION_TABLE CurrentEntry; 02995 PLIST_ENTRY Head; 02996 PLIST_ENTRY Next; 02997 BOOLEAN Status = FALSE; 02998 02999 RtlEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 03000 03001 // 03002 // Search the dynamic function table list for a match on the the function 03003 // table address. 03004 // 03005 03006 Head = &DynamicFunctionTable; 03007 for (Next = Head->Blink; Next != Head; Next = Next->Blink) { 03008 CurrentEntry = CONTAINING_RECORD(Next,DYNAMIC_FUNCTION_TABLE,Links); 03009 if (CurrentEntry->FunctionTable == FunctionTable) { 03010 RemoveEntryList((PLIST_ENTRY)CurrentEntry); 03011 RtlFreeHeap( RtlProcessHeap(), 0, CurrentEntry ); 03012 Status = TRUE; 03013 break; 03014 } 03015 } 03016 03017 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 03018 return Status; 03019 } 03020 03021 PRUNTIME_FUNCTION 03022 RtlLookupDynamicFunctionEntry( 03023 IN ULONG_PTR ControlPc 03024 ) 03025 03026 /*++ 03027 03028 Routine Description: 03029 03030 This function searches through the dynamic function entry 03031 tables and returns the function entry address that corresponds 03032 to the specified ControlPc. This routine does NOT perform the 03033 secondary function entry indirection. That is performed 03034 by RtlLookupFunctionEntry(). 03035 03036 Argument: 03037 03038 ControlPc Supplies a ControlPc. 03039 03040 Return Value 03041 03042 NULL - No function entry found that contains the ControlPc. 03043 03044 NON-NULL - Address of the function entry that describes the 03045 code containing ControlPC. 03046 03047 --*/ 03048 03049 { 03050 PDYNAMIC_FUNCTION_TABLE CurrentEntry; 03051 PLIST_ENTRY Next,Head; 03052 PRUNTIME_FUNCTION FunctionTable; 03053 PRUNTIME_FUNCTION FunctionEntry; 03054 LONG High; 03055 LONG Low; 03056 LONG Middle; 03057 03058 if (DynamicFunctionTable.Flink == NULL) 03059 return NULL; 03060 03061 if (RtlTryEnterCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock) ) { 03062 03063 // 03064 // Search the tree starting from the head, continue until the entry 03065 // is found or we reach the end of the list. 03066 // 03067 03068 Head = &DynamicFunctionTable; 03069 for (Next = Head->Blink; Next != Head; Next = Next->Blink) { 03070 CurrentEntry = CONTAINING_RECORD(Next,DYNAMIC_FUNCTION_TABLE,Links); 03071 FunctionTable = CurrentEntry->FunctionTable; 03072 03073 // 03074 // Check if the ControlPC is within the range of this function table 03075 // 03076 03077 if ((ControlPc >= CurrentEntry->MinimumAddress) && 03078 (ControlPc < CurrentEntry->MaximumAddress) ) { 03079 03080 // If this function table is sorted do a binary search. 03081 03082 if (CurrentEntry->Sorted) { 03083 03084 // 03085 // Perform binary search on the function table for a function table 03086 // entry that subsumes the specified PC. 03087 // 03088 03089 Low = 0; 03090 High = CurrentEntry->EntryCount -1 ; 03091 while (High >= Low) { 03092 03093 // 03094 // Compute next probe index and test entry. If the specified PC 03095 // is greater than of equal to the beginning address and less 03096 // than the ending address of the function table entry, then 03097 // return the address of the function table entry. Otherwise, 03098 // continue the search. 03099 // 03100 03101 Middle = (Low + High) >> 1; 03102 FunctionEntry = &FunctionTable[Middle]; 03103 if (ControlPc < RF_BEGIN_ADDRESS(FunctionEntry)) { 03104 High = Middle - 1; 03105 03106 } else if (ControlPc >= RF_END_ADDRESS(FunctionEntry)) { 03107 Low = Middle + 1; 03108 03109 } else { 03110 #if DBG 03111 ShowRuntimeFunction(FunctionEntry, "RtlLookupDynamicFunctionEntry: binary search" ); 03112 #endif 03113 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 03114 return FunctionEntry; 03115 } 03116 } 03117 03118 } else { // Not sorted. Do linear search. 03119 03120 PRUNTIME_FUNCTION LastFunctionEntry = &FunctionTable[CurrentEntry->EntryCount]; 03121 03122 for (FunctionEntry = FunctionTable; FunctionEntry < LastFunctionEntry; FunctionEntry++) { 03123 if ((ControlPc >= RF_BEGIN_ADDRESS(FunctionEntry)) && 03124 (ControlPc < RF_END_ADDRESS(FunctionEntry))) { 03125 #if DBG 03126 ShowRuntimeFunction(FunctionEntry, "RtlLookupDynamicFunctionEntry: linear search" ); 03127 #endif 03128 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 03129 return FunctionEntry; 03130 } 03131 } 03132 } // binary/linear search 03133 } // if in range 03134 } // for (... Next != Head ...) 03135 03136 RtlLeaveCriticalSection((PRTL_CRITICAL_SECTION)NtCurrentPeb()->LoaderLock); 03137 } // LoaderLock 03138 03139 03140 return NULL; 03141 } 03142 #endif 03143 #if DBG 03144 03145 void 03146 ShowRuntimeFunction( PRUNTIME_FUNCTION FunctionEntry, PSTR Label ) 03147 { 03148 BOOLEAN Secondary; 03149 BOOLEAN FixedReturn; 03150 ULONG EntryType; 03151 ULONG NullCount; 03152 03153 if (!(RtlDebugFlags & RTL_DBG_FUNCTION_ENTRY_DETAIL)) { 03154 return; 03155 } 03156 03157 if (FunctionEntry) { 03158 Secondary = FALSE; 03159 FixedReturn = FALSE; 03160 EntryType = 0; 03161 NullCount = 0; 03162 03163 DbgPrint(" %lx: %s\n", FunctionEntry, Label ); 03164 03165 if ((RF_PROLOG_END_ADDRESS(FunctionEntry) < RF_BEGIN_ADDRESS(FunctionEntry)) || 03166 (RF_PROLOG_END_ADDRESS(FunctionEntry) > RF_END_ADDRESS(FunctionEntry))) { 03167 Secondary = TRUE; 03168 EntryType = RF_ENTRY_TYPE(FunctionEntry); 03169 } else if (RF_IS_FIXED_RETURN(FunctionEntry)) { 03170 FixedReturn = TRUE; 03171 } 03172 NullCount = RF_NULL_CONTEXT_COUNT(FunctionEntry); 03173 03174 DbgPrint(" BeginAddress = %lx\n", FunctionEntry->BeginAddress); 03175 DbgPrint(" EndAddress = %lx", FunctionEntry->EndAddress); 03176 if (NullCount) { 03177 DbgPrint(" %d null-context instructions", NullCount); 03178 } 03179 DbgPrint("\n"); 03180 DbgPrint(" ExceptionHandler = %lx", FunctionEntry->ExceptionHandler); 03181 if (FunctionEntry->ExceptionHandler != NULL) { 03182 if (Secondary) { 03183 ULONG_PTR AlternateProlog = RF_ALT_PROLOG(FunctionEntry); 03184 03185 switch( EntryType ) { 03186 case RF_NOT_CONTIGUOUS: 03187 case RF_ALT_ENT_PROLOG: 03188 03189 if ((AlternateProlog >= RF_BEGIN_ADDRESS(FunctionEntry)) && 03190 (AlternateProlog <= RF_END_ADDRESS(FunctionEntry))) { 03191 DbgPrint(" alternate PrologEndAddress"); 03192 } 03193 break; 03194 case RF_NULL_CONTEXT: 03195 DbgPrint(" stack adjustment"); 03196 default: 03197 DbgPrint(" invalid entry type"); 03198 } 03199 } else if (FixedReturn) { 03200 DbgPrint(" fixed return address"); 03201 } 03202 } 03203 DbgPrint("\n"); 03204 DbgPrint(" HandlerData = %lx", FunctionEntry->HandlerData); 03205 if (Secondary) { 03206 DbgPrint(" type %d: ", EntryType); 03207 if (EntryType == RF_NOT_CONTIGUOUS) DbgPrint("RF_NOT_CONTIGUOUS"); 03208 else if (EntryType == RF_ALT_ENT_PROLOG) DbgPrint("RF_ALT_ENT_PROLOG"); 03209 else if (EntryType == RF_NULL_CONTEXT) DbgPrint("RF_NULL_CONTEXT"); 03210 else DbgPrint("***INVALID***"); 03211 } 03212 DbgPrint("\n"); 03213 DbgPrint(" PrologEndAddress = %lx\n", FunctionEntry->PrologEndAddress ); 03214 } 03215 } 03216 #endif 03217

Generated on Sat May 15 19:39:57 2004 for test by doxygen 1.3.7