Implemented RObjectIx-based memoryaccess APIs. default tip
authorTom Sutcliffe <thomas.sutcliffe@accenture.com>
Tue, 07 Dec 2010 17:29:09 +0000
changeset 90 ceac7084e2e5
parent 89 17bed177107f
Implemented RObjectIx-based memoryaccess APIs. Upshot is that objinfo now works again on platforms that define FSHELL_NO_DOBJECTIX_SUPPORT.
core/builtins/objinfo.cif
documentation/change_history.pod
libraries/memoryaccess/MemoryAccess.cpp
--- a/core/builtins/objinfo.cif	Tue Nov 30 11:11:58 2010 +0000
+++ b/core/builtins/objinfo.cif	Tue Dec 07 17:29:09 2010 +0000
@@ -20,13 +20,21 @@
 
 Given a kernel object address, prints details of the threads and processes that are currently holding handles to it (note, kernel objects addresses can be found using L<ps|ps> (e.g. C<ps -A> or C<ps -At>), L<chunkinfo|chunkinfo> or L<svrinfo|svrinfo>). Given a thread or process identifier, lists details of all the owned objects.
 
+To see all the threads and processes that have a handle open to the DObject 0x12345678:
+
+    objinfo 0x12345678
+
+For example, to see all the handles opened by process 23:
+
+    objinfo --process-id 23 --all
+
 ==see-also
 
 L<ps|ps>, L<chunkinfo|chunkinfo>, L<svrinfo|svrinfo>
 
 ==argument uint object_address optional
 
-The address of the kernel object to find the owners of. If not specified, a thread or process identifier must be specified using C<-t> or C<-p>.
+The address of the kernel object to find the owners of. If not specified, a thread or process identifier must be specified using C<--thread-id> or C<--process-id>.
 
 ==option bool r referencers
 
@@ -42,7 +50,7 @@
 
 ==option bool a all
 
-Include details of objects referenced by threads of a given process. Only useful in conjunction with the C<-p> option.
+Include details of objects referenced by threads of a given process, ie show the thread-local handles held by threads in that process as well as the process-global handles. Only useful in conjunction with the C<--process-id> option.
 
 ==copyright
 
--- a/documentation/change_history.pod	Tue Nov 30 11:11:58 2010 +0000
+++ b/documentation/change_history.pod	Tue Dec 07 17:29:09 2010 +0000
@@ -14,6 +14,16 @@
 
 =head1 FShell Change History
 
+=head2 Release 003 [NOT YET MADE]
+
+=over 5
+
+=item *
+
+Fixed objinfo command so that it works on modern (S^3 or later, S60 5th or later) baselines.
+
+=back
+
 =head2 Release 002
 
 =over 5
--- a/libraries/memoryaccess/MemoryAccess.cpp	Tue Nov 30 11:11:58 2010 +0000
+++ b/libraries/memoryaccess/MemoryAccess.cpp	Tue Dec 07 17:29:09 2010 +0000
@@ -23,6 +23,8 @@
 
 #ifdef FSHELL_DOBJECTIX_SUPPORT
 #include "dobject.h" // To pick up my defn of DObjectIx/DObjectIxNinePointOneHack
+#else
+TBool ObjectIxContains(RObjectIx& aHandles, DObject* aObj);
 #endif
 
 #include <e32cmn.h>
@@ -2114,31 +2116,10 @@
 	// Code adapted from ExecHandler::HandleInfo
 	DObject* pO=(DObject*)aObj;
 	TInt r = KErrNone;
-	/*
-	DThread& t = *iClient;
-	//TInt r=K::OpenObjectFromHandle(aHandle,pO);
-	//BEGIN this bit copied from K::OpenObjectFromHandle
-	TInt r=KErrBadHandle;
-	NKern::ThreadEnterCS();
-	NKern::LockSystem();
-	pO=t.ObjectFromHandle(aHandle);
-	if (pO)
-		r=pO->Open();
-	NKern::UnlockSystem();
-	if (r!=KErrNone)
-		{
-		pO=NULL;
-		NKern::ThreadLeaveCS();
-		}
-	//END
-	*/
 
 	if (r==KErrNone)
 		{
 		//DObjectIx::Wait(); //TOMSCI I can't call this frmo a device driver, why did the code I copied do it but none of the DMemoryAccess stuff that uses containers do it??
-		//DProcess* pCurrentProcess=TheCurrentThread->iOwningProcess;
-		//hinfo.iNumOpenInThread=TheCurrentThread->iHandles->Count(pO);
-		//hinfo.iNumOpenInProcess=pCurrentProcess->iHandles->Count(pO);
 
 		DObjectCon* const * cons=Kern::Containers();
 		DObjectCon& threads = *cons[EThread];
@@ -2164,9 +2145,6 @@
 						{
 						buf.Append(idBuf);
 						}
-					//++hinfo.iNumThreads;
-					//if (pT->iOwningProcess==pCurrentProcess)
-					//	++hinfo.iNumOpenInProcess;
 					}
 				}
 			}
