// Copyright (c) 2008-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 <e32debug.h>
#include <d32btrace.h>
#include <crashlogwalker.h>
#include <optionconfig.h>
#include "flashdatasource.h"

// Required for interface to Debug Security Server via RSecuritySvrSession
#include "coredumpsession.h"

using namespace Debug;

CFlashDataSource::CFlashDataSource(RSecuritySvrSession &aSource) :
	iSecSess(aSource),
	iLockData(NULL),
	iRomBuildInfo(NULL),
	iTraceDump(NULL),
	iVarSpecData(NULL),
    iWalker(iFlashBuf),
	iScmConfig(NULL),
	iCrashFound(EFalse)
	{
	//no implementation
	}

/**
 * This looks at the crash logs header and keeps note of where all the different types of data reside
 * @return one of the OS wide system codes
 */
TInt CFlashDataSource::ProcessCrashHeaderL(TInt aCrashStart)
	{
	LOG_MSG("CFlashDataSource::ProcessCrashHeader()");

	//record where the crash started
	TInt iCrashStart = aCrashStart;

	User::LeaveIfError(ReadCrashLog(iCrashStart, Debug::KMaxCoreHeaderSize));
	User::LeaveIfError(iWalker.ReadLogHeader(0));

	iHdr = iWalker.GetCrashHeader();
	iOffsetsHdr = iWalker.GetOffsetsHeader();

	if(iOffsetsHdr.iId == ESCMOffsetsHeader)
		{
		iOffsetsPresent = ETrue;
		}

	return KErrNone;
	}

/**
 * attempts to read the scm config block from start of flash to see if its there
 * @return The configuration block if found. Check for NULL and ownership is passed to caller
 */
SCMConfiguration* CFlashDataSource::GetSCMConfigFromFlashL()
	{
	LOG_MSG("CFlashDataSource::GetSCMConfigFromFlashL()");

	//Always at start of flash
	TInt scmLocation = 0;
	Debug::SCMConfiguration* config = new Debug::SCMConfiguration();
	CleanupStack::PushL(config);

	User::LeaveIfError(ReadCrashLog(scmLocation, SCMConfiguration::KScmConfigMaxSize));
	CleanupStack::Pop();	
	//Put a reader on the buffer
	TByteStreamReader rdr(const_cast<TUint8*>(iFlashBuf.Ptr()));
	if(config->Deserialize(rdr) == KErrNone)
		{

		LOG_MSG3("CFlashDataSource::GetSCMConfigFromFlashL()  Config found. It is [%d] [0x%X] bytes in size",
					config->GetSize(), config->GetSize());

		LOG_MSG("CFlashDataSource::GetSCMConfigFromFlashL() #2");
		return config;
		}
	else
		{
		LOG_MSG("CFlashDataSource::GetSCMConfigFromFlashL() No config found");
		delete config;
		return NULL;
		}
	}

/**
 * This looks at the entire log partition looking for where the crash of this ID
 * begins
 * @param aCrashId ID we are looking for
 * @return TInt where crash starts
 * @leave One of the OS wide codes
 */
TInt CFlashDataSource::GetCrashStartFromCrashIDL(TInt aCrashId)
	{
	LOG_MSG2("CFlashDataSource::GetCrashStartFromCrashIDL(TInt aCrashId)	 ID = %d", aCrashId);

	TInt crashStart = 0;
	TInt readStatus = KErrNone;

	//Start looking where the config ends if it exists
	Debug::SCMConfiguration* config = GetSCMConfigFromFlashL();
	if(config)
		{
		crashStart = config->GetSize();
		}

	delete config;

	while(readStatus == KErrNone)
		{
		User::LeaveIfError(ReadCrashLog(crashStart, Debug::KMaxCoreHeaderSize));

		readStatus = iWalker.ReadLogHeader(0); //Look at header from start of buffer

		if(readStatus != KErrNone)
			{
			CLTRACE("CFlashDataSource::GetCrashStartFromCrashIDL ReadCrashLogL leaving with KErrNotFound #1");
			User::Leave(KErrNotFound);
			}
		else if(iWalker.GetCrashHeader().iCrashId == aCrashId)
			{
			return crashStart;
			}

		const TCrashInfoHeader currentHdr = iWalker.GetCrashHeader();

		TUint32 flashPadding = currentHdr.iFlashBlockSize - (crashStart + currentHdr.iLogSize)%currentHdr.iFlashBlockSize;
		crashStart += (currentHdr.iLogSize + flashPadding);
		}

	CLTRACE("CFlashDataSource::GetCrashStartFromCrashIDL ReadCrashLogL leaving with KErrNotFound #2");
	User::Leave(KErrNotFound);

	return 0;  //avoid comp warnings
	}

/**
 * This walks the crash log verifying it is not corrupt and builds up a map of the log so that we can get the
 * data required faster later on when the appropriate call is made.
 * @param Crash ID to look at
 * @leave One of the system wide error codes
 */
void CFlashDataSource::AnalyseCrashL(TInt aCrashId)
	{
	LOG_MSG2("CFlashDataSource::AnalyseCrashL(TInt aCrashId = [%d])", aCrashId);

	//Reset the state
	iOffsetsPresent = EFalse;
	iCrashMemoryMap.Reset();
	iCodeSegMap.Reset();
	iHdrProcd = EFalse;

    if(iCurrentCodeSegSet)
    	{
		delete iCurrentCodeSegSet;
		iCurrentCodeSegSet = NULL;
    	}

    if(iLockData)
    	{
    	delete iLockData;
    	iLockData = NULL;
    	}

    if(iRomBuildInfo)
    	{
    	delete iRomBuildInfo;
    	iRomBuildInfo = NULL;
    	}

	TInt crashStart = GetCrashStartFromCrashIDL(aCrashId);
	ProcessCrashHeaderL(crashStart);

	TInt dataSizeRead = 0;
	TInt flashPos = crashStart;

	//either read the defined amt or the log size, whichever is less
	TInt rdSize = READ_SIZE;

	/**
	 *	Our conditions to keep reading  or decide log is corrupt are:
	 *	1. Have we read logSize bytes?
	 *			No - Keep Going
	 *			Yes - Finished
	 *			More - Corrupt
	 *  2. There is no more data of interest to be read. Is the number of bytes read = log size?
	 */

	TInt recommendedReadSize = 0;

	while(dataSizeRead != iHdr.iLogSize)
		{
		//We need to decide how much to read here. It is possible that we need to read greater than the log size
		//as the reader can't know in advance the exact size of a struct, so it has to assume the worst case scenario
		//of the largest size it could be
		rdSize = (rdSize < READ_SIZE) ? READ_SIZE : rdSize;	//resize this to be large

		TInt bytesRemaining = iHdr.iLogSize - dataSizeRead;
		if(rdSize > bytesRemaining)
			{
			rdSize = bytesRemaining;
			}

		//always be at least the rec read size
		rdSize = (rdSize < recommendedReadSize) ? recommendedReadSize : rdSize;

		User::LeaveIfError(ReadCrashLog(flashPos, rdSize));

		//Get what we can out of this buffer read
		SCMStructId id = ESCMFirst;
		TInt bufferPos = 0;
		MByteStreamSerializable* data = NULL;

		do
			{
			//Have we got to end of crash?
			if(dataSizeRead == iHdr.iLogSize)
				{
				break;
				}

			data = iWalker.GetNextDataTypeL(bufferPos, id, recommendedReadSize);

			//Analyse what we got
			if(data)
				{
				CleanupStack::PushL(data);
				dataSizeRead += data->GetSize();

				//check we are within range
				if(dataSizeRead > iHdr.iLogSize)
					{
					LOG_MSG4("CFlashDataSource::AnalyseCrashL: Corrupt -->    dataSizeRead [%d] > iHdr.iLogSize [%d] at line [%d]", dataSizeRead, iHdr.iLogSize, __LINE__);
					User::Leave(KErrCorrupt);
					}

				HelpAnalyseCrashL(data, id, flashPos + bufferPos - data->GetSize());
				CleanupStack::PopAndDestroy(data);
				}
			else
				{
				//if data was NULL, that means there wasnt enough room in the buffer to read the next one
				flashPos += bufferPos;
				}
			}
		while(data);
		}
	}

