diff -r 516af714ebb4 -r f2950aff7424 perfsrv/memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanHeapWalkUser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/perfsrv/memspy/Driver/Kernel/Source/SubChannels/MemSpyDriverLogChanHeapWalkUser.cpp Mon Oct 04 02:45:59 2010 +0300 @@ -0,0 +1,538 @@ +/* +* 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 "MemSpyDriverLogChanHeapWalkUser.h" + +// System includes +#include +#include +#include +#include + +// Shared includes +#include "MemSpyDriverOpCodes.h" +#include "MemSpyDriverObjectsInternal.h" + +// User includes +#include "MemSpyDriverHeap.h" +#include "MemSpyDriverUtils.h" +#include "MemSpyDriverDevice.h" +#include "MemSpyDriverOSAdaption.h" +#include "MemSpyDriverSuspensionManager.h" + + + +DMemSpyDriverLogChanHeapWalkUser::DMemSpyDriverLogChanHeapWalkUser( DMemSpyDriverDevice& aDevice, DThread& aThread ) +: DMemSpyDriverLogChanHeapBase( aDevice, aThread ), iWalkHeap( aDevice.OSAdaption() ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::DMemSpyDriverLogChanHeapWalk() - this: 0x%08x", this )); + } + + +DMemSpyDriverLogChanHeapWalkUser::~DMemSpyDriverLogChanHeapWalkUser() + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::~DMemSpyDriverLogChanHeapWalk() - START - this: 0x%08x", this )); + + NKern::ThreadEnterCS(); + + WalkHeapClose(); + + NKern::ThreadLeaveCS(); + + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::~DMemSpyDriverLogChanHeapWalk() - END - this: 0x%08x", this )); + } + + + + + + + +TInt DMemSpyDriverLogChanHeapWalkUser::Request( TInt aFunction, TAny* a1, TAny* a2 ) + { + TInt r = DMemSpyDriverLogChanBase::Request( aFunction, a1, a2 ); + if ( r == KErrNone ) + { + switch( aFunction ) + { + case EMemSpyDriverOpCodeHeapUserWalkInit: + r = WalkHeapInit( (TMemSpyDriverInternalWalkHeapParamsInit*) a1 ); + break; + case EMemSpyDriverOpCodeHeapUserWalkGetCellInfo: + r = WalkHeapGetCellInfo( (TAny*) a1, (TMemSpyDriverInternalWalkHeapParamsCell*) a2 ); + break; + case EMemSpyDriverOpCodeHeapUserWalkReadCellData: + r = WalkHeapReadCellData( (TMemSpyDriverInternalWalkHeapCellDataReadParams*) a1 ); + break; + case EMemSpyDriverOpCodeHeapUserWalkNextCell: + r = WalkHeapNextCell( (TUint) a1, (TMemSpyDriverInternalWalkHeapParamsCell*) a2 ); + break; + case EMemSpyDriverOpCodeHeapUserWalkClose: + r = WalkHeapClose(); + break; + + default: + r = KErrNotSupported; + break; + } + } + // + return r; + } + + +TBool DMemSpyDriverLogChanHeapWalkUser::IsHandler( TInt aFunction ) const + { + return ( aFunction > EMemSpyDriverOpCodeHeapUserWalkBase && aFunction < EMemSpyDriverOpCodeHeapUserWalkEnd ); + } + + + + + + + + + + + + + + + + + + + + + + +TInt DMemSpyDriverLogChanHeapWalkUser::WalkHeapInit( TMemSpyDriverInternalWalkHeapParamsInit* aParams ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit() - START")); + __ASSERT_ALWAYS( !iHeapWalkInitialised && iWalkHeap.Helper() == NULL, MemSpyDriverUtils::PanicThread( ClientThread(), EPanicHeapWalkPending ) ); + + TInt r = Kern::ThreadRawRead( &ClientThread(), aParams, &iHeapWalkInitialParameters, sizeof(TMemSpyDriverInternalWalkHeapParamsInit) ); + if ( r == KErrNone ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - thread id: %d, vtable: 0x%08x, debugAllocator: %d", iHeapWalkInitialParameters.iTid, iHeapWalkInitialParameters.iRHeapVTable, iHeapWalkInitialParameters.iDebugAllocator)); + + r = OpenTempObject( iHeapWalkInitialParameters.iTid, EThread ); + if ( r == KErrNone ) + { + // Find the chunk with the correct handle + DThread* thread = (DThread*) TempObject(); + if ( SuspensionManager().IsSuspended( *thread ) ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - thread: %O", thread)); + + // Open client's heap + r = iWalkHeap.OpenUserHeap(*thread, iHeapWalkInitialParameters.iDebugAllocator); + + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - opening client heap returned: %d", r) ); + + if ( r == KErrNone ) + { + // Indicates that we've initiated a walk - so we can tell whether to close + // the chunk later on. + iHeapWalkInitialised = ETrue; + iWalkHeapCellIndex = 0; + + // Walk the client's heap + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - calling heap walker constructor...")); + RMemSpyDriverHeapWalker heapWalker(iWalkHeap); + + TMemSpyDriverLogChanHeapWalkObserver observer( *this ); + heapWalker.SetObserver( &observer ); + + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - starting traversal...")); + r = heapWalker.Traverse(); + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - finished traversal - err: %d", r)); + } + + // If the initialise process didn't complete successfully, then we must be sure + // to release the associated heap chunk + if ( r < KErrNone ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - error scenario - releasing kernel heap chunk copy" )); + iWalkHeap.Close(); + } + } + else + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - parent process not suspended => KErrAccessDenied")); + r = KErrAccessDenied; + } + + CloseTempObject(); + } + else + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - thread not found")); + } + } + else + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit - params read error: %d", r)); + } + + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapInit() - END - ret: %d", r)); + return r; + } + + +TInt DMemSpyDriverLogChanHeapWalkUser::WalkHeapNextCell( TUint aTid, TMemSpyDriverInternalWalkHeapParamsCell* aParams ) + { + const TInt walkedHeapCellCount = iWalkHeapCells.Count(); + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapNextCell() - START - current cell count: %d", walkedHeapCellCount)); + __ASSERT_ALWAYS( iHeapWalkInitialised && iWalkHeap.Helper(), MemSpyDriverUtils::PanicThread( ClientThread(), EPanicHeapWalkNotInitialised ) ); + + // Open the original thread + TInt r = OpenTempObject( aTid, EThread ); + if ( r == KErrNone ) + { + // Get the thread handle and that we have suspended the process' threads + DThread* thread = (DThread*) TempObject(); + if ( SuspensionManager().IsSuspended( *thread ) ) + { + NKern::ThreadEnterCS(); + + if ( walkedHeapCellCount > 0 && iWalkHeapCellIndex >= 0 && iWalkHeapCellIndex < walkedHeapCellCount ) + { + // Write back head cell to user-space + TMemSpyDriverInternalWalkHeapParamsCell cell( iWalkHeapCells[ iWalkHeapCellIndex++ ] ); + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapNextCell - returning... cellType: %1d, addr: 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", cell.iCellType, cell.iCellAddress, cell.iLength, cell.iNestingLevel, cell.iAllocNumber )); + + r = Kern::ThreadRawWrite( &ClientThread(), aParams, &cell, sizeof(TMemSpyDriverInternalWalkHeapParamsCell) ); + if ( r != KErrNone ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapNextCell - params read error: %d", r)); + } + } + else + { + r = KErrEof; + } + + NKern::ThreadLeaveCS(); + } + else + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapNextCell - parent process not suspended => KErrAccessDenied")); + r = KErrAccessDenied; + } + + CloseTempObject(); + } + else + { + Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapNextCell - thread not found"); + } + // + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapNextCell() - END - ret: %d", r)); + return r; + } + + +TInt DMemSpyDriverLogChanHeapWalkUser::WalkHeapClose() + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapClose() - START")); + // + if ( iHeapWalkInitialised ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapClose - heap walk was still open...")); + NKern::ThreadEnterCS(); + + iWalkHeap.Close(); + + // Discard handled cells + iWalkHeapCells.Reset(); + + iHeapWalkInitialised = EFalse; + + NKern::ThreadLeaveCS(); + } + // + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapClose() - END")); + return KErrNone; + } + + +TInt DMemSpyDriverLogChanHeapWalkUser::WalkHeapReadCellData(TMemSpyDriverInternalWalkHeapCellDataReadParams* aParams) + { + __ASSERT_ALWAYS( iHeapWalkInitialised && iWalkHeap.Helper(), MemSpyDriverUtils::PanicThread( ClientThread(), EPanicHeapWalkNotInitialised ) ); + // + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData() - START - thread id: %d, vtable: 0x%08x", iHeapWalkInitialParameters.iTid, iHeapWalkInitialParameters.iRHeapVTable)); + // + TMemSpyDriverInternalWalkHeapCellDataReadParams params; + TInt r = Kern::ThreadRawRead( &ClientThread(), aParams, ¶ms, sizeof(TMemSpyDriverInternalWalkHeapCellDataReadParams) ); + if ( r != KErrNone ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData() - END - params read error: %d", r)); + return r; + } + + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - cell: 0x%08x, readLen: %8d, writeAddr: 0x%08x", params.iCellAddress, params.iReadLen, params.iDes)); + + // Open the original thread + r = OpenTempObject( iHeapWalkInitialParameters.iTid, EThread ); + if ( r == KErrNone ) + { + // Get the thread handle + DThread* thread = (DThread*) TempObject(); + + // Check the threads in the process are suspended + if ( SuspensionManager().IsSuspended( *thread ) ) + { + // Check we can find the cell in the cell list... + const TMemSpyDriverInternalWalkHeapParamsCell* cell = CellInfoForSpecificAddress( params.iCellAddress ); + + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - cell: 0x%08x for address: 0x%08x", cell, params.iCellAddress )); + + if ( cell ) + { + const TInt cellLen = cell->iLength; + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - cellLen: %d", cellLen )); + + if ( params.iReadLen <= cellLen ) + { + + // Get user side descriptor length info + TInt destLen = 0; + TInt destMax = 0; + TUint8* destPtr = NULL; + + r = Kern::ThreadGetDesInfo( &ClientThread(), params.iDes, destLen, destMax, destPtr, ETrue ); + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - user side descriptor: 0x%08x (0x%08x), len: %8d, maxLen: %8d, r: %d", params.iDes, destPtr, destLen, destMax, r )); + + // Work out the start offset for the data... + if ( r == KErrNone && destMax >= params.iReadLen ) + { + const TAny* srcPos = ((TUint8*) cell->iCellAddress); + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - srcPos: 0x%08x", srcPos )); + + // Read some data + r = Kern::ThreadRawRead( thread, srcPos, destPtr, params.iReadLen ); + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - read from thread returned: %d", r)); + + if ( r == KErrNone ) + { + // Client will update descriptor length in this situation. + r = params.iReadLen; + } + } + else + { + if ( r != KErrBadDescriptor ) + { + r = KErrArgument; + Kern::Printf( "DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - error - user-descriptor isnt big enough for requested data" ); + } + else + { + Kern::Printf( "DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - error - bad or non-writable user-side descriptor" ); + } + } + } + else + { + r = KErrArgument; + Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - error - read length is bigger than cell length"); + } + } + else + { + r = KErrArgument; + Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - no cell at user supplied address!"); + } + } + else + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - parent process not suspended => KErrAccessDenied")); + r = KErrAccessDenied; + } + + CloseTempObject(); + } + else + { + Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData - thread not found"); + } + // + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapReadCellData() - END result=%d", r)); + return r; + } + + +TInt DMemSpyDriverLogChanHeapWalkUser::WalkHeapGetCellInfo( TAny* aCellAddress, TMemSpyDriverInternalWalkHeapParamsCell* aParams ) + { + __ASSERT_ALWAYS( iHeapWalkInitialised && iWalkHeap.Helper(), MemSpyDriverUtils::PanicThread( ClientThread(), EPanicHeapWalkNotInitialised ) ); + // + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo() - START - thread id: %d, vtable: 0x%08x", iHeapWalkInitialParameters.iTid, iHeapWalkInitialParameters.iRHeapVTable)); + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo - cell: 0x%08x", aCellAddress)); + + // Open the original thread + TInt r = OpenTempObject( iHeapWalkInitialParameters.iTid, EThread ); + if (r != KErrNone) + { + Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo() - END - thread not found"); + return r; + } + + // Get the thread handle + DThread* thread = (DThread*) TempObject(); + + // Check the threads in the process are suspended + if ( !SuspensionManager().IsSuspended( *thread ) ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo - END - parent process not suspended => KErrAccessDenied")); + CloseTempObject(); + return KErrAccessDenied; + } + + // Check we can find the cell in the cell list... + const TMemSpyDriverInternalWalkHeapParamsCell* cell = CellInfoForSpecificAddress( aCellAddress ); + if ( cell == NULL ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo - no exact match for address: 0x%08x...", aCellAddress)); + + // If the cell still wasn't found, then let's look for any heap cell that contains + // the client-specified address (i.e. find the heap cell that contains the specified + // address). + if ( cell == NULL ) + { + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo - still couldnt find cell by exact address. Searching for the cell that contains the specified address...")); + cell = CellInfoForAddressWithinCellRange( aCellAddress ); + } + } + + if ( cell ) + { + // Have enough info to write back to client now + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo - returning... cellType: %1d, addr: 0x%08x, len: %8d, nestingLev: %8d, allocNum: %8d", cell->iCellType, cell->iCellAddress, cell->iLength, cell->iNestingLevel, cell->iAllocNumber )); + r = Kern::ThreadRawWrite( &ClientThread(), aParams, cell, sizeof(TMemSpyDriverInternalWalkHeapParamsCell) ); + } + else + { + r = KErrArgument; + Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo - no cell at user supplied address!"); + } + + CloseTempObject(); + // + TRACE( Kern::Printf("DMemSpyDriverLogChanHeapWalk::WalkHeapGetCellInfo() - END result=%d", r)); + return r; + } + + + + + + + + + + + + + + + + + + + + + + + + + + + +const TMemSpyDriverInternalWalkHeapParamsCell* DMemSpyDriverLogChanHeapWalkUser::CellInfoForAddressWithinCellRange( TAny* aAddress ) const + { + const TMemSpyDriverInternalWalkHeapParamsCell* ret = NULL; + // + const TInt count = iWalkHeapCells.Count(); + for(TInt i=0; i= item.iCellAddress && aAddress < cellExtent ) + { + ret = &item; + } + } + // + return ret; + } + + +const TMemSpyDriverInternalWalkHeapParamsCell* DMemSpyDriverLogChanHeapWalkUser::CellInfoForSpecificAddress( TAny* aAddress ) const + { + const TMemSpyDriverInternalWalkHeapParamsCell* ret = NULL; + // + const TInt count = iWalkHeapCells.Count(); + for(TInt i=0; i