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; }
TInt RMemSpyDriverRHeapUser::OpenUserHeap(DThread& aThread, TBool aEuserUdeb) { TLinAddr allocatorAddr = (TLinAddr)OSAdaption().DThread().GetAllocator(aThread); NKern::ThreadEnterCS(); LtkUtils::RUserAllocatorHelper* helper = new LtkUtils::RUserAllocatorHelper; if (!helper) { NKern::ThreadLeaveCS(); return KErrNoMemory; } TInt err = helper->OpenUserHeap(OSAdaption().DThread().GetId(aThread), allocatorAddr, aEuserUdeb); if (!err) { iChunk = helper->OpenUnderlyingChunk(); if (!iChunk) err = KErrNotFound; } if (err) { delete helper; } else { iHelper = helper; } NKern::ThreadLeaveCS(); return err; }
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; }
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; }
void DMemSpyDriverLogChanChunks::PrintChunkInfo( DChunk& aChunk ) { MemSpyDriverUtils::PrintChunkInfo( aChunk, OSAdaption() ); }
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; i<count; i++) { DChunk* chunk = (DChunk*) (*container)[i]; if ( chunk == params.iHandle ) { foundChunk = chunk; TRACE( PrintChunkInfo( *chunk ) ); r = foundChunk->Open(); 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; }
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)); 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<processHandleCount && r == KErrNone && currentWriteIndex < maxCount; processHandleIndex++ ) { // Get a handle from the process container... MemSpyObjectIx_HandleLookupLock(); if (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; 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; }