--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanChunks.cpp Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,553 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include "MemSpyDriverLogChanChunks.h"
+
+// System includes
+#include <memspy/driver/memspydriverobjectsshared.h>
+
+// Shared includes
+#include "MemSpyDriverOpCodes.h"
+#include "MemSpyDriverObjectsInternal.h"
+
+// User includes
+#include "MemSpyDriverUtils.h"
+#include "MemSpyDriverDevice.h"
+#include "MemSpyDriverOSAdaption.h"
+
+// Constants
+_LIT8( KMemSpyLitDllDollarData, "DLL$DATA" );
+_LIT8( KMemSpyLitDollarDat, "$DAT" );
+_LIT8( KMemSpyLitDollarCode, "$CODE" );
+_LIT8( KMemSpyLitDollarGlobalCode, "GLOBAL$CODE" );
+_LIT8( KMemSpyLitLocalObject, "Local-" );
+
+
+DMemSpyDriverLogChanChunks::DMemSpyDriverLogChanChunks( DMemSpyDriverDevice& aDevice, DThread& aThread )
+: DMemSpyDriverLogChanBase( aDevice, aThread )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::DMemSpyDriverLogChanChunks() - this: 0x%08x", this ));
+ }
+
+
+DMemSpyDriverLogChanChunks::~DMemSpyDriverLogChanChunks()
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::~DMemSpyDriverLogChanChunks() - START - this: 0x%08x", this ));
+
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::~DMemSpyDriverLogChanChunks() - END - this: 0x%08x", this ));
+ }
+
+
+
+TInt DMemSpyDriverLogChanChunks::Request( TInt aFunction, TAny* a1, TAny* a2 )
+ {
+ TInt r = DMemSpyDriverLogChanBase::Request( aFunction, a1, a2 );
+ if ( r == KErrNone )
+ {
+ switch( aFunction )
+ {
+ case EMemSpyDriverOpCodeChunkGetHandles:
+ r = GetChunkHandles( (TMemSpyDriverInternalChunkHandleParams*) a1 );
+ break;
+ case EMemSpyDriverOpCodeChunkGetInfo:
+ r = GetChunkInfo( (TMemSpyDriverInternalChunkInfoParams*) a1 );
+ break;
+
+ default:
+ r = KErrNotSupported;
+ break;
+ }
+ }
+ //
+ return r;
+ }
+
+
+TBool DMemSpyDriverLogChanChunks::IsHandler( TInt aFunction ) const
+ {
+ return ( aFunction > EMemSpyDriverOpCodeChunkBase && aFunction < EMemSpyDriverOpCodeChunkEnd );
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+TInt DMemSpyDriverLogChanChunks::GetChunkHandles( TMemSpyDriverInternalChunkHandleParams* aParams )
+ {
+ TMemSpyDriverInternalChunkHandleParams params;
+ TInt r = Kern::ThreadRawRead( &ClientThread(), aParams, ¶ms, sizeof(TMemSpyDriverInternalChunkHandleParams) );
+ if ( r != KErrNone )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkHandles() - END - params read error: %d", r));
+ return r;
+ }
+
+ const TInt maxCount = params.iMaxCount;
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkHandles() - START - id: %d, maxCount: %d, type: %d", params.iId, maxCount, params.iType));
+
+ DMemSpyDriverOSAdaptionDChunk& chunkAdaption = OSAdaption().DChunk();
+ DMemSpyDriverOSAdaptionDThread& threadAdaption = OSAdaption().DThread();
+ DMemSpyDriverOSAdaptionDProcess& processAdaption = OSAdaption().DProcess();
+
+
+ // This variable holds the number of handles that we have already
+ // written to the client-side.
+ TInt currentWriteIndex = 0;
+
+ if ( params.iType == EMemSpyDriverPrivateObjectTypeProcess || params.iType == EMemSpyDriverPrivateObjectTypeThread )
+ {
+ if ( params.iType == EMemSpyDriverPrivateObjectTypeThread )
+ {
+ r = OpenTempObject( params.iId, EThread );
+ if ( r == KErrNone )
+ {
+ // Open the owning process instead, so that we can see which chunks are mapped
+ // into the thread.
+ DThread* thread = (DThread*) TempObject();
+ DProcess* process = threadAdaption.GetOwningProcess( *thread );
+ if ( process )
+ {
+ const TUint parentProcessId = processAdaption.GetId( *process );
+ CloseTempObject();
+ r = OpenTempObject( parentProcessId, EProcess );
+ }
+ else
+ {
+ CloseTempObject();
+ r = KErrNotFound;
+ }
+ }
+ }
+ else
+ {
+ r = OpenTempObject( params.iId, EProcess );
+ }
+
+ // Handle error opening correct process
+ if (r != KErrNone)
+ {
+ Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkHandles() - END - parent process not found");
+ return r;
+ }
+
+ DProcess* process = (DProcess*) TempObject();
+ NKern::ThreadEnterCS();
+
+ // Iterate through each handle in the process
+ MemSpyObjectIx* processHandles = processAdaption.GetHandles( *process );
+ MemSpyObjectIx_Wait( processHandles );
+
+ const TInt processHandleCount = processHandles->Count();
+ for( TInt processHandleIndex = 0; processHandleIndex<processHandleCount && r == KErrNone && currentWriteIndex < maxCount; processHandleIndex++ )
+ {
+ // Get a handle from the process container...
+ NKern::LockSystem();
+ DObject* object = (*processHandles)[ processHandleIndex ];
+ NKern::UnlockSystem();
+
+ if ( object )
+ {
+ const TObjectType objectType = processAdaption.GetObjectType( *object );
+ if ( objectType == EChunk )
+ {
+ DChunk* chunk = (DChunk*) object;
+ TAny* handle = (TAny*) chunk;
+ r = Kern::ThreadRawWrite( &ClientThread(), params.iHandles + currentWriteIndex, &handle, sizeof(TAny*) );
+ if ( r == KErrNone )
+ {
+ ++currentWriteIndex;
+ }
+ }
+ }
+ }
+
+ MemSpyObjectIx_Signal( processHandles );
+
+ // If we were asked for process-related chunks, also check the chunk container
+ // for entries which we don't have handles to, but do refer to our process
+ // Need a listing of all chunks in the system. Let client filter duplicates.
+ DObjectCon* container = Kern::Containers()[ EChunk ];
+ container->Wait();
+ //
+ const TInt count = container->Count();
+ for( TInt i=0; i<count && r == KErrNone && currentWriteIndex < maxCount; i++ )
+ {
+ DChunk* chunk= (DChunk*) (*container)[ i ];
+ //
+ const TBool isRelated = DoesChunkRelateToProcess( *chunk, TempObjectAsProcess() );
+ if ( isRelated )
+ {
+ r = Kern::ThreadRawWrite( &ClientThread(), params.iHandles + currentWriteIndex, &chunk, sizeof(TAny*) );
+ if ( r == KErrNone )
+ {
+ ++currentWriteIndex;
+ }
+ }
+ }
+ //
+ container->Signal();
+ NKern::ThreadLeaveCS();
+
+ CloseTempObject();
+ }
+ else
+ {
+ // Need a listing of all chunks in the system. Let client filter duplicates.
+ DObjectCon* container = Kern::Containers()[ EChunk ];
+ NKern::ThreadEnterCS();
+ container->Wait();
+ //
+ const TInt count = container->Count();
+ for( TInt i=0; i<count && r == KErrNone && currentWriteIndex < maxCount; i++ )
+ {
+ DChunk* chunk= (DChunk*) (*container)[ i ];
+ //
+ r = Kern::ThreadRawWrite( &ClientThread(), params.iHandles + currentWriteIndex, &chunk, sizeof(TAny*) );
+ if (r == KErrNone)
+ {
+ ++currentWriteIndex;
+ }
+ }
+ //
+ container->Signal();
+ NKern::ThreadLeaveCS();
+ }
+
+ if ( r == KErrBadDescriptor )
+ {
+ MemSpyDriverUtils::PanicThread( ClientThread(), EPanicBadDescriptor );
+ }
+ else
+ {
+ const TInt finalWrite = Kern::ThreadRawWrite( &ClientThread(), params.iCountPtr, ¤tWriteIndex, sizeof(TInt) );
+ if ( r == KErrNone )
+ {
+ r = finalWrite;
+ }
+ }
+
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkHandles() - END - number of handles written to client: %d, ret: %d", currentWriteIndex, r));
+ return r;
+ }
+
+
+TInt DMemSpyDriverLogChanChunks::GetChunkInfo( TMemSpyDriverInternalChunkInfoParams* aParams )
+ {
+ TMemSpyDriverInternalChunkInfoParams params;
+ TInt r = Kern::ThreadRawRead( &ClientThread(), aParams, ¶ms, sizeof(TMemSpyDriverInternalChunkInfoParams) );
+ if ( r != KErrNone )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkInfo() - END - params read error: %d", r));
+ return r;
+ }
+
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkInfo() - START - handle: 0x%08x", params.iHandle));
+
+ DObjectCon* container = Kern::Containers()[EChunk];
+ NKern::ThreadEnterCS();
+
+ container->Wait();
+ NKern::LockSystem();
+ const TInt count = container->Count();
+ NKern::UnlockSystem();
+
+ DChunk* foundChunk = NULL;
+
+ for(TInt i=0; i<count; i++)
+ {
+ NKern::LockSystem();
+ DChunk* chunk = (DChunk*) (*container)[i];
+ NKern::UnlockSystem();
+ //
+ if ( chunk == params.iHandle )
+ {
+ foundChunk = chunk;
+ TRACE( PrintChunkInfo( *chunk ) );
+ break;
+ }
+ }
+
+ container->Signal();
+ NKern::ThreadLeaveCS();
+
+ if ( foundChunk == NULL )
+ {
+ Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkInfo() - END - KErrNotFound - couldnt find chunk");
+ return KErrNotFound;
+ }
+
+ // Prepare return data
+ DMemSpyDriverOSAdaptionDChunk& chunkAdaption = OSAdaption().DChunk();
+ //
+ params.iBaseAddress = chunkAdaption.GetBase( *foundChunk );
+ params.iSize = chunkAdaption.GetSize( *foundChunk );
+ params.iMaxSize = chunkAdaption.GetMaxSize( *foundChunk );
+ foundChunk->FullName( params.iName );
+
+ // Mirror the process memory tracker
+ DProcess* owner = chunkAdaption.GetOwningProcess( *foundChunk );
+ if ( owner )
+ {
+ params.iOwnerId = OSAdaption().DProcess().GetId( *owner );
+ }
+ else
+ {
+ owner = static_cast< DProcess* >( chunkAdaption.GetOwner( *foundChunk, EProcess ) );
+ if ( owner )
+ {
+ params.iOwnerId = OSAdaption().DProcess().GetId( *owner );
+ }
+ else
+ {
+ params.iOwnerId = chunkAdaption.GetControllingOwnerId( *foundChunk );
+ }
+ }
+
+ // Get type & attribs
+ params.iType = IdentifyChunkType( *foundChunk );
+ params.iAttributes = chunkAdaption.GetAttributes( *foundChunk );
+
+ // Write back to client
+ r = Kern::ThreadRawWrite( &ClientThread(), aParams, ¶ms, sizeof(TMemSpyDriverInternalChunkInfoParams) );
+ if ( r == KErrBadDescriptor )
+ {
+ MemSpyDriverUtils::PanicThread( ClientThread(), EPanicBadDescriptor );
+ }
+
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkInfo() - END - handle: 0x%08x, params.iOwnerId: %d, r: %d", params.iHandle, params.iOwnerId, r ));
+ return r;
+ }
+
+
+void DMemSpyDriverLogChanChunks::PrintChunkInfo( DChunk& aChunk )
+ {
+ MemSpyDriverUtils::PrintChunkInfo( aChunk, OSAdaption() );
+ }
+
+
+TMemSpyDriverChunkType DMemSpyDriverLogChanChunks::IdentifyChunkType( DChunk& aChunk )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - START" ) );
+
+ TMemSpyDriverChunkType ret = EMemSpyDriverChunkTypeUnknown;
+
+ TName name;
+ aChunk.Name( name );
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - name: %S", &name ) );
+
+ DMemSpyDriverOSAdaptionDChunk& chunkAdaption = OSAdaption().DChunk();
+ const TChunkType type = chunkAdaption.GetType( aChunk );
+
+ if ( name == KMemSpyLitDllDollarData )
+ {
+ // This chunk contains Dll Global Data for the process
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeGlobalData" ) );
+ ret = EMemSpyDriverChunkTypeGlobalData;
+ }
+ else if ( type == ERamDrive )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeRamDrive" ) );
+ ret = EMemSpyDriverChunkTypeRamDrive;
+ }
+ else if ( type == EKernelStack )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeStackKernel" ) );
+ ret = EMemSpyDriverChunkTypeStackKernel;
+ }
+ else if ( name == KMemSpyLitDollarDat )
+ {
+ // This chunk contains process global data as well as user-side stacks for
+ // the process.
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeStackAndProcessGlobalData" ) );
+ ret = EMemSpyDriverChunkTypeStackAndProcessGlobalData;
+ }
+ else if ( name == KMemSpyLitDollarGlobalCode && type == EDll )
+ {
+ // GLOBAL$CODE is used for RAM loaded code which is globally visible. This
+ // basically means locale DLLs - these must be visible to every process, even
+ // those which haven't loaded them.
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeCodeGlobal" ) );
+ ret = EMemSpyDriverChunkTypeCodeGlobal;
+ }
+ else if ( name == KMemSpyLitDollarCode || type == EKernelCode || type == EDll || type == EUserCode )
+ {
+ // RAM-loaded code, which on the multiple memory model at least means that the code chunk is eseentially just a mapping
+ // artifact. The RAM itself is owned by the code segment, therefore counting the size of these CODE elements may result
+ // in inaccurate results if the code is shared amongst multiple processes.
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeCode" ) );
+ ret = EMemSpyDriverChunkTypeCode;
+ }
+ else if ( type == EUserSelfModCode )
+ {
+ // Dynamically create code chunk
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeCodeSelfModifiable" ) );
+ ret = EMemSpyDriverChunkTypeCodeSelfModifiable;
+ }
+ else if ( IsHeapChunk( aChunk, name ) )
+ {
+ // Catch kernel heap too
+ if ( type == EKernelData )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeHeapKernel" ) );
+ ret = EMemSpyDriverChunkTypeHeapKernel;
+ }
+ else
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeHeap" ) );
+ ret = EMemSpyDriverChunkTypeHeap;
+ }
+ }
+ else if ( type == EUserData && chunkAdaption.GetOwningProcess( aChunk ) == NULL )
+ {
+ // Global shared chunks match this pattern. Of course, we could check the memory model mapping attributes
+ // as that would give us the info in a heartbeat, but it's too specific.
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeGlobal" ) );
+ ret = EMemSpyDriverChunkTypeGlobal;
+ }
+ else if ( type == EUserData && chunkAdaption.GetOwner( aChunk ) != NULL && name.Length() > KMemSpyLitLocalObject().Length() && name.Left( KMemSpyLitLocalObject().Length() ) == KMemSpyLitLocalObject )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeLocal" ) );
+ ret = EMemSpyDriverChunkTypeLocal;
+ }
+ else
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IdentifyChunkType() - EMemSpyDriverChunkTypeUnknown" ) );
+ TRACE( PrintChunkInfo( aChunk ) );
+ ret = EMemSpyDriverChunkTypeUnknown;
+ }
+
+ return ret;
+ }
+
+
+TBool DMemSpyDriverLogChanChunks::IsHeapChunk( DChunk& aChunk, const TName& aName )
+ {
+ (void) aName; // UREL warning
+ const TUint rHeapVTable = MemSpyDevice().RHeapVTable();
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - START - this: 0x%08x, aChunk: 0x%08x, RHeapVTable: 0x%08x, aName: %S, [%O]", this, &aChunk, rHeapVTable, &aName, &aChunk ) );
+
+ DMemSpyDriverOSAdaptionDChunk& chunkAdaption = OSAdaption().DChunk();
+ DMemSpyDriverOSAdaptionDProcess& processAdaption = OSAdaption().DProcess();
+
+ // The first 4 bytes of every chunk correspond to the allocator VTable (For heap chunks).
+ // If it matches RHeap's vtable, we'll treat it as a heap.
+ TBool isHeap = EFalse;
+
+ // There must be an owning process or else it's definitely not a heap chunk.
+ DProcess* process = chunkAdaption.GetOwningProcess( aChunk );
+ TUint8* base = chunkAdaption.GetBase( aChunk );
+ const TInt size = chunkAdaption.GetSize( aChunk );
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - base: 0x%08x, size: %d, process: 0x%08x (%O)", base, size, process, process ) );
+
+ if ( process && size >= 4 )
+ {
+ // Chunks are mapped into entire process so any thread within the process is enough...
+ DThread* firstThread = processAdaption.GetFirstThread( *process );
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - firstThread: 0x%08x (%O)", firstThread, firstThread ) );
+ if ( firstThread != NULL )
+ {
+ TInt err = firstThread->Open();
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - firstThread open result: %d", err ) );
+
+ if ( err == KErrNone )
+ {
+ TBuf8<4> allocatorVTableBuffer;
+ err = Kern::ThreadRawRead( firstThread, base, (TUint8*) allocatorVTableBuffer.Ptr(), allocatorVTableBuffer.MaxLength() );
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk - read result of vtable data from requested thread is: %d", err ));
+ //
+ if ( err == KErrNone )
+ {
+ TRACE( MemSpyDriverUtils::DataDump("possible chunk vtable data - %lS", allocatorVTableBuffer.Ptr(), allocatorVTableBuffer.MaxLength(), allocatorVTableBuffer.MaxLength() ) );
+ allocatorVTableBuffer.SetLength( allocatorVTableBuffer.MaxLength() );
+
+ const TUint32 vtable = allocatorVTableBuffer[0] +
+ (allocatorVTableBuffer[1] << 8) +
+ (allocatorVTableBuffer[2] << 16) +
+ (allocatorVTableBuffer[3] << 24);
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk - [possible] vTable within chunk is: 0x%08x", vtable) );
+
+ // Check the v-table to work out if it really is an RHeap
+ isHeap = ( vtable == rHeapVTable );
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - isHeap: %d", isHeap ) );
+ }
+
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - closing first thread..." ) );
+ Kern::SafeClose( (DObject*&) firstThread, NULL );
+ }
+ }
+ }
+
+ /* We only want RHeap's at the moment
+ if ( !isHeap && aName == KMemSpyLitDollarHeap )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - its called $HEAP, but its not an RHeap... we\'ll let it through though..." ) );
+ isHeap = ETrue;
+ }
+ */
+
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - END - this: 0x%08x, isHeap: %d", this, isHeap ) );
+ return isHeap;
+ }
+
+
+TBool DMemSpyDriverLogChanChunks::DoesChunkRelateToProcess( DChunk& aChunk, DProcess& aProcess )
+ {
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::DoesChunkRelateToProcess() - START - this: 0x%08x, chunk: 0x%08x (%O), process: 0x%08x (%O)", this, &aChunk, &aChunk, &aProcess, &aProcess ) );
+ TBool ret = EFalse;
+ //
+ DMemSpyDriverOSAdaptionDChunk& chunkAdaption = OSAdaption().DChunk();
+ DMemSpyDriverOSAdaptionDProcess& processAdaption = OSAdaption().DProcess();
+ //
+ const TUint pid = processAdaption.GetId( aProcess );
+ DProcess* process = chunkAdaption.GetOwningProcess( aChunk );
+ if ( process )
+ {
+ ret = ( pid == processAdaption.GetId( *process ) );
+ }
+ else
+ {
+ DObject* owner = chunkAdaption.GetOwner( aChunk, EProcess );
+ if ( owner )
+ {
+ process = (DProcess*) owner;
+ ret = ( pid == processAdaption.GetId( *process ) );
+ }
+ else
+ {
+ ret = ( pid == chunkAdaption.GetControllingOwnerId( aChunk ) );
+ }
+ }
+ //
+ TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::DoesChunkRelateToProcess() - END - this: 0x%08x, chunk: 0x%08x (%O), process: 0x%08x (%O), ret: %d", this, &aChunk, &aChunk, &aProcess, &aProcess, ret ) );
+ return ret;
+ }
+