📄 exdsptch.c
字号:
if (ControlPc < OldEntry->BeginAddress) {
OldHigh = Middle - 1;
} else if (ControlPc >= OldEntry->EndAddress) {
Low = Middle + 1;
} else {
// The capability exists for more than one function entry
// to map to the same function. This permits a function to
// have discontiguous code segments described by separate
// function table entries. If the ending prologue address
// is not within the limits of the begining and ending
// address of the function able entry, then the prologue
// ending address is the address of a function table entry
// that accurately describes the ending prologue address.
if ((OldEntry->PrologEndAddress < OldEntry->BeginAddress) ||
(OldEntry->PrologEndAddress >= OldEntry->EndAddress)) {
OldEntry = (PRUNTIME_FUNCTION)OldEntry->PrologEndAddress;
}
return OldEntry;
}
}
// If a new function table is located, then search the function table
// for a function table entry for the specified PC.
if (NewTable != NULL) {
// Initialize search indicies.
Low = 0;
// Perform binary search on the function table for a function table
// entry that subsumes the specified PC.
while (NewHigh >= Low) {
// Compute next probe index and test entry. If the specified PC
// is greater than of equal to the beginning address and less
// than the ending address of the function table entry, then
// return the address of the function table entry. Otherwise,
// continue the search.
Middle = (Low + NewHigh) >> 1;
NewEntry = &NewTable[Middle];
InstrShift = 1 + NewEntry->ThirtyTwoBits;
EndAddress = NewEntry->pFuncStart + (NewEntry->FuncLen << InstrShift);
if (ControlPc < NewEntry->pFuncStart) {
NewHigh = Middle - 1;
} else if (ControlPc >= EndAddress) {
Low = Middle + 1;
} else {
prf->BeginAddress = NewEntry->pFuncStart;
prf->EndAddress = EndAddress;
prf->PrologEndAddress = NewEntry->pFuncStart + (NewEntry->PrologLen << InstrShift);
if (NewEntry->ExceptionFlag) {
NewEH = (PPDATA_EH) MapPtrProc (NewEntry->pFuncStart, pProc) - 1;
prf->ExceptionHandler = NewEH->pHandler;
prf->HandlerData = NewEH->pHandlerData;
} else {
prf->ExceptionHandler = 0;
prf->HandlerData = 0;
}
return prf;
}
}
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
}
// A function table entry for the specified PC was not found.
return NULL;
}
#endif // COMBINED_PDATA
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOLEAN
NKUnwind(
IN PTHREAD pth,
IN PCALLSTACK TargetCStk OPTIONAL,
IN ULONG TargetFrame OPTIONAL,
IN ULONG TargetIp OPTIONAL,
IN PEXCEPTION_RECORD ExceptionRecord,
IN ULONG ReturnValue,
IN PCONTEXT ContextRecord,
IN PCALLSTACK NewStkTop
)
/*++
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
scan through the procedure call frames is then performed to find the target
of the unwind operation.
As each frame is encounter, the PC where control left the corresponding
function is determined and used to lookup exception handler information
in the runtime function table built by the linker. If the respective
routine has an exception handler, then the handler is called.
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:
None.
--*/
{
ULONG ControlPc;
DISPATCHER_CONTEXT DispatcherContext;
PCONTEXT OriginalContext;
EXCEPTION_DISPOSITION Disposition;
ULONG EstablisherFrame;
ULONG ExceptionFlags;
PRUNTIME_FUNCTION FunctionEntry;
BOOLEAN InFunction;
ULONG HighLimit;
ULONG LowLimit;
ULONG NextPc;
PCALLSTACK pcstk, pcstkForHandler;
RUNTIME_FUNCTION TempFunctionEntry;
PPROCESS pProc = pCurProc;
// Get current stack limits, capture the current context, virtually
// unwind to the caller of this routine, get the initial PC value, and
// set the unwind target address.
NKGetStackLimits(pth, &LowLimit, &HighLimit);
pcstk = pth->pcstkTop;
ControlPc = CONTEXT_TO_PROGRAM_COUNTER(ContextRecord);
CONTEXT_TO_PROGRAM_COUNTER(ContextRecord) = (ULONG)TargetIp;
EstablisherFrame = (ULONG) ContextRecord->IntSp;
OriginalContext = ContextRecord;
// If the target frame of the unwind is specified, then a normal unwind
// is being performed. Otherwise, an exit unwind is being performed.
DEBUGMSG (ZONE_SEH, (L"pcstk = %8.8lx, NewStkTop = %8.8lx, TargetCStk = %8.8lx\n", pcstk, NewStkTop, TargetCStk));
ExceptionFlags = EXCEPTION_UNWINDING;
if (!TargetFrame && !TargetCStk)
ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
// Scan backward through the call frame hierarchy and call exception
// handlers until the target frame of the unwind is reached.
do {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind(%08X): Proc=%8.8lx(%d) ControlPc=%8.8lx SP=%8.8lx\r\n"),
ContextRecord, pProc, pProc->procnum, ControlPc, ContextRecord->IntSp));
if ( (ControlPc == SYSCALL_RETURN)
|| (ControlPc+INST_SIZE == SYSCALL_RETURN)
|| (ControlPc+INST_SIZE == (DWORD) MD_CBRtn)
|| (ControlPc == (DWORD) MD_CBRtn)
|| (ControlPc == DIRECT_RETURN)
|| (ControlPc+INST_SIZE == DIRECT_RETURN)) {
// Server IPC return. If doing a PSL unwind, and this is the
// target process, then terminate to unwind loop.
pProc = pcstk->pprcLast;
if (pcstk == TargetCStk) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: TargetCStk reached.\r\n")));
break;
}
// Update the return address and process context
// information from the thread's call stack list.
ContextRecord->IntRa = (ULONG)pcstk->retAddr;
RESTORE_EXTRA_INFO(ContextRecord, pcstk->extra);
// must be calling from KMODE
DEBUGCHK (!(pcstk->dwPrcInfo & CST_MODE_FROM_USER));
SetContextMode(ContextRecord, KERNEL_MODE);
/* Returning from a user mode server, restore the previous
* address space information and return.
*/
UpdateASID(pth, pProc, pcstk->akyLast ? pcstk->akyLast : pth->aky);
ControlPc = (ULONG) ContextRecord->IntRa - INST_SIZE;
// We can't unlink CALLSTACK Object here, because C++ Nested
// exception need callstack for dispatch
#if 0
// Unlink the most recent CALLSTACK object
pth->pcstkTop = pcstk->pcstkNext;
#endif
if (pcstk->dwPrevSP) {
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: switch stack, new tls = %8.8lx\r\n"), pth->tlsSecure));
// update hi/lo/current and targetframe
KPlpvTls = pth->tlsPtr = pth->tlsSecure;
ContextRecord->IntSp = EstablisherFrame = pcstk->dwPrevSP + CALLEE_SAVED_REGS;
MDRestoreCalleeSavedRegisters (pcstk, ContextRecord);
NKGetStackLimits(pth, &LowLimit, &HighLimit);
}
#if 0
if (IsValidKPtr(pcstk))
FreeMem(pcstk,HEAP_CALLSTACK);
#endif
pcstk = pcstk->pcstkNext;
DEBUGMSG(ZONE_SEH, (TEXT("NKUnwind: PSL ret=%8.8lx\r\n"),
ControlPc + INST_SIZE));
}
// Lookup the function table entry using the point at which control
// left the procedure.
ControlPc = ZeroPtr(ControlPc);
FunctionEntry = NKLookupFunctionEntry(pCurProc, ControlPc, &TempFunctionEntry);
// If there is a function table entry for the routine, then virtually
// unwind to the caller of the routine to obtain the virtual frame
// pointer of the establisher, but don't update the context record.
if (FunctionEntry != NULL) {
NextPc = RtlpVirtualUnwind(ControlPc,
FunctionEntry,
ContextRecord,
&InFunction,
&EstablisherFrame);
// If the virtual frame pointer is not within the specified stack
// limits, the virtual frame pointer is unaligned, or the target
// frame is below the virtual frame and an exit unwind is not being
// performed, then raise the exception STATUS_BAD_STACK. Otherwise,
// check to determine if the current routine has an exception
// handler.
if ((EstablisherFrame < LowLimit)
|| (EstablisherFrame > HighLimit)
|| (TargetFrame && (TargetFrame < EstablisherFrame))
|| ((EstablisherFrame & STK_ALIGN) != 0)) {
RAISE_EXCEPTION(STATUS_BAD_STACK, ExceptionRecord);
} else if ((FunctionEntry->ExceptionHandler != NULL) && InFunction) {
// The frame has an exception handler.
// The control PC, establisher frame pointer, the address
// of the function table entry, and the address of the
// context record are all stored in the dispatcher context.
// This information is used by the unwind linkage routine
// and can be used by the exception handler itself.
//
// A linkage routine written in assembler is used to actually
// call the actual exception handler. This is required by the
// exception handler that is associated with the linkage
// routine so it can have access to two sets of dispatcher
// context when it is called.
DispatcherContext.ControlPc = ControlPc;
DispatcherContext.FunctionEntry = FunctionEntry;
DispatcherContext.EstablisherFrame = EstablisherFrame;
DispatcherContext.ContextRecord = ContextRecord;
// Call the exception handler.
do {
// If the establisher frame is the target of the unwind
// operation, then set the target unwind flag.
if ((ULONG)TargetFrame == EstablisherFrame)
ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
ExceptionRecord->ExceptionFlags = ExceptionFlags;
// Set the specified return value in case the exception
// handler directly continues execution.
ContextRecord->RetValue = (ULONG)ReturnValue;
DEBUGMSG(ZONE_SEH, (TEXT("Calling unwind handler @%8.8lx Frame=%8.8lx\r\n"),
FunctionEntry->ExceptionHandler, EstablisherFrame));
pcstkForHandler = 0;
if (KERNEL_MODE != GetContextMode (ContextRecord)) {
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,
EstablisherFrame,
ContextRecord,
&DispatcherContext,
FunctionEntry->ExceptionHandler,
pcstkForHandler);
// don't need to free pcstkForHandler since it'll be freed at callback return
DEBUGMSG(ZONE_SEH, (TEXT(" disposition = %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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -