exp.c

来自「一个类似windows」· C语言 代码 · 共 1,362 行 · 第 1/3 页

C
1,362
字号
        Context->Edi = TrapFrame->Edi;
    }

    /* Handle extended registers */
    if (((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) ==
        CONTEXT_EXTENDED_REGISTERS) &&
        ((TrapFrame->SegCs & MODE_MASK) == UserMode))
    {
        /* Get the FX Save Area */
        FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);

        /* Make sure NPX is present */
        if (KeI386NpxPresent)
        {
            /* Future use */
        }

        /* Old code */
        FxSaveArea = KiGetFpuState(KeGetCurrentThread());
        if (FxSaveArea != NULL)
        {
            memcpy(Context->ExtendedRegisters, &FxSaveArea->U.FxArea,
                   min(sizeof (Context->ExtendedRegisters), sizeof (FxSaveArea->U.FxArea)) );
        }
        else
        {
            Context->ContextFlags &= (~CONTEXT_EXTENDED_REGISTERS) | CONTEXT_i386;
        }
    }

    /* Handle Floating Point */
    if (((Context->ContextFlags & CONTEXT_FLOATING_POINT) ==
        CONTEXT_FLOATING_POINT) &&
        ((TrapFrame->SegCs & MODE_MASK) == UserMode))
    {
        /* Get the FX Save Area */
        FxSaveArea = (PFX_SAVE_AREA)(TrapFrame + 1);

        /* Make sure we have an NPX */
        if (KeI386NpxPresent)
        {
            /* Future use */
        }
        else
        {
            /* Future Use */
        }

        /* Old code */
        FxSaveArea = KiGetFpuState(KeGetCurrentThread());
        if (FxSaveArea != NULL)
        {
            KiFxSaveAreaToFloatingSaveArea(&Context->FloatSave, FxSaveArea);
        }
        else
        {
            Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386;
        }
    }

    /* Handle debug registers */
    if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) ==
        CONTEXT_DEBUG_REGISTERS)
    {
        /* Copy the debug registers */
        Context->Dr0 = TrapFrame->Dr0;
        Context->Dr1 = TrapFrame->Dr1;
        Context->Dr2 = TrapFrame->Dr2;
        Context->Dr3 = TrapFrame->Dr3;
        Context->Dr6 = TrapFrame->Dr6;

        /* For user-mode, only set DR7 if a debugger is active */
        if (((TrapFrame->SegCs & MODE_MASK) ||
            (TrapFrame->EFlags & EFLAGS_V86_MASK)) &&
            (KeGetCurrentThread()->DispatcherHeader.DebugActive))
        {
            /* Copy it over */
            Context->Dr7 = TrapFrame->Dr7;
        }
        else
        {
            /* Clear it */
            Context->Dr7 = 0;
        }
    }
}

VOID
NTAPI
KeDumpStackFrames(PULONG Frame)
{
	PULONG StackBase, StackEnd;
	MEMORY_BASIC_INFORMATION mbi;
	ULONG ResultLength = sizeof(mbi);
	NTSTATUS Status;

	DbgPrint("Frames:\n");
	_SEH_TRY
	{
		Status = MiQueryVirtualMemory (
			(HANDLE)-1,
			Frame,
			MemoryBasicInformation,
			&mbi,
			sizeof(mbi),
			&ResultLength );
		if ( !NT_SUCCESS(Status) )
		{
			DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
			return;
		}

		StackBase = Frame;
		StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);

		while ( Frame >= StackBase && Frame < StackEnd )
		{
			ULONG Addr = Frame[1];
			if (!KeRosPrintAddress((PVOID)Addr))
				DbgPrint("<%X>", Addr);
			if ( Addr == 0 || Addr == 0xDEADBEEF )
				break;
			StackBase = Frame;
			Frame = (PULONG)Frame[0];
			DbgPrint("\n");
		}
	}
	_SEH_HANDLE
	{
	}
	_SEH_END;
	DbgPrint("\n");
}

