memspy/Driver/Kernel/Source/MemSpyDriverHeapWalker.cpp
branchRCL_3
changeset 21 52e343bb8f80
parent 20 ca8a1b6995f6
--- a/memspy/Driver/Kernel/Source/MemSpyDriverHeapWalker.cpp	Tue Aug 31 16:45:49 2010 +0300
+++ b/memspy/Driver/Kernel/Source/MemSpyDriverHeapWalker.cpp	Wed Sep 01 12:37:10 2010 +0100
@@ -21,14 +21,22 @@
 #include "MemSpyDriverUtils.h"
 
 // Defines
+#define __NEXT_CELL(p)				((RMemSpyDriverRHeapBase::SCell*)(((TUint8*)p)+p->len))
 #define PRINTDEBUG( a ) { if ( PrintDebug() ) a; }
 
 
-RMemSpyDriverHeapWalker::RMemSpyDriverHeapWalker(RMemSpyDriverRHeapBase& aHeap, MMemSpyHeapWalkerObserver* aObserver)
-	: iHeap(aHeap), iPrintDebug(EFalse), iObserver(aObserver)
-	{
-	InitialiseStats();
-	}
+RMemSpyDriverHeapWalker::RMemSpyDriverHeapWalker( RMemSpyDriverRHeapBase& aHeap, TBool aDebugAllocator )
+:   iHeap( aHeap ), iIsDebugAllocator( aDebugAllocator ), iPrintDebug( EFalse ), iObserver( NULL )
+    {
+    InitialiseStats();
+    }
+
+
+RMemSpyDriverHeapWalker::RMemSpyDriverHeapWalker( RMemSpyDriverRHeapBase& aHeap, TBool aDebugAllocator, MMemSpyHeapWalkerObserver& aObserver )
+:   iHeap( aHeap ), iIsDebugAllocator( aDebugAllocator ), iPrintDebug( EFalse ), iObserver( &aObserver )
+    {
+    InitialiseStats();
+    }
 
 
 TInt RMemSpyDriverHeapWalker::Traverse()
@@ -36,7 +44,7 @@
 // Walk the heap calling the info function.
 //
 	{
-    PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - START"));
+    PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - START - delta: 0x%08x", iHeap.ClientToKernelDelta() ));
     InitialiseStats();
     if  ( iObserver )
         {
@@ -45,64 +53,135 @@
         }
 
     PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - heap walk init complete" ));
-
-	TInt err = iHeap.Helper()->Walk(&CellCallback, this);
-    FinaliseStats();
-    //PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - END - pF: 0x%08x, pC: 0x%08x, heapBase: 0x%08x, heapTop: 0x%08x", pF, pC, heapBase, heapTop));
-	return err;
-	}
+    TAny* heapBase = KernelAddress( iHeap.iBase );
+    TAny* heapTop = KernelAddress( iHeap.iTop );
+	PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - kernel-side chunk address: 0x%08x, chunkBase: 0x%08x, heapBase: 0x%08x, heapTop: 0x%08x", iHeap.ChunkKernelAddress(), iHeap.Chunk().iBase, heapBase, heapTop));
 
