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 }