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

unwindr.c File Reference

#include "ntrtlp.h"

Go to the source code of this file.

Defines

#define RAISE_EXCEPTION(Status, ExceptionRecordt)
#define IS_HANDLER_DEFINED(FunctionEntry)   (RF_EXCEPTION_HANDLER(FunctionEntry) != 0)
#define Virtual   VirtualFramePointer
#define Real   RealFramePointer

Functions

VOID RtlUnwindRfp (IN PVOID TargetRealFrame OPTIONAL, IN PVOID TargetIp OPTIONAL, IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, IN PVOID ReturnValue)
VOID RtlUnwindReturn (IN PVOID TargetFrame, IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL, IN PVOID ReturnValue)


Define Documentation

#define IS_HANDLER_DEFINED FunctionEntry   )     (RF_EXCEPTION_HANDLER(FunctionEntry) != 0)
 

Definition at line 52 of file unwindr.c.

#define RAISE_EXCEPTION Status,
ExceptionRecordt   ) 
 

Value:

{ \ EXCEPTION_RECORD ExceptionRecordn; \ \ ExceptionRecordn.ExceptionCode = Status; \ ExceptionRecordn.ExceptionFlags = EXCEPTION_NONCONTINUABLE; \ ExceptionRecordn.ExceptionRecord = ExceptionRecordt; \ ExceptionRecordn.NumberParameters = 0; \ RtlRaiseException(&ExceptionRecordn); \ }

Definition at line 38 of file unwindr.c.

#define Real   RealFramePointer
 

Definition at line 73 of file unwindr.c.

#define Virtual   VirtualFramePointer
 

Definition at line 72 of file unwindr.c.


Function Documentation

VOID RtlUnwindReturn IN PVOID  TargetFrame,
IN PEXCEPTION_RECORD ExceptionRecord  OPTIONAL,
IN PVOID  ReturnValue
 

Definition at line 492 of file unwindr.c.

References Count, DbgPrint, EXCEPTION_COLLIDED_UNWIND, EXCEPTION_TARGET_UNWIND, EXCEPTION_UNWINDING, ExceptionCollidedUnwind, ExceptionContinueSearch, FALSE, IS_HANDLER_DEFINED, NULL, RAISE_EXCEPTION, RtlLookupFunctionEntry(), RtlpExecuteHandlerForUnwind(), RtlpGetStackLimits(), RtlpRestoreContext(), RtlRaiseStatus(), and RtlVirtualUnwind().