/**
 * Helper for crash analysis. Takes a pointer to a data type, an ID to tell us what type it is, and where
 * in the flash it has been found. If it is a type of interest, we record its position
 * @param aData Data Type of interest
 * @param aStructId ID to describe data type
 * @param aPosFound Where it was found in the flash
 * @leave
 */
void CFlashDataSource::HelpAnalyseCrashL(const MByteStreamSerializable* aData, TInt aStructId, TInt aPosFound)
	{

	switch(aStructId)
		{
		case ESCMMemory :
			{
			//we want to keep track of this objects
			TObjectLocation map;
			map.iOffset = aPosFound;
			map.iObjectId = static_cast<const TMemoryDump*>(aData)->iPid;

			iCrashMemoryMap.AppendL(map);

			break;
			}
		case ESCMCodeSegSet :
			{
			//The set contains the PID for the code segs to follow - copy to our cached version
			if(iCurrentCodeSegSet)
				{
				delete iCurrentCodeSegSet;
				iCurrentCodeSegSet = NULL;
				}

			iCurrentCodeSegSet = new TCodeSegmentSet();
			*iCurrentCodeSegSet = *(static_cast<const TCodeSegmentSet*>(aData));

			break;
			}
		case ESCMCodeSeg :
			{
			//ensure we have a code segment set for this
			__ASSERT_ALWAYS(iCurrentCodeSegSet, User::Leave(KErrCorrupt));

			//we want to keep track of these objects
			TObjectLocation map;
			map.iOffset = aPosFound;
			map.iObjectId = iCurrentCodeSegSet->iPid;

			iCodeSegMap.AppendL(map);

			break;
			}
		case ESCMRomHeader :
			{
			if(iRomBuildInfo)
				{
				delete iRomBuildInfo;
				iRomBuildInfo = NULL;
				}

			iRomBuildInfo = new TRomHeaderData();
			*iRomBuildInfo = *(static_cast<const TRomHeaderData*>(aData));

			break;
			}
		case ESCMLocks:
			{
			if(iLockData)
				{
				delete iLockData;
				iLockData = NULL;
				}

			iLockData = new TSCMLockData();
			*iLockData = *(static_cast<const TSCMLockData*>(aData));

			break;
			}
		case ESCMTCrashInfo :
			{
			iHeaderStart = aPosFound;

			break;
			}
		case ESCMTraceData :
			{
			if(iTraceDump)
				{
				delete iTraceDump;
				iTraceDump = NULL;
				}

			iTraceDump = new TTraceDump();
			*iTraceDump = *(static_cast<const TTraceDump*>(aData));

			break;
			}
		case ESCMVariantData:
			{
			if(iVarSpecData)
				{
				delete iVarSpecData;
				iVarSpecData = NULL;
				}

			iVarSpecData = new TVariantSpecificData();
			*iVarSpecData = *(static_cast<const TVariantSpecificData*>(aData));

			break;
			}
		case ESCMOffsetsHeader :
		case ESCMProcessData :
		case ESCMThreadData :
		case ESCMThreadStack :
		case ESCMRegisterValue :
		case ESCMRegisterSet :
		case ESCMRawData :
			{
			//No problem if we arent interested in the object, carry on, nothing to see here
			break;
			}
		default :
			{
			LOG_MSG2("CFlashDataSource::HelpAnalyseCrashL --> Dont recognise struct ID = [%d] therefore corrupt", aStructId);

			//if we dont recognise the object, then oddness is afoot and the mist of corruption reigns thick
			User::Leave(KErrCorrupt);
			}
		}

	}

/**
 * This Reads the portion of the crash log of interest into our buffer for processing later
 *
 * @param aPos Position of crash log to begin reading
 * @param aSize amount of data to read
 * @return KErrArgument if aSize exceeds the maximum read allowed or one of the other OS wide codes
 */
TInt CFlashDataSource::ReadCrashLog(const TInt aPos, const TUint aSize)
	{
	//ensure parameters are ok
	if(aPos < 0)
		{
		return KErrArgument;
		}

	TInt err = ReallocFlashBuf(aSize);
	if(err != KErrNone)
		{
		return err;
		}

	iWalker.UpdateBuffer(iFlashBuf);

	iFlashBuf.Zero();

	//Read the data from the flash buffer
	return iSecSess.ReadCrashLog(aPos, iFlashBuf, aSize);
	}

/**
 * Two Phase Constructor for CFlashDataSource
 * @param aSource Reference to Security Server session
 * @return Pointer to new CFlashDataSource object
 * @leave
 */
CFlashDataSource* CFlashDataSource::NewL(RSecuritySvrSession &aSource)
{
    CFlashDataSource *self = new(ELeave) CFlashDataSource(aSource);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    return self;
}

/**
 * second-phase constructor
 */
void CFlashDataSource::ConstructL()
    {
    //Create flash buffer. Will be resized as required
    iFlashBuf.CreateL(KInitialBufferSize);
    iFlashBuf.FillZ();

	iScmConfig = new (ELeave) Debug::SCMConfiguration();
	iScmConfig->SetDefaultConfig();

    }

/**
 * Destructor
 */
CFlashDataSource::~CFlashDataSource()
    {
	LOG_MSG( "server_crashdatasource.cpp::CFlashDataSource::~CFlashDataSource()\n" );
	iFlashBuf.Close();
	iFirstBlockBuf.Close();

	iCodeSegMap.Close();
	iCrashMemoryMap.Close();
	iThreadOwners.Close();

	if(iScmConfig)
		{
		delete iScmConfig;
		iScmConfig = NULL;
		}

	if(iCurrentCodeSegSet)
		{
		delete iCurrentCodeSegSet;
		iCurrentCodeSegSet = NULL;
		}

	if(iLockData)
		{
		delete iLockData;
		iLockData = NULL;
		}

	if(iRomBuildInfo)
		{
		delete iRomBuildInfo;
		iRomBuildInfo = NULL;
		}

	if(iTraceDump)
		{
		delete iTraceDump;
		iTraceDump = NULL;
		}

	if(iVarSpecData)
		{
		delete iVarSpecData;
		iVarSpecData = NULL;
		}

    }

