kerneltest/e32test/rm_debug/t_rmdebug_app.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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 the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include <e32base.h>
#include <e32base_private.h>
#include <e32cmn.h>
#include <e32cmn_private.h>
#include <e32debug.h>
#include <e32property.h> 
#include "t_rmdebug_app.h"

IMPORT_C extern void RMDebug_BranchTst2();

LOCAL_C void ParseCommandLineL(TInt32& aFunctionType, TUint& aDelay, TUint& aExtraThreads)
	{
	// get the length of the command line arguments
	TInt argc = User::CommandLineLength();

	// allocate a buffer for the command line arguments and extract the data to it
	HBufC* commandLine = HBufC::NewLC(argc);
	TPtr commandLineBuffer = commandLine->Des();
	User::CommandLine(commandLineBuffer);

	// create a lexer and read through the command line
	TLex lex(*commandLine);
	while (!lex.Eos())
		{
		// expecting the first character to be a '-'
		if (lex.Get() == '-')
			{
			TChar arg = lex.Get();
			switch (arg)
				{
				case 'f':
					// the digits following '-f' give the function type
					User::LeaveIfError(lex.Val(aFunctionType));
					break;
				case 'd':
					// the digits following '-d' give the delay
					User::LeaveIfError(lex.Val(aDelay));
					break;
				case 'e':
					// the digits following '-e' give the number of extra threads to launch
					User::LeaveIfError(lex.Val(aExtraThreads));
					break;
				default:
					// unknown argument so leave
					User::Leave(KErrArgument);
				}
			lex.SkipSpace();
			}
		else
			{
			// unknown argument so leave
			User::Leave(KErrArgument);
			}
		}

	// do clean up
	CleanupStack::PopAndDestroy(commandLine);
	}

typedef void (*TPfun)();

// test function to call corresponding to EPrefetchAbortFunction
void PrefetchAbort()
	{
	TPfun f = NULL;
	f();
	}

// test function to call corresponding to EUserPanicFunction
void UserPanic()
	{
	User::Panic(KUserPanic, KUserPanicCode);
	}

// calls self repeatedly until stack is used up. Slightly convoluted to prevent UREL optimising this out...
TUint32 StackOverFlowFunction(TUint32 aInt=0)
	{
	TUint32 unusedArray[150];
	for(TInt i=0; i<150; i++)
		{
		unusedArray[i] = StackOverFlowFunction(i);
		}
	return unusedArray[0];
	}

void DataAbort()
	{
	TInt* r = (TInt*) 0x1000;
	*r = 0x42;              
	}

void UndefInstruction()
	{
	TUint32 undef = 0xE6000010;
	TPfun f = (TPfun) &undef;
	f();
	}

TInt DataRead()
	{
	TInt* r = (TInt*) 0x1000;
	TInt rr = (TInt)*r;
	//include the following line to ensure that rr doesn't get optimised out
	RDebug::Printf("Shouldn't see this being printed out: %d", rr);

	// Stop compilation warning. Should not get here anyway.
	rr++;
	return rr;
	}

void DataWrite()
	{
	TInt* r = (TInt*) 0x1000;
	*r = 0x42;                
	}

void UserException()
	{
	User::RaiseException(EExcGeneral);
	}

void SpinForeverWithBreakPoint()
	{

    // finding the process t_rmdebug2/t_rmdebug2_oem/t_rmdebug2_oem2
    // we find the process.SID to attach to the property
	_LIT(KThreadWildCard, "t_rmdebug2*");

	TInt err = KErrNone;
	TUid propertySid = KNullUid;
	TFindThread find(KThreadWildCard);
	TFullName name;
	TBool found = EFalse;
	while(find.Next(name)==KErrNone && !found)
		{
		RThread thread;
		err = thread.Open(find);
		if (err == KErrNone)
			{
			RProcess process;
			thread.Process(process);
			TFullName fullname = thread.FullName();
		    //RDebug::Printf("SID Search Match Found Name %lS Process ID%ld Thread Id %ld", &fullname, process.Id().Id(), thread.Id().Id());
			found = ETrue;
			//SID saved so that the property can be attached to
			propertySid = process.SecureId();
			process.Close();
			}
		thread.Close();
	}

    //attach to the property to publish the address of the RMDebug_BranchTst2 with the correct SID value
	RProperty integerProperty;
	err = integerProperty.Attach(propertySid, EMyPropertyInteger, EOwnerThread);
	if(KErrNone != err)
		RDebug::Printf("Error Attach to the property %d", err);

	TInt address = (TInt)&RMDebug_BranchTst2;
	
	// publish the address where the breakpoint would be set
	err = integerProperty.Set(address);
	if(KErrNone != err)
		RDebug::Printf("Error Set of the property %d", err);
	integerProperty.Close();
	
	//open semaphore to signal the fact we have reached the point where we have to set the property
	RSemaphore globsem;
	globsem.OpenGlobal(_L("RMDebugGlobSem"));
	globsem.Signal();
	globsem.Close();

	RProcess thisProcess;
	TFileName thisProcessName = thisProcess.FileName();
	RDebug::Printf("App Process Name %lS process id %ld thread id %ld", &thisProcessName, thisProcess.Id().Id(), RThread().Id().Id());

	TInt i=0;
	RThread::Rendezvous(KErrNone);
	while(i<0xffffffff)
		{
		RMDebug_BranchTst2();
		User::After(10000);
		}
	}