VOID STDCALL
KeRosDumpStackFrames ( PULONG Frame, ULONG FrameCount )
{
	ULONG i=0;
	PULONG StackBase, StackEnd;
	MEMORY_BASIC_INFORMATION mbi;
	ULONG ResultLength = sizeof(mbi);
	NTSTATUS Status;

	DbgPrint("Frames: ");
	_SEH_TRY
	{
		if ( !Frame )
		{
#if defined __GNUC__
			__asm__("mov %%ebp, %0" : "=r" (Frame) : );
#elif defined(_MSC_VER)
			__asm mov [Frame], ebp
#endif
			//Frame = (PULONG)Frame[0]; // step out of KeRosDumpStackFrames
		}

		Status = MiQueryVirtualMemory (
			(HANDLE)-1,
			Frame,
			MemoryBasicInformation,
			&mbi,
			sizeof(mbi),
			&ResultLength );
		if ( !NT_SUCCESS(Status) )
		{
			DPRINT1("Can't dump stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
			return;
		}

		StackBase = Frame;
		StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);

		while ( Frame >= StackBase && Frame < StackEnd && i++ < FrameCount )
		{
			ULONG Addr = Frame[1];
			if (!KeRosPrintAddress((PVOID)Addr))
				DbgPrint("<%X>", Addr);
			if ( Addr == 0 || Addr == 0xDEADBEEF )
				break;
			StackBase = Frame;
			Frame = (PULONG)Frame[0];
			DbgPrint(" ");
		}
	}
	_SEH_HANDLE
	{
	}
	_SEH_END;
	DbgPrint("\n");
}

ULONG STDCALL
KeRosGetStackFrames ( PULONG Frames, ULONG FrameCount )
{
	ULONG Count = 0;
	PULONG StackBase, StackEnd, Frame;
	MEMORY_BASIC_INFORMATION mbi;
	ULONG ResultLength = sizeof(mbi);
	NTSTATUS Status;

	_SEH_TRY
	{
#if defined __GNUC__
		__asm__("mov %%ebp, %0" : "=r" (Frame) : );
#elif defined(_MSC_VER)
		__asm mov [Frame], ebp
#endif

		Status = MiQueryVirtualMemory (
			(HANDLE)-1,
			Frame,
			MemoryBasicInformation,
			&mbi,
			sizeof(mbi),
			&ResultLength );
		if ( !NT_SUCCESS(Status) )
		{
			DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
			return 0;
		}

		StackBase = Frame;
		StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);

		while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
		{
			Frames[Count++] = Frame[1];
			StackBase = Frame;
			Frame = (PULONG)Frame[0];
		}
	}
	_SEH_HANDLE
	{
	}
	_SEH_END;
	return Count;
}

VOID
INIT_FUNCTION
NTAPI
KeInitExceptions(VOID)
{
    ULONG i;
    USHORT FlippedSelector;

    /* Loop the IDT */
    for (i = 0; i <= MAXIMUM_IDTVECTOR; i ++)
    {
        /* Save the current Selector */
        FlippedSelector = KiIdt[i].Selector;

        /* Flip Selector and Extended Offset */
        KiIdt[i].Selector = KiIdt[i].ExtendedOffset;
        KiIdt[i].ExtendedOffset = FlippedSelector;
    }
}

