diff -r 000000000000 -r a41df078684a kerneltest/e32test/debug/d_debugapi.cpp --- /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 +#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; + }