memspy/Engine/Source/Helpers/MemSpyEngineHelperCodeSegment.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:37:10 +0100
branchRCL_3
changeset 44 52e343bb8f80
parent 0 a03f92240627
permissions -rw-r--r--
Revert incorrect RCL_3 drop: 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/engine/memspyenginehelpercodesegment.h>

// System includes
#include <e32capability.h>
#include <f32file.h>
#include <babitflags.h>

// Driver includes
#include <memspy/driver/memspydriverclient.h>

// User includes
#include <memspy/engine/memspyengine.h>
#include <memspy/engine/memspyengineutils.h>
#include <memspy/engine/memspyengineoutputsink.h>
#include <memspy/engine/memspyengineobjectthread.h>
#include <memspy/engine/memspyengineobjectprocess.h>

// Constants
const TInt KMemSpyEngineMaxCodeSegmentCount = 512;

// Literal constants
_LIT( KMemSpyEngineCodeSegListOutputComma, ", " );



CMemSpyEngineHelperCodeSegment::CMemSpyEngineHelperCodeSegment( CMemSpyEngine& aEngine )
:   iEngine( aEngine )
    {
    }

    
CMemSpyEngineHelperCodeSegment::~CMemSpyEngineHelperCodeSegment()
    {
    }


void CMemSpyEngineHelperCodeSegment::ConstructL()
    {
    }


CMemSpyEngineHelperCodeSegment* CMemSpyEngineHelperCodeSegment::NewL( CMemSpyEngine& aEngine )
    {
    CMemSpyEngineHelperCodeSegment* self = new(ELeave) CMemSpyEngineHelperCodeSegment( aEngine );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }


EXPORT_C void CMemSpyEngineHelperCodeSegment::OutputCodeSegmentsL( TUint aPid, TDes& aLine, const TDesC& aPrefix, TChar aSectionUnderlineCharacter, TBool aLowerCaseSectionHeading)
    {
	_LIT(KHeaderLC, "Code Segments");
	_LIT(KHeaderUC, "CODE SEGMENTS");

	_LIT(KFmtOverflow, "Only first %d code segments displayed");
	_LIT(KFmtMod, "%S%08X-%08X %S");

	const TInt KMaxCount = 256;
	TAny* handles[KMaxCount];
	TInt c = KMaxCount;

	TInt r = iEngine.Driver().GetCodeSegs(aPid, handles, c);
	if  ( r == KErrNone )
    	{
        if  ( c > 0 )
            {
            if  ( aLowerCaseSectionHeading )
                {
                iEngine.Sink().OutputSectionHeadingL( KHeaderLC, aSectionUnderlineCharacter );
                }
            else
                {
            	iEngine.Sink().OutputSectionHeadingL( KHeaderUC, aSectionUnderlineCharacter );
                }

        	if (c > KMaxCount)
        		{
        		c = KMaxCount;
        		aLine.Format(KFmtOverflow, c);
        		iEngine.Sink().OutputLineL( aLine );
        		}

        	TBuf<KMaxFileName> path;
        	TMemSpyDriverCodeSegInfo info;
        	for (TInt i=0; i<c; i++)
        		{
        		r = iEngine.Driver().GetCodeSegInfo(handles[i], aPid, info);
                //
        		if  ( r == KErrNone )
        			{
        			path.Copy( info.iCreateInfo.iFileName );
        			aLine.Format(KFmtMod, &aPrefix, info.iMemoryInfo.iCodeBase,info.iMemoryInfo.iCodeBase + info.iMemoryInfo.iCodeSize, &path);
        			iEngine.Sink().OutputLineL( aLine );
        			}
        		}
            }
        }
   }


EXPORT_C CMemSpyEngineCodeSegList* CMemSpyEngineHelperCodeSegment::CodeSegmentListL()
    {
    RArray<TAny*> handles( 16 );
    CleanupClosePushL( handles );

    // Get everything
    GetCodeSegmentHandlesL( handles, NULL, EFalse );
    CMemSpyEngineCodeSegList* list = ListFromHandlesLC( handles );
    //
    CleanupStack::Pop( list );
    CleanupStack::PopAndDestroy( &handles );
    //
    return list;
    }


