Added --codeseg option to ps to list the codesegs loaded into a given process.
authorTom Sutcliffe <thomas.sutcliffe@accenture.com>
Mon, 26 Jul 2010 17:19:00 +0100
changeset 7 184a1eb85cf2
parent 6 96d581d2147d
child 11 8a3293f6c06f
Added --codeseg option to ps to list the codesegs loaded into a given process. Also tweaked some docs, added support to date to handle kernel TTimeK (epoc=0AD)
core/builtins/date.cif
core/builtins/kill.cpp
core/builtins/ps.cif
core/builtins/ps.cpp
core/builtins/ps.h
core/src/commands.cpp
core/src/commands.h
documentation/cif_syntax.pod
documentation/common_mmh.pod
libraries/memoryaccess/MemoryAccess.cpp
libraries/memoryaccess/memoryaccess.h
libraries/qr3/src/KernLbxModel.cpp
--- a/core/builtins/date.cif	Fri Jul 09 10:11:55 2010 +0100
+++ b/core/builtins/date.cif	Mon Jul 26 17:19:00 2010 +0100
@@ -67,7 +67,7 @@
 
 ==option bool j just-display
 
-Rather than going ahead and setting the specified time and date, do a dry run and just displays it in human readable form. Must be used in conjunction with C<--set>. In effect it is an option to check that the set string has been parsed correctly before actually making the change.
+Rather than going ahead and setting the specified time and date, do a dry run and just displays it in human readable form. Must be used in conjunction with C<--set> or <--raw-set>. In effect it is an option to check that the set string has been parsed correctly before actually making the change.
 
 ==option int64 R raw-set
 
@@ -77,6 +77,10 @@
 
 Display the date in timestamp format C<YYYYMMDD-HHMM.SS> suitable for use in a file name.
 
+==option bool k kern
+
+Only applicable with C<--raw> and/or C<--raw-set>. Instead of using 2000AD as the epoc, use 0AD nominal Gregorian, the kernel's internal native time format.
+
 ==copyright
 
 Copyright (c) 2006-2010 Accenture. All rights reserved.
--- a/core/builtins/kill.cpp	Fri Jul 09 10:11:55 2010 +0100
+++ b/core/builtins/kill.cpp	Mon Jul 26 17:19:00 2010 +0100
@@ -123,13 +123,16 @@
 			PrintWarning(_L("Couldn't open %S (err=%d)"), &fullName);
 			}
 		}
-	if (numFound == 0)
+	if (!iAll)
 		{
-		LeaveIfErr(KErrNotFound, _L("No matches for pattern \"%S\", or all matches are zombies"), &aPattern);
-		}
-	else if (numFound > 1 && !iAll)
-		{
-		PrintWarning(_L("%d further matches for pattern \"%S\" found, be more specific or use --all option"), numFound-1, &aPattern);
+		if (numFound == 0)
+			{
+			LeaveIfErr(KErrNotFound, _L("No matches for pattern \"%S\", or all matches are zombies"), &aPattern);
+			}
+		else if (numFound > 1)
+			{
+			PrintWarning(_L("%d further matches for pattern \"%S\" found, be more specific or use --all option"), numFound-1, &aPattern);
+			}
 		}
 	}
 
--- a/core/builtins/ps.cif	Fri Jul 09 10:11:55 2010 +0100
+++ b/core/builtins/ps.cif	Mon Jul 26 17:19:00 2010 +0100
@@ -96,6 +96,10 @@
 
 Print C<System>, C<Protected> and C<LoadedFromRam> flag values. Only available on EKA1.
 
+==option bool C codesegs
+
+Print the code segments loaded into the process.
+
 ==copyright
 
 Copyright (c) 2005-2010 Accenture. All rights reserved.
--- a/core/builtins/ps.cpp	Fri Jul 09 10:11:55 2010 +0100
+++ b/core/builtins/ps.cpp	Mon Jul 26 17:19:00 2010 +0100
@@ -169,6 +169,11 @@
 
 	_LIT(KOptAddresses, "addresses");
 	aOptions.AppendBoolL(iAddresses, KOptAddresses);