00500 : 00501 00502 This function initiates an unwind of procedure call frames. The machine 00503 state at the time of the call to unwind is captured in a context record 00504 and the unwinding flag is set in the exception flags of the exception 00505 record. A backward scan through the procedure call frames is then 00506 performed to find the target of the unwind operation. When the target 00507 frame is reached, a return is made to the caller of the target frame 00508 with the return value specified by the return value parameter. 00509 00510 As each frame is encountered, the PC where control left the corresponding 00511 function is determined and used to lookup exception handler information 00512 in the runtime function table built by the linker. If the respective 00513 routine has an exception handler, then the handler is called. 00514 00515 This function is identical to RtlUnwind except control resumes in the 00516 caller of the target frame, not in the target frame itself. 00517 00518 Arguments: 00519 00520 TargetFrame - Supplies an optional pointer to the call frame that is the 00521 target of the unwind. 00522 00523 ExceptionRecord - Supplies an optional pointer to an exception record. 00524 00525 ReturnValue - Supplies a value that is to be placed in the integer 00526 function return register just before continuing execution. 00527 00528 Return Value: 00529 00530 None. 00531 00532 --*/ 00533 00534 { 00535 00536 CONTEXT ContextRecord1; 00537 CONTEXT ContextRecord2; 00538 ULONG_PTR ControlPc; 00539 #if DBG 00540 ULONG_PTR ControlPcHistory[PC_HISTORY_DEPTH]; 00541 ULONG ControlPcHistoryIndex = 0; 00542 #endif 00543 DISPATCHER_CONTEXT DispatcherContext; 00544 EXCEPTION_DISPOSITION Disposition; 00545 FRAME_POINTERS EstablisherFrame; 00546 ULONG ExceptionFlags; 00547 EXCEPTION_RECORD ExceptionRecord1; 00548 #if DBG 00549 LONG FrameDepth = 0; 00550 #endif 00551 PRUNTIME_FUNCTION FunctionEntry; 00552 ULONG_PTR HighLimit; 00553 BOOLEAN InFunction; 00554 ULONG_PTR LastPc; 00555 ULONG_PTR LowLimit; 00556 00557 #if DBG 00558 if (RtlDebugFlags & RTL_DBG_UNWIND) { 00559 DbgPrint("\nRtlUnwindReturn(TargetFrame = %p,, ReturnValue = %lx)\n", 00560 TargetFrame, ReturnValue); 00561 } 00562 #endif 00563 00564 // 00565 // Get current stack limits, capture the current context, virtually 00566 // unwind to the caller of this routine, get the initial PC value, and 00567 // set the unwind target address. 00568 // 00569 00570 RtlpGetStackLimits(&LowLimit, &HighLimit); 00571 RtlCaptureContext(&ContextRecord1); 00572 ControlPc = (ULONG_PTR)ContextRecord1.IntRa; 00573 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00574 LastPc = RtlVirtualUnwind(ControlPc, 00575 FunctionEntry, 00576 &ContextRecord1, 00577 &InFunction, 00578 &EstablisherFrame, 00579 NULL); 00580 00581 ControlPc = LastPc; 00582 ContextRecord1.Fir = 0; 00583 00584 // 00585 // If an exception record is not specified, then build a local exception 00586 // record for use in calling exception handlers during the unwind operation. 00587 // 00588 00589 if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) { 00590 ExceptionRecord = &ExceptionRecord1; 00591 ExceptionRecord1.ExceptionCode = STATUS_UNWIND; 00592 ExceptionRecord1.ExceptionRecord = NULL; 00593 ExceptionRecord1.ExceptionAddress = (PVOID)ControlPc; 00594 ExceptionRecord1.NumberParameters = 0; 00595 } 00596 00597 // 00598 // A target frame of the unwind is specified so a normal unwind is 00599 // being performed. 00600 // 00601 00602 ExceptionFlags = EXCEPTION_UNWINDING; 00603 00604 // 00605 // Scan backward through the call frame hierarchy and call exception 00606 // handlers until the target frame of the unwind is reached. 00607 // 00608 00609 do { 00610 00611 #if DBG 00612 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 00613 DbgPrint("RtlUnwindReturn: Loop: FrameDepth = %d, sp = %p, ControlPc = %p\n", 00614 FrameDepth, (ULONG_PTR)ContextRecord1.IntSp, ControlPc); 00615 FrameDepth -= 1; 00616 } 00617 #endif 00618 00619 // 00620 // Lookup the function table entry using the point at which control 00621 // left the procedure. 00622 // 00623 00624 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00625 00626 // 00627 // If there is a function table entry for the routine, then copy the 00628 // context record, virtually unwind to the caller of the current 00629 // routine to obtain the virtual frame pointer of the establisher and 00630 // check if there is an exception handler for the frame. 00631 // 00632 00633 if (FunctionEntry != NULL) { 00634 RtlMoveMemory(&ContextRecord2, &ContextRecord1, sizeof(CONTEXT)); 00635 LastPc = RtlVirtualUnwind(ControlPc, 00636 FunctionEntry, 00637 &ContextRecord1, 00638 &InFunction, 00639 &EstablisherFrame, 00640 NULL); 00641 00642 // 00643 // If the virtual frame pointer is not within the specified stack 00644 // limits, the virtual frame pointer is unaligned, or the target 00645 // frame is below the virtual frame and an exit unwind is not being 00646 // performed, then raise the exception STATUS_BAD_STACK. Otherwise, 00647 // check to determine if the current routine has an exception 00648 // handler. 00649 // 00650 00651 if ((EstablisherFrame.Virtual < LowLimit) || 00652 (EstablisherFrame.Virtual > HighLimit) || 00653 ((ULONG_PTR)TargetFrame < EstablisherFrame.Virtual) || 00654 ((EstablisherFrame.Virtual & 0xF) != 0)) { 00655 00656 #if DBG 00657 DbgPrint("\n****** Warning - bad stack or target frame (unwind).\n"); 00658 DbgPrint(" EstablisherFrame Virtual = %p, Real = %p\n", 00659 EstablisherFrame.Virtual, EstablisherFrame.Real); 00660 DbgPrint(" TargetFrame = %p\n", TargetFrame); 00661 if ((ARGUMENT_PRESENT(TargetFrame) != FALSE) && 00662 ((ULONG_PTR)TargetFrame < EstablisherFrame.Virtual)) { 00663 DbgPrint(" TargetFrame is below EstablisherFrame!\n"); 00664 } 00665 DbgPrint(" Previous EstablisherFrame (sp) = %p\n", 00666 (ULONG_PTR)ContextRecord2.IntSp); 00667 DbgPrint(" LowLimit = %p, HighLimit = %p\n", 00668 LowLimit, HighLimit); 00669 DbgPrint(" LastPc = %p, ControlPc = %p\n", 00670 LastPc, ControlPc); 00671 DbgPrint(" Now raising STATUS_BAD_STACK exception.\n"); 00672 #endif 00673 00674 RAISE_EXCEPTION(STATUS_BAD_STACK, ExceptionRecord); 00675 00676 } else if (IS_HANDLER_DEFINED(FunctionEntry) && InFunction) { 00677 00678 #if DBG 00679 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { 00680 DbgPrint("RtlUnwindReturn: ExceptionHandler = %p, HandlerData = %p\n", 00681 FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData); 00682 } 00683 #endif 00684 00685 // 00686 // The frame has an exception handler. 00687 // 00688 // The control PC, establisher frame pointer, the address 00689 // of the function table entry, and the address of the 00690 // context record are all stored in the dispatcher context. 00691 // This information is used by the unwind linkage routine 00692 // and can be used by the exception handler itself. 00693 // 00694 // A linkage routine written in assembler is used to actually 00695 // call the actual exception handler. This is required by the 00696 // exception handler that is associated with the linkage 00697 // routine so it can have access to two sets of dispatcher 00698 // context when it is called. 00699 // 00700 00701 DispatcherContext.ControlPc = ControlPc; 00702 DispatcherContext.FunctionEntry = FunctionEntry; 00703 DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual; 00704 DispatcherContext.ContextRecord = &ContextRecord2; 00705 00706 // 00707 // Call the exception handler. 00708 // 00709 00710 do { 00711 00712 // 00713 // If the establisher frame is the target of the unwind 00714 // operation, then set the target unwind flag. 00715 // 00716 00717 if ((ULONG_PTR)TargetFrame == EstablisherFrame.Virtual) { 00718 ExceptionFlags |= EXCEPTION_TARGET_UNWIND; 00719 } 00720 00721 ExceptionRecord->ExceptionFlags = ExceptionFlags; 00722 00723 // 00724 // Set the specified return value in case the exception 00725 // handler directly continues execution. 00726 // 00727 00728 ContextRecord2.IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue; 00729 00730 #if DBG 00731 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 00732 DbgPrint("RtlUnwindReturn: calling RtlpExecuteHandlerForUnwind, ControlPc = %p\n", ControlPc); 00733 } 00734 #endif 00735 00736 Disposition = 00737 RtlpExecuteHandlerForUnwind(ExceptionRecord, 00738 EstablisherFrame.Virtual, 00739 &ContextRecord2, 00740 &DispatcherContext, 00741 RF_EXCEPTION_HANDLER(FunctionEntry)); 00742 00743 #if DBG 00744 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 00745 DbgPrint("RtlUnwindReturn: RtlpExecuteHandlerForUnwind returned Disposition = %lx\n", Disposition); 00746 } 00747 #endif 00748 00749 // 00750 // Clear target unwind and collided unwind flags. 00751 // 00752 00753 ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND | 00754 EXCEPTION_TARGET_UNWIND); 00755 00756 // 00757 // Case on the handler disposition. 00758 // 00759 00760 switch (Disposition) { 00761 00762 // 00763 // The disposition is to continue the search. 00764 // 00765 // Continue the search for a handler or continue 00766 // execution. 00767 // 00768 00769 case ExceptionContinueSearch : 00770 break; 00771 00772 // 00773 // The disposition is collided unwind. 00774 // 00775 // Set the target of the current unwind to the context 00776 // record of the previous unwind, virtually unwind to 00777 // the caller of the old routine, and reexecute the 00778 // exception handler from the collided frame with the 00779 // collided unwind flag set in the exception record. 00780 // 00781 00782 case ExceptionCollidedUnwind : 00783 ControlPc = DispatcherContext.ControlPc; 00784 FunctionEntry = DispatcherContext.FunctionEntry; 00785 RtlMoveMemory(&ContextRecord1, 00786 DispatcherContext.ContextRecord, 00787 sizeof(CONTEXT)); 00788 00789 ContextRecord1.Fir = 0; 00790 RtlMoveMemory(&ContextRecord2, 00791 &ContextRecord1, 00792 sizeof(CONTEXT)); 00793 00794 ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND; 00795 LastPc = RtlVirtualUnwind(ControlPc, 00796 FunctionEntry, 00797 &ContextRecord1, 00798 &InFunction, 00799 &EstablisherFrame, 00800 NULL); 00801 break; 00802 00803 // 00804 // All other disposition values are invalid. 00805 // 00806 // Raise invalid disposition exception. 00807 // 00808 00809 default : 00810 RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord); 00811 } 00812 00813 } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0); 00814 } 00815 00816 } else { 00817 00818 // 00819 // Set point at which control left the previous routine. 00820 // 00821 00822 LastPc = (ULONG_PTR)ContextRecord1.IntRa - 4; 00823 00824 // 00825 // If the next control PC is the same as the old control PC, then 00826 // the function table is not correctly formed. 00827 // 00828 00829 if (LastPc == ControlPc) { 00830 #if DBG 00831 ULONG Count; 00832 DbgPrint("\n****** Warning - malformed function table (unwind).\n"); 00833 DbgPrint("ControlPc = %p, %p", LastPc, ControlPc); 00834 for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) { 00835 if (ControlPcHistoryIndex > 0) { 00836 ControlPcHistoryIndex -= 1; 00837 ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH]; 00838 DbgPrint(", %p", ControlPc); 00839 } 00840 } 00841 DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n"); 00842 DbgPrint(" Now raising STATUS_BAD_FUNCTION_TABLE exception.\n"); 00843 #endif 00844 00845 RtlRaiseStatus(STATUS_BAD_FUNCTION_TABLE); 00846 } 00847 } 00848 00849 // 00850 // Set point at which control left the previous routine. 00851 // 00852 00853 #if DBG 00854 ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc; 00855 ControlPcHistoryIndex += 1; 00856 #endif 00857 00858 ControlPc = LastPc; 00859 00860 } while ((EstablisherFrame.Virtual < HighLimit) && 00861 (EstablisherFrame.Virtual != (ULONG_PTR)TargetFrame)); 00862 00863 // 00864 // If the establisher stack pointer is equal to the target frame pointer, 00865 // then continue execution at the point where the call to the target frame 00866 // was made. Otherwise the target of the unwind did not exist and the 00867 // debugger and subsystem are given a second chance to handle the unwind. 00868 // 00869 00870 if ((ULONG_PTR)ContextRecord1.IntSp == (ULONG_PTR)TargetFrame) { 00871 ContextRecord1.IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue; 00872 00873 // 00874 // Set the continuation address to the address after the point where 00875 // control left the previous frame and entered the target frame. 00876 // 00877 00878 ContextRecord1.Fir = (ULONGLONG)(LONG_PTR)LastPc + 4; 00879 00880 #if DBG 00881 if (RtlDebugFlags & RTL_DBG_UNWIND) { 00882 DbgPrint("RtlUnwindReturn: finished unwinding, and calling RtlpRestoreContext\n"); 00883 } 00884 #endif 00885 00886 RtlpRestoreContext(&ContextRecord1); 00887 00888 } else { 00889 00890 #if DBG 00891 if (RtlDebugFlags & RTL_DBG_UNWIND) { 00892 DbgPrint("RtlUnwindReturn: finished unwinding, but calling ZwRaiseException\n"); 00893 } 00894 #endif 00895 00896 ZwRaiseException(ExceptionRecord, &ContextRecord1, FALSE); 00897 } 00898 } }

VOID RtlUnwindRfp IN PVOID TargetRealFrame  OPTIONAL,
IN PVOID TargetIp  OPTIONAL,
IN PEXCEPTION_RECORD ExceptionRecord  OPTIONAL,
IN PVOID  ReturnValue
 

Definition at line 76 of file unwindr.c.

References Count, DbgPrint, DISPATCHER_CONTEXT, EXCEPTION_COLLIDED_UNWIND, EXCEPTION_EXIT_UNWIND, EXCEPTION_TARGET_UNWIND, EXCEPTION_UNWINDING, ExceptionCollidedUnwind, ExceptionContinueSearch, FALSE, IS_HANDLER_DEFINED, NULL, RAISE_EXCEPTION, RtlLookupFunctionEntry(), RtlpExecuteHandlerForUnwind(), RtlpGetStackLimits(), RtlpRestoreContext(), RtlRaiseStatus(), and RtlVirtualUnwind().

00085 : 00086 00087 This function initiates an unwind of procedure call frames. The machine 00088 state at the time of the call to unwind is captured in a context record 00089 and the unwinding flag is set in the exception flags of the exception 00090 record. If the TargetRealFrame parameter is not specified, then the exit 00091 unwind flag is also set in the exception flags of the exception record. 00092 A backward scan through the procedure call frames is then performed to 00093 find the target of the unwind operation. 00094 00095 As each frame is encountered, the PC where control left the corresponding 00096 function is determined and used to lookup exception handler information 00097 in the runtime function table built by the linker. If the respective 00098 routine has an exception handler, then the handler is called. 00099 00100 This function is identical to RtlUnwind except that the TargetRealFrame 00101 parameter is the real frame pointer instead of the virtual frame pointer. 00102 00103 Arguments: 00104 00105 TargetRealFrame - Supplies an optional pointer to the call frame that is 00106 the target of the unwind. If this parameter is not specified, then an 00107 exit unwind is performed. 00108 00109 TargetIp - Supplies an optional instruction address that specifies the 00110 continuation address of the unwind. This address is ignored if the 00111 target frame parameter is not specified. 00112 00113 ExceptionRecord - Supplies an optional pointer to an exception record. 00114 00115 ReturnValue - Supplies a value that is to be placed in the integer 00116 function return register just before continuing execution. 00117 00118 Return Value: 00119 00120 None. 00121 00122 --*/ 00123 00124 { 00125 00126 CONTEXT ContextRecord1; 00127 CONTEXT ContextRecord2; 00128 ULONG_PTR ControlPc; 00129 #if DBG 00130 ULONG_PTR ControlPcHistory[PC_HISTORY_DEPTH]; 00131 ULONG ControlPcHistoryIndex = 0; 00132 #endif 00133 DISPATCHER_CONTEXT DispatcherContext; 00134 EXCEPTION_DISPOSITION Disposition; 00135 FRAME_POINTERS EstablisherFrame; 00136 ULONG ExceptionFlags; 00137 EXCEPTION_RECORD ExceptionRecord1; 00138 #if DBG 00139 LONG FrameDepth = 0; 00140 #endif 00141 PRUNTIME_FUNCTION FunctionEntry; 00142 ULONG_PTR HighLimit; 00143 BOOLEAN InFunction; 00144 ULONG_PTR LastPc; 00145 ULONG_PTR LowLimit; 00146 00147 #if DBG 00148 if (RtlDebugFlags & RTL_DBG_UNWIND) { 00149 DbgPrint("\nRtlUnwindRfp(TargetRealFrame = %p, TargetIp = %p,, ReturnValue = %lx)\n", 00150 TargetRealFrame, TargetIp, ReturnValue); 00151 } 00152 #endif 00153 00154 // 00155 // Get current stack limits, capture the current context, virtually 00156 // unwind to the caller of this routine, get the initial PC value, and 00157 // set the unwind target address. 00158 // 00159 00160 RtlpGetStackLimits(&LowLimit, &HighLimit); 00161 RtlCaptureContext(&ContextRecord1); 00162 ControlPc = (ULONG_PTR)ContextRecord1.IntRa; 00163 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00164 LastPc = RtlVirtualUnwind(ControlPc, 00165 FunctionEntry, 00166 &ContextRecord1, 00167 &InFunction, 00168 &EstablisherFrame, 00169 NULL); 00170 00171 ControlPc = LastPc; 00172 ContextRecord1.Fir = (ULONGLONG)(LONG_PTR)TargetIp; 00173 00174 // 00175 // If an exception record is not specified, then build a local exception 00176 // record for use in calling exception handlers during the unwind operation. 00177 // 00178 00179 if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) { 00180 ExceptionRecord = &ExceptionRecord1; 00181 ExceptionRecord1.ExceptionCode = STATUS_UNWIND; 00182 ExceptionRecord1.ExceptionRecord = NULL; 00183 ExceptionRecord1.ExceptionAddress = (PVOID)ControlPc; 00184 ExceptionRecord1.NumberParameters = 0; 00185 } 00186 00187 // 00188 // If the target frame of the unwind is specified, then a normal unwind 00189 // is being performed. Otherwise, an exit unwind is being performed. 00190 // 00191 00192 ExceptionFlags = EXCEPTION_UNWINDING; 00193 if (ARGUMENT_PRESENT(TargetRealFrame) == FALSE) { 00194 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND; 00195 } 00196 00197 // 00198 // Scan backward through the call frame hierarchy and call exception 00199 // handlers until the target frame of the unwind is reached. 00200 // 00201 00202 do { 00203 00204 #if DBG 00205 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 00206 DbgPrint("RtlUnwindRfp: Loop: FrameDepth = %d, Rfp = %p, sp = %p, ControlPc = %p\n", 00207 FrameDepth, EstablisherFrame.Real, (ULONG_PTR)ContextRecord1.IntSp, ControlPc); 00208 FrameDepth -= 1; 00209 } 00210 #endif 00211 00212 // 00213 // Lookup the function table entry using the point at which control 00214 // left the procedure. 00215 // 00216 00217 FunctionEntry = RtlLookupFunctionEntry(ControlPc); 00218 00219 // 00220 // If there is a function table entry for the routine, then copy the 00221 // context record, virtually unwind to the caller of the current 00222 // routine to obtain the real frame pointer of the establisher and 00223 // check if there is an exception handler for the frame. 00224 // 00225 00226 if (FunctionEntry != NULL) { 00227 RtlMoveMemory(&ContextRecord2, &ContextRecord1, sizeof(CONTEXT)); 00228 LastPc = RtlVirtualUnwind(ControlPc, 00229 FunctionEntry, 00230 &ContextRecord1, 00231 &InFunction, 00232 &EstablisherFrame, 00233 NULL); 00234 00235 // 00236 // If the real and virtual frame pointers are not within the 00237 // specified stack limits, the frame pointers are unaligned, or 00238 // the target frame is below the real frame and an exit unwind is 00239 // not being performed, then raise the exception STATUS_BAD_STACK. 00240 // Otherwise, check to determine if the current routine has an 00241 // exception handler. 00242 // 00243 00244 if ((EstablisherFrame.Real < LowLimit) || 00245 (EstablisherFrame.Virtual > HighLimit) || 00246 (EstablisherFrame.Real > EstablisherFrame.Virtual) || 00247 ((ARGUMENT_PRESENT(TargetRealFrame) != FALSE) && 00248 ((ULONG_PTR)TargetRealFrame < EstablisherFrame.Real)) || 00249 ((EstablisherFrame.Virtual & 0xF) != 0) || 00250 ((EstablisherFrame.Real & 0xF) != 0)) { 00251 00252 #if DBG 00253 DbgPrint("\n****** Warning - bad stack or target frame (unwind).\n"); 00254 DbgPrint(" EstablisherFrame Virtual = %p, Real = %p\n", 00255 EstablisherFrame.Virtual, EstablisherFrame.Real); 00256 DbgPrint(" TargetRealFrame = %p\n", TargetRealFrame); 00257 if ((ARGUMENT_PRESENT(TargetRealFrame) != FALSE) && 00258 ((ULONG_PTR)TargetRealFrame < EstablisherFrame.Real)) { 00259 DbgPrint(" TargetRealFrame is below EstablisherFrame.Real!\n"); 00260 } 00261 DbgPrint(" Previous EstablisherFrame (sp) = %p\n", 00262 (ULONG_PTR)ContextRecord2.IntSp); 00263 DbgPrint(" LowLimit = %p, HighLimit = %p\n", 00264 LowLimit, HighLimit); 00265 DbgPrint(" LastPc = %p, ControlPc = %p\n", 00266 LastPc, ControlPc); 00267 DbgPrint(" Now raising STATUS_BAD_STACK exception.\n"); 00268 #endif 00269 00270 RAISE_EXCEPTION(STATUS_BAD_STACK, ExceptionRecord); 00271 00272 } else if (IS_HANDLER_DEFINED(FunctionEntry) && InFunction) { 00273 00274 #if DBG 00275 if (RtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) { 00276 DbgPrint("RtlUnwindRfp: ExceptionHandler = %p, HandlerData = %p\n", 00277 FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData); 00278 } 00279 #endif 00280 00281 // 00282 // The frame has an exception handler. 00283 // 00284 // The control PC, establisher frame pointer, the address 00285 // of the function table entry, and the address of the 00286 // context record are all stored in the dispatcher context. 00287 // This information is used by the unwind linkage routine 00288 // and can be used by the exception handler itself. 00289 // 00290 // A linkage routine written in assembler is used to actually 00291 // call the actual exception handler. This is required by the 00292 // exception handler that is associated with the linkage 00293 // routine so it can have access to two sets of dispatcher 00294 // context when it is called. 00295 // 00296 00297 DispatcherContext.ControlPc = ControlPc; 00298 DispatcherContext.FunctionEntry = FunctionEntry; 00299 DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual; 00300 DispatcherContext.ContextRecord = &ContextRecord2; 00301 00302 // 00303 // Call the exception handler. 00304 // 00305 00306 do { 00307 00308 // 00309 // If the establisher frame is the target of the unwind 00310 // operation, then set the target unwind flag. 00311 // 00312 00313 if ((ULONG_PTR)TargetRealFrame == EstablisherFrame.Real) { 00314 ExceptionFlags |= EXCEPTION_TARGET_UNWIND; 00315 } 00316 00317 ExceptionRecord->ExceptionFlags = ExceptionFlags; 00318 00319 // 00320 // Set the specified return value in case the exception 00321 // handler directly continues execution. 00322 // 00323 00324 ContextRecord2.IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue; 00325 00326 #if DBG 00327 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 00328 DbgPrint("RtlUnwindRfp: calling RtlpExecuteHandlerForUnwind, ControlPc = %p\n", ControlPc); 00329 } 00330 #endif 00331 00332 Disposition = 00333 RtlpExecuteHandlerForUnwind(ExceptionRecord, 00334 EstablisherFrame.Virtual, 00335 &ContextRecord2, 00336 &DispatcherContext, 00337 RF_EXCEPTION_HANDLER(FunctionEntry)); 00338 00339 #if DBG 00340 if (RtlDebugFlags & RTL_DBG_UNWIND_DETAIL) { 00341 DbgPrint("RtlUnwindRfp: RtlpExecuteHandlerForUnwind returned Disposition = %lx\n", Disposition); 00342 } 00343 #endif 00344 00345 // 00346 // Clear target unwind and collided unwind flags. 00347 // 00348 00349 ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND | 00350 EXCEPTION_TARGET_UNWIND); 00351 00352 // 00353 // Case on the handler disposition. 00354 // 00355 00356 switch (Disposition) { 00357 00358 // 00359 // The disposition is to continue the search. 00360 // 00361 // Continue the search for a handler or continue 00362 // execution. 00363 // 00364 00365 case ExceptionContinueSearch : 00366 break; 00367 00368 // 00369 // The disposition is collided unwind. 00370 // 00371 // Set the target of the current unwind to the context 00372 // record of the previous unwind, virtually unwind to 00373 // the caller of the old routine, and reexecute the 00374 // exception handler from the collided frame with the 00375 // collided unwind flag set in the exception record. 00376 // 00377 00378 case ExceptionCollidedUnwind : 00379 ControlPc = DispatcherContext.ControlPc; 00380 FunctionEntry = DispatcherContext.FunctionEntry; 00381 RtlMoveMemory(&ContextRecord1, 00382 DispatcherContext.ContextRecord, 00383 sizeof(CONTEXT)); 00384 00385 ContextRecord1.Fir = (ULONGLONG)(LONG_PTR)TargetIp; 00386 RtlMoveMemory(&ContextRecord2, 00387 &ContextRecord1, 00388 sizeof(CONTEXT)); 00389 00390 ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND; 00391 LastPc = RtlVirtualUnwind(ControlPc, 00392 FunctionEntry, 00393 &ContextRecord1, 00394 &InFunction, 00395 &EstablisherFrame, 00396 NULL); 00397 break; 00398 00399 // 00400 // All other disposition values are invalid. 00401 // 00402 // Raise invalid disposition exception. 00403 // 00404 00405 default : 00406 RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord); 00407 } 00408 00409 } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0); 00410 } 00411 00412 } else { 00413 00414 // 00415 // Set point at which control left the previous routine. 00416 // 00417 00418 LastPc = (ULONG_PTR)ContextRecord1.IntRa - 4; 00419 00420 // 00421 // If the next control PC is the same as the old control PC, then 00422 // the function table is not correctly formed. 00423 // 00424 00425 if (LastPc == ControlPc) { 00426 00427 #if DBG 00428 ULONG Count; 00429 DbgPrint("\n****** Warning - malformed function table (unwind).\n"); 00430 DbgPrint("ControlPc = %p, %p", LastPc, ControlPc); 00431 for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) { 00432 if (ControlPcHistoryIndex > 0) { 00433 ControlPcHistoryIndex -= 1; 00434 ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH]; 00435 DbgPrint(", %p", ControlPc); 00436 } 00437 } 00438 DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n"); 00439 DbgPrint(" Now raising STATUS_BAD_FUNCTION_TABLE exception.\n"); 00440 #endif 00441 00442 RtlRaiseStatus(STATUS_BAD_FUNCTION_TABLE); 00443 } 00444 } 00445 00446 // 00447 // Set point at which control left the previous routine. 00448 // 00449 00450 #if DBG 00451 ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc; 00452 ControlPcHistoryIndex += 1; 00453 #endif 00454 00455 ControlPc = LastPc; 00456 00457 } while ((EstablisherFrame.Real < HighLimit) && 00458 (EstablisherFrame.Real != (ULONG_PTR)TargetRealFrame)); 00459 00460 // 00461 // If the establisher stack pointer is equal to the target frame 00462 // pointer, then continue execution. Otherwise, an exit unwind was 00463 // performed or the target of the unwind did not exist and the 00464 // debugger and subsystem are given a second chance to handle the 00465 // unwind. 00466 // 00467 00468 if (EstablisherFrame.Real == (ULONG_PTR)TargetRealFrame) { 00469 ContextRecord2.IntV0 = (ULONGLONG)(LONG_PTR)ReturnValue; 00470 00471 #if DBG 00472 if (RtlDebugFlags & RTL_DBG_UNWIND) { 00473 DbgPrint("RtlUnwindRfp: finished unwinding, and calling RtlpRestoreContext\n"); 00474 } 00475 #endif 00476 00477 RtlpRestoreContext(&ContextRecord2); 00478 00479 } else { 00480 00481 #if DBG 00482 if (RtlDebugFlags & RTL_DBG_UNWIND) { 00483 DbgPrint("RtlUnwindRfp: finished unwinding, but calling ZwRaiseException\n"); 00484 } 00485 #endif 00486 00487 ZwRaiseException(ExceptionRecord, &ContextRecord1, FALSE); 00488 } 00489 }


Generated on Sat May 15 19:45:52 2004 for test by doxygen 1.3.7