void CFlashDataSource::GetRegisterListL( RRegisterList & aRegisterList )
	{
	//Not used
	User::Leave(KErrNotSupported);
	}

/**
 * Reads registers from flash for a given thread
 * @param aThreadId Thread of interest
 * @param aRegisterList Appends any registers found to this list
 * @leave OS wide code
 */
void CFlashDataSource::ReadRegistersL( const TUint64 aThreadId, RRegisterList  & aRegisterList )
	{
    LOG_MSG("CFlashDataSource::ReadRegistersL()");

	// Delete any objects in the array, since we will replace them.
	aRegisterList.Reset();

    /**
     * We keep 3 sets of registers in the flash at different points.
     * The first is the FullCPU register set for the thread that has crashed.
     * The second are the supervisor registers for a given thread (may not all be available)
     * The third are the user registers for a given thread (may not all be available)
     * These corrospond to 3 different configuration options
     */

	//See if it is the crashed threads full CPU set
	if(aThreadId == iHdr.iTid)
		{
	   	//Put regs into list
	   	HelpReadRegistersL(iOffsetsHdr.iCTFullRegOffset, iHdr.iLogSize, aThreadId, aRegisterList);
		return;
		}

	//Now we look at SVR registers
	HelpReadRegistersL(iOffsetsHdr.iSysSvrRegOffset, iOffsetsHdr.iSysUsrRegOffset, aThreadId, aRegisterList);

	//And finally the USR registers
	HelpReadRegistersL(iOffsetsHdr.iSysUsrRegOffset, iOffsetsHdr.iSysSvrRegOffset, aThreadId, aRegisterList);

	}

/**
 * This takes in a register list and looks at our flash buffer. It reads any registers it can out of the buffer
 * and appends them to the list.
 * @param aRegStartPoint Position in flash to begin searching from
 * @param aMaxReadPoint Position beyond which we shall not read
 * @param aThreadId Thread whose registers we want
 * @param aRegList List in which to store found registers
 * @leave KErrCorrupt if the buffer doesnt contain valid buffer data
 */
void CFlashDataSource::HelpReadRegistersL(TInt aRegStartPoint, TInt aMaxReadPoint, TUint64 aThreadId, RRegisterList& aRegList)
	{
	TRegisterValue* regVal;
	TBool stillMoreDataToBeHad = ETrue;
	TInt flashPos = aRegStartPoint;
	TInt rdSize = READ_SIZE;

	//cycle through the flash partition, rdSize bytes at a time until there is no more data of interest to be had
	while(stillMoreDataToBeHad)
		{
		User::LeaveIfError(ReadCrashLog(flashPos, rdSize));

		//Get what we can out of this buffer read
		TInt pos, bufferSize = 0;
		SCMStructId id = ESCMLast;
		MByteStreamSerializable* data = NULL;

		TRAPD(err, data = iWalker.GetNextDataTypeL(pos, id, bufferSize));
		if(err != KErrNone)
			{
			return; //We dont mind if this returns corrupt. This is only relevant during initial analysis
			}

		while(data && stillMoreDataToBeHad)
			{
			CleanupStack::PushL(data);

			switch(id)
				{
				case ESCMRegisterSet :
					{
					break;
					}
				case ESCMRegisterValue :
					{
					regVal = static_cast<TRegisterValue*>(data);

			    	//See if its for the right thread
			    	if(regVal->iOwnId != aThreadId)
			    		{
			    		break;
			    		}

			    	TRegisterData newData;
			    	ConvertFlashFormatRegL(newData, *regVal);
			    	aRegList.AppendL(newData);

					break;
					}

				//Dont care bout these
				case ESCMFirst :
				case ESCMOffsetsHeader :
				case ESCMTCrashInfo :
				case ESCMThreadData :
				case ESCMThreadStack :
				case ESCMMemory :
				case ESCMCodeSegSet :
				case ESCMCodeSeg :
				case ESCMRawData :
				case ESCMLast :
				default :
					{
					//No more registers mean no more interest
					stillMoreDataToBeHad = EFalse;
					}
				}

			CleanupStack::PopAndDestroy(data);

			//ignore beyond the max point
			if(pos + flashPos == aMaxReadPoint)
				{
				return;
				}
				
			if(stillMoreDataToBeHad)
				{
				//Get next type
				TRAPD(err, data = iWalker.GetNextDataTypeL(pos, id, bufferSize));
				if(err != KErrNone)
					{
					//We dont mind if this returns corrupt. This is only relevant during initial analysis
					return;
					}
				}
			}

		//if data was null but there is still more data to be had, that means we need to read more data
		//from the flash to give to our walker. it will need a buffer size of at least bufferSize, starting
		//from flashPos + pos
		flashPos += pos;
		rdSize = (bufferSize > rdSize) ? bufferSize : rdSize;

		}
	}

/**
 * Helper to convert between register value formats
 * @param aData Output format of the register data
 * @param aOriginalVal register format as it appears in flash
 */
void CFlashDataSource::ConvertFlashFormatRegL(TRegisterData& aData, const TRegisterValue& aOriginalVal)
	{

	aData.iRegClass = aOriginalVal.iClass;
	aData.iSubId = aOriginalVal.iSubId;
	aData.iId = aOriginalVal.iType;
	aData.iSize = aOriginalVal.iSize;
	aData.iAvailable = ETrue;

	switch(aOriginalVal.iSize)
		{
		case 0:
			{
			aData.iValue8 = aOriginalVal.iValue8;
			break;
			}
		case 1:
			{
			aData.iValue16 = aOriginalVal.iValue16;
			break;
			}
		case 2:
			{
			aData.iValue32 = aOriginalVal.iValue32;
			break;
			}
		case 3:
			{
			aData.iValue64 = aOriginalVal.iValue64;
			break;
			}
		//funny data, run for the hills
		default: User::Leave(KErrCorrupt);
		}
	}

