memspy/Driver/User/Source/MemSpyDriverClient.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 31 Aug 2010 16:45:49 +0300
branchRCL_3
changeset 20 ca8a1b6995f6
parent 0 a03f92240627
child 21 52e343bb8f80
permissions -rw-r--r--
Revision: 201033 Kit: 201035

/*
* 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 <memspy/driver/memspydriverclient.h>

// System includes
#include <e32svr.h>

// User includes
#include "MemSpyDriverOpCodes.h"
#include <memspy/driver/memspydriverconstants.h>
#include <memspy/driver/memspydriverobjectsshared.h>
#include "MemSpyDriverStreamReaderImp.h"
#include "MemSpyDriverObjectsInternal.h"
#include "heaputils.h"

// Constants
const TInt KMemSpyClientBufferGrowSize = 0x1000 * 8; // 32kb

// Forward declarations
static void PrintHeapInfo( const TMemSpyHeapInfo& aInfo );




EXPORT_C TInt RMemSpyDriverClient::Open()
	{
    TInt err = iBuffer.Create( KMemSpyClientBufferGrowSize );
    if  ( err == KErrNone )
        {
        err = User::LoadLogicalDevice( KMemSpyDriverDeviceName );
        if  ( err == KErrNone || err == KErrAlreadyExists )
		    {
		    err = DoCreate( KMemSpyDriverDeviceName, KMemSpyDriverVersion(), KNullUnit, NULL, NULL, EOwnerThread );
            if  ( err == KErrNone )
                {
                TUint heapVTable = RHeapVTable();
 	            err = DoControl( EMemSpyDriverOpCodeMiscSetRHeapVTable, (TAny*) heapVTable );
                }
		    }
        }
    //
    if ( err != KErrNone )
        {
        RDebug::Printf( "[MemSpy] RMemSpyDriverClient::Open() - END - err: %d", err );
        }
    //
	return err;
	}



EXPORT_C void RMemSpyDriverClient::Close()
	{
    RBusLogicalChannel::Close();
    const TInt err = User::FreeLogicalDevice( KMemSpyDriverDeviceName );
    //
    if ( err != KErrNone )
        {
        RDebug::Printf( "[MemSpy] RMemSpyDriverClient::Close() - free logical device error: %d", err );
        }
    //
    iBuffer.Close();
    (void) err;
	}


EXPORT_C void RMemSpyDriverClient::GetVersion( TVersion& aVersion )
    {
    TVersion v = KMemSpyDriverVersion();
    Mem::Copy( (TAny*)&aVersion, (TAny*)&v, sizeof( TVersion ) );
    }



















EXPORT_C TInt RMemSpyDriverClient::ReadMemory( TUint aTid, TLinAddr aSrc, TDes8& aDest )
	{
	TMemSpyDriverInternalReadMemParams params;
	params.iTid = aTid;
	params.iAddr = aSrc;
	params.iDes = &aDest;
    aDest.Zero();
    //
	TInt r = DoControl( EMemSpyDriverOpCodeRawMemoryRead, &params, NULL );
    if  ( r >= KErrNone )
        {
        aDest.SetLength( r );
        r = KErrNone;
        }
    //
    return r;
    }














EXPORT_C TInt RMemSpyDriverClient::GetCodeSegs( TAny** aHandleArray, TInt& aHandleCount, TBool aOnlyRamLoaded )
    {
	TMemSpyDriverInternalCodeSnapshotParams params;
	params.iFilter = aOnlyRamLoaded;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
	params.iMaxCount = aHandleCount;
    //
    aHandleCount = 0;
    //
	return DoControl( EMemSpyDriverOpCodeCodeSegsGetAll, &params, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::GetCodeSegs( TUint aPid, TAny** aHandleArray, TInt& aHandleCount )
	{
	TMemSpyDriverInternalCodeSnapshotParams params;
	params.iFilter = aPid;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
	params.iMaxCount = aHandleCount;
    //
    aHandleCount = 0;
    //
	return DoControl( EMemSpyDriverOpCodeCodeSegsGetCodeSegsForProcess, &params, NULL );
	}


EXPORT_C TInt RMemSpyDriverClient::GetCodeSegInfo( TAny* aHandle, TUint aPid, TMemSpyDriverCodeSegInfo& aInfo )
	{
	TMemSpyDriverInternalCodeSegParams params;
	params.iPid = aPid;
	params.iHandle = aHandle;
	params.iInfoPointer = &aInfo;
    //
	const TInt r = DoControl( EMemSpyDriverOpCodeCodeSegsGetCodeSegInfo, &params, NULL );
	return r;
	}



























EXPORT_C TInt RMemSpyDriverClient::GetChunkHandles( TAny** aHandleArray, TInt& aHandleCount )
    {
	TMemSpyDriverInternalChunkHandleParams params;
	params.iId = 0;
	params.iType = EMemSpyDriverPrivateObjectTypeAll;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
    params.iMaxCount = aHandleCount;
    //
    aHandleCount = 0;
	//
	const TInt err = DoControl( EMemSpyDriverOpCodeChunkGetHandles, &params, NULL );
    return err;
    }


EXPORT_C TInt RMemSpyDriverClient::GetChunkInfo( TAny* aHandle, TMemSpyDriverChunkInfo& aInfo )
    {
	TMemSpyDriverInternalChunkInfoParams params;
	TBuf8<KMaxFullName> name;
	params.iHandle = aHandle;
	const TInt r = DoControl( EMemSpyDriverOpCodeChunkGetInfo, &params, NULL );
	//
	if  ( r == KErrNone )
		{
        aInfo.iHandle = aHandle;
		aInfo.iBaseAddress = params.iBaseAddress;
		aInfo.iSize = params.iSize;
		aInfo.iMaxSize = params.iMaxSize;
		aInfo.iOwnerId = params.iOwnerId;
        aInfo.iType = params.iType;
        aInfo.iAttributes = params.iAttributes;
		aInfo.iName.Copy( params.iName );
		}
	//
	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetChunkInfo( TAny* aHandle, TMemSpyDriverChunkInfoWithoutName& aInfo )
    {
    TMemSpyDriverChunkInfo info;
    //
    const TInt r = GetChunkInfo( aHandle, info );
    if  ( r == KErrNone )
        {
        aInfo = info;
        }
    //
    return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetChunkHandlesForProcess( TUint aPid, TAny** aHandleArray, TInt& aHandleCount )
    {
	TMemSpyDriverInternalChunkHandleParams params;
	params.iId = aPid;
	params.iType = EMemSpyDriverPrivateObjectTypeProcess;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
	params.iMaxCount = aHandleCount;
	//
    aHandleCount = 0;
    //
	return DoControl( EMemSpyDriverOpCodeChunkGetHandles, &params, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::GetChunkHandlesForThread( TUint aTid, TAny** aHandleArray, TInt& aHandleCount )
    {
	TMemSpyDriverInternalChunkHandleParams params;
	params.iId = aTid;
	params.iType = EMemSpyDriverPrivateObjectTypeThread;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
	params.iMaxCount = aHandleCount;
	//
    aHandleCount = 0;
    //
	return DoControl( EMemSpyDriverOpCodeChunkGetHandles, &params, NULL );
    }





















EXPORT_C TInt RMemSpyDriverClient::GetThreadInfo( TUint aTid, TMemSpyDriverThreadInfo& aInfo )
	{
	TMemSpyDriverInternalThreadInfoParams params;
    params.iRHeapVTable = RHeapVTable();
    params.iDebugAllocator = DebugEUser();
    //
	TInt r = DoControl( EMemSpyDriverOpCodeThreadAndProcessGetInfoThread, (TAny*)aTid, &params);
	//
	if  ( r == KErrNone )
		{
        // Copy common properties
        Mem::Copy( &aInfo, &params, sizeof( TMemSpyDriverThreadInfoBase ) );

        // Copy name
        aInfo.iFullName.Copy( params.iFullName );

        // Get other basic properties via RThread
        RThread thread;
        r = OpenThread( aTid, thread );
        if ( r == KErrNone )
            {
            RProcess process;
            r = thread.Process( process );
            if ( r == KErrNone )
                {
	            aInfo.iPid = process.Id();
                process.Close();
                }

            aInfo.iThreadPriority = thread.Priority();
            aInfo.iExitReason = thread.ExitReason();
            aInfo.iExitType = thread.ExitType();
            aInfo.iExitCategory = thread.ExitCategory();

            thread.Close();
            }
        }

    return r;
	}

EXPORT_C TInt RMemSpyDriverClient::GetProcessInfo( TUint aPid, TMemSpyDriverProcessInfo& aInfo )
    {
	TInt r = DoControl( EMemSpyDriverOpCodeThreadAndProcessGetInfoProcess, (TAny*)aPid, &aInfo);
    
    // Get other properties via RProcess.
    if  ( r == KErrNone )
        {
        RProcess process;
        r = OpenProcess( aPid, process );
        if  ( r == KErrNone )
            {
            aInfo.iUids = process.Type();
            aInfo.iPriority = process.Priority();
            //
            process.Close();
            }
        }

    return r;
    }


EXPORT_C TInt RMemSpyDriverClient::ProcessThreadsSuspend( TUint aPid )
    {
	return DoControl( EMemSpyDriverOpCodeThreadAndProcessSuspendAllThreads, (TAny*) aPid, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::ProcessThreadsResume( TUint aPid )
    {
	return DoControl( EMemSpyDriverOpCodeThreadAndProcessResumeAllThreads, (TAny*) aPid, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::ThreadEnd( TUint aId, TExitType aType )
    {
    TInt err = KErrNone;
    //
    if  ( aType == EExitPending )
        {
        err = KErrArgument;
        }
    else
        {
        err = DoControl( EMemSpyDriverOpCodeThreadAndProcessEndThread, (TAny*) aId, (TAny*) aType );
        }
    //
    return err;
    }


EXPORT_C TInt RMemSpyDriverClient::OpenThread( TUint aId, RThread& aThread )
    {
    TInt ret = KErrNone;
    aThread.Close();
    //
    const TInt err = DoControl( EMemSpyDriverOpCodeThreadAndProcessOpenThread, (TAny*) aId );
    if  ( err > 0 )
        {
        aThread.SetHandle( err );
        ret = KErrNone;
        }
    else
        {
        ret = err;
        }
    //
    return ret;
    }


EXPORT_C TInt RMemSpyDriverClient::OpenProcess( TUint aId, RProcess& aProcess )
    {
    TInt ret = KErrNone;
    aProcess.Close();
    //
    const TInt err = DoControl( EMemSpyDriverOpCodeThreadAndProcessOpenProcess, (TAny*) aId );
    if  ( err > 0 )
        {
        aProcess.SetHandle( err );
        ret = KErrNone;
        }
    else
        {
        ret = err;
        }
    //
    return ret;
    }


EXPORT_C void RMemSpyDriverClient::GetThreadsL( const TProcessId& aId, RArray<TThreadId>& aThreads )
    {
	aThreads.Reset();
    //
    ResetStreamBuffer();
    const TInt err = DoControl( EMemSpyDriverOpCodeThreadAndProcessGetThreads, (TAny*) (TUint) aId, (TAny*) &iBuffer );
    User::LeaveIfError( err );

    // Open stream
    RMemSpyMemStreamReader stream = StreamOpenL();
    CleanupClosePushL( stream );
        
    // Extract thread ids
    const TInt threadCount = stream.ReadInt32L();
    for( TInt i=0; i<threadCount; i++ )
        {
        const TThreadId id( stream.ReadUint32L() );
        aThreads.AppendL( id );
        }
        
    // Tidy up
    CleanupStack::PopAndDestroy( &stream );
    }


EXPORT_C TInt RMemSpyDriverClient::SetPriority( TUint aId, TThreadPriority aPriority )
    {
    // The kernel side API to set thread priority expects a value in the range of 0-63, i.e. an absolute
    // NThread priority. In order to support process-relative thread priorities, we'd need to duplicate
    // the kernel priority mapping tables - not a good idea - therefore we'll only support absolute values.
    TInt err = KErrNone;
    if  ( aPriority < EPriorityAbsoluteVeryLow )
        {
        err = KErrArgument;
        }
    else
        {
        err = DoControl( EMemSpyDriverOpCodeThreadAndProcessSetPriorityThread, (TAny*) aId, (TAny*) aPriority );
        }
    //
    return err;
    }















EXPORT_C TInt RMemSpyDriverClient::GetHeapInfoUser( TMemSpyHeapInfo& aInfo, TUint aTid )
    {
    TMemSpyDriverInternalHeapRequestParameters params;
    //
    params.iTid = aTid;
    params.iRHeapVTable = RHeapVTable();
    params.iDebugAllocator = DebugEUser();
    params.iMasterInfo = &aInfo;
    //
	TInt r = DoControl( EMemSpyDriverOpCodeHeapInfoGetUser, &params, NULL );
	//
	if  ( r == KErrNone )
    	{
        PrintHeapInfo( aInfo );
        
        // Need to do this on the user-side
        if  ( aInfo.Type() == TMemSpyHeapInfo::ETypeRHeap )
            {
            TMemSpyHeapInfoRHeap& rHeapInfo = aInfo.AsRHeap();
            TMemSpyHeapMetaDataRHeap& metaData = rHeapInfo.MetaData();
            metaData.SetVTable( RHeapVTable() );
            //metaData.SetClassSize( sizeof( RHeap ) );
            }
        }
    else if ( r == KErrNotSupported )
        {
        aInfo.SetType( TMemSpyHeapInfo::ETypeUnknown );
        r = KErrNone;
        }
	//
	return r;
    }

EXPORT_C TInt RMemSpyDriverClient::GetHeapInfoUser( TMemSpyHeapInfo& aInfo, TUint aTid, RArray< TMemSpyDriverFreeCell >& aFreeCells )
	{
	return GetHeapInfoUser(aInfo, aTid, aFreeCells, EFalse);
	}

// For the record I don't think this function should be exported, but since the one above was I'm going with the flow. -TomS
EXPORT_C TInt RMemSpyDriverClient::GetHeapInfoUser(TMemSpyHeapInfo& aInfo, TUint aTid, RArray<TMemSpyDriverCell>& aCells, TBool aCollectAllocatedCellsAsWellAsFree)
	{
    TMemSpyDriverInternalHeapRequestParameters params;
    //
    params.iTid = aTid;
    params.iRHeapVTable = RHeapVTable();
    params.iDebugAllocator = DebugEUser();
    params.iMasterInfo = &aInfo;
    params.iBuildFreeCellList = ETrue;
	params.iBuildAllocCellList = aCollectAllocatedCellsAsWellAsFree;

    //
    aCells.Reset();
    ResetStreamBuffer();
	TInt r = DoControl( EMemSpyDriverOpCodeHeapInfoGetUser, &params );
	//
	if  ( r >= KErrNone )
    	{
        PrintHeapInfo( aInfo );
        
        // Need to do this on the user-side
        if  ( aInfo.Type() == TMemSpyHeapInfo::ETypeRHeap )
            {
            TMemSpyHeapInfoRHeap& rHeapInfo = aInfo.AsRHeap();
            TMemSpyHeapMetaDataRHeap& metaData = rHeapInfo.MetaData();
            metaData.SetVTable( RHeapVTable() );
            //metaData.SetClassSize( sizeof( RHeap ) );
            }

        // Resize transfer buffer to make room for free cells. We only make the buffer
        // bigger, not smaller.
        if  ( iBuffer.Size() < r )
            {
            r = iBuffer.ReAlloc( r );
            }
    
        // Now fetch the heap data
        if  ( r == KErrNone )
            {
            r = DoControl( EMemSpyDriverOpCodeHeapInfoFetchCellList, &iBuffer );
            if  ( r == KErrNone )
                {
                TRAP( r, ReadHeapInfoFreeCellsFromXferBufferL( aCells ) );
                }
            }
        }
    else if ( r == KErrNotSupported )
        {
        aInfo.SetType( TMemSpyHeapInfo::ETypeUnknown );
        r = KErrNone;
        }
	//
	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetHeapInfoKernel( TMemSpyHeapInfo& aInfo )
    {
    TMemSpyDriverInternalHeapRequestParameters params;
    params.iTid = KMemSpyDriverGetKernelHeapDataPseudoThreadId;
    params.iRHeapVTable = NULL;
    params.iMasterInfo = &aInfo;
	TInt r = DoControl( EMemSpyDriverOpCodeHeapInfoGetKernel, &params, NULL );
	//
	if  ( r == KErrNone )
    	{
        PrintHeapInfo( aInfo );
        }
    else if ( r == KErrNotSupported )
        {
        aInfo.SetType( TMemSpyHeapInfo::ETypeUnknown );
        r = KErrNone;
        }
	//
	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetHeapInfoKernel( TMemSpyHeapInfo& aInfo, RArray< TMemSpyDriverFreeCell >& aFreeCells )
    {
    TMemSpyDriverInternalHeapRequestParameters params;
    params.iTid = KMemSpyDriverGetKernelHeapDataPseudoThreadId;
    params.iRHeapVTable = NULL;
    params.iMasterInfo = &aInfo;
    //
    aFreeCells.Reset();
    ResetStreamBuffer();
	TInt r = DoControl( EMemSpyDriverOpCodeHeapInfoGetKernel, &params, (TAny*) &iBuffer );
	//
	if  ( r == KErrNone )
    	{
        PrintHeapInfo( aInfo );
        TRAP( r, ReadHeapInfoFreeCellsFromXferBufferL( aFreeCells ) );
        }
    else if ( r == KErrNotSupported )
        {
        aInfo.SetType( TMemSpyHeapInfo::ETypeUnknown );
        r = KErrNone;
        }
	//
	return r;
    }


EXPORT_C TBool RMemSpyDriverClient::IsDebugKernel()
    {
    TBool isDebugKernel = EFalse;
    DoControl( EMemSpyDriverOpCodeHeapInfoGetIsDebugKernel, (TAny*) &isDebugKernel );
    return isDebugKernel;
    }






















EXPORT_C TInt RMemSpyDriverClient::GetHeapData( TUint aTid, TUint32 aFreeCellChecksum, TDes8& aDest, TUint& aReadAddress, TUint& aAmountRemaining )
    {
    TMemSpyDriverInternalHeapDataParams params;
    params.iTid = aTid;
    params.iRHeapVTable = RHeapVTable();
    params.iDebugAllocator = DebugEUser();
    params.iDes = &aDest;
    params.iChecksum = aFreeCellChecksum;
    params.iRemaining = -1;
	params.iReadAddress = 0;
    aDest.Zero();
    //
	TInt r = DoControl( EMemSpyDriverOpCodeHeapDataGetUser, &params, NULL );
	//
	if  ( r >= KErrNone )
    	{
        aDest.SetLength( r );
        aReadAddress = params.iReadAddress;
    	aAmountRemaining = params.iRemaining;
        r = KErrNone;
    	}
	//
	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetHeapDataNext( TUint aTid, TDes8& aDest, TUint& aReadAddress, TUint& aAmountRemaining )
    {
    TMemSpyDriverInternalHeapDataParams params;
    params.iTid = aTid;
    params.iRHeapVTable = RHeapVTable();
    params.iDebugAllocator = DebugEUser();
    params.iDes = &aDest;
    params.iChecksum = 0;
    params.iRemaining = aAmountRemaining;
	params.iReadAddress = aReadAddress;
    aDest.Zero();
    //
	TInt r = DoControl( EMemSpyDriverOpCodeHeapDataGetUser, &params, NULL );
	//
	if  ( r >= KErrNone )
    	{
        aDest.SetLength( r );
        aReadAddress = params.iReadAddress;
    	aAmountRemaining = params.iRemaining;
        r = KErrNone;
    	}
	//
    return r;
    }



EXPORT_C HBufC8* RMemSpyDriverClient::GetHeapDataKernelLC( TMemSpyHeapInfo& aInfo, RArray<TMemSpyDriverFreeCell>& aFreeCells )
    {
    HBufC8* data = NULL;

    // Going to fetch free cells via stream buffer...
    ResetStreamBuffer();

    // First pass is to preallocate buffer for kernel heap, and fetch metadata and free cells
    TInt sizeOrError = DoControl( EMemSpyDriverOpCodeHeapDataGetKernelInit, (TAny*) &aInfo, (TAny*) &iBuffer );
	if  ( sizeOrError >= KErrNone )
    	{
        const TInt kernelHeapSize = sizeOrError;
        if  ( aInfo.Type() != TMemSpyHeapInfo::ETypeRHeap )
            {
            User::Leave( KErrNotSupported );
            }
        else
            {
            // Extract free cells
            ReadHeapInfoFreeCellsFromXferBufferL( aFreeCells );

            // It's okay to treat the heap info as an RHeap
            PrintHeapInfo( aInfo );

            // Allocate data sink and do fetch
            data = HBufC8::NewLC( kernelHeapSize );
            TPtr8 pBuffer( data->Des() );

	        sizeOrError = DoControl( EMemSpyDriverOpCodeHeapDataGetKernelFetch, &pBuffer, NULL );
            }
        }

    User::LeaveIfError( sizeOrError );
    return data;
    }




































EXPORT_C TInt RMemSpyDriverClient::WalkHeapInit( TUint aTid )
    {
    TMemSpyDriverInternalWalkHeapParamsInit params;
    params.iTid = aTid;
    params.iRHeapVTable = RHeapVTable();
    params.iDebugAllocator = DebugEUser();
    //
	const TInt r = DoControl( EMemSpyDriverOpCodeWalkHeapInit, &params, NULL );
	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::WalkHeapNextCell( TUint aTid, TMemSpyDriverCellType& aCellType, TAny*& aCellAddress, TInt& aLength, TInt& aNestingLevel, TInt& aAllocNumber, TInt& aCellHeaderSize, TAny*& aCellPayloadAddress )
    {
    aCellType = EMemSpyDriverBadCellMask;
    aCellAddress = NULL;
    aLength = 0;
    aNestingLevel = 0;
    aAllocNumber = 0;
    aCellHeaderSize = 0;
    aCellPayloadAddress = NULL;
    //
    TMemSpyDriverInternalWalkHeapParamsCell params;
	const TInt r = DoControl( EMemSpyDriverOpCodeWalkHeapNextCell, (TAny*) aTid, &params );
    //
	if  ( r == KErrNone )
	    {
        aCellType = (TMemSpyDriverCellType) params.iCellType;
        aCellAddress = params.iCellAddress;
        aLength = params.iLength;
        aNestingLevel = params.iNestingLevel;
        aAllocNumber = params.iAllocNumber;
        aCellPayloadAddress = ((TUint8*) aCellAddress) + aCellHeaderSize;
        }
    //
   	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::WalkHeapReadCellData( TAny* aCellAddress, TDes8& aDest, TInt aReadLen )
    {
    TMemSpyDriverInternalWalkHeapCellDataReadParams params;
    params.iCellAddress = aCellAddress;
    params.iReadLen = aReadLen;
    params.iDes = &aDest;
    aDest.Zero();
    //
	TInt r = DoControl( EMemSpyDriverOpCodeWalkHeapReadCellData, &params, NULL );
    if  ( r >= KErrNone )
        {
        aDest.SetLength( r );
        r = KErrNone;
        }
    //
	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::WalkHeapGetCellInfo( TAny*& aCellAddress, TMemSpyDriverCellType& aCellType, TInt& aLength, TInt& aNestingLevel, TInt& aAllocNumber, TInt& aCellHeaderSize, TAny*& aCellPayloadAddress )
    {
    aCellType = EMemSpyDriverBadCellMask;
    aLength = 0;
    aNestingLevel = 0;
    aAllocNumber = 0;
    aCellHeaderSize = 0;
    aCellPayloadAddress = NULL;
    //
    TMemSpyDriverInternalWalkHeapParamsCell params;
	const TInt r = DoControl( EMemSpyDriverOpCodeWalkHeapGetCellInfo, aCellAddress, &params );
    //
	if  ( r == KErrNone )
	    {
        aCellAddress = params.iCellAddress;
        aCellType = (TMemSpyDriverCellType) params.iCellType;
        aLength = params.iLength;
        aNestingLevel = params.iNestingLevel;
        aAllocNumber = params.iAllocNumber;
        aCellPayloadAddress = ((TUint8*) aCellAddress) + aCellHeaderSize;
        }
    //
   	return r;
    }


EXPORT_C void RMemSpyDriverClient::WalkHeapClose()
    {
	DoControl( EMemSpyDriverOpCodeWalkHeapClose, NULL, NULL );
    }



























EXPORT_C TInt RMemSpyDriverClient::GetStackInfo( TUint aTid, TMemSpyDriverStackInfo& aInfo )
    {
    TMemSpyDriverStackInfo params;
	const TInt r = DoControl( EMemSpyDriverOpCodeStackGetInfo, (TAny*)aTid, &params );
	if  (r==KErrNone)
		{
		aInfo.iUserStackPointer = params.iUserStackPointer;
		aInfo.iUserStackBase = params.iUserStackBase;
		aInfo.iUserStackSize = params.iUserStackSize;
		aInfo.iUserStackHighWatermark = params.iUserStackHighWatermark;
		aInfo.iSupervisorStackPointer = params.iSupervisorStackPointer;
		aInfo.iSupervisorStackBase = params.iSupervisorStackBase;
		aInfo.iSupervisorStackSize = params.iSupervisorStackSize;
		aInfo.iSupervisorStackHighWatermark = params.iSupervisorStackHighWatermark;
		}
	//
	return r;
    }    


EXPORT_C TInt RMemSpyDriverClient::GetStackData( TUint aTid, TDes8& aDest, TUint& aAmountRemaining, TMemSpyDriverDomainType aDomain, TBool aEntireStack )
    {
    TMemSpyDriverInternalStackDataParams params;
    params.iTid = aTid;
    params.iDes = &aDest;
    params.iDomain = aDomain;
    params.iEntireStack = aEntireStack;
    params.iRemaining = -1;
    aDest.Zero();
    //
	TInt r = DoControl( EMemSpyDriverOpCodeStackGetData, &params, NULL );
	//
	if  ( r >= KErrNone )
    	{
        aDest.SetLength( r );
    	aAmountRemaining = params.iRemaining;
        r = KErrNone;
    	}
	//
	return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetStackDataNext( TUint aTid, TDes8& aDest, TUint& aAmountRemaining, TMemSpyDriverDomainType aDomain, TBool aEntireStack )
    {
    TMemSpyDriverInternalStackDataParams params;
    params.iTid = aTid;
    params.iDes = &aDest;
    params.iDomain = aDomain;
    params.iEntireStack = aEntireStack;
    params.iRemaining = aAmountRemaining;
    //
	TInt r = DoControl( EMemSpyDriverOpCodeStackGetData, &params, NULL );
	//
	if  ( r >= KErrNone )
    	{
        aDest.SetLength( r );
    	aAmountRemaining = params.iRemaining;
        r = KErrNone;
    	}
	//
    return r;
    }































































EXPORT_C TInt RMemSpyDriverClient::EventMonitorOpen( TUint& aHandle )
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeEventMonitorOpen, (TAny*) &aHandle );
    return error;
    }


EXPORT_C TInt RMemSpyDriverClient::EventMonitorClose( TUint aHandle )
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeEventMonitorClose, (TAny*) aHandle );
    return error;
    }


EXPORT_C void RMemSpyDriverClient::EventMonitorNotify( TUint aHandle, TRequestStatus& aStatus, TUint& aContext )
    {
    aStatus = KRequestPending;
    //
    TMemSpyDriverInternalEventMonitorParams params;
    params.iHandle = aHandle;
    params.iStatus = &aStatus;
    params.iContext = (TAny*) &aContext;
    //
    const TInt err = DoControl( EMemSpyDriverOpCodeEventMonitorNotify, (TAny*) &params );
    if  ( err != KErrNone )
        {
        TRequestStatus* status = &aStatus;
        User::RequestComplete( status, err );
        }
    }


EXPORT_C void RMemSpyDriverClient::EventMonitorNotifyCancel( TUint aHandle )
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeEventMonitorNotifyCancel, (TAny*) aHandle );
    (void) error;
    }



















EXPORT_C TInt RMemSpyDriverClient::ProcessInspectionOpen( TUint aPid )
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeProcessInspectOpen, (TAny*) aPid );
    return error;
    }


EXPORT_C TInt RMemSpyDriverClient::ProcessInspectionClose( TUint aPid )
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeProcessInspectClose, (TAny*) aPid );
    return error;
    }


EXPORT_C void RMemSpyDriverClient::ProcessInspectionRequestChanges( TUint aPid, TRequestStatus& aStatus, TMemSpyDriverProcessInspectionInfo& aInfo )
    {
    aInfo.iProcessId = aPid;
    aStatus = KRequestPending;
    const TInt err = DoControl( EMemSpyDriverOpCodeProcessInspectRequestChanges, (TAny*) &aStatus, (TAny*) &aInfo );
    if  ( err != KErrNone )
        {
        TRequestStatus* status = &aStatus;
        User::RequestComplete( status, err );
        }
    }


EXPORT_C void RMemSpyDriverClient::ProcessInspectionRequestChangesCancel( TUint aPid )
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeProcessInspectRequestChangesCancel, (TAny*) aPid );
    (void) error;
    }


EXPORT_C void RMemSpyDriverClient::ProcessInspectionAutoStartItemsReset()
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeProcessInspectAutoStartListReset );
    (void) error;
    }


EXPORT_C TInt RMemSpyDriverClient::ProcessInspectionAutoStartItemsAdd( TUint aSID )
    {
    const TInt error = DoControl( EMemSpyDriverOpCodeProcessInspectAutoStartListAdd, (TAny*) aSID );
    return error;
    }






















EXPORT_C TInt RMemSpyDriverClient::GetContainerHandles( TMemSpyDriverContainerType aContainer, TAny** aHandleArray, TInt& aHandleCount )
    {
	TMemSpyDriverInternalContainerHandleParams params;
	params.iTidOrPid = KMemSpyDriverEnumerateContainerHandles;
	params.iContainer = aContainer;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
    params.iMaxCount = aHandleCount;
    params.iHandleSource = EMemSpyDriverThreadOrProcessTypeThread; // Not used
    //
    aHandleCount = 0;
	//
	return DoControl( EMemSpyDriverOpCodeContainersGetHandles, &params, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::GetThreadHandlesByType( TInt aTid, TMemSpyDriverContainerType aType, TAny** aHandleArray, TInt& aHandleCount )
    {
	TMemSpyDriverInternalContainerHandleParams params;
	params.iTidOrPid = aTid;
	params.iContainer = aType;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
    params.iMaxCount = aHandleCount;
    params.iHandleSource = EMemSpyDriverThreadOrProcessTypeThread;
	//
    aHandleCount = 0;
    //
	return DoControl( EMemSpyDriverOpCodeContainersGetHandles, &params, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::GetProcessHandlesByType( TInt aPid, TMemSpyDriverContainerType aType, TAny** aHandleArray, TInt& aHandleCount )
    {
	TMemSpyDriverInternalContainerHandleParams params;
	params.iTidOrPid = aPid;
	params.iContainer = aType;
	params.iHandles = aHandleArray;
	params.iCountPtr = &aHandleCount;
    params.iMaxCount = aHandleCount;
    params.iHandleSource = EMemSpyDriverThreadOrProcessTypeProcess;
	//
    aHandleCount = 0;
    //
	return DoControl( EMemSpyDriverOpCodeContainersGetHandles, &params, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::GetGenericHandleInfo( TInt aTid, TMemSpyDriverContainerType aType, TAny* aHandle, TMemSpyDriverHandleInfoGeneric& aParams )
    {
    aParams.iType = aType;
    aParams.iHandle = aHandle;
    //
    const TInt r = DoControl( EMemSpyDriverOpCodeContainersGetHandleInfo, (TAny*) aTid, &aParams );
    return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetApproximateKernelObjectSize( TMemSpyDriverContainerType aType )
    {
    TInt size = 0;
    const TInt error = DoControl( EMemSpyDriverOpCodeContainersGetApproxSize, (TAny*) aType, (TAny*) &size );
    (void) error;
    //
    return size;
    }


EXPORT_C TInt RMemSpyDriverClient::GetReferencesToMyThread( TUint aTid )
    {
    ResetStreamBuffer();
	return DoControl( EMemSpyDriverOpCodeContainersGetReferencesToMyThread, (TAny*) aTid, (TAny*) &iBuffer );
    }


EXPORT_C TInt RMemSpyDriverClient::GetReferencesToMyProcess( TUint aPid )
    {
    ResetStreamBuffer();
	return DoControl( EMemSpyDriverOpCodeContainersGetReferencesToMyProcess, (TAny*) aPid, (TAny*) &iBuffer );
    }


EXPORT_C TInt RMemSpyDriverClient::GetPAndSInfo( TAny* aHandle, TMemSpyDriverPAndSInfo& aInfo )
    {
    const TInt r = DoControl( EMemSpyDriverOpCodeContainersGetPAndSInfo, (TAny*) aHandle, &aInfo );
    return r;
    }


EXPORT_C TInt RMemSpyDriverClient::GetCondVarSuspendedThreads( TAny* aCondVarHandle, TAny** aThreadHandleArray, TInt& aThreadCount )
    {
    TMemSpyDriverInternalCondVarSuspendedThreadParams params;
    params.iCondVarHandle = aCondVarHandle;
    params.iThrHandles = aThreadHandleArray;
    params.iThrCountPtr = &aThreadCount;
    params.iMaxCount = aThreadCount;
    //
    aThreadCount = 0;
    //
    return DoControl( EMemSpyDriverOpCodeContainersGetCondVarSuspendedThreads, &params, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::GetCondVarSuspendedThreadInfo( TAny* aHandle, TMemSpyDriverCondVarSuspendedThreadInfo& aParams )
    {
    return DoControl( EMemSpyDriverOpCodeContainersGetCondVarSuspendedThreadInfo, aHandle, &aParams );
    }

















EXPORT_C TInt RMemSpyDriverClient::GetServerSessionHandles( TAny* aServerHandle, TAny** aSessionHandleArray, TInt& aSessionHandleCount )
    {
	TMemSpyDriverInternalServerSessionHandleParams params;
	params.iServerHandle = aServerHandle;
	params.iSessionHandles = aSessionHandleArray;
	params.iSessionCountPtr = &aSessionHandleCount;
    params.iMaxCount = aSessionHandleCount;
    //
    aSessionHandleCount = 0;
	//
	return DoControl( EMemSpyDriverOpCodeClientServerGetServerSessionHandles, &params, NULL );
    }


EXPORT_C TInt RMemSpyDriverClient::GetServerSessionInfo( TAny* aSessionHandle, TMemSpyDriverServerSessionInfo& aParams )
    {
    return DoControl( EMemSpyDriverOpCodeClientServerGetServerSessionInfo, aSessionHandle, &aParams );
    }











EXPORT_C RMemSpyMemStreamReader RMemSpyDriverClient::StreamOpenL()
    {
    CMemSpyMemStreamReader* imp = new(ELeave) CMemSpyMemStreamReader( iBuffer );
    RMemSpyMemStreamReader ret( imp );
    CleanupClosePushL( ret ); 
    imp->ConstructL();
    CleanupStack::Pop( &ret );
    return ret;
    }













EXPORT_C TMemSpyMemoryModelType RMemSpyDriverClient::MemoryModelType()
    {
    TMemSpyMemoryModelType ret = EMemSpyMemoryModelTypeUnknown;
    //
    const TInt err = DoControl( EMemSpyDriverOpCodeMiscGetMemoryModelType );
    switch( err )
        {
    default:
    case EMemSpyMemoryModelTypeUnknown:
        ret = EMemSpyMemoryModelTypeUnknown;
        break;
    case EMemSpyMemoryModelTypeMoving:
        ret = EMemSpyMemoryModelTypeMoving;
        break;
    case EMemSpyMemoryModelTypeMultiple:
        ret = EMemSpyMemoryModelTypeMultiple;
        break;
    case EMemSpyMemoryModelTypeEmulator:
        ret = EMemSpyMemoryModelTypeEmulator;
        break;
        }
    //
    return ret;
    }


EXPORT_C TUint32 RMemSpyDriverClient::RoundToPageSize( TUint32 aValue )
    {
    TUint32 temp = aValue;
    TAny* pValue = (TAny*) &temp;
    DoControl( EMemSpyDriverOpCodeMiscGetRoundToPageSize, pValue );
    return temp;
    }


EXPORT_C TInt RMemSpyDriverClient::Impersonate( TUint32 aValue )
    {
    return DoControl( EMemSpyDriverOpCodeMiscImpersonate, (TAny*) aValue );
    }


























TUint RMemSpyDriverClient::RHeapVTable()
    {
    RHeap* heap = (RHeap*) &User::Allocator();
    //
    TUint* pHeap = (TUint*) heap;
    const TUint heapVTable = *pHeap;
    //
    ////RDebug::Printf( "[MemSpy] RMemSpyDriverClient::RHeapVTable() - ret: 0x%08x", heapVTable );
    return heapVTable;
    }


TBool RMemSpyDriverClient::DebugEUser()
    {
	LtkUtils::RAllocatorHelper allocHelper;
	TBool result = EFalse;
	TInt err = allocHelper.Open(&User::Allocator());
	if (!err)
		{
		result = allocHelper.AllocatorIsUdeb();
		allocHelper.Close();
		}
	return result;
    }


void RMemSpyDriverClient::ResetStreamBuffer()
    {
    iBuffer.Zero();
    }


void RMemSpyDriverClient::ReadHeapInfoFreeCellsFromXferBufferL( RArray<TMemSpyDriverFreeCell>& aFreeCells )
    {
    aFreeCells.Reset();

#ifdef _DEBUG
    RDebug::Printf( "[MemSpy] RMemSpyDriverClient::ReadHeapInfoFreeCellsFromXferBufferL() - buf len: %d", iBuffer.Length() );
#endif

    if  ( iBuffer.Length() )
        {
        RMemSpyMemStreamReader stream = StreamOpenL();
        CleanupClosePushL( stream );

        const TInt count = stream.ReadInt32L();
#ifdef _DEBUG
        RDebug::Printf( "[MemSpy] RMemSpyDriverClient::ReadHeapInfoFreeCellsFromXferBufferL() - count: %d", count );
#endif

        for( TInt i=0; i<count; i++ )
            {
            TMemSpyDriverFreeCell entry;
            entry.iType = (TMemSpyDriverCellType)stream.ReadInt32L();
            entry.iAddress = reinterpret_cast< TAny* >( stream.ReadUint32L() );
            entry.iLength = stream.ReadInt32L();
            aFreeCells.AppendL( entry );
            }

        CleanupStack::PopAndDestroy( &stream );
        }

    ResetStreamBuffer();
    }












static void PrintHeapInfo( const TMemSpyHeapInfo& aInfo )
    {
#if defined( _DEBUG ) && !defined( __WINS__ )
    const TMemSpyHeapInfoRHeap& rHeapInfo = aInfo.AsRHeap();
    //const TMemSpyHeapObjectDataRHeap& rHeapObjectData = rHeapInfo.ObjectData();
    const TMemSpyHeapStatisticsRHeap& rHeapStats = rHeapInfo.Statistics();
    const TMemSpyHeapMetaDataRHeap& rHeapMetaData = rHeapInfo.MetaData();

	/*
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RAllocator                                      -");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RAllocator::iAccessCount:       %d", rHeapObjectData.iAccessCount);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RAllocator::iHandleCount:       %d", rHeapObjectData.iHandleCount);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RAllocator::iHandles:           0x%08x", rHeapObjectData.iHandles);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RAllocator::iFlags:             0x%08x", rHeapObjectData.iFlags);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RAllocator::iCellCount:         %d", rHeapObjectData.iCellCount);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RAllocator::iTotalAllocSize:    %d", rHeapObjectData.iTotalAllocSize);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - ");

    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap                                           -");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iMinLength:              %d", rHeapObjectData.iMinLength);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iMaxLength:              %d", rHeapObjectData.iMaxLength);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iOffset:                 %d", rHeapObjectData.iOffset);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iGrowBy:                 %d", rHeapObjectData.iGrowBy);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iChunkHandle:            0x%08x", rHeapObjectData.iChunkHandle);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iBase:                   0x%08x", rHeapObjectData.iBase);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iTop:                    0x%08x", rHeapObjectData.iTop);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iAlign:                  %d", rHeapObjectData.iAlign);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iMinCell:                %d", rHeapObjectData.iAlign);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iPageSize:               %d", rHeapObjectData.iAlign);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iFree.next:              0x%08x", rHeapObjectData.iFree.next);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iFree.len:               %d", rHeapObjectData.iFree.len);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iNestingLevel:           %d", rHeapObjectData.iNestingLevel);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iAllocCount:             %d", rHeapObjectData.iAllocCount);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iFailType:               %d", rHeapObjectData.iFailType);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iFailRate:               %d", rHeapObjectData.iFailRate);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iFailed:                 %d", rHeapObjectData.iFailed);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iFailAllocCount:         %d", rHeapObjectData.iFailAllocCount);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iRand:                   %d", rHeapObjectData.iRand);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - RHeap::iTestData:               0x%08x", rHeapObjectData.iTestData);
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - ");
	*/

    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - Stats (Free)                                    -");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell count:                     %d", rHeapStats.StatsFree().TypeCount());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell size:                      %d", rHeapStats.StatsFree().TypeSize());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell largest:                   0x%08x", rHeapStats.StatsFree().LargestCellAddress());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell largest size:              %d", rHeapStats.StatsFree().LargestCellSize());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - slack:                          0x%08x", rHeapStats.StatsFree().SlackSpaceCellAddress());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - slack size:                     %d", rHeapStats.StatsFree().SlackSpaceCellSize());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - checksum:                       0x%08x", rHeapStats.StatsFree().Checksum());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - ");

    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - Stats (Alloc)                                   -");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell count:                     %d", rHeapStats.StatsAllocated().TypeCount());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell size:                      %d", rHeapStats.StatsAllocated().TypeSize());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell largest:                   0x%08x", rHeapStats.StatsAllocated().LargestCellAddress());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell largest size:              %d", rHeapStats.StatsAllocated().LargestCellSize());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - ");

    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - Misc. Info                                      -");
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() ---------------------------------------------------");
    const TPtrC chunkName( rHeapMetaData.ChunkName() );
    RDebug::Print(_L("RMemSpyDriverClient::PrintHeapInfo() - chunk name:                     [%S]"), &chunkName );
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - chunk size:                     %d", rHeapMetaData.ChunkSize());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - chunk handle:                   0x%08x", rHeapMetaData.ChunkHandle());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - chunk base address:             0x%08x", rHeapMetaData.ChunkBaseAddress());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - debug allocator:                %d", rHeapMetaData.IsDebugAllocator());
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - shared heap:                    %d", rHeapMetaData.IsSharedHeap() );
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - user thread:                    %d", rHeapMetaData.IsUserThread() );
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - thread id:                      %d", aInfo.Tid() );
    RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - process id:                     %d", aInfo.Pid() );
    //RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell header size (free):        %d", rHeapMetaData.HeaderSizeFree());
    //RDebug::Printf("RMemSpyDriverClient::PrintHeapInfo() - cell header size (alloc):       %d", rHeapMetaData.HeaderSizeAllocated());
#else
    (void) aInfo;
#endif
    }