1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kerneltest/e32test/debug/d_debugapi.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,470 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32test\debug\d_debugapi.cpp
1.18 +// LDD-based debug agent. It uses debugAPI provided by kernel extension
1.19 +// kdebug.dll (ARMv5) or kdebugv6 (ARMv6) to access and display various
1.20 +// kernel objects. It uses debug port as output. See t_DebugAPI.cpp
1.21 +//
1.22 +//
1.23 +
1.24 +#include <kernel/kern_priv.h>
1.25 +#include "d_debugapi.h"
1.26 +
1.27 +_LIT(KClientPanicCat, "D_DEBUGAPI");
1.28 +#define KMaxNameSize 20
1.29 +
1.30 +TInt DDebugAPIChecker::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
1.31 + {
1.32 + //This is the entry point for all debuggers. Super page contains the address of DebuggerInfo instance.
1.33 + iDebugInfo = Kern::SuperPage().iDebuggerInfo;
1.34 +
1.35 + if (!iDebugInfo)
1.36 + {
1.37 + Kern::Printf("Error:Debugger is not installed");
1.38 + return KErrNotReady;
1.39 + }
1.40 + return GetOffsets(); //Obtain the copy of offsets.
1.41 + }
1.42 +
1.43 +/**
1.44 +Copies the offset tables from Debug API Kernel extension.
1.45 +*/
1.46 +TInt DDebugAPIChecker::GetOffsets()
1.47 + {
1.48 + //Get the memory-model-specific offset table
1.49 + switch (iDebugInfo->iMemoryModelType)
1.50 + {
1.51 + case EARMv5MMU:
1.52 + iMMUType = iDebugInfo->iMemoryModelType;
1.53 + if ((iVariantOffsetTable = new TMovingDebugOffsetTable)==NULL)
1.54 + return KErrNoMemory;
1.55 + memcpy(iVariantOffsetTable, iDebugInfo->iMemModelObjectOffsetTable, sizeof(TMovingDebugOffsetTable));
1.56 + break;
1.57 +
1.58 + case EARMv6MMU:
1.59 + iMMUType = iDebugInfo->iMemoryModelType;
1.60 + if ((iVariantOffsetTable = new TMultipleDebugOffsetTable)==NULL)
1.61 + return KErrNoMemory;
1.62 + memcpy(iVariantOffsetTable, iDebugInfo->iMemModelObjectOffsetTable, sizeof(TMultipleDebugOffsetTable));
1.63 + break;
1.64 +
1.65 + default:
1.66 + return KErrNotSupported;
1.67 + }
1.68 +
1.69 + //Get the main offset table
1.70 + if ((iOffsetTable = new TDebugOffsetTable)==NULL)
1.71 + {
1.72 + delete iVariantOffsetTable;
1.73 + return KErrNoMemory;
1.74 + }
1.75 + memcpy(iOffsetTable, iDebugInfo->iObjectOffsetTable, sizeof(TDebugOffsetTable));
1.76 +
1.77 + //Get the scheduler's address
1.78 + iScheduler = (TInt*)iDebugInfo->iScheduler;
1.79 + return KErrNone;
1.80 + }
1.81 +
1.82 +DDebugAPIChecker::~DDebugAPIChecker()
1.83 + {
1.84 + delete iVariantOffsetTable;
1.85 + delete iOffsetTable;
1.86 + }
1.87 +
1.88 +/**
1.89 +Transfer Symbian-like string into C style string.
1.90 +The magic numbers come from descriptor implementation.
1.91 +@param aSymbianName The address of the symbian-like string (TDesC8 type)
1.92 +@param aCharName The address of the C style string
1.93 +@returns aCharName
1.94 +*/
1.95 +TUint8* DDebugAPIChecker::ExtractName(TInt aSymbianName, TUint8* aCharName)
1.96 + {
1.97 + if(!aSymbianName) //zero length case
1.98 + {
1.99 + aCharName[0] = '*'; aCharName[1] = 0;
1.100 + return aCharName;
1.101 + }
1.102 + TInt nameLen = Read((void*)aSymbianName, 0); //The type & length of the desc. is kept in the first word
1.103 +
1.104 + //We actually need only EBuf type of descriptor in this test.
1.105 + if (nameLen >> 28 != 3)
1.106 + {
1.107 + aCharName[0] = '?';
1.108 + aCharName[1] = 0;
1.109 + return aCharName;
1.110 + }
1.111 +
1.112 + nameLen &= 0x0fffffff;
1.113 + const TUint8* namePtr = (TUint8*)(aSymbianName+8);
1.114 +
1.115 + TInt charNameLen = nameLen<(KMaxNameSize-1) ? nameLen : KMaxNameSize-1;
1.116 + memcpy(aCharName, namePtr, charNameLen);
1.117 + aCharName[charNameLen] = 0;
1.118 + return aCharName;
1.119 + }
1.120 +
1.121 +/**
1.122 +Prints the list of processes
1.123 +*/
1.124 +TInt DDebugAPIChecker::Process()
1.125 + {
1.126 + DObjectCon* processCon;
1.127 + TUint8 charName[KMaxNameSize];
1.128 +
1.129 + //Fetch the address of the object container for processes
1.130 + processCon = iDebugInfo->iContainers[EProcess];
1.131 +
1.132 + //Pend on the container's mutex before accessing any data
1.133 + NKern::ThreadEnterCS();
1.134 + processCon->Wait();
1.135 +
1.136 + TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
1.137 + TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
1.138 +
1.139 + Kern::Printf("PROCESS TABLE:");
1.140 + Kern::Printf("Id attribut codeSeg BccRunAd DatBssSC Name");
1.141 + for (TInt i = 0; i < containerCount; i++)
1.142 + {
1.143 + TInt* process = containerObjects[i];
1.144 + TInt processId = Read(process, iOffsetTable->iProcess_Id);
1.145 + TInt processAttributes = Read(process, iOffsetTable->iProcess_Attributes);
1.146 + TInt processCodeSeg = Read(process, iOffsetTable->iProcess_CodeSeg);
1.147 + TInt processCBssRunAddress = Read(process, iOffsetTable->iProcess_DataBssRunAddress);
1.148 + TInt processDataBssStackChunk = Read(process, iOffsetTable->iProcess_DataBssStackChunk);
1.149 + TInt processName = Read(process, iOffsetTable->iProcess_Name);
1.150 +
1.151 + Kern::Printf("%02x %08x %08x %08x %08x %s",
1.152 + processId,
1.153 + processAttributes,
1.154 + processCodeSeg,
1.155 + processCBssRunAddress,
1.156 + processDataBssStackChunk,
1.157 + ExtractName(processName, charName));
1.158 + }
1.159 +
1.160 + //Release container's mutex
1.161 + processCon->Signal();
1.162 + NKern::ThreadLeaveCS();
1.163 +
1.164 + return KErrNone;
1.165 + }
1.166 +
1.167 +
1.168 +/**
1.169 +Prints the list of chunks
1.170 +*/
1.171 +TInt DDebugAPIChecker::Chunk()
1.172 + {
1.173 + TInt state = -1;
1.174 + TInt homeBase = -1;
1.175 + TInt* owningProcess = (TInt*)-1;
1.176 +
1.177 + DObjectCon* processCon;
1.178 + TUint8 charName[KMaxNameSize];
1.179 +
1.180 + //Fetch the address of the object container for processes
1.181 + processCon = iDebugInfo->iContainers[EChunk];
1.182 +
1.183 + //Pend on the container's mutex before accessing any data.
1.184 + NKern::ThreadEnterCS();
1.185 + processCon->Wait();
1.186 +
1.187 + TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
1.188 + TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
1.189 +
1.190 + Kern::Printf("CHUNK TABLE:");
1.191 + Kern::Printf("size attribut type state HomeBase process");
1.192 + for (TInt i = 0; i < containerCount; i++)
1.193 + {
1.194 + TInt* chunk = containerObjects[i];
1.195 + TInt size = Read(chunk, iOffsetTable->iChunk_Size);
1.196 + TInt attributes = Read(chunk, iOffsetTable->iChunk_Attributes);
1.197 + TInt type = Read(chunk, iOffsetTable->iChunk_ChunkType);
1.198 +
1.199 + //This part is memory-model specific
1.200 + switch (iDebugInfo->iMemoryModelType)
1.201 + {
1.202 + case EARMv5MMU:
1.203 + {
1.204 + TMovingDebugOffsetTable* variantOffsets = (TMovingDebugOffsetTable*)iVariantOffsetTable;
1.205 + state = Read(chunk, iOffsetTable->iChunk_ChunkState);//armv5 specific
1.206 + homeBase = Read(chunk, iOffsetTable->iChunk_HomeBase);//armv5 specific
1.207 + owningProcess = (TInt*)Read(chunk, iOffsetTable->iChunk_OwningProcess);//armv5
1.208 +
1.209 + //In moving MM, the specific offsets are provided in both tables. Check the values match.
1.210 + if ( state != Read(chunk, variantOffsets->iChunk_ChunkState)
1.211 + || homeBase != Read(chunk, variantOffsets->iChunk_HomeBase)
1.212 + || owningProcess != (TInt*)Read(chunk, variantOffsets->iChunk_OwningProcess) )
1.213 + {
1.214 + Kern::Printf("Error: Offsets in main & specific table do not match");
1.215 + return KErrGeneral;
1.216 + }
1.217 + }
1.218 + break;
1.219 +
1.220 + case EARMv6MMU:
1.221 + {
1.222 + TMultipleDebugOffsetTable* variantOffsets = (TMultipleDebugOffsetTable*)iVariantOffsetTable;
1.223 + owningProcess = (TInt*)Read(chunk, variantOffsets->iChunk_OwningProcess);
1.224 + break;
1.225 + }
1.226 + default:
1.227 + Kern::Printf("Error: Unsupported memory model");
1.228 + return KErrGeneral;
1.229 + }
1.230 +
1.231 + TInt processName;
1.232 + if(owningProcess)
1.233 + processName = Read(owningProcess, iOffsetTable->iProcess_Name);
1.234 + else
1.235 + processName = 0;
1.236 +
1.237 + Kern::Printf("%08x %08x %08x %08x %08x %s",
1.238 + size,
1.239 + attributes,
1.240 + type,
1.241 + state,
1.242 + homeBase,
1.243 + ExtractName(processName, charName));
1.244 + }
1.245 +
1.246 + //Release container's mutex
1.247 + processCon->Signal();
1.248 + NKern::ThreadLeaveCS();
1.249 +
1.250 + return KErrNone;
1.251 + }
1.252 +
1.253 +/**
1.254 +Prints the list of threads
1.255 +*/
1.256 +TInt DDebugAPIChecker::Thread()
1.257 + {
1.258 +
1.259 + DObjectCon* processCon;
1.260 + TUint8 threadCharName[KMaxNameSize];
1.261 + TUint8 processCharName[KMaxNameSize];
1.262 +
1.263 + //Fetch the address of the object container for threads
1.264 + processCon = iDebugInfo->iContainers[EThread];
1.265 +
1.266 + //Pend on the container's mutex before accessing any data
1.267 + NKern::ThreadEnterCS();
1.268 + processCon->Wait();
1.269 +
1.270 + TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
1.271 + TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
1.272 +
1.273 + Kern::Printf("THREAD TABLE:");
1.274 + Kern::Printf("Id Pri Typ SupStack+Size UsrStack+Size ContType SavedSP ThreadName Process");
1.275 +
1.276 + for (TInt i = 0; i < containerCount; i++)
1.277 + {
1.278 + TInt* thread = containerObjects[i];
1.279 + TInt id = Read(thread, iOffsetTable->iThread_Id);
1.280 + TInt supStack = Read(thread, iOffsetTable->iThread_SupervisorStack);
1.281 + TInt supStackSize = Read(thread, iOffsetTable->iThread_SupervisorStackSize);
1.282 + TInt userStackRunAddr = Read(thread, iOffsetTable->iThread_UserStackRunAddress);
1.283 + TInt userStackSize = Read(thread, iOffsetTable->iThread_UserStackSize);
1.284 + TInt userContextType = Read8(thread, iOffsetTable->iThread_UserContextType);
1.285 +
1.286 + TInt savedSP = Read(thread, iOffsetTable->iThread_SavedSupervisorSP);
1.287 + TInt priority = Read8(thread, iOffsetTable->iThread_Priority);
1.288 + TInt type = Read8(thread, iOffsetTable->iThread_ThreadType);
1.289 + TInt name = Read(thread, iOffsetTable->iThread_Name);
1.290 + TInt* owningProcess = (TInt*)Read(thread, iOffsetTable->iThread_OwningProcess);
1.291 +
1.292 + TInt processName = Read(owningProcess, iOffsetTable->iProcess_Name);
1.293 +
1.294 + Kern::Printf("%02x %3x %3x %08x %04x %08x %04x %08x %08x %14s %s",
1.295 + id,
1.296 + priority,
1.297 + type,
1.298 + supStack,
1.299 + supStackSize,
1.300 + userStackRunAddr,
1.301 + userStackSize,
1.302 + userContextType,
1.303 + savedSP,
1.304 + ExtractName(name, threadCharName),
1.305 + ExtractName(processName, processCharName)
1.306 + );
1.307 + }
1.308 +
1.309 + //Release container's mutex
1.310 + processCon->Signal();
1.311 + NKern::ThreadLeaveCS();
1.312 +
1.313 + return KErrNone;
1.314 + }
1.315 +
1.316 +/**
1.317 +Reads memory location that belongs to the other process and compares the value with provided one.
1.318 +The input argument contains the following data:
1.319 + - ProcessId of the process that owns the address space in question
1.320 + - Address of memory location to be read.
1.321 + - The value at the location.
1.322 + */
1.323 +TInt DDebugAPIChecker::IPAccess(TAny* a1)
1.324 + {
1.325 + TInt* process;
1.326 + TInt otherProcess = 0;
1.327 + TBool processFound = EFalse;
1.328 + TBool currentProcessFound = EFalse;
1.329 + DObjectCon* processCon;
1.330 +
1.331 + RDebugAPIChecker::IPAccessArgs args;
1.332 + kumemget32 (&args, a1, sizeof(args));
1.333 +
1.334 + //Find the addresses of the current nano-thread & SymbianOS-thread
1.335 + TInt currentNThread = Read(iScheduler, iOffsetTable->iScheduler_CurrentThread);
1.336 + TInt currentDThread = currentNThread - iOffsetTable->iThread_NThread;
1.337 +
1.338 + //Find the addresses of the current process
1.339 + TInt currentProcess = Read((void*)currentDThread, iOffsetTable->iThread_OwningProcess);
1.340 +
1.341 + //Find process in the container with given processID
1.342 + processCon = iDebugInfo->iContainers[EProcess];
1.343 +
1.344 + //Pend on the container's mutex before accessing any data
1.345 + NKern::ThreadEnterCS();
1.346 + processCon->Wait();
1.347 +
1.348 + TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
1.349 + TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
1.350 +
1.351 + for (TInt i = 0; i < containerCount; i++)
1.352 + {
1.353 + process = containerObjects[i];
1.354 + TInt processId = Read(process, iOffsetTable->iProcess_Id);
1.355 +
1.356 + if (currentProcess == (TInt)process)
1.357 + currentProcessFound = ETrue;
1.358 +
1.359 + if (processId == (TInt)args.iProcessID)
1.360 + {
1.361 + otherProcess = (TInt)process;
1.362 + processFound = ETrue;
1.363 + }
1.364 + }
1.365 +
1.366 + if(!(processFound && currentProcessFound))
1.367 + {
1.368 + Kern::Printf("Could not find the-current-process or the-other-process in the process container");
1.369 + processCon->Signal();
1.370 + NKern::ThreadLeaveCS();
1.371 + return KErrNotFound;
1.372 + }
1.373 +
1.374 + //Release container's mutex
1.375 + processCon->Signal();
1.376 + NKern::ThreadLeaveCS();
1.377 +
1.378 + switch (iMMUType)
1.379 + {
1.380 + case EARMv6MMU:
1.381 + {
1.382 + TMultipleDebugOffsetTable* variantOffsets = (TMultipleDebugOffsetTable*)iVariantOffsetTable;
1.383 + iCurrentProcess_OsAsid = Read((void*)currentProcess, variantOffsets->iProcess_OsAsid);
1.384 + iCurrentProcess_LocalPageDir = Read((void*)currentProcess, variantOffsets->iProcess_LocalPageDir);
1.385 + iOtherProcess_OsAsid = Read((void*)otherProcess, variantOffsets->iProcess_OsAsid);
1.386 + iOtherProcess_LocalPageDir = Read((void*)otherProcess, variantOffsets->iProcess_LocalPageDir);
1.387 + iAddress = args.iAddress;
1.388 +
1.389 + TUint r = ReadFromOtherProcessArmv6();
1.390 +
1.391 + //Chech if the value we just read matches the provided value.
1.392 + if ( r != args.iValue)
1.393 + {
1.394 + Kern::Printf("Returned value does not match");
1.395 + return KErrGeneral;
1.396 + }
1.397 + break;
1.398 + }
1.399 + default:
1.400 + return KErrNotSupported;
1.401 + }
1.402 +
1.403 + return KErrNone;
1.404 + }
1.405 +
1.406 +TInt DDebugAPIChecker::Request(TInt aFunction, TAny* a1, TAny* /*a2*/)
1.407 + {
1.408 + TInt r = KErrNone;
1.409 + switch (aFunction)
1.410 + {
1.411 + case RDebugAPIChecker::ETProcess:
1.412 + r = Process();
1.413 + break;
1.414 +
1.415 + case RDebugAPIChecker::ETChunk:
1.416 + r = Chunk();
1.417 + break;
1.418 +
1.419 + case RDebugAPIChecker::ETThread:
1.420 + r = Thread();
1.421 + break;
1.422 +
1.423 + case RDebugAPIChecker::ETIPAccess:
1.424 + r = IPAccess(a1);
1.425 + break;
1.426 +
1.427 + default:
1.428 + Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
1.429 + break;
1.430 + }
1.431 + return r;
1.432 + }
1.433 +
1.434 +//////////////////////////////////////////////////////////////////////////////
1.435 +
1.436 +class DTestFactory : public DLogicalDevice
1.437 + {
1.438 +public:
1.439 + DTestFactory();
1.440 + // from DLogicalDevice
1.441 + virtual TInt Install();
1.442 + virtual void GetCaps(TDes8& aDes) const;
1.443 + virtual TInt Create(DLogicalChannelBase*& aChannel);
1.444 + };
1.445 +
1.446 +DTestFactory::DTestFactory()
1.447 + {
1.448 + iVersion = RDebugAPIChecker::Version();
1.449 + iParseMask = KDeviceAllowUnit;
1.450 + iUnitsMask = 0x3;
1.451 + }
1.452 +
1.453 +TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
1.454 + {
1.455 + aChannel = new DDebugAPIChecker;
1.456 + return (aChannel ? KErrNone : KErrNoMemory);
1.457 + }
1.458 +
1.459 +TInt DTestFactory::Install()
1.460 + {
1.461 + return SetName(&KTestLddName);
1.462 + }
1.463 +
1.464 +void DTestFactory::GetCaps(TDes8& /*aDes*/) const
1.465 + {
1.466 + }
1.467 +
1.468 +//////////////////////////////////////////////////////////////////////////////
1.469 +
1.470 +DECLARE_STANDARD_LDD()
1.471 + {
1.472 + return new DTestFactory;
1.473 + }