/**
Purpose:
Read memory if dumped into the flash. The parameters relate to those when
the system was live and running. If this memory region has not been dumped
this leaves with a KErrNotFound

@param aThreadId - The id of the thread relative to which the read should take place
@param aAddress - The virtual address to read from
@param aLength - The number of bytes to read
@param aData - The buffer to read into
@leave KErrNotFound if memory not available or one of the system wide codes
*/
void CFlashDataSource::ReadMemoryL(
                   const TUint64    aThreadId,
                   const TUint32    aAddress,
                   const TUint32    aLength,
                   TDes8          & aData )
	{
	LOG_MSG4("CFlashDataSource::ReadMemoryL ThreadID = [%ld] aAddress = [0x%X] aLength = [%d]", aThreadId, aAddress, aLength);

	if(aLength == 0)
		{
		return;
		}

	//check arguments
	if(aData.MaxLength() < aLength)
		{
		User::Leave(KErrOverflow);
		}

	const TUint64 procId = GetThreadOwnerL(aThreadId);
	TInt errFound = KErrNone;

	//Look through our memory map to see if we have anything for this thread
	TInt cnt = iCrashMemoryMap.Count() - 1;
	for(; cnt >= 0; cnt-- )
		{
		TObjectLocation& m = iCrashMemoryMap[cnt];

		if(m.iObjectId == procId)
			{
			TInt sizeToRead = TMemoryDump::KSCMMemDumpMaxSize;

			//we must read this struct to check if we are interested in it
			User::LeaveIfError(ReadCrashLog(m.iOffset, sizeToRead));

			TInt pos = 0;
			SCMStructId id = ESCMLast;

			MByteStreamSerializable* data = iWalker.GetNextDataTypeL(pos, id, sizeToRead);

			if(id != ESCMMemory)
				{
				delete data;
				errFound = KErrCorrupt;
				//Still keep looking through the memory list
				continue;
				}

			TMemoryDump* memDump = static_cast<TMemoryDump*>(data);
			CleanupStack::PushL(memDump);

			//have we dumped this memory
			if(aAddress >= memDump->iStartAddress   && (aAddress + aLength) <= (memDump->iStartAddress + memDump->iLength))
				{
				//Now we need to read in the Raw data structure
				User::LeaveIfError(ReadCrashLog(m.iOffset + memDump->GetSize(), TRawData::KSCMRawDataMaxSize + memDump->iLength));

				TInt bufSize = 0;
				TRawData* rawData = iWalker.GetRawDataTypeL(pos, bufSize, aData, aAddress - memDump->iStartAddress);
				if(!rawData)
					{
					//descriptor not big enough
					errFound = KErrOverflow;
					CleanupStack::PopAndDestroy();

					//Still keep looking through the memory list
					continue;
					}

				CleanupStack::PushL(rawData);

				//Now we need to copy into the buffer supplied
				//aData.Copy(rawData->iData.Mid(memDump->iStartAddress - aAddress , aLength));

				CleanupStack::PopAndDestroy(2);

				return;
				}

			CleanupStack::PopAndDestroy();
			}
		}

	if(errFound == KErrNone)
		User::Leave(KErrNotFound);
	else
		User::Leave(errFound);

	}

void CFlashDataSource::GetProcessListL( RProcessPointerList & aProcessList,
											  TUint & aTotalProcessListDescSize )
    {
    LOG_MSG("CFlashDataSource::GetProcessListL()");

	// Delete any objects in the array, since we will replace them.
	aProcessList.ResetAndDestroy();
	aTotalProcessListDescSize = 0;

    //Find out where in flash to read from
    TInt flashPos = iOffsetsHdr.iPLstOffset;
    TInt rdSize = READ_SIZE;
    TBool stillMoreDataToBeHad = ETrue;

	//cycle through the flash partition, rdSize bytes at a time until there is no more data of interest to be had
	while(stillMoreDataToBeHad)
		{
		User::LeaveIfError(ReadCrashLog(flashPos, rdSize));

		//Get what we can out of this buffer read
		TInt pos, bufferSize = 0;
		SCMStructId id = ESCMLast;
		MByteStreamSerializable* data = NULL;
		TProcessData* proc = NULL;

		TRAPD(err, data = iWalker.GetNextDataTypeL(pos, id, bufferSize));
		if(err != KErrNone)
			{
			return; //We dont mind if this returns corrupt. This is only relevant during initial analysis
			}

		while(data && stillMoreDataToBeHad)
			{
			CleanupStack::PushL(data);

			switch(id)
				{
				case ESCMProcessData :
					{
					proc = static_cast<TProcessData*>(data);

			    	//Now we need to widen the name descriptor to 16 bits
			    	RBuf name16;
			    	name16.CreateL(proc->iNamesize);
			    	name16.CleanupClosePushL();

			    	name16.Copy(proc->iName);

			    	//create the new process object
			    	CProcessInfo* pi = CProcessInfo::NewL(proc->iPid, name16);
			    	aProcessList.AppendL(pi);

			    	aTotalProcessListDescSize += pi->Size();

			    	CleanupStack::PopAndDestroy();

					break;
					}
				case ESCMFirst :
				case ESCMOffsetsHeader :
				case ESCMTCrashInfo :
				case ESCMThreadData :
				case ESCMThreadStack :
				case ESCMRegisterValue :
				case ESCMRegisterSet :
				case ESCMMemory :
				case ESCMCodeSegSet :
				case ESCMCodeSeg :
				case ESCMRawData :
				case ESCMLast :
				default :
					{
					//No more registers mean no more interest
					stillMoreDataToBeHad = EFalse;
					}
				}

			CleanupStack::PopAndDestroy(data);

			//Get next type
			TRAPD(err, data = iWalker.GetNextDataTypeL(pos, id, bufferSize));
			if(err != KErrNone)
				{
				//We dont mind if this returns corrupt. This is only relevant during initial analysis
				return;
				}

			}

		if(data)
			{
			delete data;
			}

		//if data was null but there is still more data to be had, that means we need to read more data
		//from the flash to give to our walker. it will need a buffer size of at least bufferSize, starting
		//from flashPos + pos
		flashPos += pos;
		rdSize = (bufferSize > rdSize) ? bufferSize : rdSize;

		}
	}

void CFlashDataSource::GetExecutableListL( RExecutablePointerList & aExecutableList,
											  TUint & aTotalExecutableListDescSize )
    {
    //TODO
    User::Leave(KErrNotSupported);
	}

/**
 * Creates an ownership relation between a thread and a process. As when the board crashes we cant
 * find this out from the system, we need to generate it as we go
 * @param aOwningProcessId The owning process ID
 * @param aThreadId The child thread ID
 */
void CFlashDataSource::AssignOwner(TInt64 aOwningProcessId, TInt64 aThreadId)
	{
	TChildOwnerPair pair(aOwningProcessId, aThreadId);
	iThreadOwners.Append(pair);
	}

/**
 * Obtain the thread list. If aProcessId is (TUint64 -1), we obtain the entire system
 * thread list. If aProcessId is positive we get the thread list for that process
 *
 * @param aProcessId Process to gather threads for
 * @param aThreadList Thread list stored here
 * @param aTotalThreadListDescSize list size
 * @leave One of the OS wide system codes
 */
