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     
00156     
00157     
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     
00176     
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     
00189     
00190     
00191 
00192     ExceptionFlags = 
EXCEPTION_UNWINDING;
00193     
if (ARGUMENT_PRESENT(TargetRealFrame) == 
FALSE) {
00194         ExceptionRecord->ExceptionFlags |= 
EXCEPTION_EXIT_UNWIND;
00195     }
00196 
00197     
00198     
00199     
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         
00214         
00215         
00216 
00217         FunctionEntry = 
RtlLookupFunctionEntry(ControlPc);
00218 
00219         
00220         
00221         
00222         
00223         
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             
00237             
00238             
00239             
00240             
00241             
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                 
00283                 
00284                 
00285                 
00286                 
00287                 
00288                 
00289                 
00290                 
00291                 
00292                 
00293                 
00294                 
00295                 
00296 
00297                 DispatcherContext.ControlPc = ControlPc;
00298                 DispatcherContext.FunctionEntry = FunctionEntry;
00299                 DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual;
00300                 DispatcherContext.ContextRecord = &ContextRecord2;
00301 
00302                 
00303                 
00304                 
00305 
00306                 
do {
00307 
00308                     
00309                     
00310                     
00311                     
00312 
00313                     
if ((ULONG_PTR)TargetRealFrame == EstablisherFrame.Real) {
00314                         ExceptionFlags |= 
EXCEPTION_TARGET_UNWIND;
00315                     }
00316 
00317                     ExceptionRecord->ExceptionFlags = ExceptionFlags;
00318 
00319                     
00320                     
00321                     
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                     
00347                     
00348 
00349                     ExceptionFlags &= ~(
EXCEPTION_COLLIDED_UNWIND |
00350                                         
EXCEPTION_TARGET_UNWIND);
00351 
00352                     
00353                     
00354                     
00355 
00356                     
switch (Disposition) {
00357 
00358                         
00359                         
00360                         
00361                         
00362                         
00363                         
00364 
00365                     
case ExceptionContinueSearch :
00366                         
break;
00367 
00368                         
00369                         
00370                         
00371                         
00372                         
00373                         
00374                         
00375                         
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                         
00401                         
00402                         
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             
00416             
00417 
00418             LastPc = (ULONG_PTR)ContextRecord1.IntRa - 4;
00419 
00420             
00421             
00422             
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         
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     
00462     
00463     
00464     
00465     
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 }