kerneltest/e32test/debug/t_codemodifier.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 6 0173bcd7697c
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) 2005-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:
// e32test\debug\t_codemodifier.cpp
// Overview:
// Exercises Kernel's Code Modifier. This is common use case for run-mode debuggers.
// API Information:
// DebugSupport::InitialiseCodeModifier
// DebugSupport::CloseCodeModifier
// DebugSupport::ModifyCode
// DebugSupport::RestoreCode
// Kern::ThreadRawRead
// Kern::ThreadRawWrite
// Details:
// -Three applications are running in the test:
// - t_codemodifier.exe client
// - t_codemodifier.exe server (XIP code)
// - t_codemodifier2.exe client (non-XIP code)
// -Test1 -Checks that the TestFunc (that will be altered by breakpoints) is really deadly if un-altered.
// -Test2 -Checks Code Modifier if data segment address is passed to set breakpoint.	
// -Test3 -Checks Code Modifier if invalid address is passed to set breakpoint.Kern::ThreadRawRead\Write is also checked.	
// -Test4 -Replaces BRK instruction in TestFunc with NOP using 1.2 and 4 bytes long breakpoints. Executes the 
// function in the servers.
// -Test5 -Repeats Test4 (for XIP server only) with previously shedowed TestFunc
// -Test6 -Tests scenario when a process terminates while there are still associated breakpoints.
// -Test7 -Tests out-of-breakpoints scenario
// -Test8 -Tests breakpoint-already-exists scenario
// -Test9 -Tests CodeModifier closing when there are still active breakpoints.	Breakpoints in this test occupies more then
// one shadowed page.
// -Test10-A random stress test. Sets/Clears random brekpoints in CodeArea of the both servers. Then replaces
// all BRKs with NOPs in CodeArea and executes them.
// -Test11-Checks that overlaping breakpoints are rejected.
// Platforms/Drives/Compatibility:
// Hardware (Automatic). Not supported on emulator.
// Assumptions/Requirement/Pre-requisites:
// Failures and causes:
// Base Port information:
// 
//

#define __E32TEST_EXTENSION__
#include <e32test.h>
#include <e32ldr.h>
#include <e32ldr_private.h>
#include <f32dbg.h>
#include "d_codemodifier.h"
#include "../misc/prbs.h"

LOCAL_D RTest test(_L("T_CODEMODIFIER"));
_LIT(KServerXIP,"ServerXIP");
_LIT(KServerNONXIP,"ServerNONXIP");
_LIT(KAppXIP,"t_codemodifier.exe");
_LIT(KAppNONXIP,"t_codemodifier2.exe");

extern void TestFunc();
extern void CodeArea();

//------------client globals---------------------
RCodeModifierDevice Device;

/**	These addresses/names is all the client needs to test a server.
	There are XIP and non-XIP server in the test*/
struct SServerData
	{
	TInt  		 iThreadId;
	TUint 		 iVarAddr;
	TUint 		 iFuncAddr;
	TUint 		 iInvalidAddr;
	TUint 		 iCodeAreaAddr;
	const TDesC* iAppName;
	const TDesC* iServerName;
	RProcess 	 iProcess;
	} ServerData[2];

/**Will hold assembler instructions that make TestFunc.*/
struct STestFunc
	{
	TInt iBRK;
	TInt iNOP;
	TInt iRET;
	} TestFuncCode;

/**ServerData[0] is about XIP server, ServerData[1] is non-XIP server*/
enum TWhichServer
	{
	EXip = 0,
	ENonxip = 1
	};

/**Server*/
class CCodeModifierServer : public CServer2
	{
public:
	static CCodeModifierServer* New(TInt aPriority);
private:
	CCodeModifierServer(TInt aPriority) : CServer2(aPriority){}
	CSession2* NewSessionL(const TVersion& aVersion,const RMessage2& aMessage) const;
public:
	TInt iTestVar;
	RChunk chunk;
	};

CCodeModifierServer* CCodeModifierServer::New(TInt aPriority)
	{
	return new CCodeModifierServer(aPriority);
	}

/**Server side session*/
class CCodeModifierSession : public CSession2
	{
public:
	enum TCommand {EStop, EGetServerInfo, ERunTestFunc, ERunCodeAreaFunc};
private:
	void ServiceL(const RMessage2& aMessage);
	};

/*Client-side session*/
class RCodeModifierSession : private RSessionBase
	{
public:
	/**Updates ServerData[aServer] with data from the server*/
	static TInt GetServerInfo(TInt aServer)
		{
		TPtr8 ptr((TUint8*)&ServerData[aServer].iThreadId, 5*sizeof(TInt),5*sizeof(TInt));
		TIpcArgs args(&ptr);
		return Control(CCodeModifierSession::EGetServerInfo,aServer,args);
		};
	/**Stops the server*/	
	static TInt Stop(TInt aServer)
		{TIpcArgs args;return Control(CCodeModifierSession::EStop,aServer, args);};
	/**Issues the command to server to run TestFunc*/
	static TInt RunTestFunc(TInt aServer)
		{TIpcArgs args;return Control(CCodeModifierSession::ERunTestFunc,aServer,args);};
	/**Issues the command to server to run CodeArea*/
	static TInt RunCodeAreaFunc(TInt aServer)
		{TIpcArgs args;return Control(CCodeModifierSession::ERunCodeAreaFunc,aServer,args);};
private:
	/*Executes a synchronius client-server request*/
	static TInt Control(CCodeModifierSession::TCommand aRequest, TInt aServer, TIpcArgs& aArgs)
		{
		RCodeModifierSession p;
		TInt r = p.CreateSession(*ServerData[aServer].iServerName, TVersion(), 0);
		if (r == KErrNone)
			p.SendReceive(aRequest, aArgs);
		p.Close();
		return r;
		};
	};

//------------server globals---------------------
CCodeModifierServer* CodeModifierServer;

/**Creates a new client for this server.*/
CSession2* CCodeModifierServer::NewSessionL(const TVersion&, const RMessage2&) const
	{
	return new(ELeave) CCodeModifierSession();
	}

/**Session entry point on the server side.*/
void CCodeModifierSession::ServiceL(const RMessage2& aMessage)
	{
	TInt r=KErrNone;
	switch (aMessage.Function())
		{
	case EGetServerInfo:		//Pass threadId and addresses to the client
		{
		struct SInfo
			{
			TInt  iThreadId;
			TUint iVarAddr;
			TUint iFuncAddr;
			TUint iInvalidAddr;
			TUint iCodeAreaAddr;
			} info;
		RThread thread;
		info.iThreadId =    (TInt) thread.Id();
		info.iVarAddr =     (TUint) &CodeModifierServer->iTestVar;
		info.iInvalidAddr = (TUint)CodeModifierServer->chunk.Base()+0x1000;
		info.iFuncAddr =    (TUint)&TestFunc;
		info.iCodeAreaAddr =(TUint)&CodeArea;
		TPtrC8 ptr((TUint8*)&info, sizeof(SInfo));
		r=aMessage.Write(0,ptr);
		}
		break;

	case ERunTestFunc:			//Execute TestFunc
		TestFunc();
		break;

	case ERunCodeAreaFunc:			//Execute CodeArea
		CodeArea();
		break;

	case EStop:					//This will stop the server thread.
		CActiveScheduler::Stop();
		break;

	default:
		r=KErrNotSupported;
		}
	aMessage.Complete(r);
	}

/**Server application entry point*/
LOCAL_C TInt ServerEntryPoint(TInt aServer)
	{
	TInt r=0;
	__UHEAP_MARK;
	
	CActiveScheduler *pR=new CActiveScheduler;
	if (!pR)
		User::Panic(_L("SVR:Could't create Active Scheduler\n"), KErrNoMemory);
	CActiveScheduler::Install(pR);

	CodeModifierServer = CCodeModifierServer::New(0);
	if(!CodeModifierServer)
		{
		delete pR;
		User::Panic(_L("SVR:Create svr error\n"), KErrNoMemory);
		}

	//Create a chunk with a hole between addresses 0x1000 & 0x2000
	r=CodeModifierServer->chunk.CreateDisconnectedLocal(0,0,0x200000);
	test_KErrNone(r);
	r=CodeModifierServer->chunk.Commit(0,0x1000);
	test_KErrNone(r);
	r=CodeModifierServer->chunk.Commit(0x2000,0x1000);
	test_KErrNone(r);

	//We decide here which server to start.
	if (aServer==0)
		r=CodeModifierServer->Start(KServerXIP);
	else
		r=CodeModifierServer->Start(KServerNONXIP);
		
	if (r!=KErrNone)
		{
		delete CodeModifierServer;
		delete pR;
		User::Panic(_L("SVR:Error starting server\n"), r);
		}
	RProcess::Rendezvous(KErrNone);
	CActiveScheduler::Start();

	//We come here on CActiveScheduler::Stop()
	delete CodeModifierServer;
	delete pR;
	__UHEAP_MARKEND;
	return(KErrNone);
	}

//Initializes the globals and switch off lazy (un)loader. Called just once at the start.
void UpdateClientsGlobals()
	{
	TInt* ptr = (TInt*)TestFunc;
	TestFuncCode.iBRK = *(ptr++);
	TestFuncCode.iNOP = *(ptr++);
	TestFuncCode.iRET = *(ptr++);
	test.Printf(_L("UpdateClientsGlobals BRK:%x NOP:%x RET:%x\n"),TestFuncCode.iBRK,TestFuncCode.iNOP,TestFuncCode.iRET);

	ServerData[0].iAppName=&KAppXIP;
	ServerData[1].iAppName=&KAppNONXIP;
	ServerData[0].iServerName=&KServerXIP;
	ServerData[1].iServerName=&KServerNONXIP;

	//Turn off lazy dll (un)loader.
	//If we don't this, the second run of the test (within 2 minutes of the first one) would fail.
	RLoader l;
	test_KErrNone(l.Connect());
	test_KErrNone(l.CancelLazyDllUnload());
	l.Close();
	}
	
//Starts the server (0-XIP 1-NONXIP server)
//Obtains data from the server
//Updates the driver with the threadID of the server
void StartAndUpdate(TInt aServer)
	{
	TRequestStatus status;
	RProcess& p = ServerData[aServer].iProcess;
	test.Printf(_L("StartAndUpdate %d\n"),aServer);
	//Starts the server
	TInt r = p.Create(*ServerData[aServer].iAppName,*ServerData[aServer].iServerName);
	test_KErrNone(r);
	p.Rendezvous(status);
	p.Resume();
	User::WaitForRequest(status);
	test.Printf(_L("%d returned\n"),status.Int());
	test_KErrNone(status.Int());
	//Get threadId and addresses from the server
	test_KErrNone(RCodeModifierSession::GetServerInfo(aServer));
	SServerData& s = ServerData[aServer];
	test.Printf(_L("ServerData:TId:%x VA:%x FA:%x IA:%x CA:%x \n"),s.iThreadId,s.iVarAddr,s.iFuncAddr,s.iInvalidAddr,s.iCodeAreaAddr);
	//Update threadID of the server in device driver
	test_KErrNone(Device.ThreadId(aServer, s.iThreadId));
	}

//Kills the server(by forcing to execute TestFunc), then restarts it.
void KillAndRestart(TInt aServer)
	{
	test.Printf(_L("KillAndRestart %d\n"),aServer);
	TInt r=RCodeModifierSession::RunTestFunc(aServer);
	test.Printf(_L("%d returned\n"),r);

	test.Printf(_L("Check the server died\n"));
	r = RCodeModifierSession::GetServerInfo(aServer);
	test.Printf(_L("%d returned\n"),r);
	test(r!=KErrNone);
	
	StartAndUpdate(aServer);
	}

//Terminates the server
void TerminateServer(TInt aServer)
	{
	TRequestStatus status;
	RProcess& p = ServerData[aServer].iProcess;

	test.Printf(_L("TerminateServer %d\n"),aServer);
	test_KErrNone(RCodeModifierSession::Stop(aServer));
	p.Logon(status);
	User::WaitForRequest(status);
	test_Equal(EExitKill, p.ExitType());
	CLOSE_AND_WAIT(p);
	}

//Starts LDD
void StartDriver()
	{
	test.Printf(_L("StartDriver\n"));
	TInt r = User::LoadLogicalDevice(KCodeModifierName);
	test_Value(r, r==KErrNone || r==KErrAlreadyExists);
	if((r = Device.Open())!=KErrNone)	
		{
		User::FreeLogicalDevice(KCodeModifierName);
		test.Printf(_L("Could not open LDD"));
		test(0);
		}
	}

//Unloads LDD
void StopDriver()
	{
	test.Printf(_L("StopDriver\n"));
	Device.Close();
	User::FreeLogicalDevice(KCodeModifierName);
	}

//Checks that TestFunc in servers is really deadly if we do not alter the code
void Test1()
	{
	test.Printf(_L("Test1\n"));
	KillAndRestart(EXip);
	}

//Passing data segment address to set breakpoint.
//The actual behaviour depends of the memory model
//ARMv5: KErrBadDescriptor (-38) is returned
//ARMv6: Will return 0
//We have to make sure here that nothing panics or take any nasty behaviour.
void Test2(TInt aServer)
	{
	TInt val;
	test.Printf(_L("Test2 %d\n"), aServer);
	test_KErrNone(Device.InitialiseCodeModifier(10));

	//Write/read data through ThreadRowWrite/Read
	test_KErrNone(Device.WriteWord(aServer, ServerData[aServer].iVarAddr,/*value*/1));
	test_KErrNone(Device.ReadWord(aServer, ServerData[aServer].iVarAddr,&val));
	test_Equal(1, val);
		
	//Set breakpoint
	TInt r=Device.WriteCode(aServer, ServerData[aServer].iVarAddr,/*value*/5, /*size*/4);
	test.Printf(_L("returns %d\n"),r);

	test_KErrNone(Device.CloseCodeModifier());
	}

//Passing invalid address to set breakpoint.
void Test3(TInt aServer)
	{
	TInt val;
	test.Printf(_L("Test3 %d\n"), aServer);
	test_KErrNone(Device.InitialiseCodeModifier(10));

	//Write/read by ThreadRowWrite/Read
	test_Equal(KErrBadDescriptor, Device.WriteWord(aServer, ServerData[aServer].iInvalidAddr,/*value*/1));
	test_Equal(KErrBadDescriptor, Device.ReadWord(aServer, ServerData[aServer].iInvalidAddr,&val));
		
	//Set breakpoints
	test_Equal(KErrBadDescriptor, Device.WriteCode(aServer, ServerData[aServer].iInvalidAddr,/*value*/5, /*size*/1));
	test_Equal(KErrBadDescriptor, Device.WriteCode(aServer, ServerData[aServer].iInvalidAddr,/*value*/5, /*size*/2));
	test_Equal(KErrBadDescriptor, Device.WriteCode(aServer, ServerData[aServer].iInvalidAddr,/*value*/5, /*size*/4));

	test_KErrNone(Device.CloseCodeModifier());
	}

//Replace BRK in TestFunc in server using 1,2 and 4 long breakpoints.
//Check the content of test func.
//Execute Test Func
void Test4(TInt aServer)
	{
	TInt var;
	test.Printf(_L("Test4 %d\n"), aServer);

	//Try to write code segment throught Kern::ThreadRowWrite
	test_Equal(KErrBadDescriptor, Device.WriteWord(aServer, ServerData[aServer].iFuncAddr,/*value*/1));

	test_KErrNone(Device.InitialiseCodeModifier(10));

	test.Printf(_L("Replace byte 3 of the 1st instruction\n"));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iFuncAddr+3,TestFuncCode.iNOP>>24, /*size*/1));
	test_KErrNone(Device.ReadWord(aServer,ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test((TUint)var == ((TestFuncCode.iBRK & 0xffffff) | (TestFuncCode.iNOP & 0xff000000)));

	test.Printf(_L("Replace byte 2 of the 1st instruction\n"));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iFuncAddr+2,TestFuncCode.iNOP>>16, /*size*/1));
	test_KErrNone(Device.ReadWord(aServer,ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test((TUint)var == ((TestFuncCode.iBRK & 0xffff) | (TestFuncCode.iNOP & 0xffff0000)));

	test.Printf(_L("Replace bytes 0 & 1 of the 1st instruction\n"));
	var = TestFuncCode.iNOP | 0xff0000; //byte 3 is messed up - but it won't be writen into code bacause iSize is 2
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iFuncAddr,var, /*size*/2));
	test_KErrNone(Device.ReadWord(aServer,ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test_Equal(TestFuncCode.iNOP, var);

	//We have replaced BRK with NOP. It should be safe now for the server to execute TestFunc.
	test.Printf(_L("Run TestFunc in server and check the server is still alive\n"));
	test_KErrNone(RCodeModifierSession::RunTestFunc(aServer));
	test_KErrNone(RCodeModifierSession::GetServerInfo(aServer));//Any call will work here

	test.Printf(_L("Revert bytes 0 & 1\n"));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iFuncAddr));
	test_KErrNone(Device.ReadWord(aServer, ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test((TUint)var == ((TestFuncCode.iBRK & 0xffff) | (TestFuncCode.iNOP & 0xffff0000)));

	test.Printf(_L("Revert byte 2\n"));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iFuncAddr+2));
	test_KErrNone(Device.ReadWord(aServer, ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test((TUint)var == ((TestFuncCode.iBRK & 0xffffff) | (TestFuncCode.iNOP & 0xff000000)));

	test.Printf(_L("Revert byte 3\n"));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iFuncAddr+3));
	test_KErrNone(Device.ReadWord(aServer, ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test(var == TestFuncCode.iBRK);

	test.Printf(_L("Replace the 1st instruction with the 2nd one in TestFunc\n"));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iFuncAddr,TestFuncCode.iNOP, /*size*/4));
	test_KErrNone(Device.ReadWord(aServer,ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test(var == TestFuncCode.iNOP);

	//We have replaced BRK with NOP. It should be safe now for the server to execute TestFunc.
	test.Printf(_L("Run TestFunc in server and check the server is still alive\n"));
	test_KErrNone(RCodeModifierSession::RunTestFunc(aServer));
	test_KErrNone(RCodeModifierSession::GetServerInfo(aServer));//Any call will work here

	test_KErrNone(Device.CloseCodeModifier());
	}

//Executes Test4 but with previously shadowed page
void Test5(TInt aServer)
	{
	test.Printf(_L("Test5 %d\n"), aServer);

	test_KErrNone(Device.AllocShadowPage(ServerData[aServer].iFuncAddr));
	Test4(aServer);	
	test_KErrNone(Device.FreeShadowPage(ServerData[aServer].iFuncAddr));
	}

//Tests scenario when a process terminates while there are still associated breakpoints.
void Test6(TInt aServer)
	{
	TInt var;
	test.Printf(_L("Test6 %d\n"), aServer);

	test_KErrNone(Device.InitialiseCodeModifier(10));

	test.Printf(_L("Replace the 1st instruction (BRK) with the 2nd one (NOP) in TestFunc\n"));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iFuncAddr,TestFuncCode.iNOP, /*size*/4));
	test_KErrNone(Device.ReadWord(aServer,ServerData[aServer].iFuncAddr, &var));
	test.Printf(_L("%xH returned\n"),var);
	test(var == TestFuncCode.iNOP);

	TerminateServer(aServer);
	//After application has stopped, Kernel should clean the breakpoint associated to the server's process....
	
	StartAndUpdate(aServer);
	KillAndRestart(aServer);//... and TestFunct must be deadly again.

	test_KErrNone(Device.CloseCodeModifier());
	}

//Tests out-of-breakpoints scenario
void Test7(TInt aServer)
	{
	test.Printf(_L("Test7 %d\n"), aServer);
	test_KErrNone(Device.InitialiseCodeModifier(1));

	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr,TestFuncCode.iNOP, /*size*/4));
	test_Equal(KErrNoMemory, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+4,TestFuncCode.iNOP, /*size*/4));

	test_KErrNone(Device.CloseCodeModifier());
	}

//Tests breakpoint-already-exists scenario
void Test8(TInt aServer)
	{
	test.Printf(_L("Test8 %d\n"), aServer);
	test_KErrNone(Device.InitialiseCodeModifier(1));

	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr,TestFuncCode.iNOP, /*size*/4));
	test_Equal(KErrAlreadyExists, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr,TestFuncCode.iNOP, /*size*/4));

	test_KErrNone(Device.CloseCodeModifier());
	}

//Tests CodeModifier closing when there are still breakpoints.
//Breakpoints in this test occupies more then one shadowed page.
void Test9()
	{
	TInt var;
	test.Printf(_L("Test9\n"));
	test_KErrNone(Device.InitialiseCodeModifier(10));

	//Put NOPs at the beginning of the code area
	test_KErrNone(Device.WriteCode(EXip, ServerData[EXip].iCodeAreaAddr,TestFuncCode.iNOP, /*size*/4));
	test_KErrNone(Device.WriteCode(ENonxip, ServerData[ENonxip].iCodeAreaAddr,TestFuncCode.iNOP, /*size*/4));

	//Put NOPs at the end of the code area (there are 1024 BRK instructions in CodeArea
	test_KErrNone(Device.WriteCode(EXip, ServerData[EXip].iCodeAreaAddr+1024*sizeof(TInt),TestFuncCode.iNOP, /*size*/4));
	test_KErrNone(Device.WriteCode(ENonxip, ServerData[ENonxip].iCodeAreaAddr+1024*sizeof(TInt),TestFuncCode.iNOP, /*size*/4));

	//Check NOPs are there
	test_KErrNone(Device.ReadWord(EXip,ServerData[EXip].iCodeAreaAddr, &var));
	test_Equal(TestFuncCode.iNOP, var);
	test_KErrNone(Device.ReadWord(ENonxip,ServerData[ENonxip].iCodeAreaAddr, &var));
	test_Equal(TestFuncCode.iNOP, var);
	test_KErrNone(Device.ReadWord(EXip,ServerData[EXip].iCodeAreaAddr+1024*sizeof(TInt), &var));
	test_Equal(TestFuncCode.iNOP, var);
	test_KErrNone(Device.ReadWord(ENonxip,ServerData[ENonxip].iCodeAreaAddr+1024*sizeof(TInt), &var));
	test_Equal(TestFuncCode.iNOP, var);

	//Close Code Modifier. It should revert the changes in the code.
	test_KErrNone(Device.CloseCodeModifier());

	//Check BRKs are back
	test_KErrNone(Device.ReadWord(EXip,ServerData[EXip].iCodeAreaAddr, &var));
	test_Equal(TestFuncCode.iBRK, var);
	test_KErrNone(Device.ReadWord(ENonxip,ServerData[ENonxip].iCodeAreaAddr, &var));
	test_Equal(TestFuncCode.iBRK, var);
	test_KErrNone(Device.ReadWord(EXip,ServerData[EXip].iCodeAreaAddr+1023*sizeof(TInt), &var));
	test_Equal(TestFuncCode.iBRK, var);
	test_KErrNone(Device.ReadWord(ENonxip,ServerData[ENonxip].iCodeAreaAddr+1023*sizeof(TInt), &var));
	test_Equal(TestFuncCode.iBRK, var);
	}



//Used in test 10 to keep the list of breakpoints
class TBrks:public CBase //derived from CBase as we need data initialized to 0
	{
public:	
	TInt iCounter;				//Counts the number of the active brakpoints
	TInt8 iBreakpoint[1025][2];		//0 - no breakpoint, 1-breakpoint set in CodeArea of XIP Server & NON-XIP server
	};

//Performs a random stress test on breakpoint pool.
//There are 1025*2 words in CodeArea in xip and non-xip server.
//A word is randomly picked up to set or clear 4 bytes long breakpoint.
void Test10()
	{
	TInt i,index,whichServer,var;
	TBrks* brks = new TBrks;
	test((TInt)brks);//fail if no memory
	TUint iSeed[2];
	iSeed[0]=User::TickCount();
	iSeed[1]=0;
	test.Printf(_L("Test10 iSeed=%x\n"), iSeed[0]);

	test_KErrNone(Device.InitialiseCodeModifier(2050));//enought to replace all BRK instructions in CodeArea with NOPs in both servers

	for (i=0; i<1000;i++)
		{
		index=Random(iSeed)%2050;
		whichServer = index>1024 ? 1 : 0;
		if (index >1024)
			index-=1025;
		
		TInt8& brk = brks->iBreakpoint[index][whichServer];
		 if (brk)
		 	{//Remove breakpoint
		 	brk = 0;
			test_KErrNone(Device.RestoreCode(whichServer, ServerData[whichServer].iCodeAreaAddr+index*sizeof(TInt)));
			brks->iCounter--;
		 	}
		 else
		 	{//Set breakpoint
		 	brk = 1;
			test_KErrNone(Device.WriteCode(whichServer, ServerData[whichServer].iCodeAreaAddr+index*sizeof(TInt),TestFuncCode.iNOP, /*size*/4));
			brks->iCounter++;	 	
		 	}
		}
	
	test.Printf(_L("Breakpoints left:%d\n"), brks->iCounter);

	//Check the content of the CodeArea in both XIP and Non-XIP Server
	for (i=0; i<2050;i++)
		{
		whichServer = i>1024 ? 1 : 0;
		if (i<=1024)index = i;
		else		index = i-1025;

		test_KErrNone(Device.ReadWord(whichServer,ServerData[whichServer].iCodeAreaAddr+index*sizeof(TInt), &var));
		if(brks->iBreakpoint[index][whichServer])
			test(var == TestFuncCode.iNOP); //Well, breakpoint is actually NOP ...
		else
			test(var == TestFuncCode.iBRK); //... while the original content is BRK instruction
		}

	//Now, apply breakpoints on all remaining addresses
	for (i=0; i<2050;i++)
		{
		whichServer = i>1024 ? 1 : 0;
		if (i<=1024)index = i;
		else		index = i-1025;

		if(!brks->iBreakpoint[index][whichServer])
			test_KErrNone(Device.WriteCode(whichServer, ServerData[whichServer].iCodeAreaAddr+index*sizeof(TInt),TestFuncCode.iNOP, /*size*/4));
		}

	//All BRKs are replaced with NOPs in CodeArea function in both Servers. It should be safe to call the function.
	test_KErrNone(RCodeModifierSession::RunCodeAreaFunc(EXip));
	test_KErrNone(RCodeModifierSession::GetServerInfo(EXip));//This will check the server is still alive
	test_KErrNone(RCodeModifierSession::RunCodeAreaFunc(ENonxip));
	test_KErrNone(RCodeModifierSession::GetServerInfo(ENonxip));//This will check the server is still alive

	test_KErrNone(Device.CloseCodeModifier()); //This will also remove all breakpoints
	delete brks;
	}

//Tests out-of-breakpoints scenario
void Test11(TInt aServer)
	{
	test.Printf(_L("Test11 %d\n"), aServer);
	test_KErrNone(Device.InitialiseCodeModifier(10));

	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+4, /*aValue*/0, /*size*/4));

	//4 bytes breakpoint
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/4));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/2));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+2, /*aValue*/0, /*size*/2));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/1));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+1, /*aValue*/0, /*size*/1));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+2, /*aValue*/0, /*size*/1));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+3, /*aValue*/0, /*size*/1));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr));

	//2 bytes breakpoint aligned to word
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/2));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/4));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/1));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+1, /*aValue*/0, /*size*/1));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+2, /*aValue*/0, /*size*/2));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr+2));

	//2 bytes breakpoint aligned to word+2
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+2, /*aValue*/0, /*size*/2));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/4));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+2, /*aValue*/0, /*size*/1));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+3, /*aValue*/0, /*size*/1));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/2));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr+2));

	//1 byte breakpoint
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/1));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/4));
	test_Equal(KErrAccessDenied, Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr, /*aValue*/0, /*size*/2));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+1, /*aValue*/0, /*size*/1));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+2, /*aValue*/0, /*size*/1));
	test_KErrNone(Device.WriteCode(aServer, ServerData[aServer].iCodeAreaAddr+3, /*aValue*/0, /*size*/1));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr+1));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr+2));
	test_KErrNone(Device.RestoreCode(aServer, ServerData[aServer].iCodeAreaAddr+3));

	test_KErrNone(Device.CloseCodeModifier());
	}


void ClientAppL()
	{
	test.Start(_L("ClientAppL"));
	UpdateClientsGlobals();
	StartDriver();	
	StartAndUpdate(EXip);
	StartAndUpdate(ENonxip);
	
// All tests run with the following pre-conditions:
// - both XIP and nonXIP server are running.
// - device driver has updated servers' threadIDs (used for setting breakpoints and reading/writing data).
// - all global variables (ServerData, TestFuncCode)are valid.
// - CodeModifier is not installed.
	Test1();
	Test2(EXip);
	Test2(ENonxip);
	Test3(EXip);
	Test3(ENonxip);
	Test4(EXip);
	Test4(ENonxip);
	Test5(EXip);
	Test6(EXip);
	Test7(EXip);
	Test8(EXip);
	Test9();
	Test10();
	Test11(EXip);
	Test11(ENonxip);
	TerminateServer(EXip);
	TerminateServer(ENonxip);
	StopDriver();	
	test.End();
	}

/**Entry point for both client and server apps*/
TInt E32Main()
	{
	//Chech if we are client, XIP server or nonXIP server
	TBuf<64> c;
	User::CommandLine(c);
	if (c.FindF(KServerXIP) >= 0) 
		return ServerEntryPoint(EXip);
	if (c.FindF(KServerNONXIP) >= 0) 
		return ServerEntryPoint(ENonxip);
	
	// client
	CTrapCleanup* trap = CTrapCleanup::New();
	if (!trap)
		return KErrNoMemory;
	test.Title();
	__UHEAP_MARK;
	TRAPD(r,ClientAppL());
	__UHEAP_MARKEND;
	delete trap;
	return r;
	}