void SpinForever()
	{
	TInt i=0;
	RThread::Rendezvous(KErrNone);
	while(i<0xffffffff)
		{
		User::After(10000);
		}
	}

void LaunchThreads(TUint aNumber)
	{
	_LIT(KDebugThreadName, "DebugThread");
	const TUint KDebugThreadDefaultHeapSize=0x10000;
	for(TInt i=0; i<aNumber; i++)
		{
		RThread thread;
		RBuf threadName;
		threadName.Create(KDebugThreadName().Length()+10); // the 10 is for appending i to the end of the name
		threadName.Append(KDebugThreadName());
		threadName.AppendNum(i);
		TInt err = thread.Create(threadName, (TThreadFunction)SpinForever, KDefaultStackSize, KDebugThreadDefaultHeapSize, KDebugThreadDefaultHeapSize, NULL);
		if(err != KErrNone)
			{
			RDebug::Printf("Couldn't create thread %d", err);
			threadName.Close();
			thread.Close();
			break;
			}
		thread.SetPriority(EPriorityNormal);
		TRequestStatus status;
		thread.Rendezvous(status);
		thread.Resume();
		User::WaitForRequest(status);
		thread.Close();
		threadName.Close();
		}
	}

void WaitFiveSecondsThenExit(void)
	{
	// wait for 5 seconds
	User::After(5000000);
	}

// call the function corresponding to aFunctionType
LOCAL_C void CallFunction(TDebugFunctionType aFunctionType, TUint aDelay, TUint aExtraThreads)
	{
	// pause for aDelay microseconds
	User::After(aDelay);

	// launch the extra threads
	LaunchThreads(aExtraThreads);

	// call appropriate function
	switch( aFunctionType )
		{
		case EPrefetchAbortFunction:
			PrefetchAbort();
			break;
		case EUserPanicFunction:
			UserPanic();
			break;
		case EStackOverflowFunction:
			StackOverFlowFunction();
			break;
		case EDataAbortFunction:
			DataAbort();
			break;
		case EUndefInstructionFunction:
			UndefInstruction();
			break;
		case EDataReadErrorFunction:
			DataRead();
			break;
		case EDataWriteErrorFunction:
			DataWrite();
			break;
		case EUserExceptionFunction:
			UserException();
			break;
		case EWaitFiveSecondsThenExit:
			WaitFiveSecondsThenExit();
			break;
		case ESpinForever:
			SpinForever();
			break;
		case ESpinForeverWithBreakPoint:
			SpinForeverWithBreakPoint();
			break;
		case EDefaultDebugFunction:
		default:
			break;
		}
	}

void PrintHelp()
	{
	RDebug::Printf("Invoke with arguments:\n");
	RDebug::Printf("\t-d<delay>\n\t: delay in microseconds before calling target function\n");
	RDebug::Printf("\t-f<function-number>\n\t: enumerator from TDebugFunctionType representing function to call\n");
	RDebug::Printf("\t-e<number>\n\t: number of extra threads to launch, these threads run endlessly\n");
	}

TInt E32Main()
	{
	// setup heap checking and clean up trap
	__UHEAP_MARK;
	CTrapCleanup* cleanup=CTrapCleanup::New();
	RThread().SetPriority(EPriorityNormal);
	RProcess::Rendezvous(KErrNone);

	// read arguments from command line
	TUint delay = 0;
	TInt32 functionTypeAsTInt32 = (TInt32)EDefaultDebugFunction;
	TUint extraThreads = 0;
	TRAPD(err, ParseCommandLineL(functionTypeAsTInt32, delay, extraThreads));

	if(KErrNone == err)
		{
		// if the command line arguments were successfully read then call the appropriate function
		CallFunction((TDebugFunctionType)functionTypeAsTInt32, delay, extraThreads);
		}

	// perform clean up and return any error which was recorded
	delete cleanup;
	__UHEAP_MARKEND;
	return err;
	}