//                                        Ruler
//       1         2         3         4         5         6         7         8
//345678901234567890123456789012345678901234567890123456789012345678901234567890

    /********************************************************************/
    /*                                                                  */
    /*   The standard layout.                                           */
    /*                                                                  */
    /*   The standard layout for 'cpp' files in this code is as         */
    /*   follows:                                                       */
    /*                                                                  */
    /*      1. Include files.                                           */
    /*      2. Constants local to the class.                            */
    /*      3. Data structures local to the class.                      */
    /*      4. Data initializations.                                    */
    /*      5. Static functions.                                        */
    /*      6. Class functions.                                         */
    /*                                                                  */
    /*   The constructor is typically the first function, class         */
    /*   member functions appear in alphabetical order with the         */
    /*   destructor appearing at the end of the file.  Any section      */
    /*   or function this is not required is simply omitted.            */
    /*                                                                  */
    /********************************************************************/

#include "InterfacePCH.hpp"

#include "CallStack.hpp"
#include "DebugHeap.hpp"
#include "Globallock.hpp"
#include "RockallDebugBackEnd.hpp"

    /********************************************************************/
    /*                                                                  */
    /*   Constants local to the class.                                  */
    /*                                                                  */
    /*   The constants supplied here try to make the layout of the      */
    /*   the caches easier to understand and update.  Additionally,     */
    /*   there are also various guard related constants.                */
    /*                                                                  */
    /********************************************************************/

CONST SBIT32 MaxContents			  = 32;
CONST SBIT32 DebugBufferSize		  = 256;
CONST SBIT32 SkipFunctions			  = 2;
CONST SBIT32 Stride1				  = 4;
CONST SBIT32 Stride2				  = 1024;

    /********************************************************************/
    /*                                                                  */
    /*   The description of the heap.                                   */
    /*                                                                  */
    /*   A heap is a collection of fixed sized allocation caches.       */
    /*   An allocation cache consists of an allocation size, the        */
    /*   number of pre-built allocations to cache, a chunk size and     */
    /*   a parent page size which is sub-divided to create elements     */
    /*   for this cache.  A heap consists of two arrays of caches.      */
    /*   Each of these arrays has a stride (i.e. 'Stride1' and          */
    /*   'Stride2') which is typically the smallest common factor of    */
    /*   all the allocation sizes in the array.                         */
    /*                                                                  */
    /********************************************************************/

STATIC ROCKALL_FRONT_END::CACHE_DETAILS Caches1[] =
	{
	    //
	    //   Bucket   Size Of   Bucket   Parent
	    //    Size     Cache    Chunks  Page Size
		//
		{        4,        0,       32,       32 },
		{        8,        0,       32,       32 },
		{       12,        0,       64,       64 },
		{       16,        0,       64,       64 },
		{       20,        0,       64,       64 },
		{       24,        0,      128,      128 },
		{       28,        0,      256,      256 },

		{       32,        0,       64,       64 },
		{       40,        0,      128,      128 },
		{       48,        0,      256,      256 },
		{       56,        0,      512,      512 },

		{       64,        0,      128,      128 },
		{       80,        0,      512,      512 },
		{       96,        0,      512,      512 },
		{      112,        0,     1024,     1024 },

		{      128,        0,      256,      256 },
		{      160,        0,      512,      512 },
		{      192,        0,     1024,     1024 },
		{      224,        0,      512,      512 },

		{      256,        0,      512,      512 },
		{      320,        0,     1024,     1024 },
		{      384,        0,     2048,     2048 },
		{      448,        0,     4096,     4096 },
		{      512,        0,     1024,     1024 },
		{      576,        0,     8192,     8192 },
		{      640,        0,     4096,     4096 },
		{      704,        0,     4096,     4096 },
		{      768,        0,     4096,     4096 },
		{      832,        0,     8192,     8192 },
		{      896,        0,     8192,     8192 },
		{      960,        0,     4096,     4096 },
		{ 0,0,0,0 }
	};

STATIC ROCKALL_FRONT_END::CACHE_DETAILS Caches2[] =
	{
	    //
	    //   Bucket   Size Of   Bucket   Parent
	    //    Size     Cache    Chunks  Page Size
		//
		{     1024,        0,     2048,     2048 },
		{     2048,        0,     4096,     4096 },
		{     3072,        0,    65536,    65536 },
		{     4096,        0,     8192,     8192 },
		{     5120,        0,    65536,    65536 },
		{     6144,        0,    65536,    65536 },
		{     7168,        0,    65536,    65536 },
		{     8192,        0,    65536,    65536 },
		{     9216,        0,    65536,    65536 },
		{    10240,        0,    65536,    65536 },
		{    12288,        0,    65536,    65536 },
		{    16384,        0,    65536,    65536 },
		{    21504,        0,    65536,    65536 },
		{    32768,        0,    65536,    65536 },

		{    65536,        0,    65536,    65536 },
		{    65536,        0,    65536,    65536 },
		{ 0,0,0,0 }
	};

    /********************************************************************/
    /*                                                                  */
    /*   Static data structures.                                        */
    /*                                                                  */
    /*   The static data structures are initialized and prepared for    */
    /*   use here.                                                      */
    /*                                                                  */
    /********************************************************************/

#pragma init_seg(compiler)
STATIC ROCKALL_DEBUG_BACK_END RockallDebugBackEnd( true,false );

    /********************************************************************/
    /*                                                                  */
    /*   Class constructor.                                             */
    /*                                                                  */
    /*   The overall structure and layout of the heap is controlled     */
    /*   by the various constants and calls made in this function.      */
    /*   There is a significant amount of flexibility available to      */
    /*   a heap which can lead to them having dramatically different    */
    /*   properties.                                                    */
    /*                                                                  */
    /********************************************************************/

DEBUG_HEAP::DEBUG_HEAP
		( 
		int							  MaxFreeSpace,
		bool						  Recycle,
		bool						  SingleImage,
		bool						  ThreadSafe,
		//
		//   Additional debug flags.
		//
		bool						  FunctionTrace,
		bool						  TrapOnUserError
		) :
		//
		//   Call the constructors for the contained classes.
		//
		ROCKALL_DEBUG_FRONT_END
			(
			Caches1,
			Caches2,
			MaxFreeSpace,
			& RockallDebugBackEnd,
			Recycle,
			SingleImage,
			Stride1,
			Stride2,
			ThreadSafe
			)
	{
	//
	//   We will only enable the symbols if they are
	//   requested by the user.  If not we will zero
	//   the class pointer.
	//
	if ( FunctionTrace )
		{
		//
		//   We will try to allocate some space so we can
		//   support the annoation of memory allocations
		//   will call traces.
		//
		CallStack = ((CALL_STACK*) SpecialNew( sizeof(CALL_STACK) ));
		
		//
		//   We ensure that we were able to allocate the 
		//   required space.
		//
		if ( CallStack != NULL )
			{ PLACEMENT_NEW( CallStack,CALL_STACK ); }
		}
	else
		{ CallStack = NULL; }

	//
	//   We know that Rockall can survive a wide variety
	//   of user errors.  Nonetheless, we can optionally 
	//   raise an exception whn there is an error.
	//
	ExitOnError = TrapOnUserError;
	}

    /********************************************************************/
    /*                                                                  */
    /*   Compute the heap address.                                      */
    /*                                                                  */
    /*   Compute the heap address from the user address.                */
    /*                                                                  */
    /********************************************************************/

void *DEBUG_HEAP::ComputeHeapAddress( void *Address )
	{ return ((void*) (((char*) Address) - sizeof(HEADER))); }

    /********************************************************************/
    /*                                                                  */
    /*   Compute the user address.                                      */
    /*                                                                  */
    /*   Compute the user address from the heap address.                */
    /*                                                                  */
    /********************************************************************/

void *DEBUG_HEAP::ComputeUserAddress( void *Address )
	{ return ((void*) (((char*) Address) + sizeof(HEADER))); }

    /********************************************************************/
    /*                                                                  */
    /*   Compute the user space.                                        */
    /*                                                                  */
    /*   Compute the user space from the supplied size.                 */
    /*                                                                  */
    /********************************************************************/

int DEBUG_HEAP::ComputeUserSpace( int Space )
	{ return (Space - sizeof(HEADER_AND_TRAILER)); }

    /********************************************************************/
    /*                                                                  */
    /*   Delete the guard words.                                        */
    /*                                                                  */
    /*   When we delete a memory allocation we overwrite it with        */
    /*   guard words to make it really unpleasant for anyone who        */
    /*   reads it and easy to spot when anyone write to it.             */
    /*                                                                  */
    /********************************************************************/

void DEBUG_HEAP::DeleteGuard( void *Address )
	{
	AUTO HEADER *Header;
	AUTO TRAILER *Trailer;
	AUTO int Space;

	//
	//   Although we are about to delete the memory
	//   allocation there is still a chance that it
	//   got corrupted.  So we need to verify that
	//   it is still undamaged.
	//
	if ( VerifyHeaderAndTrailer( Address,& Header,& Space,& Trailer,false ) )
		{
		//
		//   We need to overwrite all of the allocation
		//   to ensure that if the code tries to read 
		//   any existing data that it is overwritten.
		//
		WriteGuardWords( ((void*) Header),Space );

		//
		//   Delete the allocation.  This really ought 
		//   to work given we have already checked that 
		//   the allocation is valid unless there is a  
		//   race condition.
		//
		if ( ! ROCKALL_FRONT_END::Delete( ((void*) Header),Space ) )
			{ UserError( Address,NULL,"Delete failed due to race" ); }
		}
	}

    /********************************************************************/
    /*                                                                  */
    /*   Print a list of heap leaks.                                    */
    /*                                                                  */
    /*   We walk the heap and output a list of active heap              */
    /*   allocations to the debug window,                               */
    /*                                                                  */
    /********************************************************************/

void DEBUG_HEAP::HeapLeaks( void )
    {
	AUTO bool Active;
	AUTO void *Address = NULL;
	AUTO int Space;

	//
	//   Walk the heap and find all the active and
	//   available spece.  We would normally expect
	//   this to be proportional to the size of the
	//   heap.
	//
	while ( WalkGuard( & Active,& Address,& Space ) )
		{
		AUTO CHAR Contents[ ((MaxContents + 4) * 2) ];

#ifndef OUTPUT_FREE_SPACE

		//
		//   We report all active heap allocations
		//   just so the user knows there are leaks.
		//
		if ( Active )
			{
#endif
			AUTO HEADER *Header = ((HEADER*) ComputeHeapAddress( Address ) );
			AUTO SBIT32 Count;

			//
			//   Format the contents string into hexadecimal
			//   ready for output.
			//
			for 
					( 
					Count=0;
					((Count < MaxContents) && (Count < Header -> Size));
					Count += sizeof(SBIT32)
					)
				{
				REGISTER CHAR *Value =
					(((CHAR*) Header) + Count + sizeof(HEADER));

				//
				//   Format each byte into hexadecimal.
				//
				sprintf
					(
					& Contents[ (Count * 2) ],
					"%08x",
					(*((SBIT32*) Value))
					);
				}

			//
			//   Terminate the string.  If it was too long 
			//   then add the postfix "..." to the end.
			//
			if ( Count < MaxContents )
				{ Contents[ (Count * 2) ] = '\0'; }
			else
				{
				REGISTER CHAR *End = & Contents[ (Count * 2) ];

				End[0] = '.';
				End[1] = '.';
				End[2] = '.';
				End[3] = '\0';
				}

			//
			//   Format the message to be printed.
			//
			DebugPrint
				(
				"\nDetails of Memory Leak\n"
				"Active      : %d\n"
				"Address     : 0x%x\n"
				"Bytes       : %d\n"
				"Contents    : 0x%s\n",
				Active,
				((SBIT32) Address),
				Header -> Size,
				Contents
				);

			//
			//   We will generate a call trace if this
			//   is enabled.
			//
			if ( CallStack != NULL )
				{
				//
				//   Even when enabled there is a chance
				//   that the symbol subsystem could
				//   not walk the stack.
				//
				if ( Header -> Count > 0 )
					{
					AUTO CHAR Buffer[ DebugBufferSize ];

					//
					//   We add the call stack information
					//   if there is enough space.
					//
					CallStack -> FormatCallStack
						(
						Buffer,
						Header -> Functions,
						DebugBufferSize,
						Header -> Count
						);

					//
					//   Format the message to be printed.
					//
					DebugPrint
						(
						"Origin      : (See 'Call Stack')\n"
						"\n"
						"Call Stack at Allocation:\n"
						"%s\n",
						Buffer
						);
					}
				else
					{
					//
					//   Explain why there is no 'Call Stack'.
					//
					DebugPrint
						(
						"Origin      : Unknown ('StackWalk' in 'ImageHlp.DLL' "
						"was unable to walk the call stack)\n"
						);
					}
				}
			else
				{ 
				//
				//   Explain why there is no 'Call Stack'.
				//
				DebugPrint( "Origin      : 'Call Stack' is Disabled\n" ); 
				}
#ifndef OUTPUT_FREE_SPACE
			}
#endif
		}
	}

    /********************************************************************/
    /*                                                                  */
    /*   New guard words.                                               */
    /*                                                                  */
    /*   When we make a memory allocation we verify that the guard      */
    /*   words are still unmodified.  We then setup the debug           */
    /*   information so it describes the allocation.                    */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::NewGuard( void **Address,int Size,int *Space )
	{
	AUTO int ActualSize;
	AUTO SBIT32 MinimumSize =
		(((Size + sizeof(HEADER_AND_TRAILER)) + GuardMask) & ~GuardMask);
	AUTO HEADER *Header = 
		((HEADER*) ROCKALL_FRONT_END::New( MinimumSize,& ActualSize,false ));

	//
	//   We need to be sure that the memory allocation
	//   was sucessful.
	//
	if ( ((void*) Header) != ((void*) AllocationFailure) )
		{
		//
		//   We need to compute the address of the area 
		//   available to the caller and return the space
		//   available if requested.
		//
		(*Address) = ComputeUserAddress( ((void*) Header) );

		if ( Space != NULL )
			{ (*Space) = ComputeUserSpace( ActualSize ); }

		//
		//   We need to make sure that the memory has
		//   not been damaged in any way.
		//
		if ( ! VerifyGuardWords( ((void*) Header),ActualSize ) )
			{
			//
			//   Complain about the damaged guard words
			//   and repair it so processing can continue.
			//
			UserError( (*Address),NULL,"Area damaged since deletion" );

			WriteGuardWords( ((void*) Header),ActualSize );
			}

		//
		//   We now set up the header information that 
		//   describes the memory allocation.
		//
		Header -> Count = 0;
		Header -> Size = ((Space == NULL) ? Size : (*Space));

		//
		//   We will extract the current call stack if 
		//   needed and store it in the memory allocation.
		//
		if ( CallStack != NULL )
			{
			Header -> Count =
				(
				CallStack -> GetCallStack
					( 
					Header -> Functions,
					MaxFunctions,
					SkipFunctions
					)
				);
			}

		return true;
		}
	else
		{ return false; }
	}

    /********************************************************************/
    /*                                                                  */
    /*   Verify the supplied address.                                   */
    /*                                                                  */
    /*   We verify that the supplied address appaers to be a valid      */
    /*   debug memory allocation.  If not we complain and exit.         */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::VerifyAddress
		(
		void						  *Address,
		HEADER						  **Header,
		int							  *Space,
		bool						  Verify
		)
	{
	//
	//   Lets be really paranoid and make sure that
	//   this heap knows about the supplied address.
	//
	if ( ROCKALL_FRONT_END::KnownArea( Address ) )
		{
		REGISTER void *NewAddress = ComputeHeapAddress( Address );

		//
		//   Ask for the details of the allocation.  This 
		//   will fail if the memory is not allocated.
		//
		if ( ROCKALL_FRONT_END::Verify( ((void*) NewAddress),Space ) )
			{
			//
			//   Lets be even more paranoid and make sure
			//   that the address is correctly aligned
			//   and memory allocation is large enough to
			//   contain the necessary debug information.
			//
			if
					(
					((((int) NewAddress) & GuardMask) == 0)
						&&
					((*Space) >= sizeof(HEADER_AND_TRAILER))
						&&
					(((*Space) & GuardMask) == 0)
					)
				{
				//
				//   When we have established that the address
				//   seems to be valid we can return it to
				//   the caller.
				//
				(*Header) = ((HEADER*) NewAddress);

				return true;
				}
			else
				{
				//
				//   When the address is refers to something
				//   that does not appear to be from the debug
				//   heap we complain about it to the user.
				//
				UserError( Address,NULL,"Address unsuitable for debugging" );

				return false; 
				}
			}
		else
			{
			//
			//   When the address is refers to something
			//   that does not appear to be from Rockall
			//   heap we complain about it to the user.
			//
			if ( ! Verify )
				{ UserError( Address,NULL,"Address not allocated" ); }

			return false; 
			}
		}
	else
		{
		//
		//   When the address is clearly bogus we complain
		//   about it to the user.
		//
		if ( ! Verify )
			{ UserError( Address,NULL,"Address falls outside the heap" ); }

		return false;
		}
	}

    /********************************************************************/
    /*                                                                  */
    /*   Verify the guard words.                                        */
    /*                                                                  */
    /*   When we verify a memory allocation we ensure that the          */
    /*   guard words are all undamaged.  If we find a problem we        */
    /*   complain and repair the damage.                                */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::VerifyGuard( void *Address,int *Size,int *Space )
	{
	AUTO HEADER *Header;
	AUTO TRAILER *Trailer;

	//
	//   We would like to verify that the allocated
	//   area is still undamaged and extract various
	//   information about it.
	//
	if ( VerifyHeaderAndTrailer( Address,& Header,Space,& Trailer,true ) )
		{
		//
		//   We know that Rockall typically allocates
		//   a few more bytes than requested.  However,
		//   when we are debugging we pretend that this
		//   is not the case and fill the extra space 
		//   with guard words.  However, if we are asked
		//   the actual size then the game it is up and  
		//   we update the necessary fields.
		//
		if ( Space != NULL )
			{
			//
			//   Compute the available user space and
			//   update the internal sizes.
			//
			Header -> Size = ComputeUserSpace( (*Space) );

			(*Space) = Header -> Size;
			}

		//
		//   We need to return what we believe is the the 
		//   size of the user area and the total amount of
		//   user available space.
		//   
		(*Size) = Header -> Size;

		return true;
		}
	else
		{ return false; }
	}

    /********************************************************************/
    /*                                                                  */
    /*   Verify a string of guard words.                                */
    /*                                                                  */
    /*   We need to verify the guard words a various times to ensure    */
    /*   they have not been damaged.                                    */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::VerifyGuardWords( void *Address,int Size )
	{
	REGISTER SBIT32 Size1 = (((long) Address) & GuardMask);
	REGISTER SBIT32 Size2 = ((GuardSize - Size1) & GuardMask);
	REGISTER SBIT32 Size3 = ((Size - Size2) / GuardSize);
	REGISTER SBIT32 Size4 = (Size - Size2 - (Size3 * GuardSize));
	REGISTER SBIT32 *Word = ((SBIT32*) (((long) Address) & ~GuardMask));

	//
	//   Although a guard word area typically starts 
	//   on a word aligned boundary it can sometimes 
	//   start on a byte aligned boundary.
	//   
	if ( Size2 > 0 )
		{
		REGISTER SBIT32 Mask = ~((1 << (Size1 * 8)) - 1);

		//
		//   Examine the partial word and make sure
		//   the guard bytes are unmodified.
		//
		if ( ((*(Word ++)) & Mask) != (GuardValue & Mask) )
			{ return false; }
		}

	//
	//   When there is a collection of aligned guard words
	//   we can quickly verify them.
	//
	if ( Size3 > 0 )
		{
		//
		//   Verify each guard word is unmodified.
		//
		for ( Size3 --;Size3 >= 0;Size3 -- )
			{ 
			if ( Word[ Size3 ] != GuardValue )
				{ return false; }
			}
		}

	//
	//   Although a guard word area typically ends 
	//   on a word aligned boundary it can sometimes 
	//   end on a byte aligned boundary.
	//   
	if ( Size4 > 0 )
		{
		REGISTER SBIT32 Mask = ((1 << ((GuardSize - Size4) * 8)) - 1);

		//
		//   Examine the partial word and make sure
		//   the guard bytes are unmodified.
		//
		if ( ((*(Word ++)) & Mask) != (GuardValue & Mask) )
			{ return false; }
		}

	return true;
	}

    /********************************************************************/
    /*                                                                  */
    /*   Verify the header.                                             */
    /*                                                                  */
    /*   We verify that the suppied address appears to map to a         */
    /*   valid debug header.  If not we complain and exit.              */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::VerifyHeader
		(
		void						  *Address,
		HEADER						  **Header,
		int							  *Space,
		bool						  Verify
		)

	{
	//
	//   We check that the address supplied seems
	//   to make sense before examining the header
	//   and testing the guard words.
	//
	if ( VerifyAddress( Address,Header,Space,Verify ) )
		{
		REGISTER int MaxSpace = 
			((int) ((*Header) -> Size + sizeof(HEADER_AND_TRAILER)));

		//
		//   We are now fairly confident that the
		//   address is (or was at one time) a valid
		//   debug mory allocation.  So lets examine
		//   the header to see if it still seems valid.
		//
		if
				(
				((*Header) -> Count >= 0)
					&&
				((*Header) -> Count <= MaxFunctions)
					&&
				((*Header) -> Size >= 0)
					&&
				(MaxSpace <= (*Space))
				)
			{
			REGISTER int Count = ((*Header) -> Count);
			REGISTER void *GuardWords = & (*Header) -> Functions[ Count ];
			REGISTER int NumberOfGuardWords = (MaxLeadingGuardWords - Count);
			REGISTER int Size = (NumberOfGuardWords * sizeof(GuardWords));

			//
			//   Verify that the leading guard words
			//   just after the header have not been 
			//   damaged.
			//
			if ( ! VerifyGuardWords( GuardWords,Size ) )
				{
				//
				//   We complain about damaged guard
				//   words and then repair them to prevent
				//   further complaints.
				//
				UserError( Address,(*Header),"Leading guard words corrupt" );

				WriteGuardWords( GuardWords,Size );
				}
			}
		else
			{
			//
			//   When the header has been damaged we 
			//   complain about it to the user and then
			//   try to repair it to prevent further
			//   complaints.
			//
			UserError( Address,NULL,"Leading guard information corrupt" );

			WriteGuardWords( ((void*) Header),sizeof(HEADER) );

			//
			//   We select safe default settings.
			//
			(*Header) -> Count = 0;
			(*Header) -> Size = ((*Space) - sizeof(HEADER_AND_TRAILER));
			}

		return true; 
		}
	else
		{ return false; }
	}

    /********************************************************************/
    /*                                                                  */
    /*   Verify a memory allocation.                                    */
    /*                                                                  */
    /*   We need to verify that the supplied address is an undamaged    */
    /*   memory allocation.                                             */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::VerifyHeaderAndTrailer
		(
		void						  *Address,
		HEADER						  **Header,
		int							  *Space,
		TRAILER						  **Trailer,
		bool						  Verify
		)
	{
	//
	//   We need to know the space occupied by the
	//   allocation to compute the details of the
	//   trailer.  So if the space parameter is null 
	//   we use a local temporary value.
	//
	if ( Space != NULL )
		{
		//
		//   We need to verify the entire memory allocation
		//   and ensure it is fit for use.
		//
		return
			(
			VerifyHeader( Address,Header,Space,Verify )
				&&
			VerifyTrailer( (*Header),(*Space),Trailer )
			);
		}
	else
		{
		AUTO int Temporary;

		//
		//   We need to verify the entire memory allocation
		//   and ensure it is fit for use.
		//
		return
			(
			VerifyHeader( Address,Header,& Temporary,Verify )
				&&
			VerifyTrailer( (*Header),Temporary,Trailer )
			);
		}
	}

    /********************************************************************/
    /*                                                                  */
    /*   Verify the trailer.                                            */
    /*                                                                  */
    /*   We need to verify the guard words a various times to ensure    */
    /*   they have not been damaged.                                    */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::VerifyTrailer
		( 
		HEADER						  *Header,
		int							  Space,
		TRAILER						  **Trailer
		)
	{
	REGISTER SBIT32 Size = (Space - (sizeof(HEADER) + Header -> Size ));

	//
	//   Compute the address of the user area and the
	//   the trailing guard words.
	//
	(*Trailer) = 
		((TRAILER*) (((char*) Header) + sizeof(HEADER) + Header -> Size));

	//
	//   Verify that the trailing guard words
	//   just after the user area are not damaged.
	//
	if ( ! VerifyGuardWords( ((void*) (*Trailer)),Size ) )
		{
		REGISTER void *Address = ComputeUserAddress( ((void*) Header) );

		//
		//   We complain about damaged guard words 
		//   and then repair them to prevent further
		//   complaints.
		//
		UserError( Address,Header,"Trailing guard words corrupt" );

		WriteGuardWords( ((void*) (*Trailer)),Size );
		}

	return true; 
	}

    /********************************************************************/
    /*                                                                  */
    /*   Walk the heap.                                                 */
    /*                                                                  */
    /*   When we verify each memory allocation as we walk the heap      */
    /*   and ensure the guard words are all undamaged.  If we find a    */
    /*   problem we complain and repair the damage.                     */
    /*                                                                  */
    /********************************************************************/

bool DEBUG_HEAP::WalkGuard( bool *Active,void **Address,int *Space )
	{
	//
	//   We may need to convert the supplied user
	//   address into a heap address so we can walk
	//   the heap.
	//
	if ( (*Address) != ((void*) AllocationFailure) )
		{ (*Address) = ComputeHeapAddress( (*Address) ); }

	//
	//   Walk the heap.
	//
	if ( ROCKALL_FRONT_END::Walk( Active,Address,Space ) )
		{
		REGISTER void *NewAddress = ComputeUserAddress( (*Address) );

		//
		//   We inspect the guard words to make sure
		//   they have not been overwritten.
		//
		if ( (*Active) )
			{ 
			AUTO HEADER *Header;
			AUTO TRAILER *Trailer;

			//
			//   Although we are about to delete the memory
			//   allocation there is still a chance that it
			//   got corrupted.  So we need to verify that
			//   it is still undamaged.
			//
			VerifyHeaderAndTrailer( NewAddress,& Header,Space,& Trailer,false );
			}
		else
			{
			//
			//   We need to make sure that the memory has
			//   not been damaged in any way.
			//
			if ( ! VerifyGuardWords( (*Address),(*Space) ) )
				{
				//
				//   We need to overwrite the entire alloction
				//   as it has been damaged in some way. 
				//
				UserError( (*Address),NULL,"Area damaged after deletion" );

				WriteGuardWords( (*Address),(*Space) );
				}
			}

		//
		//   Compute the new heap address and adjust
		//   the reported size.
		//
		(*Address) = NewAddress;
		(*Space) = ComputeUserSpace( (*Space) );

		return true;
		}
	else
		{ return false; }
	}

    /********************************************************************/
    /*                                                                  */
    /*   Write a string of guard words.                                 */
    /*                                                                  */
    /*   We need write a string of guard words whenever we allocate     */
    /*   memory or detect some corruption.                              */
    /*                                                                  */
    /********************************************************************/

void DEBUG_HEAP::WriteGuardWords( void *Address,int Size )
	{
	REGISTER SBIT32 Size1 = (((long) Address) & GuardMask);
	REGISTER SBIT32 Size2 = ((GuardSize - Size1) & GuardMask);
	REGISTER SBIT32 Size3 = ((Size - Size2) / GuardSize);
	REGISTER SBIT32 Size4 = (Size - Size2 - (Size3 * GuardSize));
	REGISTER SBIT32 *Word = ((SBIT32*) (((long) Address) & ~GuardMask));

	//
	//   Although a guard word area typically starts 
	//   on a word aligned boundary it can sometimes 
	//   start on a byte aligned boundary.
	//   
	if ( Size2 > 0 )
		{
		REGISTER SBIT32 Mask = ~((1 << (Size1 * 8)) - 1);

		//
		//   Write the partial guard word but keep any
		//   existing data in related bytes.
		//
		(*(Word ++)) = (((*Word) & ~Mask) | (GuardValue & Mask));
		}

	//
	//   When there is a collection of aligned guard words
	//   we can quickly write them.
	//
	if ( Size3 > 0 )
		{
		//
		//   Write each guard word.
		//
		for ( Size3 --;Size3 >= 0;Size3 -- )
			{ Word[ Size3 ] = ((SBIT32) GuardValue); }
		}

	//
	//   Although a guard word area typically ends 
	//   on a word aligned boundary it can sometimes 
	//   end on a byte aligned boundary.
	//   
	if ( Size4 > 0 )
		{
		REGISTER SBIT32 Mask = ((1 << ((GuardSize - Size4) * 8)) - 1);

		//
		//   Write the partial guard word but keep any
		//   existing data in related bytes.
		//
		(*(Word ++)) = (((*Word) & ~Mask) | (GuardValue & Mask));
		}
	}

    /********************************************************************/
    /*                                                                  */
    /*   Abort on user error.                                           */
    /*                                                                  */
    /*   When we encounter an error we output all of the information    */
    /*   and throw an exception.                                        */
    /*                                                                  */
    /********************************************************************/

