Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

242 lines
7.5 KiB

/***
*xcptmisc.s
*
* Copyright (c) 1990-1995, Microsoft Corporation. All rights reserved.
*
*Purpose:
*
* 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.
*
*Revision History:
*
****/
#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 Unwind")
//++
//
// EXCEPTION_DISPOSITION
// __CxxExecuteHandlerForUnwind (
// 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(__CxxUnwindHandler)
NESTED_ENTRY(__CxxExecuteHandlerForUnwind, 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 __CxxExecuteHandlerForUnwind
SBTTL("Local Unwind Handler")
//++
//
// EXCEPTION_DISPOSITION
// __CxxUnwindHandler (
// 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(__CxxUnwindHandler)
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 __CxxUnwindHandler
SBTTL("Get Stack Limits")
//++
//
// VOID
// __CxxGetStackLimits (
// 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(__CxxGetStackLimits)
bgt sp, 10f // if sp > 0, then running on user stack
//
// 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
lda t2, -KERNEL_STACK_SIZE(t1) // compute low limit of kernel stack
br zero, 20f // finish in common code
//
// Current mode is user - get stack limits from the TEB.
//
10: 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
20: stl t2, 0(a0) // store low stack limit
stl t1, 0(a1) // store high stack limit
ret zero, (ra) // return
.end __CxxGetStackLimits