@@ -2184,7 +2162,6 @@
 				TInt rr=((DObjectIxNinePointTwoHack*)handles)->At(pO);
 				if (rr!=KErrNotFound)
 					{
-					//++hinfo.iNumProcesses;
 					TPckgBuf<TUint> idBuf(pP->iId);
 					if (buf.Length() + idBuf.Length() >= buf.MaxLength())
 						{
@@ -2199,12 +2176,6 @@
 				}
 			}
 		processes.Signal();
-		//DObjectIx::Signal();
-
-
-		//DObjectIx::Signal();
-		//pO->Close(NULL);
-		//NKern::ThreadLeaveCS();
 		}
 	
 	TInt clientLen = Kern::ThreadGetDesMaxLength(iClient, aOwnersBuf);
@@ -2213,30 +2184,92 @@
 	if (writeErr) return writeErr;
 	return (clientLen < buf.Length()) ? KErrOverflow : r;
 #else
-	return KErrNotSupported;
+
+#ifdef __HANDLES_USE_RW_SPIN_LOCK__
+#error "Memoryaccess doesn't support rw spin locks in RObjectIx!"
 #endif
+
+	TBuf8<512> buf;
+	TInt r = KErrNone;
+	DObject* object = (DObject*)aObj;
+
+	DObjectCon& threads = *Kern::Containers()[EThread];
+	threads.Wait();
+	TInt c=threads.Count();
+	for (TInt i=0;i<c;i++)
+		{
+		DThread *pT=(DThread *)threads[i];
+		if (ObjectIxContains(pT->iHandles, object))
+			{
+			TPckgBuf<TUint> idBuf(pT->iId);
+			if (buf.Length() + idBuf.Length() > buf.MaxLength())
+				{
+				r = KErrOverflow;
+				break;
+				}
+			else
+				{
+				buf.Append(idBuf);
+				}
+			
+			}
+		}
+	threads.Signal();
+
+	DObjectCon& processes = *Kern::Containers()[EProcess];
+	processes.Wait();
+	c = processes.Count();
+	for (TInt i = 0; i < c; i++)
+		{
+		DProcess* proc = (DProcess*)processes[i];
+		if (ObjectIxContains(proc->iHandles, object))
+			{
+			TPckgBuf<TUint> idBuf(proc->iId);
+			if (buf.Length() + idBuf.Length() > buf.MaxLength())
+				{
+				r = KErrOverflow;
+				break;
+				}
+			else
+				{
+				buf.Append(idBuf);
+				}
+			}
+		}
+	processes.Signal();
+
+	TInt clientLen = Kern::ThreadGetDesMaxLength(iClient, aOwnersBuf);
+	if (clientLen < 0) return clientLen;
+	TInt writeErr = Kern::ThreadDesWrite(iClient, aOwnersBuf, buf, 0, KTruncateToMaxLength, NULL);
+	if (writeErr) return writeErr;
+	return (clientLen < buf.Length()) ? KErrOverflow : r;
+
+#endif // FSHELL_DOBJECTIX_SUPPORT
 	}
 
 TInt DMemoryAccess::GetThreadHandles(TInt aThreadId, TAny* aHandlesBuf)
 	{
-#ifdef FSHELL_DOBJECTIX_SUPPORT
-	TInt maxLength = Kern::ThreadGetDesMaxLength(iClient, aHandlesBuf);
-	TInt err = KErrNone;
-
+	NKern::ThreadEnterCS();
 	DObjectCon* const * cons = Kern::Containers();
 	DObjectCon& container = *cons[EThread];
 	container.Wait();
-	NKern::ThreadEnterCS();
 	DThread* thread = Kern::ThreadFromId(aThreadId);
-	//TOMSCI FIXME we don't increment thread's ref count
-	NKern::ThreadLeaveCS();
+	if (thread && thread->Open() != KErrNone)
+		{
+		thread = NULL;
+		}
 	container.Signal();
 	if (thread == NULL) 
 		{
+		NKern::ThreadLeaveCS();
 		return KErrNotFound;
 		}
 
+#ifdef FSHELL_DOBJECTIX_SUPPORT
 	// Note, this code is inherently dodgy because it doesn't claim DObjectIx::HandleMutex.
+	TInt maxLength = Kern::ThreadGetDesMaxLength(iClient, aHandlesBuf);
+	TInt err = KErrNone;
+
 	DObjectIxNinePointTwoHack* handles = (DObjectIxNinePointTwoHack*)thread->iHandles;
 	if (handles)
 		{
@@ -2266,33 +2299,59 @@
 				}
 			}
 		}
