--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/debug/d_debugapi.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,470 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32test\debug\d_debugapi.cpp
+// LDD-based debug agent. It uses debugAPI provided by kernel extension
+// kdebug.dll (ARMv5) or kdebugv6 (ARMv6) to access and display various
+// kernel objects. It uses debug port as output. See t_DebugAPI.cpp
+//
+//
+
+#include <kernel/kern_priv.h>
+#include "d_debugapi.h"
+
+_LIT(KClientPanicCat, "D_DEBUGAPI");
+#define KMaxNameSize 20
+
+TInt DDebugAPIChecker::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
+ {
+ //This is the entry point for all debuggers. Super page contains the address of DebuggerInfo instance.
+ iDebugInfo = Kern::SuperPage().iDebuggerInfo;
+
+ if (!iDebugInfo)
+ {
+ Kern::Printf("Error:Debugger is not installed");
+ return KErrNotReady;
+ }
+ return GetOffsets(); //Obtain the copy of offsets.
+ }
+
+/**
+Copies the offset tables from Debug API Kernel extension.
+*/
+TInt DDebugAPIChecker::GetOffsets()
+ {
+ //Get the memory-model-specific offset table
+ switch (iDebugInfo->iMemoryModelType)
+ {
+ case EARMv5MMU:
+ iMMUType = iDebugInfo->iMemoryModelType;
+ if ((iVariantOffsetTable = new TMovingDebugOffsetTable)==NULL)
+ return KErrNoMemory;
+ memcpy(iVariantOffsetTable, iDebugInfo->iMemModelObjectOffsetTable, sizeof(TMovingDebugOffsetTable));
+ break;
+
+ case EARMv6MMU:
+ iMMUType = iDebugInfo->iMemoryModelType;
+ if ((iVariantOffsetTable = new TMultipleDebugOffsetTable)==NULL)
+ return KErrNoMemory;
+ memcpy(iVariantOffsetTable, iDebugInfo->iMemModelObjectOffsetTable, sizeof(TMultipleDebugOffsetTable));
+ break;
+
+ default:
+ return KErrNotSupported;
+ }
+
+ //Get the main offset table
+ if ((iOffsetTable = new TDebugOffsetTable)==NULL)
+ {
+ delete iVariantOffsetTable;
+ return KErrNoMemory;
+ }
+ memcpy(iOffsetTable, iDebugInfo->iObjectOffsetTable, sizeof(TDebugOffsetTable));
+
+ //Get the scheduler's address
+ iScheduler = (TInt*)iDebugInfo->iScheduler;
+ return KErrNone;
+ }
+
+DDebugAPIChecker::~DDebugAPIChecker()
+ {
+ delete iVariantOffsetTable;
+ delete iOffsetTable;
+ }
+
+/**
+Transfer Symbian-like string into C style string.
+The magic numbers come from descriptor implementation.
+@param aSymbianName The address of the symbian-like string (TDesC8 type)
+@param aCharName The address of the C style string
+@returns aCharName
+*/
+TUint8* DDebugAPIChecker::ExtractName(TInt aSymbianName, TUint8* aCharName)
+ {
+ if(!aSymbianName) //zero length case
+ {
+ aCharName[0] = '*'; aCharName[1] = 0;
+ return aCharName;
+ }
+ TInt nameLen = Read((void*)aSymbianName, 0); //The type & length of the desc. is kept in the first word
+
+ //We actually need only EBuf type of descriptor in this test.
+ if (nameLen >> 28 != 3)
+ {
+ aCharName[0] = '?';
+ aCharName[1] = 0;
+ return aCharName;
+ }
+
+ nameLen &= 0x0fffffff;
+ const TUint8* namePtr = (TUint8*)(aSymbianName+8);
+
+ TInt charNameLen = nameLen<(KMaxNameSize-1) ? nameLen : KMaxNameSize-1;
+ memcpy(aCharName, namePtr, charNameLen);
+ aCharName[charNameLen] = 0;
+ return aCharName;
+ }
+
+/**
+Prints the list of processes
+*/
+TInt DDebugAPIChecker::Process()
+ {
+ DObjectCon* processCon;
+ TUint8 charName[KMaxNameSize];
+
+ //Fetch the address of the object container for processes
+ processCon = iDebugInfo->iContainers[EProcess];
+
+ //Pend on the container's mutex before accessing any data
+ NKern::ThreadEnterCS();
+ processCon->Wait();
+
+ TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
+ TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
+
+ Kern::Printf("PROCESS TABLE:");
+ Kern::Printf("Id attribut codeSeg BccRunAd DatBssSC Name");
+ for (TInt i = 0; i < containerCount; i++)
+ {
+ TInt* process = containerObjects[i];
+ TInt processId = Read(process, iOffsetTable->iProcess_Id);
+ TInt processAttributes = Read(process, iOffsetTable->iProcess_Attributes);
+ TInt processCodeSeg = Read(process, iOffsetTable->iProcess_CodeSeg);
+ TInt processCBssRunAddress = Read(process, iOffsetTable->iProcess_DataBssRunAddress);
+ TInt processDataBssStackChunk = Read(process, iOffsetTable->iProcess_DataBssStackChunk);
+ TInt processName = Read(process, iOffsetTable->iProcess_Name);
+
+ Kern::Printf("%02x %08x %08x %08x %08x %s",
+ processId,
+ processAttributes,
+ processCodeSeg,
+ processCBssRunAddress,
+ processDataBssStackChunk,
+ ExtractName(processName, charName));
+ }
+
+ //Release container's mutex
+ processCon->Signal();
+ NKern::ThreadLeaveCS();
+
+ return KErrNone;
+ }
+
+
+/**
+Prints the list of chunks
+*/
+TInt DDebugAPIChecker::Chunk()
+ {
+ TInt state = -1;
+ TInt homeBase = -1;
+ TInt* owningProcess = (TInt*)-1;
+
+ DObjectCon* processCon;
+ TUint8 charName[KMaxNameSize];
+
+ //Fetch the address of the object container for processes
+ processCon = iDebugInfo->iContainers[EChunk];
+
+ //Pend on the container's mutex before accessing any data.
+ NKern::ThreadEnterCS();
+ processCon->Wait();
+
+ TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
+ TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
+
+ Kern::Printf("CHUNK TABLE:");
+ Kern::Printf("size attribut type state HomeBase process");
+ for (TInt i = 0; i < containerCount; i++)
+ {
+ TInt* chunk = containerObjects[i];
+ TInt size = Read(chunk, iOffsetTable->iChunk_Size);
+ TInt attributes = Read(chunk, iOffsetTable->iChunk_Attributes);
+ TInt type = Read(chunk, iOffsetTable->iChunk_ChunkType);
+
+ //This part is memory-model specific
+ switch (iDebugInfo->iMemoryModelType)
+ {
+ case EARMv5MMU:
+ {
+ TMovingDebugOffsetTable* variantOffsets = (TMovingDebugOffsetTable*)iVariantOffsetTable;
+ state = Read(chunk, iOffsetTable->iChunk_ChunkState);//armv5 specific
+ homeBase = Read(chunk, iOffsetTable->iChunk_HomeBase);//armv5 specific
+ owningProcess = (TInt*)Read(chunk, iOffsetTable->iChunk_OwningProcess);//armv5
+
+ //In moving MM, the specific offsets are provided in both tables. Check the values match.
+ if ( state != Read(chunk, variantOffsets->iChunk_ChunkState)
+ || homeBase != Read(chunk, variantOffsets->iChunk_HomeBase)
+ || owningProcess != (TInt*)Read(chunk, variantOffsets->iChunk_OwningProcess) )
+ {
+ Kern::Printf("Error: Offsets in main & specific table do not match");
+ return KErrGeneral;
+ }
+ }
+ break;
+
+ case EARMv6MMU:
+ {
+ TMultipleDebugOffsetTable* variantOffsets = (TMultipleDebugOffsetTable*)iVariantOffsetTable;
+ owningProcess = (TInt*)Read(chunk, variantOffsets->iChunk_OwningProcess);
+ break;
+ }
+ default:
+ Kern::Printf("Error: Unsupported memory model");
+ return KErrGeneral;
+ }
+
+ TInt processName;
+ if(owningProcess)
+ processName = Read(owningProcess, iOffsetTable->iProcess_Name);
+ else
+ processName = 0;
+
+ Kern::Printf("%08x %08x %08x %08x %08x %s",
+ size,
+ attributes,
+ type,
+ state,
+ homeBase,
+ ExtractName(processName, charName));
+ }
+
+ //Release container's mutex
+ processCon->Signal();
+ NKern::ThreadLeaveCS();
+
+ return KErrNone;
+ }
+
+/**
+Prints the list of threads
+*/
+TInt DDebugAPIChecker::Thread()
+ {
+
+ DObjectCon* processCon;
+ TUint8 threadCharName[KMaxNameSize];
+ TUint8 processCharName[KMaxNameSize];
+
+ //Fetch the address of the object container for threads
+ processCon = iDebugInfo->iContainers[EThread];
+
+ //Pend on the container's mutex before accessing any data
+ NKern::ThreadEnterCS();
+ processCon->Wait();
+
+ TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
+ TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
+
+ Kern::Printf("THREAD TABLE:");
+ Kern::Printf("Id Pri Typ SupStack+Size UsrStack+Size ContType SavedSP ThreadName Process");
+
+ for (TInt i = 0; i < containerCount; i++)
+ {
+ TInt* thread = containerObjects[i];
+ TInt id = Read(thread, iOffsetTable->iThread_Id);
+ TInt supStack = Read(thread, iOffsetTable->iThread_SupervisorStack);
+ TInt supStackSize = Read(thread, iOffsetTable->iThread_SupervisorStackSize);
+ TInt userStackRunAddr = Read(thread, iOffsetTable->iThread_UserStackRunAddress);
+ TInt userStackSize = Read(thread, iOffsetTable->iThread_UserStackSize);
+ TInt userContextType = Read8(thread, iOffsetTable->iThread_UserContextType);
+
+ TInt savedSP = Read(thread, iOffsetTable->iThread_SavedSupervisorSP);
+ TInt priority = Read8(thread, iOffsetTable->iThread_Priority);
+ TInt type = Read8(thread, iOffsetTable->iThread_ThreadType);
+ TInt name = Read(thread, iOffsetTable->iThread_Name);
+ TInt* owningProcess = (TInt*)Read(thread, iOffsetTable->iThread_OwningProcess);
+
+ TInt processName = Read(owningProcess, iOffsetTable->iProcess_Name);
+
+ Kern::Printf("%02x %3x %3x %08x %04x %08x %04x %08x %08x %14s %s",
+ id,
+ priority,
+ type,
+ supStack,
+ supStackSize,
+ userStackRunAddr,
+ userStackSize,
+ userContextType,
+ savedSP,
+ ExtractName(name, threadCharName),
+ ExtractName(processName, processCharName)
+ );
+ }
+
+ //Release container's mutex
+ processCon->Signal();
+ NKern::ThreadLeaveCS();
+
+ return KErrNone;
+ }
+
+/**
+Reads memory location that belongs to the other process and compares the value with provided one.
+The input argument contains the following data:
+ - ProcessId of the process that owns the address space in question
+ - Address of memory location to be read.
+ - The value at the location.
+ */
+TInt DDebugAPIChecker::IPAccess(TAny* a1)
+ {
+ TInt* process;
+ TInt otherProcess = 0;
+ TBool processFound = EFalse;
+ TBool currentProcessFound = EFalse;
+ DObjectCon* processCon;
+
+ RDebugAPIChecker::IPAccessArgs args;
+ kumemget32 (&args, a1, sizeof(args));
+
+ //Find the addresses of the current nano-thread & SymbianOS-thread
+ TInt currentNThread = Read(iScheduler, iOffsetTable->iScheduler_CurrentThread);
+ TInt currentDThread = currentNThread - iOffsetTable->iThread_NThread;
+
+ //Find the addresses of the current process
+ TInt currentProcess = Read((void*)currentDThread, iOffsetTable->iThread_OwningProcess);
+
+ //Find process in the container with given processID
+ processCon = iDebugInfo->iContainers[EProcess];
+
+ //Pend on the container's mutex before accessing any data
+ NKern::ThreadEnterCS();
+ processCon->Wait();
+
+ TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
+ TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
+
+ for (TInt i = 0; i < containerCount; i++)
+ {
+ process = containerObjects[i];
+ TInt processId = Read(process, iOffsetTable->iProcess_Id);
+
+ if (currentProcess == (TInt)process)
+ currentProcessFound = ETrue;
+
+ if (processId == (TInt)args.iProcessID)
+ {
+ otherProcess = (TInt)process;
+ processFound = ETrue;
+ }
+ }
+
+ if(!(processFound && currentProcessFound))
+ {
+ Kern::Printf("Could not find the-current-process or the-other-process in the process container");
+ processCon->Signal();
+ NKern::ThreadLeaveCS();
+ return KErrNotFound;
+ }
+
+ //Release container's mutex
+ processCon->Signal();
+ NKern::ThreadLeaveCS();
+
+ switch (iMMUType)
+ {
+ case EARMv6MMU:
+ {
+ TMultipleDebugOffsetTable* variantOffsets = (TMultipleDebugOffsetTable*)iVariantOffsetTable;
+ iCurrentProcess_OsAsid = Read((void*)currentProcess, variantOffsets->iProcess_OsAsid);
+ iCurrentProcess_LocalPageDir = Read((void*)currentProcess, variantOffsets->iProcess_LocalPageDir);
+ iOtherProcess_OsAsid = Read((void*)otherProcess, variantOffsets->iProcess_OsAsid);
+ iOtherProcess_LocalPageDir = Read((void*)otherProcess, variantOffsets->iProcess_LocalPageDir);
+ iAddress = args.iAddress;
+
+ TUint r = ReadFromOtherProcessArmv6();
+
+ //Chech if the value we just read matches the provided value.
+ if ( r != args.iValue)
+ {
+ Kern::Printf("Returned value does not match");
+ return KErrGeneral;
+ }
+ break;
+ }
+ default:
+ return KErrNotSupported;
+ }
+
+ return KErrNone;
+ }
+
+TInt DDebugAPIChecker::Request(TInt aFunction, TAny* a1, TAny* /*a2*/)
+ {
+ TInt r = KErrNone;
+ switch (aFunction)
+ {
+ case RDebugAPIChecker::ETProcess:
+ r = Process();
+ break;
+
+ case RDebugAPIChecker::ETChunk:
+ r = Chunk();
+ break;
+
+ case RDebugAPIChecker::ETThread:
+ r = Thread();
+ break;
+
+ case RDebugAPIChecker::ETIPAccess:
+ r = IPAccess(a1);
+ break;
+
+ default:
+ Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
+ break;
+ }
+ return r;
+ }
+
+//////////////////////////////////////////////////////////////////////////////
+
+class DTestFactory : public DLogicalDevice
+ {
+public:
+ DTestFactory();
+ // from DLogicalDevice
+ virtual TInt Install();
+ virtual void GetCaps(TDes8& aDes) const;
+ virtual TInt Create(DLogicalChannelBase*& aChannel);
+ };
+
+DTestFactory::DTestFactory()
+ {
+ iVersion = RDebugAPIChecker::Version();
+ iParseMask = KDeviceAllowUnit;
+ iUnitsMask = 0x3;
+ }
+
+TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
+ {
+ aChannel = new DDebugAPIChecker;
+ return (aChannel ? KErrNone : KErrNoMemory);
+ }
+
+TInt DTestFactory::Install()
+ {
+ return SetName(&KTestLddName);
+ }
+
+void DTestFactory::GetCaps(TDes8& /*aDes*/) const
+ {
+ }
+
+//////////////////////////////////////////////////////////////////////////////
+
+DECLARE_STANDARD_LDD()
+ {
+ return new DTestFactory;
+ }