CMemSpyEngineCodeSegList* CMemSpyEngineHelperCodeSegment::CodeSegmentListRamLoadedL()
    {
    RArray<TAny*> handles( 16 );
    CleanupClosePushL( handles );

    // Get just RAM-loaded
    GetCodeSegmentHandlesL( handles, NULL, ETrue );
    CMemSpyEngineCodeSegList* list = ListFromHandlesLC( handles );
    //
    CleanupStack::Pop( list );
    CleanupStack::PopAndDestroy( &handles );
    //
    return list;
    }


EXPORT_C CMemSpyEngineCodeSegList* CMemSpyEngineHelperCodeSegment::CodeSegmentListL( TProcessId aProcess )
    {
    TUint processId = aProcess;
    //
    RArray<TAny*> handles( 16 );
    CleanupClosePushL( handles );
    
    // Get process-specific list
    GetCodeSegmentHandlesL( handles, &processId, EFalse );
    CMemSpyEngineCodeSegList* list = ListFromHandlesLC( handles );
    //
    CleanupStack::Pop( list );
    CleanupStack::PopAndDestroy( &handles );
    //
    return list;
    }


void CMemSpyEngineHelperCodeSegment::GetCodeSegmentHandlesL( RArray<TAny*>& aHandles, TUint* aProcessId, TBool aRamOnly ) const
    {
	TAny* handles[ KMemSpyEngineMaxCodeSegmentCount ];
	TInt count = KMemSpyEngineMaxCodeSegmentCount;

	TInt r = KErrNone;
	
	if  ( aProcessId == NULL )
    	{
	    r = iEngine.Driver().GetCodeSegs( handles, count, aRamOnly );
	    }
    else
	    {
	    r = iEngine.Driver().GetCodeSegs( *aProcessId, handles, count );
	    }

	if  ( r == KErrNone )
    	{
        TInt index;
        TLinearOrder< TAny* > comparer( SortByAddress );
        
        // Remove duplicates - since we reqested code segments for all processes, there
        // might be some dupes.
        count = Min( count, KMemSpyEngineMaxCodeSegmentCount );
        for( index = 0; index < count; index++ )
            {
            TAny* handle = handles[ index ];
            const TInt error = aHandles.InsertInOrder( handle, comparer );
            //
            if  ( ! (error == KErrNone || error == KErrAlreadyExists ) )
                {
                User::Leave( error );
                }
            }
        }
    }


CMemSpyEngineCodeSegList* CMemSpyEngineHelperCodeSegment::ListFromHandlesLC( RArray<TAny*>& aHandles ) const
    {
    CMemSpyEngineCodeSegList* list = CMemSpyEngineCodeSegList::NewLC( iEngine );
    //
    TMemSpyDriverCodeSegInfo info;
    const TInt count = aHandles.Count();
    //
    for (TInt i=0; i<count; i++)
        {
        TAny* handle = aHandles[ i ];
        const TInt err = iEngine.Driver().GetCodeSegInfo( handle, 0, info );
        //
        if  ( err == KErrNone )
        	{
            // Create item
            CMemSpyEngineCodeSegEntry* entry = CMemSpyEngineCodeSegEntry::NewLC( handle, info.iSize, info.iCreateInfo, info.iMemoryInfo );
            list->AddItemL( entry );
            CleanupStack::Pop( entry );
        	}
        }
    //
    return list;
    }


TInt CMemSpyEngineHelperCodeSegment::SortByAddress( TAny* const& aLeft, TAny* const& aRight )
    {
    TInt ret = 1;
    //
    if  ( aLeft < aRight )
        {
        ret = -1;
        }
    else if ( aLeft == aRight )
        {
        ret = 0;
        }
    //
    return ret;
    }































