os/kernelhwsrv/kerneltest/e32test/debug/d_debugapi.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\debug\d_debugapi.cpp
    15 // LDD-based debug agent. It uses debugAPI provided by kernel extension 
    16 // kdebug.dll (ARMv5) or kdebugv6 (ARMv6) to access and display various
    17 // kernel objects. It uses debug port as output. See t_DebugAPI.cpp
    18 // 
    19 //
    20 
    21 #include <kernel/kern_priv.h>
    22 #include "d_debugapi.h"
    23 
    24 _LIT(KClientPanicCat, "D_DEBUGAPI");
    25 #define KMaxNameSize 20
    26 
    27 TInt DDebugAPIChecker::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
    28 	{
    29 	//This is the entry point for all debuggers. Super page contains the address of DebuggerInfo instance.
    30 	iDebugInfo = Kern::SuperPage().iDebuggerInfo;
    31 
    32 	if (!iDebugInfo)
    33 		{
    34 		Kern::Printf("Error:Debugger is not installed");
    35 		return KErrNotReady;
    36 		}
    37 	return GetOffsets(); //Obtain the copy of offsets.
    38 	}
    39 
    40 /** 
    41 Copies the offset tables from Debug API Kernel extension.
    42 */
    43 TInt DDebugAPIChecker::GetOffsets()
    44 	{
    45 	//Get the memory-model-specific offset table
    46 	switch (iDebugInfo->iMemoryModelType)
    47 		{
    48 	case EARMv5MMU:
    49 		iMMUType = iDebugInfo->iMemoryModelType;
    50 		if ((iVariantOffsetTable = new TMovingDebugOffsetTable)==NULL)
    51 			return KErrNoMemory;
    52 		memcpy(iVariantOffsetTable, iDebugInfo->iMemModelObjectOffsetTable, sizeof(TMovingDebugOffsetTable));
    53 		break;
    54 			
    55 	case EARMv6MMU:
    56 		iMMUType = iDebugInfo->iMemoryModelType;
    57 		if ((iVariantOffsetTable = new TMultipleDebugOffsetTable)==NULL)
    58 			return KErrNoMemory;
    59 		memcpy(iVariantOffsetTable, iDebugInfo->iMemModelObjectOffsetTable, sizeof(TMultipleDebugOffsetTable));
    60 		break;
    61 
    62 	default:
    63 		return KErrNotSupported;
    64 		}
    65 
    66 	//Get the main offset table
    67 	if ((iOffsetTable = new TDebugOffsetTable)==NULL)
    68 		{
    69 		delete iVariantOffsetTable;
    70 		return KErrNoMemory;
    71 		}
    72 	memcpy(iOffsetTable, iDebugInfo->iObjectOffsetTable, sizeof(TDebugOffsetTable));
    73 
    74 	//Get the scheduler's address
    75 	iScheduler = (TInt*)iDebugInfo->iScheduler;
    76 	return KErrNone;
    77 	}
    78 
    79 DDebugAPIChecker::~DDebugAPIChecker()
    80 	{
    81 	delete iVariantOffsetTable;
    82 	delete iOffsetTable;
    83 	}
    84 
    85 /**
    86 Transfer Symbian-like string into C style string.
    87 The magic numbers come from descriptor implementation.
    88 @param aSymbianName The address of the symbian-like string (TDesC8 type)
    89 @param aCharName The address of the C style string
    90 @returns aCharName
    91 */
    92 TUint8* DDebugAPIChecker::ExtractName(TInt aSymbianName, TUint8* aCharName)
    93 	{
    94 	if(!aSymbianName) //zero length case
    95 		{
    96 		aCharName[0] = '*';	aCharName[1] = 0;
    97 		return 	aCharName;
    98 		}
    99 	TInt nameLen =	Read((void*)aSymbianName, 0);	//The type & length of the desc. is kept in the first word
   100 
   101 	//We actually need only EBuf type of descriptor in this test.
   102 	if (nameLen >> 28 != 3)		
   103 		{
   104 		aCharName[0] = '?';
   105 		aCharName[1] = 0;
   106 		return 	aCharName;
   107 		}
   108 
   109 	nameLen &= 0x0fffffff;
   110 	const TUint8* namePtr =	(TUint8*)(aSymbianName+8);
   111 
   112 	TInt charNameLen = nameLen<(KMaxNameSize-1) ? nameLen : KMaxNameSize-1;
   113 	memcpy(aCharName, namePtr, charNameLen);
   114 	aCharName[charNameLen] = 0;
   115 	return 	aCharName;
   116 	}
   117 
   118 /**
   119 Prints the list of processes
   120 */
   121 TInt DDebugAPIChecker::Process()
   122 	{
   123 	DObjectCon* processCon;
   124 	TUint8 charName[KMaxNameSize];
   125 
   126 	//Fetch the address of the object container for processes
   127 	processCon = iDebugInfo->iContainers[EProcess];
   128 
   129 	//Pend on the container's mutex before accessing any data
   130 	NKern::ThreadEnterCS();
   131 	processCon->Wait();
   132 
   133 	TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
   134 	TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
   135 
   136 	Kern::Printf("PROCESS TABLE:");
   137 	Kern::Printf("Id attribut codeSeg  BccRunAd DatBssSC Name");
   138 	for (TInt i = 0; i < containerCount; i++)
   139 		{
   140 		TInt* process =					containerObjects[i];
   141 		TInt processId =				Read(process, iOffsetTable->iProcess_Id);
   142 		TInt processAttributes =		Read(process, iOffsetTable->iProcess_Attributes);
   143 		TInt processCodeSeg =			Read(process, iOffsetTable->iProcess_CodeSeg);
   144 		TInt processCBssRunAddress =	Read(process, iOffsetTable->iProcess_DataBssRunAddress);
   145 		TInt processDataBssStackChunk = Read(process, iOffsetTable->iProcess_DataBssStackChunk);
   146 		TInt processName =				Read(process, iOffsetTable->iProcess_Name);
   147 
   148 		Kern::Printf("%02x %08x %08x %08x %08x %s", 
   149 				processId, 
   150 				processAttributes,
   151 				processCodeSeg,
   152 				processCBssRunAddress,
   153 				processDataBssStackChunk,
   154 				ExtractName(processName, charName));
   155 		}
   156 
   157 	//Release container's mutex
   158 	processCon->Signal();
   159 	NKern::ThreadLeaveCS();
   160 
   161 	return KErrNone;
   162 	}
   163 
   164 
   165 /**
   166 Prints the list of chunks
   167 */
   168 TInt DDebugAPIChecker::Chunk()
   169 	{
   170 	TInt state = -1;
   171 	TInt homeBase = -1;
   172 	TInt* owningProcess = (TInt*)-1;
   173 
   174 	DObjectCon* processCon;
   175 	TUint8 charName[KMaxNameSize];
   176 
   177 	//Fetch the address of the object container for processes
   178 	processCon = iDebugInfo->iContainers[EChunk];
   179 
   180 	//Pend on the container's mutex before accessing any data.
   181 	NKern::ThreadEnterCS();
   182 	processCon->Wait();
   183 
   184 	TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
   185 	TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
   186 
   187 	Kern::Printf("CHUNK TABLE:");
   188 	Kern::Printf("size     attribut type     state    HomeBase process");
   189 	for (TInt i = 0; i < containerCount; i++)
   190 		{
   191 		TInt* chunk =			containerObjects[i];
   192 		TInt size =				Read(chunk, iOffsetTable->iChunk_Size);
   193 		TInt attributes =		Read(chunk, iOffsetTable->iChunk_Attributes);
   194 		TInt type =				Read(chunk, iOffsetTable->iChunk_ChunkType);
   195 		
   196 		//This part is memory-model specific
   197 		switch (iDebugInfo->iMemoryModelType)
   198 		{
   199 		case EARMv5MMU:
   200 			{
   201 			TMovingDebugOffsetTable* variantOffsets = (TMovingDebugOffsetTable*)iVariantOffsetTable;
   202 			state =			Read(chunk, iOffsetTable->iChunk_ChunkState);//armv5 specific
   203 			homeBase =		Read(chunk, iOffsetTable->iChunk_HomeBase);//armv5 specific
   204 			owningProcess =	(TInt*)Read(chunk, iOffsetTable->iChunk_OwningProcess);//armv5
   205 			
   206 			//In moving MM, the specific offsets are provided in both tables. Check the values match.
   207 			if (   state         != Read(chunk, variantOffsets->iChunk_ChunkState) 
   208 				|| homeBase      !=	Read(chunk, variantOffsets->iChunk_HomeBase)
   209 				|| owningProcess != (TInt*)Read(chunk, variantOffsets->iChunk_OwningProcess) )
   210 				{
   211 				Kern::Printf("Error: Offsets in main & specific table do not match");
   212 				return KErrGeneral;
   213 				}
   214 			}
   215 			break;
   216 
   217 		case EARMv6MMU:
   218 			{
   219 			TMultipleDebugOffsetTable* variantOffsets = (TMultipleDebugOffsetTable*)iVariantOffsetTable;
   220 			owningProcess =	(TInt*)Read(chunk, variantOffsets->iChunk_OwningProcess);
   221 			break;
   222 			}
   223 		default:
   224 			Kern::Printf("Error: Unsupported memory model");
   225 			return KErrGeneral;
   226 		}
   227 
   228 		TInt processName;
   229 		if(owningProcess)
   230 			processName = Read(owningProcess, iOffsetTable->iProcess_Name);
   231 		else
   232 			processName = 0;
   233 
   234 		Kern::Printf("%08x %08x %08x %08x %08x %s", 
   235 				size, 
   236 				attributes,
   237 				type,
   238 				state,
   239 				homeBase,
   240 				ExtractName(processName, charName));
   241 		}
   242 
   243 	//Release container's mutex
   244 	processCon->Signal();
   245 	NKern::ThreadLeaveCS();
   246 
   247 	return KErrNone;
   248 	}
   249 
   250 /**
   251 Prints the list of threads
   252 */
   253 TInt DDebugAPIChecker::Thread()
   254 	{
   255 
   256 	DObjectCon* processCon;
   257 	TUint8 threadCharName[KMaxNameSize];
   258 	TUint8 processCharName[KMaxNameSize];
   259 
   260 	//Fetch the address of the object container for threads
   261 	processCon = iDebugInfo->iContainers[EThread];
   262 
   263 	//Pend on the container's mutex before accessing any data
   264 	NKern::ThreadEnterCS();
   265 	processCon->Wait();
   266 
   267 	TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
   268 	TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
   269 
   270 	Kern::Printf("THREAD TABLE:");
   271 	Kern::Printf("Id Pri Typ SupStack+Size UsrStack+Size ContType SavedSP   ThreadName    Process");
   272 
   273 	for (TInt i = 0; i < containerCount; i++)
   274 		{
   275 		TInt* thread =			containerObjects[i];
   276 		TInt id =				Read(thread, iOffsetTable->iThread_Id);
   277 		TInt supStack =			Read(thread, iOffsetTable->iThread_SupervisorStack);
   278 		TInt supStackSize =		Read(thread, iOffsetTable->iThread_SupervisorStackSize);
   279 		TInt userStackRunAddr =	Read(thread, iOffsetTable->iThread_UserStackRunAddress);
   280 		TInt userStackSize =	Read(thread, iOffsetTable->iThread_UserStackSize);
   281 		TInt userContextType =	Read8(thread, iOffsetTable->iThread_UserContextType);
   282 
   283 		TInt savedSP	=		Read(thread, iOffsetTable->iThread_SavedSupervisorSP);
   284 		TInt priority =			Read8(thread, iOffsetTable->iThread_Priority);
   285 		TInt type =				Read8(thread, iOffsetTable->iThread_ThreadType);
   286 		TInt name =				Read(thread, iOffsetTable->iThread_Name);
   287 		TInt* owningProcess =	(TInt*)Read(thread, iOffsetTable->iThread_OwningProcess);
   288 
   289 		TInt processName =		Read(owningProcess, iOffsetTable->iProcess_Name);
   290 
   291 		Kern::Printf("%02x %3x %3x %08x %04x %08x %04x %08x %08x %14s %s", 
   292 				id,
   293 				priority, 
   294 				type,
   295 				supStack,
   296 				supStackSize,
   297 				userStackRunAddr,
   298 				userStackSize,
   299 				userContextType,
   300 				savedSP,
   301 				ExtractName(name, threadCharName),
   302 				ExtractName(processName, processCharName)
   303 				);
   304 		}
   305 
   306 	//Release container's mutex
   307 	processCon->Signal();
   308 	NKern::ThreadLeaveCS();
   309 
   310 	return KErrNone;
   311 	}
   312 
   313 /**
   314 Reads memory location that belongs to the other process and compares the value with provided one.
   315 The input argument contains the following data:
   316 	- ProcessId of the process that owns the address space in question
   317 	- Address of memory location to be read.
   318 	- The value at the location.
   319 	*/
   320 TInt DDebugAPIChecker::IPAccess(TAny* a1)
   321 	{
   322 	TInt* process;
   323 	TInt otherProcess = 0;
   324 	TBool processFound = EFalse;
   325 	TBool currentProcessFound = EFalse;
   326 	DObjectCon* processCon;
   327 
   328 	RDebugAPIChecker::IPAccessArgs args;
   329 	kumemget32 (&args, a1, sizeof(args));
   330 
   331 	//Find the addresses of the current nano-thread & SymbianOS-thread
   332 	TInt currentNThread = Read(iScheduler, iOffsetTable->iScheduler_CurrentThread);
   333 	TInt currentDThread = currentNThread - iOffsetTable->iThread_NThread;
   334 	
   335 	//Find the addresses of the current process
   336 	TInt currentProcess = Read((void*)currentDThread, iOffsetTable->iThread_OwningProcess);
   337 
   338 	//Find process in the container with given processID
   339 	processCon = iDebugInfo->iContainers[EProcess];
   340 
   341 	//Pend on the container's mutex before accessing any data
   342 	NKern::ThreadEnterCS();
   343 	processCon->Wait();
   344 
   345 	TInt containerCount = Read(processCon, iOffsetTable->iObjectCon_Count);
   346 	TInt** containerObjects = (TInt**)Read(processCon, iOffsetTable->iObjectCon_Objects);
   347 
   348 	for (TInt i = 0; i < containerCount; i++)
   349 		{
   350 		process = containerObjects[i];
   351 		TInt processId = Read(process, iOffsetTable->iProcess_Id);
   352 
   353 		if (currentProcess == (TInt)process)
   354 			currentProcessFound = ETrue;
   355 
   356 		if (processId == (TInt)args.iProcessID)
   357 			{
   358 			otherProcess = (TInt)process;
   359 			processFound = ETrue;
   360 			}
   361 		}
   362 
   363 	if(!(processFound &&  currentProcessFound))
   364 		{
   365 		Kern::Printf("Could not find the-current-process or the-other-process in the process container");
   366 		processCon->Signal();
   367 		NKern::ThreadLeaveCS();
   368 		return KErrNotFound;
   369 		}
   370 
   371 	//Release container's mutex
   372 	processCon->Signal();
   373 	NKern::ThreadLeaveCS();
   374 
   375 	switch (iMMUType)
   376 		{
   377 	case EARMv6MMU:
   378 		{
   379 		TMultipleDebugOffsetTable* variantOffsets = (TMultipleDebugOffsetTable*)iVariantOffsetTable;
   380 		iCurrentProcess_OsAsid =		Read((void*)currentProcess, variantOffsets->iProcess_OsAsid);
   381 		iCurrentProcess_LocalPageDir =	Read((void*)currentProcess, variantOffsets->iProcess_LocalPageDir);
   382 		iOtherProcess_OsAsid =			Read((void*)otherProcess, variantOffsets->iProcess_OsAsid);
   383 		iOtherProcess_LocalPageDir =	Read((void*)otherProcess, variantOffsets->iProcess_LocalPageDir);
   384 		iAddress =						args.iAddress;
   385 
   386 		TUint r = ReadFromOtherProcessArmv6();
   387 		
   388 		//Chech if the value we just read matches the provided value.
   389 		if ( r != args.iValue)
   390 			{
   391 			Kern::Printf("Returned value does not match");
   392 			return KErrGeneral;
   393 			}
   394 		break;	
   395 		}
   396 	default:
   397 		return KErrNotSupported;
   398 		}	
   399 
   400   return KErrNone;
   401 	}
   402 
   403 TInt DDebugAPIChecker::Request(TInt aFunction, TAny* a1, TAny* /*a2*/)
   404 	{
   405 	TInt r = KErrNone;
   406 	switch (aFunction)
   407 		{
   408 	case RDebugAPIChecker::ETProcess:
   409 		r = Process();
   410 		break;
   411 
   412 	case RDebugAPIChecker::ETChunk:
   413 		r = Chunk();
   414 		break;
   415 
   416 	case RDebugAPIChecker::ETThread:
   417 		r = Thread();
   418 		break;
   419 
   420 	case RDebugAPIChecker::ETIPAccess:
   421 		r = IPAccess(a1);
   422 		break;
   423 
   424 	default:
   425 		Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
   426 		break;
   427 		}
   428 	return r;
   429 	}
   430 
   431 //////////////////////////////////////////////////////////////////////////////
   432 
   433 class DTestFactory : public DLogicalDevice
   434 	{
   435 public:
   436 	DTestFactory();
   437 	// from DLogicalDevice
   438 	virtual TInt Install();
   439 	virtual void GetCaps(TDes8& aDes) const;
   440 	virtual TInt Create(DLogicalChannelBase*& aChannel);
   441 	};
   442 
   443 DTestFactory::DTestFactory()
   444     {
   445     iVersion = RDebugAPIChecker::Version();
   446     iParseMask = KDeviceAllowUnit;
   447     iUnitsMask = 0x3;
   448     }
   449 
   450 TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
   451     {
   452 	aChannel = new DDebugAPIChecker;
   453 	return (aChannel ? KErrNone : KErrNoMemory);
   454     }
   455 
   456 TInt DTestFactory::Install()
   457     {
   458     return SetName(&KTestLddName);
   459     }
   460 
   461 void DTestFactory::GetCaps(TDes8& /*aDes*/) const
   462     {
   463     }
   464 
   465 //////////////////////////////////////////////////////////////////////////////
   466 
   467 DECLARE_STANDARD_LDD()
   468 	{
   469     return new DTestFactory;
   470 	}