/*++

Copyright (c) 2000  Microsoft Corporation

Module Name:

    raise.c

Abstract:

    This module implements functions to raise and exception and to raise
    status.

Author:

    David N. Cutler (davec) 28-Oct-2000

Environment:

    Any mode.

--*/

#include "ntrtlp.h"

VOID
RtlRaiseException (
    IN PEXCEPTION_RECORD ExceptionRecord
    )

/*++

Routine Description:

    This function raises a software exception by building a context record
    and calling the raise exception system service.

Arguments:

    ExceptionRecord - Supplies a pointer to an exception record.

Return Value:

    None.

--*/

{

    CONTEXT ContextRecord;
    ULONG64 ControlPc;
    ULONG64 EstablisherFrame;
    PRUNTIME_FUNCTION FunctionEntry;
    PVOID HandlerData;
    ULONG64 ImageBase;
    NTSTATUS Status = STATUS_INVALID_DISPOSITION;

    //
    // Capture the current context, unwind to the caller of this routine, set
    // the exception address, and call the appropriate exception dispatcher.
    //

    RtlCaptureContext(&ContextRecord);
    ControlPc = ContextRecord.Rip;
    FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
    if (FunctionEntry != NULL) {
        RtlVirtualUnwind(UNW_FLAG_NHANDLER,
                         ImageBase,
                         ControlPc,
                         FunctionEntry,
                         &ContextRecord,
                         &HandlerData,
                         &EstablisherFrame,
                         NULL);

        ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Rip;

#if defined(NTOS_KERNEL_RUNTIME)

        if (RtlDispatchException(ExceptionRecord, &ContextRecord) != FALSE) {
            return;
    
        }

        Status = ZwRaiseException(ExceptionRecord, &ContextRecord, FALSE);

#else

        if (ZwQueryPortInformationProcess() == FALSE) {
            if (RtlDispatchException(ExceptionRecord, &ContextRecord) != FALSE) {
                return;
            }

            Status = ZwRaiseException(ExceptionRecord, &ContextRecord, FALSE);

        } else {
            Status = ZwRaiseException(ExceptionRecord, &ContextRecord, TRUE);
        }

#endif

    }

    //
    // There should never be a return from either exception dispatch or the
    // system service unless there is a problem with the argument list itself.
    // Raise another exception specifying the status value returned.
    //

    RtlRaiseStatus(Status);
    return;
}

#pragma warning(push)
#pragma warning(disable:4717)       // recursive function
                     
VOID
RtlRaiseStatus (
    IN NTSTATUS Status
    )

/*++

Routine Description:

    This function raises an exception with the specified status value. The
    exception is marked as noncontinuable with no parameters.

Arguments:

    Status - Supplies the status value to be used as the exception code
        for the exception that is to be raised.

Return Value:

    None.

--*/

{

    CONTEXT ContextRecord;
    EXCEPTION_RECORD ExceptionRecord;

    //
    // Capure the current context and construct an exception record.
    //

    RtlCaptureContext(&ContextRecord);
    ExceptionRecord.ExceptionCode = Status;
    ExceptionRecord.ExceptionRecord = NULL;
    ExceptionRecord.NumberParameters = 0;
    ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
    ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Rip;

    //
    // Attempt to dispatch the exception.
    //
    // N.B. This exception is non-continuable.
    //

#if defined(NTOS_KERNEL_RUNTIME)

    RtlDispatchException(&ExceptionRecord, &ContextRecord);
    Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, FALSE);

#else

    if (ZwQueryPortInformationProcess() == FALSE) {
        RtlDispatchException(&ExceptionRecord, &ContextRecord);
        Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, FALSE);

    } else {
        Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, TRUE);
    }

#endif

    //
    // There should never be a return from either exception dispatch or the
    // system service unless there is a problem with the argument list itself.
    // Raise another exception specifying the status value returned.
    //

    RtlRaiseStatus(Status);
    return;
}

#pragma warning(pop)