void CFlashDataSource::GetThreadListL( const TUint64 aProcessId,
											 RThreadPointerList & aThreadList,
											 TUint & aTotalThreadListDescSize )
	{
    LOG_MSG("CFlashDataSource::GetThreadListL()");

	// Delete any objects in the array, since we will replace them.
    aThreadList.ResetAndDestroy();
	aTotalThreadListDescSize = 0;

    //Find out where in flash to read from
    TInt flashPos = iOffsetsHdr.iTLstOffset;
    TInt rdSize = READ_SIZE;
    TBool stillMoreDataToBeHad = ETrue;

	//cycle through the flash partition, rdSize bytes at a time until there is no more data of interest to be had
	while(stillMoreDataToBeHad)
		{
		User::LeaveIfError(ReadCrashLog(flashPos, rdSize));

		//Get what we can out of this buffer read
		TInt pos, bufferSize = 0;
		SCMStructId id = ESCMLast;
		MByteStreamSerializable* data = NULL;
		TThreadData* thread = NULL;

		TRAPD(err, data = iWalker.GetNextDataTypeL(pos, id, bufferSize));
		if(err != KErrNone)
			{
			return; //We dont mind if this returns corrupt. This is only relevant during initial analysis
			}

		while(data && stillMoreDataToBeHad)
			{
			CleanupStack::PushL(data);

			switch(id)
				{
				case ESCMThreadData :
					{
					thread = static_cast<TThreadData*>(data);

					AssignOwner(thread->iOwnerId, thread->iTid);

					if(aProcessId == thread->iOwnerId || aProcessId == ((TUint64)-1))
						{
				    	//Now we need to widen this descriptor to 16 bits
				    	RBuf name16;
				    	name16.CreateL(thread->iNamesize);
				    	name16.CleanupClosePushL();
				    	name16.Copy(thread->iName);

				    	//Get the thread info object and add it to the thread list
			    		CThreadInfo* tinfo = CThreadInfo::NewL(thread->iTid,
			    												name16,
			    												thread->iOwnerId,
			    												thread->iPriority,
			    												thread->iSvcSP,
			    												thread->iSvcStack,
			    												thread->iSvcStacksize,
			    												thread->iUsrStack,
			    												thread->iUsrStacksize);

						// note - to minimize changes elsewhere last cpu id not added
			    		// to CThreadInfo c'tor - rather
			    		//Until the SMP work is done: tinfo->SetLastCpuId(thread->iLastCpu);
			    		tinfo->SetHeapBase(thread->iSvcHeap);
			    		tinfo->SetHeapSize(thread->iSvcHeapSize);
			    		aThreadList.AppendL(tinfo);
			    		aTotalThreadListDescSize += tinfo->Size();

			    		CleanupStack::PopAndDestroy();
						}

					break;
					}
				case ESCMFirst :
				case ESCMOffsetsHeader :
				case ESCMTCrashInfo :
				case ESCMProcessData :
				case ESCMThreadStack :
				case ESCMRegisterValue :
				case ESCMRegisterSet :
				case ESCMMemory :
				case ESCMCodeSegSet :
				case ESCMCodeSeg :
				case ESCMRawData :
				case ESCMLast :
				case ESCMTraceData :
				default :
					{
					//No more registers mean no more interest
					stillMoreDataToBeHad = EFalse;
					}
				}

			CleanupStack::PopAndDestroy(data);

			//Get next type
			TRAPD(err, data = iWalker.GetNextDataTypeL(pos, id, bufferSize));
			if(err != KErrNone)
				{
				//We dont mind if this returns corrupt. This is only relevant during initial analysis
				return;
				}

			}

		if(data)
			{
			delete data;
			}

		//if data was null but there is still more data to be had, that means we need to read more data
		//from the flash to give to our walker. it will need a buffer size of at least bufferSize, starting
		//from flashPos + pos
		flashPos += pos;
		rdSize = (bufferSize > rdSize) ? bufferSize : rdSize;

		}
	}

/**
 * Gets the owning process of this thread id
 * @param aThreadId Thread ID of interest
 * @return Owning process ID
 * @leave One of the OS wide codes
 */
TUint64 CFlashDataSource::GetThreadOwnerL(TUint64 aThreadId)
	{
	for(TInt cnt = 0; cnt < iThreadOwners.Count(); cnt++)
		{
		TChildOwnerPair pair = iThreadOwners[cnt];
		if(pair.iChildId == aThreadId)
			{
			return pair.iOwnerId;
			}
		}

	User::Leave(KErrNotFound);

	return 0;   //avoid warnings
	}

/**
 * Obtains the code segment list for a given thread.
 * @param aTid Thread identifier to obtain code segments for.
 * @param aCodeSegList Array of code segments.
 * @param aTotalCodeSegListDescSize Size in bytes of the descriptor
 * @leave One of the OS wide system codes
 */
void CFlashDataSource::GetCodeSegmentsL( const TUint64 aTid, RCodeSegPointerList &aCodeSegList, TUint & aTotalCodeSegListDescSize )
	{
	TUint64 ownerId = 0;
	TRAPD(err, ownerId = GetThreadOwnerL(aTid));

	if(KErrNone == err)
		{
		GetCodeSegmentsFromPIDL(ownerId, aCodeSegList, aTotalCodeSegListDescSize);
		}
	}

/**
 * Obtains the code segment list for a given thread.
 * @param aPid Process identifier to obtain code segments for.
 * @param aCodeSegList Array of code segments.
 * @param aTotalCodeSegListDescSize Size in bytes of the descriptor
 * @leave One of the OS wide system codes
 */
void CFlashDataSource::GetCodeSegmentsFromPIDL( const TUint64 aPid, RCodeSegPointerList &aCodeSegList, TUint & aTotalCodeSegListDescSize )
	{
	LOG_MSG("CFlashDataSource::GetCodeSegmentsL()");

	//sort out arguments
	aTotalCodeSegListDescSize = 0;
	aCodeSegList.ResetAndDestroy();

	//Look through our code seg map to see if we have anything for this process
	TInt cnt = iCodeSegMap.Count() - 1;

	for(; cnt >= 0; cnt-- )
		{
		//Look through
		TObjectLocation location = iCodeSegMap[cnt];

		//see if we have code segments for this thread ID
		if(location.iObjectId == aPid)
			{
			TInt bufferSize = TCodeSegment::KSCMCodeSegMaxSize;

			//we must read this struct to check if we are interested in it
			User::LeaveIfError(ReadCrashLog(location.iOffset, bufferSize));

			TInt pos = 0;
			SCMStructId id = ESCMLast;

			MByteStreamSerializable* data = iWalker.GetNextDataTypeL(pos, id, bufferSize);
			CleanupStack::PushL(data);

			if(id != ESCMCodeSeg || !data)
				{
				CleanupStack::PopAndDestroy(data);
				break;
				}

			TCodeSegment* seg = static_cast<TCodeSegment*>(data);

			//take our flash structure and turn it into what we need
			TCodeSegInfo* segInfo = new TCodeSegInfo();
			CleanupStack::PushL(segInfo);

			segInfo->iXIP = seg->iXip;
			segInfo->iType = seg->iCodeSegType;

			TModuleMemoryInfo memInfo = seg->iCodeSegMemInfo;

			segInfo->iCodeSize = memInfo.iCodeSize;
			segInfo->iCodeRunAddr = memInfo.iCodeBase;
			segInfo->iRoDataSize = memInfo.iConstDataSize;
			segInfo->iRoDataRunAddr = memInfo.iCodeBase + memInfo.iCodeSize;
			segInfo->iDataSize = memInfo.iInitialisedDataSize + memInfo.iUninitialisedDataSize;
			segInfo->iDataRunAddr = memInfo.iInitialisedDataBase;

			//if the code seg is XIP then these are the same
			if(segInfo->iXIP)
				{
				segInfo->iCodeLoadAddr = segInfo->iCodeRunAddr;
				segInfo->iRoDataLoadAddr = segInfo->iRoDataRunAddr;
				segInfo->iDataLoadAddr = segInfo->iDataRunAddr;
				}
			else
				{
				segInfo->iRoDataLoadAddr = 0; // as per current serverdatasource (dont worry for the moment)
				segInfo->iCodeLoadAddr = 0; // as per current serverdatasource (dont worry for the moment)
				segInfo->iDataLoadAddr = 0; // as per current serverdatasource (dont worry for the moment)
				}

			TFileName name;
			name.Copy(seg->iName);

			segInfo->iName = name;

			// crashed process code segments may have been added twice to the list as they are added
			// for the crashed process and for all processes

			TBool found = EFalse;
			for(TInt k=0;k<aCodeSegList.Count();k++)
				{
				const TCodeSegInfo& si = * aCodeSegList[k];
				if(si.iDataRunAddr ==  segInfo->iDataRunAddr && si.iDataSize == segInfo->iDataSize)
					{
					found = ETrue;

					LOG_MSG4("XXX CFlashDataSource::GetCodeSegmentsFromPIDL FOUND DUPLICATE MATCH k[%d]segInfo->iDataRunAddr[%x] segInfo->iDataSize[%d]"
							, k
							, segInfo->iDataRunAddr
							, segInfo->iDataSize );

					break;
					}
				}

			if(!found)
				{
				aCodeSegList.AppendL(segInfo);
				CleanupStack::Pop(segInfo);
				}
			else
				{
				CleanupStack::PopAndDestroy(segInfo);
				}

			CleanupStack::PopAndDestroy(data);
			}
		}

	}