VOID
NTAPI
KiDispatchException(PEXCEPTION_RECORD ExceptionRecord,
                    PKEXCEPTION_FRAME ExceptionFrame,
                    PKTRAP_FRAME TrapFrame,
                    KPROCESSOR_MODE PreviousMode,
                    BOOLEAN FirstChance)
{
    CONTEXT Context;
    KD_CONTINUE_TYPE Action;
    ULONG_PTR Stack, NewStack;
    ULONG Size;
    BOOLEAN UserDispatch = FALSE;
    DPRINT("KiDispatchException() called\n");

    /* Increase number of Exception Dispatches */
    KeGetCurrentPrcb()->KeExceptionDispatchCount++;

    /* Set the context flags */
    Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;

    /* Check if User Mode */
    if (PreviousMode == UserMode)
    {
        /* Add the FPU Flag */
        Context.ContextFlags |= CONTEXT_FLOATING_POINT;
        if (KeI386FxsrPresent) Context.ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
    }

    /* Get a Context */
    KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);

    /* Handle kernel-mode first, it's simpler */
    if (PreviousMode == KernelMode)
    {
        /* Check if this is a first-chance exception */
        if (FirstChance == TRUE)
        {
            /* Break into the debugger for the first time */
            Action = KdpEnterDebuggerException(ExceptionRecord,
                                               PreviousMode,
                                               &Context,
                                               TrapFrame,
                                               TRUE,
                                               TRUE);

            /* If the debugger said continue, then continue */
            if (Action == kdContinue) goto Handled;

            /* If the Debugger couldn't handle it, dispatch the exception */
            if (RtlDispatchException(ExceptionRecord, &Context))
            {
                /* It was handled by an exception handler, continue */
                goto Handled;
            }
        }

        /* This is a second-chance exception, only for the debugger */
        Action = KdpEnterDebuggerException(ExceptionRecord,
                                           PreviousMode,
                                           &Context,
                                           TrapFrame,
                                           FALSE,
                                           FALSE);

        /* If the debugger said continue, then continue */
        if (Action == kdContinue) goto Handled;

        /* Third strike; you're out */
        KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
                         ExceptionRecord->ExceptionCode,
                         (ULONG_PTR)ExceptionRecord->ExceptionAddress,
                         ExceptionRecord->ExceptionInformation[0],
                         ExceptionRecord->ExceptionInformation[1],
                         TrapFrame);
    }
    else
    {
        /* User mode exception, was it first-chance? */
        if (FirstChance)
        {
            /* Enter Debugger if available */
            Action = KdpEnterDebuggerException(ExceptionRecord,
                                               PreviousMode,
                                               &Context,
                                               TrapFrame,
                                               TRUE,
                                               TRUE);

            /* Exit if we're continuing */
            if (Action == kdContinue) goto Handled;

            /* FIXME: Forward exception to user mode debugger */

            /* Set up the user-stack */
            _SEH_TRY
            {
                /* Align context size and get stack pointer */
                Size = (sizeof(CONTEXT) + 3) & ~3;
                Stack = (Context.Esp & ~3) - Size;
                DPRINT("Stack: %lx\n", Stack);

                /* Probe stack and copy Context */
                ProbeForWrite((PVOID)Stack, Size, sizeof(ULONG));
                RtlCopyMemory((PVOID)Stack, &Context, sizeof(CONTEXT));

                /* Align exception record size and get stack pointer */
                Size = (sizeof(EXCEPTION_RECORD) - 
                        (EXCEPTION_MAXIMUM_PARAMETERS - ExceptionRecord->NumberParameters) *
                        sizeof(ULONG) + 3) & ~3;
                NewStack = Stack - Size;
                DPRINT("NewStack: %lx\n", NewStack);

                /* Probe stack and copy exception record. Don't forget to add the two params */
                ProbeForWrite((PVOID)(NewStack - 2 * sizeof(ULONG_PTR)),
                              Size +  2 * sizeof(ULONG_PTR),
                              sizeof(ULONG));
                RtlCopyMemory((PVOID)NewStack, ExceptionRecord, Size);

                /* Now write the two params for the user-mode dispatcher */
                *(PULONG_PTR)(NewStack - 1 * sizeof(ULONG_PTR)) = Stack;
                *(PULONG_PTR)(NewStack - 2 * sizeof(ULONG_PTR)) = NewStack;

                /* Set new Stack Pointer */
                KiEspToTrapFrame(TrapFrame, NewStack - 2 * sizeof(ULONG_PTR));

                /* Set EIP to the User-mode Dispathcer */
                TrapFrame->Eip = (ULONG)KeUserExceptionDispatcher;
                UserDispatch = TRUE;
                _SEH_LEAVE;
            }
            _SEH_HANDLE
            {
                /* Do second-chance */
            }
            _SEH_END;
        }

        /* If we dispatch to user, return now */
        if (UserDispatch) return;

        /* FIXME: Forward the exception to the debugger for 2nd chance */

        /* 3rd strike, kill the thread */
        DPRINT1("Unhandled UserMode exception, terminating thread\n");
        ZwTerminateThread(NtCurrentThread(), ExceptionRecord->ExceptionCode);
        KEBUGCHECKWITHTF(KMODE_EXCEPTION_NOT_HANDLED,
                         ExceptionRecord->ExceptionCode,
                         (ULONG_PTR)ExceptionRecord->ExceptionAddress,
                         ExceptionRecord->ExceptionInformation[0],
                         ExceptionRecord->ExceptionInformation[1],
                         TrapFrame);
    }

Handled:
    /* Convert the context back into Trap/Exception Frames */
    KeContextToTrapFrame(&Context,
                         NULL,
                         TrapFrame,
                         Context.ContextFlags,
                         PreviousMode);
    return;
}

/*
 * @implemented
 */
NTSTATUS
NTAPI
KeRaiseUserException(IN NTSTATUS ExceptionCode)
{
   ULONG OldEip;
   PKTHREAD Thread = KeGetCurrentThread();

   /* Make sure we can access the TEB */
    _SEH_TRY
    {
        Thread->Teb->ExceptionCode = ExceptionCode;
    }
    _SEH_HANDLE
    {
        return(ExceptionCode);
    }
    _SEH_END;

    /* Get the old EIP */
    OldEip = Thread->TrapFrame->Eip;

    /* Change it to the user-mode dispatcher */
    Thread->TrapFrame->Eip = (ULONG_PTR)KeRaiseUserExceptionDispatcher;

    /* Return the old EIP */
    return((NTSTATUS)OldEip);
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?