CMemSpyEngineCodeSegList::CMemSpyEngineCodeSegList( CMemSpyEngine& aEngine )
:   CMemSpyEngineTwiddlableItemArray<CMemSpyEngineCodeSegEntry>( aEngine )
    {
    }


void CMemSpyEngineCodeSegList::ConstructL()
    {
    }


CMemSpyEngineCodeSegList* CMemSpyEngineCodeSegList::NewLC( CMemSpyEngine& aEngine )
    {
    CMemSpyEngineCodeSegList* self = new(ELeave) CMemSpyEngineCodeSegList( aEngine );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }

    
EXPORT_C TInt CMemSpyEngineCodeSegList::IndexByHandle( TAny* aHandle ) const
    {
    TInt index = KErrNotFound;
    //
    const TInt count = Count();
    for(TInt i=0; i<count; i++)
        {
        const CMemSpyEngineCodeSegEntry& entry = At( i );
        if  ( entry.Handle() == aHandle )
            {
            index = i;
            break;
            }
        }
    //
    return index;
    }


EXPORT_C void CMemSpyEngineCodeSegList::SortByFileNameL()
    {
    TLinearOrder< CMemSpyEngineCodeSegEntry > comparer( CompareByFileName );
    Sort( comparer );
    }


EXPORT_C void CMemSpyEngineCodeSegList::SortByCodeSizeL()
    {
    TLinearOrder< CMemSpyEngineCodeSegEntry > comparer( CompareByCodeSize );
    Sort( comparer );
    }


EXPORT_C void CMemSpyEngineCodeSegList::SortByDataSizeL()
    {
    TLinearOrder< CMemSpyEngineCodeSegEntry > comparer( CompareByDataSize );
    Sort( comparer );
    }


EXPORT_C void CMemSpyEngineCodeSegList::SortByUidsL()
    {
    TLinearOrder< CMemSpyEngineCodeSegEntry > comparer( CompareByUid );
    Sort( comparer );
    }


EXPORT_C void CMemSpyEngineCodeSegList::ShowOnlyEntriesWithGlobalDataL()
    {
    TMemSpyEngineVisibiltyFunction< CMemSpyEngineCodeSegEntry > function( VisibilityFunctionGlobalData, NULL );
    ShowL( function );
    SortByDataSizeL();
    }


EXPORT_C void CMemSpyEngineCodeSegList::OutputDataColumnsL( CMemSpyEngine& aEngine )
    {
    HBufC* columns = HBufC::NewLC( 1500 );
    TPtr pColumns( columns->Des() );

    //
    _LIT(KCol1, "Name");
    pColumns.Append( KCol1 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol2, "Uid %d");
    pColumns.AppendFormat( KCol2, 1 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );
    pColumns.AppendFormat( KCol2, 2 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );
    pColumns.AppendFormat( KCol2, 3 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol3, "Module Version");
    pColumns.Append( KCol3 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol4, "SID");
    pColumns.Append( KCol4 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol5, "VID");
    pColumns.Append( KCol5 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol6, "Code Size");
    pColumns.Append( KCol6 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol7, "Text Size");
    pColumns.Append( KCol7 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol8, "Data Size");
    pColumns.Append( KCol8 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol9, "BSS Size");
    pColumns.Append( KCol9 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol10, "Total Data Size");
    pColumns.Append( KCol10 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol11, "Entrypoint Veneer");
    pColumns.Append( KCol11 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol12, "File Entrypoint");
    pColumns.Append( KCol12 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol13, "Dependency Count");
    pColumns.Append( KCol13 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol14, "ROM Code Load Address");
    pColumns.Append( KCol14 );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    //
    _LIT(KCol15, "Data Load Address");
    pColumns.Append( KCol15 );

    //
    _LIT(KCol16, "Capabilities...");
    pColumns.Append( KCol16 );

    //
    aEngine.Sink().OutputLineL( pColumns );
    CleanupStack::PopAndDestroy( columns );
    }


