Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// 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;
}