📄 exdsptch.c
字号:
IN ULONG TargetIp OPTIONAL,
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG ReturnValue,
IN PCONTEXT ContextRecord)
/*++
Routine Description:
This function initiates an unwind of procedure call frames. The machine
state at the time of the call to unwind is captured in a context record
and the unwinding flag is set in the exception flags of the exception
record. If the TargetFrame parameter is not specified, then the exit unwind
flag is also set in the exception flags of the exception record. A backward
walk through the procedure call frames is then performed to find the target
of the unwind operation.
N.B. The captured context passed to unwinding handlers will not be
a completely accurate context set for the 386. This is because
there isn't a standard stack frame in which registers are stored.
Only the integer registers are affected. The segement and
control registers (ebp, esp) will have correct values for
the flat 32 bit environment.
Arguments:
pth - Supplies a pointer to thread structure
TargetCStk - Supplies an optional pointer to a PSL callstack to unwind to.
This parameter is used instead of TargetFrame.
TargetFrame - Supplies an optional pointer to the call frame that is the
target of the unwind. If this parameter is not specified, then an exit
unwind is performed.
TargetIp - Supplies an optional instruction address that specifies the
continuation address of the unwind. This address is ignored if the
target frame parameter is not specified.
ExceptionRecord - Supplies an optional pointer to an exception record.
ReturnValue - Supplies a value that is to be placed in the integer
function return register just before continuing execution.
ContextRecord - Supplies a pointer to a context record that can be used
to store context druing the unwind operation.
Return Value:
TRUE if target frame or callstack reached.
--*/
{
DISPATCHER_CONTEXT DispatcherContext;
EXCEPTION_DISPOSITION Disposition;
PEXCEPTION_REGISTRATION_RECORD RegistrationPointer;
PEXCEPTION_REGISTRATION_RECORD PriorPointer;
ULONG ExceptionFlags;
ULONG HighAddress;
ULONG HighLimit;
ULONG LowLimit;
PCALLSTACK pcstk;
PPROCESS pProc;
// Get current stack limits.
NKGetStackLimits(pth, &LowLimit, &HighLimit);
pcstk = pth->pcstkTop;
// If the target frame of the unwind is specified, then set EXCEPTION_UNWINDING
// flag in the exception flags. Otherwise set both EXCEPTION_EXIT_UNWIND and
// EXCEPTION_UNWINDING flags in the exception flags.
ExceptionFlags = ExceptionRecord->ExceptionFlags | EXCEPTION_UNWINDING;
if (!TargetFrame && !TargetCStk)
ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
ContextRecord->Eax = ReturnValue;
if (TargetIp)
ContextRecord->Eip = TargetIp;
// Scan backward through the call frame hierarchy, calling exception
// handlers as they are encountered, until the target frame of the unwind
// is reached.
RegistrationPointer = GetRegistrationHead();
while (RegistrationPointer && RegistrationPointer != EXCEPTION_CHAIN_END) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: Proc=%8.8lx RP=%8.8lx\r\n"),
pCurProc, RegistrationPointer));
// Check for PSL call boundary.
while (RegistrationPointer == (PEXCEPTION_REGISTRATION_RECORD)-2) {
if (!pcstk) {
RETAILMSG(1, (TEXT("NKUnwind: no CALLSTACK with RP=%d\r\n"),
RegistrationPointer));
goto Unwind_exit;
}
if (pcstk == TargetCStk) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: TargetCStk reached.\r\n")));
goto Unwind_exit;
}
// in a PSL call.
RegistrationPointer = (PEXCEPTION_REGISTRATION_RECORD)pcstk->extra;
pProc = pcstk->pprcLast;
if ((ulong)pProc < 0x10000) {
/* This call is returning from kernel mode server. Restore
* the thread's previous operating mode and return.
*/
SetContextMode(ContextRecord, (ULONG)pProc);
} else {
/* Returning from a user mode server, restore the previous
* address space information and return.
*/
UpdateASID(pth, pProc, pcstk->akyLast ? pcstk->akyLast : pth->aky);
}
pth->pcstkTop = pcstk->pcstkNext;
if (IsValidKPtr(pcstk))
FreeMem(pcstk,HEAP_CALLSTACK);
pcstk = pth->pcstkTop;
// Update the FS:[0] exception chain
StoreRegistrationPointer(RegistrationPointer);
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: PSL return Proc=%8.8lx RP=%8.8lx pcstk=%8.8lx\r\n"),
pProc, RegistrationPointer, pcstk));
}
#if 0
// [Mercator 15263]
// Removed this check because it is possible that NKDispatchException has
// passed us its local TempRegistation structure as the target frame.
// TempRegistration lives much higher on the stack (i.e. lower in memory)
// than the current RegistrationPointer.
// If the target frame is lower in the stack than the current frame,
// then raise STATUS_INVALID_UNWIND exception.
if (TargetFrame && TargetFrame < RegistrationPointer) {
RAISE_EXCEPTION(STATUS_INVALID_UNWIND_TARGET, ExceptionRecord);
break;
}
#endif
// If the call frame is not within the specified stack limits or the
// call frame is unaligned, then raise the exception STATUS_BAD_STACK.
// Else restore the state from the specified frame to the context
// record.
HighAddress = (ULONG)RegistrationPointer + sizeof(EXCEPTION_REGISTRATION_RECORD);
if ((ULONG)RegistrationPointer < LowLimit || HighAddress > HighLimit
|| ((ULONG)RegistrationPointer & 0x3) != 0) {
RAISE_EXCEPTION(STATUS_BAD_STACK, ExceptionRecord);
break;
} else {
// Call the exception handler.
do {
// If the establisher frame is the target of the unwind
// operation, then set the target unwind flag.
if (RegistrationPointer == TargetFrame){
ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
}
ExceptionRecord->ExceptionFlags = ExceptionFlags;
// The handler must be executed by calling another routine
// that is written in assembler. This is required because
// up level addressing of the handler information is required
// when a collided unwind is encountered.
DEBUGMSG(1, (TEXT("Calling termination handler @%8.8lx RP=%8.8lx\r\n"),
RegistrationPointer->Handler, RegistrationPointer));
Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord,
(PVOID)RegistrationPointer, ContextRecord, (PVOID)&DispatcherContext,
RegistrationPointer->Handler, GetContextMode(ContextRecord));
DEBUGMSG(1, (TEXT(" dispostion = %d\r\n"), Disposition));
// Clear target unwind and collided unwind flags.
ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND |
EXCEPTION_TARGET_UNWIND);
// Case on the handler disposition.
switch (Disposition) {
// The disposition is to continue the search. Get next
// frame address and continue the search.
case ExceptionContinueSearch :
break;
// The disposition is colided unwind. Maximize the target
// of the unwind and change the context record pointer.
case ExceptionCollidedUnwind :
// Pick up the registration pointer that was active at
// the time of the unwind, and simply continue.
ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
RegistrationPointer = DispatcherContext.RegistrationPointer;
break;
// All other disposition values are invalid. Raise
// invalid disposition exception.
default :
RETAILMSG(1, (TEXT("NKUnwind: invalid dispositon (%d)\r\n"),
Disposition));
RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
break;
}
} while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
// If this is the target of the unwind, then continue execution
// by calling the continue system service.
if (RegistrationPointer == TargetFrame)
break;
// Step to next registration record and unlink
// the unwind handler since it has been called.
PriorPointer = RegistrationPointer;
RegistrationPointer = RegistrationPointer->Next;
StoreRegistrationPointer(RegistrationPointer);
}
}
Unwind_exit:
// If the registration pointer is equal to the target frame
// pointer, then continue execution. Otherwise, an exit unwind was
// performed or the target of the unwind did not exist and the
// debugger and subsystem are given a second chance to handle the
// unwind.
if ((TargetFrame && RegistrationPointer == TargetFrame)
|| (TargetCStk && pcstk == TargetCStk)) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: continuing @%8.8lx\r\n"),
CONTEXT_TO_PROGRAM_COUNTER(ContextRecord)));
return TRUE;
}
return FALSE;
}
#endif
#ifndef x86
#if MIPS
#if MIPS16SUPPORT
#define COMBINED_PDATA // define to enable combined pdata format
#else
#define OLD_PDATA // define to enable original pdata format
#endif
#define INST_SIZE 4
#define STK_ALIGN 0x7
#define RetValue IntV0
#define RESTORE_EXTRA_INFO(Context, extra) ((Context)->IntGp = (extra))
#define FIXTOC(Context)
#endif
#if SHx
#define COMPRESSED_PDATA // define to enable compressed pdata format
#define INST_SIZE 2
#define STK_ALIGN 0x3
#define IntRa PR
#define IntSp R15
#define RetValue R0
#define RESTORE_EXTRA_INFO(Context, extra)
#define FIXTOC(Context)
#endif
#if PPC
#define COMPRESSED_PDATA // define to enable compressed pdata format
#define INST_SIZE 4
#define STK_ALIGN 0x7
#define IntRa Lr
#define IntSp Gpr1
#define RetValue Gpr3
#define Psr Msr
#define RESTORE_EXTRA_INFO(Context, extra) ((Context)->Gpr2 = (extra))
#define FIXTOC(Context)
#endif
#if ARM
#define COMPRESSED_PDATA // define to enable compressed pdata format
#define INST_SIZE 4
#define STK_ALIGN 0x3
#define IntRa Lr
#define IntSp Sp
#define RetValue R0
#define RESTORE_EXTRA_INFO(Context, extra) ((Context)->R9 = (extra))
#define FIXTOC(Context)
#endif
#ifdef INST_SIZE
//
// Define private function prototypes.
//
ULONG
RtlpVirtualUnwind(
IN ULONG ControlPc,
IN PRUNTIME_FUNCTION FunctionEntry,
IN PCONTEXT ContextRecord,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -