dbgsrv/coredumpserver/server/src/coredumpsessioncalls.cpp
changeset 0 c6b0df440bee
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dbgsrv/coredumpserver/server/src/coredumpsessioncalls.cpp	Tue Mar 02 10:33:16 2010 +0530
@@ -0,0 +1,2851 @@
+// Copyright (c) 2007-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:
+// core_dump_session_calls.cpp
+//
+
+
+
+/**
+ @file
+ @internalTechnology
+ @released
+*/
+
+#include <crashlogwalker.h>
+#include <scmconfigitem.h>
+#include "coredumpsession.h"
+
+using namespace Debug;
+
+// Creates and returns a heap descriptor which holds contents of list
+HBufC8* CCoreDumpSession::MarshalListL( TListRequest & req, TAny * list )
+	{
+
+	LOG_MSG("->CCoreDumpSession::MarshalListL()\n" );
+
+	// Create a dynamic flat buffer to hold this object's member data	
+	// Can only use CBufFlat due to Store supporting CBufFlat and CBufSeg
+	// See Symbian OS guide » System libraries » Using Store » Streaming » Templated stream operators
+
+	const TInt KExpandSize = 128; // "Granularity" of dynamic buffer
+
+	CBufFlat* buf = CBufFlat::NewL( KExpandSize );
+	CleanupStack::PushL( buf );
+
+	RBufWriteStream stream( *buf ); // Stream over the buffer
+	CleanupClosePushL( stream );
+
+	for( TInt i = 0; i < req.iRemaining; i ++ )
+		{		
+		switch( req.iListType )
+			{
+			case TListRequest::EThreadList:
+				{
+				//LOG_MSG2( "  -> ((*threadPointerList)[%d])->ExternalizeL( )\n", i );
+				iThreadPointerList[i]->ExternalizeL( stream, buf );
+				//LOG_MSG2( "  buf->Size()=%d\n", buf->Size() );
+				break;
+				}
+			case TListRequest::EProcessList:
+				{
+				//LOG_MSG2( "  -> ((*processPointerList)[%d])->ExternalizeL( )\n", i );
+				iProcessPointerList[i]->ExternalizeL( stream, buf );
+				//LOG_MSG2( "  buf->Size()=%d\n", buf->Size() );
+				break;
+				}
+
+			case TListRequest::EExecutableList:
+				{
+				//LOG_MSG2( "  -> ((*processPointerList)[%d])->ExternalizeL( )\n", i );
+				iExecutablePointerList[i]->ExternalizeL( stream, buf );
+				//LOG_MSG2( "  buf->Size()=%d\n", buf->Size() );
+				break;
+				}
+            case TListRequest::EFormatterList:
+                {
+				LOG_MSG2( "  -> ((*formatterInfos)[%d])->ExternalizeL( )\n", i );
+				iFormatterInfos[i]->ExternalizeL( stream, buf );
+				//LOG_MSG2( "  buf->Size()=%d\n", buf->Size() );
+				break;
+                }
+            case TListRequest::EWriterList:
+                {
+				LOG_MSG2( "  -> ((*writerInfos)[%d])->ExternalizeL( )\n", i );
+				iWriterInfos[i]->ExternalizeL( stream, buf );
+				//LOG_MSG2( "  buf->Size()=%d\n", buf->Size() );
+				break;
+                }
+            case TListRequest::ECrashList:
+            	{
+            	LOG_MSG2( "  -> ((*iCrashList)[%d])->ExternalizeL( )\n", i );
+            	iCrashList[i]->ExternalizeL(stream, buf);
+            	//LOG_MSG2( "  buf->Size()=%d\n", buf->Size() );
+            	break;
+            	}
+			default:
+				{
+				LOG_MSG("CCoreDumpSession::MarshalListL : Received unknown list type");				
+				User::Leave( KErrNotSupported );
+				}
+			}
+		}
+
+	stream.CommitL();
+
+	TInt bufSize = buf->Size();
+
+	// Create a heap descriptor from the buffer
+	HBufC8* des = HBufC8::NewL( buf->Size() );
+	TPtr8 ptr( des->Des() );
+
+	buf->Read( 0, ptr, buf->Size() );
+	
+	CleanupStack::PopAndDestroy( &stream );
+	CleanupStack::PopAndDestroy( buf ); 
+	
+	return des;
+	}
+
+
+void CCoreDumpSession::GetListL( const RMessage2& aMessage )
+	{
+	LOG_MSG( "CCoreDumpSession::GetListL()\n" );
+
+	TListRequest listRequest; 
+	HBufC8 *listDes = NULL;
+
+	TPtr8 listReqPtr( (TUint8 *)&listRequest, sizeof(TListRequest) );
+
+	aMessage.ReadL( 0, listReqPtr );
+
+	switch( listRequest.iListType )
+		{
+		case TListRequest::EThreadList :
+			{
+			if( listRequest.iRequiredDescriptorSize != iTotalThreadListDescSize )
+				{
+				LOG_MSG( "  ERROR !* listReq.iRequiredDescriptorSize != iTotalThreadListDescSize\n" );
+				User::Leave( KErrBadDescriptor );
+				}
+			listDes = iMarshalledThreadList;
+			break;
+			}
+		case TListRequest::EProcessList :
+			{
+			if( listRequest.iRequiredDescriptorSize != iTotalProcessListDescSize )
+				{
+				LOG_MSG( "  ERROR !* listReq.iRequiredDescriptorSize != iTotalProcessListDescSize\n" );
+				User::Leave( KErrBadDescriptor );
+				}
+			listDes = iMarshalledProcessList;
+			break;
+			}
+		case TListRequest::EExecutableList :
+			{
+			if( listRequest.iRequiredDescriptorSize != iTotalExecutableListDescSize )
+				{
+				LOG_MSG( "  ERROR !* listReq.iRequiredDescriptorSize != iTotalExecutableListDescSize\n" );
+				User::Leave( KErrBadDescriptor );
+				}
+			listDes = iMarshalledExecutableList;
+			break;
+			}
+		case TListRequest::EFormatterList :
+			{
+			if( listRequest.iRequiredDescriptorSize != iTotalFormatterListDescSize )
+				{
+				LOG_MSG( "  ERROR !* listReq.iRequiredDescriptorSize != iTotalFormatterListDescSize\n" );
+				User::Leave( KErrBadDescriptor );
+				}
+			listDes = iMarshalledFormatterList;
+			break;
+			}
+		case TListRequest::EWriterList :
+			{
+			if( listRequest.iRequiredDescriptorSize != iTotalWriterListDescSize )
+				{
+				LOG_MSG( "  ERROR !* listReq.iRequiredDescriptorSize != iTotalWriterListDescSize\n" );
+				User::Leave( KErrBadDescriptor );
+				}
+			listDes = iMarshalledWriterList;
+			break;
+			}
+		case TListRequest::ECrashList :
+			{
+			if( listRequest.iRequiredDescriptorSize != iTotalCrashInfoDescSize )
+				{
+				LOG_MSG( "  ERROR !* listReq.iRequiredDescriptorSize != iTotalWriterListDescSize\n" );
+				User::Leave( KErrBadDescriptor );
+				}
+			listDes = iMarshalledCrashList;
+			break;
+			}
+		default :
+			{
+			LOG_MSG2( " ERROR !* : CCoreDumpSession::ListInfoL() : invalid TListRequestType %d\n", 	listRequest.iListType );
+			User::Leave( KErrArgument );
+			}
+		}
+
+	if ( listDes == NULL )
+		{
+
+		LOG_MSG( "  ERROR !* MarshalData returned null buf\n" );
+		User::Leave( KErrBadDescriptor );
+
+		}
+	else
+		{
+
+		//LOG_MSG( "  -> TPtr8 lsitPtr( listDes->Des() )\n" );
+		TPtr8 listPtr( listDes->Des() );
+		//LOG_MSG2( "  listPtr->Size()=%d\n", listPtr.Size() );
+
+		if( listPtr.Size() == 0 )
+			{
+			LOG_MSG( "  ERROR !* : if( lsitPtr.Size() == 0 )\n" );
+			User::Leave( KErrBadDescriptor );
+			}
+
+		//LOG_MSG( "  -> WriteL( 1, listPtr )\n" );
+		aMessage.WriteL( 1, listPtr );
+
+		}
+
+	}
+
+
+void CCoreDumpSession::ListInfoL( const RMessage2& aMessage )
+	{
+    LOG_MSG( "CCoreDumpSession::ListInfoL()\n" );
+
+	TListRequest listRequest; 
+	TUint64 procId;
+	
+	TPtr8 listReqPtr( (TUint8 *)&listRequest, sizeof(TListRequest) );
+
+	aMessage.ReadL( 0, listReqPtr );
+
+	switch( listRequest.iListType )
+		{
+		    case TListRequest::EThreadList :
+				{
+				procId = MAKE_TUINT64( listRequest.iSubId2, listRequest.iSubId1 );				
+				iDataSource->GetThreadListL( procId, iThreadPointerList, iTotalThreadListDescSize );
+	
+				listRequest.iRemaining = iThreadPointerList.Count();
+	
+	            //mark those that we observe
+	            for(TInt i = 0; i < iObservationList.Count(); i++)
+	                {
+	                for(TInt j = 0; j < iThreadPointerList.Count(); j++)
+	                    {
+	                    if(iObservationList[i]->HasThread(iThreadPointerList[j]->Name()))
+	                        {
+	                        iThreadPointerList[j]->Observed(ETrue); 
+	                        }
+	                    }
+	                }
+	
+				if( NULL != iMarshalledThreadList )
+					{
+					delete iMarshalledThreadList;
+					}
+	
+				//LOG_MSG( " EThreadList -> MarshalDataL()\n" );
+				iMarshalledThreadList = MarshalListL( listRequest, (TAny*) &iThreadPointerList );
+				listRequest.iRequiredDescriptorSize = iMarshalledThreadList->Des().Size();
+				iTotalThreadListDescSize = listRequest.iRequiredDescriptorSize;
+								
+				break;
+				}
+		case TListRequest::EProcessList :
+            {
+			iDataSource->GetProcessListL( iProcessPointerList, iTotalProcessListDescSize );
+
+			listRequest.iRemaining = iProcessPointerList.Count();
+
+            //mark those that we observe
+            for(TInt i = 0; i < iObservationList.Count(); i++)
+                {
+                for(TInt j = 0; j < iProcessPointerList.Count(); j++)
+                    {
+                    if( (iObservationList[i]->TargetName() == iProcessPointerList[j]->Name()) && //attached to it
+                        (iObservationList[i]->ThreadCount() == 0) ) //and no threads on the list 
+                        {
+                        iProcessPointerList[j]->Observed(ETrue); 
+                        }
+                    }
+                }
+
+			if( NULL != iMarshalledProcessList )
+				{
+				delete iMarshalledProcessList;
+				}
+
+			//LOG_MSG( " EProcessList -> MarshalDataL()\n" );
+			iMarshalledProcessList = MarshalListL( listRequest, (TAny*) &iProcessPointerList );
+			listRequest.iRequiredDescriptorSize = iMarshalledProcessList->Des().Size();
+			iTotalProcessListDescSize = listRequest.iRequiredDescriptorSize;
+						
+			break;
+			}			
+		case TListRequest::EExecutableList :
+            {
+			iDataSource->GetExecutableListL( iExecutablePointerList, iTotalExecutableListDescSize );
+
+			listRequest.iRemaining = iExecutablePointerList.Count();
+			//LOG_MSG2( "  listRequest.iRemaining=%d\n", listRequest.iRemaining );
+
+            //mark those that we observe
+            for(TInt i = 0; i < iObservationList.Count(); i++)
+                {
+                for(TInt j = 0; j < iExecutablePointerList.Count(); j++)
+                    {
+                    if( iObservationList[i]->TargetName() == iExecutablePointerList[j]->Name() )//attached to it
+                        {
+                        iExecutablePointerList[j]->Observed(ETrue); 
+                        }
+                    }
+                }
+
+			if( NULL != iMarshalledExecutableList )
+				{
+				delete iMarshalledExecutableList;
+				}
+
+			//LOG_MSG( " EExecutableList -> MarshalDataL()\n" );
+			iMarshalledExecutableList = MarshalListL( listRequest, (TAny*) &iExecutablePointerList );
+			listRequest.iRequiredDescriptorSize = iMarshalledExecutableList->Des().Size();
+			iTotalExecutableListDescSize = listRequest.iRequiredDescriptorSize;
+			
+			break;
+			}		
+		case TListRequest::EFormatterList :
+            {
+			listRequest.iRemaining = iFormatterInfos.Count();
+
+            if(iMarshalledFormatterList)
+                {
+                delete iMarshalledFormatterList;
+                }
+
+            iMarshalledFormatterList = MarshalListL( listRequest, (TAny*) &iFormatterInfos );
+			listRequest.iRequiredDescriptorSize = iMarshalledFormatterList->Des().Size();
+			iTotalFormatterListDescSize = listRequest.iRequiredDescriptorSize;
+			
+            break;
+            }
+		case TListRequest::EWriterList :
+            {
+			listRequest.iRemaining = iWriterInfos.Count();
+
+            if(iMarshalledWriterList)
+                {
+                delete iMarshalledWriterList;
+                }
+
+            iMarshalledWriterList = MarshalListL( listRequest, (TAny*) &iWriterInfos );
+			listRequest.iRequiredDescriptorSize = iMarshalledWriterList->Des().Size();
+			iTotalWriterListDescSize = listRequest.iRequiredDescriptorSize;
+			
+            break;
+            }
+		case TListRequest::ECrashList :
+			{
+			//Dealing with listing crashes from flash. Refresh the list and then
+			//serialise the list onto iMarshalledCrashList
+			
+			RefreshCrashListFromFlashL();			
+			listRequest.iRemaining = iCrashList.Count();
+			
+			if(iMarshalledCrashList)
+				{
+				delete iMarshalledCrashList;
+				iMarshalledCrashList = NULL;
+				}
+			
+			iMarshalledCrashList = MarshalListL(listRequest, (TAny*)&iCrashList);
+			listRequest.iRequiredDescriptorSize = iMarshalledCrashList->Des().Size();
+			iTotalCrashInfoDescSize = listRequest.iRequiredDescriptorSize;
+			
+			break;
+			}
+		default :
+			{
+			LOG_MSG2( " ERROR !* : CCoreDumpSession::ListInfoL() : invalid TListRequestType %d\n", listRequest.iListType );			
+			User::Leave( KErrArgument );
+			}
+		}
+
+	aMessage.WriteL( 0, listReqPtr );
+
+	}
+
+/**
+ * This method looks at the crash logs in the flash partition
+ * and caches them
+ */
+void CCoreDumpSession::RefreshCrashListFromFlashL()
+	{	
+	LOG_MSG("CCoreDumpSession::RefreshCrashListFromFlashL()");
+	
+	TBuf8<Debug::KMaxCoreHeaderSize> buf;	
+	iCrashList.ResetAndDestroy();
+	
+	//Start looking where the config ends if it exists
+	TInt crashLogPos = 0;
+	SCMConfiguration* config = FlashDataSource()->GetSCMConfigFromFlashL();
+	if(config)
+		{
+		crashLogPos = config->GetSize();
+		}
+	
+	delete config;
+	
+	do
+		{
+		LOG_MSG3("Looking for crash at [%d]   [0x%X]", crashLogPos, crashLogPos);
+
+		//Read in the 2 headers and the context, while we are in the crash log		
+		TInt err = iSecSess.ReadCrashLog(crashLogPos, buf, Debug::KMaxCoreHeaderSize);
+		if(err != KErrNone)
+			{
+			if(err == KErrPermissionDenied)
+				{
+				User::Leave(err);
+				}
+			
+			//We have reached the end of the crash partition
+			return;
+			}
+		
+		TCrashLogWalker wlk(buf);
+					
+		if(KErrNone == wlk.ReadLogHeader(0))
+			{
+			LOG_MSG("Found a valid crash");
+			const TCrashInfoHeader hdr = wlk.GetCrashHeader();
+			TCrashInfo* inf = TCrashInfo::NewL(hdr);
+			inf->iCrashSource = TCrashInfo::ESystemCrash;
+			inf->iContext = wlk.GetCrashContext();
+			
+			iCrashList.Append(inf);
+			
+			//Increment this so it goes up by the log size AND then enough to align it to a flash block
+			TUint32 flashPadding = 0x20000 - (crashLogPos + hdr.iLogSize)%0x20000;
+			crashLogPos += (hdr.iLogSize + flashPadding);
+			}
+		else
+			{			
+			//otherwise we dont have any more crashes			
+			return;
+			}
+		
+		}
+	while(true);		
+	
+	}
+
+
+/**
+ * Processes the crash log in the flash partition corrosponding to the crash ID of the parameter 
+ * passed through. If this doesnt match a crash in the partition, or the flash cannot be read 
+ * this will leave with KErrCorrupted
+ * @param aMessage
+ * @leave one of the OS wide codes
+ */
+void CCoreDumpSession::ProcessCrashLogL(const RMessage2& aMessage)
+	{
+	TInt crashId = aMessage.Int0();	
+	LOG_MSG2("->CCoreDumpSession::ProcessCrashLogL(ID = [%d])\n",  crashId);
+	
+	RefreshCrashListFromFlashL();
+	
+	for(TInt cnt = 0; cnt < iCrashList.Count(); cnt++)
+		{
+		if(iCrashList[cnt]->iCrashId == crashId)
+			{
+			RDebug::Printf("Going to the crash handler");
+			iCrashHandler->HandleCrashFromFlashL(*(iCrashList[cnt]));
+			}
+		}
+	}
+
+/**
+ * Processes the crash log in the flash partition Asynchronously corrosponding to the crash ID of the parameter 
+ * passed through. It refreshes the crash list and then calls the crash handler. Leaves with standard leave codes 
+ * when the underlying methods leave.  
+ * @param aMessage
+ * @leave one of the OS wide codes
+ */
+void CCoreDumpSession::ProcessCrashLogAsyncL(const RMessage2& aMessage)
+	{
+	TInt crashId = aMessage.Int0();	
+	LOG_MSG2("->CCoreDumpSession::ProcessCrashLogAsyncL(ID = [%d])\n",  crashId);
+	
+	RefreshCrashListFromFlashL();
+	
+	for(TInt cnt = 0; cnt < iCrashList.Count(); cnt++)
+		{
+		if(iCrashList[cnt]->iCrashId == crashId)
+			{
+			LOG_MSG("Going to the crash handler using the async mechanism");
+			iCrashHandler->HandleCrashFromFlashL(*(iCrashList[cnt]), aMessage);
+			}
+		}
+	}
+
+/**
+ * Cancels asynchronous processing of the crash log in the flash partition  
+ * @param aMessage
+ */
+void CCoreDumpSession::CancelProcessCrashLogAsync(const RMessage2& aMessage)
+	{
+	TInt crashId = aMessage.Int0();	
+	LOG_MSG2("->CCoreDumpSession::CancelProcessCrashLogAsyncL(ID = [%d])\n",  crashId);
+	
+	for(TInt cnt = 0; cnt < iCrashList.Count(); cnt++)
+		{
+		if(iCrashList[cnt]->iCrashId == crashId)
+			{
+			LOG_MSG("Going to the cancel async crash handler processing");
+			iCrashHandler->CancelHandleCrashFromFlash(*(iCrashList[cnt]));
+			}
+		}
+	}
+
+/**
+ * From a crash ID gets a TCrashInfo
+ * @param aCrashId crash ID to search for
+ * @param aCrashInfo the crash info for supplied crash ID
+ * @leave one of the OS wide codes
+ */
+void CCoreDumpSession::GetCrashInfoL(TInt aCrashId, TCrashInfo& aCrashInfo)
+	{
+	for(TInt i = 0; i<iCrashList.Count(); i++)
+		{
+		if(iCrashList[i]->iCrashId == aCrashId)
+			{
+			aCrashInfo = *(iCrashList[i]);
+			return;
+			}
+		}
+	
+	User::Leave(KErrNotFound);
+	}
+
+/**
+    Retrives the 'cancel crash' property value and checks if required to abort the crash dump. Updates 'crash progress' property. 
+
+@param aProgress descriptor with the crash progress value.
+@leave KErrAbort if crash cancel property has been set
+ */
+void CCoreDumpSession::UpdateProgressL(const TDesC &aProgress) const
+    {
+    LOG_MSG("->CCoreDumpSession::UpdateProgressL()\n");
+    TInt cancelCrash = EFalse;
+    TInt err = RProperty::Get(KCoreDumpServUid, ECrashProgress, cancelCrash);
+    if(err != KErrNone)
+        {
+        LOG_MSG2("CCoreDumpSession::UpdateProgressL - unable to retrive 'ECrashProgress' value! err:%d\n", err);
+        }
+
+    if(cancelCrash)
+        {
+        LOG_MSG("CCoreDumpSession::UpdateProgressL - aborting dump in progress\n");
+        User::Leave(KErrNotReady);
+        }
+
+    err = RProperty::Set(KCoreDumpServUid, ECrashProgress, aProgress);
+    if(err != KErrNone)
+        {
+        LOG_MSG2("CCoreDumpSession::UpdateProgressL - unable to retrive 'crash progress' value! err:%d\n", err);
+        }
+#ifdef DEBUG 
+    User::After(1000000);
+#endif
+  }
+
+/**
+ * This method removes a crash log from the flash partition
+ * @param aMessage
+ * @leave one of the OS wide codes
+ */
+void CCoreDumpSession::DeleteCrashLogL(const RMessage2& aMessage) 
+	{
+	User::Leave(KErrNotSupported);
+	}
+
+void CCoreDumpSession::DeleteCrashPartitionL()
+	{
+	LOG_MSG("CCoreDumpSession::DeleteCrashPartitionL()");
+	
+	UpdateProgressL(_L("Erasing Entire Log"));
+
+	//Read in config first
+	SCMConfiguration* config = FlashDataSource()->GetSCMConfigFromFlashL();
+	TCleanupItem scmCleanup(CCoreDumpSession::CleanupSCMConfiguration, (TAny*)config);
+	if(config)
+		CleanupStack::PushL(scmCleanup);
+	
+	TInt err = iSecSess.EraseCrashFlashPartition();	
+	User::LeaveIfError(err);	
+	
+	if(config)
+		{
+		//Now we rewrite the config
+		RBuf8 data;	
+		data.CreateL(config->GetSize());
+		data.SetLength(config->GetSize());
+		data.CleanupClosePushL();
+			
+		TByteStreamWriter writer(const_cast<TUint8*>(data.Ptr()), EFalse);	
+		config->Serialize(writer);
+			
+		TUint32 written = 0;
+		User::LeaveIfError(iSecSess.WriteCrashConfig(0, data, written));
+		
+		CleanupStack::PopAndDestroy(2);//data and scmCleanup
+		}
+	
+	RefreshCrashListFromFlashL();	
+
+	UpdateProgressL(_L("Idle"));
+	}
+
+void CCoreDumpSession::CreateWriterL( const TUid loadRequestUid )
+	{
+	LOG_MSG("->CCoreDumpSession::CreateWriterL()\n" );
+
+	ValidatePluginL( loadRequestUid );
+
+    if(iPluginList.Count() == 0)
+        {
+        RefreshPluginListL();
+        }
+
+    CPluginInfo *info = NULL;
+    for(TInt i = 0; i < iPluginList.Count(); i++)
+        {
+        if(iPluginList[i].iUid == loadRequestUid)
+            {
+                info = CPluginInfo::NewL(iPluginList[i].iName,
+                                         loadRequestUid.iUid,
+                                         iPluginList[i].iVersion,
+                                         TPluginRequest::EWriter);        
+                CleanupStack::PushL(info);
+                break;
+            }
+        }
+
+    if(!info)
+        {
+        LOG_MSG2("CCoreDumpSession::CreateWriterL - unable to find writer uid:%d on plugin type list!\n", loadRequestUid);
+        User::Leave(KErrArgument); 
+        }
+
+    iWriterInfos.AppendL(info);
+    CleanupStack::Pop(info);
+    
+	CCrashDataSave *writer = CCrashDataSave::NewL( (TUid)( loadRequestUid ) );
+
+    CleanupStack::PushL(writer);
+    iWriterPlugins.AppendL(writer);
+    CleanupStack::Pop(writer);
+
+    LOG_MSG3("CCoreDumpSession::CreateFormatter fmt:%d, wrt:%d\n", iFormatterPlugins.Count(), iWriterPlugins.Count());
+    //for compatibility, first pair is bound by default
+    if( (iFormatterPlugins.Count() == 1) && (iWriterPlugins.Count() == 1) )
+        {
+	        LOG_MSG("CCoreDumpSession::CreateFormatter binding default plugin pair\n" );
+            iFormatterInfos[0]->Pair(0);
+            iFormatterPlugins[0]->ConfigureDataSaveL(iWriterPlugins[0]);
+        }
+	}
+
+void CCoreDumpSession::CreateFormatterL( const TUid loadRequestUid )
+	{	
+	LOG_MSG( "->CCoreDumpSession::CreateFormatter()\n" );
+
+	ValidatePluginL( loadRequestUid );
+	
+	if(iPluginList.Count() == 0)
+		{		
+		RefreshPluginListL();
+		}
+
+    CPluginInfo *info = NULL;
+    for(TInt i = 0; i < iPluginList.Count(); i++)
+        {    	
+        if(iPluginList[i].iUid == loadRequestUid)
+            {
+                info = CPluginInfo::NewL(iPluginList[i].iName,
+                                         loadRequestUid.iUid,
+                                         iPluginList[i].iVersion,
+                                         TPluginRequest::EFormatter);        
+                CleanupStack::PushL(info);
+                break;
+            }
+        }
+
+    if(!info)
+        {
+        LOG_MSG2("CCoreDumpSession::CreateFormatterL - unable to find formatter uid:%X on plugin type list!\n", loadRequestUid);
+        User::Leave(KErrArgument);
+        }
+
+    iFormatterInfos.AppendL(info);
+    CleanupStack::Pop(info);
+
+	CCoreDumpFormatter *formatter = CCoreDumpFormatter::NewL( (TUid)( loadRequestUid ) );
+
+    CleanupStack::PushL(formatter);
+    iFormatterPlugins.AppendL(formatter);
+    CleanupStack::Pop(formatter);
+
+    LOG_MSG3("CCoreDumpSession::CreateFormatter fmt:%d, wrt:%d\n", iFormatterPlugins.Count(), iWriterPlugins.Count());
+    //for compatibility, first pair is bound by default
+    if( (iFormatterPlugins.Count() == 1) && (iWriterPlugins.Count() == 1) )
+        {
+	        LOG_MSG("CCoreDumpSession::CreateFormatter binding default plugin pair\n" );
+            iFormatterInfos[0]->Pair(0);
+            iFormatterPlugins[0]->ConfigureDataSaveL(iWriterPlugins[0]);
+        }
+	}
+
+void CCoreDumpSession::DeleteFormatterL( const TUid aFreeRequestUid, const TUint aIndex )
+{
+    LOG_MSG("->CCoreDumpSession::DeleteFormatterL()\n");
+    if( (iFormatterInfos.Count() > aIndex) && (iFormatterInfos[aIndex]->Uid() == aFreeRequestUid.iUid) )
+    {
+        delete iFormatterPlugins[aIndex];
+        iFormatterPlugins.Remove(aIndex);
+
+        delete iFormatterInfos[aIndex];
+        iFormatterInfos.Remove(aIndex);
+    }
+    else
+    {
+        User::Leave(KErrArgument);
+    }
+}
+
+void CCoreDumpSession::DeleteWriterL( const TUid aFreeRequestUid, const TUint aIndex )
+{
+    LOG_MSG("->CCoreDumpSession::DeleteWriterL()\n");
+    if( (iWriterInfos.Count() > aIndex) && (iWriterInfos[aIndex]->Uid() == aFreeRequestUid.iUid) )
+    {
+        for(TInt i = 0; i < iFormatterInfos.Count(); i++)
+        {
+            if(iFormatterInfos[i]->Pair() == aIndex)
+            {
+                iFormatterInfos[i]->Pair(KMaxTUint32);
+            }
+        }
+
+        delete iWriterPlugins[aIndex];
+        iWriterPlugins.Remove(aIndex);
+
+        delete iWriterInfos[aIndex];
+        iWriterInfos.Remove(aIndex);
+    }
+    else
+    {
+        User::Leave(KErrArgument);
+    }
+}
+
+void CCoreDumpSession::PluginRequestL(const RMessage2& aMessage)
+{
+	LOG_MSG("->CCoreDumpSession::PluginRequestL()\n");
+
+	TPluginRequest request;
+	TPtr8 pluginReqPtr((TUint8 *)&request, sizeof(TPluginRequest));
+	aMessage.ReadL(0, pluginReqPtr);
+	
+    if(request.iUid.iUid != 0) //(un)load a plugin
+    { 
+        if(request.iPluginType == TPluginRequest::EFormatter)
+        {
+            if(request.iLoad)
+            {
+                CreateFormatterL(request.iUid);
+            }
+            else
+            {
+                //index mapping compatibility  - one plugin at a time case
+                TUint index = (request.iIndex == request.iPair) ? request.iIndex : 0;
+                DeleteFormatterL(request.iUid, index);
+            }
+        }
+        else if(request.iPluginType == TPluginRequest::EWriter)
+        {
+            if(request.iLoad)
+            {
+                CreateWriterL(request.iUid);
+            }
+            else
+            {
+                //index mapping compatibility - one plugin at a time case
+                TUint index = (request.iIndex == request.iPair) ? request.iIndex : 0;
+                DeleteWriterL(request.iUid, index);
+            }
+        }
+        else
+        {
+            LOG_MSG2("CCoreDumpSession::PluginRequestL() - invalid plugin type:%d!\n", request.iPluginType);
+            User::Leave(KErrNotSupported);
+        }
+	    UpdateConfigParametersL();
+    }
+    else //bind a plugin pair
+    {
+        BindPluginsL(request.iIndex, request.iPair);
+    }
+}
+
+void CCoreDumpSession::BindPluginsL(const TUint aFormatterIndex, const TUint aWriterIndex)
+{
+   LOG_MSG3("->CCoreDumpSession::BindPluginsL(fmt=%d, wrt=%d)\n", aFormatterIndex, aWriterIndex);
+   if( (aFormatterIndex < iFormatterInfos.Count()) && (aWriterIndex < iWriterInfos.Count()) )
+   {
+        iFormatterInfos[aFormatterIndex]->Pair(aWriterIndex);
+        iFormatterPlugins[aFormatterIndex]->ConfigureDataSaveL(iWriterPlugins[aWriterIndex]);
+   }
+   else
+   {
+        LOG_MSG5("CCoreDumpSession::BindPluginsL -> fmtIndex:%d/%d wrtIndex:%d/%d\n", aFormatterIndex, iFormatterInfos.Count(),
+                                                                                     aWriterIndex, iWriterInfos.Count());
+        User::Leave(KErrNotFound);
+   }
+}
+
+CCoreDumpFormatter* CCoreDumpSession::GetValidFormatter(const TUint aCount)
+{
+    LOG_MSG2("->CCoreDumpSession::ValidFormatter(aCount=%d)", aCount);
+    TUint counter = 0;
+
+    for(TInt i = 0; i < iFormatterInfos.Count(); i++)
+    {
+        LOG_MSG3("CCoreDumpSession::ValidFormatter() - fmt[%d]->pair=%d", i, iFormatterInfos[i]->Pair());
+        if( (iFormatterInfos[i]->Pair() < iWriterInfos.Count()) && ( counter++ == aCount))
+        {
+            LOG_MSG2("CCoreDumpSession::ValidFormatter() - found valid formatter=%d", iFormatterPlugins[i]);
+            return iFormatterPlugins[i];
+        }
+    }
+    return NULL;
+}
+
+static void CleanupEComArray(TAny* aArray)
+{
+	(static_cast<RImplInfoPtrArray*> (aArray))->ResetAndDestroy();
+	(static_cast<RImplInfoPtrArray*> (aArray))->Close();
+}
+
+void CCoreDumpSession::RefreshPluginListL()
+{
+	LOG_MSG("->CCoreDumpSession::RefreshPluginList()\n");
+
+	iPluginList.Close();
+	TPluginInfo ref;
+
+	RImplInfoPtrArray infoArray;
+	TCleanupItem cleanup(CleanupEComArray, &infoArray);
+	CleanupStack::PushL(cleanup);
+    
+	CCoreDumpFormatter::ListAllImplementationsL( infoArray );
+
+	for ( TInt i = 0; i < infoArray.Count(); i++ )
+		{
+		ref.iVersion = infoArray[i]->Version();
+		ref.iName = infoArray[i]->DisplayName();
+		ref.iUid = infoArray[i]->ImplementationUid();
+		ref.iType = TPluginRequest::EFormatter;
+
+        ref.iLoaded = EFalse; //iLoaded on this list means we have an instance of that plugin
+        for(TInt j = 0; j < iFormatterInfos.Count(); j++)
+        {
+            if(iFormatterInfos[j]->Uid() == ref.iUid.iUid)
+            {
+                ref.iLoaded = ETrue;
+                break;
+            }
+        }
+
+		iPluginList.AppendL(ref);
+		}
+	
+	infoArray.ResetAndDestroy();
+
+	CCrashDataSave::ListAllImplementationsL( infoArray );
+
+	for ( TInt i = 0; i < infoArray.Count(); i++ )
+		{
+		ref.iVersion = infoArray[i]->Version();
+		ref.iName = infoArray[i]->DisplayName();
+		ref.iUid = infoArray[i]->ImplementationUid();
+		ref.iType = TPluginRequest::EWriter;
+
+        ref.iLoaded = EFalse; //iLoaded on this list means we have an instance of that plugin
+        for(TInt j = 0; j < iWriterInfos.Count(); j++)
+        {
+            if(iWriterInfos[j]->Uid() == ref.iUid.iUid)
+            {
+                ref.iLoaded = ETrue;
+                break;
+            }
+        }
+
+		iPluginList.AppendL(ref);
+		}
+
+	CleanupStack::PopAndDestroy();
+}
+
+void CCoreDumpSession::GetPluginListL(const RMessage2& aMessage)
+	{
+	//LOG_MSG("->CCoreDumpSession::GetPluginList()\n");
+
+	TListRequest listRequest; 
+
+	TPtr8 pluginReqPtr((TUint8 *)&listRequest, sizeof(TListRequest));
+
+	//read target debug app address and size from debug agent
+	aMessage.ReadL(0, pluginReqPtr);
+
+	TPluginInfoBlock * plugins = new (ELeave) TPluginInfoBlock;
+    CleanupStack::PushL(plugins);
+
+	if( 0 == listRequest.iIndex )
+		{
+		iPluginList.Reset();
+		RefreshPluginListL();
+		}
+
+	TUint toSupply = iPluginList.Count() - listRequest.iIndex;
+	if ( toSupply > KNumPluginDetails )
+		{
+		toSupply = KNumPluginDetails;
+		}
+
+	for( TUint index = 0; index < toSupply; index ++ )
+		{
+		plugins->plugins[index].iVersion		= iPluginList[index+listRequest.iIndex].iVersion;
+		plugins->plugins[index].iName			= iPluginList[index+listRequest.iIndex].iName;
+		plugins->plugins[index].iDescription	= iPluginList[index+listRequest.iIndex].iDescription;
+		plugins->plugins[index].iUid			= iPluginList[index+listRequest.iIndex].iUid;
+		plugins->plugins[index].iType			= iPluginList[index+listRequest.iIndex].iType;
+		plugins->plugins[index].iLoaded			= iPluginList[index+listRequest.iIndex].iLoaded;
+		//RDebug::Print( _L("  loaded[%d]=%d\n"), index, plugins->plugins[index].iLoaded );
+		}
+
+	listRequest.iSupplied = toSupply;
+	listRequest.iRemaining = iPluginList.Count() - (listRequest.iIndex + listRequest.iSupplied);
+
+	//RDebug::Print( _L("  supplying=%d, remaining=%d\n"), toSupply, listRequest.iRemaining );
+
+	aMessage.WriteL(0, pluginReqPtr);
+	TPtr8 pluginArrPtr( (TUint8 *)plugins, sizeof(TPluginInfoBlock) );
+	pluginArrPtr.Set( (TUint8 *)plugins, sizeof(TPluginInfoBlock), sizeof(TPluginInfoBlock) );
+
+	aMessage.WriteL(1, pluginArrPtr);
+    CleanupStack::PopAndDestroy(plugins);
+	}
+
+void CCoreDumpSession::ObservationRequestL( const RMessage2& aMessage )
+    {
+	//RDebug::Print(_L("->CCoreDumpSession::ObservationRequestL()\n"));
+    TInt deslen;
+    deslen = aMessage.GetDesLengthL(0);
+	if (deslen == 0)
+		{
+		// Zero-length target name supplied
+		User::Leave(KErrArgument);
+		}
+
+	RBuf targetName;
+	targetName.CleanupClosePushL();
+	targetName.CreateL(deslen);
+	// Read the target name into targetName
+	aMessage.ReadL(0, targetName);
+
+    deslen = aMessage.GetDesLengthL(1);
+	if (deslen == 0)
+		{
+		// Zero-length target owner name supplied
+		User::Leave(KErrArgument);
+		}
+
+	RBuf targetOwnerName;
+	targetOwnerName.CleanupClosePushL();
+	targetOwnerName.CreateL(deslen);
+	// Read the target owner name into targetOwnerName
+	aMessage.ReadL(1, targetOwnerName);
+
+    TBool observe = static_cast<TBool>(aMessage.Int2());
+    if(observe)
+        {
+        LOG_MSG("CCoreDumpSession::ObservationRequestL - KAttach\n" );
+        AttachTargetL(targetName, targetOwnerName);
+        }
+    else
+        {
+        LOG_MSG("CCoreDumpSession::ObservationRequestL - KDetach\n");
+        DetachTargetL(targetName, targetOwnerName);
+        }
+
+    CleanupStack::PopAndDestroy(&targetOwnerName);
+    CleanupStack::PopAndDestroy(&targetName);
+    }
+
+void CCoreDumpSession::AttachTargetL( const TDesC &aTargetName, const TDesC &aTargetOwnerName )
+    {
+	//LOG_MSG("->CoreDumpSession::AttachTargetL()\n");
+    TBool found = EFalse;
+
+    for(TInt i = 0; i < iObservationList.Count(); ++i)
+        {
+        if(iObservationList[i]->TargetName() == aTargetOwnerName)
+            {
+            if(aTargetName != aTargetOwnerName) //attach thread
+                {
+                iObservationList[i]->AddThreadL(aTargetName);
+                //LOG_MSG("CoreDumpSession::AttachTargetL - thread added\n");
+                }
+            else
+                {
+                LOG_MSG("CoreDumpSession::AttachTargetL - process added\n");
+                iObservationList[i]->ClearThreads();
+                } 
+            found = ETrue;
+            break;
+            }
+        }
+
+    if(!found)
+        {
+        //RDebug::Printf( "CoreDumpSession::AttachTargetL - creating new observer", &aTargetOwnerName );
+        CTargetObserver *observer = CTargetObserver::NewLC( iSecSess, *iCrashHandler, aTargetOwnerName ); 
+        User::LeaveIfError( iObservationList.Insert(observer, 0) );
+        
+        if(aTargetName != aTargetOwnerName) //attach thread
+            {
+            observer->AddThreadL(aTargetName);
+            //LOG_MSG("CoreDumpSession::AttachTargetL - thread added\n");
+            }
+
+        if( (iPreCrashEventAction & ESuspendThread) || 
+			(iPreCrashEventAction & ESuspendProcess) )
+			{
+			LOG_MSG("CCoreDumpSession::AttachTargetL() ->SetCrashEventsL(EActionSuspend)\n" );
+            SetCrashEventsL(*observer, EActionSuspend);
+			}
+        else
+			{
+			LOG_MSG("CCoreDumpSession::AttachTargetL() ->SetCrashEventsL(EActionContinue)\n" );
+            SetCrashEventsL(*observer, EActionContinue);
+			}
+
+        observer->Observe();
+
+	    //LOG_MSG("CoreDumpSession::AttachTargetL - observer started\n");
+        CleanupStack::Pop(); //observer is now in the iObservationList 
+        }
+    }
+
+void CCoreDumpSession::SetCrashEventsL(CTargetObserver &aObserver, TKernelEventAction aAction)
+{
+	LOG_MSG2("CCoreDumpSession::SetCrashEventsL(aAction=%d)\n", aAction);
+
+    if(iCrashEventTypes & ECrashHwExc)
+		{
+		LOG_MSG2("  aObserver.SetCrashEventL(EEventsHwExc, aAction=%d)\n", aAction);
+        aObserver.SetCrashEventL(EEventsHwExc, aAction);
+		}
+    else
+		{
+		LOG_MSG("  aObserver.SetCrashEventL(EEventsHwExc, EActionIgnore)\n");
+        aObserver.SetCrashEventL(EEventsHwExc, EActionIgnore);
+		}
+
+    if(iCrashEventTypes & ECrashKillThread)
+		{
+		LOG_MSG2("  aObserver.SetCrashEventL(EEventsKillThread, aAction=%d)\n", aAction);
+        aObserver.SetCrashEventL(EEventsKillThread, aAction);
+		}
+    else
+		{
+		LOG_MSG("  aObserver.SetCrashEventL(EEventsKillThread, EActionIgnore)\n");
+        aObserver.SetCrashEventL(EEventsKillThread, EActionIgnore);
+		}
+}
+
+void CCoreDumpSession::DetachTargetL( const TDesC &aTargetName, const TDesC &aTargetOwnerName )
+    {
+	//LOG_MSG("->CoreDumpSession::DetachTargetL()\n");
+    TBool found = EFalse;
+
+    RBuf ton;
+    ton.CreateL(aTargetName);
+    char *tonp = (char*) ton.Collapse().PtrZ();
+    LOG_MSG2("CCoreDumpSession::DetachTargetL(%s)\n", tonp);
+    ton.Close();
+
+    RBuf otn;
+    TInt count = iObservationList.Count();
+    for(TInt i = 0; i < count; ++i)
+        {
+        otn.CreateL(iObservationList[i]->TargetName());
+        char* otnp = (char*) otn.Collapse().PtrZ();
+        LOG_MSG3("CCoreDumpSession::DetachTargetL - iObservationList[%d]->TargetName=%s\n", i, otnp);
+        otn.Close();
+        if (iObservationList[i]->TargetName() == aTargetOwnerName)
+            {
+            if(aTargetName != aTargetOwnerName) //detach thread
+                {
+                iObservationList[i]->DelThreadL(aTargetName);
+                LOG_MSG("CoreDumpSession::DetachTargetL - thread removed\n");
+                }
+            if(iObservationList[i]->ThreadCount() == 0) //no more threads to observe or detach process
+                {
+                LOG_MSG("CoreDumpSession::DetachTargetL - destroying observer\n");
+                delete iObservationList[i]; 
+                iObservationList.Remove(i);
+                }
+            found = ETrue;
+            break;
+            }
+        }
+
+    if(!found)
+        {
+        LOG_MSG("CoreDumpSession::DetachTargetL - target not found\n");
+        User::Leave(KErrNotFound);
+        }
+    }
+
+void CCoreDumpSession::UpdateConfigParametersL()
+{
+	LOG_MSG( "->CCoreDumpSession::UpdateConfigParametersL()\n" );
+
+    COptionConfig *config = NULL;
+    iTotalConfigList.Reset();
+    TUint configParamSize;
+    
+    TInt paramNum = iConfigList.Count();
+	for(TInt i = 0; i < paramNum; i++ )
+		{
+        config = iConfigList[i];
+        
+        if(!config)
+            {
+            User::Leave(KErrBadHandle);
+            }
+
+        configParamSize = config->Size();
+        if(configParamSize > iMaxConfigParamSize)
+            {
+            iMaxConfigParamSize = configParamSize ;
+            }
+        iTotalConfigList.AppendL(config);
+		}
+
+
+    for(TInt i = 0; i < iFormatterPlugins.Count(); i++)
+        {
+        paramNum = iFormatterPlugins[i]->GetNumberConfigParametersL();
+        for(TInt index = 0; index < paramNum; index++)
+            {
+            config = iFormatterPlugins[i]->GetConfigParameterL(index);
+            if(!config)
+                {
+                User::Leave(KErrBadHandle);
+                }
+
+            configParamSize = config->Size();
+            if(configParamSize > iMaxConfigParamSize)
+                {
+                iMaxConfigParamSize = configParamSize ;
+                }
+
+            config->Instance(i); 
+            iTotalConfigList.AppendL(config);
+            }
+        }
+
+    for(TInt i = 0; i < iWriterPlugins.Count(); i++)
+        {
+        paramNum = iWriterPlugins[i]->GetNumberConfigParametersL();
+        for(TInt index = 0; index < paramNum; index++)
+            {
+            config = iWriterPlugins[i]->GetConfigParameterL(index);
+            if(!config)
+                {
+                User::Leave(KErrBadHandle);
+                }
+
+            configParamSize = config->Size();
+            if(configParamSize > iMaxConfigParamSize)
+                {
+                iMaxConfigParamSize = configParamSize ;
+                }
+
+            config->Instance(i); 
+            iTotalConfigList.AppendL(config);
+            }
+        }
+    
+    
+	TRAPD(err, iFlashDataSource->ReadSCMConfigL(iScmConfigList));
+	if(err != KErrNone)
+		{
+		LOG_MSG("Unable to retrieve config params for the SCM: [%d]");
+		return;
+		}
+	
+    for(TInt i=0;i<iScmConfigList.Count();i++)
+    	{
+    	iTotalConfigList.AppendL(iScmConfigList[i]);
+    	} 
+	}
+
+/**
+ * This logs the current SCM Config to serial 
+ */
+void CCoreDumpSession::PrintScmConfigL()
+	{	
+    for(TInt i=0;i<iScmConfigList.Count();i++)
+    	{
+    	COptionConfig* optCon = iScmConfigList[i];
+    	LOG_DES(optCon->Prompt());
+    	LOG_MSG2("\t\tHas a value of %d", optCon->Value());
+    	} 
+	}
+
+// Gather all conifg params from CDS, formatter and iWriter, 
+// collent into an array and set num to the number of configs avaliable
+void CCoreDumpSession::GetNumberConfigParametersL( const RMessage2& aMessage )
+	{
+	//LOG_MSG( "->CCoreDumpSession::GetNumberConfigParametersL()\n" );
+	 UpdateConfigParametersL( );
+
+	TInt numConfigParams = iTotalConfigList.Count();
+	//LOG_MSG2( "  numConfigParams=%d", numConfigParams );
+
+	TPtr8 numParamPtr( (TUint8 *) & numConfigParams, sizeof(TInt) );
+	// Else it does not get passed back
+	numParamPtr.Set( (TUint8 *)& numConfigParams, sizeof(TInt), sizeof(TInt) ); 
+
+	TPtr8 maxParamSizePtr( (TUint8 *) & iMaxConfigParamSize, sizeof(TInt) );
+	// Else it does not get passed back
+	maxParamSizePtr.Set( (TUint8 *)& iMaxConfigParamSize, sizeof(TInt), sizeof(TInt) ); 
+
+	/*
+	RDebug::Printf( " CCoreDumpSession::GetNumberConfigParameters(): iConfigList.Count()=%d, passing back nParams=%d, iMaxConfigParamSize=%d \n", 
+		iConfigList.Count(), numConfigParams, iMaxConfigParamSize );
+	*/
+
+	aMessage.WriteL( 0, numParamPtr );
+
+	aMessage.WriteL( 1, maxParamSizePtr );
+	}
+
+void CCoreDumpSession::GetConfigParameterL( const RMessage2& aMessage )
+	{
+//	LOG_MSG( "->CCoreDumpSession::GetConfigParameterL()\n" );
+
+
+	if(	iTotalConfigList.Count() == 0 )
+		{
+		// The user has never called GetNumberConfigParametersL(), 
+		// so update the parameters first.
+		UpdateConfigParametersL( );
+		}
+
+	if( iTotalConfigList.Count() == 0 )
+		{
+		RDebug::Printf( "  ERROR !* : Have not gathered the configuration parameters\n" );
+		User::Leave( KErrBadHandle );
+		}
+
+	TInt configIndex = aMessage.Int0();
+	//RDebug::Printf( "  configIndex=%d\n", configIndex );
+
+	if ( ( configIndex < 0 ) || ( configIndex >= iTotalConfigList.Count() ) )
+		{
+		RDebug::Printf( "  ERROR !* : config Index out of bounds\n" );
+		User::Leave( KErrBadHandle );
+		}
+
+	COptionConfig * config = iTotalConfigList[configIndex];
+	
+	HBufC8 * configDes = config->MarshalDataL();
+	CleanupStack::PushL( configDes );
+	
+	if ( configDes == NULL )
+		{
+		RDebug::Printf( "  ERROR !* MarshalData returned null buf\n" );
+		User::Leave( KErrBadDescriptor );
+		}
+	else
+		{
+		TPtr8 configPtr( configDes->Des() );
+		if( configPtr.Size() == 0 )
+			{
+			RDebug::Printf( "  ERROR !* : if( configPtr.Size() == 0 )\n" );
+			User::Leave( KErrBadDescriptor );
+			}
+
+		aMessage.WriteL( 1, configPtr );
+		}
+
+	CleanupStack::PopAndDestroy( configDes );
+	}
+
+void CCoreDumpSession::SetConfigParameterL( const RMessage2& aMessage )
+	{
+	LOG_MSG( "->CCoreDumpSession::SetConfigParameterL()\n" );
+
+	TConfigRequest configRequest; 
+	
+	TPtr8 configReqPtr( (TUint8 *)&configRequest, sizeof(TConfigRequest) );
+	aMessage.ReadL( 0, configReqPtr );
+
+	TInt32 value = aMessage.Int1();
+
+	HBufC *valueDesc = NULL;
+	TInt valueDesLen = aMessage.GetDesLength( 2 );
+	if( valueDesLen > 0 )
+		{
+		valueDesc = HBufC::NewL( valueDesLen );
+		CleanupStack::PushL( valueDesc );
+		TPtr ptr( valueDesc->Des() );
+		aMessage.ReadL( 2, ptr );
+		}
+	else
+		{
+		valueDesc = KNullDesC().AllocL();
+		CleanupStack::PushL( valueDesc );
+		}
+
+	switch(configRequest.iSource)
+		{
+		case COptionConfig::ECoreDumpServer:
+
+			SetConfigParameterL( configRequest.iIndex, value, *valueDesc );
+			break;
+
+		case COptionConfig::EFormatterPlugin:
+            {
+                if(configRequest.iInstance < iFormatterPlugins.Count())
+                    {
+                    iFormatterPlugins[configRequest.iInstance]->SetConfigParameterL(configRequest.iIndex, value, *valueDesc); 
+                    break;
+                    }
+			break;
+            }
+		case COptionConfig::EWriterPlugin:
+            {	
+                if(configRequest.iInstance < iWriterPlugins.Count())
+                    {
+                    iWriterPlugins[configRequest.iInstance]->SetConfigParameterL(configRequest.iIndex, value, *valueDesc); 
+                    break;
+                    }
+			break;
+            }
+		case COptionConfig::ESCMConfig:
+			{
+							
+    		LOG_MSG4("(CCoreDumpSession::SetConfigParameterL) Updating config param instance %d  value %d index =%d"
+    				, configRequest.iInstance , value, configRequest.iIndex);
+    		iFlashDataSource->ModifySCMConfigItemL(configRequest.iInstance, value);
+            break;
+            }
+            
+		default:
+            User::Leave(KErrArgument);
+		}
+
+	    CleanupStack::PopAndDestroy( valueDesc );
+	}
+
+
+TInt32 CCoreDumpSession::PreProcessingAction() const
+	{
+    return iConfigList[EPreCrashEventAction]->Value();
+	}
+
+TInt32 CCoreDumpSession::PostProcessingAction() const
+	{
+    return iConfigList[EPostCrashEventAction]->Value();
+	}
+
+void CCoreDumpSession::SetConfigParameterL( const TInt aIndex, 
+										 const TInt32 & aValue, 
+										 const TDesC & aDescValue )
+	{
+	LOG_MSG3( "->CCoreDumpSession::SetConfigParameterL( aIndex=%d, aValue=0x%X )\n", aIndex, aValue );
+
+	if ( ( aIndex < 0 ) || ( aIndex >= iConfigList.Count() ) )
+		{
+		LOG_MSG2( "  ERROR !* : config Index out of bounds, max=%d\n", iConfigList.Count() - 1 );
+		User::Leave( KErrBadHandle );
+		}
+
+	//Match the parameter passed in to one of our own parameters via the index
+	COptionConfig &config = *iConfigList[aIndex];
+
+	if( config.Index() != aIndex )
+		{
+		RDebug::Printf( "  ERROR !* : config Index %d does not match internal index %d\n", aIndex, config.Index() );
+		User::Leave( KErrBadHandle );
+		}
+
+	if( aIndex == (TInt)EPreCrashEventAction )
+	    {
+		switch( aValue )
+			{
+			case ENoPreAction:
+			case ESuspendThread:
+			case ESuspendProcess:
+
+				LOG_MSG2("  Changing EPreCrashEventAction to =%d\n", aValue );
+
+				iPreCrashEventAction = aValue;
+
+                for(TInt i = 0; i < iObservationList.Count(); i++)
+                    {
+                    if( (iPreCrashEventAction & ESuspendThread) || 
+						(iPreCrashEventAction & ESuspendProcess) )
+						{
+						LOG_MSG2("  SetCrashEventsL(*iObservationList[%d], EActionSuspend)\n", i );
+                        SetCrashEventsL(*iObservationList[i], EActionSuspend);
+						}
+                    else
+						{
+						LOG_MSG2("  SetCrashEventsL(*iObservationList[%d], EActionContinue);\n", i );
+                        SetCrashEventsL(*iObservationList[i], EActionContinue);
+						}
+                    }
+                
+				break;
+			default:
+				RDebug::Printf(" ERROR !* EPreCrashEventAction cannot be %d\n", aValue );
+				User::Leave(KErrArgument);
+			}
+	    }
+	else if( aIndex == (TInt)EPostCrashEventAction )
+	    {
+		switch( aValue )
+			{
+			case ENoPostAction:
+			case EResumeThread:
+			case EResumeProcess:
+			case EKillProcess:
+				iPostCrashEventAction = aValue;
+				break;
+			default:
+				RDebug::Printf(" ERROR !* EPostCrashEventAction cannot be %d\n", aValue );
+				User::Leave(KErrArgument);
+			}
+	    }
+    else if( aIndex == (TInt)ECrashEventTypes )
+        {
+		switch( aValue )
+			{
+			case ECrashHwExc:
+			case ECrashKillThread:
+			case ECrashHwExcAndKillThread:
+
+				LOG_MSG2("  Changing trigger ECrashEventTypes to =%d\n", aValue );
+				iCrashEventTypes = aValue;
+
+				for(TInt i = 0; i < iObservationList.Count(); i++)
+                    {
+                    if( (iPreCrashEventAction & ESuspendThread) || 
+						(iPreCrashEventAction & ESuspendProcess) )
+                        SetCrashEventsL(*iObservationList[i], EActionSuspend);
+                    else
+                        SetCrashEventsL(*iObservationList[i], EActionContinue);
+                    }
+
+				break;
+			default:
+				RDebug::Printf( " ERROR !* ECrashEventTypes  cannot be %d\n", aValue );
+				User::Leave(KErrArgument);
+			}
+        }
+	else
+		{
+		RDebug::Printf(
+			"CCoreDumpSession::SetConfigParameterL() : parameter with index %d does is not valid\n", 
+				aIndex );
+		User::Leave(KErrArgument);
+		}
+
+	// Change our internal values
+	config.Value( aValue );
+	//LOG_MSG( "  config->ValueL( aDescValue )\n" );
+	config.ValueL( aDescValue );
+
+	}
+
+
+
+/**
+Save one parameter for a specific section. 
+@param aParam COptionConfig pointer to save
+@param aSectName Section name in the file to save this parameter to
+@param aSaveIndex This parameter is only used to create key strings that are unique.
+@param aPersistConfigData Object used to save the configuration to. 
+*/
+void CCoreDumpSession::SaveConfigParamL( const COptionConfig * aParam, 
+									   const TPtrC	&	aSectName,
+									   const TInt		aSaveIndex,
+									   CIniDocument16 * aPersistConfigData )
+	{
+
+	LOG_MSG2( "CCoreDumpSession::SaveConfigParamL( aSaveIndex=%d )\n", aSaveIndex );
+
+	HBufC * iniStringKey;
+	TInt err;
+
+	// Save the Configuration Parameter Value
+		{
+		iniStringKey = GenerateKeyStringLC( aSaveIndex, EIniKeyValue );
+		TInt keyIntValue = aParam->Value();
+
+		// Size of character buffer required to represent a 32bit 
+		// interger as decimal should be 10.
+		TBuf<16> intValueBuf; 
+				
+		switch( aParam->Type() )
+			{
+			case COptionConfig::ETInt:
+			case COptionConfig::ETUInt:
+			case COptionConfig::ETBool:
+
+				LOG_MSG2( "  -> SetKey( int value=%d)\n", keyIntValue );
+				intValueBuf.AppendNum( keyIntValue );
+				err = aPersistConfigData->SetKey( aSectName, iniStringKey->Des(), intValueBuf );
+				
+                /*
+				const TDesC & paramV = intValueBuf;
+				RBuf valueV;
+				valueV.Create( paramV );
+				char* cl = (char*) valueV.Collapse().PtrZ();
+				RDebug::Printf("  saving integer value=%s\n", cl );
+                */
+
+				break;
+
+			case COptionConfig::ETString:
+			case COptionConfig::ETFileName:
+			case COptionConfig::ETMultiEntryEnum:
+			case COptionConfig::ETSingleEntryEnum:
+				{
+				const TDesC & paramValue = aParam->ValueAsDesc();
+
+				if( paramValue == KNullDesC )
+					{
+					LOG_MSG( "  Cannot save parameter value that is NULL\n" );	
+					CleanupStack::PopAndDestroy( iniStringKey );
+					return;
+					}
+                /*
+				RBuf value;
+				value.Create( paramValue );
+				char* cl = (char*) value.Collapse().PtrZ();
+				RDebug::Printf("  saving string value=%s\n", cl );
+                */
+
+				LOG_MSG( "  -> SetKey( string value )\n" );
+				err = aPersistConfigData->SetKey( aSectName, iniStringKey->Des(), paramValue );
+				}
+				break;
+			default:
+				{
+				// unknown type, Leave since the file could be corrupt or malformed
+				LOG_MSG2( "  Invalid COptionConfig parameter type %d\n", aParam->Type() );
+				CleanupStack::PopAndDestroy( iniStringKey );
+				User::Leave( KErrCorrupt );
+				}
+			}// switch (COptionConfig::TOptionType)
+
+		LOG_MSG( "  CleanupStack::PopAndDestroy( iniStringKey )" );
+		CleanupStack::PopAndDestroy( iniStringKey );
+		}
+
+
+
+	// Save the Configuration Parameter Index
+		{
+		iniStringKey = GenerateKeyStringLC( aSaveIndex, EIniKeyIndex );
+
+		TInt keyIndex = aParam->Index();
+		TBuf<4> intIndexBuf;
+		LOG_MSG3( "  -> keyIndex%d = parameter index %d\n", aSaveIndex, keyIndex );
+		intIndexBuf.AppendNum( keyIndex );
+
+		err = aPersistConfigData->SetKey( aSectName, iniStringKey->Des(), intIndexBuf );
+
+		CleanupStack::PopAndDestroy( iniStringKey );
+		
+		if( KErrNone != err )
+			{
+			LOG_MSG2( "  ERROR !* aPersistConfigData->AddValue() returned %d\n", err );
+			}
+		User::LeaveIfError( err );
+		}
+
+
+	// Save the Configuration Parameter Type
+		{
+		iniStringKey = GenerateKeyStringLC( aSaveIndex, EIniKeyType );
+
+		TInt keyType = aParam->Type();
+		TBuf<8> intTypeBuf;
+		LOG_MSG3( "  -> KeyType%d = parameter type %d\n", aSaveIndex, keyType );
+		intTypeBuf.AppendNum( keyType );
+
+		err = aPersistConfigData->SetKey( aSectName, iniStringKey->Des(), intTypeBuf );
+
+		CleanupStack::PopAndDestroy( iniStringKey );
+		if( KErrNone != err )
+			{
+			LOG_MSG2( "  ERROR !* aPersistConfigData->AddValue() returned %d\n", err );
+			}
+		User::LeaveIfError( err );
+		}
+	}
+
+
+
+_LIT( KPluginExtension, ".plugin" );
+#define KPluginUIDCharsPerLine 8
+
+
+_LIT( KCDSConfig,				"CoreDumpServerConfiguration"			 );
+_LIT( KWriterConfig,			"WriterConfiguration"					 );
+_LIT( KFormatterConfig,			"FormatterConfiguration"				 );
+_LIT( KObservedConfig,			"ObservedConfiguration"					 );
+
+_LIT( KDefaultIniFile, "coredumpserver.ini" );
+_LIT( KUID, "UID" );
+_LIT( KPluginPair, "Pair" );
+
+
+
+
+
+/**
+Method to parse the set of files that contain the UIDs of the allowed plugins. 
+The files are read our private directory in all drives. Thus installed .plugin
+files are also checked. 
+
+The plugin files must have the extension ".plugin". The content must be in 
+ASCII-8. The format must be one UID per line, with no empty lines. 
+The EOL can be CR+LF or just CR.
+*/
+void CCoreDumpSession::ReadPluginUidFilesL( )
+	{
+
+	RFs	fsSession;
+	CleanupClosePushL( fsSession );
+	User::LeaveIfError( fsSession.Connect() );
+
+	//RProcess thisProc;
+	
+	TDriveList driveList;
+    TVolumeInfo volInfo;
+
+    User::LeaveIfError( fsSession.DriveList( driveList ) );
+
+	HBufC* sessionPath = HBufC::NewLC( KMaxFileName );
+	TPtr privPath( sessionPath->Des() );
+
+	RBuf8 allowedPluginUidStr;
+	allowedPluginUidStr.CleanupClosePushL();
+	allowedPluginUidStr.CreateL( KPluginUIDCharsPerLine );
+
+	RFile pluginFile;
+	CleanupClosePushL( pluginFile );
+
+    for( TInt driveNumber = EDriveA; driveNumber <= EDriveZ; driveNumber++ )
+    {
+        if( ( !driveList[driveNumber] ) || 
+			( KErrNone != fsSession.Volume( volInfo, driveNumber) ) ||
+			( volInfo.iDrive.iType==EMediaNotPresent ) )
+            {
+            continue;
+            }
+
+		// Get a list of the files in the private directory of drive <driveNumber> 
+
+		fsSession.SetSessionToPrivate( driveNumber );
+		User::LeaveIfError( fsSession.SessionPath( privPath ) );
+		CDir * fileList = NULL;
+
+		// KEntryAttNormal gets only files (not dirs, hidden or system files)
+		TInt ret = fsSession.GetDir( privPath, KEntryAttNormal, ESortByName, fileList );
+		if( ( KErrNone != ret ) || ( !fileList ) )
+			{
+	if( fileList )
+				delete fileList;
+			continue;
+			}
+
+		CleanupStack::PushL( fileList );
+
+		for( TInt i = 0; i < fileList->Count(); i++ )
+			{
+			TEntry fileEntry = (*fileList)[i];
+			TParse fileNameParser;
+			fileNameParser.Set( fileEntry.iName, NULL, NULL );
+			if( fileNameParser.Ext() != KPluginExtension )
+				{
+				continue;
+				}
+
+            /*
+			RBuf8 pluginFilePrint;
+			pluginFilePrint.CreateL( fileEntry.iName.Length() + 1 );
+			pluginFilePrint.Copy( fileEntry.iName );
+			char* cl = (char*) pluginFilePrint.PtrZ();
+			LOG_MSG2("    Reading .plugin file %s\n", cl );
+            */
+
+			// File extension is .plugin, so add the list of UIDs contained inside 
+			// the file to our list of allowed plugins
+			//
+			ret = pluginFile.Open( fsSession, fileEntry.iName, EFileRead );
+			if( KErrNone != ret )
+				{
+				LOG_MSG("  Error openning file. Ignoring this file\n" );
+				continue;
+				}
+
+			while( KErrNone == ret )
+				{
+				// Read the UID characters on a line. Exactly 8 * 1 byte non-UNICODE chars per line
+				ret = pluginFile.Read( allowedPluginUidStr, KPluginUIDCharsPerLine );
+				if( ( KErrNone != ret ) || (allowedPluginUidStr.Length() != KPluginUIDCharsPerLine ) )
+					{
+					// Reached the end of file, so go to the next file
+					break;
+					}
+
+				TLex8 uidLex( allowedPluginUidStr );
+				TUint pluginUidValue = 0;
+				uidLex.Val( pluginUidValue, EHex );
+				TUid allowedUid = TUid::Uid( pluginUidValue );
+				iAllowedPlugins.AppendL( allowedUid );
+
+				// Now skip the end of line character/s CR 0x0D and possibly LF 0x0A
+				ret = pluginFile.Read( allowedPluginUidStr, 1 );
+				if( ( KErrNone == ret ) && (allowedPluginUidStr.Length() == 1) )
+					{
+					//Could have read the CR or LF
+					if( 0x0D == *(allowedPluginUidStr.Ptr()) )
+						{
+						// CR should be followed by LF, so read that too
+						ret = pluginFile.Read( allowedPluginUidStr, 1 );
+						}
+					}
+
+				if( allowedPluginUidStr.Length() == 0 )
+					{
+					ret = KErrEof;
+					}
+
+				} // while have read 8 bytes
+
+			pluginFile.Close();
+			} // for each file in file list
+
+		CleanupStack::PopAndDestroy( fileList );
+		}
+	
+	CleanupStack::PopAndDestroy( &pluginFile );
+	CleanupStack::PopAndDestroy( &allowedPluginUidStr );
+	CleanupStack::PopAndDestroy( sessionPath );
+	CleanupStack::PopAndDestroy( &fsSession );
+
+	if( 0 == iAllowedPlugins.Count() )
+		{
+		LOG_MSG( "  Warning : No plugins will be allowed\n" );
+		}
+	else
+		{
+		for( TInt i=0; i < iAllowedPlugins.Count(); i++ )
+			{
+			LOG_MSG2( "  Plugin 0x%X allowed\n", iAllowedPlugins[i] );
+			}
+		}
+
+	}
+
+void CCoreDumpSession::ValidatePluginL( const TUid aPluginUid ) const
+	{
+
+	LOG_MSG2( "->CCoreDumpSession::ValidatePlugin(aPluginId=0x%X)\n", aPluginUid.iUid );
+
+	for( TInt i = 0; i < iAllowedPlugins.Count(); i++ )
+		{
+		if( iAllowedPlugins[i] == aPluginUid )
+			{
+			LOG_MSG( "  Plugin Allowed\n" );
+			return;
+			}
+		}
+	LOG_MSG( "  Plugin Not Allowed\n" );
+    User::Leave(KErrPermissionDenied);
+	}
+
+/**
+@pre aFsSession FileSystem session must have been connected to and still be active
+@post aFileName and aPersistConfigData pushed onto the stack
+*/
+void CCoreDumpSession::OpenIniFileLC( const RMessage2	* aMessage, 
+									const TBool		  aSaving,
+									RFs				& aFsSession,
+									HBufC		   *& aFileName,
+									CIniDocument16 *& aPersistConfigData )
+	{
+
+
+	LOG_MSG( "CCoreDumpSession::OpenIniFileLC(RMessage2)\n" );
+
+	TInt ret;
+
+	TInt iniFileDesLen = 0;
+
+	if( aMessage )
+		{
+		LOG_MSG( " RMessage2 != NULL\n" );
+		iniFileDesLen = aMessage->GetDesLength( 0 );
+		if( iniFileDesLen > 0 )
+			{
+			//LOG_MSG( "  User supplied ini file name\n" );
+			aFileName = HBufC::NewL( iniFileDesLen );
+
+			//LOG_MSG( "  CleanupStack::PushL( aFileName )\n" );
+			CleanupStack::PushL( aFileName );
+
+			TPtr ptr( aFileName->Des() );
+			aMessage->ReadL( 0, ptr );
+			if( !aSaving && !aFsSession.IsValidName( ptr ) )
+				{
+				// If we are loading and the file and path are incorrect
+				//LOG_MSG( "  IsValidName() == EFalse\n" );
+				User::Leave( KErrPathNotFound );
+				}
+			}
+		}
+
+	if( 0 == iniFileDesLen )
+		{
+		aFsSession.SetSessionToPrivate( EDriveE );
+
+		RBuf privPath;
+		privPath.CleanupClosePushL();
+		privPath.CreateL( KMaxFileName );
+		
+		aFsSession.SessionPath( privPath );
+
+		privPath.Append( KDefaultIniFile );
+		aFileName = HBufC::NewL( privPath.Length() );
+		*aFileName = privPath;// Copy name
+        
+		CleanupStack::PopAndDestroy( &privPath );
+
+		CleanupStack::PushL( aFileName );
+
+		if( aSaving )
+			{
+			//LOG_MSG( " aFsSession.CreatePrivatePath( EDriveE )\n" );
+			ret = aFsSession.CreatePrivatePath( EDriveE );
+			if( ( KErrNone  != ret ) && ( KErrAlreadyExists != ret ) )
+				{
+				LOG_MSG2( " aFsSession.CreatePrivatePath( EDriveE ) returned ERROR %d\n", ret );
+				User::Leave( ret );
+				}
+			}
+		}
+
+	if( aSaving  ) 
+		{
+		// delete existing file since CIniDocument16::NewL expects a correctly formed 
+		// file or no file at all. An empty file makes the NewL Leave
+		//
+		//LOG_MSG( "  -> aFsSession.Delete( aFileName->Des() )\n");
+		aFsSession.Delete( aFileName->Des() );
+		}
+    else
+    {
+        TEntry entry;
+        User::LeaveIfError(aFsSession.Entry(aFileName->Des(), entry));
+    }
+	//LOG_MSG( "  ->CIniDocument16::NewL( aFsSession, aFileName->Des() )\n");
+	TRAPD(err, aPersistConfigData = CIniDocument16::NewL( aFsSession, aFileName->Des() ));
+
+	if( KErrNone != err )
+		{
+		LOG_MSG2( "  <- CIniDocument16::NewL( ) left with %d\n", err );
+		}
+
+	CleanupStack::PushL( aPersistConfigData );
+	}
+
+
+
+_LIT( KIniFileCommentTitle,	"CoreDumpServerSettingsFile" );
+_LIT( KIniFileCommentSymbian, "Symbian_Software_Ltd" );
+_LIT( KIniFileCommentSymbianYear, "2007" );
+_LIT( KIniFileCommentVersionString,	"Version" );
+_LIT( KIniFileCommentVersionNumber,	"1.0.0" );
+
+
+/*
+* Client request to load system configuration file
+*/
+void CCoreDumpSession::SaveConfigFileL( const RMessage2* aMessage )
+	{
+	
+	LOG_MSG( "CCoreDumpSession::SaveConfigFileL(RMessage2)\n");
+
+	RFs	fsSession;
+	CleanupClosePushL( fsSession );
+	User::LeaveIfError( fsSession.Connect() );
+
+
+	HBufC * fileName = NULL;
+	CIniDocument16 * persistConfigData = NULL;
+
+	OpenIniFileLC( aMessage, ETrue, fsSession, fileName, persistConfigData );
+
+	// persistConfigData is on top of the stack, and under it is fileName
+
+	TInt ret;
+  	TPtrC uidString;
+	uidString.Set( KUID );
+	TPtrC sectName;
+
+	sectName.Set( KIniFileCommentTitle );
+	ret = persistConfigData->AddSection( sectName );
+	User::LeaveIfError( ret );
+
+	ret = persistConfigData->SetKey( sectName, KIniFileCommentSymbian, KIniFileCommentSymbianYear );
+	User::LeaveIfError( ret );
+
+	ret = persistConfigData->SetKey( sectName, KIniFileCommentVersionString, KIniFileCommentVersionNumber );
+	User::LeaveIfError( ret );
+
+	
+	sectName.Set( KCDSConfig );
+	//LOG_MSG( "    persistConfigData->AddSection( KCDSConfig )\n" );
+	ret = persistConfigData->AddSection( sectName );
+	//LOG_MSG2( "    AddSection( KCDSConfig ) returned %d", ret );
+	User::LeaveIfError( ret );
+
+	RBuf cdsUidNumberString;
+    cdsUidNumberString.CleanupClosePushL();
+	cdsUidNumberString.CreateL( 8 );
+	cdsUidNumberString.AppendNumFixedWidth( (TUint)iOurSecureID.iUid, EHex, 8 );  // Width = 8 chars
+
+	//LOG_MSG( "    persistConfigData->SetKey( KCDSConfig, uidString, cdsUidNumberString )\n" );
+	ret = persistConfigData->SetKey( sectName, uidString, cdsUidNumberString );
+	User::LeaveIfError( ret );
+
+	for( TInt i = 0; i < iConfigList.Count(); i++ )
+		{
+		SaveConfigParamL( iConfigList[i], sectName, i, persistConfigData );
+		}
+    CleanupStack::PopAndDestroy(&cdsUidNumberString);	
+
+	if( iObservationList.Count() > 0 )
+		{
+
+		//LOG_MSG( "  Saving Observed section\n");
+
+		// There is no point in saving the id of a thread since the id is not predictable 
+		// and could be used in another boot session. Thus only save the names
+		// EIniKeyValue holds Target Name EIniKeyType holds TargetOwnerName
+		// Thus a process will have both the same, so we can differentiate them
+		HBufC * iniStringTargetValue;
+		HBufC * iniStringOwnerType;
+
+		TPtrC observationSection;
+		observationSection.Set( KObservedConfig );
+		//LOG_MSG( "  persistConfigData->AddSection( KObservedConfig )\n" );
+		ret = persistConfigData->AddSection( observationSection );
+		User::LeaveIfError( ret );
+
+		TInt observeKey = 0;
+
+		for( TInt i = 0; i < iObservationList.Count(); i ++ )
+			{
+            CTargetObserver *observer = iObservationList[i];
+            TInt count = observer->ThreadCount();
+            TInt j = 0;
+            do
+                {
+                // Key string for target name
+                iniStringTargetValue = GenerateKeyStringLC( observeKey, EIniKeyValue );
+                TPtrC targetName;
+                if(count == 0) //whole process, no threads on list => targetName == targetOwnerName
+                    {
+                    targetName.Set(observer->TargetName());
+                    }
+                else
+                    {
+                    targetName.Set(observer->Thread(j));
+                    }
+
+                //LOG_MSG2( " iPersistConfigData->SetKey( KObservedConfig, target.Length()=%d )\n", targetName.Length() );
+                ret = persistConfigData->SetKey( observationSection, 
+                                                 iniStringTargetValue->Des(), 
+                                                 targetName );
+
+                CleanupStack::PopAndDestroy( iniStringTargetValue );
+                if( KErrNone != ret )
+                    {
+                    LOG_MSG2( "  ERROR !* iPersistConfigData->AddValue() for observed target returned %d\n", ret );
+                    User::Leave( ret );
+                    }
+
+                // Key string for target owner name
+                iniStringOwnerType = GenerateKeyStringLC( observeKey, EIniKeyType ); 
+                TPtrC targetOwnerName( observer->TargetName() );
+
+                LOG_MSG2( " iPersistConfigData->SetKey( KObservedConfig, targetOwner.Length()=%d )\n", targetOwnerName.Length() );
+                ret = persistConfigData->SetKey( observationSection, 
+                                                 iniStringOwnerType->Des(), 
+                                                 targetOwnerName );
+
+                CleanupStack::PopAndDestroy( iniStringOwnerType );
+                if( KErrNone != ret )
+                    {
+                    LOG_MSG2( "  ERROR !* iPersistConfigData->AddValue() for observed target owner returned %d\n", ret );
+                    User::Leave( ret );
+                    }
+
+                j++;
+				observeKey ++;
+
+                } while(j < count);
+
+			} //for(i)
+		}
+
+    TBuf<63> sectionName;
+
+
+    for(TInt i = 0; i < iFormatterPlugins.Count(); i++)
+    {
+        sectionName = KFormatterConfig;
+        sectionName.AppendFormat(_L("%d"), i);
+
+		ret = persistConfigData->AddSection( sectionName );
+        User::LeaveIfError(ret);
+
+
+   		// Add a key "UID" with a value equal to the UID of the writer, so we can load it again
+		RBuf uidNumberString;
+        uidNumberString.CleanupClosePushL();
+		uidNumberString.CreateL( 8 );
+		uidNumberString.AppendNumFixedWidth( (TUint)iFormatterInfos[i]->Uid(), EHex, 8 ); // Width = 8 chars
+		ret = persistConfigData->SetKey( sectionName, uidString, uidNumberString );
+		User::LeaveIfError( ret );
+        CleanupStack::PopAndDestroy(&uidNumberString);
+
+        TPtrC pairString;
+        pairString.Set( KPluginPair );
+
+        //Add pair key with value equal to the paired writer plugin
+		RBuf pairNumberString;
+        pairNumberString.CleanupClosePushL();
+		pairNumberString.CreateL( 8 );
+		pairNumberString.AppendNumFixedWidth( (TUint)iFormatterInfos[i]->Pair(), EHex, 8 ); // Width = 8 chars
+		ret = persistConfigData->SetKey( sectionName, pairString, pairNumberString );
+		User::LeaveIfError( ret );
+        CleanupStack::PopAndDestroy(&pairNumberString);
+
+   		for( TInt j = 0; j < iTotalConfigList.Count(); j++ )
+			{
+			if( iTotalConfigList[j] && (COptionConfig::EFormatterPlugin == iTotalConfigList[j]->Source()) && (i == iTotalConfigList[j]->Instance()))
+				{
+				SaveConfigParamL( iTotalConfigList[j], sectionName, iTotalConfigList[j]->Index(), persistConfigData );
+				}
+			}
+    }
+
+    for(TInt i = 0; i < iWriterPlugins.Count(); i++)
+    {
+        sectionName = KWriterConfig;
+        sectionName.AppendFormat(_L("%d"), i);
+
+		ret = persistConfigData->AddSection( sectionName );
+        User::LeaveIfError(ret);
+
+   		// Add a key "UID" with a value equal to the UID of the writer, so we can load it again
+		RBuf uidNumberString;
+        uidNumberString.CleanupClosePushL();
+		uidNumberString.CreateL( 8 );
+		uidNumberString.AppendNumFixedWidth( (TUint)iWriterInfos[i]->Uid(), EHex, 8 ); // Width = 8 chars
+		ret = persistConfigData->SetKey( sectionName, uidString, uidNumberString );
+		User::LeaveIfError( ret );
+        CleanupStack::PopAndDestroy(&uidNumberString);
+
+   		for( TInt j = 0; j < iTotalConfigList.Count(); j++ )
+			{
+			if( iTotalConfigList[j] && (COptionConfig::EWriterPlugin == iTotalConfigList[j]->Source()) && (i == iTotalConfigList[j]->Instance()))
+				{
+				SaveConfigParamL( iTotalConfigList[j], sectionName, iTotalConfigList[j]->Index(), persistConfigData );
+				}
+			}
+    }
+
+	if( NULL == persistConfigData )
+		{
+		LOG_MSG( "  persistConfigData == NULL\n" );
+		}
+
+	// Now save the config to file
+	ret = persistConfigData->Externalise( fileName->Des() );
+	//LOG_MSG2( "  <- iPersistConfigData->Externalise() returned %d\n", ret );
+
+	//LOG_MSG( "  CleanupStack::PopAndDestroy( iPersistConfigData )" );
+	CleanupStack::PopAndDestroy( persistConfigData );
+
+	//LOG_MSG( "  CleanupStack::PopAndDestroy( fileName )" );
+	CleanupStack::PopAndDestroy( fileName );
+
+	//LOG_MSG( "  ->CleanupStack::PopAndDestroy( fsSession )" );
+	CleanupStack::PopAndDestroy( & fsSession );
+	//LOG_MSG( "  <-CleanupStack::PopAndDestroy( fsSession )" );
+
+	}
+
+/*
+* Client request to load system configuration file
+*/
+void CCoreDumpSession::LoadConfigFileL( const RMessage2* aMessage )
+	{
+	
+
+	LOG_MSG( "CCoreDumpSession::LoadConfigFileL(RMessage2)" );
+
+	RFs	fsSession;
+	//LOG_MSG( "  User::LeaveIfError( fsSession.Connect() )\n" );
+	User::LeaveIfError( fsSession.Connect() );
+	CleanupClosePushL( fsSession );
+
+	TPtrC16 value;
+
+	HBufC * fileName = NULL;
+	CIniDocument16 * persistConfigData = NULL;
+
+	//LOG_MSG( "   -> CIniDocument16 * iPersistConfigData = OpenIniFileLC()" );
+	OpenIniFileLC( aMessage, EFalse, fsSession, fileName, persistConfigData );
+
+	//LOG_MSG( "   -> RecreateConfigurationL( iPersistConfigData )\n" );
+	RecreateConfigurationL( persistConfigData );
+
+	//LOG_MSG( "   -> CleanupStack::PopAndDestroy( iPersistConfigData )" );
+	CleanupStack::PopAndDestroy( persistConfigData );
+	//LOG_MSG( "   -> CleanupStack::PopAndDestroy( fileName )" );
+	CleanupStack::PopAndDestroy( fileName );
+	//LOG_MSG( "   -> CleanupStack::PopAndDestroy( & fsSession )" );
+	CleanupStack::PopAndDestroy( & fsSession );
+	//LOG_MSG( "   returning from CCoreDumpSession::LoadConfigFileL(RMessage2)" );
+	}
+
+
+/**
+Method used to load and unload the formatter and writer plugins as a pair.
+Also configures the data source and data save for the formatter.
+If unloading the UIDs are still checked.
+*/
+void CCoreDumpSession::SetPluginsL( const TUid aFormatterUID, 
+								  const TUid aWriterUID, 
+								  const TBool aLoad )
+	{
+	ValidatePluginL( aFormatterUID );
+
+	ValidatePluginL( aWriterUID );
+
+    /*
+	if( iFormatter )
+		{
+		delete iFormatter;
+		iFormatterUid = TUid::Uid(0);
+		}
+
+	if( iWriter )
+		{
+		delete iWriter;
+		iWriterUid = TUid::Uid(0);
+		}
+
+	if( !aLoad )
+		{
+		return;
+		}
+
+	// We push the plugins onto the cleanup stack since if we leave here we 
+	// want them destroyed so that there is always a valid pair or none are loaded
+	iWriter = CCrashDataSave::NewL( aWriterUID );
+	CleanupStack::PushL( iWriter );
+
+	iFormatter = CCoreDumpFormatter::NewL( aFormatterUID );
+	CleanupStack::PushL( iFormatter );
+
+	iFormatter->ConfigureDataSourceL( iDataSource );
+	iFormatter->ConfigureDataSaveL( iWriter );
+
+	iFormatterUid = aFormatterUID;
+	iWriterUid = aWriterUID;
+
+	// We can pop the plugins
+	CleanupStack::Pop( 2, iWriter );
+
+    */
+	}
+
+
+
+/**
+Look through the iPersistConfigData object (initialised from the ini file)
+and attempt to recreate the state described by the object.
+This means 
+ - unloading current plugins, 
+ - loading new plugins, 
+ - updating the configuration list by calling UpdateConfigParametersL()
+ - recreating the configuration for section (CDS, formatter, writer )
+
+We have to be lax about the errors since we do not want to stop the 
+loading of a configuration if there is a non-fatal error. This applies to 
+loading of the plugins.
+*/
+void CCoreDumpSession::RecreateConfigurationL( CIniDocument16 * iPersistConfigData )
+	{
+
+	// for each section in ini file, 
+	//  read section's SID
+	//  load plugins
+	//  for each (type, index, value) triplet, 
+	//    create a COptionConfig 
+	//    append to aIniFileConfigList
+	//
+
+
+	TInt ret;
+	TBool foundCdsSection = EFalse;
+	TBool foundFormatterSection = EFalse;
+	TBool foundWriterSection = EFalse;
+
+	TPtrC uidString;
+	uidString.Set( KUID );
+
+	// Recreate CDS section
+		{
+		TPtrC cdsUidString;
+		//LOG_MSG("  iPersistConfigData->GetKeyValue( KCDSConfig, uidString, cdsUidString )\n" );
+		ret = iPersistConfigData->GetKeyValue( KCDSConfig, uidString, cdsUidString );
+		//LOG_MSG2("  iPersistConfigData->GetKeyValue( ) returned %d\n", ret );
+
+		if( KErrNone == ret )
+			{
+			foundCdsSection = ETrue;
+			}
+		else
+			{
+			// It an error for there to be no saved CDS configuration 
+			User::Leave( ret );
+			}
+
+		if( foundCdsSection )
+			{
+			TLex cdsUidLex( cdsUidString );
+			TUint cdsUidValue;
+			cdsUidLex.Val( cdsUidValue, EHex );
+			TUid savedCdsUid = TUid::Uid( cdsUidValue );
+			//LOG_MSG2("  Found CDS Config Section with UID 0x%X\n", cdsUidValue );
+			//LOG_MSG2("  Current UID is 0x%X\n", iOurSecureID.iUid );
+			if( savedCdsUid != iOurSecureID )
+				{
+				// The UID for the CDS does not match our current CDS SID.
+				// This could arise if the config file was created by a previous version 
+				// of the CDS, but more likely we are reading a corrupt file.
+				// Thus the safe option is to leave
+				LOG_MSG2( "  ERROR !* Read CDS UID from ini file as 0x%X, which is not same as our current value\n",
+					cdsUidValue );
+				User::Leave( KErrCorrupt );
+				}
+			}//foundCdsSection
+		}
+
+    TBuf<63> sectionName;
+
+
+    foundWriterSection = -1;
+    for(TInt i = 0;;i++)
+    {
+        sectionName = KWriterConfig;
+        sectionName.AppendFormat(_L("%d"), i);
+
+		TPtrC writerUidString;
+		ret = iPersistConfigData->GetKeyValue( sectionName, uidString, writerUidString );
+
+   		TUint writerUidValue;
+		if( KErrNone == ret )
+			{
+            foundWriterSection++;
+			TLex writerUidLex( writerUidString );
+			writerUidLex.Val( writerUidValue, EHex );
+			CreateWriterL( TUid::Uid( writerUidValue ) );
+			}
+		else
+			{
+                break;
+			}
+
+    } 
+
+
+    foundFormatterSection = -1;
+    for(TInt i = 0;;i++)
+    {
+        sectionName = KFormatterConfig;
+        sectionName.AppendFormat(_L("%d"), i);
+
+		TPtrC formatterUidString;
+		ret = iPersistConfigData->GetKeyValue( sectionName, uidString, formatterUidString );
+
+   		TUint formatterUidValue;
+		if( KErrNone == ret )
+			{
+			foundFormatterSection++;
+			TLex fromatterUidLex( formatterUidString );
+			fromatterUidLex.Val( formatterUidValue, EHex );
+			CreateFormatterL( TUid::Uid( formatterUidValue ) );
+
+            TPtrC pairString;
+            pairString.Set( KPluginPair );
+            TPtrC formatterPairString;
+            ret = iPersistConfigData->GetKeyValue(sectionName, pairString, formatterPairString);
+            if(ret == KErrNone)
+                {
+			    TLex fromatterPairLex( formatterPairString );
+                TUint formatterPairValue;
+			    fromatterPairLex.Val( formatterPairValue, EHex );
+                BindPluginsL(i, formatterPairValue);
+                }
+            }
+		else
+			{
+                break;
+			}
+
+    }
+
+    
+	// Now that the old plugins are unloaded (if a new one was specified in the ini file),
+	// and the new ones loaded, reconstruct the list of configuration parameters. 
+	// We will then change them with the ini file values that we are about to read.
+	// For plugins that have not been unloaded (because there was no mention in the init file)
+	// we will simply ask for the config params again, and we should get the current values.
+
+	UpdateConfigParametersL();
+
+	if( foundCdsSection )
+		{
+		//LOG_MSG( "  -> ChangeConfigParamsL( COptionConfig::ECoreDumpServer\n" );
+		ChangeConfigParamsL( COptionConfig::ECoreDumpServer, iPersistConfigData );
+		}
+
+    for(TInt i = 0; i <= foundFormatterSection; i++)
+		{
+		//LOG_MSG( "  -> ChangeConfigParamsL( COptionConfig::EFormatterPlugin\n" );
+		ChangeConfigParamsL( COptionConfig::EFormatterPlugin, iPersistConfigData, foundFormatterSection );
+		}
+
+    for(TInt i = 0; i <= foundWriterSection; i++)
+		{
+		//LOG_MSG( "  -> ChangeConfigParamsL( COptionConfig::EWriterPlugin\n" );
+		ChangeConfigParamsL( COptionConfig::EWriterPlugin, iPersistConfigData, foundWriterSection );
+		}
+
+	// Now rebuild the Observed list from the file
+		{
+
+		//LOG_MSG( "  About to Rebuild Observed Target List from Ini File\n" );
+		
+		HBufC * iniTargetValue;
+		HBufC * iniOwnerType;
+		TInt observeIndex = 0;
+		TBool targetFound = ETrue;
+		while( targetFound )
+			{
+
+			// Each value obtained via EIniKeyIndex from the file is the CConfigOption index 
+			// and is used to tie the saved to the live index.
+
+			//LOG_MSG2("  GenerateKeyStringLC( EIniKeyValue =%d)\n", observeIndex );
+			iniTargetValue = GenerateKeyStringLC( observeIndex, EIniKeyValue );
+
+			TPtrC observeTargetValue;
+
+			//LOG_MSG("  iPersistConfigData->GetKeyValue( KObservedConfig, targetName )\n" );
+			ret = iPersistConfigData->GetKeyValue( KObservedConfig, 
+													iniTargetValue->Des(), 
+													observeTargetValue );
+			//LOG_MSG2("  iPersistConfigData->GetKeyValue( ) returned %d\n", ret );
+
+			CleanupStack::PopAndDestroy( iniTargetValue );
+		
+			if( KErrNone != ret )
+				{
+				LOG_MSG2( "  Could not find a target : FindVar(EIniKeyValue) index %d returned false\n", 
+					observeIndex );
+				break;
+				}
+
+			//LOG_MSG2("  GenerateKeyStringLC( EIniKeyType =%d)\n", observeIndex );
+			iniOwnerType = GenerateKeyStringLC( observeIndex, EIniKeyType );
+
+			TPtrC observeTargetOwner;
+
+			/*
+			LOG_MSG3( "  ->FindVar( KObservedConfig, target owner %d. iniOwnerType.Length()=%d\n", 
+				observeIndex, iniOwnerType->Des().Length() );
+			*/
+
+			ret = iPersistConfigData->GetKeyValue( KObservedConfig, 
+													iniOwnerType->Des(), 
+													observeTargetOwner );
+			//LOG_MSG2("  iPersistConfigData->GetKeyValue( ) returned %d\n", ret );
+
+			CleanupStack::PopAndDestroy( iniOwnerType );
+
+			if( KErrNone != ret )
+				{
+				LOG_MSG2( "  Could not find a target owner: FindVar(EIniKeyValue) index %d returned false\n", 
+					observeIndex );
+				break;
+				}
+
+			//LOG_MSG("  Creating observation request\n" );
+
+            AttachTargetL(observeTargetValue, observeTargetOwner);
+
+			observeIndex++;
+			
+			}// while targetFound
+
+		} // Now rebuild the Observed list from the file
+
+	//LOG_MSG( "  <- returning from RecreateConfigurationL()\n" );
+
+	}
+
+
+/**
+Method that reads the saved configuration and attempts to recreate that state.
+For a given section of the ini file (indicated by the parameter aSource), 
+recreate each parameter from a triplet of settings (index, type, value) 
+and then apply the setting by calling SetConfigParameterL().
+
+@param aSource Section of the config file to read and update state for. 
+@param aPersistConfigData Pointer to CIniDocument16 object that contains 
+the parameters to restore
+
+@see CIniDocument16 
+*/
+void CCoreDumpSession::ChangeConfigParamsL( const COptionConfig::TParameterSource aSource,
+										  CIniDocument16 * aPersistConfigData, const TInt aInstance)
+	{
+
+	//LOG_MSG2( "ChangeConfigParamsL( source=%d )\n", aSource );
+
+	TPtrC sectName;
+	TInt ret = KErrNone;
+
+	switch(  aSource )
+		{
+		case COptionConfig::ECoreDumpServer:
+			sectName.Set( KCDSConfig );
+			break;
+		case COptionConfig::EFormatterPlugin:
+			sectName.Set( KFormatterConfig );
+			break;
+		case COptionConfig::EWriterPlugin:
+			sectName.Set( KWriterConfig );
+			break;
+		default:
+			User::Leave( KErrArgument );
+		}
+
+
+	HBufC * iniStringKey;
+	TUint index = 0;
+
+	// Loop to recreate all the parameters for a given section and then 
+	// call SetConfigParameterL() for each parameter
+	// As soon as one of the FindVar fails, we assume that there are no more entries for
+	// this section, and thus give up.
+
+	// Parameter index
+	TInt keyIndex;
+
+	// Parameter type
+	TInt keyType;
+
+	// Parameter integer value
+	TInt keyIntValue;
+	
+	TLex paramLex;
+
+	while( KErrNone == ret )
+		{
+
+		keyIndex = ELastParam;
+		keyType = -1;
+		keyIntValue = 0;
+		TPtrC keyStringValue;
+
+		// Get parameter index
+			{
+			// Each value obtained via EIniKeyIndex from the file is the CConfigOption index 
+			// and is used to tie the saved to the live index.
+			//LOG_MSG2("  ->GenerateKeyStringLC( index=%d, EIniKeyIndex )\n", index );
+			iniStringKey = GenerateKeyStringLC( index, EIniKeyIndex );
+			TPtrC keyIndexString;
+
+			//LOG_MSG("  ->aPersistConfigData->GetKeyValue( EIniKeyIndex )\n" );
+			ret = aPersistConfigData->GetKeyValue( sectName, iniStringKey->Des(), keyIndexString );
+			CleanupStack::PopAndDestroy( iniStringKey );
+			if( KErrNone != ret )
+				{
+				LOG_MSG3("  aPersistConfigData->GetKeyValue( EIniKeyIndex ) returned %d for index %d\n", ret, index );
+				break;
+				}
+			
+			paramLex.Assign( keyIndexString );
+			keyIndex = 0;
+			paramLex.Val( keyIndex );
+			//LOG_MSG2( "  found EIniKeyIndex =%d\n", keyIndex );
+			}
+
+
+		// Get parameter type
+			{
+
+			//LOG_MSG2("  ->GenerateKeyStringLC( index=%d, EIniKeyType )\n", index );
+			iniStringKey = GenerateKeyStringLC( index, EIniKeyType );
+			TPtrC keyTypeString;
+			
+			//LOG_MSG("  ->aPersistConfigData->GetKeyValue( EIniKeyType )\n" );
+			ret = aPersistConfigData->GetKeyValue( sectName, iniStringKey->Des(), keyTypeString );
+			CleanupStack::PopAndDestroy( iniStringKey );
+			if( KErrNone != ret )
+				{
+				LOG_MSG3("  aPersistConfigData->GetKeyValue( EIniKeyType ) returned %d for index %d\n", ret, index );
+				break;
+				}
+
+			paramLex.Assign( keyTypeString );
+			paramLex.Val( keyType );
+			//LOG_MSG2( "  found EIniKeyType =%d\n", keyType );
+			}
+
+		// Get parameter value
+			{
+
+			//LOG_MSG2("  ->GenerateKeyStringLC( index=%d, EIniKeyValue )\n", index );
+			iniStringKey = GenerateKeyStringLC( index, EIniKeyValue );
+
+			//LOG_MSG( "  aPersistConfigData->GetKeyValue( EIniKeyValue )\n" );
+			ret = aPersistConfigData->GetKeyValue( sectName, iniStringKey->Des(), keyStringValue );
+			
+			//LOG_MSG2( "  aPersistConfigData->GetKeyValue( EIniKeyValue ) returned string with length=%d\n", keyStringValue.Length() );
+			CleanupStack::PopAndDestroy( iniStringKey );
+			if( KErrNone != ret )
+				{
+				LOG_MSG3("  aPersistConfigData->GetKeyValue( EIniKeyValue ) returned %d for index %d\n", ret, index );
+				break;
+				}
+
+			switch( (COptionConfig::TOptionType) keyType )
+				{
+				case COptionConfig::ETInt:
+				case COptionConfig::ETUInt:
+				case COptionConfig::ETBool:
+					paramLex.Assign( keyStringValue );
+					paramLex.Val( keyIntValue );
+					keyStringValue.Set( KNullDesC );
+					break;
+				}
+			}
+
+
+			/*
+			{
+			if( -1 != keyIntValue )
+				{
+				LOG_MSG2( "  found EIniKeyValue as Int =%d\n", keyIntValue );
+				}
+
+			RBuf value;
+			value.Create( keyStringValue );
+			char* cl = (char*) value.Collapse().PtrZ();
+			RDebug::Printf("  found EIniKeyValue as String =%s\n", cl );
+			}
+			*/
+
+		LOG_MSG3( "  SetConfigParameterL( value=%d, string length=%d\n", keyIntValue, keyStringValue.Length() );
+
+		switch(  aSource )
+			{
+
+			case COptionConfig::ECoreDumpServer:
+				SetConfigParameterL( keyIndex, keyIntValue, keyStringValue );
+				break;
+
+			case COptionConfig::EFormatterPlugin:
+
+				if( (iFormatterPlugins.Count() > 0 ) && (iFormatterPlugins.Count() < aInstance) )
+					{
+					iFormatterPlugins[aInstance]->SetConfigParameterL( keyIndex, keyIntValue, keyStringValue );
+					}
+				else
+					{
+					LOG_MSG2("CCoreDumpSession::ChangeConfigParamsL() : formatter:%d not loaded\n", aInstance);
+					User::Leave( KErrArgument );
+					}
+				break;
+
+			case COptionConfig::EWriterPlugin:
+
+				if( (iWriterPlugins.Count() > 0 ) && (iWriterPlugins.Count() < aInstance) )
+					{
+					iWriterPlugins[aInstance]->SetConfigParameterL( keyIndex, keyIntValue, keyStringValue );
+					}
+				else
+					{
+					LOG_MSG2("CCoreDumpSession::ChangeConfigParamsL() : writer:%d not loaded\n", aInstance);
+					User::Leave( KErrArgument );
+					}
+				break;
+
+			default:
+				User::Leave( KErrArgument );
+			}
+		
+		index ++;
+		}//while
+	}
+
+
+_LIT(KKey,"Key");
+_LIT(KType,"Type");
+_LIT(KIndex,"Index");
+_LIT(KValue,"Value");
+
+/**
+This method allocates a string of two concatenated components. The first component is based on 
+the parameter aKey. The second component is the string representation of aIndex.
+Thus it maps an enum to a string and then it appends the index. The string is left on the 
+cleanup stack and it is the responsibility of the caller to remove it from the cleanup stack.
+*/
+HBufC * CCoreDumpSession::GenerateKeyStringLC( TUint aIndex, 
+										 CCoreDumpSession::TCoreDumpIniKey aKey )
+	{
+
+	HBufC * keyString = HBufC::NewL( 20 );
+	CleanupStack::PushL( keyString );
+
+	TPtr ptr = keyString->Des();
+	ptr.Append( KKey );
+
+	switch( aKey )
+		{
+		case EIniKeyType:
+			ptr.Append( KType );
+			break;
+
+		case EIniKeyIndex:
+			ptr.Append( KIndex );
+			break;
+
+		case EIniKeyValue:
+			ptr.Append( KValue );
+			break;
+		}
+
+	ptr.AppendNum( aIndex );
+	return keyString;
+	}
+
+void CCoreDumpSession::SuspendProcessL(TUint64 aPid)
+    {
+    LOG_MSG("->CCoreDumpSession::SuspendProcessL()\n");
+    iDataSource->GetThreadListL( aPid, iThreadPointerList, iTotalThreadListDescSize );
+    TInt err = KErrNone;
+    for(TInt i = 0; i < iThreadPointerList.Count(); i++)
+        {
+        LOG_MSG2("CCoreDumpSession::SuspenProcessL - suspending thread:%Ld\n", iThreadPointerList[i]->Id());
+        err = iSecSess.SuspendThread(iThreadPointerList[i]->Id());
+            if( (err != KErrNone) && (err != KErrAlreadyExists) )
+            {
+            LOG_MSG2("CCoreDumpSession::SuspendProcessL - unable to suspend thread! err:%d\n", err); 
+            User::LeaveIfError(err);
+            }
+        } 
+    }
+
+void CCoreDumpSession::ResumeThreadL(TUint64 aTid)
+{
+    LOG_MSG2("->CCoreDumpSession::ResumeThreadL(aTid=%Ld)\n", aTid);
+
+    TInt err = iSecSess.ResumeThread(TThreadId(aTid));
+    if(err != KErrNone)
+        {
+        LOG_MSG2("CCoreDumpSession::ResumeThreadL - unable to resume thread! err:%d\n", err); 
+        User::LeaveIfError(err);
+        }
+}
+
+/**
+Called to resume all the threads of the specified process. CCoreCrashHandler executes it as a post-processing action.
+@param aPid ID of process to be resumed
+@leave err one of the system wide error codes
+@see SuspendProcessL
+*/
+void CCoreDumpSession::ResumeProcessL(TUint64 aPid)
+	{
+    LOG_MSG2("->CCoreDumpSession::ResumeProcessL(aPid=%Ld)\n", aPid);
+
+    iDataSource->GetThreadListL( aPid, iThreadPointerList, iTotalThreadListDescSize );
+
+    TInt err = KErrNone;
+    //first resume child threads
+    TInt looperr = KErrNone;
+    for(TInt j = 1; j < iThreadPointerList.Count(); j++)
+        {
+        LOG_MSG2("CCoreDumpSession::ResumeProcessL - resuming thread:%Ld\n", iThreadPointerList[j]->Id());
+        looperr = iSecSess.ResumeThread( iThreadPointerList[j]->Id() );
+        if( (looperr != KErrNone) && (looperr != KErrNotFound) )
+            {
+            err = looperr;
+            LOG_MSG2("CCoreDumpSession::ResumeProcessL - unable to resume thread! err:%d\n", err);
+            }
+        }
+
+    looperr = KErrNone;
+    //then resume the main thread
+    if(iThreadPointerList.Count())
+        {
+        LOG_MSG2("CCoreDumpSession::ResumeProcessL - resuming main thread:%Ld\n", iThreadPointerList[0]->Id());
+        looperr = iSecSess.ResumeThread(iThreadPointerList[0]->Id());
+        }
+
+    if( (looperr != KErrNone) && (looperr != KErrNotFound) )
+        {
+        err = looperr;
+        LOG_MSG2("CCoreDumpSession::ResumeProcessL - unable to resume main thread! err:%d\n", err); 
+        }
+
+    User::LeaveIfError(err);
+	}
+
+
+void CCoreDumpSession::KillProcessL(TUint64 aPid)
+    {
+    LOG_MSG2("->CCoreDumpSession::KillProcessL(aPid=%Ld)\n", aPid);
+    RProcess target;
+    //LOG_MSG("CCoreDumpSession::KillProcessL - opening crashed process handle\n"); 
+    TInt err = target.Open(aPid);
+    if(err != KErrNone)
+    {
+        LOG_MSG2("CCoreDumpSession::KillProcessL - unable to open process handle! err:%d\n", err); 
+        User::Leave(err);
+    }
+
+    CleanupClosePushL(target);
+
+    TInt i;
+    for(i = 0; i < iObservationList.Count(); i++)
+        {
+        if(iObservationList[i]->TargetName().CompareF(target.FileName()) == 0) break;
+        }
+
+    ResumeProcessL(aPid);
+
+    if(i == iObservationList.Count())
+        {
+        LOG_MSG("CCoreDumpSession::KillProcessL - unable to find process observer!\n");
+        User::Leave(KErrNotFound);
+        }
+
+	LOG_MSG("  -> SetCrashEventsL(*iObservationList[i], EActionIgnore)\n" ); 
+    SetCrashEventsL(*iObservationList[i], EActionIgnore);
+
+	LOG_MSG("  -> target.Terminate(KErrAbort)\n" ); 
+    target.Terminate(KErrAbort);
+	
+	TRequestStatus logonStatus;
+	LOG_MSG("  -> target.Logon( logonStatus );\n" ); 
+	target.Logon( logonStatus );
+	LOG_MSG("  <- target.Logon( logonStatus );\n" ); 
+
+	CleanupStack::PopAndDestroy(&target); //target
+
+	User::WaitForRequest( logonStatus );
+	LOG_MSG("  <- User::WaitForRequest( logonStatus );\n" ); 
+	
+
+    if( (iPreCrashEventAction & ESuspendThread) || 
+		(iPreCrashEventAction & ESuspendProcess) )
+        SetCrashEventsL(*iObservationList[i], EActionSuspend);
+    else
+        SetCrashEventsL(*iObservationList[i], EActionContinue);
+    }
+
+/**
+ * Cleanup item implementation for SCMConfiguration
+*/
+void CCoreDumpSession::CleanupSCMConfiguration(TAny* aScmConfig)
+	{
+	SCMConfiguration* config = static_cast<SCMConfiguration*> (aScmConfig);
+	delete config;
+	config = NULL;
+	}
+
+
+//void CCoreDumpSession::ReadSCMConfigListL()
+//	{	
+//	// read the config data from the flash data source	
+//	}
+//
+//void CCoreDumpSession::WriteSCMConfigListL()
+//	{	
+//	// read the config data from the flash data source	
+//	iFlashDataSource->WriteSCMConfigL();	
+//	}
+//
+