diff options
Diffstat (limited to 'SrcShared/EmPalmHeap.cpp')
-rw-r--r-- | SrcShared/EmPalmHeap.cpp | 2263 |
1 files changed, 2263 insertions, 0 deletions
diff --git a/SrcShared/EmPalmHeap.cpp b/SrcShared/EmPalmHeap.cpp new file mode 100644 index 0000000..6745edc --- /dev/null +++ b/SrcShared/EmPalmHeap.cpp @@ -0,0 +1,2263 @@ +/* -*- mode: C++; tab-width: 4 -*- */ +/* ===================================================================== *\ + Copyright (c) 1999-2001 Palm, Inc. or its subsidiaries. + All rights reserved. + + This file is part of the Palm OS Emulator. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. +\* ===================================================================== */ + +#include "EmCommon.h" +#include "EmPalmHeap.h" + +#include "ChunkFile.h" // Chunk, EmStreamChunk +#include "EmErrCodes.h" // kError_CorruptedHeap_Foo +#include "EmMemory.h" // CEnableFullAccess, EmMemGet32, EmMemGet16, EmMemGet8 +#include "ErrorHandling.h" // Errors::ReportErrCorruptedHeap +#include "ROMStubs.h" // MemNumHeaps, MemHeapID, MemHeapPtr +#include "SessionFile.h" // SessionFile + +#include <stdio.h> // sprintf + + +// =========================================================================== +// ¥ EmPalmHeap +// =========================================================================== + +EmPalmHeapList EmPalmHeap::fgHeapList; + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Initialize [ STATIC ] + * + * DESCRIPTION: Standard initialization function. Responsible for + * initializing this sub-system when a new session is + * created. Will be followed by at least one call to + * Reset or Load. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::Initialize (void) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Reset [ STATIC ] + * + * DESCRIPTION: Re-initializes the PalmHeap sub-system. This function + * is called when the ROM is "rebooted" (which includes + * the initial boot-up after a ROM is loaded). + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::Reset (void) +{ + fgHeapList.clear (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Save [ STATIC ] + * + * DESCRIPTION: Standard save function. Saves any sub-system state to + * the given session file. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::Save (SessionFile& f) +{ + const long kCurrentVersion = 1; + + Chunk chunk; + EmStreamChunk s (chunk); + + s << kCurrentVersion; + + s << fgHeapList; + + f.WriteHeapInfo (chunk); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Load [ STATIC ] + * + * DESCRIPTION: Standard load function. Loads any sub-system state + * from the given session file. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::Load (SessionFile& f) +{ + Chunk chunk; + if (f.ReadHeapInfo (chunk)) + { + long version; + EmStreamChunk s (chunk); + + s >> version; + + if (version >= 1) + { + s >> fgHeapList; + } + } + else + { + f.SetCanReload (false); // Need to reboot + } +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Dispose [ STATIC ] + * + * DESCRIPTION: Standard dispose function. Completely release any + * resources acquired or allocated in Initialize and/or + * Load. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::Dispose (void) +{ + fgHeapList.clear (); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapListBegin [ STATIC ] + * + * DESCRIPTION: Return an iterator representing the beginning of our + * list of heap objects. + * + * PARAMETERS: None + * + * RETURNED: The iterator. + * + ***********************************************************************/ + +EmPalmHeapList::const_iterator EmPalmHeap::GetHeapListBegin (void) +{ + return fgHeapList.begin (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapListEnd [ STATIC ] + * + * DESCRIPTION: Return an iterator representing the end of our + * list of heap objects. + * + * PARAMETERS: None + * + * RETURNED: The iterator. + * + ***********************************************************************/ + +EmPalmHeapList::const_iterator EmPalmHeap::GetHeapListEnd (void) +{ + return fgHeapList.end (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapByID [ STATIC ] + * + * DESCRIPTION: Find a heap based on its ID. + * + * PARAMETERS: heapID - the ID to test. + * + * RETURNED: The pointer to the heap object. If no heap object + * has that ID, NULL is returned. + * + ***********************************************************************/ + +const EmPalmHeap* EmPalmHeap::GetHeapByID (UInt16 heapID) +{ + EmPalmHeapList::iterator iter = fgHeapList.begin (); + + while (iter != fgHeapList.end ()) + { + if (iter->fHeapID == heapID) + { + return &*iter; + } + + ++iter; + } + + return NULL; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapByPtr [ STATIC ] + * + * DESCRIPTION: Find a heap based on a pointer. + * + * PARAMETERS: p - the pointer to test. + * + * RETURNED: The pointer to the heap object. If no heap object + * contains the pointer, NULL is returned. + * + ***********************************************************************/ + +const EmPalmHeap* EmPalmHeap::GetHeapByPtr (emuptr p) +{ + return GetHeapByPtr ((MemPtr) p); +} + +const EmPalmHeap* EmPalmHeap::GetHeapByPtr (MemPtr p) +{ + // !!! Could do a binary search here, if needed. + + EmPalmHeapList::iterator iter = fgHeapList.begin (); + + while (iter != fgHeapList.end ()) + { + if (iter->Contains ((emuptr) p)) + { + return &*iter; + } + + ++iter; + } + + return NULL; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapByHdl [ STATIC ] + * + * DESCRIPTION: Find a heap based on a handle. + * + * PARAMETERS: h - the handle to test. + * + * RETURNED: The pointer to the heap object. If no heap object + * contains the handle, NULL is returned. + * + * !!! What to do when the handle and pointer aren't in the same heap? + * + ***********************************************************************/ + +const EmPalmHeap* EmPalmHeap::GetHeapByHdl (MemHandle h) +{ + MemPtr p = DerefHandle (h); + + if (p) + return GetHeapByPtr (p); + + return NULL; +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::MemInitHeapTable [ STATIC ] + * + * DESCRIPTION: All new heaps have been created. Create objects to + * represent those heaps and add them to our list of heaps. + * + * PARAMETERS: Parameters passed to MemInitHeapTable + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::MemInitHeapTable (UInt16 cardNo) +{ + UInt16 numHeaps = ::MemNumHeaps (cardNo); + + for (UInt16 heapIndex = 0; heapIndex < numHeaps; ++heapIndex) + { + UInt16 heapID = ::MemHeapID (cardNo, heapIndex); + + // Add the heap, as long as it's not the dynamic heap. During + // bootup, the memory initialization sequence goes like: + // + // if hard reset required: + // MemCardFormat + // lay out the card + // MemStoreInit + // for each heap + // MemHeapInit + // MemInit + // for each card: + // MemInitHeapTable + // for each dynamic heap: + // MemHeapInit + // for each RAM heap: + // Unlock all chunks + // Compact + // + // Which means that if there's no hard reset, MemHeapInit + // has not been called on the dynamic heap at the time + // MemInitHeapTable is called. And since the dynamic heap + // is currently in a corrupted state (because the boot stack + // and initial LCD buffer have been whapped over it), we + // can't perform the heap walk we'd normally do when adding + // a heap object. + + if (heapID != 0) + AddHeap (heapID); + } +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::MemHeapInit [ STATIC ] + * + * DESCRIPTION: A new heap has been created. Create an object to + * represent that heap and add it to our list of heaps. + * + * PARAMETERS: Parameters passed to MemHeapInit + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::MemHeapInit (UInt16 heapID, Int16, Boolean) +{ + AddHeap (heapID); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::MemHeapCompact [ STATIC ] + * FUNCTION: EmPalmHeap::MemHeapFreeByOwnerID [ STATIC ] + * FUNCTION: EmPalmHeap::MemHeapScramble [ STATIC ] + * FUNCTION: EmPalmHeap::MemChunkNew [ STATIC ] + * FUNCTION: EmPalmHeap::MemChunkFree [ STATIC ] + * FUNCTION: EmPalmHeap::MemPtrNew [ STATIC ] + * FUNCTION: EmPalmHeap::MemPtrResize [ STATIC ] + * FUNCTION: EmPalmHeap::MemHandleNew [ STATIC ] + * FUNCTION: EmPalmHeap::MemHandleResize [ STATIC ] + * FUNCTION: EmPalmHeap::MemHandleFree [ STATIC ] + * FUNCTION: EmPalmHeap::MemLocalIDToLockedPtr [ STATIC ] + * FUNCTION: EmPalmHeap::MemHandleLock [ STATIC ] + * FUNCTION: EmPalmHeap::MemHandleUnlock [ STATIC ] + * FUNCTION: EmPalmHeap::MemHandleResetLock [ STATIC ] + * FUNCTION: EmPalmHeap::MemPtrResetLock [ STATIC ] + * FUNCTION: EmPalmHeap::MemPtrUnlock [ STATIC ] + * + * DESCRIPTION: All of these functions alter the heap in some way. + * Resync our notion of the state of the heap with reality. + * + * PARAMETERS: Parameters to the Memory Manager functions that altered + * the heap. + * + * RETURNED: The chunks that cover the altered range of the heap + * are returned in the "delta" collection. + * + ***********************************************************************/ + +void EmPalmHeap::MemHeapCompact (UInt16 heapID, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemHeapFreeByOwnerID (UInt16 heapID, UInt16, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemHeapScramble (UInt16 heapID, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemChunkNew (UInt16 heapID, MemPtr p, UInt16 attr, EmPalmChunkList* delta) +{ + UNUSED_PARAM (p); + UNUSED_PARAM (attr); + + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (heapID)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemChunkFree (EmPalmHeap* heap, EmPalmChunkList* delta) +{ +// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemPtrNew (MemPtr p, EmPalmChunkList* delta) +{ + UNUSED_PARAM (p); +// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p)); + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (0)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemPtrResize (MemPtr p, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemHandleNew (MemHandle h, EmPalmChunkList* delta) +{ + UNUSED_PARAM (h); +// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h)); + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByID (0)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemHandleResize (MemHandle h, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemHandleFree (EmPalmHeap* heap, EmPalmChunkList* delta) +{ +// EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h)); + + if (heap) + heap->ResyncAll (delta); +} + +void EmPalmHeap::MemLocalIDToLockedPtr (MemPtr p, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p)); + + if (heap) + heap->ResyncPtr (p, delta); +} + +void EmPalmHeap::MemHandleLock (MemHandle h, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h)); + + if (heap) + heap->ResyncHdl (h, delta); +} + +void EmPalmHeap::MemHandleUnlock (MemHandle h, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h)); + + if (heap) + heap->ResyncHdl (h, delta); +} + +void EmPalmHeap::MemHandleResetLock (MemHandle h, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByHdl (h)); + + if (heap) + heap->ResyncHdl (h, delta); +} + +void EmPalmHeap::MemPtrResetLock (MemPtr p, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p)); + + if (heap) + heap->ResyncPtr (p, delta); +} + +void EmPalmHeap::MemPtrUnlock (MemPtr p, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p)); + + if (heap) + heap->ResyncPtr (p, delta); +} + +void EmPalmHeap::MemPtrSetOwner (MemPtr p, EmPalmChunkList* delta) +{ + EmPalmHeap* heap = const_cast <EmPalmHeap*> (GetHeapByPtr (p)); + + if (heap) + heap->ResyncPtr (p, delta); +} + +void EmPalmHeap::ValidateAllHeaps (void) +{ + EmPalmHeapList::iterator iter = fgHeapList.begin (); + + while (iter != fgHeapList.end ()) + { + (*iter).Validate (); + ++iter; + } +} + + +#pragma mark - + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::AddHeap [ STATIC ] + * + * DESCRIPTION: Add a heap based on its ID. + * + * PARAMETERS: heapID - the ID of the heap to add. + * + * RETURNED: Nothing. + * + ***********************************************************************/ + +void EmPalmHeap::AddHeap (UInt16 heapID) +{ + // Get information on the newly-created heap. + + EmPalmHeap heap (heapID); + + // Find where to add this heap to our list of heaps. We keep this + // list sorted by heap location for easy lookup on that basis. + + EmPalmHeapList::iterator iter = fgHeapList.begin (); + + while (iter != fgHeapList.end ()) + { + // If we already had an entry for this heap, replace it. + + if (iter->Start () == heap.Start ()) + { + *iter = heap; + break; + } + + // Found a place to insert this heap. + + if (iter->Start () > heap.Start ()) + { + fgHeapList.insert (iter, heap); + break; + } + + ++iter; + } + + // If the new heap couldn't be inserted before a currently existing + // heap, then add it to the end. + + if (iter == fgHeapList.end ()) + { + fgHeapList.push_back (heap); + } +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::DerefHandle [ STATIC ] + * + * DESCRIPTION: Dereferences a handle and returns the pointer + * + * PARAMETERS: h - the handle to dereference + * + * RETURNED: The pointer associated with the handle. + * + ***********************************************************************/ + +MemPtr EmPalmHeap::DerefHandle (MemHandle h) +{ + if (!h) + return NULL; + + CEnableFullAccess munge; // Remove blocks on memory access. + + emuptr pp = (emuptr) memHandleUnProtect(h); + return (MemPtr) EmMemGet32 (pp); +} + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::RecoverHandle [ STATIC ] + * + * DESCRIPTION: Finds a handle given a pointer. + * + * Note that MemPtrRecoverHandle calls memHandleProtect on + * the result even if it's NULL; we don't do that here. + * + * PARAMETERS: p - the pointer whose handle we want to find + * + * RETURNED: The handle associated with the pointer. NULL if the + * chunk was not allocated as a relocatable chunk or if + * it's a free chunk. + * + ***********************************************************************/ + +MemHandle EmPalmHeap::RecoverHandle (MemPtr p) +{ + MemHandle h = NULL; + + if (p) + { + const EmPalmHeap* heap = EmPalmHeap::GetHeapByPtr (p); + + if (heap) + { + const EmPalmChunk* chunk = heap->GetChunkBodyContaining ((emuptr) p); + + if (chunk && !chunk->Free () && chunk->HOffset ()) + { + h = (MemHandle) (((emuptr) p) - chunk->HOffset () * 2 - chunk->HeaderSize ()); + +#if _DEBUG + CEnableFullAccess munge; // Remove blocks on memory access. + EmAssert (EmMemGet32 ((emuptr) h) == (emuptr) p); +#endif + + h = memHandleProtect (h); + } + } + } + + return h; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapVersion [ STATIC ] + * + * DESCRIPTION: Determine and return the version number of the given + * heap. + * + * PARAMETERS: heapPtr - a pointer to the header for the heap whose + * version is to be determined. + * + * RETURNED: The version number of the heap. Currently, these values + * are 1 (original heap format), 2 (allows for >64K heaps), + * and 3 (uses a free list for faster allocations). + * + ***********************************************************************/ + +long EmPalmHeap::GetHeapVersion (emuptr heapHdr) +{ + CEnableFullAccess munge; // Remove blocks on memory access. + + long heapVersion = kVersionUnknown; + + // Get the heap version. If bit 14 is set, it's a version 3 heap. + // If bit 15 is set, it's a version 2 heap. Otherwise, it's a + // version 1 heap. + + uint16 flags = EmMemGet16 (heapHdr); + + if ((flags & memHeapFlagVers4) != 0) + { + heapVersion = kVersion4; // free MP's on a list + } + else if ((flags & memHeapFlagVers3) != 0) + { + heapVersion = kVersion3; // has free list + } + else if ((flags & memHeapFlagVers2) != 0) + { + heapVersion = kVersion2; // > 64K + } + else + { + heapVersion = kVersion1; // original + } + + return heapVersion; +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmHeap::EmPalmHeap (void) : + fVersion (kVersionUnknown), + fHeapID (-1), + fHeapHdrStart (0), + fHeapHdrSize (0), + fFirstChunk (0), + fFlags (0), + fSize (0), + fFirstFree (0), + fChunkHdrSize (0), + fChunkList (), + fMPTList () +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: heapID - Palm OS ID for the heap we're to track. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmHeap::EmPalmHeap (UInt16 heapID) : + fVersion (kVersionUnknown), + fHeapID (heapID), + fHeapHdrStart (0), + fHeapHdrSize (0), + fFirstChunk (0), + fFlags (0), + fSize (0), + fFirstFree (0), + fChunkHdrSize (0), + fChunkList (), + fMPTList () +{ + this->GetHeapHeaderInfo (heapID); + this->ResyncAll (NULL); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * Note: this version of the constructor doesn't work too + * well, since it doesn't determine the Palm OS heap ID. + * + * PARAMETERS: heapHdr - pointer to the heap header of the heap we're + * to track. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmHeap::EmPalmHeap (emuptr heapHdr) : + fVersion (kVersionUnknown), + fHeapID (-1), + fHeapHdrStart (0), + fHeapHdrSize (0), + fFirstChunk (0), + fFlags (0), + fSize (0), + fFirstFree (0), + fChunkHdrSize (0), + fChunkList (), + fMPTList () +{ + this->GetHeapHeaderInfo (heapHdr); + this->ResyncAll (NULL); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap copy constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: other - EmPalmHeap object we're to clone. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmHeap::EmPalmHeap (const EmPalmHeap& other) : + fVersion (other.fVersion), + fHeapID (other.fHeapID), + fHeapHdrStart (other.fHeapHdrStart), + fHeapHdrSize (other.fHeapHdrSize), + fFirstChunk (other.fFirstChunk), + fFlags (other.fFlags), + fSize (other.fSize), + fFirstFree (other.fFirstFree), + fChunkHdrSize (other.fChunkHdrSize), + fChunkList (other.fChunkList), + fMPTList (other.fMPTList) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::~EmPalmHeap + * + * DESCRIPTION: Destroy the object. Delete all data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmHeap::~EmPalmHeap (void) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetChunkListBegin + * + * DESCRIPTION: Return an iterator representing the beginning of our + * list of chunk objects. + * + * PARAMETERS: None + * + * RETURNED: The iterator. + * + ***********************************************************************/ + +EmPalmChunkList::const_iterator EmPalmHeap::GetChunkListBegin (void) const +{ + return fChunkList.begin (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetChunkListEnd + * + * DESCRIPTION: Return an iterator representing the end of our + * list of chunk objects. + * + * PARAMETERS: None + * + * RETURNED: The iterator. + * + ***********************************************************************/ + +EmPalmChunkList::const_iterator EmPalmHeap::GetChunkListEnd (void) const +{ + return fChunkList.end (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetChunkReferencedBy + * + * DESCRIPTION: Iterate over our list of chunks, finding the one + * referenced by the given handle. + * + * PARAMETERS: h - test handle + * + * RETURNED: Pointer to chunk object containing the probe address. + * NULL if not found. + * + ***********************************************************************/ + +const EmPalmChunk* EmPalmHeap::GetChunkReferencedBy (MemHandle h) const +{ + // !!! Could do a binary search here, if needed. + + emuptr p = (emuptr) EmPalmHeap::DerefHandle (h); + + ITERATE_CHUNKS (*this, iter, end) + { + if (iter->Contains (p)) + { + return &*iter; + } + + ++iter; + } + + return NULL; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetChunkContaining + * + * DESCRIPTION: Iterate over our list of chunks, finding the one + * containing the given pointer. The range includes the + * chunk header and trailer. + * + * PARAMETERS: p - probe address + * + * RETURNED: Pointer to chunk object containing the probe address. + * NULL if not found. + * + ***********************************************************************/ + +const EmPalmChunk* EmPalmHeap::GetChunkContaining (emuptr p) const +{ + // !!! Could do a binary search here, if needed. + + ITERATE_CHUNKS (*this, iter, end) + { + if (iter->Contains (p)) + { + return &*iter; + } + + ++iter; + } + + return NULL; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetChunkBodyContaining + * + * DESCRIPTION: Iterate over our list of chunks, finding the one + * containing the given pointer. The range does not + * include the chunk header or trailer. + * + * PARAMETERS: p - probe address + * + * RETURNED: Pointer to chunk object containing the probe address. + * NULL if not found. + * + ***********************************************************************/ + +const EmPalmChunk* EmPalmHeap::GetChunkBodyContaining (emuptr p) const +{ + // !!! Could do a binary search here, if needed. + + ITERATE_CHUNKS (*this, iter, end) + { + if (iter->BodyContains (p)) + { + return &*iter; + } + + ++iter; + } + + return NULL; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetMPTListBegin + * + * DESCRIPTION: Return an iterator representing the beginning of our + * list of master pointer table objects. + * + * PARAMETERS: None + * + * RETURNED: The iterator. + * + ***********************************************************************/ + +EmPalmMPTList::const_iterator EmPalmHeap::GetMPTListBegin (void) const +{ + return fMPTList.begin (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetMPTListEnd + * + * DESCRIPTION: Return an iterator representing the end of our + * list of master pointer table objects. + * + * PARAMETERS: None + * + * RETURNED: The iterator. + * + ***********************************************************************/ + +EmPalmMPTList::const_iterator EmPalmHeap::GetMPTListEnd (void) const +{ + return fMPTList.end (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Tracked + * + * DESCRIPTION: Return whether or not we should track the contents of + * this heap. For performance reasons, we currently + * track only the dynamic heap. + * + * PARAMETERS: None + * + * RETURNED: True if we track this heap's contents. + * + ***********************************************************************/ + +Bool EmPalmHeap::Tracked (void) const +{ + return this->Dynamic (); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::ReadOnly + * + * DESCRIPTION: Return whether or not this heap is read-only + * + * PARAMETERS: None + * + * RETURNED: True if so. + * + ***********************************************************************/ + +Bool EmPalmHeap::ReadOnly (void) const +{ + return (fFlags & memHeapFlagReadOnly) != 0; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Dynamic + * + * DESCRIPTION: Return whether or not this heap is the (a?) dynamic heap. + * + * PARAMETERS: None + * + * RETURNED: True if so. + * + ***********************************************************************/ + +Bool EmPalmHeap::Dynamic (void) const +{ + // This is probably the wrong test. I think there's a Palm OS call + // that indicates which heap(s) is/are dynamic. + + return fHeapID == 0; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::Validate + * + * DESCRIPTION: Check to see that our chunk collection matches what's + * actually there. + * + * PARAMETERS: None + * + * RETURNED: Nothing. + * + ***********************************************************************/ + +void EmPalmHeap::Validate (void) +{ + if (!this->Tracked ()) + return; + + EmPalmChunkList newList; + emuptr chunkHdr = this->DataStart (); + + while (1) + { + // Get information about the current chunk. + + EmPalmChunk chunk (*this, chunkHdr); + + // If the size is zero, we've reached the sentinel at the end. + + if (chunk.Size () == 0) + { + break; + } + + // See if this chunk looks valid. An exception is thrown if not. + + chunk.Validate (*this); + + // Push this guy onto our list. + + newList.push_back (chunk); + + // Go on to next chunk. + + chunkHdr += chunk.Size (); + } + + EmPalmChunkList delta; + this->GenerateDeltas (newList, fChunkList, delta); + EmAssert (delta.size () == 0); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapHeaderInfo + * + * DESCRIPTION: Scarf information out of the heap header. + * + * PARAMETERS: heapID - the heapID of the heap to query. + * + * RETURNED: Nothing, but many data members are filled in. + * + ***********************************************************************/ + +void EmPalmHeap::GetHeapHeaderInfo (UInt16 heapID) +{ + MemPtr heapHdr = MemHeapPtr (heapID); + if (heapHdr) + this->GetHeapHeaderInfo ((emuptr) heapHdr); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GetHeapHeaderInfo + * + * DESCRIPTION: Scarf up information about the managed heap. + * + * PARAMETERS: heapHdr - the pointer to the heap to query. + * + * RETURNED: Nothing, but many data members are filled in. + * + ***********************************************************************/ + +void EmPalmHeap::GetHeapHeaderInfo (emuptr heapHdr) +{ + CEnableFullAccess munge; // Remove blocks on memory access. + + + // Save the pointer to the beginning of the heap. This pointer + // points to a struct, the definition of which changes depending + // on the heap version. + + fHeapHdrStart = heapHdr; + + + // Get the heap version so we know the layout of the header. + + fVersion = GetHeapVersion (fHeapHdrStart); + + + /* + Heap layout + + flags: // Always here, always 2 bytes + size // 2 bytes in V1, 4 otherwise + firstFreeChunkOffset // Only in V3 + mstrPtrTbl + numEntries // always 2 bytes long + nextTblOffset // 2 bytes in V1, 4 otherwise + mstrP [numEntries] + ...chunks... + */ + + + switch (fVersion) + { + case kVersion1: + { + fFlags = EmMemGet16 (fHeapHdrStart); + fSize = EmMemGet16 (fHeapHdrStart + offsetof (Mem1HeapHeaderType, size)); + fFirstFree = EmMemNULL; + fChunkHdrSize = sizeof (Mem1ChunkHeaderType); + fHeapHdrSize = offsetof (Mem1HeapHeaderType, mstrPtrTbl); + + EmPalmMPT mpt (*this, this->MptStart ()); + fFirstChunk = this->MptStart () + mpt.Size (); + + // In version 1 heaps, a zero in the size field means 64K. + + if (fSize == 0) + { + fSize = 64 * 1024L; + } + break; + } + + case kVersion2: + { + fFlags = EmMemGet16 (fHeapHdrStart); + fSize = EmMemGet32 (fHeapHdrStart + offsetof (Mem2HeapHeaderType, size)); + fFirstFree = EmMemNULL; + fChunkHdrSize = sizeof (MemChunkHeaderType); + fHeapHdrSize = offsetof (Mem2HeapHeaderType, mstrPtrTbl); + + EmPalmMPT mpt (*this, this->MptStart ()); + fFirstChunk = this->MptStart () + mpt.Size (); + break; + } + + case kVersion3: + case kVersion4: + { + fFlags = EmMemGet16 (fHeapHdrStart); + fSize = EmMemGet32 (fHeapHdrStart + offsetof (MemHeapHeaderType, size)); + fFirstFree = EmMemGet32 (fHeapHdrStart + offsetof (MemHeapHeaderType, firstFreeChunkOffset)); + fChunkHdrSize = sizeof (MemChunkHeaderType); + fHeapHdrSize = offsetof (MemHeapHeaderType, mstrPtrTbl); + + EmPalmMPT mpt (*this, this->MptStart ()); + fFirstChunk = this->MptStart () + mpt.Size (); + break; + } + + default: + EmAssert (false); + break; + } +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::ResyncAll + * + * DESCRIPTION: Resynchronize our notion about the contents of the heap + * this object wraps up. + * + * PARAMETERS: delta - optional collection to receive the list of + * chunks that are different between the current and + * previous states of the heap. This collection is + * used when remarking what parts of the heap can be + * accessed by different processes. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::ResyncAll (EmPalmChunkList* delta) +{ + this->ResyncMPTList (); + this->ResyncChunkList (delta); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::ResyncMPTList + * + * DESCRIPTION: Resynchronize our notion of what master pointer tables + * exist in this heap. Does nothing if this heap is + * not a "tracked" heap (see the Tracked method). + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::ResyncMPTList (void) +{ + if (!this->Tracked ()) + return; + + emuptr p = this->MptStart (); + + fMPTList.clear (); + + while (1) + { + EmPalmMPT mpt (*this, p); + + // See if this table looks valid. An exception is thrown if not. + + mpt.Validate (*this); + + fMPTList.push_back (mpt); + + if (mpt.NextTableOffset () == 0) + break; + + p = this->fHeapHdrStart + mpt.NextTableOffset (); + } +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::ResyncChunkList + * + * DESCRIPTION: Resynchronize our notion of what memory chunks + * exist in this heap. Does nothing if this heap is + * not a "tracked" heap (see the Tracked method). + * + * PARAMETERS: delta - optional collection to receive the list of + * chunks that are different between the current and + * previous states of the heap. This collection is + * used when remarking what parts of the heap can be + * accessed by different processes. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::ResyncChunkList (EmPalmChunkList* delta) +{ + if (!this->Tracked ()) + return; + + EmPalmChunkList oldList; + + if (delta) + oldList = fChunkList; + + emuptr chunkHdr = this->DataStart (); + + fChunkList.clear (); + + while (1) + { + // Get information about the current chunk. + + EmPalmChunk chunk (*this, chunkHdr); + + // If the size is zero, we've reached the sentinel at the end. + + if (chunk.Size () == 0) + { + break; + } + + // See if this chunk looks valid. An exception is thrown if not. + + chunk.Validate (*this); + + // Push this guy onto our list. + + fChunkList.push_back (chunk); + + // Go on to next chunk. + + chunkHdr += chunk.Size (); + } + + if (delta) + this->GenerateDeltas (oldList, fChunkList, *delta); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::ResyncPtr + * + * DESCRIPTION: Resynchronize information about a single particular + * chunk. This routine works by assuming that (a) the + * chunk already exists in the chunk list and that (b) + * only minor changes have been made to the chunk (like + * its lockcount having been changed). This routine + * should not be called if the chunk has been moved or + * resized, since by implication that means that more + * than one chunk has changed. + * + * Does nothing if the heap is not "tracked". + * + * PARAMETERS: p - pointer to the body of the chunk that changed. + * + * delta - optional collection to receive the list of + * chunks that are different between the current and + * previous states of the heap. This collection is + * used when remarking what parts of the heap can be + * accessed by different processes. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::ResyncPtr (MemPtr p, EmPalmChunkList* delta) +{ + if (!this->Tracked ()) + return; + + EmPalmChunkList::iterator iter = fChunkList.begin (); + + emuptr chunkStart = ((emuptr) p) - fChunkHdrSize; + + while (iter != fChunkList.end ()) + { + if (iter->HeaderStart () == chunkStart) + { + *iter = EmPalmChunk (*this, chunkStart); + + if (delta) + delta->push_back (*iter); + + return; + } + + ++iter; + } + + EmAssert (false); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::ResyncHdl + * + * DESCRIPTION: Resynchronize information about a single particular + * chunk. This routine works by assuming that (a) the + * chunk already exists in the chunk list and that (b) + * only minor changes have been made to the chunk (like + * its lockcount having been changed). This routine + * should not be called if the chunk has been moved or + * resized, since by implication that means that more + * than one chunk has changed. + * + * Does nothing if the heap is not "tracked". + * + * PARAMETERS: h - handle of the chunk that changed. + * + * delta - optional collection to receive the list of + * chunks that are different between the current and + * previous states of the heap. This collection is + * used when remarking what parts of the heap can be + * accessed by different processes. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::ResyncHdl (MemHandle h, EmPalmChunkList* delta) +{ + if (!this->Tracked ()) + return; + + MemPtr p = DerefHandle (h); + + if (p) + ResyncPtr (p, delta); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmHeap::GenerateDeltas + * + * DESCRIPTION: Given the current heap state and a previous heap state, + * generate the list of chunks that have changed between + * the two states. + * + * PARAMETERS: oldList - a previous heap state. + * newList - the current heap state. + * delta - container for changed chunks. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +void EmPalmHeap::GenerateDeltas (const EmPalmChunkList& oldList, + const EmPalmChunkList& newList, + EmPalmChunkList& delta) +{ + // Get iterators for the "before" and "after" chunk lists. + + bool alreadyPushed = false; + EmPalmChunkList::const_iterator oldIter = oldList.begin (); + EmPalmChunkList::const_iterator newIter = newList.begin (); + + // Clear out the containing receiving the results. + + delta.clear (); + + // Iterate over the "before" and "after" chunk lists until + // we reach the end of one of them. + + while (oldIter != oldList.end () && newIter != newList.end ()) + { + // If the two chunks currently being examined are the same, + // then the heaps are in sync at this point; proceed to the + // next chunks in both heap lists. + + if (oldIter->CompareForDelta (*newIter)) + { + ++oldIter; + ++newIter; + alreadyPushed = false; + continue; + } + + // There is a difference between the two chunks. If we haven't + // already done so, record the difference by pushing the chunk + // from the "after" chunk list onto "delta". + + if (!alreadyPushed) + { + delta.push_back (*newIter); + alreadyPushed = true; + } + + // Try to find where the heap sync up again. If we increment + // the "after" iterator, make sure we invalid the flag that + // says we already added that chunk to the "delta" list. + + if (oldIter->HeaderStart () < newIter->HeaderStart ()) + { + ++oldIter; + } + else if (oldIter->HeaderStart () > newIter->HeaderStart ()) + { + ++newIter; + alreadyPushed = false; + } + else + { + ++oldIter; + ++newIter; + alreadyPushed = false; + } + } + + // If we reached the end of the "before" list, any remaining + // chunks on the "after" list are differences that need to be + // added to the "delta" container. + + while (newIter != newList.end ()) + { + delta.push_back (*newIter); + ++newIter; + } +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmPalmMPT constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmMPT::EmPalmMPT (void) : + fVersion (kVersionUnknown), + fMptHdrStart (0), + fMptHdrSize (0), + fSize (0), + fNumEntries (0), + fNextTblOffset (0) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmMPT constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: heap - heap wrapper object containing this MPT. + * mptHdr - pointer to the master pointer table. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmMPT::EmPalmMPT (const EmPalmHeap& heap, emuptr mptHdr) : + fVersion (kVersionUnknown), + fMptHdrStart (0), + fMptHdrSize (0), + fSize (0), + fNumEntries (0), + fNextTblOffset (0) +{ + this->GetMPTInfo (heap, mptHdr); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmMPT copy constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: other - MPT object we're to clone. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmMPT::EmPalmMPT (const EmPalmMPT& other) : + fVersion (other.fVersion), + fMptHdrStart (other.fMptHdrStart), + fMptHdrSize (other.fMptHdrSize), + fSize (other.fSize), + fNumEntries (other.fNumEntries), + fNextTblOffset (other.fNextTblOffset) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmMPT::~EmPalmMPT + * + * DESCRIPTION: Destroy the object. Delete all data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmMPT::~EmPalmMPT (void) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmMPT::Validate + * + * DESCRIPTION: Validate that the master pointer table looks valid. + * + * PARAMETERS: heap - heap containing the master pointe table + * + * RETURNED: Nothing (an exception is thrown on error). + * + ***********************************************************************/ + +void EmPalmMPT::Validate (const EmPalmHeap& /*heap*/) const +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmMPT::GetMPTInfo + * + * DESCRIPTION: Scarf up information about the managed master pointer + * table. + * + * PARAMETERS: heap - heap object containing this master pointer table. + * mptHdr - pointer to the master pointer table contained + * in the heap. + * + * RETURNED: Nothing, but many data members are filled in. + * + ***********************************************************************/ + +void EmPalmMPT::GetMPTInfo (const EmPalmHeap& heap, emuptr mptHdr) +{ + CEnableFullAccess munge; // Remove blocks on memory access. + + switch (heap.Version ()) + { + case EmPalmHeap::kVersion1: + fVersion = kVersion1; + + fMptHdrStart = mptHdr; + fMptHdrSize = sizeof (Mem1MstrPtrTableType); + + fNumEntries = EmMemGet16 (mptHdr + offsetof (Mem1MstrPtrTableType, numEntries)); + fNextTblOffset = EmMemGet16 (mptHdr + offsetof (Mem1MstrPtrTableType, nextTblOffset)); + break; + + case EmPalmHeap::kVersion2: + case EmPalmHeap::kVersion3: + case EmPalmHeap::kVersion4: + fVersion = kVersion2; + + fMptHdrStart = mptHdr; + fMptHdrSize = sizeof (MemMstrPtrTableType); + + fNumEntries = EmMemGet16 (mptHdr + offsetof (MemMstrPtrTableType, numEntries)); + fNextTblOffset = EmMemGet32 (mptHdr + offsetof (MemMstrPtrTableType, nextTblOffset)); + break; + + default: + EmAssert (false); + break; + } + + fSize = fMptHdrSize + fNumEntries * sizeof (MemPtr); +} + + +#pragma mark - + +/*********************************************************************** + * + * FUNCTION: EmPalmChunk constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmChunk::EmPalmChunk (void) : + fVersion (kVersionUnknown), + fChunkHdrStart (0), + fChunkHdrSize (0), + fFree (0), + fMoved (0), + fUnused2 (0), + fUnused3 (0), + fSizeAdj (0), + fSize (0), + fLockCount (0), + fOwner (0), + fHOffset (0) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmChunk constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: heap - heap wrapper object containing this chunk. + * chunkHdr - pointer to the header of the chunk we're to + * wrap up. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmChunk::EmPalmChunk (const EmPalmHeap& heap, emuptr chunkHdr) : + fVersion (kVersionUnknown), + fChunkHdrStart (0), + fChunkHdrSize (0), + fFree (0), + fMoved (0), + fUnused2 (0), + fUnused3 (0), + fSizeAdj (0), + fSize (0), + fLockCount (0), + fOwner (0), + fHOffset (0) +{ + this->GetChunkInfo (heap, chunkHdr); +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmChunk copy constructor + * + * DESCRIPTION: Create the object. Initialize all data members. + * + * PARAMETERS: other - chunk object we're to clone. + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmChunk::EmPalmChunk (const EmPalmChunk& other) : + fVersion (other.fVersion), + fChunkHdrStart (other.fChunkHdrStart), + fChunkHdrSize (other.fChunkHdrSize), + fFree (other.fFree), + fMoved (other.fMoved), + fUnused2 (other.fUnused2), + fUnused3 (other.fUnused3), + fSizeAdj (other.fSizeAdj), + fSize (other.fSize), + fLockCount (other.fLockCount), + fOwner (other.fOwner), + fHOffset (other.fHOffset) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmChunk destructor + * + * DESCRIPTION: Destroy the object. Delete all data members. + * + * PARAMETERS: None + * + * RETURNED: Nothing + * + ***********************************************************************/ + +EmPalmChunk::~EmPalmChunk (void) +{ +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmChunk::Validate + * + * DESCRIPTION: Validate that the chunk looks valid. + * + * PARAMETERS: heap - heap containing the master pointe table + * + * RETURNED: Nothing (an exception is thrown on error). + * + ***********************************************************************/ + +void EmPalmChunk::Validate (const EmPalmHeap& heap) const +{ + try + { + // Make sure the chunk is in the heap (this should always be true). + // !!! It's not...determine why and document. + + if (!heap.Contains (fChunkHdrStart)) + { + throw (kError_CorruptedHeap_ChunkNotInHeap); + } + + // Check the size. + + if (this->End () > heap.End ()) + { + char buffer[20]; + + // !!! There's a problem here. These variables are set before the + // variable that uses them. Thus, replacements based on these variables + // are made before they're ready. The result is that %chunk_size and + // %chunk_max still appear in the final message. I'm not sure how, but + // this needs to be addressed and fixed... + + sprintf (buffer, "%0x08X", (int) this->Size ()); + Errors::SetParameter ("%chunk_size", buffer); + + sprintf (buffer, "%0x08X", (int) heap.Size ()); + Errors::SetParameter ("%chunk_max", buffer); + + throw (kError_CorruptedHeap_ChunkTooLarge); + } + + // These bits should not be set. + + if (fUnused2 || fUnused3) + { + throw (kError_CorruptedHeap_InvalidFlags); + } + + if (!fFree) + { + // If it's a movable chunk, validate that the handle offset + // references the handle that points back to the chunk. + + if (fHOffset) + { + // Get the master pointer to this block. If hOffset is bogus, then + // this pointer may be bogus, too. + + emuptr h = fChunkHdrStart - fHOffset * 2; + + // Make sure it is in a master pointer block. + + ITERATE_MPTS(heap, iter, end) + { + // See if "h" is in this array. If so, break from the loop. + + if (iter->TableContains (h)) + { + break; + } + + ++iter; + } + + if (iter == end) + { + throw (kError_CorruptedHeap_HOffsetNotInMPT); + } + + // "h" is in a master pointer table. Make sure "h" points back + // to the block it's supposed to. + + CEnableFullAccess munge; // Remove blocks on memory access. + + if (EmMemGet32 (h) != this->BodyStart()) + { + throw (kError_CorruptedHeap_HOffsetNotBackPointing); + } + } + + // If it's not a movable chunk, it must have a max lock count. + + else + { + if (fLockCount != memPtrLockCount) + { + throw (kError_CorruptedHeap_InvalidLockCount); + } + } + } + + // !!! Walk the heap and make sure that fChunkHdrStart is found? + } + catch (ErrCode err) + { + // This will throw an EmExceptionReset object. + + Errors::ReportErrCorruptedHeap (err, this->fChunkHdrStart); + } +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmChunk::CompareForDelta + * + * DESCRIPTION: Compare two chunks to see if they're "close enough" + * when determining if something significant has changed. + * + * PARAMETERS: lhs - chunk to compare "*this" to. + * + * RETURNED: True if the two chunks are "equal enough". + * + ***********************************************************************/ + +Bool EmPalmChunk::CompareForDelta (const EmPalmChunk& lhs) const +{ + return + fVersion == lhs.fVersion && + fChunkHdrStart == lhs.fChunkHdrStart && + fChunkHdrSize == lhs.fChunkHdrSize && + fFree == lhs.fFree && + fMoved == lhs.fMoved && +// fUnused2 == lhs.fUnused2 && +// fUnused3 == lhs.fUnused3 && + fSizeAdj == lhs.fSizeAdj && + fSize == lhs.fSize && + (fLockCount > 0) == (lhs.fLockCount > 0) && +// fOwner == lhs.fOwner && + fHOffset == lhs.fHOffset; +} + + +/*********************************************************************** + * + * FUNCTION: EmPalmChunk::GetChunkInfo + * + * DESCRIPTION: Scarf up information about the managed chunk. + * + * PARAMETERS: heapHdr - the pointer to the heap to query. + * chunkHdr - pointer to the header of the chunk in the + * heap we're to query. + * + * RETURNED: Nothing, but many data members are filled in. + * + ***********************************************************************/ + +void EmPalmChunk::GetChunkInfo (const EmPalmHeap& heap, emuptr chunkHdr) +{ + CEnableFullAccess munge; // Remove blocks on memory access. + + switch (heap.Version ()) + { + case EmPalmHeap::kVersion1: + { + fVersion = kVersion1; + fChunkHdrStart = chunkHdr; + fChunkHdrSize = sizeof (Mem1ChunkHeaderType); + + UInt16 size = EmMemGet16 (chunkHdr + offsetof (Mem1ChunkHeaderType, size)); + + if (size == 0) + { + // Leave now. We're at the end of the heap. If we're at the end of RAM, + // too, attempts to access subsequent fields will cause a bus error. + + break; + } + + UInt8 lockOwner = EmMemGet8 (chunkHdr + offsetof (Mem1ChunkHeaderType, lockOwner)); + UInt8 flags = EmMemGet8 (chunkHdr + offsetof (Mem1ChunkHeaderType, flags)); + Int16 hOffset = EmMemGet16 (chunkHdr + offsetof (Mem1ChunkHeaderType, hOffset)); + + fFree = (flags & memChunkFlagFree) != 0; + fMoved = (flags & memChunkFlagUnused1) != 0; + fUnused2 = (flags & memChunkFlagUnused2) != 0; + fUnused3 = (flags & memChunkFlagUnused3) != 0; + fSizeAdj = (flags & mem1ChunkFlagSizeAdj); + fSize = size; + fLockCount = (lockOwner & mem1ChunkLockMask) >> 4; + fOwner = (lockOwner & mem1ChunkOwnerMask); + fHOffset = hOffset; + + break; + } + + case EmPalmHeap::kVersion2: + case EmPalmHeap::kVersion3: + case EmPalmHeap::kVersion4: + { + fVersion = kVersion2; + fChunkHdrStart = chunkHdr; + fChunkHdrSize = sizeof (MemChunkHeaderType); + + UInt32 part1 = EmMemGet32 (chunkHdr); + UInt32 part2 = 0; + + if ((part1 & 0x00FFFFFF) != 0) + { + part2 = EmMemGet32 (chunkHdr + 4); + } + + fFree = (part1 & 0x80000000) != 0; + fMoved = (part1 & 0x40000000) != 0; + fUnused2 = (part1 & 0x20000000) != 0; + fUnused3 = (part1 & 0x10000000) != 0; + fSizeAdj = (part1 & 0x0F000000) >> 24; + fSize = (part1 & 0x00FFFFFF); + fLockCount = (part2 & 0xF0000000) >> 28; + fOwner = (part2 & 0x0F000000) >> 24; + fHOffset = (part2 & 0x00FFFFFF); + + // hOffset is a signed value; make sure we keep it that way + // when we extract it by hand. + + if ((fHOffset & 0x00800000) != 0) + { + fHOffset |= 0xFF000000; + } + + break; + } + + default: + EmAssert (false); + } +} + + +#pragma mark - + +// --------------------------------------------------------------------------- +// ¥ operator << (EmStream&, EmPalmChunk&) +// --------------------------------------------------------------------------- + +EmStream& operator << (EmStream& s, const EmPalmChunk& chunk) +{ + const long kVersion = 1; + + s << kVersion; + + s << chunk.fVersion; + + s << chunk.fChunkHdrStart; + s << chunk.fChunkHdrSize; + + s << chunk.fFree; + s << chunk.fMoved; + s << chunk.fUnused2; + s << chunk.fUnused3; + s << chunk.fSizeAdj; + s << chunk.fSize; + + s << chunk.fLockCount; + s << chunk.fOwner; + s << chunk.fHOffset; + + return s; +} + +// --------------------------------------------------------------------------- +// ¥ operator >> (EmStream&, EmPalmChunk&) +// --------------------------------------------------------------------------- + +EmStream& operator >> (EmStream& s, EmPalmChunk& chunk) +{ + long version; + s >> version; + + if (version >= 1) + { + s >> chunk.fVersion; + + s >> chunk.fChunkHdrStart; + s >> chunk.fChunkHdrSize; + + s >> chunk.fFree; + s >> chunk.fMoved; + s >> chunk.fUnused2; + s >> chunk.fUnused3; + s >> chunk.fSizeAdj; + s >> chunk.fSize; + + s >> chunk.fLockCount; + s >> chunk.fOwner; + s >> chunk.fHOffset; + } + + return s; +} + +// --------------------------------------------------------------------------- +// ¥ operator << (EmStream&, EmPalmMPT&) +// --------------------------------------------------------------------------- + +EmStream& operator << (EmStream& s, const EmPalmMPT& mpt) +{ + const long kVersion = 1; + + s << kVersion; + + s << mpt.fVersion; + + s << mpt.fMptHdrStart; + s << mpt.fMptHdrSize; + s << mpt.fSize; + + s << mpt.fNumEntries; + s << mpt.fNextTblOffset; + + return s; +} + +// --------------------------------------------------------------------------- +// ¥ operator >> (EmStream&, EmPalmMPT&) +// --------------------------------------------------------------------------- + +EmStream& operator >> (EmStream& s, EmPalmMPT& mpt) +{ + long version; + s >> version; + + if (version >= 1) + { + s >> mpt.fVersion; + + s >> mpt.fMptHdrStart; + s >> mpt.fMptHdrSize; + s >> mpt.fSize; + + s >> mpt.fNumEntries; + s >> mpt.fNextTblOffset; + } + + return s; +} + +// --------------------------------------------------------------------------- +// ¥ operator << (EmStream&, EmPalmHeap&) +// --------------------------------------------------------------------------- + +EmStream& operator << (EmStream& s, const EmPalmHeap& heap) +{ + const long kVersion = 1; + + s << kVersion; + + s << heap.fVersion; + s << heap.fHeapID; + + s << heap.fHeapHdrStart; + s << heap.fHeapHdrSize; + s << heap.fFirstChunk; + + s << heap.fFlags; + s << heap.fSize; + s << heap.fFirstFree; + s << heap.fChunkHdrSize; + + s << heap.fChunkList; + s << heap.fMPTList; + + return s; +} + +// --------------------------------------------------------------------------- +// ¥ operator >> (EmStream&, EmPalmHeap&) +// --------------------------------------------------------------------------- + +EmStream& operator >> (EmStream& s, EmPalmHeap& heap) +{ + long version; + s >> version; + + if (version >= 1) + { + s >> heap.fVersion; + s >> heap.fHeapID; + + s >> heap.fHeapHdrStart; + s >> heap.fHeapHdrSize; + s >> heap.fFirstChunk; + + s >> heap.fFlags; + s >> heap.fSize; + s >> heap.fFirstFree; + s >> heap.fChunkHdrSize; + + s >> heap.fChunkList; + s >> heap.fMPTList; + } + + return s; +} + |