-TBool RMemSpyDriverHeapWalker::CellCallback(RAllocatorHelper& aHelper, TAny* aContext, RAllocatorHelper::TExtendedCellType aCellType, TLinAddr aCellAddress, TInt aLength)
-	{
-	return static_cast<RMemSpyDriverHeapWalker*>(aContext)->DoCellCallback(aHelper, aCellType, aCellAddress, aLength);
-	}
-
-TBool RMemSpyDriverHeapWalker::DoCellCallback(RAllocatorHelper& aHelper, RAllocatorHelper::TExtendedCellType aCellType, TLinAddr aCellAddress, TInt aLength)
-	{
-	TAny* cellAddress = (TAny*)aCellAddress;
-	TMemSpyDriverCellType memspyCellType = (TMemSpyDriverCellType)aCellType; // We make sure these use the same values
-	switch (aCellType)
+    TRACE_DATA( MemSpyDriverUtils::DataDump("%lS", (TUint8*) iHeap.ChunkKernelAddress(), iHeap.Chunk().iSize, iHeap.Chunk().iSize ) );
+   
+	TInt nestingLevel = 0;
+	TInt allocationNumber = 0;
+	//
+	RMemSpyDriverRHeapBase::SCell* pC = (RMemSpyDriverRHeapBase::SCell*) heapBase;		// allocated cells
+	RMemSpyDriverRHeapBase::SCell* pF = &iHeap.iFree;				            // free cells
+	PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - before while loop entry - pC: 0x%08x, pF: 0x%08x, heapBase: 0x%08x, heapTop: 0x%08x", pC, pF, heapBase, heapTop));
+    //
+    while( ( pF == &iHeap.iFree ) || ( pF >= heapBase && pF < heapTop ) )
 		{
-		case RAllocatorHelper::EHeapBadFreeCellAddress:
-			PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadFreeCellAddress: 0x%08x", cellAddress));
-			NotifyCell(memspyCellType, cellAddress, 0);
-			return EFalse;
-		case RAllocatorHelper::EHeapBadFreeCellSize:
-			PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadFreeCellSize: 0x%08x", cellAddress));
-			NotifyCell(memspyCellType, cellAddress, aLength);
-			return EFalse;
-		case RAllocatorHelper::EHeapBadAllocatedCellSize:
-			PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadAllocatedCellSize: 0x%08x", cellAddress));
-			NotifyCell(memspyCellType, cellAddress, aLength);
-			return EFalse;
-		case RAllocatorHelper::EHeapBadAllocatedCellAddress:
-			PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadAllocatedCellAddress: 0x%08x", cellAddress));
-			NotifyCell(memspyCellType, cellAddress, aLength);
-			return EFalse;
-		default:
-			break;
+        pF = (RMemSpyDriverRHeapBase::SCell*) KernelAddress( pF->next );				// next free cell
+	    PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - pC: 0x%08x, pF: 0x%08x, heapBase: 0x%08x, heapTop: 0x%08x", pC, pF, heapBase, heapTop));
+
+        if  ( pF )
+        	{
+            PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - freeCell:       0x%08x", pF ));
+
+            if  ( pF >= heapBase && pF < heapTop )
+                {
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - freeCell->next: 0x%08x", pF->next ));
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - freeCell->len:  0x%08x", pF->len ));
+                }
+            else
+                {
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - FATAL ERROR - freeCell:  0x%08x is outside heap bounds!", pF ));
+                }
+
+            PRINTDEBUG( Kern::Printf(" "));
+            }
+		
+        if  (!pF)
+            {
+            PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - next free cell address is NULL"));
+			pF = (RMemSpyDriverRHeapBase::SCell*) heapTop;		// to make size checking work
+            }
+		else if (  (TUint8*) pF < heapBase || (TUint8*) pF >= heapTop || (KernelAddress( pF->next ) && KernelAddress( pF->next ) <= pF ) )
+			{
+			// free cell pointer off the end or going backwards
+            PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadFreeCellAddress: 0x%08x", pF ));
+            NotifyCell( EMemSpyDriverBadFreeCellAddress, UserAddress(pF), 0 );
+			return KErrAbort;
+			}
+		else
+			{
+			TInt l = pF->len;
+			if ( l< iHeap.iMinCell || (l & (iHeap.iAlign-1)))
+				{
+				// free cell length invalid
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadFreeCellSize: 0x%08x", pF ));
+		        NotifyCell( EMemSpyDriverBadFreeCellSize, UserAddress(pF), l );
+			    return KErrAbort;
+				}
+			}
+
+        while ( pC != pF )				// walk allocated cells up to next free cell
+			{
+    	    if  ( pC )
+        	    {
+                // The 'next' cell field is only applicable if the cell is a 'free' cell, hence we only print the cell's
+                // address, its length, and its _calculated_ next cell (based upon address + length). Calc length is done
+                // a bit later on...
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - allocCell:       0x%08x", pC ));
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - allocCell->len:  0x%08x", pC->len ));
+                PRINTDEBUG( Kern::Printf(" "));
+                }
+            
+            TInt l = pC->len;
+			if (l<iHeap.iMinCell || (l & (iHeap.iAlign-1)))
+				{
+				// allocated cell length invalid
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadAllocatedCellSize: 0x%08x", pC ));
+		        NotifyCell( EMemSpyDriverBadAllocatedCellSize, UserAddress(pC), l );
+			    return KErrAbort;
+				}
+
+            // ALLOCATED CELL
+            if  ( iIsDebugAllocator )
+                {
+                RMemSpyDriverRHeapBase::SDebugCell* debugCell = (RMemSpyDriverRHeapBase::SDebugCell*) pC;
+                nestingLevel = debugCell->nestingLevel;
+                allocationNumber = debugCell->allocCount;
+                }
+
+            PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EGoodAllocatedCell: 0x%08x", pC ));
+	        if  ( NotifyCell( EMemSpyDriverGoodAllocatedCell, UserAddress(pC), l, nestingLevel, allocationNumber ) == EFalse )
+                {
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - END1 - KErrAbort on NotifyCell..."));
+			    return KErrAbort;
+                }
+
+			RMemSpyDriverRHeapBase::SCell* pN = (RMemSpyDriverRHeapBase::SCell*) __NEXT_CELL( pC );
+            PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - allocCell next:  0x%08x", pN ));
+			if (pN > pF)
+				{
+				// cell overlaps next free cell
+                PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EBadAllocatedCellAddress: 0x%08x", pC ));
+		        NotifyCell( EMemSpyDriverBadAllocatedCellAddress, UserAddress(pC), l );
+			    return KErrAbort;
+				}
+
+            pC = pN;
+			}
+
+        PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - freeCell before exit check is: 0x%08x", pF ));
+        if  ((TUint8*) pF >= heapTop )
+            {
+            PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - freeCell reached top of heap -> done"));
+			break;		// reached end of heap
+            }
+		
+        pC = (RMemSpyDriverRHeapBase::SCell*) __NEXT_CELL(pF);	// step to next allocated cell
+
+        // FREE CELL
+        PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EGoodFreeCell: 0x%08x", pF ));
+        if  ( NotifyCell( EMemSpyDriverGoodFreeCell, UserAddress(pF), pF->len ) == EFalse )
+            {
+            PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - END2 - KErrAbort on NotifyCell..."));
+			return KErrAbort;
+            }
 		}
 
-	if (aCellType & RAllocatorHelper::EAllocationMask)
-		{
-		PRINTDEBUG(Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EGoodAllocatedCell: 0x%08x", cellAddress));
-		TInt nestingLevel = -1;
-		aHelper.GetCellNestingLevel(cellAddress, nestingLevel);
-		TInt allocCount = aHelper.AllocCountForCell(cellAddress);
-		if (allocCount < 0) allocCount = -1; // This is what NotifyCell expects
-		return NotifyCell(memspyCellType, cellAddress, aLength, nestingLevel, allocCount);
-		}
-	else if (aCellType & RAllocatorHelper::EFreeMask)
-		{
-		PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - EGoodFreeCell: 0x%08x", cellAddress));
-		return NotifyCell(memspyCellType, cellAddress, aLength);
-		}
-	else if (aCellType & RAllocatorHelper::EBadnessMask)
-		{
-		NotifyCell(memspyCellType, cellAddress, aLength);
-		return EFalse;
-		}
-	return ETrue; // For any new types that get added
+    FinaliseStats();
+    PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::Traverse() - END - pF: 0x%08x, pC: 0x%08x, heapBase: 0x%08x, heapTop: 0x%08x", pF, pC, heapBase, heapTop));
+    return KErrNone;
 	}
 
 
@@ -140,7 +219,9 @@
     alloc.SetLargestCellAddress( (TAny*) iStats.iLargestCellAddressAlloc );
     alloc.SetLargestCellSize( iStats.iLargestCellSizeAlloc );
 
-	aStats.iCommittedFreeSpace = iHeap.Helper()->CommittedFreeSpace();
+    // Copy common info
+    TMemSpyHeapStatisticsRHeapCommon& common = aStats.StatsCommon();
+    common.SetTotalCellCount( iStats.iNumberOfWalkedCells );
 
 	PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::CopyStatsTo() - END"));
     }
