memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanHeapData.cpp
branchRCL_3
changeset 59 8ad140f3dd41
parent 49 7fdc9a71d314
--- a/memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanHeapData.cpp	Wed Sep 15 13:53:27 2010 +0300
+++ b/memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanHeapData.cpp	Wed Oct 13 16:17:58 2010 +0300
@@ -162,21 +162,25 @@
     //
     // The driver leaves kernel context with the copy of the kernel heap still associated with MemSpy's process.
     // The second driver call will copy the chunk data to user side and release the kernel side chunk.
-    //const TBool isInit = iKernelHeap.ChunkIsInitialised();
-    //TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - START - isInit: %d", isInit ));
-    //__ASSERT_ALWAYS( !isInit, MemSpyDriverUtils::PanicThread( ClientThread(), EPanicKernelHeapDataInitError ) );
+    const TBool isInit = iKernelHeap.ChunkIsInitialised();
+    TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - START - isInit: %d", isInit ));
+    __ASSERT_ALWAYS( !isInit, MemSpyDriverUtils::PanicThread( ClientThread(), EPanicKernelHeapDataInitError ) );
 
     iKernelHeap.Reset();
     NKern::ThreadEnterCS();
 
+    // We must identify if we have a debug kernel allocator
+    const TBool debugAllocator = IsDebugKernel();
+    TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - debugAllocator: %d", debugAllocator ) );
+
     TFullName heapChunkName;
     TInt r = OpenKernelHeap( iKernelHeap, &heapChunkName );
     TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelInit() - open err: %d", r));
 
     if  ( r == KErrNone )
         {
-        r = GetHeapInfoKernel( iKernelHeap, aInfo, aFreeCells );
-        TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapDataKernelInit() - base class get heap info: %d", r) );
+        r = GetHeapInfoKernel( iKernelHeap, debugAllocator, heapChunkName, aInfo, aFreeCells );
+        TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapInfoKernel() - base class get heap info: %d", r) );
 
         // If everything was okay, we can now return back to user-side, indicating the amount of heap data
         // that they must prepare to read (in the next operation).
@@ -184,12 +188,12 @@
             {
             // Indicate how big a buffer the user-side must prepare.
             r = OSAdaption().DChunk().GetSize( iKernelHeap.Chunk() );
-            TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapDataKernelInit() - user side buffer needs to be: %d", r) );
+            TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapInfo::GetHeapInfoKernel() - user side buffer needs to be: %d", r) );
             }
-        else
+        else if ( iKernelHeap.ChunkIsInitialised() )
             {
             // Error scenario - must close heap
-            iKernelHeap.Close();
+            iKernelHeap.DisassociateWithKernelChunk();
             }
         }
 
@@ -202,15 +206,12 @@
 
 TInt DMemSpyDriverLogChanHeapData::GetHeapDataKernelFetch( TDes8* aSink )
     {
-	//TOMSCI TODO this function is fundamentally flawed
-	return KErrNotSupported;
-	/*
     TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelFetch() - START"));
 
     NKern::ThreadEnterCS();
 
     // We should already have an initialised copy of the kernel heap
-    const TBool isInit = iKernelHeap.Helper() != NULL;
+    const TBool isInit = iKernelHeap.ChunkIsInitialised();
     TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelFetch() - isInit: %d", isInit ));
     __ASSERT_ALWAYS( isInit, MemSpyDriverUtils::PanicThread( ClientThread(), EPanicKernelHeapDataFetchError ) );
 
@@ -260,7 +261,6 @@
 
 	TRACE_KH( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataKernelFetch() - END - ret: %d", r));
     return r;
-	*/
     }
 
 
@@ -279,7 +279,7 @@
 
 
 
-const TInt KPageSize = 4096;
+
 
 TInt DMemSpyDriverLogChanHeapData::GetHeapDataUser( TMemSpyDriverInternalHeapDataParams& aParams )
     {
@@ -304,110 +304,135 @@
 		    return KErrAccessDenied;
             }
         }
