kernel/eka/drivers/debug/rmdebug/d_list_manager.cpp
changeset 245 647ab20fee2e
parent 244 a77889bee936
child 252 0a40b8675b23
equal deleted inserted replaced
244:a77889bee936 245:647ab20fee2e
     1 // Copyright (c) 2007-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 // Provides a class to manage the generation of lists
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "d_list_manager.h"
       
    19 #include "d_process_tracker.h"
       
    20 #include "debug_utils.h"
       
    21 #include "plat_priv.h"
       
    22 #include "debug_logging.h"
       
    23 #include <arm.h>
       
    24 
       
    25 // make accessing DThread's MState more intuitive
       
    26 #define iMState iWaitLink.iSpare1
       
    27 // make accessing NThread's NState more intuitive
       
    28 #define iNState iSpare3
       
    29 
       
    30 //constants to match against a rom entry's attributes,
       
    31 //these are defined in the file server (can't be included kernel side)
       
    32 //and in the ROM tools (also inaccessible) so redefined here
       
    33 const TUint KEntryAttXIP=0x0080;
       
    34 const TUint KEntryAttDir=0x0010;
       
    35 
       
    36 using namespace Debug;
       
    37 
       
    38 /**
       
    39   Get thread listing for the specified thread, if the thread data will not fit
       
    40   in the buffer then an error is returned.
       
    41 
       
    42   @param aBuffer buffer to put data in
       
    43   @param aDataSize on return will contain size of data
       
    44   @param aTargetThreadId thread ID to return listing for
       
    45 
       
    46   @return KErrNone on success,
       
    47   KErrTooBig if data won't fit in aBuffer
       
    48   or one of the other system wide error codes on failure
       
    49   */
       
    50 TInt TListManager::GetThreadListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const
       
    51 	{
       
    52 	LOG_MSG("TListManager::GetThreadListForThread()");
       
    53 
       
    54 	// open a handle to check whether the thread actually exists
       
    55 	DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId);
       
    56 	if(!thread)
       
    57 		{
       
    58 		return KErrArgument;
       
    59 		}
       
    60 	DProcess* process = thread->iOwningProcess;
       
    61 	if(!process)
       
    62 		{
       
    63 		return KErrArgument;
       
    64 		}
       
    65 	TUint64 processId = process->iId;
       
    66 	thread->Close(NULL);
       
    67 
       
    68 	//request a process specific list
       
    69 	return GetThreadListForProcess(aBuffer, aDataSize, processId);
       
    70 	}
       
    71 
       
    72 TInt TListManager::GetThreadListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const
       
    73 	{
       
    74 	LOG_MSG("TListManager::GetThreadListForProcess()");
       
    75 
       
    76 	// open a handle to check whether the process actually exists
       
    77 	DProcess* process = DebugUtils::OpenProcessHandle(aTargetProcessId);
       
    78 	if(!process)
       
    79 		{
       
    80 		return KErrArgument;
       
    81 		}
       
    82 	process->Close(NULL);
       
    83 
       
    84 	//request a process specific list
       
    85 	return GetThreadList(aBuffer, aDataSize, EFalse, aTargetProcessId);
       
    86 	}
       
    87 
       
    88 /**
       
    89   Get global thread listing
       
    90 
       
    91   @param aBuffer buffer to put data in
       
    92   @param aDataSize on return will contain size of data
       
    93 
       
    94   @return KErrNone on success,
       
    95   KErrTooBig if data won't fit in aBuffer
       
    96   or one of the other system wide error codes on failure
       
    97   */
       
    98 TInt TListManager::GetGlobalThreadList(TDes8& aBuffer, TUint32& aDataSize) const
       
    99 	{
       
   100 	LOG_MSG("TListManager::GetGlobalThreadList()");
       
   101 
       
   102 	//request a global list
       
   103 	return GetThreadList(aBuffer, aDataSize, ETrue, 0);
       
   104 	}
       
   105 
       
   106 /**
       
   107   Get thread listing, if the thread data will not fit
       
   108   in the buffer then an error is returned.
       
   109 
       
   110   @param aBuffer buffer to put data in
       
   111   @param aDataSize on return will contain size of data
       
   112   @param aGlobal whether or not the listing should be global or thread specific
       
   113   @param aTargetProcessId process ID to return listing for, relevant only if aGlobal == ETrue
       
   114 
       
   115   @return KErrNone on success,
       
   116   KErrTooBig if data won't fit in aBuffer
       
   117   or one of the other system wide error codes on failure
       
   118   */
       
   119 TInt TListManager::GetThreadList(TDes8& aBuffer, TUint32& aDataSize, TBool aGlobal, const TUint64 aTargetProcessId) const
       
   120 	{
       
   121 
       
   122 	LOG_MSG("TListManager::GetThreadList\n");
       
   123 
       
   124 	//have to read the threads in a critical section
       
   125 	NKern::ThreadEnterCS();
       
   126 
       
   127 	//get a pointer to the kernel's thread list
       
   128 	DObjectCon *threads = Kern::Containers()[EThread];
       
   129 
       
   130 	//if can't get container then exit
       
   131 	if(threads == NULL)
       
   132 		{
       
   133 		NKern::ThreadLeaveCS();
       
   134 
       
   135 		return KErrGeneral;
       
   136 		}
       
   137 
       
   138 	//stop the thread list from changing while we are processing them
       
   139 	threads->Wait();
       
   140 
       
   141 	aDataSize = 0;
       
   142 	aBuffer.SetLength(0);
       
   143 	//iterate through the threads adding them to the buffer
       
   144 	for(TInt i=0; i<threads->Count(); i++)
       
   145 		{
       
   146 		DThread* thread = (DThread*)(*threads)[i];
       
   147 
       
   148 		//skip this thread pointer is the thread is NULL
       
   149 		if(thread)
       
   150 			{
       
   151 			NThread& nThread = thread->iNThread;
       
   152 
       
   153 			// if the thread is marked as being dead then don't return information about it in the listing
       
   154 #ifndef __SMP__
       
   155 			if((NThread::EDead != nThread.iNState) && (DThread::EDead != thread->iMState))
       
   156 #else
       
   157  			if((!nThread.IsDead()) && (DThread::EDead != thread->iMState))
       
   158 #endif
       
   159 				{
       
   160 				if( aGlobal || (aTargetProcessId == (TUint64)thread->iOwningProcess->iId))
       
   161 					{
       
   162 					//store the data in the buffer
       
   163 					AppendThreadData(aBuffer, aDataSize, thread);
       
   164 					}
       
   165 				}
       
   166 			}
       
   167 		}
       
   168 
       
   169 	//leave critical section
       
   170 	threads->Signal();
       
   171 	NKern::ThreadLeaveCS();
       
   172 
       
   173 	//return indication of whether the kernel's data was too big
       
   174 	return (aDataSize > aBuffer.Length()) ? KErrTooBig : KErrNone;
       
   175 	}
       
   176 
       
   177 /**
       
   178   Helper function for writing thread data into a buffer
       
   179 
       
   180   @pre call in a critical section
       
   181   @pre call only on threads which have NThread state not equal to NThread::EDead
       
   182 
       
   183   @param aBuffer buffer to put data in
       
   184   @param aDataSize on return will contain size of data
       
   185   @param aThread thread object to include information about
       
   186 
       
   187   @return KErrNone on success, or one of the other system wide error codes
       
   188 */
       
   189 void TListManager::AppendThreadData(TDes8& aBuffer, TUint32& aDataSize, DThread* aThread) const
       
   190 	{
       
   191 	//get aThread's name
       
   192 	TFileName fileName;
       
   193 	aThread->FullName(fileName);
       
   194 	TUint16 nameLength = fileName.Length();
       
   195 
       
   196 	//increase aDataSize by the size of this entry
       
   197 	aDataSize = Align4(aDataSize + (2*nameLength) + sizeof(TThreadListEntry) - sizeof(TUint16));
       
   198 	//if the data would not cause overflow then add it to the buffer
       
   199 	if(aDataSize <= aBuffer.MaxLength())
       
   200 		{
       
   201 		//Create a TThreadListEntry which references the buffer.
       
   202 		TThreadListEntry& entry = *(TThreadListEntry*)(aBuffer.Ptr()+aBuffer.Length());
       
   203 		//add data to entry
       
   204 		entry.iProcessId = (TUint64)aThread->iOwningProcess->iId;
       
   205 		entry.iThreadId = (TUint64)aThread->iId;
       
   206 		entry.iSupervisorStackBase = (TUint32)aThread->iSupervisorStack;
       
   207 		entry.iSupervisorStackBaseValid = ETrue;
       
   208 		entry.iSupervisorStackSize = aThread->iSupervisorStackSize;
       
   209 		entry.iSupervisorStackSizeValid = ETrue;
       
   210 		entry.iNameLength = nameLength;
       
   211 
       
   212 		//only ask for the supervisor stack pointer if aThread is suspended
       
   213 		entry.iSupervisorStackPtrValid = EInValid;
       
   214 		entry.iSupervisorStackPtr = 0;
       
   215 		if(TheDProcessTracker.CheckSuspended(aThread))
       
   216 			{
       
   217 			NThread& nThread = aThread->iNThread;
       
   218 
       
   219 			TArmRegSet regSet;
       
   220 			TUint32 flags;
       
   221 			NKern::ThreadGetSystemContext(&nThread, &regSet, flags);
       
   222 			entry.iSupervisorStackPtr = (TUint32)regSet.iR13;
       
   223 			//need to check that the stack pointer flag is valid
       
   224 			if(flags & (1<<EArmSp))
       
   225 				{
       
   226 				entry.iSupervisorStackPtrValid = EValid;
       
   227 				}
       
   228 			}
       
   229 
       
   230 		//copy name data into the buffer
       
   231 		TUint16* ptr = &(entry.iName[0]);
       
   232 		const TUint8* ptr8 = fileName.Ptr();
       
   233 		const TUint8* ptr8End = ptr8 + nameLength;
       
   234 		while(ptr8 < ptr8End)
       
   235 			{
       
   236 			*ptr++ = (TUint16)*ptr8++;
       
   237 			}
       
   238  
       
   239 		aBuffer.SetLength(aDataSize);
       
   240 		}
       
   241 	}
       
   242 
       
   243 /**
       
   244   Get global process listing
       
   245 
       
   246   @param aBuffer buffer to put data in
       
   247   @param aDataSize on return will contain size of data
       
   248 
       
   249   @return KErrNone on success,
       
   250   KErrTooBig if data won't fit in aBuffer
       
   251   or one of the other system wide error codes on failure
       
   252   */
       
   253 TInt TListManager::GetProcessList(TDes8& aBuffer, TUint32& aDataSize) const
       
   254 	{
       
   255 	LOG_MSG("TListManager::GetProcessList()");
       
   256 
       
   257 	//get a pointer to the kernel's process list
       
   258 	DObjectCon* processes = Kern::Containers()[EProcess];
       
   259 
       
   260 	if(processes == NULL)
       
   261 		{
       
   262 		//if can't get container then something is seriously wrong
       
   263 		return KErrNotFound;
       
   264 		}
       
   265 
       
   266 	//have to read the processes in a critical section
       
   267 	NKern::ThreadEnterCS();
       
   268 	processes->Wait();
       
   269 
       
   270 	aDataSize = 0;
       
   271 	//iterate through the processes adding them to the buffer
       
   272 	for(TInt i=0; i<processes->Count(); i++)
       
   273 		{
       
   274 		DProcess* process = (DProcess*)(*processes)[i];
       
   275 		if(process)
       
   276 			{
       
   277 			//get process's file name length
       
   278 			DCodeSeg* codeSeg = process->iCodeSeg;
       
   279 			TUint16 fileNameLength = (codeSeg) ? (*codeSeg->iFileName).Length() : 0;
       
   280 
       
   281 			//get process's dynamic name length and name
       
   282 			TFullName fullName;
       
   283 			process->FullName(fullName);
       
   284 			TUint16 dynamicNameLength = fullName.Length();
       
   285 
       
   286 			//increase aDataSize to reflect size of entry
       
   287 			aDataSize = Align4(aDataSize + (2*fileNameLength) + (2*dynamicNameLength) + sizeof(TProcessListEntry) - sizeof(TUint16));
       
   288 			//if the data would not cause overflow then add it to the buffer
       
   289 			if(aDataSize <= aBuffer.MaxLength())
       
   290 				{
       
   291 				//Create a TProcessListEntry which references the buffer.
       
   292 				TProcessListEntry& entry = *(TProcessListEntry*)(aBuffer.Ptr() + aBuffer.Length());
       
   293 
       
   294 				//set values
       
   295 				entry.iProcessId = (TUint64)process->iId;
       
   296 				entry.iFileNameLength = fileNameLength;
       
   297 				entry.iDynamicNameLength = dynamicNameLength;
       
   298 				entry.iUid3 = process->iUids.iUid[2].iUid;
       
   299 
       
   300 				if(codeSeg)
       
   301 					{
       
   302 					//create TPtr to where the file name should be written
       
   303 					TPtr name = TPtr((TUint8*)&(entry.iNames[0]), fileNameLength*2, fileNameLength*2);
       
   304 					//copy the file name
       
   305 					TInt err = CopyAndExpandDes(*codeSeg->iFileName, name);
       
   306 					if(err != KErrNone)
       
   307 						{
       
   308 						processes->Signal();
       
   309 						NKern::ThreadLeaveCS();
       
   310 						return KErrGeneral;
       
   311 						}
       
   312 					}
       
   313 
       
   314 				//create TPtr to where the dynamic name should be written
       
   315 				TPtr name = TPtr((TUint8*)(&(entry.iNames[0]) + fileNameLength), dynamicNameLength*2, dynamicNameLength*2);
       
   316 				//copy the dynamic name
       
   317 				TInt err = CopyAndExpandDes(fullName, name);
       
   318 				if(err != KErrNone)
       
   319 					{
       
   320 					processes->Signal();
       
   321 					NKern::ThreadLeaveCS();
       
   322 					return KErrGeneral;
       
   323 					}
       
   324 
       
   325 				//set length same as aDataSize
       
   326 				aBuffer.SetLength(aDataSize);
       
   327 				}
       
   328 			}
       
   329 		}
       
   330 
       
   331 	//leave critical section
       
   332 	processes->Signal();
       
   333 	NKern::ThreadLeaveCS();
       
   334 
       
   335 	//return indication of whether the kernel's data was too big
       
   336 	return (aDataSize > aBuffer.Length()) ? KErrTooBig : KErrNone;
       
   337 	}
       
   338 
       
   339 /**
       
   340   Copy the descriptor aSrc to aDest and converting each byte from aSrc
       
   341   into the two-byte equivalent. For example if aSrc contains 'XYZ' then
       
   342   aDest will be filled with 'X\0Y\0Z\0' where \0 is the null character.
       
   343   The length of aDest is set to twice the length of aSrc.
       
   344 
       
   345   @param aSrc source descriptor
       
   346   @param aDest destination descriptor to copy and expand aSrc into
       
   347 
       
   348   @return KErrNone on success,
       
   349   KErrArgument if the max length of aDest is less than twice the length of aSrc
       
   350   */
       
   351 TInt TListManager::CopyAndExpandDes(const TDesC& aSrc, TDes& aDest) const
       
   352 	{
       
   353 	//check bounds
       
   354 	if(aSrc.Length() * 2 > aDest.MaxLength())
       
   355 		{
       
   356 		return KErrArgument;
       
   357 		}
       
   358 
       
   359 	//get a pointer to the start of the destination descriptor
       
   360 	TUint16* destPtr = (TUint16*)aDest.Ptr();
       
   361 
       
   362 	//get pointers to the start and end of the aSrc descriptor
       
   363 	const TUint8* srcPtr = aSrc.Ptr();
       
   364 	const TUint8* srcEnd = srcPtr + aSrc.Length();
       
   365 
       
   366 	//copy the characters from aSrc into aDest, expanding to make them 16-bit characters
       
   367 	while(srcPtr < srcEnd)
       
   368 		{
       
   369 		*destPtr = (TUint16)*srcPtr;
       
   370 		destPtr++;
       
   371 		srcPtr++;
       
   372 		}
       
   373 
       
   374 	//set aDest's length to reflect the new contents
       
   375 	aDest.SetLength(2*aSrc.Length());
       
   376 	return KErrNone;
       
   377 	}
       
   378 
       
   379 /**
       
   380   Get global code segment listing
       
   381 
       
   382   @param aBuffer buffer to put data in
       
   383   @param aDataSize on return will contain size of data
       
   384 
       
   385   @return KErrNone on success,
       
   386   KErrTooBig if data won't fit in aBuffer,
       
   387   or one of the other system wide error codes
       
   388   */
       
   389 TInt TListManager::GetGlobalCodeSegList(TDes8& aBuffer, TUint32& aDataSize) const
       
   390 	{
       
   391 	LOG_MSG("TListManager::GetGlobalCodeSegList()");
       
   392 
       
   393 	// Acquire code seg lock mutex
       
   394 	NKern::ThreadEnterCS();
       
   395 	DMutex* codeMutex = Kern::CodeSegLock();
       
   396 	Kern::MutexWait(*codeMutex);
       
   397 
       
   398 	//get global code seg list
       
   399 	SDblQue* codeSegList = Kern::CodeSegList();
       
   400 
       
   401 	//create a memory info object for use in the loop
       
   402 	TModuleMemoryInfo memoryInfo;
       
   403 
       
   404 	//iterate through the list
       
   405 	aDataSize = 0;
       
   406 	for (SDblQueLink* codeSegPtr= codeSegList->First(); codeSegPtr!=(SDblQueLink*) (codeSegList); codeSegPtr=codeSegPtr->iNext)
       
   407 		{
       
   408 		DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iLink);
       
   409 		//the code seg shouldn't be null as we're in critical section, ignore if it is null
       
   410 		if(codeSeg)
       
   411 			{
       
   412 			//get the memory info
       
   413 			TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL);
       
   414 			if(err != KErrNone)
       
   415 				{
       
   416 				// Release the codeseglock mutex again
       
   417 				Kern::MutexSignal(*codeMutex);
       
   418 				NKern::ThreadLeaveCS();
       
   419 
       
   420 				//there's been an error so return it
       
   421 				return err;
       
   422 				}
       
   423 			//calculate data values
       
   424 			TFileName fileName(codeSeg->iFileName->Ptr());
       
   425 			TBool isXip = (TBool)(codeSeg->iXIP);
       
   426 
       
   427 			//get the code seg type, can ignore error as have already checked codeSeg is not NULL
       
   428 			TCodeSegType type = EUnknownCodeSegType;
       
   429 			err = GetCodeSegType(codeSeg, type);
       
   430 			if(err != KErrNone)
       
   431 				{
       
   432 				LOG_MSG("TListManager::GetGlobalCodeSegList() : code seg is NULL");
       
   433 				}
       
   434 
       
   435 			TUint32 uid3 = codeSeg->iUids.iUid[2].iUid;
       
   436 			//append data to buffer
       
   437 			err = AppendCodeSegData(aBuffer, aDataSize, memoryInfo, isXip, type, fileName, uid3);
       
   438 			if(err != KErrNone)
       
   439 				{
       
   440 				// Release the codeseglock mutex again
       
   441 				Kern::MutexSignal(*codeMutex);
       
   442 				NKern::ThreadLeaveCS();
       
   443 
       
   444 				return KErrGeneral;
       
   445 				}
       
   446 			}
       
   447 		}
       
   448 
       
   449 	// Release the codeseglock mutex again
       
   450 	Kern::MutexSignal(*codeMutex);
       
   451 	NKern::ThreadLeaveCS();
       
   452 
       
   453 	return (aDataSize > aBuffer.MaxLength()) ? KErrTooBig : KErrNone;
       
   454 	}
       
   455 
       
   456 /**
       
   457   Get code segment list for a thread
       
   458 
       
   459   @param aBuffer buffer to store data in
       
   460   @param aDataSize size of kernel's data
       
   461   @param thread ID to get listing for
       
   462 
       
   463   @return KErrNone on success,
       
   464   KErrTooBig if data won't fit in aBuffer,
       
   465   or one of the other system wide error codes
       
   466   */
       
   467 TInt TListManager::GetCodeSegListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const
       
   468 	{
       
   469 	LOG_MSG("TListManager::GetCodeSegListForThread()");
       
   470 
       
   471 	// open a handle to check whether the thread actually exists
       
   472 	DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId);
       
   473 	if(!thread)
       
   474 		{
       
   475 		return KErrArgument;
       
   476 		}
       
   477 	DProcess* process = thread->iOwningProcess;
       
   478 	if(!process)
       
   479 		{
       
   480 		return KErrArgument;
       
   481 		}
       
   482 	TUint64 processId = process->iId;
       
   483 	thread->Close(NULL);
       
   484 
       
   485 	return GetCodeSegListForProcess(aBuffer, aDataSize, processId);
       
   486 	}
       
   487 /**
       
   488   Get code segment list for a process
       
   489 
       
   490   @param aBuffer buffer to store data in
       
   491   @param aDataSize size of kernel's data
       
   492   @param process ID to get listing for
       
   493 
       
   494   @return KErrNone on success,
       
   495   KErrTooBig if data won't fit in aBuffer,
       
   496   or one of the other system wide error codes
       
   497   */
       
   498 TInt TListManager::GetCodeSegListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const
       
   499 	{
       
   500 	LOG_MSG("TListManager::GetCodeSegListForProcess()");
       
   501 
       
   502 	//get the process
       
   503 	DProcess* process = DebugUtils::OpenProcessHandle(aTargetProcessId);
       
   504 
       
   505 	if(!process)
       
   506 		{
       
   507 		return KErrArgument;
       
   508 		}
       
   509 
       
   510 	//enter thread critical section and acquire code segment mutex
       
   511 	Kern::AccessCode();
       
   512 
       
   513 	//memory info object to use in loop
       
   514 	TModuleMemoryInfo memoryInfo;
       
   515 
       
   516 	//get code seg list
       
   517 	SDblQue queue;
       
   518 	process->TraverseCodeSegs(&queue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd);
       
   519 
       
   520 	//iterate through the list
       
   521 	aDataSize = 0;
       
   522 	for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
       
   523 		{
       
   524 		//get the code seg
       
   525 		DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
       
   526 
       
   527 		//the code seg shouldn't be null as we're in critical section, ignore if it is null
       
   528 		if(codeSeg)
       
   529 			{
       
   530 			TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL);
       
   531 			if(err != KErrNone)
       
   532 				{
       
   533 				process->Close(NULL);
       
   534 				return err;
       
   535 				}
       
   536 
       
   537 			TFileName fileName(codeSeg->iFileName->Ptr());
       
   538 			TBool isXip = (TBool)(codeSeg->iXIP);
       
   539 
       
   540 			//get the code seg type, can ignore error as have already checked codeSeg is not NULL
       
   541 			TCodeSegType type = EUnknownCodeSegType;
       
   542 			err = GetCodeSegType(codeSeg, type);
       
   543 			if(err != KErrNone)
       
   544 				{
       
   545 				LOG_MSG("TListManager::GetCodeSegListForProcess() : code seg is NULL");
       
   546 				}
       
   547 
       
   548 			TUint32 uid3 = codeSeg->iUids.iUid[2].iUid;
       
   549 			//append data to buffer
       
   550 			err = AppendCodeSegData(aBuffer, aDataSize, memoryInfo, isXip, type, fileName, uid3);
       
   551 			if(err != KErrNone)
       
   552 				{
       
   553 				process->Close(NULL);
       
   554 				return KErrGeneral;
       
   555 				}
       
   556 			}
       
   557 		}
       
   558 
       
   559 	//un mark the code segs that we've iterated over
       
   560 	DCodeSeg::EmptyQueue(queue, DCodeSeg::EMarkDebug);
       
   561 
       
   562 	//release mutex and leave CS
       
   563 	Kern::EndAccessCode();
       
   564 
       
   565 	process->Close(NULL);
       
   566 	return (aDataSize > aBuffer.MaxLength()) ? KErrTooBig : KErrNone;
       
   567 	}
       
   568 
       
   569 /**
       
   570   Appends data to a specified buffer and puts the resulting size in aDataSize.
       
   571   If the data won't fit then aDataSize is updated to reflect what the new length
       
   572   would be.
       
   573 
       
   574   @param aBuffer buffer to append data to
       
   575   @param aDataSize will contain buffer size (or the size the buffer would be) on return
       
   576   @param aMemoryInfo info to append to buffer
       
   577   @param aIsXip boolean indicating whether the code segment is XIP
       
   578   @param aFileName file name to append to buffer
       
   579 
       
   580   @return KErrNone on success, or one of the other system wide error codes
       
   581   */
       
   582 TInt TListManager::AppendCodeSegData(TDes8& aBuffer, TUint32& aDataSize, const TModuleMemoryInfo& aMemoryInfo, const TBool aIsXip, const TCodeSegType aCodeSegType, const TDesC8& aFileName, const TUint32 aUid3) const
       
   583 	{
       
   584 	//get some data elements to put in buffer
       
   585 	TUint16 fileNameLength = aFileName.Length();
       
   586 
       
   587 	//calculate the resultant size
       
   588 	aDataSize = Align4(aDataSize + sizeof(TCodeSegListEntry) + (2*fileNameLength) - sizeof(TUint16));
       
   589 	if(aDataSize <= aBuffer.MaxLength())
       
   590 		{
       
   591 		//Create a TCodeSegListEntry which references the buffer.
       
   592 		TCodeSegListEntry& entry = *(TCodeSegListEntry*)(aBuffer.Ptr() + aBuffer.Length());
       
   593 		entry.iCodeBase = aMemoryInfo.iCodeBase;
       
   594 		entry.iCodeSize = aMemoryInfo.iCodeSize;
       
   595 		entry.iConstDataSize = aMemoryInfo.iConstDataSize;
       
   596 		entry.iInitialisedDataBase = aMemoryInfo.iInitialisedDataBase;
       
   597 		entry.iInitialisedDataSize = aMemoryInfo.iInitialisedDataSize;
       
   598 		entry.iUninitialisedDataSize = aMemoryInfo.iUninitialisedDataSize;
       
   599 		entry.iIsXip = aIsXip;
       
   600 		entry.iCodeSegType = aCodeSegType;
       
   601 		entry.iNameLength = fileNameLength;
       
   602 		entry.iUid3 = aUid3;
       
   603 
       
   604 		//have to convert the stored name to 16 bit unicode
       
   605 		TPtr name = TPtr((TUint8*)&(entry.iName[0]), fileNameLength*2, fileNameLength*2);
       
   606 		TInt err = CopyAndExpandDes(aFileName, name);
       
   607 		if(err != KErrNone)
       
   608 			{
       
   609 			return KErrGeneral;
       
   610 			}
       
   611 
       
   612 		//increase length
       
   613 		aBuffer.SetLength(aDataSize);
       
   614 		}
       
   615 
       
   616 	return KErrNone;
       
   617 	}
       
   618 
       
   619 /**
       
   620   Get global XIP libraries list. The ROM file system is searched for files in
       
   621   z:\sys\bin. The files are filtered to only include library files which
       
   622   correspond to the correct hardware variant.
       
   623 
       
   624   In the rom, a directory is represented as a list of TRomEntrys, corresponding to
       
   625   the files and directories in that directory. A TRomEntry corresponding to a file
       
   626   contains a pointer to that file's location in the rom. If the TRomEntry
       
   627   corresponds to a directory then it contains a pointer to that directory in the
       
   628   ROM header. As such, from a pointer to the root directory of the z: drive, it is
       
   629   possible to extract the directory contents for a particular directory (i.e. z:\sys\bin)
       
   630   by recursively finding the subdirectories (i.e. find 'sys' in 'z:', then 'bin' in 'sys')
       
   631   and then listing the contents of that directory.
       
   632 
       
   633   @param aBuffer buffer to store data in
       
   634   @param aDataSize size of kernel's data
       
   635 
       
   636   @return KErrNone on success,
       
   637   KErrTooBig if data won't fit in aBuffer,
       
   638   or one of the other system wide error codes
       
   639   */
       
   640 TInt TListManager::GetXipLibrariesList(TDes8& aBuffer, TUint32& aDataSize) const
       
   641 	{
       
   642 	LOG_MSG("TListManager::GetXipLibrariesList()");
       
   643 
       
   644 	// z:\sys\bin expressed as 16 bit unicode..
       
   645 	_LIT(KZSysBin, "z\0:\0\\\0s\0y\0s\0\\\0b\0i\0n\0\\\0");
       
   646 
       
   647 	//array to store pointers to directory entries in
       
   648 	RPointerArray<TRomEntry> entries;
       
   649 	//get the entries in KZSysBin
       
   650 	TInt err = GetDirectoryEntries(entries, KZSysBin());
       
   651 	if(KErrNone != err)
       
   652 		{
       
   653 		entries.Close();
       
   654 		return err;
       
   655 		}
       
   656 
       
   657 	aDataSize = 0;
       
   658 	for(TInt i=0; i<entries.Count(); i++)
       
   659 		{
       
   660 		//if the entry is XIP and it's not a directory then it's a candidate to add
       
   661 		if( (entries[i]->iAtt & KEntryAttXIP) && ! (entries[i]->iAtt & KEntryAttDir) )
       
   662 			{
       
   663 			//get a reference to the dll's header
       
   664 			const TRomImageHeader& header = *(const TRomImageHeader*)(entries[i]->iAddressLin);
       
   665 
       
   666 			//check that it's uid1 value corresponds to that for a library
       
   667 			if(header.iUid1 == KDynamicLibraryUidValue)
       
   668 				{
       
   669 				//get the current hardware variant
       
   670 				TSuperPage& superPage = Kern::SuperPage();
       
   671 				TUint variant = superPage.iActiveVariant;
       
   672 				TUint cpu = (variant >> 16) & 0xff;
       
   673 				TUint asic = (variant >> 24);
       
   674 
       
   675 				//check this dll is compatible with the current variant
       
   676 				if(THardwareVariant(header.iHardwareVariant).IsCompatibleWith(cpu,asic,variant))
       
   677 					{
       
   678 					const TInt fileNameLength16 = entries[i]->iNameLength;
       
   679 					const TInt fullNameLength16 = (KZSysBin().Length() / 2) + fileNameLength16;
       
   680 					aDataSize += Align4((2 * fullNameLength16) + sizeof(TXipLibraryListEntry) - sizeof(TUint16));
       
   681 
       
   682 					if(aDataSize <= aBuffer.MaxLength())
       
   683 						{
       
   684 						//Create a TXipLibraryListEntry which references the buffer.
       
   685 						TXipLibraryListEntry& libraryInfo = *(TXipLibraryListEntry*)(aBuffer.Ptr() + aBuffer.Length());
       
   686 
       
   687 						//add the data
       
   688 						libraryInfo.iCodeBase = header.iCodeAddress;
       
   689 						libraryInfo.iCodeSize = header.iTextSize;
       
   690 						libraryInfo.iConstDataSize = header.iCodeSize - header.iTextSize;
       
   691 						libraryInfo.iInitialisedDataBase = header.iDataBssLinearBase;
       
   692 						libraryInfo.iInitialisedDataSize = header.iDataSize;
       
   693 						libraryInfo.iUninitialisedDataSize = header.iBssSize;
       
   694 						libraryInfo.iNameLength = fullNameLength16;
       
   695 
       
   696 						//create a TPtr8 to contain the fully qualified name (i.e. z:\sys\bin\ prefixed)
       
   697 						TPtr8 name((TUint8*)&(libraryInfo.iName[0]), 0, 2 * fullNameLength16);
       
   698 						name.Append(KZSysBin());
       
   699 						name.Append(TPtr8((TUint8*)&(entries[i]->iName), 2 * fileNameLength16, 2 * fileNameLength16));
       
   700 
       
   701 						//increase the buffer's length to reflect the new data size
       
   702 						aBuffer.SetLength(aDataSize);
       
   703 						}
       
   704 					}
       
   705 				}
       
   706 			}
       
   707 		}
       
   708 	entries.Close();
       
   709 	return (aDataSize == aBuffer.Length()) ? KErrNone : KErrTooBig;
       
   710 	}
       
   711 
       
   712 /**
       
   713 Get the list of TRomEntry objects in the specified directory aDirectory
       
   714 
       
   715 @param aRomEntryArray array to store pointers to the TRomEntry objects in
       
   716 @param aDirectoryName directory to get contents of. The passed in string should be
       
   717 16 bit unicode and should begin with z:. Single backslashes should be used as delimiters
       
   718 rather than forward slashes and a terminating backslash is optional.
       
   719 For example: z:\sys\bin
       
   720 
       
   721 @return KErrNone on success, or one of the other system wide error codes
       
   722 */
       
   723 TInt TListManager::GetDirectoryEntries(RPointerArray<TRomEntry>& aRomEntryArray, const TDesC& aDirectoryName) const
       
   724 	{
       
   725 	LOG_MSG("TListManager::GetDirectoryEntries()");
       
   726 
       
   727 	//definition in 16 bit unicode
       
   728 	_LIT(KForwardSlash, "/\0");
       
   729 
       
   730 	//if directory has forward slashes then exit
       
   731 	if(aDirectoryName.Find(KForwardSlash()) != KErrNotFound)
       
   732 		{
       
   733 		return KErrArgument;
       
   734 		}
       
   735 
       
   736 	//create an array to hold the folders in aDirectoryName
       
   737 	RArray<TPtr8> folders;
       
   738 
       
   739 	//split the directory up into its folders, i.e. z:\sys\bin is split into { 'z:', 'sys', 'bin' }
       
   740 	TInt err = SplitDirectoryName(aDirectoryName, folders);
       
   741 	if(KErrNone != err)
       
   742 		{
       
   743 		folders.Close();
       
   744 		return err;
       
   745 		}
       
   746 
       
   747 	if(folders.Count() == 0)
       
   748 		{
       
   749 		folders.Close();
       
   750 		//empty string passed in
       
   751 		return KErrArgument;
       
   752 		}
       
   753 
       
   754 	// z: as 16 bit unicode
       
   755 	_LIT(KZColon, "z\0:\0");
       
   756 	if(folders[0].CompareF(KZColon()) != 0)
       
   757 		{
       
   758 		//first argument must be z: otherwise not in rom
       
   759 		folders.Close();
       
   760 		return KErrArgument;
       
   761 		}
       
   762 	//remove z: from array
       
   763 	folders.Remove(0);
       
   764 	for(TInt i=0; i<folders.Count(); i++)
       
   765 		{
       
   766 		if(folders[i].Length() == 0)
       
   767 			{
       
   768 			// there were two backslashes in a row
       
   769 			folders.Close();
       
   770 			return KErrArgument;
       
   771 			}
       
   772 		}
       
   773 
       
   774 	//get a pointer to the start of the rom root directory list
       
   775 	TLinAddr romRootDirectoryList = Epoc::RomHeader().iRomRootDirectoryList;
       
   776 
       
   777 	//the first 4 bytes of the rom root directory list is a count of how many sections (rom roots) there are
       
   778 	TUint32 rootDirectoryCount = (TUint32)*(TLinAddr*)romRootDirectoryList;
       
   779 
       
   780 	//rootDirectoryPointer will be shifted through the rom root directory list and will contain pointers to the sections in the rom
       
   781 	TLinAddr rootDirectoryPointer = romRootDirectoryList;
       
   782 	for(TInt i=0; i<rootDirectoryCount; i++)
       
   783 		{
       
   784 		//the address of the section is stored in the second four bytes of the 8 byte pair reserved for each section
       
   785 		rootDirectoryPointer += 8;
       
   786 
       
   787 		//romRoot contains the address of the root of the section
       
   788 		TLinAddr romRoot = *(TLinAddr*)rootDirectoryPointer;
       
   789 
       
   790 		//append the directory entries from romRoot's z:\sys\bin subdirectory
       
   791 		TInt err = GetDirectoryEntries(aRomEntryArray, folders, romRoot);
       
   792 		if(KErrNone != err)
       
   793 			{
       
   794 			folders.Close();
       
   795 			return err;
       
   796 			}
       
   797 		}
       
   798 	folders.Close();
       
   799 	return KErrNone;
       
   800 	}
       
   801 
       
   802 /**
       
   803   Recursively finds the subdirectories in aArray and stores references to the
       
   804   entries in the most derived subdirectory in aRomEntryArray
       
   805 
       
   806   @param aRomEntryArray on return will contain the entries in the directory corresponding to aArray
       
   807   @param aArray an array containing the directory to get the entries for, i.e. { 'sys', 'bin' }
       
   808   @param aAddress address in rom to being searching from
       
   809 
       
   810   @param KErrNone on success, or one of the other system wide error codes
       
   811 */
       
   812 TInt TListManager::GetDirectoryEntries(RPointerArray<TRomEntry>& aRomEntryArray, RArray<TPtr8>& aArray, TLinAddr& aAddress) const
       
   813 	{
       
   814 	LOG_MSG2("TListManager::GetDirectoryEntries() aAddress: 0x%08x", aAddress);
       
   815 
       
   816 	//find the next subdirectory and store its address in aAddress, return error if we can't find it
       
   817 	TInt err = FindDirectory(aArray[0], aAddress);
       
   818 	if(err != KErrNone)
       
   819 		{
       
   820 		return err;
       
   821 		}
       
   822 
       
   823 	//if this is the most derived sub-directory (i.e. the bin of z:\sys\bin) then get the dir contents
       
   824 	if(aArray.Count() == 1)
       
   825 		{
       
   826 		return GetDirectoryContents(aRomEntryArray, aAddress);
       
   827 		}
       
   828 	else
       
   829 		{
       
   830 		//get the next subdirectory's contents
       
   831 		aArray.Remove(0);
       
   832 		return GetDirectoryEntries(aRomEntryArray, aArray, aAddress);
       
   833 		}
       
   834 	}
       
   835 
       
   836 /**
       
   837 Return the entries of a directory in the rom
       
   838 
       
   839 @param aRomEntryArray array to store the entries in
       
   840 @param aAddress address of a directory block in the rom
       
   841 */
       
   842 TInt TListManager::GetDirectoryContents(RPointerArray<TRomEntry>& aRomEntryArray, const TLinAddr aAddress) const
       
   843 	{
       
   844 	LOG_MSG("TListManager::GetDirectoryContents()");
       
   845 
       
   846 	TLinAddr address = aAddress;
       
   847 
       
   848 	//get the size in bytes of the block of rom to iterate over
       
   849 	const TUint32 sizeInBytes = *(TUint32*)aAddress;
       
   850 
       
   851 	//get address of first TRomEntry
       
   852 	const TLinAddr initialAddress = aAddress + sizeof(TUint32);
       
   853 
       
   854 	//get pointer to subdir count
       
   855 	address = initialAddress + sizeInBytes;
       
   856 
       
   857 	//the upper two bytes of this entry contain the number of files in this directory, and the lower two bytes
       
   858 	//contains the number of subdirectories in this directory
       
   859 	TUint32 filesAndDirectories = *(TUint32*)address;
       
   860 
       
   861 	//get number of subdirectories in this directory
       
   862 	const TUint16 subDirCount = filesAndDirectories & 0xFFFF;
       
   863 
       
   864 	//get the number of files in this dir
       
   865 	const TUint16 filesCount = filesAndDirectories >> 16;
       
   866 
       
   867 	//get total number of entries in dir
       
   868 	const TUint numDirectoryEntries = subDirCount + filesCount;
       
   869 
       
   870 	//set address to start of first entry
       
   871 	address = initialAddress;
       
   872 
       
   873 	for(TInt i=0; i<numDirectoryEntries; i++)
       
   874 		{
       
   875 		TRomEntry* romEntry = (TRomEntry*)address;
       
   876 
       
   877 		//store the entry
       
   878 		TInt err = aRomEntryArray.Append(romEntry);
       
   879 		if(KErrNone != err)
       
   880 			{
       
   881 			return err;
       
   882 			}
       
   883 
       
   884 		//length of the name of the rom entry
       
   885 		TInt nameLength = romEntry->iNameLength;
       
   886 
       
   887 		//get the size of the entry including the name
       
   888 		TUint32 romEntrySize = sizeof(TRomEntry) - sizeof(romEntry->iName) + (2 * nameLength);
       
   889 		//adjust the address to the next entry
       
   890 		address += Align4(romEntrySize);
       
   891 		}
       
   892 	return KErrNone;
       
   893 	}
       
   894 
       
   895 /**
       
   896   Finds the subdirectory with name aDirectory in the directory at aAddress
       
   897 
       
   898   @param aDirectory name of subdirectory to search for (i.e. 'bin')
       
   899   @param aAddress address in rom of containing directory (i.e. address of 'sys' directory)
       
   900 
       
   901   @param KErrNone if aDirectory could be found in aAddress, KErrNotFound if it could not be found
       
   902   */
       
   903 TInt TListManager::FindDirectory(const TDesC& aDirectory, TLinAddr& aAddress) const
       
   904 	{
       
   905 	LOG_MSG3("TListManager::FindDirectory() aDirectory: %S, aAddress: 0x%08x", &aDirectory, aAddress);
       
   906 
       
   907 	//get the directory's contents
       
   908 	RPointerArray<TRomEntry> dirContents;
       
   909 	TInt err = GetDirectoryContents(dirContents, aAddress);
       
   910 	if(KErrNone != err)
       
   911 		{
       
   912 		dirContents.Close();
       
   913 		return err;
       
   914 		}
       
   915 	for(TInt i=0; i<dirContents.Count(); i++)
       
   916 		{
       
   917 		//create a reference to the TRomEntry in the rom to access its attributes
       
   918 		TRomEntry& romEntry = *(dirContents[i]);
       
   919 		if(romEntry.iAtt & KEntryAttDir)
       
   920 			{
       
   921 			// this entry's a directory so check if it matches aDirectory
       
   922 			const TInt nameLength = romEntry.iNameLength;
       
   923 			TPtr8 name((TUint8*)&(romEntry.iName), nameLength * 2, nameLength * 2);
       
   924 			if(0 == aDirectory.CompareF(name))
       
   925 				{
       
   926 				// names matched so get the address of this directory's contents
       
   927 				aAddress = romEntry.iAddressLin;
       
   928 				dirContents.Close();
       
   929 				return KErrNone;
       
   930 				}
       
   931 			}
       
   932 		}
       
   933 	dirContents.Close();
       
   934 	//couldn't find it so return error
       
   935 	return KErrNotFound;
       
   936 	}
       
   937 
       
   938 /**
       
   939   Helper function to get code seg type.
       
   940 
       
   941   @param aCodeSeg code seg to get type of
       
   942   @param aType will contain type on return
       
   943 
       
   944   @return KErrNone on success, KErrNotFound if aCodeSeg is NULL
       
   945   */
       
   946 TInt TListManager::GetCodeSegType(const DCodeSeg* aCodeSeg, TCodeSegType& aType) const
       
   947 	{
       
   948 	if(!aCodeSeg)
       
   949 		{
       
   950 		return KErrNotFound;
       
   951 		}
       
   952 
       
   953 	if(aCodeSeg->IsExe())
       
   954 		{
       
   955 		aType = EExeCodeSegType;
       
   956 		return KErrNone;
       
   957 		}
       
   958 
       
   959 	if(aCodeSeg->IsDll())
       
   960 		{
       
   961 		aType = EDllCodeSegType;
       
   962 		return KErrNone;
       
   963 		}
       
   964 
       
   965 	aType = EUnknownCodeSegType;
       
   966 	return KErrNone;
       
   967 	}
       
   968 
       
   969 
       
   970 /**
       
   971   Split a directory name into its subdirectories, using a 16-bit backslash ('\\\0') as a delimiter.
       
   972   For example z:\sys\bin would be split into { 'z:', 'sys', 'bin' }
       
   973 
       
   974   @param aDirectoryName directory name to split into subdirectories
       
   975   @param aSubDirectories array to store the subdirectories in
       
   976   */
       
   977 TInt TListManager::SplitDirectoryName(const TDesC& aDirectoryName, RArray<TPtr8>& aSubDirectories) const
       
   978 	{
       
   979 	//definition in 16 bit unicode
       
   980 	_LIT(KBackSlash, "\\\0");
       
   981 
       
   982 	//split the directory up into its folders, i.e. z:\sys\bin is split into 
       
   983 	TPtr8 string((TUint8*)aDirectoryName.Ptr(), aDirectoryName.Length(), aDirectoryName.Length());
       
   984 	while(string.Ptr() < aDirectoryName.Ptr() + aDirectoryName.Length())
       
   985 		{
       
   986 		TInt offset = string.Find(KBackSlash());
       
   987 		if(offset == KErrNotFound)
       
   988 			{
       
   989 			//reached the end of the string
       
   990 			offset = string.Length();
       
   991 			}
       
   992 		//adjustedOffset takes account of the end of the string case
       
   993 		TInt adjustedOffset = (offset == string.Length()) ? offset : offset + KBackSlash().Length();
       
   994 		//add sub-folder name
       
   995 		TInt err = aSubDirectories.Append(TPtr8((TUint8*)string.Ptr(), offset, offset));
       
   996 		if(KErrNone != err)
       
   997 			{
       
   998 			return err;
       
   999 			}
       
  1000 		//remove the sub-folder name and continue
       
  1001 		string.Set((TUint8*)string.Ptr() + adjustedOffset, string.Length() - adjustedOffset, string.Length() - adjustedOffset);
       
  1002 		}
       
  1003 	return KErrNone;
       
  1004 	}
       
  1005 
       
  1006 
       
  1007