00312 :
00313
00314 This function initiates an unwind of
procedure call frames. The machine
00315 state at
the time of
the call to unwind
is captured in a context record
00316 and
the unwinding flag
is set in
the exception flags of
the exception
00317 record. If
the TargetFrame parameter
is not specified, then
the exit unwind
00318 flag
is also set in
the exception flags of
the exception record.
A backward
00319 walk through
the procedure call frames
is then performed to find
the target
00320 of
the unwind operation.
00321
00322 N.B. The captured context passed to unwinding handlers will not be
00323 a completely accurate context set
for the 386. This
is because
00324 there isn'
t a standard stack frame in which registers are stored.
00325
00326 Only
the integer registers are affected. The segement and
00327
control registers (ebp, esp) will have correct values for
00328 the flat 32 bit environment.
00329
00330 N.B. If you change the number of arguments, make sure you change the
00331 adjustment of ESP after the call to RtlpCaptureContext (for
00332 STDCALL calling convention)
00333
00334 Arguments:
00335
00336 TargetFrame - Supplies an optional pointer to the call frame that is the
00337 target of the unwind. If this parameter is not specified, then an exit
00338 unwind is performed.
00339
00340 TargetIp - Supplies an optional instruction address that specifies the
00341 continuation address of the unwind. This address is ignored if the
00342 target frame parameter is not specified.
00343
00344 ExceptionRecord - Supplies an optional pointer to an exception record.
00345
00346 ReturnValue - Supplies a value that is to be placed in the integer
00347 function return register just before continuing execution.
00348
00349 Return Value:
00350
00351 None.
00352
00353 --*/
00354
00355 {
00356 PCONTEXT ContextRecord;
00357 CONTEXT ContextRecord1;
00358
DISPATCHER_CONTEXT DispatcherContext;
00359 EXCEPTION_DISPOSITION Disposition;
00360 PEXCEPTION_REGISTRATION_RECORD RegistrationPointer;
00361 PEXCEPTION_REGISTRATION_RECORD PriorPointer;
00362 ULONG HighAddress;
00363 ULONG HighLimit;
00364 ULONG LowLimit;
00365 EXCEPTION_RECORD ExceptionRecord1;
00366 EXCEPTION_RECORD ExceptionRecord2;
00367
00368
00369
00370
00371
00372
RtlpGetStackLimits(&LowLimit, &HighLimit);
00373
00374
00375
00376
00377
00378
00379
if (ARGUMENT_PRESENT(ExceptionRecord) ==
FALSE) {
00380 ExceptionRecord = &ExceptionRecord1;
00381 ExceptionRecord1.ExceptionCode = STATUS_UNWIND;
00382 ExceptionRecord1.ExceptionFlags = 0;
00383 ExceptionRecord1.ExceptionRecord =
NULL;
00384 ExceptionRecord1.ExceptionAddress =
RtlpGetReturnAddress();
00385 ExceptionRecord1.NumberParameters = 0;
00386 }
00387
00388
00389
00390
00391
00392
00393
00394
if (ARGUMENT_PRESENT(TargetFrame) ==
TRUE) {
00395 ExceptionRecord->ExceptionFlags |=
EXCEPTION_UNWINDING;
00396 }
else {
00397 ExceptionRecord->ExceptionFlags |= (
EXCEPTION_UNWINDING |
00398
EXCEPTION_EXIT_UNWIND);
00399 }
00400
00401
00402
00403
00404
00405 ContextRecord = &ContextRecord1;
00406 ContextRecord1.ContextFlags =
CONTEXT_INTEGER |
CONTEXT_CONTROL | CONTEXT_SEGMENTS;
00407
RtlpCaptureContext(ContextRecord);
00408
00409
#ifdef STD_CALL
00410
00411
00412
00413 ContextRecord->Esp +=
sizeof(TargetFrame) +
00414
sizeof(TargetIp) +
00415
sizeof(ExceptionRecord) +
00416
sizeof(ReturnValue);
00417
#endif
00418
ContextRecord->Eax = (ULONG)ReturnValue;
00419
00420
00421
00422
00423
00424
00425
00426 RegistrationPointer =
RtlpGetRegistrationHead();
00427
while (RegistrationPointer != EXCEPTION_CHAIN_END) {
00428
00429
00430
00431
00432
00433
00434
if ((ULONG)RegistrationPointer == (ULONG)TargetFrame) {
00435 ZwContinue(ContextRecord, FALSE);
00436
00437
00438
00439
00440
00441
00442 }
else if ( (ARGUMENT_PRESENT(TargetFrame) ==
TRUE) &&
00443 ((ULONG)TargetFrame < (ULONG)RegistrationPointer) ) {
00444 ExceptionRecord2.ExceptionCode = STATUS_INVALID_UNWIND_TARGET;
00445 ExceptionRecord2.ExceptionFlags =
EXCEPTION_NONCONTINUABLE;
00446 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
00447 ExceptionRecord2.NumberParameters = 0;
00448
RtlRaiseException(&ExceptionRecord2);
00449 }
00450
00451
00452
00453
00454
00455
00456
00457
00458 HighAddress = (ULONG)RegistrationPointer +
00459
sizeof(EXCEPTION_REGISTRATION_RECORD);
00460
00461
if ( ((ULONG)RegistrationPointer < LowLimit) ||
00462 (HighAddress > HighLimit) ||
00463 (((ULONG)RegistrationPointer & 0x3) != 0) ) {
00464
00465
#if defined(NTOS_KERNEL_RUNTIME)
00466
00467
00468
00469
00470
00471
00472 ULONG TestAddress = (ULONG)RegistrationPointer;
00473
00474
if (((TestAddress & 0x3) == 0) &&
00475 KeGetCurrentIrql() >=
DISPATCH_LEVEL) {
00476
00477 PKPRCB Prcb =
KeGetCurrentPrcb();
00478 ULONG DpcStack = (ULONG)Prcb->DpcStack;
00479
00480
if ((Prcb->DpcRoutineActive) &&
00481 (HighAddress <= DpcStack) &&
00482 (TestAddress >= DpcStack - KERNEL_STACK_SIZE)) {
00483
00484
00485
00486
00487
00488
00489
00490 HighLimit = DpcStack;
00491 LowLimit = DpcStack - KERNEL_STACK_SIZE;
00492
continue;
00493 }
00494 }
00495
00496
#endif
00497
00498 ExceptionRecord2.ExceptionCode = STATUS_BAD_STACK;
00499 ExceptionRecord2.ExceptionFlags =
EXCEPTION_NONCONTINUABLE;
00500 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
00501 ExceptionRecord2.NumberParameters = 0;
00502
RtlRaiseException(&ExceptionRecord2);
00503 }
else {
00504
00505
00506
00507
00508
00509
00510
00511
00512 Disposition =
RtlpExecuteHandlerForUnwind(
00513 ExceptionRecord,
00514 (PVOID)RegistrationPointer,
00515 ContextRecord,
00516 (PVOID)&DispatcherContext,
00517 RegistrationPointer->Handler);
00518
00519
00520
00521
00522
00523
switch (Disposition) {
00524
00525
00526
00527
00528
00529
00530
case ExceptionContinueSearch :
00531
break;
00532
00533
00534
00535
00536
00537
00538
case ExceptionCollidedUnwind :
00539
00540
00541
00542
00543
00544
00545 RegistrationPointer = DispatcherContext.
RegistrationPointer;
00546
break;
00547
00548
00549
00550
00551
00552
00553
00554
default :
00555 ExceptionRecord2.ExceptionCode = STATUS_INVALID_DISPOSITION;
00556 ExceptionRecord2.ExceptionFlags =
EXCEPTION_NONCONTINUABLE;
00557 ExceptionRecord2.ExceptionRecord = ExceptionRecord;
00558 ExceptionRecord2.NumberParameters = 0;
00559
RtlRaiseException(&ExceptionRecord2);
00560
break;
00561 }
00562
00563
00564
00565
00566
00567 PriorPointer = RegistrationPointer;
00568 RegistrationPointer = RegistrationPointer->Next;
00569
00570
00571
00572
00573
00574
RtlpUnlinkHandler(PriorPointer);
00575
00576
00577
00578
00579
00580
00581 }
00582 }
00583
00584
if (TargetFrame == EXCEPTION_CHAIN_END) {
00585
00586
00587
00588
00589
00590
00591
00592
00593 ZwContinue(ContextRecord, FALSE);
00594
00595 }
else {
00596
00597
00598
00599
00600
00601
00602
00603
00604 ZwRaiseException(ExceptionRecord, ContextRecord, FALSE);
00605
00606 }
00607
return;
00608 }
}