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.
456 lines
9.0 KiB
456 lines
9.0 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
stack.c
|
|
|
|
Abstract:
|
|
|
|
This provides a generic stack handler to push/pop things onto it
|
|
|
|
Author:
|
|
|
|
Stephane Plante (splante)
|
|
|
|
Environment:
|
|
|
|
User, Kernel
|
|
|
|
--*/
|
|
|
|
#include "pch.h"
|
|
|
|
NTSTATUS
|
|
StackAllocate(
|
|
OUT PSTACK *Stack,
|
|
IN ULONG StackElementSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates memory and returns a stack object
|
|
|
|
Arguments:
|
|
|
|
Stack - Where to store a pointer to the stack
|
|
StackElementSize - How much space on the stack a single element takes
|
|
up
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSTACK tempStack;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
//
|
|
// Make sure that we have some place to store the stack pointer
|
|
//
|
|
ASSERT( Stack != NULL );
|
|
ASSERT( StackElementSize != 0 );
|
|
|
|
//
|
|
// Allocate a block of memory for the stack
|
|
//
|
|
tempStack = MEMORY_ALLOCATE(
|
|
sizeof(STACK) + ( (STACK_GROWTH_RATE * StackElementSize) - 1)
|
|
);
|
|
if (tempStack == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
goto StackAllocateExit;
|
|
}
|
|
|
|
//
|
|
// Setup the control block of the stack
|
|
//
|
|
tempStack->Signature = (ULONG) STACK_SIGNATURE;
|
|
tempStack->StackSize = STACK_GROWTH_RATE * StackElementSize;
|
|
tempStack->StackElementSize = StackElementSize;
|
|
tempStack->TopOfStack = 0;
|
|
|
|
//
|
|
// Zero out the current elements on the stack
|
|
//
|
|
MEMORY_ZERO(
|
|
&(tempStack->Stack[0]),
|
|
STACK_GROWTH_RATE * StackElementSize
|
|
);
|
|
|
|
//
|
|
// Return the stack pointer
|
|
//
|
|
StackAllocateExit:
|
|
*Stack = tempStack;
|
|
return status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
StackFree(
|
|
IN OUT PSTACK *Stack
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the stack
|
|
|
|
Arguments:
|
|
|
|
Stack - Where to find a pointer to the stack
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Make sure that we point to something
|
|
//
|
|
ASSERT( Stack != NULL );
|
|
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
|
|
|
|
//
|
|
// Free the stack
|
|
//
|
|
MEMORY_FREE( *Stack );
|
|
|
|
//
|
|
// Point the stack to nowhere
|
|
//
|
|
*Stack = NULL;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
StackParent(
|
|
IN OUT PSTACK *Stack,
|
|
IN PVOID Child,
|
|
OUT PVOID Parent
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns a pointer to the stack location that is before
|
|
the given Child.
|
|
|
|
Arguments:
|
|
|
|
Stack - The stack to operate on
|
|
Child - This is the node whose parent we want
|
|
Parent - This is where we store a pointer to the parent stack loc
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSTACK localStack;
|
|
ULONG Addr = (ULONG) Child;
|
|
|
|
//
|
|
// Make sure that we point to something
|
|
//
|
|
ASSERT( Stack != NULL );
|
|
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
|
|
ASSERT( Parent != NULL );
|
|
|
|
//
|
|
// make sure that the child node actually lies on the stack
|
|
//
|
|
localStack = *Stack;
|
|
if ( Addr < (ULONG) localStack->Stack ||
|
|
Addr > (ULONG) &(localStack->Stack[localStack->TopOfStack + 1]) -
|
|
localStack->StackElementSize ) {
|
|
|
|
*( (PULONG *)Parent) = NULL;
|
|
return STATUS_FAIL_CHECK;
|
|
|
|
}
|
|
|
|
//
|
|
// Make sure that the child node isn't the first element
|
|
//
|
|
if (Addr < (ULONG) &(localStack->Stack[localStack->StackElementSize]) ) {
|
|
|
|
*( (PULONG *)Parent) = NULL;
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Set the parent to be one before the child
|
|
//
|
|
*( (PULONG *)Parent) = (PULONG) (Addr - localStack->StackElementSize);
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
StackPop(
|
|
IN OUT PSTACK *Stack
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reclaims the memory used for a stack location
|
|
and wipes out whatever data existed in the reclaimed area
|
|
|
|
Arguments:
|
|
|
|
Stack - Where to find a pointer to the stack
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSTACK localStack;
|
|
|
|
//
|
|
// Make sure that we point to something
|
|
//
|
|
ASSERT( Stack != NULL );
|
|
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
|
|
|
|
//
|
|
// Is there an item that we can remove from the stack?
|
|
//
|
|
localStack = *Stack;
|
|
if ( localStack->TopOfStack == 0) {
|
|
|
|
return STATUS_FAIL_CHECK;
|
|
|
|
}
|
|
|
|
//
|
|
// Wipe out the top-most element on the stack
|
|
//
|
|
localStack->TopOfStack -= localStack->StackElementSize;
|
|
MEMORY_ZERO(
|
|
&( localStack->Stack[ localStack->TopOfStack ] ),
|
|
localStack->StackElementSize
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
StackPush(
|
|
IN OUT PSTACK *Stack,
|
|
OUT PVOID StackElement
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine obtains a pointer for an object on the top of the stack
|
|
and increments the top to point to something that can be then be used
|
|
again.
|
|
|
|
Arguments:
|
|
|
|
Stack - Where to find a pointer to the stack
|
|
StackElement - Pointer to the element to be added to the stack
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSTACK localStack;
|
|
PSTACK tempStack;
|
|
ULONG newSize;
|
|
ULONG deltaSize;
|
|
|
|
//
|
|
// Make sure that we point to something
|
|
//
|
|
ASSERT( Stack != NULL );
|
|
ASSERT( StackElement != NULL );
|
|
|
|
//
|
|
// Find the stack pointer and make sure that the signature is still
|
|
// valid
|
|
//
|
|
localStack = *Stack;
|
|
ASSERT( localStack->Signature == STACK_SIGNATURE );
|
|
|
|
//
|
|
// Do we have enough space on the stack?
|
|
//
|
|
if ( localStack->TopOfStack >= localStack->StackSize ) {
|
|
|
|
//
|
|
// Figure out how many bytes by which to grow the stack and how
|
|
// large the total stack should be
|
|
//
|
|
deltaSize = (STACK_GROWTH_RATE * localStack->StackElementSize);
|
|
newSize = sizeof(STACK) + localStack->StackSize + deltaSize - 1;
|
|
|
|
//
|
|
// Grow the stack
|
|
//
|
|
tempStack = MEMORY_ALLOCATE( newSize );
|
|
if (tempStack == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
//
|
|
// Empty the new stack and copy the old one to it
|
|
//
|
|
MEMORY_ZERO( &(tempStack->Stack[0]), newSize - sizeof(STACK) + 1);
|
|
MEMORY_COPY( tempStack, localStack , newSize - deltaSize);
|
|
|
|
//
|
|
// Make sure that the new stack has the correct size
|
|
//
|
|
tempStack->StackSize += deltaSize;
|
|
|
|
//
|
|
// Free the old stack
|
|
//
|
|
StackFree( Stack );
|
|
|
|
//
|
|
// Set the stack to point to the new one
|
|
//
|
|
*Stack = localStack = tempStack;
|
|
|
|
}
|
|
|
|
//
|
|
// Grab a pointer to the part that we will return to the caller
|
|
//
|
|
*( (PUCHAR *)StackElement) = &(localStack->Stack[ localStack->TopOfStack ]);
|
|
|
|
//
|
|
// Find the new Top of Stack
|
|
//
|
|
localStack->TopOfStack += localStack->StackElementSize;
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
StackRoot(
|
|
IN OUT PSTACK *Stack,
|
|
OUT PVOID RootElement
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the first element on the stack
|
|
|
|
Arguments:
|
|
|
|
Stack - Where the stack is located
|
|
RootElement - Where to store the pointer to the root stack element
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSTACK localStack;
|
|
|
|
ASSERT( Stack != NULL && *Stack != NULL );
|
|
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
|
|
|
|
localStack = *Stack;
|
|
if (localStack->TopOfStack < localStack->StackElementSize) {
|
|
|
|
//
|
|
// There is no stack location we can use
|
|
//
|
|
*( (PUCHAR *)RootElement) = NULL;
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
//
|
|
// Grab the root element
|
|
//
|
|
*( (PUCHAR *)RootElement) = localStack->Stack;
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
StackTop(
|
|
IN OUT PSTACK *Stack,
|
|
OUT PVOID TopElement
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the topmost stack location that is in current use
|
|
|
|
Arguments:
|
|
|
|
Stack - Where the stack is located
|
|
TopElement - Where to store the pointer to the top stack element
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PSTACK localStack;
|
|
ULONG offset;
|
|
|
|
ASSERT( Stack != NULL );
|
|
ASSERT( (*Stack)->Signature == STACK_SIGNATURE );
|
|
|
|
localStack = *Stack;
|
|
if (localStack->TopOfStack < localStack->StackElementSize) {
|
|
|
|
//
|
|
// No stack locations are in current use
|
|
//
|
|
*( (PUCHAR *)TopElement) = NULL;
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
} else {
|
|
|
|
offset = localStack->TopOfStack - localStack->StackElementSize;
|
|
}
|
|
|
|
//
|
|
// Grab the top stack location
|
|
//
|
|
*( (PUCHAR *)TopElement) = &(localStack->Stack[ offset ]);
|
|
|
|
//
|
|
// Done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|