+
+#ifdef FSHELL_MEMORY_ACCESS_SUPPORT
+	_LIT(KOptCodeSegs, "codesegs");
+	aOptions.AppendBoolL(iPrintCodesegs, KOptCodeSegs);
+#endif
 	}
 
 #if defined(__WINS__) && !defined(EKA2)
@@ -317,6 +322,10 @@
 			iFormatter->AppendFormatL(_L("\tAddress: 0x%08x\r\n"), objectInfo.iAddressOfKernelObject);
 			}
 		}
+	if (iPrintCodesegs && iMemoryAccess.Handle())
+		{
+		PrintCodeSegsL(aProcess);
+		}
 #endif // FSHELL_MEMORY_ACCESS_SUPPORT
 	
 	if (iHandleCount)
@@ -542,6 +551,30 @@
 		}
 	}
 
+void ReleaseCodesegMutex(TAny* aMemAccess)
+	{
+	static_cast<RMemoryAccess*>(aMemAccess)->ReleaseCodeSegMutex();
+	}
+
+void CCmdPs::PrintCodeSegsL(RProcess& aProcess)
+	{
+	TInt count = iMemoryAccess.AcquireCodeSegMutexAndFilterCodesegsForProcess(aProcess.Id());
+	LeaveIfErr(count, _L("Couldn't acquire codeseg mutex"));
+	CleanupStack::PushL(TCleanupItem(&ReleaseCodesegMutex, &iMemoryAccess));
+
+	iFormatter->AppendFormatL(_L("\t%d code segments:\r\n"), count);
+
+	TCodeSegKernelInfo codeSegInfo;
+	TPckg<TCodeSegKernelInfo> pkg(codeSegInfo);
+	while (iMemoryAccess.GetNextCodeSegInfo(pkg) == KErrNone)
+		{
+		// Reuse iChunkName, I'm sure it doesn't mind
+		iChunkName.Copy(codeSegInfo.iFileName);
+		iFormatter->AppendFormatL(_L("\t\t%S\r\n"), &iChunkName);
+		}
+	CleanupStack::PopAndDestroy(); // ReleaseCodesegMutex
+	}
+
 #ifdef EXE_BUILD
 EXE_BOILER_PLATE(CCmdPs)
 #endif
--- a/core/builtins/ps.h	Fri Jul 09 10:11:55 2010 +0100
+++ b/core/builtins/ps.h	Mon Jul 26 17:19:00 2010 +0100
@@ -42,6 +42,7 @@
 	void PrintCpuTimeL(RThread& aThread, const TDesC& aThreadName);
 	void PrintChunkInfoL(const TDesC& aProcessName);
 	void PrintSizeL(const TDesC& aCaption, TInt aSize);
+	void PrintCodeSegsL(RProcess& aProcess);
 private:
 	TUint iProcessId;
 	HBufC* iMatch;
@@ -55,6 +56,7 @@
 	TBool iPrintCommandLine;
 	TBool iPrintFlags;
 	TBool iPrintMemoryInfo;
+	TBool iPrintCodesegs;
 	TBool iVerbose;
 	TBool iHuman;
 	TBool iExcludeDead;
--- a/core/src/commands.cpp	Fri Jul 09 10:11:55 2010 +0100
+++ b/core/src/commands.cpp	Mon Jul 26 17:19:00 2010 +0100
@@ -2335,6 +2335,10 @@
 // CCmdDate.
 //
 