-
+    
     // Check that the process' thread's are suspended
     DThread* thread = (DThread*) TempObject();
     if  ( SuspensionManager().IsSuspended( *thread ) )
         {
-        // Open the heap
+        // Find the chunk with the correct handle
 	    TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - thread: %O", thread) );
         RMemSpyDriverRHeapUser heap( OSAdaption() );
-		r = heap.OpenUserHeap(*thread, aParams.iDebugAllocator);
-		TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - opening heap returned: %d", r) );
-        if  (r == KErrNone)
+        const TBool allocatorIsReallyRHeap = GetUserHeapHandle( *thread, heap, aParams.iRHeapVTable );
+        if  ( allocatorIsReallyRHeap )
             {
-            if  ( aParams.iChecksum != 0 )
+            const TInt chunkHandle = heap.iChunkHandle;
+	        TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunkHandle: 0x%08x, thread: %O", chunkHandle, thread) );
+
+  	        NKern::ThreadEnterCS();
+ 	        NKern::LockSystem();
+            DChunk* chunk = (DChunk*) Kern::ObjectFromHandle( thread, chunkHandle, EChunk );
+            NKern::UnlockSystem();
+	        TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunk: 0x%08x", chunk ) );
+  	        NKern::ThreadLeaveCS();
+
+            if  ( chunk != NULL )
                 {
-                TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - checksum validation requested - expecting: 0x%08x", aParams.iChecksum ) );
-                RMemSpyDriverHeapWalker heapWalker(heap);
-                
-                TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - starting traversal..." ));
-#if ( defined( TRACE_TYPE_USERHEAP ) && defined( TRACE_TYPE_HEAPWALK ) )
-                heapWalker.SetPrintDebug();
-#endif
-                r = heapWalker.Traverse();
-                const TUint32 calculatedChecksum = heapWalker.Stats().iFreeCellCRC;
-                TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - finished traversal - err: %d, checksum: 0x%08x", r, calculatedChecksum ));
+                TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunkBase: 0x%08x, size: %8d, maxLen: %8d, chunk: %O", chunk->iBase, chunk->iSize, chunk->iMaxSize, chunk) );
+
+                // If the client specified a checksum value, then we must walk the heap just to make sure
+                // it hasn't changed. Expensive operation, but good for paranoia purposes...
+                if  ( aParams.iChecksum != 0 )
+                    {
+                    TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - checksum validation requested - expecting: 0x%08x", aParams.iChecksum ) );
 
-                TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x", calculatedChecksum, aParams.iChecksum ));
-                if  ( calculatedChecksum != aParams.iChecksum )
-                    {
-                    Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x for thread %O", calculatedChecksum, aParams.iChecksum, thread );
-                    r = KErrCorrupt;
-                    }
-                }
+                    RMemSpyDriverRHeapUser rHeap( OSAdaption() );
+                    DChunk* userHeapChunk = NULL;
+                    r = OpenUserHeap( *thread, aParams.iRHeapVTable, rHeap, userHeapChunk );
+                    TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - opening client heap returned: %d", r) );
+                    if  ( r == KErrNone )
+                        {
+                        TMemSpyHeapWalkerNullObserver observer; 
+                        RMemSpyDriverHeapWalker heapWalker( rHeap, aParams.iDebugAllocator );
+                        heapWalker.SetObserver( &observer );
+                        
+                        TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - starting traversal..." ));
+#if ( defined( TRACE_TYPE_USERHEAP ) && defined( TRACE_TYPE_HEAPWALK ) )
+                        heapWalker.SetPrintDebug();
+#endif
+                        r = heapWalker.Traverse();
+                        const TUint32 calculatedChecksum = heapWalker.Stats().iFreeCellCRC;
+                        TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - finished traversal - err: %d, checksum: 0x%08x", r, calculatedChecksum ));
 
-            // Get user side (MemSpy) descriptor length info
-            if  ( r == KErrNone )
-                {
-                TInt destLen = 0;
-                TInt destMax = 0;
-                TUint8* destPtr = NULL;
-                r = Kern::ThreadGetDesInfo( &ClientThread(), aParams.iDes, destLen, destMax, destPtr, ETrue );
-                TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - user side descriptor: 0x%08x (0x%08x), len: %8d, maxLen: %8d, r: %d", aParams.iDes, destPtr, destLen, destMax, r ));
-				destMax = destMax & ~(KPageSize-1); // Round down dest max to page size
-				if (destMax <= 0 || (aParams.iReadAddress & (KPageSize-1))) r = KErrArgument; // If destMax is less than a page or the read address isn't a multiple of page size then we don't want to know
+                        // Release resources
+                        rHeap.DisassociateWithKernelChunk();
 
+                        TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x", calculatedChecksum, aParams.iChecksum ));
+                        if  ( calculatedChecksum != aParams.iChecksum )
+                            {
+                            Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - comparing CALCULATED: 0x%08x vs EXPECTED: 0x%08x for thread %O", calculatedChecksum, aParams.iChecksum, thread );
+                            r = KErrCorrupt;
+                            }
+                        }
+                    else
+                        {
+                        // Couldn't verify checksum in this situation...
+                        }
+                    }
+
+                // Get user side (MemSpy) descriptor length info
                 if  ( r == KErrNone )
                     {
-					const TLinAddr chunkBase = (TLinAddr)OSAdaption().DChunk().GetBase(heap.Chunk());
-					const TLinAddr chunkMaxAddr = chunkBase + OSAdaption().DChunk().GetMaxSize(heap.Chunk());
-        	        TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunkBase:    0x%08x", chunkBase) );
-        
-					TLinAddr readAddress = aParams.iReadAddress;
-                    if (aParams.iRemaining < 0 )
-                        {
-                        // Initial case, start from the bottom
-                        readAddress = chunkBase;
-						aParams.iRemaining = heap.Helper()->CommittedSize();
-                        }
+                    TInt destLen;
+                    TInt destMax;
+                    TUint8* destPtr = NULL;
+                    r = Kern::ThreadGetDesInfo( &ClientThread(), aParams.iDes, destLen, destMax, destPtr, ETrue );
+                    TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - user side descriptor: 0x%08x (0x%08x), len: %8d, maxLen: %8d, r: %d", aParams.iDes, destPtr, destLen, destMax, r ));
 
-                    // The remaining number of bytes should allow us to calculate the position
-                    // to read from.
-                    TInt amountToRead = Min( aParams.iRemaining, destMax );
-        	        TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - amountToRead:           %8d", amountToRead) );
-        
-                    // Do the read from the heap we are spying on into MemSpy's address space
-					// TomS: I didn't know you could do this - you live and learn
-					do
-						{
-						r = Kern::ThreadRawRead( thread, (const void*)readAddress, destPtr, amountToRead );
-        				TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - read result: %d", r) );
+                    if  ( r == KErrNone )
+                        {
+                        // Calculate start of real heap data (skipping over embedded RHeap object)
+                        const TUint8* startOfHeapOffset = heap.iBase;
+        	            TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - startOfHeapOffset:    0x%08x", startOfHeapOffset) );
+            
+                        // Deal with initial case
+                        const TUint heapSize = heap.Size();
+        	            TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - heapSize:               %8d", heapSize) );
+                        if  ( aParams.iRemaining < 0 )
+                            {
+                            // Initial case, remaining initialised to -1
+                            aParams.iRemaining = heapSize;
+                            }
 
-						if (r == KErrBadDescriptor)
-							{
-							// This is not necessarily an error - it could be we've hit an unmapped page
-							if (amountToRead > KPageSize)
-								{
-								// retry reading a single page instead
-								amountToRead = KPageSize;
-								}
-							else
-								{
-								// Try the next page
-								readAddress += KPageSize;
-								}
-							}
-						} while (r == KErrBadDescriptor && readAddress < chunkMaxAddr);
-                    //
-                    if  (r == KErrNone)
-                        {
-                        // Client takes care of updating descriptor length.
-                        r = amountToRead;
+                        // The remaining number of bytes should allow us to calculate the position
+                        // to read from.
+                        const TInt amountToRead = Min( aParams.iRemaining, destMax );
+        	            TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - amountToRead:           %8d", amountToRead) );
+                        const TInt readOffset = ( heapSize - aParams.iRemaining );
+        	            TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - readOffset:             %8d", readOffset) );
+                        const TAny* readAddress = startOfHeapOffset + readOffset;
+        	            TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - readAddress:          0x%08x", readAddress) );
+            
+                        // Do the read from the heap we are spying on into MemSpy's address space
+                        r = Kern::ThreadRawRead( thread, readAddress, destPtr, amountToRead );
+        	            TRACE( Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - read result: %d", r) );
+                        //
+                        if  (r == KErrNone)
+                            {
+                            // Client takes care of updating descriptor length.
+                            r = amountToRead;
+                            }
+                        else if ( r == KErrBadDescriptor )
+                            {
+                            MemSpyDriverUtils::PanicThread( ClientThread(), EPanicBadDescriptor );
+                            }
+            
+                        // Update remaining bytes
+                        aParams.iRemaining -= amountToRead;
+                        aParams.iReadAddress = (TUint) readAddress;
                         }
-        
-                    // Update remaining bytes
-                    aParams.iRemaining -= amountToRead;
-                    aParams.iReadAddress = readAddress;
                     }
                 }
-			}
+            else
+                {
+    	        Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - chunk not found! thread: %O", thread );
+                r = KErrNotFound;
+                }
+            }
         else
             {
-    	    Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - couldnt open heap for thread %O, err=%d", thread, r);
+    	    Kern::Printf("DMemSpyDriverLogChanHeapData::GetHeapDataUser - couldnt find heap - vtable mis-match? thread: %O", thread );
             r = KErrNotSupported;
             }
-		heap.Close();
         }
     else
         {