Пример #1
0
/**
 * Given a thread ID, return a handle to the corresponding DThread. If the returned
 * pointer is non-NULL, it is the responsibility of the caller to close the handle.
 * 
 * @pre caller must be in thread critical section
 * @post if a non-NULL value is returned then a handle to the thread has been
 * opened on the callers behalf
 * @param aThreadId ID of the thread to return a handle for
 * @return a DThread* to the appropriate thread, or NULL if a handle could not be
 * opened to the specified thread
 */
DThread* DebugUtils::OpenThreadHandle(TUint64 aThreadId)
	{
	__ASSERT_CRITICAL;
	LOG_MSG2("DebugUtils::OpenThreadHandle(0x%lx)", aThreadId);

	DObjectCon& threads = *Kern::Containers()[EThread];  // Get containing holding threads
	threads.Wait();  // Obtain the container mutex so the list does get changed under us

	DThread* thread = Kern::ThreadFromId(aThreadId);

	// Open a handle to the thread so that it doesn't exit while we are processing
	if (thread)
		{
		// if opening a handle fails then set thread to NULL
		if(KErrNone != thread->Open())
			{
			LOG_MSG2("\tCould not open handle to thread %d", (TUint32)aThreadId);
			thread = NULL;
			}
		}
	else
		{
		LOG_MSG2("\tThread with ID %d is NULL", (TUint32)aThreadId);
		}

	threads.Signal();  // Release the container mutex

	return thread;
	}
// RunL() completes a previously issued Observe call 
void CTargetObserver::RunL()
	{
    LOG_MSG2("->CTargetObserver::RunL(status:%d)", iStatus.Int());
	User::LeaveIfError(iStatus.Int()); //something bad happened

    iCrashEventInfo.iEventTime.UniversalTime(); //not 100% exact time of the crash, but as soon as we are notified about it

    Observe(); 

    RThread thread;
    LOG_MSG2("CTargetObserver::RunL() - opening handle to crashed thread:%Lu\n", iCrashEventInfo.iThreadId);
    TInt err = thread.Open(iCrashEventInfo.iThreadId);
    if(err != KErrNone)
        {
        LOG_MSG2("CTargetObserver::RunL - unable to open thread handle! err:%d\n", err); 
        User::Leave(err);
        }
    CleanupClosePushL(thread); 
    
    if( (iThreadList.Count() == 0) || (HasThread(thread.FullName())) )
        {
        //crash event of the whole process or thread that we observe
        LOG_MSG("CTargetObserver::RunL() -> HandleCrashEventL()");
        iHandler.HandleCrashEventL(iCrashEventInfo);
        }
    else //crash event of thread that we don't care about
        {
        LOG_MSG("CTargetObserver::RunL() - resuming crashed thread");
        iSecSess.ResumeThread(iCrashEventInfo.iThreadId);
        }
    CleanupStack::PopAndDestroy(); //thread

	}
Пример #3
0
/**
 * Given a process ID, return a handle to the corresponding DProcess. If the returned
 * pointer is non-NULL, it is the responsibility of the caller to close the handle.
 * 
 * @post if a non-NULL value is returned then a handle to the process has been
 * opened on the callers behalf
 * @param aProcessId ID of the process to return a handle for
 * @return a DProcess* to the appropriate process, or NULL if a handle could not be
 * opened to the specified process
 */
DProcess* DebugUtils::OpenProcessHandle(const TUint64 aProcessId)
	{
	// Commenting out this message as it gets printed out every time a RDebug::Printf statement is caught by the driver,
	// which makes looking at the serial cable output irritating. Replaced it with LOG_MSG statements below to indicate if
	// something amiss happened. By default then this function prints nothing out.
	//LOG_MSG("DebugUtils::OpenProcessHandle()");

	NKern::ThreadEnterCS();  // Prevent us from dying or suspending whilst holding a DMutex
	DObjectCon& processes = *Kern::Containers()[EProcess];  // Get containing holding threads
	processes.Wait();  // Obtain the container mutex so the list does get changed under us

	DProcess* process = Kern::ProcessFromId(aProcessId);

	// Open a handle to the process so that it doesn't exit while we are processing
	if (process)
		{
		// if opening a handle fails then set process to NULL
		if(KErrNone != process->Open())
			{
			LOG_MSG2("DebugUtils::OpenProcessHandle(): Could not open handle for 0x%lx", aProcessId);
			process = NULL;
			}
		}
	else
		{
		LOG_MSG2("DebugUtils::OpenProcessHandle(): Could not find process for 0x%lx", aProcessId);
		}

	processes.Signal();  // Release the container mutex
	NKern::ThreadLeaveCS();  // End of critical section

	return process;
	}
Пример #4
0
//
// DTrkXtiChannel::DoControl
//
TInt DTrkXtiChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
{
	LOG_MSG("DTrkXtiChannel::DoControl()");
	
	TInt err = KErrNone;
	
	switch(aFunction)
	{
		case RTrkXtiDriver::EControlWrite:
		{
			//lock the Semaphore so that write doesn't happen when a write is already in progress.
			Kern::SemaphoreWait(*iLock);
			err = DoWrite((TUint32)a1, a2);			
			Kern::SemaphoreSignal(*iLock);			
			break;
		}
		default:
		{
			return KErrGeneral;
		}

	}
	if (KErrNone != err)
	{
		LOG_MSG2("Error %d from control function", err);
	}
	return err;
}
void CTestCrashDataSource::GetThreadListL( const TUint32 aProcessId, 
									RThreadPointerList & aThreadList,
									TUint & aTotalThreadListDescSize )
	{

	RDebug::Print( _L("CTestCrashDataSource::GetThreadList( pId=0x%X)\n"), aProcessId );



	LOG_MSG2( "CTestCrashDataSource::GetThreadListL( pId=0x%X)\n", aProcessId );

	aThreadList.ResetAndDestroy();
	aTotalThreadListDescSize = 0;

        for(TInt i =0; i < KCrashThreadsCount; ++i)
        {
            CThreadInfo *thread = CThreadInfo::NewL( KCrashTid + i,
                                        KCrashThreadName,
                                        KCrashPid,
                                        KCrashThreadPriority + i,
                                        KCrashSvcStackPtr + i,
                                        KCrashSvcStackAddr + i,
                                        KCrashSvcStackSize + i,
                                        KCrashUsrStackAddr + i,
                                        KCrashUsrStackSize + i);
            aThreadList.Append(thread);
            //delete thread;
        }

	}
