diff -r 000000000000 -r 96e5fb8b040d kerneltest/e32test/debug/t_codemodifier.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/debug/t_codemodifier.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -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 +#include +#include +#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; + }