--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/debug/t_codemodifier.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,764 @@
+// 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 <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;
+ }