void CServerCrashDataSource::GetExecutableListL( RExecutablePointerList & aExecutableList,
											  TUint & aTotalExecutableListDescSize )
    {
	LOG_MSG( "CServerCrashDataSource::GetExecutableListL()\n" );

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

	if( iExecutableListBuffer.Size() != iLastExecutableListSize )
		{
		LOG_MSG2( "  iExecutableListBuffer.ReAlloc( %d)\n", iLastExecutableListSize );
		iExecutableListBuffer.ReAllocL( iLastExecutableListSize );
		}

	DoGetListL( EExecutables, (TUint)(-1), (TUint)(-1), iExecutableListBuffer, iLastExecutableListSize );

	iLastExecutableListSize = iExecutableListBuffer.Size();

	TUint8* ptr = (TUint8*)( iExecutableListBuffer.Ptr() );
	const TUint8* ptrEnd = ptr + iLastExecutableListSize;
	//LOG_MSG3( "  Data start,end=(0x%x, 0x%x)\n", ptr, ptrEnd );

	while( ptr < ptrEnd ) 
		{

	    TExecutablesListEntry *entry = (TExecutablesListEntry*)ptr;

		if( !entry )
			{
			LOG_MSG( "  ERROR !* : TExecutablesListEntry is NULL\n" );
			User::Leave(KErrBadHandle);
			}

		if( entry->iNameLength == 0 )
			{
			LOG_MSG( "  Skipping executable : entry->iNameLength=0" );
			ptr += Align4( entry->GetSize() );
			continue;
			}

        TPtrC entryName(&(entry->iName[0]), entry->iNameLength);
       
        CExecutableInfo *executableInfoPtr = 
			CExecutableInfo::NewL(entryName, entry->iIsActivelyDebugged, entry->iIsPassivelyDebugged );

		TInt err = aExecutableList.Append( executableInfoPtr );
        if(err != KErrNone)
            {
            delete executableInfoPtr;
            User::Leave(err);
            }

		aTotalExecutableListDescSize += executableInfoPtr->Size();

		ptr += Align4( entry->GetSize() );
		}
	}
void CServerCrashDataSource::DoGetListL(const TListId aListId, 
										const TThreadId aThreadId,
										const TProcessId aProcessId,
										RBuf8 & aBuffer, 
										TUint32 & aSize )
	{

	LOG_MSG5( "->CServerCrashDataSource::DoGetList(aListId=%d, aThredId=%Lu, aProcessId=%Lu, aSize=%d\n", aListId, aThreadId.Id(), aProcessId.Id(), aSize );

	TInt ret;
	TListLevel listLevel;

	if( ((TUint)-1 == (TUint)aThreadId) && ((TUint)-1 == (TUint)aProcessId) )
		{
		listLevel = EListGlobal;
		ret = iSecSess.GetList( aListId, aBuffer, aSize );
		}
	else if( ((TUint)-1 != (TUint)aThreadId) && ((TUint)-1 == (TUint)aProcessId) )
		{
		listLevel = EListThread;
        LOG_MSG("CServerCrashDataSource::DoGetList - EListThread");
		ret = iSecSess.GetList( aThreadId, aListId, aBuffer, aSize );
		}
	else
		{
		listLevel = EListProcess;
        LOG_MSG("CServerCrashDataSource::DoGetList - EListProcess");
		ret = iSecSess.GetList( aProcessId, aListId, aBuffer, aSize );
		}
		 
	while( KErrTooBig == ret )
		{
		LOG_MSG2( "CServerCrashDataSource::DoGetListL - list too big, new size=%d\n", aSize );

		// Too big, and aSize should have been modified to the required new size
		// Since the list could have increased in size between calls, give it an 
		// extra margin.
		aSize += 256;

		aBuffer.ReAllocL( aSize );

		if( EListGlobal == listLevel )
			{
			ret = iSecSess.GetList( aListId, aBuffer, aSize );
			}
		else if( EListThread == listLevel )
			{
			ret = iSecSess.GetList( aThreadId, aListId, aBuffer, aSize );
			}
		else
			{
			ret = iSecSess.GetList( aProcessId, aListId, aBuffer, aSize );
			}

		}
    User::LeaveIfError(ret);
	}
void CTargetObserver::DoCancel()
	{
	LOG_MSG( "CTargetObserver::DoCancel -> CancelGetEvent\n");
    TInt err = iSecSess.CancelGetEvent( iTargetName );
    if(err != KErrNone)
        {
        LOG_MSG2( "CTargetObserver::DoCancel - iSecSess.DetachExecutable returned:%d!", err);
        //panic client?? close DSS session?? 
        }

	LOG_MSG("CTargetObserver::DoCancel -> iSecSess.DetachExecutable\n");
    err = iSecSess.DetachExecutable( iTargetName );
    if(err != KErrNone)
        {
        LOG_MSG2( "CTargetObserver::DoCancel iSecSess.DetachExecutable returned:%d!\n", err);
        //panic client?? close DSS session?? 
        }
	}
Пример #9
0
void CProcessPair::ConstructL(const TDesC& aProcessName, const TProcessId aProcessId)
	{
	//allocate the process name buffer and fill with aProcessName
	iProcessName = aProcessName.Alloc();
	if(iProcessName == NULL)
		User::Leave(KErrNoMemory);

	LOG_MSG2( "CProcessPair::ConstructL() process name: %S", &TPtr8((TUint8*)iProcessName->Ptr(), 2*iProcessName->Length(), 2*iProcessName->Length()) );

	//set process id
	iProcessId = aProcessId;
	}
Пример #10
0
int main( int argc, char* argv[] )
{
	int nResult = INVALID_RESULT;
	START_FUNCTION();

	if( argc < 2 ) {
		LOG_ERROR( "Message should not be empty" );
		usage();
	}
	string sMessage = argv[ 1 ], sTitle = szDefaultTitle;

	size_t nSeverity = nDefaultSeverity;
	string sServer = szDefaultServer, sPluginPath = szDefaultPluginPath;
	for( int idx = 2; idx < argc; ++idx )
	{
		const char* szParam = argv[ idx ];
		if( *szParam == '-' || *szParam == '/' )
		{
			switch( szParam[1] )
			{
			case 's':
				if( ++idx == argc ) usage();
				sServer = argv[ idx ];
				break;
			case 'p':
				if( ++idx == argc ) usage();
				sPluginPath = argv[ idx ];
				break;
			case 't':
				if( ++idx == argc ) usage();
				sTitle = argv[ idx ];
				break;
			case 'e':
				if( ++idx == argc ) usage();
				nSeverity = atol( argv[ idx ] );
				break;
			}
		}
	}

	if( nSeverity <= 0 || nSeverity > 3 ) nSeverity = 1;

	string sHttpQuery;
	FormatString( sHttpQuery, szFormat, sServer.c_str(), sPluginPath.c_str(), 
		HttpUtils::HttpEncode(sMessage).c_str(), HttpUtils::HttpEncode(sTitle).c_str(), nSeverity );

	string sResponse;
	if( !HttpUtils::DownloadPage(sHttpQuery, sResponse) ) break;
	LOG_MSG2( "%s", sResponse.c_str() );

	END_FUNCTION_RET( nResult );
}
GLDEF_C TInt E32Main()
	{
	LOG_MSG("ENTER: Multi_agent_launcher E32Main()");
	__UHEAP_MARK;

	CTrapCleanup* trap = CTrapCleanup::New();
	if (!trap)
		return KErrNoMemory;

	TRAPD(err, MainL());
	LOG_MSG2("Multi_agent_launcher: returning from MainL(), err = %d", err);
	
	delete trap;
	LOG_MSG("EXIT: Multi_agent_launcher E32Main()");
	__UHEAP_MARKEND;

	return err;
	}
Пример #12
0
/*
* Symbian OS 2nd stage construction. Called from CCoreDumpServer::NewLC()
*/	
void CCoreDumpServer::ConstructL()
	{
	//LOG_MSG("->CCoreDumpServer::ConstructL()\n" );

	TInt err = iSecSess.Connect( securityServerVersion );

	if( KErrNone != err )
		{
		_LIT( KDssStartErrorMsg ,"Core Dump Server: Unable to Start/Connect to Debug Security Server");
		User::InfoPrint( KDssStartErrorMsg );

		LOG_MSG2("CCoreDumpServer::ConstructL() - unable to open security server session! err:%d\n", err);
		User::Leave(err);
		}

    err = iSecSess.ShareAuto();
    
	StartL( KCoreDumpServerName );
	} 
void CServerCrashDataSource::ReadRegistersL( const TUint64 aThreadId, RRegisterList  & aRegisterList )
	{

	LOG_MSG2("CServerCrashDataSource::ReadRegistersL(aThreadId=%Lu)\n", aThreadId);

	if( aRegisterList.Count() )
		{
		LOG_MSG("CServerCrashDataSource::ReadRegistersL - register list already supplied\n" );
		SetRegValuesL( aThreadId, aRegisterList );
		}
	else
		{
		LOG_MSG("CServerCrashDataSource::ReadRegistersL - suppliying register list\n" );
		GetRegisterListL( aRegisterList );
		SetRegValuesL( aThreadId, aRegisterList );
		}

	//PrintRegs( aRegisterList );
	}
/**
 * Launch a process
 * @param aProcess the RProcess object used for creating the process
 * @param aExeName the name of the executable to run 
 * @param aCommandLine command line parameters to pass when creating the process 
 * @return KErrNone on success, or one of the other system wide error codes
 */
TInt LaunchProcess(RProcess& aProcess, TDesC& aExeName, TDesC& aCommandLine )    
	{
	LOG_MSG("ENTER: t_multi_agent_launcher: launchProcess"); 

	LOG_MSG2("aExeName %S ", &TPtr8((TUint8*)aExeName.Ptr(), 2*aExeName.Length(), 2*aExeName.Length()));
	LOG_MSG2("aCommandLine %S", &TPtr8((TUint8*)aCommandLine.Ptr(), 2*aCommandLine.Length(), 2*aCommandLine.Length()));

	TInt err = aProcess.Create( aExeName, aCommandLine );
	LOG_MSG2("t_multi_agent_launcher launchProcess, aProcess.Create err = %d", err); 

	// check that there was no error raised
	if(err != KErrNone)
		{
		return err;
		}

	// rendezvous with process
	TRequestStatus status = KRequestPending;
	aProcess.Rendezvous(status);

	if(KRequestPending != status.Int())
		{
		// startup failed so kill the process
		LOG_MSG2("t_multi_agent_launcher: launchProcess: RProcess Rendezvous() failed with %d. Killing process", status.Int());
		aProcess.Kill(KErrNone);
		return status.Int();
		}
	else
		{
		aProcess.Resume();
		User::WaitForRequest(status);

		LOG_MSG2("t_multi_agent_launcher: launchProcess: RProcess Resume() Rendezvous successful %d: ", status.Int());

		if(KErrNone != status.Int())
			{
			LOG_MSG2("t_multi_agent_launcher: RProcess Resume() failed with %d. Killing process", status.Int());
			aProcess.Kill(KErrNone);
			}

		LOG_MSG("EXIT: t_multi_agent_launcher launchProcess");
		return status.Int();
		}
	}
