📄 exdsptch.c
字号:
// stack switch occured.
StoreRegistrationPointer ((void *) -2);
KPlpvTls = pth->tlsPtr = tlsSave;
}
UpdateASID(pth, pprcSave, akySave);
// Repair the CONTEXT for PSL handlers.
if (TargetCStk) {
ContextRecord->Esp = TargetCStk->ExEsp;
ContextRecord->Ebp = TargetCStk->ExEbp;
ContextRecord->Ebx = TargetCStk->ExEbx;
ContextRecord->Esi = TargetCStk->ExEsi;
ContextRecord->Edi = TargetCStk->ExEdi;
}
return NKUnwind(pth, TargetCStk, RegistrationPointer,
DispatcherContext.ControlPc, ExceptionRecord,
ExceptionRecord->ExceptionCode, ContextRecord);
/* The disposition is to continue execution. If the
exception is not continuable, then raise the exception
EXC_NONCONTINUABLE_EXCEPTION. Otherwise return
TRUE. */
case ExceptionContinueExecution :
if ((ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) != 0) {
RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
break;
} else {
KPlpvTls = pth->tlsPtr = tlsSave;
UpdateASID(pth, pprcSave, akySave);
return TRUE;
}
/*
The disposition is to continue the search. Get next
frame address and continue the search.
*/
case ExceptionContinueSearch :
break;
/*
The disposition is nested exception. Set the nested
context frame to the establisher frame address and set
nested exception in the exception flags.
*/
case ExceptionNestedException :
ExceptionRecord->ExceptionFlags |= EXCEPTION_NESTED_CALL;
if (DispatcherContext.RegistrationPointer > NestedRegistration){
NestedRegistration = DispatcherContext.RegistrationPointer;
}
break;
/*
All other disposition values are invalid. Raise
invalid disposition exception.
*/
default :
RETAILMSG(1, (TEXT("NKDispatchException: invalid dispositon (%d)\r\n"),
Disposition));
RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
break;
}
RegistrationPointer = RegistrationPointer->Next;
}
} while (RegistrationPointer && RegistrationPointer != EXCEPTION_CHAIN_END);
DEBUGMSG(ZONE_SEH, (TEXT("NKDispatchException: ran out of exceptions pc=%x code=%x\n"),
ContextRecord1.Eip, ExceptionRecord->ExceptionCode));
// RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
KPlpvTls = pth->tlsPtr = tlsSave;
UpdateASID(pth, pprcSave, akySave);
return FALSE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOLEAN
NKUnwind(
IN PTHREAD pth,
IN PCALLSTACK TargetCStk OPTIONAL,
IN PEXCEPTION_REGISTRATION_RECORD TargetFrame OPTIONAL,
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, pcstkForHandler;
PPROCESS pProc;
BOOLEAN continueLoop = TRUE;
DWORD ctxMode;
// 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();
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: TargetCstk =%8.8lx TargetFrame=%8.8lx, TargetIp = %8.8lx, RP = %8.8lx, ll = %8.8lx, hl = %8.8lx\r\n"),
TargetCStk, TargetFrame, TargetIp, RegistrationPointer, LowLimit, HighLimit));
while (RegistrationPointer && RegistrationPointer != EXCEPTION_CHAIN_END) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: Proc=%8.8lx(%d) RP=%8.8lx\r\n"),
pCurProc, pCurProc->procnum, 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;
if (pcstk->dwPrevSP) {
ContextRecord->Esp = pcstk->dwPrevSP;
KPlpvTls = pth->tlsPtr = pth->tlsSecure;
NKGetStackLimits(pth, &LowLimit, &HighLimit);
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: Walking across call stack, ll = %8.8lx, hl = %8.8lx\r\n"), LowLimit, HighLimit));
}
pProc = pcstk->pprcLast;
SetContextMode(ContextRecord, (pcstk->dwPrcInfo & CST_MODE_FROM_USER)? USER_MODE : KERNEL_MODE);
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 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;
}
do {
if (RegistrationPointer == TargetFrame){
// Establisher frame is the target of the unwind
// operation. Set the target unwind flag. We still
// need to excute the loop body one more time, so we
// can't just break out.
ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
continueLoop = FALSE;
}
// Update the flags.
ExceptionRecord->ExceptionFlags = ExceptionFlags;
ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND |
EXCEPTION_TARGET_UNWIND);
// 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(ZONE_SEH, (TEXT("Calling termination handler @%8.8lx RP=%8.8lx\r\n"),
RegistrationPointer->Handler, RegistrationPointer));
pcstkForHandler = 0;
ctxMode = GetContextMode(ContextRecord);
if (KERNEL_MODE != ctxMode) {
if (!(pcstkForHandler = (PCALLSTACK) AllocMem (HEAP_CALLSTACK))) {
// we're completely out of memory, can't do much about it
ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
break;
}
SetupCSTK (pcstkForHandler);
}
Disposition = RtlpExecuteHandlerForUnwind(ExceptionRecord,
(PVOID)RegistrationPointer, ContextRecord, (PVOID)&DispatcherContext,
RegistrationPointer->Handler, pcstkForHandler, ctxMode);
DEBUGMSG(ZONE_SEH, (TEXT(" disposition = %d\r\n"), Disposition));
// don't need to free pcstkForHandler since it'll be freed at callback return
if (Disposition == ExceptionContinueSearch) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: disposition == ExceptionContinueSearch\r\n")));
break;
}
if (Disposition != ExceptionCollidedUnwind) {
RETAILMSG(1, (TEXT("NKUnwind: invalid dispositon (%d)\r\n"),
Disposition));
RAISE_EXCEPTION(STATUS_INVALID_DISPOSITION, ExceptionRecord);
}
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: disposition == ExceptionCollidedUnwind\r\n")));
ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
if (RegistrationPointer == DispatcherContext.RegistrationPointer) {
break;
}
// Pick up the registration pointer that was active at
// the time of the unwind, and continue.
RegistrationPointer = DispatcherContext.RegistrationPointer;
} while (continueLoop);
// If this is the target of the unwind, then continue execution
// by calling the continue system service.
if (RegistrationPointer == TargetFrame) {
StoreRegistrationPointer(RegistrationPointer);
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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -