EXPORT_C void CMemSpyEngineHelperHeap::OutputHeapInfoUserL( const CMemSpyThread& aThread )
    {
    HBufC* threadName = aThread.FullName().AllocLC();
    //
    RArray<TMemSpyDriverFreeCell> freeCells;
    CleanupClosePushL( freeCells );
    //
    TMemSpyHeapInfo info;
    GetHeapInfoUserL( aThread.Process().Id(), aThread.Id(), info, &freeCells );
    OutputHeapInfoL( info, *threadName, &freeCells );
    //
    CleanupStack::PopAndDestroy( 2, threadName ); // freecells & thread name
    }
void CMemSpyEngineHelperHeap::OutputHeapDataUserL( const CMemSpyThread& aThread, TBool aCreateDataStream )
    {
    // Make sure the process is suspended for the entire time we are manipulating it's heap
    iEngine.ProcessSuspendLC( aThread.Process().Id() );

    // Get the heap info, including cell information
    RArray<TMemSpyDriverCell> cells;
    CleanupClosePushL( cells );
    TMemSpyHeapInfo heapInfo;
    TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::OutputHeapDataUserL() - checksum1: 0x%08x", heapInfo.AsRHeap().Statistics().StatsFree().Checksum() ) );
    GetHeapInfoUserL(aThread.Process().Id(), aThread.Id(), heapInfo, &cells, ETrue);
    TRACE( RDebug::Printf( "CMemSpyEngineHelperHeap::OutputHeapDataUserL() - checksum2: 0x%08x", heapInfo.AsRHeap().Statistics().StatsFree().Checksum() ) );

    // Get the heap data
    const TFullName pName( aThread.FullName() );
    OutputHeapDataUserL( aThread.Process().Id(), aThread.Id(), pName, heapInfo, aCreateDataStream, &cells );
    CleanupStack::PopAndDestroy( &cells );

    // Resume process
    CleanupStack::PopAndDestroy();
    }
EXPORT_C void CMemSpyEngineHelperHeap::OutputCellListingUserL( const CMemSpyThread& aThread )
    {
    // Suspend the process
    iEngine.ProcessSuspendLC( aThread.Process().Id() );

    // Free cells
    RArray<TMemSpyDriverFreeCell> freeCells;
    CleanupClosePushL( freeCells );

    // Info section
    TMemSpyHeapInfo heapInfo;
    const TInt error = iEngine.Driver().GetHeapInfoUser( heapInfo, aThread.Id(), freeCells );
    if ( error == KErrNone )
        {
        UpdateSharedHeapInfoL( aThread.Process().Id(), aThread.Id(), heapInfo );
        }
    if  ( error == KErrNone && heapInfo.Type() != TMemSpyHeapInfo::ETypeUnknown )
        {
        // Get thread name for context
        const TFullName pName( aThread.FullName() );

        // Begin a new data stream
        _LIT( KMemSpyFolder, "Heap\\Cell List" );
        _LIT( KMemSpyContext, "Cell List - %S" );
        HBufC* context = HBufC::NewLC( KMaxFileName );
        TPtr pContext( context->Des() );
        pContext.Format( KMemSpyContext, &pName );
        iEngine.Sink().DataStreamBeginL( pContext, KMemSpyFolder );
        CleanupStack::PopAndDestroy( context );

        // Set prefix for overall listing
        iEngine.Sink().OutputPrefixSetFormattedLC( KMemSpyPrefixCellList, &pName );

        // Start new section
        _LIT(KHeader, "CELL LISTING");
        iEngine.Sink().OutputSectionHeadingL( KHeader, '=' );

        // Prepare temp buffers
        TBuf<KMaxFullName + 100> printFormat;
        HBufC* tempBuffer = HBufC::NewLC( 2048 );
        TPtr pTempBuffer( tempBuffer->Des() );

        // Print initial info
        OutputHeapInfoL( heapInfo, pName, &freeCells );

        // Code segments (needed for map file reading...)
        _LIT(KCellListCodeSegInfoFormat, "CodeSegs - ");
        iEngine.HelperCodeSegment().OutputCodeSegmentsL( aThread.Process().Id(), printFormat, KCellListCodeSegInfoFormat, '-', ETrue );
    
        // Now walk the heap!
        TInt r = iEngine.Driver().WalkHeapInit( aThread.Id() );
        if  ( r == KErrNone )
            {
             _LIT(KHeader2, "Cells");
            iEngine.Sink().OutputSectionHeadingL( KHeader2, '-' );

            TMemSpyDriverCellType cellType;
            TAny* cellAddress;
            TInt cellLength;
            TInt cellNestingLevel;
            TInt cellAllocationNumber;
            TInt cellHeaderSize;
            TAny* cellPayloadAddress;
            TBuf8<4> cellData;
            //
            r = iEngine.Driver().WalkHeapNextCell( aThread.Id(), cellType, cellAddress, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
            while( r == KErrNone )
                {
                TUint fourByteCellData = 0;
                TPtrC pType(KNullDesC);
                //
				if (cellType & EMemSpyDriverAllocatedCellMask)
					{
                    r = iEngine.Driver().WalkHeapReadCellData( cellAddress, cellData, 4 );
                    if  ( r == KErrNone )
                        {
                        fourByteCellData = DescriptorAsDWORD( cellData );
                        }
                    pType.Set(KCellTypeGoodAllocatedCell);
                    }
				else if (cellType & EMemSpyDriverFreeCellMask)
					{
                    pType.Set(KCellTypeGoodFreeCell);
					}
				else if (cellType & EMemSpyDriverBadCellMask)
					{
					switch (cellType)
						{
					case EMemSpyDriverHeapBadAllocatedCellSize:
						pType.Set(KCellTypeBadAllocatedCellSize);
						break;
					case EMemSpyDriverHeapBadAllocatedCellAddress:
						pType.Set(KCellTypeBadAllocatedCellAddress);
						break;
					case EMemSpyDriverHeapBadFreeCellAddress:
						pType.Set(KCellTypeBadFreeCellAddress);
						break;
					case EMemSpyDriverHeapBadFreeCellSize:
						pType.Set(KCellTypeBadFreeCellSize);
						break;
					default:
						pType.Set(KCellTypeBad);
						break;
						}
					}
				else
					{
                    pType.Set(KCellTypeUnknown);
                    }

                if  ( r == KErrNone )
                    {
                    pTempBuffer.Format( KCellListLineFormat, &pType, cellAddress, cellLength, cellAllocationNumber, cellNestingLevel, fourByteCellData, cellPayloadAddress, cellHeaderSize );
                    iEngine.Sink().OutputLineL( pTempBuffer );
                    //
                    r = iEngine.Driver().WalkHeapNextCell( aThread.Id(), cellType, cellAddress, cellLength, cellNestingLevel, cellAllocationNumber, cellHeaderSize, cellPayloadAddress );
                    }
                }
            //
            iEngine.Driver().WalkHeapClose();
            }
        CleanupStack::PopAndDestroy( tempBuffer );
        CleanupStack::PopAndDestroy(); // clear prefix

        iEngine.Sink().DataStreamEndL();
        }

    CleanupStack::PopAndDestroy( &freeCells );
    CleanupStack::PopAndDestroy(); // resume process
    }
EXPORT_C void CMemSpyEngineHelperChunk::OutputChunkInfoForThreadL( const CMemSpyThread& aThread )
    {
    OutputChunkInfoForThreadL( aThread.Id() );
    }