@@ -152,6 +233,56 @@
     iObserver = aObserver;
     }
 
+
+TAny* RMemSpyDriverHeapWalker::KernelAddress( TAny* aUserAddress, TUint aDelta )
+    {
+    TAny* ret = NULL;
+    //
+    if  ( aUserAddress )
+        {
+	    TRACE_HEAP( Kern::Printf("RMemSpyDriverHeapWalker::KernelAddress() - aUserAddress: 0x%08x", aUserAddress));
+        ret = (TUint8*) aUserAddress + aDelta;
+        }
+    //
+	TRACE_HEAP( Kern::Printf("RMemSpyDriverHeapWalker::KernelAddress() - ret: 0x%08x", ret));
+    return ret;
+    }
+
+ 
+TAny* RMemSpyDriverHeapWalker::UserAddress( TAny* aKernelAddress, TUint aDelta )
+    {
+    TAny* ret = NULL;
+    //
+    if  ( aKernelAddress )
+        {
+	    TRACE_HEAP( Kern::Printf("RMemSpyDriverHeapWalker::UserAddress() - aKernelAddress: 0x%08x", aKernelAddress));
+        ret = (TUint8*) aKernelAddress - aDelta;
+        }
+    //
+	TRACE_HEAP( Kern::Printf("RMemSpyDriverHeapWalker::UserAddress() - ret: 0x%08x", ret));
+    return ret;
+    }
+
+
+TAny* RMemSpyDriverHeapWalker::KernelAddress( TAny* aUserAddress) const
+    {
+    return KernelAddress( aUserAddress, iHeap.ClientToKernelDelta() );
+    }
+
+
+TAny* RMemSpyDriverHeapWalker::UserAddress( TAny* aKernelAddress ) const
+    {
+    return UserAddress( aKernelAddress, iHeap.ClientToKernelDelta() );
+    }
+
+
+RMemSpyDriverRHeapBase::SCell* RMemSpyDriverHeapWalker::CellByUserAddress( TAny* aAddress, TUint aDelta )
+    {
+    RMemSpyDriverRHeapBase::SCell* ret = (RMemSpyDriverRHeapBase::SCell*) KernelAddress( aAddress, aDelta );
+    return ret;
+    }
+
+
 TBool RMemSpyDriverHeapWalker::NotifyCell( TMemSpyDriverCellType aType, TAny* aCellAddress, TInt aLength, TInt aNestingLevel, TInt aAllocNumber )
     {
     // Update stats first
@@ -170,9 +301,32 @@
 
 void RMemSpyDriverHeapWalker::UpdateStats( TMemSpyDriverCellType aCellType, TAny* aCellAddress, TInt aLength, TInt aNestingLevel, TInt aAllocNumber )
     {
-    PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - type: %d address: 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellType, aCellAddress, aLength, aNestingLevel, aAllocNumber ));
+    switch( aCellType )
+        {
+    case EMemSpyDriverGoodAllocatedCell:
+        PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - EGoodAllocatedCell       - 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellAddress, aLength, aNestingLevel, aAllocNumber ));
+        break;
+    case EMemSpyDriverGoodFreeCell:
+        PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - EGoodFreeCell            - 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellAddress, aLength, aNestingLevel, aAllocNumber ));
+        break;
+    case EMemSpyDriverBadAllocatedCellSize:
+        Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - EBadAllocatedCellSize    - 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellAddress, aLength, aNestingLevel, aAllocNumber );
+        break;
+    case EMemSpyDriverBadAllocatedCellAddress:
+        Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - EBadAllocatedCellAddress - 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellAddress, aLength, aNestingLevel, aAllocNumber );
+        break;
+    case EMemSpyDriverBadFreeCellAddress:
+        Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - EBadFreeCellAddress      - 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellAddress, aLength, aNestingLevel, aAllocNumber );
+        break;
+    case EMemSpyDriverBadFreeCellSize:
+        Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - EBadFreeCellSize         - 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", aCellAddress, aLength, aNestingLevel, aAllocNumber );
+        break;
+    default:
+        Kern::Printf("RMemSpyDriverHeapWalker::UpdateStats - UHANDLED TYPE!           - 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d, type: %d", aCellAddress, aLength, aNestingLevel, aAllocNumber, aCellType );
+        break;
+        }
 
