--- /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 @@
+<?xml version="1.0"?>
+<!DOCTYPE SystemDefinition [
+ <!ELEMENT SystemDefinition (systemModel?, build?)>
+ <!ATTLIST SystemDefinition
+ name CDATA #REQUIRED
+ schema CDATA #REQUIRED>
+ <!ELEMENT systemModel (layer+)>
+ <!ELEMENT layer (logicalset* | module*)*>
+ <!ATTLIST layer
+ name CDATA #REQUIRED
+ levels CDATA #IMPLIED
+ span CDATA #IMPLIED>
+ <!ELEMENT logicalset (logicalsubset* | module* | unit* | package* | prebuilt*)*>
+ <!ATTLIST logicalset
+ name CDATA #REQUIRED
+ levels CDATA #IMPLIED
+ span CDATA #IMPLIED
+ level CDATA #IMPLIED>
+ <!ELEMENT logicalsubset (module* | unit* | package* | prebuilt*)*>
+ <!ATTLIST logicalsubset name CDATA #REQUIRED>
+ <!ELEMENT module (component* | unit* | package* | prebuilt*)*>
+ <!ATTLIST module
+ name CDATA #REQUIRED
+ level CDATA #IMPLIED>
+ <!ELEMENT component (unit* | package* | prebuilt*)*>
+ <!ATTLIST component name CDATA #REQUIRED>
+ <!ELEMENT unit EMPTY>
+ <!ATTLIST unit
+ unitID ID #REQUIRED
+ name CDATA #REQUIRED
+ mrp CDATA #REQUIRED
+ filter CDATA #IMPLIED
+ bldFile CDATA #REQUIRED
+ priority CDATA #IMPLIED
+ contract CDATA #IMPLIED>
+ <!ELEMENT package EMPTY>
+ <!ATTLIST package
+ name CDATA #REQUIRED
+ mrp CDATA #REQUIRED
+ filter CDATA #IMPLIED
+ contract CDATA #IMPLIED>
+ <!ELEMENT prebuilt EMPTY>
+ <!ATTLIST prebuilt
+ name CDATA #REQUIRED
+ version CDATA #REQUIRED
+ late (Y|N) #IMPLIED
+ filter CDATA #IMPLIED
+ contract CDATA #IMPLIED>
+ <!ELEMENT build (option* | target+ | targetList+ | unitList+ | configuration+)*>
+ <!ELEMENT unitList (unitRef+)>
+ <!ATTLIST unitList
+ name ID #REQUIRED
+ description CDATA #REQUIRED>
+ <!ELEMENT unitRef EMPTY>
+ <!ATTLIST unitRef unit IDREF #REQUIRED>
+ <!ELEMENT targetList EMPTY>
+ <!ATTLIST targetList
+ name ID #REQUIRED
+ description CDATA #REQUIRED
+ target IDREFS #REQUIRED>
+ <!ELEMENT target EMPTY>
+ <!ATTLIST target
+ name ID #REQUIRED
+ abldTarget CDATA #REQUIRED
+ description CDATA #REQUIRED>
+ <!ELEMENT option EMPTY>
+ <!ATTLIST option
+ name ID #REQUIRED
+ abldOption CDATA #REQUIRED
+ description CDATA #REQUIRED
+ enable (Y | N | y | n) #REQUIRED>
+ <!ELEMENT configuration (unitListRef+ | layerRef+ | task+)*>
+ <!ATTLIST configuration
+ name ID #REQUIRED
+ description CDATA #REQUIRED
+ filter CDATA #REQUIRED>
+ <!ELEMENT task ( unitListRef* , (buildLayer | specialInstructions))>
+ <!ELEMENT unitListRef EMPTY>
+ <!ATTLIST unitListRef unitList IDREF #REQUIRED>
+ <!ELEMENT layerRef EMPTY>
+ <!ATTLIST layerRef layerName CDATA #REQUIRED>
+ <!ELEMENT buildLayer EMPTY>
+ <!ATTLIST buildLayer
+ command CDATA #REQUIRED
+ targetList IDREFS #IMPLIED
+ unitParallel (Y | N | y | n) #REQUIRED
+ targetParallel (Y | N | y | n) #IMPLIED>
+ <!ELEMENT specialInstructions EMPTY>
+ <!ATTLIST specialInstructions
+ name CDATA #REQUIRED
+ cwd CDATA #REQUIRED
+ command CDATA #REQUIRED>
+ <!ENTITY layer_real_source_path "sf/dev/devicedbgsrvs/dbgsrv/coredumpserver/rmdebug" >
+]>
+
+<SystemDefinition name="rmdebug" schema="1.4.0">
+ <systemModel>
+ <layer name="os_layer">
+ <module name="RunMode">
+ <unit name="RunModeComp" unitID="RunMode.Comp" mrp="" bldFile="&layer_real_source_path;/group"/>
+ </module>
+ </layer>
+ <layer name="api_test_layer">
+ <module name="RunMode_test">
+ <unit name="RunModeComp_Test" unitID="RunMode.Comp_test" mrp="" bldFile="&layer_real_source_path;/group"/>
+ </module>
+ </layer>
+ </systemModel>
+</SystemDefinition>
\ No newline at end of file
--- /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
--- /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
+
--- /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"
--- /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
--- /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
--- /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;
+ }
+
--- /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
+
--- /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 <e32debug.h>
+
+// 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;
+ }
+
--- /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 <rm_debug_api.h>
+
+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
+
--- /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 <rm_debug_api.h>
+#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
+ }
+
--- /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
+
--- /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 <e32base.h>
+#include <e32base_private.h>
+#include <e32cons.h>
+#include <e32test.h>
+#include <e32ldr.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <f32dbg.h>
+#include <f32file.h>
+#include <hal.h>
+#include <u32hal.h>
+#include <e32property.h>
+
+#include "t_rmdebug_dll.h"
+
+#include <rm_debug_api.h>
+#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<SYMBIAN_RMDBG_MEMORYSIZE> 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<SYMBIAN_RMDBG_MEMORYSIZE; i++)
+ {
+ gMemoryAccessBytes.Append(i);
+ }
+
+ TUint32 address = (TUint32)(&gMemoryAccessBytes[0]);
+ TUint32 dataSize = SYMBIAN_RMDBG_MEMORYSIZE;
+
+ //create size for buffer that is rounded up to nearest 4 bytes if not
+ //already 4 byte aligned
+ TUint32 size = dataSize;
+ if(size % 4 != 0)
+ {
+ size += (4 - (size % 4));
+ }
+
+ RBuf8 dataBlock;
+ err = dataBlock.Create(size);
+ test(err==KErrNone);
+ test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse));
+
+ //suspend the thread prior to memory operations
+ test(KErrNone == iServSession.SuspendThread(iThreadID));
+
+ err = iServSession.ReadMemory(iThreadID, address, size, dataBlock, EAccess32, EEndLE8);
+ test(err==KErrNone);
+
+ for (TInt i=0; i<dataSize; i++)
+ {
+ test(dataBlock.Ptr()[i] == gMemoryAccessBytes[i]);
+ }
+
+ test.Next(_L("TestMemoryAccess - Write Memory\n"));
+
+ // Now reset the buffer
+ for (TInt i=0; i<dataSize; i++)
+ {
+ gMemoryAccessBytes[i] = 0;
+ }
+
+ // Write our data into the buffer
+ err = iServSession.WriteMemory(iThreadID, address, size, dataBlock, EAccess32, EEndLE8);
+ test(err==KErrNone);
+
+ for (TInt i=0; i<dataSize; i++)
+ {
+ test(dataBlock.Ptr()[i] == gMemoryAccessBytes[i]);
+ }
+
+ //final test that everything's not been going wrong
+ test(gMemoryAccessBytes[5] != 0);
+
+ test.Next(_L("TestMemoryAccess - Invalid arguments\n"));
+ test.Printf(_L("This test may emit crash-like information. This is intended.\n"));
+
+ //test address that is not 32 bit aligned
+ err = iServSession.ReadMemory(iThreadID, address + 1, size, dataBlock, EAccess32, EEndLE8);
+ test(err == KErrArgument);
+
+ //test size that is not multiple of 4 bytes
+ err = iServSession.WriteMemory(iThreadID, address, size + 2, dataBlock, EAccess32, EEndLE8);
+ test(err == KErrArgument);
+
+ //test size > 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<TBreakId> 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<numberOfRegisters - 1; i++)
+ {
+ TRegisterInfo reg = (TRegisterInfo)((i + firstRegister)<<8);
+ ids.Append(reinterpret_cast<const TUint8*>(®), sizeof(TRegisterInfo));
+ }
+
+ TRegisterInfo reg = ERegisterR13Irq;
+ ids.Append(reinterpret_cast<const TUint8*>(®), 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<numberOfRegisters*sizeof(TUint32); i++)
+ {
+ if(i/sizeof(TUint32) == cpsrId)
+ {
+ //For the CPSR we wish to write data that makes sense - for USR mode we are
+ //allowed change all except the mode, ie. we must stay in usr mode. We try that here
+ //(allowedCPSRValue[4:0] = 10000) thus not changing the mode.
+ TUint32 allowedCPSRValue = 0x50000010;
+ tempValues.Append((TUint8*)&allowedCPSRValue, 4);
+ i += 3;
+ }
+ else
+ {
+ tempValues.Append(&i, 1);
+ }
+ }
+
+ test.Next(_L("TestRegisterAccess - Write\n"));
+
+ //create a buffer to store the register flags in
+ RBuf8 tempWriteFlags;
+ err = tempWriteFlags.Create(numberOfRegisters*sizeof(TUint8));
+ test(err == KErrNone);
+
+ //write the temp data into the registers
+ err = iServSession.WriteRegisters(iThreadID, ids, tempValues, tempWriteFlags);
+ test(err == KErrNone);
+
+ //create another buffer to store the register flags in
+ RBuf8 tempReadFlags;
+ err = tempReadFlags.Create(numberOfRegisters*sizeof(TUint8));
+ test(err == KErrNone);
+
+ RBuf8 tempReadValues;
+ err = tempReadValues.Create(numberOfRegisters*sizeof(TUint32));
+ test(err == KErrNone);
+
+ //read the temp data out again
+ err = iServSession.ReadRegisters(iThreadID, ids, tempReadValues, tempReadFlags);
+ test(err == KErrNone);
+
+ //check values are correct
+ for(TInt i=0; i<numberOfRegisters; i++)
+ {
+ TRegisterFlag writeFlag;
+ err = GetFlag(tempWriteFlags, i, writeFlag);
+ test(err == KErrNone);
+
+ TRegisterFlag readFlag;
+ err = GetFlag(tempReadFlags, i, readFlag);
+ test(err == KErrNone);
+
+ if((writeFlag == EValid) && (readFlag == EValid))
+ {
+ TUint8 offset = i * sizeof(TUint32);
+ for(TUint j = offset; j< offset + sizeof(TUint32); j++)
+ {
+ test(tempValues.Ptr()[j] == tempReadValues.Ptr()[j]);
+ }
+ }
+ }
+
+ //write the original data into the registers
+ err = iServSession.WriteRegisters(iThreadID, ids, originalValues, originalFlags);
+ test(err == KErrNone);
+
+ //read the data out again
+ err = iServSession.ReadRegisters(iThreadID, ids, tempValues, tempReadFlags);
+ test(err == KErrNone);
+
+ //check values are correct
+ for(TInt i=0; i<numberOfRegisters; i++)
+ {
+ TRegisterFlag writeFlag;
+ err = GetFlag(originalFlags, i, writeFlag);
+ test(err == KErrNone);
+
+ TRegisterFlag readFlag;
+ err = GetFlag(tempReadFlags, i, readFlag);
+ test(err == KErrNone);
+
+ if((writeFlag == EValid) && (readFlag == EValid))
+ {
+ TUint8 offset = i * sizeof(TUint32);
+ for(TUint j = offset; j< offset + sizeof(TUint32); j++)
+ {
+ test(tempValues.Ptr()[j] == originalValues.Ptr()[j]);
+ }
+ }
+ }
+
+ test.Next(_L("TestRegisterAccess - Invalid data\n"));
+
+ //create a buffer of max size 1
+ RBuf8 emptyBuffer;
+ emptyBuffer.Create(1);
+
+ //test register IDs buffer not being a multiple of sizeof(TRegisterInfo)
+ err = iServSession.ReadRegisters(iThreadID, emptyBuffer, tempValues, tempReadFlags);
+ test(err == KErrArgument);
+
+ //test register values buffer not being a multiple of sizeof(TUint32)
+ err = iServSession.ReadRegisters(iThreadID, ids, emptyBuffer, tempReadFlags);
+ test(err == KErrArgument);
+
+ //test flags buffer being representing different number of registers from other two
+ err = iServSession.ReadRegisters(iThreadID, ids, tempValues, emptyBuffer);
+ test(err == KErrArgument);
+
+ //set max length to 0
+ emptyBuffer.ReAlloc(0);
+
+ //test ids buffer being of 0 max length
+ err = iServSession.ReadRegisters(iThreadID, emptyBuffer, tempValues, tempReadFlags);
+ test(err == KErrArgument);
+
+ //do cleanup
+ emptyBuffer.Close();
+ tempValues.Close();
+ tempWriteFlags.Close();
+ tempReadFlags.Close();
+ tempReadValues.Close();
+
+ test.Next(_L("TestRegisterAccess - Setting PC value\n"));
+
+ //create buffer containing PC register ID
+ RBuf8 pcId;
+ err = pcId.Create(sizeof(TRegisterInfo));
+ test(err == KErrNone);
+ TRegisterInfo reg1 = (TRegisterInfo)0x00000f00;
+ pcId.Append(reinterpret_cast<const TUint8*>(®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<const TUint8*>(&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<const TUint8*>(&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<KNumberOfTypes; j++)
+ {
+ if( gUseDelay ) User::After(500000);
+
+ RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads type: %d, main action: %d, extra action: %d, extraThreads: %d",
+ j, (TUint32)aActionMain, (TUint32)aActionExtra, aExtraThreads);
+
+ // do this check as it seems to hard to do these cases with the current set up
+ if(EEventsKillThread == type[j].iEventType)
+ {
+ if(EActionSuspend != aActionMain)
+ {
+ if(aActionMain != aActionExtra)
+ {
+ return;
+ }
+ }
+ }
+ // attach to KRMDebugTestApplication
+ test(KErrNone == iServSession.AttachExecutable(KRMDebugTestApplication, EFalse));
+
+ // Set things up to wait for the expected exception in KRMDebugTestApplication
+ test(KErrNone == iServSession.SetEventAction(KRMDebugTestApplication, type[j].iEventType, aActionMain));
+
+ if(EActionSuspend != aActionMain)
+ {
+ test(KErrNone == iServSession.SetEventAction(KRMDebugTestApplication, EEventsKillThread, aActionExtra));
+ }
+
+ // declare a TRequestStatus object for asynchronous calls
+ TRequestStatus status;
+
+ TEventInfo info;
+ TPtr8 infoBuffer = TPtr8((TUint8*)&info,0,sizeof(TEventInfo));
+ if(EActionIgnore != aActionMain)
+ {
+ iServSession.GetEvent(KRMDebugTestApplication(), status, infoBuffer);
+ }
+
+ // launch the target process to trigger the expected exception
+ RProcess targetProcess;
+ test(KErrNone == LaunchProcess(targetProcess, KRMDebugTestApplication(), type[j].iDebugFunctionType, 0, aExtraThreads));
+ TProcessId processId(targetProcess.Id());
+ targetProcess.Close();
+
+ if(EActionIgnore != aActionMain)
+ {
+ // wait for notification of the exception
+ User::WaitForRequest(status);
+ test(KErrNone == status.Int());
+
+ // check that this is the event we were expecting
+ test(info.iProcessIdValid);
+ test(info.iThreadIdValid);
+ test(info.iProcessId==processId);
+ test(info.iEventType==type[j].iEventType);
+ }
+
+ if(EActionSuspend == aActionMain)
+ {
+ //RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads EActionSuspend == aActionMain, j=%d", j);
+ // read the thread list, partly to check the call works, and partly to check the thread still exists
+ test(ThreadExistsForProcess(info.iThreadId, info.iProcessId));
+
+ // register to catch all the thread kills which will occur
+ test(KErrNone == iServSession.SetEventAction(KRMDebugTestApplication, EEventsKillThread, aActionExtra));
+ // we specified EActionSuspend earlier so need to call resume on this thread
+ test(KErrNone == iServSession.ResumeThread(info.iThreadId));
+ }
+
+ // find out how many threads there are in the process and catch all the thread kill events,
+ // the number of kill thread events should correspond to the number of extra threads launched,
+ // plus one if the main thread panicked with a Sw/Hw exception
+ if(EActionIgnore != aActionExtra)
+ {
+ TInt dyingThreads = aExtraThreads + ( (type[j].iEventType != EEventsKillThread) ? 1 : 0);
+ for(TInt k=0; k<dyingThreads; k++)
+ {
+ //RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads dyingThreads, k=%d, j=%d", k,j);
+ iServSession.GetEvent(KRMDebugTestApplication(), status, infoBuffer);
+
+ // wait for notification of the kill thread
+ User::WaitForRequest(status);
+ test(KErrNone == status.Int());
+
+ // check that this is the event we were expecting
+ test(info.iProcessIdValid);
+ test(info.iThreadIdValid);
+ test(info.iProcessId==processId);
+ test(info.iEventType==EEventsKillThread);
+ if(EActionSuspend == aActionExtra)
+ {
+ // do some calls to check listings work ok at this stage
+ test(ProcessExists(info.iProcessId));
+ test(ThreadExistsForProcess(info.iThreadId, info.iProcessId));
+ // we specified EActionSuspend earlier so need to call resume on this thread
+ test(KErrNone == iServSession.ResumeThread(info.iThreadId));
+ }
+ }
+ }
+
+ if( gUseDelay ) User::After(500000);
+
+ // reset the thread kill event
+ test(KErrNone == iServSession.SetEventAction(KRMDebugTestApplication(), EEventsKillThread, EActionIgnore));
+
+ // reset events for KRMDebugTestApplication
+ test(KErrNone == iServSession.SetEventAction(KRMDebugTestApplication(), type[j].iEventType, EActionIgnore));
+
+ // finished debugging KRMDebugTestApplication so detach
+ test(KErrNone == iServSession.DetachExecutable(KRMDebugTestApplication()));
+
+ // want to validate that the process has really exited, i.e. we're not accidentally keeping a handle to it...
+ TInt waitCount = 10;
+ while((waitCount-- > 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<numBytesToCheck> 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<const TUint8*>(®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("<number>: 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<KMaxTests; i++)
+ {
+ test.Printf(_L("%2d: %S\n"), i, &(iTestArray[i].iFunctionName));
+ }
+ test.Printf(_L("Press any key...\n"));
+ test.Getch();
+ }
+
+/**
+ Parse the command line, see CRunModeAgent::PrintUsage for syntax
+ */
+void CRunModeAgent::ParseCommandLineL(TUint32& aMode, RArray<TInt>& 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<TInt> 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<KMaxTests; i++)
+ {
+ testsToRun.AppendL(i);
+ }
+ }
+
+ // if EModeReverse specified then reverse the array elements
+ TInt numberOfTests = testsToRun.Count();
+ if(testMode & EModeReverse)
+ {
+ for(TInt i=0; i<(numberOfTests>>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; i<numberOfTests; i++)
+ {
+ RunTest(testsToRun[i]);
+ if( gUseDelay ) User::After(500000);
+ }
+ testsToRun.Close();
+
+ HelpStopTestTimer();
+
+ ReportPerformance();
+
+ test.End();
+ }
+
+/**
+ Fill the test array with pointers to each test.
+ */
+void CRunModeAgent::FillArray()
+ {
+ iTestArray[0].iFunctionPtr = &CRunModeAgent::TestDriverSecurity;
+ iTestArray[0].iFunctionName = _L("TestDriverSecurity");
+ iTestArray[1].iFunctionPtr = &CRunModeAgent::TestDllUsage;
+ iTestArray[1].iFunctionName = _L("TestDllUsage");
+ iTestArray[2].iFunctionPtr = &CRunModeAgent::TestSecurity;
+ iTestArray[2].iFunctionName = _L("TestSecurity");
+ iTestArray[3].iFunctionPtr = &CRunModeAgent::TestAttachExecutable;
+ iTestArray[3].iFunctionName = _L("TestAttachExecutable");
+ iTestArray[4].iFunctionPtr = &CRunModeAgent::TestGetExecutablesList;
+ iTestArray[4].iFunctionName = _L("TestGetExecutablesList");
+ iTestArray[5].iFunctionPtr = &CRunModeAgent::TestGetProcessList;
+ iTestArray[5].iFunctionName = _L("TestGetProcessList");
+ iTestArray[6].iFunctionPtr = &CRunModeAgent::TestGetXipLibrariesList;
+ iTestArray[6].iFunctionName = _L("TestGetXipLibrariesList");
+ iTestArray[7].iFunctionPtr = &CRunModeAgent::TestGetThreadList;
+ iTestArray[7].iFunctionName = _L("TestGetThreadList");
+ iTestArray[8].iFunctionPtr = &CRunModeAgent::TestGetCodeSegsList;
+ iTestArray[8].iFunctionName = _L("TestGetCodeSegsList");
+ iTestArray[9].iFunctionPtr = &CRunModeAgent::TestGetListInvalidData;
+ iTestArray[9].iFunctionName = _L("TestGetListInvalidData");
+ iTestArray[10].iFunctionPtr = &CRunModeAgent::TestMemoryAccess;
+ iTestArray[10].iFunctionName = _L("TestMemoryAccess");
+ iTestArray[11].iFunctionPtr = &CRunModeAgent::TestDebugFunctionality;
+ iTestArray[11].iFunctionName = _L("TestDebugFunctionality");
+ iTestArray[12].iFunctionPtr = &CRunModeAgent::TestSuspendResume;
+ iTestArray[12].iFunctionName = _L("TestSuspendResume");
+ iTestArray[13].iFunctionPtr = &CRunModeAgent::TestBreakPoints;
+ iTestArray[13].iFunctionName = _L("TestBreakPoints");
+ iTestArray[14].iFunctionPtr = &CRunModeAgent::TestModifyBreak;
+ iTestArray[14].iFunctionName = _L("TestModifyBreak");
+ iTestArray[15].iFunctionPtr = &CRunModeAgent::TestBreakInfo;
+ iTestArray[15].iFunctionName = _L("TestBreakInfo");
+ iTestArray[16].iFunctionPtr = &CRunModeAgent::TestRunToBreak;
+ iTestArray[16].iFunctionName = _L("TestRunToBreak");
+ iTestArray[17].iFunctionPtr = &CRunModeAgent::TestBreakPointsInLoop;
+ iTestArray[17].iFunctionName = _L("TestBreakPointsInLoop");
+ iTestArray[18].iFunctionPtr = &CRunModeAgent::TestRegisterAccess;
+ iTestArray[18].iFunctionName = _L("TestRegisterAccess");
+ iTestArray[19].iFunctionPtr = &CRunModeAgent::TestStep;
+ iTestArray[19].iFunctionName = _L("TestStep");
+ iTestArray[20].iFunctionPtr = &CRunModeAgent::TestDemandPaging;
+ iTestArray[20].iFunctionName = _L("TestDemandPaging");
+ iTestArray[21].iFunctionPtr = &CRunModeAgent::TestEventsForExternalProcess;
+ iTestArray[21].iFunctionName = _L("TestEventsForExternalProcess");
+ iTestArray[22].iFunctionPtr = &CRunModeAgent::TestEvents;
+ iTestArray[22].iFunctionName = _L("TestEvents");
+ iTestArray[23].iFunctionPtr = &CRunModeAgent::TestKillProcess;
+ iTestArray[23].iFunctionName = _L("TestKillProcess");
+ iTestArray[24].iFunctionPtr = &CRunModeAgent::TestProcessBreakPoints;
+ iTestArray[24].iFunctionName = _L("TestProcessBreakPoints");
+ iTestArray[25].iFunctionPtr = &CRunModeAgent::TestMultipleTraceEvents;
+ iTestArray[25].iFunctionName = _L("TestMultipleTraceEvents");
+ iTestArray[26].iFunctionPtr = &CRunModeAgent::TestAddRemoveProcessEvents;
+ iTestArray[26].iFunctionName = _L("TestAddRemoveProcessEvents");
+ iTestArray[27].iFunctionPtr = &CRunModeAgent::TestCrashFlash;
+ iTestArray[27].iFunctionName = _L("TestCrashFlash");
+ iTestArray[28].iFunctionPtr = &CRunModeAgent::TestProcessKillBreakpoint;
+ iTestArray[28].iFunctionName = _L("TestProcessKillBreakpoint");
+ iTestArray[29].iFunctionPtr = &CRunModeAgent::TestAttachToAll;
+ iTestArray[29].iFunctionName = _L("TestAttachToAll");
+ iTestArray[30].iFunctionPtr = &CRunModeAgent::TestResumeBreakpointsRepeatedly;
+ iTestArray[30].iFunctionName = _L("TestResumeBreakpointsRepeatedly");
+
+ };
+
+GLDEF_C TInt E32Main()
+//
+// Entry point for run mode debug driver test
+//
+ {
+ TInt ret = KErrNone;
+
+ // client
+ CTrapCleanup* trap = CTrapCleanup::New();
+ if (!trap)
+ return KErrNoMemory;
+ test.Title();
+ RunModeAgent = CRunModeAgent::NewL();
+ if (RunModeAgent != NULL)
+ {
+ __UHEAP_MARK;
+ TRAP(ret,RunModeAgent->ClientAppL());
+ __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<TEventInfo> 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<TEventInfo> 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();
+ }
--- /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<TInt>& 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
--- /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 <e32base.h>
+#include <e32base_private.h>
+
+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
--- /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 <e32debug.h>
+
+ #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 <e32debug.h>
+
+ #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
--- /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<number of applications to launch>
+// +m<number of times to launch each application>
+// +o<order of launch, 1 means launch in reverse order>
+//
+
+#include <e32base.h>
+#include <e32base_private.h>
+#include <e32cons.h>
+#include <e32test.h>
+#include <e32ldr.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <f32dbg.h>
+#include <f32file.h>
+#include <hal.h>
+#include <u32hal.h>
+#include <e32property.h>
+
+#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( "<Target Launcher: LaunchProcess returned %d", ret );
+ CleanupStack::PopAndDestroy( &targetName );
+
+ User::LeaveIfError( ret );
+
+ //By now the add proc event should have been delivered to the
+ //test app agent.
+ }
+ }
+
+ launchSemaphore.Wait( 500000 );
+
+ CleanupStack::PopAndDestroy( &launchSemaphore );
+
+ if( commandLine )
+ CleanupStack::PopAndDestroy( commandLine );
+
+ }
+
+
+GLDEF_C TInt E32Main()
+ {
+ RProcess thisProcess;
+ thisProcess.Rendezvous(KErrNone);
+ 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;
+ }
--- /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
--- /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 <u32std.h>
+
+// 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");
+ }
+
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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 <e32base.h>
+#include <e32base_private.h>
+#include <e32cons.h>
+#include "d_rmdebugthread.h"
+
+EXPORT_C TBuf8<SYMBIAN_RMDBG_MEMORYSIZE> 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;
+ }
--- /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
--- /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 <e32base.h>
+#include <e32base_private.h>
+#include <e32cons.h>
+#include <e32debug.h>
+#include "d_rmdebugthread2.h"
+
+#include "d_rmdebug_step_test.h"
+#include "d_rmdebug_bkpt_test.h"
+#include "d_demand_paging.h"
+
+TBuf8<SYMBIAN_RMDBG_MEMORYSIZE> 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;
+ }
--- /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 <e32property.h>
+
+#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
--- /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 <e32cia.h>
+//#include <e32base.h>
+//#include <e32cons.h>
+//#include "d_rmdebugthread.h"
+
+EXPORT_C __NAKED__ void RMDebug_BranchTst1( void )
+//
+//
+//
+{
+ asm("mov r0, #0 "); // aResult==KErrNone
+ asm("bx lr "); // Return
+}
+
--- /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
+}
--- /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 <e32base.h>
+#include <e32base_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <e32debug.h>
+#include <e32property.h>
+#include <u32hal.h>
+#include <hal.h>
+#include <f32file.h>
+#include <e32svr.h>
+#include <e32const.h>
+
+
+#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<aNumber; i++)
+ {
+ RThread thread;
+ RBuf threadName;
+ threadName.Create(KDebugThreadName().Length()+10); // the 10 is for appending i to the end of the name
+ threadName.Append(KDebugThreadName());
+ threadName.AppendNum(i);
+ TInt err = thread.Create(threadName, (TThreadFunction)SpinForever, KDefaultStackSize, KDebugThreadDefaultHeapSize, KDebugThreadDefaultHeapSize, NULL);
+ if(err != KErrNone)
+ {
+ RDebug::Printf("Couldn't create thread %d", err);
+ threadName.Close();
+ thread.Close();
+ break;
+ }
+ thread.SetPriority(EPriorityNormal);
+ TRequestStatus status;
+ thread.Rendezvous(status);
+ thread.Resume();
+ User::WaitForRequest(status);
+ thread.Close();
+ threadName.Close();
+ }
+ }
+
+void WaitFiveSecondsThenExit(void)
+ {
+ // wait for 5 seconds
+ User::After(5000000);
+ }
+
+TInt NumberOfCpus()
+ {
+ TInt r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0);
+ return r;
+ }
+
+TInt SetCpuAffinity(TInt aCpuNumber)
+ {
+ TInt TestCpuCount = NumberOfCpus();
+ RDebug::Printf("SetCpuAffinity --> 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<delay>\n\t: delay in microseconds before calling target function\n");
+ RDebug::Printf("\t-f<function-number>\n\t: enumerator from TDebugFunctionType representing function to call\n");
+ RDebug::Printf("\t-e<number>\n\t: number of extra threads to launch, these threads run endlessly\n");
+ }
+
+TInt E32Main()
+ {
+
+ 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;
+ }
+
--- /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
+
--- /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 <e32std.h>
+#include <e32std_private.h>
+#include <rm_debug_api.h>
+#include "t_rmdebug_dll.h"
+
+EXPORT_C TUid GetDSSUid()
+ {
+ return Debug::KUidDebugSecurityServer;
+ }
+
--- /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 <e32std.h>
+
+/**
+ 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();
--- /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 <e32base.h>
+#include <e32base_private.h>
+#include <e32cons.h>
+#include <e32test.h>
+#include <e32ldr.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#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;
+ }
--- /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
--- /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
+
+
--- /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
--- /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
--- /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"
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
+
--- /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
--- /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
+
--- /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
+
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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
--- /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 <e32base.h>
+#include <e32property.h>
+#include <e32test.h>
+
+#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!
+ }
+
--- /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
+
+
--- /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 <e32base.h>
+#include <e32property.h>
+#include <hal.h>
+#include <e32test.h>
+#include <e32def.h>
+#include <e32svr.h>
+
+
+#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;
+ }
+
--- /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 <u32hal.h>
+#include <f32file.h>
+#include <rm_debug_api.h>
+
+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<CAgentAsyncEvent> iTargetList;
+ };
+
+#endif // RMDEBUG_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_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;
+ }
+
--- /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 <e32test.h>
+
+// 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
+
--- /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 <e32base.h>
+#include <e32property.h>
+
+#include <hal.h>
+#include <e32test.h>
+
+#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( "<LaunchProcess() ret %d", ret );
+
+ CleanupStack::PopAndDestroy( &launcherProc ); // launcherProc
+ CleanupStack::PopAndDestroy( &launcherOptions ); // launcherOptions
+ CleanupStack::PopAndDestroy( &launcher ); //launcher
+
+ test( ret == KErrNone );
+
+ RSemaphore launchSemaphore;
+ CleanupClosePushL( launchSemaphore );
+
+ TFindSemaphore launchSemFinder( KLaunchSemaphoreNameSearchString );
+ TFullName semaphoreResult;
+ ret = launchSemFinder.Next(semaphoreResult);
+ 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( " <Wait for request returned with status %d", iStatus.Int() );
+ test( iStatus==KErrNone );
+
+ 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;
+ }
--- /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 <rm_debug_api.h>
+
+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<RBuf> iTargets;
+ TRequestStatus iStatus;
+ Debug::TEventInfo iEventInfo;
+ TPtr8 iEventPtr;
+ };
+
+#endif // RMDEBUG_MULTI_TARGET_H
--- /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 <e32base.h>
+
+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
--- /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 <e32base.h>
+#include <e32property.h>
+#include <e32test.h>
+#include <e32def.h>
+#include <e32const.h>
+#include <hal.h>
+
+#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;
+ }
+
--- /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 <u32hal.h>
+#include <f32file.h>
+#include <rm_debug_api.h>
+
+/* 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<Debug::TEventInfo> 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<TUint> 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
+
--- /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 ***
--- /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
--- /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 <kernel/kern_ext.mmh>
+
+
+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
--- /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
--- /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__
--- /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.
--- /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
--- /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
--- /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 <rm_debug_api.h>
+#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<Debug::TEventInfo>* 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<Debug::TEventInfo>* iRequestGetEventStatus;
+
+ DThread* iClientThread;
+
+ /**
+ * Ring buffer of pending events. Access to it is controlled by
+ * @see iEventQueueLock
+ */
+ RArray<TDriverEventInfo> 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
+
--- /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
--- /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
--- /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 <rm_debug_api.h>
+#include <kernel/kernel.h>
+
+/**
+@file
+@internalComponent
+*/
+
+class TDriverEventInfo
+ {
+public:
+ TDriverEventInfo();
+ void Reset();
+ TInt WriteEventToClientThread(TClientDataRequest<Debug::TEventInfo>* 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<KMaxName> iFileName;
+ TBuf8<Debug::KPanicCategoryMaxName> 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
--- /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 <e32cmn.h>
+#include <kernel/kern_priv.h>
+#include <rm_debug_api.h>
+
+/**
+@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<TRomEntry>& aRomEntryArray, const TLinAddr aAddress) const;
+ TInt GetDirectoryEntries(RPointerArray<TRomEntry>& aRomEntryArray, const TDesC& aDirectoryName) const;
+ TInt FindDirectory(const TDesC& aDirectory, TLinAddr& aAddress) const;
+ TInt GetDirectoryEntries(RPointerArray<TRomEntry>& aRomEntryArray, RArray<TPtr8>& 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<TPtr8>& aSubDirectories) const;
+};
+
+#endif //T_LIST_MANAGER_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<DTargetProcess> iProcesses;
+ RPointerArray<DDebugAgent> iAgentsAttachedToAll;
+ RPointerArray<NFastSemaphore> iFrozenThreadSemaphores;
+ };
+
+// static global object
+extern DProcessTracker TheDProcessTracker;
+
+#endif // D_PROCESS_TRACKER_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 <rm_debug_api.h>
+#include <kernel/kern_priv.h>
+#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<TBreakEntry> 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
--- /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 );
+ }
+ }
--- /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
--- /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
--- /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<DDebugAgent> iAgentList;
+
+ RArray<TUint64> iSuspendedThreads;
+
+ RPointerArray<NFastSemaphore> iFrozenThreadSemaphores;
+
+};
+
+#endif // D_TARGET_PROCESS_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 <kernel/kernel.h>
+ #include <nk_trace.h>
+
+ #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 <e32debug.h>
+
+ #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
+
--- /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 <kernel/kern_priv.h>
+#include <rm_debug_api.h>
+
+class DebugUtils
+ {
+public:
+ static DThread* OpenThreadHandle(TUint64 aThreadId);
+ static DProcess* OpenProcessHandle(TUint64 aProcessId);
+ static DThread* OpenFirstThreadForProcess(DProcess* aProcess);
+ };
+
+#endif //DEBUG_UTILS_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<Debug::TProcessInfo> 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<Debug::TEventInfo>* iAsyncGetValueRequest;
+};
+
+#endif //__RM_DEBUG_DRIVER_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__
--- /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 <rm_debug_api.h>
+
+/**
+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<KMaxName> 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<KMaxName> iProcessName;
+ TUint64 iAgentId;
+};
+
+class TEventMetaData
+ {
+public:
+ TBuf8<KMaxName> 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<TAny*>(&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<TAny*>(&info),0);
+}
+
+inline TInt RRM_DebugDriver::ClearBreak(const Debug::TBreakId aBreakId)
+{
+ return DoSvControl(EControlClearBreak, reinterpret_cast<TAny*>(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<TAny*>(&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<TAny*>(&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<TAny*>(&info), 0);
+}
+
+inline TInt RRM_DebugDriver::SuspendThread(const TUint32 aThreadId)
+{
+ return DoControl(EControlSuspendThread, reinterpret_cast<TAny*>(aThreadId));
+}
+
+inline TInt RRM_DebugDriver::ResumeThread(const TUint32 aThreadId)
+{
+ return DoSvControl(EControlResumeThread, reinterpret_cast<TAny*>(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<TAny*>(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<TAny*>(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<TAny*>(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<TAny*>(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<TAny*>(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<TAny*>(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<TAny*>(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<TInt>(&info));
+}
+
+inline TInt RRM_DebugDriver::GetStaticLibraryInfo(const TInt aIndex, Debug::TEventInfo &aInfo)
+{
+ return DoControl(EControlGetStaticLibraryInfo, reinterpret_cast<TAny*>(aIndex), (TAny*)&aInfo);
+}
+
+inline TInt RRM_DebugDriver::GetDebugFunctionalityBufSize(TUint32 &aBufSize)
+{
+ return DoControl(EControlGetDebugFunctionalityBufSize, reinterpret_cast<TAny*>(&aBufSize));
+}
+
+inline TInt RRM_DebugDriver::GetDebugFunctionality(TDes8& aDebugFunctionality)
+{
+ return DoControl(EControlGetDebugFunctionality,reinterpret_cast<TAny*>(&aDebugFunctionality));
+}
+
+inline TInt RRM_DebugDriver::GetMemoryOperationMaxBlockSize(TUint32 &aMaxSize)
+{
+ return DoControl(EControlGetMemoryOperationMaxBlockSize, reinterpret_cast<TAny*>(&aMaxSize));
+}
+
+inline TInt RRM_DebugDriver::AttachProcess(TDesC8& aProcessName, TUint64 aAgentId)
+{
+ TRM_DebugAgentId info(aAgentId);
+ return DoControl(EControlAttachProcess,reinterpret_cast<TAny*>(&aProcessName),reinterpret_cast<TAny*>(&info));
+}
+
+inline TInt RRM_DebugDriver::DetachProcess(TDesC8& aProcessName, TUint64 aAgentId)
+{
+ TRM_DebugAgentId info(aAgentId);
+ return DoControl(EControlDetachProcess,reinterpret_cast<TAny*>(&aProcessName),reinterpret_cast<TAny*>(&info));
+}
+
+inline TInt RRM_DebugDriver::DetachAgent(TUint64 aAgentId)
+{
+ TRM_DebugAgentId info(aAgentId);
+ return DoControl(EControlDetachAgent,reinterpret_cast<TAny*>(&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<TAny*>(&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<TAny*>(aThreadId),reinterpret_cast<TAny*>(aNumSteps));
+}
+
+inline TInt RRM_DebugDriver::IsDebuggable(const TUint32 aProcessId)
+{
+ return DoControl(EControlIsDebuggable,reinterpret_cast<TAny*>(aProcessId),NULL);
+}
+
+inline TInt RRM_DebugDriver::KillProcess(const TUint32 aProcessId, const TInt32 aReason)
+{
+ return DoControl(EControlKillProcess,reinterpret_cast<TAny*>(aProcessId),reinterpret_cast<TAny*>(aReason));
+}
+
+#endif // __RM_DEBUG_KERNELDRIVER_H__
+
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <nk_trace.h>
+#include <arm.h>
+
+#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; i<EEventsLast; i++)
+ {
+ iEventActions[i] = EActionIgnore;
+ }
+ }
+
+DDebugAgent* DDebugAgent::New(TUint64 aId)
+ {
+ LOG_MSG2("DDebugAgent::New(id=0x%lx)", aId);
+ DDebugAgent* agent = new DDebugAgent(aId);
+ if(agent == NULL)
+ {
+ return (NULL);
+ }
+ if(KErrNone != agent->Construct())
+ {
+ 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; i<KNumberOfEventsToQueue; i++)
+ {
+ err = iEventQueue.Append(emptyEvent);
+ if (err != KErrNone)
+ {
+ LOG_MSG("Error appending blank event entry");
+ return err;
+ }
+ }
+
+ err = Kern::CreateClientDataRequest(iRequestGetEventStatus);
+ if(err != KErrNone)
+ {
+ LOG_MSG("Error creating TClientDataRequest");
+ return err;
+ }
+
+ LOG_MSG2("DDebugAgent::Construct() iRequestGetEventStatus=0x%08x", iRequestGetEventStatus);
+
+ return err;
+ }
+
+// dtor
+DDebugAgent::~DDebugAgent()
+ {
+ iEventQueue.Reset();
+
+ if (iEventQueueLock)
+ iEventQueueLock->Close(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<TEventInfo>* 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
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <u32std.h>
+#include <kernel/kernel.h>
+#include <rm_debug_api.h>
+#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<ERegisterLast; i++)
+ {
+ if(Register::GetCoreRegId(DebugFunctionalityRegistersCoreInfo[i].iTagId) == Register::GetCoreRegId(aRegisterInfo))
+ {
+ aTag = DebugFunctionalityRegistersCoreInfo[i];
+ return KErrNone;
+ }
+ }
+ }
+ else if(Register::IsCoproReg(aRegisterInfo))
+ {
+ //get aRegisterInfo's details
+ TUint32 crn = Register::GetCRn(aRegisterInfo);
+ TUint32 crm = Register::GetCRm(aRegisterInfo);
+ TUint32 opcode1 = Register::GetOpcode1(aRegisterInfo);
+ TUint32 opcode2 = Register::GetOpcode2(aRegisterInfo);
+ TUint32 coproNum = Register::GetCoproNum(aRegisterInfo);
+
+ for(TInt i=0; i<sizeof(DebugFunctionalityRegistersCoProInfo)/sizeof(TTag); i++)
+ {
+ TUint32 tagId = DebugFunctionalityRegistersCoProInfo[i].iTagId;
+
+ //if this entry is the DACR
+ if((Register::GetCRm(tagId) == 3) && (Register::GetCoproNum(tagId) == 15))
+ {
+ if((crm == 3) && (coproNum == 15))
+ {
+ aTag = DebugFunctionalityRegistersCoProInfo[i];
+ return KErrNone;
+ }
+ }
+ //each coprocessor register that is supported will need logic adding here
+ }
+ }
+ else // in the future there could be other types of register supported
+ {
+ //for now just fall through to unsupported case
+ }
+
+ //found an unsupported register so just return EAccessUnknown as the access level
+ aTag.iTagId = aRegisterInfo;
+ aTag.iSize = 0;
+ aTag.iValue = EAccessUnknown;
+
+ return KErrNotSupported;
+ }
+
+/**
+ * Returns the maximum memory block size which can be read or written.
+ * @return the maximum memory block size which can be read or written
+*/
+TUint32 TDebugFunctionality::GetMemoryOperationMaxBlockSize()
+ {
+ return DebugFunctionalityMemoryInfo[EMemoryMaxBlockSize].iValue;
+ }
+
+/**
+ * Helper function to append a DebugFunctionalityXXX SubBlock
+ * into a TDes buffer
+ */
+void TDebugFunctionality::AppendBlock(const TSubBlock& aDFSubBlock, TDes8& aDFBlock)
+ {
+ // Copy the aSubDFBlock.header into aDFBlock (Note we don't put in a TSubBlock structure
+ // as the block is just that - a flat block so the pointer is not required)
+ TPtr8 SubDFBlockHdrPtr((TUint8*)&aDFSubBlock.iHeader,sizeof(TTagHeader),sizeof(TTagHeader));
+
+ aDFBlock.Append(SubDFBlockHdrPtr);
+
+ // Append all the Tags
+ for (TUint i=0; i<aDFSubBlock.iHeader.iNumTags; i++)
+ {
+ TPtr8 tmpPtr((TUint8*)&aDFSubBlock.iTagArray[i],sizeof(TTag),sizeof(TTag));
+
+ aDFBlock.Append(tmpPtr);
+ }
+ }
+
+/**
+ * Computes the size in bytes of aDFBlock
+ * @param aDFSubBlock
+ * @return TUint32 size of sub block
+ */
+TUint32 TDebugFunctionality::ComputeBlockSize(const TSubBlock& aDFSubBlock)
+ {
+ TUint32 size = 0;
+
+ // Header size
+ size += sizeof(TTagHeader);
+
+ // size of all the tags within the header:
+ size += aDFSubBlock.iHeader.iNumTags * sizeof(TTag);
+
+ return size;
+ }
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debugsrv/runmodedebug/rmdriver/src/d_driver_event_info.cpp Fri Aug 27 11:37:29 2010 +0300
@@ -0,0 +1,342 @@
+// 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 "d_driver_event_info.h"
+#include "debug_logging.h"
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+
+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<TEventInfo>* 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;
+ }
+
--- /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 <arm.h>
+
+// 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; i<threads->Count(); 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<<EArmSp))
+ {
+ entry.iSupervisorStackPtrValid = EValid;
+ }
+ }
+
+ //copy name data into the buffer
+ TUint16* ptr = &(entry.iName[0]);
+ const TUint8* ptr8 = fileName.Ptr();
+ const TUint8* ptr8End = ptr8 + nameLength;
+ while(ptr8 < ptr8End)
+ {
+ *ptr++ = (TUint16)*ptr8++;
+ }
+
+ aBuffer.SetLength(aDataSize);
+ }
+ }
+
+/**
+ Get global process 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::GetProcessList(TDes8& aBuffer, TUint32& aDataSize) const
+ {
+ LOG_MSG("TListManager::GetProcessList()");
+
+ //get a pointer to the kernel's process list
+ DObjectCon* processes = Kern::Containers()[EProcess];
+
+ if(processes == NULL)
+ {
+ //if can't get container then something is seriously wrong
+ return KErrNotFound;
+ }
+
+ //have to read the processes in a critical section
+ NKern::ThreadEnterCS();
+ processes->Wait();
+
+ aDataSize = 0;
+ //iterate through the processes adding them to the buffer
+ for(TInt i=0; i<processes->Count(); 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<TRomEntry> entries;
+ //get the entries in KZSysBin
+ TInt err = GetDirectoryEntries(entries, KZSysBin());
+ if(KErrNone != err)
+ {
+ entries.Close();
+ return err;
+ }
+
+ aDataSize = 0;
+ for(TInt i=0; i<entries.Count(); i++)
+ {
+ //if the entry is XIP and it's not a directory then it's a candidate to add
+ if( (entries[i]->iAtt & 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<TRomEntry>& 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<TPtr8> 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<folders.Count(); i++)
+ {
+ if(folders[i].Length() == 0)
+ {
+ // there were two backslashes in a row
+ folders.Close();
+ return KErrArgument;
+ }
+ }
+
+ //get a pointer to the start of the rom root directory list
+ TLinAddr romRootDirectoryList = Epoc::RomHeader().iRomRootDirectoryList;
+
+ //the first 4 bytes of the rom root directory list is a count of how many sections (rom roots) there are
+ TUint32 rootDirectoryCount = (TUint32)*(TLinAddr*)romRootDirectoryList;
+
+ //rootDirectoryPointer will be shifted through the rom root directory list and will contain pointers to the sections in the rom
+ TLinAddr rootDirectoryPointer = romRootDirectoryList;
+ for(TInt i=0; i<rootDirectoryCount; i++)
+ {
+ //the address of the section is stored in the second four bytes of the 8 byte pair reserved for each section
+ rootDirectoryPointer += 8;
+
+ //romRoot contains the address of the root of the section
+ TLinAddr romRoot = *(TLinAddr*)rootDirectoryPointer;
+
+ //append the directory entries from romRoot's z:\sys\bin subdirectory
+ TInt err = GetDirectoryEntries(aRomEntryArray, folders, romRoot);
+ if(KErrNone != err)
+ {
+ folders.Close();
+ return err;
+ }
+ }
+ folders.Close();
+ return KErrNone;
+ }
+
+/**
+ Recursively finds the subdirectories in aArray and stores references to the
+ entries in the most derived subdirectory in aRomEntryArray
+
+ @param aRomEntryArray on return will contain the entries in the directory corresponding to aArray
+ @param aArray an array containing the directory to get the entries for, i.e. { 'sys', 'bin' }
+ @param aAddress address in rom to being searching from
+
+ @param KErrNone on success, or one of the other system wide error codes
+*/
+TInt TListManager::GetDirectoryEntries(RPointerArray<TRomEntry>& aRomEntryArray, RArray<TPtr8>& 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<TRomEntry>& 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; i<numDirectoryEntries; i++)
+ {
+ TRomEntry* romEntry = (TRomEntry*)address;
+
+ //store the entry
+ TInt err = aRomEntryArray.Append(romEntry);
+ if(KErrNone != err)
+ {
+ return err;
+ }
+
+ //length of the name of the rom entry
+ TInt nameLength = romEntry->iNameLength;
+
+ //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<TRomEntry> dirContents;
+ TInt err = GetDirectoryContents(dirContents, aAddress);
+ if(KErrNone != err)
+ {
+ dirContents.Close();
+ return err;
+ }
+ for(TInt i=0; i<dirContents.Count(); i++)
+ {
+ //create a reference to the TRomEntry in the rom to access its attributes
+ TRomEntry& romEntry = *(dirContents[i]);
+ if(romEntry.iAtt & KEntryAttDir)
+ {
+ // this entry's a directory so check if it matches aDirectory
+ const TInt nameLength = romEntry.iNameLength;
+ TPtr8 name((TUint8*)&(romEntry.iName), nameLength * 2, nameLength * 2);
+ if(0 == aDirectory.CompareF(name))
+ {
+ // names matched so get the address of this directory's contents
+ aAddress = romEntry.iAddressLin;
+ dirContents.Close();
+ return KErrNone;
+ }
+ }
+ }
+ dirContents.Close();
+ //couldn't find it so return error
+ return KErrNotFound;
+ }
+
+/**
+ Helper function to get code seg type.
+
+ @param aCodeSeg code seg to get type of
+ @param aType will contain type on return
+
+ @return KErrNone on success, KErrNotFound if aCodeSeg is NULL
+ */
+TInt TListManager::GetCodeSegType(const DCodeSeg* aCodeSeg, TCodeSegType& aType) const
+ {
+ if(!aCodeSeg)
+ {
+ return KErrNotFound;
+ }
+
+ if(aCodeSeg->IsExe())
+ {
+ 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<TPtr8>& 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;
+ }
+
+
+
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+
+#include <rm_debug_api.h>
+#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; i<iFrozenThreadSemaphores.Count(); i++)
+ {
+ LOG_MSG2("~DProcessTracker Resuming frozen NThread 0x%08x via FSSignal ", iFrozenThreadSemaphores[i]->iOwningThread );
+ 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; i<numberOfProcesses; i++)
+ {
+ // remove the agent from the process (we don't care about the return code)
+ iProcesses[i]->RemoveAgent(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; i<iFrozenThreadSemaphores.Count(); i++)
+ {
+ if(iFrozenThreadSemaphores[i]->iOwningThread == 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; i<iFrozenThreadSemaphores.Count(); i++)
+ {
+ if(iFrozenThreadSemaphores[i]->iOwningThread == &(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;
+ }
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <u32std.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <nk_trace.h>
+#include <arm.h>
+#include <kernel/cache.h>
+#include <platform.h>
+#include <nkern.h>
+#include <u32hal.h>
+
+#include <rm_debug_api.h>
+#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; i<iBreakPointList.Count(); i++)
+ {
+ if ((iBreakPointList[i].iAddress != 0) && !iBreakPointList[i].iObsoleteLibraryBreakpoint)
+ {
+ TUint32 id = iBreakPointList[i].iId + (iBreakPointList[i].iThreadSpecific ? 0 : 1);
+ LOG_MSG5(" Will try to clear breakpoint[%d] at address 0x%x, iId=0x%016lx, thrdSpec=%d",
+ i, iBreakPointList[i].iAddress, iBreakPointList[i].iId, iBreakPointList[i].iThreadSpecific);
+
+ DThread *threadObj = DebugUtils::OpenThreadHandle(id);
+ if (threadObj)
+ {
+ XTRAPD(r, XT_DEFAULT, err = DebugSupport::RestoreCode(threadObj, iBreakPointList[i].iAddress));
+ err = (KErrNone == r) ? err : r;
+ threadObj->Close(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<iBreakPointList.Count(); i++)
+ {
+ if ((iBreakPointList[i].iAddress >= 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
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <nk_trace.h>
+#include <arm.h>
+#include <rm_debug_api.h>
+
+#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<TUint16>(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<amode>
+ 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
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include "nk_priv.h"
+#include <rm_debug_api.h>
+
+#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);
+ }
+ }
+ }
+
--- /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;
+ }
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <kernel/arm/arm.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <nk_trace.h>
+
+#include <rm_debug_api.h>
+#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; i<EEventLimit; i++)
+ {
+ iEventHandlers[i] = &DRM_DebugChannel::HandleUnsupportedEvent;
+ }
+ iEventHandlers[EEventUserTrace] = &DRM_DebugChannel::HandleUserTrace;
+ iEventHandlers[EEventRemoveLibrary] = &DRM_DebugChannel::RemoveLibrary;
+ iEventHandlers[EEventAddLibrary] = &DRM_DebugChannel::AddLibrary;
+ iEventHandlers[EEventStartThread] = &DRM_DebugChannel::StartThread;
+ iEventHandlers[EEventSwExc] = &DRM_DebugChannel::HandleSwException;
+ iEventHandlers[EEventHwExc] = &DRM_DebugChannel::HandleHwException;
+ iEventHandlers[EEventKillThread] = &DRM_DebugChannel::HandleEventKillThread;
+ iEventHandlers[EEventAddProcess] = &DRM_DebugChannel::HandleAddProcessEvent;
+ iEventHandlers[EEventRemoveProcess] = &DRM_DebugChannel::HandleRemoveProcessEvent;
+}
+
+TInt DRM_DebugEventHandler::Create(DLogicalDevice* aDevice, DLogicalChannel* aChannel, DThread* aClient)
+{
+ LOG_MSG3("DRM_DebugEventHandler::Create(), aClientthread=0x%08x id=%d", aClient, aClient->iId);
+
+ 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;
+ }
+
--- /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 <e32def.h>
+#include <e32def_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <e32ldr.h>
+#include <u32std.h>
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <nk_trace.h>
+#include <arm.h>
+#include <kernel/cache.h>
+#include <platform.h>
+#include <nkern.h>
+#include <u32hal.h>
+#include <rm_debug_api.h>
+
+#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<SCodeSegEntry>* dynamicCode = &(process->iDynamicCode);
+
+ for (TInt j=0; j<dynamicCode->Count(); 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; i<iDebugProcessList.Count(); i++)
+ {
+ if(process->iId == 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<numberOfRegisters; i++)
+ {
+ //get current register id
+ TRegisterInfo reg;
+ TInt err = GetTRegisterInfo(aRegisterIds, i, reg);
+ //exit with the error value if there was an error
+ if(err != KErrNone)
+ return err;
+
+ //if unknown register then exit as can't know how many bytes this entry will
+ //represent in aRegisterValues
+ TTag registerTag;
+ TDebugFunctionality::GetRegister(reg, registerTag);
+ if(registerTag.iValue == EAccessUnknown)
+ {
+ return KErrArgument;
+ }
+
+ //get the current register id as a kernel register
+ TArmReg armReg;
+ err = GetKernelRegisterId(reg, armReg);
+ if((err == KErrNotSupported) || (registerTag.iValue == EAccessNone) || (registerTag.iValue == EAccessWriteOnly))
+ {
+ //reading this register is not supported
+ aRegisterFlags.Append(ENotSupported);
+ //just skip over this entry in the values buffer
+ if(aRegisterValues.Length() + registerTag.iSize > 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<numberOfRegisters; i++)
+ {
+ //get current register id
+ TRegisterInfo reg;
+ TInt err = GetTRegisterInfo(aRegisterIds, i, reg);
+ //exit with the error value if there was an error
+ if(err != KErrNone)
+ {
+ return err;
+ }
+
+ //if unknown register then exit as can't know how many bytes this entry will
+ //represent in aRegisterValues
+ TTag registerTag;
+ TDebugFunctionality::GetRegister(reg, registerTag);
+ if(registerTag.iValue == EAccessUnknown)
+ {
+ return KErrArgument;
+ }
+
+ //get the current register id as a kernel register
+ TArmReg armReg;
+ err = GetKernelRegisterId(reg, armReg);
+ if((err == KErrNotSupported) || (registerTag.iValue == EAccessNone) || (registerTag.iValue == EAccessReadOnly))
+ {
+ //writing to this register is not supported
+ aRegisterFlags.Append(ENotSupported);
+ }
+ else if(GetFlagAtOffset(flags, armReg))
+ {
+ if(registerTag.iSize == sizeof(TArmReg))
+ {
+ //set flag as valid
+ aRegisterFlags.Append(EValid);
+ if(offset + sizeof(TArmReg) > 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<const TRegisterInfo*>(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<<aIndex);
+ }
+
+/* Register the attachment of a debug agent to a process to be debugged
+ *
+ * @param a1 - TDes8 target process name
+ * @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::AttachProcess(TAny* a1, TAny* a2)
+ {
+ LOG_MSG("DRM_DebugChannel::AttachProcess()");
+
+ // Validate the supplied TDes8 target process name in a1
+ TInt length = Kern::ThreadGetDesLength(iClientThread, a1);
+ if (length < 0) return length;
+
+ // Check the processname is a valid size for a filepath
+ if (length < 1 || length >= 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;
+ }
--- /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
--- /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
+
--- /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 <rm_debug_api.h>
+
+#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
--- /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 <rm_debug_api.h>
+#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<CProcessPair> iActiveDebugMap;
+ RPointerArray<CProcessPair> 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
--- /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 <f32file.h>
+#include <d32locd.h>
+
+#include <rm_debug_api.h>
+
+#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<CSecuritySvrAsync> 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
+
--- /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 <e32base.h>
+
+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
+
--- /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
--- /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 <e32cmn.h>
+#include <e32def_private.h>
+
+/**
+ 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 <e32std.h>
+
+// 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<TThreadId> 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<TThreadId> 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<TThreadId> threadIdPckg(aThreadId);
+
+ TBreakInfo breakInfo;
+ breakInfo.iAddress = aAddress;
+ breakInfo.iArchitectureMode = aArchitectureMode;
+ TPckgBuf<TBreakInfo> 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<TThreadId> 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<TProcessId> 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<TProcessId> threadIdPckg(aProcessId);
+
+ TBreakInfo breakInfo;
+ breakInfo.iAddress = aAddress;
+ breakInfo.iArchitectureMode = aArchitectureMode;
+ TPckgBuf<TBreakInfo> 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<TThreadId> threadIdPckg(aThreadId);
+ //set up memory info object
+ TMemoryInfo memoryInfo;
+ memoryInfo.iAddress = aAddress;
+ memoryInfo.iSize = aLength;
+ memoryInfo.iAccess = aAccessSize;
+ memoryInfo.iEndianess = aEndianess;
+
+ TPckgBuf<TMemoryInfo> 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<TThreadId> threadIdPckg(aThreadId);
+ //create memory info object
+ TMemoryInfo memoryInfo;
+ memoryInfo.iAddress = aAddress;
+ memoryInfo.iSize = aLength;
+ memoryInfo.iAccess = aAccessSize;
+ memoryInfo.iEndianess = aEndianess;
+
+ TPckgBuf<TMemoryInfo> 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<TThreadId> 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<TThreadId> 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<TThreadId> 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<TProcessId> 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
+
+
+
--- /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 <kernel/kernel.h>
+ #include <nkern/nk_trace.h>
+
+ #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 <e32debug.h>
+
+ #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
+
--- /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 <e32base.h>
+#include <e32base_private.h>
+
+// Required for logging
+#include <rm_debug_api.h>
+
+#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;
+ }
+
--- /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 <e32base.h>
+#include <e32base_private.h>
+
+#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
+
--- /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 <e32base.h>
+#include <e32base_private.h>
+#include <rm_debug_api.h>
+#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; i<iActiveDebugMap.Count(); i++)
+ {
+ // Note that the equality is of the debug agent id and the proc name
+ if(*processPair == *(iActiveDebugMap[i]))
+ {
+ //process already exists
+ LOG_MSG( " AttachProcessL() error : KErrAlreadyExists in active map\n" );
+ delete processPair;
+ return KErrAlreadyExists;
+ }
+ }
+
+ //check whether the pair already exists in the passive map
+ for(TInt i=0; i<iPassiveDebugMap.Count(); i++)
+ {
+ if(*processPair == *(iPassiveDebugMap[i]))
+ {
+ //process already exists
+ LOG_MSG( " AttachProcessL() error : KErrAlreadyExists in passive map\n" );
+ delete processPair;
+ return KErrAlreadyExists;
+ }
+ }
+
+ if(aPassive)
+ {
+ //just add the pair and return
+ TInt err = iPassiveDebugMap.Append(processPair);
+ if(err != KErrNone)
+ {
+ // couldn't add pair for some unknown reason, so delete the pair
+ LOG_MSG2( " AttachProcessL() error %d appending passive process pair", err );
+ delete processPair;
+ }
+ return err;
+ }
+ else
+ {
+ //check whether the process Id has already been reserved
+ for(TInt i=0; i<iActiveDebugMap.Count(); i++)
+ {
+ // Now check if this is already debugged, but only if its for a particular process.
+ // We can have several entries from AttachAll calls, and its ok to add them
+ if( (!processPair->ProcessNameMatches(_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; i<iActiveDebugMap.Count(); i++)
+ {
+ if(iActiveDebugMap[i]->Equals(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; i<iPassiveDebugMap.Count(); i++)
+ {
+ if(iPassiveDebugMap[i]->Equals(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; i<iActiveDebugMap.Count(); i++)
+ {
+ // If both match, which can include aTargetProcessName being "*"
+ if(iActiveDebugMap[i]->Equals(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<CProcessPair>& map = (aPassive) ? iPassiveDebugMap : iActiveDebugMap;
+
+ //iterate through the map trying to match the aTargetProcessName
+ for(TInt i=0; i<map.Count(); i++)
+ {
+ if(map[i]->ProcessNameMatches(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; i<iPassiveDebugMap.Count(); i++)
+ {
+ if(iPassiveDebugMap[i]->Equals(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
+
--- /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 <e32std.h>
+#include <e32std_private.h>
+#include <e32btrace.h>
+#include <d32btrace.h>
+#include <e32base.h>
+#include <e32base_private.h>
+#include <e32uid.h>
+#include <f32file.h>
+#include <e32capability.h>
+#include <rm_debug_api.h>
+
+// required for direct parsing of e32image/tromimage headers
+#include <f32image.h>
+#include <e32rom.h>
+
+//added for direct access to media driver
+#include <partitions.h>
+#include <ftlcontrolio.h>
+
+#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<CSecuritySvrServer*>(const_cast<CServer2*>(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<RLibrary::TInfo> 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_<DA_SID>.exe" where <DA_SID> 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<TLocalDriveCapsV2> capsBuf(iCaps);
+
+ //check for the symbian crash partition
+ for (i=0; i<KMaxLocalDrives; i++)
+ {
+ error = iLocalDrive.Connect (i, changed);
+ if ( error == KErrNone)
+ {
+ error = iLocalDrive.Caps(capsBuf);
+ if ( error != KErrNone)
+ {
+ //continue if not found
+ continue;
+ }
+ if ( iCaps.iPartitionType == (TUint16)KPartitionTypeSymbianCrashLog)
+ {
+ LOG_MSG2("Found Symbian crash log partition on drive: %d",i);
+ iCrashConnected = ETrue;
+ break;
+ }
+ }
+ }
+ if ( i == KMaxLocalDrives)
+ {
+ LOG_MSG("No crash log partition found with valid crash log signature found. Exiting...");
+ User::Leave (KErrNotFound);
+ }
+
+ // Nand Flash not currently supported.
+ if (iCaps.iType == EMediaNANDFlash)
+ {
+ LOG_MSG( "CSecuritySvrSession::ConnectCrashPartitionL() Nand Flash not currently supported\n" );
+ User::Leave (KErrNotSupported);
+ }
+ }
+/** Checks that aHeaderData contains enough data to cast it to the
+ appropriate header type.
+
+ @param aHeaderData buffer containing header data read from a file
+ @param aXip boolean indicating whether the header data is for an XIP image
+
+ @return ETrue if enough data in buffer, EFalse otherwise
+ */
+TBool CSecuritySvrSession::CheckSufficientData(const TDesC8& aHeaderData, const TBool aXip) const
+ {
+ TUint minimumHeaderSize = aXip ? sizeof(TRomImageHeader) : sizeof(E32ImageHeaderV);
+ return (aHeaderData.Length() >= 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; i<iAsyncHandlers.Count(); i++)
+ {
+ if (processName8.Compare(iAsyncHandlers[i]->ProcessName()) == 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; i<iAsyncHandlers.Count(); i++)
+ {
+ if (iAsyncHandlers[i]->ProcessName().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; i<iAsyncHandlers.Count(); i++)
+ {
+ if (processName8.Compare(iAsyncHandlers[i]->ProcessName()) == 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; i<iAsyncHandlers.Count(); i++)
+ {
+ if (processName8.Compare(iAsyncHandlers[i]->ProcessName()) == 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; i<KMaxDrives; i++)
+ {
+ //if the drive is not valid then skip this drive
+ if(!driveList[i])
+ {
+ //skip processing this drive
+ continue;
+ }
+
+ //get the drive letter and insert it as the drive letter for dirName
+ TChar driveLetter;
+ User::LeaveIfError(fs.DriveToChar(i, driveLetter));
+ dirName[0] = (TUint)driveLetter;
+
+ //get a list of the exes in this drive's sys/bin directory
+ CDir* localDir = NULL;
+ TInt err = fs.GetDir(dirName, uids, ESortByName, localDir);
+ if(KErrNoMemory == err)
+ {
+ User::Leave(err);
+ }
+ if(!localDir)
+ {
+ //skip processing this drive
+ continue;
+ }
+
+ //push onto cleanup stack in case we leave
+ CleanupStack::PushL(localDir);
+
+ //iterate through the files
+ for(TInt j=0; j<localDir->Count(); j++)
+ {
+ //will store x:\sys\bin\<file-name> 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
--- /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 <rm_debug_api.h>
+#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();
+ }
+
--- /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 <e32base.h>
+#include <e32base_private.h>
+#include <rm_debug_api.h>
+
+#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;
+ }
--- 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 @@
<component name="tracecompiler">
<unit unitID="tools.tracecompiler" mrp="" bldFile="&layer_real_source_path;/tracefw/tracecompiler/group" name="tracecompiler" />
</component>
+ <component name="runmodedebug">
+ <unit unitID="tools.runmodedebug" mrp="" bldFile="&layer_real_source_path;/debugsrv/runmodedebug/group" name="runmodedebug" />
+ </component>
</module>
</layer>
</systemModel>
Binary file piprofiler/group/ReleaseNotes_PIProfiler.txt has changed
--- 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)
--- 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;
--- /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 <ecom/registryinfo.rh>
+
+// 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";
+ }
+ };
+ }
+ };
+ }
--- /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 <platform_paths.hrh>
+
+
+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
--- /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
--- /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 <w32std.h>
+#include <e32std.h>
+
+#include <e32property.h>
+#include <HWRMPower.h>
+#include <HWRMLight.h>
+
+// user definitions
+#include <piprofiler/SamplerPluginInterface.h>
+#include <piprofiler/ProfilerGenericClassesUsr.h>
+
+// 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<TSamplerAttributes>* 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<TSamplerAttributes>* 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
+
--- /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"
--- /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 <piprofiler/ProfilerTraces.h>
+
+#include <centralrepository.h>
+#include <HWRMPower.h>
+#include <HWRMLight.h>
+#include <hwrm/hwrmpowerdomaincrkeys.h>
+
+
+// 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<TSamplerAttributes>(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<TSamplerAttributes>* 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); i<aAllSettings->MdcaCount(); 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);j<aAllSettings->MdcaCount();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
--- /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 <e32std.h>
+#include <ecom/implementationproxy.h>
+
+#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;
+}
+
--- 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
--- /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__
--- /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