mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
501 lines
15 KiB
501 lines
15 KiB
// TITLE("Miscellaneous Exception Handling")
|
|
//++
|
|
//
|
|
// Copyright (c) 1990 Microsoft Corporation
|
|
// Copyright (c) 1992 Digital Equipment Corporation
|
|
//
|
|
// Module Name:
|
|
//
|
|
// xcptmisc.s
|
|
//
|
|
// Abstract:
|
|
//
|
|
// This module implements miscellaneous routines that are required to
|
|
// support exception handling. Functions are provided to call an exception
|
|
// handler for an exception, call an exception handler for unwinding, call
|
|
// an exception filter, call a termination handler, and get the caller's
|
|
// stack limits.
|
|
//
|
|
// Author:
|
|
//
|
|
// David N. Cutler (davec) 12-Sep-1990
|
|
//
|
|
// Environment:
|
|
//
|
|
// Any mode.
|
|
//
|
|
// Revision History:
|
|
//
|
|
// Thomas Van Baak (tvb) 7-May-1992
|
|
//
|
|
// Adapted for Alpha AXP.
|
|
//
|
|
//--
|
|
|
|
#include "ksalpha.h"
|
|
|
|
//
|
|
// Define call frame for calling exception handlers.
|
|
//
|
|
|
|
.struct 0
|
|
CfRa: .space 8 // saved return address
|
|
CfA3: .space 8 // save area for argument a3
|
|
.space 0 * 8 // 16-byte stack alignment
|
|
CfFrameLength: // length of stack frame
|
|
|
|
SBTTL("Execute Handler for Exception")
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpExecuteHandlerForException (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN ULONG EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PDISPATCHER_CONTEXT DispatcherContext,
|
|
// IN PEXCEPTION_ROUTINE ExceptionRoutine
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function allocates a call frame, stores the establisher frame
|
|
// pointer in the frame, establishes an exception handler, and then calls
|
|
// the specified exception handler as an exception handler. If a nested
|
|
// exception occurs, then the exception handler of this function is called
|
|
// and the establisher frame pointer is returned to the exception dispatcher
|
|
// via the dispatcher context parameter. If control is returned to this
|
|
// routine, then the frame is deallocated and the disposition status is
|
|
// returned to the exception dispatcher.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (a0) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (a1) - Supplies the frame pointer of the establisher
|
|
// of the exception handler that is to be called.
|
|
//
|
|
// ContextRecord (a2) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (a3) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// ExceptionRoutine (a4) - Supplies a pointer to the exception handler that
|
|
// is to be called.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The disposition value returned by the specified exception handler is
|
|
// returned as the function value.
|
|
//
|
|
//--
|
|
|
|
//
|
|
// N.B. This function specifies its own private exception handler.
|
|
//
|
|
|
|
EXCEPTION_HANDLER(RtlpExceptionHandler)
|
|
|
|
NESTED_ENTRY(RtlpExecuteHandlerForException, CfFrameLength, zero)
|
|
|
|
lda sp, -CfFrameLength(sp) // allocate stack frame
|
|
stq ra, CfRa(sp) // save return address
|
|
|
|
PROLOGUE_END
|
|
|
|
//
|
|
// Save the address of the dispatcher context record in our stack frame so
|
|
// that our own exception handler (not the one we're calling) can retrieve it.
|
|
//
|
|
|
|
stq a3, CfA3(sp) // save address of dispatcher context
|
|
|
|
//
|
|
// Now call the exception handler and return its return value as ours.
|
|
//
|
|
|
|
bic a4, 3, a4 // clear low-order bits (IEEE mode)
|
|
jsr ra, (a4) // call exception handler
|
|
|
|
ldq ra, CfRa(sp) // restore return address
|
|
lda sp, CfFrameLength(sp) // deallocate stack frame
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlpExecuteHandlerForException
|
|
|
|
SBTTL("Local Exception Handler")
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpExceptionHandler (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN ULONG EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PDISPATCHER_CONTEXT DispatcherContext
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function is called when a nested exception occurs. Its function
|
|
// is to retrieve the establisher frame pointer from its establisher's
|
|
// call frame, store this information in the dispatcher context record,
|
|
// and return a disposition value of nested exception.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (a0) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (a1) - Supplies the frame pointer of the establisher
|
|
// of this exception handler.
|
|
//
|
|
// ContextRecord (a2) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (a3) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// A disposition value ExceptionNestedException is returned if an unwind
|
|
// is not in progress. Otherwise a value of ExceptionContinueSearch is
|
|
// returned.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlpExceptionHandler)
|
|
|
|
ldl t0, ErExceptionFlags(a0) // get exception flags
|
|
and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress
|
|
bne t0, 10f // if neq, unwind in progress
|
|
|
|
//
|
|
// Unwind is not in progress - return nested exception disposition.
|
|
//
|
|
|
|
//
|
|
// Convert the given establisher virtual frame pointer (a1) to a real frame
|
|
// pointer (the value of a1 minus CfFrameLength) and retrieve the pointer to
|
|
// the dispatcher context that earlier was stored in the stack frame.
|
|
//
|
|
|
|
ldq t0, -CfFrameLength + CfA3(a1) // get dispatcher context address
|
|
|
|
ldl t1, DcEstablisherFrame(t0) // copy the establisher frame pointer
|
|
stl t1, DcEstablisherFrame(a3) // to current dispatcher context
|
|
|
|
ldil v0, ExceptionNestedException // set disposition value
|
|
ret zero, (ra) // return
|
|
|
|
//
|
|
// Unwind is in progress - return continue search disposition.
|
|
//
|
|
|
|
10: ldil v0, ExceptionContinueSearch // set disposition value
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlpExceptionHandler
|
|
|
|
SBTTL("Execute Handler for Unwind")
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpExecuteHandlerForUnwind (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN PVOID EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PVOID DispatcherContext,
|
|
// IN PEXCEPTION_ROUTINE ExceptionRoutine
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function allocates a call frame, stores the establisher frame
|
|
// pointer and the context record address in the frame, establishes an
|
|
// exception handler, and then calls the specified exception handler as
|
|
// an unwind handler. If a collided unwind occurs, then the exception
|
|
// handler of this function is called and the establisher frame pointer
|
|
// and context record address are returned to the unwind dispatcher via
|
|
// the dispatcher context parameter. If control is returned to this routine,
|
|
// then the frame is deallocated and the disposition status is returned to
|
|
// the unwind dispatcher.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (a0) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (a1) - Supplies the frame pointer of the establisher
|
|
// of the exception handler that is to be called.
|
|
//
|
|
// ContextRecord (a2) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (a3) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// ExceptionRoutine (a4) - Supplies a pointer to the exception handler that
|
|
// is to be called.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The disposition value returned by the specified exception handler is
|
|
// returned as the function value.
|
|
//
|
|
//--
|
|
|
|
//
|
|
// N.B. This function specifies its own private exception handler.
|
|
//
|
|
|
|
EXCEPTION_HANDLER(RtlpUnwindHandler)
|
|
|
|
NESTED_ENTRY(RtlpExecuteHandlerForUnwind, CfFrameLength, zero)
|
|
|
|
lda sp, -CfFrameLength(sp) // allocate stack frame
|
|
stq ra, CfRa(sp) // save return address
|
|
|
|
PROLOGUE_END
|
|
|
|
//
|
|
// Save the address of the dispatcher context record in our stack frame so
|
|
// that our own exception handler (not the one we're calling) can retrieve it.
|
|
//
|
|
|
|
stq a3, CfA3(sp) // save address of dispatcher context
|
|
|
|
//
|
|
// Now call the exception handler and return its return value as our return
|
|
// value.
|
|
//
|
|
|
|
bic a4, 3, a4 // clear low-order bits (IEEE mode)
|
|
jsr ra, (a4) // call exception handler
|
|
|
|
ldq ra, CfRa(sp) // restore return address
|
|
lda sp, CfFrameLength(sp) // deallocate stack frame
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlpExecuteHandlerForUnwind
|
|
|
|
SBTTL("Local Unwind Handler")
|
|
//++
|
|
//
|
|
// EXCEPTION_DISPOSITION
|
|
// RtlpUnwindHandler (
|
|
// IN PEXCEPTION_RECORD ExceptionRecord,
|
|
// IN PVOID EstablisherFrame,
|
|
// IN OUT PCONTEXT ContextRecord,
|
|
// IN OUT PVOID DispatcherContext
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function is called when a collided unwind occurs. Its function
|
|
// is to retrieve the establisher dispatcher context, copy it to the
|
|
// current dispatcher context, and return a disposition value of nested
|
|
// unwind.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionRecord (a0) - Supplies a pointer to an exception record.
|
|
//
|
|
// EstablisherFrame (a1) - Supplies the frame pointer of the establisher
|
|
// of this exception handler.
|
|
//
|
|
// ContextRecord (a2) - Supplies a pointer to a context record.
|
|
//
|
|
// DispatcherContext (a3) - Supplies a pointer to the dispatcher context
|
|
// record.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// A disposition value ExceptionCollidedUnwind is returned if an unwind is
|
|
// in progress. Otherwise, a value of ExceptionContinueSearch is returned.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlpUnwindHandler)
|
|
|
|
ldl t0, ErExceptionFlags(a0) // get exception flags
|
|
and t0, EXCEPTION_UNWIND, t0 // check if unwind in progress
|
|
beq t0, 10f // if eq, unwind not in progress
|
|
|
|
//
|
|
// Unwind is in progress - return collided unwind disposition.
|
|
//
|
|
|
|
//
|
|
// Convert the given establisher virtual frame pointer (a1) to a real frame
|
|
// pointer (the value of a1 minus CfFrameLength) and retrieve the pointer to
|
|
// the dispatcher context that earlier was stored in the stack frame.
|
|
//
|
|
|
|
ldq t0, -CfFrameLength + CfA3(a1) // get dispatcher context address
|
|
|
|
ldl t1, DcControlPc(t0) // copy the entire dispatcher
|
|
ldl t2, DcFunctionEntry(t0) // context of the establisher
|
|
ldl t3, DcEstablisherFrame(t0) // frame...
|
|
ldl t4, DcContextRecord(t0) //
|
|
|
|
stl t1, DcControlPc(a3) // to the current dispatcher
|
|
stl t2, DcFunctionEntry(a3) // context (it's four words
|
|
stl t3, DcEstablisherFrame(a3) // long).
|
|
stl t4, DcContextRecord(a3) //
|
|
|
|
ldil v0, ExceptionCollidedUnwind // set disposition value
|
|
ret zero, (ra) // return
|
|
|
|
//
|
|
// Unwind is not in progress - return continue search disposition.
|
|
//
|
|
|
|
10: ldil v0, ExceptionContinueSearch // set disposition value
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlpUnwindHandler
|
|
|
|
SBTTL("Execute Exception Filter")
|
|
//++
|
|
//
|
|
// ULONG
|
|
// RtlpExecuteExceptionFilter (
|
|
// PEXCEPTION_POINTERS ExceptionPointers,
|
|
// EXCEPTION_FILTER ExceptionFilter,
|
|
// ULONG EstablisherFrame
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sets the static link and transfers control to the specified
|
|
// exception filter routine.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// ExceptionPointers (a0) - Supplies a pointer to the exception pointers
|
|
// structure.
|
|
//
|
|
// ExceptionFilter (a1) - Supplies the address of the exception filter
|
|
// routine.
|
|
//
|
|
// EstablisherFrame (a2) - Supplies the establisher frame pointer.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// The value returned by the exception filter routine.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlpExecuteExceptionFilter)
|
|
|
|
//
|
|
// The protocol for calling exception filters used by the acc C-compiler is
|
|
// that the uplevel frame pointer is passed in register v0 and the pointer
|
|
// to the exception pointers structure is passed in register a0. The Gem
|
|
// compiler expects the static link in t0. Here we do both.
|
|
//
|
|
|
|
mov a2, v0 // set static link
|
|
mov a2, t0 // set alternate static link
|
|
jmp zero, (a1) // transfer control to exception filter
|
|
|
|
.end RtlpExecuteExceptionFilter
|
|
|
|
SBTTL("Execute Termination Handler")
|
|
//++
|
|
//
|
|
// VOID
|
|
// RtlpExecuteTerminationHandler (
|
|
// BOOLEAN AbnormalTermination,
|
|
// TERMINATION_HANDLER TerminationHandler,
|
|
// ULONG EstablisherFrame
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function sets the static link and transfers control to the specified
|
|
// termination handler routine.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// AbnormalTermination (a0) - Supplies a boolean value that determines
|
|
// whether the termination is abnormal.
|
|
//
|
|
// TerminationHandler (a1) - Supplies the address of the termination handler
|
|
// routine.
|
|
//
|
|
// EstablisherFrame (a2) - Supplies the establisher frame pointer.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlpExecuteTerminationHandler)
|
|
|
|
//
|
|
// The protocol for calling termination handlers used by the acc C-compiler
|
|
// is that the uplevel frame pointer is passed in register v0 and the boolean
|
|
// abnormal termination value is passed in register a0. The Gem compiler
|
|
// expects the static link in t0. Here we do both.
|
|
//
|
|
|
|
mov a2, v0 // set static link
|
|
mov a2, t0 // set alternate static link
|
|
jmp zero, (a1) // transfer control to termination handler
|
|
|
|
.end RtlpExecuteTerminationHandler
|
|
|
|
SBTTL("Get Stack Limits")
|
|
//++
|
|
//
|
|
// VOID
|
|
// RtlpGetStackLimits (
|
|
// OUT PULONG LowLimit,
|
|
// OUT PULONG HighLimit
|
|
// )
|
|
//
|
|
// Routine Description:
|
|
//
|
|
// This function returns the current stack limits based on the current
|
|
// processor mode.
|
|
//
|
|
// Arguments:
|
|
//
|
|
// LowLimit (a0) - Supplies a pointer to a variable that is to receive
|
|
// the low limit of the stack.
|
|
//
|
|
// HighLimit (a1) - Supplies a pointer to a variable that is to receive
|
|
// the high limit of the stack.
|
|
//
|
|
// Return Value:
|
|
//
|
|
// None.
|
|
//
|
|
//--
|
|
|
|
LEAF_ENTRY(RtlpGetStackLimits)
|
|
#if defined(NTOS_KERNEL_RUNTIME)
|
|
|
|
//
|
|
// Current mode is kernel - compute stack limits.
|
|
//
|
|
|
|
GET_INITIAL_KERNEL_STACK // get initial kernel stack in v0
|
|
|
|
mov v0, t1 // copy high limit of kernel stack
|
|
GET_CURRENT_THREAD // get current thread in v0
|
|
ldl t2, ThStackLimit(v0) // get low limit of kernel stack
|
|
#else
|
|
|
|
//
|
|
// Current mode is user - get stack limits from the TEB.
|
|
//
|
|
|
|
GET_THREAD_ENVIRONMENT_BLOCK // get address of TEB in v0
|
|
|
|
ldl t1, TeStackBase(v0) // get high limit of user stack
|
|
ldl t2, TeStackLimit(v0) // get low limit of user stack
|
|
#endif
|
|
|
|
stl t2, 0(a0) // store low stack limit
|
|
stl t1, 0(a1) // store high stack limit
|
|
ret zero, (ra) // return
|
|
|
|
.end RtlpGetStackLimits
|