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