diff -r 185201be11b0 -r 516af714ebb4 perfsrv/memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanChunks.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/perfsrv/memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanChunks.cpp Fri Sep 17 08:38:31 2010 +0300 @@ -0,0 +1,557 @@ +/* +* 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 + +// 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_HandleLookupLock(); + const TInt processHandleCount = processHandles->Count(); + MemSpyObjectIx_HandleLookupUnlock(); + + for( TInt processHandleIndex = 0; processHandleIndex= processHandles->Count()) break; // Count may have changed in the meantime + DObject* object = (*processHandles)[ processHandleIndex ]; + if (object && object->Open() != KErrNone) object = NULL; + MemSpyObjectIx_HandleLookupUnlock(); + + 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; + } + } + object->Close(NULL); + } + } + + // 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; iSignal(); + 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; iSignal(); + 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(); + const TInt count = container->Count(); + + DChunk* foundChunk = NULL; + + for(TInt i=0; iOpen(); + break; + } + } + + container->Signal(); + + if ( foundChunk == NULL ) + { + Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkInfo() - END - KErrNotFound - couldnt find chunk"); + NKern::ThreadLeaveCS(); + return KErrNotFound; + } + if (r) + { + Kern::Printf("DMemSpyDriverLogChanChunks::GetChunkInfo() - END - %d - Failed to open chunk", r); + NKern::ThreadLeaveCS(); + return r; + } + + // 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 ); + + // Finished with foundChunk + foundChunk->Close(NULL); + NKern::ThreadLeaveCS(); + + // 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 ) + { + NKern::ThreadEnterCS(); + // Chunks are mapped into entire process so any thread within the process is enough... + DThread* firstThread = processAdaption.OpenFirstThread( *process ); + TRACE( Kern::Printf("DMemSpyDriverLogChanChunks::IsHeapChunk() - firstThread: 0x%08x (%O)", firstThread, firstThread ) ); + if ( firstThread != NULL ) + { + TBuf8<4> allocatorVTableBuffer; + TInt 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 ); + } + NKern::ThreadLeaveCS(); + } + + /* 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; + } +