-    if (aCellType & EMemSpyDriverFreeCellMask)
+    if  ( aCellType == EMemSpyDriverGoodFreeCell )
         {
         // Update checksum
         iStats.iFreeCellCRC = iStats.iFreeCellCRC ^ reinterpret_cast<TUint32>( aCellAddress );
@@ -201,7 +355,7 @@
             iStats.iFirstFreeCellAddress = (TLinAddr) aCellAddress;
             }
         }
-    else if (aCellType & EMemSpyDriverAllocatedCellMask)
+    else if ( aCellType == EMemSpyDriverGoodAllocatedCell )
         {
         // Track cell counts and length
         ++iStats.iAllocCellCount;
@@ -218,10 +372,14 @@
             iStats.iLargestCellAddressAlloc = (TLinAddr) aCellAddress;
             }
         }
+    else
+        {
+        iStats.iLastFreeCellLength = aLength;
+        }
 
     iStats.iLastCellType = aCellType;
     iStats.iLastCellAddress = (TLinAddr) aCellAddress;
-    iStats.iLastCellWasFreeCell = (aCellType & EMemSpyDriverFreeCellMask);
+    iStats.iLastCellWasFreeCell = ( aCellType == EMemSpyDriverGoodFreeCell );
     ++iStats.iNumberOfWalkedCells;
     }
 
