# HG changeset patch # User hgs # Date 1282898249 -10800 # Node ID 0ff24a8f6ca29ed379b0410731a49d250104fe25 # Parent 838cdffd57cec4730b0287ba5ac5b1f94bcd0efd 201033 diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/build.config.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/build.config.xml Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]> + + + + + + + + + + + + + + + \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/group/bld.inf Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,25 @@ +// Copyright (c) 2010 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: +// Run mode component and test top level bld.inf +// +// + +/** + @file +*/ + +#include "../rmdriver/group/bld.inf" + + +#include "../rmdebug_test/group/bld.inf" \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/eabi/t_rmdebug_dllu.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/eabi/t_rmdebug_dllu.def Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,3 @@ +EXPORTS + _Z9GetDSSUidv @ 1 NONAME + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/group/bld.inf Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,22 @@ +// Copyright (c) 2010 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: +// Kernel and User library test code +// +// + +/** + @file +*/ + +#include "../rm_debug/group/bld.inf" diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/group/e32test.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/group/e32test.bld Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,5 @@ + +!EXPLICIT +!INCREMENTAL + +e32test e32test\group diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/group/mk_rmdbg_test.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/group/mk_rmdbg_test.bat Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,18 @@ +@rem +@rem Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +@rem All rights reserved. +@rem This component and the accompanying materials are made available +@rem under the terms of "Eclipse Public License v1.0" +@rem which accompanies this distribution, and is available +@rem at the URL "http://www.eclipse.org/legal/epl-v10.html". +@rem +@rem Initial Contributors: +@rem Nokia Corporation - initial contribution. +@rem +@rem Contributors: +@rem +@rem Description: +@rem + +makesis rmdbg_test.pkg +signsis rmdbg_test.sis rmdbg_test.sisx RDTest_02.der RDTest_02.key \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_kernel_low_memory_security_svr_session.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_kernel_low_memory_security_svr_session.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,39 @@ +// 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: +// Implementation of RKernelLowMemorySecuritySvrSession +// +// + +#include "r_kernel_low_memory_security_svr_session.h" + +void RKernelLowMemorySecuritySvrSession::FailAlloc(const TInt aCount) + { + __KHEAP_FAILNEXT(aCount); + } + +void RKernelLowMemorySecuritySvrSession::HeapReset() + { + __KHEAP_RESET; + } + +void RKernelLowMemorySecuritySvrSession::MarkHeap() + { + __KHEAP_MARK; + } + +void RKernelLowMemorySecuritySvrSession::MarkHeapEnd() + { + __KHEAP_MARKEND; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_kernel_low_memory_security_svr_session.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_kernel_low_memory_security_svr_session.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,39 @@ +// 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: +// Version of security server session to enable testing of low memory conditions on kernel side +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef R_KERNEL_LOW_MEMORY_SECURITY_SVR_SESSION_H +#define R_KERNEL_LOW_MEMORY_SECURITY_SVR_SESSION_H + +#include "r_low_memory_security_svr_session.h" + +class RKernelLowMemorySecuritySvrSession : public RLowMemorySecuritySvrSession + { +protected: + void FailAlloc(const TInt aCount); + void HeapReset(); + void MarkHeap(); + void MarkHeapEnd(); + }; + +#endif //R_KERNEL_LOW_MEMORY_SECURITY_SVR_SESSION_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_low_memory_security_svr_session.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_low_memory_security_svr_session.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,86 @@ +// 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: +// Implementation of RLowMemorySecuritySvrSession +// +// + +#include "r_low_memory_security_svr_session.h" +#include + +// test the effects of heap failure on global RSecuritySvrSession::GetList() in debug mode, +// in release mode normal call is made (heap checking not applicable) +TInt RLowMemorySecuritySvrSession::GetList(const Debug::TListId aListId, TDes8& aListData, TUint32& aDataSize) + { + TInt failAt = 0; + TInt err = KErrNoMemory; + while(err == KErrNoMemory) + { + failAt++; + FailAlloc(failAt); + MarkHeap(); + err = this->RSecuritySvrSession::GetList(aListId, aListData, aDataSize); + if(KErrNoMemory == err) + { + MarkHeapEnd(); + } + HeapReset(); + //RDebug::Printf("Debug::RLowMemorySecuritySvrSession::GetList(): failAt: %d, err: %d", failAt, err); + } + return err; + } + +// test the effects of heap failure on thread-specific RSecuritySvrSession::GetList() in debug mode, +// in release mode normal call is made (heap checking not applicable) +TInt RLowMemorySecuritySvrSession::GetList(const TThreadId aThreadId, const Debug::TListId aListId, TDes8& aListData, TUint32& aDataSize) + { + TInt failAt = 0; + TInt err = KErrNoMemory; + while(err == KErrNoMemory) + { + failAt++; + FailAlloc(failAt); + MarkHeap(); + err = this->RSecuritySvrSession::GetList(aThreadId, aListId, aListData, aDataSize); + if(KErrNoMemory == err) + { + MarkHeapEnd(); + } + HeapReset(); + //RDebug::Printf("Debug::RLowMemorySecuritySvrSession::GetList(TThreadId): failAt: %d, err: %d", failAt, err); + } + return err; + } + +// test the effects of heap failure on process-specific RSecuritySvrSession::GetList() in debug mode, +// in release mode normal call is made (heap checking not applicable) +TInt RLowMemorySecuritySvrSession::GetList(const TProcessId aProcessId, const Debug::TListId aListId, TDes8& aListData, TUint32& aDataSize) + { + TInt failAt = 0; + TInt err = KErrNoMemory; + while(err == KErrNoMemory) + { + failAt++; + FailAlloc(failAt); + MarkHeap(); + err = this->RSecuritySvrSession::GetList(aProcessId, aListId, aListData, aDataSize); + if(KErrNoMemory == err) + { + MarkHeapEnd(); + } + HeapReset(); + //RDebug::Printf("Debug::RLowMemorySecuritySvrSession::GetList(TProcessId): failAt: %d, err: %d", failAt, err); + } + return err; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_low_memory_security_svr_session.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_low_memory_security_svr_session.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,43 @@ +// 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: +// Version of security server session to enable testing of low memory conditions +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef R_LOW_MEMORY_SECURITY_SVR_SESSION_H +#define R_LOW_MEMORY_SECURITY_SVR_SESSION_H + +#include + +class RLowMemorySecuritySvrSession : public Debug::RSecuritySvrSession + { +public: + TInt GetList(const Debug::TListId aListId, TDes8& aListData, TUint32& aDataSize); + TInt GetList(const TThreadId aThreadId, const Debug::TListId aListId, TDes8& aListData, TUint32& aDataSize); + TInt GetList(const TProcessId aProcessId, const Debug::TListId aListId, TDes8& aListData, TUint32& aDataSize); +protected: + virtual void FailAlloc(const TInt aCount) = 0; + virtual void HeapReset() = 0; + virtual void MarkHeap() = 0; + virtual void MarkHeapEnd() = 0; + }; + +#endif //R_LOW_MEMORY_SECURITY_SVR_SESSION_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_user_low_memory_security_svr_session.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_user_low_memory_security_svr_session.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,54 @@ +// 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: +// r_kernel_low_memory_security_svr_session.cpp +// Implementation of RUserLowMemorySecuritySvrSession +// +// + +#include "r_user_low_memory_security_svr_session.h" +#include +#ifdef _DEBUG +#include "low_mem_requests.h" +#endif + +void RUserLowMemorySecuritySvrSession::FailAlloc(const TInt aCount) + { +#ifdef _DEBUG + TIpcArgs args(aCount); + SendReceive(EDebugServFailAlloc, args); +#endif + } + +void RUserLowMemorySecuritySvrSession::HeapReset() + { +#ifdef _DEBUG + TIpcArgs args(0); + SendReceive(EDebugServFailAlloc, args); +#endif + } + +void RUserLowMemorySecuritySvrSession::MarkHeap() + { +#ifdef _DEBUG + SendReceive(EDebugServMarkHeap); +#endif + } + +void RUserLowMemorySecuritySvrSession::MarkHeapEnd() + { +#ifdef _DEBUG + SendReceive(EDebugServMarkEnd); +#endif + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_user_low_memory_security_svr_session.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/r_user_low_memory_security_svr_session.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,39 @@ +// 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: +// Version of security server session to enable testing of low memory conditions on user side +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef R_USER_LOW_MEMORY_SECURITY_SVR_SESSION_H +#define R_USER_LOW_MEMORY_SECURITY_SVR_SESSION_H + +#include "r_low_memory_security_svr_session.h" + +class RUserLowMemorySecuritySvrSession : public RLowMemorySecuritySvrSession + { +protected: + void FailAlloc(const TInt aCount); + void HeapReset(); + void MarkHeap(); + void MarkHeapEnd(); + }; + +#endif //R_USER_LOW_MEMORY_SECURITY_SVR_SESSION_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/t_rmdebug2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/t_rmdebug2.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,4985 @@ +// Copyright (c) 2006-2010 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: +// Tests the functionality of the run mode debug device driver. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "t_rmdebug_dll.h" + +#include +#include "d_rmdebugthread2.h" +#include "t_rmdebug2.h" +#include "t_rmdebug_app.h" + +#ifdef __MARM_ARMV4__ +#include "d_rmdebug_step_test_armv4.h" +#endif + +#ifdef __MARM_ARMV5__ +#include "d_rmdebug_step_test.h" +#include "d_rmdebug_bkpt_test.h" +#endif + +#include "d_demand_paging.h" + +#ifdef KERNEL_OOM_TESTING + #ifdef USER_OOM_TESTING + #error "Cannot define both KERNEL_OOM_TESTING and USER_OOM_TESTING" + #endif +#endif + +#if defined (NO_DEBUGTOKEN) || defined (SOMECAPS_DEBUGTOKEN) || defined (FEWCAPS_DEBUGTOKEN) +_LIT8(KCrashDummyData, "This is a sample write"); +#endif + +using namespace Debug; + +const TVersion securityServerVersion(0,1,1); + +const TVersion testVersion(2,1,0); + +IMPORT_C TInt StartDebugThread(RThread& aServerThread, const TDesC& aDebugThreadName); + +extern TInt TestData; +extern TTestFunction FunctionChooser; +extern TBuf8 gMemoryAccessBytes; + +IMPORT_C TInt TestFunction(); +IMPORT_C void TestPagedCode(); +IMPORT_C extern TInt RMDebugDemandPagingTest(); + +// Device driver name +_LIT(KDebugDriverFileName,"rm_debug.ldd"); +_LIT(KRMDebugAppName, "t_rmdebug_app"); + + +#if defined(NO_DEBUGTOKEN) + _LIT(KTestName, "T_RMDEBUG2"); +#elif defined(SOMECAPS_DEBUGTOKEN) + _LIT(KTestName, "T_RMDEBUG2_OEM"); +#elif defined(FEWCAPS_DEBUGTOKEN) + _LIT(KTestName, "T_RMDEBUG2_OEM2"); +#elif defined(ALLCAPS_DEBUGTOKEN) + _LIT(KTestName, "T_RMDEBUG2_ALLCAPS"); +#endif + +#define TIMED_WAIT(request, timeoutInMs) CRunModeAgent::TimedWait(request, timeoutInMs, __LINE__) + +LOCAL_D RTest test(KTestName); + +TBool gUseDelay; + +CRunModeAgent::CRunModeAgent() +// +// CRunModeAgent constructor +// + { + FillArray(); + RProcess thisProcess; + iFileName = thisProcess.FileName(); + thisProcess.Close(); + } + +CRunModeAgent* CRunModeAgent::NewL() +// +// CRunModeAgent::NewL +// + { + CRunModeAgent* self = new(ELeave) CRunModeAgent(); + + self->ConstructL(); + + return self; + } + +CRunModeAgent::~CRunModeAgent() +// +// CRunModeAgent destructor +// + { + iTimer.Close(); + iRunCountSubscribe.Close(); + + User::FreeLogicalDevice(KDebugDriverFileName); + iServSession.Close(); + iDebugThread.Close(); + } + +void CRunModeAgent::ConstructL() +// +// CRunModeAgent::ConstructL +// + { + // nothing to do here + } + +void CRunModeAgent::SetupAndAttachToDSS() +// +// CRunModeAgent::SetupAndAttachToDSS +// + { + TInt err = StartDebugThread(iDebugThread, KDebugThreadName); + + // get the thread id for use in the tests + iThreadID = iDebugThread.Id(); + + if (err != KErrNone) + { + User::Panic(_L("Can't start debug thread"), err); + } + + err = iRunCountSubscribe.Attach( RProcess().SecureId(), CDebugServThread::ERMDBGRunCountProperty); + if (err != KErrNone) + { + User::Panic(_L("Can't attach to RProperty iRunCountSubscribe"), err); + } + + err = iTimer.CreateLocal(); + if (err != KErrNone) + { + User::Panic(_L("Can't create RTimer::CreateLocal()"), err); + } + + err = iServSession.Connect(securityServerVersion); + if (err != KErrNone) + { + User::Panic(_L("Can't open server session"), err); + } + } + +CRunModeAgent *RunModeAgent; + +// helper function to check whether the listing of type aListId is supported for a scope of aListScope +TBool CRunModeAgent::ListingSupported(const TListId aListId, const TListScope aListScope) + { + TTag tag = GetTag(ETagHeaderList, aListId); + + return (tag.iValue) & aListScope; + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0426 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test getting the list of XIP libraries +//! @SYMTestActions The XIP library list should be successfully obtained +//! @SYMTestExpectedResults The specified ldd file should be present in the obtained listing +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestGetXipLibrariesList() + { + test.Next(_L("TestGetXipLibrariesList\n")); + + test(ListingSupported(EXipLibraries, EScopeGlobal)); + test(!ListingSupported(EXipLibraries, EScopeProcessSpecific)); + test(!ListingSupported(EXipLibraries, EScopeThreadSpecific)); + + //allocate a very small buffer so the GetList call initially fails + RBuf8 buffer; + test(KErrNone == buffer.Create(1)); + TUint32 size = 0; + + //get the list data + DoGetList(EXipLibraries, EScopeGlobal, buffer, size); + + //search the buffer for entry corresponding to the debug kernel driver + //which should be in the rom + _LIT(KRmDebugLddName, "z:\\sys\\bin\\rm_debug.ldd"); + + //iterate through the buffer and set found to ETrue if we find the driver + TBool found = EFalse; + TUint8* ptr = (TUint8*)buffer.Ptr(); + const TUint8* ptrEnd = ptr + size; + while(ptr < ptrEnd) + { + TXipLibraryListEntry& xipLibrary = *(TXipLibraryListEntry*)ptr; + + //get the name of the library + TPtr name(&xipLibrary.iName[0], xipLibrary.iNameLength, xipLibrary.iNameLength); + if(name.CompareF(KRmDebugLddName()) == 0) + { + //found the library but continue reading the rest of the buffer to + //check nothing bad happens towards the end + found = ETrue; + } + //move pointer on to next library + ptr += Align4(xipLibrary.GetSize()); + } + test(found); + + //do cleanup + buffer.Close(); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0427 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test getting the list of executables +//! @SYMTestActions The list of debuggable executable files should be obtained +//! @SYMTestExpectedResults The client exe should appear in the list +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestGetExecutablesList() + { + test.Next(_L("TestGetExecutablesList\n")); + + test(ListingSupported(EExecutables, EScopeGlobal)); + test(!ListingSupported(EExecutables, EScopeProcessSpecific)); + test(!ListingSupported(EExecutables, EScopeThreadSpecific)); + + //allocate a very small buffer so the GetList call initially fails + RBuf8 buffer; + test(KErrNone == buffer.Create(1)); + TUint32 size = 0; + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + //get the list data + DoGetList(EExecutables, EScopeGlobal, buffer, size); + + //get this process' name + RProcess thisProcess; + TFileName thisProcessName = thisProcess.FileName(); + + //look through the buffer and check if the target debug thread is there + TBool found = EFalse; + TUint8* ptr = (TUint8*)buffer.Ptr(); + const TUint8* ptrEnd = ptr + size; + while(ptr < ptrEnd) + { + TExecutablesListEntry& entry = *(TExecutablesListEntry*)ptr; + //get name + TPtr name(&entry.iName[0], entry.iNameLength, entry.iNameLength); + if( (entry.iIsActivelyDebugged != 0) && (0 == thisProcessName.CompareF(name)) ) + { + //found this process and asserted it is being actively debugged + found = ETrue; + } + //move pointer on to next entry + ptr += Align4(entry.GetSize()); + } + test(found); + + //clean up + buffer.Close(); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0428 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test error conditions for the GetList calls +//! @SYMTestActions Multiple calls to test calling GetList with bad arguments +//! @SYMTestExpectedResults All tests should fail with the appropriate error codes +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestGetListInvalidData() + { + test.Next(_L("TestGetListInvalidData\n")); + + //allocate a buffer, the size should not matter as expecting all calls to fail + RBuf8 buffer; + test(KErrNone == buffer.Create(1)); + TUint32 size = 0; + + //test what happens if we ask for an unsupported list type globally + test(KErrNotSupported == iServSession.GetList((TListId)1234, buffer, size)); + + //test what happens if we ask for an unsupported list type + test(KErrNotSupported == iServSession.GetList(RThread().Id(), (TListId)1234, buffer, size)); + + //test what happens if we try to get a non-global libraries list + test(KErrArgument == iServSession.GetList(RThread().Id(), EXipLibraries, buffer, size)); + + //test what happens if we try to get a non-global executables list + test(KErrArgument == iServSession.GetList(RThread().Id(), EExecutables, buffer, size)); + + //test what happens if we try to get a non-global process list + test(KErrArgument == iServSession.GetList(RThread().Id(), EProcesses, buffer, size)); + + //check that using a process id fails + test(KErrArgument == iServSession.GetList(RProcess().Id(), EProcesses, buffer, size)); + + //check that specifying a non-existant thread id fails + test(KErrArgument == iServSession.GetList((TThreadId)0x12345678, EThreads, buffer, size)); + + //check that specifying a non-existant process id fails + test(KErrArgument == iServSession.GetList((TProcessId)0x12345678, EThreads, buffer, size)); + + //check that specifying a non-existant thread id fails + test(KErrArgument == iServSession.GetList((TThreadId)0x12345678, ECodeSegs, buffer, size)); + + //check that specifying a non-existant process id fails + test(KErrArgument == iServSession.GetList((TProcessId)0x12345678, ECodeSegs, buffer, size)); + + //cleanup + buffer.Close(); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0429 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test getting the process list +//! @SYMTestActions Get the process listing +//! @SYMTestExpectedResults The process listing should be successfully obtained and the current process should be present in the list +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestGetProcessList() + { + test.Next(_L("TestGetProcessList\n")); + + test(ListingSupported(EProcesses, EScopeGlobal)); + test(!ListingSupported(EProcesses, EScopeProcessSpecific)); + test(!ListingSupported(EProcesses, EScopeThreadSpecific)); + + //allocate a very small buffer so the GetList call fails + RBuf8 buffer; + test(KErrNone == buffer.Create(1)); + TUint32 size = 0; + + //get the list data + DoGetList(EProcesses, EScopeGlobal, buffer, size); + + //initialise data about the target debug thread to compare the kernel's data against + RProcess thisProcess; + TFileName thisProcessName = thisProcess.FileName(); + TUint32 processId = thisProcess.Id().Id(); + + //look through the buffer and check if the target debug thread is there + TBool found = EFalse; + TUint8* ptr = (TUint8*)buffer.Ptr(); + const TUint8* ptrEnd = ptr + size; + while(ptr < ptrEnd) + { + TProcessListEntry& entry = *(TProcessListEntry*)ptr; + if( (RProcess().Id().Id() == entry.iProcessId) && + (0 == thisProcessName.CompareF(TPtr(&(entry.iNames[0]), entry.iFileNameLength, entry.iFileNameLength))) && + (0 == thisProcess.FullName().CompareF(TPtr(&(entry.iNames[0]) + entry.iFileNameLength, entry.iDynamicNameLength, entry.iDynamicNameLength))) && + 0x4321bbbb /* Magic */ == entry.iUid3) + { + //if all match then we've found it + found = ETrue; + } + ptr += Align4(entry.GetSize()); + } + + //check whether the expected result happened + test(found); + + //clean up + buffer.Close(); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0430 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test getting the thread list +//! @SYMTestActions Get the thread listing globally and for a specified thread or process +//! @SYMTestExpectedResults The thread listings should all be successfully obtained and the current thread should be present in all listings +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestGetThreadList() + { + test.Next(_L("TestGetThreadList\n")); + + test(ListingSupported(EThreads, EScopeGlobal)); + test(ListingSupported(EThreads, EScopeProcessSpecific)); + test(ListingSupported(EThreads, EScopeThreadSpecific)); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + test(KErrNone == iServSession.SuspendThread(iThreadID)); + + TBool found = EFalse; + + /* We need these loops because on some system the kernel run mode debugger does not + immediately present the thread in the thread list. + */ + + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting this process's thread list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeProcessSpecific, RProcess().Id().Id()); + } + test( found ); + found = EFalse; + + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting the global list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeGlobal); + } + test( found ); + + found = EFalse; + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting this thread's thread list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeThreadSpecific, RThread().Id().Id()); + } + test( found ); + + test(KErrNone == iServSession.ResumeThread(iThreadID)); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +TBool CRunModeAgent::DoTestGetThreadList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId) + { + //create data to pass + RBuf8 buffer; + TUint32 size = 0; + + //perform the call to get the thread list + DoGetList(EThreads, aListScope, buffer, size, aTargetId); + + //initialise data about the target debug thread to compare the kernel's data against + TFileName name = iDebugThread.FullName(); + RProcess thisProcess; + TUint64 processId = thisProcess.Id(); + TUint64 threadId = iDebugThread.Id(); + + //look through the buffer and check if the target debug thread is there + TBool found = EFalse; + TUint8* ptr = (TUint8*)buffer.Ptr(); + const TUint8* ptrEnd = ptr + size; + while(ptr < ptrEnd) + { + TThreadListEntry* entry = (TThreadListEntry*)ptr; + TPtr entryName(&(entry->iName[0]), entry->iNameLength, entry->iNameLength); + + if( (threadId == entry->iThreadId) && (processId == entry->iProcessId) && (0 == name.CompareF(entryName)) ) + { + test(entry->iSupervisorStackBaseValid); + test(entry->iSupervisorStackSizeValid); + //if all match then we've found it + found = ETrue; + break; + } + + ptr += Align4(entry->GetSize()); + } + + //clean up + buffer.Close(); + return found; + + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0431 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test getting the code segment list +//! @SYMTestActions Get the code segment list global and for a specified thread +//! @SYMTestExpectedResults The listings should be returned successfully +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestGetCodeSegsList() + { + test.Next(_L("TestGetCodeSegsList\n")); + + test(ListingSupported(ECodeSegs, EScopeGlobal)); + test(ListingSupported(ECodeSegs, EScopeProcessSpecific)); + test(ListingSupported(ECodeSegs, EScopeThreadSpecific)); + + // Cannot perform this test with OEM2 debug token, as the t_rmdebug2 app + // needs AllFiles, and the OEM2 debug token does not authorise this. + // It seems reasonable to suppose that it would work anyway + +#ifndef FEWCAPS_DEBUGTOKEN + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + //test getting the global list, ETrue as should find this process' main codeSeg + DoTestGetCodeSegsList(ETrue, EScopeGlobal); + + //test getting this process' codeSegs, ETrue as should find this process' main codeSeg + DoTestGetCodeSegsList(ETrue, EScopeProcessSpecific, RProcess().Id().Id()); + + //test getting this thread's codeSegs, ETrue as should find this process' main codeSeg + DoTestGetCodeSegsList(ETrue, EScopeThreadSpecific, RThread().Id().Id()); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); +#endif // FEWCAPS_DEBUGTOKEN + + } + +void CRunModeAgent::DoTestGetCodeSegsList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId) + { + //create data to pass + RBuf8 buffer; + TUint32 size = 0; + + //perform the call to get the Code segs + DoGetList(ECodeSegs, aListScope, buffer, size, aTargetId); + + //create memoryInfo to contain info about this process + RProcess thisProcess; + TModuleMemoryInfo memoryInfo; + test(KErrNone == thisProcess.GetMemoryInfo(memoryInfo)); + + // check whether this process came from a file in ROM so we know whether to + // expect the code seg to be XIP or not. + RFs fs; + test(KErrNone == fs.Connect()); + TBool thisFileIsInRom = EFalse; + if(fs.IsFileInRom(iFileName)) + { + thisFileIsInRom = ETrue; + } + + //look through the buffer to find this process' main code seg + TBool found = EFalse; + TUint8* ptr = (TUint8*)buffer.Ptr(); + const TUint8* ptrEnd = ptr + size; + while(ptr < ptrEnd) + { + TCodeSegListEntry* codeSeg = (TCodeSegListEntry*)ptr; + + if( (codeSeg->iIsXip == thisFileIsInRom) && (0 == iFileName.CompareF(TPtr(&(codeSeg->iName[0]), codeSeg->iNameLength, codeSeg->iNameLength))) ) + { + if( (memoryInfo.iCodeBase == codeSeg->iCodeBase) && + (memoryInfo.iCodeSize == codeSeg->iCodeSize) && + (memoryInfo.iConstDataSize == codeSeg->iConstDataSize) && + (memoryInfo.iInitialisedDataBase == codeSeg->iInitialisedDataBase) && + (memoryInfo.iInitialisedDataSize == codeSeg->iInitialisedDataSize) && + (memoryInfo.iUninitialisedDataSize == codeSeg->iUninitialisedDataSize)) + { + //all matched so means we've found the codeSeg we're looking for + found = ETrue; + } + } + ptr += Align4(codeSeg->GetSize()); + } + + //check whether the result was as expected + test(found == aShouldPass); + + // only care about rm_debug.ldd if we have global scope (belongs to the system not this process) + if (aListScope == EScopeGlobal) + { + // Search for rm_debug.ldd library and check its UID3 is correct + found = EFalse; + +_LIT(KRMDebugDriverFileName,"Z:\\sys\bin\\rm_debug.ldd"); + + TFileName rmdebugFilename(KRMDebugDriverFileName); + + // reset the Ptr + ptr = (TUint8*)buffer.Ptr(); + ptrEnd = ptr+size; + while(ptr < ptrEnd) + { + TCodeSegListEntry* codeSeg = (TCodeSegListEntry*)ptr; + + if( rmdebugFilename.CompareF(TPtr(&(codeSeg->iName[0]), codeSeg->iNameLength, codeSeg->iNameLength))) + { + if(codeSeg->iUid3 == 0x101f7157 /* Magic */) + { + //all matched so means we've found the codeSeg we're looking for + found = ETrue; + } + } + ptr += Align4(codeSeg->GetSize()); + } + test((TUint32)found == (TUint32)ETrue); + } + + //clean up + buffer.Close(); + + } + + +/** + * Get a list from the run mode debug system. Most list calls will initially return KErrTooBig, + * since the initial size of the buffer is 0. However it is sometimes valid for a list to be empty + * given its filtering and scope. These calls should return KErrNone. + */ +void CRunModeAgent::DoGetList(const TListId aListId, const TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId) + { + //close the buffer in case there's stuff allocated in it + aBuffer.Close(); + //initialise it to be one byte big, which will guarantee data won't fit in it + test(KErrNone == aBuffer.Create(1)); + aSize = 0; + + TInt ret = KErrNone; + //should pass this test (assuming we've passed in sensible arguments above...) + if(EScopeGlobal == aListScope) + { + ret = iServSession.GetList(aListId, aBuffer, aSize); + } + else if(EScopeThreadSpecific == aListScope) + { + ret = iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize); + } + else if(EScopeProcessSpecific == aListScope) + { + ret = iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize); + } + else + { + // unknown list scope + test(0); + } + + if( KErrNone == ret ) + { + /* In the case that there is no data, just return and let the caller check + the buffer. It is valid for a caller to not expect any data to be returned. + */ + return; + } + + // The only other allowed return is KErrTooBig + test( ret == KErrTooBig ); + + //keep allocating larger buffers, beginning with the aSize returned by the above call, + //and hopefully we'll eventually make a large enough one + test(KErrNone == aBuffer.ReAlloc(aSize)); + + for(;;) + { + TInt err = KErrNone; + if(EScopeGlobal == aListScope) + { + err = iServSession.GetList(aListId, aBuffer, aSize); + } + else if(EScopeThreadSpecific == aListScope) + { + err = iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize); + } + else if(EScopeProcessSpecific == aListScope) + { + err = iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize); + } + else + { + // unknown list scope + test(0); + } + if(err == KErrTooBig) + { + //wasn't big enough so double it + aSize = aSize << 1; + err = aBuffer.ReAlloc(aSize); + if(err != KErrNone) + { + //print out a message if couldn't allocate memory and quit + test.Printf(_L("Out ot memory when attempting to allocate %d bytes."), aSize); + test(KErrNone == err); + } + + RDebug::Printf(" List size =%d", aSize ); + } + else + { + test(KErrNone == err); + test(aBuffer.Length() == aSize); + //break out of the loop if the list has been successfully read in + break; + } + } + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0432 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test reading and writing memory +//! @SYMTestActions Multiple calls to read and write memory, with various sizes and at various locations. +//! Also test that bad input values cause appropriate errors to be returned. +//! @SYMTestExpectedResults All tests should pass and the target process should be left unaffected +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestMemoryAccess() +{ + TInt err; + + test.Next(_L("TestMemoryAccess - Read Memory\n")); + + //initialise buffer + gMemoryAccessBytes.SetLength(0); + for (TInt i=0; i max block size + err = iServSession.ReadMemory(iThreadID, address, (1<<15), dataBlock, EAccess32, EEndLE8); + test(err == KErrArgument); + + //test access size == 2 bytes + err = iServSession.ReadMemory(iThreadID, address, size, dataBlock, EAccess16, EEndLE8); + test(err == KErrNotSupported); + + //test access size == 1 byte + err = iServSession.WriteMemory(iThreadID, address, size, dataBlock, EAccess8, EEndLE8); + test(err == KErrNotSupported); + + //test endianess == EEndBE8 + err = iServSession.ReadMemory(iThreadID, address, size, dataBlock, EAccess32, EEndBE8); + test(err == KErrNotSupported); + + //test endianess == EEndBE32 + err = iServSession.WriteMemory(iThreadID, address, size, dataBlock, EAccess32, EEndBE32); + test(err == KErrNotSupported); + + //test reading off end of memory + err = iServSession.ReadMemory(iThreadID, 0xffffff00, 0x00000101, dataBlock, EAccess32, EEndLE8); + test(err == KErrArgument); + + //The following three tests check that edge conditions in the range check are handled correctly. + err = iServSession.ReadMemory(iThreadID, 0xffffff00, 0x000000FF, dataBlock, EAccess32, EEndLE8); + test(err == KErrArgument); + + err = iServSession.ReadMemory(iThreadID, 0xffffff00, 0x000000F0, dataBlock, EAccess32, EEndLE8); + test(err == KErrBadDescriptor); + + //Third range check test. Check that range check is handled correctly even when base + size wraps to 0. + err = iServSession.ReadMemory(iThreadID, 0xffffff00, 0x00000100, dataBlock, EAccess32, EEndLE8); + test(err == KErrBadDescriptor); + //end of range check tests + + //test size == 0 + err = iServSession.WriteMemory(iThreadID, address, 0, dataBlock, EAccess32, EEndLE8); + test(err == KErrArgument); + + //attempt to write to address outside of process data segments, + //this address corresponds to the vectors so shouldn't be able to write + err = iServSession.WriteMemory(iThreadID, 0xffff0000, size, dataBlock, EAccess32, EEndLE8); + test(err == KErrBadDescriptor); + + //attempt to read and write to address in process code segment + + //open a handle to the thread + RThread debugThread; + test(debugThread.Open(iThreadID) == KErrNone); + + //get a reference to the debug process + RProcess debugProcess; + test(debugThread.Process(debugProcess) == KErrNone); + + //get the memory info for the process + TProcessMemoryInfo info; + test(debugProcess.GetMemoryInfo(info) == KErrNone); + + address = info.iCodeBase; + if(size <= info.iCodeSize) + { + test(KErrNone == iServSession.ReadMemory(iThreadID, address, size, dataBlock, EAccess32, EEndLE8)); + test(KErrBadDescriptor == iServSession.WriteMemory(iThreadID, address, size, dataBlock, EAccess32, EEndLE8)); + } + + // Some performance tests now + TUint32 bytesRead = 0; + + // Allocate a data buffer + TUint32* p = (TUint32*)User::Alloc(size); + test(p != 0); + + TInt nanokernel_tick_period; + HAL::Get(HAL::ENanoTickPeriod, nanokernel_tick_period); + test (nanokernel_tick_period != 0); + + static const TInt KOneMillion = 1000000; + + TInt nkTicksPerSecond = KOneMillion/nanokernel_tick_period; + + TUint32 stopTickCount = User::NTickCount() + nkTicksPerSecond; + + while (User::NTickCount() < stopTickCount) + { + err = iServSession.ReadMemory(iThreadID, (TUint32)p, size, dataBlock, EAccess32, EEndLE8); + test(err==KErrNone); + + // Increase the count of bytes read + bytesRead += size; + } + + test(bytesRead != 0); + iMemoryReadKbytesPerSecond = bytesRead/1024; + + // write memory test + TUint32 bytesWritten = 0; + + stopTickCount = User::NTickCount() + nkTicksPerSecond; + + while (User::NTickCount() < stopTickCount) + { + err = iServSession.WriteMemory(iThreadID, (TUint32)p, size, dataBlock, EAccess32, EEndLE8); + test(err==KErrNone); + + // Increase the count of bytes read + bytesWritten += size; + } + + test (bytesWritten != 0); + iMemoryWriteKbytesPerSecond = bytesWritten/1024; + + User::Free(p); + + //resume the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + + debugThread.Close(); + dataBlock.Close(); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0433 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test suspending and resuming threads +//! @SYMTestActions Multiple calls to suspend and resume threads with and without attaching to the thread +//! @SYMTestExpectedResults All tests should pass and the target process should be left unaffected +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestSuspendResume() + { + TInt err; + + test.Next(_L("TestSuspendResume - Suspend\n")); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + err = iServSession.SuspendThread(iThreadID); + test(err==KErrNone); + err = TestRunCountSame( iRunCountSubscribe, iTimer ); + test( KErrNone == err ); + + // Resume the thread + test.Next(_L("TestSuspendResume - Resume\n")); + err = iServSession.ResumeThread(iThreadID); + test(err==KErrNone); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + + err = WaitForRunCountChange( iRunCountSubscribe, iTimer ); + test(KErrNone == err ); + + // check that agent can resume thread which it previously detached from + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + test(KErrNone == iServSession.SuspendThread(iThreadID)); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + err = TestRunCountSame( iRunCountSubscribe, iTimer ); + test( KErrNone == err ); + test(KErrNone == iServSession.ResumeThread(iThreadID)); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + + err = WaitForRunCountChange( iRunCountSubscribe, iTimer ); + test( KErrNone == err ); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + test(KErrNone == iServSession.SuspendThread(iThreadID)); + err = TestRunCountSame( iRunCountSubscribe, iTimer ); + test( KErrNone == err ); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + err = TestRunCountSame( iRunCountSubscribe, iTimer ); + test( KErrNone == err ); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + err = TestRunCountSame( iRunCountSubscribe, iTimer ); + test( KErrNone == err ); + test(KErrNone == iServSession.ResumeThread(iThreadID)); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + + err = WaitForRunCountChange( iRunCountSubscribe, iTimer ); + test( KErrNone == err ); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0434 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test getting the debug functionality from the driver +//! @SYMTestActions Get the size and contents of the debug functionality block +//! @SYMTestExpectedResults All tests should pass and the expected data should appear in the functionality block +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestDebugFunctionality() + { + + TInt err; + + test.Next(_L("TestDebugFunctionality - GetDebugFunctionalityBufSize\n")); + + TUint32 bufsize = 0; // Safe default size + + // Get functionality block size + err = iServSession.GetDebugFunctionalityBufSize(&bufsize); + test(err==KErrNone); + test.Next(_L("TestDebugFunctionality - GetDebugFunctionality\n")); + + // Ensure we have a finite buffer size + test(bufsize!=0); + + // Allocate space for the functionality data + HBufC8* dftext = HBufC8::NewLC(bufsize); + + // create an empty TPtr8 refering to dftext + TPtr8 dftextPtr(dftext->Des()); + + // Get the functionality block + err = iServSession.GetDebugFunctionality(dftextPtr); + test(err==KErrNone); + + // Check that the first entry is correct + TTagHeader RefHdr = + { + ETagHeaderIdCore,ECoreLast, + }; + + // First header passed from rm_debug.ldd + TTagHeader* TestHdr = (TTagHeader*)dftextPtr.Ptr(); + + // Check + test(RefHdr.iTagHdrId==TestHdr->iTagHdrId); + // this test might fail if the agent is used with a Debug Security Server different from + // the one it was compiled against. So removing it for now. + //test(RefHdr.iNumTags==TestHdr->iNumTags); + + // read a value from the data to check it has come through as expected + TTagHeader* header = GetTagHdr(dftext->Des(), ETagHeaderIdApiConstants); + test(header != NULL); + TTag* tag = GetTag(header, EApiConstantsTEventInfoSize); + test(tag != NULL); + // this test might fail if the agent is used with a Debug Security Server different from + // the one it was compiled against. So removing it for now. + //test(sizeof(TEventInfo) == tag->iValue); + + // Remove our temporary buffer + CleanupStack::PopAndDestroy(dftext); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0435 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test setting and clearing consecutive breakpoints +//! @SYMTestActions Set and clear consecutive breakpoints of all combinations of breakpoint types +//! @SYMTestExpectedResults All breakpoints should be set and cleared without error +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestConsecutiveBreakPoints() + { + test.Next(_L("TestConsecutiveBreakPoints\n")); + + test(KErrNone == iServSession.SuspendThread(iThreadID)); + + // just a temporary structure for storing info about a breakpoint + struct TBreakPoint + { + public: + TBreakPoint() + :iId(0), + iMode((TArchitectureMode)0), + iAddress(0) + {} + TBreakId iId; + TArchitectureMode iMode; + TUint32 iAddress; + inline TInt Size() { return (EArmMode == iMode) ? 4 : 2; } + }; + + //an address in the target debug thread + TUint32 address = (TUint32)(&TestFunction); + + // there are six orders in which three breakpoints can be set, these are looped + // through below to check setting and clearing consecutive breakpoints works + TUint8 order[6][3] = + { + {0,1,2}, + {0,2,1}, + {1,0,2}, + {1,2,0}, + {2,0,1}, + {2,1,0} + }; + + // The following code checks that setting and clearing consecutive breakpoints works correctly: + // It checks that setting all combinations of three arm and thumb breakpoints succeeds, and check that the + // breakpoints can be set in any order, and then cleared in any order + + // the 3 least significant bits of i control whether each of the three breakpoints should be arm or thumb + for(TInt i=0; i<8; i++) + { + // controls the order in which the breakpoints should be set + for(TInt j=0; j<6; j++) + { + // create the three breakpoints and set their modes + TBreakPoint bp[3]; + bp[0].iMode = (i&1) ? EArmMode : EThumbMode; + bp[1].iMode = (i&2) ? EArmMode : EThumbMode; + bp[2].iMode = (i&4) ? EArmMode : EThumbMode; + + // set the address of each of the breakpoints + bp[0].iAddress = address; + if(EArmMode == bp[0].iMode) + { // if an arm breakpoint then must be on a four byte boundary + bp[0].iAddress = Align4(bp[0].iAddress); + } + bp[1].iAddress = bp[0].iAddress + bp[0].Size(); + if(EArmMode == bp[1].iMode) + { // if an arm breakpoint then must be on a four byte boundary + bp[1].iAddress = Align4(bp[1].iAddress); + } + bp[2].iAddress = bp[1].iAddress + bp[1].Size(); + if(EArmMode == bp[2].iMode) + { // if an arm breakpoint then must be on a four byte boundary + bp[2].iAddress = Align4(bp[2].iAddress); + } + for(TInt k=0; k<6; k++) + { + // set the three breakpoints in the order defined by j and then clear them in the order defined by k + test(KErrNone==iServSession.SetBreak(bp[order[j][0]].iId, iThreadID, bp[order[j][0]].iAddress, bp[order[j][0]].iMode)); + test(KErrNone==iServSession.SetBreak(bp[order[j][1]].iId, iThreadID, bp[order[j][1]].iAddress, bp[order[j][1]].iMode)); + test(KErrNone==iServSession.SetBreak(bp[order[j][2]].iId, iThreadID, bp[order[j][2]].iAddress, bp[order[j][2]].iMode)); + test(KErrNone==iServSession.ClearBreak(bp[order[k][0]].iId)); + test(KErrNone==iServSession.ClearBreak(bp[order[k][1]].iId)); + test(KErrNone==iServSession.ClearBreak(bp[order[k][2]].iId)); + } + } + } + + // resume the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0436 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test breakpoint functionality +//! @SYMTestActions Multiple calls to set and clear breakpoints. Checking bad input produces appropriate errors. +//! @SYMTestExpectedResults All tests should pass and the target debug thread should be left unaffected +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestBreakPoints() + { + TInt err; + + test.Next(_L("TestBreakPoints - Set\n")); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + TestConsecutiveBreakPoints(); + + //an address in the target debug thread + TUint32 address = (TUint32)(&TestFunction); + + /* + * Ensure that breakpoint operations don't + * affect memory read/write by checking that reads/writes + * in locations containing breakpoints don't change behaviour + * because of the breakpoints. + */ + + TUint32 size = SYMBIAN_RMDBG_MEMORYSIZE; + + RBuf8 originalDataBlock; + err = originalDataBlock.Create(size); + test(err==KErrNone); + + //suspend the thread + test(KErrNone == iServSession.SuspendThread(iThreadID)); + + err = iServSession.ReadMemory(iThreadID, address, size, originalDataBlock, EAccess32, EEndLE8); + test(err==KErrNone); + + // Test data block for comparison + RBuf8 testDataBlock; + err = testDataBlock.Create(size); + test(err==KErrNone); + + /* + * set an arm breakpoint + */ + test.Next(_L("TestBreakPoints - set an arm breakpoint1")); + + TBreakId armBreakId = 0; + err = iServSession.SetBreak(armBreakId, iThreadID, address, EArmMode); + test(err == KErrNone); + + // Ensure that memory read is not corrupted + test.Next(_L("TestBreakPoints - read mem 2")); + err = iServSession.ReadMemory(iThreadID, address, size, testDataBlock, EAccess32, EEndLE8); + test(err==KErrNone); + + test (testDataBlock == originalDataBlock); + + /* + * set a thumb breakpoint + */ + test.Next(_L("TestBreak- set a thumb breakpoint1")); + TBreakId thumbBreakId = 0; + err = iServSession.SetBreak(thumbBreakId, iThreadID, address+4, EThumbMode); + test(err == KErrNone); + + /* + * set a thumb2EE breakpoint + */ + test.Next(_L("TestBreak- set a thumb2EE breakpoint")); + + TBreakId thumb2EEBreakId = 0; + err = iServSession.SetBreak(thumb2EEBreakId, iThreadID, address+8, EThumb2EEMode); + test(err == KErrNotSupported); + + /* + * overlapping breakpoint (same address/threadId/mode) + */ + test.Next(_L("TestBreak- set overlapping breakpoint 1")); + TBreakId overlapBreakId = 0; + err = iServSession.SetBreak(overlapBreakId, iThreadID, address, EArmMode); + test(err == KErrAlreadyExists); + + /* + * overlapping breakpoint (different address/same threadId/different mode) + * + * address - EArmBreakpoint + * address+2 - EThumbBreakpoint + */ + test.Next(_L("TestBreak- set overlapping breakpoint 2")); + TBreakId overlap2BreakId = 0; + err = iServSession.SetBreak(overlap2BreakId, iThreadID, address+2, EThumbMode); + test(err == KErrAlreadyExists); + + /* + * Un-aligned address (arm) + */ + test.Next(_L("TestBreak- set Un-aligned address (arm)")); + TBreakId armUnalignedBreakId = 0; + err = iServSession.SetBreak(armUnalignedBreakId, iThreadID, address+6, EArmMode); + test(err == KErrArgument); + + /* + * Un-aligned address (thumb) + */ + test.Next(_L("TestBreak- set Un-aligned address (thumb)")); + TBreakId thumbUnalignedBreakId = 0; + err = iServSession.SetBreak(thumbUnalignedBreakId, iThreadID, address+7, EThumbMode); + test(err == KErrArgument); + + /* + * Invalid address (arm) + */ + test.Next(_L("TestBreak- set Invalid address (arm)")); + TBreakId armBadAddressBreakId = 0; + err = iServSession.SetBreak(armBadAddressBreakId, iThreadID, 0 /* address */, EThumbMode); + test(err == KErrBadDescriptor); + + /* + * Different thread, same address. Should fail for the same process, but succeed + * for a different process. + */ + + /* + * Invalid thread + */ + TBreakId invalidThreadBreakId = 0; + err = iServSession.SetBreak(invalidThreadBreakId, 0xbabababa, address, EThumbMode); + test(err == KErrPermissionDenied); + + // Clear the ARM breakpoint + err = iServSession.ClearBreak(armBreakId); + test(err == KErrNone); + + // Clear the Thumb breakpoint + err = iServSession.ClearBreak(thumbBreakId); + test(err == KErrNone); + + // to do : two threads at the same address + // to do : two processes at the same address + + // Ensure that memory read is not corrupted after clearing the breakpoints + err = iServSession.ReadMemory(iThreadID, address, size, testDataBlock, EAccess32, EEndLE8); + test(err==KErrNone); + + test (testDataBlock == originalDataBlock); + + /* + * How fast can we set breakpoints? + * + * Measure the time by setting/clearing breakpoints for 1 second. + */ + TInt nanokernel_tick_period; + HAL::Get(HAL::ENanoTickPeriod, nanokernel_tick_period); + test (nanokernel_tick_period != 0); + + TInt nkTicksPerSecond = HelpTicksPerSecond(); + + TInt breaksPerSecond = 0; + + TUint32 stopTickCount = User::NTickCount() + nkTicksPerSecond; + + while (User::NTickCount() < stopTickCount) + { + // set the breakpoint + TBreakId armBreakId = 0; + err = iServSession.SetBreak(armBreakId, iThreadID, address, EArmMode); + test(err == KErrNone); + + // Clear the breakpoint + err = iServSession.ClearBreak(armBreakId); + test(err == KErrNone); + + // Update the count of breakpoints + breaksPerSecond++; + + // Gone wrong if we wrap to negative breakpoints (cannot set 2billion/second!) + test(breaksPerSecond >0); + } + + // Store the results for later + iBreakpointsPerSecond = breaksPerSecond; + + /* + * How many breakpoints can we set? + */ + + TBool done = EFalse; + + // We assume all the breakpoints id's are issued in ascending order + TInt maxBreakPoints = 0; + + // Temporary buffer + RArray breakIdList; + + TUint32 testAddress = address; + + while(!done) + { + TBreakId breakId = 0; + + // set the breakpoint + testAddress += 4; // ensure the addresses don't overlap + + err = iServSession.SetBreak(breakId, iThreadID, testAddress, EArmMode); + test (err == KErrNone || err == KErrOverflow); + if (err != KErrNone) + { + // we've reached the limit of the number of breaks we can set + done = ETrue; + break; + } + + // store the id of this breakpoint + breakIdList.Append(breakId); + + // Increase the count of breakpoints + maxBreakPoints++; + test(maxBreakPoints > 0); + } + + // How many breakpoints can we set? + iMaxBreakpoints = maxBreakPoints; + + // now clear all those breakpoints again + while(breakIdList.Count() != 0) + { + // Place it into a TBreakId + TBreakId id = breakIdList[0]; + + err = iServSession.ClearBreak(id); + test(err == KErrNone); + + // next id + breakIdList.Remove(0); + } + + breakIdList.Close(); + + // close our temporary buffers + originalDataBlock.Close(); + testDataBlock.Close(); + + err = iServSession.ResumeThread(iThreadID); + test (err == KErrNone); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0437 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test modifying breakpoints +//! @SYMTestActions Several calls to modify breakpoints +//! @SYMTestExpectedResults Valid requests should result in the breakpoints being changed, invalid requests should return errors +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestModifyBreak() + { + test.Next(_L("TestModifyBreak\n")); + + DoTestModifyBreak(ETrue); + DoTestModifyBreak(EFalse); + } + +void CRunModeAgent::DoTestModifyBreak(TBool aThreadSpecific) + { + test.Printf(_L("DoTestModifyBreak: aThreadSpecific: %d\n"), aThreadSpecific?1:0); + + TInt err; + + RProcess process; + TProcessId processId = process.Id(); + process.Close(); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + //suspend the thread + test(KErrNone == iServSession.SuspendThread(iThreadID)); + + //an address in the target debug thread + TUint32 address = (TUint32)(&TestFunction); + + //set an arm mode break point + TBreakId armBreakId = 0; + err = aThreadSpecific + ? iServSession.SetBreak(armBreakId, iThreadID, address, EArmMode) + : iServSession.SetProcessBreak(armBreakId, processId, address, EArmMode); + test(err == KErrNone); + + /* + * Invalid thread + */ + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, 0xbabababa, address, EArmMode) + : iServSession.ModifyProcessBreak(armBreakId, 0xbabababa, address, EArmMode); + test(err == KErrPermissionDenied); + + /* + * Valid address + */ + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, iThreadID, address+4, EArmMode) + : iServSession.ModifyProcessBreak(armBreakId, processId, address+4, EArmMode); + test(err == KErrNone); + + /* + * Invalid address + */ + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, iThreadID, 0, EArmMode) + : iServSession.ModifyProcessBreak(armBreakId, processId, 0, EArmMode); + test(err == KErrBadDescriptor); + + /* + * Thumb mode + */ + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, iThreadID, address, EThumbMode) + : iServSession.ModifyProcessBreak(armBreakId, processId, address, EThumbMode); + test(err == KErrNone); + + /* + * Thumb2EE mode + */ + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, iThreadID, address, EThumb2EEMode) + : iServSession.ModifyProcessBreak(armBreakId, processId, address, EThumb2EEMode); + test(err == KErrNotSupported); + + /* + * Arm mode + */ + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, iThreadID, address, EArmMode) + : iServSession.ModifyProcessBreak(armBreakId, processId, address, EArmMode); + test(err == KErrNone); + + // Finally, clear the breakpoint + err = iServSession.ClearBreak(armBreakId); + test(err == KErrNone); + + //resume the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0438 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test extracting information about breakpoints +//! @SYMTestActions Several calls to get information about breakpoints +//! @SYMTestExpectedResults All tests should pass and the target process should be left unaffected +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestBreakInfo() + { + test.Next(_L("TestBreakInfo\n")); + + DoTestBreakInfo(ETrue); + DoTestBreakInfo(EFalse); + } + +void CRunModeAgent::DoTestBreakInfo(TBool aThreadSpecific) + { + test.Printf(_L("DoTestModifyBreak: aThreadSpecific: %d\n"), aThreadSpecific?1:0); + + TInt err; + + RProcess process; + TProcessId processId = process.Id(); + process.Close(); + + //an address in the target debug thread + TUint32 address = (TUint32)(&TestFunction); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + //suspend thread + test(KErrNone == iServSession.SuspendThread(iThreadID)); + + //set an arm mode break point + TBreakId armBreakId = 0; + err = aThreadSpecific + ? iServSession.SetBreak(armBreakId, iThreadID, address, EArmMode) + : iServSession.SetProcessBreak(armBreakId, processId, address, EArmMode); + test(err == KErrNone); + + // Read back the information and check it is correct + TThreadId testThreadId = TThreadId(0); + TProcessId testProcessId = TProcessId(0); + TUint32 testAddress = 0; + TArchitectureMode testMode = EArmMode; + + err = aThreadSpecific + ? iServSession.BreakInfo(armBreakId,testThreadId,testAddress, testMode) + : iServSession.ProcessBreakInfo(armBreakId, testProcessId, testAddress, testMode); + test (err == KErrNone); + test (aThreadSpecific ? (testThreadId == iThreadID) : (testProcessId == processId)); + test (testAddress == address); + test (testMode == EArmMode); + + //change the address + TUint32 changeAddress = address + 64; + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, iThreadID, changeAddress,EArmMode) + : iServSession.ModifyProcessBreak(armBreakId, processId, changeAddress, EArmMode); + test(err == KErrNone); + + // Check the address has changed + err = aThreadSpecific + ? iServSession.BreakInfo(armBreakId,testThreadId,testAddress, testMode) + : iServSession.ProcessBreakInfo(armBreakId, testProcessId, testAddress, testMode); + test (err == KErrNone); + test (testAddress == changeAddress); + + // change the architecture type + TArchitectureMode checkMode = EThumbMode; + err = aThreadSpecific + ? iServSession.ModifyBreak(armBreakId, iThreadID, address,checkMode) + : iServSession.ModifyProcessBreak(armBreakId, processId, address, checkMode); + test (err == KErrNone); + + // Check the mode has changed + err = aThreadSpecific + ? iServSession.BreakInfo(armBreakId,testThreadId,testAddress,testMode) + : iServSession.ProcessBreakInfo(armBreakId, testProcessId, testAddress, testMode); + test (err == KErrNone); + test (testMode == checkMode); + + // clear the breakpoint again + err = iServSession.ClearBreak(armBreakId); + test (err == KErrNone); + + //resume thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +// Needed for the RunToBreak test +IMPORT_C extern void RMDebug_BranchTst1(); +IMPORT_C extern void RMDebug_BranchTst2(); + +//--------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0439 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test hitting various types of breakpoints +//! @SYMTestActions Several calls to register to observe breakpoints and to hit breakpoints of different types +//! @SYMTestExpectedResults All tests should pass and the target process should be left unaffected +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestRunToBreak() + { + test.Next(_L("TestRunToBreak\n")); + + DoTestRunToBreak(ETrue); + DoTestRunToBreak(EFalse); + } + +void CRunModeAgent::DoTestRunToBreak(TBool aThreadSpecific) + { + test.Printf(_L("DoTestRunToBreak: aThreadSpecific: %d\n"), aThreadSpecific?1:0); + + TInt err = KErrNone; + + RProcess process; + TProcessId processId = process.Id(); + process.Close(); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + // we should suspend the thread first, then set the breakpoint + err = iServSession.SuspendThread(iThreadID); + test (err == KErrNone); + + // Try to set the breakpoint + TBreakId armBreakId; + TUint32 address = (TUint32)(&RMDebug_BranchTst1); + + err = aThreadSpecific + ? iServSession.SetBreak(armBreakId,iThreadID,address,EArmMode) + : iServSession.SetProcessBreak(armBreakId, processId, address, EArmMode); + test(err == KErrNone); + + err = aThreadSpecific + ? iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionContinue) + : iServSession.SetEventAction(iFileName,EEventsProcessBreakPoint, EActionContinue); + test (err == KErrNone); + + // Continue the thread + err = iServSession.ResumeThread(iThreadID); + test (err == KErrNone); + + // wait for the breakpoint to be hit + TEventInfo info; + static TRequestStatus status; + + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of the breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + + // info should now be filled with the details + test(info.iEventType == (aThreadSpecific ? EEventsBreakPoint : EEventsProcessBreakPoint)); + test(info.iThreadBreakPointInfo.iRmdArmExcInfo.iR15 == address); + test(info.iProcessIdValid); + test(info.iThreadIdValid); + + // Not interested in breakpoint events any more + err = aThreadSpecific + ? iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionIgnore) + : iServSession.SetEventAction(iFileName, EEventsProcessBreakPoint, EActionIgnore); + test (err == KErrNone); + + // Clear the breakpoint again + err = iServSession.ClearBreak(armBreakId); + test(err == KErrNone); + + // continue the thread again + err = iServSession.ResumeThread(iThreadID); + test (err == KErrNone); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//--------------------------------------------- +//! @SYMTestCaseID KBASE-rmdebug2-2704 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test breakpoints in a loop +//! @SYMTestActions Several calls to register to verify breakpoints are stopping at correct address +//! @SYMTestExpectedResults All tests should pass and the target thread should be left unaffected +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//--------------------------------------------- +void CRunModeAgent::TestBreakPointsInLoop() + { + test.Next(_L("TestBreakPointsInLoop\n")); + + DoTestBreakPointsInLoop(ETrue); + DoTestBreakPointsInLoop(EFalse); + } + +void CRunModeAgent::DoTestBreakPointsInLoop(TBool aThreadSpecific) + { + test.Printf(_L("DoTestBreakPointsInLoop: aThreadSpecific: %d\n"), aThreadSpecific?1:0); + + TInt err = KErrNone; + TProcessId processId = RProcess().Id(); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + // We should suspend the thread first, then set the breakpoint + err = iServSession.SuspendThread(iThreadID); + test (err == KErrNone); + + // 2 breakpoints are sufficient to find issues with hitting breakpoints in a loop + const TInt numOfBreakPointsInLoop = 2; + + TBreakId armBreakId[numOfBreakPointsInLoop]; + TUint32 address[numOfBreakPointsInLoop]; + + TUint32 entryAddress = (TUint32)(&RMDebug_Bkpt_Test_Entry); + TBreakId entryArmBreakId; + + // Copy breakpoint address's in array + address[0] = (TUint32)(&RMDebug_Bkpt_Test_Loop_Break_1); + address[1] = (TUint32)(&RMDebug_Bkpt_Test_Loop_Break_2); + + err = aThreadSpecific + ? iServSession.SetBreak(entryArmBreakId,iThreadID,entryAddress,EArmMode) + : iServSession.SetProcessBreak(entryArmBreakId, processId, entryAddress, EArmMode); + test(err == KErrNone); + + // Try to set the breakpoints inside loop + for (TInt i = 0; i < numOfBreakPointsInLoop; i++) + { + err = aThreadSpecific + ? iServSession.SetBreak(armBreakId[i],iThreadID,address[i],EArmMode) + : iServSession.SetProcessBreak(armBreakId[i], processId, address[i], EArmMode); + test(err == KErrNone); + } + + err = aThreadSpecific + ? iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionSuspend) + : iServSession.SetEventAction(iFileName,EEventsProcessBreakPoint, EActionSuspend); + test (err == KErrNone); + + // Continue the thread + err = iServSession.ResumeThread(iThreadID); + test (err == KErrNone); + + // Wait for the breakpoint to be hit + TEventInfo info; + TRequestStatus status; + + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of breakpoint event + User::WaitForRequest(status); + test(status==KErrNone); + + // Info should now be filled with the details + test(info.iEventType == (aThreadSpecific ? EEventsBreakPoint : EEventsProcessBreakPoint)); + + // Have we stopped at the correct breakpoint? + test(info.iThreadBreakPointInfo.iRmdArmExcInfo.iR15 == entryAddress); + test(info.iProcessIdValid); + test(info.iThreadIdValid); + + // Don't require the entry breakpoint anymore + err = iServSession.ClearBreak(entryArmBreakId); + test(err == KErrNone); + + // Stress the system by setting loop count to 100 + const TUint32 loopCount = 100; + + for (TInt i = 0; i < loopCount; i++) + { + // Continue the thread + err = iServSession.ResumeThread(iThreadID); + test (err == KErrNone); + + // Wait for the breakpoint to be hit + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of the breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + + // Info should now be filled with the details + test(info.iEventType == (aThreadSpecific ? EEventsBreakPoint : EEventsProcessBreakPoint)); + + // Have we stopped at the correct breakpoint? + test(info.iThreadBreakPointInfo.iRmdArmExcInfo.iR15 == address[i%numOfBreakPointsInLoop]); + + // Check process and thread id too + test(info.iProcessIdValid); + test(info.iThreadIdValid); + } + + // Not interested in breakpoint events any more + err = aThreadSpecific + ? iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionIgnore) + : iServSession.SetEventAction(iFileName, EEventsProcessBreakPoint, EActionIgnore); + test (err == KErrNone); + + // Clear breakpoints + for (TInt i = 0; i < numOfBreakPointsInLoop; i++) + { + err = iServSession.ClearBreak(armBreakId[i]); + test(err == KErrNone); + } + + // Continue the thread again + err = iServSession.ResumeThread(iThreadID); + test (err == KErrNone); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0440 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test access to target user-side registers. +//! @SYMTestActions Suspends a target thread, and reads/writes target thread register contents +//! +//! @SYMTestExpectedResults KErrNone. Should access target registers without problems. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestRegisterAccess() + { + TInt err; + + test.Next(_L("TestRegisterAccess - Read\n")); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + //suspend the thread to read registers + err = iServSession.SuspendThread(iThreadID); + test(err==KErrNone); + + //we'll try to read/write registers ERegisterR0 - ERegisterCPSR and ERegisterR13_IRQ + //this way should get valid register values back, invalid ones and not supported ones, and it + //means that the register IDs are not completely contiguous + + TInt firstRegister = 0; + TInt lastRegister = 17; + TInt numberOfRegisters = (lastRegister - firstRegister) + 1; + + RBuf8 ids; + err = ids.Create(numberOfRegisters * sizeof(TRegisterInfo)); + test(err == KErrNone); + + for(TInt i=0; i(®), sizeof(TRegisterInfo)); + } + + TRegisterInfo reg = ERegisterR13Irq; + ids.Append(reinterpret_cast(®), sizeof(TRegisterInfo)); + + //create a buffer to store the register values in + RBuf8 originalValues; + err = originalValues.Create(numberOfRegisters*sizeof(TUint32)); + test(err == KErrNone); + + //create a buffer to store the register flags in + RBuf8 originalFlags; + err = originalFlags.Create(numberOfRegisters*sizeof(TUint8)); + test(err == KErrNone); + + //read register values + err = iServSession.ReadRegisters(iThreadID, ids, originalValues, originalFlags); + test(err == KErrNone); + + //create a buffer containing data to write into the registers + RBuf8 tempValues; + err = tempValues.Create(numberOfRegisters*sizeof(TUint32)); + test(err == KErrNone); + + TUint cpsrId = 16; + for(TUint8 i=0; i(®1), sizeof(TRegisterInfo)); + + //create buffer containing desired PC value + RBuf8 pcValue; + err = pcValue.Create(sizeof(TUint32)); + test(err == KErrNone); + TUint32 address = (TUint32)(&TestFunction); + pcValue.Append(reinterpret_cast(&address), sizeof(TUint32)); + + //craete buffer for PC flag value + RBuf8 pcFlag; + err = pcFlag.Create(sizeof(TUint8)); + + //write the new PC value + err = iServSession.WriteRegisters(iThreadID, pcId, pcValue, pcFlag); + test(err==KErrNone); + + //get the flag and check the PC value was written ok + TRegisterFlag flag = ENotSupported; + err = GetFlag(pcFlag, 0, flag); + test(err==KErrNone); + test( flag == EValid); + if(flag == EValid) + { + /* The PC value was changed to execute the function TestFunction. + * TestFunction changes the value of TestData to a given value and + * then calls RMDebug_BranchTst1. + * We place a breakpoint on RMDebug_BranchTst1 so that to we are able + * to test the value of TestData. + */ + + test(KErrNone == iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionSuspend)); + TBreakId armBreakId; + TUint32 address = (TUint32)(&RMDebug_BranchTst1); + test(KErrNone == iServSession.SetBreak(armBreakId,iThreadID,address,EArmMode)); + + // Continue the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + + // wait for the breakpoint to be hit + TEventInfo info; + static TRequestStatus status; + + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of the breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + + // info should now be filled with the details + test(info.iEventType == EEventsBreakPoint); + test(info.iThreadBreakPointInfo.iRmdArmExcInfo.iR15 == address); + test(info.iProcessIdValid); + test(info.iThreadIdValid); + + test(KErrNone == iServSession.ClearBreak(armBreakId)); + + // Finally test the value + test(TestData == 0xffeeddcc); + } + + //Make sure we cannot change the CPSR + test.Next(_L("Verifying we cannot change the CPSR mode from USR Mode")); + + TUint32 disallowedCpsr = 0x50000013; + + RBuf8 cpsrRegId; + err = cpsrRegId.Create(sizeof(TUint32)); + test(err == KErrNone); + + TRegisterInfo cpsr = (TRegisterInfo)((cpsrId + firstRegister)<<8); + cpsrRegId.Append(reinterpret_cast(&cpsr), sizeof(TRegisterInfo)); + + RBuf8 cpsrRegFlags; + err = cpsrRegFlags.Create(sizeof(TUint8)); + test(err == KErrNone); + + RBuf8 cpsrVal; + err = cpsrVal.Create(sizeof(TUint32)); + test(err == KErrNone); + + cpsrVal.Append((TUint8*)&disallowedCpsr, 4); + + //attempt to write disallowed CPSR in + err = iServSession.WriteRegisters(iThreadID, cpsrRegId, cpsrVal, cpsrRegFlags); + test(err == KErrNone); + + RBuf8 cpsrReadVal; + err = cpsrReadVal.Create(sizeof(TUint32)); + test(err == KErrNone); + + //Read back the CPSR + err = iServSession.ReadRegisters(iThreadID, cpsrRegId, cpsrReadVal, cpsrRegFlags); + test(err == KErrNone); + + //Make sure we havent switched modes ie. its not what we wrote + TUint32* readVal = (TUint32*)cpsrReadVal.Ptr(); + test(*readVal != disallowedCpsr); + + cpsrRegId.Close(); + cpsrRegFlags.Close(); + cpsrVal.Close(); + cpsrReadVal.Close(); + + //write the original values back into here + err = iServSession.WriteRegisters(iThreadID, ids, originalValues, originalFlags); + test(err == KErrNone); + + test(KErrNone == SwitchTestFunction(EDefaultFunction)); + + // Resume the thread + err = iServSession.ResumeThread(iThreadID); + test(err==KErrNone); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + + //do cleanup + pcId.Close(); + pcValue.Close(); + pcFlag.Close(); + ids.Close(); + originalValues.Close(); + originalFlags.Close(); + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0441 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test registration/de-registration of debug interest in target exe with the Debug Security Server +//! @SYMTestActions As per description +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestAttachExecutable() + { + + test.Next(_L("TestAttachExecutable - Attach\n")); + + //attach to process passively + test(KErrNone == iServSession.AttachExecutable(iFileName, ETrue)); + + //make a thread id for a non-existent thread + TThreadId threadId(0x12345678); + + //get a handle to the target thread + RThread targetThread; + TInt err = targetThread.Open(threadId); + test(err != KErrNone); + + //not registered for this thread's process (as it doesn't exist) + //so should fail security check + err = iServSession.ResumeThread(threadId); + test(err==KErrPermissionDenied || err==KErrNotFound); // newer DSS returns the more-descriptive KErrNotFound here + + //try to attach to the same process (and fail) + test(KErrAlreadyExists == iServSession.AttachExecutable(iFileName, EFalse)); + + test.Next(_L("TestAttachExecutable - Detach\n")); + + //detach from process + test(KErrNone == iServSession.DetachExecutable(iFileName)); + + //attach non-passively + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + //not registered for this thread's process (as it doesn't exist) + //so should fail security check + err = iServSession.ResumeThread(0x12345678); + test(err==KErrPermissionDenied || err==KErrNotFound); // newer DSS returns the more-descriptive KErrNotFound here + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0442 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests single-stepping target threads. +//! @SYMTestActions Steps target thread assembly level instructions, mainly branch/change PC +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestStep() + { + test.Next(_L("TestStep\n")); + + DoTestStep(EFalse); + DoTestStep(ETrue); + } + +void CRunModeAgent::DoTestStep(TBool aThreadSpecific) + { + test.Printf(_L("DoTestStep: aThreadSpecific: %d\n"), aThreadSpecific?1:0); + + TInt err = KErrNone; + + RProcess process; + TProcessId processId = process.Id(); + process.Close(); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + //set the target thread to execute the stepping functions + test(KErrNone == SwitchTestFunction(EStepFunction, EFalse)); + + + err = iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionContinue); + test (err == KErrNone); + + if(!aThreadSpecific) + { + err = iServSession.SetEventAction(iFileName, EEventsProcessBreakPoint, EActionContinue); + test (err == KErrNone); + } + + TUint32 startAddress; + TUint32 endAddress; + + /* + * RMDebug_StepTest_Non_PC_Modifying + */ + test.Next(_L("TestStep - Non-PC modifying\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Non_PC_Modifying); + + endAddress = (TUint32)(&RMDebug_StepTest_Non_PC_Modifying_OK); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1, EFalse, processId); + test(err==KErrNone); + + /* + * RMDebug_StepTest_Branch + */ + test.Next(_L("TestStep - Branch\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Branch); + + endAddress = (TUint32)(&RMDebug_StepTest_Branch_1); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1, EFalse, processId); + test(err==KErrNone); + + /* + * RMDebug_StepTest_Branch_And_Link + */ + test.Next(_L("TestStep - Branch_And_Link\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Branch_And_Link_1); + + endAddress = (TUint32)(&RMDebug_StepTest_Branch_And_Link_2); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1, EFalse, processId); + test(err==KErrNone); + + /* + * RMDebug_StepTest_MOV_PC + */ + test.Next(_L("TestStep - MOV PC,X\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_MOV_PC_1); + + endAddress = (TUint32)(&RMDebug_StepTest_MOV_PC_2); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1, EFalse, processId); + test(err==KErrNone); + + /* + * RMDebug_StepTest_LDR_PC + */ + test.Next(_L("TestStep - LDR PC\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_LDR_PC); + + endAddress = (TUint32)(&RMDebug_StepTest_LDR_PC_1); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1, EFalse, processId); + test(err==KErrNone); + +// thumb and interworking tests are not supported on armv4 +#ifdef __MARM_ARMV5__ + + /* + * RMDebug_StepTest_Thumb_Non_PC_Modifying + */ + test.Next(_L("TestStep - Thumb Non PC-Modifying\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Thumb_Non_PC_Modifying_1); + + endAddress = (TUint32)(&RMDebug_StepTest_Thumb_Non_PC_Modifying_2); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1, EFalse, processId); + test(err==KErrNone); + + /* + * RMDebug_StepTest_Thumb_Branch + */ + test.Next(_L("TestStep - Thumb Branch\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Thumb_Branch_1); + + endAddress = (TUint32)(&RMDebug_StepTest_Thumb_Branch_2); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1, EFalse, processId); + test(err==KErrNone); + + /* + * RMDebug_StepTest_Thumb_Branch_And_Link + */ + test.Next(_L("TestStep - Thumb Branch_And_Link\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Thumb_Branch_And_Link_2); + + endAddress = (TUint32)(&RMDebug_StepTest_Thumb_Branch_And_Link_3); + + TInt muid=0; + test(HAL::Get(HAL::EMachineUid, muid)==KErrNone); + + // check if running on ARMv7 core + if(muid==HAL::EMachineUid_OmapH6 || muid==HAL::EMachineUid_OmapZoom || muid==HAL::EMachineUid_EmuBoard) + { + // Note: ARMv7 treats BL instructions as single 32-bit instructions + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1, EFalse, processId); + } + else + { + // Note: Due to the fact that the stepper treats BL instructions + // as two instructions (as the hardware does), then we must step + // the first half instruction first) + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,startAddress+2,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,startAddress+2,EThumbMode,1, EFalse, processId); + test(err==KErrNone); + + // Now we actually do the BL + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress+2,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress+2,endAddress,EThumbMode,1, EFalse, processId); + } + test(err==KErrNone); + + /* + * RMDebug_StepTest_Thumb_Back_Branch_And_Link + */ + test.Next(_L("TestStep - Thumb Back_Branch_And_Link\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Thumb_Back_Branch_And_Link_2); + + endAddress = (TUint32)(&RMDebug_StepTest_Thumb_Back_Branch_And_Link_3); + + // check if running on ARMv7 core + if(muid==HAL::EMachineUid_OmapH6 || muid==HAL::EMachineUid_OmapZoom || muid==HAL::EMachineUid_EmuBoard) + { + // Note: ARMv7 treats BL instructions as single 32-bit instructions + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1, EFalse, processId); + } + else + { + // Note: Due to the fact that the stepper treats BL instructions + // as two instructions (as the hardware does), then we must step + // the first half instruction first) + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,startAddress+2,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,startAddress+2,EThumbMode,1, EFalse, processId); + test(err==KErrNone); + + // Now we actually do the BL + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress+2,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress+2,endAddress,EThumbMode,1, EFalse, processId); + } + test(err==KErrNone); + + /* + * RMDebug_StepTest_Thumb_AddPC + */ + test.Next(_L("TestStep - Thumb ADD PC, PC, R0\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Thumb_AddPC_2); + + endAddress = (TUint32)(&RMDebug_StepTest_Thumb_AddPC_3); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1, EFalse, processId); + test(err==KErrNone); + + /* + * RMDebug_StepTest_Interwork ARM to Thumb + */ + test.Next(_L("TestStep - Interworking ARM to Thumb - BLX \n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Interwork_1); + + endAddress = (TUint32)(&RMDebug_StepTest_Interwork_2); + + err = aThreadSpecific // nb initial breakpoint in ARM code + ? HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,1, EFalse, processId); + + test(err==KErrNone); + + /* + * RMDebug_StepTest_Interwork Thumb to ARM + */ + test.Next(_L("TestStep - Interworking Thumb to ARM - BLX\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_Interwork_2); + + endAddress = (TUint32)(&RMDebug_StepTest_Interwork_3); + + // check if running on ARMv7 core + if(muid==HAL::EMachineUid_OmapH6 || muid==HAL::EMachineUid_OmapZoom || muid==HAL::EMachineUid_EmuBoard) + { + // ARMv7 treats BLX instructions as single 32-bit instructions + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,endAddress,EThumbMode,1, EFalse, processId); + } + else + { + // Stepper treats this as a two-stage instruction (just like the hardware) + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,startAddress+2,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress,startAddress+2,EThumbMode,1, EFalse, processId); + test(err == KErrNone); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress+2,endAddress,EThumbMode,1) + : HelpTestStep(iThreadID,startAddress+2,endAddress,EThumbMode,1, EFalse, processId); + } + test(err == KErrNone); + +#endif // __MARM_ARMV5__ + + /* + * Test multiple-step of ARM code + */ + test.Next(_L("TestStep - ARM Multiple instruction step\n")); + + startAddress = (TUint32)(&RMDebug_StepTest_ARM_Step_Multiple); + + endAddress = (TUint32)(&RMDebug_StepTest_ARM_Step_Multiple_1); + + err = aThreadSpecific + ? HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,5) + : HelpTestStep(iThreadID,startAddress,endAddress,EArmMode,5, EFalse, processId); + test(err == KErrNone); + // stepping performance + test.Next(_L("TestStep - Steps per second\n")); + + // run until we reach RMDebug_StepTest_Count_1 + TBreakId stepBreakId; + startAddress = (TUint32)(&RMDebug_StepTest_Count_1); + endAddress = (TUint32)(&RMDebug_StepTest_Count_2); + + err = aThreadSpecific + ? HelpTestStepSetBreak(stepBreakId,iThreadID,startAddress,EArmMode) + : HelpTestStepSetBreak(stepBreakId,iThreadID,startAddress,EArmMode,EFalse,processId); + test (err == KErrNone); + + // wait until we hit the breakpoint + TEventInfo info; + err = HelpTestStepWaitForBreak(iFileName,info); + test (err == KErrNone); + + // Now clear the breakpoint + err = iServSession.ClearBreak(stepBreakId); + test(err == KErrNone); + + if(aThreadSpecific) + { + // now step the code + TInt stepsPerSecond = 0; + + TUint32 stopTickCount = User::NTickCount() + HelpTicksPerSecond(); + + while (User::NTickCount() < stopTickCount) + { + err = iServSession.Step(iThreadID,1); + test (err == KErrNone); + + // we need to wait now until the step completes before asking for the next step + { + TEventInfo info; + static TRequestStatus status; + + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of the breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + } + + // Update the count of steps + stepsPerSecond += 1; + + // Gone wrong if we do too many + test(stepsPerSecond < 10000); + } + + iStepsPerSecond = stepsPerSecond; + test(iStepsPerSecond != 0); + } + + // finally resume the thread + err = iServSession.ResumeThread(iThreadID); + test (err == KErrNone); + + err = iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionIgnore); + test (err == KErrNone); + + if(!aThreadSpecific) + { + err = iServSession.SetEventAction(iFileName, EEventsProcessBreakPoint, EActionIgnore); + test (err == KErrNone); + } + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0443 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests registration and occurrence of target thread event (in this case panic) +//! @SYMTestActions Registers for a panic in the target thread, causes it, and catches the panic notification. +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestEvents() + { + TInt err = KErrNone; + + test.Next(_L("TestEvents\n")); + + TInt panicReason = 12345; + + test.Printf(_L("Thread t_rmdebug.exe::DebugThread should panic with reason %d.\n"), panicReason); + + //attach non-passively + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + RThread threadToPanic; + test(KErrNone == StartDebugThread(threadToPanic, _L("EventsThread"))); + TThreadId threadToPanicId = threadToPanic.Id(); + TEventInfo info; + + // Set things up to wait for a thread kill event + err = iServSession.SetEventAction(iFileName, EEventsKillThread, EActionContinue); + test(err==KErrNone); + + // Wait for an event to occur in this process - nothing should have happened yet. + static TRequestStatus status; + + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + + iServSession.GetEvent(iFileName,status,infoPtr); + + // Test Request cancellation + err = iServSession.CancelGetEvent(iFileName); + test (err==KErrNone); + + // Again wait for an event to occur in our process - we will provoke the + // thread kill event by panic'ing the test thread. + iServSession.GetEvent(iFileName,status,infoPtr); + + // Panic the debug thread to cause a thread kill event + threadToPanic.Panic(_L("t_rmdebug panic thread test"), panicReason); + + // Wait for notification of the Thread Kill event + User::WaitForRequest(status); + test(status==KErrNone); + + // Check we are really recieving information about the panic + test(info.iProcessIdValid); + test(info.iThreadIdValid); + test(info.iProcessId==RProcess().Id()); + test(info.iThreadId==threadToPanicId); + test(info.iEventType==EEventsKillThread); + test(info.iThreadKillInfo.iExitType==EExitPanic); + + // Ignore other panic events + err = iServSession.SetEventAction(iFileName, EEventsKillThread, EActionIgnore); + test(err==KErrNone); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0444 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests registration and occurence of target thread events in separate process. +//! @SYMTestActions Registers for a hardware exception and kill thread events, and receives them. +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- +void CRunModeAgent::TestEventsForExternalProcess() + { + test.Next(_L("TestEventsForExternalProcess\n")); + + for(TInt main=0; main<3; main++) + { + for(TInt extra=0; extra<3; extra++) + { + TestEventsWithExtraThreads((TKernelEventAction)main, (TKernelEventAction)extra, 0); + TestEventsWithExtraThreads((TKernelEventAction)main, (TKernelEventAction)extra, 2); + } + } + } + +void CRunModeAgent::TestEventsWithExtraThreads(TKernelEventAction aActionMain, TKernelEventAction aActionExtra, TUint32 aExtraThreads) + { + const TInt KNumberOfTypes = 8; + struct TEventStruct + { + public: + TDebugFunctionType iDebugFunctionType; + TEventType iEventType; + }; + + TEventStruct type[KNumberOfTypes] = + { + {EStackOverflowFunction, EEventsHwExc}, + {EUserPanicFunction, EEventsKillThread}, + {EPrefetchAbortFunction, EEventsHwExc}, + {EDataAbortFunction, EEventsHwExc}, + {EUndefInstructionFunction, EEventsHwExc}, + {EDataReadErrorFunction, EEventsHwExc}, + {EDataWriteErrorFunction, EEventsHwExc}, + {EUserExceptionFunction, EEventsSwExc}, + }; + + for(TInt j=0; j 0) && ProcessExists(processId)) + { + /* Wait a little while and try again, just in case the process is still being removed. + This can happen on a very busy system or when a popup for the events is still active + */ + RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads. ProcessExists(id=%d), waiting count exit=%d", + I64LOW(processId), waitCount); + User::After(50000); + } + test(!ProcessExists(processId)); + } + } + +// helper function to check whether a thread with id aThreadId exists in the process with id aProcessId +TBool CRunModeAgent::ThreadExistsForProcess(const TThreadId aThreadId, const TProcessId aProcessId) + { + RThread lThread; + TInt ret = lThread.Open( aThreadId.Id() ); + + if( ret != KErrNone ) + { + RDebug::Printf("ThreadExistsForProcess: thread id=%d opening returned %d", + I64LOW( aThreadId.Id() ), ret ); + lThread.Close(); + return EFalse; + } + + RProcess lProcess; + ret = lThread.Process( lProcess ); + + lThread.Close(); + + if( ret != KErrNone ) + { + RDebug::Printf("ThreadExistsForProcess: proc opening returned %d", ret ); + ret = KErrNotFound; + } + else if( lProcess.Id() != aProcessId ) + { + RDebug::Printf("ThreadExistsForProcess: lProcess.Id()(%d)!= aProcessId(%d)", + I64LOW(lProcess.Id().Id()), I64LOW(aProcessId.Id())); + ret = KErrNotFound; + } + + lProcess.Close(); + + return ( ret == KErrNone ); + } + +// helper function to check whether a process with id aProcessId exists +TBool CRunModeAgent::ProcessExists(const TProcessId aProcessId) + { + TUint32 size; + RBuf8 buffer; + test(KErrNone == buffer.Create(1024)); + TInt err = iServSession.GetList(EProcesses, buffer, size); + while(KErrTooBig == err) + { + size*=2; + test(size<=47*1024); // 256 TProcessListEntrys is about 46KB. (256 is max num processes) + test(KErrNone == buffer.ReAlloc(size)); + err = iServSession.GetList(EProcesses, buffer, size); + } + test(KErrNone == err); + + //look through the buffer and check if the target debug thread is there + TUint8* ptr = (TUint8*)buffer.Ptr(); + const TUint8* ptrEnd = ptr + size; + while(ptr < ptrEnd) + { + TProcessListEntry& entry = *(TProcessListEntry*)ptr; + if(aProcessId.Id() == entry.iProcessId) + { + buffer.Close(); + return ETrue; + } + ptr += Align4(entry.GetSize()); + } + buffer.Close(); + return EFalse; + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0445 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests basic debug functions work on demand-paged target threads +//! @SYMTestActions Checks it can r/w memory, set breakpoints etc in a demand paged target. +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestDemandPaging(void) + { + test.Next(_L("TestDemandPaging\n")); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + test(KErrNone == iServSession.SuspendThread(iThreadID)); + + // get the address of a function in code that will be paged in + TUint32 address = (TUint32)(&RMDebugDemandPagingTest); + const TUint32 armInstSize = 4; + + // read the memory at &RMDebugDemandPagingTest to check that reading memory in demand paged code works + TUint32 demandPagedInst = 0; + TPtr8 demandPagedInstBuf((TUint8*)&demandPagedInst, armInstSize); + test(KErrNone == iServSession.ReadMemory(iThreadID, address, armInstSize, demandPagedInstBuf, EAccess32, EEndLE8)); + + // this is the MOVS instruction that we expect to find in RMDebugDemandPagingTest + TUint32 expectedDemandPagedInst = 0xe1b02000; + + // check that the instruction we read is as expected + test(demandPagedInst == expectedDemandPagedInst); + + // set event action for break points + test(KErrNone == iServSession.SetEventAction(RProcess().FileName(), EEventsBreakPoint, EActionContinue)); + + // set an arm breakpoint on RMDebugDemandPagingTest + TBreakId armBreakId = 0; + test(KErrNone == iServSession.SetBreak(armBreakId, iThreadID, address, EArmMode)); + + // Ensure that after setting the breakpoint the memory read returns the correct value + TUint32 demandPagedInstWithBreakPoint = 0; + TPtr8 spinForeverInstWithBreakPointBuf((TUint8*)&demandPagedInstWithBreakPoint, armInstSize); + test(KErrNone == iServSession.ReadMemory(iThreadID, address, armInstSize, spinForeverInstWithBreakPointBuf, EAccess32, EEndLE8)); + test(demandPagedInst == demandPagedInstWithBreakPoint); + + // switch the target thread to run the demand paging function + test(KErrNone == SwitchTestFunction(EDemandPagingFunction)); + + // set up event watcher to catch breakpoint being hit in demand paged code + TEventInfo info; + static TRequestStatus status; + TPtr8 infoPtr((TUint8*)&info,sizeof(TEventInfo)); + iServSession.GetEvent(RProcess().FileName(), status, infoPtr); + + // resume the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + // wait for notification of the breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + + // info should now be filled with the details + test(info.iProcessIdValid); + test(info.iThreadIdValid); + test(info.iEventType == EEventsBreakPoint); + test(info.iThreadBreakPointInfo.iRmdArmExcInfo.iR15 == address); + + // remove the break point and resume the thread + test(KErrNone == iServSession.ClearBreak(armBreakId)); + + // switch the target thread to run the default function + test(KErrNone == SwitchTestFunction(EDefaultFunction)); + + test(KErrNone == iServSession.ResumeThread(iThreadID)); + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +// Names of some test programs used for testing security +_LIT(KRMDebugSecurity0FileName,"z:\\sys\\bin\\t_rmdebug_security0.exe"); // Debuggable +_LIT(KRMDebugSecurity1FileName,"z:\\sys\\bin\\t_rmdebug_security1.exe"); // Not debuggable + +#if defined (NO_DEBUGTOKEN) || defined (SOMECAPS_DEBUGTOKEN) || defined(FEWCAPS_DEBUGTOKEN) +_LIT(KRMDebugSecurity2FileName,"z:\\sys\\bin\\t_rmdebug_security2.exe"); // AllFiles +#endif + +_LIT(KRMDebugSecurity3FileName,"z:\\sys\\bin\\t_rmdebug_security3.exe"); // TCB AllFiles + +// include the test header file here +#include "rm_debug_kerneldriver.h" + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0446 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests Debug Device Driver is locked to the SID of the Debug Security Svr. +//! @SYMTestActions Loads rm-debug.ldd and tries to open a handle to it. This should fail. +//! +//! @SYMTestExpectedResults KErrPermissionDenied. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestDriverSecurity(void) + { + test.Next(_L("TestDriverSecurity\n")); + + RRM_DebugDriver kernelDriver; + + // Load the debug device driver + TInt err = User::LoadLogicalDevice( KDebugDriverFileName ); + test((KErrNone == err) || (KErrAlreadyExists == err)); + + // we were allowed to load the driver, or its already loaded. + + // Try to open a handle to the driver - this should return KErrPermissionDenied as we don't have the DSS SID + TRM_DebugDriverInfo driverInfo; + driverInfo.iUserLibraryEnd = 0; + err = kernelDriver.Open(driverInfo); + test((err == KErrInUse) || (err == KErrPermissionDenied)); + + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0447 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests Debug driver can only be access via the DSS. Also tests DSS cannot +//! be subverted. Tests functionality of two representative OEM Debug Tokens. +//! @SYMTestActions Tries to open rm_debug.ldd (should fail). Tries to debug various processes +//! (only debuggable one should succeed). Checks that DSS behaves correctly +//! when different versions are passed in to Connect(). +//! +//! @SYMTestExpectedResults KErrPermissionDenied. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestSecurity(void) + { + // Things to test + // + // try to use debug driver directly ( should have the wrong UID/SID value!) + test.Next(_L("TestSecurity - Bypass Debug Security Server to Debug Device Driver - DSS running\n")); + + // Things to test + // + // Load the debug device driver + RRM_DebugDriver kernelDriver; + TInt err = User::LoadLogicalDevice( KDebugDriverFileName ); + test((KErrNone == err) || (KErrAlreadyExists == err)); + + // we were allowed to load the driver, or its already loaded. + + // Try to open handle a to the driver - this should return KErrPermission/KErrInUse as we don't have the DSS SID + // and we expect the DSS to already be using it. + TRM_DebugDriverInfo driverInfo; + driverInfo.iUserLibraryEnd = 0; + err = kernelDriver.Open(driverInfo); + test(err == KErrInUse); + + // Try requesting an unsupported version of DSS + test.Next(_L("TestSecurity - requesting unsupported versions of DSS\n")); + RSecuritySvrSession dss; + err = dss.Connect(TVersion(999999, 0, 0)); + test(err == KErrNotSupported); // Prior to DEF142018 this would crash, causing a KErrServerTerminated + err = dss.Connect(TVersion(KDebugServMajorVersionNumber, 999999, 0)); + test(err == KErrNotSupported); // Explicitly asking for a minor version should give KErrNotSupported too if it's newer than what's running. + err = dss.Connect(TVersion(KDebugServMajorVersionNumber, 0, 0)); + test(err == KErrNone); // But the correct major version and no explicit minor version should always succeed + dss.Close(); + + // + // Attach to the Debug Security Server (passive) + // + test.Next(_L("TestSecurity - Attach to the Debug Security Server (passive)\n")); + + _LIT(KSecurityServerProcessName, "z:\\sys\\bin\\rm_debug_svr.exe"); + + test(KErrPermissionDenied == iServSession.AttachExecutable(KSecurityServerProcessName, ETrue)); + + // + // Attach to the Debug Security Server (active) + // + test.Next(_L("TestSecurity - Attach to the Debug Security Server (active)\n")); + + test(KErrPermissionDenied == iServSession.AttachExecutable(KSecurityServerProcessName, EFalse)); + + // + // Attach to Process 0 + // + // Target: Debuggable + // + test.Next(_L("TestSecurity - Attach to test process 0\n")); + + // Agent can debug the target app as it is marked debuggable - ie capabilities are ignored) + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity0FileName,ETrue); + + // + // Attach to Process - 1 + // + // Target: Non-debuggable for ordinary debug agent, debuggable for OEM/OEM2 token authorised agent + // + // Note: This target app has no PlatSec capabilities + // + // Agent cannot debug the app unless it has an OEM/OEM2 Debug Token + + +#ifdef NO_DEBUGTOKEN + test.Next(_L("TestSecurity NO_DEBUGTOKEN - Attach to test process 1\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity1FileName,EFalse); +#endif + +#ifdef SOMECAPS_DEBUGTOKEN + test.Next(_L("TestSecurity SOMECAPS_DEBUGTOKEN - Attach to test process 1\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity1FileName,ETrue); +#endif + +#ifdef FEWCAPS_DEBUGTOKEN + test.Next(_L("TestSecurity FEWCAPS_DEBUGTOKEN - Attach to test process 1\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity1FileName,ETrue); +#endif + + // + // Attach to Process - 2 + // + // Target: Non-debuggable for ordinary debug agent, non-debuggable for OEM2 authorised agent (insufficient caps) + // + // Note: This target app has AllFiles capability + // + // Agent cannot debug the app unless it has an OEM Debug Token + + +#ifdef NO_DEBUGTOKEN + test.Next(_L("TestSecurity NO_DEBUGTOKEN - Attach to test process 2\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity2FileName,EFalse); +#endif + +#ifdef SOMECAPS_DEBUGTOKEN + test.Next(_L("TestSecurity SOMECAPS_DEBUGTOKEN - Attach to test process 2\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity2FileName,ETrue); +#endif + +#ifdef FEWCAPS_DEBUGTOKEN + test.Next(_L("TestSecurity FEWCAPS_DEBUGTOKEN - Attach to test process 2\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity2FileName,EFalse); +#endif + + // + // Attach to Process - 3 + // + // Target: Non-debuggable for ordinary debug agent, non-debuggable for OEM authorised agent (insufficient caps) + // + // Note: This target app has AllFiles and TCB and NetworkControl capabilities + // + +#if defined (NO_DEBUGTOKEN) || defined (SOMECAPS_DEBUGTOKEN) || defined (FEWCAPS_DEBUGTOKEN) + test.Next(_L("TestSecurity - Attach to test process 3 : Should not be able to debug it\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity3FileName,EFalse); +#else + test.Next(_L("TestSecurity - Attach to test process 3 : Should be able to debug it\n")); + HelpTestSecurityAttachDetachExecutable(KRMDebugSecurity3FileName,ETrue); +#endif + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0543 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Validates that a dll can be built which #include's the rm_debug_api.h header, i.e. rm_debug_api.h contains no static data. +//! @SYMTestActions Calls a dummy function in t_rmdebug_dll.dll which implies the dll has been built correctly. +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- +void CRunModeAgent::TestDllUsage(void) + { + test.Next(_L("TestDllUsage\n")); + test(KUidDebugSecurityServer == GetDSSUid()); + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0812 +//! @SYMTestType +//! @SYMPREQ PREQ1700 +//! @SYMTestCaseDesc Writes a known data to the crash flash and validates the data written +//! using the read operation and finally erase the data. In the absence +//! of an OEM debug token, access to the crash partition should not be allowed +//! @SYMTestActions Invoke the flash write method in DSS and call the read method in DSS +//! to validate the data is written correctly and then erase the written area +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- +void CRunModeAgent::TestCrashFlash(void) + { +#if defined (NO_DEBUGTOKEN) || defined (FEWCAPS_DEBUGTOKEN) + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-006 Testing We cannot Erase the Crash Flash with insufficient privileges")); + + TUint32 size = 0; + TInt err = iServSession.EraseCrashLog(0, 1); + test(KErrPermissionDenied == err); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-005 Testing We can't Write to the Crash Flash with insufficient privileges")); + + err = iServSession.WriteCrashConfig(0, KCrashDummyData, size); + test(KErrPermissionDenied == err); + test(size == 0); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-008 Testing We can't Read from the Crash Flash with insufficient privileges")); + + TUint32 readSize = 0x10; + RBuf8 buf; + buf.CleanupClosePushL(); + err = buf.Create(readSize); + + test(err == KErrNone); + + err = iServSession.ReadCrashLog(0, buf, readSize); + test(KErrPermissionDenied == err); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-004 Testing Writing To an invalid location")); + + TUint32 writeSize = 0; + err = iServSession.WriteCrashConfig(0xFFFFFFFF, KCrashDummyData, writeSize); + + test(err == KErrPermissionDenied); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-003 Testing Reading from an invalid location")); + + buf.FillZ(); + err = iServSession.ReadCrashLog(0, buf, writeSize); + + test(err == KErrPermissionDenied); + + CleanupStack::PopAndDestroy(&buf); + +#endif + +#ifdef SOMECAPS_DEBUGTOKEN + + TInt err = KErrNone; + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-007 Testing We can Erase the Crash Flash with sufficient privileges")); + + err = iServSession.EraseCrashLog(0, 1); + + // For platforms where NAND flash is not currently supported we get a KErrNotSupported - this is still a pass + if (KErrNotSupported == err) + { + test.Printf(_L("Nand flash not supported - continue")); + return; + } + + //For platforms without a flash partition we get KErrNotFound - this is still a pass + if(KErrNotFound == err) + { + test.Printf(_L("Platform has no flash partition - continue")); + return; + } + + test(KErrNone == err); + + //Read back the start of the block to make sure its 0xFFFFFFFF + const TUint numBytesToCheck = 0x80; //We dont know the block size + TBuf8 eraseCheck; + eraseCheck.SetLength(numBytesToCheck); + + err = iServSession.ReadCrashLog(0, eraseCheck, numBytesToCheck); + test(err == KErrNone); + + TBool dataIsOk = ETrue; + for(TUint cnt = 0; cnt < numBytesToCheck; cnt++) + { + if(eraseCheck[cnt] != 0xFF) + { + dataIsOk = EFalse; + } + } + + test(dataIsOk); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-002 Testing We can Write to the Crash Flash with sufficient privileges")); + + TUint32 writeSize = 0; + err = iServSession.WriteCrashConfig(0, KCrashDummyData, writeSize); + + test(writeSize == KCrashDummyData().Length()); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-001 Testing We can Read from the Crash Flash with sufficient privileges")); + + RBuf8 buf; + buf.CleanupClosePushL(); + err = buf.Create(writeSize); + + test(err == KErrNone); + + buf.FillZ(); + + err = iServSession.ReadCrashLog(0, buf, writeSize); + + test(0 == buf.Compare(KCrashDummyData)); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-004 Testing Writing To an invalid location")); + + writeSize = 0; + err = iServSession.WriteCrashConfig(0xFFFFFFFF, KCrashDummyData, writeSize); + + test(err == KErrArgument); + + test.Next(_L("@SYMTestCaseID:DT-debug-securityserver-003 Testing Reading from an invalid location")); + + buf.FillZ(); + err = iServSession.ReadCrashLog(0xFFFFFFFF, buf, writeSize); + + test(err == KErrArgument); + + CleanupStack::PopAndDestroy(&buf); + +#endif + } +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0735 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests the Kill Process functionality. Only can kill a debuggable process. +//! @SYMTestActions Launches a debuggable and non-debuggable process and tries to kill both. +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- +void CRunModeAgent::TestKillProcess(void) + { + test.Next(_L("TestKillProcess\n")); + + // Kill a debuggable process + + // check that killing a process is supported + TTag tag = GetTag(ETagHeaderIdKillObjects, EFunctionalityKillProcess); + test(tag.iValue); + // check that killing a thread is not supported + tag = GetTag(ETagHeaderIdKillObjects, EFunctionalityKillThread); + test(!tag.iValue); + + // attach first! + TInt err = iServSession.AttachExecutable(KRMDebugTestApplication, EFalse /* Active */); + test(err == KErrNone); + + // first launch a debuggable process + RProcess process; + err = LaunchProcess(process, KRMDebugTestApplication(),ESpinForever, 0, 0); + test (err == KErrNone); + + // try to find the process in the list +_LIT(KRMDebugAppName, "t_rmdebug_app"); + + TBool found = ProcessExists(KRMDebugAppName); + test (found); + + TInt processId = process.Id(); + process.Close(); + + // program now running, so try to kill it + err = iServSession.KillProcess(processId, 0 /* kill reason */); + test(err == KErrNone); + + User::After(2000000); // should die within two seconds. + + // can we still find it? Should be gone + found = ProcessExists(KRMDebugAppName); + test (!found); + + // release the program again. + err = iServSession.DetachExecutable(KRMDebugTestApplication); + test(err == KErrNone); + + // Try to kill a non-debuggable process and fail. + + // first launch a non-debuggable process + RProcess process2; + err = LaunchProcess(process2, KRMDebugSecurity1FileName(),ESpinForever, 0, 0); + test (err == KErrNone); + + // try to find the process in the list +_LIT(KRMDebugAppName2, "t_rmdebug_security1"); + + TBool found2 = ProcessExists(KRMDebugAppName2); + test (found2); + + TInt process2Id = process2.Id(); + process2.Close(); + + // program now running, so try to kill it + err = iServSession.KillProcess(process2Id, 0 /* kill reason */); + test(err == KErrPermissionDenied); + + User::After(2000000); // should die within two seconds if it is going to die. + + // can we still find it? Should be still around! + found2 = ProcessExists(KRMDebugAppName2); + test (found2); + + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-1388 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Tests the correct operation of the AddProcess and Remove Process +//! @SYMTestActions 1. Registers for AddProcess and Remove Process events +//! 2. Starts a test process z:\sys\bin\t_rmdebug_security0.exe +//! 3. Wait for the AddProcess event to be reported +//! 4. Kill the newly started test process +//! 5. Wait for the RemoveProcess event to be reported +//! 6. Tell the DSS it is no longer interested in AddProcess and RemoveProcess events +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestAddRemoveProcessEvents() + { + test.Next(_L("TestAddRemoveProcessEvents\n")); + + // attach to a process (e.g. one of the simple security test programs) + // launch the security program + // wait for the add event + // continue the program. + // wait for the remove event + // detach process + + test(KErrNone == iServSession.AttachExecutable(KRMDebugSecurity0FileName, EFalse)); + + test(KErrNone == iServSession.SetEventAction(KRMDebugSecurity0FileName,EEventsAddProcess, EActionContinue)); + + test(KErrNone == iServSession.SetEventAction(KRMDebugSecurity0FileName,EEventsRemoveProcess, EActionContinue)); + + // Creator thread ID of the current thread (to be creator of test application) + TInt creatorThreadId = RThread().Id(); + + RProcess process; + TInt err = process.Create(KRMDebugSecurity0FileName, KNullDesC, EOwnerProcess); + test (err == KErrNone); + + // Rendezvous with process + TRequestStatus status; + process.Rendezvous(status); + + // Start the test program + process.Resume(); + User::WaitForRequest(status); + test(status==KErrNone); + + // Wait for the addprocess event + TEventInfo info; + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + + iServSession.GetEvent(KRMDebugSecurity0FileName,status,infoPtr); + + // Wait for notification of the addprocess hit event + User::WaitForRequest(status); + test(status==KErrNone); + + // Check this was the right kind of event + test(info.iEventType == EEventsAddProcess); + + const TInt uid3offset = 2; + + // Get UID3 for current process + TUint32 Uid3 = process.Type()[uid3offset].iUid; + + // Check correct UID3 is returned from the driver + test(info.iAddProcessInfo.iUid3 == Uid3); + + // Check correct creator ID for test application is returned from the driver + test(info.iAddProcessInfo.iCreatorThreadId == creatorThreadId); + + // Kill the process, as we don't need it anymore + process.Kill(KErrNone); + + // Wait for the remove process event + iServSession.GetEvent(KRMDebugSecurity0FileName,status,infoPtr); + + // Wait for notification of the remove process hit event + User::WaitForRequest(status); + test(status==KErrNone); + + // Check this was the right kind of event + test(info.iEventType == EEventsRemoveProcess); + + test(KErrNone == iServSession.SetEventAction(KRMDebugSecurity0FileName,EEventsRemoveProcess, EActionIgnore)); + + test(KErrNone == iServSession.SetEventAction(KRMDebugSecurity0FileName,EEventsAddProcess, EActionIgnore)); + + test(KErrNone == iServSession.DetachExecutable(KRMDebugSecurity0FileName)); + + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-0736 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Checks that process break points can be set, and that they can co-exist alongside thread breakpoints +//! @SYMTestActions Checks that process break points can be set, and that they can co-exist alongside thread breakpoints +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- +void CRunModeAgent::TestProcessBreakPoints(void) + { + test.Next(_L("TestProcessBreakPoints\n")); + + // check that process breakpoints are supported + TTag tag = GetTag(ETagHeaderIdBreakpoints, EBreakpointProcess); + test(tag.iValue); + + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + test(KErrNone == iServSession.SuspendThread(iThreadID)); + + // Try to set the breakpoint + TBreakId breakId; + TUint32 address = (TUint32)(&RMDebug_BranchTst1); + RProcess process; + TProcessId processId = process.Id(); + process.Close(); + + test(KErrNone == iServSession.SetProcessBreak(breakId, processId, address, EArmMode)); + test(KErrAlreadyExists == iServSession.SetBreak(breakId, iThreadID, address, EArmMode)); + test(KErrAlreadyExists == iServSession.SetBreak(breakId, iThreadID, address, EThumbMode)); + test(KErrAlreadyExists == iServSession.SetProcessBreak(breakId, processId, address, EArmMode)); + test(KErrAlreadyExists == iServSession.SetProcessBreak(breakId, processId, address, EThumbMode)); + test(KErrNone == iServSession.ClearBreak(breakId)); + + test(KErrNone == iServSession.SetBreak(breakId, iThreadID, address, EArmMode)); + test(KErrAlreadyExists == iServSession.SetProcessBreak(breakId, processId, address, EArmMode)); + test(KErrAlreadyExists == iServSession.SetProcessBreak(breakId, processId, address, EThumbMode)); + test(KErrNone == iServSession.ClearBreak(breakId)); + + test(KErrNone == iServSession.ResumeThread(iThreadID)); + + test(KErrNone == iServSession.DetachExecutable(iFileName)); + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-1309 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Checks that in the case of multiple low priority events (user traces in this case) we can still receive higher +//! priority events should the buffer reach a critical level +//! @SYMTestActions Run to first breakpoint in our test code. Then multiple trace events are issued. We should still be able to hit +//! the second breakpoint +//! +//! @SYMTestExpectedResults KErrNone. +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestMultipleTraceEvents(void) + { + test.Next(_L("TestMultipleTraceEvents\n")); + + //attach to target debug process + test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); + + //set the target thread to execute the trace test function + test(KErrNone == SwitchTestFunction(EMultipleTraceCalls, EFalse)); + + + + //register interest in BP's & trace events and trace ignored events + test(KErrNone == iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionSuspend)); + test(KErrNone == iServSession.SetEventAction(iFileName,EEventsUserTrace, EActionContinue)); + test(KErrNone == iServSession.SetEventAction(iFileName,EEventsUserTracesLost, EActionContinue)); + + // Try to set the breakpoints + TBreakId armBreakId; + TBreakId armBreakId2; + TUint32 address = (TUint32)(&RMDebug_BranchTst1); + TUint32 address2 = (TUint32)(&RMDebug_StepTest_Non_PC_Modifying); + + test(KErrNone == iServSession.SetBreak(armBreakId,iThreadID,address,EArmMode)); + test(KErrNone == iServSession.SetBreak(armBreakId2,iThreadID,address2,EArmMode)); + + // Continue the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + + // wait for the breakpoint to be hit + TEventInfo info; + static TRequestStatus status; + + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of the 1st breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + + // info should now be filled with the details + test(info.iEventType == EEventsBreakPoint); + test(info.iThreadBreakPointInfo.iRmdArmExcInfo.iR15 == address); + test(info.iProcessIdValid); + test(info.iThreadIdValid); + + // Continue the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + + //Now we try to hit the second breakpoint. This will occur after a number of trace calls. If we hit this breakpoint it + //means many trace calls are not preventing us hitting breakpoints. + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of the 2nd breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + + TBool receivedTracesLost = EFalse; + + while(info.iEventType == EEventsUserTrace || info.iEventType == EEventsUserTracesLost) + { + //ensure we get told traces are being thrown away - we generate enough to flood the buffer + if(info.iEventType == EEventsUserTracesLost) + { + receivedTracesLost = ETrue; + + // Now stop the target thread from generating trace events + test(KErrNone == SwitchTestFunction(EDoNothing, EFalse)); + break; + } + else + { + // Its EEventsUserTrace, so delay us in getting the next event so that it will be more + // likely to get a EEventsUserTracesLost next time. + // This is important on SMP since the platform can process lots of events, and thus + // withouth the delay it is difficult for this test to reproduce the abnormal situation of + // lost trace packets + User::After(200000); + } + + iServSession.GetEvent(iFileName,status,infoPtr); + + // Wait for notification of the 2nd breakpoint hit event + User::WaitForRequest(status); + test(status==KErrNone); + } + + //make sure we got told traces were lost + test(receivedTracesLost != EFalse); + + //dont care for breakpoints or trace events no more + test(KErrNone == iServSession.SetEventAction(iFileName,EEventsBreakPoint, EActionIgnore)); + test(KErrNone == iServSession.SetEventAction(iFileName,EEventsUserTrace, EActionIgnore)); + test(KErrNone == iServSession.SetEventAction(iFileName,EEventsUserTracesLost, EActionIgnore)); + + //clear the breaks we set + test(KErrNone == iServSession.ClearBreak(armBreakId)); + test(KErrNone == iServSession.ClearBreak(armBreakId2)); + + // Continue the thread + test(KErrNone == iServSession.ResumeThread(iThreadID)); + + //attach to target debug process + test(KErrNone == iServSession.DetachExecutable(iFileName)); + + } + +//---------------------------------------------------------------------------------------------- +//! @SYMTestCaseID KBase-T-RMDEBUG2-2441 +//! @SYMTestType +//! @SYMPREQ PREQ1426 +//! @SYMTestCaseDesc Test clearing of a process breakpoint once the process has been killed. +//! @SYMTestActions Creates a new process then tries to set a process breakpoint and then kills the process which should clear the previously set breakpoint. Then repeat the step once again. +//! @SYMTestExpectedResults KErrNone +//! @SYMTestPriority High +//! @SYMTestStatus Implemented +//---------------------------------------------------------------------------------------------- + +void CRunModeAgent::TestProcessKillBreakpoint(void) + { + test.Next(_L("TestProcessKillBreakpoint\n")); + + DoTestProcessKillBreakpoint(); + // called once again + // to check if we can set the breakpoint once again after the process gets killed + DoTestProcessKillBreakpoint(); + + // And do it a couple more times, there was a leaked process handle that didn't show up + // until the third or fourth time this code was run + DoTestProcessKillBreakpoint(); + DoTestProcessKillBreakpoint(); + } + +void CRunModeAgent::DoTestProcessKillBreakpoint() + { + test.Printf(_L("\nDoTestProcessKillBreakpoint\n")); + + // check that killing a process is supported + TTag tag = GetTag(ETagHeaderIdKillObjects, EFunctionalityKillProcess); + test(tag.iValue); + // check that killing a thread is not supported + tag = GetTag(ETagHeaderIdKillObjects, EFunctionalityKillThread); + test(!tag.iValue); + + // attach first! + test ( KErrNone == iServSession.AttachExecutable(KRMDebugTestApplication, EFalse/* Active */)); + + RProcess processDebug; + TThreadId dontCare; + LaunchDebugProcessAndSetBreakpoint(processDebug, dontCare); + + // Not interested in breakpoint events any more + test(KErrNone == iServSession.SetEventAction(KRMDebugTestApplication, EEventsProcessBreakPoint, EActionIgnore)); + + // program now running, so try to kill it which should clear all the breakpoints + test(KErrNone == iServSession.KillProcess(processDebug.Id(), 0 /* kill reason */ )); + + TRequestStatus stat; + processDebug.NotifyDestruction(stat); + processDebug.Close(); + TIMED_WAIT(stat, 1000); + + // release the program again + test(KErrNone == iServSession.DetachExecutable(KRMDebugTestApplication)); + } + +void CRunModeAgent::LaunchDebugProcessAndSetBreakpoint(RProcess& aResultProcess, TThreadId& aResultThread) + { + // define a property to pass on the address from the other process we would try to debug + static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); + TInt err = RProperty::Define(RProcess().SecureId(), EMyPropertyInteger, RProperty::EInt, KAllowAllPolicy, KAllowAllPolicy); + test (err == KErrNone || err == KErrAlreadyExists); + + RSemaphore addressGlobSem; + //define a global semaphore to synchronise with debuggable process publishing the property + err = addressGlobSem.CreateGlobal(_L("RMDebugGlobSem"), 0); + test (err == KErrNone); + + // first launch a debuggable process + RProcess& processDebug(aResultProcess); + test ( KErrNone == LaunchProcess(processDebug, KRMDebugTestApplication(),ESpinForeverWithBreakPoint, 0, 0)); + + // try to find the process in the list + TBool found = ProcessExists(KRMDebugAppName); + test (found); + + //search for the main thread created + _LIT(KThreadWildCard, "t_rmdebug_app*"); + TProcessId processDebugId = processDebug.Id(); + TThreadId& threadDebugId(aResultThread); + + TFindThread find(KThreadWildCard); + TFullName name; + found = EFalse; + while(find.Next(name)==KErrNone && !found) + { + RThread thread; + err = thread.Open(find); + if (err == KErrNone) + { + RProcess process; + thread.Process(process); + if (((TUint32)process.Id() == processDebugId)) + { + TFullName fullname = thread.FullName(); + test.Printf(_L("Match Found Name: %S Process id: %ld Thread id: %ld\n"), &fullname, process.Id().Id(), thread.Id().Id()); + found = ETrue; + threadDebugId = thread.Id(); + } + process.Close(); + } + thread.Close(); + } + + test (found); //check if we actually found the thread we want to debug + + //waiting on semaphore to be sure that the property is set + addressGlobSem.Wait(); + + //get the value(property) for the breakpoint address for the process to debug + TInt address; + test(KErrNone == RProperty::Get(RProcess().SecureId(), EMyPropertyInteger, address)); + + test.Printf(_L("Address retrieved to set breakpoint 0x%08x\n"), address); + + //suspend the thread before we set a breakpoint + test (KErrNone == iServSession.SuspendThread(threadDebugId)); + + //set a process breakpoint + TBreakId breakId; + test(KErrNone == iServSession.SetProcessBreak(breakId, processDebugId, address, EArmMode)); + + test(KErrNone == iServSession.SetEventAction(KRMDebugTestApplication, EEventsProcessBreakPoint, EActionContinue)); + + //resume the thread now + test(KErrNone == iServSession.ResumeThread(threadDebugId)); + + // wait for the breakpoint to be hit + TRequestStatus status; + TEventInfo info; + TPtr8 infoPtr((TUint8*)&info,0,sizeof(TEventInfo)); + iServSession.GetEvent(KRMDebugTestApplication,status,infoPtr); + // Wait for notification of the breakpoint hit event + TIMED_WAIT(status, 2000); + test(status==KErrNone); + + // info should now be filled with the details + test(info.iEventType == EEventsProcessBreakPoint); + test(info.iThreadBreakPointInfo.iRmdArmExcInfo.iR15 == address); + test(info.iProcessIdValid); + test(info.iThreadIdValid); + + addressGlobSem.Close(); + } + +void CRunModeAgent::HelpTestSecurityAttachDetachExecutable(const TDesC& aProcessName, TBool aExpectSuccess) + { + RProcess process; + TInt err = process.Create(aProcessName, KNullDesC, EOwnerProcess); + test (err == KErrNone); + + // rendezvous with process + TRequestStatus status; + process.Rendezvous(status); + + // start the test program + process.Resume(); + User::WaitForRequest(status); + test(status==KErrNone); + + // attach to the program (passively) + err = iServSession.AttachExecutable(aProcessName, EFalse); + + if( gUseDelay ) User::After(500000); + + // Do we expect to successfully attach + if (aExpectSuccess) + { + // Yes + test(KErrNone == err); + + // Now detach again + test(KErrNone == iServSession.DetachExecutable(aProcessName)); + if( gUseDelay ) User::After(500000); + } + else + { + // No + test(KErrPermissionDenied == err); + + // Just to be sure, try active attachment + test(KErrPermissionDenied == iServSession.AttachExecutable(aProcessName, ETrue)); + if( gUseDelay ) User::After(500000); + } + + // Kill the process, as we don't need it anymore + process.Kill(KErrNone); + if( gUseDelay ) User::After(500000); + } + +void CRunModeAgent::ReportPerformance(void) +// +// Reports performance metrics from all the tests +// + { + test.Printf(_L("\nPerformance\n")); + test.Printf(_L("========================\n")); + + // Memory + test.Printf(_L("Memory read: %d KBytes/sec\n"),iMemoryReadKbytesPerSecond); + test.Printf(_L("Memory write: %d KBytes/sec\n"),iMemoryWriteKbytesPerSecond); + + // Registers + // to do + + // events + // to do + + // Breakpoints + test.Printf(_L("Breakpoint set/clear: %d/sec\n"),iBreakpointsPerSecond); + test.Printf(_L("Maximum number of breakpoints: %d\n"),iMaxBreakpoints); + + // Stepping + test.Printf(_L("Stepping speed: %d/sec\n"),iStepsPerSecond); + + // Runtime + TInt ticks = HelpGetTestTicks(); + test (ticks != 0); + + TInt nkTicksPerSecond = HelpTicksPerSecond(); + test (nkTicksPerSecond != 0); + + test.Printf(_L("Total test runtime: %d seconds\n"),ticks/nkTicksPerSecond); + + // Final sizes of executables/rom/ram etc + // to do + + test.Printf(_L("\n")); + } + +/** + * Helper code for the stepping tests. Sets a breakpoint in a running thread. + * It suspends the thread, sets the breakpoint, and resumes the thread. + * + * @param aBreakId - Reference to a TBreakId which will be set when the breakpoint is set + * @param aThreadId - The thread id for which we should set the breakpoint. + * @param aBreakAddress - The address to set the breakpoint + * @param aMode - The architecture of the breakpoint to be set (ARM/Thumb/Thumb2EE) + * @return KErrNone if successful. One of the other system wide error codes otherwise. + */ +TInt CRunModeAgent::HelpTestStepSetBreak(TBreakId& aBreakId, TThreadId aThreadId, const TUint32 aBreakAddress, TArchitectureMode aMode, TBool aThreadSpecific, TProcessId aProcessId) + { + TInt err = KErrNone; + + + // Set the breakpoint + err = aThreadSpecific + ? iServSession.SetBreak(aBreakId,aThreadId,aBreakAddress,aMode) + : iServSession.SetProcessBreak(aBreakId, aProcessId, aBreakAddress, aMode); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStepSetBreak - Failed to set breakpoint\n")); + return err; + } + + // Continue the thread + err = iServSession.ResumeThread(aThreadId); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStepSetBreak - Failed to resume thread\n")); + return err; + } + + return KErrNone; + } + +/** + * Helper code for the stepping tests. Clears a breakpoint in a running thread. + * It suspends the thread, clears the breakpoint, and resumes the thread. + * + * @param aBreakId - Reference to a TBreakId which will be set when the breakpoint is set + * @return KErrNone if successful. One of the other system wide error codes otherwise. + */ +TInt CRunModeAgent::HelpTestStepClearBreak(TBreakId aBreakId, const TThreadId aThreadId, TBool aThreadSpecific) + { + TInt err = KErrNone; + + // Find out what thread id we need to suspend + TThreadId threadId; + TProcessId processId; + TUint32 address; + TArchitectureMode mode; + + err = aThreadSpecific + ? iServSession.BreakInfo(aBreakId, threadId, address, mode) + : iServSession.ProcessBreakInfo(aBreakId, processId, address, mode); + if (err != KErrNone ) + { + test.Printf(_L("HelpTestStepClearBreak - failed to obtain information for breakpoint\n")); + return err; + } + if(aThreadSpecific && aThreadId != threadId) + { + test.Printf(_L("HelpTestStepClearBreak - mismatched thread Ids\n")); + return KErrGeneral; + } + + // Clear the breakpoint + err = iServSession.ClearBreak(aBreakId); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStepClearBreak - failed to clear breakpoint\n")); + return err; + } + + return KErrNone; + } + +/** + * Helper code for the stepping tests. Waits for a previously set breakpoint to be hit. + * + * @param aProcessName - The name of the process in which the breakpoint is set. E.g. z:\sys\bin\app.exe + * @param aEventInfo - The event information block which is filled in when the breakpoint is hit. + * @return KErrNone if successful. One of the other system wide error codes otherwise. + */ +TInt CRunModeAgent::HelpTestStepWaitForBreak(const TDesC& aProcessName, TEventInfo& aEventInfo) + { + static TRequestStatus status; + + TPtr8 infoPtr((TUint8*)&aEventInfo,0,sizeof(TEventInfo)); + + iServSession.GetEvent(aProcessName,status,infoPtr); + + // Wait for notification of the breakpoint hit event + User::WaitForRequest(status); + if (status == KErrNone) + { + return KErrNone; + } + else + { + return KErrGeneral; + } + } + +/** + * Helper code for the stepping tests. Reads the current target PC for a given thread. + * + * @param aThreadId - Thread id for which to read the current target PC. + * @param aPc - Reference to a TUint32 which will be set to the current target PC. + * @return KErrNone if successful. One of the other system wide error codes otherwise. + */ +TInt CRunModeAgent::HelpTestStepReadPC(TThreadId aThreadId, TUint32& aPC) + { + TInt err = KErrNone; + + //create buffer containing PC register ID + RBuf8 pcId; + err = pcId.Create(sizeof(TRegisterInfo)); + if (err != KErrNone) + { + return err; + } + + TRegisterInfo reg1 = (TRegisterInfo)0x00000f00; + pcId.Append(reinterpret_cast(®1), sizeof(TRegisterInfo)); + + //create buffer containing desired PC value + TPtr8 pcValue((TUint8*)&aPC,4,4); + + //create buffer for PC flag value + RBuf8 pcFlag; + err = pcFlag.Create(sizeof(TUint8)); + + //read the new PC value + err = iServSession.ReadRegisters(aThreadId, pcId, pcValue, pcFlag); + if (err != KErrNone) + { + //delete temporary buffers + pcId.Close(); + pcFlag.Close(); + return err; + } + + //get the flag and check the PC value was read ok + TRegisterFlag flag = ENotSupported; + err = GetFlag(pcFlag, 0, flag); + if (err != KErrNone) + { + //delete temporary buffers + pcId.Close(); + pcFlag.Close(); + return err; + } + + if (flag == EValid) + { + //delete temporary buffers + pcId.Close(); + pcFlag.Close(); + return KErrNone; + } + else + { + //delete temporary buffers + pcId.Close(); + pcFlag.Close(); + return err; + } + } + +/** + * Helper code for the stepping tests. Single steps a given thread from aStartAddress to aEndAddress. Note + * that it reaches aStartAddress by setting a breakpoint at that address and waiting until it is hit. + * + * @param aThreadId - Thread id for which to read the current target PC. + * @param aStartAddress - The target address at which stepping will start. + * @param aEndAddress - The target address at which stepping will end. + * @param aMode - The architecture of the breakpoint which must be set at the start address (ARM/Thumb/Thumb2EE). + * @return KErrNone if successful. One of the other system wide error codes otherwise. + */ +TInt CRunModeAgent::HelpTestStep(TThreadId aThreadId, TUint32 aStartAddress, TUint32 aEndAddress, TArchitectureMode aMode, TUint aNumSteps, TBool aThreadSpecific, TProcessId aProcessId) + { + TInt err = KErrNone; + + // Ensure that the supplied addresses are word/half-word aligned as appropriate. + if (aMode == EArmMode) + { + // ARM breakpoints must be word-aligned (2 lsb must be zero) + aStartAddress &= 0xFFFFFFFC; + aEndAddress &= 0xFFFFFFFC; + } + else if (aMode == EThumbMode) + { + // Thumb breakpoints must be half-word aligned (lsb must be zero) + aStartAddress &= 0xFFFFFFFE; + aEndAddress &= 0xFFFFFFFE; + } + else if (aMode == EThumb2EEMode) + { + // Thumb2EE breakpoints are not currently supported + return KErrNotSupported; + } + + // Set breakpoint at the start address + TBreakId tempBreakId; + TEventInfo info; + + err = HelpTestStepSetBreak(tempBreakId,aThreadId,aStartAddress,aMode,aThreadSpecific,aProcessId); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStep - Failed to set breakpoint at aStartAddress 0x%08x\n"),aStartAddress); + return err; + } + + // wait for the breakpoint to be hit + err = HelpTestStepWaitForBreak(iFileName,info); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStep - Failed to hit the breakpoint at aStartAddress 0x%08x\n"),aStartAddress); + return err; + } + + // Check the PC == aStartAddress + TUint32 pc = 0; + err = HelpTestStepReadPC(aThreadId,pc); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStep - Failed to read the PC after hitting breakpoint at aStartAddress 0x%08x\n"),aStartAddress); + return err; + } + + if (pc != aStartAddress) + { + test.Printf(_L("HelpTestStep - Incorrect PC value after hitting breakpoint (expected 0x%08x actual 0x%08x)\n"),aStartAddress,pc); + return KErrGeneral; + } + + err = iServSession.Step(aThreadId,aNumSteps); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStep - Failed to do step from 0x%08x to 0x%08x\n"),aStartAddress,aEndAddress,aNumSteps); + return err; + } + + // only one 'completed step' event in the buffer. + err = HelpTestStepWaitForBreak(iFileName,info); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStep - Could not read breakpoint event info after stepping")); + return err; + } + // end + + // Check PC == aEndAddress + err = HelpTestStepReadPC(aThreadId,pc); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStep - failed read the PC after stepping\n")); + return err; + } + if (pc != aEndAddress) + { + test.Printf(_L("HelpTestStep - Incorrect PC value after stepping (expected 0x%08x actual 0x%08x)\n"),aEndAddress,pc); + return KErrGeneral; + } + + // Clear the breakpoint + err = HelpTestStepClearBreak(tempBreakId, aThreadId, aThreadSpecific); + if (err != KErrNone) + { + test.Printf(_L("HelpTestStep - failed to clear temporary breakpoint\n")); + return err; + } + + return KErrNone; + } + +/** + * Helper code for the stepping tests. Returns the number of nanokernel ticks in one second. + * + * @return Number of nanokernel ticks. 0 if unsuccesful. + */ +TInt CRunModeAgent::HelpTicksPerSecond(void) + { + TInt nanokernel_tick_period; + HAL::Get(HAL::ENanoTickPeriod, nanokernel_tick_period); + + ASSERT(nanokernel_tick_period != 0); + + static const TInt KOneMillion = 1000000; + + return KOneMillion/nanokernel_tick_period; + } + +/** + Given aTestNumber runs the appropriate test inside heap markers + + @param aTestNumber test to run, corresponds to an entry in iTestArray + + @panic Panic if aTestNumber is not in valid range + */ +void CRunModeAgent::RunTest(TInt aTestNumber) + { + if( (aTestNumber<0) || (aTestNumber>=KMaxTests) ) + { + User::Panic(_L("Test number out of range"), aTestNumber); + } + __UHEAP_MARK; + (this->*(iTestArray[aTestNumber].iFunctionPtr))(); + __UHEAP_MARKEND; + } + +void CRunModeAgent::PrintVersion() + { + test.Printf(_L("\nt_rmdebug2.exe\nVersion: %S\n"), &(testVersion.Name())); + test.Printf(_L("Press any key...\n")); + test.Getch(); + } + +void CRunModeAgent::PrintUsage() + { + test.Printf(_L("Invoke with arguments:\n")); + test.Printf(_L("-r: run specified tests in reverse order\n")); + test.Printf(_L("-h: display usage information\n")); + test.Printf(_L("-v: display version\n")); + test.Printf(_L("-d: use delays\n")); + test.Printf(_L(": test number to run, can specify more than one from the following list:\n")); + test.Printf(_L("Press any key for list...\n")); + test.Getch(); + // if there are too many of these they won't fit on the screen! Stick another Getch() in if there get too many + for(TInt i=0; i& aTests) + { + // 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); + + // reset mode + aMode = (TTestMode)0; + + // 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 'v': + //print out the help + aMode |= EModeVersion; + break; + case 'h': + //print out the help + aMode |= EModeHelp; + break; + case 'r': + //store the fact that we want to run in reverse + aMode |= EModeReverse; + break; + case 'd': + //store the fact that we want to run in reverse + gUseDelay = EFalse; + RDebug::Printf("Not using delays"); + break; + default: + // unknown argument so leave + User::Leave(KErrArgument); + } + } + else + { + lex.UnGet(); + TInt testNumber; + User::LeaveIfError(lex.Val(testNumber)); + if( (testNumber<0) || (testNumber>=KMaxTests) ) + { + User::Leave(KErrArgument); + } + aTests.AppendL(testNumber); + } + lex.SkipSpace(); + } + // if no tests specified then run them all + if(aTests.Count() == 0) + { + aMode |= EModeAll; + } + + // do clean up + CleanupStack::PopAndDestroy(commandLine); + } + +void CRunModeAgent::ClientAppL() +// +// Performs each test in turn +// + { + test.Start(_L("ClientAppL")); + + RArray testsToRun; + TUint32 testMode = 0; + ParseCommandLineL(testMode, testsToRun); + + //if help or version mode specified then just print out the relevant stuff and quit + if((testMode & EModeHelp) || (testMode & EModeVersion)) + { + if(testMode & EModeHelp) + { + PrintUsage(); + } + if(testMode & EModeVersion) + { + PrintVersion(); + } + test.End(); + return; + } + + if(testMode & EModeAll) + { + for(TInt i=0; i>1); i++) + { + TInt temp = testsToRun[i]; + testsToRun[i] = testsToRun[numberOfTests - (i+1)]; + testsToRun[numberOfTests - (i+1)] = temp; + } + } + + __UHEAP_MARK; + SetupAndAttachToDSS(); + __UHEAP_MARKEND; + + HelpStartTestTimer(); + for(TInt i=0; iClientAppL()); + __UHEAP_MARKEND; + + delete RunModeAgent; + } + + delete trap; + + return ret; + } + +/** +Helper function to get the aOffset'th value from aFlags + +@param aFlags descriptor containing TRegisterFlag type flags +@param aOffset index of flag value to extract from aFlags +@param aFlagValue the flag value if function returned successfully + +@return KErrNone if value was read successfully, KErrTooBig if aOffset is + greater than aFlags.Length() +*/ +TInt CRunModeAgent::GetFlag(const TDes8& aFlags, const TUint aOffset, TRegisterFlag &aFlagValue) const + { + //get pointer to data + const TUint8 *ptr = aFlags.Ptr(); + + //check aOffset is valid + TUint length = aFlags.Length(); + if(aOffset >= length) + return KErrTooBig; + + //get flag value + aFlagValue = (TRegisterFlag)ptr[aOffset]; + return KErrNone; + } + +/** + Helper function to set the value of FunctionChooser in the target debug thread. + + @param aTestFunction TTestFunction enum to set FunctionChooser to + + @return KErrNone if the value was set correctly, or one of the other system wide error codes + */ +TInt CRunModeAgent::SwitchTestFunction(TTestFunction aTestFunction, const TBool aResume) + { + //suspend the target thread + TInt suspendError = iServSession.SuspendThread(iThreadID); + if(! ( (suspendError == KErrNone) || (suspendError == KErrAlreadyExists) ) ) + { + //the thread is not suspended so exit + return suspendError; + } + + //get the address of FunctionChooser + TUint32 functionChooserAddress = (TUint32)&FunctionChooser; + //put the new value for FunctionChooser into a descriptor + TPtr8 functionBuf((TUint8*)&aTestFunction, sizeof(TTestFunction), sizeof(TTestFunction)); + //write the new value into the target thread + TInt writeError = iServSession.WriteMemory(iThreadID, functionChooserAddress, sizeof(TTestFunction), functionBuf, EAccess32, EEndLE8); + + if( (KErrNone == suspendError) && aResume ) + { + //if this function suspended the target thread then we need to resume it + TInt resumeError = iServSession.ResumeThread(iThreadID); + if(KErrNone != resumeError) + { + //resuming failed so return the error + return resumeError; + } + } + + //suspending and resuming was successful so return the error code from the WriteMemory call + return writeError; + } + +/** + Launch a separate process to debug. + + @param aProcess the RProcess object to use to create the process + @param aFileName file name of the executable to create the process from + @param aFunctionType function that the target process should call on execution + @param aDelay delay before the new process should call the function represented by aFunctionType + @param aExtraThreads number of extra threads to create in the child process + + @return KErrNone on success, or one of the other system wide error codes + */ +TInt CRunModeAgent::LaunchProcess(RProcess& aProcess, const TDesC& aFileName, TDebugFunctionType aFunctionType, TUint32 aDelay, TUint32 aExtraThreads) + { + // at the moment we support two arguments, this number might have to be increased to support arguments + const TUint KMaxCommandLineLength = 32; + + // create a command line buffer + RBuf commandLine; + commandLine.Create(KMaxCommandLineLength); + + // append the command line arguments to the buffer + _LIT(KFArg, "-f"); + commandLine.Append(KFArg()); + commandLine.AppendNum(aFunctionType); + + _LIT(KSpace, " "); + commandLine.Append(KSpace()); + + _LIT(KDArg, "-d"); + commandLine.Append(KDArg()); + commandLine.AppendNum(aDelay); + + commandLine.Append(KSpace()); + + _LIT(KEArg, "-e"); + commandLine.Append(KEArg()); + commandLine.AppendNum(aExtraThreads); + + // create the new process, matching on file name only, not specifying uid values + TInt err = aProcess.Create(aFileName, commandLine); // owned by the process + + // check that there was no error raised + if(err != KErrNone) + { + commandLine.Close(); + return err; + } + + TRequestStatus status = KRequestPending; + aProcess.Rendezvous(status); + + commandLine.Close(); // after target thread starts + + if(KRequestPending != status.Int()) + { + // startup failed so kill the process + aProcess.Kill(KErrNone); + return status.Int(); + } + else + { + // start up succeeded so resume the process + aProcess.Resume(); + User::WaitForRequest(status); + if(KErrNone != status.Int()) + { + aProcess.Kill(KErrNone); + } + return status.Int(); + } + } + +/** + Helper function to read a tag header from a debug functionality block + + @param aDebugFunctionalityBlock block to read header from + @param aTagHdrId header type to find + + @return pointer to the header, or NULL if not available + */ +TTagHeader* CRunModeAgent::GetTagHdr(const TDesC8& aDebugFunctionalityBlock, const TTagHeaderId aTagHdrId) const + { + TUint8* ptr = (TUint8*) aDebugFunctionalityBlock.Ptr(); + TUint8* blockEnd = ptr + aDebugFunctionalityBlock.Size(); + + while(ptr < blockEnd) + { + TTagHeader* header = (TTagHeader*)ptr; + if(header->iTagHdrId == aTagHdrId) + { + return header; + } + ptr += sizeof(TTagHeader) + (header->iNumTags * sizeof(TTag)); + } + return NULL; + } + +/** + Helper function to read a tag from a debug functionality block + + @param aTagHdr pointer to a tag header in a debug functionality block + @param aElement element to return from the header's data + + @return pointer to the tag, or NULL if not available + */ +TTag* CRunModeAgent::GetTag(const TTagHeader* aTagHdr, const TInt aElement) const + { + TUint8* ptr = (TUint8*)aTagHdr + sizeof(TTagHeader); + TUint8* blockEnd = ptr + (aTagHdr->iNumTags * sizeof(TTag)); + + while(ptr < blockEnd) + { + TTag* tag = (TTag*)ptr; + if(tag->iTagId == aElement) + { + return tag; + } + ptr += sizeof(TTag); + } + return NULL; + } + +TTag CRunModeAgent::GetTag(const TTagHeaderId aTagHdrId, const TInt aElement) + { + TUint32 bufsize = 0; // Safe default size + + // Get functionality block size + test(KErrNone == iServSession.GetDebugFunctionalityBufSize(&bufsize)); + + // Ensure we have a finite buffer size + test(bufsize!=0); + + // Allocate space for the functionality data + HBufC8* dftext = HBufC8::NewLC(bufsize); + + // create an empty TPtr8 refering to dftext + TPtr8 dftextPtr(dftext->Des()); + + // Get the functionality block + test(KErrNone == iServSession.GetDebugFunctionality(dftextPtr)); + + // read a value from the data to check it has come through as expected + TTagHeader* header = GetTagHdr(dftext->Des(), aTagHdrId); + test(header != NULL); + TTag* tag = GetTag(header, aElement); + test(tag != NULL); + + TTag tagToReturn = *tag; + + // Remove our temporary buffer + CleanupStack::PopAndDestroy(dftext); + + return tagToReturn; + } + +/** + Helper function which returns a Boolean indicating with a process with the + specified name is currently running. + + @param aProcessName - Name of the process to find + @return ETrue if found, EFalse otherwise + */ +TBool CRunModeAgent::ProcessExists(const TDesC& aProcessName) + { + TInt err=KErrNone; + TBool found = FALSE; + +_LIT(KWildCard,"*"); + + TFindProcess find(KWildCard); + TFullName name; + while(find.Next(name)==KErrNone) + { + RProcess process; + err = process.Open(find); + if (err == KErrNone) + { + if (name.Find(aProcessName) != KErrNotFound) + { + found = TRUE; + } + process.Close(); + } + } + + return found; + } + +TInt PanicFn(TAny*) + { + User::Panic(_L("trmdebug_dummy"), 123); + return 0; + } + +void CRunModeAgent::TestAttachToAll() + { + test.Next(_L("TestAttachToAll - Attach\n")); + +#ifdef ALLCAPS_DEBUGTOKEN + test.Next(_L("---- First AttachAll \n")); + test(iServSession.AttachAll() == KErrNone); + test.Next(_L("---- Second AttachAll \n")); + test(iServSession.AttachAll() == KErrAlreadyExists); // Don't think an agent should be allowed to AttachToAll more than once + + test.Next(_L("---- DetachAll\n")); + test(iServSession.DetachAll() == KErrNone); + test.Next(_L("---- AttachAll again\n")); + test(iServSession.AttachAll() == KErrNone); + + test.Next(_L("---- Suspend thread\n")); + test( iServSession.SuspendThread(iThreadID) == KErrNone); + + // Check that AttachAll picks up thread crashes without needing to be explicitly attached + test.Next(_L("---- Attach all SetEventAction\n")); + TInt err = iServSession.SetEventAction(EEventsKillThread, EActionSuspend); + test(err == KErrNone); + + test.Next(_L("---- Create DebugThread2\n")); + // Set up the thread + RThread threadToPanic; + err = threadToPanic.Create(_L("DebugThread2"), &PanicFn, 8192, NULL, NULL); + test(err == KErrNone); + TRequestStatus undertakerStat; + threadToPanic.Logon(undertakerStat); + test(undertakerStat.Int() == KRequestPending); + + // Start listening for events + TRequestStatus stat; + TEventInfo info; + TPckg infoPkg(info); + test.Next(_L("Attach all get event and then resume thread DebugThread2\n")); + + iServSession.GetEvent(stat, infoPkg); + + threadToPanic.Resume(); + + test.Printf(_L("Waiting for DebugThread2 panic event to be picked up by AttachToAll\n")); + User::WaitForRequest(stat); + test(stat.Int() == KErrNone); + test(info.iThreadId == threadToPanic.Id()); + test(info.iEventType == EEventsKillThread); + test(info.iThreadKillInfo.iExitType == EExitPanic); + + test(undertakerStat.Int() == KRequestPending); // This shouldn't get completed until after we call iServSession.ResumeThread below + + // Now resume the thread and wait for the Logon to complete + test.Next(_L("---- Attach all resume panic thread and then wait for event after DSS has handled it\n")); + err = iServSession.ResumeThread(threadToPanic.Id()); + test(err == KErrNone); + User::WaitForRequest(undertakerStat); + test(undertakerStat.Int() == 123); // The panic reason set in PanicFn is 123 + + // And clean up, + ResetAttachToAll(threadToPanic); + //still attached to all + + // Test that an explicit attach eclipses an AttachAll, and the AttachAll session + // doesn't see the events for specifically attached executables + test.Next(_L(" ---- ExplicitAttachBeatsAttachAll\n")); + + // We shouldn't see this event because of sess2 + err = iServSession.SetEventAction(EEventsStartThread, EActionContinue); + test(err == KErrNone); + iServSession.GetEvent(stat, infoPkg); + test(stat.Int() == KRequestPending); + + test.Next(_L("---- New sec session\n")); + RSecuritySvrSession sess2; + test(sess2.Connect(securityServerVersion) == KErrNone); + test.Next(_L("---- New sec session Attach executable \n")); + test(sess2.AttachExecutable(iFileName, EFalse) == KErrNone); + err = sess2.SetEventAction(iFileName, EEventsKillThread, EActionSuspend); + test(err == KErrNone); + // The EActionSuspend above should trump this EActionContinue + err = iServSession.SetEventAction(EEventsKillThread, EActionContinue); + test(err == KErrNone); + + test.Next(_L("---- New sec session create DebugThread3\n")); + err = threadToPanic.Create(_L("DebugThread3"), &PanicFn, 8192, NULL, NULL); + test(err == KErrNone); + + // The attach executable above leads the DSS to launch the token, which results + // in a start thread event, and since we have done an attach all and a get event, + // the TReqStat will be completed accordingly for this token start event. + + threadToPanic.Logon(undertakerStat); + test(undertakerStat.Int() == KRequestPending); + + TRequestStatus sess2stat; + TEventInfo sess2event; + TPckg sess2eventPkg(sess2event); + test.Next(_L("---- New sec session get event, TReqStat\n") ); + RDebug::Printf(" undertakerStat=0x%x, sess2stat = 0x%x, Pkg=0x%x", + &undertakerStat, &sess2stat, &sess2eventPkg); + + sess2.GetEvent(iFileName, sess2stat, sess2eventPkg); + // sess2 didn't ask for EEventsStartThread so we should still be pending at this point + test(sess2stat == KRequestPending); + + test.Next(_L("---- New sec session resume thread and wait for kill event\n")); + threadToPanic.Resume(); + User::WaitForRequest(sess2stat); + + test(sess2stat.Int() == KErrNone); + test(sess2event.iThreadId == threadToPanic.Id()); + test(sess2event.iEventType == EEventsKillThread); + test(sess2event.iThreadKillInfo.iExitType == EExitPanic); + + // the EActionSuspend that sess2 specified should ensure this doesn't get completed + test(undertakerStat == KRequestPending); + + // Now resume the thread and wait for the Logon to complete + test.Next(_L("---- ExplicitAttachBeatsAttachAll resume thread 3 after kill\n")); + err = sess2.ResumeThread(threadToPanic.Id()); + test(err == KErrNone); + User::WaitForRequest(undertakerStat); + test(undertakerStat.Int() == 123); // The panic reason set in PanicFn is 123 + + // And clean up + ResetAttachToAll(threadToPanic, &stat, &sess2); + test.Next(_L("---- Finishing ExplicitAttachBeatsAttachAll > sess2.Close\n")); + + sess2.Close(); +#if 0 + //TODO allow this by changing from agent pid to session ids in DSS. + // This will allow a client to have more than one session and call attachall + + // Test that a second AttachAll eclipses the first + // Commented out since not sure we require this + + test.Next(_L("SecondAttachAllBeatsAttachAll")); + + //TODO fix detachall in ResetAttachToAll + test(iServSession.AttachAll() == KErrNone); + test(sess2.AttachAll() == KErrNone); + err = iServSession.SetEventAction(EEventsKillThread, EActionSuspend); + test(err == KErrNone); + err = sess2.SetEventAction(EEventsKillThread, EActionSuspend); + test(err == KErrNone); + err = threadToPanic.Create(_L("DebugThread4"), &PanicFn, 8192, NULL, NULL); + test(err == KErrNone); + iServSession.GetEvent(stat, infoPkg); + test(stat.Int() == KRequestPending); + sess2.GetEvent(sess2stat, sess2eventPkg); + test(sess2stat.Int() == KRequestPending); + + threadToPanic.Resume(); + User::WaitForRequest(sess2stat); + test(sess2event.iThreadId == threadToPanic.Id()); + test(sess2event.iEventType == EEventsKillThread); + test(sess2event.iThreadKillInfo.iExitType == EExitPanic); + test(stat.Int() == KRequestPending); // Shouldn't see the killthread event because of sess2 + + // And cleanup + ResetAttachToAll(threadToPanic, &stat, &sess2); + //TODO fixme test(sess2.DetachAll() == KErrNone); +#endif + +#else + test(iServSession.AttachAll() == KErrPermissionDenied); +#endif + } + +void CRunModeAgent::ResetAttachToAll(RThread& aTestThread, TRequestStatus* aFirstSessionStat, RSecuritySvrSession* aSecondSession) + { + + aTestThread.Close(); + + RDebug::Printf("---- ResetAttachToAll : > iServSession.SetEventAction Ignore for Kill and StartThread"); + TInt err = iServSession.SetEventAction(EEventsKillThread, EActionIgnore); + test(err == KErrNone); + err = iServSession.SetEventAction(EEventsStartThread, EActionIgnore); + test(err == KErrNone); + + + if (aFirstSessionStat) + { + RDebug::Printf("---- ResetAttachToAll : > iServSession.CancelGetEvent"); + iServSession.CancelGetEvent(); + + RDebug::Printf("---- ResetAttachToAll : > User::WaitForRequest(*aFirstSessionStat);"); + User::WaitForRequest(*aFirstSessionStat); + + User::After(1000000); + RDebug::Printf("---- ResetAttachToAll : > iServSession.DetachAll"); + test(iServSession.DetachAll() == KErrNone); + } + + if (aSecondSession != NULL) + { + User::After(1000000); + RDebug::Printf("---- ResetAttachToAll : > aSecondSession.SetEventAction kill ignore"); + err = aSecondSession->SetEventAction(iFileName, EEventsKillThread, EActionIgnore); + User::After(1000000); + test(err == KErrNone); + RDebug::Printf("---- ResetAttachToAll : > aSecondSession.SetEventAction start thrd ignore"); + err = aSecondSession->SetEventAction(iFileName, EEventsStartThread, EActionIgnore); + User::After(1000000); + test(err == KErrNone); + RDebug::Printf("---- ResetAttachToAll : > aSecondSession.DetachExecutable"); + err = aSecondSession->DetachExecutable(iFileName); + User::After(1000000); + test( err == KErrNone); + } + } + +void CRunModeAgent::TestResumeBreakpointsRepeatedly() + { + test.Next(_L("TestResumeBreakpointsRepeatedly\n")); + test(iServSession.AttachExecutable(KRMDebugTestApplication, EFalse/* Active */) == KErrNone); + + RProcess debugProcess; + TThreadId debugThreadId; + LaunchDebugProcessAndSetBreakpoint(debugProcess, debugThreadId); + test(iServSession.ResumeThread(debugThreadId) == KErrNone); + + // Let the thread die naturally (at least from DSS's point of view) + debugProcess.Kill(0); + debugProcess.Close(); + + test.Printf(_L("Closing iServSession\n")); + iServSession.Close(); + //User::After(1000000); // I hate myself... + test(iServSession.Connect(securityServerVersion) == KErrNone); + test(iServSession.AttachExecutable(KRMDebugTestApplication, EFalse/* Active */) == KErrNone); + + test.Printf(_L("Launching process for second time\n")); + + LaunchDebugProcessAndSetBreakpoint(debugProcess, debugThreadId); + test(iServSession.ResumeThread(debugThreadId) == KErrNone); + debugProcess.Kill(0); + debugProcess.Close(); + + /*test.Printf(_L("Launching process for third time\n")); + debugProcess.Kill(0); + debugProcess.Close(); + iServSession.Close(); + User::After(1000000); // I hate myself... + test(iServSession.Connect(securityServerVersion) == KErrNone); + test(iServSession.AttachExecutable(KRMDebugTestApplication, EFalse/ * Active * /) == KErrNone); + */ + + test(KErrNone == iServSession.DetachExecutable(KRMDebugTestApplication)); + } + +void CRunModeAgent::TimedWait(TRequestStatus& aStatus, TInt aTimeoutInMs, TInt aLineNumber) + { + RTimer timer; + TInt err = timer.CreateLocal(); + test(err == KErrNone); + + TRequestStatus timerstat; + timer.After(timerstat, aTimeoutInMs*1000); + User::WaitForRequest(aStatus, timerstat); + if (timerstat != KRequestPending) + { + test.Panic(_L("Timed out at line %d\n"), aLineNumber); + } + else + { + timer.Cancel(); + User::WaitForRequest(timerstat); + } + timer.Close(); + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/t_rmdebug2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/t_rmdebug2.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,202 @@ +// Copyright (c) 2006-2010 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: +// Definitions for the run mode debug tests +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef RMDEBUG_H +#define RMDEBUG_H + +#include "t_rmdebug_app.h" +#include "r_user_low_memory_security_svr_session.h" +#include "r_kernel_low_memory_security_svr_session.h" + + +class CRunModeAgent; + +// Create a pointer to function type +typedef void (CRunModeAgent::*testFunction)(); + +class TFunctionData + { +public: + testFunction iFunctionPtr; + TBuf<40> iFunctionName; + }; + +//number of test functions that we have +const TInt KMaxTests = 31; + +// +// class CRunModeAgent +// +// The basic run mode agent. +// +class CRunModeAgent : public CBase + { +public: + static CRunModeAgent* NewL(); + ~CRunModeAgent(); + void ClientAppL(); + +private: + CRunModeAgent(); + void ConstructL(); + void SetupAndAttachToDSS(); + + TInt TestStartup(); + TInt TestShutdown(); + + void TestGetExecutablesList(); + void TestGetProcessList(); + void TestGetThreadList(); + void TestGetCodeSegsList(); + void TestGetXipLibrariesList(); + void TestGetListInvalidData(); + + TBool DoTestGetThreadList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); + void DoTestGetCodeSegsList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); + + void DoGetList(const Debug::TListId aListId, const Debug::TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId=0); + + void TestMemoryAccess(); + void TestSuspendResume(); + void TestBreakPoints(); + void TestConsecutiveBreakPoints(); + void TestModifyBreak(); + void DoTestModifyBreak(TBool aThreadSpecific); + void TestBreakInfo(); + void DoTestBreakInfo(TBool aThreadSpecific); + void TestRunToBreak(); + void DoTestRunToBreak(TBool aThreadSpecific); + void TestBreakPointsInLoop(); + void DoTestBreakPointsInLoop(TBool aThreadSpecific); + void TestRegisterAccess(); + void TestAttachExecutable(); + void TestDebugFunctionality(); + void TestStep(); + void DoTestStep(TBool aThreadSpecific); + void TestDriverSecurity(); + void TestSecurity(); + void TestEvents(); + void TestEventsForExternalProcess(); + void TestDemandPaging(); + void TestTraceSecurity(); + void TestDllUsage(); + void TestKillProcess(); + void TestProcessBreakPoints(); + void TestMultipleTraceEvents(); + void TestAddRemoveProcessEvents(); + void TestProcessKillBreakpoint(); + void DoTestProcessKillBreakpoint(); + void TestAttachToAll(); + void ResetAttachToAll(RThread& aTestThread, TRequestStatus* aFirstSessionStat=NULL, Debug::RSecuritySvrSession* aSecondSession=NULL); + void LaunchDebugProcessAndSetBreakpoint(RProcess& aResultProcess, TThreadId& aResultThread); + void TestResumeBreakpointsRepeatedly(); + + //crash flash test functions + void TestCrashFlash(); + + TInt GetFlag(const TDes8 &aFlags, const TUint aOffset, Debug::TRegisterFlag &aFlagValue) const; + + void ReportPerformance(void); + + // helper functions + void HelpTestSecurityAttachDetachExecutable(const TDesC& aProcessName, TBool aExpectSuccess); + + TInt HelpTestStepSetBreak(Debug::TBreakId& aBreakId, TThreadId aThreadId, const TUint32 aBreakAddress, Debug::TArchitectureMode aMode, TBool aThreadSpecific=ETrue, TProcessId aProcessId=0); + TInt HelpTestStepClearBreak(const Debug::TBreakId aBreakId, const TThreadId aThreadId, TBool aThreadSpecific); + TInt HelpTestStepWaitForBreak(const TDesC& aProcessName, Debug::TEventInfo& aEventInfo); + TInt HelpTestStepReadPC(TThreadId aThreadId, TUint32& aPC); + TInt HelpTestStep(TThreadId aThreadId, TUint32 aStartAddress, TUint32 aEndAddress, Debug::TArchitectureMode aMode, TUint aNumSteps, TBool aThreadSpecific=ETrue, TProcessId=0); + + TInt HelpTicksPerSecond(void); + + // helper functions + void HelpStartTestTimer(void) { iStartTick = User::NTickCount(); iStopTick = 0; }; + void HelpStopTestTimer(void) { iStopTick = User::NTickCount(); }; + TInt HelpGetTestTicks(void) { return (iStopTick - iStartTick); }; + TInt SwitchTestFunction(TTestFunction aTestFunction, const TBool aResume = ETrue); + TInt LaunchProcess(RProcess& aProcess, const TDesC& aFileName, TDebugFunctionType aFunctionType, TUint32 aDelay=0, TUint32 aExtraThreads=0); + Debug::TTagHeader* GetTagHdr(const TDesC8& aDebugFunctionalityBlock, const Debug::TTagHeaderId aTagHdrId) const; + Debug::TTag* GetTag(const Debug::TTagHeader* aTagHdr, const TInt aElement) const; + Debug::TTag GetTag(const Debug::TTagHeaderId aTagHdrId, const TInt aElement); + TBool ProcessExists(const TProcessId aProcessId); + TBool ThreadExistsForProcess(const TThreadId aThreadId, const TProcessId aProcessId); + TBool ListingSupported(const Debug::TListId aListId, const Debug::TListScope aListScope); + void TestEventsWithExtraThreads(Debug::TKernelEventAction aActionMain, Debug::TKernelEventAction aActionExtra, TUint32 aExtraThreads); + void FillArray(); + void PrintUsage(); + void PrintVersion(); + + enum TTestMode + { + //run all the tests + EModeAll = 1<<0, + //run the specified tests in reverse order + EModeReverse = 1<<1, + //print out help + EModeHelp = 1<<2, + //print out help + EModeVersion = 1<<3 + }; + + void RunTest(TInt aTestNumber); + void ParseCommandLineL(TUint32& aMode, RArray& aTests); + + TBool ProcessExists(const TDesC& aProcessName); + static void TimedWait(TRequestStatus& aStatus, TInt aTimeoutInMs, TInt aLineNumber); + + +private: + + TFunctionData iTestArray[KMaxTests]; +#if defined(KERNEL_OOM_TESTING) + RKernelLowMemorySecuritySvrSession iServSession; +#elif defined (USER_OOM_TESTING) + RUserLowMemorySecuritySvrSession iServSession; +#else + Debug::RSecuritySvrSession iServSession; +#endif + RThread iDebugThread; + + //Set by test thread, used to check its run state + RProperty iRunCountSubscribe; + + // Used for timeouts when checking the run state + RTimer iTimer; + + RProcess iDSSProcess; + TThreadId iThreadID; + TFileName iFileName; + + // Performance data + TInt iMemoryReadKbytesPerSecond; + TInt iMemoryWriteKbytesPerSecond; + TInt iBreakpointsPerSecond; + TInt iMaxBreakpoints; + TInt iStepsPerSecond; + + // Timing information + TInt iStartTick; + TInt iStopTick; + }; + +#endif // RMDEBUG_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/t_rmdebug2_oemtoken.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/basic_tests/t_rmdebug2_oemtoken.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,32 @@ +// 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: +// + +/** + @file + @internalTechnology + @released +*/ + +#include +#include + +GLDEF_C TInt E32Main() + { + // No need to do anything, the only requirement is that + // this executable can be loaded and runs to completion + return 0; + } + +// End of file - t_rmdebug2_oemtoken.cpp diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/common/t_debug_logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/common/t_debug_logging.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,68 @@ +// Copyright (c) 2006-2010 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: +// Logging macros for use in debug subsystem +// +// + +#ifndef RMDEBUG_LOGGING_H +#define RMDEBUG_LOGGING_H + +/* Debug messages + * + * Debug messages are only generated for debug builds. + * + * As user mode use RDebug::Printf(). + * + */ + +// Uncomment if logging of required +//#define RMDEBUG_LOGGING + +#ifdef RMDEBUG_LOGGING + + #include + + #define LOG_MSG(args...) RDebug::Printf(args) + #define LOG_DES(args...) RDebug::Print(args) // For wide descriptors + #define LOG_ENTRY() RDebug::Printf("+%s", __PRETTY_FUNCTION__) + #define LOG_EXIT() RDebug::Printf("-%s", __PRETTY_FUNCTION__) + #define LOG_ARGS(fmt, args...) RDebug::Printf("+%s " fmt, __PRETTY_FUNCTION__, args) + #define LOG_RETURN(x) RDebug::Printf("Returning %d from [%s]", x, __PRETTY_FUNCTION__) + + // Kept for compatibility + #define LOG_MSG2( a, b ) RDebug::Printf( a, b ) + #define LOG_MSG3( a, b, c ) RDebug::Printf( a, b, c ) + #define LOG_MSG4( a, b, c, d ) RDebug::Printf( a, b, c, d ) + #define LOG_MSG5( a, b, c, d, e ) RDebug::Printf( a, b, c, d, e ) + +#else + + #include + + #define LOG_MSG(args...) + #define LOG_DES(args...) + #define LOG_ENTRY() + #define LOG_EXIT() + #define LOG_ARGS(fmt, args...) + #define LOG_RETURN(x) + + // Kept for compatibility + #define LOG_MSG2( a, b ) + #define LOG_MSG3( a, b, c ) + #define LOG_MSG4( a, b, c, d ) + #define LOG_MSG5( a, b, c, d, e ) + +#endif + +#endif //RMDEBUG_LOGGING diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/common/t_target_launcher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/common/t_target_launcher.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,224 @@ +// 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: +// Helper app to launch debug targets. Uses command-line parameters as follows using a + sign: +// +n +// +m +// +o +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "t_target_launcher.h" + + +/** + Launch a process + + @param aProcess The RProcess object to use to create the process + @param aExeName File name of the executable to create the process from + @param aCommandLine The command line to pass to the new process + @return KErrNone on success, or one of the other system wide error codes + */ +TInt LaunchProcess(RProcess& aProcess, TDesC & aExeName, TPtr & aCommandLine ) + { + + TPtrC commandLine( aCommandLine ); + + TInt err = aProcess.Create( aExeName, commandLine ); + + // check that there was no error raised + if(err != KErrNone) + { + return err; + } + + TRequestStatus status = KRequestPending; + aProcess.Rendezvous(status); + + if(KRequestPending != status.Int()) + { + // startup failed so kill the process + RDebug::Printf( "> RProcess Rendezvous() failed with %d. Killing process", status.Int() ); + aProcess.Kill(KErrNone); + return status.Int(); + } + else + { + // start up succeeded so resume the process + aProcess.Resume(); + User::WaitForRequest(status); + if(KErrNone != status.Int()) + { + RDebug::Printf( "> RProcess Resume() failed with %d. Killing process", status.Int() ); + aProcess.Kill(KErrNone); + } + return status.Int(); + } + } + +/** + * Read command line parameters and control the launching of targets. + * Create global launch semaphore KLaunchSemaphoreName + */ +void MainL() + { + + TInt numApps = KNumApps; + TInt numLaunches = KNumLaunches; + TInt launchControl = 0; + + TInt argc = User::CommandLineLength(); + HBufC* commandLine = NULL; + RDebug::Printf( ">Launcher Process() argc=%d", argc ); + + if( argc ) + { + commandLine = HBufC::NewLC(argc); + TPtr commandLineBuffer = commandLine->Des(); + User::CommandLine(commandLineBuffer); + + RBuf printCommandLine; + CleanupClosePushL( printCommandLine ); + printCommandLine.CreateL( commandLine->Des().Length() ); + printCommandLine.Copy( commandLine->Des() ); + printCommandLine.Collapse(); + RDebug::Printf( ">command line = %S", &printCommandLine ); + CleanupStack::PopAndDestroy( &printCommandLine ); + + // create a lexer and read through the command line + TLex lex(*commandLine); + while (!lex.Eos()) + { + // only look for options with first character '+', other switches are for the targets + if (lex.Get() == '+') + { + TChar arg = lex.Get(); + switch (arg) + { + case 'n': + lex.Val( numApps ); + RDebug::Printf("parsed numApps as %d", numApps); + break; + case 'm': + lex.Val( numLaunches ); + RDebug::Printf("parsed numLaunches as %d", numLaunches ); + break; + case 'o': + lex.Val( launchControl ); + RDebug::Printf("parsed launchControl as %d", launchControl); + break; + default: + // unknown argument ignore it + break; + }//switch + }// if + + }//while + }//if argc + + RSemaphore launchSemaphore; + TInt ret = KErrNone; + CleanupClosePushL( launchSemaphore ); + ret = launchSemaphore.CreateGlobal( KLaunchSemaphoreName, 0 ); + RDebug::Printf( ">Target Launcher : RSemaphore.CreateGlobal ret %d", ret); + User::LeaveIfError( ret ); + + ret = launchSemaphore.OpenGlobal( KLaunchSemaphoreName ); + RDebug::Printf( ">Target Launcher : RSemaphore.OpenGlobal ret %d", ret); + User::LeaveIfError( ret ); + + //Only now indicate to the launcher that we have fully started, so they can find and open the semaphore + RProcess::Rendezvous(KErrNone); + + //Now launch the requested number of apps for the requested number of launches + for( ; numLaunches > 0; numLaunches-- ) + { + for( TInt launchIndex = numApps; launchIndex > 0; launchIndex-- ) + { + RDebug::Printf( ">Target Launcher: Semaphore wait app %d, launch %d", launchIndex, numLaunches ); + launchSemaphore.Wait(); + + RBuf targetName; + CleanupClosePushL( targetName ); + RDebug::Printf( ">Target Launcher: targetName.Create %d, launch %d", launchIndex, numLaunches ); + targetName.Create( KTargetExe().Length() + 2 ); + + if( launchControl == 1 ) + { + // Reverse the order of the apps launched by reversing the index in the name + RDebug::Printf( ">Target Launcher: targetName.Format %d, launch %d", numApps - launchIndex + 1, numLaunches ); + targetName.Format( KTargetExe(), numApps - launchIndex + 1 ); + } + else + { + RDebug::Printf( ">Target Launcher: targetName.Format %d, launch %d", launchIndex, numLaunches ); + targetName.Format( KTargetExe(), launchIndex ); + } + + RProcess aProc; + CleanupClosePushL( aProc ); + + RDebug::Printf( ">Target Launcher: LaunchProcess %d, launch %d", launchIndex, numLaunches ); + RDebug::Printf( ">LaunchProcess %lS", &targetName ); + TPtr cmdLinePtr( commandLine->Des() ); + ret = LaunchProcess( aProc, targetName, cmdLinePtr ); + CleanupStack::PopAndDestroy( &aProc ); + + RDebug::Printf( "Launcher Process()" ); + + CTrapCleanup* trap = CTrapCleanup::New(); + if (!trap) + return KErrNoMemory; + + TRAPD(err, MainL()); + RDebug::Printf( "< Target launching returned %d", err); + + delete trap; + + return err; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/common/t_target_launcher.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/common/t_target_launcher.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,48 @@ +// Copyright (c) 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: +// Definitions for target launcher +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef RMDEBUG_TARGET_LAUNCHER_H +#define RMDEBUG_TARGET_LAUNCHER_H + +// Controls how many times the target applications are launched +const TInt KNumLaunches = 3; + +// Controls how many applications are attached and launched +// If changing this, need to make sure there are enough apps +// being built. see KTargetExe and t_rmdebug_app* +const TInt KNumApps = 4; + +_LIT(KLaunchSemaphoreName, "t_rmdebug_launch_semaphore"); +_LIT(KLaunchSemaphoreNameSearchString, "t_rmdebug_launch_semaphore*"); +_LIT(KTargetExe,"z:\\sys\\bin\\t_rmdebug_app%d.exe"); +_LIT8(KTargetExeName,"t_rmdebug_app%d.exe"); +_LIT(KProcessFinder,"*t_rmdebug_app%d*"); +_LIT(KTargetOptions,"-f%d"); + +_LIT(KZSysBin,"z:\\sys\\bin\\"); + +_LIT(KLauncherExe,"t_rmdebug_target_launcher.exe"); + +_LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); + +#endif // RMDEBUG_TARGET_LAUNCHER_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_demand_paging.cia --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_demand_paging.cia Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,57 @@ +// Copyright (c) 2007-2010 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 + +// unused function that contains enough padding that the test function +// RMDebugDemandPagingTest starts in a new page. +__NAKED__ TInt RMDebugDemandPagingPaddingBefore() + { + asm("movs r2,r0"); + asm("adds r0,r2,r1"); + asm("bx lr"); + // add padding to make this function 4kb in size. + // The 4084 corresponds to 2^12 (=4096) - 12, + // the 12 being the total size of the movs, adds and bx instructions. + asm(".space 4084"); + } + +// test function which is in a page by itself +__NAKED__ TInt RMDebugDemandPagingTest() + { + asm("movs r2,r0"); + asm("adds r0,r2,r1"); + asm("bx lr"); + // add padding to make this function 4kb in size. + // The 4084 corresponds to 2^12 (=4096) - 12, + // the 12 being the total size of the movs, adds and bx instructions. + asm(".space 4084"); + } + +// unused function that contains enough padding to ensure that no used code +// is in the same page as RMDebugDemandPagingTest +__NAKED__ TInt RMDebugDemandPagingPaddingAfter() + { + asm("movs r2,r0"); + asm("adds r0,r2,r1"); + asm("bx lr"); + // add padding to make this function 4kb in size. + // The 4084 corresponds to 2^12 (=4096) - 12, + // the 12 being the total size of the movs, adds and bx instructions. + asm(".space 4084"); + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_demand_paging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_demand_paging.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,22 @@ +// Copyright (c) 2007-2010 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: +// definitions of functions in d_demand_paging.cia +// + +#ifndef D_DEMAND_PAGING_H +#define D_DEMAND_PAGING_H + +TInt RMDebugDemandPagingTest(); + +#endif // D_DEMAND_PAGING_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_bkpt_test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_bkpt_test.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,28 @@ +// Copyright (c) 2010 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: +// + +// definitions of functions in d_rmdebug_bkpt_test.s + +#ifndef D_RMDEBUG_BKPT_TESTS_H +#define D_RMDEBUG_BKPT_TESTS_H + +extern "C" +{ + // Breakpoints in loop test + unsigned int RMDebug_Bkpt_Test_Entry(void); + unsigned int RMDebug_Bkpt_Test_Loop_Break_1(void); + unsigned int RMDebug_Bkpt_Test_Loop_Break_2(void); +} +#endif // D_RMDEBUG_BKPT_TESTS_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_bkpt_test.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_bkpt_test.s Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,52 @@ +; Copyright (c) 2010 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: +; + + AREA |d-rmdebug-bkpt$$Code|, CODE, READONLY, ALIGN=6 + + CODE32 + +; +; Breakpoints in loop test +; +; This function initialises some variables and then performs some basic operations +; within the for loop. This allows us to set multiple breakpoints within the loop +; to test and see whether they are being hit. +; + + EXPORT RMDebug_Bkpt_Test_Entry + EXPORT RMDebug_Bkpt_Test_Loop_Break_1 + EXPORT RMDebug_Bkpt_Test_Loop_Break_2 + +RMDebug_Bkpt_Test_Entry + mov r2,#10 + mov r0,#20 + mov r3,#0 + mov r1,#1 + b COMPARE +LOOP + add r3,r2,r0 +RMDebug_Bkpt_Test_Loop_Break_1 + mov r2,r0 +RMDebug_Bkpt_Test_Loop_Break_2 + mov r0,r3 + add r1,r1,#1 +COMPARE + cmp r1,#30 + ble LOOP + bx lr + + END + +; End of file - d_rmdebug_bkpt_test.s diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,81 @@ +// Copyright (c) 2007-2010 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: +// +// definitions of functions in d_rmdebug_step_tests.s +// + +#ifndef D_RMDEBUG_STEP_TESTS_H +#define D_RMDEBUG_STEP_TESTS_H + +extern "C" +{ + // ARM tests + unsigned int RMDebug_StepTest_Non_PC_Modifying(void); + unsigned int RMDebug_StepTest_Non_PC_Modifying_OK(void); + + unsigned int RMDebug_StepTest_Branch(void); + unsigned int RMDebug_StepTest_Branch_1(void); + + unsigned int RMDebug_StepTest_Branch_And_Link(void); + unsigned int RMDebug_StepTest_Branch_And_Link_1(void); + unsigned int RMDebug_StepTest_Branch_And_Link_2(void); + + unsigned int RMDebug_StepTest_MOV_PC(void); + unsigned int RMDebug_StepTest_MOV_PC_1(void); + unsigned int RMDebug_StepTest_MOV_PC_2(void); + + unsigned int RMDebug_StepTest_LDR_PC(void); + unsigned int RMDebug_StepTest_LDR_PC_1(void); + + // Thumb tests + unsigned int RMDebug_StepTest_Thumb_Non_PC_Modifying(void); + unsigned int RMDebug_StepTest_Thumb_Non_PC_Modifying_1(void); + unsigned int RMDebug_StepTest_Thumb_Non_PC_Modifying_2(void); + + unsigned int RMDebug_StepTest_Thumb_Branch(void); + unsigned int RMDebug_StepTest_Thumb_Branch_1(void); + unsigned int RMDebug_StepTest_Thumb_Branch_2(void); + + unsigned int RMDebug_StepTest_Thumb_Branch_And_Link(void); + unsigned int RMDebug_StepTest_Thumb_Branch_And_Link_1(void); + unsigned int RMDebug_StepTest_Thumb_Branch_And_Link_2(void); + unsigned int RMDebug_StepTest_Thumb_Branch_And_Link_3(void); + + unsigned int RMDebug_StepTest_Thumb_Back_Branch_And_Link(void); + unsigned int RMDebug_StepTest_Thumb_Back_Branch_And_Link_1(void); + unsigned int RMDebug_StepTest_Thumb_Back_Branch_And_Link_2(void); + unsigned int RMDebug_StepTest_Thumb_Back_Branch_And_Link_3(void); + + unsigned int RMDebug_StepTest_Thumb_AddPC(void); + unsigned int RMDebug_StepTest_Thumb_AddPC_1(void); + unsigned int RMDebug_StepTest_Thumb_AddPC_2(void); + unsigned int RMDebug_StepTest_Thumb_AddPC_3(void); + + // ARM<->Thumb interworking tests + unsigned int RMDebug_StepTest_Interwork(void); + unsigned int RMDebug_StepTest_Interwork_1(void); + unsigned int RMDebug_StepTest_Interwork_2(void); + unsigned int RMDebug_StepTest_Interwork_3(void); + + // Stepping performance test + unsigned int RMDebug_StepTest_Count(void); + unsigned int RMDebug_StepTest_Count_1(void); + unsigned int RMDebug_StepTest_Count_2(void); + + // Multiple step test + unsigned int RMDebug_StepTest_ARM_Step_Multiple(void); + unsigned int RMDebug_StepTest_ARM_Step_Multiple_1(void); + +} +#endif // D_RMDEBUG_STEP_TESTS_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test.s Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,268 @@ +; Copyright (c) 2007-2010 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: +; +; + + + AREA |d-rmdebug-step$$Code|, CODE, READONLY, ALIGN=6 + + CODE32 + + ; ARM tests + +; +; Non-PC modifying +; + EXPORT RMDebug_StepTest_Non_PC_Modifying + EXPORT RMDebug_StepTest_Non_PC_Modifying_OK + +RMDebug_StepTest_Non_PC_Modifying + mov r0,r0 ; nop +RMDebug_StepTest_Non_PC_Modifying_OK + bx lr ; should return to normal execution of the test thread + +; +; Branch +; + EXPORT RMDebug_StepTest_Branch + EXPORT RMDebug_StepTest_Branch_1 + +RMDebug_StepTest_Branch + b RMDebug_StepTest_Branch_1 + mov r0, #2 ; if the pc ends up here, we know its gone wrong +RMDebug_StepTest_Branch_1 + bx lr ; return + +; +; Branch and Link +; + EXPORT RMDebug_StepTest_Branch_And_Link + EXPORT RMDebug_StepTest_Branch_And_Link_1 + EXPORT RMDebug_StepTest_Branch_And_Link_2 + +RMDebug_StepTest_Branch_And_Link + mov r0, lr ; preserve lr for the moment +RMDebug_StepTest_Branch_And_Link_1 + bl RMDebug_StepTest_Branch_And_Link_2 + mov r1, #1 ; insert a gap in the instruction stream so we know we branched. +RMDebug_StepTest_Branch_And_Link_2 + mov lr, r0 ; restore lr + bx lr ; should return to normal execution of the test thread + +; +; MOV PC +; + EXPORT RMDebug_StepTest_MOV_PC + EXPORT RMDebug_StepTest_MOV_PC_1 + EXPORT RMDebug_StepTest_MOV_PC_2 + +RMDebug_StepTest_MOV_PC + mov r0, #4 +RMDebug_StepTest_MOV_PC_1 + add pc, pc, r0 ; should be a jump (bear in mind reading pc = current inst + 8bytes for arm) + mov r0, #1 ; Simple instructions which allow us to test where the PC really is + mov r0, #2 ; just by reading r0. +RMDebug_StepTest_MOV_PC_2 + mov r0, #3 ; + mov r0, #4 ; + bx lr ; should return to normal execution of the test thread + +; +; LDR PC +; + EXPORT RMDebug_StepTest_LDR_PC + EXPORT RMDebug_StepTest_LDR_PC_1 + +RMDebug_StepTest_LDR_PC + ldr pc, =RMDebug_StepTest_LDR_PC_1 + mov r0, #1 ; separate the branch target so we can prove it works +RMDebug_StepTest_LDR_PC_1 + bx lr ; should return to normal execution of the test thread + +; +; ARM -> Thumb -> ARM interworking test +; +; Note: We always start and finish this test +; in ARM mode. + EXPORT RMDebug_StepTest_Interwork + EXPORT RMDebug_StepTest_Interwork_1 + EXPORT RMDebug_StepTest_Interwork_2 + EXPORT RMDebug_StepTest_Interwork_3 +RMDebug_StepTest_Interwork + mov r0, lr ; preserve lr +RMDebug_StepTest_Interwork_1 + blx RMDebug_StepTest_Interwork_2 + + CODE16 +RMDebug_StepTest_Interwork_2 + blx RMDebug_StepTest_Interwork_3 + + CODE32 + +RMDebug_StepTest_Interwork_3 + bx r0 + +; +; Stepping performance tests +; +; This counts down from 100000 to 0 +; This means that for all practical purposes +; we can single-step as much as we like +; in less than one second and have some likelyhood +; that we will not step too far from our loop + + EXPORT RMDebug_StepTest_Count + EXPORT RMDebug_StepTest_Count_1 + EXPORT RMDebug_StepTest_Count_2 + +RMDebug_StepTest_Count + ldr r2, =100000 +RMDebug_StepTest_Count_1 + subs r2, r2, #1 +RMDebug_StepTest_Count_2 + bne RMDebug_StepTest_Count_1 + bx lr + +; Thumb tests + +; Thumb non-pc modifying +; +; +RMDebug_StepTest_Thumb_Non_PC_Modifying + mov r0, lr ; preserve lr + blx RMDebug_StepTest_Thumb_Non_PC_Modifying_1 + bx r0 + +; +; Thumb Branch +; +RMDebug_StepTest_Thumb_Branch + mov r0, lr ; preserve lr + blx RMDebug_StepTest_Thumb_Branch_1 + bx r0 + +; +; Thumb Branch and link +; +RMDebug_StepTest_Thumb_Branch_And_Link + mov r0, lr ; preserve lr + blx RMDebug_StepTest_Thumb_Branch_And_Link_1 + bx r0 + +; +; Thumb Back Branch and link +; +RMDebug_StepTest_Thumb_Back_Branch_And_Link + mov r0, lr ; preserve lr + blx RMDebug_StepTest_Thumb_Back_Branch_And_Link_1 + bx r0 + +; +; Thumb ADD PC,PC, #0 +; +RMDebug_StepTest_Thumb_AddPC + mov r0, lr ; preserve lr + blx RMDebug_StepTest_Thumb_AddPC_1 + bx r0 + + CODE16 + + ; Thumb tests + EXPORT RMDebug_StepTest_Thumb_Non_PC_Modifying + EXPORT RMDebug_StepTest_Thumb_Non_PC_Modifying_1 + EXPORT RMDebug_StepTest_Thumb_Non_PC_Modifying_2 + + EXPORT RMDebug_StepTest_Thumb_Branch + EXPORT RMDebug_StepTest_Thumb_Branch_1 + EXPORT RMDebug_StepTest_Thumb_Branch_2 + + EXPORT RMDebug_StepTest_Thumb_Branch_And_Link + EXPORT RMDebug_StepTest_Thumb_Branch_And_Link_1 + EXPORT RMDebug_StepTest_Thumb_Branch_And_Link_2 + EXPORT RMDebug_StepTest_Thumb_Branch_And_Link_3 + + EXPORT RMDebug_StepTest_Thumb_Back_Branch_And_Link + EXPORT RMDebug_StepTest_Thumb_Back_Branch_And_Link_1 + EXPORT RMDebug_StepTest_Thumb_Back_Branch_And_Link_2 + EXPORT RMDebug_StepTest_Thumb_Back_Branch_And_Link_3 + +RMDebug_StepTest_Thumb_Non_PC_Modifying_1 + mov r0, r0 ; nop +RMDebug_StepTest_Thumb_Non_PC_Modifying_2 + bx lr + +RMDebug_StepTest_Thumb_Branch_1 + b RMDebug_StepTest_Thumb_Branch_2 + mov r0, r0 +RMDebug_StepTest_Thumb_Branch_2 + bx lr + +RMDebug_StepTest_Thumb_Branch_And_Link_1 + mov r1, lr +RMDebug_StepTest_Thumb_Branch_And_Link_2 + bl RMDebug_StepTest_Thumb_Branch_And_Link_3 + mov r0, r0 +RMDebug_StepTest_Thumb_Branch_And_Link_3 + bx r1 + +RMDebug_StepTest_Thumb_Back_Branch_And_Link_3 + bx r1 + +RMDebug_StepTest_Thumb_Back_Branch_And_Link_1 + mov r1, lr +RMDebug_StepTest_Thumb_Back_Branch_And_Link_2 + bl RMDebug_StepTest_Thumb_Back_Branch_And_Link_3 + bx r1 + +; +; ADD PC +; + EXPORT RMDebug_StepTest_Thumb_AddPC + EXPORT RMDebug_StepTest_Thumb_AddPC_1 + EXPORT RMDebug_StepTest_Thumb_AddPC_2 + EXPORT RMDebug_StepTest_Thumb_AddPC_3 + +RMDebug_StepTest_Thumb_AddPC_1 + mov r1, lr + mov r2, #4 +RMDebug_StepTest_Thumb_AddPC_2 + add pc, pc, r2 ; should arrive at RMDebug_StepTest_Thumb_AddPC_3 + mov r0, r0 + mov r0, r0 + mov r0, r0 +RMDebug_StepTest_Thumb_AddPC_3 + bx r1 + + ALIGN 4 + + CODE32 + +; +; ARM multiple-step ( 5 steps ) +; + EXPORT RMDebug_StepTest_ARM_Step_Multiple + EXPORT RMDebug_StepTest_ARM_Step_Multiple_1 + +RMDebug_StepTest_ARM_Step_Multiple + mov r0,r0 ; nop + mov r0,r0 ; nop + mov r0,r0 ; nop + mov r0,r0 ; nop + mov r0,r0 ; nop +RMDebug_StepTest_ARM_Step_Multiple_1 + bx lr + + END + +; End of file - d_rmdebug_step_test.s diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test_armv4.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test_armv4.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,50 @@ +// Copyright (c) 2007-2010 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: +// definitions of functions in d_rmdebug_step_tests_armv4.s +// + +#ifndef D_RMDEBUG_STEP_TESTS_H +#define D_RMDEBUG_STEP_TESTS_H + +extern "C" +{ + // ARM tests + unsigned int RMDebug_StepTest_Non_PC_Modifying(void); + unsigned int RMDebug_StepTest_Non_PC_Modifying_OK(void); + + unsigned int RMDebug_StepTest_Branch(void); + unsigned int RMDebug_StepTest_Branch_1(void); + + unsigned int RMDebug_StepTest_Branch_And_Link(void); + unsigned int RMDebug_StepTest_Branch_And_Link_1(void); + unsigned int RMDebug_StepTest_Branch_And_Link_2(void); + + unsigned int RMDebug_StepTest_MOV_PC(void); + unsigned int RMDebug_StepTest_MOV_PC_1(void); + unsigned int RMDebug_StepTest_MOV_PC_2(void); + + unsigned int RMDebug_StepTest_LDR_PC(void); + unsigned int RMDebug_StepTest_LDR_PC_1(void); + + // Stepping performance test + unsigned int RMDebug_StepTest_Count(void); + unsigned int RMDebug_StepTest_Count_1(void); + unsigned int RMDebug_StepTest_Count_2(void); + + // Multiple step test + unsigned int RMDebug_StepTest_ARM_Step_Multiple(void); + unsigned int RMDebug_StepTest_ARM_Step_Multiple_1(void); + +} +#endif // D_RMDEBUG_STEP_TESTS_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test_armv4.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebug_step_test_armv4.s Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,130 @@ +; Copyright (c) 2007-2010 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: +; +; + + AREA |d-rmdebug-bkpt$$Code|, CODE, READONLY, ALIGN=6 + + CODE32 + + ; ARM tests + +; +; Non-PC modifying +; + EXPORT RMDebug_StepTest_Non_PC_Modifying + EXPORT RMDebug_StepTest_Non_PC_Modifying_OK + +RMDebug_StepTest_Non_PC_Modifying + mov r0,r0 ; nop +RMDebug_StepTest_Non_PC_Modifying_OK + bx lr ; should return to normal execution of the test thread + +; +; Branch +; + EXPORT RMDebug_StepTest_Branch + EXPORT RMDebug_StepTest_Branch_1 + +RMDebug_StepTest_Branch + b RMDebug_StepTest_Branch_1 + mov r0, #2 ; if the pc ends up here, we know its gone wrong +RMDebug_StepTest_Branch_1 + bx lr ; return + +; +; Branch and Link +; + EXPORT RMDebug_StepTest_Branch_And_Link + EXPORT RMDebug_StepTest_Branch_And_Link_1 + EXPORT RMDebug_StepTest_Branch_And_Link_2 + +RMDebug_StepTest_Branch_And_Link + mov r0, lr ; preserve lr for the moment +RMDebug_StepTest_Branch_And_Link_1 + bl RMDebug_StepTest_Branch_And_Link_2 + mov r1, #1 ; insert a gap in the instruction stream so we know we branched. +RMDebug_StepTest_Branch_And_Link_2 + mov lr, r0 ; restore lr + bx lr ; should return to normal execution of the test thread + +; +; MOV PC +; + EXPORT RMDebug_StepTest_MOV_PC + EXPORT RMDebug_StepTest_MOV_PC_1 + EXPORT RMDebug_StepTest_MOV_PC_2 + +RMDebug_StepTest_MOV_PC + mov r0, #4 +RMDebug_StepTest_MOV_PC_1 + add pc, pc, r0 ; should be a jump (bear in mind reading pc = current inst + 8bytes for arm) + mov r0, #1 ; Simple instructions which allow us to test where the PC really is + mov r0, #2 ; just by reading r0. +RMDebug_StepTest_MOV_PC_2 + mov r0, #3 ; + mov r0, #4 ; + bx lr ; should return to normal execution of the test thread + +; +; LDR PC +; + EXPORT RMDebug_StepTest_LDR_PC + EXPORT RMDebug_StepTest_LDR_PC_1 + +RMDebug_StepTest_LDR_PC + ldr pc, =RMDebug_StepTest_LDR_PC_1 + mov r0, #1 ; separate the branch target so we can prove it works +RMDebug_StepTest_LDR_PC_1 + bx lr ; should return to normal execution of the test thread + +; +; Stepping performance tests +; +; This counts down from 100000 to 0 +; This means that for all practical purposes +; we can single-step as much as we like +; in less than one second and have some likelyhood +; that we will not step too far from our loop + + EXPORT RMDebug_StepTest_Count + EXPORT RMDebug_StepTest_Count_1 + EXPORT RMDebug_StepTest_Count_2 + +RMDebug_StepTest_Count + ldr r2, =100000 +RMDebug_StepTest_Count_1 + subs r2, r2, #1 +RMDebug_StepTest_Count_2 + bne RMDebug_StepTest_Count_1 + bx lr + +; +; ARM multiple-step ( 5 steps ) +; + EXPORT RMDebug_StepTest_ARM_Step_Multiple + EXPORT RMDebug_StepTest_ARM_Step_Multiple_1 + +RMDebug_StepTest_ARM_Step_Multiple + mov r0,r0 ; nop + mov r0,r0 ; nop + mov r0,r0 ; nop + mov r0,r0 ; nop + mov r0,r0 ; nop +RMDebug_StepTest_ARM_Step_Multiple_1 + bx lr + + END + +; End of file - d_rmdebug_step_test_armv4.s diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,106 @@ +// Copyright (c) 2006-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: +// Implements a debug thread for testing. +// +// + +#include +#include +#include +#include "d_rmdebugthread.h" + +EXPORT_C TBuf8 gMemoryAccessBytes; +extern void RMDebug_BranchTst1(); + +EXPORT_C TInt TestData; + +CDebugServThread::CDebugServThread() +// +// Empty constructor +// + { + } + +GLDEF_C TInt CDebugServThread::ThreadFunction(TAny*) +// +// Generic thread function for testing +// + { + CTrapCleanup* cleanup=CTrapCleanup::New(); + if (cleanup == NULL) + { + User::Leave(KErrNoMemory); + } + + RThread::Rendezvous(KErrNone); + + TestData = 1; + + while(1) + { + RMDebug_BranchTst1(); + + TestData++; + + // Wait half a second (suspends this thread) + User::After(500000); + + if (TestData == 0xFFFFFFFF) + { + break; + } + } + + delete cleanup; + + return (KErrNone); + } + +EXPORT_C TInt StartDebugThread(RThread& aDebugThread) +// +// Starts the test thread +// +{ + TInt res=KErrNone; + + // Create the thread + res = aDebugThread.Create( KDebugThreadName, + CDebugServThread::ThreadFunction, + KDefaultStackSize, + KDebugThreadDefaultHeapSize, + KDebugThreadDefaultHeapSize, + NULL + ); + + // Check that the creation worked + if (res == KErrNone) + { + TRequestStatus rendezvousStatus; + + aDebugThread.SetPriority(EPriorityNormal); + // Make a request for a rendezvous + aDebugThread.Rendezvous(rendezvousStatus); + // Set the thread as ready for execution + aDebugThread.Resume(); + // Wait for the resumption + User::WaitForRequest(rendezvousStatus); + } + else + { + // Close the handle. + aDebugThread.Close(); + } + + return res; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,38 @@ +// Copyright (c) 2006-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: +// t_rmdebugthread.h +// Definitions for the run mode debug test thread. +// +// + +#ifndef RMDEBUGSVRTHRD_H +#define RMDEBUGSVRTHRD_H + +#define SYMBIAN_RMDBG_MEMORYSIZE 1024*4 + +// Thread name +_LIT(KDebugThreadName,"DebugThread"); + +const TUint KDebugThreadDefaultHeapSize=0x10000; + +class CDebugServThread : public CBase + { + public: + CDebugServThread(); + static TInt ThreadFunction(TAny* aStarted); + + public: + }; + +#endif // RMDEBUGSVRTHRD_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread2.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread2.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,318 @@ +// Copyright (c) 2006-2010 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: +// Implements a debug thread for testing. +// +// + +#include +#include +#include +#include +#include "d_rmdebugthread2.h" + +#include "d_rmdebug_step_test.h" +#include "d_rmdebug_bkpt_test.h" +#include "d_demand_paging.h" + +TBuf8 gMemoryAccessBytes; +IMPORT_C extern void RMDebug_BranchTst1(); +IMPORT_C extern TInt RMDebugDemandPagingTest(); + +TInt TestData; +TTestFunction FunctionChooser; + +const TInt KNumberOfTraceCalls = 50; + +EXPORT_C TInt TestFunction() + { + // Set TestData to an arbitrary value that can be checked by a tester + TestData = 0xffeeddcc; + RMDebug_BranchTst1(); + + // Code here may not be executed because tests can change the PC value + // at any time, typically once the test passes + return 0; + } + +/** + Wrapper around RMDebugDemandPagingTest, need to pause for a short time to + allow time in t_rmdebug.cpp to issue a User::WaitForRequest to catch the break point + */ +EXPORT_C void TestPagedCode() + { + User::After(100000); + + // call the function in paged code + RMDebugDemandPagingTest(); + } + +EXPORT_C void TestMultipleTraceCalls() + { + //arbitrary function to set a BP on + RMDebug_BranchTst1(); + + // The tester will change FunctionChooser once it gets what it needs out of the test + for(TInt cnt = KNumberOfTraceCalls; cnt>0 && (FunctionChooser==EMultipleTraceCalls); cnt--) + { + RDebug::Printf("T"); + RDebug::Printf("R"); + RDebug::Printf("A"); + RDebug::Printf("C"); + RDebug::Printf("E"); + } + + //another arbitrary function to set a BP on + RMDebug_StepTest_Non_PC_Modifying(); + } + +CDebugServThread::~CDebugServThread() + { + } + +CDebugServThread::CDebugServThread() +// +// Empty constructor +// + { + } + + +/** + * Check that the RProperty argument does not change within the given amount of time. + * If the property does change, the error KErrInUse is returned. + * + */ +EXPORT_C TInt TestRunCountSame( RProperty & aProperty, RTimer & aTimer, TTimeIntervalMicroSeconds32 aTimeOut ) + { + TRequestStatus propertyStatus; + TRequestStatus timerStatus; + TInt propertyValueBefore = 0; + TInt propertyValueAfter = 0; + + aProperty.Subscribe( propertyStatus ); + aProperty.Get( propertyValueBefore ); + aTimer.After( timerStatus, aTimeOut ); + + User::WaitForRequest( propertyStatus, timerStatus ); + if (propertyStatus != KRequestPending) + { + RDebug::Printf(" CDebugServThread::TestRunCountSame: Property has been set. Returning KErrInUse"); + aTimer.Cancel(); + // Wait for the KErrCancel + User::WaitForRequest( timerStatus ); + return KErrInUse; + } + + aProperty.Cancel(); + //This will wait for the KErrCancel to be issued by the property. + User::WaitForRequest( propertyStatus ); + + aProperty.Get( propertyValueAfter ); + if( propertyValueAfter != propertyValueBefore ) + { + RDebug::Printf(" CDebugServThread::TestRunCountSame: Change in property value. Returning KErrInUse"); + return KErrInUse; + } + + return KErrNone; + } + + +/** + * Check that the RProperty argument changes within the given amount of time. + * If the property does not change, the error KErrTimedOut is returned. + * If the values before and after are the same, the error KErrNotReady is returned + */ +EXPORT_C TInt WaitForRunCountChange( RProperty & aProperty, RTimer & aTimer, TTimeIntervalMicroSeconds32 aTimeOut ) + { + TRequestStatus propertyStatus; + TRequestStatus timerStatus; + TInt propertyValueBefore = 0; + TInt propertyValueAfter = 0; + + aProperty.Get( propertyValueBefore ); + aProperty.Subscribe( propertyStatus ); + + aTimer.After( timerStatus, aTimeOut ); + + User::WaitForRequest( propertyStatus, timerStatus ); + if (timerStatus != KRequestPending) + { + RDebug::Printf(" CDebugServThread::WaitForRunCountChange: timeout. Returning KErrTimedOut"); + aProperty.Cancel(); + // Wait for the KErrCancel + User::WaitForRequest( propertyStatus ); + return KErrTimedOut; + } + + aTimer.Cancel(); + //This will wait for the KErrCancel to be issued by the timer. + User::WaitForRequest( timerStatus ); + + aProperty.Get( propertyValueAfter ); + if( propertyValueAfter == propertyValueBefore ) + { + RDebug::Printf(" CDebugServThread::WaitForRunCountChange: No change in property value. Returning KErrNotReady"); + return KErrNotReady; + } + + return KErrNone; + } + +GLDEF_C TInt CDebugServThread::ThreadFunction(TAny*) +// +// Generic thread function for testing +// + { + // set FunctionChooser to run the default function + FunctionChooser = EDefaultFunction; + + CTrapCleanup* cleanup=CTrapCleanup::New(); + if (cleanup == NULL) + { + User::Leave(KErrNoMemory); + } + + TInt err = RProperty::Define( RProcess().SecureId(), ERMDBGRunCountProperty, RProperty::EInt ); + if( (err != KErrAlreadyExists) && (err != KErrNone) ) + { + RDebug::Printf("CDebugServThread::ThreadFunction - unable to create 'ERunCount' property. err:%d", err); + } + + RThread::Rendezvous(KErrNone); + + TestData = 1; + + /* Beware of adding printf or other debug-generating events in this loop because + * they interfere with the tests + */ + while(TestData != 0xFFFFFFFF) + { + //iRunCountPublish.Set( TestData ); + RProperty::Set( RProcess().SecureId(), ERMDBGRunCountProperty, TestData ); + + switch(FunctionChooser) + { + case EDemandPagingFunction: + TestPagedCode(); + break; + case EDefaultFunction: + // the default function is the stepping test functions + case EStepFunction: + { + RMDebug_BranchTst1(); + + // Single stepping test support code + + // ARM tests + RMDebug_StepTest_Non_PC_Modifying(); + + RMDebug_StepTest_Branch(); + + RMDebug_StepTest_Branch_And_Link(); + + RMDebug_StepTest_MOV_PC(); + + RMDebug_StepTest_LDR_PC(); + +// thumb/interworking tests not supported on armv4 +#ifdef __MARM_ARMV5__ + + // Thumb tests + RMDebug_StepTest_Thumb_Non_PC_Modifying(); + + RMDebug_StepTest_Thumb_Branch(); + + RMDebug_StepTest_Thumb_Branch_And_Link(); + + RMDebug_StepTest_Thumb_Back_Branch_And_Link(); + + // ARM <-> Thumb interworking tests + RMDebug_StepTest_Interwork(); + + RMDebug_StepTest_Thumb_AddPC(); + +#endif // __MARM_ARMV5__ + + // Single-stepping performance + RMDebug_StepTest_Count(); + + // multiple step test + RMDebug_StepTest_ARM_Step_Multiple(); + + // Breakpoints in loop test + RMDebug_Bkpt_Test_Entry(); + + TestData++; + + RDebug::Printf("** TestData=%d", TestData) ; + + // Wait 50mSecs. // (suspends this thread) + User::After(50000); + + break; + } + case EMultipleTraceCalls: + TestMultipleTraceCalls(); + break; + default: + //do nothing + break; + } + } + + RProperty::Delete( RProcess().SecureId(), ERMDBGRunCountProperty ); + + delete cleanup; + + return (KErrNone); + } + +EXPORT_C TInt StartDebugThread(RThread& aDebugThread, const TDesC& aDebugThreadName) +// +// Starts a test thread +// +{ + TInt res=KErrNone; + + // Create the thread + res = aDebugThread.Create( aDebugThreadName, + CDebugServThread::ThreadFunction, + KDefaultStackSize, + KDebugThreadDefaultHeapSize, + KDebugThreadDefaultHeapSize, + NULL + ); + + // Check that the creation worked + if (res == KErrNone) + { + TRequestStatus rendezvousStatus; + + aDebugThread.SetPriority(EPriorityNormal); + // Make a request for a rendezvous + aDebugThread.Rendezvous(rendezvousStatus); + // Set the thread as ready for execution + aDebugThread.Resume(); + // Wait for the resumption + User::WaitForRequest(rendezvousStatus); + } + else + { + // Close the handle. + aDebugThread.Close(); + } + + return res; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread2.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthread2.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,71 @@ +// Copyright (c) 2006-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: +// Definitions for the run mode debug test thread. +// +// + +#ifndef RMDEBUGSVRTHRD_H +#define RMDEBUGSVRTHRD_H + +#include + +#define SYMBIAN_RMDBG_MEMORYSIZE 1024*4 + +// Thread name +_LIT(KDebugThreadName,"DebugThread"); + + +IMPORT_C TInt TestRunCountSame( + RProperty & aProperty, + RTimer & aTimer, + TTimeIntervalMicroSeconds32 aTimeOut = 500000 ); + + +IMPORT_C TInt WaitForRunCountChange( + RProperty & aProperty, + RTimer & aTimer, + TTimeIntervalMicroSeconds32 aTimeOut = 500000 ); + +const TUint KDebugThreadDefaultHeapSize=0x10000; + +// enumeration of functions which the target debug thread can call, the +// debugger can choose to switch the thread to a different function by +// writing the appropriate enumeration value into FunctionChooser, the +// target thread will finish executing the function it is currently running +// then execute the chosen function. +enum TTestFunction + { + EDefaultFunction = 0, + EStepFunction = 1, + EDemandPagingFunction = 2, + EMultipleTraceCalls = 3, + EDoNothing = 4 + }; + +class CDebugServThread : public CBase + { + public: + CDebugServThread(); + ~CDebugServThread(); + static TInt ThreadFunction(TAny* aStarted); + + + //Enums for all the properties used by this class + enum TRMDebugProperties + { + ERMDBGRunCountProperty = 3 + }; + }; + +#endif // RMDEBUGSVRTHRD_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthreadasm.cia --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthreadasm.cia Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,32 @@ +// Copyright (c) 2006-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: +// d_rmdebugthreadasm.h +// Assembler file for debug thread testing. +// +// + +//#include +//#include +//#include +//#include "d_rmdebugthread.h" + +EXPORT_C __NAKED__ void RMDebug_BranchTst1( void ) +// +// +// +{ + asm("mov r0, #0 "); // aResult==KErrNone + asm("bx lr "); // Return +} + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthreadasm2.cia --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/d_rmdebugthreadasm2.cia Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,35 @@ +// Copyright (c) 2006-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: +// d_rmdebugthreadasm2.h +// Assembler file for debug thread testing. +// +// + +EXPORT_C __NAKED__ void RMDebug_BranchTst1( void ) +// +// +// +{ + asm("mov r0, #0 "); // aResult==KErrNone + asm("bx lr "); // Return +} + +EXPORT_C __NAKED__ void RMDebug_BranchTst2( void ) +// +// +// +{ + asm("mov r0, #0 "); // aResult==KErrNone + asm("bx lr "); // Return +} diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_app.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_app.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,415 @@ +// Copyright (c) 2007-2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "t_rmdebug_app.h" + +IMPORT_C extern void RMDebug_BranchTst2(); + +LOCAL_C void ParseCommandLineL(TInt32& aFunctionType, TUint& aDelay, TUint& aExtraThreads, TInt32& aCpuNumber, TInt32& aThreadPriority) + { + + // get the length of the command line arguments + TInt argc = User::CommandLineLength(); + RDebug::Printf(" t_rmdebug_app: ParseCommandLineL argc=%d", argc); + + // 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)); + RDebug::Printf(" t_rmdebug_app: setting aFunctionType=%d", aFunctionType); + break; + case 'd': + // the digits following '-d' give the delay + User::LeaveIfError(lex.Val(aDelay)); + RDebug::Printf(" t_rmdebug_app: setting aDelay=%d", aDelay); + break; + case 'e': + // the digits following '-e' give the number of extra threads to launch + User::LeaveIfError(lex.Val(aExtraThreads)); + RDebug::Printf(" t_rmdebug_app: setting aExtraThreads=%d", aExtraThreads); + break; + + case 'p': + // the digits following '-p' gives the value to set for the main thread priority + User::LeaveIfError(lex.Val(aThreadPriority)); + RDebug::Printf(" t_rmdebug_app: aThreadPriority =%d", aThreadPriority); + break; + + case 'a': + // the digits following '-a' gives the cpu on which this thread will execute on + User::LeaveIfError(lex.Val(aCpuNumber)); + RDebug::Printf(" t_rmdebug_app: CPU Number =%d", aCpuNumber ); + 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(); + } + + // publish the address of the RMDebug_BranchTst2 with the correct SID value + TInt address = (TInt)&RMDebug_BranchTst2; + err = RProperty::Set(propertySid, EMyPropertyInteger, address); + if(KErrNone != err) + RDebug::Printf("Error Set of the property %d", err); + + //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::Print(_L("App Process Name %S 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 NormalExit() + { + RDebug::Printf("Target app: NormalExit() function. Returning to MainL" ); + } + +void LaunchThreads(TUint aNumber) + { + _LIT(KDebugThreadName, "DebugThread"); + const TUint KDebugThreadDefaultHeapSize=0x10000; + for(TInt i=0; i TestCpuCount = %d\n", TestCpuCount); + TUint32 cpu = 0; + + if ((aCpuNumber % TestCpuCount) != 0) + cpu = (TUint32)(aCpuNumber % TestCpuCount); + + RDebug::Printf("SetCpuAffinity --> Setting cpu %3d\n", cpu); + TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)cpu, 0); + return r; + } + +void SetCurrentThreadPriority(TInt aThreadPriority) + { + RDebug::Printf("SetCurrentThreadPriority aThreadPriority =%d\n", aThreadPriority); + RThread().SetPriority((TThreadPriority) aThreadPriority); + RDebug::Printf("SetCurrentThreadPriority Crashapp RThread Priority() = %d", (TInt) RThread().Priority()) ; + } + +TInt GetTimeInMs() +{ + TInt period = 0; + User::LeaveIfError(HAL::Get(HALData::ENanoTickPeriod, period)); + TInt periodInMs = period / 1000; + return User::NTickCount() * periodInMs; +} + +void SetNanoTickTime() + { + TUid t_performance_test_Sid; + t_performance_test_Sid.iUid = 0x102831E5; + RProperty::Set(t_performance_test_Sid, EPropertyTimeOfCrash, GetTimeInMs()); + } + +// call the function corresponding to aFunctionType +LOCAL_C void CallFunction(TDebugFunctionType aFunctionType, TUint aDelay, TUint aExtraThreads, TInt32 aCpuNumber, TUint aThreadPriority ) + { + + // pause for aDelay microseconds + User::After(aDelay); + + // set cpu on which this thread should execute on + if ( aCpuNumber ) + SetCpuAffinity(aCpuNumber); + + if ( aThreadPriority ) + SetCurrentThreadPriority(aThreadPriority); + + // launch the extra threads + LaunchThreads(aExtraThreads); + + // Publish Nano tick count time for RMDBG performance testing + SetNanoTickTime(); + + // 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 ENormalExit: + NormalExit(); + break; + case EDefaultDebugFunction: + default: + break; + } + } + +void PrintHelp() + { + RDebug::Printf("Invoke with arguments:\n"); + RDebug::Printf("\t-d\n\t: delay in microseconds before calling target function\n"); + RDebug::Printf("\t-f\n\t: enumerator from TDebugFunctionType representing function to call\n"); + RDebug::Printf("\t-e\n\t: number of extra threads to launch, these threads run endlessly\n"); + } + +TInt E32Main() + { + + RDebug::Printf("<<<<< E32Main() RThread Priority() = %d, RProcess Priority() = %d", (TInt) RThread().Priority(), (TInt) RProcess().Priority()) ; + RDebug::Printf("t_rmdebug_app tid=%d,pid=%d", I64LOW(RThread().Id().Id()), I64LOW(RProcess().Id().Id()) ) ; + // 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; + TInt32 aCpuNumber = 0; + TInt32 aThreadPriority = 0; + + TRAPD(err, ParseCommandLineL(functionTypeAsTInt32, delay, extraThreads, aCpuNumber, aThreadPriority)); + + RDebug::Printf("E32Main :: aThreadPriority=%d", aThreadPriority ) ; + + if(KErrNone == err) + { + // if the command line arguments were successfully read then call the appropriate function + CallFunction((TDebugFunctionType)functionTypeAsTInt32, delay, extraThreads, aCpuNumber, aThreadPriority); + } + + // perform clean up and return any error which was recorded + delete cleanup; + __UHEAP_MARKEND; + return err; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_app.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_app.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,46 @@ +// 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: +// + +#ifndef T_RMDEBUG_APP_H +#define T_RMDEBUG_APP_H + +_LIT(KRMDebugTestApplication, "z:\\sys\\bin\\t_rmdebug_app.exe"); +_LIT(KUserPanic, "UserPanic"); +const TInt KUserPanicCode = 0x1234ABCD; + +enum TMyPropertyKeys {EMyPropertyInteger}; +enum TPropertyTimeKeys {EPropertyTimeOfCrash}; + + +// enumeration of functions to call in test debug application +enum TDebugFunctionType + { + EDefaultDebugFunction, + EPrefetchAbortFunction, + EUserPanicFunction, + EStackOverflowFunction, + EDataAbortFunction, + EUndefInstructionFunction, + EDataReadErrorFunction, + EDataWriteErrorFunction, + EUserExceptionFunction, + EWaitFiveSecondsThenExit, + ESpinForever, + ESpinForeverWithBreakPoint, + ENormalExit + }; + +#endif //T_RMDEBUG_APP_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_dll.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_dll.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,25 @@ +// 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 +#include +#include +#include "t_rmdebug_dll.h" + +EXPORT_C TUid GetDSSUid() + { + return Debug::KUidDebugSecurityServer; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_dll.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_dll.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,23 @@ +// 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 + +/** + This is a simple function that uses an element from rm_debug_api.h. + If the e32tests can be built and run then this is 'proof' that the + rm_debug_api.h header file can be #include'd into a dll + */ +IMPORT_C TUid GetDSSUid(); diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_security.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_security.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,100 @@ +// Copyright (c) 2006-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: +// Target application to be debugged by t_rmdebug.exe when testing +// security restrictions. This application is built with various +// capabilities by the t_rmdebug_securityX.mmp files. This allows +// the t_rmdebug2 program to ensure that security restrictions are +// properly enforced by the DSS/DDD subsystem. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include "t_rmdebug_security.h" + +CRunModeApp* CRunModeApp::NewL() +// +// CRunModeApp::NewL +// + { + CRunModeApp* self = new(ELeave) CRunModeApp(); + + self->ConstructL(); + + return self; + } + +CRunModeApp::CRunModeApp() +// +// CRunModeApp constructor +// + { + } + +CRunModeApp::~CRunModeApp() +// +// CRunModeApp destructor +// + { + } + +void CRunModeApp::ConstructL() +// +// CRunModeApp::ConstructL +// + { + } + +void CRunModeApp::TestWaitDebug() +// +// CRunModeApp::TestWaitDebug +// + { + RProcess::Rendezvous(KErrNone); + + // Wait a 3secs then quit (long enough to test, but not hang around forever) + User::After(3000000); + } + +GLDEF_C TInt E32Main() +// +// Entry point for run mode debug app test program +// + { + TInt ret = KErrNone; + + // client + CTrapCleanup* trap = CTrapCleanup::New(); + if (!trap) + return KErrNoMemory; + + CRunModeApp* myApp = CRunModeApp::NewL(); + if (myApp != NULL) + { + __UHEAP_MARK; + TRAP(ret,myApp->TestWaitDebug()); + __UHEAP_MARKEND; + + delete myApp; + } + + delete trap; + + return ret; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_security.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/debug_targets/t_rmdebug_security.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,44 @@ +// Copyright (c) 2006-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: +// Target application to be debugged by t_rmdebug2.exe when testing +// security restrictions. This application is built with various +// capabilities by the t_rmdebug_securityX.mmp files. This allows +// the t_rmdebug2 program to ensure that security restrictions are +// properly enforced by the DSS/DDD subsystem. +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef T_RMDEBUG_SECURITY_H +#define T_RMDEBUG_SECURITY_H + +class CRunModeApp : public CBase +{ +public: + static CRunModeApp* NewL(); + ~CRunModeApp(); + + void TestWaitDebug(); + +private: + CRunModeApp(); + void ConstructL(); +}; + +#endif // T_RMDEBUG_SECURITY_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/bld.inf Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,94 @@ +// Copyright (c) 2010 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/group/bld.inf +// Kernel and User library test code +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_TESTEXPORTS + +./t_rmdebug_tests.iby /epoc32/rom/include/t_rmdebug_tests.iby +./mytraces_rm_debug_ekern.txt /epoc32/rombuild/mytraces_rm_debug_ekern.txt +./mytraces_rm_debug.txt /epoc32/rombuild/mytraces_rm_debug.txt + +./rmdebug.iby /epoc32/rom/include/rmdebug.iby +../scripts/tef_execute_rtests.script z:/scripts/tef_execute_rtests.script + + +PRJ_TESTMMPFILES + +/****************************************************************************** + Put all device drivers here. These build both SMP and non-SMP variants. + User side code builds a single variant for both. + *NOTE: Base BTB will build properly any kernel-side test code embedded within + positive check ( #ifdef SMP ), however these binaries will not be included in BTB + autotest images for SMP platforms. Refer to DTW-KHS BTB00055 for more details. + ******************************************************************************/ + +/****************************************************************************** + User side code here - builds a single variant for both SMP and non-SMP. + ******************************************************************************/ + +#if defined(MARM_ARMV5) +./t_rmdebug_app support +./t_rmdebug_app1 support +./t_rmdebug_app2 support +./t_rmdebug_app3 support +./t_rmdebug_app4 support +./t_rmdebug_app5 support +./t_rmdebug_app6 support +./t_rmdebug_app7 support +./t_rmdebug_app8 support +./t_rmdebug_app9 support +./t_rmdebug_app10 support + +./t_rmdebug_dll support + +./t_rmdebug_security0 support +./t_rmdebug_security1 support +./t_rmdebug_security2 support +./t_rmdebug_security3 support + +./t_rmdebug2.mmp + +./t_rmdebug2_oem.mmp +./t_rmdebug2_oemtoken support + +./t_rmdebug2_oem2.mmp +./t_rmdebug2_oemtoken2 support + +./t_rmdebug2_allcaps.mmp +./t_rmdebug2_allcapstoken support + +./t_rmdebug_target_launcher support +./t_rmdebug_multi_target.mmp + +./t_rmdebug_multi_agent support +./t_multi_agent_launcher.mmp + +./t_rmdebug_performance_allcapstoken +./t_performance_test.mmp + +#endif + + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/mytraces_rm_debug.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/mytraces_rm_debug.txt Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,37 @@ +_fh4hrp_scmonitornor.dll +_h4hrp_scmonitornor.dll +OEMDebug_10282FE5.exe +OEMDebug_102831E5.exe +OEMDebug_F1234567.exe +OEMDebug_F123ABCD.exe +OEMDebug_F123ABCE.exe +rm_debug.ldd +rm_debug_svr.exe +scmonitor_serial.dll +t_crashmonitor_lib.exe +t_performance_test.exe +t_rmdebug_app.exe +t_rmdebug_app1.exe +t_rmdebug_app10.exe +t_rmdebug_app2.exe +t_rmdebug_app3.exe +t_rmdebug_app4.exe +t_rmdebug_app5.exe +t_rmdebug_app6.exe +t_rmdebug_app7.exe +t_rmdebug_app8.exe +t_rmdebug_app9.exe +t_rmdebug_attachall.exe +t_rmdebug_dll.dll +t_rmdebug_multi_agent.exe +t_rmdebug_multi_target.exe +t_rmdebug_security0.exe +t_rmdebug_security1.exe +t_rmdebug_security2.exe +t_rmdebug_security3.exe +t_rmdebug_target_launcher.exe +t_rmdebug2.exe +t_rmdebug2_allcaps.exe +t_rmdebug2_oem.exe +t_rmdebug2_oem2.exe +t_trkdummyapp.exe \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/mytraces_rm_debug_ekern.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/mytraces_rm_debug_ekern.txt Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,49 @@ +_34xx_sdp_ekern.exe +_8500_ekern.exe +_f34xx_sdp_ekern.exe +_fh4hrp_ekern.exe +_fne1_tb_ekern.exe +_h4hrp_ekern.exe +_lab_ekern.exe +_ne1_tb_ekern.exe +_rapu_ekern.exe +_rapu_fmm_ekern.exe +_template_ekern.exe + +_fh4hrp_scmonitornor.dll +_h4hrp_scmonitornor.dll +OEMDebug_10282FE5.exe +OEMDebug_102831E5.exe +OEMDebug_F1234567.exe +OEMDebug_F123ABCD.exe +OEMDebug_F123ABCE.exe +rm_debug.ldd +rm_debug_svr.exe +scmonitor_serial.dll +t_crashmonitor_lib.exe +t_performance_test.exe +t_rmdebug_app.exe +t_rmdebug_app1.exe +t_rmdebug_app10.exe +t_rmdebug_app2.exe +t_rmdebug_app3.exe +t_rmdebug_app4.exe +t_rmdebug_app5.exe +t_rmdebug_app6.exe +t_rmdebug_app7.exe +t_rmdebug_app8.exe +t_rmdebug_app9.exe +t_rmdebug_attachall.exe +t_rmdebug_dll.dll +t_rmdebug_multi_agent.exe +t_rmdebug_multi_target.exe +t_rmdebug_security0.exe +t_rmdebug_security1.exe +t_rmdebug_security2.exe +t_rmdebug_security3.exe +t_rmdebug_target_launcher.exe +t_rmdebug2.exe +t_rmdebug2_allcaps.exe +t_rmdebug2_oem.exe +t_rmdebug2_oem2.exe +t_trkdummyapp.exe \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/rmdbg_test.pkg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/rmdbg_test.pkg Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,64 @@ +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// + +// BINARIES NEEDED BY TESTS BELOW +"\epoc32\release\armv5\udeb\t_rmdebug_app.exe"-"c:\sys\bin\t_rmdebug_app.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app1.exe"-"c:\sys\bin\t_rmdebug_app1.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app2.exe"-"c:\sys\bin\t_rmdebug_app2.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app3.exe"-"c:\sys\bin\t_rmdebug_app3.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app4.exe"-"c:\sys\bin\t_rmdebug_app4.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app5.exe"-"c:\sys\bin\t_rmdebug_app5.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app6.exe"-"c:\sys\bin\t_rmdebug_app6.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app7.exe"-"c:\sys\bin\t_rmdebug_app7.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app8.exe"-"c:\sys\bin\t_rmdebug_app8.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app9.exe"-"c:\sys\bin\t_rmdebug_app9.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_app10.exe"-"c:\sys\bin\t_rmdebug_app10.exe" + +"\epoc32\release\armv5\udeb\t_rmdebug_dll.dll"-"c:\sys\bin\t_rmdebug_dll.dll" + +"\epoc32\release\armv5\udeb\t_rmdebug_security0.exe"-"c:\sys\bin\t_rmdebug_security0.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_security1.exe"-"c:\sys\bin\t_rmdebug_security1.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_security2.exe"-"c:\sys\bin\t_rmdebug_security2.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_security3.exe"-"c:\sys\bin\t_rmdebug_security3.exe" + + +//RUN_RTESTS_AS_TEF +"\epoc32\data\z\scripts\tef_execute_rtests.script"-"c:\scripts\tef_execute_rtests.script" + + +//No token required +"\epoc32\release\armv5\udeb\t_rmdebug2.exe"-"c:\sys\bin\t_rmdebug2.exe" + +//SOMECAPS_DEBUGTOKEN +"\epoc32\release\armv5\udeb\t_rmdebug2_oem.exe"-"c:\sys\bin\t_rmdebug2_oem.exe" +"\epoc32\release\armv5\udeb\OEMDebug_F123ABCD.exe"-"c:\sys\bin\OEMDebug_F123ABCD.exe" + +//FEWCAPS_DEBUGTOKEN +"\epoc32\release\armv5\udeb\t_rmdebug2_oem2.exe"-"c:\sys\bin\t_rmdebug2_oem2.exe" +"\epoc32\release\armv5\udeb\OEMDebug_F1234567.exe"-"c:\sys\bin\OEMDebug_F1234567.exe" + +//ALLCAPS_DEBUGTOKEN +"\epoc32\release\armv5\udeb\t_rmdebug2_allcaps.exe"-"c:\sys\bin\t_rmdebug2_allcaps.exe" +"\epoc32\release\armv5\udeb\OEMDebug_F123ABCE.exe"-"c:\sys\bin\OEMDebug_F123ABCE.exe" + +"\epoc32\release\armv5\udeb\t_rmdebug_target_launcher.exe"-"c:\sys\bin\t_rmdebug_target_launcher.exe" +"\epoc32\release\armv5\udeb\t_rmdebug_multi_target.exe"-"c:\sys\bin\t_rmdebug_multi_target.exe" + +"\epoc32\release\armv5\udeb\t_rmdebug_multi_agent.exe"-"c:\sys\bin\t_rmdebug_multi_agent.exe" +"\epoc32\release\armv5\udeb\t_multi_agent_launcher.exe"-"c:\sys\bin\t_multi_agent_launcher.exe" + +//PERFORMANCE TEST DEBUGTOKEN +"\epoc32\release\armv5\udeb\t_performance_test.exe"-"c:\sys\bin\t_performance_test.exe" +"\epoc32\release\armv5\udeb\OEMDebug_102831E5.exe"-"c:\sys\bin\OEMDebug_102831E5.exe" diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/rmdebug.iby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/rmdebug.iby Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,18 @@ +// Copyright (c) 2010 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: +// Build configuration file for Sirocco +// + +extension[VARID]=KERNEL_DIR\DEBUG_DIR\rm_debug.ldd \sys\bin\rm_debug.ldd +file=KERNEL_DIR\DEBUG_DIR\rm_debug_svr.exe \sys\bin\rm_debug_svr.exe diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_multi_agent_launcher.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_multi_agent_launcher.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,44 @@ +// Copyright (c) 2006-2010 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: +// Application that launches multiple agents which in-turn test the ability of +// the run mode debug component to debug several targets +// +// + +// This is an RTest configured to run on Sirocco, hence the testexecuteutils linked in lib below. + +targettype exe +target t_multi_agent_launcher.exe + +library euser.lib hal.lib +library testexecuteutils.lib // for Sirocco + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +userinclude ../debug_targets +userinclude ../common +userinclude ../multi_agent_tests + +sourcepath ../multi_agent_tests +source t_multi_agent_launcher.cpp + +UID 0x0 0x4321bbbc +SECUREID 0x1234aaab +VENDORID 0x70000001 + +DEBUGGABLE + +macro NO_DEBUGTOKEN + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_performance_test.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_performance_test.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,40 @@ +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// +// + +// This is an RTest configured to run on Sirocco, hence the testexecuteutils linked in lib below. + +TARGET t_performance_test.exe +TARGETTYPE exe +UID 0x1000008D 0x102831E5 +VENDORID 0x70000001 + + +USERINCLUDE ../common +USERINCLUDE ../performance_test +USERINCLUDE ../debug_targets +SOURCEPATH ../performance_test + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +library euser.lib +library hal.lib +library testexecuteutils.lib // for Sirocco + +DEBUGGABLE + +MACRO SYMBIAN_TRACE_ENABLE + +SOURCE t_rmdebug_performance_test.cpp diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug.iby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug.iby Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,28 @@ +// Copyright (c) 2010 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: +// Tests the functionality of the run mode debug device driver. +// +// + + +#ifndef T_RMDEBUG_IBY +#define T_RMDEBUG_IBY + +file=ABI_DIR\DEBUG_DIR\t_rmdebug2.exe \sys\bin\t_rmdebug2.exe +file=ABI_DIR\DEBUG_DIR\t_rmdebug2_oem.exe \sys\bin\t_rmdebug2_oem.exe +file=ABI_DIR\DEBUG_DIR\OEMDebug_F123ABCD.exe \sys\bin\OEMDebug_F123ABCD.exe + +file=ABI_DIR\DEBUG_DIR\t_rmdebug_dll.dll \sys\bin\t_rmdebug_dll.dll + +#endif \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,40 @@ +// Copyright (c) 2006-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: +// +// + +ALWAYS_BUILD_AS_ARM + +target t_rmdebug.exe +targettype exe + +sourcepath ../metro_trk +source d_rmdebugserver.cpp +source d_rmdebugthread.cpp +source t_rmdebug.cpp +sourcepath ../common +source d_rmdebugthreadasm.cia + +library euser.lib + +SYMBIAN_BASE_SYSTEMINCLUDE(nkern) +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +UID 0x100039CE 0x101F7159 +SECUREID 0x101F7159 +VENDORID 0x70000001 + +CAPABILITY ALL -TCB + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2.mmh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2.mmh Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,66 @@ +// Copyright (c) 2006-2010 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: +// +// + +ALWAYS_BUILD_AS_ARM + +targettype exe + +sourcepath ..\debug_targets + +source d_rmdebugthread2.cpp +source d_rmdebugthreadasm2.cia + +#if defined(MARM_ARMV5) +source d_rmdebug_step_test.s +source d_rmdebug_bkpt_test.s +#endif + +#if defined(MARM_ARMV4) +source d_rmdebug_step_test_armv4.s +#endif + +source d_demand_paging.cia + +library euser.lib +library hal.lib +library efsrv.lib +library t_rmdebug_dll.lib + +userinclude ..\..\..\rmdriver\inc +userinclude ..\..\..\securityserver\inc +userinclude ..\debug_targets + + +#ifdef SYMBIAN_OLD_EXPORT_LOCATION +SYMBIAN_BASE_SYSTEMINCLUDE(drivers) +SYMBIAN_BASE_SYSTEMINCLUDE(kernel) +#endif +SYMBIAN_BASE_SYSTEMINCLUDE(nkern) +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +PAGED + +// To test heap allocation failure uncomment one or other of the following macros. +// NOTE: Do not uncomment both, the tests will panic if both are defined! + +// To test heap allocation failure in the Debug Device Driver uncomment this macro +//macro KERNEL_OOM_TESTING + +// To test heap allocation failure in the Debug Security Server uncomment this macro +//macro USER_OOM_TESTING + + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,39 @@ +// Copyright (c) 2006-2010 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: +// +// + +// This is an RTest configured to run on Sirocco, hence the testexecuteutils linked in lib below. + +#include "t_rmdebug2.mmh" + +target t_rmdebug2.exe + +sourcepath ../basic_tests +source t_rmdebug2.cpp +source r_low_memory_security_svr_session.cpp +source r_kernel_low_memory_security_svr_session.cpp +source r_user_low_memory_security_svr_session.cpp + +library testexecuteutils.lib // for Sirocco + +UID 0x0 0x4321bbbb +SECUREID 0x1234aaaa +VENDORID 0x70000001 + +CAPABILITY READUSERDATA POWERMGMT ALLFILES + +DEBUGGABLE + +macro NO_DEBUGTOKEN diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_allcaps.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_allcaps.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,42 @@ +// Copyright (c) 2006-2010 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: +// Same tests as t_rmdebug2.mmp but with OEM rights conferred +// by the OEMDebug_F123ABCD.exe token file. +// +// + +// This is an RTest configured to run on Sirocco, hence the testexecuteutils linked in lib below. + +#include "t_rmdebug2.mmh" + +target t_rmdebug2_allcaps.exe + +sourcepath ../basic_tests +source t_rmdebug2.cpp +source r_low_memory_security_svr_session.cpp +source r_kernel_low_memory_security_svr_session.cpp +source r_user_low_memory_security_svr_session.cpp + +library testexecuteutils.lib // for Sirocco + +UID 0x0 0x4321bbbb +SECUREID 0xF123abce +VENDORID 0x70000001 + +CAPABILITY READUSERDATA POWERMGMT ALLFILES + +// Used when compiling tests to work in the presence of an +// OEM Debug Token +macro ALLCAPS_DEBUGTOKEN + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_allcapstoken.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_allcapstoken.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// +// + +ALWAYS_BUILD_AS_ARM + +target OEMDebug_F123ABCE.exe +targettype exe + +sourcepath ../basic_tests + +source t_rmdebug2_oemtoken.cpp + +library euser.lib + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +capability All + +UID 0x0 0x0 +SECUREID 0x0 +VENDORID 0x70000001 + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oem.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oem.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,42 @@ +// Copyright (c) 2006-2010 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: +// Same tests as t_rmdebug2.mmp but with OEM rights conferred +// by the OEMDebug_F123ABCD.exe token file. +// +// + +// This is an RTest configured to run on Sirocco, hence the testexecuteutils linked in lib below. + +#include "t_rmdebug2.mmh" + +target t_rmdebug2_oem.exe + +sourcepath ../basic_tests +source t_rmdebug2.cpp +source r_low_memory_security_svr_session.cpp +source r_kernel_low_memory_security_svr_session.cpp +source r_user_low_memory_security_svr_session.cpp + +library testexecuteutils.lib // for Sirocco + +UID 0x0 0x4321bbbb +SECUREID 0xF123abcd +VENDORID 0x70000001 + +CAPABILITY READUSERDATA POWERMGMT ALLFILES + +// Used when compiling tests to work in the presence of an +// OEM Debug Token +macro SOMECAPS_DEBUGTOKEN + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oem2.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oem2.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,42 @@ +// Copyright (c) 2006-2010 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: +// Same tests as t_rmdebug2.mmp but with some OEM rights conferred +// by the OEMDebug_F1234567.exe token file. +// +// + +//RTEST + +#include "t_rmdebug2.mmh" + +target t_rmdebug2_oem2.exe + +sourcepath ../basic_tests +source t_rmdebug2.cpp +source r_low_memory_security_svr_session.cpp +source r_kernel_low_memory_security_svr_session.cpp +source r_user_low_memory_security_svr_session.cpp + +library testexecuteutils.lib // for Sirocco + +UID 0x0 0x4321bbbb +SECUREID 0xF1234567 +VENDORID 0x70000001 + +CAPABILITY READUSERDATA POWERMGMT + +// Used when compiling tests to work in the presence of an +// OEM Debug Token with AllFiles only capability +macro FEWCAPS_DEBUGTOKEN + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oemtoken.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oemtoken.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// +// + +ALWAYS_BUILD_AS_ARM + +target OEMDebug_F123ABCD.exe +targettype exe + +sourcepath ../basic_tests + +source t_rmdebug2_oemtoken.cpp + +library euser.lib + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +capability PowerMgmt AllFiles Tcb ReadUserData WriteUserData + +UID 0x0 0x0 +SECUREID 0x0 +VENDORID 0x70000001 + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oemtoken2.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug2_oemtoken2.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,37 @@ +// 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: +// +// + +ALWAYS_BUILD_AS_ARM + +target OEMDebug_F1234567.exe +targettype exe + +sourcepath ../basic_tests + +source t_rmdebug2_oemtoken.cpp + +library euser.lib + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +// Token requires AllFiles +capability AllFiles ReadUserData PowerMgmt + +UID 0x0 0x0 +SECUREID 0x0 +VENDORID 0x70000001 + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,35 @@ +// 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: +// +// + +target t_rmdebug_app.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app1.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app1.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app1.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app10.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app10.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app10.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app2.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app2.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app2.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app3.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app3.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app3.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app4.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app4.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app4.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app5.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app5.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app5.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app6.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app6.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app6.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app7.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app7.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app7.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app8.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app8.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app8.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app9.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_app9.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// 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: +// Target application to be debugged +// +// + +target t_rmdebug_app9.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_app.cpp +source d_rmdebugthreadasm2.cia + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +library euser.lib hal.lib + +uid 0x0 0x0 +capability none + +always_build_as_arm +pagedcode + +DEBUGGABLE + +SMPSAFE \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_dll.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_dll.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,38 @@ +// 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: +// +// + +ALWAYS_BUILD_AS_ARM + +target t_rmdebug_dll.dll +targettype dll + +DEFFILE ../../~/t_rmdebug_dll.def + +sourcepath ../debug_targets + +source t_rmdebug_dll.cpp + +library euser.lib + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +capability PowerMgmt AllFiles ReadUserData + +UID 0x0 0x0 +SECUREID 0x0 +VENDORID 0x70000001 + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_multi_agent.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_multi_agent.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,41 @@ +// Copyright (c) 2006-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: +// Application that tests the ability of the run mode debug component +// to debug multiple targets +// +// + +targettype exe +target t_rmdebug_multi_agent.exe + +library euser.lib hal.lib + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +userinclude ../debug_targets +userinclude ../common +userinclude ../multi_agent_tests + +sourcepath ../multi_agent_tests +source t_multi_agent.cpp t_agent_eventhandler.cpp + +UID 0x0 0x4321bbbc +SECUREID 0x1234aaab +VENDORID 0x70000001 + +DEBUGGABLE + +macro NO_DEBUGTOKEN + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_multi_target.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_multi_target.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,46 @@ +// Copyright (c) 2006-2010 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: +// Application that tests the ability of the run mode debug component +// to debug several targets +// +// + +// This is an RTest configured to run on Sirocco, hence the testexecuteutils linked in lib below. + +ALWAYS_BUILD_AS_ARM + +targettype exe +target t_rmdebug_multi_target.exe + +library euser.lib hal.lib +library testexecuteutils.lib // for Sirocco + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +userinclude ../debug_targets +userinclude ../common +userinclude ../multi_target_tests + +sourcepath ../multi_target_tests +source t_multi_target.cpp + +UID 0x0 0x4321bbbc +SECUREID 0x1234aaab +VENDORID 0x70000001 + +DEBUGGABLE + +macro NO_DEBUGTOKEN + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_performance_allcapstoken.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_performance_allcapstoken.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// Copyright (c) 2010 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: +// +// + +ALWAYS_BUILD_AS_ARM + +target OEMDebug_102831E5.exe +targettype exe + +sourcepath ../performance_test + +source t_rmdebug_performance_oemtoken.cpp + +library euser.lib + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +capability All + +UID 0x0 0x0 +SECUREID 0x0 +VENDORID 0x70000001 + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security0.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security0.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,36 @@ +// Copyright (c) 2006-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: +// +// + +ALWAYS_BUILD_AS_ARM + +target t_rmdebug_security0.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_security.cpp + +library euser.lib hal.lib + +SYMBIAN_BASE_SYSTEMINCLUDE(nkern) +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +UID 0x100039CE 0xbaaaf00d +SECUREID 0x101F7159 +VENDORID 0x70000001 + +DEBUGGABLE + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security1.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security1.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,35 @@ +// Copyright (c) 2006-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: +// +// + +ALWAYS_BUILD_AS_ARM + +target t_rmdebug_security1.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_security.cpp + +library euser.lib hal.lib + +SYMBIAN_BASE_SYSTEMINCLUDE(nkern) +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +UID 0x100039CE 0xdeadbaaa +SECUREID 0x101F7159 +VENDORID 0x70000001 + + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security2.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security2.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,37 @@ +// Copyright (c) 2006-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: +// +// + +ALWAYS_BUILD_AS_ARM + +target t_rmdebug_security2.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_security.cpp + +library euser.lib hal.lib + +SYMBIAN_BASE_SYSTEMINCLUDE(nkern) +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +capability AllFiles + +UID 0x100039CE 0xdeadbaaa +SECUREID 0x101F7159 +VENDORID 0x70000001 + + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security3.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_security3.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,37 @@ +// Copyright (c) 2006-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: +// +// + +ALWAYS_BUILD_AS_ARM + +target t_rmdebug_security3.exe +targettype exe + +sourcepath ../debug_targets +source t_rmdebug_security.cpp + +library euser.lib hal.lib + +SYMBIAN_BASE_SYSTEMINCLUDE(nkern) +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +capability TCB AllFiles NetworkControl + +UID 0x100039CE 0xdeadbaaa +SECUREID 0x101F7159 +VENDORID 0x70000001 + + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_target_launcher.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_target_launcher.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,38 @@ +// Copyright (c) 2006-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: +// Application that test the ability of the run mode debug component +// to handle several target applications +// +// + +target t_rmdebug_target_launcher.exe +targettype exe + +library euser.lib + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + +userinclude ../common +sourcepath ../common +source t_target_launcher.cpp + +UID 0x0 0x4321bbbd +SECUREID 0x1234aaac +VENDORID 0x70000001 + +DEBUGGABLE + +macro NO_DEBUGTOKEN + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_tests.iby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/group/t_rmdebug_tests.iby Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,63 @@ +// Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// Run Mode Debug Tests ROM include file + + +file=ABI_DIR\BUILD_DIR\t_rmdebug_app.exe Sys\Bin\t_rmdebug_app.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app1.exe Sys\Bin\t_rmdebug_app1.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app2.exe Sys\Bin\t_rmdebug_app2.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app3.exe Sys\Bin\t_rmdebug_app3.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app4.exe Sys\Bin\t_rmdebug_app4.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app5.exe Sys\Bin\t_rmdebug_app5.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app6.exe Sys\Bin\t_rmdebug_app6.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app7.exe Sys\Bin\t_rmdebug_app7.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app8.exe Sys\Bin\t_rmdebug_app8.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app9.exe Sys\Bin\t_rmdebug_app9.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_app10.exe Sys\Bin\t_rmdebug_app10.exe + +file=ABI_DIR\BUILD_DIR\t_rmdebug_dll.dll Sys\Bin\t_rmdebug_dll.dll + +file=ABI_DIR\BUILD_DIR\t_rmdebug_security0.exe Sys\Bin\t_rmdebug_security0.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_security1.exe Sys\Bin\t_rmdebug_security1.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_security2.exe Sys\Bin\t_rmdebug_security2.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_security3.exe Sys\Bin\t_rmdebug_security3.exe + +// This script wraps RTests as TEF3 tests. +data=DATAZ_\scripts\tef_execute_rtests.script scripts\tef_execute_rtests.script + + +//No token required +file=ABI_DIR\BUILD_DIR\t_rmdebug2.exe Sys\Bin\t_rmdebug2.exe + +//SOMECAPS_DEBUGTOKEN +file=ABI_DIR\BUILD_DIR\t_rmdebug2_oem.exe Sys\Bin\t_rmdebug2_oem.exe +file=ABI_DIR\BUILD_DIR\OEMDebug_F123ABCD.exe Sys\Bin\OEMDebug_F123ABCD.exe + +//FEWCAPS_DEBUGTOKEN +file=ABI_DIR\BUILD_DIR\t_rmdebug2_oem2.exe Sys\Bin\t_rmdebug2_oem2.exe +file=ABI_DIR\BUILD_DIR\OEMDebug_F1234567.exe Sys\Bin\OEMDebug_F1234567.exe + +//ALLCAPS_DEBUGTOKEN +file=ABI_DIR\BUILD_DIR\t_rmdebug2_allcaps.exe Sys\Bin\t_rmdebug2_allcaps.exe +file=ABI_DIR\BUILD_DIR\OEMDebug_F123ABCE.exe Sys\Bin\OEMDebug_F123ABCE.exe + +file=ABI_DIR\BUILD_DIR\t_rmdebug_target_launcher.exe Sys\Bin\t_rmdebug_target_launcher.exe +file=ABI_DIR\BUILD_DIR\t_rmdebug_multi_target.exe Sys\Bin\t_rmdebug_multi_target.exe + +file=ABI_DIR\BUILD_DIR\t_rmdebug_multi_agent.exe Sys\Bin\t_rmdebug_multi_agent.exe +file=ABI_DIR\BUILD_DIR\t_multi_agent_launcher.exe Sys\Bin\t_multi_agent_launcher.exe + +//PERFORMANCE TEST DEBUGTOKEN +file=ABI_DIR\BUILD_DIR\OEMDebug_102831E5.exe Sys\Bin\OEMDebug_102831E5.exe +file=ABI_DIR\BUILD_DIR\t_performance_test.exe Sys\Bin\t_performance_test.exe diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_agent_eventhandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_agent_eventhandler.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,124 @@ +// Copyright (c) 2007-2010 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: +// Implements the handling of run mode events for a particular target executable +// + +#include +#include +#include + +#include "t_rmdebug_app.h" +#include "t_agent_eventhandler.h" +#include "t_multi_agent.h" +#include "t_debug_logging.h" + +using namespace Debug; + +CAgentAsyncEvent::CAgentAsyncEvent(CMultiAgent& aDriver, const TDesC& aExeName, const TDesC& aExeConfig): + CActive(EPriorityStandard), iDriver(aDriver) + { + } + +CAgentAsyncEvent* CAgentAsyncEvent::NewLC(CMultiAgent& aDriver, const TDesC& aExeName, const TDesC& aExeConfig) + { + CAgentAsyncEvent* self = new(ELeave) CAgentAsyncEvent(aDriver, aExeName, aExeConfig); + CleanupStack::PushL(self); + self->ConstructL(aExeName, aExeConfig); + return self; + } + +CAgentAsyncEvent* CAgentAsyncEvent::NewL(CMultiAgent& aDriver, const TDesC& aExeName, const TDesC& aExeConfig) + { + CAgentAsyncEvent* self = CAgentAsyncEvent::NewLC(aDriver, aExeName, aExeConfig); + CleanupStack::Pop(); // self + return self; + } + +void CAgentAsyncEvent::ConstructL(const TDesC& aExeName, const TDesC& aExeConfig) + { + iExeName.CreateL(aExeName); + iExeConfig.CreateL(aExeConfig); + CActiveScheduler::Add(this); + } + +CAgentAsyncEvent::~CAgentAsyncEvent() + { + LOG_MSG2("~CAgentAsyncEvent(), this = 0x%08x", this); + + iSEventInfo.iEventInfoBuf.Delete(0, sizeof(TEventInfo)); + iExeName.Close(); + iExeConfig.Close(); + iProc.Close(); + Cancel(); // Cancel any request, if outstanding + } + +/* + * Issue request to DSS and notify the active scheduler + */ +void CAgentAsyncEvent::Watch() + { + LOG_MSG2("ENTER: CAgentAsyncEvent::Watch, this = 0x%08x", this); + iDriver.DebugDriver().GetEvent(GetExecutable(), iStatus, iSEventInfo.iEventInfoBuf); + + if (!IsActive()) + { + LOG_MSG("CAgentAsyncEvent::Watch(): SetActive()"); + SetActive(); + } + + LOG_MSG("EXIT: CAgentAsyncEvent::Watch"); + } + +void CAgentAsyncEvent::RunL() + { + LOG_MSG4("ENTER: CAgentAsyncEvent::RunL iDebugType=%d, iStatus.Int() %d, this 0x%x08", + iSEventInfo.iEventInfo.iEventType, iStatus.Int(), this); + + LOG_MSG2("%S", &TPtr8((TUint8*)GetExecutable().Ptr(), 2*GetExecutable().Length(), 2*GetExecutable().Length())); + iDriver.HandleEvent(iSEventInfo.iEventInfo); + + LOG_MSG2("iDriver.GetNumApps() %d: ", iDriver.GetNumApps()); + LOG_MSG2("iDriver.iLaunchCompleted %d: ", iDriver.GetLaunchCompleted()); + + if (iDriver.GetLaunchCompleted() < iDriver.GetNumApps()) + { + // Do not call Watch() if target has run to completion but test is still on going + if (iSEventInfo.iEventInfo.iEventType != EEventsRemoveProcess) + { + LOG_MSG("CAgentAsyncEvent::RunL Setting Watch()"); + Watch(); + } + } + else + { + // Stop event handling for all targets + LOG_MSG("CAgentAsyncEvent::RunL CActiveScheduler::Stop() & Cancel"); + CActiveScheduler::Stop(); + } + + LOG_MSG2("EXIT: CAgentAsyncEvent::RunL", KNullDesC); + } + +void CAgentAsyncEvent::DoCancel() + { + LOG_MSG("CAgentAsyncEvent::DoCancel"); + } + +TInt CAgentAsyncEvent::RunError(TInt aError) + { + LOG_MSG3(" RunL() has left with error %d, this 0x%08X", aError, this); + return aError; + // Can we handle this error? Not at the moment! + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_agent_eventhandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_agent_eventhandler.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,90 @@ +// Copyright (c) 2007-2010 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: +// Definitions for event handling via the DSS and target specific information +// +// + +#ifndef RMDEBUG_AGENT_EVENTHANDLER_H +#define RMDEBUG_AGENT_EVENTHANDLER_H + +#include "t_multi_agent.h" + +using namespace Debug; + +class CMultiAgent; + +/** + Class for gathering event data from the run-mode driver + */ +class TAgentEventInfo +{ +public: + TAgentEventInfo() : + iEventInfoBuf((TUint8*)&iEventInfo, sizeof(TEventInfo), sizeof(TEventInfo)) + { + } + +public: + // This is the underlying class for event interaction with the Run Mode debug API + TEventInfo iEventInfo; + + // A convenience handle for iEventInfo used across the Debug::GetEvent() method + TPtr8 iEventInfoBuf; +}; + +/** + Active object class used to trap asynchronous events + Also, contains target specific parameters + */ +class CAgentAsyncEvent : public CActive + { +public: + // Close buffers and Cancel and destroy + ~CAgentAsyncEvent(); + + // Two-phased constructor + static CAgentAsyncEvent* NewLC(CMultiAgent& aDriver, const TDesC& aExeName, const TDesC& aExeConfig); + + // Two-phased constructor + static CAgentAsyncEvent* NewL(CMultiAgent& aDriver, const TDesC& aExeName, const TDesC& aExeConfig); + + // set up ASP and issue another request + void Watch(); + + TDesC& GetExecutable() { return iExeName; } + TDesC& GetExeConfig() { return iExeConfig; } + RProcess& GetProcHandle() { return iProc; } + +protected: + // from CActive + virtual void RunL(); + virtual void DoCancel(); + virtual TInt RunError(TInt aError); + +private: + CAgentAsyncEvent(CMultiAgent& aDriver, const TDesC& aExeName, const TDesC& aExeConfig); + void ConstructL(const TDesC& aExeName, const TDesC& aExeConfig); + +private: + RBuf iExeName; + RBuf iExeConfig; + RProcess iProc; + + CMultiAgent& iDriver; + TAgentEventInfo iSEventInfo; + }; + +#endif // RMDEBUG_AGENT_EVENTHANDLER_H + + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,434 @@ +// Copyright (c) 2007-2010 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: +// Tests the run mode debug device component by launching multiple targets +// on different CPUs. On a single core the targets run on the same CPU. +// + +#include +#include +#include +#include +#include +#include + + +#include "t_rmdebug_app.h" +#include "t_multi_agent.h" +#include "t_agent_eventhandler.h" +#include "t_debug_logging.h" + +const TVersion securityServerVersion(0,1,1); + +/** + * First phase constructor + */ +CMultiAgent* CMultiAgent::NewL() + { + CMultiAgent* self = new(ELeave) CMultiAgent(); + self->ConstructL(); + return self; + } + +/** + * Destructor + */ +CMultiAgent::~CMultiAgent() + { + LOG_MSG("~CMultiTargetAgent\n"); + iServSession.Close(); + } + +/** + * Constructor + */ +CMultiAgent::CMultiAgent() + { + } + +/** + * Second phase constructor + */ +void CMultiAgent::ConstructL() + { + } + +/** + Parse the command line, set agent cpu affinity and call main test function + */ +void CMultiAgent::ClientAppL() + { + LOG_MSG("ENTER: CMultiTargetAgent::ClientAppL"); + + iNumApps = KNumApps; + iAgentCpuNo = KAgentCpu; + iTargetNameOffset = KTargetOffset; + + TInt argc = User::CommandLineLength(); + HBufC* commandLine = NULL; + LOG_MSG2(">Launcher Process() argc=%d", argc); + + if(argc) + { + commandLine = HBufC::NewLC(argc); + TPtr commandLineBuffer = commandLine->Des(); + User::CommandLine(commandLineBuffer); + + RBuf printCommandLine; + CleanupClosePushL(printCommandLine); + printCommandLine.CreateL(commandLine->Des().Length()); + printCommandLine.Copy(commandLine->Des()); + printCommandLine.Collapse(); + LOG_MSG2(">command line = %S", &printCommandLine ); + CleanupStack::PopAndDestroy( &printCommandLine ); + + // create a lexer and read through the command line + TLex lex(*commandLine); + + while (!lex.Eos()) + { + // only look for options with first character '-' + if (lex.Get() == '-') + { + TChar arg = lex.Get(); + + switch ( arg ) + { + case 'n': + lex.Val( iNumApps ); + LOG_MSG2("parsed numApps as %d", iNumApps); + break; + + case 'a': + lex.Val( iAgentCpuNo ); + LOG_MSG2("parsed agentCpuNo as %d", iAgentCpuNo); + break; + + case 'o': + lex.Val( iTargetNameOffset ); + LOG_MSG2("parsed iTargetNameOffset as %d", iTargetNameOffset); + break; + + default: + LOG_MSG("Bad argument from user"); + break; + } + } + } + } + // Create active scheduler (to run active objects) + CActiveScheduler* scheduler = new (ELeave) CActiveScheduler(); + CleanupStack::PushL(scheduler); + CActiveScheduler::Install(scheduler); + + if (iAgentCpuNo) + { + LOG_MSG2("CMultiAgent::ClientAppL() - setting agent to cpu %d", iAgentCpuNo); + UserSvr::HalFunction(EHalGroupKernel, EKernelHalLockThreadToCpu, (TAny *)iAgentCpuNo, 0); + } + + TInt err = iServSession.Connect(securityServerVersion); + + if (err != KErrNone) + { + User::Panic(_L("Can't open server session"), err); + } + + StartTest(); + + // Note: below is a workaround to overcome an issue with RTest server crashing + // when writing to the windows console from different agents (on different CPUs + // at the same time). To overcome this we signal the launcher using a global + // semaphore to indicate a RTest complete instead + RSemaphore launchSemaphore; + CleanupClosePushL(launchSemaphore); + + TFindSemaphore launchSemFinder(KLaunchSemaphoreSearchString); + TFullName semaphoreResult; + TInt ret = launchSemFinder.Next(semaphoreResult); + LOG_MSG3( "> Find Launch Semaphote.Next ret=%d, %lS", ret, &semaphoreResult); + + ret = launchSemaphore.OpenGlobal(semaphoreResult); + LOG_MSG2( ">OpenGlobal semaphore ret=%d", ret ); + + LOG_MSG( ">Signalling semaphore" ); + launchSemaphore.Signal(); + CleanupStack::PopAndDestroy(&launchSemaphore); // launchSemaphore + + // Delete active scheduler + CleanupStack::PopAndDestroy(scheduler); + + if (commandLine) + CleanupStack::PopAndDestroy(commandLine); + + LOG_MSG( "EXIT: CMultiTargetAgent::ClientAppL"); + } + +/** + Launch a process + @param aProcess the RProcess object used to create the process + @param aFileName file name of the executable used to create the process + @return KErrNone on success, or one of the other system wide error codes + */ +TInt CMultiAgent::LaunchProcess(RProcess& aProcess, const TDesC& aExeName, const TDesC& aCommandLine) + { + LOG_MSG( "ENTER: CMultiAgent::LaunchProcess"); + LOG_MSG2("%S", &TPtr8((TUint8*)aExeName.Ptr(), 2*aExeName.Length(), 2*aExeName.Length())); + + // wait for 0.5 seconds due to issue with creating several processes in smp quickly + User::After(500000); + + TInt err = aProcess.Create( aExeName, aCommandLine ); + LOG_MSG2( "CMultiAgent::LaunchProcess, aProcess.Create err = %d", err); + + // check that there was no error raised + if (err != KErrNone) + return err; + + // rendezvous with process + TRequestStatus status = KRequestPending; + aProcess.Rendezvous(status); + + if (KRequestPending != status.Int()) + { + // startup failed so kill the process + LOG_MSG2( "> RProcess Rendezvous() failed with %d. Killing process", status.Int() ); + aProcess.Kill(KErrNone); + LOG_MSG( "EXIT: CMultiAgent::LaunchProcess"); + return status.Int(); + } + else + { + // start the test target + aProcess.Resume(); + User::WaitForRequest(status); + + LOG_MSG2( "> CMultiAgent::LaunchProcess: RProcess Resume() Rendezvous successful %d: ", status.Int() ); + + if(KErrNone != status.Int()) + { + LOG_MSG2( "> RProcess Resume() failed with %d. Killing process", status.Int() ); + aProcess.Kill(KErrNone); + } + + LOG_MSG( "EXIT: CMultiAgent::LaunchProcess"); + return status.Int(); + } + } + +/** + Handle Event + @param aEventInfo object containing event information from the DSS + */ +void CMultiAgent::HandleEvent(TEventInfo& aEventInfo) + { + LOG_MSG( "ENTER: CMultiAgent::HandleEvent" ); + TInt ret = KErrNone; + const TInt idValid = 1; + + switch ( aEventInfo.iEventType ) + { + case EEventsAddProcess: + { + LOG_MSG(">> EEventsAddProcess"); + TPtrC8 exeNamePtr8(aEventInfo.iAddProcessInfo.iFileName, aEventInfo.iAddProcessInfo.iFileNameLength); + + RBuf8 exeName8; + CleanupClosePushL(exeName8); + exeName8.CreateL(exeNamePtr8); + LOG_MSG2("From event: exeName8=%S", &exeName8); + CleanupStack::PopAndDestroy(&exeName8); + LOG_MSG("Testing if event process id is valid"); + + LOG_MSG2("Got aEventInfo.iProcessId=%d", I64LOW( aEventInfo.iProcessId)); + __ASSERT_ALWAYS((aEventInfo.iProcessIdValid==idValid), User::Panic(_L("ProcessId Invalid"), aEventInfo.iProcessIdValid)); + + RProcess targetProc; + ret = targetProc.Open(TProcessId(aEventInfo.iProcessId)); + LOG_MSG2("RProcess open ret=%d", ret); + targetProc.Close(); + + __ASSERT_ALWAYS((ret == KErrNone), User::Panic(_L("ProcessId Invalid"), aEventInfo.iProcessIdValid)); + break; + } + + case EEventsStartThread: + { + LOG_MSG(">> EEventsStartThread"); + TPtrC8 exeNamePtr8(aEventInfo.iStartThreadInfo.iFileName, aEventInfo.iStartThreadInfo.iFileNameLength); + RBuf8 exe8Name; + CleanupClosePushL(exe8Name); + exe8Name.CreateL(exeNamePtr8); + LOG_MSG2("From event: exeName8=%S", &exe8Name); + CleanupStack::PopAndDestroy(&exe8Name); + + LOG_MSG("Testing if event process id is valid" ); + + __ASSERT_ALWAYS((aEventInfo.iProcessIdValid==idValid), User::Panic(_L("ProcessId Invalid"), aEventInfo.iProcessIdValid)); + + LOG_MSG2("Got aEventInfo.iProcessId=%d", I64LOW(aEventInfo.iProcessId)); + + LOG_MSG("Testing if event thread id is valid"); + + __ASSERT_ALWAYS((aEventInfo.iThreadIdValid==idValid), User::Panic(_L("ThreadId Invalid"), aEventInfo.iThreadIdValid)); + + LOG_MSG2("Got aEventInfo.iThreadId=%d", I64LOW(aEventInfo.iThreadId)); + break; + } + + case EEventsUserTrace: + { + LOG_MSG(">> EEventsUserTrace"); + break; + } + + case EEventsRemoveProcess: + { + LOG_MSG( ">> EEventsRemoveProcess"); + iLaunchCompleted++; + break; + } + + default: + { + LOG_MSG( ">> Unknown event - probably due to DSS busy?"); + break; + } + } + + LOG_MSG("EXIT: CMultiAgent::HandleEvent"); + } + +/** + * Main test function which launches several targets and stresses the DSS + */ +TInt CMultiAgent::StartTest() + { + LOG_MSG("ENTER: CMultiTargetAgent::StartTest"); + + for( TInt i = 0; i < iNumApps; i++ ) + { + RBuf targetName; + RBuf launcherOptions; + + CleanupClosePushL(targetName); + CleanupClosePushL(launcherOptions); + + targetName.CreateL( KTargetExe().Length() + 2 ); + targetName.Format( KTargetExe(), i + iTargetNameOffset + 1 ); + + LOG_MSG2("App %d: ", i+1); + LOG_MSG2("%S", &TPtr8((TUint8*)targetName.Ptr(), 2*targetName.Length(), 2*targetName.Length())); + + launcherOptions.CreateL( KTargetOptions().Length() + 2 ); + launcherOptions.Format( KTargetOptions(), (TUint)ENormalExit, (i+1) ); + + LOG_MSG( "AppOptions : "); + LOG_MSG2("%S", &TPtr8((TUint8*)launcherOptions.Ptr(), 2*launcherOptions.Length(), 2*launcherOptions.Length())); + + // Add each test target to array + iTargetList.AppendL(CAgentAsyncEvent::NewL(*this, targetName, launcherOptions)); + CleanupStack::PopAndDestroy(2, &targetName ); + } + + iLaunchCompleted = 0; + TInt err = KErrNone; + + for (TInt i = 0; i < iNumApps; i++) + { + // Attach to process non-passively + LOG_MSG2( ">AttachExecutable app %d ", i + iTargetNameOffset + 1 ); + LOG_MSG2("%S", &TPtr8((TUint8*)iTargetList[i]->GetExecutable().Ptr(), 2*iTargetList[i]->GetExecutable().Length(), + 2*iTargetList[i]->GetExecutable().Length())); + + err = iServSession.AttachExecutable( iTargetList[i]->GetExecutable(), EFalse); + __ASSERT_ALWAYS((err == KErrNone), User::Panic(_L("DSS Attach failed"), err)); + + // Continue on interested event actions + LOG_MSG2( ">SetEventAction app %d, EEventsStartThread EAcionContinue", i + iTargetNameOffset + 1); + + err = iServSession.SetEventAction( iTargetList[i]->GetExecutable(), EEventsStartThread, EActionContinue); + __ASSERT_ALWAYS((err==KErrNone), User::Panic(_L("SetEventAction Error"), err)); + + LOG_MSG2(">SetEventAction app %d, EEventsAddProcess EActionContinue", i + iTargetNameOffset + 1); + err = iServSession.SetEventAction( iTargetList[i]->GetExecutable(), EEventsAddProcess, EActionContinue); + __ASSERT_ALWAYS((err==KErrNone), User::Panic(_L("SetEventAction Error"), err)); + + LOG_MSG2(">SetEventAction app %d, EEventsUserTrace EActionContinue", i + iTargetNameOffset + 1); + err = iServSession.SetEventAction( iTargetList[i]->GetExecutable(), EEventsUserTrace, EActionContinue); + __ASSERT_ALWAYS((err==KErrNone), User::Panic(_L("SetEventAction Error"), err)); + + LOG_MSG2(">SetEventAction app %d, EEventsRemoveProcess EActionContinue", i + iTargetNameOffset + 1); + err = iServSession.SetEventAction( iTargetList[i]->GetExecutable(), EEventsRemoveProcess, EActionContinue); + __ASSERT_ALWAYS((err==KErrNone), User::Panic(_L("SetEventAction Error"), err)); + + // Add target object to active schedular + iTargetList[i]->Watch(); + } + + for (TInt i= 0; i< iNumApps; i++) + { + LOG_MSG( ">Calling LaunchProcess function"); + err = LaunchProcess(iTargetList[i]->GetProcHandle(), iTargetList[i]->GetExecutable(), iTargetList[i]->GetExeConfig()); + __ASSERT_ALWAYS((err==KErrNone), User::Panic(_L("LaunchProcess failed"), err)); + } + + LOG_MSG( ">CActiveScheduler::Start()"); + CActiveScheduler::Start(); + + for (TInt i= 0; i < iNumApps; i++) + { + // Now detach again + LOG_MSG( "Before iServSession.DetachExecutable" ); + err = iServSession.DetachExecutable(iTargetList[i]->GetExecutable()); + __ASSERT_ALWAYS((err==KErrNone), User::Panic(_L("DetachExecutable failed"), err)); + } + + // Free all the memory + iTargetList.ResetAndDestroy(); + LOG_MSG( "EXIT: CMultiTargetAgent::StartTest" ); + + return KErrNone; + } + +/** + * Entry point for run mode debug driver test + */ +GLDEF_C TInt E32Main() + { + LOG_MSG( "ENTER: Multi_agent E32Main "); + __UHEAP_MARK; + + TInt ret = KErrNone; + RProcess::Rendezvous(KErrNone); + + CTrapCleanup* trap = CTrapCleanup::New(); + + if (!trap) + return KErrNoMemory; + + CMultiAgent *runModeAgent = CMultiAgent::NewL(); + + if (runModeAgent != NULL) + { + TRAP(ret,runModeAgent->ClientAppL()); + LOG_MSG2( "ClientAppL returned %d", ret ); + delete runModeAgent; + } + + delete trap; + __UHEAP_MARKEND; + LOG_MSG( "EXIT: Multi_agent E32Main "); + return ret; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,110 @@ +// Copyright (c) 2006-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: +// Definitions for the run mode debug tests +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef RMDEBUG_MULTI_AGENT_H +#define RMDEBUG_MULTI_AGENT_H + +#include +#include +#include + +using namespace Debug; + +_LIT(KLaunchSemaphoreName, "t_rmdebug_launch_semaphore"); +_LIT(KLaunchSemaphoreSearchString, "t_rmdebug_launch_semaphore*"); + +// Currently the targets are instances of t_rmdebug_app.exe +_LIT(KTargetExe,"z:\\sys\\bin\\t_rmdebug_app%d.exe"); + +_LIT(KTargetOptions,"-f%d -a%d"); + +// If changing this, make sure there are enough apps built/in the rom +const TInt KNumApps = 5; + +// Default CPU execution for Agent +const TInt KAgentCpu = 0; + +// Workaround to ensure we have the same agent binary when running multiple agents +const TInt KTargetOffset = 0; + +class CAgentAsyncEvent; + +/** + @Class CRunModeAgent + + The basic run mode agent + */ +class CMultiAgent : public CBase + { + public: + static CMultiAgent* NewL(); + ~CMultiAgent(); + void ClientAppL(); + RSecuritySvrSession& DebugDriver() { return iServSession; }; + void HandleEvent(TEventInfo& aSEventInfo); + + public: + TInt GetLaunchCompleted() const { return iLaunchCompleted; } + TInt GetNumApps() const { return iNumApps; } + TInt GetTargetOffset() const { return iTargetNameOffset; } + + private: + CMultiAgent(); + void ConstructL(); + TInt StartTest(); + TInt LaunchProcess(RProcess& aProcess, const TDesC& aExeName, const TDesC& aCommandLine); + + private: + + /** + * CPU agent executes on; by default this is 0 + */ + TInt iAgentCpuNo; + + /* + * Offset for running multiple targets using the same agent + */ + TInt iTargetNameOffset; + + /** + * Number of applications/targets per agent + */ + TInt iNumApps; + + /** + * Flag used for terminating the event handling for a target + */ + TInt iLaunchCompleted; + + /* + * Handle to DSS + */ + RSecuritySvrSession iServSession; + + /** + * Array to target parameters required by the agent + */ + RPointerArray iTargetList; + }; + +#endif // RMDEBUG_MULTI_AGENT_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent_launcher.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent_launcher.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,229 @@ +// 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: +// Helper app to launch debug targets +// +// + +#include "t_multi_agent_launcher.h" + +#include "t_debug_logging.h" + +/** + * Launch a process + * @param aProcess the RProcess object used for creating the process + * @param aExeName the name of the executable to run + * @param aCommandLine command line parameters to pass when creating the process + * @return KErrNone on success, or one of the other system wide error codes + */ +TInt LaunchProcess(RProcess& aProcess, TDesC& aExeName, TDesC& aCommandLine ) + { + LOG_MSG("ENTER: t_multi_agent_launcher: launchProcess"); + + LOG_MSG2("aExeName %S ", &TPtr8((TUint8*)aExeName.Ptr(), 2*aExeName.Length(), 2*aExeName.Length())); + LOG_MSG2("aCommandLine %S", &TPtr8((TUint8*)aCommandLine.Ptr(), 2*aCommandLine.Length(), 2*aCommandLine.Length())); + + TInt err = aProcess.Create( aExeName, aCommandLine ); + LOG_MSG2("t_multi_agent_launcher launchProcess, aProcess.Create err = %d", err); + + // check that there was no error raised + if(err != KErrNone) + { + return err; + } + + // rendezvous with process + TRequestStatus status = KRequestPending; + aProcess.Rendezvous(status); + + if(KRequestPending != status.Int()) + { + // startup failed so kill the process + LOG_MSG2("t_multi_agent_launcher: launchProcess: RProcess Rendezvous() failed with %d. Killing process", status.Int()); + aProcess.Kill(KErrNone); + return status.Int(); + } + else + { + aProcess.Resume(); + User::WaitForRequest(status); + + LOG_MSG2("t_multi_agent_launcher: launchProcess: RProcess Resume() Rendezvous successful %d: ", status.Int()); + + if(KErrNone != status.Int()) + { + LOG_MSG2("t_multi_agent_launcher: RProcess Resume() failed with %d. Killing process", status.Int()); + aProcess.Kill(KErrNone); + } + + LOG_MSG("EXIT: t_multi_agent_launcher launchProcess"); + return status.Int(); + } + } + +/** + * Read command line parameters and control the launching of the agents. + */ +void MainL() + { + LOG_MSG( "ENTER: t_multi_agent_launcher MainL()"); + + TInt ret = KErrNone; + TInt numAgents = KNumAgents; + TInt numTargets = KNumTargets; + TInt numTestRuns = KNumTestRuns; + + TInt argc = User::CommandLineLength(); + HBufC* commandLine = NULL; + LOG_MSG2("t_multi_agent_launcher: MainL(): argc=%d", argc); + + if(argc) + { + commandLine = HBufC::NewLC(argc); + TPtr commandLineBuffer = commandLine->Des(); + User::CommandLine(commandLineBuffer); + + RBuf printCommandLine; + CleanupClosePushL( printCommandLine ); + printCommandLine.CreateL( commandLine->Des().Length() ); + printCommandLine.Copy( commandLine->Des() ); + printCommandLine.Collapse(); + LOG_MSG2("t_multi_agent_launcher: command line = %S", &printCommandLine); + CleanupStack::PopAndDestroy( &printCommandLine ); + + // create a lexer and read through the command line + TLex lex(*commandLine); + while (!lex.Eos()) + { + // only look for options with first character '-' + if (lex.Get() == '-') + { + TChar arg = lex.Get(); + switch ( arg ) + { + case 'n': + lex.Val( numAgents ); + LOG_MSG2("t_multi_agent_launcher: parsed numAgents as %d", numAgents); + break; + case 'm': + lex.Val( numTargets ); + LOG_MSG2("t_multi_agent_launcher: parsed numTargets as %d", numTargets); + break; + case 't': + lex.Val( numTestRuns ); + LOG_MSG2("t_multi_agent_launcher: parsed numTestRuns as %d", numTestRuns); + break; + default: + LOG_MSG("t_multi_agent_launcher: unknown argument ignoring it"); + break; + } + } + } + } + + // Note: below is a workaround to overcome an issue with RTest server crashing + // when writing to the windows console from different agents (on different CPUs + // at the same time). To overcome this we get signaled by the agents when they have + // completed their tests so that we can do a RTest complete + RSemaphore launchSemaphore; + CleanupClosePushL(launchSemaphore); + ret = launchSemaphore.CreateGlobal(KLaunchSemaphoreName, 0); + LOG_MSG2( ">Target Launcher : RSemaphore.CreateGlobal ret %d", ret); + User::LeaveIfError( ret ); + + ret = launchSemaphore.OpenGlobal(KLaunchSemaphoreName); + LOG_MSG2( ">Target Launcher : RSemaphore.OpenGlobal ret %d", ret); + User::LeaveIfError( ret ); + + //Now launch the requested number of apps for the requested number of test runs + for( TInt j = 0; j < numTestRuns; j++ ) + { + for( TInt i = 0; i < numAgents; i++ ) + { + RBuf targetName; + targetName.CleanupClosePushL(); + targetName.CreateL(KAgentExe()); + + RProcess aProc; + CleanupClosePushL(aProc); + RBuf launcherOptions; + CleanupClosePushL(launcherOptions); + const TInt additionalWords = 2; + launcherOptions.CreateL( KAgentOptions().Length() + additionalWords ); + + // Apply offset: launcherOptions.Format( .., .., i * numTargets, ..) + // workaround to ensure we have the same binary for multiple agents. + // e.g. So if offset = 0, agent attaches to app1, app2, app3, app4, app5 + // if offset = 5, agent attached to app6, app7, app8, app9, app10 etc. + // Note: apps need to be in rom otherwise the agent will fail on an assert + // (with KErrNotFound) + launcherOptions.Format( KAgentOptions(), (TUint)numTargets, i * numTargets, 0); + + ret = LaunchProcess( aProc, targetName, launcherOptions ); + CleanupStack::PopAndDestroy(3,&targetName); + User::LeaveIfError(ret); + } + } + + // Wait for all agents to do their testing before checking the semaphore + User::After(12000000); + + LOG_MSG( ">Target Launcher: Semaphore wait"); + + for (TInt i = 0; i < numAgents; i ++) + { + //We need this delay just in case an agent crashes and never signals the sem + ret = launchSemaphore.Wait(100000); + if( ret != KErrNone ) + { + LOG_MSG3("launchSemaphore.Wait ret %d for agent %d", ret, i); + break; + } + } + + LOG_MSG2( "testing for Semaphore ret %d", ret); + + // We only want to have one RTest instance at any one time since otherwise RTest can panic + RTest test(_L("T_MULTI_AGENT_LAUNCHER")); + test.Start(_L("t_multi_agent_launcher Check for agents finishing correctly")); + test(ret == KErrNone); + test.End(); + test.Close(); + + CleanupStack::PopAndDestroy(&launchSemaphore); // launchSemaphore + + if( commandLine ) + CleanupStack::PopAndDestroy(commandLine); + + LOG_MSG("EXIT: t_multi_agent_launcher MainL()"); + } + +GLDEF_C TInt E32Main() + { + LOG_MSG("ENTER: Multi_agent_launcher E32Main()"); + __UHEAP_MARK; + + CTrapCleanup* trap = CTrapCleanup::New(); + if (!trap) + return KErrNoMemory; + + TRAPD(err, MainL()); + LOG_MSG2("Multi_agent_launcher: returning from MainL(), err = %d", err); + + delete trap; + LOG_MSG("EXIT: Multi_agent_launcher E32Main()"); + __UHEAP_MARKEND; + + return err; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent_launcher.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_agent_tests/t_multi_agent_launcher.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,45 @@ +// Copyright (c) 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: +// Definitions for agent launcher +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef RMDEBUG_MULTI_AGENT_LAUNCHER_H +#define RMDEBUG_MULTI_AGENT_LAUNCHER_H + +#include + +// Default test runs +const TInt KNumTestRuns = 1; + +// Default number of targets per agent +const TInt KNumTargets = 5; + +// Default number of agents, if changing this make sure there are enough apps being built +const TInt KNumAgents = 2; + +_LIT(KAgentExe,"z:\\sys\\bin\\t_rmdebug_multi_agent.exe"); +_LIT(KAgentOptions,"-n%d -o%d -a%d"); + +_LIT(KLaunchSemaphoreName, "t_rmdebug_launch_semaphore"); +_LIT(KLaunchSemaphoreSearchString, "t_rmdebug_launch_semaphore*"); + +#endif // RMDEBUG_MULTI_AGENT_LAUNCHER_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_target_tests/t_multi_target.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_target_tests/t_multi_target.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,405 @@ +// Copyright (c) 2006-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: +// Test the ability of the debug system to handle events from several debug targets +// +// + +#include +#include + +#include +#include + +#include "t_multi_target.h" +#include "t_target_launcher.h" +#include "t_rmdebug_app.h" + +#ifdef KERNEL_OOM_TESTING + #ifdef USER_OOM_TESTING + #error "Cannot define both KERNEL_OOM_TESTING and USER_OOM_TESTING" + #endif +#endif + + +using namespace Debug; + +const TVersion securityServerVersion(0,1,1); + +const TVersion testVersion(2,1,0); + +#ifdef NO_DEBUGTOKEN +LOCAL_D RTest test(_L("T_RMDEBUG_MULTI_TARGET")); +#endif + +#ifdef SOMECAPS_DEBUGTOKEN +LOCAL_D RTest test(_L("T_RMDEBUG_MULTI_TARGET_OEM")); +#endif + +#ifdef FEWCAPS_DEBUGTOKEN +LOCAL_D RTest test(_L("T_RMDEBUG_MULTI_TARGET_OEM2")); +#endif + + + +CMultiTargetAgent* CMultiTargetAgent::NewL() +// +// CMultiTargetAgent::NewL +// + { + CMultiTargetAgent* self = new(ELeave) CMultiTargetAgent(); + + self->ConstructL(); + + return self; + } + + +CMultiTargetAgent::~CMultiTargetAgent() +// +// CMultiTargetAgent destructor +// + { + RDebug::Printf("~CMultiTargetAgent\n"); + iServSession.Close(); + } + + +CMultiTargetAgent::CMultiTargetAgent() : + iEventPtr( (TUint8*)&iEventInfo, sizeof(TEventInfo) ) + { + } + + +void CMultiTargetAgent::ConstructL() +// +// CMultiTargetAgent::ConstructL +// + { + } + +/** + * Helper code for the stepping tests. Returns the number of nanokernel ticks in one second. + * + * @return Number of nanokernel ticks. 0 if unsuccesful. + */ +TInt CMultiTargetAgent::HelpTicksPerSecond(void) + { + TInt nanokernel_tick_period; + HAL::Get(HAL::ENanoTickPeriod, nanokernel_tick_period); + + ASSERT(nanokernel_tick_period != 0); + + static const TInt KOneMillion = 1000000; + + return KOneMillion/nanokernel_tick_period; + } + +void CMultiTargetAgent::ClientAppL() +// +// Performs each test in turn +// + { + test.Start(_L("ClientAppL")); + TInt err = iServSession.Connect(securityServerVersion); + if (err != KErrNone) + { + User::Panic(_L("Can't open server session"), err); + } + SetupDebugServerL(); + LaunchTargetsInOrderL(); + RDebug::Printf( "returning from CMultiTargetAgent::ClientAppL" ); + test.End(); + } + +/** + Launch a process + + @param aProcess The RProcess object to use to create the process + @param aExeName File name of the executable to create the process from + @param aCommandLine The command line to pass to the new process + @return KErrNone on success, or one of the other system wide error codes + */ +TInt CMultiTargetAgent::LaunchProcess(RProcess& aProcess, TDesC & aExeName, TDesC & aCommandLine ) + { + TInt err = aProcess.Create( aExeName, aCommandLine ); + if(err != KErrNone) + { + RDebug::Printf( "aProcess.Create ret %d", err); + return err; + } + + TRequestStatus status = KRequestPending; + aProcess.Rendezvous(status); + if(KRequestPending != status.Int()) + { + // startup failed so kill the process + aProcess.Kill(KErrNone); + return status.Int(); + } + else + { + // start up succeeded so resume the process + aProcess.Resume(); + // Give the process a chance to run + User::After( 500000 ); + return KErrNone; + } + } + +void CMultiTargetAgent::SetupDebugServerL() + { + RDebug::Printf( "CMultiTargetAgent::SetupDebugServerL" ); + test.Next(_L("SetupDebugServerL\n")); + iTargets.ReserveL( KNumApps ); + + RBuf targetName; + CleanupClosePushL( targetName ); + + for( TInt numApps = 0; numApps < KNumApps; numApps++ ) + { + iTargets.AppendL( targetName ); + RDebug::Printf( "Attach to DSS for app %d ", numApps ); + + iTargets[numApps].CreateL( KTargetExe().Length() + 2 ); + iTargets[numApps].Format( KTargetExe(), numApps+1 ); + + TInt ret = iServSession.AttachExecutable( iTargets[numApps], EFalse ); + test( ret == KErrNone ); + + RDebug::Printf( ">SetEventAction app %d, EEventsStartThread EActionSuspend", numApps ); + ret = iServSession.SetEventAction( iTargets[numApps], EEventsStartThread, EActionSuspend ); + test( ret == KErrNone ); + + RDebug::Printf( ">SetEventAction app %d, EEventsAddProcess EActionContinue", numApps ); + ret = iServSession.SetEventAction( iTargets[numApps], EEventsAddProcess, EActionContinue ); + test( ret == KErrNone ); + + RDebug::Printf( ">SetEventAction app %d, EEventsRemoveProcess EActionContinue", numApps ); + ret = iServSession.SetEventAction( iTargets[numApps], EEventsRemoveProcess, EActionContinue ); + test( ret == KErrNone ); + } + + CleanupStack::PopAndDestroy( &targetName ); // targetName + + } + + + +TInt CMultiTargetAgent::LaunchTargetsInOrderL() + { + RDebug::Printf( "CMultiTargetAgent::LaunchTargetsInOrderL" ); + + RBuf launcher; + CleanupClosePushL( launcher ); + launcher.CreateL( KLauncherExe() ); + + RBuf launcherOptions; + CleanupClosePushL( launcherOptions ); + launcherOptions.CreateL( KTargetOptions().Length() + 2 ); + launcherOptions.Format( KTargetOptions(), (TUint)ENormalExit ); + + RDebug::Printf( ">LaunchProcess()" ); + RProcess launcherProc; + CleanupClosePushL( launcherProc ); + + TInt ret = LaunchProcess( launcherProc, launcher, launcherOptions ); + RDebug::Printf( " Find Launch Semaphote.Next ret=%d, %lS", ret, &semaphoreResult ); + test( ret == KErrNone ); + + ret = launchSemaphore.OpenGlobal( semaphoreResult ); + RDebug::Printf( "> OpenGlobal semaphore ret=%d", ret ); + test( ret == KErrNone ); + + TBool thisLaunchCompleted; + + test.Next(_L("LaunchTargetsInOrderL\n")); + for( TInt numLaunches = KNumLaunches; numLaunches > 0; numLaunches-- ) + { + for( TInt numApps = KNumApps; numApps > 0; numApps-- ) + { + thisLaunchCompleted = EFalse; + // This will trigger the launcher app to launch the next target + RDebug::Printf( " >Semaphore.Signal app=%d, launch=%d", numApps, numLaunches); + launchSemaphore.Signal(); + + RBuf8 tgt8Name; + CleanupClosePushL( tgt8Name ); + + RBuf tgtCollapseName; + CleanupClosePushL( tgtCollapseName ); + + tgtCollapseName.CreateL( iTargets[numApps-1] ); + tgt8Name.CreateL( tgtCollapseName.Collapse() ); + + + while( ! thisLaunchCompleted ) + { + RDebug::Printf( ">GetEvent app %d for %S", numApps, &tgt8Name ); + iServSession.GetEvent( iTargets[numApps-1], iStatus, iEventPtr ); + + // Wait for the target to get started. + RDebug::Printf( " >Wait for event from target app=%d, launch=%d\n", numApps, numLaunches); + User::WaitForRequest( iStatus ); + RDebug::Printf( " Got iEventType =%d, app=%d", iEventInfo.iEventType, numApps ); + switch( iEventInfo.iEventType ) + { + case EEventsAddProcess: + { + RDebug::Printf( "Got EEventsAddProcess" ); + TPtrC8 exeNamePtr8( iEventInfo.iAddProcessInfo.iFileName, iEventInfo.iAddProcessInfo.iFileNameLength ); + + RBuf8 exeName8; + CleanupClosePushL( exeName8 ); + exeName8.CreateL( exeNamePtr8 ); + RDebug::Printf( " from event: exeName8=%S", &exeName8 ); + CleanupStack::PopAndDestroy( &exeName8 ); + + RBuf8 compareName8; + CleanupClosePushL( compareName8 ); + compareName8.CreateL( KTargetExeName().Length() + 10 ); + compareName8.Format( KTargetExeName(), numApps ); + RDebug::Printf( " comparing to: compareName8=%S", &compareName8 ); + + test( compareName8.CompareC( exeNamePtr8 ) == 0 ); + CleanupStack::PopAndDestroy( &compareName8 ); + + RDebug::Printf( "Testing if event process id is valid" ); + test( iEventInfo.iProcessIdValid ); + RDebug::Printf( "Got iEventInfo.iProcessId=%d", I64LOW( iEventInfo.iProcessId ) ); + + RProcess targetProc; + ret = targetProc.Open( TProcessId( iEventInfo.iProcessId ) ); + RDebug::Printf( "RProcess open ret=%d",ret ); + targetProc.Close(); + test( ret == KErrNone ); + + break; + }//EEventsAddProcess + + case EEventsStartThread: + { + RDebug::Printf( "Got EEventsStartThread" ); + + TPtrC8 exeNamePtr8( iEventInfo.iStartThreadInfo.iFileName, iEventInfo.iStartThreadInfo.iFileNameLength ); + RBuf8 exe8Name; + CleanupClosePushL( exe8Name ); + exe8Name.CreateL( exeNamePtr8 ); + RDebug::Printf( " from event: exeName8=%S", &exe8Name ); + CleanupStack::PopAndDestroy( &exe8Name ); + + test( tgt8Name.CompareC( exeNamePtr8 ) == 0 ); + + RDebug::Printf( "Testing if event process id is valid" ); + test( iEventInfo.iProcessIdValid ); + RDebug::Printf( "Got iEventInfo.iProcessId=%d", I64LOW( iEventInfo.iProcessId ) ); + + RDebug::Printf( "Testing if event thread id is valid" ); + test( iEventInfo.iThreadIdValid ); + RDebug::Printf( "Got iEventInfo.iThreadId=%d", I64LOW( iEventInfo.iThreadId ) ); + + RThread targetThread; + CleanupClosePushL( targetThread ); + + ret = targetThread.Open( TThreadId( iEventInfo.iThreadId ) ); + RDebug::Printf( "RThread open ret=%d", ret ); + test( ret == KErrNone ); + + test( iEventInfo.iThreadId == targetThread.Id() ); + + RDebug::Printf( "Resuming thread for app=%d, id=%d", numApps, I64LOW( targetThread.Id() )); + ret = iServSession.ResumeThread( iEventInfo.iThreadId ); + CleanupStack::PopAndDestroy( &targetThread ); + + test( ret == KErrNone ); + + ret = iServSession.ResumeThread( iEventInfo.iThreadId ); + break; + }//case EEventsStartThread + + case ( EEventsRemoveProcess ): + { + RDebug::Printf( "*** Got EEventsRemoveProcess. app%d has exited. Moving on to next app", numApps ); + thisLaunchCompleted = ETrue; + break; + } + + default : + RDebug::Printf( "Got unknown event" ); + test( EFalse ); + break; + } + }//while + + CleanupStack::PopAndDestroy( &tgtCollapseName ); // tgtCollapseName + CleanupStack::PopAndDestroy( &tgt8Name ); // tgt8Name + } + } + + launchSemaphore.Signal(); + + CleanupStack::PopAndDestroy( &launchSemaphore ); // launchSemaphore + + for( TInt i = iTargets.Count()-1; i>=0; i-- ) + { + RDebug::Printf( "Closing target %d", i ); + iTargets[ i ].Close(); + } + + iTargets.Close(); + + return KErrNone; + } + + +GLDEF_C TInt E32Main() + { + TInt ret = KErrNone; + + + CTrapCleanup* trap = CTrapCleanup::New(); + if (!trap) + return KErrNoMemory; + test.Title(); + + CMultiTargetAgent *runModeAgent = CMultiTargetAgent::NewL(); + if (runModeAgent != NULL) + { + __UHEAP_MARK; + TRAP(ret,runModeAgent->ClientAppL()); + __UHEAP_MARKEND; + + RDebug::Printf( "ClientAppL returned %d", ret ); + delete runModeAgent; + } + + delete trap; + return ret; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_target_tests/t_multi_target.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/multi_target_tests/t_multi_target.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,93 @@ +// Copyright (c) 2006-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: +// Definitions for the run mode debug tests +// +// + +/** + @file + @internalTechnology + @released +*/ + +#ifndef RMDEBUG_MULTI_TARGET_H +#define RMDEBUG_MULTI_TARGET_H + +#include "t_rmdebug_app.h" + +#include + +class CMultiTargetAgent; + +// +// class CRunModeAgent +// +// The basic run mode agent. +// +class CMultiTargetAgent : public CBase + { +public: + static CMultiTargetAgent* NewL(); + ~CMultiTargetAgent(); + void ClientAppL(); + + TInt LaunchProcess(RProcess& aProcess, TDesC & aExeName, TDesC & aCommandLine ); + +private: + CMultiTargetAgent(); + void ConstructL(); + + void ReportPerformance(void); + + TInt HelpTicksPerSecond(void); + + enum TTestMode + { + //run all the tests + EModeAll = 1<<0, + //run the specified tests in reverse order + EModeReverse = 1<<1, + //print out help + EModeHelp = 1<<2, + //print out help + EModeVersion = 1<<3 + }; + + TInt LaunchTargetsInOrderL(); + void SetupDebugServerL(); + +private: + +#if defined(KERNEL_OOM_TESTING) + RKernelLowMemorySecuritySvrSession iServSession; +#elif defined (USER_OOM_TESTING) + RUserLowMemorySecuritySvrSession iServSession; +#else + Debug::RSecuritySvrSession iServSession; +#endif + RSemaphore iAddressGlobSem; + + TUid iMySid; + + // Timing information + TInt iStartTick; + TInt iStopTick; + + RArray iTargets; + TRequestStatus iStatus; + Debug::TEventInfo iEventInfo; + TPtr8 iEventPtr; + }; + +#endif // RMDEBUG_MULTI_TARGET_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/performance_test/t_rmdebug_performance_oemtoken.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/performance_test/t_rmdebug_performance_oemtoken.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,31 @@ +// Copyright (c) 2010 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: +// + +/** + @file + @internalTechnology + @released +*/ + +#include + +GLDEF_C TInt E32Main() + { + // No need to do anything, the only requirement is that + // this executable can be loaded and runs to completion + return 0; + } + +// End of file - t_rmdebug_performance_oemtoken.cpp diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/performance_test/t_rmdebug_performance_test.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/performance_test/t_rmdebug_performance_test.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,599 @@ +// Copyright (c) 2010 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: +// Tests performance of run mode debug device component +// + +#include +#include +#include +#include +#include +#include + +#include "t_rmdebug_performance_test.h" +#include "t_debug_logging.h" +#include "t_rmdebug_app.h" + +const TVersion securityServerVersion(0,1,1); + +_LIT(KTestName, "T_RMDEBUG_PERFORMANCE_TEST"); + +LOCAL_D RTest test(KTestName); + +using namespace Debug; + +CRunModeAgent* CRunModeAgent::NewL() + { + LOG_ENTRY(); + CRunModeAgent* self = new(ELeave) CRunModeAgent(); + self->ConstructL(); + LOG_EXIT(); + return self; + } + +void CRunModeAgent::ConstructL() + { + // ConstructL list does not match destruction list as R-Class member variables are implicitly open. + // DebugDriver().Connect() is conditionally set depending on the test case hence not part of this function. + LOG_ENTRY(); + User::LeaveIfError(iIntegerProperty.Attach(RProcess().SecureId(), EPropertyTimeOfCrash, EOwnerThread)); + LOG_EXIT(); + } + +CRunModeAgent::~CRunModeAgent() + { + LOG_ENTRY(); + DebugDriver().Close(); + iTimeDifs.Close(); + iIntegerProperty.Close(); + RProperty::Delete(EPropertyTimeOfCrash); + LOG_EXIT(); + } + + +void CRunModeAgent::ClientAppL() + { + LOG_ENTRY(); + + if ( ParseCommandLine() == EDisplayHelp ) + { + DisplayUsage(); + } + else + { + static _LIT_SECURITY_POLICY_PASS(KAllowAllPolicy); + RProperty::Define(RProcess().SecureId(), EPropertyTimeOfCrash, RProperty::EInt, KAllowAllPolicy, KAllowAllPolicy); + StartTest(); + } + + LOG_EXIT(); + } + +TInt CRunModeAgent::GetTimeInMs() +{ + return User::NTickCount() * iTickPeriodMs; +} + +void CRunModeAgent::GetStartTime() + { + LOG_ENTRY(); + + test ( KErrNone == iIntegerProperty.Get(iParams.iCountStart) ); + LOG_MSG2("iParams.iCountStart %d", iParams.iCountStart); + + LOG_EXIT(); + } + +void CRunModeAgent::GetNanoTickPeriod() + { + LOG_ENTRY(); + + TInt period = 0; + User::LeaveIfError(HAL::Get(HALData::ENanoTickPeriod, period)); + iTickPeriodMs = period / 1000; + LOG_MSG("iTickPeriodMs = %d\n", iTickPeriodMs); + + LOG_EXIT(); + } + +void CRunModeAgent::StartTest() + { + LOG_ENTRY(); + + GetNanoTickPeriod(); + + if (iParams.iTestType == PerformanceTestParams::EBenchMarkTest) + { + RunBenchMarkTest(); + } + else + { + TestDriverPerformance(); + } + + CalculatePerformance(); + + LOG_EXIT(); + } + +// This function allows us to provide a benchmark when comparing the performance with the +// old and new APIs using the TestDriverPerformance function below. The two possible +// configurations are as follows: +// 1. Run t_rmdebug_app with a prefetch abort configuration and measure the time from the +// point of crash to the logon request completion. +// 2. Load the debug-system and then run the above configuration. +void CRunModeAgent::RunBenchMarkTest() + { + LOG_ENTRY(); + + test.Start(_L("RunBenchMarkTest")); + + RProcess process; + TRequestStatus status; + + if (iParams.iDriver) + { + RDebug::Printf("RunBenchMarkTest() - DebugDriver().Connect()"); + test(KErrNone == DebugDriver().Connect(securityServerVersion)); + } + + LOG_MSG("iParams.iNumOfTestRuns = %d", iParams.iNumOfTestRuns); + + for ( TUint i = 0; i < iParams.iNumOfTestRuns; i++ ) + { + // Start test application + test( KErrNone == LaunchProcessL(process, KRMDebugTestApplication(), KTargetOptions()) ); + + process.Logon(status); + User::WaitForRequest(status); + + // Stop timer on logon request completion + iParams.iCountEnd = GetTimeInMs(); + LOG_MSG("iParams.iCountEnd = %d", iParams.iCountEnd); + + LOG_MSG( "status.Int() = %d " , status.Int() ); + + // prefetch abort should raise a KERN-EXEC 3 + test(3 == status.Int()); + + process.Close(); + GetStartTime(); + + // NTickCount shouldn't overflow, so no reason why this assertion should fail + test(iParams.iCountEnd > iParams.iCountStart); + iTimeDifs.Append( iParams.iCountEnd - iParams.iCountStart ); + } + + LOG_EXIT(); + } + +// This function can be used to compare the performance with the old (e.g. attachExe) and new +// (e.g. attachAll) APIs depending depending on the parameters passed in when running this test. +void CRunModeAgent::TestDriverPerformance() + { + LOG_ENTRY(); + test.Start(_L("TestDriverPerformance")); + + RProcess process; + + test(KErrNone == DebugDriver().Connect(securityServerVersion)); + + LOG_MSG("iParams.iNumOfTestRuns = %d", iParams.iNumOfTestRuns); + for ( TUint i = 0; i < iParams.iNumOfTestRuns; i++ ) + { + ilaunchCompleted = EFalse; + + Attach(); + SetEventAction(); + test(KErrNone == LaunchProcessL(process, KRMDebugTestApplication(), KTargetOptions)); + + LOG_MSG("CRunModeAgent::TestDriverPerformance - process.Logon"); + + while ( !ilaunchCompleted ) + { + LOG_MSG("CRunModeAgent::TestDriverPerformance - DebugDriver().GetEvent"); + + GetEvent(); + + LOG_MSG("CRunModeAgent::TestDriverPerformance - User::WaitForRequest"); + + User::WaitForRequest(iStatus); + LOG_MSG( "iStatus.Int() = %d " , iStatus.Int() ); + + LOG_MSG("CRunModeAgent::TestDriverPerformance - HandleEvent"); + HandleEvent(iSEventInfo.iEventInfo); + } + + process.Logon(iStatus); + LOG_MSG("CRunModeAgent::TestDriverPerformance - process.Logon, User::WaitForRequest"); + User::WaitForRequest(iStatus); + LOG_MSG( "iStatus.Int() = %d " , iStatus.Int() ); + + // Stop timer on logon request completion as in benchmark performance test + iParams.iCountEnd = GetTimeInMs(); + + // prefetch abort should raise a KERN-EXEC 3 + test(3 == iStatus.Int()); + + Detach(); + process.Close(); + GetStartTime(); + + // NTickCount shouldn't overflow, so no reason why this assertion should fail + test(iParams.iCountEnd > iParams.iCountStart); + iTimeDifs.Append( iParams.iCountEnd - iParams.iCountStart ); + } + + LOG_EXIT(); + } + +void CRunModeAgent::CalculatePerformance() + { + LOG_ENTRY(); + + TUint median; + TUint arrayCount = iTimeDifs.Count(); + + for (TInt i = 0; i < arrayCount; i++) + { + RDebug::Printf("iTimeDifs[%d] = %d ",i,iTimeDifs[i]); + } + + // Sort in ascending order + iTimeDifs.Sort(); + + //If the number of elements is odd, the middle element in the sorted array is the median. + //If the number of elements is even, the median is the average of the two midmost elements. + if ( arrayCount%2 != 0 ) + { + median = iTimeDifs[arrayCount/2]; + } + else + { + median = (iTimeDifs[arrayCount/2] + iTimeDifs[arrayCount/2 -1])/2; + } + + RDebug::Printf("Median time %d ms", median ); + + LOG_EXIT(); + } + +/** + Launch a process + @param aExeName the executable used to create the process + @param aCommandLine the commandline parameters passed to the new process file name of the executable used to create the process + @return KErrNone on success, or one of the other system wide error codes + */ +TInt CRunModeAgent::LaunchProcessL( RProcess& aProcess, const TDesC& aExeName, const TDesC& aCommandLine ) + { + LOG_ENTRY(); + + RBuf launcherOptions; + launcherOptions.CleanupClosePushL(); + const TInt additionalWords = 1; + launcherOptions.CreateL( aCommandLine.Length() + additionalWords ); + launcherOptions.Format( aCommandLine, iParams.iTestTargetPriority); + + LOG_DES(_L("launcherOptions %S"), &launcherOptions); + + TInt err = aProcess.Create( aExeName, launcherOptions ); + CleanupStack::PopAndDestroy(); + + // check that there was no error raised + if (err != KErrNone) + return err; + + // rendezvous with process + TRequestStatus status = KRequestPending; + aProcess.Rendezvous(status); + + // start the test target + aProcess.Resume(); + User::WaitForRequest(status); + + if(KErrNone != status.Int()) + { + aProcess.Kill(KErrNone); + } + LOG_EXIT(); + return status.Int(); + + } + +void CRunModeAgent::SetEventAction() + { + LOG_ENTRY(); + + if (iParams.iTestType == PerformanceTestParams::EAttachExe) + { + test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsKillThread, EActionContinue)); + + if ( iParams.iEvents ) + { + test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsAddLibrary, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsUserTrace, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsStartThread, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsAddProcess, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( KRMDebugTestApplication(), EEventsRemoveProcess, EActionContinue)); + } + } + else + { + test(KErrNone == DebugDriver().SetEventAction( EEventsKillThread, EActionContinue)); + + if ( iParams.iEvents ) + { + test(KErrNone == DebugDriver().SetEventAction( EEventsAddLibrary, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( EEventsUserTrace, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( EEventsStartThread, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( EEventsAddProcess, EActionContinue)); + test(KErrNone == DebugDriver().SetEventAction( EEventsRemoveProcess, EActionContinue)); + } + } + + LOG_EXIT(); + } + +void CRunModeAgent::Attach() + { + LOG_ENTRY(); + + if( iParams.iTestType == PerformanceTestParams::EAttachExe ) + { + // Attach to process non-passively + test(KErrNone == DebugDriver().AttachExecutable( KRMDebugTestApplication(), EFalse)); + LOG_MSG("DebugDriver().AttachExecutable"); + } + else + { + // Attach to all the processes on the system + test(KErrNone == DebugDriver().AttachAll()); + LOG_MSG("DebugDriver().AttachAll()"); + } + + LOG_EXIT(); + } + +void CRunModeAgent::GetEvent() + { + LOG_ENTRY(); + + if( iParams.iTestType == PerformanceTestParams::EAttachExe ) + { + DebugDriver().GetEvent( KRMDebugTestApplication(), iStatus, iSEventInfo.iEventInfoBuf ); + } + else + { + DebugDriver().GetEvent( iStatus, iSEventInfo.iEventInfoBuf ); + } + + LOG_EXIT(); + } + +void CRunModeAgent::Detach() + { + LOG_ENTRY(); + + if( iParams.iTestType == PerformanceTestParams::EAttachExe ) + { + test (KErrNone == DebugDriver().DetachExecutable(KRMDebugTestApplication())); + } + else + { + test(KErrNone == DebugDriver().DetachAll()); + } + + LOG_EXIT(); + } + +void CRunModeAgent::HandleEvent(TEventInfo& aEventInfo) + { + LOG_ENTRY(); + + switch ( aEventInfo.iEventType ) + { + case EEventsAddProcess: + { + LOG_MSG(">>> EEventsAddProcess"); + break; + } + + case EEventsStartThread: + { + LOG_MSG(">>> EEventsStartThread"); + break; + } + + case EEventsUserTrace: + { + LOG_MSG(">>> EEventsUserTrace"); + break; + } + + case EEventsRemoveProcess: + { + LOG_MSG(">>> EEventsRemoveProcess"); + break; + } + + case EEventsKillThread: + { + LOG_MSG(">>> EEventsKillThread"); + ilaunchCompleted = ETrue; + break; + } + + default: + { + LOG_MSG( ">>> Unknown event "); + break; + } + } + + LOG_EXIT(); + } + +void CRunModeAgent::SetDefaultParamValues() + { + LOG_ENTRY(); + + iParams.iNumOfTestRuns = KNumOfTestRuns; + iParams.iTestType = PerformanceTestParams::EBenchMarkTest; + iParams.iTestTargetPriority = 0; + iParams.iEvents = 0; + iParams.iDriver = 0; + + LOG_EXIT(); + } + +TInt CRunModeAgent::ParseCommandLine() + { + LOG_ENTRY(); + + TBool ifDisplayHelp = EDontDisplayHelp; + SetDefaultParamValues(); + + TInt argc = User::CommandLineLength(); + LOG_MSG( "Launcher Process() argc=%d", argc ); + + if( argc ) + { + HBufC* commandLine = NULL; + commandLine = HBufC::NewLC(argc); + TPtr commandLineBuffer = commandLine->Des(); + User::CommandLine(commandLineBuffer); + + LOG_DES(_L("CommandLine = %S"), &commandLineBuffer); + + // create a lexer and read through the command line + TLex lex(*commandLine); + while (!lex.Eos()) + { + // only look for options with first character '-', other switches are for the targets + if (lex.Get() == '-') + { + TChar arg = lex.Get(); + switch (arg) + { + case 'n': + lex.Val( iParams.iNumOfTestRuns ); + LOG_MSG("Number of test runs %d", iParams.iNumOfTestRuns); + break; + case 't': + lex.Val( iParams.iTestType ); + LOG_MSG("parsed testType as %d", iParams.iTestType ); + break; + case 'p': + lex.Val( iParams.iTestTargetPriority ); + LOG_MSG("parsed test target priority as %d", iParams.iTestTargetPriority ); + break; + case 'e': + lex.Val( iParams.iEvents ); + LOG_MSG("parsed events as %d", iParams.iEvents ); + break; + case 'd': + lex.Val( iParams.iDriver ); + LOG_MSG("parsed iDriver as %d", iParams.iDriver ); + break; + case 'h': + LOG_MSG( "Display help" ); + ifDisplayHelp = EDisplayHelp; + default: + LOG_MSG( "Default usage" ); + break; + } + } + } + CleanupStack::PopAndDestroy(commandLine); + } + + LOG_EXIT(); + return ifDisplayHelp; + } + +void CRunModeAgent::DisplayUsage() + { + LOG_ENTRY(); + test.Printf(_L("\nUsage: t_rmdebug_performance_test [options] \nOptions:\n")); + + test.Printf(_L("\t-t \t\ttest type\n")); + test.Printf(_L("\t\t\t 0 - AttachAll\n")); + test.Printf(_L("\t\t\t 1 - AttachExe\n")); + test.Printf(_L("\t\t\t 2 - None\n")); + + test.Printf(_L("\t-n \t\tnumber of iterations\n")); + test.Printf(_L("\t-e \t\ttest with events\n")); + test.Printf(_L("\t\t\t 0 - No\n")); + test.Printf(_L("\t\t\t 1 - Yes\n")); + test.Printf(_L("\t-p \t\tpriority of test target thread\n")); + + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteVeryLow \n"), EPriorityAbsoluteVeryLow); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteLowNormal \n"), EPriorityAbsoluteLowNormal); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteLow \n"), EPriorityAbsoluteLow); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteBackgroundNormal \n"), EPriorityAbsoluteBackgroundNormal); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteBackground \n"), EPriorityAbsoluteBackground); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteForegroundNormal \n"), EPriorityAbsoluteForegroundNormal); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteForeground \n"), EPriorityAbsoluteForeground); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteHighNormal \n"), EPriorityAbsoluteHighNormal); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteHigh \n"), EPriorityAbsoluteHigh); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime1 \n"), EPriorityAbsoluteRealTime1); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime2 \n"), EPriorityAbsoluteRealTime2); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime3 \n"), EPriorityAbsoluteRealTime3); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime4 \n"), EPriorityAbsoluteRealTime4); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime5 \n"), EPriorityAbsoluteRealTime5); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime6 \n"), EPriorityAbsoluteRealTime6); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime7 \n"), EPriorityAbsoluteRealTime7); + test.Printf(_L("\t\t\t %d - EPriorityAbsoluteRealTime8 \n"), EPriorityAbsoluteRealTime8); + + test.Printf(_L("\t-d \t\tload driver\n")); + test.Printf(_L("\t\t\t 0 - No\n")); + test.Printf(_L("\t\t\t 1 - Yes\n")); + + test.Printf(_L("\t-h \t\tdisplay usage information\n\n")); + + test.Printf(_L("Press any key...\n")); + test.Getch(); + + LOG_EXIT(); + } + +GLDEF_C TInt E32Main() + { + __UHEAP_MARK; + + TInt ret = KErrNone; + CTrapCleanup* trap = CTrapCleanup::New(); + + if (!trap) + return KErrNoMemory; + + test.Start(KTestName); + + CRunModeAgent *runModeAgent = CRunModeAgent::NewL(); + + if (runModeAgent != NULL) + { + TRAP(ret,runModeAgent->ClientAppL()); + LOG_MSG( "ClientAppL() returned %d", ret ); + delete runModeAgent; + } + + test.End(); + test.Close(); + + delete trap; + __UHEAP_MARKEND; + return ret; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/performance_test/t_rmdebug_performance_test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/performance_test/t_rmdebug_performance_test.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,142 @@ +// Copyright (c) 2010 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: +// Tests performance of run mode debug device component +// +// + +#ifndef RMDEBUG_PERFORMANCE_H +#define RMDEBUG_PERFORMANCE_H + +#include +#include +#include + +/* Config for t_rmdebug_app.exe: + * -f1: prefetch abort, + * -d0: zero delay before crash + * -p: priority of test target main thread + */ +_LIT(KTargetOptions,"-f1 -d0 -p%d"); + +// Default number of test runs +const TInt KNumOfTestRuns = 7; + +/** + @Class TAgentEventInfo + + Class for gathering event data from the run-mode driver + */ +class TAgentEventInfo +{ +public: + TAgentEventInfo() : iEventInfoBuf(iEventInfo) {} + +public: + // This is the underlying class for event interaction with the Run Mode debug API + Debug::TEventInfo iEventInfo; + + TPckg iEventInfoBuf; +}; + +/** + @Class CRunModeAgent + + The basic run mode agent + */ +class CRunModeAgent : public CBase + { +public: + + enum displayHelp {EDontDisplayHelp =0, EDisplayHelp }; + + static CRunModeAgent* NewL(); + ~CRunModeAgent(); + void ClientAppL(); + Debug::RSecuritySvrSession& DebugDriver() { return iServSession; }; + +private: + void ConstructL(); + void StartTest(); + void TestDriverPerformance(); + void RunBenchMarkTest(); + TInt ParseCommandLine(); + + void Attach(); + void Detach(); + + void HandleEvent(Debug::TEventInfo& aEventInfo); + TInt LaunchProcessL(RProcess& aProcess, const TDesC& aExeName, const TDesC& aCommandLine); + void DisplayUsage(); + void GetNanoTickPeriod(); + void SetEventAction(); + void SetDefaultParamValues(); + + void CalculatePerformance(); + void GetEvent(); + void GetStartTime(); + TInt GetTimeInMs(); + +private: + + /** + Used for test cases interacting with the RMDBG only + */ + TRequestStatus iStatus; + + /** + The nanokernel tick period in MS + */ + TInt iTickPeriodMs; + + /* + * Handle to DSS + */ + Debug::RSecuritySvrSession iServSession; + + /** + Array to store tick counts between an iteration of a test run + */ + RArray iTimeDifs; + + /** + Object to gather event data from RMDBG + */ + TAgentEventInfo iSEventInfo; + + /** + Flag to indicate test target has crashed + */ + TBool ilaunchCompleted; + + /* + * RProperty to get counter value from test app + */ + RProperty iIntegerProperty; + + struct PerformanceTestParams + { + enum TestOptions {EAttachAll=0,EAttachExe, EBenchMarkTest }; + TUint iTestType; + TUint iNumOfTestRuns; + TUint iTestTargetPriority; + TUint iEvents; + TInt iCountEnd; + TInt iCountStart; + TUint iDriver; + } iParams; + + }; + +#endif // RMDEBUG_PERFORMANCE_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdebug_test/rm_debug/scripts/tef_execute_rtests.script --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdebug_test/rm_debug/scripts/tef_execute_rtests.script Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,59 @@ +// Copyright (c) 2010 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 "Symbian Foundation License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: Script file for running Run-Mode Debug Tests (RTests) as TEF3 tests. +// Please note, for a description of the tests please goto the RTests themselves. +// This file is a temporary measure, until the RTest component itself is updated. +// The problem is RTest does not produce logs when run on Sirocco, +// so this wrapper allows us to do that. +// +//! @File +//! @SYMTestSuiteName tef_execute_rtests.script +//! @SYMScriptTestEnvironment RTEST as TEF3 + +PRINT *** Running RTests as TEF3 tests *** + +START_TESTCASE KBASE-t_rmdebug2 +RUN_PROGRAM 120 t_rmdebug2 +END_TESTCASE KBASE-t_rmdebug2 + + +START_TESTCASE KBASE-t_rmdebug2_oem +RUN_PROGRAM 120 t_rmdebug2_oem +END_TESTCASE KBASE-t_rmdebug2_oem + + +START_TESTCASE KBASE-t_rmdebug2_oem2 +RUN_PROGRAM 120 t_rmdebug2_oem2 +END_TESTCASE KBASE-t_rmdebug2_oem2 + + +START_TESTCASE KBASE-t_rmdebug2_allcaps +RUN_PROGRAM 120 t_rmdebug2_allcaps +END_TESTCASE KBASE-t_rmdebug2_allcaps + + +START_TESTCASE KBASE-t_performance_test +RUN_PROGRAM 120 t_performance_test +END_TESTCASE KBASE-t_performance_test + + +START_TESTCASE KBASE-t_rmdebug_multi_target +RUN_PROGRAM 120 t_rmdebug_multi_target +END_TESTCASE KBASE-t_rmdebug_multi_target + + +START_TESTCASE KBASE-t_multi_agent_launcher +RUN_PROGRAM 120 t_multi_agent_launcher +END_TESTCASE KBASE-t_multi_agent_launcher + +PRINT *** Completed RTests as TEF3 tests *** diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/group/bld.inf Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,52 @@ +// Copyright (c) 2007-2010 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: +// e32/drivers/debug/bld.inf +// Run mode debugger +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_EXPORTS + +../../securityServer/inc/rm_debug_api.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(rm_debug_api.h) +rm_debug_svr.iby /epoc32/rom/include/ // Run mode debug driver + +PRJ_MMPFILES + +#ifndef GCCXML + +#if defined(GENERIC_MARM) || defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if defined(MARM_ARMV5) || defined(MARM_ARMV4) + + +rm_debug_kerneldriver +../../securityServer/group/rm_debug_svr + +#endif + +#endif +#endif + + +#endif //#ifndef GCCXML diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/group/rm_debug_kerneldriver.mmh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/group/rm_debug_kerneldriver.mmh Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,50 @@ +// Copyright (c) 2009-2010 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: +// + +OS_LAYER_SYSTEMINCLUDE + +#include + + +UID 0x100000AF 0x101F7157 + +SOURCEPATH ../src +SOURCE d_list_manager.cpp +SOURCE rm_debug_kerneldriver.cpp +SOURCE rm_debug_eventhandler.cpp +SOURCE d_process_tracker.cpp +SOURCE d_target_process.cpp +SOURCE d_debug_agent.cpp +SOURCE d_rmd_breakpoints.cpp +SOURCE d_rmd_stepping.cpp +SOURCE d_driver_event_info.cpp +SOURCE d_debug_functionality.cpp +SOURCE debug_utils.cpp + +#ifdef SYMBIAN_OLD_EXPORT_LOCATION +SYMBIAN_BASE_SYSTEMINCLUDE(memmodel/epoc/mmubase) +SYMBIAN_BASE_SYSTEMINCLUDE(drivers) +#endif + +userinclude ../inc + +VENDORID 0x70000001 + +//Specified to allow global data +EPOCALLOWDLLDATA + +capability all + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/group/rm_debug_kerneldriver.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/group/rm_debug_kerneldriver.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,20 @@ +// Copyright (c) 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 "rm_debug_kerneldriver.mmh" + +TARGET rm_debug.ldd + +TARGETTYPE LDD diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/group/rm_debug_svr.iby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/group/rm_debug_svr.iby Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,48 @@ +/* +* Copyright (c) 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: +* +*/ +#ifndef __RM_DEBUG_SVR_IBY__ +#define __RM_DEBUG_SVR_IBY__ + +#ifndef INST_ARM4 +#ifdef KMAIN + +// Debug Device Driver +extension[VARID]= \Epoc32\Release\##KMAIN##\##BUILD##\rm_debug.ldd \sys\bin\rm_debug.ldd + +// Debug Security Server +file= \Epoc32\Release\##MAIN##\##BUILD##\rm_debug_svr.exe \sys\bin\rm_debug_svr.exe + +#endif + +#ifndef KMAIN + +// Debug Device Driver +#ifdef STOP_MODE_DEBUGGING_V2 +extension[VARID]=KERNEL_DIR\DEBUG_DIR\rm_debug_ext.ldd \sys\bin\rm_debug.ldd +#else +extension[VARID]=KERNEL_DIR\DEBUG_DIR\rm_debug.ldd \sys\bin\rm_debug.ldd +#endif + +// Debug Security Server +file=KERNEL_DIR\DEBUG_DIR\rm_debug_svr.exe \sys\bin\rm_debug_svr.exe + +#endif + + +#endif // INST_ARM4 + +#endif // __RM_DEBUG_SVR_IBY__ diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/group/sis/eula.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/group/sis/eula.txt Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,1 @@ +RMDebug Test Sw. For Nokia use only. diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/group/sis/mk_rmdbg.bat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/group/sis/mk_rmdbg.bat Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,18 @@ +@rem +@rem Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +@rem All rights reserved. +@rem This component and the accompanying materials are made available +@rem under the terms of "Eclipse Public License v1.0" +@rem which accompanies this distribution, and is available +@rem at the URL "http://www.eclipse.org/legal/epl-v10.html". +@rem +@rem Initial Contributors: +@rem Nokia Corporation - initial contribution. +@rem +@rem Contributors: +@rem +@rem Description: +@rem + +makesis rmdbg.pkg +signsis rmdbg.sis rmdbg.sisx RDTest_02.der RDTest_02.key \ No newline at end of file diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/group/sis/rmdbg.pkg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/group/sis/rmdbg.pkg Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,48 @@ +; +; Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +; All rights reserved. +; This component and the accompanying materials are made available +; under the terms of "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: +; + + + +;Languages +&EN + +;Header +#{"RMDBG"},(0x101F7157),1,4,1, TYPE=SA,RU + + +;Localised Vendor name +%{"Nokia"} + +;Unique Vendor name +:"Nokia" + +;Supports Series 60 v 5.0 +[0x1028315], 0, 0, 0, {"Series60ProductID"} + +"eula.txt"-"", FILETEXT, TEXTEXIT + +; Files to install +; Note D Drive is RAM in HW79 products + +"\epoc32\release\armv5\udeb\rm_debug_svr.exe" -"d:\sys\bin\rm_debug_svr.exe" +"\epoc32\release\armv5\udeb\rm_debug.ldd" -"d:\sys\bin\rm_debug.ldd" + + +; Required files +; None + +; Component .sis files +; None diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_debug_agent.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_debug_agent.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,151 @@ +// Copyright (c) 2006-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: +// Purpose: Kernel-side tracking of debug agent information associated +// with each process being debugged. +// +// + +#ifndef D_DEBUG_AGENT_H +#define D_DEBUG_AGENT_H + +#include +#include "d_driver_event_info.h" + +/** +* Handles events from the kernel, filters them according to the debug agent's requests, +* and signals these events to the user side in FIFO-style. +* @see TKernelEventAction +* @see TEventInfo +*/ +class DDebugAgent : public DBase + { +public: + static DDebugAgent* New(TUint64 aId); + ~DDebugAgent(); + + TInt SetEventAction(Debug::TEventType aEvent, Debug::TKernelEventAction aEventAction); + void GetEvent(TClientDataRequest* aAsyncGetValueRequest, DThread* aClientThread); + TInt EventAction(Debug::TEventType aEvent); + + TInt CancelGetEvent(void); + void NotifyEvent(const TDriverEventInfo& aEventInfo); + TUint64 Id(); + +protected: + DDebugAgent(TUint64 aId); + TInt Construct(); + +private: + void QueueEvent(const TDriverEventInfo& aEventInfo); + TBool BufferEmpty() const; + TBool BufferFull() const; + TBool BufferCanStoreEvent() const; + TBool BufferAtCriticalLevel() const; + void IncrementHeadPosition(void); + void IncrementTailPosition(void); + TInt NumberOfEmptySlots() const; + void LockEventQueue(void); + void UnlockEventQueue(void); + +private: + + TUint64 iId; + Debug::TKernelEventAction iEventActions[Debug::EEventsLast]; + + /** + * Object used to write events back to DSS thread + * @see TEventInfo + */ + TClientDataRequest* iRequestGetEventStatus; + + DThread* iClientThread; + + /** + * Ring buffer of pending events. Access to it is controlled by + * @see iEventQueueLock + */ + RArray iEventQueue; + + /** + * Ring buffer head. Points to the next empty slot in iEventQueue + * @see iEventQueue + */ + TInt iHead; + + /** + * Ring buffer tail. Points to the oldest full slot in iEventQueue + * @see iEventQueue + */ + TInt iTail; + + /** + * Control access to event queue. + * @see iEventQueue + */ + DSemaphore* iEventQueueLock; + + /** + * Keeps track of how many free slots are available in the event queue. + * @see iEventQueue + */ + TInt iFreeSlots; + + /** + * Boolean to indicate if we have told the agent that we are ignoring trace events + * @see QueueEvent + */ + TBool iIgnoringTrace; + + /** + * Used to control the delivery of events to the client so that only + * when more requests than deliveries have taken place can we deliver the + * next event + * + * Incremented when a request for event takes place + * @see GetEvent + * + * Decremented when an event is delivered. + * @see NotifyEvent + * + * Cleared when event requests are cancelled + * @see CancelGetEvent + * + */ + TInt iEventBalance; + + /** + * Length of kernel-event queue. + * This is a power of two for efficiency when using the + * remainder operator + * @see DDebugAgent::iEventQueue + */ + static const TUint KNumberOfEventsToQueue = 128; + + /** + * This determines the number of events at which we stop accepting + * low priority events into the event queue. + * @see DDebugAgent::BufferAtCriticalLevel + * @see DDebugAgent::iEventQueue + */ + static const TUint KCriticalBufferSize = 64; + + /** + * If we encounter an event that will take down the agent (eg a process critical thread crashing) + * we use this flag to stop trying to deliver thread death notifications to it. + */ + TBool iAgentDying; + }; + +#endif // D_DEBUG_AGENT_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_debug_agent.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_debug_agent.inl Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,109 @@ +// Copyright (c) 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: +// Inline methods for debug agent class +// + + +/** + @file + @internalComponent + @released +*/ + +#ifndef D_DEBUG_AGENT_INL +#define D_DEBUG_AGENT_INL + + +/** + Checks whether the event queue is empty +*/ +inline TBool DDebugAgent::BufferEmpty() const + { + return (NumberOfEmptySlots() == KNumberOfEventsToQueue); + } + +/** + Checks whether the event queue is full +*/ +inline TBool DDebugAgent::BufferFull() const + { + return (NumberOfEmptySlots() == 0); + } + +/** + Checks whether there is room in the event queue to store an event +*/ +inline TBool DDebugAgent::BufferCanStoreEvent() const + { + return (NumberOfEmptySlots() > 0); + } + +/** + This looks to see if the buffer is close to being full and should only + accept higher priority debug events (user trace is the only low priority event) +*/ +inline TBool DDebugAgent::BufferAtCriticalLevel() const + { + return (NumberOfEmptySlots() < KNumberOfEventsToQueue - KCriticalBufferSize); + } + +/** + Increments Head position, wrapping at KNumberOfEventsToQueue if necessary +*/ +inline void DDebugAgent::IncrementHeadPosition(void) + { + iHead = (iHead + 1) % KNumberOfEventsToQueue; + + iFreeSlots--; + } + +/** + Increments Tail position, wrapping at KNumberOfEventsToQueue if necessary +*/ +inline void DDebugAgent::IncrementTailPosition(void) + { + iTail = (iTail + 1) % KNumberOfEventsToQueue; + + iFreeSlots++; +} + +/** + Returns the number of free slots in the event queue +*/ +inline TInt DDebugAgent::NumberOfEmptySlots() const + { + return iFreeSlots; + } + +/** + Lock access to this agent's event queue +*/ +inline void DDebugAgent::LockEventQueue(void) + { + NKern::ThreadEnterCS(); // Waiting on a semaphore is broken but this makes things marginally better. + // Anyone changing this, bear in mind the CS is also needed for some of the DebugUtils::OpenThreadHandle calls + Kern::SemaphoreWait(*iEventQueueLock); + } + +/** + Release the lock on this agent's event queue +*/ +inline void DDebugAgent::UnlockEventQueue(void) + { + Kern::SemaphoreSignal(*iEventQueueLock); + NKern::ThreadLeaveCS(); + } + + +#endif // D_DEBUG_AGENT_INL diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_debug_functionality.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_debug_functionality.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,40 @@ +// Copyright (c) 2006-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: +// Internal class used to assemble debug functionality data block +// + +#ifndef T_DEBUG_FUNCTIONALITY_H +#define T_DEBUG_FUNCTIONALITY_H + +/** + * This class is used to represent and assemble the debug functionality + * block + */ +class TDebugFunctionality + { + + public: + TUint32 GetDebugFunctionalityBufSize(void); + TBool GetDebugFunctionality(TDes8& aDFBlock); + static TInt GetRegister(const Debug::TRegisterInfo aRegisterInfo, Debug::TTag& aTag); + static TUint32 GetMemoryOperationMaxBlockSize(); + + private: + + // Helper functions when assembling the buffer + void AppendBlock(const Debug::TSubBlock& aDFSubBlock, TDes8& aDFBlock); + TUint32 ComputeBlockSize(const Debug::TSubBlock& aDFSubBlock); +}; + +#endif // T_DEBUG_FUNCTIONALITY_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_driver_event_info.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_driver_event_info.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,90 @@ +// 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: +// Purpose: Kernel-side tracking of event information +// +// + +#ifndef T_DRIVER_EVENT_INFO_H +#define T_DRIVER_EVENT_INFO_H + +#include +#include + +/** +@file +@internalComponent +*/ + +class TDriverEventInfo + { +public: + TDriverEventInfo(); + void Reset(); + TInt WriteEventToClientThread(TClientDataRequest* aAsyncGetValueRequest, DThread* aClientThread) const; + TBool FreezeOnSuspend() const; + +private: + TInt PopulateCommonEventInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateEventSpecificInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateThreadBreakPointInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateThreadHwExceptionInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateThreadSwExceptionInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateThreadKillInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateLibraryLoadedInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateLibraryUnloadedInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateRmdArmExcInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateUserTraceInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateStartThreadInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateAddProcessInfo(Debug::TEventInfo& aEventInfo) const; + TInt PopulateRemoveProcessInfo(Debug::TEventInfo& aEventInfo) const; + TBool TookException() const; + +public: + Debug::TEventType iEventType; + TUint64 iProcessId; + TUint64 iThreadId; + TUint64 iCreatorThreadId; + TUint32 iCurrentPC; + TInt iExceptionNumber; + TBuf8 iFileName; + TBuf8 iPanicCategory; + TUint32 iCodeAddress; + TUint32 iDataAddress; + TUint8 iExitType; + TUint8 iThreadIdValid; + TUint8 iProcessIdValid; + TUidType iUids; + TUint8 iUidsValid; + Debug::TKernelEventAction iActionTaken; + TUint32 iThreadFlags; + + //The objects that these pointers point to are not + //owned by the Debug::TEventInfo class so no cleanup is required + TAny* iArg1; // a1 + TAny* iArg2; // a2 + + union + { + Debug::TRmdArmExcInfo iRmdArmExcInfo; + //To store Trace info + TUint8 iUserTraceText[Debug::TUserTraceSize]; + }; + + //status of trace message + Debug::TUserTraceMessageContext iMessageStatus; + + }; + + +#endif //T_DRIVER_EVENT_INFO_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_list_manager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_list_manager.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,57 @@ +// 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: +// Definitions for the list manager +// +// + +#ifndef T_LIST_MANAGER_H +#define T_LIST_MANAGER_H + +#include +#include +#include + +/** +@file +@internalComponent +@released +*/ + +class TListManager +{ +public: + TInt GetThreadListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const; + TInt GetThreadListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const; + TInt GetGlobalThreadList(TDes8& aBuffer, TUint32& aDataSize) const; + TInt GetProcessList(TDes8& aBuffer, TUint32& aDataSize) const; + TInt GetCodeSegListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const; + TInt GetCodeSegListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const; + TInt GetGlobalCodeSegList(TDes8& aBuffer, TUint32& aDataSize) const; + TInt GetXipLibrariesList(TDes8& aBuffer, TUint32& aDataSize) const; +private: + TInt GetThreadList(TDes8& aBuffer, TUint32& aDataSize, TBool aGlobal, const TUint64 aTargetProcessId) const; + TInt GetDirectoryContents(RPointerArray& aRomEntryArray, const TLinAddr aAddress) const; + TInt GetDirectoryEntries(RPointerArray& aRomEntryArray, const TDesC& aDirectoryName) const; + TInt FindDirectory(const TDesC& aDirectory, TLinAddr& aAddress) const; + TInt GetDirectoryEntries(RPointerArray& aRomEntryArray, RArray& aArray, TLinAddr& aAddress) const; + + TInt AppendCodeSegData(TDes8& aBuffer, TUint32& aDataSize, const TModuleMemoryInfo& aMemoryInfo, const TBool aIsXip, const Debug::TCodeSegType aCodeSegType, const TDesC8& aFileName, const TUint32 aUid3) const; + void AppendThreadData(TDes8& aBuffer, TUint32& aDataSize, DThread* aThread) const; + TInt CopyAndExpandDes(const TDesC& aSrc, TDes& aDest) const; + TInt GetCodeSegType(const DCodeSeg* aCodeSeg, Debug::TCodeSegType& aType) const; + TInt SplitDirectoryName(const TDesC& aDirectoryName, RArray& aSubDirectories) const; +}; + +#endif //T_LIST_MANAGER_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_process_tracker.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_process_tracker.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,73 @@ +// Copyright (c) 2006-2010 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: +// Purpose: Kernel-side tracking of process state +// +// + +#ifndef D_PROCESS_TRACKER_H +#define D_PROCESS_TRACKER_H + +#include "d_target_process.h" + +// The global class which tracks all debugged processes. +// +// Note that multiple debug agents may attach to a process, +// as the security server will ensure only one is an 'active' +// agent, preventing conflicts. Other agents will be 'passive', +// typically interested only in recording events. +// +// The above requirement generates the requirement for the class +// to track the agent IDs, as multiple debug agents may be interested +// in a process. + +class DProcessTracker : public DBase +{ +public: + DProcessTracker(); + ~DProcessTracker(); + + TInt AttachProcess(const TDesC8& aProcessName, TUint64 aAgentId); + + TInt DetachProcess(const TDesC8& aProcessName, TUint64 aAgentId); + + TInt DetachAgent(TUint64 aAgentId); + + DTargetProcess* FindProcess(const TDesC8& aProcessName) const; + DTargetProcess* FuzzyFindProcess(const TDesC8& aProcessName); + + DDebugAgent* GetCurrentAgentAttachedToAll() const; + DDebugAgent* FindAgentForProcessAndId(const TDesC8& aProcessName, TUint64 aAgentId) const; + TBool NotifyAgentsForProcessEvent(const TDesC8& aProcessName, const TDriverEventInfo& aEvent, TBool aAllowFuzzy=EFalse); + + TInt SuspendThread(DThread* aTargetThread, TBool aFreezeThread=EFalse); + TInt ResumeThread(DThread* aTargetThread); + void FSWait(); + TInt ResumeFrozenThread(DThread* aThread); + TInt FreezeThread(); + +private: + TInt RemoveSuspendedThread(DThread* aThread); + TInt AddSuspendedThread(DThread* aThread); + const TDesC8* GetFileName(DThread* aThread) const; + +private: + RPointerArray iProcesses; + RPointerArray iAgentsAttachedToAll; + RPointerArray iFrozenThreadSemaphores; + }; + +// static global object +extern DProcessTracker TheDProcessTracker; + +#endif // D_PROCESS_TRACKER_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_rmd_breakpoints.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_rmd_breakpoints.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,213 @@ +// Copyright (c) 2004-2010 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: +// Refactored class containing breakpoint related code from rm_debug_kerneldriver.cpp +// + + + +/** + @file + @internalComponent + @released +*/ + +#ifndef D_RMD_BREAKPOINTS_H +#define D_RMD_BREAKPOINTS_H + +#include +#include +#include "rm_debug_kerneldriver.h" + +// fwd declaration of friend classes needed due to re-factoring +class DRM_DebugChannel; + +class DRMDStepper; + +// +// Macros +// +const TUint32 KArmBreakPoint = 0xE7F123F4; +const TUint16 KThumbBreakPoint = 0xDE56; +const TUint16 KT2EEBreakPoint = 0xC100; // From ARM ARM DDI0406A, section A9.2.1 Undefined instruction encoding for Thumb2-EE. + +#define NUMBER_OF_TEMP_BREAKPOINTS 10 + +#define NUMBER_OF_MAX_BREAKPOINTS 100 + +// +// class TBreakEntry +// +class TBreakEntry +{ +public: + + inline TBreakEntry() { Reset(); }; + + inline TBreakEntry(Debug::TBreakId aBreakId, TUint64 aId, TBool aThreadSpecific, TUint32 aAddress, Debug::TArchitectureMode aMode) + : iBreakId(aBreakId), + iId(aId), + iAddress(aAddress), + iMode(aMode), + iThreadSpecific(aThreadSpecific) + { + iInstruction.FillZ(4); + iPageAddress = 0; + iDisabledForStep = EFalse; + iObsoleteLibraryBreakpoint = EFalse; + iResumeOnceOutOfRange = EFalse; + iSteppingInto = EFalse; + iRangeStart = 0; + iRangeEnd = 0; + iStepTarget = EFalse; + iNumSteps = 0; + }; + + inline void Reset() + { + iId = 0; + iAddress = 0; + iMode = Debug::EArmMode; + iInstruction.FillZ(4); + iPageAddress = 0; + iDisabledForStep = EFalse; + iObsoleteLibraryBreakpoint = EFalse; + iResumeOnceOutOfRange = EFalse; + iSteppingInto = EFalse; + iRangeStart = 0; + iRangeEnd = 0; + iStepTarget = EFalse; + iNumSteps = 0; + }; + +public: + // Unique Id for this breakpoint. Assigned by D_RMD_Breakpoints::DoSetBreak(). @see D_RMD_Breakpoints::DoSetBreak + TInt32 iBreakId; + // Consider making the iId into a union of TProcessId, TThreadId, global etc. to make things more obvious + // Object Id in which this breakpoint should operate. + TUint64 iId; + // Address at which this breakpoint should operate + TUint32 iAddress; + // CPU ISA which this breakpoint uses, e.g. EArmMode/EThumbMode. + Debug::TArchitectureMode iMode; + // The original instruction which was stored at iAddress. + TBuf8<4> iInstruction; + TUint32 iPageAddress; //not used: BC if we remove it + + // Indicates whether this breakpoint has been temporarily replaced with original instruction to enable step-off this breakpoint + TBool iDisabledForStep; + /* This is used when libraries and processes are removed, so that + * the driver can say 'ok' when requested to remove breakpoints + * that existed in these cases, rather than 'Not Found'. + * + * Its not logical, but its a BC break if we change it :-( + */ + TBool iObsoleteLibraryBreakpoint; + // Indicates whether this thread should be resumed after stepping off this breakpoint + TBool iResumeOnceOutOfRange; + TBool iSteppingInto; + TUint32 iRangeStart; + TUint32 iRangeEnd; + TBool iThreadSpecific; + TBool iStepTarget; + + // Indicates how many more instruction steps should occur after hitting this breakpoint + TInt iNumSteps; +}; +/** +@internalTechnology + +This class encapsulates all the data concerning run-mode and stop mode breakpoints +as understood by the run-mode and stop-mode debug system. + +Note: + The internal list of breakpoints is currently divided into two sections. The range from + 0...NUMBER_OF_TEMP_BREAKPOINTS is used internally by the debug driver for implementing + stepping. The range from NUMBER_OF_TEMP_BREAKPOINTS to NUMBER_OF_MAX_BREAKPOINTS is used + to store information about breakpoints set by the client debug agents. + + In future, this should change, so that each breakpoint knows what kind of breakpoint it + is (user/temp etc). + + +*/ +class D_RMD_Breakpoints : public DBase +{ +public: + D_RMD_Breakpoints(DRM_DebugChannel* aChannel); + ~D_RMD_Breakpoints(); + + TInt Init(); + + // from rm_debug_driver.h + TInt DoSetBreak(TInt32 &aBreakId, const TUint64 aId, const TBool aThreadSpecific, const TUint32 aAddress, const Debug::TArchitectureMode aMode ); + TInt DoEnableBreak(TBreakEntry &aEntry, TBool aSaveOldInstruction); + TInt DoClearBreak(const TInt32 aBreakId, TBool aIgnoreTerminatedThreads=EFalse); + TInt DoModifyBreak(TModifyBreakInfo* aBreakInfo); + TInt DoModifyProcessBreak(TModifyProcessBreakInfo* aBreakInfo); + TInt DoBreakInfo(TGetBreakInfo* aBreakInfo); + void ClearAllBreakPoints(); + TInt DisableBreakAtAddress(TUint32 aAddress); + TInt DoEnableDisabledBreak(TUint64 aThreadId); + + void DoRemoveThreadBreaks(TUint64 aThreadId); + void RemoveBreaksForProcess(TUint64 aProcessId, TUint32 aCodeAddress, TUint32 aCodeSize); + void InvalidateLibraryBreakPoints(TUint32 aCodeAddress, TUint32 aCodeSize); + TInt BreakPointCount() const; + TBreakEntry* GetNextBreak(const TBreakEntry* aBreakEntry) const; + TBool IsTemporaryBreak(const TBreakEntry& aBreakEntry) const; + + TInt DoGetBreakList(TUint32* aBuffer, const TUint32 aBufSize, const TUint32 aElement, TUint32& aLastElement); + + // Useful helper functions for debugging breakpoint issues + inline void print_BreakpointsDisabledForStep(); + inline void print_BreakpointsList(); + +private: + // Locked versions of public functions + TInt priv_DoSetBreak(TInt32 &aBreakId, const TUint64 aId, const TBool aThreadSpecific, const TUint32 aAddress, const Debug::TArchitectureMode aMode ); + TInt priv_DoEnableBreak(TBreakEntry &aEntry, TBool aSaveOldInstruction); + TInt priv_DoClearBreak(const TInt32 aBreakId, TBool aIgnoreTerminatedThreads); + TInt priv_DoModifyBreak(TModifyBreakInfo* aBreakInfo); + TInt priv_DoModifyProcessBreak(TModifyProcessBreakInfo* aBreakInfo); + TInt priv_DoBreakInfo(TGetBreakInfo* aBreakInfo); + TInt priv_DisableBreakAtAddress(TUint32 aAddress); + TInt priv_DoEnableDisabledBreak(TUint64 aThreadId); + void priv_DoRemoveThreadBreaks(TUint64 aThreadId); + void priv_ClearAllBreakPoints(); + TBool priv_IsTemporaryBreak(const TBreakEntry& aBreakEntry) const; + + // helper functions + TBool Aligned(TUint32 aAddress, Debug::TArchitectureMode aMode); + TInt BreakSize(Debug::TArchitectureMode aMode); + TBool BreakpointsOverlap(TBreakEntry& aFirst, TBreakEntry& aSecond); + TUint32 BreakInst(Debug::TArchitectureMode aMode); + +private: + RArray iBreakPointList; + TInt iNextBreakId; + + DRM_DebugChannel* iChannel; // temporary reference back to DRM_DebugChannel to help with refactoring + + /* Protect access to the breakpoint list with a DSemaphore + * + * This means that stop-mode debuggers know when the list is being updated by the run-mode debug subsystem. + */ + DSemaphore* iLock; + + TBool iInitialised; +}; + +#include "d_rmd_breakpoints_debug.inl" + +#endif diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_rmd_breakpoints_debug.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_rmd_breakpoints_debug.inl Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,39 @@ +// Copyright (c) 2010 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 "debug_logging.h" + +// Print breakpoints disabled for stepping +inline void D_RMD_Breakpoints::print_BreakpointsDisabledForStep() + { + for (TInt i = 0; i < iBreakPointList.Count(); i++) + { + if(iBreakPointList[i].iDisabledForStep) + { + LOG_MSG2("Breakpoint disabled for stepping: iBreakPointList[%d]", i); + LOG_MSG4("iBreakId = %x, iId = %d, iAddress = %x", iBreakPointList[i].iBreakId, iBreakPointList[i].iId, iBreakPointList[i].iAddress ); + } + } + } + +// Print breakpoint list +inline void D_RMD_Breakpoints::print_BreakpointsList() + { + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + LOG_MSG2("Breakpoint list: iBreakPointList[%d]", i); + LOG_MSG4("iBreakId = %x, iId = %d, iAddress = %x", iBreakPointList[i].iBreakId, iBreakPointList[i].iId, iBreakPointList[i].iAddress ); + } + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_rmd_stepping.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_rmd_stepping.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,126 @@ +// Copyright (c) 2004-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: +// + +#ifndef D_RMD_STEPPING_H +#define D_RMD_STEPPING_H + +// fwd declaration of DRM_DebugChannel +class DRM_DebugChannel; + +// extracted from rm_debug_kerneldriver.h +// Register definitions +#define SP_REGISTER 13 +#define LINK_REGISTER 14 +#define PC_REGISTER 15 +#define STATUS_REGISTER 16 + +class DRMDStepping : public DBase +{ +public: + // ctor + DRMDStepping(DRM_DebugChannel* aChannel); + + // dtor + ~DRMDStepping(); + + // extracted from rm_debug_kerneldriver.cpp + TBool IsExecuted(TUint8 aCondition, TUint32 aStatusRegister); + TBool IsPreviousInstructionMovePCToLR(DThread *aThread); + void DecodeDataProcessingInstruction(TUint8 aOpcode, TUint32 aOp1, TUint32 aOp2, TUint32 aStatusRegister, TUint32 &aBreakAddress); + TUint32 PCAfterInstructionExecutes(DThread *aThread, TUint32 aCurrentPC, TUint32 aStatusRegister, TInt aInstSize, TUint32 &aNewRangeEnd, TBool &aChangingModes); + TUint32 ShiftedRegValue(DThread *aThread, TUint32 aInstruction, TUint32 aCurrentPC, TUint32 aStatusRegister); + TInt ModifyBreaksForStep(DThread *aThread, TUint32 aRangeStart, TUint32 aRangeEnd,TBool aResumeOnceOutOfRange, TBool aCheckForStubs, const TUint32 aNumSteps); + +private: + + // Needed to access private data until re-structuring work is complete. + friend class DRM_DebugChannel; + + DRM_DebugChannel* iChannel; // temporary reference back to DRM_DebugChannel to help with refactoring + + // Set of inline functions for decoding instructions. Formerly these were all macros + + // ARM instruction bitmasks + inline TUint32 arm_opcode(const TUint32 aInst); + + // Generic instruction defines + inline TUint32 arm_rm(const TUint32 aInst); + inline TUint32 arm_rs(const TUint32 aInst); + inline TUint32 arm_rd(const TUint32 aInst); + inline TUint32 arm_rn(const TUint32 aInst); + inline TUint32 arm_load(const TUint32 aInst); + + // Data processing instruction defines + inline TUint32 arm_data_shift(const TUint32 aInst); + inline TUint32 arm_data_c(const TUint32 aInst); + inline TUint32 arm_data_imm(const TUint32 aInst); + inline TUint32 arm_data_rot(const TUint32 aInst); + + // Single date transfer instruction defines + inline TUint32 arm_single_imm(const TUint32 aInst); + inline TUint32 arm_single_byte(const TUint32 aInst); + inline TUint32 arm_single_u(const TUint32 aInst); + inline TUint32 arm_single_pre(const TUint32 aInst); + + // Block data transfer instruction defines + inline TUint32 arm_block_reglist(const TUint32 aInst); + inline TUint32 arm_block_u(const TUint32 aInst); + inline TUint32 arm_block_pre(const TUint32 aInst); + + // Branch instruction defines + inline TUint32 arm_b_addr(const TUint32 aInst); + inline TUint32 arm_instr_b_dest(const TUint32 aInst, TUint32& aAddr); + inline TUint32 thumb_b_addr(const TUint32 aInst); + inline TUint32 thumb_instr_b_dest(const TUint32 aInst, TUint32& aAddr); + inline TUint32 arm_carry_bit(void); + + + // Thumb instruction bitmasks + inline TUint16 thumb_opcode(const TUint16 aInst); + inline TUint16 thumb_inst_7_15(const TUint16 aInst); + inline TUint16 thumb_inst_8_15(const TUint16 aInst); + + // Thumb2 decode support functions + inline TUint16 t2opcode16(const TUint16 aInst); + + inline TUint16 t2opcode16special(const TUint16 aInst); + + // Helper functions + TInt CurrentPC(DThread* aThread, TUint32& aPC); + + TInt CurrentCPSR(DThread* aThread, TUint32& aCPSR); + + TInt CurrentInstruction(DThread* aThread, TUint32& aInstruction); + + TInt CurrentArchMode(const TUint32 cpsr, Debug::TArchitectureMode& mode); + + TInt RegisterValue(DThread *aThread, const TUint32 aKernelRegisterId, TUint32 &aValue); + + TInt ReadMem32(DThread* aThread, const TUint32 aAddress, TUint32& aValue); + + TInt ReadMem16(DThread* aThread, const TUint32 aAddress, TUint16& aValue); + + TInt ReadMem8(DThread* aThread, const TUint32 aAddress, TUint8& aValue); + + inline TUint32 BitCount(const TUint32 aVal); + + inline TUint32 IsBitSet(const TUint32 aBitset, const TUint8 aBitNum); +}; + +#include "d_rmd_stepping.inl" + +#endif // D_RMD_STEPPPING_H + +// End of file - d-rmd-stepping.h diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_rmd_stepping.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_rmd_stepping.inl Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,313 @@ +// Copyright (c) 2004-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: +// + + + +/** + @file + @internalComponent + @released +*/ + +#ifndef D_RMD_STEPPING_INL +#define D_RMD_STEPPING_INL + +// +// IsBitSet +// +// Returns 1 if the bit 'aNum' is set within aBitset, 0 otherwise +inline TUint32 DRMDStepping::IsBitSet(const TUint32 aBitset, const TUint8 aNum) + { + return (aBitset & (1 << aNum) ); + } + +// +// BitCount +// +// Count number of bits in aVal +inline TUint32 DRMDStepping::BitCount(const TUint32 aVal) + { + TUint32 num = 0; + + for(TInt i = 0; i < 32; i++) + { + if ((1 << i) & aVal) + { + num++; + } + } + return num; + } + +// +// Thumb2 opcode decoding +// +// Special data instructions and branch and exchange. +// +// Returns Opcode as defined in ARM ARM DDI0406A, section A6.2.3 +inline TUint16 DRMDStepping::t2opcode16special(const TUint16 aInst) + { + TUint8 aVal = (aInst & 0x03C0) >> 5; + + return aVal; + } + + +// Thumb2 opcode decoding instructions +// +// Returns Opcode as defined in ARM ARM DDI0406A, section A6.2 +// 16-bit Thumb instruction encoding +inline TUint16 DRMDStepping::t2opcode16(const TUint16 aInst) +{ + TUint16 aVal = (aInst & 0xFC00) >> 9; + + return aVal; +} + +// ARM opcode decoding functions +inline TUint32 DRMDStepping::arm_opcode(const TUint32 aInst) +{ +// #define ARM_OPCODE(x) (((TUint32)(x) & 0x0E000000) >> 25) + + TUint32 aVal = ((aInst) & 0x0E000000) >> 25; + + return aVal; +} + +inline TUint32 DRMDStepping:: arm_rm(const TUint32 aInst) +{ +//#define ARM_RM(x) ((TUint32)(x) & 0x0000000F) // bit 0- 4 + + TUint32 aVal = (aInst) & 0x0000000F; + + return aVal; +} + +inline TUint32 DRMDStepping:: arm_rs(const TUint32 aInst) +{ +//#define ARM_RS(x) (((TUint32)(x) & 0x00000F00) >> 8) // bit 8-11 + + TUint32 aVal = ((aInst) & 0x00000F00) >> 8; + + return aVal; +} + +inline TUint32 DRMDStepping:: arm_rd(const TUint32 aInst) +{ +//#define ARM_RD(x) (((TUint32)(x) & 0x0000F000) >> 12) // bit 12-15 + + TUint32 aVal = ((aInst) & 0x0000F000) >> 12; + + return aVal; +} + +inline TUint32 DRMDStepping:: arm_rn(const TUint32 aInst) +{ +//#define ARM_RN(x) (((TUint32)(x) & 0x000F0000) >> 16) // bit 16-19 + + TUint32 aVal = ((aInst) & 0x000F0000) >> 16; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_load(const TUint32 aInst) +{ +//#define ARM_LOAD(x) (((TUint32)(x) & 0x00100000) >> 20) // bit 20 + + TUint32 aVal = ((aInst) & 0x00100000) >> 20; + + return aVal; +} + +// Data processing instruction defines +inline TUint32 DRMDStepping::arm_data_shift(const TUint32 aInst) +{ +//#define ARM_DATA_SHIFT(x) (((TUint32)(x) & 0x00000060) >> 5) // bit 5- 6 + + TUint32 aVal = ((aInst) & 0x00000060) >> 5; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_data_c(const TUint32 aInst) +{ +//#define ARM_DATA_C(x) (((TUint32)(x) & 0x00000F80) >> 7) // bit 7-11 + + TUint32 aVal = ((aInst) & 0x00000F80) >> 7; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_data_imm(const TUint32 aInst) +{ +//#define ARM_DATA_IMM(x) ((TUint32)(x) & 0x000000FF) // bit 0-7 + + TUint32 aVal = (aInst) & 0x000000FF; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_data_rot(const TUint32 aInst) +{ +//#define ARM_DATA_ROT(x) (((TUint32)(x) & 0x00000F00) >> 8) // bit 8-11 + + TUint32 aVal = ((aInst) & 0x00000F00) >> 8; + + return aVal; +} + +// Single date transfer instruction defines +inline TUint32 DRMDStepping::arm_single_imm(const TUint32 aInst) +{ +//#define ARM_SINGLE_IMM(x) ((TUint32)(x) & 0x00000FFF) // bit 0-11 + + TUint32 aVal = (aInst) & 0x00000FFF; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_single_byte(const TUint32 aInst) +{ +//#define ARM_SINGLE_BYTE(x) (((TUint32)(x) & 0x00400000) >> 22) // bit 22 + + TUint32 aVal = ((aInst) & 0x00400000) >> 22; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_single_u(const TUint32 aInst) +{ +//#define ARM_SINGLE_U(x) (((TUint32)(x) & 0x00800000) >> 23) // bit 23 + + TUint32 aVal = ((aInst) & 0x00800000) >> 23; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_single_pre(const TUint32 aInst) +{ +//#define ARM_SINGLE_PRE(x) (((TUint32)(x) & 0x01000000) >> 24) // bit 24 + + TUint32 aVal = ((aInst) & 0x01000000) >> 24; + + return aVal; +} + +// Block data transfer instruction defines +inline TUint32 DRMDStepping::arm_block_reglist(const TUint32 aInst) +{ +//#define ARM_BLOCK_REGLIST(x) ((TUint32)(x) & 0x0000FFFF) // bit 0-15 + + TUint32 aVal = (aInst) & 0x0000FFFF; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_block_u(const TUint32 aInst) +{ +//#define ARM_BLOCK_U(x) (((TUint32)(x) & 0x00800000) >> 23) // bit 23 + + TUint32 aVal = ((aInst) & 0x00800000) >> 23; + + return aVal; +} + +inline TUint32 DRMDStepping::arm_block_pre(const TUint32 aInst) +{ +//#define ARM_BLOCK_PRE(x) (((TUint32)(x) & 0x01000000) >> 24) // bit 24 + + TUint32 aVal = ((aInst) & 0x01000000) >> 24; + + return aVal; +} + +// Branch instruction defines +inline TUint32 DRMDStepping::arm_b_addr(const TUint32 aInst) +{ +//#define ARM_B_ADDR(x) ((x & 0x00800000) ? ((TUint32)(x) & 0x00FFFFFF | 0xFF000000) : (TUint32)(x) & 0x00FFFFFF) + + TUint32 aVal = ((aInst & 0x00800000) ? ((TUint32)(aInst) & 0x00FFFFFF | 0xFF000000) : (TUint32)(aInst) & 0x00FFFFFF); + + return aVal; +} + +inline TUint32 DRMDStepping::arm_instr_b_dest(const TUint32 aInst, TUint32& aAddress) +{ +//#define ARM_INSTR_B_DEST(x,a) (ARM_B_ADDR(x) << 2) + ((TUint32)(a) + 8) + + TUint32 aVal = (arm_b_addr(aInst) << 2) + ((TUint32)(aAddress) + 8); + + return aVal; +} + +inline TUint32 DRMDStepping::thumb_b_addr(const TUint32 aInst) +{ +//#define THUMB_B_ADDR(x) ((x & 0x0400) ? ((((TUint32)(x) & 0x07FF)<<11) | (((TUint32)(x) & 0x07FF0000)>>16) | 0xFFC00000) :\ + ((TUint32)(x) & 0x07FF)<<11) | (((TUint32)(x) & 0x07FF0000)>>16) + + TUint32 aVal = ((((TUint32)(aInst) & 0x07FF)<<11) | ((TUint32)(aInst) & 0x07FF0000)>>16); + + return ((aInst & 0x0400) ? (aVal | 0xFFC00000) : aVal); +} + +inline TUint32 DRMDStepping::thumb_instr_b_dest(const TUint32 aInst, TUint32& aAddress) +{ +//#define THUMB_INSTR_B_DEST(x,a) (THUMB_B_ADDR(x) << 1) + ((TUint32)(a) + 4) + + TUint32 aVal = (thumb_b_addr(aInst) << 1) + ((TUint32)(aAddress) + 4); + + return aVal; +} + +inline TUint32 DRMDStepping::arm_carry_bit(void) +{ +//#define ARM_CARRY_BIT 0x20000000 // bit 30 + + TUint32 aVal = 0x20000000; + + return aVal; +} + +// Thumb instruction bitmasks +inline TUint16 DRMDStepping::thumb_opcode(const TUint16 aInst) +{ +// #define THUMB_OPCODE(x) (((TUint16)(x) & 0xF800) >> 11) + + TUint16 aVal = ((aInst) & 0xF800) >> 11; + + return aVal; +} + +inline TUint16 DRMDStepping::thumb_inst_7_15(const TUint16 aInst) +{ +// #define THUMB_INST_7_15(x) (((TUint16)(x) & 0xFF80) >> 7) + + TUint16 aVal = ((aInst) & 0xFF80) >> 7; + + return aVal; +} + +inline TUint16 DRMDStepping::thumb_inst_8_15(const TUint16 aInst) +{ +// #define THUMB_INST_8_15(x) (((TUint16)(x) & 0xFF00) >> 8) + + TUint16 aVal = ((aInst) & 0xFF00) >> 8; + + return aVal; +} + +#endif // D_RMD_STEPPPING_INL + +// End of file - d-rmd-stepping.inl diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/d_target_process.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/d_target_process.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,57 @@ +// Copyright (c) 2006-2010 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: +// Purpose: Kernel-side tracking of process state +// +// + +#ifndef D_TARGET_PROCESS_H +#define D_TARGET_PROCESS_H + +#include "d_debug_agent.h" + +// Debug Process Tracker class +class DTargetProcess : public DBase +{ +public: + DTargetProcess(); + ~DTargetProcess(); + + static TInt Compare(const DTargetProcess& aFirst, const DTargetProcess& aSecond); + + TInt SetProcessName(const TDesC8& aProcessName); + const TDesC8& ProcessName() const; + + TInt AddAgent(const TUint64 aAgentId); + + TInt RemoveAgent(TUint64 aAgentId); + + DDebugAgent* operator[](TInt aIndex); + + DDebugAgent* Agent(TUint64 aAgentId); + + TInt AgentCount() const; + void NotifyEvent(const TDriverEventInfo& aEventInfo); + +private: + HBuf8* iProcessName; + RPointerArray iAgentList; + + RArray iSuspendedThreads; + + RPointerArray iFrozenThreadSemaphores; + +}; + +#endif // D_TARGET_PROCESS_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/debug_logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/debug_logging.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,108 @@ +// Copyright (c) 2006-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: +// Logging macros for use in debug subsystem +// +// + +#ifndef DEBUG_LOGGING_H +#define DEBUG_LOGGING_H + +/** + * Debug messages + * + * Debug messages are only generated for debug builds. + * + * For kernel mode, use __KTRACE_OPT(KDEBUGGER, Kern::Printf(), + * for user mode use RDebug::Printf(). + * + */ + +#ifdef _DEBUG + + #ifdef __KERNEL_MODE__ + + #include + #include + + #define LOG_MSG( a ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a )) + #define LOG_MSG2( a, b ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b )) + #define LOG_MSG3( a, b, c ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c )) + #define LOG_MSG4( a, b, c, d ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c, d )) + #define LOG_MSG5( a, b, c, d, e ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c, d, e )) + + #ifdef __LOG_EVENTS__ + + #define LOG_EVENT_MSG( a ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a )) + #define LOG_EVENT_MSG2( a, b ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b )) + #define LOG_EVENT_MSG3( a, b, c ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c )) + #define LOG_EVENT_MSG4( a, b, c, d ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c, d )) + #define LOG_EVENT_MSG5( a, b, c, d, e ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c, d, e )) + + #else + + #define LOG_EVENT_MSG( a ) + #define LOG_EVENT_MSG2( a, b ) + #define LOG_EVENT_MSG3( a, b, c ) + #define LOG_EVENT_MSG4( a, b, c, d ) + #define LOG_EVENT_MSG5( a, b, c, d, e ) + + #endif + + #else + + #include + + #define LOG_MSG( a ) RDebug::Printf( a ) + #define LOG_MSG2( a, b ) RDebug::Printf( a, b ) + #define LOG_MSG3( a, b, c ) RDebug::Printf( a, b, c ) + #define LOG_MSG4( a, b, c, d ) RDebug::Printf( a, b, c, d ) + #define LOG_MSG5( a, b, c, d, e ) RDebug::Printf( a, b, c, d, e ) + + #ifdef __LOG_EVENTS__ + + #define LOG_EVENT_MSG( a ) RDebug::Printf( a ) + #define LOG_EVENT_MSG2( a, b ) RDebug::Printf( a, b ) + #define LOG_EVENT_MSG3( a, b, c ) RDebug::Printf( a, b, c ) + #define LOG_EVENT_MSG4( a, b, c, d ) RDebug::Printf( a, b, c, d ) + #define LOG_EVENT_MSG5( a, b, c, d, e ) RDebug::Printf( a, b, c, d, e ) + + #else + + #define LOG_EVENT_MSG( a ) + #define LOG_EVENT_MSG2( a, b ) + #define LOG_EVENT_MSG3( a, b, c ) + #define LOG_EVENT_MSG4( a, b, c, d ) + #define LOG_EVENT_MSG5( a, b, c, d, e ) + + #endif + + #endif +#else + + #define LOG_MSG( a ) + #define LOG_MSG2( a, b ) + #define LOG_MSG3( a, b, c ) + #define LOG_MSG4( a, b, c, d ) + #define LOG_MSG5( a, b, c, d, e ) + + #define LOG_EVENT_MSG( a ) + #define LOG_EVENT_MSG2( a, b ) + #define LOG_EVENT_MSG3( a, b, c ) + #define LOG_EVENT_MSG4( a, b, c, d ) + #define LOG_EVENT_MSG5( a, b, c, d, e ) + +#endif + +#endif //DEBUG_LOGGING_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/debug_utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/debug_utils.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,38 @@ +// Copyright (c) 2004-2010 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: +// Purpose: Static functions for use by debug driver classes +// + +/** + * @file + * @internalComponent + * @released + */ + +#ifndef DEBUG_UTILS_H +#define DEBUG_UTILS_H + +#include +#include + +class DebugUtils + { +public: + static DThread* OpenThreadHandle(TUint64 aThreadId); + static DProcess* OpenProcessHandle(TUint64 aProcessId); + static DThread* OpenFirstThreadForProcess(DProcess* aProcess); + }; + +#endif //DEBUG_UTILS_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/rm_debug_driver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/rm_debug_driver.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,199 @@ +// Copyright (c) 2004-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: +// + + + +/** + @file + @internalTechnology + @released +*/ + +#ifndef __RM_DEBUG_DRIVER_H__ +#define __RM_DEBUG_DRIVER_H__ + +#include "d_rmd_stepping.h" +#include "d_rmd_breakpoints.h" +#include "d_driver_event_info.h" + +// From mmboot.h header +const TLinAddr KDataSectionEnd =0x40000000u; +const TLinAddr KRomLinearBase =0xF8000000u; + + +#define ROM_LINEAR_BASE KRomLinearBase + +// Result checking +#define ReturnIfError(x) { TInt y = x; if (KErrNone != y) return y; } + +// +// class DRM_DebugDriverFactory +// +class DRM_DebugDriverFactory : public DLogicalDevice +{ +public: + + DRM_DebugDriverFactory(); + virtual TInt Install(); + virtual void GetCaps(TDes8& aDes) const; + virtual TInt Create(DLogicalChannelBase*& aChannel); +}; + +class DRM_DebugEventHandler; +// +// DRM_DebugChannel +// +class DRM_DebugChannel : public DLogicalChannel +{ +public: + + DRM_DebugChannel(DLogicalDevice* aLogicalDevice); + ~DRM_DebugChannel(); + + virtual TInt DoCreate(TInt aUnit, const TDesC* anInfo, const TVersion& aVer); + virtual void HandleMsg(TMessageBase* aMsg); + virtual TInt SendMsg(TMessageBase* aMsg); + TInt SendRequest(TMessageBase* aMsg); + + //called from the event handler + TBool RemoveProcess(TAny* a1, TAny* a2); + TBool StartThread(TAny* a1, TAny* a2); + TBool AddLibrary(TAny* a1, TAny* a2); + TBool RemoveLibrary(TAny* a1, TAny* a2); + TBool HandleEventKillThread(TAny* a1, TAny* a2); + TBool HandleSwException(TAny* a1, TAny* a2); + TBool HandleHwException(TAny* a1, TAny* a2); + TBool HandleUserTrace(TAny* a1, TAny* a2); + TBool HandleUnsupportedEvent(TAny* a1, TAny* a2) { return EFalse; } + TBool HandleAddProcessEvent(TAny* a1, TAny* a2); + TBool HandleRemoveProcessEvent(TAny* a1, TAny* a2); + + // Used to be able to signal events to the DSS + DThread* ClientThread(void) {return iClientThread; }; + +protected: + virtual void DoCancel(TInt aReqNo); + virtual void DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2); + virtual TInt DoControl(TInt aFunction, TAny *a1, TAny *a2); + +private: + TInt PreAsyncGetValue(Debug::TEventInfo* aValue, TRequestStatus* aStatus); + TInt CreateDfcQ(); + void DestroyDfcQ(); + TBool HandleInvalidOpCodeException(TDriverEventInfo& aEventInfo, DThread* aCurrentThread); + + TInt SetBreak(TSetBreakInfo* aBreakInfo); + TInt StepRange(DThread* aThread, TRM_DebugStepInfo* aStepInfo); + TInt ReadMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo); + TInt WriteMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo); + TInt ReadRegistersLegacy(DThread* aThread, TRM_DebugRegisterInfo* aRegisterInfo); + TInt WriteRegistersLegacy(DThread* aThread, const TRM_DebugRegisterInfo* aRegisterInfo); + TInt ReadRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const; + TInt WriteRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const; + TInt GetProcessInfo(TInt aIndex, TRM_DebugTaskInfo* aTaskInfo); + TInt GetThreadInfo(TInt aIndex, TRM_DebugTaskInfo* aTaskInfo); + TInt GetList(TListInformation* aListInformation) const; + + TInt Step(const TUint32 aThreadId, const TUint32 aNumSteps); + TInt KillProcess(const TUint32 aProcessId, const TInt aReason); + + //Crash Flash + TInt ReadCrashLog(TFlashInfo* aBuffer); + TInt WriteCrashLog(TFlashInfo* aBuffer) const; + TInt EraseCrashLog(); + + // Stop/go + TInt DoSuspendThread(DThread *aThread); + TInt DoResumeThread(DThread *aThread); + TInt DoStepRange(DThread *aThread, const TUint32 aStartAddress, const TUint32 aStopAddress, TBool aStepInto, TBool aResumeOnceOutOfRange, const TUint32 aNumSteps, TBool aUserRequest = EFalse); + TInt DoReadMemory(const DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) const; + TInt DoWriteMemory(DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData); + TInt DoReadRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDes8 &aValues); + TInt DoReadRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDes8 &aRegisterValues, TDes8 &aRegisterFlags) const; + TInt DoWriteRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDesC8 &aValues); + TInt DoWriteRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDesC8 &aRegisterValues, TDes8 &aRegisterFlags) const; + TInt DoGetProcessInfo(const TInt aIndex, TRM_DebugTaskInfo *aInfo); + TInt DoGetThreadInfo(const TInt aIndex, TRM_DebugTaskInfo *aInfo); + TBool DoSecurityCheck(); + + TInt TryToReadMemory(const DThread *aThread, const TAny *aSrc, TAny *aDest, const TUint32 aLength) const; + TInt TryToWriteMemory(const DThread *aThread, TAny *aDest, const TAny *aSrc, const TUint32 aLength); + TInt32 ReadRegister(DThread *aThread, TInt aNum); + TInt32 ReadDebugRegisterValue(DThread *aThread, const Debug::TRegisterInfo aDebugRegisterId, T4ByteRegisterValue &aValue) const; + TInt32 ReadKernelRegisterValue(DThread *aThread, const TArmReg aKernelRegisterId, T4ByteRegisterValue &aValue) const; + + void NotifyEvent(const TDriverEventInfo& aEventInfo); + + TInt GetTRegisterInfo(const TDesC8 &aRegisterIds, const TUint aIndex, Debug::TRegisterInfo &aValue) const; + TInt GetDebugRegisterId(const TArmReg aKernelRegister, Debug::TRegisterInfo& aDebugRegister) const; + TInt GetKernelRegisterId(const Debug::TRegisterInfo aDebugRegister, TArmReg& aKernelRegister) const; + TBool GetFlagAtOffset(const TUint32 aFlags, const TArmReg aIndex) const; + + TInt AllocAndReadDes(DThread *aThread, const TDesC8& aSrcDes, TPtr8& aDestDes, const TBool aReadFromClient=ETrue, const TUint aOffset=0) const; + + TInt AttachProcess(TAny* a1, TAny* a2); + TInt DetachProcess(TAny* a1, TAny* a2); + TInt DetachAgent(TAny* a1, TAny* a2); + TInt SetEventAction(TAny* a1, TAny* a2); + TBool CheckSuspended(const DThread *aThread) const; + + // Needed so moved functions can access iBreakpoint list and related functions + friend class D_RMD_Breakpoints; + // Needed so moved functions can access stepping functionality + friend class DRMDStepping; + + // helper function was previously in rm_debug_kerneldriver.cpp + inline TInt Bitcount(TUint32 val) + { + TInt nbits; + + for (nbits = 0; val != 0; nbits++) + { + val &= val - 1; // delete rightmost 1-bit in val + } + + return nbits; + } + + // Security critical - this returns whether the specified process is debuggable or not + TInt IsDebuggable(const TUint32 aProcessId); + + TInt NotifyAgentsFromEventPid(const TDriverEventInfo& aEventInfo); + +private: + DThread* iClientThread; + DRM_DebugEventHandler* iEventHandler; + + TUint32 iExcludedROMAddressStart; + TUint32 iExcludedROMAddressEnd; + + TUint32 iPageSize; + + RArray iDebugProcessList; //processes that we are debugging + + D_RMD_Breakpoints* iBreakManager; // new D_RMD_Breakpoints + + DRMDStepping* iStepper; // new DRMDStepping + + DSemaphore* iStepLock; // Synchronisation for stepping code. + + TDynamicDfcQue* iDfcQ; + + TBool iInitialisedCodeModifier; // Ensures we control its lifetime + + TClientDataRequest* iAsyncGetValueRequest; +}; + +#endif //__RM_DEBUG_DRIVER_H__ diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/rm_debug_eventhandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/rm_debug_eventhandler.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,60 @@ +// Copyright (c) 2004-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: +// + +/** Event handler and container for all objects being tracked. */ +#ifndef __RM_DEBUG_EVENTHANDLER_H__ +#define __RM_DEBUG_EVENTHANDLER_H__ + + +class DRM_DebugEventHandler : public DKernelEventHandler +{ + public: + DRM_DebugEventHandler(); + TInt Create(DLogicalDevice* aDevice, DLogicalChannel* aChannel, DThread* aClient); + ~DRM_DebugEventHandler(); + TInt Start(); + TInt Stop(); + + inline void DRM_DebugEventHandler::LockDataAccess() + { + Kern::SemaphoreWait(*iProtectionLock); + } + + inline void DRM_DebugEventHandler::ReleaseDataAccess() + { + Kern::SemaphoreSignal(*iProtectionLock); + } + + private: + static TUint EventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis); + TUint HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2); + TBool HandleSpecificEvent(TKernelEvent aType, TAny* a1, TAny* a2); + + private: + /** Used to serialise access data structures */ + DSemaphore* iProtectionLock; + + TBool iTracking; + + DLogicalDevice* iDevice; // open reference to LDD for avoiding lifetime issues + DThread* iClientThread; + DRM_DebugChannel* iChannel; + + // typdef for functions which handle our specific events + typedef TBool (DRM_DebugChannel::*eventHandler)(TAny* a1, TAny* a2); + eventHandler iEventHandlers[EEventLimit]; +}; + +#endif //__RM_DEBUG_EVENTHANDLER_H__ diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/inc/rm_debug_kerneldriver.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/inc/rm_debug_kerneldriver.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,777 @@ +// Copyright (c) 2004-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: +// + + + +/** + @file + @internalTechnology + @released +*/ + +#ifndef __RM_DEBUG_KERNELDRIVER_H__ +#define __RM_DEBUG_KERNELDRIVER_H__ + +#include + +/** +Used to store a value read from or written to an ARM register +*/ +typedef TUint32 T4ByteRegisterValue; + + +/** +Provides static methods for accessing the information stored in a TRegisterInfo +object. +*/ +class Register + { +public: + static TBool IsCoreReg(const Debug::TRegisterInfo aRegister); + static TBool IsCoproReg(const Debug::TRegisterInfo aRegister); + static TUint32 GetCoreRegId(const Debug::TRegisterInfo aRegister); + static TUint32 GetCRm(const Debug::TRegisterInfo aRegister); + static TUint32 GetCRn(const Debug::TRegisterInfo aRegister); + static TUint32 GetOpcode1(const Debug::TRegisterInfo aRegister); + static TUint32 GetOpcode2(const Debug::TRegisterInfo aRegister); + static TUint32 GetCoproNum(const Debug::TRegisterInfo aRegister); + }; + +/** +Identify whether aRegister is a core register +@param aRegister register ID to analyse +@return ETrue if core register, EFalse otherwise +*/ +inline TBool Register::IsCoreReg(const Debug::TRegisterInfo aRegister) + { + return ((aRegister & 0xff) == 0x0); + } + +/** +Identify whether aRegister is a coprocessor register +@param aRegister register ID to analyse +@return ETrue if coprocessor register, EFalse otherwise +*/ +inline TBool Register::IsCoproReg(const Debug::TRegisterInfo aRegister) + { + return ((aRegister & 0xff) == 0x1); + } + +/** +Get the ID of the core register +@param aRegister register ID to analyse +@return ID of the core register +*/ +inline TUint32 Register::GetCoreRegId(const Debug::TRegisterInfo aRegister) + { + return ((aRegister >> 8) & 0xff); + } + +/** +Get the CRm value of a coprocessor register +@param aRegister register ID to analyse +@return the CRm value of a coprocessor register +*/ +inline TUint32 Register::GetCRm(const Debug::TRegisterInfo aRegister) + { + return ((aRegister >> 16) & 0xf); + } + +/** +Get the CRm value of a coprocessor register +@param aRegister register ID to analyse +@return the CRm value of a coprocessor register +*/ +inline TUint32 Register::GetCRn(const Debug::TRegisterInfo aRegister) + { + return ((aRegister >> 20) & 0xf); + } + +/** +Get the Opcode1 value of a coprocessor register +@param aRegister register ID to analyse +@return the Opcode1 value of a coprocessor register +*/ +inline TUint32 Register::GetOpcode1(const Debug::TRegisterInfo aRegister) + { + return ((aRegister >> 24) & 0x8); + } + +/** +Get the Opcode2 value of a coprocessor register +@param aRegister register ID to analyse +@return the Opcode2 value of a coprocessor register +*/ +inline TUint32 Register::GetOpcode2(const Debug::TRegisterInfo aRegister) + { + return ((aRegister >> 27) & 0x8); + } + +/** +Get the coprocessor number of a coprocessor register +@param aRegister register ID to analyse +@return the coprocessor number of a coprocessor register +*/ +inline TUint32 Register::GetCoproNum(const Debug::TRegisterInfo aRegister) + { + return ((aRegister >> 8) & 0xff); + } + +// +// class TCapsRM_DebugDriver +// +class TCapsRM_DebugDriver +{ +public: + TVersion iVersion; +}; + +/** +Stores listings information for passing between the DSS and the kernel driver +*/ +class TListInformation +{ +public: + inline TListInformation(const Debug::TListId aType=(Debug::TListId)NULL, const Debug::TListScope aListScope=(Debug::TListScope)NULL, TDes8* aBuffer=NULL, TUint32* aDataSize=NULL, TUint64 aTargetId=0) + : iType(aType), + iListScope(aListScope), + iBuffer(aBuffer), + iDataSize(aDataSize), + iTargetId(aTargetId) {}; +public: + Debug::TListId iType; + Debug::TListScope iListScope; + TDes8* iBuffer; + TUint32* iDataSize; + TUint64 iTargetId; +}; + +/** +Data structure to hold information to the crash flash +(Possibly: Could be expanded to hold on configuration data too) +*/ +class TFlashInfo +{ +public: + inline TFlashInfo(TUint32 aPos, TUint32* aSize, TDes8* aData) + :iPos(aPos), + iSize(aSize), + iData(aData){}; +public: + TUint32 iPos; + TUint32* iSize; + TDes8* iData; +}; +// +// class TRM_DebugMemoryInfo +// +class TRM_DebugMemoryInfo +{ +public: + + inline TRM_DebugMemoryInfo(const TUint32 aAddress, const TUint32 aLength, TDesC8 *aData) + : iAddress(aAddress), + iLength(aLength), + iData(aData) {}; + +public: + + TUint32 iAddress; + TUint32 iLength; + TDesC8* iData; +}; + + +/** +@deprecated +This class is only used by TRK phase 1 functions. + +@see TRM_DebugRegisterInformation which offers similar storage suitable for use +with the TRK pahse 2 API. +*/ +class TRM_DebugRegisterInfo +{ +public: + + inline TRM_DebugRegisterInfo(const TInt16 aFirstRegister, const TInt16 aLastRegister, TDesC8 *aValues) + : iFirstRegister(aFirstRegister), + iLastRegister(aLastRegister), + iValues(aValues) {}; + +public: + + TInt16 iFirstRegister; + TInt16 iLastRegister; + TDesC8* iValues; +}; + +/** +Structure used to store information about registers +*/ +class TRM_DebugRegisterInformation +{ +public: + + inline TRM_DebugRegisterInformation(const TDes8 *aRegisterIds=NULL, TDes8 *aRegisterValues=NULL, TDes8 *aRegisterFlags=NULL) + : iRegisterIds(aRegisterIds), + iRegisterValues(aRegisterValues), + iRegisterFlags(aRegisterFlags) {}; + +public: + + const TDes8* iRegisterIds; + TDes8* iRegisterValues; + TDes8* iRegisterFlags; +}; + +// +// class TRM_DebugTaskInfo +// +class TRM_DebugTaskInfo +{ +public: + + inline TRM_DebugTaskInfo(TUint32 aOtherId) + : iId(0), + iOtherId(aOtherId), + iPriority(0) { iName.FillZ(); }; + +public: + + TUint32 iId; + TUint32 iOtherId; + TUint32 iPriority; + TBuf8 iName; +}; + +// +// class TRM_DebugStepInfo +// +class TRM_DebugStepInfo +{ +public: + + inline TRM_DebugStepInfo(const TUint32 aStartAddress, const TUint32 aStopAddress, const TBool aStepInto) + : iStartAddress(aStartAddress), + iStopAddress(aStopAddress), + iStepInto(aStepInto) {}; + +public: + + TUint32 iStartAddress; + TUint32 iStopAddress; + TBool iStepInto; +}; + + +// +// class TRM_DebugDriverInfo +// +class TRM_DebugDriverInfo +{ +public: + + TUint32 iPanic1Address; + TUint32 iPanic2Address; + TUint32 iException1Address; + TUint32 iException2Address; + TUint32 iLibraryLoadedAddress; + TUint32 iUserLibraryEnd; +}; + + +// +// class TRM_DebugProcessInfo +// +class TRM_DebugProcessInfo +{ +public: + + inline TRM_DebugProcessInfo(TUint32 *aCodeAddress, TUint32 *aDataAddress) + : iCodeAddress(aCodeAddress), + iDataAddress(aDataAddress) {}; + +public: + + TUint32* iCodeAddress; + TUint32* iDataAddress; +}; + +// +// class TRM_DebugEventActionInfo +// +class TRM_DebugEventActionInfo +{ +public: + inline TRM_DebugEventActionInfo(TUint32 aEvent, TUint32 aAction, TUint64 aAgentId) + : iEvent(aEvent), + iAction(aAction), + iAgentId(aAgentId) {}; +public: + TUint32 iEvent; + TUint32 iAction; + TUint64 iAgentId; +}; + +// +// class TRM_DebugEventInfo +// +class TRM_DebugEventInfo +{ +public: + inline TRM_DebugEventInfo(TDesC8& aProcessName, TUint32& aBufSize) + : iProcessName(aProcessName), + iBufSize(aBufSize) {}; + +public: + TDesC8& iProcessName; + TUint32& iBufSize; +}; + +// +// class TRMD_DebugAgentId +// +class TRM_DebugAgentId +{ +public: + inline TRM_DebugAgentId(TUint64 aAgentId) + : iAgentId(aAgentId) {}; + +public: + TUint64 iAgentId; +}; + +// +// Class TRMD_DebugCancelInfo +// +class TRMD_DebugCancelInfo +{ +public: + inline TRMD_DebugCancelInfo(TUint32 aCancelRequest,TDesC8& aProcessName, TUint64 aAgentId) + : iCancelRequest(aCancelRequest), + iProcessName(aProcessName), + iAgentId(aAgentId) {}; + + inline TRMD_DebugCancelInfo(void) + : iCancelRequest(0), + iAgentId(0) + { + }; + +public: + TUint32 iCancelRequest; + TBuf8 iProcessName; + TUint64 iAgentId; +}; + +class TEventMetaData + { +public: + TBuf8 iTargetProcessName; + TUint64 iDebugAgentProcessId; + }; + +/** +@internalComponent +*/ +class TSetBreakInfo +{ +public: + + inline TSetBreakInfo(Debug::TBreakId* aBreakId, + TUint64 aId,\ + TUint32 aAddress,\ + Debug::TArchitectureMode aMode, + TBool aThreadSpecific) + : iBreakId(aBreakId), + iId(aId), + iAddress(aAddress), + iMode(aMode), + iThreadSpecific(aThreadSpecific) {}; + +inline TSetBreakInfo(void) + : iBreakId((Debug::TBreakId*)0), + iId(0), + iAddress(0), + iMode(Debug::EArmMode), + iThreadSpecific(ETrue) {}; + + +public: + Debug::TBreakId* iBreakId; + TUint64 iId; + TUint32 iAddress; + Debug::TArchitectureMode iMode; + TBool iThreadSpecific; +}; + +/** +@internalComponent +*/ +class TModifyBreakInfo +{ +public: + + inline TModifyBreakInfo(Debug::TBreakId aBreakId,\ + const TUint64 aThreadId,\ + const TUint32 aAddress,\ + const Debug::TArchitectureMode aMode) + : iBreakId(aBreakId), + iThreadId(aThreadId), + iAddress(aAddress), + iMode(aMode) {}; + +public: + const Debug::TBreakId iBreakId; + const TUint64 iThreadId; + const TUint32 iAddress; + const Debug::TArchitectureMode iMode; +}; + +/** +@internalComponent +*/ +class TModifyProcessBreakInfo +{ +public: + + inline TModifyProcessBreakInfo(Debug::TBreakId aBreakId,\ + const TUint64 aProcessId,\ + const TUint32 aAddress,\ + const Debug::TArchitectureMode aMode) + : iBreakId(aBreakId), + iProcessId(aProcessId), + iAddress(aAddress), + iMode(aMode) {}; + +public: + const Debug::TBreakId iBreakId; + const TUint64 iProcessId; + const TUint32 iAddress; + const Debug::TArchitectureMode iMode; +}; + +/** +@internalComponent +*/ +class TGetBreakInfo +{ +public: + + inline TGetBreakInfo(Debug::TBreakId aBreakId,\ + TUint64& aId,\ + TUint32& aAddress,\ + Debug::TArchitectureMode& aMode, + TBool& aThreadSpecific) + : iBreakId(aBreakId), + iId(&aId), + iAddress(&aAddress), + iMode(&aMode), + iThreadSpecific(&aThreadSpecific) {}; + + inline TGetBreakInfo() + : iBreakId((Debug::TBreakId)0), + iId((TUint64*)0), + iAddress((TUint32*)0), + iMode((Debug::TArchitectureMode*)0), + iThreadSpecific((TBool*)0) {}; + +public: + const Debug::TBreakId iBreakId; + TUint64* iId; + TUint32* iAddress; + Debug::TArchitectureMode* iMode; + TBool* iThreadSpecific; +}; + +// +// class RRM_DebugDriver +// +class RRM_DebugDriver : public RBusLogicalChannel +{ +public: + + enum TControl + { + EControlSetBreak = 0, + EControlClearBreak, + EControlModifyBreak, + EControlBreakInfo, + EControlSuspendThread, + EControlResumeThread, + EControlStepRange, + EControlReadMemory, + EControlWriteMemory, + EControlReadRegisters, + EControlWriteRegisters, + EControlGetStaticLibraryInfo, + EControlGetDebugFunctionalityBufSize, + EControlGetDebugFunctionality, + EControlReadRegistersLegacy, + EControlWriteRegistersLegacy, + EControlGetMemoryOperationMaxBlockSize, + EControlAttachProcess, + EControlDetachProcess, + EControlDetachAgent, + EControlSetEventAction, + EControlGetList, + EControlStep, + EControlIsDebuggable, + EControlKillProcess, + EControlModifyProcessBreak, + }; + + enum TRequest + { + ERequestGetEvent=0x0, ERequestGetEventCancel=0x1 + }; + +public: + + inline TInt Open(const TRM_DebugDriverInfo aDriverInfo); + + inline TInt SetBreak(Debug::TBreakId &aBreakId,const TUint32 aThreadId, const TUint32 aAddress, const Debug::TArchitectureMode aThumbMode ); + inline TInt SetProcessBreak(Debug::TBreakId &aBreakId,const TUint32 aProcessId, const TUint32 aAddress, const Debug::TArchitectureMode aThumbMode ); + + inline TInt ClearBreak(const TInt32 aBreakId); + + inline TInt ModifyBreak(const Debug::TBreakId aBreakId, const TUint32 aThreadId, const TUint32 aAddress, const Debug::TArchitectureMode aArchitectureMode ); + inline TInt ModifyProcessBreak(const Debug::TBreakId aBreakId, const TUint32 aProcessId, const TUint32 aAddress, const Debug::TArchitectureMode aArchitectureMode ); + + inline TInt BreakInfo(const Debug::TBreakId aBreakId, TUint64& aId, TUint32& aAddress, Debug::TArchitectureMode& aMode, TBool& aThreadSpecific); + + inline TInt SuspendThread(const TUint32 aThreadId); + inline TInt ResumeThread(const TUint32 aThreadId); + inline TInt StepRange(const TUint32 aThreadId, const TUint32 aStartAddress, const TUint32 aStopAddress, TBool aStepInto); + inline TInt ReadMemory(const TUint32 aThreadId, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData); + inline TInt WriteMemory(const TUint32 aThreadId, const TUint32 aAddress, const TUint32 aLength, const TDesC8 &aData); + inline TInt ReadRegisters(const TUint32 aThreadId, const TDes8 &aRegisterIds, TDes8 &aRegisterValues, TDes8 &aRegisterFlags); + inline TInt WriteRegisters(const TUint32 aThreadId, const TDes8 &aRegisterIds, const TDes8 &aRegisterValues, TDes8 &aRegisterFlags); + inline TInt ReadRegisters(const TUint32 aThreadId, const TInt32 aFirstRegister, const TInt32 aLastRegister, TDes8 &aValues); + inline TInt WriteRegisters(const TUint32 aThreadId, const TInt32 aFirstRegister, const TInt32 aLastRegister, TDesC8 &aValues); + inline void GetEvent(TDesC8& aProcessName, TUint64 aAgentId, TRequestStatus &aStatus, Debug::TEventInfo &aEventInfo); + inline void CancelGetEvent(TDesC8& aProcessName, TUint64 aAgentId); +// inline TInt GetProcessInfo(const TInt aIndex, TRM_DebugTaskInfo &aInfo); +// inline TInt GetThreadInfo(const TInt aIndex, TRM_DebugTaskInfo &aInfo); + inline TInt GetStaticLibraryInfo(const TInt aIndex, Debug::TEventInfo &aInfo); + inline TInt GetDebugFunctionalityBufSize(TUint32 &aBufSize); + inline TInt GetDebugFunctionality(TDes8& aDebugFunctionality); + inline TInt GetMemoryOperationMaxBlockSize(TUint32 &aMaxSize); + inline TInt AttachProcess(TDesC8& aProcessName, TUint64 aAgentId); + inline TInt DetachProcess(TDesC8& aProcessName, TUint64 aAgentId); + inline TInt DetachAgent(TUint64 aAgentId); + inline TInt SetEventAction(TDesC8& aProcessName, Debug::TEventType aEvent, Debug::TKernelEventAction aEventAction, TUint64 aAgentId); + inline TInt GetList(const Debug::TListId aType, const Debug::TListScope aListScope, const TUint64 aTargetId, const TUint64 aDebugProcessId, TDes8& aBuffer, TUint32& aDataSize); + inline TInt Step(const TUint32 aThreadId, const TUint32 aNumSteps); + inline TInt IsDebuggable(const TUint32 aProcessId); + inline TInt KillProcess(const TUint32 aProcessId, const TInt32 aReason); +}; + +_LIT(KRM_DebugDriverName,"RM Debug Driver"); + +//priority set equal to that of KDfcThread0Priority defined in e32/kernel/sinit.cpp +const TInt KRmDebugDriverThreadPriority = 27; + +// Version information +const TInt KMajorVersionNumber=2; +const TInt KMinorVersionNumber=1; +const TInt KBuildVersionNumber=0; + + +inline TInt RRM_DebugDriver::Open(const TRM_DebugDriverInfo aDriverInfo) +{ + TBuf8<32> buf; + buf.Append((TUint8*)&aDriverInfo.iPanic1Address, 4); + buf.Append((TUint8*)&aDriverInfo.iPanic2Address, 4); + buf.Append((TUint8*)&aDriverInfo.iException1Address, 4); + buf.Append((TUint8*)&aDriverInfo.iException2Address, 4); + buf.Append((TUint8*)&aDriverInfo.iLibraryLoadedAddress, 4); + buf.Append((TUint8*)&aDriverInfo.iUserLibraryEnd, 4); + + #ifdef EKA2 + return DoCreate(KRM_DebugDriverName, TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber), KNullUnit, NULL, &buf); + #else + return DoCreate(KRM_DebugDriverName, TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber), NULL, KNullUnit, NULL, &buf); + #endif +} + +inline TInt RRM_DebugDriver::SetBreak(Debug::TBreakId &aBreakId, const TUint32 aThreadId, const TUint32 aAddress, const Debug::TArchitectureMode aMode ) +{ + TSetBreakInfo info(&aBreakId, aThreadId, aAddress, aMode, ETrue); + return DoSvControl(EControlSetBreak, reinterpret_cast(&info),0); +} +inline TInt RRM_DebugDriver::SetProcessBreak(Debug::TBreakId &aBreakId, const TUint32 aProcessId, const TUint32 aAddress, const Debug::TArchitectureMode aMode ) +{ + TSetBreakInfo info(&aBreakId, aProcessId, aAddress, aMode, EFalse); + return DoSvControl(EControlSetBreak, reinterpret_cast(&info),0); +} + +inline TInt RRM_DebugDriver::ClearBreak(const Debug::TBreakId aBreakId) +{ + return DoSvControl(EControlClearBreak, reinterpret_cast(aBreakId), 0); +} + +inline TInt RRM_DebugDriver::ModifyBreak(const Debug::TBreakId aBreakId, const TUint32 aThreadId, const TUint32 aAddress, const Debug::TArchitectureMode aMode) +{ + TModifyBreakInfo info(aBreakId, aThreadId, aAddress, aMode); + return DoControl(EControlModifyBreak, reinterpret_cast(&info), 0); +} + +inline TInt RRM_DebugDriver::ModifyProcessBreak(const Debug::TBreakId aBreakId, const TUint32 aProcessId, const TUint32 aAddress, const Debug::TArchitectureMode aMode) +{ + TModifyProcessBreakInfo info(aBreakId, aProcessId, aAddress, aMode); + return DoControl(EControlModifyProcessBreak, reinterpret_cast(&info), 0); +} + +inline TInt RRM_DebugDriver::BreakInfo(const Debug::TBreakId aBreakId, TUint64& aId, TUint32& aAddress, Debug::TArchitectureMode& aMode, TBool& aThreadSpecific) +{ + TGetBreakInfo info(aBreakId, aId, aAddress, aMode, aThreadSpecific); + return DoControl(EControlBreakInfo, reinterpret_cast(&info), 0); +} + +inline TInt RRM_DebugDriver::SuspendThread(const TUint32 aThreadId) +{ + return DoControl(EControlSuspendThread, reinterpret_cast(aThreadId)); +} + +inline TInt RRM_DebugDriver::ResumeThread(const TUint32 aThreadId) +{ + return DoSvControl(EControlResumeThread, reinterpret_cast(aThreadId)); +} + +inline TInt RRM_DebugDriver::StepRange(const TUint32 aThreadId, const TUint32 aStartAddress, const TUint32 aStopAddress, TBool aStepInto) +{ + TRM_DebugStepInfo info(aStartAddress, aStopAddress, aStepInto); + return DoSvControl(EControlStepRange, reinterpret_cast(aThreadId), (TAny*)&info); +} + +inline TInt RRM_DebugDriver::ReadMemory(const TUint32 aThreadId, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) +{ + TRM_DebugMemoryInfo info(aAddress, aLength, &aData); + return DoControl(EControlReadMemory, reinterpret_cast(aThreadId), (TAny*)&info); +} + +inline TInt RRM_DebugDriver::WriteMemory(const TUint32 aThreadId, const TUint32 aAddress, const TUint32 aLength, const TDesC8 &aData) +{ + TRM_DebugMemoryInfo info(aAddress, aLength, (TDesC8*)&aData); + return DoControl(EControlWriteMemory, reinterpret_cast(aThreadId), (TAny*)&info); +} + +inline TInt RRM_DebugDriver::ReadRegisters(const TUint32 aThreadId, const TDes8 &aRegisterIds, TDes8 &aRegisterValues, TDes8 &aRegisterFlags) + { + TRM_DebugRegisterInformation info(&aRegisterIds, &aRegisterValues, &aRegisterFlags); + return DoControl(EControlReadRegisters, reinterpret_cast(aThreadId), (TAny*)&info); + } + +inline TInt RRM_DebugDriver::WriteRegisters(const TUint32 aThreadId, const TDes8 &aRegisterIds, const TDes8 &aRegisterValues, TDes8 &aRegisterFlags) + { + TRM_DebugRegisterInformation info(&aRegisterIds, (TDes8*)&aRegisterValues, &aRegisterFlags); + return DoControl(EControlWriteRegisters, reinterpret_cast(aThreadId), (TAny*)&info); + } + +inline TInt RRM_DebugDriver::ReadRegisters(const TUint32 aThreadId, const TInt32 aFirstRegister, const TInt32 aLastRegister, TDes8 &aValues) +{ + TRM_DebugRegisterInfo info(aFirstRegister, aLastRegister, &aValues); + return DoControl(EControlReadRegistersLegacy, reinterpret_cast(aThreadId), (TAny*)&info); +} + +inline TInt RRM_DebugDriver::WriteRegisters(const TUint32 aThreadId, const TInt32 aFirstRegister, const TInt32 aLastRegister, TDesC8 &aValues) +{ + TRM_DebugRegisterInfo info(aFirstRegister, aLastRegister, &aValues); + return DoControl(EControlWriteRegistersLegacy, reinterpret_cast(aThreadId), (TAny*)&info); +} + +inline void RRM_DebugDriver::GetEvent(TDesC8& aProcessName, TUint64 aAgentId, TRequestStatus &aStatus, Debug::TEventInfo &aEventInfo) +{ + // temporary object not needed beyond the DoRequest call + TEventMetaData eventMetaData; + eventMetaData.iTargetProcessName.Copy(aProcessName); + eventMetaData.iDebugAgentProcessId = aAgentId; + DoRequest(ERequestGetEvent, aStatus, (TAny*)&aEventInfo, (TAny*)&eventMetaData); +} + +inline void RRM_DebugDriver::CancelGetEvent(TDesC8& aProcessName, TUint64 aAgentId) +{ + TRMD_DebugCancelInfo info(ERequestGetEventCancel,aProcessName,aAgentId); + DoCancel(reinterpret_cast(&info)); +} + +inline TInt RRM_DebugDriver::GetStaticLibraryInfo(const TInt aIndex, Debug::TEventInfo &aInfo) +{ + return DoControl(EControlGetStaticLibraryInfo, reinterpret_cast(aIndex), (TAny*)&aInfo); +} + +inline TInt RRM_DebugDriver::GetDebugFunctionalityBufSize(TUint32 &aBufSize) +{ + return DoControl(EControlGetDebugFunctionalityBufSize, reinterpret_cast(&aBufSize)); +} + +inline TInt RRM_DebugDriver::GetDebugFunctionality(TDes8& aDebugFunctionality) +{ + return DoControl(EControlGetDebugFunctionality,reinterpret_cast(&aDebugFunctionality)); +} + +inline TInt RRM_DebugDriver::GetMemoryOperationMaxBlockSize(TUint32 &aMaxSize) +{ + return DoControl(EControlGetMemoryOperationMaxBlockSize, reinterpret_cast(&aMaxSize)); +} + +inline TInt RRM_DebugDriver::AttachProcess(TDesC8& aProcessName, TUint64 aAgentId) +{ + TRM_DebugAgentId info(aAgentId); + return DoControl(EControlAttachProcess,reinterpret_cast(&aProcessName),reinterpret_cast(&info)); +} + +inline TInt RRM_DebugDriver::DetachProcess(TDesC8& aProcessName, TUint64 aAgentId) +{ + TRM_DebugAgentId info(aAgentId); + return DoControl(EControlDetachProcess,reinterpret_cast(&aProcessName),reinterpret_cast(&info)); +} + +inline TInt RRM_DebugDriver::DetachAgent(TUint64 aAgentId) +{ + TRM_DebugAgentId info(aAgentId); + return DoControl(EControlDetachAgent,reinterpret_cast(&info),0); +} + +inline TInt RRM_DebugDriver::SetEventAction(TDesC8& aProcessName, Debug::TEventType aEvent, Debug::TKernelEventAction aEventAction, TUint64 aAgentId) +{ + TRM_DebugEventActionInfo info (aEvent,aEventAction, aAgentId); + return DoControl(EControlSetEventAction,reinterpret_cast(&aProcessName),(TAny*)&info); +} + +inline TInt RRM_DebugDriver::GetList(const Debug::TListId aType, const Debug::TListScope aListScope, const TUint64 aTargetId, const TUint64 aDebugProcessId, TDes8& aBuffer, TUint32& aDataSize) +{ + TListInformation info(aType, aListScope, &aBuffer, &aDataSize, aTargetId); + return DoControl(EControlGetList, (TAny*)&info); +} + +inline TInt RRM_DebugDriver::Step(const TUint32 aThreadId, const TUint32 aNumSteps) +{ + return DoControl(EControlStep,reinterpret_cast(aThreadId),reinterpret_cast(aNumSteps)); +} + +inline TInt RRM_DebugDriver::IsDebuggable(const TUint32 aProcessId) +{ + return DoControl(EControlIsDebuggable,reinterpret_cast(aProcessId),NULL); +} + +inline TInt RRM_DebugDriver::KillProcess(const TUint32 aProcessId, const TInt32 aReason) +{ + return DoControl(EControlKillProcess,reinterpret_cast(aProcessId),reinterpret_cast(aReason)); +} + +#endif // __RM_DEBUG_KERNELDRIVER_H__ + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/d_debug_agent.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/d_debug_agent.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,468 @@ +// Copyright (c) 2006-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: +// Purpose: Kernel-side tracking of debug agent information associated +// with each process being debugged. +// +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "d_process_tracker.h" +#include "debug_logging.h" + +#include "d_debug_agent.h" +#include "debug_utils.h" + +#include "d_debug_agent.inl" + +using namespace Debug; + +// ctor +DDebugAgent::DDebugAgent(TUint64 aId) : + iId(aId), + iRequestGetEventStatus(NULL), + iClientThread(0), + iEventQueue(KNumberOfEventsToQueue, 0), + iHead(0), + iTail(0), + iEventQueueLock(NULL), + iFreeSlots(KNumberOfEventsToQueue), + iIgnoringTrace(EFalse), + iEventBalance(0) + { + LOG_MSG2("DDebugAgent::DDebugAgent(), this=0x%x ", this); + + // Initialize all the Event Actions to Ignore + for(TInt i=0; iConstruct()) + { + delete agent; + return (NULL); + } + + // Use a semaphore to serialise access + TInt err = Kern::SemaphoreCreate(agent->iEventQueueLock, _L("RM_DebugAgentQueueLock"), 1 /* Initial count */); + if (err != KErrNone) + return NULL; + + return agent; + } + +/** Standard contructor. + * Fills event queue with empty events + * @return : standard system error code + */ +TInt DDebugAgent::Construct() + { + // Empty the event queue + TDriverEventInfo emptyEvent; + TInt err = KErrNone; + + for (TInt i=0; iClose(NULL); + + if(iRequestGetEventStatus) + Kern::DestroyClientRequest(iRequestGetEventStatus); + + } + +// Associate an action with a particular kernel event +TInt DDebugAgent::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction) + { + // Valid Event? + if (aEvent >= EEventsLast) + { + LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent); + return KErrArgument; + } + + iEventActions[aEvent] = aEventAction; + + return KErrNone; + } + +/** Get the aEventAction associated with aEvent + * + * @return : aEventAction (always +ve), or KErrArgument. + */ +TInt DDebugAgent::EventAction(TEventType aEvent) + { + // Validate the Event id + if (aEvent >= EEventsLast) + { + LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent); + return KErrArgument; + } + + // Return the action associated with this event + return iEventActions[aEvent]; + } + +/** Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo + * If there is no event in the queue for this process+agent combination, store the details + * so that it can be notified later when an event actually occurs. + * + * @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory + * @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS. + */ +void DDebugAgent::GetEvent(TClientDataRequest* aAsyncGetValueRequest, DThread* aClientThread) + { + LockEventQueue(); + + iRequestGetEventStatus->Reset(); + TInt err = iRequestGetEventStatus->SetStatus( aAsyncGetValueRequest->StatusPtr() ); + if (err != KErrNone) + { + LOG_MSG2("Error :iRequestGetEventStatus->SetStatus ret %d", err); + UnlockEventQueue(); + return; + } + + iRequestGetEventStatus->SetDestPtr( aAsyncGetValueRequest->DestPtr() ); + + iEventBalance++; + + LOG_MSG5("DDebugAgent::GetEvent: this=0x%08x, iRequestGetEventStatus=0x%08x, iEventBalance=%d, destPrt=0x%08x", + this, iRequestGetEventStatus, iEventBalance, aAsyncGetValueRequest->DestPtr() ); + + iClientThread = aClientThread; + + if (BufferEmpty()) + { + LOG_MSG2("Event buffer empty, iEventBalance=%d", iEventBalance); + UnlockEventQueue(); + return; + } + + LOG_MSG5("Event already available at queue pos (tail)=%d, evType=%d, threadId=0x%x, actionTaken=%d", + iTail, iEventQueue[iTail].iEventType, + iEventQueue[iTail].iThreadId, iEventQueue[iTail].iActionTaken ); + + // returning the event to the client + err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread); + if (err != KErrNone) + { + LOG_MSG2("Error writing event info: %d", err); + UnlockEventQueue(); + return; + } + + // signal the DSS thread + Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone); + iEventBalance--; + + iEventQueue[iTail].Reset(); + + // move to the next slot + IncrementTailPosition(); + + UnlockEventQueue(); + } + +/** + * Stop waiting for an event to occur. This means events will be placed + * in the iEventQueue (by setting iEventBalance to 0) until GetEvent is called. + */ +TInt DDebugAgent::CancelGetEvent(void) + { + LOG_MSG2("DDebugAgent::CancelGetEvent. iEventBalance=%d. > QueueRequestComplete", iEventBalance); + Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel); + iEventBalance=0; + iClientThread = 0; + return KErrNone; + } + +/** Signal a kernel event to the user-side DSS when it occurs, or queue it for later + * if the user-side has not called GetEvent (see above). + * + * @param aEventInfo - the details of the event to queue. + */ +void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo) + { + + if(aEventInfo.iEventType >= EEventsLast) + { + LOG_MSG3("DDebugAgent::NotifyEvent(),iEventType %d, this=0x%x. Ignoring since > EEventsLast", aEventInfo.iEventType, this); + return; + } + + LockEventQueue(); + + DThread* currentThread = &Kern::CurrentThread(); + + + TKernelEventAction action = iEventActions[aEventInfo.iEventType]; + + if (aEventInfo.iProcessId == Id() && + (aEventInfo.iEventType == EEventsSwExc || aEventInfo.iEventType == EEventsHwExc || aEventInfo.iEventType == EEventsKillThread)) + { + + // It might be nice not to deliver *any* events about the debug agent to the agent itself, but this is a bit too drastic a change to make. + // There's a risk it might completely break TRK or similar, and at a more practical level it would require major rewriting of the t_rmdebug2 + // tests. + // + // So instead, we only don't suspend&deliver events about the debug agent IF it's a thread crash event AND the thread is process + // critical/permanent AND (in the case of a critical thread) it's an abnormal exit. We're not worrying (yet) about the case where the entire + // process is set as system critical + // This fixes the original problem with CDS's worker thread crashing, and doesn't wreck the t_rmdebug2 tests. + + TBool problematic = ( + (aEventInfo.iThreadFlags & (KThreadFlagProcessCritical|KThreadFlagSystemCritical) && (aEventInfo.iEventType != EEventsKillThread || aEventInfo.iExitType != EExitKill)) // process or system critical, and either an exception (not a EEventsKillThread) or a non EExitKill exit + || (aEventInfo.iThreadFlags & (KThreadFlagProcessPermanent|KThreadFlagSystemPermanent)) + ); + + if (problematic) + { + LOG_MSG("Agent is dying - no further events will be delivered to it"); + iAgentDying = ETrue; + } + + } + + if (iAgentDying && action == EActionSuspend) + { + LOG_MSG("Not delivering this event or suspending the thread because agent is dying"); + action = EActionIgnore; + } + + switch (action) + { + case EActionSuspend: + { + LOG_MSG5("DDebugAgent::NotifyEvent(), Suspend thread, iEventType %d, this=0x%x currThrd=0x%08x, iEventBalance=%d", + aEventInfo.iEventType, this, currentThread, iEventBalance ); + + switch(aEventInfo.iEventType) + { + case EEventsAddLibrary: + case EEventsRemoveLibrary: + // TomS: Anybody want to explain what is going on here?? + currentThread = DebugUtils::OpenThreadHandle(aEventInfo.iThreadId); + if(currentThread) + { + currentThread->Close(NULL); + } + break; + default: + break; + } + + // Do not call suspend for breakpoints, since the breakpoint code that runs when deciding if an exception + // is a breakpoint will itself suspend the thread + if( (aEventInfo.iEventType != EEventsBreakPoint) && (aEventInfo.iEventType != EEventsProcessBreakPoint) ) + { + TInt err = TheDProcessTracker.SuspendThread(currentThread, aEventInfo.FreezeOnSuspend()); + if((err != KErrNone) && (err != KErrAlreadyExists)) + { + // Is there anything we can do in the future to deal with this error having happened? + LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err); + } + } + + // now drop through to the continue case, which typically notifies + // the debug agent of the event + } + case EActionContinue: + { + if( action == EActionContinue ) + { + LOG_MSG5("DDebugAgent::NotifyEvent(), Action continue, iEventType %d, this=0x%x currThrd=0x%08x, iEventBalance=%d", + aEventInfo.iEventType, this, currentThread, iEventBalance ); + } + + // Queue this event + TDriverEventInfo eventInfo = aEventInfo; + eventInfo.iActionTaken = action; + QueueEvent(eventInfo); + + // Tell the user about the oldest event in the queue + if ( iClientThread ) + { + if( iRequestGetEventStatus && (iEventBalance > 0) ) + { + // Fill the event data + TInt err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread); + if (err != KErrNone) + { + LOG_MSG2("Error writing event info: %d", err); + } + + // signal the debugger thread + LOG_MSG4("> QueueRequestComplete iRequestGetEventStatus=0x%08x, iEventBalance=%d, iTail=%d", + iRequestGetEventStatus->iStatus, iEventBalance, iTail ); + Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone); + + iEventBalance--; + + iEventQueue[iTail].Reset(); + + // move to the next slot + IncrementTailPosition(); + } + else + { + if( !iRequestGetEventStatus ) + { + LOG_MSG("iRequestGetEventStatus is NULL so not signalling client" ); + } + else + { + LOG_MSG2("Queued event. iEventBalance=%d (unbalanced event requests vs notifications)", + iEventBalance ); + } + } + } + else + { + LOG_MSG("DDebugAgent::NotifyEvent() : Not informing client since its thread is NULL"); + } + break; + } + case EActionIgnore: + default: + // Ignore everything we don't understand. + break; + } + + UnlockEventQueue(); + + } + +// Used to identify which Debug Agent this DDebugAgent is associated with. +TUint64 DDebugAgent::Id(void) + { + return iId; + } + +/** + * Used to add an event to the event queue for this debug agent if event + * queue is not at critical level. If it is at critical and it is trace event, + * we start ignoring trace events and insert a lost trace event. + * If the buffer cannot store an event, only insert a buffer full event. + * @see EEventsBufferFull + * @see EEventsUserTracesLost + * @see TDriverEventInfo + * @see iEventQueue + */ +void DDebugAgent::QueueEvent(const TDriverEventInfo& aEventInfo) + { + // Have we caught the tail? + if(BufferFull()) + { + LOG_MSG("DDebugAgent::QueueEvent : BufferFull. Not queueing"); + return; + } + + // Assert if we think there is space but the slot is not marked empty + __NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown); + + const TBool bufferAtCritical = BufferAtCriticalLevel(); + + if(!bufferAtCritical) + { + //reset the iIgnoringTrace flag as we are not at + //critical level and can store event + iIgnoringTrace = EFalse; + + // Insert the event into the ring buffer at iHead + iEventQueue[iHead] = aEventInfo; + IncrementHeadPosition(); + } + else if(bufferAtCritical && BufferCanStoreEvent()) + { + LOG_MSG("DDebugAgent::QueueEvent : BufferCritical"); + if(aEventInfo.iEventType == EEventsUserTrace) + { + if(!iIgnoringTrace) + { + //if this is the first time we are ignoring trace events, + //we need to issue a EEventsUserTracesLost event + iEventQueue[iHead].Reset(); + iEventQueue[iHead].iEventType = EEventsUserTracesLost; + IncrementHeadPosition(); + + iIgnoringTrace = ETrue; + } + else + { + //otherwise, ignore this event + LOG_MSG("DDebugAgent::QueueEvent : Ignore EEventsUserTrace event"); + } + } + else + { + // Store the event since its not a trace event + iEventQueue[iHead] = aEventInfo; + IncrementHeadPosition(); + } + } + else + { + //At critical level and cannot store new events, so + //only one space left. Store a EEventsBufferFull event + LOG_MSG("DDebugAgent::QueueEvent : Event Buffer Full, ignoring event"); + iEventQueue[iHead].Reset(); + iEventQueue[iHead].iEventType = EEventsBufferFull; + IncrementHeadPosition(); + } + } + +// End of file - d_debug_agent.cpp diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/d_debug_functionality.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/d_debug_functionality.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,426 @@ +// Copyright (c) 2006-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: +// Defines the DebugFunctionality class. This is responsible for +// providing configuration data needed by a host debugger to be able +// to correctly use the functionality provided by the run-mode debug subsystem. +// + +#include +#include +#include +#include +#include +#include +#include +#include "d_rmd_breakpoints.h" +#include "rm_debug_kerneldriver.h" +#include "d_debug_functionality.h" + +using namespace Debug; + +// Core +const TTag DebugFunctionalityCoreInfo[] = + { + {ECoreEvents,ETagTypeBoolean,0,ETrue}, + {ECoreStartStop,ETagTypeBoolean,0,ETrue}, + {ECoreMemory,ETagTypeBoolean,0,ETrue}, + {ECoreRegister,ETagTypeBoolean,0,ETrue}, + {ECoreBreakpoint,ETagTypeBoolean,0,ETrue}, + {ECoreStepping,ETagTypeBoolean,0,ETrue}, + {ECoreLists,ETagTypeBoolean,0,ETrue}, + {ECoreLogging,ETagTypeBoolean,0,EFalse}, + {ECoreHardware,ETagTypeBoolean,0,EFalse}, + {ECoreApiConstants,ETagTypeBoolean,0,ETrue}, + {ECoreKillObjects,ETagTypeBoolean,0,ETrue}, + {ECoreSecurity,ETagTypeBoolean,0,ETrue}, + }; + +const TSubBlock DebugFunctionalityCore[] = + { + ETagHeaderIdCore,ECoreLast, + (TTag*)DebugFunctionalityCoreInfo + }; + +// Memory +const TTag DebugFunctionalityMemoryInfo[] = + { + {EMemoryRead,ETagTypeBoolean,0,ETrue}, + {EMemoryWrite,ETagTypeBoolean,0,ETrue}, + {EMemoryAccess64,ETagTypeBoolean,0,EFalse}, + {EMemoryAccess32,ETagTypeBoolean,0,ETrue}, + {EMemoryAccess16,ETagTypeBoolean,0,EFalse}, + {EMemoryAccess8,ETagTypeBoolean,0,EFalse}, + {EMemoryBE8,ETagTypeBoolean,0,EFalse}, + {EMemoryBE32,ETagTypeBoolean,0,EFalse}, + {EMemoryLE8,ETagTypeBoolean,0,ETrue}, + {EMemoryMaxBlockSize,ETagTypeTUint32,0,16 * KKilo /* 16Kbytes */} // binaryMax size of memory requests in bytes + }; + +const TSubBlock DebugFunctionalityMemory[]= + { + ETagHeaderIdMemory,EMemoryLast, + (TTag*)DebugFunctionalityMemoryInfo + }; + +// Kill Objects +const TTag DebugFunctionalityKillObjectsInfo[] = + { + {EFunctionalityKillThread,ETagTypeBoolean,0,EFalse}, + {EFunctionalityKillProcess,ETagTypeBoolean,0,ETrue} + }; + +const TSubBlock DebugFunctionalityKillObjects[]= + { + ETagHeaderIdKillObjects,EFunctionalityKillObjectLast, + (TTag*)DebugFunctionalityKillObjectsInfo + }; + +// Core Registers +const TTag DebugFunctionalityRegistersCoreInfo[] = + { + {ERegisterR0,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR1,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR2,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR3,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR4,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR5,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR6,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR7,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR8,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR9,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR10,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR11,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR12,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR13,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR14,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR15,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterCpsr,ETagTypeEnum, 4,EAccessReadWrite}, + {ERegisterR13Svc,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR14Svc,ETagTypeEnum, 4,EAccessNone}, + {ERegisterSpsrSvc,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR13Abt,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR14Abt,ETagTypeEnum, 4,EAccessNone}, + {ERegisterSpsrAbt,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR13Und,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR14Und,ETagTypeEnum, 4,EAccessNone}, + {ERegisterSpsrUnd,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR13Irq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR14Irq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterSpsrIrq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR8Fiq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR9Fiq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR10Fiq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR11Fiq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR12Fiq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR13Fiq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterR14Fiq,ETagTypeEnum, 4,EAccessNone}, + {ERegisterSpsrFiq, ETagTypeEnum, 4,EAccessNone} + }; + +const TSubBlock DebugFunctionalityRegistersCore[] = + { + ETagHeaderIdRegistersCore, ERegisterLast, + (TTag*)DebugFunctionalityRegistersCoreInfo + }; + +// Co-processor registers +const TTag DebugFunctionalityRegistersCoProInfo[]= + { + //this is the DACR register + {0x00300f01, ETagTypeTUint32, 4, EAccessReadWrite} + }; + +const TSubBlock DebugFunctionalityRegistersCoPro[]= + { + ETagHeaderIdCoProRegisters,1, + (TTag*)DebugFunctionalityRegistersCoProInfo + }; + +// Breakpoints +const TTag DebugFunctionalityBreakpointsInfo[]= + { + {EBreakpointThread,ETagTypeBoolean,0,ETrue}, + {EBreakpointProcess,ETagTypeBoolean,0,ETrue}, + {EBreakpointSystem,ETagTypeBoolean,0,EFalse}, + {EBreakpointArm,ETagTypeBoolean,0,ETrue}, + {EBreakpointThumb,ETagTypeBoolean,0,ETrue}, + {EBreakpointT2EE,ETagTypeBoolean,0,ETrue}, + {EBreakpointArmInst,ETagTypeBoolean,0,EFalse}, + {EBreakpointThumbInst,ETagTypeBoolean,0,EFalse}, + {EBreakpointT2EEInst,ETagTypeBoolean,0,ETrue}, + {EBreakpointSetArmInst,ETagTypeBoolean,0,EFalse}, + {EBreakpointSetThumbInst,ETagTypeBoolean,0,EFalse}, + {EBreakpointSetT2EEInst,ETagTypeBoolean,0,ETrue} + }; + +const TSubBlock DebugFunctionalityBreakpoints[] = + { + ETagHeaderIdBreakpoints, EBreakpointLast, + (TTag*)DebugFunctionalityBreakpointsInfo + }; + +// Stepping +const TTag DebugFunctionalitySteppingInfo[]= + { + {EStep,ETagTypeBoolean,0,ETrue} + }; + +const TSubBlock DebugFunctionalityStepping[] = + { + ETagHeaderIdStepping, EStepLast, + (TTag*)DebugFunctionalitySteppingInfo + }; + +// Execution Control +const TTag DebugFunctionalityExecutionInfo[]= + { + {EExecThreadSuspendResume,ETagTypeBoolean,0,ETrue}, + {EExecProcessSuspendResume,ETagTypeBoolean,0,EFalse}, + {EExecSystemSuspendResume,ETagTypeBoolean,0,EFalse}, + }; + +const TSubBlock DebugFunctionalityExecution[]= + { + ETagHeaderIdExecution, EExecLast, + (TTag*)DebugFunctionalityExecutionInfo + }; + +// Events +const TTag DebugFunctionalityEventsInfo[]= + { + {EEventsBreakPoint,ETagTypeEnum,0,EActionSuspend}, + {EEventsProcessBreakPoint,ETagTypeEnum,0,EActionSuspend}, + {EEventsSwExc,ETagTypeEnum,0,EActionSuspend}, + {EEventsHwExc,ETagTypeEnum,0,EActionSuspend}, + {EEventsKillThread,ETagTypeEnum,0,EActionContinue}, + {EEventsAddLibrary,ETagTypeEnum,0,EActionSuspend}, + {EEventsRemoveLibrary,ETagTypeEnum,0,EActionSuspend}, + {EEventsUserTrace,ETagTypeEnum,0,EActionSuspend}, + {EEventsStartThread,ETagTypeEnum,0,EActionSuspend}, + {EEventsBufferFull,ETagTypeEnum,0,EActionContinue}, + {EEventsUnknown,ETagTypeEnum,0,EActionContinue}, + {EEventsUserTracesLost, ETagTypeEnum, 0, EActionContinue}, + {EEventsAddProcess,ETagTypeEnum,0,EActionContinue}, + {EEventsRemoveProcess,ETagTypeEnum,0,EActionContinue} + }; + +const TSubBlock DebugFunctionalityEvents[] = + { + ETagHeaderIdEvents, EEventsLast, + (TTag*)DebugFunctionalityEventsInfo + }; + +// API Constants +const TTag DebugFunctionalityApiConstantsInfo[]= + { + {EApiConstantsTEventInfoSize,ETagTypeTUint32,0,sizeof(TEventInfo)}, + }; + +const TSubBlock DebugFunctionalityApiConstants[] = + { + ETagHeaderIdApiConstants, EApiConstantsLast, + (TTag*)DebugFunctionalityApiConstantsInfo + }; + +// Listings +const TTag DebugFunctionalityListInfo[] = + { + {EProcesses,ETagTypeBitField,0,EScopeGlobal}, + {EThreads,ETagTypeBitField,0,EScopeGlobal|EScopeProcessSpecific|EScopeThreadSpecific}, + {ECodeSegs,ETagTypeBitField,0,EScopeGlobal|EScopeProcessSpecific|EScopeThreadSpecific}, + {EXipLibraries,ETagTypeBitField,0,EScopeGlobal}, + {EExecutables,ETagTypeBitField,0,EScopeGlobal}, + {ELogicalDevices,ETagTypeBitField,0,EScopeNone}, + {EMutexes,ETagTypeBitField,0,EScopeNone}, + {EServers,ETagTypeBitField,0,EScopeNone}, + {ESessions,ETagTypeBitField,0,EScopeNone}, + {ESemaphores,ETagTypeBitField,0,EScopeNone}, + {EChunks,ETagTypeBitField,0,EScopeNone}, + {EBreakpoints,ETagTypeBitField,0,EScopeNone}, + {ESetBreak,ETagTypeBitField,0,EScopeNone}, + {ERemoveBreak,ETagTypeBitField,0,EScopeNone}, + {EModifyBreak,ETagTypeBitField,0,EScopeNone}, + }; + +const TSubBlock DebugFunctionalityList[] = + { + ETagHeaderList, EListLast, + (TTag*)DebugFunctionalityListInfo + }; + +// Security +const TTag DebugFunctionalitySecurityInfo[]= + { + {ESecurityOEMDebugToken,ETagTypeBoolean,0,ETrue} + }; + +const TSubBlock DebugFunctionalitySecurity[] = + { + ETagHeaderIdSecurity, ESecurityLast, + (TTag*)DebugFunctionalitySecurityInfo + }; + +TUint32 TDebugFunctionality::GetDebugFunctionalityBufSize(void) + { + TUint32 df_size = 0; + + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityCore); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityMemory); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityRegistersCore); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityRegistersCoPro); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityBreakpoints); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityStepping); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityExecution); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityEvents); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityApiConstants); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityList); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalityKillObjects); + df_size += ComputeBlockSize((const TSubBlock&)DebugFunctionalitySecurity); + + return df_size; + } + +TBool TDebugFunctionality::GetDebugFunctionality(TDes8& aDFBlock) + { + if (aDFBlock.MaxLength() < GetDebugFunctionalityBufSize() ) + { + // Insufficient space to contain the debug functionality block + return EFalse; + } + + AppendBlock((const TSubBlock&)DebugFunctionalityCore,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityMemory,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityRegistersCore,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityRegistersCoPro,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityBreakpoints,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityStepping,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityExecution,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityEvents,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityApiConstants,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityList,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalityKillObjects,aDFBlock); + AppendBlock((const TSubBlock&)DebugFunctionalitySecurity,aDFBlock); + + return ETrue; + } + +/** + * Get the register information associated with aRegisterInfo. If aRegisterInfo is + * an unsupported register then an entry of the form: + * {aRegisterInfo, x, 0, EAccessUnknown} + * will be returned where x is an arbitrary value. + * + * @param aRegisterInfo register id information + * @param aTag The functionality information for this register. + * @return One of the system wide error codes + */ +TInt TDebugFunctionality::GetRegister(const TRegisterInfo aRegisterInfo, TTag& aTag) + { + if(Register::IsCoreReg(aRegisterInfo)) + { + for(TInt i=0; i +#include + +using namespace Debug; + +TDriverEventInfo::TDriverEventInfo() + { + Reset(); + } + +void TDriverEventInfo::Reset() + { + iProcessId = 0; + iThreadId = 0; + iCurrentPC = 0; + iExceptionNumber = 0; + iFileName.Zero(); + iPanicCategory.Zero(); + iCodeAddress = 0; + iDataAddress = 0; + iThreadIdValid = (TUint8)EFalse; + iProcessIdValid = (TUint8)EFalse; + iEventType = EEventsUnknown; + iUidsValid = (TUint8)EFalse; + iActionTaken = EActionIgnore; + iThreadFlags = 0; + }; + +/** + Copy the data from this object into the object pointed to by aEventInfo in + the client thread aClientThread. It is assumed that the write is performed + on behalf of aClientThread. + + @param aClientThread client thread to write the data to + @param aEventInfo TEventInfo object in the client thread to populate with data + @param aAsyncGetValueRequest TClientDataRequest object used for pinning user memory + + @return KErrNone on success, or one of the other system wide error codes + */ +TInt TDriverEventInfo::WriteEventToClientThread(TClientDataRequest* aAsyncGetValueRequest, DThread* aClientThread) const + { + // create a temporary TEventInfo to populate with the relevant data + TEventInfo eventInfo; + TInt err = KErrNone; + + // populate the data that is common to all events + err = PopulateCommonEventInfo(eventInfo); + + if(KErrNone != err) + { + return err; + } + + // populate the event specific data (means filling in the correct union member) + err = PopulateEventSpecificInfo(eventInfo); + + // write the data to the client and return any error + if(KErrNone == err) + { + aAsyncGetValueRequest->Data() = eventInfo; + } + + return err; + } + +/** + Write the common event values into aEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateCommonEventInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iEventType = iEventType; + aEventInfo.iProcessId = iProcessId; + aEventInfo.iProcessIdValid = iProcessIdValid; + aEventInfo.iThreadId = iThreadId; + aEventInfo.iThreadIdValid = iThreadIdValid; + aEventInfo.iActionTaken = iActionTaken; + LOG_MSG5("TDriverEventInfo:: PopulateCommon : eventType=%d, tidValid=%d, tid=0x%x, actionTaken=%d", + iEventType, iThreadIdValid, TUint(iThreadId), iActionTaken ); + return KErrNone; + } + +/** + Write the event specific values into aEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateEventSpecificInfo(TEventInfo& aEventInfo) const + { + TInt ret = KErrNone; + + switch(aEventInfo.iEventType) + { + case EEventsBreakPoint: + ret = PopulateThreadBreakPointInfo(aEventInfo); + return ret; + case EEventsProcessBreakPoint: + ret = PopulateThreadBreakPointInfo(aEventInfo); + return ret; + case EEventsSwExc: + ret = PopulateThreadSwExceptionInfo(aEventInfo); + return ret; + case EEventsHwExc: + ret = PopulateThreadHwExceptionInfo(aEventInfo); + return ret; + case EEventsKillThread: + ret = PopulateThreadKillInfo(aEventInfo); + return ret; + case EEventsAddLibrary: + ret = PopulateLibraryLoadedInfo(aEventInfo); + return ret; + case EEventsRemoveLibrary: + ret = PopulateLibraryUnloadedInfo(aEventInfo); + return ret; + case EEventsUserTrace: + ret = PopulateUserTraceInfo(aEventInfo); + return ret; + case EEventsStartThread: + ret = PopulateStartThreadInfo(aEventInfo); + return ret; + case EEventsUserTracesLost: + //no event specific data to be filled here + return KErrNone; + case EEventsAddProcess: + ret = PopulateAddProcessInfo(aEventInfo); + return ret; + case EEventsRemoveProcess: + ret = PopulateRemoveProcessInfo(aEventInfo); + return ret; + } + + return KErrArgument; + } + +/** + Write the event specific values for a break point event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateThreadBreakPointInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iThreadBreakPointInfo.iExceptionNumber = (TExcType)iExceptionNumber; + TInt ret = PopulateRmdArmExcInfo(aEventInfo); + + return ret; + } + +/** + Write the event specific values for a thread exception event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateThreadSwExceptionInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iThreadSwExceptionInfo.iCurrentPC = iCurrentPC; + aEventInfo.iThreadSwExceptionInfo.iExceptionNumber = (TExcType)iExceptionNumber; + + return KErrNone; + } + +/** + Write the event specific values for a thread exception event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateThreadHwExceptionInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iThreadHwExceptionInfo.iExceptionNumber = (TExcType)iExceptionNumber; + TInt ret = PopulateRmdArmExcInfo(aEventInfo); + return ret; + } + +/** + Write the event specific values for a thread panic event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateThreadKillInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iThreadKillInfo.iCurrentPC = iCurrentPC; + aEventInfo.iThreadKillInfo.iExitReason = iExceptionNumber; + aEventInfo.iThreadKillInfo.iExitType = iExitType; + aEventInfo.iThreadKillInfo.iPanicCategoryLength = iPanicCategory.Length(); + TPtr8 panicCategoryPtr(&(aEventInfo.iThreadKillInfo.iPanicCategory[0]), iPanicCategory.Length()); + panicCategoryPtr = iPanicCategory; + + return KErrNone; + } + +/** + Write the event specific values for a library loaded event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateStartThreadInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iStartThreadInfo.iFileNameLength = iFileName.Length(); + TPtr8 fileNamePtr(&(aEventInfo.iStartThreadInfo.iFileName[0]), iFileName.Length()); + fileNamePtr = iFileName; + + return KErrNone; + } + +/** + Write the event specific values for an AddProcess event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateAddProcessInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iAddProcessInfo.iFileNameLength = iFileName.Length(); + TPtr8 fileNamePtr(&(aEventInfo.iAddProcessInfo.iFileName[0]), iFileName.Length()); + fileNamePtr = iFileName; + + const TInt uid3offset = 2; + aEventInfo.iAddProcessInfo.iUid3 = iUids.iUid[uid3offset].iUid; + aEventInfo.iAddProcessInfo.iCreatorThreadId = iCreatorThreadId; + + return KErrNone; + } + +/** + Write the event specific values for a RemoveProcess event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateRemoveProcessInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iRemoveProcessInfo.iFileNameLength = iFileName.Length(); + TPtr8 fileNamePtr(&(aEventInfo.iRemoveProcessInfo.iFileName[0]), iFileName.Length()); + fileNamePtr = iFileName; + + return KErrNone; + } + +/** + Write the event specific values for a library loaded event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateLibraryLoadedInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iLibraryLoadedInfo.iCodeAddress = iCodeAddress; + aEventInfo.iLibraryLoadedInfo.iDataAddress = iDataAddress; + aEventInfo.iLibraryLoadedInfo.iFileNameLength = iFileName.Length(); + TPtr8 fileNamePtr(&(aEventInfo.iLibraryLoadedInfo.iFileName[0]), iFileName.Length()); + fileNamePtr = iFileName; + + return KErrNone; + } + +/** + Write the event specific values for a library unloaded event into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateLibraryUnloadedInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iLibraryUnloadedInfo.iFileNameLength = iFileName.Length(); + TPtr8 fileNamePtr(&(aEventInfo.iLibraryUnloadedInfo.iFileName[0]), iFileName.Length()); + fileNamePtr = iFileName; + + return KErrNone; + } + +/** + Write the ArmExcInfo values into TEventInfo + + @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateRmdArmExcInfo(TEventInfo& aEventInfo) const + { + switch(iEventType) + { + case EEventsProcessBreakPoint: + case EEventsBreakPoint: + aEventInfo.iThreadBreakPointInfo.iRmdArmExcInfo = iRmdArmExcInfo; + break; + case EEventsHwExc: + aEventInfo.iThreadHwExceptionInfo.iRmdArmExcInfo = iRmdArmExcInfo; + break; + } + + return KErrNone; + } + +/** + * Writes the user trace into TEventInfo + * + * @param aEventInfo TEventInfo object to write data into + */ +TInt TDriverEventInfo::PopulateUserTraceInfo(TEventInfo& aEventInfo) const + { + aEventInfo.iUserTraceInfo.iUserTraceLength = (TInt)iArg2; + + TPtr8 ptr(aEventInfo.iUserTraceInfo.iUserTraceText, (TInt)iArg2, TUserTraceSize ); + ptr.Copy(iUserTraceText, (TInt)iArg2); + + return KErrNone; + } + +TBool TDriverEventInfo::FreezeOnSuspend() const + { + switch(iEventType) + { + case EEventsHwExc: + case EEventsBreakPoint: + case EEventsProcessBreakPoint: + return ETrue; + case EEventsKillThread: + { + return (iExitType == EExitPanic); + } + } + return EFalse; + } + +TBool TDriverEventInfo::TookException() const + { + return iExitType == EExitPanic && + iExceptionNumber == ECausedException && + iPanicCategory == KLitKernExec; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/d_list_manager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/d_list_manager.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,996 @@ +// 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: +// Provides a class to manage the generation of lists +// +// + +#include "d_list_manager.h" +#include "d_process_tracker.h" +#include "debug_utils.h" +#include "plat_priv.h" +#include "debug_logging.h" +#include + +// make accessing DThread's MState more intuitive +#define iMState iWaitLink.iSpare1 +// make accessing NThread's NState more intuitive +#define iNState iSpare3 + +//constants to match against a rom entry's attributes, +//these are defined in the file server (can't be included kernel side) +//and in the ROM tools (also inaccessible) so redefined here +const TUint KEntryAttXIP=0x0080; +const TUint KEntryAttDir=0x0010; + +using namespace Debug; + +/** + Get thread listing for the specified thread, if the thread data will not fit + in the buffer then an error is returned. + + @param aBuffer buffer to put data in + @param aDataSize on return will contain size of data + @param aTargetThreadId thread ID to return listing for + + @return KErrNone on success, + KErrTooBig if data won't fit in aBuffer + or one of the other system wide error codes on failure + */ +TInt TListManager::GetThreadListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const + { + LOG_MSG("TListManager::GetThreadListForThread()"); + + // open a handle to check whether the thread actually exists + NKern::ThreadEnterCS(); + DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId); + TUint64 processId = 0; + if (thread) + { + processId = thread->iOwningProcess->iId; + thread->Close(NULL); + } + NKern::ThreadLeaveCS(); + if (!thread) + { + return KErrArgument; + } + + //request a process specific list + return GetThreadListForProcess(aBuffer, aDataSize, processId); + } + +TInt TListManager::GetThreadListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const + { + LOG_MSG("TListManager::GetThreadListForProcess()"); + + // open a handle to check whether the process actually exists + DProcess* process = DebugUtils::OpenProcessHandle(aTargetProcessId); + if(!process) + { + return KErrArgument; + } + process->Close(NULL); + + //request a process specific list + return GetThreadList(aBuffer, aDataSize, EFalse, aTargetProcessId); + } + +/** + Get global thread listing + + @param aBuffer buffer to put data in + @param aDataSize on return will contain size of data + + @return KErrNone on success, + KErrTooBig if data won't fit in aBuffer + or one of the other system wide error codes on failure + */ +TInt TListManager::GetGlobalThreadList(TDes8& aBuffer, TUint32& aDataSize) const + { + LOG_MSG("TListManager::GetGlobalThreadList()"); + + //request a global list + return GetThreadList(aBuffer, aDataSize, ETrue, 0); + } + +/** + Get thread listing, if the thread data will not fit + in the buffer then an error is returned. + + @param aBuffer buffer to put data in + @param aDataSize on return will contain size of data + @param aGlobal whether or not the listing should be global or thread specific + @param aTargetProcessId process ID to return listing for, relevant only if aGlobal == ETrue + + @return KErrNone on success, + KErrTooBig if data won't fit in aBuffer + or one of the other system wide error codes on failure + */ +TInt TListManager::GetThreadList(TDes8& aBuffer, TUint32& aDataSize, TBool aGlobal, const TUint64 aTargetProcessId) const + { + LOG_MSG("TListManager::GetThreadList\n"); + + NKern::ThreadEnterCS(); + DObjectCon *threads = Kern::Containers()[EThread]; + threads->Wait(); + + aDataSize = 0; + aBuffer.SetLength(0); + //iterate through the threads adding them to the buffer + for(TInt i=0; iCount(); i++) + { + DThread* thread = (DThread*)(*threads)[i]; + + //skip this thread pointer is the thread is NULL + if(thread) + { + NThread& nThread = thread->iNThread; + + // if the thread is marked as being dead then don't return information about it in the listing +#ifndef __SMP__ + if((NThread::EDead != nThread.iNState) && (DThread::EDead != thread->iMState)) +#else + if((!nThread.IsDead()) && (DThread::EDead != thread->iMState)) +#endif + { + if( aGlobal || (aTargetProcessId == (TUint64)thread->iOwningProcess->iId)) + { + //store the data in the buffer + AppendThreadData(aBuffer, aDataSize, thread); + } + } + } + } + + //leave critical section + threads->Signal(); + NKern::ThreadLeaveCS(); + + //return indication of whether the kernel's data was too big + return (aDataSize > aBuffer.Length()) ? KErrTooBig : KErrNone; + } + +/** + Helper function for writing thread data into a buffer + + @pre call in a critical section + @pre call only on threads which have NThread state not equal to NThread::EDead + + @param aBuffer buffer to put data in + @param aDataSize on return will contain size of data + @param aThread thread object to include information about + + @return KErrNone on success, or one of the other system wide error codes +*/ +void TListManager::AppendThreadData(TDes8& aBuffer, TUint32& aDataSize, DThread* aThread) const + { + LOG_MSG3("TListManager::AppendThreadData for thrd 0x%08x, currThrd=0x%08x", + aThread->iId, Kern::CurrentThread().iId ); + + //get aThread's name + TFileName fileName; + aThread->FullName(fileName); + TUint16 nameLength = fileName.Length(); + + //increase aDataSize by the size of this entry + aDataSize = Align4(aDataSize + (2*nameLength) + sizeof(TThreadListEntry) - sizeof(TUint16)); + //if the data would not cause overflow then add it to the buffer + if(aDataSize <= aBuffer.MaxLength()) + { + //Create a TThreadListEntry which references the buffer. + TThreadListEntry& entry = *(TThreadListEntry*)(aBuffer.Ptr()+aBuffer.Length()); + //add data to entry + entry.iProcessId = (TUint64)aThread->iOwningProcess->iId; + entry.iThreadId = (TUint64)aThread->iId; + entry.iSupervisorStackBase = (TUint32)aThread->iSupervisorStack; + entry.iSupervisorStackBaseValid = ETrue; + entry.iSupervisorStackSize = aThread->iSupervisorStackSize; + entry.iSupervisorStackSizeValid = ETrue; + entry.iNameLength = nameLength; + + entry.iSupervisorStackPtrValid = EInValid; + entry.iSupervisorStackPtr = 0; + + if(aThread->iId != Kern::CurrentThread().iId) + { + NThread& nThread = aThread->iNThread; + + TArmRegSet regSet; + TUint32 flags; + NKern::ThreadGetSystemContext(&nThread, ®Set, flags); + entry.iSupervisorStackPtr = (TUint32)regSet.iR13; + //need to check that the stack pointer flag is valid + if(flags & (1<Wait(); + + aDataSize = 0; + //iterate through the processes adding them to the buffer + for(TInt i=0; iCount(); i++) + { + DProcess* process = (DProcess*)(*processes)[i]; + if(process) + { + //get process's file name length + DCodeSeg* codeSeg = process->iCodeSeg; + TUint16 fileNameLength = (codeSeg) ? (*codeSeg->iFileName).Length() : 0; + + //get process's dynamic name length and name + TFullName fullName; + process->FullName(fullName); + TUint16 dynamicNameLength = fullName.Length(); + + //increase aDataSize to reflect size of entry + aDataSize = Align4(aDataSize + (2*fileNameLength) + (2*dynamicNameLength) + sizeof(TProcessListEntry) - sizeof(TUint16)); + //if the data would not cause overflow then add it to the buffer + if(aDataSize <= aBuffer.MaxLength()) + { + //Create a TProcessListEntry which references the buffer. + TProcessListEntry& entry = *(TProcessListEntry*)(aBuffer.Ptr() + aBuffer.Length()); + + //set values + entry.iProcessId = (TUint64)process->iId; + entry.iFileNameLength = fileNameLength; + entry.iDynamicNameLength = dynamicNameLength; + entry.iUid3 = process->iUids.iUid[2].iUid; + + if(codeSeg) + { + //create TPtr to where the file name should be written + TPtr name = TPtr((TUint8*)&(entry.iNames[0]), fileNameLength*2, fileNameLength*2); + //copy the file name + TInt err = CopyAndExpandDes(*codeSeg->iFileName, name); + if(err != KErrNone) + { + processes->Signal(); + NKern::ThreadLeaveCS(); + return KErrGeneral; + } + } + + //create TPtr to where the dynamic name should be written + TPtr name = TPtr((TUint8*)(&(entry.iNames[0]) + fileNameLength), dynamicNameLength*2, dynamicNameLength*2); + //copy the dynamic name + TInt err = CopyAndExpandDes(fullName, name); + if(err != KErrNone) + { + processes->Signal(); + NKern::ThreadLeaveCS(); + return KErrGeneral; + } + + //set length same as aDataSize + aBuffer.SetLength(aDataSize); + } + } + } + + //leave critical section + processes->Signal(); + NKern::ThreadLeaveCS(); + + //return indication of whether the kernel's data was too big + return (aDataSize > aBuffer.Length()) ? KErrTooBig : KErrNone; + } + +/** + Copy the descriptor aSrc to aDest and converting each byte from aSrc + into the two-byte equivalent. For example if aSrc contains 'XYZ' then + aDest will be filled with 'X\0Y\0Z\0' where \0 is the null character. + The length of aDest is set to twice the length of aSrc. + + @param aSrc source descriptor + @param aDest destination descriptor to copy and expand aSrc into + + @return KErrNone on success, + KErrArgument if the max length of aDest is less than twice the length of aSrc + */ +TInt TListManager::CopyAndExpandDes(const TDesC& aSrc, TDes& aDest) const + { + //check bounds + if(aSrc.Length() * 2 > aDest.MaxLength()) + { + return KErrArgument; + } + + //get a pointer to the start of the destination descriptor + TUint16* destPtr = (TUint16*)aDest.Ptr(); + + //get pointers to the start and end of the aSrc descriptor + const TUint8* srcPtr = aSrc.Ptr(); + const TUint8* srcEnd = srcPtr + aSrc.Length(); + + //copy the characters from aSrc into aDest, expanding to make them 16-bit characters + while(srcPtr < srcEnd) + { + *destPtr = (TUint16)*srcPtr; + destPtr++; + srcPtr++; + } + + //set aDest's length to reflect the new contents + aDest.SetLength(2*aSrc.Length()); + return KErrNone; + } + +/** + Get global code segment listing + + @param aBuffer buffer to put data in + @param aDataSize on return will contain size of data + + @return KErrNone on success, + KErrTooBig if data won't fit in aBuffer, + or one of the other system wide error codes + */ +TInt TListManager::GetGlobalCodeSegList(TDes8& aBuffer, TUint32& aDataSize) const + { + LOG_MSG("TListManager::GetGlobalCodeSegList()"); + + // Acquire code seg lock mutex + NKern::ThreadEnterCS(); + DMutex* codeMutex = Kern::CodeSegLock(); + Kern::MutexWait(*codeMutex); + + //get global code seg list + SDblQue* codeSegList = Kern::CodeSegList(); + + //create a memory info object for use in the loop + TModuleMemoryInfo memoryInfo; + + //iterate through the list + aDataSize = 0; + for (SDblQueLink* codeSegPtr= codeSegList->First(); codeSegPtr!=(SDblQueLink*) (codeSegList); codeSegPtr=codeSegPtr->iNext) + { + DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iLink); + //the code seg shouldn't be null as we're in critical section, ignore if it is null + if(codeSeg) + { + //get the memory info + TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); + if(err != KErrNone) + { + // Release the codeseglock mutex again + Kern::MutexSignal(*codeMutex); + NKern::ThreadLeaveCS(); + + //there's been an error so return it + return err; + } + //calculate data values + TFileName fileName(codeSeg->iFileName->Ptr()); + TBool isXip = (TBool)(codeSeg->iXIP); + + //get the code seg type, can ignore error as have already checked codeSeg is not NULL + TCodeSegType type = EUnknownCodeSegType; + err = GetCodeSegType(codeSeg, type); + if(err != KErrNone) + { + LOG_MSG("TListManager::GetGlobalCodeSegList() : code seg is NULL"); + } + + TUint32 uid3 = codeSeg->iUids.iUid[2].iUid; + //append data to buffer + err = AppendCodeSegData(aBuffer, aDataSize, memoryInfo, isXip, type, fileName, uid3); + if(err != KErrNone) + { + // Release the codeseglock mutex again + Kern::MutexSignal(*codeMutex); + NKern::ThreadLeaveCS(); + + return KErrGeneral; + } + } + } + + // Release the codeseglock mutex again + Kern::MutexSignal(*codeMutex); + NKern::ThreadLeaveCS(); + + return (aDataSize > aBuffer.MaxLength()) ? KErrTooBig : KErrNone; + } + +/** + Get code segment list for a thread + + @param aBuffer buffer to store data in + @param aDataSize size of kernel's data + @param thread ID to get listing for + + @return KErrNone on success, + KErrTooBig if data won't fit in aBuffer, + or one of the other system wide error codes + */ +TInt TListManager::GetCodeSegListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const + { + LOG_MSG("TListManager::GetCodeSegListForThread()"); + + TUint64 processId = 0; + NKern::ThreadEnterCS(); + DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId); + if (thread) + { + processId = thread->iOwningProcess->iId; + thread->Close(NULL); + } + NKern::ThreadLeaveCS(); + + if (processId == 0) + { + return KErrArgument; + } + + return GetCodeSegListForProcess(aBuffer, aDataSize, processId); + } + +/** + Get code segment list for a process + + @param aBuffer buffer to store data in + @param aDataSize size of kernel's data + @param process ID to get listing for + + @return KErrNone on success, + KErrTooBig if data won't fit in aBuffer, + or one of the other system wide error codes + */ +TInt TListManager::GetCodeSegListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const + { + LOG_MSG("TListManager::GetCodeSegListForProcess()"); + + NKern::ThreadEnterCS(); + + //get the process + DProcess* process = DebugUtils::OpenProcessHandle(aTargetProcessId); + + if(!process) + { + NKern::ThreadLeaveCS(); + return KErrArgument; + } + + // acquire code segment mutex + Kern::AccessCode(); + + //memory info object to use in loop + TModuleMemoryInfo memoryInfo; + + //get code seg list + SDblQue queue; + process->TraverseCodeSegs(&queue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd); + + //iterate through the list + aDataSize = 0; + TInt err = KErrNone; + for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext) + { + //get the code seg + DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink); + + //the code seg shouldn't be null as we're in critical section, ignore if it is null + if(codeSeg) + { + err = codeSeg->GetMemoryInfo(memoryInfo, NULL); + if (err) break; + + TFileName fileName(codeSeg->iFileName->Ptr()); + TBool isXip = (TBool)(codeSeg->iXIP); + + //get the code seg type, can ignore error as have already checked codeSeg is not NULL + TCodeSegType type = EUnknownCodeSegType; + err = GetCodeSegType(codeSeg, type); + if(err != KErrNone) + { + LOG_MSG("TListManager::GetCodeSegListForProcess() : code seg is NULL"); + } + + TUint32 uid3 = codeSeg->iUids.iUid[2].iUid; + //append data to buffer + err = AppendCodeSegData(aBuffer, aDataSize, memoryInfo, isXip, type, fileName, uid3); + if (err) break; + } + } + + //un mark the code segs that we've iterated over + DCodeSeg::EmptyQueue(queue, DCodeSeg::EMarkDebug); + + //release mutex + Kern::EndAccessCode(); + + process->Close(NULL); + NKern::ThreadLeaveCS(); + return (aDataSize > aBuffer.MaxLength()) ? KErrTooBig : err; + } + +/** + Appends data to a specified buffer and puts the resulting size in aDataSize. + If the data won't fit then aDataSize is updated to reflect what the new length + would be. + + @param aBuffer buffer to append data to + @param aDataSize will contain buffer size (or the size the buffer would be) on return + @param aMemoryInfo info to append to buffer + @param aIsXip boolean indicating whether the code segment is XIP + @param aFileName file name to append to buffer + + @return KErrNone on success, or one of the other system wide error codes + */ +TInt TListManager::AppendCodeSegData(TDes8& aBuffer, TUint32& aDataSize, const TModuleMemoryInfo& aMemoryInfo, const TBool aIsXip, const TCodeSegType aCodeSegType, const TDesC8& aFileName, const TUint32 aUid3) const + { + //get some data elements to put in buffer + TUint16 fileNameLength = aFileName.Length(); + + //calculate the resultant size + aDataSize = Align4(aDataSize + sizeof(TCodeSegListEntry) + (2*fileNameLength) - sizeof(TUint16)); + if(aDataSize <= aBuffer.MaxLength()) + { + //Create a TCodeSegListEntry which references the buffer. + TCodeSegListEntry& entry = *(TCodeSegListEntry*)(aBuffer.Ptr() + aBuffer.Length()); + entry.iCodeBase = aMemoryInfo.iCodeBase; + entry.iCodeSize = aMemoryInfo.iCodeSize; + entry.iConstDataSize = aMemoryInfo.iConstDataSize; + entry.iInitialisedDataBase = aMemoryInfo.iInitialisedDataBase; + entry.iInitialisedDataSize = aMemoryInfo.iInitialisedDataSize; + entry.iUninitialisedDataSize = aMemoryInfo.iUninitialisedDataSize; + entry.iIsXip = aIsXip; + entry.iCodeSegType = aCodeSegType; + entry.iNameLength = fileNameLength; + entry.iUid3 = aUid3; + + //have to convert the stored name to 16 bit unicode + TPtr name = TPtr((TUint8*)&(entry.iName[0]), fileNameLength*2, fileNameLength*2); + TInt err = CopyAndExpandDes(aFileName, name); + if(err != KErrNone) + { + return KErrGeneral; + } + + //increase length + aBuffer.SetLength(aDataSize); + } + + return KErrNone; + } + +/** + Get global XIP libraries list. The ROM file system is searched for files in + z:\sys\bin. The files are filtered to only include library files which + correspond to the correct hardware variant. + + In the rom, a directory is represented as a list of TRomEntrys, corresponding to + the files and directories in that directory. A TRomEntry corresponding to a file + contains a pointer to that file's location in the rom. If the TRomEntry + corresponds to a directory then it contains a pointer to that directory in the + ROM header. As such, from a pointer to the root directory of the z: drive, it is + possible to extract the directory contents for a particular directory (i.e. z:\sys\bin) + by recursively finding the subdirectories (i.e. find 'sys' in 'z:', then 'bin' in 'sys') + and then listing the contents of that directory. + + @param aBuffer buffer to store data in + @param aDataSize size of kernel's data + + @return KErrNone on success, + KErrTooBig if data won't fit in aBuffer, + or one of the other system wide error codes + */ +TInt TListManager::GetXipLibrariesList(TDes8& aBuffer, TUint32& aDataSize) const + { + LOG_MSG("TListManager::GetXipLibrariesList()"); + + // z:\sys\bin expressed as 16 bit unicode.. + _LIT(KZSysBin, "z\0:\0\\\0s\0y\0s\0\\\0b\0i\0n\0\\\0"); + + //array to store pointers to directory entries in + RPointerArray entries; + //get the entries in KZSysBin + TInt err = GetDirectoryEntries(entries, KZSysBin()); + if(KErrNone != err) + { + entries.Close(); + return err; + } + + aDataSize = 0; + for(TInt i=0; iiAtt & KEntryAttXIP) && ! (entries[i]->iAtt & KEntryAttDir) ) + { + //get a reference to the dll's header + const TRomImageHeader& header = *(const TRomImageHeader*)(entries[i]->iAddressLin); + + //check that it's uid1 value corresponds to that for a library + if(header.iUid1 == KDynamicLibraryUidValue) + { + //get the current hardware variant + TSuperPage& superPage = Kern::SuperPage(); + TUint variant = superPage.iActiveVariant; + TUint cpu = (variant >> 16) & 0xff; + TUint asic = (variant >> 24); + + //check this dll is compatible with the current variant + if(THardwareVariant(header.iHardwareVariant).IsCompatibleWith(cpu,asic,variant)) + { + const TInt fileNameLength16 = entries[i]->iNameLength; + const TInt fullNameLength16 = (KZSysBin().Length() / 2) + fileNameLength16; + aDataSize += Align4((2 * fullNameLength16) + sizeof(TXipLibraryListEntry) - sizeof(TUint16)); + + if(aDataSize <= aBuffer.MaxLength()) + { + //Create a TXipLibraryListEntry which references the buffer. + TXipLibraryListEntry& libraryInfo = *(TXipLibraryListEntry*)(aBuffer.Ptr() + aBuffer.Length()); + + //add the data + libraryInfo.iCodeBase = header.iCodeAddress; + libraryInfo.iCodeSize = header.iTextSize; + libraryInfo.iConstDataSize = header.iCodeSize - header.iTextSize; + libraryInfo.iInitialisedDataBase = header.iDataBssLinearBase; + libraryInfo.iInitialisedDataSize = header.iDataSize; + libraryInfo.iUninitialisedDataSize = header.iBssSize; + libraryInfo.iNameLength = fullNameLength16; + + //create a TPtr8 to contain the fully qualified name (i.e. z:\sys\bin\ prefixed) + TPtr8 name((TUint8*)&(libraryInfo.iName[0]), 0, 2 * fullNameLength16); + name.Append(KZSysBin()); + name.Append(TPtr8((TUint8*)&(entries[i]->iName), 2 * fileNameLength16, 2 * fileNameLength16)); + + //increase the buffer's length to reflect the new data size + aBuffer.SetLength(aDataSize); + } + } + } + } + } + entries.Close(); + return (aDataSize == aBuffer.Length()) ? KErrNone : KErrTooBig; + } + +/** +Get the list of TRomEntry objects in the specified directory aDirectory + +@param aRomEntryArray array to store pointers to the TRomEntry objects in +@param aDirectoryName directory to get contents of. The passed in string should be +16 bit unicode and should begin with z:. Single backslashes should be used as delimiters +rather than forward slashes and a terminating backslash is optional. +For example: z:\sys\bin + +@return KErrNone on success, or one of the other system wide error codes +*/ +TInt TListManager::GetDirectoryEntries(RPointerArray& aRomEntryArray, const TDesC& aDirectoryName) const + { + LOG_MSG("TListManager::GetDirectoryEntries()"); + + //definition in 16 bit unicode + _LIT(KForwardSlash, "/\0"); + + //if directory has forward slashes then exit + if(aDirectoryName.Find(KForwardSlash()) != KErrNotFound) + { + return KErrArgument; + } + + //create an array to hold the folders in aDirectoryName + RArray folders; + + //split the directory up into its folders, i.e. z:\sys\bin is split into { 'z:', 'sys', 'bin' } + TInt err = SplitDirectoryName(aDirectoryName, folders); + if(KErrNone != err) + { + folders.Close(); + return err; + } + + if(folders.Count() == 0) + { + folders.Close(); + //empty string passed in + return KErrArgument; + } + + // z: as 16 bit unicode + _LIT(KZColon, "z\0:\0"); + if(folders[0].CompareF(KZColon()) != 0) + { + //first argument must be z: otherwise not in rom + folders.Close(); + return KErrArgument; + } + //remove z: from array + folders.Remove(0); + for(TInt i=0; i& aRomEntryArray, RArray& aArray, TLinAddr& aAddress) const + { + LOG_MSG2("TListManager::GetDirectoryEntries() aAddress: 0x%08x", aAddress); + + //find the next subdirectory and store its address in aAddress, return error if we can't find it + TInt err = FindDirectory(aArray[0], aAddress); + if(err != KErrNone) + { + return err; + } + + //if this is the most derived sub-directory (i.e. the bin of z:\sys\bin) then get the dir contents + if(aArray.Count() == 1) + { + return GetDirectoryContents(aRomEntryArray, aAddress); + } + else + { + //get the next subdirectory's contents + aArray.Remove(0); + return GetDirectoryEntries(aRomEntryArray, aArray, aAddress); + } + } + +/** +Return the entries of a directory in the rom + +@param aRomEntryArray array to store the entries in +@param aAddress address of a directory block in the rom +*/ +TInt TListManager::GetDirectoryContents(RPointerArray& aRomEntryArray, const TLinAddr aAddress) const + { + LOG_MSG("TListManager::GetDirectoryContents()"); + + TLinAddr address = aAddress; + + //get the size in bytes of the block of rom to iterate over + const TUint32 sizeInBytes = *(TUint32*)aAddress; + + //get address of first TRomEntry + const TLinAddr initialAddress = aAddress + sizeof(TUint32); + + //get pointer to subdir count + address = initialAddress + sizeInBytes; + + //the upper two bytes of this entry contain the number of files in this directory, and the lower two bytes + //contains the number of subdirectories in this directory + TUint32 filesAndDirectories = *(TUint32*)address; + + //get number of subdirectories in this directory + const TUint16 subDirCount = filesAndDirectories & 0xFFFF; + + //get the number of files in this dir + const TUint16 filesCount = filesAndDirectories >> 16; + + //get total number of entries in dir + const TUint numDirectoryEntries = subDirCount + filesCount; + + //set address to start of first entry + address = initialAddress; + + for(TInt i=0; iiNameLength; + + //get the size of the entry including the name + TUint32 romEntrySize = sizeof(TRomEntry) - sizeof(romEntry->iName) + (2 * nameLength); + //adjust the address to the next entry + address += Align4(romEntrySize); + } + return KErrNone; + } + +/** + Finds the subdirectory with name aDirectory in the directory at aAddress + + @param aDirectory name of subdirectory to search for (i.e. 'bin') + @param aAddress address in rom of containing directory (i.e. address of 'sys' directory) + + @param KErrNone if aDirectory could be found in aAddress, KErrNotFound if it could not be found + */ +TInt TListManager::FindDirectory(const TDesC& aDirectory, TLinAddr& aAddress) const + { + LOG_MSG3("TListManager::FindDirectory() aDirectory: %S, aAddress: 0x%08x", &aDirectory, aAddress); + + //get the directory's contents + RPointerArray dirContents; + TInt err = GetDirectoryContents(dirContents, aAddress); + if(KErrNone != err) + { + dirContents.Close(); + return err; + } + for(TInt i=0; iIsExe()) + { + aType = EExeCodeSegType; + return KErrNone; + } + + if(aCodeSeg->IsDll()) + { + aType = EDllCodeSegType; + return KErrNone; + } + + aType = EUnknownCodeSegType; + return KErrNone; + } + + +/** + Split a directory name into its subdirectories, using a 16-bit backslash ('\\\0') as a delimiter. + For example z:\sys\bin would be split into { 'z:', 'sys', 'bin' } + + @param aDirectoryName directory name to split into subdirectories + @param aSubDirectories array to store the subdirectories in + */ +TInt TListManager::SplitDirectoryName(const TDesC& aDirectoryName, RArray& aSubDirectories) const + { + //definition in 16 bit unicode + _LIT(KBackSlash, "\\\0"); + + //split the directory up into its folders, i.e. z:\sys\bin is split into + TPtr8 string((TUint8*)aDirectoryName.Ptr(), aDirectoryName.Length(), aDirectoryName.Length()); + while(string.Ptr() < aDirectoryName.Ptr() + aDirectoryName.Length()) + { + TInt offset = string.Find(KBackSlash()); + if(offset == KErrNotFound) + { + //reached the end of the string + offset = string.Length(); + } + //adjustedOffset takes account of the end of the string case + TInt adjustedOffset = (offset == string.Length()) ? offset : offset + KBackSlash().Length(); + //add sub-folder name + TInt err = aSubDirectories.Append(TPtr8((TUint8*)string.Ptr(), offset, offset)); + if(KErrNone != err) + { + return err; + } + //remove the sub-folder name and continue + string.Set((TUint8*)string.Ptr() + adjustedOffset, string.Length() - adjustedOffset, string.Length() - adjustedOffset); + } + return KErrNone; + } + + + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/d_process_tracker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/d_process_tracker.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,664 @@ +// Copyright (c) 2006-2010 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: +// Purpose: The DProcessTracker object tracks which processes are being +// debugged. The DProcessTracker class uses a DTargetProcess object for +// each process being debugged. +// Note: Although TheDProcessTracker object is a global, it will be unique +// as only the Debug Security Server can load and use rm_debug.ldd. +// +// + +#include +#include +#include +#include +#include +#include + +#include +#include "debug_logging.h" +#include "d_process_tracker.h" +#include "debug_utils.h" + +// Global Run-mode debugged process tracking object +DProcessTracker TheDProcessTracker; + +// ctor +DProcessTracker::DProcessTracker() + { + } + +/** + * dtor + * Go through forzen thread list and resume each one before clearing our structures + * @internalTechnology + */ +DProcessTracker::~DProcessTracker() + { + + for(TInt i=0; iiOwningThread ); + NKern::FSSignal(iFrozenThreadSemaphores[i]); + } + + NKern::ThreadEnterCS(); + // The ResetAndDestroy() will call the individual deletes for all objects in the containers + iFrozenThreadSemaphores.ResetAndDestroy(); + iProcesses.ResetAndDestroy(); + iAgentsAttachedToAll.ResetAndDestroy(); + NKern::ThreadLeaveCS(); + } + +/** + * @internalTechnology + * + * Creates and stores an internal mapping of debug agent to debugged process. + * Note that an individual process may be mapped to a number of debug agents. + * + * @param aProcessName - The fullly qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe + * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id() + * @return KErrNone if there are no errors. KErrArgument if the processname is too long/short for a valid filepath. + * KErrNoMemory if there is insufficient memory. + */ +TInt DProcessTracker::AttachProcess(const TDesC8& aProcessName,TUint64 aAgentId) + { + LOG_MSG3("DProcessTracker::AttachProcess name=%S agentId=0x%lx", + &aProcessName, aAgentId); + + // Valid ProcessName? + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath) + { + return KErrArgument; + } + + if (aProcessName == _L8("*")) + { + DDebugAgent* agent = FindAgentForProcessAndId( aProcessName, aAgentId ); + if(agent != NULL) + { + LOG_MSG("Found agent already attached to all"); + return KErrAlreadyExists; + } + + agent = DDebugAgent::New(aAgentId); + if(agent == NULL) + { + LOG_MSG("DProcessTracker::AttachProcess() couldn't allocate memory for DDebugAgent"); + return KErrNoMemory; + } + + return iAgentsAttachedToAll.Append(agent); + + } + + // Not attach all, but for a specific process/exe + + // Create an DTargetProcess to store + DTargetProcess* tmpProcess = new DTargetProcess; + if (tmpProcess == 0) + { + return KErrNoMemory; + } + LOG_MSG2(" AttachProcess: < new DTargetProcess=0x%08x", tmpProcess ); + + // Set the name + TInt err = KErrNone; + err = tmpProcess->SetProcessName(aProcessName); + if (err != KErrNone) + { + LOG_MSG2(" AttachProcess: < SetProcessName returned %d", err ); + return err; + } + + // Is this process being debugged (ie already attached?) + TInt found = KErrNotFound; + const TInt numberOfProcesses = iProcesses.Count(); + for (TInt index = 0; index < numberOfProcesses; index++) + { + if (iProcesses[index]->ProcessName().CompareF(aProcessName) == 0) + { + LOG_MSG3(" Proc count=%d, found proc in iProcesses at %d. Count=%d", + index, iProcesses.Count() ); + found = index; + break; + } + } + + if (found != KErrNotFound) + { + // Yes, it is being debugged + + // Add the agent to the list of agents for this process + LOG_MSG3(" > AddAgent(agent id %d) to existing iProcesses[%d]", I64LOW(aAgentId), found); + + iProcesses[found]->AddAgent(aAgentId); + + return KErrNone; + } + else + { + // No, it is not being debugged + + // Add the agent to the list of agents for this process + LOG_MSG2(" > AddAgent(agent %d) to new proc at index 0", I64LOW(aAgentId) ); + + tmpProcess->AddAgent(aAgentId); + + // Add the process to the list of processes being debugged + return iProcesses.Append(tmpProcess); + } + } + +/** + * @internalTechnology + * + * Removes a previously created mapping between a debug agent and a debugged process, + * as created by AttachProcess. + * + * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe + * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id() + * @return KErrNone if there are no problems. KErrArgument if the processname is too long/short for a valid filepath. + * KErrNotFound if the mapping does not exist (and therefore cannot be removed). + */ +TInt DProcessTracker::DetachProcess(const TDesC8& aProcessName, TUint64 aAgentId) + { + LOG_MSG3("DProcessTracker::DetachProcess name=%S agentId=0x%lx", + &aProcessName, aAgentId); + + // Valid ProcessName? + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath) + { + return KErrArgument; + } + + if (aProcessName == _L8("*")) + { + TInt const agentCount = iAgentsAttachedToAll.Count(); + LOG_MSG2(" iAgentsAttachedToAll size=%d", agentCount ); + + for (TInt i = 0; i < agentCount; i++) + { + if (iAgentsAttachedToAll[i]->Id() == aAgentId) + { + LOG_MSG2(" Agent id found at index %d, deleting it", i); + delete iAgentsAttachedToAll[i]; + iAgentsAttachedToAll.Remove(i); + return KErrNone; + } + } + + //Not found, so error condition + return KErrNotFound; + } + + // Are we debugging this process? + const TInt numberOfProcesses = iProcesses.Count(); + TInt foundIdx = KErrNotFound; + for(TInt i = 0; i < numberOfProcesses; i++) + { + if (iProcesses[i]->ProcessName().CompareF(aProcessName) == 0) + { + foundIdx = i; + break; + } + } + + if (foundIdx == KErrNotFound) + { + return KErrNotFound; + } + + // remove the agent from the process + iProcesses[foundIdx]->RemoveAgent(aAgentId); + + // Found it, are there any more attached agents, or suspended threads in the process? + + + if (iProcesses[foundIdx]->AgentCount() == 0) + { + // Delete the process as no more agents are still attached + delete iProcesses[foundIdx]; + + // Remove the now obsolete pointer from our array. + iProcesses.Remove(foundIdx); + } + + return KErrNone; + } + +/** + * @internalTechnology + * + * Detachs a debug agent from every process being debugged. Used when a debug agent is being detached + * from the debug security server and has not supplied a specific process name from which to detach. + */ +TInt DProcessTracker::DetachAgent(const TUint64 aAgentId) + { + + LOG_MSG2("DProcessTracker::DetachAgent 0x%lx", aAgentId); + + // Remove this agent from all the processes being tracked. + TInt numberOfProcesses = iProcesses.Count(); + for(TInt i=0; iRemoveAgent(aAgentId); + } + + // Increment down through the array as we then don't have to worry about + // missing entries which have been shifted after deletes. + // The initial value of i correspnds to the index of the final element + // in the array. + for(TInt i = iProcesses.Count()-1; i>=0; i--) + { + if (iProcesses[i]->AgentCount() == 0) + { + // No agents remain for this process. Delete the + // process object and remove the pointer from the array + delete iProcesses[i]; + iProcesses.Remove(i); + } + } + + TInt const agentCount = iAgentsAttachedToAll.Count(); + for (TInt i = 0; i < agentCount; i++) + { + if (iAgentsAttachedToAll[i]->Id() == aAgentId) + { + LOG_MSG2(" Agent id found at index %d, deleting it", i); + delete iAgentsAttachedToAll[i]; + iAgentsAttachedToAll.Remove(i); + } + } + + return KErrNone; + } + +/** + * @internalTechnology + * + * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process + * with all the relevant debug agents interested in that process, as determined + * by AttachProcess. + * + * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe + * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated + * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid. + */ +DTargetProcess* DProcessTracker::FindProcess(const TDesC8& aProcessName) const + { + // Valid ProcessName? + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath) + { + return NULL; + } + + // Can we find this in the array? + + // Are we debugging this process? + const TInt numberOfProcesses = iProcesses.Count(); + DTargetProcess* found = NULL; + for(TInt i = 0; i < numberOfProcesses; i++) + { + if (iProcesses[i]->ProcessName().CompareF(aProcessName) == 0) + { + found = iProcesses[i]; + LOG_EVENT_MSG3("DProcessTracker::FindProcess(%S) found at list pos %i", + &aProcessName, i); + break; + } + } + + if (found == NULL) + { + LOG_EVENT_MSG2("DProcessTracker::FindProcess(%S), not found", &aProcessName); + } + + return found; + } + +/** + * @internalTechnology + * + * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process + * with all the relevant debug agents interested in that process, as determined + * by AttachProcess. + * + * Note: This does not attempt an exact match, because the AddProcess event does not provide + * a fully-qualified path, it provides something like [t_rmdebug_security0.exe]. + * + * So for the purposes of dealing with this event, we need a "fuzzier" match which does not use the complete + * path. + * + * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe + * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated + * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid. + */ +DTargetProcess* DProcessTracker::FuzzyFindProcess(const TDesC8& aProcessName) + { + // Valid ProcessName? + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath) + { + return 0; // not found + } + + // Can we find this in the array? + TBool found = EFalse; + DTargetProcess* foundProcess = 0; + const TChar KBackSlash('\\'); + + TInt numberOfProcesses = iProcesses.Count(); + for(TInt i=0; i < numberOfProcesses; i++) + { + foundProcess = iProcesses[i]; + + TInt procListBackSlash = foundProcess->ProcessName().LocateReverse( KBackSlash ); + if( procListBackSlash == KErrNotFound ) + { + procListBackSlash = 0; + } + else + { + //Now move to the char after the backlash + procListBackSlash++; + } + + TInt eventBackSlash = aProcessName.LocateReverse( KBackSlash ); + if( eventBackSlash == KErrNotFound ) + { + eventBackSlash = 0; + } + else + { + //Now move to the char after the backlash + eventBackSlash++; + } + + if( ( procListBackSlash == 0 ) && ( eventBackSlash == 0 ) ) + { + //There were no backslashes on either name, so no point in continuing + break; + } + + TPtrC8 eventCleanName( aProcessName.Mid( eventBackSlash ) ); + TPtrC8 procListCleanName( foundProcess->ProcessName().Mid( procListBackSlash ) ); + + if ( eventCleanName.CompareF( procListCleanName ) == 0 ) + { + LOG_MSG2("DProcessTracker::FuzzyFindProcess() found a match : process list[%d]", i ); + found = ETrue; + break; + } + } + + if (found == EFalse) + { + return 0; // not found + } + + return foundProcess; + } + +/** + Freeze the current thread + + @return KErrNone if the thread is successfully suspended, + KErrAlreadyExists if the agent has already suspended the thread, + or one of the other system wide error codes + + This marks the current thread for waiting on a Fast Semaphore + when exception handling for this thread has completed - see + rm_debug_eventhandler.cpp for details. + */ +TInt DProcessTracker::FreezeThread() + { + // create and store a fast semaphore to stop the thread on + TInt err = KErrGeneral; + NKern::ThreadEnterCS(); + NFastSemaphore* sem = new NFastSemaphore( &(Kern::CurrentThread().iNThread) ); + if( sem != NULL ) + { + LOG_MSG3("DProcessTracker::FreezeThread(): new NFastSemaphore(curr NThread=0x%08x), DThread=0x%08x", + sem->iOwningThread, &(Kern::CurrentThread()) ); + err = iFrozenThreadSemaphores.Append(sem); + } + else + { + LOG_MSG("DProcessTracker::FreezeThread(): Error : could not allocate NFastSemaphore"); + err = KErrNoMemory; + } + + NKern::ThreadLeaveCS(); + return err; + } + +/** + Waits the current thread on a Fast Semaphore. + + This is useful for situations where the current thread + has hit a breakpoint within a critical section, and + otherwise could not be suspended at this point. + + Note that the Fast Semaphore structure on which the thread + waits must be a member data item of this class instance, + as it needs to be FSSignal()'d by another thread to resume + again. + */ +void DProcessTracker::FSWait() + { + NThread* currentNThread = &(Kern::CurrentThread().iNThread); + for(TInt i=0; iiOwningThread == currentNThread) + { + LOG_MSG4("DProcessTracker::FSWait(): > FSWait frozen sem %d, currentNThread=0x%08x, id=0x%x", + i, currentNThread, Kern::CurrentThread().iId ); + NKern::FSWait(iFrozenThreadSemaphores[i]); + return; + } + } + } + +/** + Resume the specified frozen thread + + @param aThread thread to resume + + @return KErrNone if the thread has previously been suspended and is resumed, + KErrNotFound if the thread has not previously been suspended + */ +TInt DProcessTracker::ResumeFrozenThread(DThread* aThread) + { + for(TInt i=0; iiOwningThread == &(aThread->iNThread)) + { + LOG_MSG2("DProcessTracker::ResumeFrozenThread 0x%08x, signalling then deleting this FastSem", aThread->iId ); + NKern::FSSignal(iFrozenThreadSemaphores[i]); + NKern::ThreadEnterCS(); + delete iFrozenThreadSemaphores[i]; + NKern::ThreadLeaveCS(); + iFrozenThreadSemaphores.Remove(i); + return KErrNone; + } + } + return KErrNotFound; + } + +TInt DProcessTracker::SuspendThread(DThread* aTargetThread, TBool aFreezeThread) + { + LOG_MSG5("DProcessTracker::SuspendThread() id 0x%08x, iCsCount=%d, , iCsFunction=%d, iSuspendCount=%d ", + aTargetThread->iId, aTargetThread->iNThread.iCsCount, aTargetThread->iNThread.iCsFunction, aTargetThread->iNThread.iSuspendCount ); + if( !aFreezeThread ) + { + if(!aTargetThread) + { + LOG_MSG("DProcessTracker::SuspendThread() > Kern::ThreadSuspend NullThrd Ptr!!"); + return KErrBadHandle; + } + + Kern::ThreadSuspend(*aTargetThread, 1); + return KErrNone; + } + + if( Kern::CurrentThread().iId != aTargetThread->iId ) + { + LOG_MSG2("DProcessTracker::SuspendThread() Error: Freeze for thread 0x%08x, but different from current thread", + aTargetThread->iId); + return KErrBadHandle; + } + + return FreezeThread(); + } + + +TInt DProcessTracker::ResumeThread(DThread* aTargetThread) + { + LOG_MSG5("DProcessTracker::ResumeThread() id 0x%08x, iCsCount=%d, , iCsFunction=%d, iSuspendCount=%d ", + aTargetThread->iId, aTargetThread->iNThread.iCsCount, aTargetThread->iNThread.iCsFunction, aTargetThread->iNThread.iSuspendCount ); + + TInt err = ResumeFrozenThread( aTargetThread ); + if( err == KErrNotFound ) + { + LOG_MSG(" ResumeThread() : not found in frozen list. Using Kern::ThreadResume" ); + Kern::ThreadResume(*aTargetThread); + return KErrNone; + } + + return err; + } + +/** + Get a thread's originating file name + + @param aThread the thread to get the file name for + + @return a pointer to the thread's file name, if there are problems accessing + the file name then NULL will be returned + */ +const TDesC* DProcessTracker::GetFileName(DThread* aThread) const + { + //check if the thread is NULL and return if so + if(!aThread) + { + return NULL; + } + + //get the owning process and return if it is NULL + DProcess* process = aThread->iOwningProcess; + if(!process) + { + return NULL; + } + + //get the process' code seg and return if it is NULL + DCodeSeg* codeSeg = process->iCodeSeg; + if(!codeSeg) + { + return NULL; + } + + //return the code seg's stored file name (which could theoretically be NULL) + return codeSeg->iFileName; + } + +/** +If any agent has called AttachToAll, return the most recently attached one. +*/ +DDebugAgent* DProcessTracker::GetCurrentAgentAttachedToAll() const + { + if (iAgentsAttachedToAll.Count() > 0) + { + return iAgentsAttachedToAll[iAgentsAttachedToAll.Count()-1]; + } + else + { + return NULL; + } + } + +/** +Returns ETrue if at least one agent was found for this process (either a specifically-attached +one or a current attached to all). Search specifically attached first, since these have +priority over attach all. +*/ +TBool DProcessTracker::NotifyAgentsForProcessEvent(const TDesC8& aProcessName, const TDriverEventInfo& aEvent, TBool aAllowFuzzy) + { + TBool foundAgent = EFalse; + + DTargetProcess* process = FindProcess(aProcessName); + if (process == NULL && aAllowFuzzy) + { + process = FuzzyFindProcess(aProcessName); + } + + if (process) + { + LOG_MSG3("DProcessTracker::NotifyAgentsForProcessEvent name=%S eventtype=%d", + &aProcessName, aEvent.iEventType); + process->NotifyEvent(aEvent); + return ETrue; + } + + // Since no specifically attached agents were found, try the attach all + + DDebugAgent* currentAll = GetCurrentAgentAttachedToAll(); + if (currentAll) + { + foundAgent = ETrue; + LOG_MSG4("DProcessTracker::NotifyAgentsForProcessEvent via AttachAll name=%S eventtype=%d, agent 0x%lx", + &aProcessName, aEvent.iEventType, currentAll->Id()); + currentAll->NotifyEvent(aEvent); + } + + return foundAgent; + } + +/** + * Find the agent that matches this exe/proc name. Name could be the attachall indicator "*", + * in which case it returns the agent that matched the pid from the attach all list + */ +DDebugAgent* DProcessTracker::FindAgentForProcessAndId(const TDesC8& aProcessName, TUint64 aAgentId) const + { + + if (aProcessName == _L8("*")) + { + TInt const agentCount = iAgentsAttachedToAll.Count(); + + LOG_MSG3("FindAgentForProcessAndId : Searching for agent id 0x%lx, iAgentsAttachedToAll size=%d", + aAgentId, agentCount ); + + // Then check the attached to all list. Should not have more than one entry + // for each agent, but just in case we search backwards to match the append + // + for (TInt i = agentCount - 1 ; i >= 0; i--) + { + DDebugAgent* agent = iAgentsAttachedToAll[i]; + if (agent->Id() == aAgentId) + { + return agent; + } + } + } + else + { + DTargetProcess* process = FindProcess(aProcessName); + if (process) + { + return process->Agent(aAgentId); + } + } + return NULL; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/d_rmd_breakpoints.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/d_rmd_breakpoints.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,1816 @@ +// Copyright (c) 2004-2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "d_rmd_breakpoints.h" +#include "d_process_tracker.h" +#include "d_rmd_stepping.h" +#include "rm_debug_kerneldriver.h" // needed to access DRM_DebugChannel +#include "rm_debug_driver.h" +#include "debug_utils.h" +#include "debug_logging.h" + +using namespace Debug; + +/* @internalTechnology + * + * Checks whether aAddress is correctly aligned for placing a breakpoint of + * cpu architecture aMode. + * + * @param aAddress - Virtual memory address to check + * @param aMode - The CPU architecture mode of the breakpoint to be placed at aAddress + * @return ETrue if aAddress is suitably aligned, EFalse otherwise. + */ +TBool D_RMD_Breakpoints::Aligned(TUint32 aAddress, Debug::TArchitectureMode aMode) + { + switch(aMode) + { + case Debug::EArmMode: + // ARM breakpoints must be 32-bit aligned (lower two bits must be zero) + if (aAddress & 0x3) + { + // Not 32-bit aligned. + return EFalse; + } + break; + case Debug::EThumbMode: + // Thumb breakpoints must be 16-bit aligned (low bit must be zero) + if (aAddress & 0x1) + { + // Not 16-bit aligned + return EFalse; + } + break; + case Debug::EThumb2EEMode: + // Thumb-EE instructions are half-word aligned. See ARM ARM DDI0406A, section A3.2 Alignment Support + // Note that some instructions need to be word-aligned, but this function does not know which ones. + // It may also depend on the System Control register U bit. + if (aAddress & 0x1) + { + // Not 16-bit aligned + return EFalse; + } + break; + default: + { + // No idea + return EFalse; + } + } + + // Must be OK + return ETrue; + }; + +/* @internalTechnology + * + * Returns the size of a breakpoint of architecture aMode in bytes + * + * @param aMode - The architure of the breakpoint + * @return The size of the breakpoints in bytes. 0 if un-recognised architecture. + */ +TInt D_RMD_Breakpoints::BreakSize(Debug::TArchitectureMode aMode) + { + switch(aMode) + { + case Debug::EArmMode: + { + return 4; + } + case Debug::EThumbMode: + { + return 2; + } + case Debug::EThumb2EEMode: + { + // Only needs to be two bytes in size. + return 2; + } + default: + { + // No idea + return 0; + } + } + }; + +/* @internalTechnology + * + * Checks whether two TBreakEntrys overlap + * + * @param aFirst - A TBreakEntry with valid iAddress and iMode fields. + * @param aSecond - A TBreakEntry with valid iAddress and iMode fields. + * @return ETrue if the aFirst and aSecond overlap or the overlap cannot be determined + * , EFalse otherwise + */ +TBool D_RMD_Breakpoints::BreakpointsOverlap(TBreakEntry& aFirst, TBreakEntry& aSecond) + { + TInt firstSize = BreakSize(aFirst.iMode); + TInt secondSize = BreakSize(aSecond.iMode); + + // Do we know the size of each breakpoint? + if ((firstSize <= 0) || (secondSize <= 0)) + { + // We don't know the size of the breakpoint, so assume they overlap + return ETrue; + } + + TInt firstStartAddress = aFirst.iAddress; + TInt secondStartAddress = aSecond.iAddress; + TInt firstEndAddress = firstStartAddress + firstSize - 1; + TInt secondEndAddress = secondStartAddress + secondSize - 1; + + // If second breakpoint is past the end of the first then we're ok + if(firstEndAddress < secondStartAddress) + { + return EFalse; + } + + // If first breakpoint is past the end of the second then we're ok + if(secondEndAddress < firstStartAddress) + { + return EFalse; + } + + // The breakpoints overlap + return ETrue; + } + +/* @internalTechnology + * + * Returns the breakpoint bitpattern to use for each architecture type + * + * @param aMode - the cpu architecture type + * @return The bit-pattern to use for the specified architecture, or 0 if unsupported. + */ +TUint32 D_RMD_Breakpoints::BreakInst(Debug::TArchitectureMode aMode) + { + switch(aMode) + { + case Debug::EArmMode: + { + return KArmBreakPoint; + } + case Debug::EThumbMode: + { + return KThumbBreakPoint; + } + case Debug::EThumb2EEMode: + { + return KT2EEBreakPoint; + } + default: + { + // No idea what the breakpoint should be + return 0; + } + } + }; + +/** +Constructor. Initialises its internal list of empty breakpoints. +*/ +D_RMD_Breakpoints::D_RMD_Breakpoints(DRM_DebugChannel* aChannel) +: iBreakPointList(NUMBER_OF_TEMP_BREAKPOINTS, 0), + iNextBreakId(NUMBER_OF_TEMP_BREAKPOINTS), + iChannel(aChannel), + iInitialised(EFalse) + { + iBreakPointList.Reset(); + TBreakEntry emptyTempBreak; + + for (TInt i = 0; i < NUMBER_OF_TEMP_BREAKPOINTS; i++) + { + emptyTempBreak.iBreakId = i; + + if (KErrNone != iBreakPointList.Append(emptyTempBreak)) + { + LOG_MSG("D_RMD_Breakpoints::D_RMD_Breakpoints() - Error appending blank temp break entry"); + } + } + } + +/** +Destructor. Clears all the breakpoints in the system, deletes its internal list of breakpoints, +and closes the exclusivity semaphore. +*/ +D_RMD_Breakpoints::~D_RMD_Breakpoints() + { + ClearAllBreakPoints(); + + // close the breakpoint list and free the memory associated with it + iBreakPointList.Close(); + + if (iLock) + iLock->Close(NULL); + } + +/** +Initialises the breakpoint list exclusion semaphore. This should be called once immediately after +the constructor. + +@return KErrNone if successful, one of the other system wide error codes otherwise. +*/ +TInt D_RMD_Breakpoints::Init() + { + TInt err = KErrNone; + + // Only create a semaphore if we are not initialised + if(!iInitialised) + { + // Initialise the semaphore ensuring exclusive access to the breakpoint list + err = Kern::SemaphoreCreate(iLock, _L("RM_DebugBreakpointLock"), 1 /* Initial count */); + if (err == KErrNone) + { + iInitialised = ETrue; + } + } + else + { + err = KErrNone; + } + + return err; + } + +/** +Public member function which sets a thread-specific breakpoint in the specified thread +and returns an opaque handle to the caller. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DoSetBreak + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +@param aBreakId - Reference to a TUint32 into which the function will return a unique breakpoint Id. +@param aThreadId - The thread Id in which to place the breakpoint +@param aAddress - Address to place the breakpoint +@param aMode - The cpu instruction set architecture type breakpoint (e.g. EArmMode or EThumbMode) +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::DoSetBreak(TInt32 &aBreakId, const TUint64 aId, const TBool aThreadSpecific, const TUint32 aAddress, const TArchitectureMode aMode) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DoSetBreak(aBreakId, aId, aThreadSpecific, aAddress,aMode); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } +/** +Private member function which sets a thread-specific breakpoint in the specified thread +and returns an opaque handle to the caller. + +@see DoSetBreak + +@param aBreakId - Reference to a TUint32 into which the function will return a unique breakpoint Id. +@param aThreadId - The thread Id in which to place the breakpoint +@param aAddress - Address to place the breakpoint +@param aMode - The cpu instruction set architecture type breakpoint (e.g. EArmMode or EThumbMode) +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::priv_DoSetBreak(TInt32 &aBreakId, const TUint64 aId, const TBool aThreadSpecific, const TUint32 aAddress, const TArchitectureMode aMode) + { + LOG_MSG4("D_RMD_Breakpoints::priv_DoSetBreak(aThreadId = 0x%lx, aAddress = 0x%08x, aMode = %d)",aId,aAddress,aMode); + + // EThumb2EEMode breakpoints are not supported + if (EThumb2EEMode == aMode) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - EThumb2EEMode breakpoints are not supported"); + return KErrNotSupported; + } + + // Check how many breakpoints we have in existence + if ((iBreakPointList.Count()+1) >= NUMBER_OF_MAX_BREAKPOINTS) + { + // Too many breakpoints are set! + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Too many breakpoints set"); + return KErrOverflow; + } + + // check the alignment of the breakpoint + if (!Aligned(aAddress,aMode)) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Unaligned address"); + return KErrArgument; + } + + // make sure there is not already a breakpoint at this address + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + /* We need to check if the breakpoint overlaps the address at all, + * and this depends upon the size of the two breakpoints as well as + * their address. + */ + + // newInstSize = size in bytes of new breakpoint + TInt newInstSize = BreakSize(aMode); + if (newInstSize == 0) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Unknown architecture type for new breakpoint"); + return KErrNotSupported; + } + + // oldInstSize = size in bytes of the existing breakpoint + TInt oldInstSize = BreakSize(iBreakPointList[i].iMode); + if (oldInstSize == 0) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - : Unknown architecture type of existing breakpoint"); + return KErrNotSupported; + } + + // Overlap checking - temp is used as the new breakpoint description for checking purposes only + TBreakEntry temp; + + temp.iAddress = aAddress; + temp.iMode = aMode; + + // do they overlap? + if ( BreakpointsOverlap(temp,iBreakPointList[i]) ) + { + // Yes + if(iBreakPointList[i].iThreadSpecific && aThreadSpecific) + { + if(aId == iBreakPointList[i].iId) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New thread specific breakpoint overlaps an existing thread specific breakpoint"); + return KErrAlreadyExists; + } + } + else if(!iBreakPointList[i].iThreadSpecific && aThreadSpecific) + { + NKern::ThreadEnterCS(); + DThread* thread = DebugUtils::OpenThreadHandle(aId); + TInt err = KErrNone; + if (!thread) + { + err = KErrNotFound; + } + if (!err && thread->iOwningProcess->iId == iBreakPointList[i].iId) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New thread specific breakpoint overlaps an existing breakpoint"); + err = KErrAlreadyExists; + } + thread->Close(NULL); + NKern::ThreadLeaveCS(); + if (err) return err; + } + else if(iBreakPointList[i].iThreadSpecific && !aThreadSpecific) + { + NKern::ThreadEnterCS(); + DThread* thread = DebugUtils::OpenThreadHandle(iBreakPointList[i].iId); + TInt err = KErrNone; + if (!thread) + { + err = KErrNotFound; + } + if (!err && thread->iOwningProcess->iId == aId) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New breakpoint overlaps an existing thread specific breakpoint"); + err = KErrAlreadyExists; + } + if (thread) thread->Close(NULL); + NKern::ThreadLeaveCS(); + if (err) return err; + } + else // !iBreakPointList[i].iThreadSpecific && !aThreadSpecific + { + if(iBreakPointList[i].iId == aId) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - New breakpoint overlaps an existing breakpoint"); + return KErrAlreadyExists; + } + } + } + } + + // increment the break id + aBreakId = iNextBreakId++; + + // create the new breakpoint entry + TBreakEntry breakEntry(aBreakId, aId, aThreadSpecific, aAddress, aMode); + + TInt err = priv_DoEnableBreak(breakEntry, ETrue); + if (KErrNone != err) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Could not enable the breakpoint"); + + return err; + } + + err = iBreakPointList.Append(breakEntry); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoSetBreak() - Failed to append breakpoint"); + } + + LOG_MSG2("D_RMD_Breakpoints::priv_DoSetBreak(breakId = 0x%08x) done",aBreakId); + + return err; + } + +/** +Public member function which enables a previously set breakpoint. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DoEnableBreak + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +Note 3 +Historically, this function accepted a reference to a TBreakEntry in the class' own +iBreakPointList. It now checks whether the reference is to an element of its own list, +or one invented by the caller. + +@param aEntry reference to a TBreakEntry datastructure describing the breakpoint to be re-enabled. +@param aSaveOldInstruction ETrue preserves the instruction at the breakpoint address, EFalse otherwise. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::DoEnableBreak(TBreakEntry &aEntry, TBool aSaveOldInstruction) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DoEnableBreak(aEntry,aSaveOldInstruction); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Private member function which enables a previously set breakpoint, as per DoEnableBreak, but +does not serialise access. + +@see DoEnableBreak + +@param aEntry reference to a TBreakEntry datastructure describing the breakpoint to be re-enabled. +@param aSaveOldInstruction ETrue preserves the instruction at the breakpoint address, EFalse otherwise. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::priv_DoEnableBreak(TBreakEntry &aEntry, TBool aSaveOldInstruction) + { + LOG_MSG("D_RMD_Breakpoints::DoEnableBreak()"); + + TUint32 inst = BreakInst(aEntry.iMode); + TInt instSize = BreakSize(aEntry.iMode); + if (instSize == 0 || inst == 0) + { + // not supported + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableBreak - unsupported breakpoint architecture"); + return KErrNotSupported; + } + + TInt err = KErrNone; + + // Get thread id + TUint64 threadId = aEntry.iId + (aEntry.iThreadSpecific ? 0 : 1); + NKern::ThreadEnterCS(); + DThread* threadObj = DebugUtils::OpenThreadHandle(threadId); + if (!threadObj) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableBreak - bad handle. Could not identify a threadObj"); + NKern::ThreadLeaveCS(); + return KErrBadHandle; + } + + if (aSaveOldInstruction) + { + TUint32 instruction; + + // read the instruction at the address so we can store it in the break entry for when we clear this breakpoint + // trap exceptions in case the address is invalid + XTRAPD(r, XT_DEFAULT, err = iChannel->TryToReadMemory(threadObj, (TAny *)aEntry.iAddress, (TAny *)&instruction, instSize)); + + //consider the leave as more important than the error code so store the leave if it's not KErrNone + if(KErrNone != r) + { + err = r; + } + + if(KErrNone != err) + { + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableBreak() - failed to read memory"); + return err; + } + + aEntry.iInstruction.Copy((TUint8 *)&instruction, instSize); + } + + TBool breakpointAlredySet = EFalse; + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + if(iBreakPointList[i].iAddress == aEntry.iAddress && !iBreakPointList[i].iDisabledForStep ) + { + breakpointAlredySet = ETrue; + break; + } + } + if(!breakpointAlredySet) + { + + LOG_MSG5("D_RMD_Breakpoints::DoEnableBreak() tId=0x%x, addr=0x%x, instSize=%d, inst=0x%x", + threadObj->iId, aEntry.iAddress, instSize, instSize == 4 ? (TUint32)inst : (TUint16)inst ); + XTRAPD(r, XT_DEFAULT, err = DebugSupport::ModifyCode(threadObj, aEntry.iAddress, instSize, inst, DebugSupport::EBreakpointGlobal)); + if(r != DebugSupport::EBreakpointGlobal) + { + err = r; + } + } + else + { + LOG_MSG5("D_RMD_Breakpoints::DoEnableBreak() ALREADY SET: tId=0x%x, addr=0x%x, instSize=%d, inst=0x%x", + threadObj->iId, aEntry.iAddress, instSize, instSize == 4 ? (TUint32)inst : (TUint16)inst ); + + } + + // Close the thread handle which has been opened by OpenThreadHandle + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + return err; + } + +/** +Public member function which clears a previously set breakpoint. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DoClearBreak + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +@param aBreakId A breakpoint Id as previously returned by DoSetBreak. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::DoClearBreak(const TInt32 aBreakId, TBool aIgnoreTerminatedThreads) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DoClearBreak(aBreakId, aIgnoreTerminatedThreads); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Private member function which clears a previously set breakpoint, as per DoClearBreak, but +does not serialise access. + +@see DoClearBreak + +@param aBreakId A breakpoint Id as previously returned by DoSetBreak. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::priv_DoClearBreak(const TInt32 aBreakId, TBool aIgnoreTerminatedThreads) + { + LOG_MSG3("D_RMD_Breakpoints::priv_DoClearBreak(0x%08x), aIgnoreTerminatedThreads=%d", + aBreakId, aIgnoreTerminatedThreads); + + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id + TBreakEntry entry; + entry.iBreakId = aBreakId; + TInt index = iBreakPointList.FindInSignedKeyOrder(entry); + + TInt err = KErrNone; + if (index >= 0) + { + // if this breakpoint was set in a library and that library has already been unloaded, don't try to clear it + if (!iBreakPointList[index].iObsoleteLibraryBreakpoint) + { + NKern::ThreadEnterCS(); + DThread* threadObj = DebugUtils::OpenThreadHandle(iBreakPointList[index].iId + (iBreakPointList[index].iThreadSpecific ? 0 : 1)); + if (threadObj) + { + LOG_MSG2("priv_DoClearBreak() OpenThreadHandle ret thread 0x%08x", threadObj->iId ); + TBool needToCallCodeModifier = ETrue; + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + if (i != index) + { + if ( BreakpointsOverlap(iBreakPointList[index],iBreakPointList[i]) ) + { + needToCallCodeModifier = EFalse; + break; + } + } + } + if(needToCallCodeModifier) + { + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[index].iAddress)); + if (r != KErrNone) + { + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - restore code trap harness returned error %d",r); + } + if (err == KErrNotFound) + { + LOG_MSG("restore code reported the breakpoint not found, continuing"); + err = KErrNone; + } + else if (err != KErrNone) + { + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - restore code returned error %d",err); + } + err = (KErrNone == r) ? err : r; + } + + // Close the thread handle opened by OpenThreadHandle + threadObj->Close(NULL); + } + else + { + LOG_MSG("D_RMD_Breakpoints::OpenThreadHandle ret null thread"); + err = KErrBadHandle; + } + NKern::ThreadLeaveCS(); + } + + LOG_MSG4("D_RMD_Breakpoints::priv_DoClearBreak() - Clearing breakpoint at address: %x, err: %d, ignore terminated: %d", iBreakPointList[index].iAddress, err, aIgnoreTerminatedThreads?1:0); + if ((aIgnoreTerminatedThreads && KErrBadHandle == err) || KErrNone == err) + { + // if this is a temp breakpoint, just clear out the values, otherwise remove it from the list + err = KErrNone; + if (index < NUMBER_OF_TEMP_BREAKPOINTS) + { + // if this is a temp breakpoint, just clear out the values, otherwise remove it from the list + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - Reseting temp breakpoint[%d]",index); + iBreakPointList[index].Reset(); + } + else + { + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - Removing breakpoint[%d]",index); + iBreakPointList.Remove(index); + } + } + else + { + LOG_MSG3("D_RMD_Breakpoints::priv_DoClearBreak() - *** Not removing breakpoint[%d] due to error=%d",index, err); + } + + return err; + } + + LOG_MSG2("D_RMD_Breakpoints::priv_DoClearBreak() - Break Id %d not found", aBreakId); + + return KErrNotFound; + } + +/** +Public member function which modifies a previously set breakpoint. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DoModifyBreak + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +@param aBreakInfo A TModifyBreakInfo describing the breakpoint properties that are wanted. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::DoModifyBreak(TModifyBreakInfo* aBreakInfo) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DoModifyBreak(aBreakInfo); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Private member function which modifies a previously set breakpoint, as per DoModifyBreak, but +does not serialise access. + +@see DoModifyBreak + +@param aBreakInfo A TModifyBreakInfo describing the breakpoint properties that are wanted. +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::priv_DoModifyBreak(TModifyBreakInfo* aBreakInfo) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak()"); + + // Check arguments + if (!aBreakInfo) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() was passed a NULL argument"); + return KErrArgument; + } + + //User side memory is not accessible directly + TSetBreakInfo info; + TInt err = Kern::ThreadRawRead(iChannel->iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TSetBreakInfo)); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() was passed a bad argument"); + return err; + } + + // EThumb2EEMode breakpoints are not supported + if (EThumb2EEMode == info.iMode) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() - EThumb2EEMode breakpoints are not supported"); + return KErrNotSupported; + } + + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id + TBreakEntry entry; + entry.iBreakId = (TUint32)info.iBreakId; + TInt index = iBreakPointList.FindInSignedKeyOrder(entry); + if (index < 0) + { + // Could not find the breakpoint + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyBreak() - Could not find the breakpoint id 0x%08x",(TUint32)info.iBreakId); + return KErrNotFound; + } + + // first check its not obsolete + if (!iBreakPointList[index].iObsoleteLibraryBreakpoint) + { + // its still a valid breakpoint + + // remove the old breakpoint + NKern::ThreadEnterCS(); + DThread* threadObj = DebugUtils::OpenThreadHandle(iBreakPointList[index].iId); + if (threadObj) + { + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyBreak - Unsetting breakpoint at address 0x%08x",iBreakPointList[index].iAddress); + + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[index].iAddress)); + if (r != 0) + { + LOG_MSG("Failed to construct trap handler for DebugSupport::RestoreCode"); + } + + // Close the thread handle which has been opened by OpenThreadHandle + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + } + else + { + // Bad handle + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - Could not identify the breakpoint thread id"); + NKern::ThreadLeaveCS(); + return KErrBadHandle; + } + } + + // make sure there is not already a breakpoint at the new address + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + // Ignore data for the breakpoint entry being modified. + if (i != index) + { + /* We need to check if the breakpoint overlaps the address at all, + * and this depends upon the size of the two breakpoints as well as + * their address. + */ + + // newInstSize = size in bytes of new breakpoint + TInt newInstSize = BreakSize(info.iMode); + if (newInstSize == 0) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - Unknown architecture type for new breakpoint"); + return KErrNotSupported; + } + + // oldInstSize = size in bytes of the existing breakpoint + TInt oldInstSize = BreakSize(iBreakPointList[i].iMode); + if (oldInstSize == 0) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - Unknown architecture type of existing breakpoint"); + return KErrNotSupported; + } + + // Overlap checking - temp is used as the new breakpoint description for checking purposes only + TBreakEntry temp; + + temp.iAddress = info.iAddress; + temp.iMode = info.iMode; + + // do they overlap? + if ( BreakpointsOverlap(temp,iBreakPointList[i]) ) + { + // Yes + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() - New breakpoint overlaps an existing breakpoint"); + return KErrAlreadyExists; + } + } + } + + // Prepare iBreakPointList[index] with the new information, then set the breakpoint + iBreakPointList[index].iId = info.iId; + iBreakPointList[index].iAddress = info.iAddress; + iBreakPointList[index].iMode = info.iMode; + + TBreakEntry& newBreakEntry = iBreakPointList[index]; + + // Decide the size of the breakpoint instruction + TUint32 inst = BreakInst(newBreakEntry.iMode); + TInt instSize = BreakSize(newBreakEntry.iMode); + + if (inst == 0 || instSize == 0) + { + // Unsupported architecture + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak - unsupported breakpoint architecture"); + return KErrNotSupported; + } + + + //if thread id is 0xFFFFFFFF, then the breakpoint is not thread specific + if (newBreakEntry.iId != 0xFFFFFFFF) + { + newBreakEntry.iThreadSpecific = ETrue; + } + + // Get thread id from the process that we are debugging + TProcessInfo * proc = NULL; + TUint64 threadId = NULL; + + threadId = newBreakEntry.iId; + + NKern::ThreadEnterCS(); + DThread* threadObj = DebugUtils::OpenThreadHandle(threadId); + //if we don't have the right thread id for the address, + //then try with the thread id of the process that we are debugging + if (!threadObj && iChannel->iDebugProcessList.Count()) + { + proc = &iChannel->iDebugProcessList[0]; + if (proc) + { + threadId = proc->iId+1; + } + threadObj = DebugUtils::OpenThreadHandle(threadId); + } + + if(!threadObj) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyBreak() - bad handle. Could not identify a threadObj"); + NKern::ThreadLeaveCS(); + return KErrBadHandle; + } + + // save the old instruction + TUint32 instruction; + + // read the instruction at the address so we can store it in the break entry for when we clear this breakpoint + // trap exceptions in case the address is invalid + XTRAPD(r, XT_DEFAULT, err = iChannel->TryToReadMemory(threadObj, (TAny *)newBreakEntry.iAddress, (TAny *)&instruction, instSize)); + + //consider the leave as more important than the error code so store the leave if it's not KErrNone + if(KErrNone != r) + { + err = r; + } + if(KErrNone != err) + { + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + return err; + } + + newBreakEntry.iInstruction.Copy((TUint8 *)&instruction, instSize); + + newBreakEntry.iId = threadId; //set the thread ID here + LOG_MSG3("ModifyCode2 instSize:%d, inst: 0x%08x", instSize, inst); + XTRAPD(s, XT_DEFAULT, err = DebugSupport::ModifyCode(threadObj, newBreakEntry.iAddress, instSize, inst, DebugSupport::EBreakpointGlobal)); + if(s != DebugSupport::EBreakpointGlobal) + { + err = s; + } + + // Close the thread handle which has been opened by OpenThreadHandle + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + return err; + } + +// +// D_RMD_Breakpoints::DoModifyProcessBreak +// +TInt D_RMD_Breakpoints::DoModifyProcessBreak(TModifyProcessBreakInfo* aBreakInfo) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DoModifyProcessBreak(aBreakInfo); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } + +TInt D_RMD_Breakpoints::priv_DoModifyProcessBreak(TModifyProcessBreakInfo* aBreakInfo) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak()"); + + // Check arguments + if (!aBreakInfo) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() was passed a NULL argument"); + return KErrArgument; + } + + //User side memory is not accessible directly + TSetBreakInfo info; + TInt err = Kern::ThreadRawRead(iChannel->iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TModifyProcessBreakInfo)); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() was passed a bad argument"); + return err; + } + + // EThumb2EEMode breakpoints are not supported + if (EThumb2EEMode == info.iMode) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - EThumb2EEMode breakpoints are not supported"); + return KErrNotSupported; + } + + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id + TBreakEntry entry; + entry.iBreakId = (TUint32)info.iBreakId; + TInt index = iBreakPointList.FindInSignedKeyOrder(entry); + if (index < 0) + { + // Could not find the breakpoint + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Could not find the breakpoint id 0x%08x",(TUint32)info.iBreakId); + return KErrNotFound; + } + + // first check its not obsolete + if (!iBreakPointList[index].iObsoleteLibraryBreakpoint) + { + // its still a valid breakpoint + + // remove the old breakpoint + NKern::ThreadEnterCS(); + DProcess *process = DebugUtils::OpenProcessHandle(iBreakPointList[index].iId); + DThread* threadObj = NULL; + if(process) + { + threadObj = DebugUtils::OpenFirstThreadForProcess(process); + process->Close(NULL); + } + + if (threadObj) + { + LOG_MSG2("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Unsetting breakpoint at address 0x%08x",iBreakPointList[index].iAddress); + + XTRAPD(r, XT_DEFAULT, /*err =*/ DebugSupport::RestoreCode(threadObj, iBreakPointList[index].iAddress)); // Any error here is not important. The semantics of ModifyBreakpoint are such that if it fails the previous breakpoint location is removed, which means that a further call to ModifyBreakpoint shouldn't fail because the CodeModifier doesn't know about it. + if (r != 0) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Failed to construct trap handler for DebugSupport::RestoreCode"); + } + + // Close the thread handle which has been opened by OpenThreadHandle + threadObj->Close(NULL); + } + else + { + // Bad handle + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Could not identify the breakpoint process id"); + err = KErrBadHandle; + } + NKern::ThreadLeaveCS(); + if (err) return err; + } + + // make sure there is not already a breakpoint at the new address + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + // Ignore data for the breakpoint entry being modified. + if (i != index) + { + /* We need to check if the breakpoint overlaps the address at all, + * and this depends upon the size of the two breakpoints as well as + * their address. + */ + + // newInstSize = size in bytes of new breakpoint + TInt newInstSize = BreakSize(info.iMode); + if (newInstSize == 0) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - Unknown architecture type for new breakpoint"); + return KErrNotSupported; + } + + // oldInstSize = size in bytes of the existing breakpoint + TInt oldInstSize = BreakSize(iBreakPointList[i].iMode); + if (oldInstSize == 0) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - : Unknown architecture type of existing breakpoint"); + return KErrNotSupported; + } + + // Overlap checking - temp is used as the new breakpoint description for checking purposes only + TBreakEntry temp; + + temp.iAddress = info.iAddress; + temp.iMode = info.iMode; + + // do they overlap? + if ( BreakpointsOverlap(temp,iBreakPointList[i]) ) + { + // Yes + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - New breakpoint overlaps an existing breakpoint"); + return KErrAlreadyExists; + } + } + } + + // Prepare iBreakPointList[index] with the new information, then set the breakpoint + iBreakPointList[index].iId = info.iId; + iBreakPointList[index].iAddress = info.iAddress; + iBreakPointList[index].iMode = info.iMode; + + TBreakEntry& newBreakEntry = iBreakPointList[index]; + + // Decide the size of the breakpoint instruction + TUint32 inst = BreakInst(newBreakEntry.iMode); + TInt instSize = BreakSize(newBreakEntry.iMode); + + if (inst == 0 || instSize == 0) + { + // Unsupported architecture + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - unsupported breakpoint architecture"); + return KErrNotSupported; + } + + newBreakEntry.iThreadSpecific = EFalse; + + DThread* threadObj = NULL; + NKern::ThreadEnterCS(); + DProcess* process = DebugUtils::OpenProcessHandle(newBreakEntry.iId); + if (process) + { + threadObj = DebugUtils::OpenFirstThreadForProcess(process); + if (!threadObj) err = KErrNotFound; + process->Close(NULL); + } + else + { + LOG_MSG("D_RMD_Breakpoints::priv_DoModifyProcessBreak() - bad handle. Could not identify a process"); + err = KErrBadHandle; + } + + if (err) + { + NKern::ThreadLeaveCS(); + return err; + } + + // save the old instruction + TUint32 instruction; + + // read the instruction at the address so we can store it in the break entry for when we clear this breakpoint + // trap exceptions in case the address is invalid + XTRAPD(r, XT_DEFAULT, err = iChannel->TryToReadMemory(threadObj, (TAny *)newBreakEntry.iAddress, (TAny *)&instruction, instSize)); + + //consider the leave as more important than the error code so store the leave if it's not KErrNone + if(KErrNone != r) + { + err = r; + } + if(KErrNone != err) + { + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + return err; + } + + newBreakEntry.iInstruction.Copy((TUint8 *)&instruction, instSize); + + XTRAPD(s, XT_DEFAULT, err = DebugSupport::ModifyCode(threadObj, newBreakEntry.iAddress, instSize, inst, DebugSupport::EBreakpointGlobal)); + if(s != DebugSupport::EBreakpointGlobal) + { + err = s; + } + + // Close the thread handle which has been opened by OpenThreadHandle + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + return err; + } + +/** +Public member function which returns information about a previously set breakpoint. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DoBreakInfo + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +@param aBreakInfo Address of aBreakInfo structure in user-side memory within the DSS client thread. CAN ONLY BE ACCESSED VIA Kern::ThreadRawRead() +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::DoBreakInfo(TGetBreakInfo* aBreakInfo) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DoBreakInfo(aBreakInfo); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Private member function function which returns information about a previously set breakpoint.. + +@see DoBreakInfo + +@param aBreakInfo Address of aBreakInfo structure in user-side memory within the DSS client thread. CAN ONLY BE ACCESSED VIA Kern::ThreadRawRead() +@return KErrNone if successful, otherwise one of the other system wide error codes. +*/ +TInt D_RMD_Breakpoints::priv_DoBreakInfo(TGetBreakInfo* aBreakInfo) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo()"); + + if (!aBreakInfo) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() was passed a NULL argument"); + + return KErrArgument; + } + + //User side memory is not accessible directly + TGetBreakInfo info; + TInt err = Kern::ThreadRawRead(iChannel->iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TGetBreakInfo)); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() was passed a bad argument"); + + return err; + } + + // find the break entry matching this id. note that the breakpoints are already sorted in ascending order by id + TBreakEntry entry; + entry.iBreakId = (TUint32)info.iBreakId; + TInt index = iBreakPointList.FindInSignedKeyOrder(entry); + + if (index >=0) + { + // get the thread id for this breakpoint + TUint64 threadId = iBreakPointList[index].iId; + + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iId,&threadId,sizeof(TUint64)); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return breakpoint iThreadId information"); + return err; + } + + // get the threadSpecific-ness + TBool threadSpecific = iBreakPointList[index].iThreadSpecific; + + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iThreadSpecific,&threadSpecific,sizeof(TBool)); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return thread specific information"); + return err; + } + + + // get the address + TUint32 address = iBreakPointList[index].iAddress; + + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iAddress,&address,sizeof(TUint32)); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return breakpoint iAddress information"); + return err; + } + + + // get the architecture + TArchitectureMode mode = iBreakPointList[index].iMode; + + err = Kern::ThreadRawWrite(iChannel->iClientThread,(TUint8*)info.iMode,&mode,sizeof(TUint32)); + if (err != KErrNone) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoBreakInfo() - failed to return breakpoint iMode information"); + return err; + } + + return err; + } + + LOG_MSG2("D_RMD_Breakpoints::priv_DoBreakInfo - Could not find the breakpoint id specified 0x%08x", entry.iBreakId); + return KErrNotFound; + } + +/** +Public member function which clears all the breakpoints in the system. Generally used for shutting down +the debug device driver. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_ClearAllBreakPoints + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; +*/ +void D_RMD_Breakpoints::ClearAllBreakPoints() + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + priv_ClearAllBreakPoints(); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + } + +/** +Private member function which clears all the breakpoints in the system. Generally used for shutting down +the debug device driver. + +@see DoClearAllBreakPoints +*/ +void D_RMD_Breakpoints::priv_ClearAllBreakPoints() + { + LOG_MSG("D_RMD_Breakpoints::priv_ClearAllBreakPoints()"); + + TInt err = KErrNone; + NKern::ThreadEnterCS(); + for (TInt i=0; iClose(NULL); + } + else + { + LOG_MSG(" OpenThreadHandle returned NULL handle"); + err = KErrBadHandle; + } + + if (KErrNone != err) + { + LOG_MSG2("D_RMD_Breakpoints::priv_ClearAllBreakPoints() - Error 0x%08x while clearing breakpoint", err); + } + } + else if(iBreakPointList[i].iAddress == 0) + { + LOG_MSG3("Breakpoint[%d]: address is 0, iId=0x%016lx", i, iBreakPointList[i].iId ); + } + else + { + LOG_MSG4("Breakpoint[%d]: Obsoleted, address =0x%x, iId=0x%016lx", i, iBreakPointList[i].iAddress, iBreakPointList[i].iId ); + } + } + NKern::ThreadLeaveCS(); + + iBreakPointList.Reset(); + } + +/** +Public member function which disables the breakpoint at the specified address. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DisableBreakAtAddress + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +@param aAddress Address at which to disable breakpoints (all threads) +@return KErrNone if successful, one of the other system wide error codes otherwise. +*/ +TInt D_RMD_Breakpoints::DisableBreakAtAddress(TUint32 aAddress) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DisableBreakAtAddress(aAddress); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Private member function which clears all the breakpoints in the system. Generally used for shutting down +the debug device driver. + +@see DisableBreakAtAddress + +@param aAddress clears the breakpoint at the specified address +@return KErrNone if successful, one of the other system wide error codes otherwise. +*/ +TInt D_RMD_Breakpoints::priv_DisableBreakAtAddress(TUint32 aAddress) + { + LOG_MSG2("D_RMD_Breakpoints::priv_DisableBreakAtAddress(aAddress=0x%x)", aAddress); + + TInt err = KErrNone; + + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + if (iBreakPointList[i].iAddress == aAddress) + { + iBreakPointList[i].iDisabledForStep = ETrue; + LOG_MSG2("D_RMD_Breakpoints::priv_DisableBreakAtAddress - Disabling breakpoint at address 0x%x", iBreakPointList[i].iAddress); + + //clear the breakpoint with code modifier + //code modifier will restore the org instruction and also frees the shadow page if necessary + TUint64 id = iBreakPointList[i].iId + (iBreakPointList[i].iThreadSpecific ? 0 : 1); + DThread* threadObj = NULL; + NKern::ThreadEnterCS(); + if(iBreakPointList[i].iThreadSpecific) + { + threadObj = DebugUtils::OpenThreadHandle(id); + } + else + { + DProcess* process = DebugUtils::OpenProcessHandle(iBreakPointList[i].iId); + if(process) + { + threadObj = DebugUtils::OpenFirstThreadForProcess(process); + process->Close(NULL); + } + } + + if (threadObj) + { + XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, aAddress)); + if(KErrNone != err || KErrNone != r) + { + LOG_MSG3("Error from DebugSupport::RestoreCode: r: %d, err: %d", r, err); + } + err = (KErrNone == r) ? err : r; + threadObj->Close(NULL); + } + else + { + err = KErrBadHandle; + LOG_MSG2("Couldn't find thread for breakpoint id %d", iBreakPointList[i].iId); + } + NKern::ThreadLeaveCS(); + if (err) break; + } + } + + return err; + } + +/** +Public member function which enables previously disabled breakpoints within a given thread. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DoEnableDisabledBreak + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +@param aThreadId Thread in which to enable all previously disabled breakpoints +@return KErrNone if successful, one of the system wide error codes otherwise. +*/ +TInt D_RMD_Breakpoints::DoEnableDisabledBreak(TUint64 aThreadId) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return KErrNotReady; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TInt err = priv_DoEnableDisabledBreak(aThreadId); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Private member function which enables previously disabled breakpoints within a given thread. + +@see DoEnableDisabledBreak + +@param aThreadId Thread in which to enable all previously disabled breakpoints +@return KErrNone if successful, one of the system wide error codes otherwise. +*/ +TInt D_RMD_Breakpoints::priv_DoEnableDisabledBreak(TUint64 aThreadId) + { + LOG_MSG("D_RMD_Breakpoints::priv_DoEnableDisabledBreak()"); + NKern::ThreadEnterCS(); + DThread* thread = DebugUtils::OpenThreadHandle(aThreadId); + if(!thread) + { + LOG_MSG2("Thread: 0x%08x does not exist", aThreadId); + NKern::ThreadLeaveCS(); + return KErrNotFound; + } + TUint64 processId = thread->iOwningProcess->iId; + thread->Close(NULL); + NKern::ThreadLeaveCS(); + + for (TInt i = NUMBER_OF_TEMP_BREAKPOINTS; i < iBreakPointList.Count(); i++) + { + TBool needsEnabling = EFalse; + if(iBreakPointList[i].iDisabledForStep) + { + if(iBreakPointList[i].iThreadSpecific) + { + needsEnabling = (aThreadId == iBreakPointList[i].iId); + } + else + { + needsEnabling = (processId == iBreakPointList[i].iId); + } + } + if (needsEnabling) + { + LOG_MSG2("Re-enabling breakpoint at address %x", iBreakPointList[i].iAddress); + TInt err = priv_DoEnableBreak(iBreakPointList[i], EFalse); + if(KErrNone != err) + { + LOG_MSG2("Error returned from DoEnableBreak: %d", err); + iBreakPointList[i].iDisabledForStep = EFalse; + return err; + } + } + } + + return KErrNone; + } + +/** +Public member function which removes all the breakpoints within a given thread. + +Note 1: +This function ensures exclusive access to the breakpoint data structures +by using a semaphore to serialise access. + +@see priv_DoRemoveThreadBreaks + +Note 2: +As implied by Note 1, the caller must have previously called Init() or this +function will return KErrNotReady; + +@param aThreadId Thread from which to remove all existing breakpoints +@return KErrNone if successful, one of the system wide error codes otherwise. +*/ +void D_RMD_Breakpoints::DoRemoveThreadBreaks(TUint64 aThreadId) + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + priv_DoRemoveThreadBreaks(aThreadId); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + } + +/** +Private member function which removes all the breakpoints particular to a particular thread + +@see DoRemoveThreadBreaks + +@param aThreadId Thread from which to remove all existing breakpoints +@return KErrNone if successful, one of the system wide error codes otherwise. +*/ +void D_RMD_Breakpoints::priv_DoRemoveThreadBreaks(TUint64 aThreadId) + { + LOG_MSG2("D_RMD_Breakpoints::priv_DoRemoveThreadBreaks(aThreadId = 0x%lx)\n",aThreadId); + + TInt err = KErrNone; + TUint64 threadId; + + for (TInt i=iBreakPointList.Count()-1; i >= 0; i--) + { + if ((iBreakPointList[i].iAddress != 0) && !iBreakPointList[i].iObsoleteLibraryBreakpoint) + { + threadId = iBreakPointList[i].iId + (iBreakPointList[i].iThreadSpecific ? 0 : 1); + if (threadId == aThreadId) + { + LOG_MSG5("D_RMD_Breakpoints::priv_DoRemoveThreadBreaks() - Clearing breakpoint[%d],idx=%x at address 0x%08x, iId=0x%016lx", + i, iBreakPointList[i].iBreakId, iBreakPointList[i].iAddress, iBreakPointList[i].iId ); + + err = priv_DoClearBreak(iBreakPointList[i].iBreakId, EFalse); + + if (err != KErrNone) + { + LOG_MSG2("D_RMD_Breakpoints::priv_DoRemoveThreadBreaks() - failed to remove break id 0x%08x\n",iBreakPointList[i].iBreakId); + return; + } + } + } + else if(iBreakPointList[i].iAddress == 0) + { + LOG_MSG3("Breakpoint[%d]: address is 0, iId=0x%016lx", i, iBreakPointList[i].iId ); + } + else + { + LOG_MSG4("Breakpoint[%d]: Obsoleted, address =0x%x, iId=0x%016lx", i, iBreakPointList[i].iAddress, iBreakPointList[i].iId ); + } + } + } + +// Remove the process breakpoints for process with PID aProcessId in the range [aCodeAddress, aCodeAddress + aCodeSize) +void D_RMD_Breakpoints::RemoveBreaksForProcess(TUint64 aProcessId, TUint32 aCodeAddress, TUint32 aCodeSize) + { + LOG_MSG4("D_RMD_Breakpoints::RemoveBreaksForProcess(), aProcId=0x%016lx, codeAddr=0x%x, codeSize=0x%x", + aProcessId,aCodeAddress, aCodeSize); + NKern::ThreadEnterCS(); + for (TInt i=iBreakPointList.Count() - 1; i>=0; i--) + { + TBool remove = EFalse; + TBreakEntry& breakEntry = iBreakPointList[i]; + + if( breakEntry.iId == 0 || breakEntry.iAddress == 0 ) + { + breakEntry.Reset(); + continue; + } + + LOG_MSG5(" break[%d], iId=0x%016lx, threadSpec=%d, aProcessId=0x%016lx", + i, breakEntry.iId, breakEntry.iThreadSpecific, aProcessId); + + if(!breakEntry.iThreadSpecific && breakEntry.iId == aProcessId) + { + remove = ETrue; + } + else if(breakEntry.iThreadSpecific) + { + //breakEntry.iId is thread id. Get its pid, then check if aProcessId is same, then remove + DThread* thread = DebugUtils::OpenThreadHandle(breakEntry.iId); + if(!thread) + { + LOG_MSG2("Could not open handle to thread (aThreadId = 0x%016lx)",breakEntry.iId); + continue; + } + + LOG_MSG2(" thread->iOwningProcess->iId=0x%016lx", thread->iOwningProcess->iId ); + + if( thread->iOwningProcess->iId == aProcessId ) + { + LOG_MSG3("Thread spec breakpoint @ index[%d] matches aProcessId= 0x%016lx. Removing",i, aProcessId); + remove = ETrue; + } + + thread->Close(NULL); + } + + if ( remove && (breakEntry.iAddress >= aCodeAddress) && (breakEntry.iAddress < (aCodeAddress + aCodeSize))) + { + LOG_MSG2("Removing process breakpoint at address %x", (TUint32)breakEntry.iAddress); + TInt err = DoClearBreak(breakEntry.iBreakId, ETrue); + if(KErrNone != err) + { + LOG_MSG2("Error removing breakpoint: %d", err); + } + } + else + { + LOG_MSG4("Not removing breakpoint at index[%d], id=0x%016lx, address=0x%x", + i, breakEntry.iId, (TUint32)breakEntry.iAddress); + } + } + NKern::ThreadLeaveCS(); + } + +// mark the breakpoints in the range [aCodeAddress, aCodeAddress + aCodeSize) +void D_RMD_Breakpoints::InvalidateLibraryBreakPoints(TUint32 aCodeAddress, TUint32 aCodeSize) + { + LOG_MSG3("D_RMD_Breakpoints::InvalidateLibraryBreakPoints(aCodeAddress=0x%x, aCodeSize=0x%x)", + aCodeAddress, aCodeSize ); + + for (TInt i=0; i= aCodeAddress) && (iBreakPointList[i].iAddress < (aCodeAddress + aCodeSize))) + { + LOG_MSG2("Obsoleting library breakpoint at address %x", iBreakPointList[i].iAddress); + iBreakPointList[i].iObsoleteLibraryBreakpoint = ETrue; + } + } + } + +TInt D_RMD_Breakpoints::BreakPointCount() const + { + return iBreakPointList.Count(); + } + +/** + Gets next breakpoint in list. + @param aBreakEntry The break entry to get the successor of. If NULL then returns the first entry. + @return A pointer to the next break entry, or NULL if the end of the list has been reached + */ +TBreakEntry* D_RMD_Breakpoints::GetNextBreak(const TBreakEntry* aBreakEntry) const + { + if(!aBreakEntry) + { + return (TBreakEntry*)&(iBreakPointList[0]); + } + TInt index = iBreakPointList.FindInSignedKeyOrder(*aBreakEntry) + 1; + return (index < BreakPointCount()) ? (TBreakEntry*)&(iBreakPointList[index]) : NULL; + } + +TBool D_RMD_Breakpoints::IsTemporaryBreak(const TBreakEntry& aBreakEntry) const + { + // Ensure we have a valid semaphore + if (!iInitialised || !iLock) + { + return EFalse; + } + + // Acquire the lock + NKern::ThreadEnterCS(); + Kern::SemaphoreWait(*iLock); + + // Really do the work + TBool tempBreak = priv_IsTemporaryBreak(aBreakEntry); + + // Release the lock + Kern::SemaphoreSignal(*iLock); + NKern::ThreadLeaveCS(); + + return tempBreak; + } + +/** +Private member function which tells us if a breakpoint is temporary + +@see IsTemporaryBreak + +@param aBreakEntry +@return TBool indicating if the break is temporary or not +*/ +TBool D_RMD_Breakpoints::priv_IsTemporaryBreak(const TBreakEntry& aBreakEntry) const + { + return aBreakEntry.iBreakId < NUMBER_OF_TEMP_BREAKPOINTS; + } + + +// End of file - d_rmd_breakpoints.cpp diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/d_rmd_stepping.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/d_rmd_stepping.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,1884 @@ +// Copyright (c) 2004-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: +// This file contains stepping code refactored from rm_debug_kerneldriver.cpp/rm_debug_kerneldriver.h +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "d_rmd_stepping.h" +#include "d_rmd_breakpoints.h" +#include "rm_debug_kerneldriver.h" // needed to access DRM_DebugChannel +#include "rm_debug_driver.h" +#include "debug_logging.h" + +using namespace Debug; + +// +// DRMDStepping::DRMDStepping +// +DRMDStepping::DRMDStepping(DRM_DebugChannel* aChannel) +: + iChannel(aChannel) + { + // to do + } + +// +// DRMDStepping::~DRM_DebugChannel +// +DRMDStepping::~DRMDStepping() + { + // to do + } + +// +// DRMDStepping::IsExecuted +// +TBool DRMDStepping::IsExecuted(TUint8 aCondition ,TUint32 aStatusRegister) + { + LOG_MSG("DRMDStepping::IsExecuted()"); + + TBool N = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000008; + TBool Z = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000004; + TBool C = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000002; + TBool V = ((aStatusRegister >> 28) & 0x0000000F) & 0x00000001; + + switch(aCondition) + { + case 0: + return Z; + case 1: + return !Z; + case 2: + return C; + case 3: + return !C; + case 4: + return N; + case 5: + return !N; + case 6: + return V; + case 7: + return !V; + case 8: + return (C && !Z); + case 9: + return (!C || Z); + case 10: + return (N == V); + case 11: + return (N != V); + case 12: + return ((N == V) && !Z); + case 13: + return (Z || (N != V)); + case 14: + case 15: + return ETrue; + } + + return EFalse; + } + +// +// DRMDStepping::IsPreviousInstructionMovePCToLR +// +TBool DRMDStepping::IsPreviousInstructionMovePCToLR(DThread *aThread) + { + LOG_MSG("DRMDStepping::IsPreviousInstructionMovePCToLR()"); + + TInt err = KErrNone; + + // there are several types of instructions that modify the PC that aren't + // designated as linked or non linked branches. the way gcc generates the + // code can tell us whether or not these instructions are to be treated as + // linked branches. the main cases are bx and any type of mov or load or + // arithmatic operation that changes the PC. if these are really just + // function calls that will return, gcc will generate a mov lr, pc + // instruction as the previous instruction. note that this is just for arm + // and armi + + // get the address of the previous instruction + TUint32 address = 0; + err = iChannel->ReadKernelRegisterValue(aThread, PC_REGISTER, address); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + address -= 4; + + TBuf8<4> previousInstruction; + err = iChannel->DoReadMemory(aThread, address, 4, previousInstruction); + if (KErrNone != err) + { + LOG_MSG2("Error %d reading memory at address %x", address); + return EFalse; + } + + const TUint32 movePCToLRIgnoringCondition = 0x01A0E00F; + + TUint32 inst = *(TUint32 *)previousInstruction.Ptr(); + + if ((inst & 0x0FFFFFFF) == movePCToLRIgnoringCondition) + { + return ETrue; + } + + return EFalse; + } + +// +// DRMDStepping::DecodeDataProcessingInstruction +// +void DRMDStepping::DecodeDataProcessingInstruction(TUint8 aOpcode, TUint32 aOp1, TUint32 aOp2, TUint32 aStatusRegister, TUint32 &aBreakAddress) + { + LOG_MSG("DRMDStepping::DecodeDataProcessingInstruction()"); + + switch(aOpcode) + { + case 0: + { + // AND + aBreakAddress = aOp1 & aOp2; + break; + } + case 1: + { + // EOR + aBreakAddress = aOp1 ^ aOp2; + break; + } + case 2: + { + // SUB + aBreakAddress = aOp1 - aOp2; + break; + } + case 3: + { + // RSB + aBreakAddress = aOp2 - aOp1; + break; + } + case 4: + { + // ADD + aBreakAddress = aOp1 + aOp2; + break; + } + case 5: + { + // ADC + aBreakAddress = aOp1 + aOp2 + (aStatusRegister & arm_carry_bit()) ? 1 : 0; + break; + } + case 6: + { + // SBC + aBreakAddress = aOp1 - aOp2 - (aStatusRegister & arm_carry_bit()) ? 0 : 1; + break; + } + case 7: + { + // RSC + aBreakAddress = aOp2 - aOp1 - (aStatusRegister & arm_carry_bit()) ? 0 : 1; + break; + } + case 12: + { + // ORR + aBreakAddress = aOp1 | aOp2; + break; + } + case 13: + { + // MOV + aBreakAddress = aOp2; + break; + } + case 14: + { + // BIC + aBreakAddress = aOp1 & ~aOp2; + break; + } + case 15: + { + // MVN + aBreakAddress = ~aOp2; + break; + } + } + } + +// +// DRMDStepping::CurrentInstruction +// +// Returns the current instruction bitpattern (either 32-bits or 16-bits) if possible +TInt DRMDStepping::CurrentInstruction(DThread* aThread, TUint32& aInstruction) + { + LOG_MSG("DRMDStepping::CurrentInstruction"); + + // What is the current PC? + TUint32 pc; + ReturnIfError(CurrentPC(aThread,pc)); + + // Read it one byte at a time to ensure alignment doesn't matter + TUint32 inst = 0; + for(TInt i=3;i>=0;i--) + { + + TBuf8<1> instruction; + TInt err = iChannel->DoReadMemory(aThread, (pc+i), 1, instruction); + if (KErrNone != err) + { + LOG_MSG2("DRMDStepping::CurrentInstruction : Failed to read memory at current PC: return 0x%08x",pc); + return err; + } + + inst = (inst << 8) | (*(TUint8 *)instruction.Ptr()); + } + + aInstruction = inst; + + LOG_MSG2("DRMDStepping::CurrentInstruction 0x%08x", aInstruction); + + return KErrNone; + } + +// +// DRMDStepping::CurrentArchMode +// +// Determines architecture mode from the supplied cpsr +TInt DRMDStepping::CurrentArchMode(const TUint32 aCpsr, Debug::TArchitectureMode& aMode) + { +// Thumb2 work will depend on having a suitable cpu architecture to compile for... +#ifdef ECpuJf + // State table as per ARM ARM DDI0406A, section A.2.5.1 + if(aCpsr & ECpuJf) + { + if (aCpsr & ECpuThumb) + { + // ThumbEE (Thumb2) + aMode = Debug::EThumb2EEMode; + } + else + { + // Jazelle mode - not supported + return KErrNotSupported; + } + } + else +#endif + { + if (aCpsr & ECpuThumb) + { + // Thumb mode + aMode = Debug::EThumbMode; + } + else + { + // ARM mode + aMode = Debug::EArmMode; + } + } + + return KErrNone; + } + +// +// DRMDStepping::PCAfterInstructionExecutes +// +// Note, this function pretty much ignores all the arguments except for aThread. +// The arguments continue to exist so that the function has the same prototype as +// the original from Nokia. In the long term this function will be re-factored +// to remove obsolete parameters. +// +TUint32 DRMDStepping::PCAfterInstructionExecutes(DThread *aThread, TUint32 aCurrentPC, TUint32 aStatusRegister, TInt aInstSize, /*TBool aStepInto,*/ TUint32 &aNewRangeEnd, TBool &aChangingModes) + { + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes()"); + + // by default we will set the breakpoint at the next instruction + TUint32 breakAddress = aCurrentPC + aInstSize; + + TInt err = KErrNone; + + // determine the architecture + TUint32 cpuid; + asm("mrc p15, 0, cpuid, c0, c0, 0 "); + LOG_MSG2("DRMDStepping::PCAfterInstructionExecutes() - cpuid = 0x%08x\n",cpuid); + + cpuid >>= 8; + cpuid &= 0xFF; + + // determine the architecture mode for the current instruction + TArchitectureMode mode = EArmMode; // Default assumption is ARM + + // Now we must examine the CPSR to read the T and J bits. See ARM ARM DDI0406A, section B1.3.3 + TUint32 cpsr; + + ReturnIfError(CurrentCPSR(aThread,cpsr)); + LOG_MSG2("DRMDStepping::PCAfterInstructionExecutes() - cpsr = 0x%08x\n",cpsr); + + // Determine the mode + ReturnIfError(CurrentArchMode(cpsr,mode)); + + // Decode instruction based on current CPU mode + switch(mode) + { + case Debug::EArmMode: + { + // Obtain the current instruction bit pattern + TUint32 inst; + ReturnIfError(CurrentInstruction(aThread,inst)); + + LOG_MSG2("Current instruction: %x", inst); + + // check the conditions to see if this will actually get executed + if (IsExecuted(((inst>>28) & 0x0000000F), aStatusRegister)) + { + switch(arm_opcode(inst)) // bits 27-25 + { + case 0: + { + switch((inst & 0x00000010) >> 4) // bit 4 + { + case 0: + { + switch((inst & 0x01800000) >> 23) // bits 24-23 + { + case 2: + { + // move to/from status register. pc updates not allowed + // or TST, TEQ, CMP, CMN which don't modify the PC + break; + } + default: + { + // Data processing immediate shift + if (arm_rd(inst) == PC_REGISTER) + { + TUint32 rn = aCurrentPC + 8; + if (arm_rn(inst) != PC_REGISTER) // bits 19-16 + { + err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), rn); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + } + + TUint32 shifter = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister); + + DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress); + } + break; + } + } + break; + } + case 1: + { + switch((inst & 0x00000080) >> 7) // bit 7 + { + case 0: + { + switch((inst & 0x01900000) >> 20) // bits 24-23 and bit 20 + { + case 0x10: + { + // from figure 3-3 + switch((inst & 0x000000F0) >> 4) // bits 7-4 + { + case 1: + { + if (((inst & 0x00400000) >> 22) == 0) // bit 22 + { + // BX + // this is a strange case. normally this is used in the epilogue to branch the the link + // register. sometimes it is used to call a function, and the LR is stored in the previous + // instruction. since what we want to do is different for the two cases when stepping over, + // we need to read the previous instruction to see what we should do + err = iChannel->ReadKernelRegisterValue(aThread, (inst & 0x0000000F), breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + + if ((breakAddress & 0x00000001) == 1) + { + aChangingModes = ETrue; + } + + breakAddress &= 0xFFFFFFFE; + } + break; + } + case 3: + { + // BLX + { + err = iChannel->ReadKernelRegisterValue(aThread, (inst & 0x0000000F), breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + + if ((breakAddress & 0x00000001) == 1) + { + aChangingModes = ETrue; + } + + breakAddress &= 0xFFFFFFFE; + } + break; + } + default: + { + // either doesn't modify the PC or it is illegal to + break; + } + } + break; + } + default: + { + // Data processing register shift + if (((inst & 0x01800000) >> 23) == 2) // bits 24-23 + { + // TST, TEQ, CMP, CMN don't modify the PC + } + else if (arm_rd(inst) == PC_REGISTER) + { + // destination register is the PC + TUint32 rn = aCurrentPC + 8; + if (arm_rn(inst) != PC_REGISTER) // bits 19-16 + { + err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), rn); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + } + + TUint32 shifter = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister); + + DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress); + } + break; + } + } + break; + } + default: + { + // from figure 3-2, updates to the PC illegal + break; + } + } + break; + } + } + break; + } + case 1: + { + if (((inst & 0x01800000) >> 23) == 2) // bits 24-23 + { + // cannot modify the PC + break; + } + else if (arm_rd(inst) == PC_REGISTER) + { + // destination register is the PC + TUint32 rn; + err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), rn); // bits 19-16 + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + TUint32 shifter = ((arm_data_imm(inst) >> arm_data_rot(inst)) | (arm_data_imm(inst) << (32 - arm_data_rot(inst)))) & 0xffffffff; + + DecodeDataProcessingInstruction(((inst & 0x01E00000) >> 21), rn, shifter, aStatusRegister, breakAddress); + } + break; + } + case 2: + { + // load/store immediate offset + if (arm_load(inst)) // bit 20 + { + // loading a register from memory + if (arm_rd(inst) == PC_REGISTER) + { + // loading the PC register + TUint32 base; + err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), base); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + + /* Note: At runtime the PC would be 8 further on + */ + if (arm_rn(inst) == PC_REGISTER) + { + base = aCurrentPC + 8; + } + + TUint32 offset = 0; + + if (arm_single_pre(inst)) + { + // Pre-indexing + offset = arm_single_imm(inst); + + if (arm_single_u(inst)) + { + base += offset; + } + else + { + base -= offset; + } + } + + TBuf8<4> destination; + err = iChannel->DoReadMemory(aThread, base, 4, destination); + + if (KErrNone == err) + { + breakAddress = *(TUint32 *)destination.Ptr(); + + if ((breakAddress & 0x00000001) == 1) + { + aChangingModes = ETrue; + } + breakAddress &= 0xFFFFFFFE; + } + else + { + LOG_MSG("Error reading memory in decoding step instruction"); + } + } + } + break; + } + case 3: + { + if (((inst & 0xF0000000) != 0xF0000000) && ((inst & 0x00000010) == 0)) + { + // load/store register offset + if (arm_load(inst)) // bit 20 + { + // loading a register from memory + if (arm_rd(inst) == PC_REGISTER) + { + // loading the PC register + TUint32 base = 0; + if(arm_rn(inst) == PC_REGISTER) + { + base = aCurrentPC + 8; + } + else + { + err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), base); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + } + + TUint32 offset = 0; + + if (arm_single_pre(inst)) + { + offset = ShiftedRegValue(aThread, inst, aCurrentPC, aStatusRegister); + + if (arm_single_u(inst)) + { + base += offset; + } + else + { + base -= offset; + } + } + + TBuf8<4> destination; + err = iChannel->DoReadMemory(aThread, base, 4, destination); + + if (KErrNone == err) + { + breakAddress = *(TUint32 *)destination.Ptr(); + + if ((breakAddress & 0x00000001) == 1) + { + aChangingModes = ETrue; + } + breakAddress &= 0xFFFFFFFE; + } + else + { + LOG_MSG("Error reading memory in decoding step instruction"); + } + } + } + } + break; + } + case 4: + { + if ((inst & 0xF0000000) != 0xF0000000) + { + // load/store multiple + if (arm_load(inst)) // bit 20 + { + // loading a register from memory + if (((inst & 0x00008000) >> 15)) + { + // loading the PC register + TInt offset = 0; + if (arm_block_u(inst)) + { + TUint32 reglist = arm_block_reglist(inst); + offset = iChannel->Bitcount(reglist) * 4 - 4; + if (arm_block_pre(inst)) + offset += 4; + } + else if (arm_block_pre(inst)) + { + offset = -4; + } + + TUint32 temp = 0; + err = iChannel->ReadKernelRegisterValue(aThread, arm_rn(inst), temp); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + + temp += offset; + + TBuf8<4> destination; + err = iChannel->DoReadMemory(aThread, temp, 4, destination); + + if (KErrNone == err) + { + breakAddress = *(TUint32 *)destination.Ptr(); + if ((breakAddress & 0x00000001) == 1) + { + aChangingModes = ETrue; + } + breakAddress &= 0xFFFFFFFE; + } + else + { + LOG_MSG("Error reading memory in decoding step instruction"); + } + } + } + } + break; + } + case 5: + { + if ((inst & 0xF0000000) == 0xF0000000) + { + // BLX + breakAddress = (TUint32)arm_instr_b_dest(inst, aCurrentPC); + + // Unconditionally change into Thumb mode + aChangingModes = ETrue; + breakAddress &= 0xFFFFFFFE; + } + else + { + if ((inst & 0x01000000)) // bit 24 + { + // BL + breakAddress = (TUint32)arm_instr_b_dest(inst, aCurrentPC); + } + else + { + // B + breakAddress = (TUint32)arm_instr_b_dest(inst, aCurrentPC); + } + } + break; + } // case 5 + } //switch(arm_opcode(inst)) // bits 27-25 + } // if (IsExecuted(((inst>>28) & 0x0000000F), aStatusRegister)) + } // case Debug::EArmMode: + break; + + case Debug::EThumbMode: + { + // Thumb Mode + // + // Notes: This now includes the extra code + // required to decode V6T2 instructions + + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Thumb Instruction"); + + TUint16 inst; + + // Obtain the current instruction bit pattern + TUint32 inst32; + ReturnIfError(CurrentInstruction(aThread,inst32)); + + inst = static_cast(inst32 & 0xFFFF); + + LOG_MSG2("Current Thumb instruction: 0x%x", inst); + + // v6T2 instructions + + // Note: v6T2 decoding is only enabled for DEBUG builds or if using an + // an ARM_V6T2 supporting build system. At the time of writing, no + // ARM_V6T2 supporting build system exists, so the stepping code cannot + // be said to be known to work. Hence it is not run for release builds + + TBool use_v6t2_decodings = EFalse; + +#if defined(DEBUG) || defined(__ARMV6T2__) + use_v6t2_decodings = ETrue; +#endif + // coverity[dead_error_line] + if (use_v6t2_decodings) + { + // 16-bit encodings + + // A6.2.5 Misc 16-bit instructions + // DONE Compare and branch on zero (page A8-66) + // If then hints + + // ARM ARM DDI0406A - section A8.6.27 CBNZ, CBZ + // + // Compare and branch on Nonzero and Compare and Branch on Zero. + if ((inst & 0xF500) == 0xB100) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.27 CBNZ, CBZ"); + + // Decoding as per ARM ARM description + TUint32 op = (inst & 0x0800) >> 11; + TUint32 i = (inst & 0x0200) >> 9; + TUint32 imm5 = (inst & 0x00F8) >> 3; + TUint32 Rn = inst & 0x0007; + + TUint32 imm32 = (i << 6) | (imm5 << 1); + + // Obtain value for register Rn + TUint32 RnVal = 0; + ReturnIfError(RegisterValue(aThread,Rn,RnVal)); + + if (op) + { + // nonzero + if (RnVal != 0x0) + { + // Branch + breakAddress = aCurrentPC + imm32; + } + } + else + { + // zero + if (RnVal == 0x0) + { + // Branch + breakAddress = aCurrentPC + imm32; + } + } + } + + // ARM ARM DDI0406A - section A8.6.50 IT + // + // If Then instruction + if ((inst & 0xFF00) == 0xBF00) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.50 IT"); + + // Decoding as per ARM ARM description + TUint32 firstcond = inst & 0x00F0 >> 4; + TUint32 mask = inst & 0x000F; + + if (firstcond == 0xF) + { + // unpredictable + LOG_MSG("ARM ARM DDI0406A - section A8.6.50 IT - Unpredictable"); + break; + } + + if ((firstcond == 0xE) && (BitCount(mask) != 1)) + { + // unpredictable + LOG_MSG("ARM ARM DDI0406A - section A8.6.50 IT - Unpredictable"); + break; + } + + // should check if 'in-it-block' + LOG_MSG("Cannot step IT instructions."); + + // all the conds are as per Table A8-1 (i.e. the usual 16 cases) + // no idea how to decode the it block 'after-the-fact' + // so probably need to treat instructions in the it block + // as 'may' be executed. So breakpoints at both possible locations + // depending on whether the instruction is executed or not. + + // also, how do we know if we have hit a breakpoint whilst 'in' an it block? + // can we check the status registers to find out? + // + // see arm arm page 390. + // + // seems to depend on the itstate field. this also says what the condition code + // actually is, and how many instructions are left in the itblock. + // perhaps we can just totally ignore this state, and always do the two-instruction + // breakpoint thing? Not if there is any possibility that the address target + // would be invalid for the non-taken branch address... + } + + + // 32-bit encodings. + // + + // Load word A6-23 + // Data processing instructions a6-28 + // + + // ARM ARM DDI0406A - section A8.6.26 + if (inst32 & 0xFFF0FFFF == 0xE3C08F00) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.26 - BXJ is not supported"); + + // Decoding as per ARM ARM description + // TUint32 Rm = inst32 & 0x000F0000; // not needed yet + } + + // return from exception... SUBS PC,LR. page b6-25 + // + // ARM ARM DDi046A - section B6.1.13 - SUBS PC,LR + // + // Encoding T1 + if (inst32 & 0xFFFFFF00 == 0xF3DE8F00) + { + LOG_MSG("ARM ARM DDI0406A - section B6.1.13 - SUBS PC,LR Encoding T1"); + + // Decoding as per ARM ARM description + TUint32 imm8 = inst32 & 0x000000FF; + TUint32 imm32 = imm8; + + // TUint32 register_form = EFalse; // not needed for this decoding + // TUint32 opcode = 0x2; // SUB // not needed for this decoding + TUint32 n = 14; + + // Obtain LR + TUint32 lrVal; + ReturnIfError(RegisterValue(aThread,n,lrVal)); + + TUint32 operand2 = imm32; // always for Encoding T1 + + TUint32 result = lrVal - operand2; + + breakAddress = result; + } + + // ARM ARM DDI0406A - section A8.6.16 - B + // + // Branch Encoding T3 + if (inst32 & 0xF800D000 == 0xF0008000) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.16 - B Encoding T3"); + + // Decoding as per ARM ARM description + TUint32 S = inst32 & 0x04000000 >> 26; + // TUint32 cond = inst32 & 0x03C00000 >> 22; // not needed for this decoding + TUint32 imm6 = inst32 & 0x003F0000 >> 16; + TUint32 J1 = inst32 & 0x00002000 >> 13; + TUint32 J2 = inst32 & 0x00000800 >> 11; + TUint32 imm11 = inst32 & 0x000007FF; + + TUint32 imm32 = S ? 0xFFFFFFFF : 0 ; + imm32 = (imm32 << 1) | J2; + imm32 = (imm32 << 1) | J1; + imm32 = (imm32 << 6) | imm6; + imm32 = (imm32 << 11) | imm11; + imm32 = (imm32 << 1) | 0; + + breakAddress = aCurrentPC + imm32; + } + + // ARM ARM DDI0406A - section A8.6.16 - B + // + // Branch Encoding T4 + if (inst32 & 0xF800D000 == 0xF0009000) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.16 - B"); + + // Decoding as per ARM ARM description + TUint32 S = inst32 & 0x04000000 >> 26; + TUint32 imm10 = inst32 & 0x03FF0000 >> 16; + TUint32 J1 = inst32 & 0x00002000 >> 12; + TUint32 J2 = inst32 & 0x00000800 >> 11; + TUint32 imm11 = inst32 & 0x000003FF; + + TUint32 I1 = !(J1 ^ S); + TUint32 I2 = !(J2 ^ S); + + TUint32 imm32 = S ? 0xFFFFFFFF : 0; + imm32 = (imm32 << 1) | S; + imm32 = (imm32 << 1) | I1; + imm32 = (imm32 << 1) | I2; + imm32 = (imm32 << 10) | imm10; + imm32 = (imm32 << 11) | imm11; + imm32 = (imm32 << 1) | 0; + + breakAddress = aCurrentPC + imm32; + } + + + // ARM ARM DDI0406A - section A8.6.225 - TBB, TBH + // + // Table Branch Byte, Table Branch Halfword + if (inst32 & 0xFFF0FFE0 == 0xE8D0F000) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.225 TBB,TBH Encoding T1"); + + // Decoding as per ARM ARM description + TUint32 Rn = inst32 & 0x000F0000 >> 16; + TUint32 H = inst32 & 0x00000010 >> 4; + TUint32 Rm = inst32 & 0x0000000F; + + // Unpredictable? + if (Rm == 13 || Rm == 15) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.225 TBB,TBH Encoding T1 - Unpredictable"); + break; + } + + TUint32 halfwords; + TUint32 address; + ReturnIfError(RegisterValue(aThread,Rn,address)); + + TUint32 offset; + ReturnIfError(RegisterValue(aThread,Rm,offset)); + + if (H) + { + address += offset << 1; + } + else + { + address += offset; + } + + ReturnIfError(ReadMem32(aThread,address,halfwords)); + + breakAddress = aCurrentPC + 2*halfwords; + break; + } + + // ARM ARM DDI0406A - section A8.6.55 - LDMDB, LDMEA + // + // LDMDB Encoding T1 + if (inst32 & 0xFFD02000 == 0xE9100000) + { + LOG_MSG("ARM ARM DDI0406 - section A8.6.55 LDMDB Encoding T1"); + + // Decoding as per ARM ARM description + // TUint32 W = inst32 & 0x00200000 >> 21; // Not needed for this encoding + TUint32 Rn = inst32 & 0x000F0000 >> 16; + TUint32 P = inst32 & 0x00008000 >> 15; + TUint32 M = inst32 & 0x00004000 >> 14; + TUint32 registers = inst32 & 0x00001FFF; + + //TBool wback = (W == 1); // not needed for this encoding + + // Unpredictable? + if (Rn == 15 || BitCount(registers) < 2 || ((P == 1) && (M==1))) + { + LOG_MSG("ARM ARM DDI0406 - section A8.6.55 LDMDB Encoding T1 - Unpredictable"); + break; + } + + TUint32 address; + ReturnIfError(RegisterValue(aThread,Rn,address)); + + address -= 4*BitCount(registers); + + for(TInt i=0; i<15; i++) + { + if (IsBitSet(registers,i)) + { + address +=4; + } + } + + if (IsBitSet(registers,15)) + { + TUint32 RnVal = 0; + ReturnIfError(ReadMem32(aThread,address,RnVal)); + + breakAddress = RnVal; + } + break; + } + + // ARM ARM DDI0406A - section A8.6.121 POP + // + // POP.W Encoding T2 + if (inst32 & 0xFFFF2000 == 0xE8BD0000) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T2"); + + // Decoding as per ARM ARM description + TUint32 registers = inst32 & 0x00001FFF; + TUint32 P = inst32 & 0x00008000; + TUint32 M = inst32 & 0x00004000; + + // Unpredictable? + if ( (BitCount(registers)<2) || ((P == 1)&&(M == 1)) ) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T2 - Unpredictable"); + break; + } + + TUint32 address; + ReturnIfError(RegisterValue(aThread,13,address)); + + for(TInt i=0; i< 15; i++) + { + if (IsBitSet(registers,i)) + { + address += 4; + } + } + + // Is the PC written? + if (IsBitSet(registers,15)) + { + // Yes + ReturnIfError(ReadMem32(aThread,address,breakAddress)); + } + } + + // POP Encoding T3 + if (inst32 & 0xFFFF0FFFF == 0xF85D0B04) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T3"); + + // Decoding as per ARM ARM description + TUint32 Rt = inst32 & 0x0000F000 >> 12; + TUint32 registers = 1 << Rt; + + // Unpredictable? + if (Rt == 13 || Rt == 15) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.121 POP Encoding T3 - Unpredictable"); + break; + } + + TUint32 address; + ReturnIfError(RegisterValue(aThread,13,address)); + + for(TInt i=0; i< 15; i++) + { + if (IsBitSet(registers,i)) + { + address += 4; + } + } + + // Is the PC written? + if (IsBitSet(registers,15)) + { + // Yes + ReturnIfError(ReadMem32(aThread,address,breakAddress)); + } + + break; + } + + // ARM ARM DDI0406A - section A8.6.53 LDM + // + // Load Multiple Encoding T2 + if ((inst32 & 0xFFD02000) == 0xE8900000) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.53 LDM Encoding T2"); + + // Decoding as per ARM ARM description + TUint32 W = inst32 & 0x0020000 >> 21; + TUint32 Rn = inst32 & 0x000F0000 >> 16; + TUint32 P = inst32 & 0x00008000 >> 15; + TUint32 M = inst32 & 0x00004000 >> 14; + TUint32 registers = inst32 & 0x0000FFFF; + TUint32 register_list = inst32 & 0x00001FFF; + + // POP? + if ( (W == 1) && (Rn == 13) ) + { + // POP instruction + LOG_MSG("ARM ARM DDI0406A - section A8.6.53 LDM Encoding T2 - POP"); + } + + // Unpredictable? + if (Rn == 15 || BitCount(register_list) < 2 || ((P == 1) && (M == 1)) ) + { + LOG_MSG("ARM ARM DDI0406A - section A8.6.53 LDM Encoding T2 - Unpredictable"); + break; + } + + TUint32 RnVal; + ReturnIfError(RegisterValue(aThread,Rn,RnVal)); + + TUint32 address = RnVal; + + // Calculate offset of address + for(TInt i = 0; i < 15; i++) + { + if (IsBitSet(registers,i)) + { + address += 4; + } + } + + // Does it load the PC? + if (IsBitSet(registers,15)) + { + // Obtain the value loaded into the PC + ReturnIfError(ReadMem32(aThread,address,breakAddress)); + } + break; + + } + + // ARM ARM DDI0406A - section B6.1.8 RFE + // + // Return From Exception Encoding T1 RFEDB + if ((inst32 & 0xFFD0FFFF) == 0xE810C000) + { + LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T1"); + + // Decoding as per ARM ARM description + // TUint32 W = (inst32 & 0x00200000) >> 21; // not needed for this encoding + TUint32 Rn = (inst32 & 0x000F0000) >> 16; + + // TBool wback = (W == 1); // not needed for this encoding + TBool increment = EFalse; + TBool wordhigher = EFalse; + + // Do calculation + if (Rn == 15) + { + // Unpredictable + LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T1 - Unpredictable"); + break; + } + + TUint32 RnVal = 0; + ReturnIfError(RegisterValue(aThread,Rn,RnVal)); + + TUint32 address = 0; + ReturnIfError(ReadMem32(aThread,RnVal,address)); + + if (increment) + { + address -= 8; + } + + if (wordhigher) + { + address += 4; + } + + breakAddress = address; + break; + } + + // Return From Exception Encoding T2 RFEIA + if ((inst32 & 0xFFD0FFFF) == 0xE990C000) + { + LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T2"); + + // Decoding as per ARM ARM description + // TUint32 W = (inst32 & 0x00200000) >> 21; // not needed for this encoding + TUint32 Rn = (inst32 & 0x000F0000) >> 16; + + // TBool wback = (W == 1); // not needed for this encoding + TBool increment = ETrue; + TBool wordhigher = EFalse; + + // Do calculation + if (Rn == 15) + { + // Unpredictable + LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding T2 - Unpredictable"); + break; + } + + TUint32 RnVal = 0; + ReturnIfError(RegisterValue(aThread,Rn,RnVal)); + + TUint32 address = 0; + ReturnIfError(ReadMem32(aThread,RnVal,address)); + + if (increment) + { + address -= 8; + } + + if (wordhigher) + { + address += 4; + } + + breakAddress = RnVal; + break; + } + + // Return From Exception Encoding A1 RFE + if ((inst32 & 0xFE50FFFF) == 0xF8100A00) + { + LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding A1"); + + // Decoding as per ARM ARM description + TUint32 P = (inst32 & 0x01000000) >> 24; + TUint32 U = (inst32 & 0x00800000) >> 23; + // TUint32 W = (inst32 & 0x00200000) >> 21; // not needed for this encoding + TUint32 Rn = (inst32 & 0x000F0000) >> 16; + + // TBool wback = (W == 1); // not needed for this encoding + TBool increment = (U == 1); + TBool wordhigher = (P == U); + + // Do calculation + if (Rn == 15) + { + // Unpredictable + LOG_MSG("ARM ARM DDI0406A - section B6.1.8 RFE Encoding A1 - Unpredictable"); + break; + } + + TUint32 RnVal = 0; + ReturnIfError(RegisterValue(aThread,Rn,RnVal)); + + TUint32 address = 0; + ReturnIfError(ReadMem32(aThread,RnVal,address)); + + if (increment) + { + address -= 8; + } + + if (wordhigher) + { + address += 4; + } + + breakAddress = address; + break; + } + } + + // v4T/v5T/v6T instructions + switch(thumb_opcode(inst)) + { + case 0x08: + { + // Data-processing. See ARM ARM DDI0406A, section A6-8, A6.2.2. + + if ((thumb_inst_7_15(inst) == 0x08F)) + { + // BLX(2) + err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + + if ((breakAddress & 0x00000001) == 0) + { + aChangingModes = ETrue; + } + + breakAddress &= 0xFFFFFFFE; + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BLX (2)"); + } + else if (thumb_inst_7_15(inst) == 0x08E) + { + // BX + err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + + if ((breakAddress & 0x00000001) == 0) + { + aChangingModes = ETrue; + } + + breakAddress &= 0xFFFFFFFE; + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BX"); + } + else if ((thumb_inst_8_15(inst) == 0x46) && ((inst & 0x87) == 0x87)) + { + // MOV with PC as the destination + err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as MOV with PC as the destination"); + } + else if ((thumb_inst_8_15(inst) == 0x44) && ((inst & 0x87) == 0x87)) + { + // ADD with PC as the destination + err = iChannel->ReadKernelRegisterValue(aThread, ((inst & 0x0078) >> 3), breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + breakAddress += aCurrentPC + 4; // +4 because we need to use the PC+4 according to ARM ARM DDI0406A, section A6.1.2. + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as ADD with PC as the destination"); + } + break; + } + case 0x13: + { + // Load/Store single data item. See ARM ARM DDI0406A, section A6-10 + + //This instruction doesn't modify the PC. + + //if (thumb_inst_8_15(inst) == 0x9F) + //{ + // LDR(4) with the PC as the destination + // breakAddress = ReadRegister(aThread, SP_REGISTER) + (4 * (inst & 0x00FF)); + //} + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as This instruction doesn't modify the PC."); + break; + } + case 0x17: + { + // Misc 16-bit instruction. See ARM ARM DDI0406A, section A6-11 + + if (thumb_inst_8_15(inst) == 0xBD) + { + // POP with the PC in the list + TUint32 regList = (inst & 0x00FF); + TInt offset = 0; + err = iChannel->ReadKernelRegisterValue(aThread, SP_REGISTER, (T4ByteRegisterValue&)offset); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + offset += (iChannel->Bitcount(regList) * 4); + + TBuf8<4> destination; + err = iChannel->DoReadMemory(aThread, offset, 4, destination); + + if (KErrNone == err) + { + breakAddress = *(TUint32 *)destination.Ptr(); + + if ((breakAddress & 0x00000001) == 0) + { + aChangingModes = ETrue; + } + + breakAddress &= 0xFFFFFFFE; + } + else + { + LOG_MSG("Error reading memory in decoding step instruction"); + } + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as POP with the PC in the list"); + } + break; + } + case 0x1A: + case 0x1B: + { + // Conditional branch, and supervisor call. See ARM ARM DDI0406A, section A6-13 + + if (thumb_inst_8_15(inst) < 0xDE) + { + // B(1) conditional branch + if (IsExecuted(((inst & 0x0F00) >> 8), aStatusRegister)) + { + TUint32 offset = ((inst & 0x000000FF) << 1); + if (offset & 0x00000100) + { + offset |= 0xFFFFFF00; + } + + breakAddress = aCurrentPC + 4 + offset; + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as B(1) conditional branch"); + } + } + break; + } + case 0x1C: + { + // Unconditional branch, See ARM ARM DDI0406A, section A8-44. + + // B(2) unconditional branch + TUint32 offset = (inst & 0x000007FF) << 1; + if (offset & 0x00000800) + { + offset |= 0xFFFFF800; + } + + breakAddress = aCurrentPC + 4 + offset; + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as B(2) unconditional branch"); + + break; + } + case 0x1D: + { + if (!(inst & 0x0001)) + { + // BLX(1) + err = iChannel->ReadKernelRegisterValue(aThread, LINK_REGISTER, breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + breakAddress += ((inst & 0x07FF) << 1); + if ((breakAddress & 0x00000001) == 0) + { + aChangingModes = ETrue; + } + + breakAddress &= 0xFFFFFFFC; + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BLX(1)"); + + } + break; + } + case 0x1E: + { + // Check for ARMv7 CPU + if(cpuid == 0xC0) + { + // BL/BLX 32-bit instruction + aNewRangeEnd += 4; + + breakAddress = (TUint32)thumb_instr_b_dest(inst32, aCurrentPC); + + if((inst32 >> 27) == 0x1D) + { + // BLX(1) + if ((breakAddress & 0x00000001) == 0) + { + aChangingModes = ETrue; + } + + breakAddress &= 0xFFFFFFFC; + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as 32-bit BLX(1)"); + } + else + { + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: 32-bit BL instruction"); + } + LOG_MSG2(" 32-bit BL/BLX instruction: breakAddress = 0x%X", breakAddress); + } // if(cpuid == 0xC0) + else + { + // BL/BLX prefix - destination is encoded in this and the next instruction + aNewRangeEnd += 2; + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: BL/BLX prefix - destination is encoded in this and the next instruction"); + } + + break; + } + case 0x1F: + { + // BL + err = iChannel->ReadKernelRegisterValue(aThread, LINK_REGISTER, breakAddress); + if(err != KErrNone) + { + LOG_MSG2("Non-zero error code discarded: %d", err); + } + breakAddress += ((inst & 0x07FF) << 1); + + // Report how we decoded this instruction + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes: Decoded as BL"); + break; + } + default: + { + // Don't know any better at this point! + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes:- default to next instruction"); + } + break; + } // switch(thumb_opcode(inst)) + } // case Debug::EThumbMode: + break; + + case Debug::EThumb2EEMode: + { + // Not yet supported + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes - Debug::EThumb2Mode is not supported"); + + } + break; + + default: + LOG_MSG("DRMDStepping::PCAfterInstructionExecutes - Cannot determine CPU mode architecture"); + } // switch(mode) + + LOG_MSG2("DRMDStepping::PCAfterInstructionExecutes : return 0x%08x",breakAddress); + return breakAddress; + } + +// Obtain a 32-bit memory value with minimum fuss +TInt DRMDStepping::ReadMem32(DThread* aThread, const TUint32 aAddress, TUint32& aValue) + { + TBuf8<4> valBuf; + TInt err = iChannel->DoReadMemory(aThread, aAddress, 4, valBuf); + if (err != KErrNone) + { + LOG_MSG2("DRMDStepping::ReadMem32 failed to read memory at 0x%08x", aAddress); + return err; + } + + aValue = *(TUint32 *)valBuf.Ptr(); + + return KErrNone; + } + +// Obtain a 16-bit memory value with minimum fuss +TInt DRMDStepping::ReadMem16(DThread* aThread, const TUint32 aAddress, TUint16& aValue) + { + TBuf8<2> valBuf; + TInt err = iChannel->DoReadMemory(aThread, aAddress, 2, valBuf); + if (err != KErrNone) + { + LOG_MSG2("DRMDStepping::ReadMem16 failed to read memory at 0x%08x", aAddress); + return err; + } + + aValue = *(TUint16 *)valBuf.Ptr(); + + return KErrNone; + } + +// Obtain a 16-bit memory value with minimum fuss +TInt DRMDStepping::ReadMem8(DThread* aThread, const TUint32 aAddress, TUint8& aValue) + { + TBuf8<1> valBuf; + TInt err = iChannel->DoReadMemory(aThread, aAddress, 1, valBuf); + if (err != KErrNone) + { + LOG_MSG2("DRMDStepping::ReadMem8 failed to read memory at 0x%08x", aAddress); + return err; + } + + aValue = *(TUint8 *)valBuf.Ptr(); + + return KErrNone; + } + +// Obtain a core register value with minimum fuss +TInt DRMDStepping::RegisterValue(DThread *aThread, const TUint32 aKernelRegisterId, TUint32 &aValue) + { + TInt err = iChannel->ReadKernelRegisterValue(aThread, aKernelRegisterId, aValue); + if(err != KErrNone) + { + LOG_MSG3("DRMDStepping::RegisterValue failed to read register %d err = %d", aKernelRegisterId, err); + } + return err; + } + + +// Encodings from ARM ARM DDI0406A, section 9.2.1 +enum TThumb2EEOpcode + { + EThumb2HDP, // Handler Branch with Parameter + EThumb2UNDEF, // UNDEFINED + EThumb2HB, // Handler Branch, Handler Branch with Link + EThumb2HBLP, // Handle Branch with Link and Parameter + EThumb2LDRF, // Load Register from a frame + EThumb2CHKA, // Check Array + EThumb2LDRL, // Load Register from a literal pool + EThumb2LDRA, // Load Register (array operations) + EThumb2STR // Store Register to a frame + }; + +// +// DRMDStepping::ShiftedRegValue +// +TUint32 DRMDStepping::ShiftedRegValue(DThread *aThread, TUint32 aInstruction, TUint32 aCurrentPC, TUint32 aStatusRegister) + { + LOG_MSG("DRMDStepping::ShiftedRegValue()"); + + TUint32 shift = 0; + if (aInstruction & 0x10) // bit 4 + { + shift = (arm_rs(aInstruction) == PC_REGISTER ? aCurrentPC + 8 : aStatusRegister) & 0xFF; + } + else + { + shift = arm_data_c(aInstruction); + } + + TInt rm = arm_rm(aInstruction); + + TUint32 res = 0; + if(rm == PC_REGISTER) + { + res = aCurrentPC + ((aInstruction & 0x10) ? 12 : 8); + } + else + { + TInt err = iChannel->ReadKernelRegisterValue(aThread, rm, res); + if(err != KErrNone) + { + LOG_MSG2("DRMDStepping::ShiftedRegValue - Non-zero error code discarded: %d", err); + } + } + + switch(arm_data_shift(aInstruction)) + { + case 0: // LSL + { + res = shift >= 32 ? 0 : res << shift; + break; + } + case 1: // LSR + { + res = shift >= 32 ? 0 : res >> shift; + break; + } + case 2: // ASR + { + if (shift >= 32) + shift = 31; + res = ((res & 0x80000000L) ? ~((~res) >> shift) : res >> shift); + break; + } + case 3: // ROR/RRX + { + shift &= 31; + if (shift == 0) + { + res = (res >> 1) | ((aStatusRegister & arm_carry_bit()) ? 0x80000000L : 0); + } + else + { + res = (res >> shift) | (res << (32 - shift)); + } + break; + } + } + + return res & 0xFFFFFFFF; +} + +// +// DRMDStepping::CurrentPC +// +// +// +TInt DRMDStepping::CurrentPC(DThread* aThread, TUint32& aPC) + { + LOG_MSG("DRMDStepping::CurrentPC"); + + TInt err = iChannel->ReadKernelRegisterValue(aThread, PC_REGISTER, aPC); + if(err != KErrNone) + { + // We don't know the current PC for this thread! + LOG_MSG("DRMDStepping::CurrentPC - Failed to read the current PC"); + + return KErrGeneral; + } + + LOG_MSG2("DRMDStepping::CurrentPC 0x%08x", aPC); + + return KErrNone; + } + +// +// DRMDStepping::CurrentCPSR +// +// +// +TInt DRMDStepping::CurrentCPSR(DThread* aThread, TUint32& aCPSR) + { + LOG_MSG("DRMDStepping::CurrentCPSR"); + + TInt err = iChannel->ReadKernelRegisterValue(aThread, STATUS_REGISTER, aCPSR); + if(err != KErrNone) + { + // We don't know the current PC for this thread! + LOG_MSG("DRMDStepping::CurrentPC - Failed to read the current CPSR"); + + return KErrGeneral; + } + + LOG_MSG2("DRMDStepping::CurrentCPSR 0x%08x", aCPSR); + + return KErrNone; + } + +// +// DRMDStepping::ModifyBreaksForStep +// +// Set a temporary breakpoint at the next instruction to be executed after the one at the current PC +// Disable the breakpoint at the current PC if one exists +// +TInt DRMDStepping::ModifyBreaksForStep(DThread *aThread, TUint32 aRangeStart, TUint32 aRangeEnd, /*TBool aStepInto,*/ TBool aResumeOnceOutOfRange, TBool aCheckForStubs, const TUint32 aNumSteps) + { + LOG_MSG2("DRMDStepping::ModifyBreaksForStep() Numsteps 0x%d",aNumSteps); + + // Validate arguments + if (!aThread) + { + LOG_MSG("DRMDStepping::ModifyBreaksForStep() - No aThread specified to step"); + return KErrArgument; + } + + // Current PC + TUint32 currentPC; + + ReturnIfError(CurrentPC(aThread,currentPC)); + LOG_MSG2("Current PC: 0x%x", currentPC); + + // disable breakpoint at the current PC if necessary + ReturnIfError(iChannel->iBreakManager->DisableBreakAtAddress(currentPC)); + + // Current CPSR + TUint32 statusRegister; + + ReturnIfError(CurrentCPSR(aThread,statusRegister)); + LOG_MSG2("Current CPSR: %x", statusRegister); + + TBool thumbMode = (statusRegister & ECpuThumb); + if (thumbMode) + LOG_MSG("Thumb Mode"); + + TInt instSize = thumbMode ? 2 : 4; + + TBool changingModes = EFalse; + + TUint32 breakAddress = 0; + + TUint32 newRangeEnd = aRangeEnd; + + breakAddress = PCAfterInstructionExecutes(aThread, currentPC, statusRegister, instSize, /* aStepInto, */ newRangeEnd, changingModes); + + /* + If there is already a user breakpoint at this address, we do not need to set a temp breakpoint. The program + should simply stop at that address. + */ + TBreakEntry* breakEntry = NULL; + do + { + breakEntry = iChannel->iBreakManager->GetNextBreak(breakEntry); + if(breakEntry && !iChannel->iBreakManager->IsTemporaryBreak(*breakEntry)) + { + if ((breakEntry->iAddress == breakAddress) && ((breakEntry->iThreadSpecific && breakEntry->iId == aThread->iId) || (!breakEntry->iThreadSpecific && breakEntry->iId == aThread->iOwningProcess->iId))) + { + LOG_MSG("DRMDStepping::ModifyBreaksForStep - Breakpoint already exists at the step target address\n"); + + // note also that if this is the case, we will not keep stepping if we hit a real breakpoint, so may as well set + // the step count = 0. + breakEntry->iNumSteps = 0; + + return KErrNone; + } + } + } while(breakEntry); + + breakEntry = NULL; + do + { + breakEntry = iChannel->iBreakManager->GetNextBreak(breakEntry); + if(breakEntry && iChannel->iBreakManager->IsTemporaryBreak(*breakEntry)) + { + if (breakEntry->iAddress == 0) + { + breakEntry->iId = aThread->iId; + breakEntry->iAddress = breakAddress; + breakEntry->iThreadSpecific = ETrue; + + TBool realThumbMode = (thumbMode && !changingModes) || (!thumbMode && changingModes); + + // Need to set the correct type of breakpoint for the mode we are in + // and the the one we are changing into + if(realThumbMode) + { + // We are remaining in Thumb mode + breakEntry->iMode = EThumbMode; + } + else + { + // We are switching to ARM mode + breakEntry->iMode = EArmMode; + } + + breakEntry->iResumeOnceOutOfRange = aResumeOnceOutOfRange; + breakEntry->iSteppingInto = ETrue /* aStepInto */; + breakEntry->iRangeStart = 0; // no longer used + breakEntry->iRangeEnd = 0; // no longer used + + LOG_MSG2("Adding temp breakpoint with id: %d", breakEntry->iBreakId); + LOG_MSG2("Adding temp breakpoint with thread id: %d", aThread->iId); + + // Record how many more steps to go after we hit this one + breakEntry->iNumSteps = aNumSteps; + + LOG_MSG3("Setting temp breakpoint id %d with %d steps to go\n", breakEntry->iBreakId, aNumSteps); + + return iChannel->iBreakManager->DoEnableBreak(*breakEntry, ETrue); + } + } + } while(breakEntry); + LOG_MSG("ModifyBreaksForStep : Failed to set suitable breakpoint for stepping"); + return KErrNoMemory; // should never get here +} + +// End of file - d-rmd-stepping.cpp diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/d_target_process.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/d_target_process.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,157 @@ +// Copyright (c) 2006-2010 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: +// Purpose: The DProcessTracker object tracks which processes are being +// debugged. The DProcessTracker class uses a DTargetProcess object for +// each process being debugged. +// Note: Although TheDProcessTracker object is a global, it should be unique +// as only the Debug Security Server should load and use this driver. +// +// + +#include +#include +#include +#include +#include +#include +#include "nk_priv.h" +#include + +#include "d_target_process.h" +#include "debug_logging.h" +#include "debug_utils.h" + +// ctor +DTargetProcess::DTargetProcess() + :iProcessName(NULL) + { + } + +// dtor +DTargetProcess::~DTargetProcess() + { + delete iProcessName; + iAgentList.ResetAndDestroy(); + } + +// Compare two DTargetProcess items. They are the same if they have the same name. +TInt DTargetProcess::Compare(const DTargetProcess& aFirst, const DTargetProcess& aSecond) + { + const TDesC& left = aFirst.iProcessName ? *aFirst.iProcessName : KNullDesC(); + const TDesC& right = aSecond.iProcessName ? *aSecond.iProcessName : KNullDesC(); + return left.Compare(right); + } + +// Set the name of the process we are tracking +TInt DTargetProcess::SetProcessName(const TDesC8& aProcessName) + { + // Argument checking + if (aProcessName.Length() < 1) + { + return KErrArgument; + } + + if (iProcessName) + return KErrNotReady; // You can only set the processname once + iProcessName = HBuf8::New(aProcessName); + if (!iProcessName) + return KErrNoMemory; + return KErrNone; + } + +// Obtain the name of the process being tracked +const TDesC& DTargetProcess::ProcessName() const + { + return iProcessName ? *iProcessName : KNullDesC(); + } + +// Returns a pointer to the DDebugAgent with aAgentId. +// If the agent is not in the list, it returns NULL. +DDebugAgent* DTargetProcess::Agent(TUint64 aAgentId) + { + for(TInt i = 0; i < iAgentList.Count(); i++) + { + if (iAgentList[i]->Id() == aAgentId) + { + return iAgentList[i]; + } + } + + // what do we return if we don't have any agents? + return NULL; + } + +// Adds aAgentId as a tracking agent for this process. +TInt DTargetProcess::AddAgent(TUint64 aAgentId) + { + DDebugAgent* agent = DDebugAgent::New(aAgentId); + LOG_MSG4("DTargetProcess::AddAgent(), agentId=%d, curr iAgentList.Count=%d, new agent=0x%08x", + I64LOW(aAgentId), iAgentList.Count(), agent ); + + if(agent == NULL) + { + LOG_MSG("DTargetProcess::AddAgent() couldn't allocate memory for DDebugAgent"); + return KErrNoMemory; + } + return iAgentList.Insert(agent,0); + } + +// Stops tracking the process with this agent +TInt DTargetProcess::RemoveAgent(TUint64 aAgentId) + { + // We need to find and then remove the agent + for(TUint i = 0; i < iAgentList.Count(); i++) + { + if (iAgentList[i]->Id() == aAgentId) + { + LOG_MSG4("DTargetProcess::RemoveAgent(), deleting agent[%d], id 0x%x, address=0x%x", + i, I64LOW(aAgentId), iAgentList[i]); + delete iAgentList[i]; + iAgentList.Remove(i); + return KErrNone; + } + } + + return KErrNotFound; + } + +// Index through the agents by position +DDebugAgent* DTargetProcess::operator[](TInt aIndex) + { + return iAgentList[aIndex]; + } + +// returns the number of agents tracking this process. +TInt DTargetProcess::AgentCount() const + { + return iAgentList.Count(); + } + +void DTargetProcess::NotifyEvent(const TDriverEventInfo& aEventInfo) + { + // Stuff the event info into all the tracking agents event queues + LOG_MSG4("DTargetProcess::NotifyEvent(): num attached agents: %d, iEventType=%d, this=0x%08x", + AgentCount(), aEventInfo.iEventType, this); + + for(TInt i = 0; i < AgentCount(); i++) + { + // Index through all the relevant debug agents + DDebugAgent* debugAgent = iAgentList[i]; + if(debugAgent != NULL) + { + debugAgent->NotifyEvent(aEventInfo); + } + } + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/debug_utils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/debug_utils.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,134 @@ +// Copyright (c) 2004-2010 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: +// Purpose: Implementation of static functions for use by debug driver classes +// + +#include "debug_logging.h" +#include "debug_utils.h" + +/** + * Given a thread ID, return a handle to the corresponding DThread. If the returned + * pointer is non-NULL, it is the responsibility of the caller to close the handle. + * + * @pre caller must be in thread critical section + * @post if a non-NULL value is returned then a handle to the thread has been + * opened on the callers behalf + * @param aThreadId ID of the thread to return a handle for + * @return a DThread* to the appropriate thread, or NULL if a handle could not be + * opened to the specified thread + */ +DThread* DebugUtils::OpenThreadHandle(TUint64 aThreadId) + { + __ASSERT_CRITICAL; + LOG_MSG2("DebugUtils::OpenThreadHandle(0x%lx)", aThreadId); + + DObjectCon& threads = *Kern::Containers()[EThread]; // Get containing holding threads + threads.Wait(); // Obtain the container mutex so the list does get changed under us + + DThread* thread = Kern::ThreadFromId(aThreadId); + + // Open a handle to the thread so that it doesn't exit while we are processing + if (thread) + { + // if opening a handle fails then set thread to NULL + if(KErrNone != thread->Open()) + { + LOG_MSG2("\tCould not open handle to thread %d", (TUint32)aThreadId); + thread = NULL; + } + } + else + { + LOG_MSG2("\tThread with ID %d is NULL", (TUint32)aThreadId); + } + + threads.Signal(); // Release the container mutex + + return thread; + } + +/** + * Given a process ID, return a handle to the corresponding DProcess. If the returned + * pointer is non-NULL, it is the responsibility of the caller to close the handle. + * + * @post if a non-NULL value is returned then a handle to the process has been + * opened on the callers behalf + * @param aProcessId ID of the process to return a handle for + * @return a DProcess* to the appropriate process, or NULL if a handle could not be + * opened to the specified process + */ +DProcess* DebugUtils::OpenProcessHandle(const TUint64 aProcessId) + { + // Commenting out this message as it gets printed out every time a RDebug::Printf statement is caught by the driver, + // which makes looking at the serial cable output irritating. Replaced it with LOG_MSG statements below to indicate if + // something amiss happened. By default then this function prints nothing out. + //LOG_MSG("DebugUtils::OpenProcessHandle()"); + + NKern::ThreadEnterCS(); // Prevent us from dying or suspending whilst holding a DMutex + DObjectCon& processes = *Kern::Containers()[EProcess]; // Get containing holding threads + processes.Wait(); // Obtain the container mutex so the list does get changed under us + + DProcess* process = Kern::ProcessFromId(aProcessId); + + // Open a handle to the process so that it doesn't exit while we are processing + if (process) + { + // if opening a handle fails then set process to NULL + if(KErrNone != process->Open()) + { + LOG_MSG2("DebugUtils::OpenProcessHandle(): Could not open handle for 0x%lx", aProcessId); + process = NULL; + } + } + else + { + LOG_MSG2("DebugUtils::OpenProcessHandle(): Could not find process for 0x%lx", aProcessId); + } + + processes.Signal(); // Release the container mutex + NKern::ThreadLeaveCS(); // End of critical section + + return process; + } + +/** + * Opens a reference to the first thread of the given process. Returns NULL if + * there are no threads remaining in the process or if the thread couldn't be opened. + * + * @pre Caller must be in thread context, in critical section, no fast mutexes held. + * @post if result is non-NULL caller is responsible for closing the handle + * @param aProcess The process whose first thread is to be opened + * @return an Open()ed pointer to the first thread in the process, or NULL. + */ +DThread* DebugUtils::OpenFirstThreadForProcess(DProcess* aProcess) + { + __ASSERT_CRITICAL; + // Copied from memspy's DMemSpyDriverOSAdaptionDProcess::OpenFirstThread() + + // It appears that the system lock needs to be held while manipulating the iThreadQ + DThread* result = NULL; + NKern::LockSystem(); + // We don't use DProcess::FirstThread() as that doesn't appear to do any checking of whether the list is empty, ie if there are no threads at all + SDblQueLink* threadLink = aProcess->iThreadQ.First(); + if (threadLink != NULL && threadLink != &aProcess->iThreadQ.iA) + { + result = _LOFF(threadLink,DThread,iProcessLink); + if (result->Open() != KErrNone) + { + result = NULL; + } + } + NKern::UnlockSystem(); + return result; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/rm_debug_eventhandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/rm_debug_eventhandler.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,177 @@ +// Copyright (c) 2004-2010 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: +// Kernel Event handler for Run Mode Debug. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "debug_logging.h" +#include "d_process_tracker.h" +#include "d_rmd_stepping.h" +#include "rm_debug_kerneldriver.h" +#include "rm_debug_driver.h" +#include "rm_debug_eventhandler.h" + + +DRM_DebugEventHandler::DRM_DebugEventHandler() + : DKernelEventHandler(EventHandler, this) +{ + LOG_MSG("DRM_DebugEventHandler::DRM_DebugEventHandler()"); + + for(TInt i=0; iiId); + + TInt err; + err = aDevice->Open(); + if (err != KErrNone) + return err; + iDevice = aDevice; + + iChannel = (DRM_DebugChannel*)aChannel; //Don't add ref the channel, since channel closes the event handler before it ever gets destroyed. + + err = aClient->Open(); + if (err != KErrNone) + return err; + iClientThread = aClient; + + // Use a semaphore to protect our data structures from concurrent access. + err = Kern::SemaphoreCreate(iProtectionLock, _L("RM_DebugEventHandlerLock"), 1 /* Initial count */); + if (err != KErrNone) + return err; + + + return Add(); +} + + +DRM_DebugEventHandler::~DRM_DebugEventHandler() +{ + LOG_MSG("DRM_DebugEventHandler::~DRM_DebugEventHandler()"); + + if (iProtectionLock) + iProtectionLock->Close(NULL); + + if (iDevice) + iDevice->Close(NULL); + + if (iClientThread) + Kern::SafeClose((DObject*&)iClientThread, NULL); + +} + + +TInt DRM_DebugEventHandler::Start() +{ + LOG_MSG("DRM_DebugEventHandler::Start()"); + + iTracking = ETrue; + + return KErrNone; +} + + +TInt DRM_DebugEventHandler::Stop() +{ + LOG_MSG("DRM_DebugEventHandler::Stop()"); + + iTracking = EFalse; + + return KErrNone; +} + + +TUint DRM_DebugEventHandler::EventHandler(TKernelEvent aType, TAny* a1, TAny* a2, TAny* aThis) +{ + return ((DRM_DebugEventHandler*)aThis)->HandleEvent(aType, a1, a2); +} + + + +TUint DRM_DebugEventHandler::HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2) + { + + /* + * Check if we are tracking things at all OR + * this event is beyond the limit of known events OR + * this event is from the debug thread itself (don't want to debug ourselves) OR + * this event has a handler (there is no point in proceeding without a handler) + */ + if( (!iTracking) || + (aType > (TUint32)EEventLimit) || + (iClientThread == &Kern::CurrentThread()) || + (iEventHandlers[aType] == &DRM_DebugChannel::HandleUnsupportedEvent) ) + { + return ERunNext; + } + + return HandleSpecificEvent(aType,a1,a2) && aType == EEventHwExc ? EExcHandled : ERunNext; + + + } + +TBool DRM_DebugEventHandler::HandleSpecificEvent(TKernelEvent aType, TAny* a1, TAny* a2) + { + TBool ret = EFalse; + + NKern::ThreadEnterCS(); + LockDataAccess(); + + + if (iChannel) + { + ret = (iChannel->*(iEventHandlers[aType]))(a1, a2); + } + ReleaseDataAccess(); + NKern::ThreadLeaveCS(); + + switch(aType) + { + case EEventHwExc: + case EEventKillThread: + { + LOG_MSG2("DRM_DebugEventHandler::HandleEvent() -> FSWait(), kernel event type: %d", (TUint32)aType); + TheDProcessTracker.FSWait(); + LOG_MSG("DRM_DebugEventHandler::HandleEvent() <- FSWait()"); + break; + } + default: + break; + } + return ret; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/rmdriver/src/rm_debug_kerneldriver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/rmdriver/src/rm_debug_kerneldriver.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,3530 @@ +// Copyright (c) 2004-2010 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: +// Device driver for kernel side debug assist +// + +#ifdef __WINS__ +#error - this driver cannot be built for emulation +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug_logging.h" +#include "d_rmd_breakpoints.h" // moved breakpoints code lives here +#include "d_rmd_stepping.h" // moved stepping code lives here +#include "rm_debug_kerneldriver.h" +#include "d_list_manager.h" +#include "rm_debug_driver.h" +#include "rm_debug_eventhandler.h" +#include "d_debug_functionality.h" +#include "d_process_tracker.h" +#include "debug_utils.h" + +using namespace Debug; + +///////////////////////////////////////////////////////////////////////// +// +// DRM_DebugDriverFactory implementation +// +///////////////////////////////////////////////////////////////////////// + +// +// DRM_DebugDriverFactory constructor +// +DRM_DebugDriverFactory::DRM_DebugDriverFactory() + { + iVersion = TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); + } + +// +// DRM_DebugDriverFactory::Create +// +TInt DRM_DebugDriverFactory::Create(DLogicalChannelBase*& aChannel) + { + if (iOpenChannels != 0) + return KErrInUse; // a channel is already open + + aChannel = new DRM_DebugChannel(this); + + return aChannel ? KErrNone : KErrNoMemory; + } + +// +// DRM_DebugDriverFactory::Install +// +TInt DRM_DebugDriverFactory::Install() + { + return(SetName(&KRM_DebugDriverName)); + } + +// +// DRM_DebugDriverFactory::Install +// +void DRM_DebugDriverFactory::GetCaps(TDes8& aDes) const + { + TCapsRM_DebugDriver b; + b.iVersion = TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber); + + Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b)); + } + +///////////////////////////////////////////////////////////////////////// +// +// DRM_DebugChannel implementation +// +///////////////////////////////////////////////////////////////////////// + +// +// DRM_DebugChannel constructor +// +DRM_DebugChannel::DRM_DebugChannel(DLogicalDevice* aLogicalDevice) + : iExcludedROMAddressStart(ROM_LINEAR_BASE), + iExcludedROMAddressEnd(0), + iPageSize(0x1000), + iBreakManager(0), + iStepper(0), + iStepLock(0), + iDfcQ(NULL), + iInitialisedCodeModifier(0), + iAsyncGetValueRequest(NULL) + { + LOG_MSG("DRM_DebugChannel::DRM_DebugChannel()"); + + iDevice = aLogicalDevice; + + iClientThread = &Kern::CurrentThread(); + + // Opening handle to current thread, so no need to check for return-value + (void)iClientThread->Open(); + + LOG_MSG3("DRM_DebugChannel::DRM_DebugChannel() clientThread = 0x%08x, id=%d", + iClientThread, iClientThread->iId ); + + + iPageSize = Kern::RoundToPageSize(1); + } + +// +// DRM_DebugChannel destructor +// +DRM_DebugChannel::~DRM_DebugChannel() + { + LOG_MSG("DRM_DebugChannel::~DRM_DebugChannel()"); + + if (iAsyncGetValueRequest) + { + Kern::QueueRequestComplete(iClientThread, iAsyncGetValueRequest, KErrCancel); // does nothing if request not pending + Kern::DestroyClientRequest(iAsyncGetValueRequest); + } + + NKern::ThreadEnterCS(); + Kern::SafeClose((DObject*&)iClientThread, NULL); + NKern::ThreadLeaveCS(); + + // Close breakpoint manager + if (iBreakManager) + { + NKern::ThreadEnterCS(); + delete iBreakManager; + NKern::ThreadLeaveCS(); + } + + // Close stepping manager + if (iStepper) + { + NKern::ThreadEnterCS(); + delete iStepper; + NKern::ThreadLeaveCS(); + } + + //close the debug process list + iDebugProcessList.Close(); + + DestroyDfcQ(); + + //close the code modifier + if (iInitialisedCodeModifier) + { + DebugSupport::CloseCodeModifier(); + } + } + +void DRM_DebugChannel::DestroyDfcQ() + { + LOG_MSG("DRM_DebugChannel::DestroyDfcQ()"); + if (iDfcQ) + { + NKern::ThreadEnterCS(); + iDfcQ->Destroy(); + NKern::ThreadLeaveCS(); + } + } + +// +// DRM_DebugChannel::DoCreate +// +TInt DRM_DebugChannel::DoCreate(TInt /*aUnit*/, const TDesC* anInfo, const TVersion& aVer) + { + LOG_MSG("DRM_DebugChannel::DoCreate()"); + TInt err = Kern::CreateClientDataRequest(iAsyncGetValueRequest); + if(err != KErrNone) + return err; + + if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber, KMinorVersionNumber, KBuildVersionNumber), aVer)) + return KErrNotSupported; + + // Do the security check here so that any arbitrary application doesn't make + // use of Trk kernel driver. + if (!DoSecurityCheck()) + { + LOG_MSG("DRM_DebugChannel::DoCreate() - permission denied!"); + return KErrPermissionDenied; + } + + if (anInfo) + { + // this is the end address of the user library. + // this doesn't seem to be valid for EKA2. + // right now we dont need this for EKA2 since we are not worried + // about kernel being stopped as kernel is multithreaded. + // just retaining this for future use. + TBuf8<32> buf; + TInt err = Kern::ThreadRawRead(iClientThread, anInfo, &buf, 32); + if(err != KErrNone) + return err; + } + + // Allocate a D_RMD_Breakpoints class as a breakpoint manager + NKern::ThreadEnterCS(); + iBreakManager = new D_RMD_Breakpoints(this); + NKern::ThreadLeaveCS(); + if (iBreakManager == NULL) + { + LOG_MSG("DRM_DebugChannel::DRM_DebugChannel - could not construct breakpoint manager"); + return KErrNoMemory; + } + + // Initialise the new breakpoint manager object + iBreakManager->Init(); + + // Allocate a DRMDStepping class as the stepping manager + NKern::ThreadEnterCS(); + iStepper = new DRMDStepping(this); + NKern::ThreadLeaveCS(); + if (iStepper == NULL) + { + LOG_MSG("DRM_DebugChannel::DRM_DebugChannel - could not construct stepper manager"); + return KErrNoMemory; + } + + // Initialize the code modifier for managing breakpoints. + TUint caps; //ignored for now + err = DebugSupport::InitialiseCodeModifier(caps, NUMBER_OF_MAX_BREAKPOINTS); + //if code modifier initializer failed, + //return here, since we can't set an breakpoints + if(err != KErrNone) + { + return err; + } + else + { + iInitialisedCodeModifier = ETrue; + } + + //create and set the driver's Dfc queue + err = CreateDfcQ(); + if(err != KErrNone) + { + LOG_MSG("DRM_DebugChannel::DoCreate() Creating Dfc queue failed."); + } + SetDfcQ(iDfcQ); + + iMsgQ.Receive(); + + iEventHandler = new DRM_DebugEventHandler; + if (!iEventHandler) + return KErrNoMemory; + err = iEventHandler->Create(iDevice, this, iClientThread); + if (err != KErrNone) + return err; + + //return KErrNone; + return iEventHandler->Start(); + } + +/** +Forward call to either synch or asynch methods while serialising all calls via lock. + +Protect access via a the event handler lock to +serialise all calls and protect concurrent access to data structures + +@param aMsg pointer to a TMessageBase object + +@return error returned by called methods + +@see DRM_DebugEventHandler::HandleSpecificEvent where lock is also used +@see DRM_DebugEventHandler::iProtectionLock + +*/ +TInt DRM_DebugChannel::SendMsg(TMessageBase* aMsg) + { + DThread * currThread = &Kern::CurrentThread(); + + iEventHandler->LockDataAccess(); + LOG_MSG3("DRM_DebugChannel::SendMsg() currThread = 0x%08x, iClientThread=0x%08x", currThread, iClientThread ); + + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt id = m.iValue; + TInt err = KErrNone; + + if (id != (TInt)ECloseMsg && id != KMaxTInt && id < 0) + { + // DoRequest + TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); + err = SendRequest(aMsg); + if (err != KErrNone) + Kern::RequestComplete(pStatus,err); + } + else + { + err = DLogicalChannel::SendMsg(aMsg); + } + + iEventHandler->ReleaseDataAccess(); + return err; + } + +// +// DRM_DebugChannel::SendRequest +// +TInt DRM_DebugChannel::SendRequest(TMessageBase* aMsg) + { + LOG_MSG("DRM_DebugChannel::SendRequest()"); + + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt function = ~m.iValue; + TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); + TAny* a1 = m.Ptr1(); + + TInt err = KErrNotSupported; + switch(function) + { + case RRM_DebugDriver::ERequestGetEvent: + err = PreAsyncGetValue((TEventInfo*)a1,pStatus); + break; + } + if (err == KErrNone) + err = DLogicalChannel::SendMsg(aMsg); + return err; + } + +// +// DRM_DebugChannel::PreAsyncGetValue +// +TInt DRM_DebugChannel::PreAsyncGetValue(TEventInfo* aValue, TRequestStatus* aStatus) + { + LOG_MSG3("DRM_DebugChannel::PreAsyncGetValue() TEventInfo=0x%08x, TRequestStatus=0x%08x", + aValue, aStatus ); + + iAsyncGetValueRequest->Reset(); + + TInt err = iAsyncGetValueRequest->SetStatus(aStatus); + if (err != KErrNone) + return err; + + iAsyncGetValueRequest->SetDestPtr(aValue); + return KErrNone; + } + +/** + Create the Dfc queue for receiving messages + */ +TInt DRM_DebugChannel::CreateDfcQ() + { + LOG_MSG("DRM_DebugChannel::CreateDfcQ()"); + TInt r = Kern::DynamicDfcQCreate(iDfcQ, KRmDebugDriverThreadPriority, KRM_DebugDriverName); + + if (r == KErrNone) + iDfcQ->SetRealtimeState(ERealtimeStateOff); + return r; + } + +// +// DRM_DebugChannel::DoCancel +// +// New: The cancel call does not take an enum parameter describing +// the request to be cancelled. Rather it supplies a pointer +// to a user-side struct defining the cancellation +// +void DRM_DebugChannel::DoCancel(TInt aReqNo) + { + LOG_MSG("DRM_DebugChannel::DoCancel()"); + + TRMD_DebugCancelInfo info; + + TInt err = Kern::ThreadRawRead(iClientThread,(TAny*)aReqNo,(TAny*)&info,sizeof(info)); + if (err != KErrNone) + { + // How do we cancel something we know nothing about??? + LOG_MSG("DRM_DebugChannel::DoCancel - bad arguments"); + return; + } + + DDebugAgent* debugAgent = TheDProcessTracker.FindAgentForProcessAndId(info.iProcessName, info.iAgentId); + if (debugAgent == NULL) + { + // Bad agent means there is no tracking agent + LOG_MSG2("Cannot locate debug agent with pid 0x%x", info.iAgentId); + return; + } + + // Agent completes/pends the request as appropriate. + debugAgent->CancelGetEvent(); + + } + +// +// DRM_DebugChannel::DoRequest +// +void DRM_DebugChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) + { + LOG_MSG4("DRM_DebugChannel::DoRequest(), iClientThread=0x%08x, tid=0x%08x, TRequestStatus=0x%08x", + iClientThread, I64LOW(iClientThread->iId), aStatus); + + switch(aReqNo) + { + case RRM_DebugDriver::ERequestGetEvent: + { + TEventMetaData eventMetaData; + TInt err = Kern::ThreadRawRead(iClientThread, a2, (TUint8 *)&eventMetaData, sizeof(TEventMetaData) ); + if (err != KErrNone) + { + LOG_MSG("Error: could not read argument data from the DSS (TEventMetaData)"); + + // We could not read information from the user, so the a2 argument is probably wrong + Kern::RequestComplete(iClientThread, aStatus, KErrArgument); + return; + } + + DDebugAgent* debugAgent = TheDProcessTracker.FindAgentForProcessAndId(eventMetaData.iTargetProcessName, eventMetaData.iDebugAgentProcessId); + if (debugAgent == NULL) + { + // Bad agent means there is no tracking agent + LOG_MSG2("Cannot locate debug agent with pid 0x%x", eventMetaData.iDebugAgentProcessId); + Kern::RequestComplete(iClientThread, aStatus, KErrNotFound); + return; + } + // Agent completes/pends the request as appropriate. + debugAgent->GetEvent(iAsyncGetValueRequest, iClientThread); + + break; + } + default: + { + // Should not get here! + LOG_MSG2("DRM_DebugChannel::DoRequest was passed unsupported request aReqNo=%d", aReqNo ); + Kern::RequestComplete(iClientThread, aStatus, KErrNotSupported); + } + } + } + +// +// DRM_DebugChannel::DoControl +// +TInt DRM_DebugChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) + { + LOG_MSG("DRM_DebugChannel::DoControl()"); + + LOG_MSG2("DoControl Function %d", aFunction); + + TInt err = KErrNone; + DThread* threadObj = NULL; + // Open a thread handle for the operations that need one + switch (aFunction) + { + case RRM_DebugDriver::EControlSuspendThread: + case RRM_DebugDriver::EControlResumeThread: + case RRM_DebugDriver::EControlStepRange: + case RRM_DebugDriver::EControlReadMemory: + case RRM_DebugDriver::EControlWriteMemory: + case RRM_DebugDriver::EControlReadRegistersLegacy: + case RRM_DebugDriver::EControlWriteRegistersLegacy: + case RRM_DebugDriver::EControlReadRegisters: + case RRM_DebugDriver::EControlWriteRegisters: + { + NKern::ThreadEnterCS(); + threadObj = DebugUtils::OpenThreadHandle((TUint32)a1); + if (!threadObj) + { + NKern::ThreadLeaveCS(); + return KErrBadHandle; + } + break; + } + default: + break; + } + + switch(aFunction) + { + /* Security first */ + case RRM_DebugDriver::EControlIsDebuggable: + { + err = IsDebuggable((TUint32)a1); + break; + } + case RRM_DebugDriver::EControlSetBreak: + { + err = SetBreak((TSetBreakInfo*)a1); + break; + } + case RRM_DebugDriver::EControlClearBreak: + { + err = iBreakManager->DoClearBreak((TInt32)a1); + break; + } + case RRM_DebugDriver::EControlModifyBreak: + { + err = iBreakManager->DoModifyBreak((TModifyBreakInfo*)a1); + break; + } + case RRM_DebugDriver::EControlModifyProcessBreak: + { + err = iBreakManager->DoModifyProcessBreak((TModifyProcessBreakInfo*)a1); + break; + } + case RRM_DebugDriver::EControlBreakInfo: + { + err = iBreakManager->DoBreakInfo((TGetBreakInfo*)a1); + break; + } + case RRM_DebugDriver::EControlSuspendThread: + { + err = DoSuspendThread(threadObj); + break; + } + case RRM_DebugDriver::EControlResumeThread: + { + err = DoResumeThread(threadObj); + break; + } + case RRM_DebugDriver::EControlStepRange: + { + err = StepRange(threadObj, (TRM_DebugStepInfo*)a2); + break; + } + case RRM_DebugDriver::EControlReadMemory: + { + err = ReadMemory(threadObj, (TRM_DebugMemoryInfo*)a2); + break; + } + case RRM_DebugDriver::EControlWriteMemory: + { + err = WriteMemory(threadObj, (TRM_DebugMemoryInfo*)a2); + break; + } + case RRM_DebugDriver::EControlReadRegistersLegacy: + { + err = ReadRegistersLegacy(threadObj, (TRM_DebugRegisterInfo*)a2); + break; + } + case RRM_DebugDriver::EControlWriteRegistersLegacy: + { + err = WriteRegistersLegacy(threadObj, (TRM_DebugRegisterInfo*)a2); + break; + } + case RRM_DebugDriver::EControlReadRegisters: + { + err = ReadRegisters(threadObj, (TRM_DebugRegisterInformation*)a2); + break; + } + case RRM_DebugDriver::EControlWriteRegisters: + { + err = WriteRegisters(threadObj, (TRM_DebugRegisterInformation*)a2); + break; + } + case RRM_DebugDriver::EControlGetDebugFunctionalityBufSize: + { + LOG_MSG("RRM_DebugDriver::EControlGetDebugFunctionalityBufSize\n"); + + TDebugFunctionality df; + + TUint size = df.GetDebugFunctionalityBufSize(); + + // Return size to user-side in a safe manner + err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8*)&size, sizeof(TUint), iClientThread); + break; + } + case RRM_DebugDriver::EControlGetDebugFunctionality: + { + LOG_MSG("RRM_DebugDriver::EControlGetDebugFunctionality\n"); + + TDebugFunctionality df; + + TUint32 dfsize = df.GetDebugFunctionalityBufSize(); + + // Alloc tmp buffer for Debug Functionality data + NKern::ThreadEnterCS(); + TUint8* dfbuffer = (TUint8*)Kern::AllocZ(dfsize); + if (dfbuffer==NULL) + { + LOG_MSG2("Could not allocate memory for %d bytes\n",dfsize); + NKern::ThreadLeaveCS(); + // could not allocate memory + return KErrNoMemory; + } + + // Temporary descriptor to hold DF data + TPtr8 tmpPtr(dfbuffer,0,dfsize); + + // Obtain the DF data + if (df.GetDebugFunctionality(tmpPtr) ) + { + // Return the DF data to the user-side + err = Kern::ThreadDesWrite(iClientThread, a1, tmpPtr, 0, KChunkShiftBy0, iClientThread); + } + else + { + // Failed. + err = KErrGeneral; + } + + // Free tmp buffer + Kern::Free(dfbuffer); + NKern::ThreadLeaveCS(); + break; + } + case RRM_DebugDriver::EControlAttachProcess: + { + LOG_MSG("RRM_DebugDriver::EControlAttachProcess"); + + err = AttachProcess(a1,a2); + break; + } + case RRM_DebugDriver::EControlDetachProcess: + { + LOG_MSG("RRM_DebugDriver::EControlDetachProcess"); + + err = DetachProcess(a1,a2); + break; + } + case RRM_DebugDriver::EControlDetachAgent: + { + LOG_MSG("RRM_DebugDriver::EControlDetachAgent"); + + err = DetachAgent(a1,a2); + break; + } + case RRM_DebugDriver::EControlSetEventAction: + { + LOG_MSG("RRM_DebugDriver::EControlSetEventAction"); + + err = SetEventAction(a1,a2); + break; + } + case RRM_DebugDriver::EControlGetMemoryOperationMaxBlockSize: + { + LOG_MSG("RRM_DebugDriver::EControlGetMemoryOperationMaxBlockSize\n"); + + TUint32 maxSize = TDebugFunctionality::GetMemoryOperationMaxBlockSize(); + + // Return size to user-side in a safe manner + err = Kern::ThreadRawWrite(iClientThread, a1, (TUint8*)&maxSize, sizeof(TUint32), iClientThread); + break; + } + case RRM_DebugDriver::EControlGetList: + { + LOG_MSG("RRM_DebugDriver::EControlGetList\n"); + err = GetList((TListInformation*)a1); + break; + } + case RRM_DebugDriver::EControlStep: + { + LOG_MSG("RRM_DebugDriver::EControlStep\n"); + + err = Step((TUint32)a1,(TUint32)a2); + break; + } + case RRM_DebugDriver::EControlKillProcess: + { + LOG_MSG("RRM_DebugDriver::EControlKillProcess\n"); + + err = KillProcess((TUint32)a1,(TUint32)a2); + break; + } + default: + { + err = KErrGeneral; + } + } + + if (KErrNone != err) + { + LOG_MSG2("Error %d from control function", err); + } + + if (threadObj) + { + // Close the thread handle which has been opened by DebugUtils::OpenThreadHandle + threadObj->Close(NULL); + NKern::ThreadLeaveCS(); + } + + return err; + } + +void DRM_DebugChannel::HandleMsg(TMessageBase* aMsg) + { + LOG_MSG("DRM_DebugChannel::HandleMsg()"); + + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt id = m.iValue; + + if (id == (TInt)ECloseMsg) + { + if (iEventHandler) + { + iEventHandler->Stop(); + iEventHandler->Close(); + iEventHandler = NULL; + } + m.Complete(KErrNone, EFalse); + return; + } + + if (id == KMaxTInt) + { + // DoCancel + DoCancel(m.Int0()); + m.Complete(KErrNone, ETrue); + return; + } + + if (id < 0) + { + // DoRequest + TRequestStatus* pStatus = (TRequestStatus*)m.Ptr0(); + DoRequest(~id, pStatus, m.Ptr1(), m.Ptr2()); + m.Complete(KErrNone, ETrue); + } + else + { + // DoControl + TInt err = DoControl(id, m.Ptr0(), m.Ptr1()); + m.Complete(err, ETrue); + } + } + +// +// DRM_DebugChannel::RemoveProcess +// +TBool DRM_DebugChannel::RemoveProcess(TAny* a1, TAny* a2) + { + LOG_MSG("DRM_DebugChannel::RemoveProcess()"); + + DProcess *aProcess = (DProcess*)a1; + + // Sanity check + if (!aProcess) + { + // No process was specified! + LOG_MSG("DRM_DebugChannel::RemoveProcess was called with an invalid process ID"); + return EFalse; + } + + // this is called when a process dies. we want to mark any breakpoints in this + // process space as obsolete. the main reason for this is so we don't return + // an error when the host debugger tries to clear breakpoints for the process + + TUint32 codeAddress = 0; + TUint32 codeSize = 0; + + LOG_EVENT_MSG2("Process being removed, Name %S", aProcess->iName); + + DCodeSeg* codeSeg = aProcess->iCodeSeg; + + if (codeSeg) + { + TModuleMemoryInfo processMemoryInfo; + TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, aProcess); + if (err != KErrNone) + { + codeAddress = processMemoryInfo.iCodeBase; + codeSize = processMemoryInfo.iCodeSize; + } + else + { + LOG_MSG2("Error in getting memory info: %d", err); + } + } + + if (!codeAddress || !codeSize) + { + LOG_EVENT_MSG2("Code segment not available for process %d", aProcess->iId); + // make sure there is not already a breakpoint at this address + for (TInt i = 0; i < iDebugProcessList.Count(); i++) + { + if (iDebugProcessList[i].iId == aProcess->iId) + { + codeAddress = iDebugProcessList[i].iCodeAddress; + codeSize = iDebugProcessList[i].iCodeSize; + + //now remove from the list + iDebugProcessList.Remove(i); + break; + } + } + } + + if (!codeAddress || !codeSize) + { + return EFalse; + } + + iBreakManager->RemoveBreaksForProcess(aProcess->iId, codeAddress, codeSize); + return EFalse; + } + +// +// DRM_DebugChannel::StartThread +// +TBool DRM_DebugChannel::StartThread(TAny* a1, TAny* a2) + { + LOG_EVENT_MSG("DRM_DebugChannel::StartThread()"); + + DThread *aThread = (DThread*)a1; + if(!aThread) + { + LOG_MSG("Error getting DThread object"); + __NK_ASSERT_DEBUG(aThread); + return EFalse; + } + + //a2 points to the thread creating the new thread. + //We have no use for it at the moment so just ignore it for now + + TDriverEventInfo info; + info.iEventType = EEventsStartThread; + info.iThreadId = aThread->iId; + info.iThreadIdValid = ETrue; + DProcess* owningProcess = aThread->iOwningProcess; + if(owningProcess) + { + info.iProcessId = owningProcess->iId; + info.iProcessIdValid = ETrue; + DCodeSeg* p = owningProcess->iCodeSeg; + if(p && p->iFileName) + { + info.iFileName.Copy(*(p->iFileName)); + TheDProcessTracker.NotifyAgentsForProcessEvent(*p->iFileName, info); + } + else + { + if(p) + { + LOG_EVENT_MSG("\tCode segment name missing"); + } + else + { + LOG_EVENT_MSG("\tCode segment is NULL"); + } + } + } + return EFalse; + } + +// +// DRM_DebugChannel::HandleAddProcessEvent +// +TBool DRM_DebugChannel::HandleAddProcessEvent(TAny* a1, TAny* a2) + { + LOG_EVENT_MSG("DRM_DebugChannel::AddProcess()"); + + DProcess *aProcess = (DProcess*)a1; + // a2 points to the thread creating the new process. + DThread *aThread = (DThread*)a2; + + if(!aProcess) + { + LOG_MSG("Error getting DProcess object"); + __NK_ASSERT_DEBUG(aProcess); + return EFalse; + } + + TDriverEventInfo info; + info.iEventType = EEventsAddProcess; + info.iProcessId = aProcess->iId; + + info.iCreatorThreadId = aThread ? aThread->iId : 0; + info.iProcessIdValid = ETrue; + + // Copy TUids + info.iUids = aProcess->iUids; + + info.iUidsValid = ETrue; + + // copy name of the process + if (aProcess->iName) + { + // copy the name of the process + info.iFileName.Copy(*aProcess->iName); + // AddProcess event does not have fully-qualified path, it has "filename.exe" + // So we allow a less-precise match by passing in ETrue + TheDProcessTracker.NotifyAgentsForProcessEvent(*aProcess->iName, info, ETrue); + } + else + { + LOG_EVENT_MSG("DRM_DebugChannel::AddProcess - No iName for this process"); + } + + return EFalse; + } + +// +// DRM_DebugChannel::HandleRemoveProcessEvent +// +TBool DRM_DebugChannel::HandleRemoveProcessEvent(TAny* a1, TAny* a2) + { + LOG_MSG("DRM_DebugChannel::HandleRemoveProcessEvent()"); + + DProcess *aProcess = (DProcess*)a1; + if(!aProcess) + { + LOG_MSG("Error getting DProcess object"); + __NK_ASSERT_DEBUG(aProcess); + return EFalse; + } + + // a2 points to the thread creating the new process. + // We have no use for it at the moment so just ignore it for now + // Also, it may not be known and therefore NULL + + TDriverEventInfo info; + info.iEventType = EEventsRemoveProcess; + info.iProcessId = aProcess->iId; + info.iProcessIdValid = ETrue; + + // copy name of the process + if (aProcess->iName) + { + info.iFileName.Copy(*aProcess->iName); + + // RemoveProcess event does not have fully-qualified path, it has "filename.exe" + // So we allow a less-precise match by passing in ETrue + TheDProcessTracker.NotifyAgentsForProcessEvent(*aProcess->iName, info, ETrue); + } + else + { + LOG_EVENT_MSG("DRM_DebugChannel::AddProcess - No iName for this process"); + } + + return EFalse; + } + +// +// DRM_DebugChannel::AddLibrary +// +TBool DRM_DebugChannel::AddLibrary(TAny* a1, TAny* a2) + { + LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary()"); + + DLibrary *aLibrary = (DLibrary*)a1; + DThread *aThread = (DThread*)a2; + + // sanity check + if (!aLibrary) + { + LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary called with no library specified"); + return EFalse; + } + + if (!aThread) + { + LOG_EVENT_MSG("DRM_DebugChannel::AddLibrary called with no thread specified"); + return EFalse; + } + +#ifdef __LOG_EVENTS__ + TFullName threadName; + aThread->FullName(threadName); + LOG_EVENT_MSG3(("Lib %S loaded by %S"), aLibrary->iName, &threadName); +#endif + + if (aThread) + { + // make sure this is not the debugger thread + if ((aThread != iClientThread) && (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) + { + TDriverEventInfo info; + + info.iEventType = EEventsAddLibrary; + info.iProcessId = aThread->iOwningProcess->iId; + info.iProcessIdValid = ETrue; + info.iThreadId = aThread->iId; + info.iThreadIdValid = ETrue; + + //get the code address + DCodeSeg* codeSeg = aLibrary->iCodeSeg; + if (!codeSeg) + { + LOG_EVENT_MSG2("Code segment not available for library %S", aLibrary->iName); + return EFalse; + } + + // Uid3 + info.iUids = codeSeg->iUids; + info.iUidsValid = ETrue; + + TModuleMemoryInfo memoryInfo; + TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL); //NULL for DProcess should be ok; + if (err != KErrNone) + { + LOG_EVENT_MSG2("Error in getting memory info: %d", err); + return EFalse; + } + + info.iCodeAddress = memoryInfo.iCodeBase; + info.iDataAddress = memoryInfo.iInitialisedDataBase; + + info.iFileName.Copy(*(aLibrary->iName)); //just the name, without uid info. + + //queue up or complete the event + info.iArg1 = a1; + info.iArg2 = a2; + NotifyAgentsFromEventPid(info); + } + + } + return EFalse; + } + +// +// DRM_DebugChannel::RemoveLibrary +// +TBool DRM_DebugChannel::RemoveLibrary(TAny* a1, TAny* a2) + { + LOG_EVENT_MSG("DRM_DebugChannel::RemoveLibrary()"); + DLibrary *aLibrary = (DLibrary*)a1; + + // sanity check + if (!aLibrary) + { + LOG_EVENT_MSG("DRM_DebugChannel::RemoveLibrary called with no library specified"); + return EFalse; + } + + LOG_EVENT_MSG2(("Lib unloaded: %S"), aLibrary->iName); + + // this is called when all handles to this library have been closed. this can happen when a process dies, or when a dll is + // unloaded while the process lives on. in former case, we don't need to notify the host debugger because that process is + // dying anyway. for the latter case, we do need to notify the host so it can unload the symbolics, etc. + + DThread* aThread = &Kern::CurrentThread(); + + if ((aThread) && + (aThread != iClientThread) && + (aThread->iOwningProcess->iId != iClientThread->iOwningProcess->iId)) + { + //the library gets unloaded only when the mapcount is 0. + if (aLibrary->iMapCount != 0) + return EFalse; + + DCodeSeg* codeSeg = aLibrary->iCodeSeg; + if (!codeSeg) + { + LOG_EVENT_MSG2("Code segment not available for library %S", aLibrary->iName); + return EFalse; + } + + TModuleMemoryInfo processMemoryInfo; + TInt err = codeSeg->GetMemoryInfo(processMemoryInfo, NULL); //passing NULL for the DProcess argument should be ok; + if (err != KErrNone) + { + LOG_EVENT_MSG2("Error in getting memory info: %d", err); + return EFalse; + } + + TUint32 codeAddress = processMemoryInfo.iCodeBase; + TUint32 codeSize = processMemoryInfo.iCodeSize; + + // first invalidate all breakpoints that were set in the library code + iBreakManager->InvalidateLibraryBreakPoints(codeAddress, codeSize); + DProcess *process = &Kern::CurrentProcess(); + RArray* dynamicCode = &(process->iDynamicCode); + + for (TInt j=0; jCount(); j++) + { + if ((*dynamicCode)[j].iLib == aLibrary) + { + TDriverEventInfo info; + + info.iEventType = EEventsRemoveLibrary; + info.iFileName.Copy(*(aLibrary->iName)); //lib name without uid info + //info.iFileName.ZeroTerminate(); + info.iProcessId = process->iId; + info.iProcessIdValid = ETrue; + info.iThreadId = 0xFFFFFFFF; // don't care! + info.iThreadIdValid = EFalse; + // Uid3 + info.iUids = codeSeg->iUids; + info.iUidsValid = ETrue; + + //queue up or complete the event + info.iArg1 = a1; + info.iArg2 = a2; + NotifyAgentsFromEventPid(info); + } + } + } + return EFalse; + } + +// +// DRM_DebugChannel::HandleEventKillThread +// +TBool DRM_DebugChannel::HandleEventKillThread(TAny* a1, TAny* a2) + { + DThread* currentThread = &Kern::CurrentThread(); + + // a1 should point to the current thread, check this to make sure it does + __NK_ASSERT_DEBUG((DThread*)a1 == currentThread); + + TDriverEventInfo info; + + LOG_MSG5(" HandleEventKillThread for thread 0x%x, CritScount=%d, suspCnt=%d, waitObj=0x%x", + currentThread->iId, + currentThread->iNThread.iCsCount, + currentThread->iNThread.iSuspendCount, + currentThread->iWaitObj); + + info.iProcessId = currentThread->iOwningProcess->iId; + info.iProcessIdValid = ETrue; + info.iThreadId = currentThread->iId; + info.iThreadIdValid = ETrue; + + TInt err = ReadKernelRegisterValue(currentThread, 14, info.iCurrentPC); + if(err != KErrNone) + { + LOG_EVENT_MSG2("DRM_DebugChannel::HandleEventKillThread - Non-zero error code discarded: %d", err); + } + + LOG_MSG5(" HandleEventKillThread for thread exit category=%S reason=%d, exitType=0x%x, PC=0x%x", + ¤tThread->iExitCategory, + currentThread->iExitReason, + currentThread->iExitType, + info.iCurrentPC); + + if (currentThread->iExitType == EExitPanic) + { + info.iPanicCategory.Copy(currentThread->iExitCategory); + } + info.iExceptionNumber = currentThread->iExitReason; + info.iExitType = currentThread->iExitType; + info.iEventType = EEventsKillThread; + info.iThreadFlags = currentThread->iFlags; + + // remove all the breakpoints in this thread, whether we are debugging it or not. + iBreakManager->DoRemoveThreadBreaks(info.iThreadId); + + info.iArg1 = a1; + info.iArg2 = a2; + NotifyAgentsFromEventPid(info); + + return ETrue; + } + +// +// DRM_DebugChannel::HandleSwException +// +TBool DRM_DebugChannel::HandleSwException(TAny* a1, TAny* a2) + { + LOG_EVENT_MSG("DRM_DebugChannel::HandleSwException"); + TExcType aExcType = (TExcType)(TInt)a1; + + TDriverEventInfo info; + + DThread* currentThread = &Kern::CurrentThread(); + if (!currentThread) + { + LOG_MSG("Error getting current thread"); + __NK_ASSERT_DEBUG(currentThread); + return EFalse; + } + + info.iProcessId = currentThread->iOwningProcess->iId; + info.iProcessIdValid = ETrue; + info.iThreadId = currentThread->iId; + info.iThreadIdValid = ETrue; + TInt err = ReadKernelRegisterValue(currentThread, PC_REGISTER, info.iCurrentPC); + if(err != KErrNone) + { + LOG_EVENT_MSG2("DRM_DebugChannel::HandleSwException - Non-zero error code discarded: %d", err); + } + info.iExceptionNumber = aExcType; + info.iEventType = EEventsSwExc; + info.iThreadFlags = currentThread->iFlags; + info.iArg1 = a1; + info.iArg2 = a2; + + NotifyAgentsFromEventPid(info); + + return EFalse; + } + +// +// DRM_DebugChannel::HandleHwException +// +TBool DRM_DebugChannel::HandleHwException(TAny* a1, TAny* a2) + { + TArmExcInfo* aExcInfo = (TArmExcInfo*)a1; + + // sanity check + if (!aExcInfo) + { + LOG_MSG("DRM_DebugChannel::HandleHwException called with no aExcInfo"); + __NK_ASSERT_DEBUG(aExcInfo); + return EFalse; + } + + TDriverEventInfo info; + + DThread* currentThread = &Kern::CurrentThread(); + + if (!currentThread) + { + LOG_MSG("Error getting current thread"); + __NK_ASSERT_DEBUG(currentThread); + return EFalse; + } + + info.iProcessId = currentThread->iOwningProcess->iId; + info.iProcessIdValid = ETrue; + info.iThreadId = currentThread->iId; + info.iThreadIdValid = ETrue; + info.iRmdArmExcInfo.iFaultAddress= aExcInfo->iFaultAddress; + info.iRmdArmExcInfo.iFaultStatus= aExcInfo->iFaultStatus; + + LOG_MSG5("DRM_DebugChannel::HandleHwException current thread = 0x%08x, CritSect count=%d,\n" + " iFaultAddress=0x%08x, iFaultStatus=0x%08x", + currentThread, currentThread->iNThread.iCsCount, aExcInfo->iFaultAddress, aExcInfo->iFaultStatus); + + + LOG_MSG3(" HandleHwException CsFunc=%d, suspCount=%d", + currentThread->iNThread.iCsFunction, currentThread->iNThread.iSuspendCount ); + + info.iRmdArmExcInfo.iR0= aExcInfo->iR0; + info.iRmdArmExcInfo.iR1= aExcInfo->iR1; + info.iRmdArmExcInfo.iR2= aExcInfo->iR2; + info.iRmdArmExcInfo.iR3= aExcInfo->iR3; + + info.iRmdArmExcInfo.iR4= aExcInfo->iR4; + info.iRmdArmExcInfo.iR5= aExcInfo->iR5; + info.iRmdArmExcInfo.iR6= aExcInfo->iR6; + info.iRmdArmExcInfo.iR7= aExcInfo->iR7; + info.iRmdArmExcInfo.iR8= aExcInfo->iR8; + info.iRmdArmExcInfo.iR9= aExcInfo->iR9; + info.iRmdArmExcInfo.iR10= aExcInfo->iR10; + info.iRmdArmExcInfo.iR11= aExcInfo->iR11; + info.iRmdArmExcInfo.iR12= aExcInfo->iR12; + + info.iRmdArmExcInfo.iR13= aExcInfo->iR13; + info.iRmdArmExcInfo.iR14= aExcInfo->iR14; + info.iRmdArmExcInfo.iR15= aExcInfo->iR15; + + info.iRmdArmExcInfo.iCpsr= aExcInfo->iCpsr; + info.iRmdArmExcInfo.iR13Svc= aExcInfo->iR13Svc; + info.iRmdArmExcInfo.iR14Svc= aExcInfo->iR14Svc; + info.iRmdArmExcInfo.iSpsrSvc= aExcInfo->iSpsrSvc; + LOG_MSG5(" iCpsr=0x%x, iExcCode=0x%x, R14=0x%x, R15=0x%x", + aExcInfo->iCpsr, aExcInfo->iExcCode, aExcInfo->iR14, aExcInfo->iR15); + + switch (aExcInfo->iExcCode) + { + case 0: + info.iExceptionNumber = EExcCodeAbort; + LOG_MSG(" iExcCode == 0 => EExcCodeAbort"); + break; + case 1: + info.iExceptionNumber = EExcDataAbort; + LOG_MSG(" iExcCode == 1 => EExcDataAbort"); + break; + case 2: + info.iExceptionNumber = EExcInvalidOpCode; + LOG_MSG(" iExcCode == 2 => EExcInvalidOpCode"); + break; + default: + // new event? Something gone wrong? + __NK_ASSERT_DEBUG(EFalse); + return EFalse; + } + + info.iEventType = EEventsHwExc; + info.iThreadFlags = currentThread->iFlags; + + info.iArg1 = a1; + info.iArg2 = a2; + + if(EExcInvalidOpCode == info.iExceptionNumber) + { + return HandleInvalidOpCodeException(info, currentThread); + } + + NotifyAgentsFromEventPid(info); + return EFalse; + } + +// +// DRM_DebugChannel::HandUserTrace +// +TBool DRM_DebugChannel::HandleUserTrace(TAny* a1, TAny* a2) + { + LOG_EVENT_MSG("DRM_DebugChannel::HandleUserTrace()"); + + DThread* currentThread = &Kern::CurrentThread(); + if (!currentThread) + { + LOG_EVENT_MSG("Error getting current thread"); + __NK_ASSERT_DEBUG(currentThread); + return EFalse; + } + + TDriverEventInfo info; + info.iProcessId = currentThread->iOwningProcess->iId; + info.iProcessIdValid = ETrue; + info.iThreadId = currentThread->iId; + info.iThreadIdValid = ETrue; + info.iEventType = EEventsUserTrace; + info.iArg1 = a1; + info.iArg2 = a2; + + TInt err = KErrNone; + + //User Trace info + XTRAP(err, XT_DEFAULT, kumemget(info.iUserTraceText, info.iArg1, (TInt)a2)); + if(KErrNone != err) + { + return EFalse; + } + + info.iMessageStatus = ESingleMessage; + + NotifyAgentsFromEventPid(info); + + return EFalse; + } + +// +// DRM_DebugChannel::HandleException +// +TBool DRM_DebugChannel::HandleInvalidOpCodeException(TDriverEventInfo& aEventInfo, DThread* aCurrentThread) + { + LOG_MSG("DRM_DebugChannel::HandleInvalidOpCodeException()"); + + TInt err = KErrNone; + + TUint32 inst = KArmBreakPoint; + TInt instSize = 4; + + // change these for thumb mode + TUint32 regValue; + err = ReadKernelRegisterValue(aCurrentThread, STATUS_REGISTER, regValue); + if(err != KErrNone) + { + LOG_MSG2("DRM_DebugChannel::HandleInvalidOpCodeException - Non-zero error code discarded: %d", err); + } + + if (regValue & ECpuThumb) + { + inst = KThumbBreakPoint; + instSize = 2; + } + + TUint32 instruction = 0; + err = Kern::ThreadRawRead(aCurrentThread, (TUint32 *)aEventInfo.iRmdArmExcInfo.iR15, (TUint8 *)&instruction, instSize); + + if (KErrNone != err) + LOG_MSG2("Error reading instruction at currentpc: %d", err); + + if (!memcompare((TUint8 *)&inst, instSize, (TUint8 *)&instruction, instSize)) + { + TInt err = DoSuspendThread(aCurrentThread); + if(! ((KErrNone == err) || (KErrAlreadyExists == err)) ) + { + LOG_MSG2("DRM_DebugChannel::HandleInvalidOpCodeException() Thread with id 0x%08x could not be suspended.", aCurrentThread->iId); + return EFalse; + } + + // the exception was a breakpoint instruction. see if we have a breakpoint at that address + TBreakEntry* breakEntry = NULL; + do + { + breakEntry = iBreakManager->GetNextBreak(breakEntry); + if (breakEntry && ((breakEntry->iThreadSpecific && breakEntry->iId == aEventInfo.iThreadId) || (!breakEntry->iThreadSpecific && breakEntry->iId == aEventInfo.iProcessId)) && breakEntry->iAddress == aEventInfo.iRmdArmExcInfo.iR15) + { + LOG_MSG2("Breakpoint with Id %d has been hit", breakEntry->iBreakId); + + TBreakEntry tempBreakEntry = *breakEntry; + + //change the event type to breakpoint type + aEventInfo.iEventType = breakEntry->iThreadSpecific ? EEventsBreakPoint : EEventsProcessBreakPoint; + + // enable any breakpoints we had to disable for this thread + err = iBreakManager->DoEnableDisabledBreak(aEventInfo.iThreadId); + if (KErrNone != err) + LOG_MSG2("Error %d enabling disabled breakpoints", err); + + // see if this is a temp breakpoint + if (iBreakManager->IsTemporaryBreak(*breakEntry)) + { + // this was a temp breakpoint, so we need to clear it now + err = iBreakManager->DoClearBreak(breakEntry->iBreakId); + if (KErrNone != err) + LOG_MSG2("Error %d clearing temp breakpoint", err); + + // Find out how many steps remain to be done + + // reduce the number of steps to complete by 1 + tempBreakEntry.iNumSteps--; + + LOG_MSG2("There are %d steps remaining\n", tempBreakEntry.iNumSteps); + + // New. If we have not finished do all the steps, continue stepping and don't notify event + if (tempBreakEntry.iNumSteps) + { + LOG_MSG("Continuing stepping...not telling the agent yet\n"); + err = DoStepRange(aCurrentThread, aEventInfo.iRmdArmExcInfo.iR15, aEventInfo.iRmdArmExcInfo.iR15, ETrue, tempBreakEntry.iResumeOnceOutOfRange /*EFalse*/, tempBreakEntry.iNumSteps, ETrue); + if (err != KErrNone) + { + LOG_EVENT_MSG("Failed to continue stepping\n"); + + // what do we do? might as well stop here and tell the user + NotifyAgentsFromEventPid(aEventInfo); + + return ETrue; + } + + // continue as though no event occured. No need to suspend/resume anything... + LOG_MSG("Continuing to step\n"); + return ETrue; + } + + // Is this a case where we just want to continue? + if (tempBreakEntry.iResumeOnceOutOfRange) + { + LOG_MSG("PC is out of range, continuing thread"); + DoResumeThread(aCurrentThread); + + return ETrue; + } + } + + // if the breakpoint is thread specific, make sure it's the right thread + // if not, just continue the thread. take special care if it's the debugger + // thread. if it hits a regular breakpoint, we NEVER want to stop at it. if + // it hits a temp breakpoint, we're probably just stepping past a real breakpoint + // and we do need to handle it. + TBool needToResume = (tempBreakEntry.iThreadSpecific && tempBreakEntry.iId != aEventInfo.iThreadId) || + (!tempBreakEntry.iThreadSpecific && tempBreakEntry.iId != aEventInfo.iProcessId); + + if (needToResume) + { + LOG_MSG("breakpoint does not match threadId, calling DoResumeThread"); + err = DoResumeThread(aCurrentThread); + if (KErrNone != err) + LOG_MSG2("Error in DoResumeThread: %d", err); + + return EFalse; + } + + //normal user break point, just notify the event + break; + } + } while(breakEntry); + } + + NotifyAgentsFromEventPid(aEventInfo); + + return (aEventInfo.iEventType == EEventsBreakPoint) || (aEventInfo.iEventType == EEventsProcessBreakPoint); + } + +// +// DRM_DebugChannel::SetBreak +// +TInt DRM_DebugChannel::SetBreak(TSetBreakInfo* aBreakInfo) + { + LOG_MSG("DRM_DebugChannel::SetBreak()"); + + TInt err = KErrNone; + + if (!aBreakInfo) + { + LOG_MSG("DRM_DebugChannel::SetBreak() was passed a NULL argument"); + return KErrArgument; + } + + //User side memory is not accessible directly + TSetBreakInfo info; + err = Kern::ThreadRawRead(iClientThread, aBreakInfo, (TUint8*)&info, sizeof(TSetBreakInfo)); + if (err != KErrNone) + { + LOG_MSG("DRM_DebugChannel::SetBreak() was passed a bad argument"); + return err; + } + + DProcess* process = NULL; + NKern::ThreadEnterCS(); + if(info.iThreadSpecific) + { + DThread* thread = DebugUtils::OpenThreadHandle(info.iId); + if(!thread) + { + LOG_MSG2("DRM_DebugChannel::SetBreak() Thread with id 0x%08x not found", info.iId); + } + else + { + process = DebugUtils::OpenProcessHandle(thread->iOwningProcess->iId); + thread->Close(NULL); + } + } + else + { + process = DebugUtils::OpenProcessHandle(info.iId); + if(!process) + { + LOG_MSG2("DRM_DebugChannel::SetBreak() Process with id 0x%08x not found", info.iId); + } + } + + if (process == NULL) + { + NKern::ThreadLeaveCS(); + return KErrNotFound; + } + + TBool found = EFalse; + for(TInt i=0; iiId == iDebugProcessList[i].iId) + { + found = ETrue; + } + } + + if(!found) + { + DCodeSeg* codeSeg = process->iCodeSeg; + if (!codeSeg) + { + LOG_MSG2("DRM_DebugChannel::SetBreak() Code seg for process with id 0x%08x not found", process->iId); + err = KErrNotFound; + } + + TModuleMemoryInfo memoryInfo; + if (!err) + { + err = codeSeg->GetMemoryInfo(memoryInfo, process); + if (err != KErrNone) + { + LOG_MSG2("DRM_DebugChannel::SetBreak() Error getting memory info for process with id 0x%08x", process->iId); + } + } + + if (!err) + { + //add this process to the list of processes that we are debugging + TProcessInfo processInfo(process->iId, memoryInfo.iCodeBase, memoryInfo.iCodeSize, memoryInfo.iInitialisedDataBase); + iDebugProcessList.Append(processInfo); + } + } + + process->Close(NULL); + NKern::ThreadLeaveCS(); + + if (!info.iBreakId) //first check if the iId address is valid + return KErrArgument; + + if (err == KErrNone) + { + TInt32 iBreakId; + + err = iBreakManager->DoSetBreak(iBreakId, info.iId, info.iThreadSpecific, info.iAddress, info.iMode ); + + if (err == KErrNone) + { + err = Kern::ThreadRawWrite(iClientThread, (TUint8 *)info.iBreakId, &iBreakId, sizeof(TInt32), iClientThread); + } + } + + return err; + } + +// +// DRM_DebugChannel::StepRange +// +TInt DRM_DebugChannel::StepRange(DThread* aThread, TRM_DebugStepInfo* aStepInfo) + { + LOG_MSG("DRM_DebugChannel::StepRange()"); + + TInt err = KErrNone; + + if (!aStepInfo) + return KErrArgument; + + TRM_DebugStepInfo info(0, 0, 0); + err = Kern::ThreadRawRead(iClientThread, aStepInfo, (TUint8*)&info, sizeof(TRM_DebugStepInfo)); + + if (err != KErrNone) + return err; + + err = DoStepRange(aThread, info.iStartAddress, info.iStopAddress, info.iStepInto, EFalse, ETrue); + + return err; + } + +/** +Read memory from a target thread and return the data to the client. If the +memory block has breakpoints in it then the correct values are placed in the +returned data + +@param aThread pointer to thread whose memory space the memory is to be read from +@param aMemoryInfo information about what memory to read + +@return KErrNone if memory read successfully, + KErrArgument if aMemoryInfo is not initialised correctly, + KErrNoMemory if a temporary buffer could not be allocated, + KErrBadHandle if aThread is invalid, + or another of the system wide error codes +*/ +TInt DRM_DebugChannel::ReadMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo) + { + LOG_MSG("DRM_DebugChannel::ReadMemory()"); + + TInt err = KErrNone; + + if (!aMemoryInfo) + return KErrArgument; + + TRM_DebugMemoryInfo info(0, 0, 0); + err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TRM_DebugMemoryInfo)); + if (err != KErrNone) + { + LOG_MSG2("DRM_DebugChannel::ReadMemory returning error %d after Kern::ThreadRawRead()", err); + return err; + } + + if (!info.iData) + return KErrArgument; + + NKern::ThreadEnterCS(); + TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); + NKern::ThreadLeaveCS(); + if (!data) + { + return KErrNoMemory; + } + + TPtr8 dataDes(data, info.iLength); + + err = DoReadMemory(aThread, info.iAddress, info.iLength, dataDes); + if (err == KErrNone) + { + err = Kern::ThreadDesWrite(iClientThread, info.iData, dataDes, 0, KChunkShiftBy0, iClientThread); + if (err) + { + LOG_MSG2("DRM_DebugChannel::ReadMemory - Kern::ThreadDesWrite() returned error %d", err); + } + } + + NKern::ThreadEnterCS(); + Kern::Free(data); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Attempt to write memory to aThread's address space + +@param aThread thread to whose address space memory is to be written +@param aMemoryInfo memory info object representing the data to write + +@return KErrNone if memory written successfully, + KErrNoMemory if memory could not be allocated + KErrArgument if aMemoryInfo is NULL, if aMemoryInfo.iData is NULL, + if aMemoryInfo.iLength is greater than than the length of the passed + in descrptor + KErrBadHandle if aThread is invalid, + or another of the system wide error codes +*/ +TInt DRM_DebugChannel::WriteMemory(DThread* aThread, TRM_DebugMemoryInfo* aMemoryInfo) + { + LOG_MSG("DRM_DebugChannel::WriteMemory()"); + + TInt err = KErrNone; + + if (!aMemoryInfo) + return KErrArgument; + + TRM_DebugMemoryInfo info(0, 0, 0); + err = Kern::ThreadRawRead(iClientThread, aMemoryInfo, (TUint8*)&info, sizeof(TRM_DebugMemoryInfo)); + if (err != KErrNone) + return err; + + if (!info.iData) + return KErrArgument; + + NKern::ThreadEnterCS(); + TUint8 *data = (TUint8*)Kern::Alloc(info.iLength); + NKern::ThreadLeaveCS(); + if (!data) + { + return KErrNoMemory; + } + + TPtr8 dataDes(data, info.iLength); + + err = Kern::ThreadDesRead(iClientThread, info.iData, dataDes, 0); + if (err == KErrNone) + { + err = DoWriteMemory(aThread, info.iAddress, info.iLength, dataDes); + } + + NKern::ThreadEnterCS(); + Kern::Free(data); + NKern::ThreadLeaveCS(); + + return err; + } + +// +// DRM_DebugChannel::ReadRegisters +// +TInt DRM_DebugChannel::ReadRegistersLegacy(DThread* aThread, TRM_DebugRegisterInfo* aRegisterInfo) + { + LOG_MSG("DRM_DebugChannel::ReadRegistersLegacy()"); + + TInt err = KErrNone; + + if (!aRegisterInfo) + return KErrArgument; + + TRM_DebugRegisterInfo info(0, 0, 0); + err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInfo)); + if (err != KErrNone) + return err; + + if (!info.iValues) + return KErrArgument; + + TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; + + NKern::ThreadEnterCS(); + TUint8 *values = (TUint8*)Kern::Alloc(length); + NKern::ThreadLeaveCS(); + if (!values) + { + return KErrNoMemory; + } + + TPtr8 valuesDes(values, length); + + err = DoReadRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); + if (err == KErrNone) + { + err = Kern::ThreadDesWrite(iClientThread, info.iValues, valuesDes, 0, KChunkShiftBy0, iClientThread); + } + + NKern::ThreadEnterCS(); + Kern::Free(values); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Get listing information. + +@param aListInformation pointer to a TListInformation object containing the + user specified listings information + +@return KErrNone on success, + KErrTooBig if the kernel's data is too big to fit in the passed buffer, + KErrArgument if aListInformation is NULL, + or one of the other system-wide error codes +*/ +TInt DRM_DebugChannel::GetList(TListInformation* aListInformation) const + { + LOG_MSG("DRM_DebugChannel::GetList()"); + + TInt err = KErrNone; + + if(aListInformation == NULL) + { + return KErrArgument; + } + + //read DSS' data into local structure + TListInformation info; + err = Kern::ThreadRawRead(iClientThread, aListInformation, (TUint8*)&info, sizeof(TListInformation)); + if(err != KErrNone) + { + return err; + } + + //check arguments + TPtr8 buffer(NULL, 0); + err = AllocAndReadDes(iClientThread, *info.iBuffer, buffer); + if(err != KErrNone) + { + //need to free the buffer if it was allocated + if(err != KErrNoMemory) + { + NKern::ThreadEnterCS(); + Kern::Free((TAny*)buffer.Ptr()); + NKern::ThreadLeaveCS(); + } + return err; + } + + //get the list + TUint32 dataSize = 0; + TListManager manager; + err = KErrArgument; + switch(info.iType) + { + case EXipLibraries: + if(Debug::EScopeGlobal == info.iListScope) + { + err = manager.GetXipLibrariesList(buffer, dataSize); + } + break; + + case EThreads: + if(Debug::EScopeGlobal == info.iListScope) + { + err = manager.GetGlobalThreadList(buffer, dataSize); + } + else if(Debug::EScopeProcessSpecific == info.iListScope) + { + err = manager.GetThreadListForProcess(buffer, dataSize, info.iTargetId); + } + else if(Debug::EScopeThreadSpecific == info.iListScope) + { + err = manager.GetThreadListForThread(buffer, dataSize, info.iTargetId); + } + break; + + case EProcesses: + if(Debug::EScopeGlobal == info.iListScope) + { + err = manager.GetProcessList(buffer, dataSize); + } + break; + + case ECodeSegs: + if(Debug::EScopeGlobal == info.iListScope) + { + err = manager.GetGlobalCodeSegList(buffer, dataSize); + } + else if(Debug::EScopeProcessSpecific == info.iListScope) + { + err = manager.GetCodeSegListForProcess(buffer, dataSize, info.iTargetId); + } + else if(Debug::EScopeThreadSpecific == info.iListScope) + { + err = manager.GetCodeSegListForThread(buffer, dataSize, info.iTargetId); + } + break; + + default: + err = KErrNotSupported; + } + + if(err == KErrNone) + { + //if no error then write the buffer back + err = Kern::ThreadDesWrite(iClientThread, info.iBuffer, buffer, 0, KChunkShiftBy0, iClientThread); + } + + //write back the size of the data regardless of any error + TInt writeErr = Kern::ThreadRawWrite(iClientThread, info.iDataSize, (TUint8*)&dataSize, sizeof(TUint32), iClientThread); + if(writeErr != KErrNone) + { + //if there was an error writing the size return that error instead + err = writeErr; + } + + //free the buffer + NKern::ThreadEnterCS(); + Kern::Free((TAny*)buffer.Ptr()); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Read registers and store register data in aRegisterInfo + +@param aThread thread to read registers from +@param aRegisterInfo structure specifying which registers to read and providing + descriptors to write the register data into + +@return KErrNone if registers were read successfully. Note that this does not + mean that all the registers could be read, the + aRegisterInfo.iRegisterFlags array should be checked as to whether each + individual register could be read, + KErrArgument if aRegisterInfo is NULL, or if any of the pointers that + are members of aRegisterInfo are NULL, if an unknown register is + specified or if the passed in register values buffer is too small + KErrNoMemory if there is insufficient memory, + KErrDied, if the thread with thread ID aThreadId is dead +*/ +TInt DRM_DebugChannel::ReadRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const + { + LOG_MSG("DRM_DebugChannel::ReadRegisters()"); + + TInt err = KErrNone; + + if (!aRegisterInfo) + return KErrArgument; + + TRM_DebugRegisterInformation info; + err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInformation)); + if (err != KErrNone) + return err; + + if ((!info.iRegisterIds) || (!info.iRegisterValues) || (!info.iRegisterFlags)) + return KErrArgument; + + //read ids from client thread + TPtr8 ids(NULL, 0); + err = AllocAndReadDes(iClientThread, *info.iRegisterIds, ids); + if(err != KErrNone) + { + if(err == KErrNoMemory) + { + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + NKern::ThreadLeaveCS(); + } + return err; + } + + //read values from client thread + TPtr8 values(NULL, 0); + err = AllocAndReadDes(iClientThread, *info.iRegisterValues, values, EFalse); + if(err != KErrNone) + { + if(err == KErrNoMemory) + { + NKern::ThreadEnterCS(); + Kern::Free((TAny*)values.Ptr()); + NKern::ThreadLeaveCS(); + } + + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + NKern::ThreadLeaveCS(); + return err; + } + + //read flags from client thread + TPtr8 flags(NULL, 0); + err = AllocAndReadDes(iClientThread, *info.iRegisterFlags, flags, EFalse); + if(err != KErrNone) + { + if(err == KErrNoMemory) + { + NKern::ThreadEnterCS(); + Kern::Free((TAny*)flags.Ptr()); + NKern::ThreadLeaveCS(); + } + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + Kern::Free((TAny*)values.Ptr()); + NKern::ThreadLeaveCS(); + return err; + } + + err = DoReadRegisters(aThread, ids, values, flags); + if (err == KErrNone) + { + err = Kern::ThreadDesWrite(iClientThread, info.iRegisterValues, values, 0, KChunkShiftBy0, iClientThread); + if(err == KErrNone) + { + err = Kern::ThreadDesWrite(iClientThread, info.iRegisterFlags, flags, 0, KChunkShiftBy0, iClientThread); + } + } + + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + Kern::Free((TAny*)values.Ptr()); + Kern::Free((TAny*)flags.Ptr()); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +@deprecated use DRM_DebugChannel::WriteRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) instead +*/ +TInt DRM_DebugChannel::WriteRegistersLegacy(DThread* aThread, const TRM_DebugRegisterInfo* aRegisterInfo) + { + LOG_MSG("DRM_DebugChannel::WriteRegistersLegacy()"); + + TInt err = KErrNone; + + if (!aRegisterInfo) + return KErrArgument; + + TRM_DebugRegisterInfo info(0, 0, 0); + err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInfo)); + if (err != KErrNone) + return err; + + if (!info.iValues) + return KErrArgument; + + TUint length = (info.iLastRegister - info.iFirstRegister + 1) * 4; + + NKern::ThreadEnterCS(); + TUint8 *values = (TUint8*)Kern::Alloc(length); + NKern::ThreadLeaveCS(); + if (!values) + { + return KErrNoMemory; + } + + TPtr8 valuesDes(values, length); + + err = Kern::ThreadDesRead(iClientThread, info.iValues, valuesDes, 0); + if (err == KErrNone) + { + err = DoWriteRegisters(aThread, info.iFirstRegister, info.iLastRegister, valuesDes); + } + + NKern::ThreadEnterCS(); + Kern::Free(values); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Write registers and store flags data in aRegisterInfo + +@param aThread thread to write registers to +@param aRegisterInfo structure specifying which registers to write and providing + descriptors to write the register flags data into + +@return KErrNone if registers were written successfully. Note that this does not + mean that all the registers could be written, the flags array + should be checked as to whether each individual register could be read, + KErrArgument if aRegisterInfo is NULL, or if any of the pointers that + are members of aRegisterInfo are NULL, if an unknown register is + specified or if the passed in register values buffer is too small, or + if aThread is NULL, + KErrGeneral if there was a problem initialising the register set, + KErrNoMemory if there is insufficient memory, + KErrDied, if the thread with thread ID aThreadId is dead +*/ +TInt DRM_DebugChannel::WriteRegisters(DThread* aThread, TRM_DebugRegisterInformation* aRegisterInfo) const + { + LOG_MSG("DRM_DebugChannel::WriteRegisters()"); + + TInt err = KErrNone; + + if (!aRegisterInfo) + return KErrArgument; + + TRM_DebugRegisterInformation info; + err = Kern::ThreadRawRead(iClientThread, aRegisterInfo, (TUint8*)&info, sizeof(TRM_DebugRegisterInformation)); + if (err != KErrNone) + return err; + + if ((!info.iRegisterIds) || (!info.iRegisterValues) ||(!info.iRegisterFlags)) + return KErrArgument; + + //read ids from client thread + TPtr8 ids(NULL, 0); + err = AllocAndReadDes(iClientThread, *info.iRegisterIds, ids); + if(err != KErrNone) + { + if(err == KErrNoMemory) + { + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + NKern::ThreadLeaveCS(); + } + return err; + } + + //read values from client thread + TPtr8 values(NULL, 0); + err = AllocAndReadDes(iClientThread, *info.iRegisterValues, values); + if(err != KErrNone) + { + if(err == KErrNoMemory) + { + NKern::ThreadEnterCS(); + Kern::Free((TAny*)values.Ptr()); + NKern::ThreadLeaveCS(); + } + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + NKern::ThreadLeaveCS(); + return err; + } + + //read flags from client thread + TPtr8 flags(NULL, 0); + err = AllocAndReadDes(iClientThread, *info.iRegisterFlags, flags, EFalse); + if(err != KErrNone) + { + if(err == KErrNoMemory) + { + NKern::ThreadEnterCS(); + Kern::Free((TAny*)flags.Ptr()); + NKern::ThreadLeaveCS(); + } + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + Kern::Free((TAny*)values.Ptr()); + NKern::ThreadLeaveCS(); + return err; + } + + err = DoWriteRegisters(aThread, ids, values, flags); + if(err == KErrNone) + { + err = Kern::ThreadDesWrite(iClientThread, info.iRegisterFlags, flags, 0, KChunkShiftBy0, iClientThread); + } + + NKern::ThreadEnterCS(); + Kern::Free((TAny*)ids.Ptr()); + Kern::Free((TAny*)values.Ptr()); + Kern::Free((TAny*)flags.Ptr()); + NKern::ThreadLeaveCS(); + + return err; + } + +/** +Suspends execution of the specified thread. + +@param aThread thread to resume + +@return KErrNone if there were no problems or KErrArgument if aThread is NULL +*/ +TInt DRM_DebugChannel::DoSuspendThread(DThread *aThread) + { + LOG_MSG("DRM_DebugChannel::DoSuspendThread()"); + + if (!aThread) + { + LOG_MSG("Invalid dthread object"); + return KErrArgument; + } + + return TheDProcessTracker.SuspendThread(aThread); + } + +/** +Resumes execution of the specified thread. + +@param aThread thread to resume + +@return KErrNone if there were no problems, KErrArgument if aThread is NULL + or an error value returned from DoStepRange() +*/ +TInt DRM_DebugChannel::DoResumeThread(DThread *aThread) + { + if (!aThread) + return KErrArgument; + + // get the current PC + TUint32 currentPC; + TInt err = ReadKernelRegisterValue(aThread, PC_REGISTER, currentPC); + if(err != KErrNone) + { + LOG_MSG2("DRM_DebugChannel::DoResumeThread : Read PC reg error %d.", err); + // Set to this value because 0 is dangerous since structures are usually 0-initialised, + // and could thus lead to a false positive in tmp break loop below + currentPC = 0xFFFFFFFF; + } + else + { + LOG_MSG2("DRM_DebugChannel::DoResumeThread(), pc=0x%x", currentPC); + } + + // if there is a breakpoint at the current PC, we need to single step past it + TBreakEntry* breakEntry = NULL; + do + { + breakEntry = iBreakManager->GetNextBreak(breakEntry); + if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) + { + if (breakEntry->iAddress == currentPC) + { + LOG_MSG2("DRM_DebugChannel::DoResumeThread : > DoStepRange(pc+1)=0x%x, resume once out of range", currentPC+1 ); + return DoStepRange(aThread, currentPC, currentPC+1, ETrue, 1, ETrue); + } + } + } while(breakEntry); + + return TheDProcessTracker.ResumeThread(aThread); + } + +// +// DRM_DebugChannel::DoStepRange +// +TInt DRM_DebugChannel::DoStepRange(DThread *aThread, const TUint32 aStartAddress, const TUint32 aStopAddress, TBool aStepInto, TBool aResumeOnceOutOfRange, const TUint32 aNumSteps, TBool aUserRequest) + { + LOG_MSG("DRM_DebugChannel::DoStepRange()"); + + if (!aThread) + return KErrArgument; + + + TUint32 startAddress = (aStartAddress & 0x1) ? aStartAddress + 1 : aStartAddress; + TUint32 stopAddress = (aStopAddress & 0x1) ? aStopAddress + 1 : aStopAddress;; + + // don't allow the user to step in the excluded ROM region. this could be called + // internally however. for example, the the special breakpoints we set to handle + // panics, exceptions, and library loaded events are in the user library, and we + // will need to step past the breakpoint before continuing the thread. + //if (aUserRequest && (startAddress >= iExcludedROMAddressStart) && (startAddress < iExcludedROMAddressEnd)) + //{ + // return KErrNotSupported; + //} + + // set the temp breakpoint, and disable the breakpoint at the current PC if necessary + // if its not a user request, and we are just trying to resume from a breakpoint, + // then we don't need to check for stubs. The last parameter aUserRequest tells + // ModifyBreaksForStep to check for stubs or not. In some cases, the check for stubs + // is true even if its not a user request.For example, this is true in cases where + // we are doing a step range and the instruction in the range modified PC. + // in this case, DoStepRange will be called from the exception handler where + // we need to check for the stubs for the valid behavior. So truly, we don't need to check + // for stubs only when resuming from a breakpoint. + ReturnIfError(iStepper->ModifyBreaksForStep(aThread, startAddress, stopAddress, aResumeOnceOutOfRange, aUserRequest, aNumSteps)); + + LOG_MSG("DRM_DebugChannel::DoStepRange() - resuming thread\n"); + + return TheDProcessTracker.ResumeThread(aThread); + } + +/** +Read memory from the specified addres into the aData descriptor. If there is a +breakpoint set in the region of memory returned then the correct data value is +inserted into the descriptor + +@param aThread pointer to thread whose address space memory is to be read from +@param aAddress address to start reading memory from +@param aLength length of memory block to read +@param aData descriptor to read memory into + +@return KErrNone if memory read successfully, + KErrNotSupported if reading from the rom section is not supported, + KErrBadHandle if aThread is invalid, + or one of the other system wide error codes +*/ +TInt DRM_DebugChannel::DoReadMemory(const DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) const + { + LOG_MSG("DRM_DebugChannel::DoReadMemory()"); + + // make sure the parameters are valid + if (aLength > aData.MaxSize()) + return KErrArgument; + + TInt err = KErrNone; + + // trap exceptions in case the address is invalid + XTRAPD(r, XT_DEFAULT, err = TryToReadMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); + + err = (KErrNone == r) ? err : r; + + if (KErrNone == err) + { + aData.SetLength(aLength); + + TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); + + // if we have any breakpoints in this range, put the actual instruction in the buffer + TBreakEntry* breakEntry = NULL; + do + { + breakEntry = iBreakManager->GetNextBreak(breakEntry); + if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) + { + if ((breakEntry->iAddress >= aAddress) && (breakEntry->iAddress < (aAddress + aLength))) + { + TInt instSize; + + switch(breakEntry->iMode) + { + case EArmMode: + instSize = 4; + break; + + case EThumbMode: + instSize = 2; + break; + + case EThumb2EEMode: + default: + LOG_MSG("DRM_DebugChannel::DoReadMemory() cannot fixup breakpoints with unsupported architecture"); + return KErrNotSupported; + } + memcpy((TAny*)&data[breakEntry->iAddress - aAddress], (TAny *)breakEntry->iInstruction.Ptr(), instSize); + } + } + } while(breakEntry); + } + + return err; + } + +/** +Attempt to write memory to aThread's address space + +@param aThread thread to whose address space memory is to be written +@param aAddress memory location to write memory to +@param aLength number of bytes of data to write +@param aData descriptor containing memory to write + +@return KErrNone if memory written successfully, + KErrArgument if aLength is greater than than the length of the aData + KErrBadHandle if aThread is invalid, + or another of the system wide error codes +*/ +TInt DRM_DebugChannel::DoWriteMemory(DThread *aThread, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData) + { + LOG_MSG("DRM_DebugChannel::DoWriteMemory()"); + + // make sure the parameters are valid + if (aLength > aData.Length()) + return KErrArgument; + + TInt err = KErrNone; + + // trap exceptions in case the address is invalid + XTRAPD(r, XT_DEFAULT, err = TryToWriteMemory(aThread, (TAny *)aAddress, (TAny *)aData.Ptr(), aLength)); + + err = (KErrNone == r) ? err : r; + + // reset any breakpoints we may have just overwritten + if (KErrNone == err) + { + TPtr8 data((TUint8 *)aData.Ptr(), aLength, aLength); + + TBreakEntry* breakEntry = NULL; + do + { + breakEntry = iBreakManager->GetNextBreak(breakEntry); + if(breakEntry && !iBreakManager->IsTemporaryBreak(*breakEntry)) + { + if ((breakEntry->iAddress >= aAddress) && (breakEntry->iAddress < (aAddress + aLength))) + { + // default to arm mode + TUint32 inst; + TInt instSize; + + switch (breakEntry->iMode) + { + case EArmMode: + inst = KArmBreakPoint; + instSize = 4; + break; + + case EThumbMode: + inst = KThumbBreakPoint; + instSize = 2; + break; + + case EThumb2EEMode: + default: + LOG_MSG("DRM_DebugChannel::DoWriteMemory() cannot fixup breakpoints of unsupported architecture type"); + + return KErrNotSupported; + } + + breakEntry->iInstruction.Copy(&data[breakEntry->iAddress - aAddress], instSize); + memcpy((TAny*)breakEntry->iAddress, (TAny *)&inst, instSize); + } + } + + } while(breakEntry); + } + return err; + } + +// +// DRM_DebugChannel::DoReadRegisters +// +TInt DRM_DebugChannel::DoReadRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDes8 &aValues) + { + LOG_EVENT_MSG("DRM_DebugChannel::DoReadRegisters()"); + + // make sure the parameters are valid + if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) + return KErrArgument; + + // make sure the descriptor is big enough to hold the requested data + if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.MaxSize())) + return KErrArgument; + + TArmRegSet regSet; + TUint32 unused; + + NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); + + LOG_MSG2( "DRM_DebugChannel::DoReadRegistersLegacy() : unused = 0x%X\n", unused ); + + TArmReg *reg = ®Set.iR0; + + if (!reg) + return KErrGeneral; + + for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) + aValues.Append((TUint8 *)®[i], sizeof(TArmReg)); + + return KErrNone; +} + +/** + @prototype + + Experimental function for determining whether a thread is suspended. + + @param aThread thread to check if suspended + + @return ETrue if the thread is suspended, EFalse if it isn't or does not exist + */ +TBool DRM_DebugChannel::CheckSuspended(const DThread *aThread) const + { + if(!aThread) + { + return EFalse; + } + + if( (aThread->iNThread.iCsCount>0) && (aThread->iNThread.iCsFunction>0) ) + { + return ETrue; + } + + if(aThread->iNThread.iSuspendCount > 0) + { + return ETrue; + } + return EFalse; + } + +/** +Read registers and store register values in aRegisterValues and the flags +indicating which registers could be read in aRegisterFlags + +@param aThread thread to read registers from +@param aRegisterIds array containing register IDs to read +@param aRegisterValues array to store register values in +@param aRegisterFlags array to store flags in + +@return KErrNone if registers were read successfully. Note that this does not + mean that all the registers could be read, the aRegisterFlags array + should be checked as to whether each individual register could be read, + KErrArgument if aThread is NULL, if an unknown register is specified in + aRegisterValues or if aRegisterValues is too small + KErrGeneral if there was a problem initialising the register set +*/ +TInt DRM_DebugChannel::DoReadRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDes8 &aRegisterValues, TDes8& aRegisterFlags) const + { + LOG_MSG("DRM_DebugChannel::DoReadRegisters()"); + + // make sure the parameters are valid + if (!aThread) + return KErrArgument; + + //Need to revisit this to determine whether there is a way to validate this +#if 0 + if ( !CheckSuspended(aThread) ) + { + LOG_MSG2("DRM_DebugChannel::DoReadRegisters() thread with id 0x%08x is not suspended", aThread->iId); + return KErrInUse; + } +#endif + + //set lengths of output descriptors to 0 prior to filling + aRegisterValues.SetLength(0); + aRegisterFlags.SetLength(0); + + TArmRegSet regSet; + TUint32 flags; + + NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, flags); + + LOG_MSG2( "DRM_DebugChannel::DoReadRegisters() : flags = 0x%X\n", flags ); + + TArmReg *regPtr = ®Set.iR0; + + if (!regPtr) + return KErrGeneral; + + TUint numberOfRegisters = aRegisterIds.Length() / sizeof(TRegisterInfo); + + //iterate through registers setting the relevant aFlags value + for(TUint i=0; i aRegisterValues.MaxLength()) + { + //writing this value would cause overflow so exit + return KErrArgument; + } + aRegisterValues.SetLength(aRegisterValues.Length() + registerTag.iSize); + } + else + { + if(registerTag.iSize == sizeof(TArmReg)) + { + if(GetFlagAtOffset(flags, armReg)) + { + //set flag as valid + aRegisterFlags.Append(EValid); + } + else + { + // Even though the flag is invalid, we can return the value of the register + // and let the user decide what to do + aRegisterFlags.Append(EInValid); + } + + if(aRegisterValues.Length() + sizeof(TArmReg) > aRegisterValues.MaxLength()) + { + //writing this value would cause overflow so exit + return KErrArgument; + } + //write value into register into regSet + aRegisterValues.Append((TUint8 *)®Ptr[armReg], registerTag.iSize); + } + else + { + //currently all kernel supported registers are 4 bytes so + //return EBadSize. Would need updating if/when other register + //value sizes are supported + aRegisterFlags.Append(EBadSize); + aRegisterValues.SetLength(aRegisterValues.Length() + registerTag.iSize); + } + } + } + return KErrNone; + } + +// +// DRM_DebugChannel::DoWriteRegisters +// +TInt DRM_DebugChannel::DoWriteRegisters(DThread *aThread, const TInt16 aFirstRegister, const TInt16 aLastRegister, TDesC8 &aValues) + { + LOG_MSG("DRM_DebugChannel::DoWriteRegisters()"); + + // make sure the parameters are valid + if (!aThread || (aFirstRegister < 0) || (aLastRegister >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) + return KErrArgument; + + // make sure the descriptor is big enough to hold the data to write + if ((TInt)((aLastRegister - aFirstRegister + 1) * sizeof(TArmReg)) > (aValues.Length())) + return KErrArgument; + + TArmRegSet regSet; + TUint32 unused; + + NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); + + TArmReg *reg = ®Set.iR0; + + for (TInt16 i = aFirstRegister; i <= aLastRegister; i++) + reg[i] = *(TUint32 *)&aValues[(i-aFirstRegister)*sizeof(TArmReg)]; + + NKern::ThreadSetUserContext(&aThread->iNThread, ®Set); + + return KErrNone; + } + +/** +Write registers and store flags indicating which registers could be read in +aRegisterFlags + +@param aThread thread to write registers to +@param aRegisterIds array containing register IDs to write +@param aRegisterValues array containing register values to write +@param aRegisterFlags array to store flags in + +@return KErrNone if registers were written successfully. Note that this does not + mean that all the registers could be written, the aRegisterFlags array + should be checked as to whether each individual register could be read, + KErrArgument if aThread is NULL, if the buffer passed in as + aRegisterValue is too small, or if an unknown register is requested, + KErrGeneral if there was a problem initialising the register set +*/ +TInt DRM_DebugChannel::DoWriteRegisters(DThread *aThread, const TDesC8 &aRegisterIds, TDesC8 &aRegisterValues, TDes8 &aRegisterFlags) const + { + LOG_MSG("DRM_DebugChannel::DoWriteRegisters()"); + + // make sure the parameters are valid + if (!aThread) + return KErrArgument; + + + //get register values from kernel + TArmRegSet regSet; + TUint32 flags; + NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, flags); + + //set lengths of output descriptors to 0 prior to filling + aRegisterFlags.SetLength(0); + + //pointer to first kernel register + TArmReg *regPtr = ®Set.iR0; + + if (!regPtr) + return KErrGeneral; + + //calculate number of registers + TUint numberOfRegisters = aRegisterIds.Length() / sizeof(TRegisterInfo); + + //iterate through registers setting the relevant aRegisterFlags value and + //setting the necessary value in regSet ready to write to kernel + for(TUint i=0, offset = 0; i aRegisterValues.Length()) + { + //getting this value would cause overflow so exit + return KErrArgument; + } + //write value into register into regSet + regPtr[armReg] = *(TUint32 *)&aRegisterValues[offset]; + } + else + { + //currently all kernel supported registers are 4 bytes so + //return EBadSize. Would need updating if/when other register + //value sizes are supported + aRegisterFlags.Append(EBadSize); + } + + } + else + { + //set flag as invalid as register value couldn't be read + aRegisterFlags.Append(EInValid); + } + offset+=registerTag.iSize; + } + + //write the input data into the registers + NKern::ThreadSetUserContext(&aThread->iNThread, ®Set); + + //return normally + return KErrNone; + } + +// +// DRM_DebugChannel::DoSecurityCheck +// +TBool DRM_DebugChannel::DoSecurityCheck() + { + LOG_MSG("DRM_DebugChannel::DoSecurityCheck"); + DProcess* clientProcess = iClientThread->iOwningProcess; + if (clientProcess) + { + SSecurityInfo secureInfo = clientProcess->iS; + + LOG_MSG2("DoSecurityCheck - client secure id is 0x%08x",secureInfo.iSecureId); + + // Ensure we really are communicating with the Debug Security Server + if (secureInfo.iSecureId == KUidDebugSecurityServer.iUid ) + { + return ETrue; + } + } + return EFalse; + } + +/** +Attempt to read memory from aThread's address space + +@param aThread thread from whose address space memory is to be read +@param aSrc pointer to memory location to read memory from +@param aDest pointer to memory location to write memory to +@param aLength number of bytes of data to read + +@return KErrNone if memory read successfully, + or another of the system wide error codes +*/ +TInt DRM_DebugChannel::TryToReadMemory(const DThread *aThread, const TAny *aSrc, TAny *aDest, const TUint32 aLength) const + { + LOG_MSG("DRM_DebugChannel::TryToReadMemory()"); + + // make sure the parameters are valid + if (!aThread) + return KErrArgument; + + //Need to revisit this to determine whether there is a way to validate this +#if 0 + //check that the thread is suspended before reading the memory + if ( !CheckSuspended(aThread) ) + { + LOG_MSG2("DRM_DebugChannel::TryToReadMemory() thread with id 0x%08x is not suspended", aThread->iId); + return KErrInUse; + } +#endif + + LOG_MSG2("Using Kern::ThreadRawRead to read memory at address %x", aSrc); + return Kern::ThreadRawRead((DThread *)aThread, aSrc, aDest, aLength); + } + +/** +Attempt to write memory to aThread's address space + +@param aThread thread to whose address space memory is to be written +@param aDest pointer to memory location to write memory to +@param aSrc pointer to memory location to read memory from +@param aLength number of bytes of data to write + +@return KErrNone if memory written successfully, or another of the system wide + error codes +*/ +TInt DRM_DebugChannel::TryToWriteMemory(const DThread *aThread, TAny *aDest, const TAny *aSrc, const TUint32 aLength) + { + LOG_MSG("DRM_DebugChannel::TryToWriteMemory()"); + + + LOG_MSG2("Using Kern::ThreadRawWrite to write memory at address %x", (TUint32)aDest); + return Kern::ThreadRawWrite((DThread *)aThread, aDest, aSrc, aLength, iClientThread); + } + +/** +@deprecated use DRM_DebugChannel::ReadKernelRegisterValue(DThread *aThread, const TArmReg aKernelRegisterId, T4ByteRegisterValue &aValue) instead +*/ +TInt32 DRM_DebugChannel::ReadRegister(DThread *aThread, TInt aNum) + { + LOG_MSG("DRM_DebugChannel::ReadRegister()"); + + if (!aThread || (aNum < 0) || (aNum >= (TInt16)(sizeof(TArmRegSet)/sizeof(TArmReg)))) + { + LOG_MSG2("Invalid register number (%d) passed to ReadRegister", aNum); + return 0; + } + + TArmRegSet regSet; + TUint32 unused; + + NKern::ThreadGetUserContext(&aThread->iNThread, ®Set, unused); + + TArmReg *reg = ®Set.iR0; + + return ((TUint32 *)reg)[aNum]; + } + +/** +Given a TArmReg register ID, read the value of the register. The register value +will be stored in aValue if the register could be read. + +@param aThread thread to read register from +@param aKernelRegisterId ID of register to read from +@param aValue value read from register + +@return KErrNone if value was successfully stored in aValue, + KErrNotSupported if aKernelRegister is not supported by the debug + security server, + or a return value from DRM_DebugChannel::ReadDebugRegisterValue() +*/ +TInt32 DRM_DebugChannel::ReadKernelRegisterValue(DThread *aThread, const TArmReg aKernelRegisterId, T4ByteRegisterValue &aValue) const + { + //get register ID as a TRegisterInfo ID + TRegisterInfo regId; + TInt err = GetDebugRegisterId(aKernelRegisterId, regId); + if(err != KErrNone) + return err; + + //get the value for the register + err = ReadDebugRegisterValue(aThread, regId, aValue); + return err; + } + +/** +Given a TRegisterInfo register ID, read the value of this register. The +register value will be stored in aValue if the register could be read. + +@param aThread thread to read register from +@param aDebugRegisterId ID of register to read from +@param aValue value read from register + +@return KErrNone if value was successfully stored in aValue, + TRegisterFlag::EInValid if value could not be read from the register, + TRegisterFlag::ENotSupported if the register is not supported, + KErrNoMemory if temporary memory could not be allocated, + or a return value from DRM_DebugChannel::DoReadRegisters +*/ +TInt32 DRM_DebugChannel::ReadDebugRegisterValue(DThread *aThread, const TRegisterInfo aDebugRegisterId, T4ByteRegisterValue &aValue) const + { + //allocate temporary buffers to store data + NKern::ThreadEnterCS(); + TUint8* id = (TUint8*)Kern::Alloc(sizeof(TRegisterInfo)); + NKern::ThreadLeaveCS(); + if(id == NULL) + { + return KErrNoMemory; + } + + TPtr8 idPtr(id, sizeof(TRegisterInfo)); + + NKern::ThreadEnterCS(); + TUint8* value = (TUint8*)Kern::Alloc(sizeof(T4ByteRegisterValue)); + NKern::ThreadLeaveCS(); + if(value == NULL) + { + return KErrNoMemory; + } + TPtr8 valuePtr(value, sizeof(T4ByteRegisterValue)); + + NKern::ThreadEnterCS(); + TUint8* flag = (TUint8*)Kern::Alloc(sizeof(TUint8)); + NKern::ThreadLeaveCS(); + if(flag == NULL) + { + return KErrNoMemory; + } + TPtr8 flagPtr(flag, sizeof(TUint8)); + + //store register id in buffer + idPtr.Append((TUint8*)&aDebugRegisterId, sizeof(TRegisterInfo)); + + //read registers + TInt err = DoReadRegisters(aThread, idPtr, valuePtr, flagPtr); + if(err == KErrNone) + { + if(*flag == EValid) + { + //register could be read so store value + aValue = *(T4ByteRegisterValue*)value; + } + else + { + //register couldn't be read for some reason + err = *flag; + } + } + + //free memory + NKern::ThreadEnterCS(); + Kern::Free(id); + Kern::Free(value); + Kern::Free(flag); + NKern::ThreadLeaveCS(); + + return err; + } + +// +// DRM_DebugChannel::NotifyAgentsFromEventPid +// +TBool DRM_DebugChannel::NotifyAgentsFromEventPid(const TDriverEventInfo& aEventInfo) + { + + // Look for the relevant DTargetProcess + // We can find out the relevant process id from aEventInfo + TUint32 pid = aEventInfo.iProcessId; + +#ifdef _DEBUG + if (aEventInfo.iEventType != EEventsUserTrace) + { + LOG_MSG3(" NotifyAgentsFromEventPid - pid = 0x%x, evType=%d", pid, aEventInfo.iEventType); + } +#endif + + //opening handle to process + DProcess* targetProcess = DebugUtils::OpenProcessHandle(pid); + + if(!targetProcess) + { + LOG_EVENT_MSG("process does not exist!"); + return EFalse; + } + + // Are we debugging this process - decide based on iFileName + DCodeSeg* p = targetProcess->iCodeSeg; + DTargetProcess* foundProcess; + if (p) + { + foundProcess = TheDProcessTracker.FindProcess(*(p->iFileName)); + } + else + { + // special case: may not have a code seg in some cases. in which case we tell everyone! + if (targetProcess->iName) + { + // copy the name of the process + foundProcess = TheDProcessTracker.FindProcess(*(targetProcess->iName)); + } + else + { + foundProcess = NULL; + } + } + + //close the handle + targetProcess->Close(NULL); + + if (foundProcess) + { + foundProcess->NotifyEvent(aEventInfo); + return ETrue; + } + else + { + // Check if there's an attach-to-all handler + DDebugAgent* agent = TheDProcessTracker.GetCurrentAgentAttachedToAll(); + if (agent) + { + LOG_EVENT_MSG2(" NotifyAgentsFromEventPid - found attach all agent 0x%lx", agent->Id()); + agent->NotifyEvent(aEventInfo); + return ETrue; + } + } + + // we are not debugging this process + return EFalse; + } + +DECLARE_STANDARD_LDD() + { + return new DRM_DebugDriverFactory; + } + +/** +Helper function + +Allocates memory in current thread with a max length the same as aSrcDes. If +aReadFromClient is true (as it is by default) then the data from aSrdDes is +copied into the allocated aDestDes buffer. + +Use of this function should be followed at a later time by a call such as +Kern::Free(aDestDes.Ptr()) + +@param aThread pointer to thread to read data from +@param aSrcDes descriptor in aThread to read data from +@param aDestDes location to read data to. Memory is allocated at this location, + if memory is already allocated at this location then the function will + return KErrArgument +@param aReadFromClient if false then data is not actually read from the + client, the memory is simply allocated +@param aOffest offset into aSrcDes to start reading from. Default is 0. + +@return KErrNone if there were no problems, + KErrArgument if aDestDes.Ptr() != NULL or aSrcDes has max length 0, + KErrNoMemory if could not allocate memory, + or one of the other system wide error codes +*/ +TInt DRM_DebugChannel::AllocAndReadDes(DThread *aThread, const TDesC8& aSrcDes, TPtr8& aDestDes, const TBool aReadFromClient, const TUint aOffset) const + { + + //check thread is not null + if(!aThread) + { + return KErrArgument; + } + + //check aDestDes is empty + if(aDestDes.Ptr() != NULL) + { + return KErrArgument; + } + + //get the source descriptor's max length and exit if 0 + TUint srcMaxLength = Kern::ThreadGetDesMaxLength(aThread, &aSrcDes); + if(srcMaxLength == 0) + { + return KErrNone; + } + + //allocate memory and return if none available + NKern::ThreadEnterCS(); + TUint8 *destPtr = (TUint8*)Kern::Alloc(srcMaxLength); + NKern::ThreadLeaveCS(); + if (!destPtr) + { + return KErrNoMemory; + } + + //point the TPtr8 at the target memory + aDestDes.Set(destPtr, srcMaxLength, srcMaxLength); + + if(aReadFromClient) + { + //read data from the client thread and return status code + return Kern::ThreadDesRead(aThread, &aSrcDes, aDestDes, aOffset); + } + else + { + return KErrNone; + } + } + +/** +Helper function to extract a TRegisterInfo value from a descriptor containing +binary data. + +@param aRegisterIds descriptor containing register IDs +@param aOffset offset in bytes into the descriptor to start reading data from. + If this value is not a multiple of sizeof(TRegisterInfo) then a + KErrArgument error is returned. +@param aValue will contain the returned value + +@return KErrNone if aValue was set correctly, KErrArgument if bad arguments + were passed in +*/ +TInt DRM_DebugChannel::GetTRegisterInfo(const TDesC8 &aRegisterIds, const TUint aIndex, TRegisterInfo &aValue) const + { + TUint length = aRegisterIds.Length(); + + TUint size = sizeof(TRegisterInfo); + + //check that not trying to read past end of descriptor + if((aIndex + 1) * size > length) + return KErrArgument; + + //get pointer to descriptor's data + const TUint8 *dataPtr = aRegisterIds.Ptr(); + const TRegisterInfo *registerId = reinterpret_cast(dataPtr + (aIndex * size)); + + aValue = *registerId; + + return KErrNone; + } + +/** +Helper function to get the kernel register ID of the TRegisterInfo defined register. + +@param aDebugRegister the debug register ID to return the kernel ID for +@param aKernelRegister corresponding value of register aDebugRegister + +@return KErrNone if translation occurred without problems + KErrNotSupported if aDebugRegister is not supported by the kernel +*/ +TInt DRM_DebugChannel::GetKernelRegisterId(const TRegisterInfo aDebugRegister, TArmReg& aKernelRegister) const + { + if(Register::IsCoreReg(aDebugRegister)) + { + TUint id = Register::GetCoreRegId(aDebugRegister); + //first 17 registers match the first 17 kernel registers + if(id < 17) + { + aKernelRegister = id; + } + else + { + return KErrNotSupported; + } + } + else if(Register::IsCoproReg(aDebugRegister)) + { + TUint32 crn = Register::GetCRn(aDebugRegister); + TUint32 crm = Register::GetCRm(aDebugRegister); + TUint32 opcode1 = Register::GetOpcode1(aDebugRegister); + TUint32 opcode2 = Register::GetOpcode2(aDebugRegister); + TUint32 coproNum = Register::GetCoproNum(aDebugRegister); + + //each coprocessor register has potentially different characteristics + //so need to identify each individually + + //this is the DACR, the ARM ARM specifies that the CRn and the + //Opcodes are not relevant, section B3-24, point 3.7.3 + if((coproNum == 15) && (crm == 3)) + { + aKernelRegister = EArmDacr; + } + else + { + return KErrNotSupported; + } + } + else // might be supported at a later date + { + return KErrNotSupported; + } + + return KErrNone; + } + +/** +Helper function to get the debug register ID of the kernel defined register. + +@param aKernelRegister the kernel register ID to return the debug ID for +@param aDebugRegister corresponding value of register aKernelRegister + +@return KErrNone if translation occured without problems + KErrNotSupported if aKernelRegister is not supported by the debug + security server +*/ +TInt DRM_DebugChannel::GetDebugRegisterId(const TArmReg aKernelRegister, TRegisterInfo &aDebugRegister) const + { + + // registers 0 - 15 and the CPSR share the same values as with the debug enums + if(aKernelRegister < 17) + { + TUint32 id = aKernelRegister; + aDebugRegister = id << 8; + } + //the DACR value is special and corresponds to EDF_Register_DACR + else if(aKernelRegister == EArmDacr) + { + aDebugRegister = 0x00300f01; + } + // must be an unsupported register, return an error as such + else + { + return KErrNotSupported; + } + + //found a supported register so return KErrNone + return KErrNone; + } + +/** +Helper function to find out whether the aIndex flag is set. This is equivalent +to the aIndex bit of aFlags being non-zero. + +@param aFlags set of flags +@param aIndex offset into aFlags to get flag from + +@return ETrue if bit is set, EFalse if not +*/ +TBool DRM_DebugChannel::GetFlagAtOffset(const TUint32 aFlags, const TArmReg aIndex) const + { + return aFlags & (1<= KMaxPath) + { + return KErrArgument; + } + + // Allocate space to store the target process name in a kernel-side TPtr8 + NKern::ThreadEnterCS(); + TUint8* buffer = (TUint8*)Kern::AllocZ(length); + NKern::ThreadLeaveCS(); + if (buffer==NULL) + { + // Out of memory + return KErrNoMemory; + } + + // A temporary descriptor to store the target process name + TPtr8 targetProcessName(buffer,length,length); + + // Read the user-side data into targetProcessName + TInt err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); + if (err != KErrNone) + { + // Could not read the user-side descriptor containing the target process name + NKern::ThreadEnterCS(); + Kern::Free(buffer); + NKern::ThreadLeaveCS(); + + return err; + } + + // Obtain the Debug Agent Id + TUint64 debugAgentId = 0; + + err = Kern::ThreadRawRead(iClientThread,a2,&debugAgentId,sizeof(debugAgentId)); + if (err != KErrNone) + { + // Something bad happened so free the memory and return + NKern::ThreadEnterCS(); + Kern::Free(buffer); + NKern::ThreadLeaveCS(); + return err; + } + + // Add the target process to our list of tracked processes + err = TheDProcessTracker.AttachProcess(targetProcessName, debugAgentId); + + // Free the kernel-side memory containing targetProcessName data + NKern::ThreadEnterCS(); + Kern::Free(buffer); + NKern::ThreadLeaveCS(); + + return err; + } + +/* Register the detachment of a debug agent to a process to be debugged. + * + * @param - a1 TDes8 target process name in a1 + * @param a2 - &TUint64 - Debug Agent Id + * + * @return - KErrNone if successful. KErrArgument if the filepath is not a valid size. + * KErrOutOfMemory if there is insufficient memory. Or one of the other system wide error codes + * if appropriate. + */ +TInt DRM_DebugChannel::DetachProcess(TAny* a1, TAny* a2) + { + TInt length = Kern::ThreadGetDesLength(iClientThread, a1); + if (length < 0) + { + return length; + } + + if (length < 1 || length >= KMaxPath) + { + return KErrArgument; + } + + HBuf* targetProcessName = HBuf::New(length); + if (targetProcessName == NULL) + { + // Out of memory + return KErrNoMemory; + } + + // Read the user-side data into buf + TInt err = Kern::ThreadDesRead(iClientThread,a1,*targetProcessName,0,KChunkShiftBy0); + if (err != KErrNone) + { + // Something bad happened so free the memory and return + delete targetProcessName; + return err; + } + + // Obtain the AgentId + TUint64 debugAgentId = 0; + + err = Kern::ThreadRawRead(iClientThread,a2,&debugAgentId,sizeof(debugAgentId)); + if (err == KErrNone) + { + // Remove the process from our list of tracked processes + err = TheDProcessTracker.DetachProcess(*targetProcessName, debugAgentId); + } + + // Free the kernel-side memory containing targetProcessName data + delete targetProcessName; + return err; + } + +/* Register the detachment of a debug agent from all processes being debugged. + * + * @param - a1 - &TUint64 Debug Agent Id. + * @return - KErrNone if successful. One of the system-wide error codes otherwise. + */ +TInt DRM_DebugChannel::DetachAgent(TAny* a1, TAny* a2) + { + // Obtain the AgentId + TUint64 debugAgentId = 0; + + TInt err = Kern::ThreadRawRead(iClientThread,a1,&debugAgentId,sizeof(debugAgentId)); + if (err != KErrNone) + { + return err; + } + + // Remove the process from our list of tracked processes + return TheDProcessTracker.DetachAgent(debugAgentId); + } + +/* Set the action associated with a particular kernel event for a given agent and target process + * + * @param - a1 TDes8 target process name in a1 + * @param - a2 &TRM_DebugEventActionInfo + * @return - KErrNone if successful. KErrArgument if the filepath is an invalid size. Or one of + * the other system wide error codes if appropriate. + */ +TInt DRM_DebugChannel::SetEventAction(TAny* a1, TAny* a2) + { + // Validate the supplied TDes8 target process name in a1 + TInt length, maxLength; + TUint8* aPtr; + + TInt err = Kern::ThreadGetDesInfo(iClientThread,\ + a1,\ + length,\ + maxLength,\ + aPtr,\ + EFalse); + if (err != KErrNone) + { + return err; + } + + if (length < 1 || length >= KMaxPath) + { + return KErrArgument; + } + + if (maxLength < 1 || maxLength >= KMaxPath) + { + return KErrArgument; + } + + // Allocate space to store the target process name in a kernelspace TPtr8 + NKern::ThreadEnterCS(); + TUint8* buffer = (TUint8*)Kern::AllocZ(length); + NKern::ThreadLeaveCS(); + if (buffer==NULL) + { + // Out of memory + return KErrNoMemory; + } + TPtr8 targetProcessName(buffer,length,length); + + // Read the user-side data into targetProcessName + err = Kern::ThreadDesRead(iClientThread,a1,targetProcessName,0,KChunkShiftBy0); + if (err != KErrNone) + { + // Something bad happened so free the memory and return + NKern::ThreadEnterCS(); + Kern::Free(buffer); + NKern::ThreadLeaveCS(); + + return err; + } + + // Read the Event and Action from the user-side + TRM_DebugEventActionInfo info(0,0,0); + + err = Kern::ThreadRawRead(iClientThread, a2, &info, sizeof(info)); + if (err != KErrNone) + { + // Could not read event action data from the user-side + + // Free memory used for targetProcessName + NKern::ThreadEnterCS(); + Kern::Free(buffer); + NKern::ThreadLeaveCS(); + + return err; + } + + DDebugAgent* debugAgent = TheDProcessTracker.FindAgentForProcessAndId( targetProcessName, info.iAgentId ); + if (debugAgent != NULL) + { + // Set the event action + err = debugAgent->SetEventAction((TEventType)info.iEvent,(TKernelEventAction)info.iAction); + } + else + { + // Bad agent means there is no tracking agent + LOG_MSG2("Cannot locate debug agent with pid 0x%0xlx",info.iAgentId); + err = KErrNotFound; + } + + // Free memory used for targetProcessName + NKern::ThreadEnterCS(); + Kern::Free(buffer); + NKern::ThreadLeaveCS(); + + return err; + + } + +TInt DRM_DebugChannel::Step(const TUint32 aThreadId, const TUint32 aNumSteps) + { + LOG_MSG3("DRM_DebugChannel::Step(aThreadId = 0x%08x, aNumSteps = 0x%08x)\n",aThreadId,aNumSteps); + + DThread* thread = DebugUtils::OpenThreadHandle(aThreadId); + + if (thread == NULL) + { + // The thread terminated before we could open it. + LOG_MSG2("DRM_DebugChannel::Step - Could not open thread %u", aThreadId); + + return KErrArgument; + } + + // We simply repeat this for desired number of steps + TInt err = KErrNone; + + // Need to step from the current location for 'n' steps + TUint32 startAddress; + + // We always step from the current PC. + err = ReadKernelRegisterValue(thread, PC_REGISTER, startAddress); + if(err != KErrNone) + { + LOG_MSG2("DRM_DebugChannel::Step - Could not read the PC: %d", err); + + // Close the handle + thread->Close(NULL); + + return err; + } + + err = DoStepRange(thread, startAddress, startAddress, ETrue, EFalse, aNumSteps, ETrue); + + if (err != KErrNone) + { + // There was a problem, return straightaway + LOG_MSG("DRM_DebugChannel::Step - failed to step"); + } + + // Close the handle + thread->Close(NULL); + + return err; + } + +TInt DRM_DebugChannel::KillProcess(const TUint32 aProcessId, const TInt aReason) + { + LOG_MSG3("DRM_DebugChannel::KillProcess(aProcessId = 0x%08x, aReason = 0x%08x)\n",aProcessId,aReason); + + DProcess* process = DebugUtils::OpenProcessHandle(aProcessId); + + if (process == NULL) + { + // The process terminated before we could open it to kill it ourselves. + LOG_MSG2("DRM_DebugChannel::KillProcess - Could not open process %u", aProcessId); + + return KErrArgument; + } + + TInt err = KErrNone; + + DebugSupport::TerminateProcess(process,aReason); + + // Close the handle + process->Close(NULL); + + return err; + } + +/* Security critical - this checks whether the specified process is debuggable or not + * + * @param aProcessId - The process id of the process to check + * @return KErrNone if debuggable, KErrPermissionDenied if not debuggable. + */ +TInt DRM_DebugChannel::IsDebuggable(const TUint32 aProcessId) + { + /* In order to ensure that only processes which are debuggable + * can be debugged, this function enables the security server + * to read the DProcess.iDebugAttributes field and ensure + * the process was created from a debuggable executable. + */ + LOG_MSG2("DRM_DebugChannel::IsDebuggable(aProcessId 0x%08x)\n",aProcessId); + + TInt err = KErrPermissionDenied; + + DProcess* process = DebugUtils::OpenProcessHandle(aProcessId); + if (process) + { + if (process->iDebugAttributes & TProcessCreateInfo::EDebugAllowed) + { + // Yes this process exists and is debuggable + err = KErrNone; + } + process->Close(NULL); + } + + if (err == KErrNone) + { + LOG_MSG2("DRM_DebugChannel::IsDebuggable(aProcessId 0x%08x) - Yes it is debuggable\n",aProcessId); + } + + return err; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/group/rm_debug_svr.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/group/rm_debug_svr.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,51 @@ +// Copyright (c) 2006-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: +// + +ALWAYS_BUILD_AS_ARM + +target rm_debug_svr.exe +targettype exe + +sourcepath ../src +source c_shutdown_timer.cpp +source c_process_pair.cpp +source c_security_svr_server.cpp +source c_security_svr_session.cpp +source c_security_svr_async.cpp +source rm_debug_svr.cpp + +library euser.lib +library efsrv.lib +library btracec.lib + +userinclude ../inc +userinclude ../../rmdriver/inc + +SYMBIAN_BASE_SYSTEMINCLUDE(nkern) +OS_LAYER_SYSTEMINCLUDE_SYMBIAN + + +UID 0x100039CE 0x102834E2 +SECUREID 0x102834E2 +VENDORID 0x70000001 + + +// Enables UTrace logging of DSS public API calls +macro SYMBIAN_TRACE_ENABLE + +//TCB is added for the RLocalDrive methods. +CAPABILITY AllFiles TCB + +SMPSAFE diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/c_process_pair.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/c_process_pair.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,53 @@ +// Copyright (c) 2006-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: +// Provides a helper class for process security management +// +// + +#ifndef C_PROCESS_PAIR_H +#define C_PROCESS_PAIR_H + +/** +@file +@internalTechnology +@released +*/ + +/** +CProcessPair is a mapping between a debug agent's process Id, and +the process fileName of a process the agent is interested in debugging. +*/ +class CProcessPair : public CBase + { +public: + static CProcessPair* NewL(const TDesC& aProcessName, const TProcessId aProcessId); + ~CProcessPair(); + TBool operator==(const CProcessPair &aProcessPair) const; + TBool Equals(const TDesC& aProcessName, const TProcessId aProcessId) const; + TBool ProcessIdMatches(const CProcessPair &aProcessPair) const; + TBool ProcessNameMatches(const CProcessPair &aProcessPair) const; + TBool ProcessIdMatches(const TProcessId &aProcessId) const; + TBool ProcessNameMatches(const TDesC& aProcessName) const; + +private: + CProcessPair(); + void ConstructL(const TDesC& aProcessName, TProcessId aProcessId); + +private: + HBufC16* iProcessName; + TProcessId iProcessId; + }; + +#endif //C_PROCESS_PAIR_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/c_security_svr_async.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/c_security_svr_async.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,83 @@ +// Copyright (c) 2006-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: +// Asynchronous security server responder active object class. +// +// + +#ifndef C_SECURITY_SVR_ASYNC_H +#define C_SECURITY_SVR_ASYNC_H + +#include + +#include "c_security_svr_session.h" +#include "c_security_svr_server.h" + +// forward declaration +class CSecuritySvrSession; + +/** +Class used to handle asynchronous events within a DSS session. Currently this +is only used to handle GetEvent() calls. It sets up an active object when a +client makes a GetEvent() call, and completes it when ready, or cancels it +if the client so wishes. + +Only one outstanding active object per client session is permitted. +*/ +class CSecuritySvrAsync : public CActive + { +public: + ~CSecuritySvrAsync(); + static CSecuritySvrAsync* NewL(CSecuritySvrSession* aSession, const TDesC8& aProcessName, TProcessId aAgentId); + + void GetEvent(const RMessage2& aMessage); + const TDesC8& ProcessName(void); + +protected: + CSecuritySvrAsync(CSecuritySvrSession* aSession, TProcessId aAgentId); + + void ConstructL(const TDesC8& aProcessName); + + virtual void RunL(); + virtual void DoCancel(); + virtual TInt RunError(TInt aError); + +private: + + /* + * The last GetEvent message details. Needed for completion by RunL() + */ + RMessagePtr2 iMessage; + + /* + * Temporary storage area for rm_debug.ldd to return data asynchronously + */ + Debug::TEventInfo iInfo; + + /* + * Identity of this server session. Used for completing iMessage + */ + CSecuritySvrSession* iSession; + + /* + * Name of the process being debugged associated with this AO + */ + RBuf8 iProcessName; + + /* + * Debug Agent Id + */ + TProcessId iAgentId; + }; + +#endif // C_SECURITY_SVR_ASYNC_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/c_security_svr_server.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/c_security_svr_server.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,80 @@ +// Copyright (c) 2006-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: +// Definitions for the security server server. +// +// + +#ifndef C_SECURITY_SVR_SERVER_H +#define C_SECURITY_SVR_SERVER_H + +/** +@file +@internalTechnology +@released +*/ + +#include +#include "c_process_pair.h" +#include "c_shutdown_timer.h" +#include "rm_debug_kerneldriver.h" + +_LIT(KDebugDriverFileName,"rm_debug.ldd"); +class CSecuritySvrSession; + +/** +Definition of a Debug Security Server. Responsible for managing all debug agent clients, +including attachment/detachment from target executables. Keeps track of which executables +are being debugged. +*/ +class CSecuritySvrServer : public CServer2 + { + public: + CSession2* NewSessionL(const TVersion& aVersion, const RMessage2& aMessage) const; + TInt AttachProcessL(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId, const TBool aPassive); + TInt DetachProcess(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId); + void DetachAllProcesses(const TProcessId aDebugAgentProcessId); + TBool CheckAttached(const TThreadId aTargetThreadId, const RMessage2& aMessage, const TBool aPassive); + TBool CheckAttached(const TProcessId aTargetProcessId, const RMessage2& aMessage, const TBool aPassive); + TBool CheckAttachedProcess(const TDesC& aTargetProcessName, const RMessage2& aMessage, const TBool aPassive) const; + TBool IsDebugged(const TDesC& aTargetProcessName, const TBool aPassive) const; + void SessionClosed(); + void SessionOpened(); + static CSecuritySvrServer* NewLC(); + + TBool OEMTokenPermitsDebugL(const TCapabilitySet aTokenCaps, const TCapabilitySet aTargetCaps); + TBool OEMTokenPermitsFlashAccessL(const TCapabilitySet aTokenCaps); + + protected: + CSecuritySvrServer(CActive::TPriority aActiveObjectPriority); + void ConstructL(); + + private: + ~CSecuritySvrServer(); + TBool IsActiveDebugger(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId) const; + TBool IsDebugger(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId) const; + TInt GetProcessIdFromMessage(TProcessId& aProcessId, const RMessage2& aMessage) const; + + private: + RPointerArray iActiveDebugMap; + RPointerArray iPassiveDebugMap; + TInt iSessionCount; + CShutdownTimer iShutdown; + RRM_DebugDriver iKernelDriver; + + // Declare the CSecuritySvrAsync as a friend so it can use the iKernelDriver too + friend class CSecuritySvrAsync; + friend class CSecuritySvrSession; + }; + +#endif // C_SECURITY_SVR_SERVER_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/c_security_svr_session.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/c_security_svr_session.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,204 @@ +// Copyright (c) 2006-2010 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: +// Definitions for the security server server side session. +// +// + +#ifndef C_SECURITY_SVR_SESSION_H +#define C_SECURITY_SVR_SESSION_H + +/** +@file +@internalTechnology +@released +*/ + +// forward declaration +class CSecuritySvrAsync; + +#include "c_security_svr_async.h" +#include +#include + +#include + +#include "rm_debug_kerneldriver.h" + +// Server name +_LIT(KDebugDriverName,"RunMode Debug Driver"); + +class CSecuritySvrServer; + +/** +Debug Security Server session. Manages the session with one debug agent and +as many target executables as it has attached to. +*/ +class CSecuritySvrSession : public CSession2 + { +public: + CSecuritySvrSession(const TProcessId& aDebugAgentProcessId); + ~CSecuritySvrSession(); + void ConstructL (); + void CreateL(); + + TInt OpenHandle(const TRM_DebugDriverInfo& aDriverInfo); + void ServiceL(const RMessage2& aMessage); + void ServiceError(const RMessage2 &aMessage, TInt aError); + + void ResumeThreadL(const RMessage2& aMessage); + void SuspendThreadL(const RMessage2& aMessage); + //break + void SetBreakL(const RMessage2& aMessage); + void ClearBreakL(const RMessage2& aMessage); + void ModifyBreakL(const RMessage2& aMessage); + void BreakInfoL(const RMessage2& aMessage); + + void StepRangeL(const RMessage2& aMessage); + + void GetEventL(const RMessage2& aMessage); + void CancelGetEventL(const RMessage2& aMessage); + + void AttachProcessL(const RMessage2& aMessage); + void DetachProcessL(const RMessage2& aMessage); + + void AttachAllL(const RMessage2& aMessage); + void DetachAllL(const RMessage2& aMessage); + + //debug functionality + void GetDebugFunctionalityBufSizeL(const RMessage2& aMessage); + void GetDebugFunctionalityL(const RMessage2& aMessage); + //memory + void ReadMemoryL(const RMessage2& aMessage); + void WriteMemoryL(const RMessage2& aMessage); + //registers + void ReadRegistersL(const RMessage2& aMessage); + void WriteRegistersL(const RMessage2& aMessage); + //event + void SetEventActionL(const RMessage2& aMessage); + + void GetListL(const RMessage2& aMessage); + void StepL(const RMessage2& aMessage); + void TraceExecutableL(const RMessage2& aMessage); + + //crash log + void ReadCrashLogL(const RMessage2& aMessage); + void WriteCrashConfigL(const RMessage2& aMessage); + void EraseCrashLogL(const RMessage2& aMessage); + void EraseEntireCrashLogL(const RMessage2& aMessage); + + void SetProcessBreakL(const RMessage2& aMessage); + void ModifyProcessBreakL(const RMessage2& aMessage); + void ProcessBreakInfoL(const RMessage2& aMessage); + + void KillProcessL(const RMessage2& aMessage); + + TCapabilitySet GetOEMDebugCapabilities(void) const { return iOEMDebugCapabilities; }; + +#ifdef _DEBUG + void DoFailAlloc(const RMessage2& aMessage); +#endif + +private: + CSecuritySvrServer& Server() const; + void HeapWatcher(const TUint32 aFunction, const TBool aEntry) const; + void WriteDataL(const RMessage2& aMessage, const TInt aIndex, const TAny* aPtr, const TUint32 aPtrSize) const; + void CheckAttachedL(const TThreadId aThreadId, const RMessage2& aMessage, const TBool aPassive) const; + void CheckAttachedL(const TProcessId aProcessId, const RMessage2& aMessage, const TBool aPassive) const; + TBool PermitDebugL(const TProcessId aDebugAgentProcessId, const TDesC& aTargetProcessName) const; + TBool IsDebugged(const TDesC& aFileName, const TBool aPassive) const; + void OpenFileHandleL(const TDesC& aFileName, RFs& aFs, RFile& aFileHandle); + TBool IsTraceBitSet(const TDesC8& aHeaderData, const TBool aXip); + TBool IsDebugBitSet(const TDesC8& aHeaderData, const TBool aXip); + TBool CheckSufficientData(const TDesC8& aHeaderData, const TBool aXip) const; + + void ValidateMemoryInfoL(const TThreadId aThreadId, const Debug::TMemoryInfo &aMemoryInfo, const TBool aReadOperation); + void ValidateRegisterBuffersL(const RMessage2& aMessage, TUint32& aNumberOfRegisters); + + TInt GetExecutablesListL(TDes8& aBuffer, TUint32& aSize) const; + void AppendExecutableData(TDes8& aBuffer, TUint32& aSize, const TDesC& aEntryName) const; + void GetSecureIdL(const TDesC& aFileName, TUid& aSecureId); + TUid GetSecureIdL(const TDesC8& aHeaderData, TBool aXip); + + void IsDebuggableL(const TDesC& aFileName); + TThreadId ReadTThreadIdL(const RMessagePtr2& aMessage, const TInt aIndex) const; + TProcessId ReadTProcessIdL(const RMessagePtr2& aMessage, const TInt aIndex) const; + TBool IsExecutableXipL(RFile& aExecutable); + + void ConnectCrashPartitionL(void); + + void GetDebugAgentOEMTokenCapsL(); + TInt CheckFlashAccessPermissionL(const RThread& aClientThread); + + // Declare the CSecuritySvrAsync as a friend so it can use the iKernelDriver too + friend class CSecuritySvrAsync; + +private: + /** + The TProcessId of the Debug Agent associated with this session. A convenience to + save looking it up repeatedly. + */ + TProcessId iDebugAgentProcessId; + /** + Need an array of async completion objects, one for each target executable. + */ + RPointerArray iAsyncHandlers; + + /** + Used to track whether the Debug Agent has been notified when closing the session. + */ + TBool iServerNotified; + + /** + OEM Debug token support. This is only used when the Debug Agent has OEM debug + authority provided by a specific authorisation token file. This token confers + the ability to debug certain executables which have not been built as 'Debuggable'. + + The OEM Debug token executable must be marked with 'AllFiles', as this is analogous + to looking 'inside' executables - with AllFiles, it could read all the data out of an + executable in \sys\bin\. In addition, since debug control of an executable implies the + ability to execute arbitrary code within the target process space, this would imply that + a Debug Agent could use any PlatSec capability which that target process possessed. + + Therefore, we require that the OEM Debug Token must also be marked with a superset of + the PlatSec capabilities of the executable which is to be debugged. This means the + Debug Agent is not granted more access/PlatSec capabilities than its authorisation + token allows, and cannot exploit a target executable to leverage greater access than + should be permitted. + + iTargetCapabilities tracks which PlatSec capabilities the target executables may + possess and still be debugged by this debug agent. The capabilities are NOT those + of the debug agent process, they are the capabilites indicated in the OEM Debug Token + which describe the capabilities the debug agent is authorised to debug. E.g. a Debug + Agent might use CommsDD, but wish to debug a DRM capable executable. In that case, the + Debug Agent exe must be signed with CommsDD, but the OEM Debug Token need only possess + DRM and AllFiles (permission to look inside another executable). + */ + TCapabilitySet iOEMDebugCapabilities; + + //RLocalDrive to access the crash Flash + RLocalDrive iLocalDrive; + + //For NOR flash + TLocalDriveCapsV2 iCaps; + + /** + * If true means the local drive connected to the crash partition else connect + * when access required to crash flash partition for read operation + */ + TBool iCrashConnected; + }; + + +#endif // C_SECURITY_SVR_SESSION_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/c_shutdown_timer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/c_shutdown_timer.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,46 @@ +// 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: +// Definitions for the security server's shutdown timer. +// +// + +#ifndef C_SHUTDOWN_TIMER_H +#define C_SHUTDOWN_TIMER_H + +/** +@file +@internalTechnology +@released +*/ + +#include + +const TInt KShutdownDelay = 5000000; // approx 5 seconds +const TInt KActivePriorityShutdown = -1; // priority for shutdown AO + +/** +Timer class used to manage shutdown of the DSS +*/ +class CShutdownTimer : public CTimer + { +public: + CShutdownTimer(); + void ConstructL(); + void Start(); +private: + void RunL(); + }; + +#endif // C_SHUTDOWN_TIMER_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/low_mem_requests.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/low_mem_requests.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,37 @@ +// 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: +// Request numbers for use with the Debug Security Server and low mem tests +// +// + +#ifndef LOW_MEM_REQUESTS_H +#define LOW_MEM_REQUESTS_H + +/** +@file +@internalTechnology +@released +*/ + +#ifdef _DEBUG +// enumerators to use to call Debug Security Server in debug mode for low mem tests +enum TLowMemDebugServRqst + { + EDebugServFailAlloc = 0x10000001, + EDebugServMarkEnd = 0x10000002, + EDebugServMarkHeap = 0x10000003 + }; +#endif + +#endif //LOW_MEM_REQUESTS_H diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/rm_debug_api.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/rm_debug_api.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,2657 @@ +// Copyright (c) 2006-2010 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: +// Definitions for the run mode debug agent client side sessions. +// +// WARNING: This file contains some APIs which are internal and are subject +// to change without notice. Such APIs should therefore not be used +// outside the Kernel and Hardware Services package. +// + +#ifndef RM_DEBUG_API_H +#define RM_DEBUG_API_H + +/** +@file +@publishedPartner +@released +*/ + +#include +#include + +/** + The Debug namespace contains all API definitions used for on-target debugging. + */ +namespace Debug { + +/** This is the maximum size in bytes a user trace can be */ +const TInt TUserTraceSize = 256; + +/** + Information in the debug functionality block is represented as a concatenation + of pairs of TTagHeader structures and arrays of TTag objects. + @see TTagHeader + @see RSecuritySvrSession::GetDebugFunctionality + */ +struct TTag +{ + /** Tag ID, value identifying this tag. */ + TUint32 iTagId; + /** + Values correspond to TTagType enumerators. + @see TTagType + */ + TUint16 iType; + /** Size of external data associated with this tag. */ + TUint16 iSize; + /** Data associated with this tag. */ + TUint32 iValue; +}; + +/** + Enumeration defining the supported tag types. These enumerators are used in TTag.iTagId. + @see TTag + */ +enum TTagType +{ + /** Indicates that the iValue field of a TTag structure will contain either ETrue or EFalse. */ + ETagTypeBoolean = 0, + /** Indicates that the iValue field of a TTag structure will contain a value in the TUint32 range. */ + ETagTypeTUint32 = 1, + /** Indicates that the iValue field of a TTag structure will contain values from an enumeration. */ + ETagTypeEnum = 2, + /** Indicates that the iValue field of a TTag structure should be interpreted as a bit field. */ + ETagTypeBitField = 3, + /** Indicates that the type of the iValue field of a TTag structure is unknown. */ + ETagTypeUnknown = 4, + /** Indicates that the iValue field of a TTag structure will contain a pointer. */ + ETagTypePointer = 5 +}; + +/** + Information in the debug functionality block is represented as a concatenation + of pairs of TTagHeader structures and arrays of TTag objects. + @see TTag + @see RSecuritySvrSession::GetDebugFunctionality + */ +struct TTagHeader +{ + /** Value identifying the contents of this TTagHeader, should be interpreted as an enumerator from TTagHeaderId. + @see TTagHeaderId + */ + TUint16 iTagHdrId; + /** The number of TTag elements in the array associated with this TTagHeader. */ + TUint16 iNumTags; +}; + +/** + Enumeration used to identify TTagHeader structures, TTagHeader::iTagHdrId elements take these enumerators as values. + @see TTagHeader + */ +enum TTagHeaderId +{ + ETagHeaderIdCore = 0, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityCore. */ + ETagHeaderIdMemory = 1, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityMemory. */ + /** + Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityRegister. + These values are defined as in the document Symbian Core Dump File Format Appendix C + (see SGL.TS0028.027 - Symbian Core Dump File Format v1.0.doc). + The TTag objects in the associated array have an iSize value corresponding to the size of the register's data in bytes. + */ + ETagHeaderIdRegistersCore = 2, + /** + Identifies a TTagHeader with associated TTag elements with iTagId values corresponding to coprocessor register identifiers. + Coprocessor registers are defined as in the document Symbian Core Dump File Format Appendix C as follows + (see SGL.TS0028.027 - Symbian Core Dump File Format v1.0.doc): + + For each 32-bit data word defining a co-pro register, the definition of the meaning of the bits follows + the ARM Architecture Reference manual instruction coding + + Upper Halfword Lower Halfword + Opcode 2 CRm + + For example: The Domain Access Control Register is Register 3 of co-processor 15. The encoding is therefore + CRm = 3 + Opcode2 = 0 + + Therefore the functionality tag would be: + TagID: 15 // co-processor number + Type: ETagTypeTUint32 + Data: 0x00000003 // Opcode2 = 0, CRm = 3 + */ + ETagHeaderIdCoProRegisters = 3, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityRegister. */ + ETagHeaderIdBreakpoints = 4, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityBreakpoint. */ + ETagHeaderIdStepping = 5, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityStep. */ + ETagHeaderIdExecution = 6, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityExec. */ + ETagHeaderIdEvents = 7, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TEventType. */ + ETagHeaderIdApiConstants = 8, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityApiConstants.*/ + ETagHeaderList = 9, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TListId. */ + ETagHeaderIdKillObjects = 10, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityKillObject. */ + ETagHeaderIdSecurity = 11, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalitySecurity */ + ETagHeaderIdBuffers = 12, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TBufferType. */ + ETagHeaderIdStopModeFunctions = 13, /**< Identifies a TTagHeader with associated TTag elements with iTagId values from TFunctionalityStopModeFunctions. */ +}; + +/** + This structure is not used in the run-mode debug API. + @deprecated + */ +struct TSubBlock +{ + /** Header to identify the TSubBlock. */ + TTagHeader iHeader; + /** Pointer to array of TTag values associated with this TSubBlock. */ + TTag* iTagArray; +}; + +/** + These tags define what kinds of core functionality are supported by the run-mode debug subsystem. + TTag structures associated with the ETagHeaderIdCore sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalityCore +{ + ECoreEvents = 0, /**< Indicates whether events processing is supported. */ + ECoreStartStop = 1, /**< Indicates whether suspending and resuming threads is supported. */ + ECoreMemory = 2, /**< Indicates whether reading and writing memory is supported. */ + ECoreRegister = 3, /**< Indicates whether reading and writing register values is supported. */ + ECoreBreakpoint = 4, /**< Indicates whether breakpoints are supported. */ + ECoreStepping = 5, /**< Indicates whether stepping is supported. */ + ECoreLists = 6, /**< Indicates whether listings are supported. */ + ECoreLogging = 7, /**< Indicates whether logging is supported. */ + ECoreHardware = 8, /**< Indicates whether hardware support is supported. */ + ECoreApiConstants = 9, /**< Indicates whether the information in the ETagHeaderIdApiConstants sub-block is relevant. */ + ECoreKillObjects = 10, /**< Indicates whether killing objects (i.e. threads and processes) is supported. */ + ECoreSecurity = 11, /**< Indicates whether OEM Debug token support or other security info is supported. */ + ECoreStopModeFunctions = 12, /**< Indicates whether Stop Mode function calling is supported. */ + ECoreStopModeBuffers = 13, /**< Indicates whether Stop Mode buffers are supported. */ + + /** + @internalTechnology + A debug agent should find the number of core tags from the DFBlock rather than this enumerator. + */ + ECoreLast +}; + +/** + These tags define what kind of memory operations can be performed. + TTag structures associated with the ETagHeaderIdMemory sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalityMemory +{ + EMemoryRead = 0, /**< Indicates whether reading memory is supported. */ + EMemoryWrite = 1, /**< Indicates whether writing memory is supported. */ + EMemoryAccess64 = 2, /**< Indicates whether 64 bit memory access is supported. */ + EMemoryAccess32 = 3, /**< Indicates whether 32 bit memory access is supported. */ + EMemoryAccess16 = 4, /**< Indicates whether 16 bit memory access is supported. */ + EMemoryAccess8 = 5, /**< Indicates whether 8 bit memory access is supported. */ + EMemoryBE8 = 6, /**< Indicates whether reading memory as 8 bit big-endian values is supported. */ + EMemoryBE32 = 7, /**< Indicates whether reading memory as 32 bit big-endian values is supported. */ + EMemoryLE8 = 8, /**< Indicates whether reading memory as 8 bit little-endian values is supported. */ + EMemoryMaxBlockSize = 9, /**< Corresponds to the maximum size of a block of memory which can be requested. */ + /** + @internalTechnology + A debug agent should find the number of memory tags from the DFBlock rather than this enumerator. + */ + EMemoryLast +}; + +/** + These tags define which objects can be killed by the device driver. + TTag structures associated with the ETagHeaderIdKillObjects sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalityKillObject +{ + EFunctionalityKillThread = 0, /**< Indicates whether killing threads is supported. */ + EFunctionalityKillProcess = 1, /**< Indicates whether killing processes is supported. */ + /** + @internalTechnology + A debug agent should find the number of kill object tags from the DFBlock rather than this enumerator. + */ + EFunctionalityKillObjectLast +}; + +/** + A TTag with an id from the TFunctionalityRegister enum will have a value from this enumeration. + The values define how a register can be accessed, if at all. + */ +enum TFunctionalityAccess +{ + EAccessNone = 0, /**< Indicates that a register cannot be accessed. */ + EAccessReadOnly = 1, /**< Indicates that a register can be read, but not written to. */ + EAccessWriteOnly = 2, /**< Indicates that a register can be written to, but not read. */ + EAccessReadWrite = 3, /**< Indicates that a register can be both read and written to. */ + EAccessUnknown = 4, /**< Indicates that it is unspecified whether reading or writing to a register is possible. */ +}; + +/** + These enumerators act as core register identifiers. + TTag structures associated with the ETagHeaderIdRegistersCore sub-block will have iTagId values from this enumeration. + The numeric value of each enumerator identifies the register according to the definitions in the Symbian Core Dump File Format Appendix B + (see SGL.TS0028.027 - Symbian Core Dump File Format v1.0.doc). + */ +enum TFunctionalityRegister +{ + ERegisterR0 = 0x00000000, /**< Identifier for user mode register R0. */ + ERegisterR1 = 0x00000100, /**< Identifier for user mode register R1. */ + ERegisterR2 = 0x00000200, /**< Identifier for user mode register R2. */ + ERegisterR3 = 0x00000300, /**< Identifier for user mode register R3. */ + ERegisterR4 = 0x00000400, /**< Identifier for user mode register R4. */ + ERegisterR5 = 0x00000500, /**< Identifier for user mode register R5. */ + ERegisterR6 = 0x00000600, /**< Identifier for user mode register R6. */ + ERegisterR7 = 0x00000700, /**< Identifier for user mode register R7. */ + ERegisterR8 = 0x00000800, /**< Identifier for user mode register R8. */ + ERegisterR9 = 0x00000900, /**< Identifier for user mode register R9. */ + ERegisterR10 = 0x00000a00, /**< Identifier for user mode register R10. */ + ERegisterR11 = 0x00000b00, /**< Identifier for user mode register R11. */ + ERegisterR12 = 0x00000c00, /**< Identifier for user mode register R12. */ + ERegisterR13 = 0x00000d00, /**< Identifier for user mode register R13. */ + ERegisterR14 = 0x00000e00, /**< Identifier for user mode register R14. */ + ERegisterR15 = 0x00000f00, /**< Identifier for user mode register R15. */ + ERegisterCpsr = 0x00001000, /**< Identifier for CPSR. */ + ERegisterR13Svc = 0x00001100, /**< Identifier for R13 supervisor mode banked register. */ + ERegisterR14Svc = 0x00001200, /**< Identifier for R14 supervisor mode banked register. */ + ERegisterSpsrSvc = 0x00001300, /**< Identifier for SPSR supervisor mode banked register. */ + ERegisterR13Abt = 0x00001400, /**< Identifier for R13 Abort mode banked register. */ + ERegisterR14Abt = 0x00001500, /**< Identifier for R14 Abort mode banked register. */ + ERegisterSpsrAbt = 0x00001600, /**< Identifier for SPSR Abort mode banked register. */ + ERegisterR13Und = 0x00001700, /**< Identifier for R13 Undefined mode banked register. */ + ERegisterR14Und = 0x00001800, /**< Identifier for R14 Undefined mode banked register. */ + ERegisterSpsrUnd = 0x00001900, /**< Identifier for SPSR Undefined mode banked register. */ + ERegisterR13Irq = 0x00001a00, /**< Identifier for R13 Interrupt mode banked register. */ + ERegisterR14Irq = 0x00001b00, /**< Identifier for R14 Interrupt mode banked register. */ + ERegisterSpsrIrq = 0x00001c00, /**< Identifier for SPSR Interrupt mode banked register. */ + ERegisterR8Fiq = 0x00001d00, /**< Identifier for R8 Fast Interrupt mode banked register. */ + ERegisterR9Fiq = 0x00001e00, /**< Identifier for R9 Fast Interrupt mode banked register. */ + ERegisterR10Fiq = 0x00001f00, /**< Identifier for R10 Fast Interrupt mode banked register. */ + ERegisterR11Fiq = 0x00002000, /**< Identifier for R11 Fast Interrupt mode banked register. */ + ERegisterR12Fiq = 0x00002100, /**< Identifier for R12 Fast Interrupt mode banked register. */ + ERegisterR13Fiq = 0x00002200, /**< Identifier for R13 Fast Interrupt mode banked register. */ + ERegisterR14Fiq = 0x00002300, /**< Identifier for R14 Fast Interrupt mode banked register. */ + ERegisterSpsrFiq = 0x00002400, /**< Identifier for SPSR Fast Interrupt mode banked register. */ + /** + @internalTechnology + A debug agent should find the number of core registers from the DFBlock rather than this enumerator. + */ + ERegisterLast = 37 +}; + + +/** + These tags define the kind of breakpoints that are supported. + TTag structures associated with the ETagHeaderIdBreakpoints sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalityBreakpoint +{ + EBreakpointThread = 0, /**< Indicates whether thread specific breakpoints are supported. */ + EBreakpointProcess = 1, /**< Indicates whether process specific breakpoints are supported. */ + EBreakpointSystem = 2, /**< Indicates whether system wide breakpoints are supported. */ + EBreakpointArm = 3, /**< Indicates whether ARM mode breakpoints are supported. */ + EBreakpointThumb = 4, /**< Indicates whether Thumb mode breakpoints are supported. */ + EBreakpointT2EE = 5, /**< Indicates whether Thumb2 mode breakpoints are supported. */ + EBreakpointArmInst = 6, /**< Reserved for future use. */ + EBreakpointThumbInst = 7, /**< Reserved for future use. */ + EBreakpointT2EEInst = 8, /**< Reserved for future use. */ + EBreakpointSetArmInst = 9, /**< Reserved for future use. */ + EBreakpointSetThumbInst = 10, /**< Reserved for future use. */ + EBreakpointSetT2EEInst = 11, /**< Reserved for future use. */ + /** + @internalTechnology + A debug agent should find the number of breakpoint tags from the DFBlock rather than this enumerator. + */ + EBreakpointLast +}; + +/** + These enumerators provide information about the stepping capabilities of the debug sub-system. + TTag structures associated with the ETagHeaderIdStepping sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalityStep +{ + EStep = 0, /**< Indicates whether instruction stepping is supported. */ + /** + @internalTechnology + A debug agent should find the number of stepping tags from the DFBlock rather than this enumerator. + */ + EStepLast +}; + +/** + These enumerators provide information about the execution control capabilities of the debug sub-system. + TTag structures associated with the ETagHeaderIdExecution sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalityExec +{ + EExecThreadSuspendResume = 0, /**< Indicates whether suspending and resuming threads is supported. */ + EExecProcessSuspendResume = 1, /**< Indicates whether suspending and resuming processes is supported. */ + EExecSystemSuspendResume = 2, /**< Indicates whether suspending and resuming the entire system is supported. */ + /** + @internalTechnology + A debug agent should find the number of execution control tags from the DFBlock rather than this enumerator. + */ + EExecLast +}; + +/** + This enumeration defines the event types supported by the debug sub-system. + TTag structures associated with the ETagHeaderIdEvents sub-block will have + iTagId values from this enumeration, and iValue values from the TKernelEventAction enumeration. + + These enumerators are also used by the RSecuritySvrSession API to identify events. + @see RSecuritySvrSession + @see TKernelEventAction + */ +enum TEventType +{ + EEventsBreakPoint = 0, /**< Identifies a breakpoint event. */ + EEventsSwExc = 1, /**< Identifies a software exception event. */ + EEventsHwExc = 2, /**< Identifies a hardware exception event. */ + EEventsKillThread = 3, /**< Identifies a kill thread event. */ + EEventsAddLibrary = 4, /**< Identifies an add library event. */ + EEventsRemoveLibrary = 5, /**< Identifies a remove library event. */ + /** + If an event is generated and there is only a single space remaining in the events queue then + an event of type EEventsBufferFull will be stored in the queue and the generated event will + be discarded. If further events occur while the buffer is full the events will be discarded. + As such an event of type EEventsBufferFull being returned signifies that one or more events + were discarded. An event of this type has no valid data associated with it. + */ + EEventsBufferFull = 6, + EEventsUnknown = 7, /**< Identifies an event of unknown type. */ + EEventsUserTrace = 8, /**< Identifies a user trace. */ + EEventsProcessBreakPoint = 9, /**< Identifies a process breakpoint event. */ + EEventsStartThread = 10, /**< Identifies a start thread event. */ + EEventsUserTracesLost = 11, /**< Identifies user traces being lost. */ + EEventsAddProcess = 12, /**< Identifies an AddProcess event */ + EEventsRemoveProcess = 13, /**< Identifies a RemoveProcess event */ + /** + @internalTechnology + A debug agent should find the number of event types from the DFBlock rather than this enumerator. + */ + EEventsLast +}; + +/** + These enumerators provide information about constants which are used in the RSecuritySvrSession API. + TTag structures associated with the ETagHeaderIdApiConstants sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalityApiConstants + { + /** + Corresponds to the size of a buffer required to store a TEventInfo. + @see TEventInfo + */ + EApiConstantsTEventInfoSize = 0, + /** + @internalTechnology + A debug agent should find the number of API constants tags from the DFBlock rather than this enumerator. + */ + EApiConstantsLast, + }; + +/** + The set of possible actions which could be taken when a kernel event occurs. + Not all actions are possible for all events. The debug functionality sub-block with header id ETagHeaderIdEvents + indicates which values are permitted for each event. The value given for that event should be + considered as the most intrusive action the debugger may set: with the definition that EActionSuspend is more + intrusive than EActionContinue, which is more intrusive than EActionIgnore. + @see RSecuritySvrSession + */ +enum TKernelEventAction +{ + /** If an event action is set to this value then events of that type will be + ignored, and not reported to the debugger. */ + EActionIgnore = 0, + /** If an event action is set to this value then events of that type will be + reported to the debugger and the thread which generated the event will be + allowed to continue executing. */ + EActionContinue = 1, + /** If an event action is set to this value then events of that type will be + reported to the debugger and the thread which generated the event will be + suspended. */ + EActionSuspend = 2, + /** + @internalTechnology + Count of event actions. + */ + EActionLast +}; + +/** + These enumerators provide information about the ability of the debug subsystem to support OEM Debug tokens. + TTag structures associated with the ETagHeaderIdSecurity sub-block will have iTagId values from this enumeration. + See each enumerator for an explanation of how a TTag with that iTagId should be interpreted. + */ +enum TFunctionalitySecurity +{ + ESecurityOEMDebugToken = 0, /**< Indicates whether the DSS supports the use of OEM Debug Tokens. */ + + /** + @internalTechnology + A debug agent should find the number of tags from the DFBlock rather than this enumerator. + */ + ESecurityLast +}; + +/** + Used for storing the contents of a 32 bit register + */ +typedef TUint32 TRegisterValue32; + + +/** + * Processor mode + */ +enum TArmProcessorModes +{ + EUserMode=0x10, //!< EUserMode + EFiqMode=0x11, //!< EFiqMode + EIrqMode=0x12, //!< EIrqMode + ESvcMode=0x13, //!< ESvcMode + EAbortMode=0x17, //!< EAbortMode + EUndefMode=0x1b, //!< EUndefMode + EMaskMode=0x1f //!< EMaskMode +}; + + + +/** + Structure containing information about the state of the registers when a + hardware exception occurred + */ +class TRmdArmExcInfo + { +public: + /** Enumeration detailing the types of exception which may occur. */ + enum TExceptionType + { + /** Enumerator signifying that a prefetch abort error has occurred. */ + EPrefetchAbort = 0, + /** Enumerator signifying that a data abort error has occurred. */ + EDataAbort = 1, + /** Enumerator signifying that an undefined instruction error has occurred. */ + EUndef =2 + }; + + /** Value of CPSR. */ + TRegisterValue32 iCpsr; + /** Type of exception which has occurred. */ + TExceptionType iExcCode; + /** Value of R13 supervisor mode banked register. */ + TRegisterValue32 iR13Svc; + /** Value of user mode register R4. */ + TRegisterValue32 iR4; + /** Value of user mode register R5. */ + TRegisterValue32 iR5; + /** Value of user mode register R6. */ + TRegisterValue32 iR6; + /** Value of user mode register R7. */ + TRegisterValue32 iR7; + /** Value of user mode register R8. */ + TRegisterValue32 iR8; + /** Value of user mode register R9. */ + TRegisterValue32 iR9; + /** Value of user mode register R10. */ + TRegisterValue32 iR10; + /** Value of user mode register R11. */ + TRegisterValue32 iR11; + /** Value of R14 supervisor mode banked register. */ + TRegisterValue32 iR14Svc; + /** Address which caused exception (System Control Coprocessor Fault Address Register) */ + TRegisterValue32 iFaultAddress; + /** Value of System Control Coprocessor Fault Status Register. */ + TRegisterValue32 iFaultStatus; + /** Value of SPSR supervisor mode banked register. */ + TRegisterValue32 iSpsrSvc; + /** Value of user mode register R13. */ + TRegisterValue32 iR13; + /** Value of user mode register R14. */ + TRegisterValue32 iR14; + /** Value of user mode register R0. */ + TRegisterValue32 iR0; + /** Value of user mode register R1. */ + TRegisterValue32 iR1; + /** Value of user mode register R2. */ + TRegisterValue32 iR2; + /** Value of user mode register R3. */ + TRegisterValue32 iR3; + /** Value of user mode register R12. */ + TRegisterValue32 iR12; + /** Value of user mode register R15, points to instruction which caused exception. */ + TRegisterValue32 iR15; + }; + +/** + The maximum size, in bytes, of the panic category string returned as part of a + TEventInfo object. + + @see TEventInfo + @see TThreadKillInfo + */ +const TInt KPanicCategoryMaxName = KMaxName; + +/** + Event specific information returned as part of a TEventInfo object when + an agent set breakpoint is hit. + */ +class TThreadBreakPointInfo + { +public: + /** Identifies the type of exception. */ + TExcType iExceptionNumber; + /** Structure containing information about the ARM register values. */ + TRmdArmExcInfo iRmdArmExcInfo; + }; + +/** + Event specific information returned as part of a TEventInfo object when + a software exception occurs. + */ +class TThreadSwExceptionInfo + { +public: + /** The value of the program counter. */ + TUint32 iCurrentPC; + /** Identifies the type of exception. */ + TExcType iExceptionNumber; + }; + +/** + Event specific information returned as part of a TEventInfo object when + a hardware exception occurs. + */ +class TThreadHwExceptionInfo + { +public: + /** Identifies the type of exception. */ + TExcType iExceptionNumber; + /** Structure containing information about the ARM register values. */ + TRmdArmExcInfo iRmdArmExcInfo; + }; + +/** + Event specific information returned as part of a TEventInfo object when + a thread kill event occurs. + */ +class TThreadKillInfo + { +public: + /** The value of the program counter. */ + TUint32 iCurrentPC; + /** Specifies the reason for the kill thread event, this value is specific to the killed thread and does not correspond to a standard Symbian enumeration. */ + TInt iExitReason; + /** Specifies the type of the thread kill event, values correspond to elements of TExitType. */ + TUint8 iExitType; + /** The panic category of the killed thread. */ + TUint8 iPanicCategory[KPanicCategoryMaxName]; + /** Contains the length in bytes of the initialised data in iPanicCategory. */ + TInt iPanicCategoryLength; + }; + +/** + Event specific information returned as part of a TEventInfo object when + a library load event occurs. + */ +class TLibraryLoadedInfo + { +public: + /** The name of the file that the library was loaded from. */ + TUint8 iFileName[KMaxName]; + /** Contains the length in bytes of the initialised data in iFileName. */ + TInt iFileNameLength; + /** The code base address (.text). */ + TUint32 iCodeAddress; + /** The base address of the initialised data section (.data). */ + TUint32 iDataAddress; + }; + +/** + Event specific information returned as part of a TEventInfo object when + a thread is started + */ +class TStartThreadInfo + { +public: + /** The name of the file that the process owning the thread was created from. */ + TUint8 iFileName[KMaxName]; + /** Contains the length in bytes of the initialised data in iFileName. */ + TInt iFileNameLength; + }; + +/** + Event specific information returned as part of a TEventInfo object when + a process is added. Note that the Process may not be fully constructed, + e.g. no threads. + */ +class TAddProcessInfo + { +public: + /** The name of the file that the process was created from. */ + TUint8 iFileName[KMaxName]; + /** Contains the length in bytes of the initialised data in iFileName. */ + TInt iFileNameLength; + /** The UID3 of this process */ + TUint32 iUid3; + /** Contains the CreatorThread ID if available: May be 0 */ + TUint64 iCreatorThreadId; + }; + +/** + Event specific information returned as part of a TEventInfo object when + a process is removed. Note that the Process may not be fully destroyed, + so its resources should only be accessed if you already have a handle to it. + */ +class TRemoveProcessInfo + { +public: + /** The name of the file that the process was created from. */ + TUint8 iFileName[KMaxName]; + /** Contains the length in bytes of the initialised data in iFileName. */ + TInt iFileNameLength; + TUint32 iSpare1; // Unused + }; + +/** + Event specific information returned as part of a TEventInfo object when + a library unload event occurs. + */ +class TLibraryUnloadedInfo + { +public: + /** The name of the file that the library was loaded from. */ + TUint8 iFileName[KMaxName]; + /** Contains the length in bytes of the initialised data in iFileName. */ + TInt iFileNameLength; + }; + +/** + * Enum to represent the context of a user trace message + */ +enum TUserTraceMessageContext +{ + ESingleMessage = 0x1, /** Indicates this message is the only one corresponding to a given user trace */ + EMultiStart = 0x2, /** Indicates this message is the start of a user trace which consists of multiple messages */ + EMultiMid = 0x3, /** Indicates this message is one in a series of user trace messages */ + EMultiEnd = 0x4, /** Indicates this message is the last in a series of user trace messages */ + /** + @internalTechnology + A debug agent should find the number of core tags from the DFBlock rather than this enumerator. + */ + ELast = 0x5 +}; + +/** + * Event specific information returned as part of a TEventInfo object + * when a user trace event occurs. + */ +class TUserTraceInfo + { +public: + /** The user trace text */ + TUint8 iUserTraceText[TUserTraceSize]; + + /** User trace text length */ + TInt iUserTraceLength; + + /** The context of the message */ + TUserTraceMessageContext iMessageStatus; + }; + + +/** + Structure used to store information about an event. An object of this type + is passed as an argument to the RSecuritySvrSession::GetEvent function, + and is filled in by the debug driver, and returned to the agent, when a + relevant event occurs. + + The debug functionality block contains the size in bytes of the data that + the driver will return when a GetEvent call is issued. A debug agent should + ensure that this value equals the size of this TEventInfo object to ensure + that a compatible debug driver is being used. The value is stored as + EApiConstantsTEventInfoSize in the TFunctionalityApiConstants block. + + @see RSecuritySvrSession::GetDebugFunctionality + @see RSecuritySvrSession::GetEvent + */ +class TEventInfo + { +public: + + /** Constructor sets all elements to default values. */ + inline TEventInfo() { Reset(); }; + + /** Resets all values to default values. */ + inline void Reset() + { + iProcessId = 0; + iProcessIdValid = EFalse; + iThreadId = 0; + iThreadIdValid = EFalse; + iEventType = (TEventType)NULL; + iActionTaken = EActionIgnore; + }; + +public: + + /** The process ID of the process which the event occurred in. */ + TUint64 iProcessId; + /** The thread ID of the thread which the event occurred in. */ + TUint64 iThreadId; + /** Has value ETrue if iProcessId is valid, EFalse otherwise. */ + TUint8 iProcessIdValid; + /** Has value ETrue if iThreadId is valid, EFalse otherwise. */ + TUint8 iThreadIdValid; + /** What action was taken by the debug system when it received the event. A TKernelEventAction */ + TUint8 iActionTaken; + TUint8 iSpare; + + /** Indicates the type of the event. This type should be used to determine + the type of the information stored in the union which is part of this class. */ + TEventType iEventType; + union + { + /** Information which is specific to the break point event. */ + TThreadBreakPointInfo iThreadBreakPointInfo; + /** Information which is specific to the software exception event. */ + TThreadSwExceptionInfo iThreadSwExceptionInfo; + /** Information which is specific to the hardware exception event. */ + TThreadHwExceptionInfo iThreadHwExceptionInfo; + /** Information which is specific to the thread kill event. */ + TThreadKillInfo iThreadKillInfo; + /** Information which is specific to the library loaded event. */ + TLibraryLoadedInfo iLibraryLoadedInfo; + /** Information which is specific to the library unloaded event. */ + TLibraryUnloadedInfo iLibraryUnloadedInfo; + /** Information which is specific to the user trace event. */ + TUserTraceInfo iUserTraceInfo; + /** Information which is specific to the start thread event. */ + TStartThreadInfo iStartThreadInfo; + /** Information which is specific to the Add Process event. */ + TAddProcessInfo iAddProcessInfo; + /** Information which is specific to the Remove Process event. */ + TRemoveProcessInfo iRemoveProcessInfo; + }; + }; + +/** + @internalComponent + */ +class TProcessInfo + { + public: + + inline TProcessInfo() { Reset(); } + + inline TProcessInfo(TUint32 aId, TUint32 aCodeAddress, TUint32 aCodeSize, TUint32 aDataAddress) + : iId(aId), + iCodeAddress(aCodeAddress), + iCodeSize(aCodeSize), + iDataAddress(aDataAddress) { } + + inline void Reset() + { + iId = 0; + iCodeAddress = 0; + iCodeSize = 0; + iDataAddress = 0; + } + + public: + + TUint32 iId; + TUint32 iCodeAddress; + TUint32 iCodeSize; + TUint32 iDataAddress; + }; + +/* Other functionality may be defined here later */ + +/** +Represents a register id value, in the terms of the Symbian ELF format: + - bits 0-7 define the class + - bits 8-15 define the rd_id + - bits 16-31 define the rd_sub_id + +Both the core registers (TFunctionalityRegister type) and the coprocessor registers +follow this identifier scheme. +*/ +typedef TUint32 TRegisterInfo; + +/** +Enum representing the status flags which could be returned from a register +access call. +*/ +enum TRegisterFlag + { + /** + Default value, a register access call will never return this value + */ + ENotSet = 0, + /** + Would be returned if the register is supported by the debug driver but the kernel cannot access the register + */ + EInValid = 1, + /** + Would be returned if the register could be accessed correctly + */ + EValid = 2, + /** + Would be returned if the register is not supported by the debug driver + */ + ENotSupported = 3, + /** + Would be returned if a non-4 byte register value was requested + */ + EBadSize = 4 + }; + +/** +Enum representing the different ARM CPU instruction set architectures. +*/ +enum TArchitectureMode + { + /** Represents the ARM CPU architecture. */ + EArmMode = 1, + /** Represents the Thumb CPU architecture. */ + EThumbMode = 2, + /** + Represents the Thumb2 CPU architecture. + @prototype + */ + EThumb2EEMode = 3 + }; + +/** + Used as an identifier for breakpoints set by the RSecuritySvrSession::SetBreak function. + @see RSecuritySvrSession + */ +typedef TInt32 TBreakId; + +/** + Specifies the type of a code segment. + @see TCodeSegListEntry + */ +enum TCodeSegType + { + EUnknownCodeSegType = 0, /**< Signifies an unknown code segment type. */ + EExeCodeSegType = 1, /**< Signifies a code segment belonging to an executable. */ + EDllCodeSegType = 2 /**< Signifies a code segment belonging to a library. */ + }; + +/** +Structure used for extracting data from a descriptor returned by a call to +RSecuritySvrSession::GetList() when GetList() is called with TListId::ECodeSegs +as the first argument. + +@see RSecuritySvrSession::GetList() + +@code +//buffer is a TDesC8 containing 4-byte aligned TCodeSegListEntry objects +//create a pointer to the start of the data +TUint8* ptr = (TUint8*)buffer.Ptr(); +//create a pointer to the end of the data +const TUint8* ptrEnd = ptr + buffer.Length(); +while(ptr < ptrEnd) + { + //cast the pointer to be a TCodeSegListEntry object + TCodeSegListEntry& entry = *(TCodeSegListEntry*)ptr; + //use the TCodeSegListEntry pointer, i.e. + TUint16 nameLength = entry.iNameLength; + TPtr name(&(entry.iName[0]), nameLength, nameLength); + // move ptr on to point to the next TCodeSegListEntry object + ptr += Align4(entry.GetSize()); + } +@endcode +*/ +class TCodeSegListEntry + { +public: + TInt GetSize() const; +public: + /** + Address of the start of the code segment. + */ + TUint32 iCodeBase; + /** + Size of the code segment. + */ + TUint32 iCodeSize; + /** + Size of the const data segment + */ + TUint32 iConstDataSize; + /** + Address of the initialised data + */ + TUint32 iInitialisedDataBase; + /** + Size of the initialised data + */ + TUint32 iInitialisedDataSize; + /** + Size of the uninitialised data + */ + TUint32 iUninitialisedDataSize; + /** + Boolean indicating whether the code segment is execute in place + */ + TBool iIsXip; + /** + Indicates whether the code segment is from an executable or a dll, or neither + */ + TCodeSegType iCodeSegType; + /** Uid3 of this segment. */ + TUint32 iUid3; + /** Currently unused element. May be used in future to aid maintaining compatibility. */ + TUint32 iSpare2; + /** + Length of the code segment's name + */ + TUint16 iNameLength; + /** + First two bytes of the code segment's name, the name should be considered to + extend past the end of the TCodeSegListEntry structure to a length + corresponding to iNameLength + */ + TUint16 iName[1]; + }; + +/** +Returns the size of the TCodeSegListEntry, including the file name length + +@return the size, in bytes, of the TCodeSegListEntry and the code segment's +file name +*/ +inline TInt TCodeSegListEntry::GetSize() const + { + return sizeof(TCodeSegListEntry) - sizeof(iName) + (2 * iNameLength); + } + +/** +Structure used for extracting data from a descriptor returned by a call to +RSecuritySvrSession::GetList() when GetList() is called with TListId::EXipLibraries +as the first argument. + +@see RSecuritySvrSession::GetList() + +@code +//buffer is a TDesC8 containing 4-byte aligned TXipLibraryListEntry objects +//create a pointer to the start of the data +TUint8* ptr = (TUint8*)buffer.Ptr(); +//create a pointer to the end of the data +const TUint8* ptrEnd = ptr + buffer.Length(); +while(ptr < ptrEnd) + { + //cast the pointer to be a TXipLibraryListEntry object + TXipLibraryListEntry& entry = *(TXipLibraryListEntry*)ptr; + //use the TXipLibraryListEntry pointer, i.e. + TUint16 nameLength = entry.iNameLength; + TPtr name(&(entry.iName[0]), nameLength, nameLength); + // move ptr on to point to the next TXipLibraryListEntry object + ptr += Align4(entry.GetSize()); + } +@endcode +*/ +class TXipLibraryListEntry + { +public: + TInt GetSize() const; +public: + /** + Address of the start of the library's code segment. + */ + TUint32 iCodeBase; + /** + Size of the code segment. + */ + TUint32 iCodeSize; + /** + Size of the const data segment + */ + TUint32 iConstDataSize; + /** + Address of the initialised data + */ + TUint32 iInitialisedDataBase; + /** + Size of the initialised data + */ + TUint32 iInitialisedDataSize; + /** + Size of the uninitialised data + */ + TUint32 iUninitialisedDataSize; + /** Currently unused element. May be used in future to aid maintaining compatibility. */ + TUint32 iSpare1; + /** Currently unused element. May be used in future to aid maintaining compatibility. */ + TUint32 iSpare2; + /** + Length of the library's name + */ + TUint16 iNameLength; + /** + First two bytes of the code segment's name, the name should be considered to + extend past the end of the TXipLibraryListEntry structure to a length + corresponding to iNameLength + */ + TUint16 iName[1]; + }; + +/** +Returns the size of the TXipLibraryListEntry, including the file name length + +@return the size, in bytes, of the TXipLibraryListEntry and the library's +file name +*/ +inline TInt TXipLibraryListEntry::GetSize() const + { + return sizeof(TXipLibraryListEntry) - sizeof(iName) + (2 * iNameLength); + } + +/** +Structure used for extracting data from a descriptor returned by a call to +RSecuritySvrSession::GetList() when GetList() is called with TListId::EExecutables +as the first argument. + +@see RSecuritySvrSession::GetList() + +@code +//buffer is a TDesC8 containing 4-byte aligned TExecutablesListEntry objects +//create a pointer to the start of the data +TUint8* ptr = (TUint8*)buffer.Ptr(); +//create a pointer to the end of the data +const TUint8* ptrEnd = ptr + buffer.Length(); +while(ptr < ptrEnd) + { + //cast the pointer to be a TExecutablesListEntry object + TExecutablesListEntry& entry = *(TExecutablesListEntry*)ptr; + //use the TExecutablesListEntry pointer, i.e. + TUint16 nameLength = entry.iNameLength; + TPtr name(&(entry.iName[0]), nameLength, nameLength); + // move ptr on to point to the next TExecutablesListEntry object + ptr += Align4(entry.GetSize()); + } +@endcode +*/ +class TExecutablesListEntry + { +public: + TInt GetSize() const; +public: + /** + Indicates whether an agent has registered to actively debug the executable, + a non-zero value indicates that an agent has attached. + */ + TUint8 iIsActivelyDebugged; + /** + Indicates whether any agents have registered to passively debug the executable, + a non-zero value indicates that at least one agent is attached passively + */ + TUint8 iIsPassivelyDebugged; + /** Currently unused element. May be used in future to aid maintaining compatibility. */ + TUint32 iSpare1; + /** Currently unused element. May be used in future to aid maintaining compatibility. */ + TUint32 iSpare2; + /** + Length of the executable's name + */ + TUint16 iNameLength; + /** + First two bytes of the executable's name, the name should be considered to + extend past the end of the TExecutablesListEntry structure to a length + corresponding to iNameLength + */ + TUint16 iName[1]; + }; + +/** +Returns the size of the TExecutablesListEntry, including the file name length + +@return the size, in bytes, of the TExecutablesListEntry and the executable's +file name +*/ +inline TInt TExecutablesListEntry::GetSize() const + { + return sizeof(TExecutablesListEntry) - sizeof(iName) + (2*iNameLength); + } + +/** +Structure used for extracting data from a descriptor returned by a call to +RSecuritySvrSession::GetList() when GetList() is called with TListId::EProcesses +as the first argument. + +@see RSecuritySvrSession::GetList() + +@code +//buffer is a TDesC8 containing 4-byte aligned TProcessListEntry objects +//create a pointer to the start of the data +TUint8* ptr = (TUint8*)buffer.Ptr(); +//create a pointer to the end of the data +const TUint8* ptrEnd = ptr + buffer.Length(); +while(ptr < ptrEnd) + { + //cast the pointer to be a TProcessListEntry object + TProcessListEntry& entry = *(TProcessListEntry*)ptr; + //use the TProcessListEntry pointer, i.e. + TUint16 fileNameLength = entry.iFileNameLength; + TPtr name(&(entry.iNames[0]), fileNameLength, fileNameLength); + // move ptr on to point to the next TProcessListEntry object + ptr += Align4(entry.GetSize()); + } +@endcode +*/ +class TProcessListEntry + { + public: + TInt GetSize() const; + + public: + /** Process ID */ + TUint64 iProcessId; + + /** The Uid3 of the process */ + TUint32 iUid3; + + /** + * Process Attributes + * @see DProcess::TProcessAttributes + */ + TInt iAttributes; + + /** + * Length of fully qualified file name of the process in bytes. Note that this + * entry may be 0 if the process is in the process of shutting down. + */ + TUint16 iFileNameLength; + + /** + * Length of current dynamic name of the process in bytes + */ + TUint16 iDynamicNameLength; + + /** + * First two bytes of the process' file name, the name should be considered to + * extend past the end of the TProcessListEntry structure to a length + * corresponding to iFileNameLength. Directly after the data corresponding to the + * file name, the dynamic name is stored with a length of iDynamicNameLength characters. + * Note that these names are not null terminated and are concatenated directly after each other. + * + * @code + * TProcessListEntry& entry; // entry is a reference to a TProcessListEntry + * + * //get the file name.. + * TPtr fileName(&(entry.iNames[0]), iFileNameLength, iFileNameLength); + * + * //get the dynamic name length.. + * TPtr dynamicName(&(entry.iNames[0]) + iFileNameLength, iDynamicNameLength, iDynamicNameLength); + * @endcode + */ + TUint16 iNames[1]; + }; + +/** +Returns the size of the TProcessListEntry, including the file name length and the +dynamic name length + +@return the size, in bytes, of the TProcessListEntry and the executable's +file name file name and dynamic name +*/ +inline TInt TProcessListEntry::GetSize() const + { + return sizeof(TProcessListEntry) - sizeof(iNames) + (2 * (iFileNameLength + iDynamicNameLength)); + } + +/** +Structure used for extracting data from a descriptor returned by a call to +RSecuritySvrSession::GetList() when GetList() is called with TListId::EThreads +as the first argument. + +@see RSecuritySvrSession::GetList() + +@code +//buffer is a TDesC8 containing 4-byte aligned TThreadListEntry objects +//create a pointer to the start of the data +TUint8* ptr = (TUint8*)buffer.Ptr(); +//create a pointer to the end of the data +const TUint8* ptrEnd = ptr + buffer.Length(); +while(ptr < ptrEnd) + { + //cast the pointer to be a TThreadListEntry object + TThreadListEntry& entry = *(TThreadListEntry*)ptr; + //use the TThreadListEntry pointer, i.e. + TUint16 nameLength = entry.iNameLength; + TPtr name(&(entry.iName[0]), nameLength, nameLength); + // move ptr on to point to the next TThreadListEntry object + ptr += Align4(entry.GetSize()); + } +@endcode +*/ +class TThreadListEntry + { +public: + TInt GetSize() const; +public: + /** + Thread ID + */ + TUint64 iThreadId; + /** + Process ID + */ + TUint64 iProcessId; + /** + Address of the base of the supervisor stack + */ + TUint32 iSupervisorStackBase; + /** + Size of the supervisor stack + */ + TUint32 iSupervisorStackSize; + /** + Non-zero if iSupervisorStackBase has been set correctly + */ + TUint8 iSupervisorStackBaseValid; + /** + Non-zero if iSupervisorStackSize has been set correctly + */ + TUint8 iSupervisorStackSizeValid; + /** + Address of the thread's supervisor stack pointer + */ + TUint32 iSupervisorStackPtr; + /** + Indicator of whether the value returned as iSupervisorStackPtr is valid. + It is necessary, but not necessarily sufficient, that the thread be suspended + for a valid value to be returned. This may be removed from the final API and + the value would be extracted instead via the ReadRegisters type calls. + */ + TRegisterFlag iSupervisorStackPtrValid; + /** Currently unused element. May be used in future to aid maintaining compatibility. */ + TUint32 iSpare1; + /** Currently unused element. May be used in future to aid maintaining compatibility. */ + TUint32 iSpare2; + /** + The length of the thread's name + */ + TUint16 iNameLength; + /** + First two bytes of the thread's name, the name should be considered to + extend past the end of the TThreadListEntry structure to a length + corresponding to iNameLength + */ + TUint16 iName[1]; + }; + +/** +Returns the size of the TThreadListEntry, including the name length + +@return the size, in bytes, of the TExecutablesListEntry and the thread's name +*/ +inline TInt TThreadListEntry::GetSize() const + { + return sizeof(TThreadListEntry) - sizeof(iName) + (2 * iNameLength); + } + +/** +Denotes which list type to return from a RSecuritySvrSession::GetList() call + +@see RSecuritySvrSession::GetList() +*/ +enum TListId + { + /** + Indicates that the GetList() call should return a list of the processes in + the system. The returned buffer will contain an array of 4-byte aligned + TProcessListEntry objects. + + @see TProcessListEntry + */ + EProcesses = 0, + /** + Indicates that the GetList() call should return a list of the threads in + the system. The returned buffer will contain an array of 4-byte aligned + TThreadListEntry objects. + + @see TThreadListEntry + */ + EThreads = 1, + /** + Indicates that the GetList() call should return a list of the code segments in + the system. The returned buffer will contain an array of 4-byte aligned + TCodeSegListEntry objects. + + @see TCodeSegListEntry + */ + ECodeSegs = 2, + /** + Indicates that the GetList() call should return a list of the XIP libraries in + the system. The returned buffer will contain an array of 4-byte aligned + EXipLibraries objects. + + @see EXipLibraries + */ + EXipLibraries = 3, + /** + Indicates that the GetList() call should return a list of the executables in + the system. The returned buffer will contain an array of 4-byte aligned + EExecutables objects. + + @see EExecutables + */ + EExecutables = 4, + /** + Indicates that the GetList() call should return a list of the logical devices in the system. + */ + ELogicalDevices = 5, + /** + Indicates that the GetList() call should return a list of the mutexes in the system. + */ + EMutexes = 6, + /** + Indicates that the GetList() call should return a list of the servers in the system. + */ + EServers = 7, + /** + Indicates that the GetList() call should return a list of the sessions in the system. + */ + ESessions = 8, + /** + Indicates that the GetList() call should return a list of the semaphores in the system. + */ + ESemaphores = 9, + /** + Indicates that the GetList() call should return a list of the chunks in the system. + */ + EChunks = 10, + + /** + Provides a complete list of all the breakpoints in the system and their + current state. + + @see EBreakpoints + */ + EBreakpoints = 11, + + /** + The following are for the possible use of kernel-side debug and SMP breakpoint + manipulation. + */ + ESetBreak = 12, + ERemoveBreak = 13, + EModifyBreak = 14, + + /** + * Provides static information of the system + */ + EStaticInfo = 15, + + /** Last listing enum. */ + EListLast + }; + +/** + Bit field values denoting the scope of a listing. + + In the debug functionality block, the TTag::iValue element which is returned for a listing tag + should be considered as a union of the supported values from this enumeration for that listing. + */ +enum TListScope + { + EScopeNone = 0x0, /**< Corresponds to no scope for a listing. equivalent to not supported */ + EScopeGlobal= 0x1, /**< Corresponds to a global scope for a listing. */ + EScopeProcessSpecific = 0x2, /**< Corresponds to a process specific scope for a listing. */ + EScopeThreadSpecific = 0x4 /**< Corresponds to a thread specific scope for a listing. */ + }; + +/** +@internalComponent + +Interface constructor for passing IPC data for the GetList call. +*/ +class TListDetails + { +public: + TListDetails(const TListId aListId, const TListScope aListScope, TUint64 aTargetId=0) + : iListId(aListId), + iListScope(aListScope), + iTargetId(aTargetId) {} +public: + TListId iListId; + TListScope iListScope; + TUint64 iTargetId; + }; + +/** Debug Security Server Secure ID */ +const TUid KUidDebugSecurityServer = { 0x102834E2 }; + +} // end of Debug namespace declaration + +// the remaining functionality in this file is intended for use on user side only +#ifndef __KERNEL_MODE__ + +#include + +// API definition for Debug namespace appears elsewhere in this file. +namespace Debug { + +/** The name of the Debug Security Server. */ +_LIT(KSecurityServerName,"DebugSecurityServer"); + +/** Wildcard used for attach all calls */ +_LIT(KStar, "*"); + +// A version must be specified when creating a session with the server +/** The Debug Security Server's major version number. */ +const TUint KDebugServMajorVersionNumber=2; +/** The Debug Security Server's minor version number. */ +const TUint KDebugServMinorVersionNumber=5; +/** The Debug Security Server's patch version number. */ +const TUint KDebugServPatchVersionNumber=0; + +/** +Denotes how memory should be accessed +*/ +enum TAccess + { + EAccess8 = 1, /**< Currently unsupported, signifies 8 bit access. */ + EAccess16 = 2, /**< Currently unsupported, signifies 16 bit access. */ + EAccess32 = 4 /**< Signifies 32 bit access. */ + }; + +/** +Denotes how data should be interpreted +*/ +enum TEndianess + { + EEndLE8 = 0, /**< Signifies 8 bit little-endian. */ + EEndBE8 = 1, /**< Currently unsupported, signifies 8 bit big-endian. */ + EEndBE32 = 2 /**< Currently unsupported, signifies 32 bit big-endian. */ + }; + +/** +Structure used to store information about a memory operation + +@internalComponent +*/ +class TMemoryInfo + { +public: + + TMemoryInfo(TUint32 aAddress=0, TUint32 aLength=0, TAccess aAccess=EAccess32, TEndianess aEndianess=EEndLE8) + : iAddress(aAddress), + iSize(aLength), + iAccess(aAccess), + iEndianess(aEndianess) + {} + +public: + + /** + Address to start reading/writing memory + */ + TUint32 iAddress; + /** + Number of bytes of memory to read/write + */ + TUint32 iSize; + /** + Access size for read/write + @see TAccess + */ + TAccess iAccess; + /** + Endianess to interpret data as + @see TEndianess + */ + TEndianess iEndianess; + }; + +/** +@internalComponent +*/ +class TBreakInfo + { +public: + TUint32 iAddress; + TArchitectureMode iArchitectureMode; + }; + +/** +@internalComponent + +Function codes (opcodes) used in message passing between client and server +in this header file and what arguments should be passed with each of these +*/ +enum TDebugServRqst + { + EDebugServOpen = 1, + EDebugServClose = 2, + EDebugServSuspendThread = 3, + EDebugServResumeThread = 4, + EDebugServReadMemory = 5, + EDebugServWriteMemory = 6, + EDebugServSetBreak = 7, + EDebugServClearBreak = 8, + EDebugServModifyBreak = 9, + EDebugServGetEvent = 10, + EDebugServCancelGetEvent = 11, + EDebugServAttachExecutable = 12, + EDebugServDetachExecutable = 13, + EDebugServGetDebugFunctionalityBufSize = 14, + EDebugServGetDebugFunctionality = 15, + EDebugServReadRegisters = 16, + EDebugServWriteRegisters = 17, + EDebugServSetEventAction = 18, + EDebugServBreakInfo = 19, + EDebugServGetList = 20, + EDebugServStep = 21, + EDebugServSetProcessBreak = 22, + EDebugServProcessBreakInfo = 23, + EDebugServKillProcess = 24, + EDebugServModifyProcessBreak = 25, + EDebugServReadCrashFlash = 26, + EDebugServWriteCrashFlash = 27, + EDebugServEraseCrashFlash = 28, + EDebugServEraseEntireCrashFlash = 29, + EDebugServAttachAll = 30, + EDebugServDetachAll = 31, + }; + +/** +Client side API to debug security server (DSS). Interaction with the DSS should +be conducted through this class only. +*/ +class RSecuritySvrSession : public RSessionBase + { +public: + RSecuritySvrSession(); + TVersion Version() const; + + TInt AttachExecutable(const TDesC& aProcessName, TBool aPassive); + TInt DetachExecutable(const TDesC& aProcessName); + + TInt GetDebugFunctionalityBufSize(TUint32* aBufSize); + TInt GetDebugFunctionality(TDes8& aBuffer); + + TInt SuspendThread(const TThreadId aThreadId); + TInt ResumeThread(const TThreadId aThreadId); + + TInt ReadMemory(const TThreadId aThreadId, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData, const TAccess aAccessSize, const TEndianess aEndianess); + TInt WriteMemory(const TThreadId aThreadId, const TUint32 aAddress, const TUint32 aLength, const TDesC8 &aData, const TAccess aAccessSize, const TEndianess aEndianess); + + TInt ReadRegisters(const TThreadId aThreadId, const TDesC8& aRegisterIds, TDes8& aRegisterValues, TDes8& aRegisterFlags); + TInt WriteRegisters(const TThreadId aThreadId, const TDesC8& aRegisterIds, const TDesC8& aRegisterValues, TDes8& aRegisterFlags); + + void GetEvent(const TDesC& aExecutableName, TRequestStatus &aStatus, TDes8& aEventInfo); + TInt CancelGetEvent(const TDesC& aExecutableName); + + TInt SetEventAction(const TDesC& aExecutableName, TEventType aEvent, TKernelEventAction aEventAction); + + TInt SetBreak( TBreakId &aId, const TThreadId aThreadId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode); + TInt ClearBreak(const TBreakId aBreakId); + TInt ModifyBreak(const TBreakId aBreakId, const TThreadId aThreadId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode); + TInt BreakInfo(const TBreakId aBreakId, TThreadId& aThreadId, TUint32& aAddress, TArchitectureMode& aMode); + TInt SetProcessBreak( TBreakId &aId, const TProcessId aProcessId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode); + TInt ProcessBreakInfo(const TBreakId aBreakId, TProcessId& aProcessId, TUint32& aAddress, TArchitectureMode& aMode); + TInt ModifyProcessBreak(const TBreakId aBreakId, const TProcessId aProcessId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode); + + TInt GetList(const TListId aListId, TDes8& aListData, TUint32& aDataSize); + TInt GetList(const TThreadId aThreadId, const TListId aListId, TDes8& aListData, TUint32& aDataSize); + TInt GetList(const TProcessId aProcessId, const TListId aListId, TDes8& aListData, TUint32& aDataSize); + TInt Step(const TThreadId aThreadId, TUint32 aNumSteps); + TInt KillProcess(const TProcessId aProcessId, const TInt aReason); + TInt ReadCrashLog(const TUint32 aPos, TDes8& aData, const TUint32 aDataSize); + TInt WriteCrashConfig(const TUint32 aPos, const TDesC8& aBuffer, TUint32& aSize); + TInt EraseCrashLog(const TUint32 aPos, const TUint32 aBlockNumber); + TInt EraseCrashFlashPartition(); + + TInt Connect(const TVersion aVersion); + + // Added in version 2.5 + TInt AttachAll(); + TInt DetachAll(); + void GetEvent(TRequestStatus &aStatus, TDes8& aEventInfo); + TInt CancelGetEvent(); + TInt SetEventAction(TEventType aEvent, TKernelEventAction aEventAction); + +private: + TInt StartServer(void); + }; + +/** +Server session constructor +*/ +inline RSecuritySvrSession::RSecuritySvrSession() + { + } + +/** +Called by a client to create a session with the DSS. This method starts the +DSS if it is not running, or connects to it if it already exists. + +@param aVersion version of the DSS to connect to + +@return KErrNone if a connection was successfully created, or one of the other +system wide error codes +*/ +inline TInt RSecuritySvrSession::Connect(const TVersion aVersion) + { + // Default asynch outstanding message slots for the server. Not that these are + // allocated from a system-wide pool of 255, so have to be careful with resources. + const TUint KDefaultMessageSlots = 8; + + TInt retry=2; + for (;;) + { + TInt r=CreateSession(KSecurityServerName, aVersion, KDefaultMessageSlots); + if (r!=KErrNotFound && r!=KErrServerTerminated) + { + return r; + } + if (--retry==0) + { + return r; + } + r=StartServer(); + if (r!=KErrNone && r!=KErrAlreadyExists) + { + return r; + } + } + } + +/** + Start the server + + @return KErrNone on success, or one of the other system wide error codes + */ +inline TInt RSecuritySvrSession::StartServer() + { + // constants for the server + _LIT(KSecurityServerProcessName, "rm_debug_svr"); + const TUidType serverUid(KNullUid, KNullUid, KUidDebugSecurityServer); + + RProcess server; + TInt err = server.Create(KSecurityServerProcessName, KNullDesC, serverUid); + + if(KErrNone != err) + { + return err; + } + + // Synchronise with the process to make sure it hasn't died straight away + TRequestStatus stat; + server.Rendezvous(stat); + if (stat != KRequestPending) + { + // logon failed - server is not yet running, so cannot have terminated + server.Kill(0); // Abort startup + } + else + { + // logon OK - start the server + server.Resume(); + } + + // Wait to synchronise with server - if it dies in the meantime, it + // also gets completed + User::WaitForRequest(stat); + + // We can't use the 'exit reason' if the server panicked as this + // is the panic 'reason' and may be '0' which cannot be distinguished + // from KErrNone + err = (server.ExitType()==EExitPanic) ? KErrGeneral : stat.Int(); + server.Close(); + return err; + } + +/** +Get version of RSecuritySvrSession + +@return a TVersion object specifying the version +*/ +inline TVersion RSecuritySvrSession::Version(void) const + { + return (TVersion(KDebugServMajorVersionNumber, KDebugServMinorVersionNumber, KDebugServPatchVersionNumber)); + } + +/** +Suspends execution of the specified thread. + +@param aThreadId thread ID of the thread to suspend + +@return KErrNone if there were no problems, KErrPermissionDenied if security + check fails or KErrArgument if the thread does not exist +*/ +inline TInt RSecuritySvrSession::SuspendThread(const TThreadId aThreadId) + { + TPckgBuf threadIdPckg(aThreadId); + TIpcArgs args(&threadIdPckg); + + return SendReceive(EDebugServSuspendThread, args); + } + +/** +Resumes execution of the specified thread. + +@param aThreadId thread ID of the thread to resume + +@return KErrNone if there were no problems, KErrPermissionDenied if security + check fails or KErrArgument if the thread does not exist +*/ +inline TInt RSecuritySvrSession::ResumeThread(const TThreadId aThreadId) + { + TPckgBuf threadIdPckg(aThreadId); + TIpcArgs args(&threadIdPckg); + + return SendReceive(EDebugServResumeThread, args); + } + +/** +Purpose: +Set a thread-specific breakpoint in an attached process. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. + +@param aThreadId The thread id to which the breakpoint will apply. +@param aAddress The virtual memory address at which to place the breakpoint. +@param aArchitectureMode The kind of breakpoint which is to be set (e.g. ARM/Thumb/Thumb2EE) +@param aBreakId The address to which the assigned breakpoint ID will be written by this function +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::SetBreak( TBreakId &aBreakId,const TThreadId aThreadId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode) + { + TPtr8 breakIdPtr((TUint8*)&aBreakId, sizeof(aBreakId)); + + TPckgBuf threadIdPckg(aThreadId); + + TBreakInfo breakInfo; + breakInfo.iAddress = aAddress; + breakInfo.iArchitectureMode = aArchitectureMode; + TPckgBuf breakInfoPckg(breakInfo); + + //call driver to attempt to set break + TIpcArgs args(&threadIdPckg, &breakInfoPckg, &breakIdPtr); + return SendReceive(EDebugServSetBreak, args); + } + +/** +Purpose: +Clears a previously set thread-specific or process-specific breakpoint. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. + +@param aBreakId The TBreakId returned by a prior SetBreak call. Must have been set by the same Debug Agent. +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::ClearBreak(const TBreakId aBreakId) + { + TIpcArgs args(aBreakId); + return SendReceive(EDebugServClearBreak, args); + } + +/** +Purpose: +Modifies the properties of a previously set breakpoint. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. + +@param aBreakId the TBreakId returned by a prior SetBreak() call. Must have been set by the same Debug Agent. +@param aThreadId the thread id of the thread to move the breakpoint to +@param aAddress the virtual memory address at which to place the breakpoint. +@param aArchitectureMode the kind of breakpoint which is to be set (e.g. ARM/Thumb/Thumb2EE) +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::ModifyBreak(const TBreakId aBreakId, const TThreadId aThreadId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode) + + { + TPckgBuf threadIdPckg(aThreadId); + TIpcArgs args(aBreakId,&threadIdPckg,aAddress,aArchitectureMode); + return SendReceive(EDebugServModifyBreak, args); + } + +/** +Purpose: +Modifies the properties of a previously set process breakpoint. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. + +@param aBreakId the TBreakId returned by a prior SetBreak() call. Must have been set by the same Debug Agent. +@param aProcessId the process id of the process to move the breakpoint to +@param aAddress the virtual memory address at which to place the breakpoint. +@param aArchitectureMode the kind of breakpoint which is to be set (e.g. ARM/Thumb/Thumb2EE) +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::ModifyProcessBreak(const TBreakId aBreakId, const TProcessId aProcessId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode) + + { + TPckgBuf processIdPckg(aProcessId); + TIpcArgs args(aBreakId,&processIdPckg,aAddress,aArchitectureMode); + return SendReceive(EDebugServModifyProcessBreak, args); + } + +/** +Purpose: +Returns the properties associated with a given TBreakId. The supplied break id must previously have been allocated +to the debug agent by a SetBreak() call. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. +@pre The aBreakId must have been previously returned by a SetBreak() call and not subsequently cleared by ClearBreak(). + +@param aBreakId the TBreakId returned by a prior SetBreak() call. Must have been set by the same Debug Agent. +@param aAddress on return contains the virtual memory address of the breakpoint +@param aThreadId on return contains the thread id of the thread that the breakpoint is set in +@param aMode on return contains the type of this breakpoint (e.g. ARM/Thumb/Thumb2EE) +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::BreakInfo(const TBreakId aBreakId, TThreadId& aThreadId, TUint32& aAddress, TArchitectureMode& aMode) + { + // temporary descriptors + TPtr8 threadId((TUint8*)&aThreadId,0,sizeof(TThreadId)); + TPtr8 address((TUint8*)&aAddress,0,sizeof(TUint32)); + TPtr8 mode((TUint8*)&aMode,0,sizeof(TArchitectureMode)); + + TIpcArgs args(aBreakId,&threadId,&address,&mode); + return SendReceive(EDebugServBreakInfo, args); + } + +/** +Purpose: +Set a process-specific breakpoint in an attached process. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. + +@param aProcessId The process id to which the breakpoint will apply. +@param aAddress The virtual memory address at which to place the breakpoint. +@param aArchitectureMode The kind of breakpoint which is to be set (e.g. ARM/Thumb/Thumb2EE) +@param aBreakId The address to which the assigned breakpoint ID will be written by this function +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::SetProcessBreak( TBreakId &aBreakId, const TProcessId aProcessId, const TUint32 aAddress, const TArchitectureMode aArchitectureMode) + { + TPtr8 breakIdPtr((TUint8*)&aBreakId, sizeof(aBreakId)); + + TPckgBuf threadIdPckg(aProcessId); + + TBreakInfo breakInfo; + breakInfo.iAddress = aAddress; + breakInfo.iArchitectureMode = aArchitectureMode; + TPckgBuf breakInfoPckg(breakInfo); + + //call driver to attempt to set break + TIpcArgs args(&threadIdPckg, &breakInfoPckg, &breakIdPtr); + return SendReceive(EDebugServSetProcessBreak, args); + } + +/** +Purpose: +Returns the properties associated with a given TBreakId. The supplied break id must previously have been allocated +to the debug agent by a SetProcessBreak() call. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. +@pre The aBreakId must have been previously returned by a SetProcessBreak() call and not subsequently cleared by ClearBreak(). + +@param aBreakId the TBreakId returned by a prior SetBreak() call. Must have been set by the same Debug Agent. +@param aAddress on return contains the virtual memory address of the breakpoint +@param aThreadId on return contains the thread id of the thread that the breakpoint is set in +@param aMode on return contains the type of this breakpoint (e.g. ARM/Thumb/Thumb2EE) +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::ProcessBreakInfo(const TBreakId aBreakId, TProcessId& aProcessId, TUint32& aAddress, TArchitectureMode& aMode) + { + // temporary descriptors + TPtr8 processId((TUint8*)&aProcessId,0,sizeof(TProcessId)); + TPtr8 address((TUint8*)&aAddress,0,sizeof(TUint32)); + TPtr8 mode((TUint8*)&aMode,0,sizeof(TArchitectureMode)); + + TIpcArgs args(aBreakId,&processId,&address,&mode); + return SendReceive(EDebugServProcessBreakInfo, args); + } + +/** +Purpose: +Wait for an event to occur to the target executable being debugged. When an event +occurs, the TRequestStatus is completed. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. + +Note 1: Events are reported on a per-executable basis, not per-thread. + +Note 2: All the parameters must remain in scope until either CancelGetEvent is called, or +until the request is completed. In practice, this generally +means these parameters should not be based on the stack, as they may go out of +scope before the call completes. + +Note 3: Errors are signalled by completing aStatus + +@param aExecutableName The name of any executable to which the Debug Agent is attached. +@param aStatus Debug Agent request status variable. +@param aEventInfo Descriptor containing a TEventInfo object. + +*/ +inline void RSecuritySvrSession::GetEvent(const TDesC& aExecutableName, TRequestStatus &aStatus, TDes8& aEventInfo) + { + TIpcArgs args(&aExecutableName, &aEventInfo); + + SendReceive(EDebugServGetEvent, args, aStatus ); + + } + +/** +Purpose: +Cancel a previously issued asynchronous RSecuritySvrSession::GetEvent call. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent should have called AttachExecutable and GetEvent for the same executable + +@param aExecutableName The name of the executable being debugged. +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::CancelGetEvent(const TDesC& aExecutableName) +{ + TIpcArgs args(&aExecutableName); + + return SendReceive(EDebugServCancelGetEvent,args); +} + + +/** +Purpose: +Wait for an event to occur from any process. When an event +occurs, the TRequestStatus is completed. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must have called AttachAll. + +Note 1: Events are reported on a FIFO basis + +Note 2: All the parameters must remain in scope until either CancelGetEvent is called, or +until the request is completed. In practice, this generally +means these parameters should not be based on the stack, as they may go out of +scope before the call completes. + +Note 3: Errors are signalled by completing aStatus + +@param aStatus Debug Agent request status variable. +@param aEventInfo Descriptor containing a TEventInfo object. + +*/ +inline void RSecuritySvrSession::GetEvent(TRequestStatus &aStatus, TDes8& aEventInfo) + { + TIpcArgs args(&KStar, &aEventInfo); + + SendReceive(EDebugServGetEvent, args, aStatus ); + } + +/** +Purpose: +Cancel a previously issued asynchronous RSecuritySvrSession::GetEvent call. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent should have called AttachAll and GetEvent + +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::CancelGetEvent() + { + TIpcArgs args(&KStar); + + return SendReceive(EDebugServCancelGetEvent,args); + } + + +/** +Called by a debug agent to request debug privileges for the executable with +file name aExecutableName. + +@param aExecutableName a fully qualified file name of the executable to attach to +@param aPassive if true then the agent has reduced debug rights. + +@return KErrNone if attached successfully, one of the other system wide error + codes otherwise +*/ +inline TInt RSecuritySvrSession::AttachExecutable(const TDesC& aExecutableName, TBool aPassive) + { + TIpcArgs args((TInt)aPassive, &aExecutableName); + return SendReceive(EDebugServAttachExecutable, args); + } + +/** +Called by a debug agent to detach from the executable with file +name aExecutableName. + +@param aExecutableName the fully qualified file name of the executable to detach from + +@return KErrNone if detached successfully, one of the other system wide error + codes otherwise +*/ +inline TInt RSecuritySvrSession::DetachExecutable(const TDesC& aExecutableName) + { + TIpcArgs args(&aExecutableName); + return SendReceive(EDebugServDetachExecutable, args); + } + +/** +Called by a debug agent to attach to events from all processes + +@return KErrNone if attached successfully, one of the other system wide error + codes otherwise +*/ +inline TInt RSecuritySvrSession::AttachAll() + { + return SendReceive(EDebugServAttachAll); + } + +/** +Called by a debug agent to detach from all events from all processes + +@return KErrNone if detached successfully, one of the other system wide error + codes otherwise +*/ +inline TInt RSecuritySvrSession::DetachAll() + { + return SendReceive(EDebugServDetachAll); + } + +/** +Get buffer size required to contain Functionality text block. + +@see in-source documentation in rm_debug_api.h + +@param aBufSize function will fill this with the required buffer size + +@return KErrNone if the call succeeded, or one of the other system wide error + codes if the call failed +*/ +inline TInt RSecuritySvrSession::GetDebugFunctionalityBufSize(TUint32 *aBufSize) + { + TInt res = KErrNone; + + TPtr8 stuff((TUint8*)aBufSize,4, 4); + + TIpcArgs args(&stuff); + + res = SendReceive(EDebugServGetDebugFunctionalityBufSize, args); + + return res; + } + +/** +Get debug functionality text block and place it into aBuffer. + +The debug functionality block (DFBlock) is used to provide information about the functionality +(i.e. features) which are supported by the rm_debug.ldd device driver. + +Calling this function with a suitably sized buffer aBuffer will result in the debug +functionality information being stored in aBuffer. The necessary size of aBuffer can +be determined by calling DebugFunctionalityBufSize(). + +The format of the DFBlock is: + +@code +Sub-block 0 +Sub-block 1 +... +Sub-block N-1 +@endcode + +The data which will be returned by a call to GetDebugFunctionality() is constant so is +guaranteed to fit exactly into the aBuffer allocated, assuming that the size of aBuffer +corresponds to the value returned from GetDebugFunctionalityBufSize(). + +Each sub-block is composed of a TTagHeader object followed by a C-style array of TTag objects. +The sub-block contains information about a particular aspect of the debug sub-system, for example +information about the manner in which memory can be accessed. +The TTagHeader is comprised of an identifier which determines the type of data +it contains, together with the number of TTag elements in the array following the TTagHeader. +Each TTag in a sub-block has a unique ID, stored in the TTag::iTagId member variable. + +The only sub-block that is guaranteed to exist has TTagHeader::iTagHdrId = ETagHeaderIdCore, all other +sub-blocks are optional. The ETagHeaderIdCore sub-block is the first sub-block within the DFBlock. +Other sub-blocks may appear in any order after the ETagHeaderIdCore sub-block. + +The following is a diagrammatic representation of a sub-block the DFBlock: + +@code +The HHHH represents the tag header ID of a sub-block (TTagHeader::iTagHdrId) +The NNNN represents the number of TTag elements in the sub-block (TTagHeader::iNumTags) +The IIIIIIII represents the ID of the TTag (TTag::iTagId) +The TTTT represents the type of the TTag (TTag::iType) +The SSSS represents the size of the TTag's associated data (TTag::iSize) +The VVVVVVVV represents the TTag's value (TTag::iValue) + +0xNNNNHHHH TTagHeader element for first sub-block (has N1 TTag elements) +0xIIIIIIII \ +0xSSSSTTTT -- TTag 0 +0xVVVVVVVV / +0xIIIIIIII \ +0xSSSSTTTT -- TTag 1 +0xVVVVVVVV / +... +0xIIIIIIII \ +0xSSSSTTTT -- TTag N1 - 1 +0xVVVVVVVV / +0xNNNNHHHH TTagHeader element for second sub-block (has N2 TTag elements) +0xIIIIIIII \ +0xSSSSTTTT -- TTag 0 +0xVVVVVVVV / +... +0xIIIIIIII \ +0xSSSSTTTT -- TTag N2 - 1 +0xVVVVVVVV / +... +0xNNNNHHHH TTagHeader element for last sub-block (has NX TTag elements) +0xIIIIIIII \ +0xSSSSTTTT -- TTag 0 +0xVVVVVVVV / +... +0xIIIIIIII \ +0xSSSSTTTT -- TTag NX - 1 +0xVVVVVVVV / +@endcode + +The following example DFBlock contains two sub-blocks (values taken from enums below): +- ETagHeaderIdCore +- ETagHeaderIdMemory + +@code +Binary Meaning Value + +0x000A0000 iTagHdrId, iNumTags ETagHeaderIdCore, ECoreLast +0x00000000 iTagId ECoreEvents +0x00000000 iType, iSize ETagTypeBoolean, 0 +0x00000001 iValue ETrue +0x00000001 iTagId ECoreStartStop +0x00000000 iType, iSize ETagTypeBoolean, 0 +0x00000001 iValue ETrue +... +0x00000008 iTagId ECoreHardware +0x00000000 iType, iSize ETagTypeBoolean, 0 +0x00000000 iValue EFalse +0x00000009 iTagId ECoreApiConstants +0x00000000 iType, iSize ETagTypeBoolean, 0 +0x00000001 iValue ETrue + +0x000A0001 iTagHdrId, iNumTags ETagHeaderIdMemory, EMemoryLast +0x00000000 iTagId EMemoryRead +0x00000000 iType, iSize ETagTypeBoolean, 0 +0x00000001 iValue ETrue +0x00000001 iTagId EMemoryWrite +0x00000000 iType, iSize ETagTypeBoolean, 0 +0x00000001 iValue ETrue +... +0x00000008 iTagId EMemoryLE8 +0x00000000 iType, iSize ETagTypeBoolean, 0 +0x00000001 iValue ETrue +0x00000009 iTagId EMemoryMaxBlockSize +0x00000001 iType, iSize ETagTypeTUint32, 0 +0x00004000 iValue 0x4000 +@endcode + +- Debug Agent DFBlock Processing: + +Debug Agents MUST understand and process the ETagHeaderIdCore block. The other +blocks may be ignored if not recognised. Tags within each block may be ignored if +not recognised. + +@pre aBuffer.MaxLength() >= *aBufSize where aBufSize is set by a call to: + RSecuritySvrSession::GetDebugFunctionalityBufSize(TUint32 *aBufSize) + +@param aBuffer buffer to store functionality block in + +@return KErrNone if call succeeded, + KErrNoMemory if temporary memory could not be allocated, + KErrGeneral if debug functionality block could not be accessed +*/ +inline TInt RSecuritySvrSession::GetDebugFunctionality(TDes8& aBuffer) + { + TIpcArgs args(&aBuffer); + + TInt res = KErrNone; + + res = SendReceive(EDebugServGetDebugFunctionality, args); + + return res; + } + +/** +Read a block of memory from the target debug thread defined by aThreadId. + +@pre the client should attach to the process containing the target thread +@pre aData.MaxLength() >= aLength + +@param aThreadId thread ID of the thread to read memory from +@param aAddress address to start reading memory from +@param aLength number of bytes of memory to read +@param aData descriptor to read memory into +@param aAccessSize access size for memory reads, default is TAccess::EAccess32 +@param aEndianess interpretation of endianess of target data, default is + TEndianess::EEndLE8 + +@return KErrNone if memory read successfully, or one of the other system wide error codes +*/ +inline TInt RSecuritySvrSession::ReadMemory(const TThreadId aThreadId, const TUint32 aAddress, const TUint32 aLength, TDes8 &aData, const TAccess aAccessSize, const TEndianess aEndianess) + { + TPckgBuf threadIdPckg(aThreadId); + //set up memory info object + TMemoryInfo memoryInfo; + memoryInfo.iAddress = aAddress; + memoryInfo.iSize = aLength; + memoryInfo.iAccess = aAccessSize; + memoryInfo.iEndianess = aEndianess; + + TPckgBuf pckg(memoryInfo); + + TIpcArgs args(&threadIdPckg, &pckg, &aData); + + return SendReceive(EDebugServReadMemory, args); + } + +/** +Write a block of memory to the target debug thread defined by aThreadId. + +@pre the client should attach non-passively to the process containing the + target thread + +@param aThreadId thread ID of the thread to write memory to +@param aAddress address to start writing memory at +@param aLength number of bytes of memory to write +@param aData descriptor to read memory from +@param aAccessSize access size for memory writes, default is TAccess::EAccess32 +@param aEndianess interpretation of endianess of target data, default is + TEndianess::EEndLE8 + +@return KErrNone if memory written successfully, or one of the other system wide error codes +*/ +inline TInt RSecuritySvrSession::WriteMemory(const TThreadId aThreadId, const TUint32 aAddress, const TUint32 aLength, const TDesC8 &aData, const TAccess aAccessSize, const TEndianess aEndianess) + { + TPckgBuf threadIdPckg(aThreadId); + //create memory info object + TMemoryInfo memoryInfo; + memoryInfo.iAddress = aAddress; + memoryInfo.iSize = aLength; + memoryInfo.iAccess = aAccessSize; + memoryInfo.iEndianess = aEndianess; + + TPckgBuf pckg(memoryInfo); + + TIpcArgs args(&threadIdPckg, &pckg, &aData); + + return SendReceive(EDebugServWriteMemory, args); + } + +/** +Read register values from the thread with thread ID aThreadId. The IDs of the +registers to read are stored as an array of TRegisterInfo objects in +aRegisterIds. If the nth register requested could be read then the value of the +register will be appended to aRegisterValues and EValid stored at +offset n in aRegisterFlags. If the register is supported but could not be read +then EInValid will be stored at offset n in aRegisterFlags and arbitrary data +appended in aRegisterValues. If reading the specified register is not +supported by the kernel then ENotSupported will be stored at offset n in +aRegisterFlags and arbitrary data appended to aRegisterValues. If an unknown +register is specified then EUnknown will be put in aRegisterFlags and +arbitrary data placed in aRegisterValues. + +@pre the client should attach to the process containing the target thread + +@see the register ID format is defined in: + SGL.TS0028.027 - Symbian Core Dump File Format v1.0.doc + +@param aThreadId thread ID of the thread to read register values from +@param aRegisterIds descriptor containing array of TFunctionalityRegister defined + register IDs +@param aRegisterValues descriptor to contain register values +@param aRegisterFlags descriptor containing array of TUint8 flags, with values + taken from TRegisterFlag + +@return KErrNone if registers were read successfully, or one of the other system wide error codes +*/ +inline TInt RSecuritySvrSession::ReadRegisters(const TThreadId aThreadId, const TDesC8& aRegisterIds, TDes8& aRegisterValues, TDes8& aRegisterFlags) + { + TPckgBuf threadIdPckg(aThreadId); + TIpcArgs args(&threadIdPckg, &aRegisterIds, &aRegisterValues, &aRegisterFlags); + + return SendReceive(EDebugServReadRegisters, args); + } + +/** +Write register values to the thread with thread ID aThreadId. The IDs of the +registers to write are stored as an array of TRegisterInfo objects in +aRegisterIds. The values to put in the registers are stored as an array of +objects in aRegisterValues. If the nth register to write could be +written then EValid stored at offset n in aRegisterFlags. If the register is +supported but could not be written then EInValid will be stored at offset n in +aRegisterFlags. If writing to the specified register is not supported by the +kernel then ENotSupported will be stored at offset n in aRegisterFlags. If an +unknown register is specified then EUnknown will be put in aRegisterFlags. + +@pre the client should attach non-passively to the process containing the + target thread + +@see the register ID format is defined in: + SGL.TS0028.027 - Symbian Core Dump File Format v1.0.doc + +@param aThreadId thread ID of the thread to write register values to +@param aRegisterIds descriptor containing array of TFunctionalityRegister defined + register IDs +@param aRegisterValues descriptor containing array of register values +@param aRegisterFlags descriptor containing array of TUint8 flags, with values + taken from TRegisterFlag + +@return KErrNone if registers were written successfully, or one of the other system wide error codes +*/ +inline TInt RSecuritySvrSession::WriteRegisters(const TThreadId aThreadId, const TDesC8& aRegisterIds, const TDesC8& aRegisterValues, TDes8& aRegisterFlags) + { + TPckgBuf threadIdPckg(aThreadId); + TIpcArgs args(&threadIdPckg, &aRegisterIds, &aRegisterValues, &aRegisterFlags); + + return SendReceive(EDebugServWriteRegisters, args); + } + +/** +Purpose: +Set the requisite actions to be taken when a particular event occurs. +The events are defined in Debug::TEventType and the +actions are defined in Debug::TKernelEventAction. + +The default action for all events is EActionIgnore. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to the executable specified by aExecutableName. + +Note: Event actions are on a per-executable basis. This is +to ensure that events such as EEventStartThread are notified to the Debug +Agent, even though the debug agent cannot be aware of the existence +of a new thread at the time the event occurs. + +@param aExecutableName The name of the executable to which the Debug Agent is attached. +@param aEvent A TEventType enum defined in rm_debug_api.h:Debug::TEventType +@param aEventAction Any TKernelEventAction permitted by the DFBlock. +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::SetEventAction(const TDesC& aExecutableName, TEventType aEvent, TKernelEventAction aEventAction) +{ + TInt res = KErrNone; + + TIpcArgs args(&aExecutableName,aEvent,aEventAction); + + res = SendReceive(EDebugServSetEventAction, args); + + return res; +} + +/** +Purpose: +Set the requisite actions to be taken when a particular event occurs that is not +associated with any particular process or executable. + +The events are defined in Debug::TEventType and the +actions are defined in Debug::TKernelEventAction. + +The default action for all events is EActionIgnore. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must have called AttachAll. + +@param aEvent A TEventType enum defined in rm_debug_api.h:Debug::TEventType +@param aEventAction Any TKernelEventAction permitted by the DFBlock. +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction) + { + TInt res = KErrNone; + + TIpcArgs args(&KStar, aEvent, aEventAction); + + res = SendReceive(EDebugServSetEventAction, args); + + return res; + } + +/** +Returns a global listing corresponding to the type specified as aListId. The structure +of the returned data depends on the value of aListId, see TListId for details. +If aListData is not large enough to contain the listings data then +the necessary buffer size is stored in aDataSize and the function returns +KErrTooBig. In this case the contents of aListData will not contain useful data. + +Note that if the aListData buffer was too small to hold the data then the value +returned as aDataSize corresponds to the size of the data at that particular +instance. The size of the data will vary over time, for example the thread list +will increase and decrease in size as threads are created and destroyed, so +re-requesting data with a buffer with max length aDataSize will not necessarily +succeed if a list has increased in size between the two calls. + +@see TListId + +@param aListId enum from TListId signifying which type of listing to return +@param aListData buffer provided by the debug agent in which data can be returned by the debug system +@param aDataSize if aListData was not large enough to contain the requested + data then the necessary buffer size is stored in aDataSize. If aListData + was large enough then the value of aDataSize is the length of aListData + +@return KErrNone if data was returned successfully, + KErrTooBig if aListData is too small to hold the data, + one of the other system-wide error codes +*/ +inline TInt RSecuritySvrSession::GetList(const TListId aListId, TDes8& aListData, TUint32& aDataSize) + { + //second argument of ETrue implies a global listing + TListDetails info(aListId, EScopeGlobal); + TPtr8 infoBuf((TUint8*)&info, sizeof(TListDetails), sizeof(TListDetails)); + TPtr8 dataSizeBuf((TUint8*)&aDataSize, sizeof(TUint32), sizeof(TUint32)); + TIpcArgs args(&infoBuf, &aListData, &dataSizeBuf); + return SendReceive(EDebugServGetList, args); + } + +/** +Returns a thread-specific listing corresponding to the type specified as aListId. The structure +of the returned data depends on the value of aListId, see TListId for details. +If aListData is not large enough to contain the listings data then +the necessary buffer size is stored in aDataSize and the function returns +KErrTooBig. In this case the contents of aListData will not contain useful data. + +Note that if the aListData buffer is too small to hold the data then the value +returned as aDataSize corresponds to the size of the data at that particular +instant. The size of the data will vary over time, for example the thread list +will increase and decrease in size as threads are created and destroyed, so +re-requesting data with a buffer with max length aDataSize will not necessarily +succeed if a list has increased in size between the two calls. + +@see TListId + +@param aThreadId thread to return the listing for +@param aListId member of TListId signifying which type of listing to return +@param aListData buffer provided by the debug agent in which data can be returned by the debug system. +@param aDataSize if aListData was not large enough to contain the requested + data then the necessary buffer size is stored in aDataSize. If aListData + was large enough then the value of aDataSize is the length of aListData + +@return KErrNone if data was returned successfully, + KErrTooBig if aListData is too small to hold the data, + one of the other system-wide error codes +*/ +inline TInt RSecuritySvrSession::GetList(const TThreadId aThreadId, const TListId aListId, TDes8& aListData, TUint32& aDataSize) + { + TListDetails info(aListId, EScopeThreadSpecific, aThreadId.Id()); + TPtr8 infoBuf((TUint8*)&info, sizeof(TListDetails), sizeof(TListDetails)); + TPtr8 dataSizeBuf((TUint8*)&aDataSize, sizeof(TUint32), sizeof(TUint32)); + TIpcArgs args(&infoBuf, &aListData, &dataSizeBuf); + return SendReceive(EDebugServGetList, args); + } + +/** +Returns a process-specific listing corresponding to the type specified as aListId. The structure +of the returned data depends on the value of aListId, see TListId for details. +If aListData is not large enough to contain the listings data then +the necessary buffer size is stored in aDataSize and the function returns +KErrTooBig. In this case the contents of aListData will not contain useful data. + +Note that if the aListData buffer is too small to hold the data then the value +returned as aDataSize corresponds to the size of the data at that particular +instant. The size of the data will vary over time, for example the thread list +will increase and decrease in size as threads are created and destroyed, so +re-requesting data with a buffer with max length aDataSize will not necessarily +succeed if a list has increased in size between the two calls. + +@see TListId + +@param aProcessId process to return the listing for +@param aListId member of TListId signifying which type of listing to return +@param aListData buffer provided by the debug agent in which data can be returned by the debug system. +@param aDataSize if aListData was not large enough to contain the requested + data then the necessary buffer size is stored in aDataSize. If aListData + was large enough then the value of aDataSize is the length of aListData + +@return KErrNone if data was returned successfully, + KErrTooBig if aListData is too small to hold the data, + one of the other system-wide error codes +*/ +inline TInt RSecuritySvrSession::GetList(const TProcessId aProcessId, const TListId aListId, TDes8& aListData, TUint32& aDataSize) + { + TListDetails info(aListId, EScopeProcessSpecific, aProcessId.Id()); + TPtr8 infoBuf((TUint8*)&info, sizeof(TListDetails), sizeof(TListDetails)); + TPtr8 dataSizeBuf((TUint8*)&aDataSize, sizeof(TUint32), sizeof(TUint32)); + TIpcArgs args(&infoBuf, &aListData, &dataSizeBuf); + return SendReceive(EDebugServGetList, args); + } + +/** +Purpose: +Step one or more CPU instructions in the specified thread from the current PC. + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. +@pre The thread being stepped must be suspended by the Debug Agent. + +@param aThreadId the id of the thread which is to be stepped +@param aNumSteps how many machine-level instructions are to be stepped. +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::Step(const TThreadId aThreadId, const TUint32 aNumSteps) + { + TPckgBuf threadIdPckg(aThreadId); + TInt res = KErrNone; + + TIpcArgs args(&threadIdPckg,aNumSteps); + + res = SendReceive(EDebugServStep,args); + + return res; + } + +/** +Purpose: +Kill the specified process with the supplied reason. Reason codes are equivalent +to those in RProcess.Kill(). + +@pre Debug Agent must be connected to the debug security server +@pre Debug Agent must be attached to a process. + +@param aProcessId the id of the process which is to be killed +@param aReason The reason to be associated with the ending of this process +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::KillProcess(const TProcessId aProcessId, const TInt aReason) + { + TPckgBuf processIdPckg(aProcessId); + TInt res = KErrNone; + + TIpcArgs args(&processIdPckg,aReason); + + res = SendReceive(EDebugServKillProcess,args); + + return res; + } + +/** +Purpose +Method to read data from the crash flash + +@pre aData buffer to retrieve the data from the crash flash +@pre aDataSize Size of the data + +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::ReadCrashLog(const TUint32 aPos, TDes8& aData, const TUint32 aDataSize) + { + TIpcArgs args(aPos, &aData, aDataSize); + TInt res = SendReceive(EDebugServReadCrashFlash,args); + return res; + } + +/** + * @internalTechnology + * @prototype + * +Purpose: +Method to write the crash flash config + +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::WriteCrashConfig(const TUint32 aPos, const TDesC8& aBuffer, TUint32& aSize) + { + TPtr8 sizePtr((TUint8*)&aSize,4, 4); + TIpcArgs args(aPos, &aBuffer, &sizePtr); + TInt res = SendReceive(EDebugServWriteCrashFlash, args); + return res; + } +/** +Purpose: +Method to erase a block in the crash flash + +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::EraseCrashLog(const TUint32 aPos, const TUint32 aBlockNumber) + { + TIpcArgs args(aPos, aBlockNumber); + TInt res = SendReceive(EDebugServEraseCrashFlash, args); + return res; + } + +/** +Purpose: +Method to erase entire flash partition + +@return Any error which may be returned by RSessionBase::SendReceive() +*/ +inline TInt RSecuritySvrSession::EraseCrashFlashPartition() + { + TInt res = SendReceive(EDebugServEraseEntireCrashFlash); + return res; + } + +} // end of Debug namespace declaration + +#endif // #ifndef __KERNEL_MODE__ + +#endif // RM_DEBUG_API_H + + + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/inc/rm_debug_logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/inc/rm_debug_logging.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,83 @@ +// Copyright (c) 2006-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: +// Logging macros for use in debug subsystem +// +// + +#ifndef RM_DEBUG_LOGGING_H +#define RM_DEBUG_LOGGING_H + +/* Debug messages + * + * Debug messages are only generated for debug builds. + * + * For kernel mode, use __KTRACE_OPT(KDEBUGGER, Kern::Printf(), + * for user mode use RDebug::Printf(). + * + */ + +#ifdef _DEBUG + + #ifdef __KERNEL_MODE__ + + #include + #include + + #define LOG_MSG(args...) __KTRACE_OPT(KDEBUGGER, Kern::Printf(args)) + #define LOG_ENTRY() __KTRACE_OPT(KDEBUGGER, Kern::Printf("+%s", __PRETTY_FUNCTION__)) + #define LOG_EXIT() __KTRACE_OPT(KDEBUGGER, Kern::Printf("-%s", __PRETTY_FUNCTION__)) + #define LOG_ARGS(fmt, args...) __KTRACE_OPT(KDEBUGGER, Kern::Printf("+%s " fmt, __PRETTY_FUNCTION__, args)) + #define LOG_RETURN(x) __KTRACE_OPT(KDEBUGGER, Kern::Printf("Returning %d from [%s]", x, __PRETTY_FUNCTION__) + + // These kept for compatability + #define LOG_MSG2( a, b ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b )) + #define LOG_MSG3( a, b, c ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c )) + #define LOG_MSG4( a, b, c, d ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c, d )) + #define LOG_MSG5( a, b, c, d, e ) __KTRACE_OPT(KDEBUGGER, Kern::Printf( a, b, c, d, e )) + #else + + #include + + #define LOG_MSG(args...) RDebug::Printf(args) + #define LOG_DES(args...) RDebug::Print(args) // For wide descriptors + #define LOG_ENTRY() RDebug::Printf("+%s", __PRETTY_FUNCTION__) + #define LOG_EXIT() RDebug::Printf("-%s", __PRETTY_FUNCTION__) + #define LOG_ARGS(fmt, args...) RDebug::Printf("+%s " fmt, __PRETTY_FUNCTION__, args) + #define LOG_RETURN(x) RDebug::Printf("Returning %d from [%s]", x, __PRETTY_FUNCTION__) + + #define LOG_MSG2( a, b ) RDebug::Printf( a, b ) + #define LOG_MSG3( a, b, c ) RDebug::Printf( a, b, c ) + #define LOG_MSG4( a, b, c, d ) RDebug::Printf( a, b, c, d ) + #define LOG_MSG5( a, b, c, d, e ) RDebug::Printf( a, b, c, d, e ) + + #endif + +#else + + #define LOG_MSG(args...) + #define LOG_DES(args...) + #define LOG_ENTRY() + #define LOG_EXIT() + #define LOG_ARGS(fmt, args...) + #define LOG_RETURN(x) + + #define LOG_MSG2( a, b ) + #define LOG_MSG3( a, b, c ) + #define LOG_MSG4( a, b, c, d ) + #define LOG_MSG5( a, b, c, d, e ) + +#endif + +#endif //RM_DEBUG_LOGGING_H + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/src/c_process_pair.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/src/c_process_pair.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,132 @@ +// Copyright (c) 2006-2010 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: +// Provides a helper class for process security management +// +// + +#include +#include + +// Required for logging +#include + +#include "c_process_pair.h" +#include "rm_debug_logging.h" + + +CProcessPair* CProcessPair::NewL(const TDesC& aProcessName, const TProcessId aProcessId) + { + CProcessPair* self=new (ELeave) CProcessPair(); + CleanupStack::PushL(self); + self->ConstructL(aProcessName, aProcessId); + CleanupStack::Pop(self); + return self; + } + +void CProcessPair::ConstructL(const TDesC& aProcessName, const TProcessId aProcessId) + { + //allocate the process name buffer and fill with aProcessName + iProcessName = aProcessName.Alloc(); + if(iProcessName == NULL) + User::Leave(KErrNoMemory); + + LOG_MSG2( "CProcessPair::ConstructL() process name: %S", &TPtr8((TUint8*)iProcessName->Ptr(), 2*iProcessName->Length(), 2*iProcessName->Length()) ); + + //set process id + iProcessId = aProcessId; + } + +CProcessPair::CProcessPair(): + iProcessName(NULL) + { + } + +CProcessPair::~CProcessPair() + { + delete iProcessName; + } + +/** +Check whether two CProcessPair objects are equal + +@param aProcessPair a CProcessPair object to match with this one + +@return 0 if process ids and names do not match, non-zero if they do +*/ +TBool CProcessPair::operator==(const CProcessPair &aProcessPair) const + { + return Equals(*aProcessPair.iProcessName, aProcessPair.iProcessId); + } + +/** +Check whether this CProcessPair object has these values set + +@param aProcessName process name to check +@param aProcessId process id to check + +@return 0 if process ids and names do not match, non-zero if they do +*/ +TBool CProcessPair::Equals(const TDesC& aProcessName, const TProcessId aProcessId) const + { + return (ProcessIdMatches(aProcessId) && (ProcessNameMatches(aProcessName))); + } + +/** +Check whether the process ids of two objects match + +@param aProcessPair a CProcessPair object to compare with this one + +@return 0 if process ids do not match, non-zero if they do +*/ +TBool CProcessPair::ProcessIdMatches(const CProcessPair &aProcessPair) const + { + return ProcessIdMatches(aProcessPair.iProcessId); + } + +/** +Check whether two process ids match + +@param aProcessId a process ID to compare with this pair's process ID + +@return 0 if process ids do not match, non-zero if they do +*/ +TBool CProcessPair::ProcessIdMatches(const TProcessId &aProcessId) const + { + return iProcessId == aProcessId; + } + +/** +Check whether the process names of two objects match in-case-sensitively + +@param aProcessPair a CProcessPair object to compare with this one + +@return 0 if process names do not match, non-zero if they do +*/ +TBool CProcessPair::ProcessNameMatches(const CProcessPair &aProcessPair) const + { + return ProcessNameMatches(*aProcessPair.iProcessName); + } + +/** +Check whether two strings match in-case-sensitively + +@param aProcessName a process name to compare with this pair's process name + +@return 0 if process names do not match, non-zero if they do +*/ +TBool CProcessPair::ProcessNameMatches(const TDesC& aProcessName) const + { + return iProcessName->CompareF(aProcessName) == 0; + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/src/c_security_svr_async.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/src/c_security_svr_async.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,154 @@ +// Copyright (c) 2006-2010 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: +// Asynchronous security server active object class. +// +// + +#include +#include + +#include "c_security_svr_async.h" +#include "rm_debug_logging.h" + +using namespace Debug; + +__ASSERT_COMPILE(_FOFF(TEventInfo, iEventType) == 20); // Checking that adding iActionTaken hasn't resized the class + +CSecuritySvrAsync::CSecuritySvrAsync(CSecuritySvrSession* aSession, TProcessId aAgentId) + : CActive(CActive::EPriorityStandard), + iSession(aSession), + iProcessName(NULL), + iAgentId(aAgentId) + { + LOG_MSG2("CSecuritySvrAsync::CSecuritySvrAsync(aAgentId=0x%x)", TUint(aAgentId.Id())); + CActiveScheduler::Add(this); + } + +// returns a CSecuritySvrAsync active object associated with +// the specified agent and debugged process. +CSecuritySvrAsync* CSecuritySvrAsync::NewL(CSecuritySvrSession* aSession, const TDesC8& aProcessName, TProcessId aAgentId) + { + CSecuritySvrAsync* me = new (ELeave) CSecuritySvrAsync(aSession, aAgentId); + + CleanupStack::PushL(me); + + me->ConstructL(aProcessName); + + CleanupStack::Pop(me); + LOG_MSG2("CSecuritySvrAsync::NewL() obj addr=0x%x", me); + return (me); + } + +// dtor +CSecuritySvrAsync::~CSecuritySvrAsync() + { + LOG_MSG("CSecuritySvrAsync::~CSecuritySvrAsync()"); + + // NOTE: the Cancel() function calls DoCancel() which may rely on class members so be careful not + // to destroy/close data members before this call if they are needed + Cancel(); + iProcessName.Close(); + } + +// Associates the agent id and process name with the Active Object being constructed +void CSecuritySvrAsync::ConstructL(const TDesC8& aProcessName) + { + LOG_MSG("CSecuritySvrAsync::ConstructL()"); + iProcessName.CreateL(aProcessName.Length()); + iProcessName.Copy(aProcessName); + } + +// RunL() completes a previously issued call (currently only GetEvent() completion) +void CSecuritySvrAsync::RunL() + { + + LOG_MSG4("CSecuritySvrAsync::RunL() &iInfo=0x%08x, iAgentId.Id()=0x%x, iEventType=%d", + (TUint8*)&iInfo, iAgentId.Id(), iInfo.iEventType); + LOG_MSG5(" RunL() : iProcessIdValid=%d, iThreadId=0x%x, iProcessId=0x%x, &iStatus=0x%x", + iInfo.iProcessIdValid, TUint(iInfo.iThreadId) , TUint(iInfo.iProcessId), &iStatus ); + + // Something bad happened in the driver + User::LeaveIfError(iStatus.Int()); + + // Write back the event data to the debug agent. + // For compatibility we need to check the size of the buffer that the + // client has passed in as the size of TEventInfo will increase over time. + // Clients can calculate the required size from the EApiConstantsTEventInfoSize entry + // in the Debug Functionality block but may still pass in buffers which + // are smaller than the Debug Security Server's calculation of sizeof(TEventInfo), + // returning KErrTooBig in this case would be + // inappropriate as we would break compatibility. + TInt dataLengthToReturn = sizeof(TEventInfo); + TInt maxLengthClientSide = iMessage.GetDesMaxLengthL(1); + if(maxLengthClientSide < dataLengthToReturn) + { + dataLengthToReturn = maxLengthClientSide; + } + + + TPtr8 data((TUint8*)&iInfo, dataLengthToReturn, dataLengthToReturn); + iMessage.WriteL(1, data, 0); + iMessage.Complete(KErrNone); + } + +// Cancels the oustanding GetEvent call. May cope with other async calls in future. +void CSecuritySvrAsync::DoCancel() + { + LOG_MSG("CSecuritySvrAsync::DoCancel()"); + iSession->Server().iKernelDriver.CancelGetEvent(iProcessName,iAgentId.Id()); + + iMessage.Complete(KErrCancel); + } + +// Report any leave to the client if possible. +TInt CSecuritySvrAsync::RunError(TInt aError) + { + LOG_MSG2("CSecuritySvrAsync::RunError()=%d", aError); + iMessage.Complete(aError); + + return KErrNone; + } + +/** + * Start an asynchronous GetEvent call to the debug driver + * and activates this active object. + * If active object already active, completes the message with error KErrInUse + * and takes no further action. + */ +void CSecuritySvrAsync::GetEvent(const RMessage2& aMessage) + { + if( !IsActive() ) + { + iMessage = aMessage; + LOG_MSG4("CSecuritySvrAsync::GetEvent() this = 0x%08x, iInfo=0x%08x, iStatus=0x%08x", this, &iInfo, &iStatus); + + SetActive(); + iSession->Server().iKernelDriver.GetEvent(iProcessName,iAgentId.Id(),iStatus,iInfo); + } + else + { + LOG_MSG2("CSecuritySvrAsync::GetEvent() this = 0x%08x: ! Warning: ActiveObject is active. Returning with no effect", + this ); + aMessage.Complete( KErrInUse ); + } + } + +// Used for identifying which AO is associated with a debugged process +const TDesC8& CSecuritySvrAsync::ProcessName(void) + { + return iProcessName; + } + +// End of file - c_security_svr_async.cpp + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/src/c_security_svr_server.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/src/c_security_svr_server.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,685 @@ +// Copyright (c) 2006-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: +// Provides the debug security server server implementation. +// +// + +/** + @file + @internalTechnology + @released +*/ + +#include +#include +#include +#include "c_process_pair.h" +#include "c_security_svr_session.h" +#include "c_security_svr_server.h" +#include "rm_debug_logging.h" + +using namespace Debug; + +/** +Server constructor, sessions are created as ESharableSessions, meaning that +each session will be used by at most one debug agent +*/ +CSecuritySvrServer::CSecuritySvrServer(CActive::TPriority aActiveObjectPriority) + : CServer2(aActiveObjectPriority, ESharableSessions), + iSessionCount(0), + iShutdown() + { + LOG_MSG("CSecuritySvrServer::CSecuritySvrServer()\n"); + } + +/** +Standard implementation + +@return pointer to new CSecuritySvrServer object +*/ +CSecuritySvrServer* CSecuritySvrServer::NewLC() + { + LOG_MSG("CSecuritySvrServer::NewLC()\n"); + + CSecuritySvrServer* self=new(ELeave) CSecuritySvrServer(EPriorityStandard); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +/** +Server destructor, performs cleanup for the server +*/ +CSecuritySvrServer::~CSecuritySvrServer() + { + LOG_MSG("CSecuritySvrServer::~CSecuritySvrServer()\n"); + + // stop the kernel side driver + iKernelDriver.Close(); + User::FreeLogicalDevice(KDebugDriverName); + + //deallocate both the debug maps + iPassiveDebugMap.ResetAndDestroy(); + iActiveDebugMap.ResetAndDestroy(); + } + +/** +Starts the server and constructs and starts the servers shutdown timer +*/ +void CSecuritySvrServer::ConstructL() + { + LOG_MSG("CSecuritySvrServer::ConstructL()"); + + StartL(KSecurityServerName); + iShutdown.ConstructL(); + iShutdown.Start(); + + //load the kernel driver + TInt err = User::LoadLogicalDevice(KDebugDriverFileName); + if(! ((KErrNone == err) || (KErrAlreadyExists == err))) + { + User::Leave(err); + } + //create an information object for initialising the driver + TRM_DebugDriverInfo driverInfo; + driverInfo.iUserLibraryEnd = 0; + User::LeaveIfError(iKernelDriver.Open(driverInfo)); + } + +/** +Creates a new session with the DSS. A version check is done to ensure that an +up to date version of the DSS is available (according to the DA's needs). +The device driver is loaded if necessary and a session with the server and a +handle to the driver opened. + +@param aRequiredVersion the minimal version of the DSS required by the DA + +@return a pointer to the new sever session, or NULL if any of the + initialisation process failed +*/ +CSession2* CSecuritySvrServer::NewSessionL(const TVersion& aRequiredVersion, const RMessage2& aMessage) const +// +// Session constructor +// + { + LOG_ARGS("version=%d.%d.%d", aRequiredVersion.iMajor, aRequiredVersion.iMinor, aRequiredVersion.iBuild); + + //assert compatible version + TVersion currentVersion(KDebugServMajorVersionNumber, KDebugServMinorVersionNumber, KDebugServPatchVersionNumber); + if(!User::QueryVersionSupported(currentVersion, aRequiredVersion)) + { + LOG_MSG("Requested version not compatible with this version. Asked for %d.%d.%d but this is %d.%d.%d", aRequiredVersion.iMajor, aRequiredVersion.iMinor, aRequiredVersion.iBuild, KDebugServMajorVersionNumber, KDebugServMinorVersionNumber, KDebugServPatchVersionNumber); + User::Leave(KErrNotSupported); + } + + //get the debug agent's process id + RThread clientThread; + User::LeaveIfError(aMessage.Client(clientThread)); + CleanupClosePushL(clientThread); + RProcess clientProcess; + User::LeaveIfError(clientThread.Process(clientProcess)); + CleanupStack::PopAndDestroy(&clientThread); + TProcessId processId = clientProcess.Id(); + clientProcess.Close(); + + //create session + LOG_MSG("About to call new(ELeave) CSecuritySvrSession()"); + CSecuritySvrSession* servSession = new(ELeave) CSecuritySvrSession(processId); + + CleanupStack::PushL(servSession); + servSession->ConstructL(); + CleanupStack::Pop(servSession); + return servSession; + } + +/** +Manages requests from debug agents to attach to target debug processes + +Given the debug agent process ID and the target process name: +(1) checks whether the pair is already in either of the debug maps, if so + then returns KErrAlreadyExists +(2) if aPassive == ETrue then just add the pair to the passive map and return + whatever the return value of the array write was +(3) if aPassive == EFalse then check whether the target debug process is + already reserved by another debug agent. If it is then return KErrInUse, + otherwise add the pair to the active debug map and return the status + value of the array write. + +@param aTargetProcessName original FileName of the process to attach to +@param aDebugAgentProcessId process ID of the debug agent +@param aPassive ETrue if wish to attach passively, EFalse otherwise + +@return KErrNone if successfully attached, otherwise another system wide error + code as above +*/ +TInt CSecuritySvrServer::AttachProcessL(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId, const TBool aPassive) + { + //store the pair of values + LOG_MSG3("CSecuritySvrServer::AttachProcessL() 0x%lx aPassive=%d", aDebugAgentProcessId.Id(), aPassive); + + CProcessPair *processPair = CProcessPair::NewL(aTargetProcessName, aDebugAgentProcessId); + if(processPair == NULL) + return KErrNoMemory; + + //check whether the pair already exists in the active debug map + for(TInt i=0; iProcessNameMatches(_L("*"))) && + (processPair->ProcessNameMatches(*(iActiveDebugMap[i])) ) ) + { + //process already being debugged + LOG_MSG( " AttachProcessL() error : process already being debugged" ); + delete processPair; + return KErrInUse; + } + } + //try to add the pair. + TInt err = iActiveDebugMap.Append(processPair); + if(err != KErrNone) + { + // couldn't add pair for some unknown reason, so delete the pair + LOG_MSG2( " AttachProcessL() error %d inserting active process pair", err ); + delete processPair; + } + return err; + } + } + +/* +Detach from debugging the specified process + +@param aTargetProcessName name of the process to detach from +@param aDebugAgentProcessId process ID of the debug agent + +@return KErrNone if successfully detached, KErrNotFound if an attempt is made + to detach from a process which the debug agent hasn't previously attached to +*/ +TInt CSecuritySvrServer::DetachProcess(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId) + { + LOG_MSG2( "CSecuritySvrServer::DetachProcess() for agent with id 0x%lx", aDebugAgentProcessId.Id() ); + + //check whether the pair is in the active debug map + for(TInt i=0; iEquals(aTargetProcessName, aDebugAgentProcessId)) + { + //remove the process pair from the active debug map + delete iActiveDebugMap[i]; + iActiveDebugMap.Remove(i); + return KErrNone; + } + } + + //check whether the pair is in the passive debug map + for(TInt i=0; iEquals(aTargetProcessName, aDebugAgentProcessId)) + { + //remove the process pair from the active debug map + delete iPassiveDebugMap[i]; + iPassiveDebugMap.Remove(i); + return KErrNone; + } + } + + //process pair wasn't in either map + return KErrNotFound; + } + +/** +Given a debug agent process ID, removes all references to that debug agent +from the debug maps + +@param aMessage message from the debug agent + +@return returns KErrNone if successful, another system wide error code otherwise +*/ +void CSecuritySvrServer::DetachAllProcesses(const TProcessId aDebugAgentProcessId) + { + //check whether the debug agent process ID is in the active debug map + for(TInt i=iActiveDebugMap.Count()-1; i>=0; i--) + { + if(iActiveDebugMap[i]->ProcessIdMatches(aDebugAgentProcessId)) + { + //remove the process pair from the active debug map + delete iActiveDebugMap[i]; + iActiveDebugMap.Remove(i); + } + } + + //check whether the debug agent process ID is in the passive debug map + for(TInt i=iPassiveDebugMap.Count()-1; i>=0; i--) + { + if(iPassiveDebugMap[i]->ProcessIdMatches(aDebugAgentProcessId)) + { + //remove the process pair from the passive debug map + delete iPassiveDebugMap[i]; + iPassiveDebugMap.Remove(i); + } + } + } + +/* +Check whether the specified debug agent is attaced to the specfied target +process. + +@param aTargetThreadId thread ID of a thread in the target process +@param aMessage a message which originates with the debug agent +@param aPassive if EFalse then checks whether the debug agent is the active + debugger of the target process. If ETrue then checks whether the debug + agent is attached to the target process, irrespective of whether it is + attached passively or actively + +@return ETrue if attached, EFalse otherwise +*/ +TBool CSecuritySvrServer::CheckAttached(const TThreadId aTargetThreadId, const RMessage2& aMessage, const TBool aPassive) + { + + //get a handle to the target thread + RThread targetThread; + TInt err = targetThread.Open(aTargetThreadId); + if(err != KErrNone) + { + return EFalse; + } + + //get a handle to the target process + RProcess targetProcess; + err = targetThread.Process(targetProcess); + //finshed with the thread handle so close it + targetThread.Close(); + if(err != KErrNone) + return EFalse; + + //get the target process' file name + TFileName targetFileName = targetProcess.FileName(); + + // Tamperproofing. Ensure that the debug agent really has a superset + // of the target process PlatSec capabilities, as authorised + // by an OEM Debug Token (if any) + + TSecurityInfo targetSecInfo(targetProcess); + + // Now compare the capabilities, to ensure the DebugAgent has been authorised with + // sufficient capabilities from its OEM Debug token + CSecuritySvrSession* session = (CSecuritySvrSession*)aMessage.Session(); + + // Presume we need to check the target process is debuggable unless a valid OEM Debug token in effect? + if (!OEMTokenPermitsDebugL(session->GetOEMDebugCapabilities(), targetSecInfo.iCaps) ) + { + // No debug token therefore check if the process is debuggable + err = iKernelDriver.IsDebuggable(targetProcess.Id()); + } + + //finished with the process handle so close it + targetProcess.Close(); + + if (err != KErrNone) + { + // The process was not marked as debuggable by the loader, and the OEM + // debug token did not override the lack of a debuggable bit. + // The process was not marked as debuggable by the loader + return EFalse; + } + + return CheckAttachedProcess(targetFileName, aMessage, aPassive); + } + +/* +Check whether the specified debug agent is attaced to the specfied target +process. + +@param aTargetProcessId process ID of the target process +@param aMessage a message which originates with the debug agent +@param aPassive if EFalse then checks whether the debug agent is the active + debugger of the target process. If ETrue then checks whether the debug + agent is attached to the target process, irrespective of whether it is + attached passively or actively + +@return ETrue if attached, EFalse otherwise +*/ +TBool CSecuritySvrServer::CheckAttached(const TProcessId aTargetProcessId, const RMessage2& aMessage, const TBool aPassive) + { + //get a handle to the target process + RProcess targetProcess; + TInt err =targetProcess.Open(aTargetProcessId); + if(err != KErrNone) + { + return EFalse; + } + + //get the target process' file name + TFileName targetFileName = targetProcess.FileName(); + + // Tamperproofing. Ensure that the debug agent really has a superset + // of the target process PlatSec capabilities, as authorised + // by an OEM Debug Token (if any) + + TSecurityInfo targetSecInfo(targetProcess); + + // Now compare the capabilities, to ensure the DebugAgent has been authorised with + // sufficient capabilities from its OEM Debug token + CSecuritySvrSession* session = (CSecuritySvrSession*)aMessage.Session(); + + // Presume we need to check the target process is debuggable unless a valid OEM Debug token in effect? + if ( !OEMTokenPermitsDebugL(session->GetOEMDebugCapabilities(), targetSecInfo.iCaps) ) + { + // No debug token therefore check if the process is debuggable + err = iKernelDriver.IsDebuggable(targetProcess.Id()); + } + + //finished with the process handle so close it + targetProcess.Close(); + + if (err != KErrNone) + { + return EFalse; + } + + return CheckAttachedProcess(targetFileName, aMessage, aPassive); + } + +/* +Check whether the specified debug agent is attaced to the specfied target +process. + +@param aTargetProcessName +@param aMessage a message which originates with the debug agent + +@return ETrue if attached, EFalse otherwise +*/ +TBool CSecuritySvrServer::CheckAttachedProcess(const TDesC& aTargetProcessName, const RMessage2& aMessage, const TBool aPassive) const + { + //get the debug agent's process id + TProcessId clientProcessId = 0; + TInt err = GetProcessIdFromMessage(clientProcessId, aMessage); + if(err != KErrNone) + return EFalse; + + //check permissions + if(aPassive) + return IsDebugger(aTargetProcessName, clientProcessId); + else + return IsActiveDebugger(aTargetProcessName, clientProcessId); + } + +/** +Tests whether the debug agent is attached actively to the target debug process + +@param aTargetProcessName target debug process' FileName +@param aDebugAgentProcessId process ID of a debug agent + +@return ETrue if the specified debug agent is actively attached to the + specified target debug process, EFalse otherwise +*/ +TBool CSecuritySvrServer::IsActiveDebugger(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId) const + { + //check whether the pair is in the active debug map + for(TInt i=0; iEquals(aTargetProcessName, aDebugAgentProcessId)) + { + LOG_MSG2( "CSecuritySvrServer::IsActiveDebugger() for agent id 0x%lx matches name and pid", + aDebugAgentProcessId.Id() ); + return ETrue; + } + // if the pid matches and the name in the map is "*", indicating that + // this is an attach all agent, and thus debugging + if( iActiveDebugMap[i]->ProcessIdMatches(aDebugAgentProcessId) && + iActiveDebugMap[i]->ProcessNameMatches(_L("*")) ) + { + LOG_MSG2( "CSecuritySvrServer::IsActiveDebugger() for AttachAll agent id 0x%lx", + aDebugAgentProcessId.Id() ); + return ETrue; + } + } + //not found so return false + return EFalse; + } + +/** +Tests whether the target process is being debugged + +@param aTargetProcessName target process' FileName +@param aPassive indicates whether to check for the process being actively debugged, +or passively debugged + +@return ETrue if the specified target process is being debugged, + EFalse otherwise +*/ +TBool CSecuritySvrServer::IsDebugged(const TDesC& aTargetProcessName, const TBool aPassive) const + { + //get a reference to the appropriate list + const RPointerArray& map = (aPassive) ? iPassiveDebugMap : iActiveDebugMap; + + //iterate through the map trying to match the aTargetProcessName + for(TInt i=0; iProcessNameMatches(aTargetProcessName)) + { + return ETrue; + } + } + return EFalse; + } + +/** +Tests whether the debug agent is attached to the target debug process + +@param aTargetProcessName target debug process' FileName +@param aDebugAgentProcessId process ID of a debug agent + +@return ETrue if the specified debug agent is attached to the + specified target debug process (regardless of whether it is attached + passively or actively), EFalse otherwise +*/ +TBool CSecuritySvrServer::IsDebugger(const TDesC& aTargetProcessName, const TProcessId aDebugAgentProcessId) const + { + //check whether the pair is in the active debug map + if(IsActiveDebugger(aTargetProcessName, aDebugAgentProcessId)) + return ETrue; + + //check whether the pair is in the passive debug map + for(TInt i=0; iEquals(aTargetProcessName, aDebugAgentProcessId)) + return ETrue; + } + //not found so return false + return EFalse; + } + +/** +Decrements the server's count of how many sessions are connected to it and +starts the shutdown timer if there are no sessions connected +*/ +void CSecuritySvrServer::SessionClosed() + { + if(--iSessionCount < 1) + { + iShutdown.Start(); + } + } + +/** +Increments the servers count of how many sessions are connected to it and +cancels the shutdown timer if it is running +*/ +void CSecuritySvrServer::SessionOpened() + { + iSessionCount++; + iShutdown.Cancel(); + } + +/** + Get the process id of the thread which sent aMessage + @param aProcessId process id of the thread which sent aMessage + @param aMessage message object sent by thread + + @return KErrNone if aProcessId could be set, or one of the system wide error codes if not + */ +TInt CSecuritySvrServer::GetProcessIdFromMessage(TProcessId& aProcessId, const RMessage2& aMessage) const + { + //get the debug agent's thread + RThread clientThread; + TInt err = aMessage.Client(clientThread); + if(err != KErrNone) + { + return err; + } + + //get the debug agent's process + RProcess clientProcess; + err = clientThread.Process(clientProcess); + + //finished with the thread handle so close it + clientThread.Close(); + + //check if there was an error from getting the process + if(err != KErrNone) + { + return err; + } + + //get the debug agent's process id + aProcessId = clientProcess.Id(); + + //finished with the process handle so close it + clientProcess.Close(); + + return KErrNone; + } + +/** + Helper function which determines whether the capabilities of the + OEM Token are sufficient to permit debug of an application. + + Normally, we use the AllFiles capability as a proxy which + means a Debug Agent can debug non-debuggable executables, + provided it has a superset of the capabilities of the executable + to be debugged. + + However, this causes the problem that all OEM Debug Tokens implicitly + give the power to debug an AllFiles executable, even if all that + is really needed is the power to debug an app with no capabilities, + or capabilities other than AllFiles. + + To address this, we treat the AllFiles capability in a special way. + The AllFiles capability in a token is taken to mean that an OEM has + signed the token, and hence can debug other executables. But this does + not inclue the ability to debug an AllFiles executable. To debug an AllFiles + executable, the token must also have TCB. + + @param aTokenCaps - The PlatSec capabilities of a token + @param aTargetCaps - The PlatSec capabilities of a target app to be debugged + + @return ETrue if authorised for debugging, EFalse otherwise. + + @leave Any system error code. + */ +TBool CSecuritySvrServer::OEMTokenPermitsDebugL(const TCapabilitySet aTokenCaps, const TCapabilitySet aTargetCaps) + { + LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL\n"); + + // Is the token valid - i.e. does it have AllFiles. + if ( !aTokenCaps.HasCapability(ECapabilityAllFiles) ) + { + // Token is not valid, as it does not have AllFiles. + LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL - Token does not have AllFiles\n"); + + return EFalse; + } + + // Token MUST have a strict superset of capabilities + if ( !aTokenCaps.HasCapabilities(aTargetCaps) ) + { + // Token does not have at least all the capabilities of the target + LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL - Token does not have superset of target capabilities\n"); + + return EFalse; + } + + // Special case: If the target has AllFiles, the Token must have TCB + if ( aTargetCaps.HasCapability(ECapabilityAllFiles) ) + { + // Target has AllFiles, so does the Token have TCB? + if ( !aTokenCaps.HasCapability(ECapabilityTCB) ) + { + // Token does not have TCB. + LOG_MSG("CSecuritySvrSession::OEMTokenPermitsDebugL - Token does not have TCB when target has AllFiles\n"); + + return EFalse; + } + } + + // If we have passed all the above tests, the token permits debug + return ETrue; + } + +/** + * This looks at a debug tokens capability and ensures it is sufficient + * to provide access to the flash partition + * @param aTokenCaps Capabilties of the Token + * @return TBool Whether or not flash access is permitted + */ +TBool CSecuritySvrServer::OEMTokenPermitsFlashAccessL(const TCapabilitySet aTokenCaps) + { + //Must have TCB to access flash + return aTokenCaps.HasCapability(ECapabilityTCB); + } + +//eof + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/src/c_security_svr_session.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/src/c_security_svr_session.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,2653 @@ +// Copyright (c) 2006-2010 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: +// Provides the debug security server session implementation. +// +// + +/** + @file + @internalTechnology + @released +*/ + +// Needed so we get the text strings for capabilities +#define __INCLUDE_CAPABILITY_NAMES__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// required for direct parsing of e32image/tromimage headers +#include +#include + +//added for direct access to media driver +#include +#include + +#include "c_security_svr_session.h" +#include "c_security_svr_server.h" +#include "c_security_svr_async.h" +#include "rm_debug_logging.h" +#ifdef _DEBUG +#include "low_mem_requests.h" +#endif + +using namespace Debug; + +CSecuritySvrSession::CSecuritySvrSession(const TProcessId& aDebugAgentProcessId) + : iDebugAgentProcessId(aDebugAgentProcessId), + iServerNotified(EFalse), + iCrashConnected(EFalse) + { + // Ensure that this debug agent has no target capability override + // by default + iOEMDebugCapabilities.SetEmpty(); + } + +void CSecuritySvrSession::ServiceError(const RMessage2 &aMessage, TInt aError) + { + LOG_MSG2("CSecuritySvrSession::ServiceError(), aError: %d\n", aError); + + //insert ending heap markers + HeapWatcher(aMessage.Function(), EFalse); + + aMessage.Complete(aError); + } + +/** +Called by the client/server framework as part of session creation. + +Notifies the server that a session is being created +*/ +void CSecuritySvrSession::CreateL() + { + LOG_MSG("CSecuritySvrSession::CreateL()\n"); + + //notify the server that the session has been opened + Server().SessionOpened(); + iServerNotified = ETrue; + } + +/** + Returns a reference to the DSS + + @return a reference to the DSS + */ +CSecuritySvrServer& CSecuritySvrSession::Server() const + { + return *static_cast(const_cast(CSession2::Server())); + } + +/** +Session destructor. Performs necessary cleanup and notifies the server that the +session is being closed +*/ +CSecuritySvrSession::~CSecuritySvrSession() + { + LOG_MSG("CSecuritySvrSession::~CSecuritySvrSession!()\n"); + + // Cancel any outstanding async objects. + iAsyncHandlers.ResetAndDestroy(); + + // Inform the device driver of the agent detach. + Server().iKernelDriver.DetachAgent(iDebugAgentProcessId.Id()); + + LOG_MSG( "CSecuritySvrSession::~CSecuritySvrSession() : -> securityServer.DetachAllProcesses()\n" ); + Server().DetachAllProcesses(iDebugAgentProcessId); + + //notify the server that the session has closed + if(iServerNotified) + { + Server().SessionClosed(); + } + } + +void CSecuritySvrSession::ConstructL() + { + // nothing to do + } + +/** + Used to insert heap checking markers. + + @param aFunction The function that heap markers should be added for + @param aEntry if ETrue indicates that heap checking is starting, if EFalse + that heap checking is ending. + */ +void CSecuritySvrSession::HeapWatcher(const TUint32 aFunction, const TBool aEntry) const + { + switch(aFunction) + { + case EDebugServAttachExecutable: + return; + case EDebugServDetachExecutable: + return; + case EDebugServSuspendThread: + return; + case EDebugServResumeThread: + return; + case EDebugServAttachAll: + return; + case EDebugServDetachAll: + return; +// used for out-of-memory testing in debug mode +#ifdef _DEBUG + // start heap marking in on entry, do nothing on exit + case EDebugServMarkHeap: + { + if(aEntry) + { + __UHEAP_MARK; + } + return; + } + // stop heap marking on exit, do nothing on entry + case EDebugServMarkEnd: + { + if(!aEntry) + { + __UHEAP_MARKEND; + } + return; + } +#endif + default: + if(aEntry) + { + __UHEAP_MARK; + } + else + { + __UHEAP_MARKEND; + } + return; + } + } + +void CSecuritySvrSession::ServiceL(const RMessage2& aMessage) +// +// Session service handler +// + { + //insert starting heap markers + HeapWatcher(aMessage.Function(), ETrue); + + switch(aMessage.Function()) + { + case EDebugServResumeThread: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServResumeThread\n" ); + ResumeThreadL(aMessage); + break; + + case EDebugServSuspendThread: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServSuspendThread\n" ); + SuspendThreadL(aMessage); + break; + + case EDebugServReadMemory: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServReadMemory\n" ); + ReadMemoryL(aMessage); + break; + + case EDebugServWriteMemory: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServWriteMemory\n" ); + WriteMemoryL(aMessage); + break; + + case EDebugServSetBreak: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServSetBreak\n" ); + SetBreakL(aMessage); + break; + + case EDebugServClearBreak: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServClearBreak\n" ); + ClearBreakL(aMessage); + break; + + case EDebugServModifyBreak: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServModifyBreak\n" ); + ModifyBreakL(aMessage); + break; + + case EDebugServModifyProcessBreak: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServModifyProcessBreak\n" ); + ModifyProcessBreakL(aMessage); + break; + + case EDebugServBreakInfo: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServBreakInfo\n" ); + BreakInfoL(aMessage); + break; + + case EDebugServReadRegisters: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServReadRegisters\n" ); + ReadRegistersL(aMessage); + break; + + case EDebugServWriteRegisters: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServWriteRegisters\n" ); + WriteRegistersL(aMessage); + break; + + case EDebugServGetEvent: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetEvent\n" ); + GetEventL(aMessage); + break; + + case EDebugServCancelGetEvent: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServCancelGetEvent\n" ); + CancelGetEventL(aMessage); + break; + + case EDebugServAttachExecutable: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServAttachExecutable\n" ); + AttachProcessL(aMessage); + break; + + case EDebugServDetachExecutable: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServDetachExecutable\n" ); + DetachProcessL(aMessage); + break; + + case EDebugServAttachAll: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServAttachAll\n" ); + AttachAllL(aMessage); + break; + + case EDebugServDetachAll: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServDetachAll\n" ); + DetachAllL(aMessage); + break; + + case EDebugServGetDebugFunctionalityBufSize: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetDebugFunctionalityBufSize\n" ); + GetDebugFunctionalityBufSizeL(aMessage); + break; + + case EDebugServGetDebugFunctionality: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetDebugFunctionality\n" ); + GetDebugFunctionalityL(aMessage); + break; + + case EDebugServSetEventAction: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServSetEventAction\n" ); + SetEventActionL(aMessage); + break; + + case EDebugServGetList: + LOG_MSG( "CSecuritySvrSession::ServiceL() EDebugServGetList\n" ); + GetListL(aMessage); + break; + + case EDebugServStep: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServStep\n"); + StepL(aMessage); + break; + + case EDebugServSetProcessBreak: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServSetProcessBreak\n"); + SetProcessBreakL(aMessage); + break; + + case EDebugServProcessBreakInfo: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServProcessBreakInfo\n"); + ProcessBreakInfoL(aMessage); + break; + + case EDebugServKillProcess: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServKillProcess\n"); + KillProcessL(aMessage); + break; + +#ifdef _DEBUG + case EDebugServMarkHeap: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServMarkHeap\n"); + // all taken care of in HeapWatcher + aMessage.Complete(KErrNone); + break; + + case EDebugServMarkEnd: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServMarkEnd\n"); + // all taken care of in HeapWatcher + aMessage.Complete(KErrNone); + break; + + case EDebugServFailAlloc: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServFailAlloc\n"); + DoFailAlloc(aMessage); + break; +#endif + case EDebugServReadCrashFlash: + ReadCrashLogL(aMessage); + break; + case EDebugServWriteCrashFlash: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServWriteCrashFlash\n"); + WriteCrashConfigL(aMessage); + break; + case EDebugServEraseCrashFlash: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServEraseCrashFlash\n"); + EraseCrashLogL(aMessage); + break; + case EDebugServEraseEntireCrashFlash: + LOG_MSG("CSecuritySvrSession::ServiceL() EDebugServEraseEntireCrashFlash\n"); + EraseEntireCrashLogL(aMessage); + break; + default: + LOG_MSG( "CSecuritySvrSession::ServiceL() Unknown request, calling User::Leave(KErrNotSupported);\n" ); + User::Leave(KErrNotSupported); + break; + } + + //insert ending heap markers + HeapWatcher(aMessage.Function(), EFalse); + + LOG_EXIT(); + } + +#ifdef _DEBUG +/** + Used to control heap failure in debug mode. + @param aMessage If aMessage.Int0 is non-zero then heap will be set to fail on that allocation. + If aMessage.Int0 is zero then the heap failure count is reset + */ +void CSecuritySvrSession::DoFailAlloc(const RMessage2& aMessage) + { + TInt count = aMessage.Int0(); + if(count == 0) + { + __UHEAP_RESET; + } + else + { + __UHEAP_FAILNEXT(count); + } + aMessage.Complete(KErrNone); + } +#endif + +/** +Suspends execution of the specified thread. + +@param aMessage contains an integer representation of the target thread's + thread ID at offset 0. + +@leave KErrPermissionDenied if security check fails or KErrArgument if the + thread does not exist +*/ +void CSecuritySvrSession::SuspendThreadL(const RMessage2& aMessage) + { + + LOG_MSG( "CSecuritySvrSession::SuspendThreadL()\n" ); + + //get thread ID + TThreadId threadId = ReadTThreadIdL(aMessage, 0); + //check attached + CheckAttachedL(threadId, aMessage, EFalse); + + //security check passed so can perform actions + User::LeaveIfError(Server().iKernelDriver.SuspendThread(threadId)); + + aMessage.Complete(KErrNone); + } + +/** +Resumes execution of the specified thread. + +@param aMessage contains an integer representation of the target thread's + thread ID at offset 0. + +@leave KErrPermissionDenied if security check fails or KErrArgument if the + thread does not exist +*/ +void CSecuritySvrSession::ResumeThreadL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::ResumeThreadL()\n" ); + + //get thread ID + TThreadId threadId = ReadTThreadIdL(aMessage, 0); + + //check attached + CheckAttachedL(threadId, aMessage, EFalse); + + //security check passed so can perform actions + TInt err = Server().iKernelDriver.ResumeThread(threadId); + aMessage.Complete(err); + } + +void CSecuritySvrSession::GetDebugFunctionalityBufSizeL(const RMessage2& aMessage) +// +// Retrieve size of functionality data buffer in bytes which must be allocated +// by the client +// + { + LOG_MSG( "CSecuritySvrSession::GetDebugFunctionalityBufSizeL()\n" ); + + TUint32 result = 0; + // Get Buffer size from the kernel driver + User::LeaveIfError(Server().iKernelDriver.GetDebugFunctionalityBufSize(result)); + + TPtr8 stuff((TUint8*)&result,4, 4); + + aMessage.WriteL(0,stuff); + + aMessage.Complete(KErrNone); + } + +void CSecuritySvrSession::GetDebugFunctionalityL(const RMessage2& aMessage) +// +// Retrieve the functionality data and place it in a buffer +// allocated by the client. +// + { + LOG_MSG( "CSecuritySvrSession::GetDebugFunctionalityL()\n" ); + + TUint32 dfsize = 0; + + // Get Buffer size from the kernel driver + User::LeaveIfError(Server().iKernelDriver.GetDebugFunctionalityBufSize(dfsize)); + + // Allocate space for the functionality data + HBufC8* dftext = HBufC8::NewLC(dfsize); + + const TPtr8& dfPtr = dftext->Des(); + + // Extract said data from the device driver + User::LeaveIfError(Server().iKernelDriver.GetDebugFunctionality((TDes8&)dfPtr)); + + // Return data to client + aMessage.WriteL(0,dfPtr); + + // Free buffer + CleanupStack::PopAndDestroy(dftext); + + aMessage.Complete(KErrNone); + } + +/** +Reads memory from a specified thread using the passed parameters. The user +should ensure that the TPtr8 that is passed in has size greater than or equal +to the size of the memory that is trying to be read. + +@param aMessage The RMessage2 object should be constructed as follows: + * aMessage.Int0() is the thread ID of the target debug app + * aMessage.Ptr1() is a TMemoryInfo object which contains the following: + * the address of the memory to be read from the target debug thread + * the size of the memory block to be read from the target debug thread + * the access size to use + * the endianess to interpret the data as + * aMessage.Ptr2() is the address of the buffer in the debug agent thread + that the data from the target debug app should be written into + +@leave KErrPermissionDenied if client is not attached to the target + thread's process, + KErrNoMemory if memory could not be allocated, + KErrArgument if there are problems with the aMessage object, + KErrBadHandle if the thread represented by aMessage.Ptr0() is invalid, + an error value from CSecuritySvrSession::ValidateMemoryInfo if checking + the memory attributes failed, + or another of the system wide error codes +*/ +void CSecuritySvrSession::ReadMemoryL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::ReadMemoryL()\n" ); + + //get debug app thread ID + TThreadId threadId = ReadTThreadIdL(aMessage, 0); + + CheckAttachedL(threadId, aMessage, ETrue); + + //create and initialise the memory info object + TMemoryInfo targetMemory; + TPtr8 targetMemoryPtr( (TUint8 *)&targetMemory, sizeof(TMemoryInfo) ); + + aMessage.ReadL(1,targetMemoryPtr); + + //check memory info is acceptable + ValidateMemoryInfoL(threadId, targetMemory, ETrue); + + RBuf8 data; + data.CreateL(targetMemory.iSize); + data.CleanupClosePushL(); + + //fill buffer with data from target debug thread + User::LeaveIfError(Server().iKernelDriver.ReadMemory(threadId, targetMemory.iAddress, targetMemory.iSize, data)); + + //attempt to write the data from the target debug thread back to the agent + aMessage.WriteL(2, data); + + //delete temporary buffer + CleanupStack::PopAndDestroy(&data); + + aMessage.Complete(KErrNone); + } + +/** +Writes memory to a specified thread using the passed parameters. + +@param aMessage The RMessage2 object should be constructed as follows: + * aMessage.Ptr0() is the thread ID of the target debug app + * aMessage.Ptr1() is a TMemoryInfo object which contains the following: + * the address of the memory to be written to the target debug thread + * the size of the memory block to be written to the target debug thread + * the access size to use + * the endianess to interpret the data as + * aMessage.Ptr2() is the address of the buffer in the debug agent thread + that the data to write to the target debug app should be read from + +@leave KErrPermissionDenied if client is not attached (actively) to the target + thread's process, + KErrNoMemory if memory could not be allocated, + KErrArgument if there are problems with the aMessage object, + KErrBadHandle if the thread represented by aMessage.Ptr0() is invalid, + an error value from CSecuritySvrSession::ValidateMemoryInfo if checking + the memory attributes failed, + or another of the system wide error codes +*/ +void CSecuritySvrSession::WriteMemoryL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::WriteMemoryL()\n" ); + + //get debug app thread ID + TThreadId threadId = ReadTThreadIdL(aMessage, 0); + + CheckAttachedL(threadId, aMessage, EFalse); + + //create and initialise the memory info object + TMemoryInfo targetMemory; + TPtr8 targetMemoryPtr( (TUint8 *)&targetMemory, sizeof(TMemoryInfo) ); + + aMessage.ReadL(1,targetMemoryPtr); + + //check memory info is acceptable + ValidateMemoryInfoL(threadId, targetMemory, EFalse); + + //create temporary buffer and read data from client + RBuf8 data; + data.CreateL(targetMemory.iSize); + data.CleanupClosePushL(); + + aMessage.ReadL(2, data); + + // what about telling the driver about endianess/access size? + User::LeaveIfError(Server().iKernelDriver.WriteMemory(threadId, targetMemory.iAddress, targetMemory.iSize, data)); + + //free temporary buffer + CleanupStack::PopAndDestroy(&data); + + aMessage.Complete(KErrNone); + } + +/** +@internalTechnology + +Notes: This call is used to set a thread specific breakpoint. Its input arguments +are the thread id, address and architecture type of the breakpoint. It returns success +or failure, and if successful, it sets the TBreakId in the Debug Agent to the +breakpoint id by which it can be referenced in future calls to ModifyBreak,ClearBreak and +BreakInfo. + +@param aMessage.Ptr0() - aThreadId is thread id of the target debug process +@param aMessage.Ptr1() - Address of a TBreakInfo in the Debug Agent +@param aMessage.Ptr2() - Address of a TBreakId in the Debug Agent +@leave KErrPermissionDenied if the security check fails. + KErrAlreadyExists if there is a breakpoint overlapping the desired address. + KErrNotSupported if the architecture type is unrecognised. + KErrNoMemory if there is no more memory to complete the operation. + KErrArgument if the breakpoint address alignment is unsuitable for the requested + breakpoint. + KErrOverflow if there are too many breakpoints set. +*/ +void CSecuritySvrSession::SetBreakL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::SetBreakL!()\n" ); + + //get debug app thread ID + TThreadId threadId = ReadTThreadIdL(aMessage, 0); + + //check that the agent has attached to the target process + CheckAttachedL(threadId, aMessage, EFalse); + + //create and initialise the break info object + TBreakInfo breakInfo; + TPtr8 breakInfoPtr( (TUint8 *)&breakInfo, sizeof(TBreakInfo) ); + + aMessage.ReadL(1,breakInfoPtr); + + LOG_MSG4( "CSecuritySvrSession::SetBreakL, threadId=0x%lx, addr=0x%x, mode=%d", + threadId.Id(), breakInfo.iAddress, breakInfo.iArchitectureMode); + + //set break in target app + TBreakId breakId = 0; + User::LeaveIfError(Server().iKernelDriver.SetBreak(breakId, threadId, breakInfo.iAddress, breakInfo.iArchitectureMode)); + + //attempt to write the break id back to the debug agent + WriteDataL(aMessage, 2, &breakId, sizeof(breakId)); + + aMessage.Complete(KErrNone); + } + +/** +Clears a breakpoint previously set by a SetBreak() call. + +@param aMessage.Int0() - TBreakId of the breakpoint to be removed. +*/ +void CSecuritySvrSession::ClearBreakL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::ClearBreakL()\n" ); + + const TInt breakId = aMessage.Int0(); + + // Check that the breakpoint exists + TUint64 objectId; + TUint32 address; + TArchitectureMode mode; + TBool threadSpecific = EFalse; + + User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,objectId,address,mode,threadSpecific)); + + if(threadSpecific) + { + // Check that the debug agent is attached to the thread for which the + // breakpoint is currently set. + LOG_MSG4( "CSecuritySvrSession::ClearBreakL( brkId=%d), addr=0x%x, tId=0x%x", + breakId, address, I64LOW(objectId) ); + CheckAttachedL(TThreadId(objectId), aMessage, EFalse); + } + else + { + // Check that the debug agent is attached to the process for which the + // breakpoint is currently set. + LOG_MSG4( "CSecuritySvrSession::ClearBreakL( brkId=%d), addr=0x%x, pId=0x%x", + breakId, address, I64LOW(objectId) ); + CheckAttachedL(TProcessId(objectId), aMessage, EFalse); + } + + // Finally clear the breakpoint + User::LeaveIfError(Server().iKernelDriver.ClearBreak(breakId)); + + aMessage.Complete(KErrNone); + } + +/** +@param aMessage.Int0() - Breakpoint Id of interest +@param aMessage.Ptr1() - Address in Debug Agent to place threadId of the breakpoint +@param aMessage.Ptr2() - Address in Debug Agent to place address of the breakpoint +@param aMessage.Ptr3() - Address in Debug Agent to place the architecture mode of the breakpoint +@leave Any error which may be returned by RSessionBase::SendReceive() +*/ +void CSecuritySvrSession::BreakInfoL(const RMessage2& aMessage) + { + const TBreakId breakId = (TBreakId)aMessage.Int0(); + + TThreadId threadId; + TUint32 address; + TArchitectureMode mode; + TBool threadSpecific = ETrue; + + TUint64 threadIdData; + User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,threadIdData,address,mode,threadSpecific)); + + if(!threadSpecific) + { + User::Leave(KErrNotFound); + } + + threadId = TThreadId(threadIdData); + + //check that the agent has attached to the target process + CheckAttachedL(threadId, aMessage, EFalse); + + // return the threadId + WriteDataL(aMessage, 1, &threadId, sizeof(threadId)); + + // return the address + WriteDataL(aMessage, 2, &address, sizeof(address)); + + // return the mode + WriteDataL(aMessage, 3, &mode, sizeof(mode)); + + aMessage.Complete(KErrNone); + } + +/** +@internalTechnology + +Modify a previously set breakpoint. + +@param aMessage.Int0() - The breakpoint id of the breakpoint to modify +@param aMessage.Ptr1() - The new Thread Id for the breakpoint +@param aMessage.Int2() - The new virtual memory address for the breakpoint +@param aMessage.Int3() - The new architecture mode for the breakpoint +@return KErrNone if succesful. KErrPermissionDenied if the security check fails. + KErrAlreadyExists if there is a breakpoint overlapping the desired address. + KErrNotSupported if the architecture type is unrecognised. + KErrNoMemory if there is no more memory to complete the operation. + KErrArgument if the breakpoint address alignment is unsuitable for the requested + breakpoint. + KErrOverflow if there are too many breakpoints set. +*/ +void CSecuritySvrSession::ModifyBreakL(const RMessage2& aMessage) + { + const TBreakId breakId = (TBreakId)aMessage.Int0(); + const TThreadId threadId = ReadTThreadIdL(aMessage, 1); + const TUint32 address = aMessage.Int2(); + const TArchitectureMode mode = (TArchitectureMode)aMessage.Int3(); + + // Get information on the breakpoint to check the security status + TUint64 checkThreadId; + TUint32 checkAddress; + TArchitectureMode checkMode; + TBool threadSpecific; + + User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,checkThreadId,checkAddress,checkMode,threadSpecific)); + + LOG_MSG4( "CSecuritySvrSession::ModifyBreakL(brkId=%d) tId=0x%x, addr=0x%x", + breakId, I64LOW(threadId.Id()), address ); + + // Security check that the thread Id is associated with the debug agent + + //check that the agent has attached to the target process + CheckAttachedL(TThreadId(checkThreadId), aMessage, EFalse); + + // now check that the thread Id which is being set is permitted + //check that the agent has attached to the target process + CheckAttachedL(threadId, aMessage, EFalse); + + User::LeaveIfError(Server().iKernelDriver.ModifyBreak(breakId,threadId,address,mode)); + + aMessage.Complete(KErrNone); + } + +/** +@internalTechnology + +Notes: This call is used to set a process wide breakpoint. Its input arguments +are the process id, address and architecture type of the breakpoint. It returns success +or failure, and if successful, it sets the TBreakId in the Debug Agent to the +breakpoint id by which it can be referenced in future calls to ModifyBreak,ClearBreak and +BreakInfo. + +@param aMessage.Ptr0() - aProcessId is process id of the target debug process +@param aMessage.Ptr1() - Address of a TBreakInfo in the Debug Agent +@param aMessage.Ptr2() - Address of a TBreakId in the Debug Agent +@leave KErrPermissionDenied if the security check fails. + KErrAlreadyExists if there is a breakpoint overlapping the desired address. + KErrNotSupported if the architecture type is unrecognised. + KErrNoMemory if there is no more memory to complete the operation. + KErrArgument if the breakpoint address alignment is unsuitable for the requested + breakpoint. + KErrOverflow if there are too many breakpoints set. +*/ +void CSecuritySvrSession::SetProcessBreakL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::SetProcessBreakL()\n" ); + + //get debug app thread ID + TProcessId procId = ReadTProcessIdL(aMessage, 0); + + //check that the agent has attached to the target process + CheckAttachedL(procId, aMessage, EFalse); + + //create and initialise the memory info object + TBreakInfo breakInfo; + TPtr8 breakInfoPtr( (TUint8 *)&breakInfo, sizeof(TBreakInfo) ); + + aMessage.ReadL(1,breakInfoPtr); + + LOG_MSG4( "CSecuritySvrSession::SetProcessBreakL pId=0x%x, addr=0x%x, mode=%d ", + I64LOW(procId.Id()), breakInfo.iAddress, breakInfo.iArchitectureMode ); + + //set break in target app + TBreakId breakId = 0; + User::LeaveIfError(Server().iKernelDriver.SetProcessBreak(breakId, procId, breakInfo.iAddress, breakInfo.iArchitectureMode)); + + //attempt to write the break id back to the debug agent + WriteDataL(aMessage, 2, &breakId, sizeof(breakId)); + + aMessage.Complete(KErrNone); + } + +/** +@internalTechnology + +Modify a previously set process breakpoint. + +@param aMessage.Int0() - The breakpoint id of the breakpoint to modify +@param aMessage.Ptr1() - The new Process Id for the breakpoint +@param aMessage.Int2() - The new virtual memory address for the breakpoint +@param aMessage.Int3() - The new architecture mode for the breakpoint +@return KErrNone if succesful. KErrPermissionDenied if the security check fails. + KErrAlreadyExists if there is a breakpoint overlapping the desired address. + KErrNotSupported if the architecture type is unrecognised. + KErrNoMemory if there is no more memory to complete the operation. + KErrArgument if the breakpoint address alignment is unsuitable for the requested + breakpoint. + KErrOverflow if there are too many breakpoints set. +*/ +void CSecuritySvrSession::ModifyProcessBreakL(const RMessage2& aMessage) + { + const TBreakId breakId = (TBreakId)aMessage.Int0(); + const TProcessId processId = ReadTProcessIdL(aMessage, 1); + const TUint32 address = aMessage.Int2(); + const TArchitectureMode mode = (TArchitectureMode)aMessage.Int3(); + + // Get information on the breakpoint to check the security status + TUint64 checkProcessId; + TUint32 checkAddress; + TArchitectureMode checkMode; + TBool threadSpecific; + + User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,checkProcessId,checkAddress,checkMode,threadSpecific)); + + LOG_MSG4( "CSecuritySvrSession::ModifyProcessBreakL(brkId=%d) pId=0x%x, addr=0x%x", + breakId, I64LOW(processId.Id()), address ); + + + // Security check that the process Id is associated with the debug agent + + //check that the agent has attached to the target process + CheckAttachedL(TProcessId(checkProcessId), aMessage, EFalse); + + // now check that the process Id which is being set is permitted + //check that the agent has attached to the target process + CheckAttachedL(processId, aMessage, EFalse); + + User::LeaveIfError(Server().iKernelDriver.ModifyProcessBreak(breakId,processId,address,mode)); + + aMessage.Complete(KErrNone); + } + +/** +@param aMessage.Int0() - Breakpoint Id of interest +@param aMessage.Ptr1() - Address in Debug Agent to place process Id of the breakpoint +@param aMessage.Ptr2() - Address in Debug Agent to place address of the breakpoint +@param aMessage.Ptr3() - Address in Debug Agent to place the architecture mode of the breakpoint +@leave Any error which may be returned by RSessionBase::SendReceive() +*/ +void CSecuritySvrSession::ProcessBreakInfoL(const RMessage2& aMessage) + { + const TBreakId breakId = (TBreakId)aMessage.Int0(); + + TProcessId procId; + TUint32 address; + TArchitectureMode mode; + TBool threadSpecific; + + TUint64 procIdData; + User::LeaveIfError(Server().iKernelDriver.BreakInfo(breakId,procIdData,address,mode,threadSpecific)); + if(threadSpecific) + { + User::Leave(KErrNotFound); + } + procId = TProcessId(procIdData); + + //check that the agent has attached to the target process + CheckAttachedL(procId, aMessage, EFalse); + + // return the processId + WriteDataL(aMessage, 1, &procId, sizeof(procId)); + + // return the address + WriteDataL(aMessage, 2, &address, sizeof(address)); + + // return the mode + WriteDataL(aMessage, 3, &mode, sizeof(mode)); + + aMessage.Complete(KErrNone); + } + +/** +Read register values. + +@param aMessage should contain: + * at offset 0 a pointer to the thread ID of the target thread + * at offset 1 a descriptor representing an array of TRegisterInfo + register IDs + * at offset 2 a descriptor representing an array into which TRegister + register values will be written + * at offset 3 a descriptor representing an array into which TUint8 + register flags will be written + +@leave KErrArgument if the max length of the array at offset 1 is not a + multiple of sizeof(TRegisterInfo), if the max length of the array + at offset 2 is not a multiple of sizeof(TRegister), if the max + length of the array at offset 3 is not a multiple of sizeof(TUint8), if + any of the descriptors have max length of 0, or if the three + descriptors do not represent the same number of registers, + KErrNoMemory if there is insufficient memory, + KErrDied, if the thread with thread ID aThreadId is dead +*/ +void CSecuritySvrSession::ReadRegistersL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::ReadRegistersL()\n" ); + + const TThreadId threadId = ReadTThreadIdL(aMessage, 0); + + //check the agent is attached to the thread + CheckAttachedL(threadId, aMessage, ETrue); + + //number of registers being requested + TUint32 numberOfRegisters; + + //check length of descriptors is acceptable + ValidateRegisterBuffersL(aMessage, numberOfRegisters); + + // Passed data will be saved in this descriptor. + RBuf8 ids; + ids.CreateL(numberOfRegisters * sizeof(TRegisterInfo)); + // Do the right cleanup if anything subsequently goes wrong + ids.CleanupClosePushL(); + + //read the data from the client thread + aMessage.ReadL(1, ids); + + //create buffer to fill with data from target debug thread + HBufC8 *data = HBufC8::NewLC(aMessage.GetDesMaxLength(2)); + TPtr8 values(data->Des()); + + HBufC8 *flagsData = HBufC8::NewLC(numberOfRegisters * sizeof(TUint8)); + TPtr8 flags(flagsData->Des()); + + //get register info and return relevant parts back to agent + User::LeaveIfError(Server().iKernelDriver.ReadRegisters(threadId, ids, values, flags)); + aMessage.WriteL(2, values); + aMessage.WriteL(3, flags); + + //delete temporary buffers and return status + CleanupStack::PopAndDestroy(flagsData); + CleanupStack::PopAndDestroy(data); + CleanupStack::PopAndDestroy(&ids); + + aMessage.Complete(KErrNone); + } + +/** +Write register values. + +@param aMessage should contain: + * at offset 0 a pointer to the thread ID of the target thread + * at offset 1 a descriptor representing an array of TRegisterInfo + register IDs + * at offset 2 a descriptor representing an array of TRegister register + values + * at offset 3 a descriptor representing an array into which TUint8 + register flags will be written + +@leave KErrArgument if the max length of the array at offset 1 is not a + multiple of sizeof(TRegisterInfo), if the max length of the array + at offset 2 is not a multiple of sizeof(TRegister), if the max + length of the array at offset 3 is not a multiple of sizeof(TUint8), if + any of the descriptors have max length of 0, or if the three + descriptors do not represent the same number of registers, + KErrNoMemory if there is insufficient memory, + KErrDied, if the thread with thread ID aThreadId is dead +*/ +void CSecuritySvrSession::WriteRegistersL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::WriteRegistersL()\n" ); + + const TThreadId threadId = ReadTThreadIdL(aMessage, 0); + + CheckAttachedL(threadId, aMessage, EFalse); + + //number of registers attempting to set + TUint32 numberOfRegisters; + + //check length of descriptors is acceptable + ValidateRegisterBuffersL(aMessage, numberOfRegisters); + + // Passed register ids will be saved in this descriptor. + RBuf8 ids; + + //allocate buffer + ids.CreateL(numberOfRegisters * sizeof(TRegisterInfo)); + + // Do the right cleanup if anything subsequently goes wrong + ids.CleanupClosePushL(); + + //read the data from the client thread + aMessage.ReadL(1, ids); + + // Passed register values will be saved in this descriptor. + RBuf8 values; + + //allocate buffer + values.CreateL(aMessage.GetDesMaxLength(2)); + // Do the right cleanup if anything subsequently goes wrong + values.CleanupClosePushL(); + //read the data from the client thread + aMessage.ReadL(2,values); + + HBufC8 *flagsData = HBufC8::NewLC(numberOfRegisters*sizeof(TUint8)); + TPtr8 flags(flagsData->Des()); + + //get register info and return relevant parts back to agent + User::LeaveIfError(Server().iKernelDriver.WriteRegisters(threadId, ids, values, flags)); + + //write flags data back + aMessage.WriteL(3, flags); + + CleanupStack::PopAndDestroy(flagsData); + CleanupStack::PopAndDestroy(&values); + CleanupStack::PopAndDestroy(&ids); + + aMessage.Complete(KErrNone); + } + +/** +Processes an attach request from a debug agent. Gets the target debug +processes' original FileName as an argument. The method sets completion +status of the aMessage argument to KErrNone if successfully attached and to +another of the system wide error codes if there were problems. + +@param aMessage contains: + * a boolean at offset 0 which indicates whether the agent wishes to + attach passively + * a buffer at offset 1 which contains the FileName + of the target debug process. +*/ +void CSecuritySvrSession::AttachProcessL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::AttachProcessL()\n" ); + + const TBool passive = aMessage.Int0(); + + TInt deslen = aMessage.GetDesLengthL(1); + + // Passed data will be saved in this descriptor. + RBuf processName; + + // Max length set to the value of "deslen", but current length is zero + processName.CreateL(deslen); + + // Do the right cleanup if anything subsequently goes wrong + processName.CleanupClosePushL(); + + // Copy the client's descriptor data into our buffer. + aMessage.ReadL(1,processName); + + // + // Security Check + // + // It is not permitted to debug the debug security server! + // + // get the secure id of the executable + TUid secureId(TUid::Null()); + GetSecureIdL(processName, secureId); + if (KUidDebugSecurityServer.iUid == secureId.iUid) + { + // The debug agent has requested to debug the Debug Security Server + // This is either an error, or an attempt to breach security. We + // therefore refuse to agree to this request, and return KErrPermissionDenied + LOG_MSG("Debug Agent attempted to debug the Debug Security Server"); + User::Leave(KErrPermissionDenied); + } + + // Check the OEM Debug token capabilities + GetDebugAgentOEMTokenCapsL(); + + // Get the Security info via rlibrary::getinfo + RLibrary::TInfo info; + TPckg infoBuf(info); + + TInt err = RLibrary::GetInfo(processName, infoBuf); + if (err != KErrNone) + { + LOG_MSG2("Cannot parse the target executable header, err=%d", err); + // Could not read the header for this executable :-( + CleanupStack::PopAndDestroy(&processName); + aMessage.Complete(err); + return; + } + + // Special case for AllFiles - OEM Debug tokens MUST have + // AllFiles, as this is what allows them to read contents + // of other executables. + TBool checkDebuggable = ETrue; + + // Does an OEM Debug Token permit debug where it would normally not be + // permitted? + if ( Server().OEMTokenPermitsDebugL(iOEMDebugCapabilities, info.iSecurityInfo.iCaps) ) + { + // OEM Debug token is valid and has sufficient capabilities + LOG_MSG("CSecuritySvrSession::AttachProcessL() - Debug Agent has sufficient capabilites based on OEM Debug Token"); + + checkDebuggable = EFalse; + } + + if (checkDebuggable) + { + // OEM Debug token (if any), does not confer sufficient capabilities to + // debug the specified target executable. Therefore debugging can only + // be permitted if the target executable itself has been built as 'Debuggable' + LOG_MSG("CSecuritySvrSession::AttachProcessL() - Debug Agent has insufficient capabilites based on OEM Debug Token"); + + IsDebuggableL(processName); + } + + User::LeaveIfError(Server().AttachProcessL(processName, iDebugAgentProcessId, passive)); + + // Inform the kernel driver about the attachment, so that it + // can track per-agent data about the process. + RBuf8 processName8; + + processName8.CreateL(deslen); + + processName8.CleanupClosePushL(); + + processName8.Copy(processName); + + User::LeaveIfError(Server().iKernelDriver.AttachProcess(processName8, iDebugAgentProcessId.Id())); + + // Create an Active Object to handle asynchronous calls to GetEvent + CSecuritySvrAsync* handler = CSecuritySvrAsync::NewL(this,processName8,iDebugAgentProcessId); + + err = iAsyncHandlers.Insert(handler,0); + if (err != KErrNone) + { + // If we don't have an asynchronous handler, we should detach + // the driver as well. + Server().iKernelDriver.DetachProcess(processName8,iDebugAgentProcessId.Id()); + Server().DetachProcess(processName, iDebugAgentProcessId); + // The DSS should NEVER panic itself. If the above calls fail, so be it we will attempt to limp on + } + + User::LeaveIfError(err); + + CleanupStack::PopAndDestroy(&processName8); + + CleanupStack::PopAndDestroy(&processName); + + aMessage.Complete(KErrNone); + } + + +/** +Processes an attach request from a debug agent from all processes. +The method sets completion status of the aMessage argument to KErrNone +if successfully attached and to another of the system wide error codes +if there were problems. + +@param aMessage contains no data +*/ +void CSecuritySvrSession::AttachAllL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::AttachAllL()\n" ); + + + // Run the OEM Debug token, if run ok then sets iOEMDebugCapabilities + GetDebugAgentOEMTokenCapsL(); + + // Debug token must have All caps to use AttachToAll + TCapabilitySet allCaps; + allCaps.SetAllSupported(); + if (!Server().OEMTokenPermitsDebugL(iOEMDebugCapabilities, allCaps)) + { + LOG_MSG("Client's OEM token doesn't have capability ALL required for AttachAll()"); + User::Leave(KErrPermissionDenied); + } + + + User::LeaveIfError(Server().AttachProcessL(_L("*"), iDebugAgentProcessId, EFalse)); + + TBuf8<1> KStar8=_L8("*"); + + User::LeaveIfError(Server().iKernelDriver.AttachProcess(KStar8, iDebugAgentProcessId.Id())); + + // Create an Active Object to handle asynchronous calls to GetAllEvent + CSecuritySvrAsync* handler = CSecuritySvrAsync::NewL(this,KStar8,iDebugAgentProcessId); + TInt err = iAsyncHandlers.Insert(handler,0); + if (err != KErrNone) + { + // If we don't have an asynchronous handler, we should detach + // the driver as well. + Server().iKernelDriver.DetachProcess(KStar8,iDebugAgentProcessId.Id()); + Server().DetachProcess(_L("*"), iDebugAgentProcessId); + } + + User::LeaveIfError(err); + + aMessage.Complete(KErrNone); + } + + +/** +Reads the OEM Debug Token associated with the debug agent if any. The OEM Debug Token +allows the Debug Agent to debug certain executables which have not been built as +'Debuggable'. + +This works as follows: The OEM Debug Token is an executable with a special name +of the form "OEMDebug_.exe" where is the Secure ID of the Debug Agent +in hexadecimal. For example: "OEMDebug_F123ABCD.exe" would be a valid name. This token executable +must be signed with 'AllFiles' + X, where X is the set of PlatSec capabilities that are +possessed by the target executable to be debugged. + +This function reads the capabilities possessed by the token by creating a process based +on the executable, and reading the TSecurityInfo associated with the process. This ensures +that the loader has validated the token has not been tampered with and that the security +information is valid. + +The security information is then stored for future use as member data in iOEMDebugCapabilities. + +Leaves if there is an error, otherwise simply fills in the capabilities +in iOEMDebugCapabilities. + +It is not an error for the OEM Debug token not to exist. In this case, the function simply returns. +*/ +void CSecuritySvrSession::GetDebugAgentOEMTokenCapsL(void) + { + if (iOEMDebugCapabilities.HasCapability(ECapabilityAllFiles)) + { + // Then we've already read the caps - wasteful to read them again + return; + } + + // Obtain the security info about the debug agent process + //get the debug agent's process + RProcess debugAgentProcess; + + CleanupClosePushL(debugAgentProcess); + + debugAgentProcess.Open(iDebugAgentProcessId); + + // We have now obtained a process handle based on the token executable, so we can check its security properties. + TSecurityInfo secInfo(debugAgentProcess); + + // Compute the name of the OEM debug token based on the SID of the debug agent + _LIT(KDSSOEMDebugTokenPrefix,"OEMDebug_"); + _LIT(KDSSOEMDebugTokenAppendFmt,"%08X.exe"); + + RBuf agentTokenName; + agentTokenName.CreateL(KDSSOEMDebugTokenPrefix().Size()+8+1); // allow space for SID+null terminator + agentTokenName.CleanupClosePushL(); + + agentTokenName.SetLength(0); + + // Add OEMDebug_ + agentTokenName.Append(KDSSOEMDebugTokenPrefix()); + + // Add debug agent Secure ID + agentTokenName.AppendFormat(KDSSOEMDebugTokenAppendFmt,secInfo.iSecureId.iId); + + // just log the token name for the moment. + RBuf8 agentTokenName8; + + agentTokenName8.CreateL(agentTokenName.Length()+1); + + agentTokenName8.CleanupClosePushL(); + + agentTokenName8.Copy(agentTokenName); + + agentTokenName8.Append(TChar(0)); + + LOG_MSG2("CSecuritySvrSession::GetDebugAgentOEMTokenCapsL() - OEM Debug Token Name is %s",agentTokenName8.Ptr()); + + // Cleanup + CleanupStack::PopAndDestroy(&agentTokenName8); + + // Now locate and start the executable... + RProcess agentToken; + TInt err = agentToken.Create(agentTokenName, KNullDesC); + if (KErrNone != err) + { + // Failed to create a process based on the token, just give up + LOG_MSG2("CSecuritySvrSession::GetDebugAgentOEMTokenCapsL() - Could not create process based on token due to err 0x%8x\n",err); + + // Cleanup remaining items from the stack + CleanupStack::PopAndDestroy(&agentTokenName); + + CleanupStack::PopAndDestroy(&debugAgentProcess); + return; + } + + // Synchronise with the process to make sure it hasn't died straight away + TRequestStatus stat; + agentToken.Rendezvous(stat); + if (stat != KRequestPending) + { + // logon failed - agentToken is not yet running, so cannot have terminated + agentToken.Kill(0); // Abort startup + } + + // store the OEM Debug Token security data + TSecurityInfo agentSecInfo(agentToken); + + // Note capabilities for future use + iOEMDebugCapabilities=agentSecInfo.iCaps; + + // resume the token. It _should_ just exit, but we don't really care. + agentToken.Resume(); + + // Wait to synchronise with agentToken - if it dies in the meantime, it + // also gets completed + User::WaitForRequest(stat); + + // Just close the handle to it again. + agentToken.Close(); + + // Cleanup remaining items from the stack + CleanupStack::PopAndDestroy(&agentTokenName); + + CleanupStack::PopAndDestroy(&debugAgentProcess); + + } + +/** + Checks whether the file passed in as aExecutable is XIP or not + + @param aExecutable file to check + @return ETrue if the file is XIP, EFalse otherwise + */ +TBool CSecuritySvrSession::IsExecutableXipL(RFile& aExecutable) + { + TUint atts; + User::LeaveIfError(aExecutable.Att(atts)); + + return atts & KEntryAttXIP; + } + +/** + Gets access to the symbian crash partition for crash access operation. + */ +void CSecuritySvrSession::ConnectCrashPartitionL (void) + { + LOG_MSG("CSecuritySvrSession::ConnectCrashPartitionL()"); + + TBool changed; + TInt error = KErrNone; + TInt i=0; + + //Intialising to EFalse + iCrashConnected = EFalse; + + TPckg capsBuf(iCaps); + + //check for the symbian crash partition + for (i=0; i= minimumHeaderSize); + } + +/** + Opens a file handle to aFileName using aFileHandle + @param aFileName file to open handle to + @param aFs file system to use to open the handle + @param aFileHandle file handle to open + + @leave one of the system wide error codes + */ +void CSecuritySvrSession::OpenFileHandleL(const TDesC& aFileName, RFs& aFs, RFile& aFileHandle) + { + TInt err = aFileHandle.Open(aFs, aFileName, EFileRead | EFileShareReadersOnly); + if (err != KErrNone) + { + // Could not open the file for reading + LOG_MSG("CSecuritySvrSession::OpenFileHandleL - Failed to open executable\n"); + + User::Leave(err); + } + } + +/** + Checks whether an executable has the debug bit set + + @param aHeaderData buffer containing the header of the executable + @param aXip indication of whether the executable is XIP or not + + @return ETrue if debug bit is set, EFalse otherwise + */ +TBool CSecuritySvrSession::IsDebugBitSet(const TDesC8& aHeaderData, const TBool aXip) + { + if(!CheckSufficientData(aHeaderData, aXip)) + { + return EFalse; + } + + if (aXip) + { + TRomImageHeader* hdr = (TRomImageHeader*)aHeaderData.Ptr(); + return (hdr->iFlags & KRomImageDebuggable); + } + else + { + // it is an epoc32 image + E32ImageHeaderV* hdr = (E32ImageHeaderV*)aHeaderData.Ptr(); + return (hdr->iFlags & KImageDebuggable); + } + } + +/** +Determines whether a particular executable is marked as 'debuggable' + +Notes: +This function is currently hard coded to understand the format of e32 and +TRomImage file headers. Ideally this will be replaced by a call to RLibrary::GetInfo +which can return the 'debuggable' information. Unfortunately, this call currently +does not provide the information for XIP executables :-( + +@leave KErrPermissionDenied if the debug bit is not set, or one of the other +system wide error codes +*/ +void CSecuritySvrSession::IsDebuggableL(const TDesC& aFileName) + { +#ifndef IGNORE_DEBUGGABLE_BIT + + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + RFile targetExe; + OpenFileHandleL(aFileName, fs, targetExe); + CleanupClosePushL(targetExe); + + // Read in the entire header + RBuf8 e32HdrBuf; + e32HdrBuf.CreateL(RLibrary::KRequiredImageHeaderSize); + e32HdrBuf.CleanupClosePushL(); + + // Read the entire header as far as possible + TInt err = targetExe.Read(e32HdrBuf); + if (err != KErrNone) + { + // Could not read the file + LOG_MSG("CSecuritySvrSession::IsDebuggableL - Failed to read executable\n"); + + User::Leave(err); + } + + if(!CheckSufficientData(e32HdrBuf, IsExecutableXipL(targetExe))) + { + User::Leave(KErrGeneral); + } + + if(! IsDebugBitSet(e32HdrBuf, IsExecutableXipL(targetExe))) + { + User::Leave(KErrPermissionDenied); + } + CleanupStack::PopAndDestroy(3, &fs); + +#else + LOG_MSG("CSecuritySvrSession::IsDebuggableL() Debuggable bit temporarily ignored!!!"); +#endif + } + +/** +Processes a detach request from a debug agent. Gets the target debug +processes' original FileName as an argument. The method sets completion +status of the aMessage argument to KErrNone if successfully detached and to +another of the system wide error codes if there were problems. + +@param aMessage contains: + * a buffer at offset 0 which contains the FileName + of the target debug process. +*/ +void CSecuritySvrSession::DetachProcessL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::DetachProcessL()\n" ); + + TInt deslen = aMessage.GetDesLengthL(0); + // Passed data will be saved in this descriptor. + RBuf processName; + + // Max length set to the value of "deslen", but current length is zero + processName.CreateL(deslen); + + // Do the right cleanup if anything subsequently goes wrong + processName.CleanupClosePushL(); + + // Copy the client's descriptor data into our buffer. + aMessage.ReadL(0,processName); + + User::LeaveIfError(Server().DetachProcess(processName, iDebugAgentProcessId)); + + // Inform the kernel driver about the detachment, so that + // it can stop tracking per-agent data for the debugged process. + RBuf8 processName8; + + processName8.CreateL(deslen); + + processName8.CleanupClosePushL(); + + processName8.Copy(processName); + + // Remove the Asynchronous Object associated with this process + for(TInt i=0; iProcessName()) == 0) + { + delete iAsyncHandlers[i]; + iAsyncHandlers.Remove(i); + + break; + } + } + + // Inform the driver that we are no longer attached to this process + User::LeaveIfError(Server().iKernelDriver.DetachProcess(processName8,iDebugAgentProcessId.Id())); + + CleanupStack::PopAndDestroy(&processName8); + CleanupStack::PopAndDestroy(&processName); + + aMessage.Complete(KErrNone); + } + +/** +Processes a DetachAll request from a debug agent. +The method sets completion status of the aMessage argument to +KErrNone if successfully detached and to +another of the system wide error codes if there were problems. + +@param aMessage contains: + * a buffer at offset 0 which contains the FileName + of the target debug process. +*/ +void CSecuritySvrSession::DetachAllL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::DetachAllL()" ); + + User::LeaveIfError(Server().DetachProcess(_L("*"), iDebugAgentProcessId)); + + TBuf8<1> KStar8=_L8("*"); + + TBool found = EFalse; + + // Remove the Asynchronous Object associated with the AttachAll, not the rest + for(TInt i=0; iProcessName().Compare(KStar8) == 0) + { + delete iAsyncHandlers[i]; + iAsyncHandlers.Remove(i); + User::LeaveIfError(Server().iKernelDriver.DetachProcess(KStar8,iDebugAgentProcessId.Id())); + found = ETrue; + break; + } + } + + if( !found ) + { + LOG_MSG2( "CSecuritySvrSession::DetachAllL() : Did not find the asynch handler for agent 0x%lx", + iDebugAgentProcessId.Id() ); + User::Leave(KErrNotFound); + } + + aMessage.Complete(KErrNone); + } + +/** +@param aMessage The RMessage2 object is expected to contain: + * aMessage.Int0() - TDes8 Containing the process name. + * aMessage.Int1() - Address of TPtr8 containing TEventInfo + +*/ +void CSecuritySvrSession::GetEventL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::GetEventL()\n" ); + + // Local descriptor to contain target process name + TInt deslen = aMessage.GetDesLengthL(0); + + RBuf processName; + + processName.CreateL(deslen); + + processName.CleanupClosePushL(); + + // Read the target process name into processName + aMessage.ReadL(0,processName); + + // Check if debug agent is attached to process + if(!Server().CheckAttachedProcess(processName, aMessage, EFalse)) + { + LOG_MSG("CSecuritySvrSession::GetEventL() - Not attached to this process\n"); + + // Debug Agent is not attached at all to the requested process + User::Leave(KErrPermissionDenied); + } + + // Identify which process is being debugged, so that + // we can locate the appropriate active object handler. + RBuf8 processName8; + + processName8.CreateL(processName.Length()); + + processName8.CleanupClosePushL(); + + processName8.Copy(processName); + + // Find the Asynchronous Object associated with this process, + // as it is permissible to have an outstanding GetEvent call + // for each attached process. + TBool foundHandler = EFalse; + for(TInt i=0; iProcessName()) == 0) + { + iAsyncHandlers[i]->GetEvent(aMessage); + foundHandler = ETrue; + break; + } + } + + if (foundHandler == EFalse) + { + // could not find an async handler object. Report the problem. + LOG_MSG("CSecuritySvrSessionL - Could not find a handler object\n"); + User::Leave(KErrNotFound); + } + + // Actually make the driver call, passing in the agent Id + // so that the driver knows which per-agent event queue + // to interrogate to retrieve the latest event. + CleanupStack::PopAndDestroy(&processName8); + CleanupStack::PopAndDestroy(&processName); + } + +/** +Cancels a pre-issued GetEvent call for a specific debugged process. + +@param aMessage.Int0() - TDes8 containing aProcessName +*/ +void CSecuritySvrSession::CancelGetEventL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::CancelGetEventL()\n" ); + + // Local descriptor to contain target process name + TInt deslen = aMessage.GetDesLengthL(0); + + RBuf processName; + + processName.CreateL(deslen); + + processName.CleanupClosePushL(); + + // Read the target process name into processName + aMessage.ReadL(0,processName,0); + + // Debug Agent is not an active debugger. Check if the DA is passively attached + if(!Server().CheckAttachedProcess(processName, aMessage, EFalse)) + { + // Debug Agent is not attached at all to the requested process + User::Leave(KErrPermissionDenied); + } + + // Identify the appropriate active object associate + // with this process. + RBuf8 processName8; + + processName8.CreateL(processName.Length()); + + processName8.CleanupClosePushL(); + + processName8.Copy(processName); + + // Find the Asynchronous Object associated with this process + TBool foundHandler = EFalse; + for(TInt i=0; iProcessName()) == 0) + { + + // Found the AO handler, so cancel the outstanding getevent call. + iAsyncHandlers[i]->Cancel(); + foundHandler = ETrue; + break; + } + } + + if(!foundHandler) + { + // We could not found a handler, so report the problem to the debug agent + User::Leave(KErrNotFound); + } + + //do cleanup + CleanupStack::PopAndDestroy(&processName8); + CleanupStack::PopAndDestroy(&processName); + + aMessage.Complete(KErrNone); + } + +/* + Purpose: Sets the required event action to be taken for a specific + process and event combination + +@param aMessage The RMessage2 object is expected to contain: + * aMessage.Int0() - TDes8 Containing the process name. + * aMessage.Int1() - TEventType + * aMessage.Int2() - TKernelEventAction + * +*/ +void CSecuritySvrSession::SetEventActionL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::SetEventActionL()\n" ); + + // Local descriptor to contain target process name + TInt deslen = aMessage.GetDesLengthL(0); + + RBuf processName; + + processName.CreateL(deslen); + + processName.CleanupClosePushL(); + + // Read the target process name into processName + aMessage.ReadL(0,processName); + + //check that the agent has attached to the target process + if(!Server().CheckAttachedProcess(processName, aMessage, EFalse)) + { + // Debug Agent is not attached at all to the requested process + User::Leave(KErrPermissionDenied); + } + + // Extract and validate the arguments from aMessage + TUint32 event = aMessage.Int1(); + if (event >= EEventsLast) + { + // Supplied event Id was not recognised + User::Leave(KErrArgument); + } + + TUint32 action = aMessage.Int2(); + if(action >= EActionLast) + { + // Supplied event action was not recognised + User::Leave(KErrArgument); + } + + RBuf8 processName8; + + processName8.CreateL(processName.Length()); + + processName8.CleanupClosePushL(); + + processName8.Copy(processName); + + // Make the call to the device driver + TInt err = Server().iKernelDriver.SetEventAction(processName8, \ + (TEventType)event,\ + (TKernelEventAction)action,\ + iDebugAgentProcessId.Id()); + + User::LeaveIfError(err); + + CleanupStack::PopAndDestroy(&processName8); + CleanupStack::PopAndDestroy(&processName); + + aMessage.Complete(KErrNone); +} + +/** +Purpose: Single-step a thread for a specified number of instructions + +@param aMessage.Ptr0() - Thread Id of the thread to be stepped +@param aMessage.Int1() - Number of instructions to step. + +@leave one of the system wide error codes + +*/ +void CSecuritySvrSession::StepL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::StepL()\n" ); + + const TThreadId threadId = ReadTThreadIdL(aMessage, 0); + const TInt32 numSteps = aMessage.Int1(); + + CheckAttachedL(threadId, aMessage, EFalse); + + User::LeaveIfError(Server().iKernelDriver.Step( threadId, numSteps )); + + aMessage.Complete(KErrNone); + } + +/** + * This checks whether or not the agent is permitted access to the flash partition + * @return KErrNone if allowed, otherwise one of the system wide error codes + * @leave one of the system wide error codes + */ +TInt CSecuritySvrSession::CheckFlashAccessPermissionL(const RThread& aClientThread) + { + // Read the OEM Debug token capabilities (if any) + GetDebugAgentOEMTokenCapsL(); + + if(Server().OEMTokenPermitsFlashAccessL((iOEMDebugCapabilities))) + { + return KErrNone; + } + + return KErrPermissionDenied; + } + +/** +Purpose: Read the crash log from the crash flash partition +@param aMessage.Int0() - Position to read from. +@param aMessage.Ptr1() - Buffer to hold the data retrieved +@param aMessage.Int2() - Size of the data to read. + +@leave one of the system wide error codes +*/ +void CSecuritySvrSession::ReadCrashLogL (const RMessage2& aMessage) + { + //get the debug agent's thread and push handle onto clean up stack + RThread clientThread; + User::LeaveIfError(aMessage.Client(clientThread)); + CleanupClosePushL(clientThread); + + TInt err = CheckFlashAccessPermissionL(clientThread); + + CleanupStack::PopAndDestroy(&clientThread); + + if(KErrNone != err) + { + LOG_MSG2( "CSecuritySvrSession::ReadCrashLogL() Access Not Granted - [%d]\n", err ); + aMessage.Complete(err); + return; + } + + //Check whether drive connected. + if(!iCrashConnected) + ConnectCrashPartitionL(); + + TInt readPosition = aMessage.Int0(); //read position + + TInt readSize = aMessage.Int2(); //read size + + RBuf8 readBuf; + readBuf.CreateL(readSize); + readBuf.CleanupClosePushL(); + + err = iLocalDrive.Read (readPosition, readSize, readBuf); + + //write the list data back + aMessage.WriteL (1, readBuf); + + CleanupStack::PopAndDestroy (&readBuf); + + //Complete message + aMessage.Complete(err); + } +/** +Purpose: Function to write the crash config to the crash flash partition + +@param aMessage.Int0() - write position in bytes from start position in flash partition. +@param aMessage.Ptr1() - Buffer containing the data to be written onto the flash. + The size could be 0 if only flash partition size is needed. +@param aMessage.Int2() - returns the size of the flash partition. + +@leave one of the system wide error codes +*/ +void CSecuritySvrSession::WriteCrashConfigL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::WriteCrashConfigL()\n" ); + + //get the debug agent's thread and push handle onto clean up stack + RThread clientThread; + User::LeaveIfError(aMessage.Client(clientThread)); + CleanupClosePushL(clientThread); + + TInt err = CheckFlashAccessPermissionL(clientThread); + + CleanupStack::PopAndDestroy(&clientThread); + + if(KErrNone != err) + { + LOG_MSG2( "CSecuritySvrSession::WriteCrashConfigL() Access Not Granted - [%d]\n", err ); + aMessage.Complete(err); + return; + } + + //Check whether drive connected. + if(!iCrashConnected) + ConnectCrashPartitionL(); + + // Get the length of the buffer + TInt deslen = aMessage.GetDesLengthL(1); + + RBuf8 dataBuf; + dataBuf.CreateL(deslen); + dataBuf.CleanupClosePushL(); + + // data to be written to flash + aMessage.ReadL(1,dataBuf); + + TUint32 position = aMessage.Int0(); //position to start from + + err = iLocalDrive.Write(position,(const TDesC8&)dataBuf); + + TPtr8 dataSize((TUint8*)&deslen,4, 4); + + //write the size of the data written back + aMessage.WriteL(2,dataSize); + + //destroy buffer + CleanupStack::PopAndDestroy(&dataBuf); + + aMessage.Complete(err); + } +/** +Purpose: Method to erase the crash flash block + +@param aMessage.Int0() - write position in bytes from start position in flash partition. +@param aMessage.Int2() - Number of blocks to erase. + +@leave one of the system wide error codes +*/ + +void CSecuritySvrSession::EraseCrashLogL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::EraseCrashLogL()\n" ); + + //get the debug agent's thread and push handle onto clean up stack + RThread clientThread; + User::LeaveIfError(aMessage.Client(clientThread)); + CleanupClosePushL(clientThread); + + TInt err = CheckFlashAccessPermissionL(clientThread); + + CleanupStack::PopAndDestroy(&clientThread); + + if(KErrNone != err) + { + LOG_MSG2( "CSecuritySvrSession::EraseCrashLogL() Access Not Granted - [%d]\n", err ); + aMessage.Complete(err); + return; + } + + //Check whether drive connected. + if(!iCrashConnected) + ConnectCrashPartitionL(); + + TInt64 position = aMessage.Int0(); + TInt size = aMessage.Int1(); + + //Format drive + err = iLocalDrive.Format(position,size*iCaps.iEraseBlockSize); + + aMessage.Complete(err); + } + +/** +Purpose: Method to erase the entire crash flash block +@leave one of the system wide error codes +*/ + +void CSecuritySvrSession::EraseEntireCrashLogL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::EraseEntireCrashLogL()\n" ); + + //get the debug agent's thread and push handle onto clean up stack + RThread clientThread; + User::LeaveIfError(aMessage.Client(clientThread)); + CleanupClosePushL(clientThread); + + TInt err = CheckFlashAccessPermissionL(clientThread); + + CleanupStack::PopAndDestroy(&clientThread); + + if(KErrNone != err) + { + LOG_MSG2( "CSecuritySvrSession::EraseEntireCrashLogL() Access Not Granted - [%d]\n", err ); + aMessage.Complete(err); + return; + } + + //Check whether drive connected. + if(!iCrashConnected) + ConnectCrashPartitionL(); + + TUint numberBlocks = iCaps.iSize /iCaps.iEraseBlockSize; + + //Format drive + for(TInt i = 0; i < numberBlocks; i++) + { + err = iLocalDrive.Format(i*iCaps.iEraseBlockSize,iCaps.iEraseBlockSize); + if(KErrNone != err) + { + RDebug::Printf("err = %d", err); + aMessage.Complete(err); + return; + } + } + + + aMessage.Complete(err); + } + + +/** +Purpose: Kill a specified process + +@param aMessage.Ptr0() - Process Id of the thread to be stepped +@param aMessage.Int1() - Reason code to supply when killing the process. + +@leave one of the system wide error codes + +*/ +void CSecuritySvrSession::KillProcessL(const RMessage2& aMessage) + { + LOG_MSG( "CSecuritySvrSession::KillProcessL()\n" ); + + const TProcessId processId = ReadTProcessIdL(aMessage, 0); + const TInt32 reason = aMessage.Int1(); + + CheckAttachedL(processId, aMessage, EFalse); + + User::LeaveIfError(Server().iKernelDriver.KillProcess( processId, reason )); + + aMessage.Complete(KErrNone); + } + +/** Gets the secure id of aFileName + @param aFileName file name of executable to get SID for + @param aSecureId on return will contain the SID of aFileName + + @leave one of the system wide error codes + */ +void CSecuritySvrSession::GetSecureIdL(const TDesC& aFileName, TUid& aSecureId) + { + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + RFile targetExe; + OpenFileHandleL(aFileName, fs, targetExe); + CleanupClosePushL(targetExe); + + // Read in the entire header + RBuf8 e32HdrBuf; + e32HdrBuf.CreateL(RLibrary::KRequiredImageHeaderSize); + e32HdrBuf.CleanupClosePushL(); + + // Read the entire header as far as possible + TInt err = targetExe.Read(e32HdrBuf); + if (err != KErrNone) + { + // Could not read the file + LOG_MSG("CSecuritySvrSession::GetSecureIdL - Failed to read executable\n"); + + User::Leave(err); + } + + if(!CheckSufficientData(e32HdrBuf, IsExecutableXipL(targetExe))) + { + User::Leave(KErrGeneral); + } + + aSecureId = GetSecureIdL(e32HdrBuf, IsExecutableXipL(targetExe)); + + CleanupStack::PopAndDestroy(3, &fs); + } + +/** Get the secure id from aHeaderData + @param aHeaderData an executable's header data to read SID from + @param aXip indication of whether the header data is from an XIP file + + @return secure ID from aHeaderData + */ +TUid CSecuritySvrSession::GetSecureIdL(const TDesC8& aHeaderData, TBool aXip) + { + if(!CheckSufficientData(aHeaderData, aXip)) + { + User::Leave(KErrGeneral); + } + + if (aXip) + { + TRomImageHeader* hdr = (TRomImageHeader*)aHeaderData.Ptr(); + return TUid::Uid(hdr->iS.iSecureId); + } + else + { + // it is an epoc32 image + E32ImageHeaderV* hdr = (E32ImageHeaderV*)aHeaderData.Ptr(); + return TUid::Uid(hdr->iS.iSecureId); + } + } + +/** +@param aMessage contains: + * aMessage.Ptr0() a TListDetails object + * aMessage.Ptr1() a client supplied TDes8 for the driver to return data in + * aMessage.Ptr2() a TUint32 for the driver to return the size of the requested listing's data in + +@leave KErrTooBig if the buffer passed as argument 1 of aMessage is too + small to contain the requested data, + KErrNoMemory if a temporary buffer could not be allocated, + or one of the other system wide error codes +*/ +void CSecuritySvrSession::GetListL(const RMessage2& aMessage) + { + LOG_MSG("CSecuritySvrSession::GetListL()"); + + // buffer to write list data into before copying back to agent + RBuf8 listDetailsBuf; + + //allocate buffer + listDetailsBuf.CreateL(sizeof(TListDetails)); + + // Do the right cleanup if anything subsequently goes wrong + listDetailsBuf.CleanupClosePushL(); + + //read the data from the client thread + aMessage.ReadL(0, listDetailsBuf); + TListDetails* listDetails = (TListDetails*)listDetailsBuf.Ptr(); + + //get the type of list requested + TListId type = (TListId)aMessage.Int0(); + + //create a buffer to store the data in + RBuf8 buffer; + buffer.CreateL(aMessage.GetDesMaxLength(1)); + buffer.CleanupClosePushL(); + + //create a temporary variable to potentially store data length in + TUint32 size = 0; + + TInt err = KErrNone; + + // the executables list is generated in the DSS rather than in the driver + // so is treated separately + if(listDetails->iListId == EExecutables) + { + if(listDetails->iListScope != EScopeGlobal) + { + User::Leave(KErrArgument); + } + if(listDetails->iTargetId != 0) + { + User::Leave(KErrArgument); + } + err = GetExecutablesListL(buffer, size); + } + else + { + err = Server().iKernelDriver.GetList(listDetails->iListId, listDetails->iListScope, listDetails->iTargetId, iDebugAgentProcessId, buffer, size); + } + + if(err == KErrNone) + { + //write the list data back + aMessage.WriteL(1, buffer); + } + + TPtr8 sizePtr((TUint8*)&size, sizeof(TUint32), sizeof(TUint32)); + //write size back to agent + aMessage.WriteL(2, sizePtr); + + CleanupStack::PopAndDestroy(&buffer); + CleanupStack::PopAndDestroy(&listDetailsBuf); + + aMessage.Complete(err); + } + +/** +Gets the executables list and returns it in aBuffer if it's big enough + +@param aBuffer caller supplied buffer to write data into +@param aSize on return contains the size of the data in the buffer, or the + size that the buffer would need to be to contain the data + +@return KErrNone on success, or KErrTooBig if the requested data will not fit in aBuffer + +@leave one of the system wide error codes +*/ +TInt CSecuritySvrSession::GetExecutablesListL(TDes8& aBuffer, TUint32& aSize) const + { + LOG_MSG("CSecuritySvrSession::GetExecutablesList()"); + + //initialise values and connect to file system + aSize = 0; + aBuffer.SetLength(0); + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + // uids corresponding to executable image + TUidType uids(KExecutableImageUid, KNullUid, KNullUid); + + //create a string containing the directory name. The drive letter is represented + //by X but will be replaced by the appropriate drive letter for each drive + _LIT(KColonSysBin,":\\sys\\bin\\"); + + //create a modifiable copy of KColonSysBin, preceeded by an empty space for the drive letter + RBuf dirName; + dirName.CreateL(1 + KColonSysBin().Length()); + dirName.CleanupClosePushL(); + + //set the length to 1 (to later fill with the drive letter) and then append KColonSysBin + dirName.SetLength(1); + dirName.Append(KColonSysBin()); + + //get the list of valid drives for the device + TDriveList driveList; + User::LeaveIfError(fs.DriveList(driveList)); + + //check each valid sys/bin directory for executables + for(TInt i=0; iCount(); j++) + { + //will store x:\sys\bin\ type string + RBuf fullPathName; + + TUint16 nameLength = dirName.Length() + (*localDir)[j].iName.Length(); + fullPathName.CreateL(nameLength); + fullPathName.CleanupClosePushL(); + fullPathName.Copy(dirName); + fullPathName.Append((*localDir)[j].iName); + + //add the data to the buffer + AppendExecutableData(aBuffer, aSize, fullPathName); + + //do cleanup + CleanupStack::PopAndDestroy(&fullPathName); + } + + //do cleanup + CleanupStack::PopAndDestroy(localDir); + } + + //do cleanup + CleanupStack::PopAndDestroy(2, &fs); + + //return appropriate value as to whether the kernel's data was too big + return (aSize <= aBuffer.MaxLength()) ? KErrNone : KErrTooBig; + } + + +/** + Append data to aBuffer and update size of aSize if the data will fit. If it will + not fit then just puts the nee size in aSize. + + @param aBuffer buffer to append the data to + @param aSize on return contains the new size of the buffer if the data could be + appended, otherwise aSize is updated to reflect the size the buffer would have if + the data had fitted. + @param aEntryName file name of the entry to add to the buffer + */ +void CSecuritySvrSession::AppendExecutableData(TDes8& aBuffer, TUint32& aSize, const TDesC& aEntryName) const + { + //update aSize to include the size of the data for this entry + aSize = Align4(aSize + sizeof(TExecutablesListEntry) + (2*aEntryName.Length()) - sizeof(TUint16)); + + //if the data will fit, and we haven't already stopped putting data in, then append the data, + //if we've stopped putting data in then aSize will be bigger than aBuffer.MaxLength() + if(aSize <= aBuffer.MaxLength()) + { + TExecutablesListEntry& entry = *(TExecutablesListEntry*)(aBuffer.Ptr() + aBuffer.Length()); + //check whether an agent has registered to actively debug fullPathName + TBool activelyDebugged = IsDebugged(aEntryName, EFalse); + entry.iIsActivelyDebugged = activelyDebugged ? 1 : 0; + + //check whether any agents have registered to passively debug fullPathName + TBool passivelyDebugged = IsDebugged(aEntryName, ETrue); + entry.iIsPassivelyDebugged = passivelyDebugged ? 1 : 0; + + entry.iNameLength = aEntryName.Length(); + TPtr name(&(entry.iName[0]), aEntryName.Length(), aEntryName.Length()); + name = aEntryName; + //pad the buffer to a four byte boundary + aBuffer.SetLength(aSize); + } + } +/** +Helper function + +Write data back to the thread that owns aMessage + +@param aMessage the message which is passed between processes +@param aIndex the message slot which the data will be passed back in +@param aPtr pointer to data in this thread to be written into aMessage +@param aPtrSize size in bytes of the data to be written + +@leave one of the system wide error codes +*/ +void CSecuritySvrSession::WriteDataL(const RMessage2& aMessage, const TInt aIndex, const TAny* aPtr, const TUint32 aPtrSize) const + { + TPtr8 dataPtr((TUint8*)aPtr, aPtrSize, aPtrSize); + + aMessage.WriteL(aIndex, dataPtr); + } + +/** +Helper function. + +Checks whether the debug agent (the owner of the aMessage) is attached to the +thread with thread id of aThreadId. + +@param aThreadId thread ID of target debug thread +@param aMessage message owned by the debug agent +@param aPassive indicates whether to check if attached passively or actively + +@leave KErrPermissionDenied if the agent is not attached to the process, + KErrNoMemory if the security server could not be accessed +*/ +void CSecuritySvrSession::CheckAttachedL(const TThreadId aThreadId, const RMessage2& aMessage, const TBool aPassive) const + { + //check that the agent has attached to the target process + if(! Server().CheckAttached(aThreadId, aMessage, aPassive)) + { + LOG_MSG("CSecuritySvrSession::CheckAttachedL() failed"); + User::Leave(KErrPermissionDenied); + } + } + +/** +Helper function. + +Checks whether the debug agent (the owner of the aMessage) is attached to the +process with process id of aProcessId. + +@param aProcessId process ID of target debug thread +@param aMessage message owned by the debug agent +@param aPassive indicates whether to check if attached passively or actively + +@leave KErrPermissionDenied if the agent is not attached to the process, + KErrNoMemory if the security server could not be accessed +*/ +void CSecuritySvrSession::CheckAttachedL(const TProcessId aProcessId, const RMessage2& aMessage, const TBool aPassive) const + { + + //check that the agent has attached to the target process + if(! Server().CheckAttached(aProcessId, aMessage, aPassive)) + { + LOG_MSG("CSecuritySvrSession::CheckAttachedL() (process) failed"); + User::Leave(KErrPermissionDenied); + } + } + +/** +Check whether the debug agent is permitted to attach to the target process. +Note that this function does not actually attach the agent to the process, it +simply tests whether an attach call would potentially be successful. + +Currently this method returns ETrue in all cases but will be updated once +the security checking framework is in place. + +@param aDebugAgentProcessId process id of the debug agent +@param aTargetProcessName original file name of the target process + +@return ETrue if the debug agent would be allowed to attch to the target process, + EFalse otherwise +*/ +TBool CSecuritySvrSession::PermitDebugL(const TProcessId aDebugAgentProcessId, const TDesC& aTargetProcessName) const + { + return ETrue; + } + +/** +Helper function + +Validates that the memory info passed in meets the debug driver's requirements + +@param aMemoryInfo memory info passed in from client + +@leave KErrArgument if: + * size is zero + * size is greater than the max block size + * size + address > 0xffffffff + * address is not access size aligned + * size is not a multiple of the access size + KErrNotSupported if: + * iAccess is not TAccess::EAccess32 + * iEndianess is not TEndianess::EEndLE8 + KErrUnknown if: + * the max memory block size cannot be determined + or one of the other system wide error codes +*/ +void CSecuritySvrSession::ValidateMemoryInfoL(const TThreadId aThreadId, const TMemoryInfo &aMemoryInfo, const TBool aReadOperation) + { + //check size is not 0 + if(aMemoryInfo.iSize == 0) + User::Leave(KErrArgument); + + //get the max block size supported + TUint32 maxSize = 0; + User::LeaveIfError(Server().iKernelDriver.GetMemoryOperationMaxBlockSize(maxSize)); + + //check that the block size given is less than the max block size + if(aMemoryInfo.iSize > maxSize) + User::Leave(KErrArgument); + + //must ensure that address + size <= 0xffffffff as will attempt to + //read past 0xffffffff, which wouldn't be good + TUint32 maxAddress = (~aMemoryInfo.iSize) + 1; + if(aMemoryInfo.iAddress > maxAddress) + User::Leave(KErrArgument); + + //check that arguments are supported + if(aMemoryInfo.iAccess != EAccess32) + User::Leave(KErrNotSupported); + + if(aMemoryInfo.iEndianess != EEndLE8) + User::Leave(KErrNotSupported); + + //check that address is multiple of access size + TInt addressIndicator = aMemoryInfo.iAddress % aMemoryInfo.iAccess; + if(addressIndicator != 0) + { + User::Leave(KErrArgument); + } + + //check that size is multiple of access size + TInt sizeIndicator = aMemoryInfo.iSize % aMemoryInfo.iAccess; + if(sizeIndicator != 0) + User::Leave(KErrArgument); + } + +/** +Helper function + +Validates that the three buffers relating to reading register data are of +appropriate sizes, and calculates the number of registers being requested. + +@param aMessage message which in offsets 1, 2 and 3 contains descriptors +@param aNumberOfRegisters if the function returns with KErrNone this will + contain the number of registers being requested, guaranteed to be non-zero + +@leave KErrArgument if descriptors do not represent the same number of + registers, if any of the descriptors have max length of 0, if any of + the descriptors have max lengths which are not multiples of their data + type's size or if any of the descriptors have max lengths greater than + the max block size for memory operations + or one of the other system wide error codes if there were problems + in getting the descriptors' lengths. +*/ +void CSecuritySvrSession::ValidateRegisterBuffersL(const RMessage2& aMessage, TUint32& aNumberOfRegisters) + { + //get lengths of buffers, if error occurs returned value will be less then zero + TInt idsBufferLength = aMessage.GetDesMaxLength(1); + if(idsBufferLength < 0) + { + User::Leave(idsBufferLength); + } + TInt valuesBufferLength = aMessage.GetDesMaxLength(2); + if(valuesBufferLength < 0) + { + User::Leave(valuesBufferLength); + } + TInt flagsBufferLength = aMessage.GetDesMaxLength(3); + if(flagsBufferLength < 0) + { + User::Leave(flagsBufferLength); + } + + //get the max block size supported + TUint32 maxSize = 0; + User::LeaveIfError(Server().iKernelDriver.GetMemoryOperationMaxBlockSize(maxSize)); + + //check none of the descriptors have size greater than the max block size + if((idsBufferLength > maxSize) || (valuesBufferLength > maxSize) || (flagsBufferLength > maxSize)) + User::Leave(KErrArgument); + + //get sizes of the three types of data the buffers represent arrays of + //and validate that the buffer lengths are multiples of the data sizes + TUint idSize = sizeof(TRegisterInfo); + if(idsBufferLength % idSize != 0) + User::Leave(KErrArgument); + + TUint flagSize = sizeof(TUint8); + if(flagsBufferLength % flagSize != 0) + User::Leave(KErrArgument); + + //perform check on id buffer length + if(idsBufferLength == 0) + User::Leave(KErrArgument); + + //calculate number of registers being requested + aNumberOfRegisters = idsBufferLength / idSize; + + //check flags buffer is of appropriate size + if(flagsBufferLength != (aNumberOfRegisters * flagSize)) + User::Leave(KErrArgument); + } + +/** +Establish whether any agents have registered to debug the specified aFileName + +@param aFileName originating file name of the target process +@param aPassive indicates whether to check if there has been active attachment, +or passive attachment. + +@return ETrue if aFileName is being debugged, EFalse otherwise + +*/ +TBool CSecuritySvrSession::IsDebugged(const TDesC& aFileName, const TBool aPassive) const + { + //check whether the target process is being debugged + return Server().IsDebugged(aFileName, aPassive); + } + +/** + Helper function which reads a TThreadId object from a client + + @param aMessage the message object containing the reference to the TThreadId + @param aIndex the message argument containing the reference + + @return the TThreadId passed in by the client + @leave KErrArgument if aIndex is outside of the valid range + */ +TThreadId CSecuritySvrSession::ReadTThreadIdL(const RMessagePtr2& aMessage, const TInt aIndex) const + { + //create a temporary TThreadId to read the data into + TThreadId tempThreadId; + TPtr8 threadIdPtr((TUint8*)&tempThreadId, sizeof(TThreadId)); + + // read the data in from the client + aMessage.ReadL(aIndex, threadIdPtr); + + return tempThreadId; + } + +/** + Helper function which reads a TProcessId object from a client + + @param aMessage the message object containing the reference to the TProcessId + @param aIndex the message argument containing the reference + + @return the TProcessId passed in by the client + @leave KErrArgument if aIndex is outside of the valid range + */ +TProcessId CSecuritySvrSession::ReadTProcessIdL(const RMessagePtr2& aMessage, const TInt aIndex) const + { + //create a temporary TProcessId to read the data into + TProcessId tempProcessId; + TPtr8 processIdPtr((TUint8*)&tempProcessId, sizeof(TProcessId)); + + // read the data in from the client + aMessage.ReadL(aIndex, processIdPtr); + + return tempProcessId; + } + +// End of file - c_security_svr_session.cpp diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/src/c_shutdown_timer.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/src/c_shutdown_timer.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,65 @@ +// 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: +// Provides the debug security server's shutdown timer implementation +// +// + +/** + @file + @internalTechnology + @released +*/ + +#include +#include "c_shutdown_timer.h" +#include "rm_debug_logging.h" + +/** +Constructor. Adds the timer to the thread's active scheduler, +*/ +CShutdownTimer::CShutdownTimer() + :CTimer(KActivePriorityShutdown) + { + LOG_MSG("CShutdownTimer::CShutdownTimer()\n"); + CActiveScheduler::Add(this); + } + +/** +Initialisation of timer +*/ +void CShutdownTimer::ConstructL() + { + LOG_MSG("CShutdownTimer::ConstructL()\n"); + CTimer::ConstructL(); + } + +/** +Starts the timer which would expire after KShutdownDelay +*/ +void CShutdownTimer::Start() + { + LOG_MSG("CShutdownTimer::Start()\n"); + After(KShutdownDelay); + } + +/** +Stops the active scheduler. Stopping the active scheduler effectively closes +the Debug Security Server +*/ +void CShutdownTimer::RunL() + { + LOG_MSG("CShutdownTimer::RunL()\n"); + CActiveScheduler::Stop(); + } + diff -r 838cdffd57ce -r 0ff24a8f6ca2 debugsrv/runmodedebug/securityserver/src/rm_debug_svr.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debugsrv/runmodedebug/securityserver/src/rm_debug_svr.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,81 @@ +// Copyright (c) 2006-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: +// Entry point to debug security server, sets up server/session +// +// + +/** + @file + @internalTechnology + @released +*/ + +#include +#include +#include + +#include "c_security_svr_server.h" +#include "c_security_svr_session.h" +#include "rm_debug_logging.h" + +using namespace Debug; + +/** +Perform all server initialisation, in particular creation of the +scheduler and server and then run the scheduler +*/ +void RunServerL() + { + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : -> new(ELeave) CActiveScheduler\n" ); + CActiveScheduler* s=new(ELeave) CActiveScheduler; + + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : -> CleanupStack::PushL(s)\n" ); + CleanupStack::PushL(s); + + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : -> CActiveScheduler::Install()\n" ); + CActiveScheduler::Install(s); + + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : -> CSecuritySvrServer::NewLC()\n" ); + CSecuritySvrServer::NewLC(); + + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : -> Rendezvous(KErrNone)\n" ); + // Signal whoever has started us that we have done so. + RProcess::Rendezvous(KErrNone); + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : <- Rendezvous()\n" ); + + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : -> CActiveScheduler::Start()\n" ); + CActiveScheduler::Start(); + LOG_MSG( "rm_debug_svr.cpp::RunServerL() <- CActiveScheduler::Start()\n" ); + + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : -> CleanupStack::PopAndDestroy()\n" ); + CleanupStack::PopAndDestroy(2, s); + LOG_MSG( "rm_debug_svr.cpp::RunServerL() : <- CleanupStack::PopAndDestroy()\n" ); + } + +/** +Entry point for debug security server +*/ +GLDEF_C TInt E32Main() + { + __UHEAP_MARK; + CTrapCleanup* cleanup=CTrapCleanup::New(); + TInt r = KErrNoMemory; + if (cleanup) + { + TRAP(r,RunServerL()); + delete cleanup; + } + __UHEAP_MARKEND; + return r; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 layers.sysdef.xml --- a/layers.sysdef.xml Mon Aug 23 15:29:36 2010 +0300 +++ b/layers.sysdef.xml Fri Aug 27 11:37:29 2010 +0300 @@ -13,6 +13,9 @@ + + + diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/group/ReleaseNotes_PIProfiler.txt Binary file piprofiler/group/ReleaseNotes_PIProfiler.txt has changed diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/group/bld.inf --- a/piprofiler/group/bld.inf Mon Aug 23 15:29:36 2010 +0300 +++ b/piprofiler/group/bld.inf Fri Aug 27 11:37:29 2010 +0300 @@ -26,8 +26,15 @@ #include "../plugins/DebugOutputWriterPlugin/group/bld.inf" #include "../plugins/DiskWriterPlugin/group/bld.inf" +#if ( SYMBIAN_VERSION_SUPPORT >= SYMBIAN_3 ) + #include "../plugins/PWRPlugin/group/bld.inf" +#endif PRJ_EXPORTS -../rom/piprofiler.iby CORE_IBY_EXPORT_PATH(tools,piprofiler.iby) +#if ( SYMBIAN_VERSION_SUPPORT >= SYMBIAN_3 ) + ../rom/piprofiler.iby CORE_IBY_EXPORT_PATH(tools,piprofiler.iby) +#else + ../rom/piprofiler_s2.iby CORE_IBY_EXPORT_PATH(tools,piprofiler.iby) +#endif ../rom/piprofiler_ldd.iby CORE_IBY_EXPORT_PATH(tools/rom,piprofiler_ldd.iby) diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/GeneralsPlugin/src/GppSamplerImpl.cpp --- a/piprofiler/plugins/GeneralsPlugin/src/GppSamplerImpl.cpp Mon Aug 23 15:29:36 2010 +0300 +++ b/piprofiler/plugins/GeneralsPlugin/src/GppSamplerImpl.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -76,7 +76,7 @@ { LOGTEXT("GppSamplerImpl::Reset"); iLastPc = 0; - iLastThread = 0; + iLastThread = 0xfffffffe; iRepeat = 0; iIsaStatus = 0; iIsaStart = 0; diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/PWRplugin/data/2001E5B9.rss --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/plugins/PWRplugin/data/2001E5B9.rss Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,51 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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 + +// Declares info for two implementations +RESOURCE REGISTRY_INFO theInfo + { + // UID for the DLL. See mmp files + //__SERIES60_3X__ can't be used in resource files + dll_uid = 0x2001E5B9; + + // Declare array of interface info. This dll contains implementations for + // only one interface (CSamplerInterfaceDefinition). + interfaces = + { + INTERFACE_INFO + { + // UID of interface that is implemented + interface_uid = 0x2001E5BC; + + implementations = + { + IMPLEMENTATION_INFO + { + implementation_uid = 0x2001E5B9; + + version_no = 1; + display_name = "PWR Sampler"; + default_data = "pwr"; + opaque_data = "10"; + } + }; + } + }; + } diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/PWRplugin/group/PWRPlugin.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/plugins/PWRplugin/group/PWRPlugin.mmp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,53 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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 + + +TARGET PIProfilerPWR.dll +TARGETTYPE PLUGIN +UID 0x10009D8D 0x2001E5B9 +VENDORID VID_DEFAULT +CAPABILITY ALL -TCB +SMPSAFE + +OS_LAYER_SYSTEMINCLUDE +USERINCLUDE ../inc +USERINCLUDE ../../../inc +SOURCEPATH ../src + +START RESOURCE ../data/2001E5B9.rss +TARGET PIProfilerPWR.rsc +END + +SOURCE PwrPluginImplementationTable.cpp +SOURCE PwrPlugin.cpp + +LIBRARY euser.lib +LIBRARY ecom.lib +LIBRARY apparc.lib +LIBRARY cone.lib +LIBRARY gdi.lib +LIBRARY ws32.lib +LIBRARY efsrv.lib +LIBRARY charconv.lib +LIBRARY CommonEngine.lib +LIBRARY flogger.lib +LIBRARY centralrepository.lib +LIBRARY HWRMPowerClient.lib +LIBRARY HWRMLightClient.lib diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/PWRplugin/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/plugins/PWRplugin/group/bld.inf Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,28 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +#ifndef SBSV2 +PRJ_PLATFORMS +DEFAULT +#endif + +PRJ_MMPFILES +#ifdef MARM + #ifndef __SERIES60_30__ + PWRPlugin.mmp + #endif +#endif diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/PWRplugin/inc/PwrPlugin.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/plugins/PWRplugin/inc/PwrPlugin.h Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,167 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +#ifndef BAPPEA_PWR_SAMPLER_H +#define BAPPEA_PWR_SAMPLER_H + +//#define PWR_SAMPLER_BACKLIGHT + +//#include "PIProfilerConfigInternal.h" + +// system definitions +#include +#include + +#include +#include +#include + +// user definitions +#include +#include + +// caption definitions +_LIT8(KPWRShortName, "pwr"); +_LIT8(KPWRMediumName, "Power sampler"); +_LIT8(KPWRLongName, "Power usage sampler"); +_LIT8(KPWRDescription, "Power sampler: \nSampling power consumption on Nokia S60 devices\nHW dep: N/A\nSW dep: S60 3.0\n"); + +// Minimum allowed sampling interval (in ms). 0 means undefined. +const TInt KMinSampleInterval = 250; +const TInt KReportingPeriodInfinite = 0; + +const TUid KGppPropertyCat={0x20201F70}; +enum TGppPropertyKeys + { + EGppPropertySyncSampleNumber + }; + +const TUid KPwrNotifierUid = { 0x2001E5B9 }; +class CProfilerPowerListener; + +/* + * + * PWR sampler plug-in definition + * + */ + +class CPwrPlugin : public CSamplerPluginInterface +{ +public: + static CPwrPlugin* NewL(const TUid aImplementationUid, TAny* aInitParams); + ~CPwrPlugin(); + + TInt ResetAndActivateL(CProfilerSampleStream& aStream); + TInt StopSampling(); + TBool Enabled() { return iEnabled; } + void SetEnabled(TBool aEnabled); + TInt GetSamplerType(); + + TInt CreateFirstSample(); + + void GetAttributesL(CArrayFixFlat* aAttributes); + TInt SetAttributesL(TSamplerAttributes aAttributes); + void InitiateSamplerAttributesL(); + + TInt ConvertRawSettingsToAttributes(CDesC8ArrayFlat* aSingleSettingArray); + + TInt DoSetSamplerSettings(CDesC8ArrayFlat* aAllSettings, TDesC8& aSamplerName, TInt aIndex); + void SaveSettingToAttributes(const TDesC8& aSetting, TInt aIndex); + + TUid Id(TInt aSubId) const; + + // subsampler settings, i.e. samplers implemented within a plugin + // no sub samplers, from CSamplerPluginInterface + TInt SubId(TUid aId) const {return KErrNotFound;} + TInt GetSubSamplers(TDes* aDes){return KErrNotFound;} + +private: + CPwrPlugin(); + void ConstructL(); + +private: + TUint8 iVersion[20]; + TPtr8 iVersionDescriptor; + + TInt iSamplerType; + + CProfilerPowerListener* iPowerListener; + + TInt iPeriod; + CArrayFixFlat* iSamplerAttributes; +public: + TUint32* iSampleTime; +}; + +#ifdef PWR_SAMPLER_BACKLIGHT +class CProfilerPowerListener : public MHWRMBatteryPowerObserver, public MHWRMLightObserver +#else +class CProfilerPowerListener : public MHWRMBatteryPowerObserver +#endif +{ +public: + static CProfilerPowerListener* NewL(CPwrPlugin* aSampler); + ~CProfilerPowerListener(); + +private: + CProfilerPowerListener(CPwrPlugin* aSampler); + void ConstructL(); + +public: + TInt StartL(const TDesC8& aBuf); + TInt Stop(); + TInt DisplayNotifierL(const TDesC& aLine1, const TDesC& aLine2, const TDesC& aButton1, const TDesC& aButton2); + + // From MHWRMBatteryPowerObserver + virtual void PowerMeasurement(TInt aErr, CHWRMPower::TBatteryPowerMeasurementData& aMeasurement); +#ifdef PWR_SAMPLER_BACKLIGHT + // From MHWRMLightObserver + virtual void LightStatusChanged(TInt aTarget, CHWRMLight::TLightStatus aStatus); +#endif + +private: + void Sample(); + +public: + TInt iPwrSamplingPeriod; + TInt iSampleStartTime; + // Value that is read from Central Repository and restored after sampling + TInt iOriginalReportingPeriod; + +private: + +#ifdef PWR_SAMPLER_BACKLIGHT + TUint8 iSample[13]; +#else + TUint8 iSample[12]; +#endif + + TUint16 iNominalCapa; + TUint16 iVoltage; + TUint16 iCurrent; + + CPwrPlugin* iSampler; + CHWRMPower* iPowerAPI; + +#ifdef PWR_SAMPLER_BACKLIGHT + CHWRMLight* iLightAPI; + CHWRMLight::TLightStatus iBackLightStatus; +#endif +}; + +#endif + diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/PWRplugin/sis/PWRPlugin.pkg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/plugins/PWRplugin/sis/PWRPlugin.pkg Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,44 @@ +; +; Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +; All rights reserved. +; This component and the accompanying materials are made available +; under the terms of "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: +; +; ShapeImplementation_30_gcce.pkg +; + +;Language - standard language definitions +&EN + +; standard sis file header +#{"Shape plugin"},(0xE01F614F),2,0,0 + + +; +;Localised Vendor name +; +%{"Forum Nokia"} + +; +;Unique Vendor name +; +:"Forum Nokia" + +; +;Supports Series 60 v 3.0 +; +[0x101F7961], 0, 0, 0, {"Series60ProductID"} + + +;Files to include. Check the source paths they match your SDK setup. +"\Symbian\9.1\S60_3rd_MR\Epoc32\release\gcce\urel\shapeimplementation.dll" - "!:\sys\bin\shapeimplementation.dll" +"\Symbian\9.1\S60_3rd_MR\epoc32\data\Z\Resource\plugins\shapeimplementation.rsc" - "!:\Resource\Plugins\shapeimplementation.RSC" diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/PWRplugin/src/PwrPlugin.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/plugins/PWRplugin/src/PwrPlugin.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,623 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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 "PwrPlugin.h" +#include + +#include +#include +#include +#include + + +// texts for notes +_LIT(KPowerTextLine1, "Power sampler:"); +_LIT(KPowerTextLine2, "Failed to start power measurement"); +_LIT(KPowerTextErrorSampling, "Error receiving measurement data"); +_LIT(KButtonOk, "Ok"); + +// LITERALS + +_LIT8(KSamplingPeriodMs, "sampling_period_ms"); + +// CONSTANTS +// Use this UID if plugin is PwrPlugin: +const TUid KSamplerPwrPluginUid = { 0x2001E5B9 }; + +/* + * + * class CPwrPlugin implementation + * + */ + +CPwrPlugin* CPwrPlugin::NewL(const TUid /*aImplementationUid*/, TAny* aInitParams) + { + LOGTEXT(_L("CPwrPlugin::NewL() - entry")); + CPwrPlugin* self = new (ELeave) CPwrPlugin(); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + LOGTEXT(_L("CPwrPlugin::NewL() - exit")); + return self; + } + +CPwrPlugin::CPwrPlugin() : + iVersionDescriptor(&(this->iVersion[1]),0,19), + iSamplerType(PROFILER_USER_MODE_SAMPLER) + { + iPeriod = 250; + iSamplerId = PROFILER_PWR_SAMPLER_ID; + iEnabled = EFalse; + iPowerListener = NULL; + LOGTEXT(_L("CPwrPlugin::CPwrPlugin() - konstruktori")); + + } + +void CPwrPlugin::ConstructL() + { + LOGTEXT(_L("CPwrPlugin::ConstructL() - entry")); + // initiate sampler attributes array + iSamplerAttributes = new(ELeave) CArrayFixFlat(1); // only one sampler + + // insert default attributes to array + InitiateSamplerAttributesL(); + + LOGTEXT(_L("CPwrPlugin::ConstructL() - exit")); + } + +CPwrPlugin::~CPwrPlugin() + { + LOGTEXT(_L("CPwrPlugin::~CPwrPlugin() - entry")); + if(iPowerListener) + { + if(Enabled()) + { + iPowerListener->Stop(); + } + delete iPowerListener; + iPowerListener = NULL; + } + + if(iSamplerAttributes) + { + iSamplerAttributes->Reset(); + delete iSamplerAttributes; + iSamplerAttributes = NULL; + } + + LOGTEXT(_L("CPwrPlugin::~CPwrPlugin() - exit")); + } + +TUid CPwrPlugin::Id(TInt /*aSubId*/) const + { + LOGSTRING2( "CPwrPlugin::Id():0x%X", KSamplerPwrPluginUid.iUid ); + return KSamplerPwrPluginUid; + } + +void CPwrPlugin::InitiateSamplerAttributesL() + { + // create TSamplerAttributes + TSamplerAttributes attr(KSamplerPwrPluginUid.iUid, + KPWRShortName(), + KPWRLongName(), + KPWRDescription(), + 250, + EFalse, + EFalse, + 0); + this->iSamplerAttributes->AppendL(attr); + } + +void CPwrPlugin::SetEnabled(TBool aEnabled) + { + iEnabled = aEnabled; + } + +// returns setting array +void CPwrPlugin::GetAttributesL(CArrayFixFlat* aAttributes) + { + aAttributes->AppendL(iSamplerAttributes->At(0)); + } + +TInt CPwrPlugin::SetAttributesL(TSamplerAttributes aAttributes) + { + TSamplerAttributes attr; + + attr = iSamplerAttributes->At(0); + // replace the old attribute container + iSamplerAttributes->Delete(0); + iSamplerAttributes->InsertL(0, aAttributes); + return KErrNone; + } + +/* + * Method for parsing and transforming text array settings into TSamplerAttributes (per each sub sampler), + * called by CSamplerController class + * + * @param array of raw text setting lines, e.g. [gpp]\nenabled=true\nsampling_period_ms=1\n + */ +TInt CPwrPlugin::ConvertRawSettingsToAttributes(CDesC8ArrayFlat* aAllSettingsArray) + { + // local literals + _LIT8(KPWRShort, "pwr"); + + TInt err(KErrNone); + TBuf8<16> samplerSearchName; + samplerSearchName.Copy(KPWRShort); + + // get sampler specific settings + err = DoSetSamplerSettings(aAllSettingsArray, samplerSearchName, 0); + + // returns KErrNone if settings found, otherwise KErrNotFound + return err; + } + +TInt CPwrPlugin::DoSetSamplerSettings(CDesC8ArrayFlat* aAllSettings, TDesC8& aSamplerName, TInt aIndex) + { + // + TBuf8<16> samplerSearch; + samplerSearch.Copy(KBracketOpen); + samplerSearch.Append(aSamplerName); + samplerSearch.Append(KBracketClose); + + // read a line + for (TInt i(0); iMdcaCount(); i++) + { + // check if this line has a setting block start, i.e. contains [xxx] in it + if (aAllSettings->MdcaPoint(i).CompareF(samplerSearch) == 0) + { + // right settings block found, now loop until the next block is found + for(TInt j(i+1);jMdcaCount();j++) + { + // check if the next settings block was found + if(aAllSettings->MdcaPoint(j).Left(1).CompareF(KBracketOpen) != 0) + { + // save found setting value directly to its owners attributes + SaveSettingToAttributes(aAllSettings->MdcaPoint(j), aIndex); + } + else + { + // next block found, return KErrNone + return KErrNone; + } + } + } + } + + return KErrNotFound; + } + +/** + * Method for setting a specific descriptor (from settings file) to attribute structure + * + * @param aSetting + * @param aName + */ +void CPwrPlugin::SaveSettingToAttributes(const TDesC8& aSetting, TInt aIndex) + { + // find the equal mark from the setting line + TInt sepPos = aSetting.Find(KSettingItemSeparator); + // check that '=' is found + if (sepPos > 0) + { + // check that the element matches + if (aSetting.Left(sepPos).CompareF(KEnabled) == 0) + { + TBool en; + CSamplerPluginInterface::Str2Bool(aSetting.Right(aSetting.Length()-sepPos-1), en); + if(en != iSamplerAttributes->At(aIndex).iEnabled) + { + iSamplerAttributes->At(aIndex).iEnabled = en; + } + } + else if (aSetting.Left(sepPos).CompareF(KSamplingPeriodMs) == 0) + { + TInt sr; + CSamplerPluginInterface::Str2Int(aSetting.Right(aSetting.Length()-sepPos-1), sr); + if(sr != iSamplerAttributes->At(aIndex).iSampleRate) + { + iSamplerAttributes->At(aIndex).iSampleRate = sr; + } + } + } + } + +TInt CPwrPlugin::GetSamplerType() + { + return iSamplerType; + } + +TInt CPwrPlugin::ResetAndActivateL(CProfilerSampleStream& aStream) + { + LOGTEXT(_L("CPwrPlugin::ResetAndActivate() - entry")); + // check if sampler enabled + if(iSamplerAttributes->At(0).iEnabled) + { + // create a new listener instance for every trace, destroy it on stop + iPowerListener = CProfilerPowerListener::NewL(this); + + iStream = &aStream; + TInt length = this->CreateFirstSample(); + iVersion[0] = (TUint8)length; + LOGSTRING2("CPwrPlugin::ResetAndActivate() - AddSample, length %d", length); + TInt ret = this->AddSample(iVersion, length+1, 0); + + LOGSTRING2("CPwrPlugin::ConstructL() - sampling period %d", this->iPeriod); + + HBufC8* iBufRes = HBufC8::NewMaxLC(10); + TPtr8 iPtrRes = iBufRes->Des(); + + // check if sampling rate set to something reasonable, relevant only in SYNC case + if(iSamplerAttributes->At(0).iSampleRate != -1) + { + iPtrRes.Num(iSamplerAttributes->At(0).iSampleRate); + } + else + { + iPtrRes.Append(KNullDesC8); + } + + // set disabled + SetEnabled(ETrue); + + // activate power listener + ret = iPowerListener->StartL(iPtrRes); + LOGTEXT(_L("CPwrPlugin::ResetAndActivate() - exit")); + + CleanupStack::PopAndDestroy(); + + if(ret != KErrNone) + return ret; + } + return KErrNone; + } + +TInt CPwrPlugin::CreateFirstSample() + { + LOGTEXT(_L("CPwrPlugin::CreateFirstSample - entry")); + this->iVersionDescriptor.Zero(); + this->iVersionDescriptor.Append(_L8("Bappea_PWR_V")); + this->iVersionDescriptor.Append(PROFILER_PWR_SAMPLER_VERSION); + LOGTEXT(_L("CPwrPlugin::CreateFirstSample - exit")); + return (TInt)(this->iVersionDescriptor.Length()); + } + +TInt CPwrPlugin::StopSampling() + { + if(iPowerListener) + { + iPowerListener->Stop(); + delete iPowerListener; + iPowerListener = NULL; + } + + // set disabled + SetEnabled(EFalse); + + return KErrNone; + } + + +/* + * + * class CProfilerPowerListener implementation + * + */ + +CProfilerPowerListener::CProfilerPowerListener(CPwrPlugin* aSampler) : + iPwrSamplingPeriod(0), + iOriginalReportingPeriod(0), + iNominalCapa(0), + iVoltage(0), + iCurrent(0), + iPowerAPI(0) +#ifdef PWR_SAMPLER_BACKLIGHT + ,iLightAPI(0), + iBackLightStatus(CHWRMLight::ELightStatusUnknown) +#endif + + { + LOGTEXT(_L("CProfilerPowerListener::CProfilerPowerListener() - konstuktori")); + this->iSampler = aSampler; + LOGTEXT(_L("CProfilerPowerListener::CProfilerPowerListener() - konstuktori exit")); + } + +CProfilerPowerListener* CProfilerPowerListener::NewL(CPwrPlugin* aSampler) + { + LOGTEXT(_L("CProfilerPowerListener::NewL() - entry")); + CProfilerPowerListener* self = new (ELeave) CProfilerPowerListener(aSampler); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + LOGTEXT(_L("CProfilerPowerListener::NewL() - exit")); + return self; + } + +void CProfilerPowerListener::ConstructL() + { + LOGTEXT(_L("CProfilerPowerListener::ConstructL() - entry")); + iSampleStartTime = 0; + LOGTEXT(_L("CProfilerPowerListener::ConstructL() - exit")); + } + +CProfilerPowerListener::~CProfilerPowerListener() + { + LOGTEXT(_L("CProfilerPowerListener::~CProfilerPowerListener() - entry")); + + if (iPowerAPI) + { + delete iPowerAPI; + iPowerAPI = 0; + } +#ifdef PWR_SAMPLER_BACKLIGHT + if (iLightAPI) + { + delete iLightAPI; + iLightAPI = 0; + } +#endif + + LOGTEXT(_L("CProfilerPowerListener::~CProfilerPowerListener() - exit")); + } + +TInt CProfilerPowerListener::DisplayNotifierL(const TDesC& aLine1, const TDesC& aLine2, const TDesC& aButton1, const TDesC& aButton2) + { + RNotifier notifier; + TRequestStatus stat; + + TInt buttonValue(0); + + User::LeaveIfError(notifier.Connect()); + + notifier.Notify(aLine1, aLine2, aButton1, aButton2, buttonValue, stat); + User::WaitForRequest(stat); + + notifier.Close(); + return buttonValue; + } + + +TInt CProfilerPowerListener::StartL(const TDesC8& aBuf) + { + LOGTEXT(_L("CProfilerPowerListener::StartL() - entry")); + + // get the property value + TInt r = RProperty::Get(KGppPropertyCat, EGppPropertySyncSampleNumber, iSampleStartTime); + if(r != KErrNone) + { + LOGSTRING2("CProfilerPowerListener::StartL() - getting iSyncOffset failed, error %d", r); + } + + // check if given sampling period is valid + if(aBuf.CompareF(KNullDesC8)!= 0) + { + TLex8* lex = new TLex8(aBuf); + lex->Val(iPwrSamplingPeriod); + delete lex; + } + else + { + // set default period + iPwrSamplingPeriod = 250; + } + + // Check that sampling period is in allowed range + if (KMinSampleInterval > 0 && iPwrSamplingPeriod < KMinSampleInterval) + { + iPwrSamplingPeriod = KMinSampleInterval; + } + + LOGSTRING2("CProfilerPowerListener::StartL() - Sampling period %d", iPwrSamplingPeriod); + + // Start monitoring voltage and current + iPowerAPI = CHWRMPower::NewL(); + iPowerAPI->SetPowerReportObserver(this); + + // Read HWRM reporting settings from central repository + CRepository* centRep = CRepository::NewL(KCRUidPowerSettings); + TInt baseInterval(0); + User::LeaveIfError(centRep->Get(KPowerBaseTimeInterval, baseInterval)); + User::LeaveIfError(centRep->Get(KPowerMaxReportingPeriod, iOriginalReportingPeriod)); + + LOGSTRING2("CProfilerPowerListener::StartL() - HWRM base power report interval: %d", baseInterval); + LOGSTRING2("CProfilerPowerListener::StartL() - Original HWRM max power reporting period: %d", iOriginalReportingPeriod); + + User::LeaveIfError(centRep->Set(KPowerMaxReportingPeriod, KReportingPeriodInfinite)); + + // Power reporting interval reading may return too low value sometimes. Minimum value expected to be 250ms. + if ( baseInterval < KMinSampleInterval ) + { + baseInterval = KMinSampleInterval; + LOGSTRING2("CProfilerPowerListener::StartL() - Power report interval too low. Changed to: %d", baseInterval); + } + + // Power reporting period is multiplier of HWRM base period + TInt intervalMultiplier = iPwrSamplingPeriod / baseInterval; + + if (intervalMultiplier < 1) + { + intervalMultiplier = 1; + } + + LOGSTRING2("CProfilerPowerListener::StartL() - Reporting period multiplier: %d", intervalMultiplier); + + TRequestStatus status(KRequestPending); + iPowerAPI->StartAveragePowerReporting(status, intervalMultiplier); + User::WaitForRequest(status); + + if (status.Int() != KErrNone) + { + LOGTEXT(_L("CProfilerPowerListener::StartL() - Failed to initialize power reporting")); + + DisplayNotifierL(KPowerTextLine1, KPowerTextLine2, KButtonOk, KNullDesC); + + return status.Int(); + } + +#ifdef PWR_SAMPLER_BACKLIGHT + // Start monitoring backlight status + iLightAPI = CHWRMLight::NewL(this); +#endif + + LOGTEXT(_L("CProfilerPowerListener::StartL() - exit")); + return KErrNone; + } + +void CProfilerPowerListener::Sample() + { + LOGTEXT(_L("CProfilerPowerListener::Sample() - entry")); + + TRequestStatus status; + CHWRMPower::TBatteryConsumptionData consumptionData; + + iPowerAPI->GetBatteryInfo(status, consumptionData); + User::WaitForRequest(status); + + // Data is valid only if status == KErrNone + if (status.Int() != KErrNone) + { + LOGSTRING2("CProfilerPowerListener::Sample() - Getting battery info failed with code: ", status.Int()); + iNominalCapa = 0; + } + else + { + iNominalCapa = consumptionData.iNominalCapacity; + } + + // Space for GPP sample time + //TUint32 sampleTime = iSampler->iStream->iSampler->GetSampleTime(); + TUint32 sampleTime = User::NTickCount() - iSampleStartTime; + LOGSTRING2("CProfilerPowerListener::Sample() - Sample time: %d", sampleTime); + LOGSTRING2("CProfilerPowerListener::Sample() - Nominal capacitance: %d", iNominalCapa); + LOGSTRING2("CProfilerPowerListener::Sample() - Voltage: %d", iVoltage); + LOGSTRING2("CProfilerPowerListener::Sample() - Current: %d", iCurrent); +#ifdef PWR_SAMPLER_BACKLIGHT + LOGSTRING2("CProfilerPowerListener::Sample() - Backlight status: %d", (TUint8)iBackLightStatus); +#endif + + iSample[0] = iNominalCapa; + iSample[1] = iNominalCapa >> 8; + iSample[2] = iVoltage; + iSample[3] = iVoltage >> 8; + iSample[4] = iCurrent; + iSample[5] = iCurrent >> 8; + iSample[6] = iCurrent >> 16; + iSample[7] = iCurrent >> 24; +#ifdef PWR_SAMPLER_BACKLIGHT + iSample[8] = (TUint8)iBackLightStatus; + iSample[9] = sampleTime; + iSample[10] = sampleTime >> 8; + iSample[11] = sampleTime >> 16; + iSample[12] = sampleTime >> 24; + + iSampler->AddSample(iSample, 13, 0); +#else + iSample[8] = sampleTime; + iSample[9] = sampleTime >> 8; + iSample[10] = sampleTime >> 16; + iSample[11] = sampleTime >> 24; + + iSampler->AddSample(iSample, 12, 0); +#endif + + LOGTEXT(_L("CProfilerPowerListener::Sample() - exit")); + } + +TInt CProfilerPowerListener::Stop() + { + LOGTEXT(_L("CProfilerPowerListener::Stop() - entry")); + + if (iPowerAPI) + { + TRAPD(err, iPowerAPI->StopAveragePowerReportingL()); + if(err != KErrNone) + { + LOGSTRING2("CProfilerPowerListener::Stop() - Failed to stop power reporting: %d", err); + } + else + { + LOGTEXT(_L("CProfilerPowerListener::Stop() - Stopped power monitoring")); + } + delete iPowerAPI; + iPowerAPI = 0; + + // Restore original value to max sampling period + CRepository* centRep = 0; + TRAP(err, centRep = CRepository::NewL(KCRUidPowerSettings)); + if (err != KErrNone) + { + LOGSTRING2("CProfilerPowerListener::Stop() - Failed to open Central Repository: %d", err); + } + else + { + err = centRep->Set(KPowerMaxReportingPeriod, iOriginalReportingPeriod); + if(err != KErrNone) + { + LOGSTRING2("CProfilerPowerListener::Stop() - Failed to restore max sampling period: %d", err); + } + } + } +#ifdef PWR_SAMPLER_BACKLIGHT + if (iLightAPI) + { + delete iLightAPI; + iLightAPI = 0; + } +#endif + + LOGTEXT(_L("CProfilerPowerListener::Stop() - exit")); + return KErrNone; + } + +void CProfilerPowerListener::PowerMeasurement(TInt aErr, CHWRMPower::TBatteryPowerMeasurementData& aMeasurement) + { + LOGTEXT(_L("CProfilerPowerListener::PowerMeasurement - entry")); + + if (aErr == KErrNone) + { + LOGSTRING3("CProfilerPowerListener::PowerMeasurement - Previous values - Voltage: %d Current: %d", iVoltage, iCurrent); + iVoltage = aMeasurement.iAverageVoltage; + iCurrent = aMeasurement.iAverageCurrent; + LOGSTRING3("CProfilerPowerListener::PowerMeasurement - New values - Voltage: %d Current: %d", iVoltage, iCurrent); + + this->Sample(); + } + else + { + LOGSTRING2("CProfilerPowerListener::PowerMeasurement - Failed with error code: %d", aErr); + DisplayNotifierL(KPowerTextLine1, KPowerTextErrorSampling, KButtonOk, KNullDesC); + } + LOGTEXT(_L("CProfilerPowerListener::PowerMeasurement - exit")); + } + +#ifdef PWR_SAMPLER_BACKLIGHT +void CProfilerPowerListener::LightStatusChanged(TInt aTarget, CHWRMLight::TLightStatus aStatus) + { + LOGTEXT(_L("CProfilerPowerListener::LightStatusChanged - entry")); + LOGSTRING3("CProfilerPowerListener::LightStatusChanged - Target: %d Status: %d", aTarget, aStatus); + + if (aTarget == CHWRMLight::EPrimaryDisplay) + { + LOGSTRING2("CProfilerPowerListener::LightStatusChanged - Previous light status: %d", iBackLightStatus); + iBackLightStatus = aStatus; + LOGSTRING2("CProfilerPowerListener::LightStatusChanged - New light status: %d", iBackLightStatus); + + this->Sample(); + } + LOGTEXT(_L("CProfilerPowerListener::LightStatusChanged - exit")); + } +#endif diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/plugins/PWRplugin/src/PwrPluginImplementationTable.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/plugins/PWRplugin/src/PwrPluginImplementationTable.cpp Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,39 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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 FILES +#include +#include + +#include "PwrPlugin.h" + + +// Provides a key value pair table, this is used to identify +// the correct construction function for the requested interface. +const TImplementationProxy ImplementationTable[] = +{ + IMPLEMENTATION_PROXY_ENTRY(0x2001E5B9, CPwrPlugin::NewL), +}; + +// Function used to return an instance of the proxy table. +EXPORT_C const TImplementationProxy* ImplementationGroupProxy(TInt& aTableCount) +{ + aTableCount = sizeof(ImplementationTable) / sizeof(TImplementationProxy); + return ImplementationTable; +} + diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/rom/piprofiler.iby --- a/piprofiler/rom/piprofiler.iby Mon Aug 23 15:29:36 2010 +0300 +++ b/piprofiler/rom/piprofiler.iby Fri Aug 27 11:37:29 2010 +0300 @@ -22,11 +22,11 @@ // PI Profiler Engine itself file=ABI_DIR\BUILD_DIR\PIProfilerEngine.exe sys\bin\PIProfilerEngine.exe file=ABI_DIR\BUILD_DIR\PIProfiler.exe sys\bin\PIProfiler.exe -data=ZSYSTEM\Install\PIProfiler_stub.sis system\install\PIProfiler_stub.sis // sampler plugins // NOTE: Mandatory kernel driver included in piprofiler_ldd.iby ECOM_PLUGIN(PIProfilerGenerals.dll, PIProfilerGenerals.rsc) +ECOM_PLUGIN(PIProfilerPWR.dll, PIProfilerPWR.rsc) ECOM_PLUGIN(PIProfilerBUP.dll, PIProfilerBUP.rsc) file=ABI_DIR\BUILD_DIR\PIProfilerTouchEventAnim.dll sys\bin\PIProfilerTouchEventAnim.dll diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/rom/piprofiler_s2.iby --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/rom/piprofiler_s2.iby Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,37 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + + +#ifndef __PIPROFILER__ +#define __PIPROFILER__ + +// PI Profiler Engine itself +file=ABI_DIR\BUILD_DIR\PIProfilerEngine.exe sys\bin\PIProfilerEngine.exe +file=ABI_DIR\BUILD_DIR\PIProfiler.exe sys\bin\PIProfiler.exe + +// sampler plugins +// NOTE: Mandatory kernel driver included in piprofiler_ldd.iby +ECOM_PLUGIN(PIProfilerGenerals.dll, PIProfilerGenerals.rsc) + +ECOM_PLUGIN(PIProfilerBUP.dll, PIProfilerBUP.rsc) +file=ABI_DIR\BUILD_DIR\PIProfilerTouchEventAnim.dll sys\bin\PIProfilerTouchEventAnim.dll + +// Writer plugins +ECOM_PLUGIN(piprofilerdebugwriter.dll, piprofilerdebugwriter.rsc) +ECOM_PLUGIN(piprofilerdiskwriter.dll, piprofilerdiskwriter.rsc) + +#endif //__PIPROFILER__ diff -r 838cdffd57ce -r 0ff24a8f6ca2 piprofiler/symbian_version.hrh --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/piprofiler/symbian_version.hrh Fri Aug 27 11:37:29 2010 +0300 @@ -0,0 +1,43 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: Symbian version configuration file +* +*/ + +#ifndef __SYMBIAN_VERSION_HRH +#define __SYMBIAN_VERSION_HRH + +// S60 and Symbian version number enumeration definitions + +#define S60_30 30 +#define S60_31 31 +#define S60_32 32 +#define S60_50 50 +#define S60_51 91 +#define S60_52 92 +#define SYMBIAN_1 50 +#define SYMBIAN_2 91 +#define SYMBIAN_3 92 +#define SYMBIAN_4 101 + + +/** + * Defines the S60 or Symbian version used by this component. This flag can be + * used to variate the source code based on the SDK in use. The value of the + * flag should be always changed to reflect the current build environment. + */ +#define SYMBIAN_VERSION_SUPPORT SYMBIAN_4 + + +#endif // __SYMBIAN_VERSION_HRH