void CServerCrashDataSource::GetProcessListL( RProcessPointerList & aProcessList,
											  TUint & aTotalProcessListDescSize )
    {
	//LOG_MSG( "CServerCrashDataSource::GetProcessListL()\n" );

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

	if( iProcListBuffer.Size() != iLastProcListSize )
		{
		LOG_MSG2( "  iProcListBuffer.ReAlloc( %d)\n", iLastProcListSize );
		iProcListBuffer.ReAllocL( iLastProcListSize );
		}

	DoGetListL( EProcesses, (TUint)(-1), (TUint)(-1), iProcListBuffer, iLastProcListSize );

	iLastProcListSize = iProcListBuffer.Size();

	TUint8* ptr = (TUint8*)( iProcListBuffer.Ptr() );
	const TUint8* ptrEnd = ptr + iLastProcListSize;
	//LOG_MSG3( "  Data start,end=(0x%x, 0x%x)\n", ptr, ptrEnd );

	while( ptr < ptrEnd ) 
		{

	    TProcessListEntry *entry = (TProcessListEntry*)ptr;

		if( !entry )
			{
			LOG_MSG( "  ERROR !* : TProcessListEntry is NULL\n" );
			User::Leave(KErrBadHandle);
			}

		TUint64 id = entry->iProcessId;
		if( entry->iFileNameLength == 0 )
			{
			LOG_MSG4( "  Skipping process 0x%X%X : entry->iFileNameLength=%d", 
				I64HIGH(entry->iProcessId), I64LOW(entry->iProcessId), entry->iFileNameLength );
			ptr += Align4( entry->GetSize() );
			continue;
			}

		/*
		LOG_MSG4( "  process 0x%X%X has iFileNameLength=%d", 
			I64HIGH(entry->iProcessId), I64LOW(entry->iProcessId), entry->iFileNameLength );
		*/

        TPtrC entryName(&(entry->iNames[0]), entry->iFileNameLength);
       
        CProcessInfo *procInfoPtr = CProcessInfo::NewL(id, entryName );

		TInt err = aProcessList.Append( procInfoPtr );
        if(err != KErrNone)
            {
            delete procInfoPtr;
            User::Leave(err);
            }

		aTotalProcessListDescSize += procInfoPtr->Size();

		ptr += Align4( entry->GetSize() );
		}
	}
const TDesC& CTargetObserver::Thread(TInt aIndex) const
{
    LOG_MSG2("CTargetObserver::Thread(%d)\n", aIndex);
    return *iThreadList[aIndex];
}
Пример #17
0
TBool CConfigureCDSDialog::OkToExitL(TInt aButtonId)
	{
	LOG_MSG( "-> CConfigureCDSDialog::OkToExitL" );
	TBool ret = ETrue;
	TInt err;

	RPointerArray<CEikEdwin> edwins;
	CEikEdwin *edwin = static_cast<CEikEdwin*>(Control(EEdwin1));
	edwins.Append(edwin);
	edwin = static_cast<CEikEdwin*>(Control(EEdwin2));
	edwins.Append(edwin);
	edwin = static_cast<CEikEdwin*>(Control(EEdwin3));
	edwins.Append(edwin);
	edwin = static_cast<CEikEdwin*>(Control(EEdwin4));
	edwins.Append(edwin);
	edwin = static_cast<CEikEdwin*>(Control(EEdwin5));
	edwins.Append(edwin);
	edwin = static_cast<CEikEdwin*>(Control(EEdwin6));
	edwins.Append(edwin);
	edwin = static_cast<CEikEdwin*>(Control(EEdwin7));
	edwins.Append(edwin);

	switch (aButtonId)
		{
		case EEikBidCancel:
			{
			//RDebug::Print(_L("CConfigureCDSDialog::OkToExitL: Cancel pressed"));
			}
			break;
		case EBidCDSConfigure:
			{
			//RDebug::Print(_L("CConfigureCDSDialog::OkToExitL: iConfs.Count() == %d"), iConfs.Count());
			for (TInt i = 0; ( i < iConfs.Count() ) && ret; i++)
				{
				err = KErrNone;

				HBufC *input = NULL;
				if (edwins[i]->TextLength() > 0)
					{
					input = edwins[i]->GetTextInHBufL();
					}
				if ( ! input )
					{
					LOG_MSG2( "  NULL input for param %d" , i );
					continue;
					}

				//RDebug::Print(_L("CConfigureCDSDialog::OkToExitL: iConfs[i]->Type() == %d"), iConfs[i]->Type());

				switch (iConfs[i]->Type())
					{
					case COptionConfig::ETInt:
					case COptionConfig::ETUInt:
						{
						TLex opts(*input);
						TInt32 conf;
						err = opts.Val(conf);
						if ( err )
							{
							LOG_MSG("  error from opts.Val(conf) -> CConfigureCDSDialog::CEikonEnv::Static()->InfoMsg;" );
							CEikonEnv::Static()->InfoMsg(_L("Value must be an integer"));
							break;
							}

						//RDebug::Print(_L("CConfigureCDSDialog::OkToExitL: conf == %d"), conf);
						iConfs[i]->Value(conf);
						TRAP( err, iCoreDumpSession.SetConfigParameterL( *iConfs[i]) );
						}
						break;

					case COptionConfig::ETFileName:
					case COptionConfig::ETString:
					case COptionConfig::ETSingleEntryEnum:
					case COptionConfig::ETMultiEntryEnum:
						{						
						TRAP( err, iConfs[i]->ValueL(*input) );
						if ( KErrNone == err )
							{
							TRAP( err, iCoreDumpSession.SetConfigParameterL( *iConfs[i]) );
							}
						}
						break;

					case COptionConfig::ETBool:
						if (input->CompareF(_L("True"))== 0)
							{
							iConfs[i]->Value(ETrue);
							iConfs[i]->ValueL(_L("True"));
							}
						else if (input->CompareF(_L("False"))== 0)
							{
							iConfs[i]->Value(EFalse);
							iConfs[i]->ValueL(_L("False"));
							}
						else
							{
							err = KErrCorrupt;
							}

						if ( KErrNone == err )
							{
							TRAP( err, iCoreDumpSession.SetConfigParameterL( *iConfs[i]) );
							}

						break;

					default:
						CEikonEnv::Static()->InfoMsg(_L("Error with parameter type"));
						LOG_MSG( "CConfigureCDSDialog::OkToExitL: none of the above" );
						err = KErrCorrupt;
						break;

					}//switch

				if ( err )
					{
					RBuf errorString;
					CleanupClosePushL( errorString );
					errorString.CreateL( 128 );
					errorString.Append( _L("CDS Error ") ); 
					errorString.AppendNum( err );
					errorString.Append( _L(" setting parameter number ") );
					errorString.AppendNum( i );
					CEikonEnv::InfoWinL( errorString, KNullDesC );
					CleanupStack::PopAndDestroy( &errorString );
					ret = EFalse;
					}
                if(input)
                    {
                    delete input;
                    input = NULL;
                    }
				}
			}
			break;
		default:
			break;
		}

    edwins.Close();
	return ret;
	}