+// Appearently kernel reckons to 365.2485 days per year between 0AD (nominal gregorian) and 2000AD, which comes to 730497 days in total.
+// timeanddate.com agrees once you factor in Julian->Gregorian and assuming 0AD wasn't a leap year (it refuses to allow you to directly enter 0AD nominal Gregorian)
+const TInt64 KY2kInMicroSeconds = 730497 * 24 * 60 * (TInt64)(60 * 1000 * 1000);
+
 CCommandBase* CCmdDate::NewLC()
 	{
 	CCmdDate* self = new(ELeave) CCmdDate();
@@ -2356,7 +2360,9 @@
 	{
 	if (iRaw)
 		{
-		Printf(_L("%Ld\r\n"), aTime.Int64());
+		TInt64 time = aTime.Int64();
+		if (iUseKernelFormat) time += KY2kInMicroSeconds;
+		Printf(_L("%Ld\r\n"), time);
 		}
 	else if (iUseTimestampFormat)
 		{
@@ -2412,6 +2418,7 @@
 	else
 		{
 		_LIT(KSettingError, "Cannot set the time");
+		if (iUseKernelFormat) iRawTimeToSet -= KY2kInMicroSeconds;
 		TTime time(iRawTimeToSet);
 		if (iDateToSet)
 			{
@@ -2469,7 +2476,8 @@
 	_LIT(KCmdDateOptRaw, "raw");
 	_LIT(KCmdDateOptJustDisplay, "just-display");
 	_LIT(KCmdDateOptSetRaw, "raw-set");
-	_LIT(KCmdDataOptTimestamp, "timestamp");
+	_LIT(KCmdDateOptTimestamp, "timestamp");
+	_LIT(KCmdDateOptKern, "kern");
 
 	aOptions.AppendBoolL(iUniversalTime, KCmdDateOptUniversal);
 	aOptions.AppendStringL(iDateToSet, KCmdDateOptSet);
@@ -2480,7 +2488,8 @@
 	aOptions.AppendBoolL(iRaw, KCmdDateOptRaw);
 	aOptions.AppendBoolL(iJustDisplay, KCmdDateOptJustDisplay);
 	aOptions.AppendIntL(iRawTimeToSet, KCmdDateOptSetRaw);
-	aOptions.AppendBoolL(iUseTimestampFormat, KCmdDataOptTimestamp);
+	aOptions.AppendBoolL(iUseTimestampFormat, KCmdDateOptTimestamp);
+	aOptions.AppendBoolL(iUseKernelFormat, KCmdDateOptKern);
 	}
 
 
--- a/core/src/commands.h	Fri Jul 09 10:11:55 2010 +0100
+++ b/core/src/commands.h	Mon Jul 26 17:19:00 2010 +0100
@@ -555,6 +555,7 @@
 	TBool iJustDisplay;
 	TInt64 iRawTimeToSet;
 	TBool iUseTimestampFormat;
+	TBool iUseKernelFormat;
 	};
 
 
--- a/documentation/cif_syntax.pod	Fri Jul 09 10:11:55 2010 +0100
+++ b/documentation/cif_syntax.pod	Mon Jul 26 17:19:00 2010 +0100
@@ -16,7 +16,7 @@
 
 =head2 Introduction
 
-Command Info Files (CIFs) can be used to define the interface and documentation for fshell commands that are implemented using CCommandBase. Where previously details of arguments and options etc. were specified in C++ source code, the majority of this information can now be defined in a CIF, which is a plain text file. The format of CIFs is similar to POD (Perl's documentation source format), but with an additional set of key-words that relate to the specifics of command interfaces.
+Command Info Files (CIFs) can be used to define the interface and documentation for fshell commands that are implemented using CCommandBase. Where previously details of arguments and options etc. were specified in C++ source code, the majority of this information can now be defined in a CIF, which is a plain text file. The format of CIFs is similar to POD (Perl's documentation source format), but with an additional set of keywords that relate to the specifics of command interfaces.
 
 CIF files for fshell commands live in F<\resource\cif\fshell> and should be named I<commandname>.cif where I<commandname> is the same as what is returned by the command's Name() function.
 
@@ -72,7 +72,7 @@
 
 =item *
 
-Only the final argument is allowed to have the C<last> attribute. It indicates that further arguments are allowed without needing to quote them and will be merged into this argument. C<last> may not be combined with C<multiple>. If a string provided for a C<last> argument naturally (i.e. as a result of normal string quote and escape handling) forms a single argument and consumes the whole of the remainder of the command line, the resulting single argument will be used as is. Otherwise, the string will be used without any quote or escape handling. Here are some example (using fshell's 'time' command, which takes a single argument that uses the C<last> attribute):
+Only the final argument is allowed to have the C<last> attribute. It indicates that further arguments are allowed without needing to quote them and will be merged into this argument. C<last> may not be combined with C<multiple>. If a string provided for a C<last> argument naturally (i.e. as a result of normal string quote and escape handling) forms a single argument and consumes the whole of the remainder of the command line, the resulting single argument will be used as is. Otherwise, the string will be used without any quote or escape handling. Here are some examples (using fshell's 'time' command, which takes a single argument that uses the C<last> attribute):
 
       Input command-line            Argument receive by the 'time' command
 
@@ -167,7 +167,7 @@
     ...
     void CMyCommand::ArgumentsL(RCommandArgumentList& aArguments)
         {
-        aArguments.AppendEnum((TInt&)iOperation, _L("operation"));
+        aArguments.AppendEnumL((TInt&)iOperation, _L("operation"));
         }
 
 The CIF file would therefore contain:
--- a/documentation/common_mmh.pod	Fri Jul 09 10:11:55 2010 +0100
+++ b/documentation/common_mmh.pod	Mon Jul 26 17:19:00 2010 +0100
@@ -12,7 +12,7 @@
 
 =head1 common.mmh and platform.mmh Syntax
 
-The fshell build system uses a number of macros to control what should be built and how. These are defined in F<fshell/build/common/common.mmh> and F<fshell/platforms/E<lt>PLATFORME<gt>/platform.mmh>. Each platform defines the things it does and doesn't support in its platform.mmh. common.mmh takes these and defines some derived macros. This system allows fshell to be built in a large number of configurations, ranging from minimal base textshell on Symbian OS v9.1 to full GUI on the latest Symbian Foundation codeline.
+The fshell build system uses a number of macros to control what should be built and how. These are defined in F<fshell/build/common/common.mmh> and F<fshell/build/E<lt>PLATFORME<gt>/platform.mmh>. Each platform defines the things it does and doesn't support in its platform.mmh. common.mmh takes these and defines some derived macros. This system allows fshell to be built in a large number of configurations, ranging from minimal base textshell on Symbian OS v9.1 to full GUI on the latest Symbian Foundation codeline.
 
 Any code wishing to use the fshell conditional system should C<< #include <fshell/common.mmh> >> and use the macros below and/or the ones defined in common.mmh to decide how to behave. Below follows the complete list of things that the platform.mmh can define. This isn't the complete list of all the macros that can be I<used>, for that see common.mmh directly. common.mmh can be included anywhere that the preprocessor is used - eg in source code, MMP files, RSS files or bld.infs.
 
@@ -24,7 +24,7 @@
 
 =item FSHELL_[NO_]BTRACE_SUPPORT
 
-BTrace (including timestamp2) supported in kernel.
+BTrace (including timestamp2) supported in kernel. Everything except legacy v9.1-based platforms support btrace.
 
 =item FSHELL_[NO_]PIPS_SUPPORT
 
@@ -132,7 +132,7 @@
 
 =item FSHELL_CORE_SUPPORT_LICENSE
 
-Build platform specific license support into fshell. Note, the platform must export F<\epoc32\build\fshell\core\generated\license.cpp> that provides the implementation of the interface defined in F<\fshell\core\src\license.h>.
+Build platform specific license support into fshell. Note, the platform must export F<\epoc32\build\fshell\core\generated\license.cpp> that provides the implementation of the interface defined in F<\fshell\core\src\license.h>. Obsolete.
 
 =item FSHELL_[NO_]SAMPLINGPROFILER_SUPPORT
 
@@ -231,6 +231,7 @@
 An example platform.mmh is included below. This is for an imaginary platform based on the S^4 release, that is text-only but supports most other things. Generally the older and/or more restricted the platform is, the more C<FSHELL_NO_...> macros you have to define.
 
 	// platform.mmh for the imaginary Mythic platform
+	// This would belong in \fshell\build\mythic\platform.mmh
 
 	#ifndef FSHELL_PLATFORM_MMH
 	#define FSHELL_PLATFORM_MMH
--- a/libraries/memoryaccess/MemoryAccess.cpp	Fri Jul 09 10:11:55 2010 +0100
+++ b/libraries/memoryaccess/MemoryAccess.cpp	Mon Jul 26 17:19:00 2010 +0100
@@ -15,6 +15,10 @@
 #include <kernel.h>
 #include <kern_priv.h>
 
+#ifdef __EPOC32__
+#include <memmodel/epoc/plat_priv.h> // For DEpocCodeSeg
+#endif
+
 #include <fshell/common.mmh>
 
 #ifdef FSHELL_DOBJECTIX_SUPPORT
@@ -119,6 +123,7 @@
 	TInt GetObjectAddresses(TObjectType aObjectType, const TDesC8& aOwningProcess, TDes8* aKernelInfoBuf);
 	TInt GetChunkAddresses(TUint aControllingProcessId, TDes8* aKernelInfoBuf);
 	TInt AcquireCodeSegMutex();
+	TInt AcquireCodeSegMutexAndFilterCodesegsForProcess(TUint aProcessId);
 	TInt ReleaseCodeSegMutex();
 	TInt GetNextCodeSegInfo(TDes8* aCodeSegInfoBuf);
 	TInt ObjectDie(TObjectKillParamsBuf& aObjectKillParamsBuf);
@@ -173,12 +178,19 @@
 private:
 	DThread* iClient;
 	TBool iLocks[ENumObjectTypes];
-	TBool iCodeSegLock;
-	DCodeSeg* iCurrentCodeSeg;
+	enum TCodesegLogStatus
+		{
+		ENotHeld,
+		EHeld,
+		EHeldAndTraversing,
+		} iCodeSegLock;
+	SDblQueLink* iCurrentCodeSegLink;
 	DThreadChangeHandler* iEventHandler;
 	DPropertyAccess* iPropertyAccess;
 	TAny* iClientBreakpointNotifyPkg;
 	TRequestStatus* iClientBreakpointNotifyStatus;
+
+	SDblQue iFilteredCodesegQue;
 	};
 
 
@@ -563,6 +575,8 @@
 		}
     case RMemoryAccess::EControlAcquireCodeSegMutex:
     	return AcquireCodeSegMutex();
+    case RMemoryAccess::EControlAcquireCodeSegMutexAndFilterCodesegsForProcess:
+		return AcquireCodeSegMutexAndFilterCodesegsForProcess((TUint)a1);
     case RMemoryAccess::EControlReleaseCodeSegMutex:
     	return ReleaseCodeSegMutex();
     case RMemoryAccess::EControlGetNextCodeSegInfo:
@@ -1201,7 +1215,7 @@
 		if (codeSegLock)
 			{
 			Kern::MutexWait(*codeSegLock);
-			iCodeSegLock = ETrue;
+			iCodeSegLock = EHeld;
 			}
 		else
 			{
@@ -1212,6 +1226,34 @@
 	return err;    	
 	}
 
+TInt DMemoryAccess::AcquireCodeSegMutexAndFilterCodesegsForProcess(TUint aProcessId)
+	{
+	TInt err = KErrNone;
+	NKern::ThreadEnterCS();
+	Kern::Containers()[EProcess]->Wait();
+	DProcess* process = Kern::ProcessFromId(aProcessId);
+	if (process == NULL || process->Open() != KErrNone)
+		{
+		err = KErrNotFound;
+		}
+	Kern::Containers()[EProcess]->Signal();
+
+	if (!err)
+		{
+		err = AcquireCodeSegMutex();
+		}
+	if (!err)
+		{
+		iCodeSegLock = EHeldAndTraversing;
+		TInt numTraversed = process->TraverseCodeSegs(&iFilteredCodesegQue, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd);
+		err = numTraversed;
+		}
+
+	if (process) process->Close(NULL);
+	NKern::ThreadLeaveCS();
+	return err;
+	}
+
 TInt DMemoryAccess::GetObjectAddresses(TObjectType aObjectType, const TDesC8& aOwningProcess, TDes8* aKernelInfoBuf)
 	{
 	DObjectCon* const * cons = Kern::Containers();
@@ -1325,30 +1367,20 @@
 TInt DMemoryAccess::ReleaseCodeSegMutex()
 	{
 	// Kern::Printf("[DMemoryAccess] ::ReleaseCodeSegMutex");
-	TInt err=KErrNone;
-
-	if (!iCodeSegLock)
-		{ //Check the lock on code segs is not currently held
-		Kern::ThreadKill(iClient, EExitPanic, EMemAccessMutexNotHeld, KMemAccessPanicCategory);
-		err = KErrAbort;
+	if (iCodeSegLock == ENotHeld)
+		{
+		return KErrNotReady;
 		}
 
-	DMutex* const codeSegLock = Kern::CodeSegLock();
-
-	if (!err)
+	if (iCodeSegLock == EHeldAndTraversing)
 		{
-		if (codeSegLock)
-			{
-			Kern::MutexSignal(*codeSegLock);
-			iCodeSegLock = EFalse;
-			}
-		else
-			{
-			err = KErrNotFound;
-			}
+		DCodeSeg::EmptyQueue(iFilteredCodesegQue, DCodeSeg::EMarkDebug);
 		}
+
+	Kern::MutexSignal(*Kern::CodeSegLock());
+	iCodeSegLock = ENotHeld;
 	// Kern::Printf("[DMemoryAccess] ::ReleaseCodeSegMutex returning %d", err);
-	return err;    	
+	return KErrNone;
 	}
 
 
@@ -1357,28 +1389,37 @@
 	// Kern::Printf("[DMemoryAccess] ::GetNextCodeSegInfo");
 	TInt err = KErrNone;
 	
-	SDblQue* p = Kern::CodeSegList();
-	SDblQueLink* anchor=&p->iA;
-
-	if (!iCurrentCodeSeg)
+	SDblQue* p;
+	if (iCodeSegLock == EHeldAndTraversing)
 		{
-		iCurrentCodeSeg = _LOFF(anchor->iNext, DCodeSeg, iLink);
-		}
-
-	if (iCurrentCodeSeg->iLink.iNext != anchor)
-		{
-		iCurrentCodeSeg = _LOFF(iCurrentCodeSeg->iLink.iNext, DCodeSeg, iLink);
+		p = &iFilteredCodesegQue;
 		}
 	else
 		{
-		iCurrentCodeSeg = NULL;
+		p = Kern::CodeSegList();
+		}
+	SDblQueLink* anchor=&p->iA;
+
+	if (!iCurrentCodeSegLink)
+		{
+		iCurrentCodeSegLink = anchor;
+		}
+
+	if (iCurrentCodeSegLink->iNext != anchor)
+		{
+		iCurrentCodeSegLink = iCurrentCodeSegLink->iNext;
+		}
+	else
+		{
+		iCurrentCodeSegLink = NULL;
 		err = KErrNotFound;
 		}
 		
 	if (!err)
 		{
 		//TCodeSegKernelInfoBuf* localInfoBuf = new TCodeSegKernelInfoBuf;
-		TPckgBuf<TTomsciCodeSegKernelInfo>* localInfoBuf = new TPckgBuf<TTomsciCodeSegKernelInfo>;
+		DCodeSeg* currentCodeseg = (iCodeSegLock == EHeldAndTraversing) ? _LOFF(iCurrentCodeSegLink, DCodeSeg, iTempLink) : _LOFF(iCurrentCodeSegLink, DCodeSeg, iLink);
+		TPckgBuf<TCodeSegKernelInfo>* localInfoBuf = new TPckgBuf<TCodeSegKernelInfo>;
 		if (!localInfoBuf)
 			{
 			err = KErrNoMemory;
@@ -1386,14 +1427,21 @@
 		else
 			{	
 			//Get the code seg info
-			(*localInfoBuf)().iRunAddress = iCurrentCodeSeg->iRunAddress;
-			(*localInfoBuf)().iSize = iCurrentCodeSeg->iSize;
-			(*localInfoBuf)().iFileName = iCurrentCodeSeg->iFileName->Right((*localInfoBuf)().iFileName.MaxLength());
-			(*localInfoBuf)().iAccessCount = iCurrentCodeSeg->iAccessCount;
-			(*localInfoBuf)().iAddressOfKernelObject = (TUint8*)iCurrentCodeSeg;
-			(*localInfoBuf)().iName = iCurrentCodeSeg->iRootName;
-			(*localInfoBuf)().iDepCount = iCurrentCodeSeg->iDepCount;
-
+			(*localInfoBuf)().iRunAddress = currentCodeseg->iRunAddress;
+			(*localInfoBuf)().iSize = currentCodeseg->iSize;
+			if (currentCodeseg->iFileName)
+				{
+				(*localInfoBuf)().iFileName = currentCodeseg->iFileName->Right((*localInfoBuf)().iFileName.MaxLength());
+				}
+			(*localInfoBuf)().iAccessCount = currentCodeseg->iAccessCount;
+			(*localInfoBuf)().iAddressOfKernelObject = (TUint8*)currentCodeseg;
+			(*localInfoBuf)().iName = currentCodeseg->iRootName;
+			(*localInfoBuf)().iDepCount = currentCodeseg->iDepCount;
+#ifdef __EPOC32__
+			(*localInfoBuf)().iXip = ((DEpocCodeSeg*)currentCodeseg)->iXIP;
+#else
+			(*localInfoBuf)().iXip = EFalse;
+#endif
 			//Copy the local info buffer into the client's address space
 		    err = Kern::ThreadDesWrite(iClient, aCodeSegInfoBuf, *localInfoBuf, 0, KTruncateToMaxLength, NULL);
 			delete localInfoBuf;
--- a/libraries/memoryaccess/memoryaccess.h	Fri Jul 09 10:11:55 2010 +0100
+++ b/libraries/memoryaccess/memoryaccess.h	Mon Jul 26 17:19:00 2010 +0100
@@ -305,23 +305,26 @@
 	};
 typedef TPckgBuf<TCondVarKernelInfo> TCondVarKernelInfoBuf;	 
 
-class TCodeSegKernelInfo
+class TCodeSegKernelInfoBase
 	{
 public:
 	TUint32 iRunAddress;
 	TInt iSize;
 	TFileName8 iFileName;
 	};
-typedef TPckgBuf<TCodeSegKernelInfo> TCodeSegKernelInfoBuf;	 
 
-class TTomsciCodeSegKernelInfo : public TCodeSegKernelInfo
+// We don't really need a base class, it's just for BC reasons 
+class TCodeSegKernelInfo : public TCodeSegKernelInfoBase
 	{
 public:
 	TUint8* iAddressOfKernelObject;
 	TFullName8 iName;
 	TInt iAccessCount;
 	TInt iDepCount;
+	TBool iXip;
 	};
+typedef TPckgBuf<TCodeSegKernelInfo> TCodeSegKernelInfoBuf;	 
+
 
 class TProp
 	{
@@ -451,6 +454,7 @@
 		EControlPropertyNotify,
 		EControlPropertyNotifyCancel,
 		EControlSubscribeToProperty,
+		EControlAcquireCodeSegMutexAndFilterCodesegsForProcess,
 		ENumRequests,  // Add new commands above this line
         };
 public:
@@ -492,6 +496,7 @@
 	TInt GetObjectInfoByHandle (TObjectType aObjectType, TInt aThreadId, TInt aObjectHandle, TDes8& aObjectInfoBuf);
 	//Wait on the kernel's code seg mutex
 	TInt AcquireCodeSegMutex();
+	TInt AcquireCodeSegMutexAndFilterCodesegsForProcess(TUint aProcessId);
 	//Signal the kernel's code seg mutex
 	TInt ReleaseCodeSegMutex();
 	//Get info about the next code seg.  Call repeatedly to iterate all code segs.  Call AcquireCodeSegMutex before calling.
@@ -683,6 +688,8 @@
 	}
 inline TInt RMemoryAccess::AcquireCodeSegMutex()
 	{	return DoControl(EControlAcquireCodeSegMutex, NULL, NULL);		}
+inline TInt RMemoryAccess::AcquireCodeSegMutexAndFilterCodesegsForProcess(TUint aProcessId)
+	{	return DoControl(EControlAcquireCodeSegMutexAndFilterCodesegsForProcess, (TAny*)aProcessId);	}
 inline TInt RMemoryAccess::ReleaseCodeSegMutex()
 	{	return DoControl(EControlReleaseCodeSegMutex, NULL, NULL);		}
 inline TInt RMemoryAccess::GetNextCodeSegInfo(TDes8& aCodeSegInfoBuf)
--- a/libraries/qr3/src/KernLbxModel.cpp	Fri Jul 09 10:11:55 2010 +0100
+++ b/libraries/qr3/src/KernLbxModel.cpp	Mon Jul 26 17:19:00 2010 +0100
@@ -289,7 +289,7 @@
 		}
 	case EListCodeSeg:
 		{
-		TTomsciCodeSegKernelInfo& info = *reinterpret_cast<TTomsciCodeSegKernelInfo*>(aInfo);
+		TCodeSegKernelInfo& info = *reinterpret_cast<TCodeSegKernelInfo*>(aInfo);
 		name.Copy(info.iName);
 
 		TBuf<16> size;
@@ -418,7 +418,7 @@
 	case EListCodeSeg:
 		{
 		if (i == 0) clogger.Log(KCodesegDesc);
-		TTomsciCodeSegKernelInfo& info = *reinterpret_cast<TTomsciCodeSegKernelInfo*>(aInfo);
+		TCodeSegKernelInfo& info = *reinterpret_cast<TCodeSegKernelInfo*>(aInfo);
 		TBuf8<16> size;
 		HR(size, info.iSize);
 		clogger.Log(KCodesegFmt, &info.iName, info.iSize, &size, info.iAccessCount, info.iDepCount);
@@ -598,7 +598,7 @@
 			}
 		case EListCodeSeg:
 			{
-			TTomsciCodeSegKernelInfo& info = *reinterpret_cast<TTomsciCodeSegKernelInfo*>(iInfo);
+			TCodeSegKernelInfo& info = *reinterpret_cast<TCodeSegKernelInfo*>(iInfo);
 			_LIT(KInfo, "Code segment info");
 			aTitle.Copy(KInfo);
 			inf.Copy(info.iName);
@@ -985,9 +985,9 @@
 	if (iCurrentList == EListCodeSeg)
 		{
 		mem.AcquireCodeSegMutex();
-		TTomsciCodeSegKernelInfo* inf = new(ELeave) TTomsciCodeSegKernelInfo;
+		TCodeSegKernelInfo* inf = new(ELeave) TCodeSegKernelInfo;
 		info = reinterpret_cast<TObjectKernelInfo*>(inf); // These aren't actually related classes, just convenient
-		buf.Set(TPckg<TTomsciCodeSegKernelInfo>(*inf));
+		buf.Set(TPckg<TCodeSegKernelInfo>(*inf));
 		while (mem.GetNextCodeSegInfo(buf) == KErrNone)
 			{
 			TRAPD(err, model.NewKernDataL(iCurrentList, info));
@@ -996,8 +996,8 @@
 				break;
 				}
 			inf = NULL;
-			inf = new(ELeave) TTomsciCodeSegKernelInfo;
-			buf.Set(TPckg<TTomsciCodeSegKernelInfo>(*inf));
+			inf = new(ELeave) TCodeSegKernelInfo;
+			buf.Set(TPckg<TCodeSegKernelInfo>(*inf));
 			info = reinterpret_cast<TObjectKernelInfo*>(inf); // These aren't actually related classes, just convenient
 			}
 		delete inf;