EXPORT_C TInt CMemSpyEngineCodeSegList::MdcaCount() const
    {
    return Count();
    }


EXPORT_C TPtrC CMemSpyEngineCodeSegList::MdcaPoint( TInt aIndex ) const
    {
    const CMemSpyEngineCodeSegEntry& item = At( aIndex );
    return TPtrC( item.Caption() );
    }


TInt CMemSpyEngineCodeSegList::IndexByName( const TDesC& aName ) const
    {
    TInt index = KErrNotFound;
    //
    const TInt count = Count();
    for(TInt i=0; i<count; i++)
        {
        const CMemSpyEngineCodeSegEntry& entry = At( i );
        if  ( entry.FileName().FindF( aName ) >= 0 )
            {
            index = i;
            break;
            }
        }
    //
    return index;
    }


TInt CMemSpyEngineCodeSegList::CompareByFileName( const CMemSpyEngineCodeSegEntry& aLeft, const CMemSpyEngineCodeSegEntry& aRight )
    {
    const TInt ret = aLeft.FileName().CompareF( aRight.FileName() );
    return ret;
    }


TInt CMemSpyEngineCodeSegList::CompareByCodeSize( const CMemSpyEngineCodeSegEntry& aLeft, const CMemSpyEngineCodeSegEntry& aRight )
    {
    TInt ret = -1;
    //
    if  ( aLeft.CreateInfo().iCodeSize < aRight.CreateInfo().iCodeSize )
        {
        ret = 1;
        }
    else if ( aLeft.CreateInfo().iCodeSize == aRight.CreateInfo().iCodeSize )
        {
        ret = 0;
        }
    //
    return ret;
    }


TInt CMemSpyEngineCodeSegList::CompareByDataSize( const CMemSpyEngineCodeSegEntry& aLeft, const CMemSpyEngineCodeSegEntry& aRight )
    {
    TInt ret = -1;
    //
    if  ( aLeft.CreateInfo().iTotalDataSize < aRight.CreateInfo().iTotalDataSize )
        {
        ret = 1;
        }
    else if ( aLeft.CreateInfo().iTotalDataSize == aRight.CreateInfo().iTotalDataSize )
        {
        ret = 0;
        }
    //
    return ret;
    }


TInt CMemSpyEngineCodeSegList::CompareByUid( const CMemSpyEngineCodeSegEntry& aLeft, const CMemSpyEngineCodeSegEntry& aRight )
    {
    TInt ret = -1;
    //
    if  ( aLeft.CreateInfo().iUids.MostDerived().iUid < aRight.CreateInfo().iUids.MostDerived().iUid )
        {
        ret = 1;
        }
    else if ( aLeft.CreateInfo().iUids.MostDerived().iUid == aRight.CreateInfo().iUids.MostDerived().iUid )
        {
        ret = 0;
        }
    //
    return ret;
    }


TBool CMemSpyEngineCodeSegList::VisibilityFunctionGlobalData( const CMemSpyEngineCodeSegEntry*& aItem, TAny* /*aRune*/ )
    {
    const TBool hasGlobalData = ( aItem->CreateInfo().iTotalDataSize > 0 );
    return hasGlobalData;
    }


















CMemSpyEngineCodeSegEntry::CMemSpyEngineCodeSegEntry( TAny* aHandle, TInt aSize, const TCodeSegCreateInfo& aCreateInfo, const TProcessMemoryInfo& aMemoryInfo )
:   CDesCArrayFlat( 10 ), iHandle( aHandle ), iSize( aSize ), iCreateInfo( aCreateInfo ), iMemoryInfo( aMemoryInfo )
    {
    }


EXPORT_C CMemSpyEngineCodeSegEntry::~CMemSpyEngineCodeSegEntry()
    {
    delete iCaption;
    delete iFileName;
    }