LOCAL_C void processConfigL()
	{

	// Create a CCrashConfig object, the configuration client-side 
	// object of the CoreDump Server .
    RCoreDumpSession coredumpinterface;

	TInt ret = coredumpinterface.Connect();

	if( KErrNone != ret )
		{
		LOG_MSG2( "requestConfigLoadL():: Could not create a Core Dump configuration object, error=%d", ret );
		User::Leave( ret );
		}

	TUint crashes = 1;

    TInt argc = User::CommandLineLength();
    TPtrC configFile(KNullDesC);	
	HBufC* args = NULL;
    if(argc > 0)
    {
        args = HBufC::NewLC(User::CommandLineLength());
        TPtr argv = args->Des();
	    User::CommandLine(argv);

	    TLex lex(*args);

        while(!lex.Eos())
        {
            if(lex.Get() == '-')
            {
                TChar c = lex.Get();
                if(c == '-')
                {
                    TPtrC16 token = lex.NextToken();
                    c = token[0];
                }

                lex.SkipSpace();
                switch(c)
                {
                case 'c':
                    lex.Val(crashes);
                    break;
                case 'f':
                    configFile.Set(lex.NextToken());
                    break;
                default:
                    User::Leave(KErrArgument);
                }
            }
            lex.SkipSpace();
        }
    }

    TRAPD(err, coredumpinterface.LoadConfigL( configFile ));

    if(err != KErrNone)
    {
	LOG_MSG2("unable to load config file! err:%d\n", err );
    coredumpinterface.Disconnect();
    User::Leave(err);
    }

	LOG_MSG2( "Will wait for %u crashes\n", crashes );

	RProperty crashCountProperty;
	User::LeaveIfError( crashCountProperty.Attach( KCoreDumpServUid, ECrashCount ) );

	TInt crashCount = 0;
	do
		{
		
		User::After(5000000);
		ret = crashCountProperty.Get( crashCount );
		LOG_MSG2( "  crashCountProperty.Get( crashCount )=%d\n", crashCount );
		if ( KErrNone != ret )
			{
			break;
			}
		}
	while( crashes > crashCount );

    crashCountProperty.Close();
	if(args)
        {
        CleanupStack::PopAndDestroy(args);  
        }
    coredumpinterface.Disconnect();
	LOG_MSG( "  returned from CleanupStack::PopAndDestroy( cmd );" );

	}
void CServerCrashDataSource::GetCodeSegmentsL( const TUint64 aTid, RCodeSegPointerList &aCodeSegList, TUint & aTotalCodeSegListDescSize )
	{
	LOG_MSG2("->CServerCrashDataSource::GetCodeSegmentsL(aTid=%Lu)\n", aTid );

    aCodeSegList.ResetAndDestroy();
    aTotalCodeSegListDescSize = 0;

	TUint32 size = KMaxFileName;
	RBuf8 buffer;
    buffer.CreateL(KMaxFileName);
    CleanupClosePushL(buffer);

	DoGetListL( ECodeSegs, aTid, (TUint)-1, buffer, size );
	LOG_MSG2( " DoGetListL( ECodeSegs ) returned buffer.Size()=0x%X\n", buffer.Size() );

	TUint8* ptr = (TUint8*)buffer.Ptr();
	const TUint8* ptrEnd = ptr + size;

	while(ptr < ptrEnd)
		{
		TCodeSegListEntry* entry = (TCodeSegListEntry*)ptr;

		LOG_MSG4( "  entry->CodeBase=0x%X, CodeSize=0x%X, ConstDataSize=0x%X\n", 
			entry->iCodeBase, entry->iCodeSize, entry->iConstDataSize );
		LOG_MSG4( "  InitDataBase=0x%X, InitDataSize=0x%X, UnintDataSize=0x%X\n", 
			entry->iInitialisedDataBase, entry->iInitialisedDataSize, entry->iUninitialisedDataSize );
		LOG_MSG3( "  IsXip=0x%X, CodeSegType=0x%X\n", entry->iIsXip, entry->iCodeSegType );
		
        TCodeSegInfo *codeSeg = new(ELeave) TCodeSegInfo;

		TPtr name(&(entry->iName[0]), entry->iNameLength, entry->iNameLength);
        codeSeg->iName = name;	

        codeSeg->iType = entry->iCodeSegType;
        codeSeg->iXIP = entry->iIsXip;

        codeSeg->iCodeSize = entry->iCodeSize;
        codeSeg->iCodeRunAddr = entry->iCodeBase;
        if( codeSeg->iXIP )
            {
            codeSeg->iCodeLoadAddr = codeSeg->iCodeRunAddr;
            }
        else
            {
            codeSeg->iCodeLoadAddr = 0; //TODO
            }

        codeSeg->iRoDataSize = entry->iConstDataSize;
        codeSeg->iRoDataRunAddr = entry->iCodeBase + entry->iCodeSize;
        if( codeSeg->iXIP )
            {
            codeSeg->iRoDataLoadAddr = codeSeg->iRoDataRunAddr;
            }
        else
            {
            codeSeg->iRoDataLoadAddr = 0; //TODO
            }

        codeSeg->iDataSize = entry->iInitialisedDataSize + entry->iUninitialisedDataSize;
        codeSeg->iDataRunAddr = entry->iInitialisedDataBase;
        if( codeSeg->iXIP )
            {
            codeSeg->iDataLoadAddr = codeSeg->iDataRunAddr;
            }
        else
            {
            codeSeg->iDataLoadAddr = 0; //TODO
            }

        TInt err = aCodeSegList.Append(codeSeg);
        if(err != KErrNone)
            {
            delete codeSeg;
            User::Leave(err);
            }

		aTotalCodeSegListDescSize += sizeof(TCodeSegInfo);
        ptr += Align4(entry->GetSize());
		}

    CleanupStack::PopAndDestroy(&buffer);
	}
/** Obtain the thread list. If aProcessId is negative, we obtain the entire system
thread list. If aProcessId is positive we get the thread list for that process */
void CServerCrashDataSource::GetThreadListL( const TUint64 aProcessId, 
											 RThreadPointerList & aThreadList,
											 TUint & aTotalThreadListDescSize )
	{
	LOG_MSG2( "->CServerCrashDataSource::GetThreadListL(aProcessId=%Lu)\n", aProcessId); 

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

	if( iThreadListBuffer.Size() != iLastThreadListSize )
		{
		LOG_MSG2("CServerCrashDataSource::GetThreadListL -> iThreadListBuffer.ReAlloc(%d)\n", iLastThreadListSize );
		iThreadListBuffer.ReAllocL( iLastThreadListSize );
		}

	LOG_MSG( "CServerCrashDataSource::GetThreadListL -> DoGetListL()\n" );
	DoGetListL( EThreads, (TUint)-1, aProcessId, iThreadListBuffer, iLastThreadListSize );

	iLastThreadListSize = iThreadListBuffer.Size();
	

	CThreadInfo		 *  threadInfoPtr;
	RThread				thread;
	TThreadStackInfo	stackInfo;
	TThreadListEntry *	entry;
	TUint				usrStackSize;
	TLinAddr			usrStackAddr;
	TLinAddr			svcStackPtr;
	TLinAddr			svcStackBase;
	TUint				svcStackSize;

	TUint				priority;

	TUint8* ptr = (TUint8*)( iThreadListBuffer.Ptr() );
	const TUint8* ptrEnd = ptr + iLastThreadListSize;
	//LOG_MSG3( "  Data start,end=(0x%x, 0x%x)\n", ptr, ptrEnd );

	while( ptr < ptrEnd ) 
		{

		entry = (TThreadListEntry*)ptr;

		if( !entry )
			{
			LOG_MSG( "  ERROR !* : TThreadListEntry is NULL\n" );
			User::Leave(KErrBadHandle);
			}

		if( entry->iNameLength == 0 )
			{
			LOG_MSG4( "  Skipping Thread 0x%X%X : entry->iNameLength=%d", 
				I64HIGH(entry->iThreadId), I64LOW(entry->iThreadId), entry->iNameLength );
			ptr += Align4( entry->GetSize() );
			continue;
			}

		//LOG_MSG3( "  entry &=0x%X, size=%d\n", &(entry->iThreadId), entry->GetSize() );
		//LOG_MSG3( "  entry->iThreadId= 0x%X%X\n", I64HIGH(entry->iThreadId), I64LOW(entry->iThreadId) );
		//LOG_MSG3( "  found tid=%d, pid=%d\n", I64LOW(entry->iThreadId), I64LOW(entry->iProcessId) );
			
		if( entry->iSupervisorStackPtrValid )
			{
			svcStackPtr = entry->iSupervisorStackPtr;
			}
		else
			{
			svcStackPtr = 0;
			}

		if( entry->iSupervisorStackBaseValid )
			{
			svcStackBase = entry->iSupervisorStackBase;
			}
		else
			{
			svcStackBase = 0;
			}
		
		if( entry->iSupervisorStackSizeValid )
			{
			svcStackSize = entry->iSupervisorStackSize;
			}
		else
			{
			svcStackSize = 0;
			}		



		if( KErrNone == thread.Open( entry->iThreadId ) )
			{
			priority = (TUint)(thread.Priority());

			if( KErrNone == thread.StackInfo( stackInfo ) )
				{
				usrStackAddr = stackInfo.iLimit;
				usrStackSize = stackInfo.iBase - stackInfo.iLimit;
				}
			else
				{
				usrStackSize = 0;
				usrStackAddr = 0;
				}

			thread.Close();
			}
		else
			{
			usrStackSize = 0;
			usrStackAddr = 0;
			priority = 0;
			}

		/*
		LOG_MSG3( "  entry->iNameLength=%d, &(entry->iName[0])=0x%X\n", 
				entry->iNameLength, &(entry->iName[0]) );
		*/

		TPtrC entryName( &(entry->iName[0]), entry->iNameLength );
		//LOG_MSG2( "  -> threadInfoPtr = CThreadInfo::NewL( name.Size()=%d)\n", entryName.Size() );

		threadInfoPtr = CThreadInfo::NewL( 
										entry->iThreadId, 
										entryName,
										entry->iProcessId,
										(TUint)priority,
										svcStackPtr,
										svcStackBase,
										svcStackSize,
										usrStackAddr,
										usrStackSize );

		/*
		LOG_MSG3( "  threadInfoPtr->iSvcStackAddr=0x%X, threadInfoPtr->iSvcStackSize=0x%X\n", 
			threadInfoPtr->SvcStackAddr(), threadInfoPtr->SvcStackSize() );
		*/

		TInt err = aThreadList.Append( threadInfoPtr );
		if( err != KErrNone )
			{
			// We use this id so as not to use Push(), AppendL(), Pop()
			delete threadInfoPtr;
			User::Leave( err );
			}

		aTotalThreadListDescSize += threadInfoPtr->Size();

		/*
		LOG_MSG3( "  aTotalThreadListDescSize = %d after adding %d\n", 
				aTotalThreadListDescSize, threadInfoPtr->Size() );

		RBuf rPrintBuf;
		rPrintBuf.Create( threadInfoPtr->Name()); 
		RDebug::Printf( "  <- rPrintBuf.Create(), rPrintBuf.Length()=%d\n", rPrintBuf.Length() );
		char* cl = (char*) rPrintBuf.Collapse().PtrZ();
		RDebug::Printf("  name=%s\n", cl );
		rPrintBuf.Close();
		*/

		ptr += Align4( entry->GetSize() );
		//LOG_MSG2( "  ptr += Align4(entry->GetSize()) = 0x%X\n", ptr );

		} // while

	}
