--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/debugsrv/runmodedebug/rmdriver/src/d_list_manager.cpp Thu Sep 02 22:05:40 2010 +0300
@@ -0,0 +1,996 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Provides a class to manage the generation of lists
+//
+//
+
+#include "d_list_manager.h"
+#include "d_process_tracker.h"
+#include "debug_utils.h"
+#include "plat_priv.h"
+#include "debug_logging.h"
+#include <arm.h>
+
+// make accessing DThread's MState more intuitive
+#define iMState iWaitLink.iSpare1
+// make accessing NThread's NState more intuitive
+#define iNState iSpare3
+
+//constants to match against a rom entry's attributes,
+//these are defined in the file server (can't be included kernel side)
+//and in the ROM tools (also inaccessible) so redefined here
+const TUint KEntryAttXIP=0x0080;
+const TUint KEntryAttDir=0x0010;
+
+using namespace Debug;
+
+/**
+ Get thread listing for the specified thread, if the thread data will not fit
+ in the buffer then an error is returned.
+
+ @param aBuffer buffer to put data in
+ @param aDataSize on return will contain size of data
+ @param aTargetThreadId thread ID to return listing for
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer
+ or one of the other system wide error codes on failure
+ */
+TInt TListManager::GetThreadListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const
+ {
+ LOG_MSG("TListManager::GetThreadListForThread()");
+
+ // open a handle to check whether the thread actually exists
+ NKern::ThreadEnterCS();
+ DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId);
+ TUint64 processId = 0;
+ if (thread)
+ {
+ processId = thread->iOwningProcess->iId;
+ thread->Close(NULL);
+ }
+ NKern::ThreadLeaveCS();
+ if (!thread)
+ {
+ return KErrArgument;
+ }
+
+ //request a process specific list
+ return GetThreadListForProcess(aBuffer, aDataSize, processId);
+ }
+
+TInt TListManager::GetThreadListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const
+ {
+ LOG_MSG("TListManager::GetThreadListForProcess()");
+
+ // open a handle to check whether the process actually exists
+ DProcess* process = DebugUtils::OpenProcessHandle(aTargetProcessId);
+ if(!process)
+ {
+ return KErrArgument;
+ }
+ process->Close(NULL);
+
+ //request a process specific list
+ return GetThreadList(aBuffer, aDataSize, EFalse, aTargetProcessId);
+ }
+
+/**
+ Get global thread listing
+
+ @param aBuffer buffer to put data in
+ @param aDataSize on return will contain size of data
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer
+ or one of the other system wide error codes on failure
+ */
+TInt TListManager::GetGlobalThreadList(TDes8& aBuffer, TUint32& aDataSize) const
+ {
+ LOG_MSG("TListManager::GetGlobalThreadList()");
+
+ //request a global list
+ return GetThreadList(aBuffer, aDataSize, ETrue, 0);
+ }
+
+/**
+ Get thread listing, if the thread data will not fit
+ in the buffer then an error is returned.
+
+ @param aBuffer buffer to put data in
+ @param aDataSize on return will contain size of data
+ @param aGlobal whether or not the listing should be global or thread specific
+ @param aTargetProcessId process ID to return listing for, relevant only if aGlobal == ETrue
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer
+ or one of the other system wide error codes on failure
+ */
+TInt TListManager::GetThreadList(TDes8& aBuffer, TUint32& aDataSize, TBool aGlobal, const TUint64 aTargetProcessId) const
+ {
+ LOG_MSG("TListManager::GetThreadList\n");
+
+ NKern::ThreadEnterCS();
+ DObjectCon *threads = Kern::Containers()[EThread];
+ threads->Wait();
+
+ aDataSize = 0;
+ aBuffer.SetLength(0);
+ //iterate through the threads adding them to the buffer
+ for(TInt i=0; i<threads->Count(); i++)
+ {
+ DThread* thread = (DThread*)(*threads)[i];
+
+ //skip this thread pointer is the thread is NULL
+ if(thread)
+ {
+ NThread& nThread = thread->iNThread;
+
+ // if the thread is marked as being dead then don't return information about it in the listing
+#ifndef __SMP__
+ if((NThread::EDead != nThread.iNState) && (DThread::EDead != thread->iMState))
+#else
+ if((!nThread.IsDead()) && (DThread::EDead != thread->iMState))
+#endif
+ {
+ if( aGlobal || (aTargetProcessId == (TUint64)thread->iOwningProcess->iId))
+ {
+ //store the data in the buffer
+ AppendThreadData(aBuffer, aDataSize, thread);
+ }
+ }
+ }
+ }
+
+ //leave critical section
+ threads->Signal();
+ NKern::ThreadLeaveCS();
+
+ //return indication of whether the kernel's data was too big
+ return (aDataSize > aBuffer.Length()) ? KErrTooBig : KErrNone;
+ }
+
+/**
+ Helper function for writing thread data into a buffer
+
+ @pre call in a critical section
+ @pre call only on threads which have NThread state not equal to NThread::EDead
+
+ @param aBuffer buffer to put data in
+ @param aDataSize on return will contain size of data
+ @param aThread thread object to include information about
+
+ @return KErrNone on success, or one of the other system wide error codes
+*/
+void TListManager::AppendThreadData(TDes8& aBuffer, TUint32& aDataSize, DThread* aThread) const
+ {
+ LOG_MSG3("TListManager::AppendThreadData for thrd 0x%08x, currThrd=0x%08x",
+ aThread->iId, Kern::CurrentThread().iId );
+
+ //get aThread's name
+ TFileName fileName;
+ aThread->FullName(fileName);
+ TUint16 nameLength = fileName.Length();
+
+ //increase aDataSize by the size of this entry
+ aDataSize = Align4(aDataSize + (2*nameLength) + sizeof(TThreadListEntry) - sizeof(TUint16));
+ //if the data would not cause overflow then add it to the buffer
+ if(aDataSize <= aBuffer.MaxLength())
+ {
+ //Create a TThreadListEntry which references the buffer.
+ TThreadListEntry& entry = *(TThreadListEntry*)(aBuffer.Ptr()+aBuffer.Length());
+ //add data to entry
+ entry.iProcessId = (TUint64)aThread->iOwningProcess->iId;
+ entry.iThreadId = (TUint64)aThread->iId;
+ entry.iSupervisorStackBase = (TUint32)aThread->iSupervisorStack;
+ entry.iSupervisorStackBaseValid = ETrue;
+ entry.iSupervisorStackSize = aThread->iSupervisorStackSize;
+ entry.iSupervisorStackSizeValid = ETrue;
+ entry.iNameLength = nameLength;
+
+ entry.iSupervisorStackPtrValid = EInValid;
+ entry.iSupervisorStackPtr = 0;
+
+ if(aThread->iId != Kern::CurrentThread().iId)
+ {
+ NThread& nThread = aThread->iNThread;
+
+ TArmRegSet regSet;
+ TUint32 flags;
+ NKern::ThreadGetSystemContext(&nThread, ®Set, flags);
+ entry.iSupervisorStackPtr = (TUint32)regSet.iR13;
+ //need to check that the stack pointer flag is valid
+ if(flags & (1<<EArmSp))
+ {
+ entry.iSupervisorStackPtrValid = EValid;
+ }
+ }
+
+ //copy name data into the buffer
+ TUint16* ptr = &(entry.iName[0]);
+ const TUint8* ptr8 = fileName.Ptr();
+ const TUint8* ptr8End = ptr8 + nameLength;
+ while(ptr8 < ptr8End)
+ {
+ *ptr++ = (TUint16)*ptr8++;
+ }
+
+ aBuffer.SetLength(aDataSize);
+ }
+ }
+
+/**
+ Get global process listing
+
+ @param aBuffer buffer to put data in
+ @param aDataSize on return will contain size of data
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer
+ or one of the other system wide error codes on failure
+ */
+TInt TListManager::GetProcessList(TDes8& aBuffer, TUint32& aDataSize) const
+ {
+ LOG_MSG("TListManager::GetProcessList()");
+
+ //get a pointer to the kernel's process list
+ DObjectCon* processes = Kern::Containers()[EProcess];
+
+ if(processes == NULL)
+ {
+ //if can't get container then something is seriously wrong
+ return KErrNotFound;
+ }
+
+ //have to read the processes in a critical section
+ NKern::ThreadEnterCS();
+ processes->Wait();
+
+ aDataSize = 0;
+ //iterate through the processes adding them to the buffer
+ for(TInt i=0; i<processes->Count(); i++)
+ {
+ DProcess* process = (DProcess*)(*processes)[i];
+ if(process)
+ {
+ //get process's file name length
+ DCodeSeg* codeSeg = process->iCodeSeg;
+ TUint16 fileNameLength = (codeSeg) ? (*codeSeg->iFileName).Length() : 0;
+
+ //get process's dynamic name length and name
+ TFullName fullName;
+ process->FullName(fullName);
+ TUint16 dynamicNameLength = fullName.Length();
+
+ //increase aDataSize to reflect size of entry
+ aDataSize = Align4(aDataSize + (2*fileNameLength) + (2*dynamicNameLength) + sizeof(TProcessListEntry) - sizeof(TUint16));
+ //if the data would not cause overflow then add it to the buffer
+ if(aDataSize <= aBuffer.MaxLength())
+ {
+ //Create a TProcessListEntry which references the buffer.
+ TProcessListEntry& entry = *(TProcessListEntry*)(aBuffer.Ptr() + aBuffer.Length());
+
+ //set values
+ entry.iProcessId = (TUint64)process->iId;
+ entry.iFileNameLength = fileNameLength;
+ entry.iDynamicNameLength = dynamicNameLength;
+ entry.iUid3 = process->iUids.iUid[2].iUid;
+
+ if(codeSeg)
+ {
+ //create TPtr to where the file name should be written
+ TPtr name = TPtr((TUint8*)&(entry.iNames[0]), fileNameLength*2, fileNameLength*2);
+ //copy the file name
+ TInt err = CopyAndExpandDes(*codeSeg->iFileName, name);
+ if(err != KErrNone)
+ {
+ processes->Signal();
+ NKern::ThreadLeaveCS();
+ return KErrGeneral;
+ }
+ }
+
+ //create TPtr to where the dynamic name should be written
+ TPtr name = TPtr((TUint8*)(&(entry.iNames[0]) + fileNameLength), dynamicNameLength*2, dynamicNameLength*2);
+ //copy the dynamic name
+ TInt err = CopyAndExpandDes(fullName, name);
+ if(err != KErrNone)
+ {
+ processes->Signal();
+ NKern::ThreadLeaveCS();
+ return KErrGeneral;
+ }
+
+ //set length same as aDataSize
+ aBuffer.SetLength(aDataSize);
+ }
+ }
+ }
+
+ //leave critical section
+ processes->Signal();
+ NKern::ThreadLeaveCS();
+
+ //return indication of whether the kernel's data was too big
+ return (aDataSize > aBuffer.Length()) ? KErrTooBig : KErrNone;
+ }
+
+/**
+ Copy the descriptor aSrc to aDest and converting each byte from aSrc
+ into the two-byte equivalent. For example if aSrc contains 'XYZ' then
+ aDest will be filled with 'X\0Y\0Z\0' where \0 is the null character.
+ The length of aDest is set to twice the length of aSrc.
+
+ @param aSrc source descriptor
+ @param aDest destination descriptor to copy and expand aSrc into
+
+ @return KErrNone on success,
+ KErrArgument if the max length of aDest is less than twice the length of aSrc
+ */
+TInt TListManager::CopyAndExpandDes(const TDesC& aSrc, TDes& aDest) const
+ {
+ //check bounds
+ if(aSrc.Length() * 2 > aDest.MaxLength())
+ {
+ return KErrArgument;
+ }
+
+ //get a pointer to the start of the destination descriptor
+ TUint16* destPtr = (TUint16*)aDest.Ptr();
+
+ //get pointers to the start and end of the aSrc descriptor
+ const TUint8* srcPtr = aSrc.Ptr();
+ const TUint8* srcEnd = srcPtr + aSrc.Length();
+
+ //copy the characters from aSrc into aDest, expanding to make them 16-bit characters
+ while(srcPtr < srcEnd)
+ {
+ *destPtr = (TUint16)*srcPtr;
+ destPtr++;
+ srcPtr++;
+ }
+
+ //set aDest's length to reflect the new contents
+ aDest.SetLength(2*aSrc.Length());
+ return KErrNone;
+ }
+
+/**
+ Get global code segment listing
+
+ @param aBuffer buffer to put data in
+ @param aDataSize on return will contain size of data
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer,
+ or one of the other system wide error codes
+ */
+TInt TListManager::GetGlobalCodeSegList(TDes8& aBuffer, TUint32& aDataSize) const
+ {
+ LOG_MSG("TListManager::GetGlobalCodeSegList()");
+
+ // Acquire code seg lock mutex
+ NKern::ThreadEnterCS();
+ DMutex* codeMutex = Kern::CodeSegLock();
+ Kern::MutexWait(*codeMutex);
+
+ //get global code seg list
+ SDblQue* codeSegList = Kern::CodeSegList();
+
+ //create a memory info object for use in the loop
+ TModuleMemoryInfo memoryInfo;
+
+ //iterate through the list
+ aDataSize = 0;
+ for (SDblQueLink* codeSegPtr= codeSegList->First(); codeSegPtr!=(SDblQueLink*) (codeSegList); codeSegPtr=codeSegPtr->iNext)
+ {
+ DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iLink);
+ //the code seg shouldn't be null as we're in critical section, ignore if it is null
+ if(codeSeg)
+ {
+ //get the memory info
+ TInt err = codeSeg->GetMemoryInfo(memoryInfo, NULL);
+ if(err != KErrNone)
+ {
+ // Release the codeseglock mutex again
+ Kern::MutexSignal(*codeMutex);
+ NKern::ThreadLeaveCS();
+
+ //there's been an error so return it
+ return err;
+ }
+ //calculate data values
+ TFileName fileName(codeSeg->iFileName->Ptr());
+ TBool isXip = (TBool)(codeSeg->iXIP);
+
+ //get the code seg type, can ignore error as have already checked codeSeg is not NULL
+ TCodeSegType type = EUnknownCodeSegType;
+ err = GetCodeSegType(codeSeg, type);
+ if(err != KErrNone)
+ {
+ LOG_MSG("TListManager::GetGlobalCodeSegList() : code seg is NULL");
+ }
+
+ TUint32 uid3 = codeSeg->iUids.iUid[2].iUid;
+ //append data to buffer
+ err = AppendCodeSegData(aBuffer, aDataSize, memoryInfo, isXip, type, fileName, uid3);
+ if(err != KErrNone)
+ {
+ // Release the codeseglock mutex again
+ Kern::MutexSignal(*codeMutex);
+ NKern::ThreadLeaveCS();
+
+ return KErrGeneral;
+ }
+ }
+ }
+
+ // Release the codeseglock mutex again
+ Kern::MutexSignal(*codeMutex);
+ NKern::ThreadLeaveCS();
+
+ return (aDataSize > aBuffer.MaxLength()) ? KErrTooBig : KErrNone;
+ }
+
+/**
+ Get code segment list for a thread
+
+ @param aBuffer buffer to store data in
+ @param aDataSize size of kernel's data
+ @param thread ID to get listing for
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer,
+ or one of the other system wide error codes
+ */
+TInt TListManager::GetCodeSegListForThread(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetThreadId) const
+ {
+ LOG_MSG("TListManager::GetCodeSegListForThread()");
+
+ TUint64 processId = 0;
+ NKern::ThreadEnterCS();
+ DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId);
+ if (thread)
+ {
+ processId = thread->iOwningProcess->iId;
+ thread->Close(NULL);
+ }
+ NKern::ThreadLeaveCS();
+
+ if (processId == 0)
+ {
+ return KErrArgument;
+ }
+
+ return GetCodeSegListForProcess(aBuffer, aDataSize, processId);
+ }
+
+/**
+ Get code segment list for a process
+
+ @param aBuffer buffer to store data in
+ @param aDataSize size of kernel's data
+ @param process ID to get listing for
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer,
+ or one of the other system wide error codes
+ */
+TInt TListManager::GetCodeSegListForProcess(TDes8& aBuffer, TUint32& aDataSize, const TUint64 aTargetProcessId) const
+ {
+ LOG_MSG("TListManager::GetCodeSegListForProcess()");
+
+ NKern::ThreadEnterCS();
+
+ //get the process
+ DProcess* process = DebugUtils::OpenProcessHandle(aTargetProcessId);
+
+ if(!process)
+ {
+ NKern::ThreadLeaveCS();
+ return KErrArgument;
+ }
+
+ // acquire code segment mutex
+ Kern::AccessCode();
+
+ //memory info object to use in loop
+ TModuleMemoryInfo memoryInfo;
+
+ //get code seg list
+ SDblQue queue;
+ process->TraverseCodeSegs(&queue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd);
+
+ //iterate through the list
+ aDataSize = 0;
+ TInt err = KErrNone;
+ for(SDblQueLink* codeSegPtr= queue.First(); codeSegPtr!=(SDblQueLink*) (&queue); codeSegPtr=codeSegPtr->iNext)
+ {
+ //get the code seg
+ DEpocCodeSeg* codeSeg = (DEpocCodeSeg*)_LOFF(codeSegPtr,DCodeSeg, iTempLink);
+
+ //the code seg shouldn't be null as we're in critical section, ignore if it is null
+ if(codeSeg)
+ {
+ err = codeSeg->GetMemoryInfo(memoryInfo, NULL);
+ if (err) break;
+
+ TFileName fileName(codeSeg->iFileName->Ptr());
+ TBool isXip = (TBool)(codeSeg->iXIP);
+
+ //get the code seg type, can ignore error as have already checked codeSeg is not NULL
+ TCodeSegType type = EUnknownCodeSegType;
+ err = GetCodeSegType(codeSeg, type);
+ if(err != KErrNone)
+ {
+ LOG_MSG("TListManager::GetCodeSegListForProcess() : code seg is NULL");
+ }
+
+ TUint32 uid3 = codeSeg->iUids.iUid[2].iUid;
+ //append data to buffer
+ err = AppendCodeSegData(aBuffer, aDataSize, memoryInfo, isXip, type, fileName, uid3);
+ if (err) break;
+ }
+ }
+
+ //un mark the code segs that we've iterated over
+ DCodeSeg::EmptyQueue(queue, DCodeSeg::EMarkDebug);
+
+ //release mutex
+ Kern::EndAccessCode();
+
+ process->Close(NULL);
+ NKern::ThreadLeaveCS();
+ return (aDataSize > aBuffer.MaxLength()) ? KErrTooBig : err;
+ }
+
+/**
+ Appends data to a specified buffer and puts the resulting size in aDataSize.
+ If the data won't fit then aDataSize is updated to reflect what the new length
+ would be.
+
+ @param aBuffer buffer to append data to
+ @param aDataSize will contain buffer size (or the size the buffer would be) on return
+ @param aMemoryInfo info to append to buffer
+ @param aIsXip boolean indicating whether the code segment is XIP
+ @param aFileName file name to append to buffer
+
+ @return KErrNone on success, or one of the other system wide error codes
+ */
+TInt TListManager::AppendCodeSegData(TDes8& aBuffer, TUint32& aDataSize, const TModuleMemoryInfo& aMemoryInfo, const TBool aIsXip, const TCodeSegType aCodeSegType, const TDesC8& aFileName, const TUint32 aUid3) const
+ {
+ //get some data elements to put in buffer
+ TUint16 fileNameLength = aFileName.Length();
+
+ //calculate the resultant size
+ aDataSize = Align4(aDataSize + sizeof(TCodeSegListEntry) + (2*fileNameLength) - sizeof(TUint16));
+ if(aDataSize <= aBuffer.MaxLength())
+ {
+ //Create a TCodeSegListEntry which references the buffer.
+ TCodeSegListEntry& entry = *(TCodeSegListEntry*)(aBuffer.Ptr() + aBuffer.Length());
+ entry.iCodeBase = aMemoryInfo.iCodeBase;
+ entry.iCodeSize = aMemoryInfo.iCodeSize;
+ entry.iConstDataSize = aMemoryInfo.iConstDataSize;
+ entry.iInitialisedDataBase = aMemoryInfo.iInitialisedDataBase;
+ entry.iInitialisedDataSize = aMemoryInfo.iInitialisedDataSize;
+ entry.iUninitialisedDataSize = aMemoryInfo.iUninitialisedDataSize;
+ entry.iIsXip = aIsXip;
+ entry.iCodeSegType = aCodeSegType;
+ entry.iNameLength = fileNameLength;
+ entry.iUid3 = aUid3;
+
+ //have to convert the stored name to 16 bit unicode
+ TPtr name = TPtr((TUint8*)&(entry.iName[0]), fileNameLength*2, fileNameLength*2);
+ TInt err = CopyAndExpandDes(aFileName, name);
+ if(err != KErrNone)
+ {
+ return KErrGeneral;
+ }
+
+ //increase length
+ aBuffer.SetLength(aDataSize);
+ }
+
+ return KErrNone;
+ }
+
+/**
+ Get global XIP libraries list. The ROM file system is searched for files in
+ z:\sys\bin. The files are filtered to only include library files which
+ correspond to the correct hardware variant.
+
+ In the rom, a directory is represented as a list of TRomEntrys, corresponding to
+ the files and directories in that directory. A TRomEntry corresponding to a file
+ contains a pointer to that file's location in the rom. If the TRomEntry
+ corresponds to a directory then it contains a pointer to that directory in the
+ ROM header. As such, from a pointer to the root directory of the z: drive, it is
+ possible to extract the directory contents for a particular directory (i.e. z:\sys\bin)
+ by recursively finding the subdirectories (i.e. find 'sys' in 'z:', then 'bin' in 'sys')
+ and then listing the contents of that directory.
+
+ @param aBuffer buffer to store data in
+ @param aDataSize size of kernel's data
+
+ @return KErrNone on success,
+ KErrTooBig if data won't fit in aBuffer,
+ or one of the other system wide error codes
+ */
+TInt TListManager::GetXipLibrariesList(TDes8& aBuffer, TUint32& aDataSize) const
+ {
+ LOG_MSG("TListManager::GetXipLibrariesList()");
+
+ // z:\sys\bin expressed as 16 bit unicode..
+ _LIT(KZSysBin, "z\0:\0\\\0s\0y\0s\0\\\0b\0i\0n\0\\\0");
+
+ //array to store pointers to directory entries in
+ RPointerArray<TRomEntry> entries;
+ //get the entries in KZSysBin
+ TInt err = GetDirectoryEntries(entries, KZSysBin());
+ if(KErrNone != err)
+ {
+ entries.Close();
+ return err;
+ }
+
+ aDataSize = 0;
+ for(TInt i=0; i<entries.Count(); i++)
+ {
+ //if the entry is XIP and it's not a directory then it's a candidate to add
+ if( (entries[i]->iAtt & KEntryAttXIP) && ! (entries[i]->iAtt & KEntryAttDir) )
+ {
+ //get a reference to the dll's header
+ const TRomImageHeader& header = *(const TRomImageHeader*)(entries[i]->iAddressLin);
+
+ //check that it's uid1 value corresponds to that for a library
+ if(header.iUid1 == KDynamicLibraryUidValue)
+ {
+ //get the current hardware variant
+ TSuperPage& superPage = Kern::SuperPage();
+ TUint variant = superPage.iActiveVariant;
+ TUint cpu = (variant >> 16) & 0xff;
+ TUint asic = (variant >> 24);
+
+ //check this dll is compatible with the current variant
+ if(THardwareVariant(header.iHardwareVariant).IsCompatibleWith(cpu,asic,variant))
+ {
+ const TInt fileNameLength16 = entries[i]->iNameLength;
+ const TInt fullNameLength16 = (KZSysBin().Length() / 2) + fileNameLength16;
+ aDataSize += Align4((2 * fullNameLength16) + sizeof(TXipLibraryListEntry) - sizeof(TUint16));
+
+ if(aDataSize <= aBuffer.MaxLength())
+ {
+ //Create a TXipLibraryListEntry which references the buffer.
+ TXipLibraryListEntry& libraryInfo = *(TXipLibraryListEntry*)(aBuffer.Ptr() + aBuffer.Length());
+
+ //add the data
+ libraryInfo.iCodeBase = header.iCodeAddress;
+ libraryInfo.iCodeSize = header.iTextSize;
+ libraryInfo.iConstDataSize = header.iCodeSize - header.iTextSize;
+ libraryInfo.iInitialisedDataBase = header.iDataBssLinearBase;
+ libraryInfo.iInitialisedDataSize = header.iDataSize;
+ libraryInfo.iUninitialisedDataSize = header.iBssSize;
+ libraryInfo.iNameLength = fullNameLength16;
+
+ //create a TPtr8 to contain the fully qualified name (i.e. z:\sys\bin\ prefixed)
+ TPtr8 name((TUint8*)&(libraryInfo.iName[0]), 0, 2 * fullNameLength16);
+ name.Append(KZSysBin());
+ name.Append(TPtr8((TUint8*)&(entries[i]->iName), 2 * fileNameLength16, 2 * fileNameLength16));
+
+ //increase the buffer's length to reflect the new data size
+ aBuffer.SetLength(aDataSize);
+ }
+ }
+ }
+ }
+ }
+ entries.Close();
+ return (aDataSize == aBuffer.Length()) ? KErrNone : KErrTooBig;
+ }
+
+/**
+Get the list of TRomEntry objects in the specified directory aDirectory
+
+@param aRomEntryArray array to store pointers to the TRomEntry objects in
+@param aDirectoryName directory to get contents of. The passed in string should be
+16 bit unicode and should begin with z:. Single backslashes should be used as delimiters
+rather than forward slashes and a terminating backslash is optional.
+For example: z:\sys\bin
+
+@return KErrNone on success, or one of the other system wide error codes
+*/
+TInt TListManager::GetDirectoryEntries(RPointerArray<TRomEntry>& aRomEntryArray, const TDesC& aDirectoryName) const
+ {
+ LOG_MSG("TListManager::GetDirectoryEntries()");
+
+ //definition in 16 bit unicode
+ _LIT(KForwardSlash, "/\0");
+
+ //if directory has forward slashes then exit
+ if(aDirectoryName.Find(KForwardSlash()) != KErrNotFound)
+ {
+ return KErrArgument;
+ }
+
+ //create an array to hold the folders in aDirectoryName
+ RArray<TPtr8> folders;
+
+ //split the directory up into its folders, i.e. z:\sys\bin is split into { 'z:', 'sys', 'bin' }
+ TInt err = SplitDirectoryName(aDirectoryName, folders);
+ if(KErrNone != err)
+ {
+ folders.Close();
+ return err;
+ }
+
+ if(folders.Count() == 0)
+ {
+ folders.Close();
+ //empty string passed in
+ return KErrArgument;
+ }
+
+ // z: as 16 bit unicode
+ _LIT(KZColon, "z\0:\0");
+ if(folders[0].CompareF(KZColon()) != 0)
+ {
+ //first argument must be z: otherwise not in rom
+ folders.Close();
+ return KErrArgument;
+ }
+ //remove z: from array
+ folders.Remove(0);
+ for(TInt i=0; i<folders.Count(); i++)
+ {
+ if(folders[i].Length() == 0)
+ {
+ // there were two backslashes in a row
+ folders.Close();
+ return KErrArgument;
+ }
+ }
+
+ //get a pointer to the start of the rom root directory list
+ TLinAddr romRootDirectoryList = Epoc::RomHeader().iRomRootDirectoryList;
+
+ //the first 4 bytes of the rom root directory list is a count of how many sections (rom roots) there are
+ TUint32 rootDirectoryCount = (TUint32)*(TLinAddr*)romRootDirectoryList;
+
+ //rootDirectoryPointer will be shifted through the rom root directory list and will contain pointers to the sections in the rom
+ TLinAddr rootDirectoryPointer = romRootDirectoryList;
+ for(TInt i=0; i<rootDirectoryCount; i++)
+ {
+ //the address of the section is stored in the second four bytes of the 8 byte pair reserved for each section
+ rootDirectoryPointer += 8;
+
+ //romRoot contains the address of the root of the section
+ TLinAddr romRoot = *(TLinAddr*)rootDirectoryPointer;
+
+ //append the directory entries from romRoot's z:\sys\bin subdirectory
+ TInt err = GetDirectoryEntries(aRomEntryArray, folders, romRoot);
+ if(KErrNone != err)
+ {
+ folders.Close();
+ return err;
+ }
+ }
+ folders.Close();
+ return KErrNone;
+ }
+
+/**
+ Recursively finds the subdirectories in aArray and stores references to the
+ entries in the most derived subdirectory in aRomEntryArray
+
+ @param aRomEntryArray on return will contain the entries in the directory corresponding to aArray
+ @param aArray an array containing the directory to get the entries for, i.e. { 'sys', 'bin' }
+ @param aAddress address in rom to being searching from
+
+ @param KErrNone on success, or one of the other system wide error codes
+*/
+TInt TListManager::GetDirectoryEntries(RPointerArray<TRomEntry>& aRomEntryArray, RArray<TPtr8>& aArray, TLinAddr& aAddress) const
+ {
+ LOG_MSG2("TListManager::GetDirectoryEntries() aAddress: 0x%08x", aAddress);
+
+ //find the next subdirectory and store its address in aAddress, return error if we can't find it
+ TInt err = FindDirectory(aArray[0], aAddress);
+ if(err != KErrNone)
+ {
+ return err;
+ }
+
+ //if this is the most derived sub-directory (i.e. the bin of z:\sys\bin) then get the dir contents
+ if(aArray.Count() == 1)
+ {
+ return GetDirectoryContents(aRomEntryArray, aAddress);
+ }
+ else
+ {
+ //get the next subdirectory's contents
+ aArray.Remove(0);
+ return GetDirectoryEntries(aRomEntryArray, aArray, aAddress);
+ }
+ }
+
+/**
+Return the entries of a directory in the rom
+
+@param aRomEntryArray array to store the entries in
+@param aAddress address of a directory block in the rom
+*/
+TInt TListManager::GetDirectoryContents(RPointerArray<TRomEntry>& aRomEntryArray, const TLinAddr aAddress) const
+ {
+ LOG_MSG("TListManager::GetDirectoryContents()");
+
+ TLinAddr address = aAddress;
+
+ //get the size in bytes of the block of rom to iterate over
+ const TUint32 sizeInBytes = *(TUint32*)aAddress;
+
+ //get address of first TRomEntry
+ const TLinAddr initialAddress = aAddress + sizeof(TUint32);
+
+ //get pointer to subdir count
+ address = initialAddress + sizeInBytes;
+
+ //the upper two bytes of this entry contain the number of files in this directory, and the lower two bytes
+ //contains the number of subdirectories in this directory
+ TUint32 filesAndDirectories = *(TUint32*)address;
+
+ //get number of subdirectories in this directory
+ const TUint16 subDirCount = filesAndDirectories & 0xFFFF;
+
+ //get the number of files in this dir
+ const TUint16 filesCount = filesAndDirectories >> 16;
+
+ //get total number of entries in dir
+ const TUint numDirectoryEntries = subDirCount + filesCount;
+
+ //set address to start of first entry
+ address = initialAddress;
+
+ for(TInt i=0; i<numDirectoryEntries; i++)
+ {
+ TRomEntry* romEntry = (TRomEntry*)address;
+
+ //store the entry
+ TInt err = aRomEntryArray.Append(romEntry);
+ if(KErrNone != err)
+ {
+ return err;
+ }
+
+ //length of the name of the rom entry
+ TInt nameLength = romEntry->iNameLength;
+
+ //get the size of the entry including the name
+ TUint32 romEntrySize = sizeof(TRomEntry) - sizeof(romEntry->iName) + (2 * nameLength);
+ //adjust the address to the next entry
+ address += Align4(romEntrySize);
+ }
+ return KErrNone;
+ }
+
+/**
+ Finds the subdirectory with name aDirectory in the directory at aAddress
+
+ @param aDirectory name of subdirectory to search for (i.e. 'bin')
+ @param aAddress address in rom of containing directory (i.e. address of 'sys' directory)
+
+ @param KErrNone if aDirectory could be found in aAddress, KErrNotFound if it could not be found
+ */
+TInt TListManager::FindDirectory(const TDesC& aDirectory, TLinAddr& aAddress) const
+ {
+ LOG_MSG3("TListManager::FindDirectory() aDirectory: %S, aAddress: 0x%08x", &aDirectory, aAddress);
+
+ //get the directory's contents
+ RPointerArray<TRomEntry> dirContents;
+ TInt err = GetDirectoryContents(dirContents, aAddress);
+ if(KErrNone != err)
+ {
+ dirContents.Close();
+ return err;
+ }
+ for(TInt i=0; i<dirContents.Count(); i++)
+ {
+ //create a reference to the TRomEntry in the rom to access its attributes
+ TRomEntry& romEntry = *(dirContents[i]);
+ if(romEntry.iAtt & KEntryAttDir)
+ {
+ // this entry's a directory so check if it matches aDirectory
+ const TInt nameLength = romEntry.iNameLength;
+ TPtr8 name((TUint8*)&(romEntry.iName), nameLength * 2, nameLength * 2);
+ if(0 == aDirectory.CompareF(name))
+ {
+ // names matched so get the address of this directory's contents
+ aAddress = romEntry.iAddressLin;
+ dirContents.Close();
+ return KErrNone;
+ }
+ }
+ }
+ dirContents.Close();
+ //couldn't find it so return error
+ return KErrNotFound;
+ }
+
+/**
+ Helper function to get code seg type.
+
+ @param aCodeSeg code seg to get type of
+ @param aType will contain type on return
+
+ @return KErrNone on success, KErrNotFound if aCodeSeg is NULL
+ */
+TInt TListManager::GetCodeSegType(const DCodeSeg* aCodeSeg, TCodeSegType& aType) const
+ {
+ if(!aCodeSeg)
+ {
+ return KErrNotFound;
+ }
+
+ if(aCodeSeg->IsExe())
+ {
+ aType = EExeCodeSegType;
+ return KErrNone;
+ }
+
+ if(aCodeSeg->IsDll())
+ {
+ aType = EDllCodeSegType;
+ return KErrNone;
+ }
+
+ aType = EUnknownCodeSegType;
+ return KErrNone;
+ }
+
+
+/**
+ Split a directory name into its subdirectories, using a 16-bit backslash ('\\\0') as a delimiter.
+ For example z:\sys\bin would be split into { 'z:', 'sys', 'bin' }
+
+ @param aDirectoryName directory name to split into subdirectories
+ @param aSubDirectories array to store the subdirectories in
+ */
+TInt TListManager::SplitDirectoryName(const TDesC& aDirectoryName, RArray<TPtr8>& aSubDirectories) const
+ {
+ //definition in 16 bit unicode
+ _LIT(KBackSlash, "\\\0");
+
+ //split the directory up into its folders, i.e. z:\sys\bin is split into
+ TPtr8 string((TUint8*)aDirectoryName.Ptr(), aDirectoryName.Length(), aDirectoryName.Length());
+ while(string.Ptr() < aDirectoryName.Ptr() + aDirectoryName.Length())
+ {
+ TInt offset = string.Find(KBackSlash());
+ if(offset == KErrNotFound)
+ {
+ //reached the end of the string
+ offset = string.Length();
+ }
+ //adjustedOffset takes account of the end of the string case
+ TInt adjustedOffset = (offset == string.Length()) ? offset : offset + KBackSlash().Length();
+ //add sub-folder name
+ TInt err = aSubDirectories.Append(TPtr8((TUint8*)string.Ptr(), offset, offset));
+ if(KErrNone != err)
+ {
+ return err;
+ }
+ //remove the sub-folder name and continue
+ string.Set((TUint8*)string.Ptr() + adjustedOffset, string.Length() - adjustedOffset, string.Length() - adjustedOffset);
+ }
+ return KErrNone;
+ }
+
+
+