void DEBUG_HEAP::UserError( void *Address,void *Details,char *Message )
	{
	REGISTER HEADER *Header = ((HEADER*) Details);
	STATIC GLOBALLOCK Globallock;

	//
	//   Claim a lock so that multiple threads have
	//   to wait to output any heap statistics.
	//
	Globallock.ClaimLock();

	//
	//   When we have an description of the 
	//   allocation we can complain about it
	//
	if ( Header != NULL )
		{
		AUTO CHAR Contents[ ((MaxContents + 4) * 2) ];
		AUTO SBIT32 Count;

		//
		//   Format the contents string into hexadecimal
		//   ready for output.
		//
		for 
				( 
				Count=0;
				((Count < MaxContents) && (Count < Header -> Size));
				Count += sizeof(SBIT32)
				)
			{
			REGISTER CHAR *Value =
				(((CHAR*) Header) + Count + sizeof(HEADER));

			//
			//   Format each byte into hexadecimal.
			//
			sprintf
				(
				& Contents[ (Count * 2) ],
				"%08x",
				(*((SBIT32*) Value))
				);
			}

		//
		//   Terminate the string.  If it was too long 
		//   then add the postfix "..." to the end.
		//
		if ( Count < MaxContents )
			{ Contents[ (Count * 2) ] = '\0'; }
		else
			{
			REGISTER CHAR *End = & Contents[ (Count * 2) ];

			End[0] = '.';
			End[1] = '.';
			End[2] = '.';
			End[3] = '\0';
			}

		//
		//   Format the message to be printed.
		//
		DebugPrint
			(
			"\nDetails of Heap Corruption\n"
			"Address     : 0x%x\n"
			"Bytes       : %d\n"
			"Contents    : 0x%s\n"
			"Message     : %s\n",
			Address,
			Header -> Size,
			Contents,
			Message
			);

		//
		//   We will generate a call trace if this
		//   is enabled.
		//
		if ( CallStack != NULL )
			{
			//
			//   Even when enabled there is a chance
			//   that the symbol subsystem could
			//   not walk the stack.
			//
			if ( Header -> Count > 0 )
				{
				AUTO CHAR Buffer[ DebugBufferSize ];

				//
				//   We add the call stack information
				//   if there is enough space.
				//
				CallStack -> FormatCallStack
					(
					Buffer,
					Header -> Functions,
					DebugBufferSize,
					Header -> Count
					);

				//
				//   Format the message to be printed.
				//
				DebugPrint
					(
					"Origin      : (See 'Call Stack')\n\n"
					"Call Stack at Allocation:\n"
					"%s\n",
					Buffer
					);
				}
			else
				{
				//
				//   Explain why there is no 'Call Stack'.
				//
				DebugPrint
					(
					"Origin      : Unknown ('StackWalk' in 'ImageHlp.DLL' "
					"was unable to walk the call stack)\n"
					);
				}
			}
		else
			{ 
			//
			//   Explain why there is no 'Call Stack'.
			//
			DebugPrint( "Origin      : 'Call Stack' is Disabled\n" ); 
			}
		}
	else
		{
		//
		//   Format the message to be printed.
		//
		DebugPrint
			(
			"\nDetails of Heap Corruption\n"
			"Address     : 0x%x\n"
			"Bytes       : (unknown)\n"
			"Contents    : (unknown)\n"
			"Message     : %s\n\n",
			Address,
			Message
			);
		}

	//
	//   Relesae the lock.
	//
	Globallock.ReleaseLock();

	//
	//   Terminate the application (if enabled).
	//
	if ( ExitOnError )
		{ Failure( Message ); }
	}

    /********************************************************************/
    /*                                                                  */
    /*   Class destructor.                                              */
    /*                                                                  */
    /*   Destory the current instance of the class.                     */
    /*                                                                  */
    /********************************************************************/

DEBUG_HEAP::~DEBUG_HEAP( void )
	{
	AUTO bool Active;
	AUTO void *Address = NULL;
	AUTO int Space;

	//
	//   Output a warning message related to debug heaps
	//   and the inflated size of allocations.
	//
	DebugPrint
		( 
		"\n"
		"REMINDER: The heap at 0x%x is a 'DEBUG_HEAP'.\n"
		"REMINDER: All allocations are inflated by %d bytes.\n"
		"\n", 
		this,
		sizeof(HEADER_AND_TRAILER)
		);

	//
	//   Walk the heap to verify all the allocations
	//   so that we know that the heap is undamaged.
	//
	while ( WalkGuard( & Active,& Address,& Space ) );

	//
	//   Destroy the symbols if they are active.
	//
	if ( CallStack != NULL )
		{ PLACEMENT_DELETE( CallStack,CALL_STACK ); }
	}