void CMemSpyEngineCodeSegEntry::ConstructL()
    {
    iFileName = HBufC::NewL( iCreateInfo.iFileName.Length() );
    iFileName->Des().Copy( iCreateInfo.iFileName );

    // Make caption
    TParsePtrC parser( *iFileName );
    const TPtrC pFileNameWithoutPath( parser.NameAndExt() );
    TBuf<KMaxFullName + 128> item;
    //
    _LIT(KCodeSegFormat, "\t%S\t\t%S code");
    const TMemSpySizeText codeSize( MemSpyEngineUtils::FormatSizeText( iCreateInfo.iCodeSize ) );
    item.Format( KCodeSegFormat, &pFileNameWithoutPath, &codeSize );
    if  ( iCreateInfo.iDataSize > 0 )
        {
        _LIT(KCodeSegFormatAdditionalData, ", %S data");
        const TMemSpySizeText dataSize( MemSpyEngineUtils::FormatSizeText( iCreateInfo.iTotalDataSize ) );
        item.AppendFormat( KCodeSegFormatAdditionalData, &dataSize );
        }
    iCaption = item.AllocL();

    //
    _LIT(KItem0, "\tName\t\t%S");
    item.Format( KItem0, &pFileNameWithoutPath );
    AppendL( item );

    // Uids
    const TUidType uids( iCreateInfo.iUids );
    for( TInt i=0; i<KMaxCheckedUid; i++ )
        {
        _LIT(KItem1, "\tUid #%d\t\t0x%08x");
        const TUid uidValue( uids[ i ] );
        //
        item.Format( KItem1, i+1, uidValue.iUid );
        AppendL( item );
        }
    //
    if  ( iCreateInfo.iModuleVersion == KModuleVersionWild )
        {
        _LIT(KItem12, "\tModule Version\t\t[Wild]");
        AppendL( KItem12 );
        }
    else if ( iCreateInfo.iModuleVersion == KModuleVersionNull )
        {
        _LIT(KItem12, "\tModule Version\t\t[Null]");
        AppendL( KItem12 );
        }
    else
        {
        _LIT(KItem12, "\tModule Version\t\t0x%08x");
        item.Format( KItem12, iCreateInfo.iModuleVersion );
        AppendL( item );
        }

    //
    _LIT(KItem13, "\tSID\t\t0x%08x");
    item.Format( KItem13, iCreateInfo.iS.iSecureId );
    AppendL( item );

    //
    _LIT(KItem14, "\tVID\t\t0x%08x");
    item.Format( KItem14, iCreateInfo.iS.iVendorId );
    AppendL( item );

    //
    if  ( iCreateInfo.iCodeSize > 0 )
        {
        _LIT(KItem2, "\tCode Size\t\t%d");
        item.Format( KItem2, iCreateInfo.iCodeSize );
        AppendL( item );
        }

    //
    if  ( iCreateInfo.iTotalDataSize > 0 )
        {
        _LIT(KItem6, "\tTotal Data Size\t\t%d");
        item.Format( KItem6, iCreateInfo.iTotalDataSize );
        AppendL( item );
        }

    //
    if  ( iCreateInfo.iTextSize > 0 )
        {
        _LIT(KItem3, "\tText Size\t\t%d");
        item.Format( KItem3, iCreateInfo.iTextSize );
        AppendL( item );
        }

    //
    if  ( iCreateInfo.iDataSize > 0 )
        {
        _LIT(KItem4, "\tData Size\t\t%d");
        item.Format( KItem4, iCreateInfo.iDataSize );
        AppendL( item );
        }

    //
    if  ( iCreateInfo.iBssSize > 0 )
        {
        _LIT(KItem5, "\tBSS Size\t\t%d");
        item.Format( KItem5, iCreateInfo.iBssSize );
        AppendL( item );
        }

    //
    _LIT(KItem7, "\tEntrypoint Veneer\t\t0x%08x");
    item.Format( KItem7, iCreateInfo.iEntryPtVeneer );
    AppendL( item );

    //
    _LIT(KItem8, "\tFile Entrypoint\t\t0x%08x");
    item.Format( KItem8, iCreateInfo.iFileEntryPoint );
    AppendL( item );

    //
    _LIT(KItem9, "\tDependency Count\t\t%d");
    item.Format( KItem9, iCreateInfo.iDepCount );
    AppendL( item );

    //
    if  ( iCreateInfo.iCodeLoadAddress != 0 )
        {
        _LIT(KItem10, "\tROM Code Load Addr.\t\t0x%08x");
        item.Format( KItem10, iCreateInfo.iCodeLoadAddress );
        AppendL( item );
        }
    else
        {
        _LIT(KItem10, "\tROM Code Load Addr.\t\t[RAM Loaded]");
        AppendL( KItem10 );
        }

    //
    if  ( iCreateInfo.iDataLoadAddress != 0 )
        {
        _LIT(KItem11, "\tData Load Addr.\t\t0x%08x");
        item.Format( KItem11, iCreateInfo.iDataLoadAddress );
        AppendL( item );
        }

    //
    AddCapabilityItemsL();
    }