/**
 * Gets the size of the trace buffer that is available
 */
TUint CFlashDataSource::GetAvailableTraceSizeL()
	{
	CLTRACE("Start CFlashDataSource::GetAvailableTraceSizeL()");

	if(iTraceDump)
		{
		return iTraceDump->iSizeOfMemory;
		}
	else
		{
		User::Leave(KErrNotFound);
		}

	return 0; //comp warnings
	}

/**
 Reads data from the trace buffer into the supplied descriptor
 @param aTraceData The buffer to be read into
 @param aPos Position in trace buffer to read from
 @leave KErrArgument if aPos is greater than the memory available or one of the other system wide codes
*/
void CFlashDataSource::ReadTraceBufferL(TDes8 &aTraceData, TUint aPos)
	{
    CLTRACE2("CFlashDataSource::ReadTraceBufferL() from aPos = [%d] into a buffer of [%d]", aPos, aTraceData.MaxLength());

    aTraceData.Zero();

    if(!iTraceDump)
    	User::Leave(KErrNotFound);

    CLTRACE1("traceDump->iNumberOfParts=%d", iTraceDump->iNumberOfParts);
    TUint nextRawDataPos = iOffsetsHdr.iTraceOffset + iTraceDump->GetSize();
    TInt currentTracePos = 0;

	//Because the trace is a circular buffer it must be read in parts and therefore dumped on the flash
	//in parts - ie. TRawData structs. Must read each of these and append to trace data
    for(TInt part = 0; part < iTraceDump->iNumberOfParts; part++)
		{
		User::LeaveIfError(ReadCrashLog(nextRawDataPos, TRawData::KSCMRawDataMaxSize));

		TInt nextRead = 0;
		SCMStructId id = ESCMLast;
		TInt nextBufSize = 0;

		MByteStreamSerializable* theRawness = iWalker.GetNextDataTypeL(nextRead, id, nextBufSize);
		if(theRawness && id == ESCMRawData)
			{
			TRawData* raw = static_cast<TRawData*>(theRawness);
			CleanupStack::PushL(theRawness);

			//Read the trace into the trace buffer
			TUint rdSize = raw->iLength;
			TUint rdPos = nextRawDataPos + TRawData::KSCMRawDataMaxSize;

			if(aPos >= (currentTracePos + raw->iLength))
				{
				//no dumpage
				}
			else
				{
				if(aPos >= currentTracePos)
					{
					rdSize = currentTracePos + raw->iLength - aPos;
					rdPos += aPos - currentTracePos;
					}

				ReadRawFlashL(aTraceData,  rdPos, rdSize);
				}

			nextRawDataPos += raw->GetSize();
			currentTracePos += raw->iLength;

			CleanupStack::PopAndDestroy(theRawness);
			}
		else
			{
			User::Leave(KErrNotFound);
			}
		}
	}

/**
 * This allows us to read directly from the flash into a buffer of our choosing
 * @param aDestinationBuffer This is the buffer we will read that data into. It will be appended on to the end of this descriptor
 * @param aReadPos Point in flash from which to read
 * @param aReadSize Amount of data to read. If this is greater than the space in aDestinationBuffer, not all the data will be read
 * @leave one of the system wide codes
 */
void CFlashDataSource::ReadRawFlashL(TDes8& aDestinationBuffer, TUint aReadPos, TUint aReadSize)
	{
	TUint8* destination = const_cast<TUint8*>(aDestinationBuffer.Ptr());
	TUint spaceInBuffer = aDestinationBuffer.MaxLength() - aDestinationBuffer.Length();
	TUint rdSize = (aReadSize > spaceInBuffer) ? spaceInBuffer : aReadSize;

	//Give it a ptr starting at the end of the desc so it doesnt overwrite any data already there (ReadCrashLog always writes the data from 0)
	TPtr8 ptr(destination + aDestinationBuffer.Length(), aDestinationBuffer.MaxLength() - aDestinationBuffer.Length());

	User::LeaveIfError(iSecSess.ReadCrashLog(aReadPos, ptr, rdSize));

	aDestinationBuffer.SetLength(aDestinationBuffer.Length() + ptr.Length());
	}

/**
 * Read the SCM configuration data from flash buffer
 */