// second-phase constructor
void CServerCrashDataSource::ConstructL()
    {
	LOG_MSG("->CServerCrashDataSource::ConstructL()\n" );
	// Get the debug func block and make appropriate changes to our structures
    TInt err;
	TUint32 bufsize = 0;
	LOG_MSG( "  -> iSecSess->GetDebugFunctionalityBufSize( &bufsize )\n" );
    err = iSecSess.GetDebugFunctionalityBufSize( &bufsize );

	if( (err != KErrNone) || (0 == bufsize) )
		{
		// No debug functionality block, cannot do much without that.
		LOG_MSG2("CServerCrashDataSource::ConstructL() - unable to get debug functionality block! err:%d\n", err);
		User::Leave( KErrNotSupported );
		}

    RBuf8 DFBlock;
    DFBlock.CreateL(bufsize);
    DFBlock.CleanupClosePushL();

	LOG_MSG2( "  -> HBufC8::NewLC( bufsize=%d )\n", bufsize );


	LOG_MSG("CServerCrashDataSource::ConstrucL -> GetDebugFunctionality()\n" );
    err = iSecSess.GetDebugFunctionality(DFBlock);
	if( KErrNone != err )
		{
		LOG_MSG( "CServerCrashDataSource::ConstructL() : ERROR !* : Could not retrieve debug functionality block\n" );
		User::Leave( KErrNotSupported );
		}

	LOG_MSG( "  -> GetDebugHeader( EDF_TagHdrId_RegistersCore )\n" );
	TTagHeader * hdr = GetDebugHeader( ETagHeaderIdRegistersCore, DFBlock );

	if( hdr == NULL )
		{
		LOG_MSG( "Could not retrieve ETagHeaderIdRegistersCore register debug block\n" );
		}
	else if( 0 == hdr->iNumTags )
		{
		LOG_MSG( "Zero tags found for ETagHeaderIdRegistersCore register debug block\n" );
		}
	else
		{

		iRegisterList.ReserveL( (TInt)hdr->iNumTags );

		// Skip the header to get to the tags
		TUint8 * ptr = ((TUint8 *) hdr) + sizeof( TTagHeader );
		TTag * tag = (TTag *) ptr;

		TRegisterData regData;
		TRegisterData * reg = &regData;

		// Process all the register tags
		for( TInt regIdx = 0; regIdx < hdr->iNumTags; regIdx ++ )
			{
			reg->iRegClass  = 0;			// Core = 0
			reg->iId        = tag->iTagId;	//
			reg->iSubId     = 0;			//
			reg->iSize      = 2;			// Should all be 32 bits == 2.
			reg->iAvailable = ETrue;
			reg->iValue64	= 0;
			iRegisterList.Append( *reg );
			tag++;
			}
		}

	hdr = GetDebugHeader( ETagHeaderIdMemory, DFBlock );
	if( hdr == NULL )
		{
		LOG_MSG( "Could not retrieve ETagHeaderIdMemory. Cannot read memory\n" );
		iMaxMemReadSize = 0;
		}
	else if( 0 == hdr->iNumTags )
		{
		LOG_MSG( "Zero tags found for ETagHeaderIdMemory register debug block\n" );
		iMaxMemReadSize = 0;
		}
	else
		{
		TTag* tag = GetTag( hdr, EMemoryMaxBlockSize );
		if( tag )
			{
			//LOG_MSG2( " EMemoryMaxBlockSize =0x%X\n", tag->iValue );
			iMaxMemReadSize = tag->iValue;
			}
		}

	iLastThreadListSize = 1;
	iLastProcListSize = 1;
	iLastRegListSize = 1;

	CleanupStack::PopAndDestroy(&DFBlock);
    }
/**
 * Read command line parameters and control the launching of the agents. 
 */