CMemSpyEngineCodeSegEntry* CMemSpyEngineCodeSegEntry::NewLC( TAny* aHandle, TInt aSize, const TCodeSegCreateInfo& aCreateInfo, const TProcessMemoryInfo& aMemoryInfo )
    {
    CMemSpyEngineCodeSegEntry* self = new(ELeave) CMemSpyEngineCodeSegEntry( aHandle, aSize, aCreateInfo, aMemoryInfo );
    CleanupStack::PushL( self );
    self->ConstructL();
    return self;
    }


EXPORT_C TBool CMemSpyEngineCodeSegEntry::HasCapability( TCapability aCapability ) const
    {
    TBool hasCap = EFalse;
    //
    for( TInt i=0; i<SCapabilitySet::ENCapW && !hasCap; i++ )
        {
        const TUint32 capsRawValue = iCreateInfo.iS.iCaps[i];
        const TBitFlags flags( capsRawValue );
        //
        hasCap = flags.IsSet( aCapability );
        }
    //
    return hasCap;
    }


EXPORT_C void CMemSpyEngineCodeSegEntry::OutputDataL( CMemSpyEngineHelperCodeSegment& aHelper ) const
    {
    _LIT(KHexFormat, "0x%08x");

    HBufC* columns = HBufC::NewLC( 4096 );
    TPtr pColumns( columns->Des() );

    // Name
    TParsePtrC parser( *iFileName );
    const TPtrC pFileNameWithoutPath( parser.NameAndExt() );
    pColumns.Append( pFileNameWithoutPath );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Uids
    const TUidType uids( iCreateInfo.iUids );
    for( TInt i=0; i<KMaxCheckedUid; i++ )
        {
        const TUid uidValue( uids[ i ] );
        //
        pColumns.AppendFormat( KHexFormat, uidValue.iUid );
        pColumns.Append( KMemSpyEngineCodeSegListOutputComma );
        }

    // Module version
    if  ( iCreateInfo.iModuleVersion == KModuleVersionWild )
        {
        _LIT( KCaption, "Wild");
        pColumns.Append( KCaption );
        }
    else if ( iCreateInfo.iModuleVersion == KModuleVersionNull )
        {
        _LIT( KCaption, "Null");
        pColumns.Append( KCaption );
        }
    else
        {
        pColumns.AppendFormat( KHexFormat, iCreateInfo.iModuleVersion );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // SID
    pColumns.AppendFormat( KHexFormat, iCreateInfo.iS.iSecureId );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // VID
    pColumns.AppendFormat( KHexFormat, iCreateInfo.iS.iVendorId );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Code size
    if  ( iCreateInfo.iCodeSize > 0 )
        {
        pColumns.AppendNum( iCreateInfo.iCodeSize, EDecimal );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Text size
    if  ( iCreateInfo.iTextSize > 0 )
        {
        pColumns.AppendNum( iCreateInfo.iTextSize, EDecimal );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Data size
    if  ( iCreateInfo.iDataSize > 0 )
        {
        pColumns.AppendNum( iCreateInfo.iDataSize, EDecimal );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // BSS
    if  ( iCreateInfo.iBssSize > 0 )
        {
        pColumns.AppendNum( iCreateInfo.iBssSize, EDecimal );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Total data size
    if  ( iCreateInfo.iTotalDataSize > 0 )
        {
        pColumns.AppendNum( iCreateInfo.iTotalDataSize, EDecimal );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Entrypoint veneer
    pColumns.AppendFormat( KHexFormat, iCreateInfo.iEntryPtVeneer );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // File Entrypoint
    pColumns.AppendFormat( KHexFormat, iCreateInfo.iFileEntryPoint );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Dependency Count
    pColumns.AppendNum( iCreateInfo.iDepCount, EDecimal );
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // ROM Code Load Address
    if  ( iCreateInfo.iCodeLoadAddress != 0 )
        {
        pColumns.AppendFormat( KHexFormat, iCreateInfo.iCodeLoadAddress );
        }
    else
        {
        _LIT(KCaption, "N.A. - RAM Loaded");
        pColumns.Append( KCaption );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Data Load Address
    if  ( iCreateInfo.iDataLoadAddress != 0 )
        {
        pColumns.AppendFormat( KHexFormat, iCreateInfo.iDataLoadAddress );
        }
    pColumns.Append( KMemSpyEngineCodeSegListOutputComma );

    // Capabilities
    CDesCArray* capabilities = CapabilityStringsLC();
    const TInt count = capabilities->Count();
    //
    for( TInt j=0; j<count; j++ )
        {
        const TPtrC capabilityName( (*capabilities)[ j ] );
        //
        pColumns.Append( capabilityName );
        if  ( j < count-1 )
            {
            pColumns.Append( KMemSpyEngineCodeSegListOutputComma );
            }
        }
    //
    CleanupStack::PopAndDestroy( capabilities );

    aHelper.Engine().Sink().OutputLineL( pColumns );

    CleanupStack::PopAndDestroy( columns );
    }


void CMemSpyEngineCodeSegEntry::AddCapabilityItemsL()
    {
    _LIT(KCapFormat, "\tCapability #%3d\t\t%S");
    TBuf<128> item;
    //
    CDesCArray* capabilities = CapabilityStringsLC();
    const TInt count = capabilities->Count();
    //
    for( TInt i=0; i<count; i++ )
        {
        const TPtrC capabilityName( (*capabilities)[ i ] );
        item.Format( KCapFormat, i+1, &capabilityName );
        AppendL( item );
        }
    //
    CleanupStack::PopAndDestroy( capabilities );
    }


CDesCArray* CMemSpyEngineCodeSegEntry::CapabilityStringsLC() const
    {
    CDesCArrayFlat* array = new(ELeave) CDesCArrayFlat( ECapability_Limit );
    CleanupStack::PushL( array );
    //
    const TInt KCapabilityCountPer32Bits = 32;
    //
    for( TInt i=0; i<SCapabilitySet::ENCapW; i++ )
        {
        const TUint32 caps = iCreateInfo.iS.iCaps[i];
        //
        AddCapabilitiesL( caps, i * KCapabilityCountPer32Bits, *array );
        }
    //
    return array;
    }


void CMemSpyEngineCodeSegEntry::AddCapabilitiesL( TUint32 aCaps, TInt aCapCount, CDesCArray& aArray ) const
    {
    TBitFlags flags( aCaps );
    TBuf<128> capabilityName;
    //
    for( TInt i=aCapCount; i<aCapCount + 32 && i<ECapability_Limit; i++ )
        {
        const TBool isSet = flags.IsSet( i );
        //
        if  ( isSet )
            {
            // Get capability name
            const TCapability capability = static_cast< TCapability >( i );
            MemSpyEngineUtils::GetCapabilityName( capabilityName, capability );

            // Make a capability entry for this item
            aArray.AppendL( capabilityName );
            }
        }
    }