void CFlashDataSource::ReadSCMConfigL(RConfigParameterList& aScmConfigList)
	{

	LOG_MSG("CFlashDataSource::ReadSCMConfigL");

	aScmConfigList.ResetAndDestroy();

	Debug::SCMConfiguration* theConfig = GetSCMConfigFromFlashL();

	if(!theConfig)
		{
		CLTRACE("(CFlashDataSource::ReadSCMConfigL) no config saved - using default");
		iScmConfig->SetDefaultConfig();
		}
	else
		{

		CLTRACE("(CFlashDataSource::ReadSCMConfigL) config FOUND");
		delete iScmConfig;
		iScmConfig = theConfig;

		// ok we have a config - now read to see if we have a crash following
		ReallocFlashBuf(Align4(TCrashInfoHeader::KSCMCrashInfoMaxSize));
		User::LeaveIfError(iSecSess.ReadCrashLog(Align4(iScmConfig->GetSize()), iFlashBuf, TCrashInfoHeader::KSCMCrashInfoMaxSize));

		TCrashInfoHeader header;
		TByteStreamReader r2(const_cast<TUint8*>((iFlashBuf).Ptr()));
		if( header.Deserialize(r2) == KErrNone)
			{
			CLTRACE("(CFlashDataSource::ReadSCMConfigL) HEADER found OK");

 			// we should now have a blocksize in the header
  			iCrashFound = ETrue;
  			// create a buffer big enough to hold the entire first block
  			iFirstBlockBuf.Close();
  			iFirstBlockBuf.Create(header.iFlashBlockSize);

  			// read the whole block into the buffer
  			TInt err = iSecSess.ReadCrashLog(0, iFirstBlockBuf, header.iFlashBlockSize);

  			if(err != KErrNone)
  				{
				CLTRACE1("(CFlashDataSource::ReadSCMConfigL) Error reading cache block %d", err);
				}
  			}
	 	else
  			{
  			CLTRACE("(CFlashDataSource::ReadSCMConfigL) NO crash header found");
 			}

		}

	TConfigItem* item = iScmConfig->ConfigList();
	TInt i = 0;
	while(item)
		{
		// transfer the TCongigItems into the array
    	COptionConfig* config =  COptionConfig::NewL( i,
    								   item->GetDataType(),
    								   COptionConfig::ESCMConfig,
    								   COptionConfig::ETInt,
    								   TConfigItem::GetSCMConfigOptionText(item->GetDataType()),
    								   0,
    								   KNullDesC,
    								   item->GetPriority(),
    								   KNullDesC );
        config->Instance(item->GetDataType());
        i++;
		aScmConfigList.AppendL(config);
		item = item->Next();
		}
	}

void CFlashDataSource::WriteSCMConfigL()
	{
	// if we have a crash found then use the appropriate buffer
	RBuf8& buf = iCrashFound ? iFirstBlockBuf : iFlashBuf;

	CLTRACE2("(CFlashDataSource::WriteSCMConfigL) - Writing config buf.Length() = %d iCrashFound %d",
			buf.Length(), iCrashFound );

	TByteStreamWriter writer(const_cast<TUint8*>(buf.Ptr()));
	iScmConfig->Serialize(writer);

	iSecSess.EraseCrashLog(0, 1);
	TUint32 size = 0;
	TInt res = iSecSess.WriteCrashConfig(0, buf, size);

	CLTRACE2("(CFlashDataSource::WriteSCMConfigL) RESULT res = %d size = %d", res, size);
	}

void CFlashDataSource::ModifySCMConfigItemL(TUint32 aDataType, TInt32 aPriority)
	{
	CLTRACE2("(CFlashDataSource::ModifySCMConfigItemL) - modifying aDataType %d with priority %d", aDataType, aPriority);

	//check for Priority value to be within 0-255 otherwise leave with KErrArgument
	if( (aPriority < 0) || (aPriority > 255) )
		{
			LOG_MSG( " ERROR: SCM Priority out of bounds, should be within 0-255\n");
			User::Leave(KErrArgument);
		}

	TInt err = iScmConfig->ModifyConfigItemPriority((Debug::TConfigItem::TSCMDataType)aDataType, aPriority);

	if( err == KErrNone)
		{
		// also write change through to flash
		WriteSCMConfigL();
		}
	else
		{
		 CLTRACE3("CFlashDataSource::ModifySCMConfigItemL) failed to modify err = %d aDataType = %d aPriority = %d"
				 , err, aDataType, aPriority );
		}
	}

Debug::SCMConfiguration& CFlashDataSource::SCMConfiguration()
	{
	return *iScmConfig;
	}

/**
 * Cleanup item implementation for Code Seg List
 * @param aArray pointer to the list that is supposed to be freed
*/
void CFlashDataSource::CleanupCodeSegList(TAny *aArray)
	{
    LOG_MSG("->CFlashDataSource::CleanupCodeSegList()\n");
	RCodeSegPointerList *codeSegList = static_cast<RCodeSegPointerList*> (aArray);
    codeSegList->ResetAndDestroy();
    codeSegList->Close();
    delete codeSegList;
	}

/**
 * Cleanup item implementation for process list.
 * @param aArray pointer to the list that is supposed to be freed
*/
void CFlashDataSource::CleanupProcessList(TAny *aArray)
	{
    LOG_MSG("->CFlashDataSource::CleanupProcessList()\n");
	RProcessPointerList *processList = static_cast<RProcessPointerList*> (aArray);
    processList->ResetAndDestroy();
    processList->Close();
    delete processList;
	}

/**
 * Cleanup item implementation for thread list.
 * @param aArray pointer to the list that is supposed to be freed
*/
void CFlashDataSource::CleanupThreadList(TAny *aArray)
	{
    LOG_MSG("->CFlashDataSource::CleanupThreadList()\n");
	RThreadPointerList *threadList = static_cast<RThreadPointerList*> (aArray);
    threadList->ResetAndDestroy();
    threadList->Close();
    delete threadList;
	}

/**
 * CalculateChecksum - calsulates the checksum for the given length of
 * the flash buffer (if this is the entire length it should not include
 * the checksum footer)
 * @param aLogSize - the total size of flash buf to check
 * @param aChecksum -  the checksum where the result will be placed - as this checksum is
 * commutative the aChecksum value may be reset or already hold data as required
 * @return void
*/
void CFlashDataSource::CalculateChecksumL(TInt aStart, TInt aLength, TScmChecksum& aChecksum)
	{
	if( aLength <= 0)
		{
		// invalid block length
		User::Leave(KErrGeneral);
		}

	const TInt KDefaultBlockSize = 0xFF;
	const TInt KBlocksize = aLength > KDefaultBlockSize ? KDefaultBlockSize : aLength;

	TInt remaining = aLength;
	TInt pos = aStart;

	while(remaining > KBlocksize)
		{
		//CLTRACE2("->CFlashDataSource::CalculateChecksum rem = %d blksz = %d\n", remaining, KBlocksize);
		User::LeaveIfError(ReadCrashLog(pos, KBlocksize));
		pos += KBlocksize;
		remaining -= KBlocksize;
		aChecksum.ChecksumBlock(iFlashBuf);
		}

	if(remaining > 0)
		{
		User::LeaveIfError(ReadCrashLog(pos, remaining));
		aChecksum.ChecksumBlock(iFlashBuf);

		pos += remaining;
		if(pos != aLength)
			{
			User::Leave(KErrCorrupt);
			}
		}
	}

/**
 * Retrieves ROM build information from flash partition if available
 * @param aRomHeader stores the rom build info
 * @leave one of the OS wide codes
 */
void CFlashDataSource::GetROMBuildInfoL(TRomHeaderData& aRomHeader)
	{
	if(iRomBuildInfo)
		{
		aRomHeader = *iRomBuildInfo;
		return;
		}

	User::Leave(KErrNotFound);
	}

/**
 * Retrieves System lock data
 * @param aLockData Contains the data for the system locks
 * @leave one of the OS wide codes
 */
void CFlashDataSource::GetLocksL(TSCMLockData& aLockData)
	{
	if(iLockData)
		{
		aLockData = *iLockData;
		return;
		}

	User::Leave(KErrNotFound);
	}

