diff -r 7fdc9a71d314 -r 8ad140f3dd41 memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanHeapData.cpp --- 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 {