void MainL()
	{	
	LOG_MSG( "ENTER: t_multi_agent_launcher MainL()");

	TInt ret = KErrNone;
	TInt numAgents = KNumAgents;
	TInt numTargets = KNumTargets;
	TInt numTestRuns = KNumTestRuns;

	TInt argc = User::CommandLineLength();
	HBufC* commandLine = NULL;
	LOG_MSG2("t_multi_agent_launcher: MainL(): argc=%d", argc);
    
	if(argc)
		{
		commandLine = HBufC::NewLC(argc);
		TPtr commandLineBuffer = commandLine->Des();
		User::CommandLine(commandLineBuffer);

		RBuf printCommandLine;
		CleanupClosePushL( printCommandLine );
		printCommandLine.CreateL( commandLine->Des().Length() );
		printCommandLine.Copy( commandLine->Des() );
		printCommandLine.Collapse();
		LOG_MSG2("t_multi_agent_launcher: command line = %S", &printCommandLine);
		CleanupStack::PopAndDestroy( &printCommandLine );
 
		// create a lexer and read through the command line
		TLex lex(*commandLine);
		while (!lex.Eos())
			{
			// only look for options with first character '-'
			if (lex.Get() == '-')
				{
					TChar arg = lex.Get();
					switch ( arg )
						{
						case 'n':
							lex.Val( numAgents );
							LOG_MSG2("t_multi_agent_launcher: parsed numAgents as %d", numAgents);
							break;
						case 'm':
							lex.Val( numTargets );
							LOG_MSG2("t_multi_agent_launcher: parsed numTargets as %d", numTargets);                        
							break;  
						case 't':
							lex.Val( numTestRuns );
							LOG_MSG2("t_multi_agent_launcher: parsed numTestRuns as %d", numTestRuns);                        
							break;                    
						default:
							LOG_MSG("t_multi_agent_launcher: unknown argument ignoring it");
							break;                 
						}
				}
			}
		}

	// Note: below is a workaround to overcome an issue with RTest server crashing 
	// when writing to the windows console from different agents (on different CPUs 
	// at the same time). To overcome this we get signaled by the agents when they have 
	// completed their tests so that we can do a RTest complete
	RSemaphore launchSemaphore;
	CleanupClosePushL(launchSemaphore);
	ret = launchSemaphore.CreateGlobal(KLaunchSemaphoreName, 0);
	LOG_MSG2( ">Target Launcher : RSemaphore.CreateGlobal ret %d", ret);
	User::LeaveIfError( ret );

	ret = launchSemaphore.OpenGlobal(KLaunchSemaphoreName);
	LOG_MSG2( ">Target Launcher : RSemaphore.OpenGlobal ret %d", ret);
	User::LeaveIfError( ret );

	//Now launch the requested number of apps for the requested number of test runs
	for( TInt j = 0; j < numTestRuns; j++ )
		{ 
			for( TInt i = 0; i < numAgents; i++ )  
				{
					RBuf targetName;
					targetName.CleanupClosePushL();
					targetName.CreateL(KAgentExe());

					RProcess aProc;
					CleanupClosePushL(aProc); 
					RBuf launcherOptions;
					CleanupClosePushL(launcherOptions);
				    const TInt additionalWords = 2;	
					launcherOptions.CreateL( KAgentOptions().Length() + additionalWords );
		
					// Apply offset: launcherOptions.Format( .., .., i * numTargets, ..)
					// workaround to ensure we have the same binary for multiple agents. 
					// e.g. So if offset = 0, agent attaches to app1, app2, app3, app4, app5
					// if offset = 5, agent attached to app6, app7, app8, app9, app10 etc.
					// Note: apps need to be in rom otherwise the agent will fail on an assert 
					// (with KErrNotFound)
					launcherOptions.Format( KAgentOptions(), (TUint)numTargets, i * numTargets, 0);
			
					ret = LaunchProcess( aProc, targetName, launcherOptions );	
					CleanupStack::PopAndDestroy(3,&targetName);
					User::LeaveIfError(ret);
				}
		}

	// Wait for all agents to do their testing before checking the semaphore
	User::After(12000000);

	LOG_MSG( ">Target Launcher:  Semaphore wait");

	for (TInt i = 0; i < numAgents; i ++)
		{
		//We need this delay just in case an agent crashes and never signals the sem
		ret = launchSemaphore.Wait(100000);
		if( ret != KErrNone )
			{
			LOG_MSG3("launchSemaphore.Wait ret %d for agent %d", ret, i);
			break;
			}
		}

	LOG_MSG2( "testing for Semaphore ret %d", ret);

	// We only want to have one RTest instance at any one time since otherwise RTest can panic
	RTest test(_L("T_MULTI_AGENT_LAUNCHER"));
	test.Start(_L("t_multi_agent_launcher Check for agents finishing correctly"));
	test(ret == KErrNone);
	test.End();
	test.Close();

	CleanupStack::PopAndDestroy(&launchSemaphore); // launchSemaphore

	if( commandLine )
	CleanupStack::PopAndDestroy(commandLine);
	
	LOG_MSG("EXIT: t_multi_agent_launcher MainL()");
	}
void CServerCrashDataSource::SetRegValuesL( const TUint64 aThreadId, RRegisterList &aRegisterList )
	{

	LOG_MSG2("->CServerCrashDataSource::SetRegValuesL(aThreadId=%Lu)\n", aThreadId); 

	TInt numberOfRegisters = aRegisterList.Count();

	RBuf8 ids;
	ids.CreateL( numberOfRegisters * sizeof(TFunctionalityRegister) );
    ids.CleanupClosePushL();

	TInt totalByteSize = 0; // Keeps track of the number of bytes that we are requesting

	for( TInt i=0; i < numberOfRegisters; i++ )
		{
		TRegisterInfo reg = (TRegisterInfo)( aRegisterList[i].iId ); 

		// iSize = (0 == 1 byte); (3 == 8 bytes)
		TInt byteSize = (aRegisterList[i].iSize) << 1;
		totalByteSize += byteSize;
		ids.Append( reinterpret_cast<const TUint8*>(&reg), sizeof(TRegisterInfo) );
		}

	
	RBuf8 registerValues;
	registerValues.CreateL( totalByteSize );
    registerValues.CleanupClosePushL();

	RBuf8 registerFlags;
	registerFlags.CreateL( numberOfRegisters );
    registerFlags.CleanupClosePushL();

    LOG_MSG("CServerCrashDataSource::SetRegValuesL - reading registers\n");
    User::LeaveIfError(iSecSess.ReadRegisters( aThreadId, ids, registerValues, registerFlags ));

	// Now copy the values back to the array and mark the availability from the flags

	TUint8* valuePtr = (TUint8*) registerValues.Ptr();

	for( TInt i=0; i < numberOfRegisters; i++ )
		{

		TRegisterData & reg = aRegisterList[i];

		switch( reg.iSize )
			{
			case 0:
				reg.iValue8 = *((TUint8 *)valuePtr);
				valuePtr += 1;
				break;
			case 1:
				reg.iValue16 = *((TUint16 *)valuePtr);
				valuePtr += 2;
				break;
			case 2:
				reg.iValue32 = *((TUint32 *)valuePtr);
				valuePtr += 4;
				break;
			case 3:
				reg.iValue64 = *((TUint64 *)valuePtr);
				valuePtr += 8;
				break;
			}

		if( EValid == registerFlags[i] ) 
			{
			reg.iAvailable = ETrue;
			}
		else
			{
			reg.iAvailable = EFalse;
			}
		}

    CleanupStack::PopAndDestroy(&registerFlags);
    CleanupStack::PopAndDestroy(&registerValues);
    CleanupStack::PopAndDestroy(&ids);
	}