TInt CFlashDataSource::ReallocFlashBuf(const TUint aSize)
  	{
  	//Reallocate the flash buffer to be the size required

  	if(aSize > iFlashBuf.MaxLength())
  		{
  		TInt err = iFlashBuf.ReAlloc(aSize);
  		if (KErrNone != err)
  			{
  			CLTRACE2("(CFlashDataSource::ReallocFlashBuf) - ERROR alloc on iFlashBuf err = %d. Trying to alloc aSize [0x%x] bytes", err, aSize);
  			return err;
  			}
  		}
  	else
  		{
		iFlashBuf.SetLength(aSize);
  		}

  	return KErrNone;
  	}

void CFlashDataSource::PrintFlashBuf()
	{
	CLTRACE1("(CFlashDataSource::PrintFlashBuf) iFlashBuf.Length = %d ", iFlashBuf.Length());
	for(TInt i=0;i<iFlashBuf.Length();i++)
		{
		CLTRACE4("iFlashBuf[%d] = char<%c> dec<%d> hex<%x>", i, iFlashBuf[i], iFlashBuf[i] ,iFlashBuf[i]);
		}
	}

void  CFlashDataSource::ReleaseFirstBlockBuf()
	{
	iFirstBlockBuf.Close();
	iCrashFound = EFalse;
	}

void CFlashDataSource::GetExceptionStackL(const Debug::TArmProcessorModes aMode, TDes8& aStack, TUint aStartReadPoint)
	{
	//Not implemented
	}

/**
 * @see CCrashDataSource::GetVersion
 */
TVersion CFlashDataSource::GetVersion() const
	{
	return KFlashCrashDataSourceVersion;
	}

/**
 * @see CCrashDataSource::GetDataSourceFunctionalityBufSize
 */
TInt CFlashDataSource::GetDataSourceFunctionalityBufSize(TUint& aBufSize)
	{
	return KErrNotSupported;
	}

/**
 * @see CCrashDataSource::GetDataSourceFunctionality
 */
TInt CFlashDataSource::GetDataSourceFunctionality(TDes8& aFuncBuffer)
	{
	return KErrNotSupported;
	}
/**
 * @see CCrashDataSource::GetExceptionStackSizeL
 */
TUint CFlashDataSource::GetExceptionStackSizeL(const Debug::TArmProcessorModes aMode)
  	{
  /*    TInt bufferSize = 0;
      TInt pos = 0;
      SCMStructId id = ESCMLast;

      TBool validStack = ETrue;
      TUint32 rdPoint = iOffsetsHdr.iExcStkOffset;

      while(validStack)
      	{
      	//Read in the thread stack, memory dump and raw data structs each time
      	User::LeaveIfError(ReadCrashLog(rdPoint, TThreadStack::MAX_SIZE + TMemoryDump::MAX_SIZE + TRawData::MAX_SIZE));

      	MByteStreamSerializable* data = iWalker.GetNextDataTypeL(pos, id, bufferSize);
      	CleanupStack::PushL(data);

      	//Make sure we have a valid TRawData or TMemory or TThreadStack
      	if(id == ESCMThreadStack)
      		{
      		TThreadStack* thread = static_cast<TThreadStack*>(data);

      		//The enums here dont match so gotta case
      		switch(aMode)
      			{
      			case Debug::EFiqMode :
      				{
      				if(thread->iStackType == TThreadStack::EFIQStack)
      					{
      					CleanupStack::PopAndDestroy(data);
      					return thread.iStackSize;
      					}
      				//otherwise fall through to default
      				}
      			case Debug::EIrqMode :
      				{
      				if(thread->iStackType == TThreadStack::EIRQStack)
      					{
      					CleanupStack::PopAndDestroy(data);
      					return thread.iStackSize;
      					}

      				//otherwise fall through to default
      				}
      			//Not supported for now
      			case Debug::ESvcMode :
      			case Debug::EAbortMode :
      			case Debug::EUndefMode :
      			case Debug::EMaskMode :
      			default:
      				{
      				CleanupStack::PopAndDestroy(data);
      				continue;
      				}
      			}

      		//Now is it the stack of interest
      		}
      	else
      		{
      		CleanupStack::PopAndDestroy(data);
      		User::Leave(KErrNotFound);
      		}
      	}

  	*/
  	return 0;
	}

/**
 * @see CCrashDataSource::GetVariantSpecificDataSize
 */
TInt CFlashDataSource::GetVariantSpecificDataSize(TUint& aDataSize)
	{
	CLTRACE("Start CFlashDataSource::GetVariantSpecificDataSize()");

	if(iVarSpecData)
		{
		aDataSize = iVarSpecData->iSize;
		return KErrNone;
		}
	else
		{
		return KErrNotSupported;
		}
	}

/**
 * @see CCrashDataSource::GetVariantSpecificData
 */
TInt CFlashDataSource::GetVariantSpecificData(TDes8 &aVarSpecData)
	{
	aVarSpecData.Zero();

	if(!iVarSpecData)
		{
		CLTRACE("CFlashDataSource::GetVariantSpecificData --> No variant specific data in flash");
		return KErrNotFound;
		}

	if(aVarSpecData.MaxSize() != iVarSpecData->iSize)
		{
		CLTRACE1("CFlashDataSource::GetVariantSpecificData --> Supplied descriptor was not big enough for data. Need at least [%d] bytes", iVarSpecData->iSize);
		return KErrBadDescriptor;
		}

	TUint rawDataPos = iOffsetsHdr.iVarSpecInfOffset + iVarSpecData->GetSize();

	TInt err = ReadCrashLog(rawDataPos, TRawData::KSCMRawDataMaxSize);
	if(KErrNone != err)
		{
		CLTRACE1("CFlashDataSource::GetVariantSpecificData -- Unable to read variant data from crash log: [%d]", err);
		return err;
		}
	
	SCMStructId id = ESCMLast;
	TInt nextBufferSizeIfNull = 0;
	TInt nextBufferRead = 0;

	//We now walk the data that we just buffered in the ReadCrashLog call (our data is at start of buffer)
	MByteStreamSerializable* theRawness = iWalker.GetNextDataTypeL(nextBufferRead, id, nextBufferSizeIfNull);
	if(theRawness && id == ESCMRawData)
		{
		TRawData* raw = static_cast<TRawData*>(theRawness);
		CleanupStack::PushL(theRawness);

		//Read the raw data into supplied buffer
		TRAP(err, ReadRawFlashL(aVarSpecData, rawDataPos + TRawData::KSCMRawDataMaxSize, raw->iLength));
		CleanupStack::PopAndDestroy(theRawness);
		if(KErrNone != err)
			{
			CLTRACE1("CFlashDataSource::GetVariantSpecificData -- Reading raw data fromn flash failed: [%d]", err);
			aVarSpecData.Zero();
			return err;
			}
		}
	else
		{
		//The read crash log gave it the correct values (size etc) so if its NULL it means it's not been found
		//(Perhaps this should be a KErrCorrupt as to get this far, the crash log has been telling us there is
		//var specific data. Don't want to make the parsing too strict though.)
		return KErrNotFound;
		}

	return KErrNone;
	}

//eof flashdatasource.cpp