@@ -232,7 +390,7 @@
     iStats.iNumberOfWalkedCells = 0;
     iStats.iFirstFreeCellAddress = 0;
     iStats.iFirstFreeCellLength = 0;
-    iStats.iLastCellType = EMemSpyDriverAllocatedCellMask;
+    iStats.iLastCellType = EMemSpyDriverGoodAllocatedCell;
     iStats.iLastCellWasFreeCell = EFalse;
     iStats.iLastFreeCellLength = 0;
     iStats.iTotalFreeSpace = 0;
@@ -248,6 +406,10 @@
     iStats.iLargestCellAddressFreePrevious = 0;
     iStats.iSpackSpaceCellAddress = 0;
     iStats.iLastCellAddress = 0;
+
+    // These two can be identified up front
+    iStats.iFreeCellOverheadHeaderLength = RMemSpyDriverRHeapBase::FreeCellHeaderSize();
+    iStats.iAllocCellOverheadHeaderLength = RMemSpyDriverRHeapBase::AllocatedCellHeaderSize( iIsDebugAllocator );
     }
 
 
@@ -285,3 +447,4 @@
     PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iLargestCellAddressAlloc     : 0x%08x", iStats.iLargestCellAddressAlloc ) );
     PRINTDEBUG( Kern::Printf("RMemSpyDriverHeapWalker::PrintStats - iFreeCellCRC                 : 0x%08x", iStats.iFreeCellCRC ) );
     }
+