+#else
+	
+	TInt c = thread->iHandles.Count();
+	HBuf8* buf = HBuf::New(c * sizeof(DObject*));
+	TInt err = KErrNoMemory;
+	if (buf)
+		{
+		DObject** ptr = (DObject**)buf->Ptr();
+		NKern::LockSystem();
+		c = Min(thread->iHandles.Count(), c); // In case it's changed
+		buf->SetLength(c * sizeof(DObject*));
+		for (TInt i = 0; i < c; i++)
+			{
+			ptr[i] = thread->iHandles[i];
+			}
+		NKern::UnlockSystem();
 
-	//TOMSCI What is this unlock doing here? TODO FIXME!!!
-	NKern::UnlockSystem();
+		err = Kern::ThreadDesWrite(iClient, aHandlesBuf, *buf, 0);
+		delete buf;
+		}
+	else
+		{
+		err = KErrNoMemory;
+		}
+#endif
+
+	thread->Close(NULL);
+	NKern::ThreadLeaveCS();
 	return err;
-#else
-	return KErrNotSupported;
-#endif
 	}
 
 TInt DMemoryAccess::GetProcessHandles(TInt aProcessId, TAny* aHandlesBuf)
 	{
-#ifdef FSHELL_DOBJECTIX_SUPPORT
-	TInt maxLength = Kern::ThreadGetDesMaxLength(iClient, aHandlesBuf);
-	TInt err = KErrNone;
-
+	NKern::ThreadEnterCS();
 	DObjectCon* const * cons = Kern::Containers();
 	DObjectCon& container = *cons[EProcess];
 	container.Wait();
-	NKern::ThreadEnterCS();
-	DProcess* process = Kern::ProcessFromId(aProcessId);
-	NKern::ThreadLeaveCS();
+	DProcess* proc = Kern::ProcessFromId(aProcessId);
+	if (proc && proc->Open() != KErrNone)
+		{
+		proc = NULL;
+		}
 	container.Signal();
-	if (process == NULL) 
+	if (proc == NULL)
 		{
+		NKern::ThreadLeaveCS();
 		return KErrNotFound;
 		}
 
+#ifdef FSHELL_DOBJECTIX_SUPPORT
+	TInt maxLength = Kern::ThreadGetDesMaxLength(iClient, aHandlesBuf);
+	TInt err = KErrNone;
+
 	// Note, this code is inherently dodgy because it doesn't claim DObjectIx::HandleMutex.
 	DObjectIxNinePointTwoHack* handles = (DObjectIxNinePointTwoHack*)process->iHandles;
 	if (handles)
@@ -2324,10 +2383,35 @@
 			}
 		}
 
+#else // new RObjectIx code
+
+	TInt c = proc->iHandles.Count();
+	HBuf8* buf = HBuf::New(c * sizeof(DObject*));
+	TInt err = KErrNoMemory;
+	if (buf)
+		{
+		DObject** ptr = (DObject**)buf->Ptr();
+		NKern::LockSystem();
+		c = Min(proc->iHandles.Count(), c); // In case it's changed
+		buf->SetLength(c * sizeof(DObject*));
+		for (TInt i = 0; i < c; i++)
+			{
+			ptr[i] = proc->iHandles[i];
+			}
+		NKern::UnlockSystem();
+
+		err = Kern::ThreadDesWrite(iClient, aHandlesBuf, *buf, 0);
+		delete buf;
+		}
+	else
+		{
+		err = KErrNoMemory;
+		}
+#endif // FSHELL_DOBJECTIX_SUPPORT
+
+	proc->Close(NULL);
+	NKern::ThreadLeaveCS();
 	return err;
-#else
-	return KErrNotSupported;
-#endif
 	}
 
 TInt DMemoryAccess::SetCriticalFlags(TInt aThreadHandle, TUint aFlags)
@@ -3113,3 +3197,32 @@
 		iClientBreakpointNotifyPkg = NULL;
 		}
 	}
+
+#ifndef FSHELL_DOBJECTIX_SUPPORT
+
+DObject* RObjectIx::operator[](TInt aIndex)
+	{
+	// Must be holding system lock (technically, the 'read' lock)
+	DObject* obj = 0;
+	SSlot* slot = iSlots + aIndex;
+	obj = Occupant(slot);
+	return obj;
+	}
+
+TBool ObjectIxContains(RObjectIx& aHandles, DObject* aObj)
+	{
+	NKern::LockSystem();
+	TInt c = aHandles.Count();
+	for (TInt i = 0; i < c; i++)
+		{
+		if (aHandles[i] == aObj)
+			{
+			NKern::UnlockSystem();
+			return ETrue;
+			}
+		}
+	NKern::UnlockSystem();
+	return EFalse;
+	}
+
+#endif