libraries/btrace_parser/src/btrace_context.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libraries/btrace_parser/src/btrace_context.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,896 @@
+// btrace_context.cpp
+// 
+// Copyright (c) 2008 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "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:
+// Accenture - Initial contribution
+//
+
+#include <e32debug.h>
+#include "btrace_parser.h"
+
+
+_LIT(KUnknown, "unknown");
+
+
+EXPORT_C TBtraceIdBase::TBtraceIdBase()
+	: iId(0)
+	{
+	}
+
+EXPORT_C TBtraceIdBase::TBtraceIdBase(TUint aId)
+	: iId(aId)
+	{
+	}
+
+EXPORT_C TBtraceIdBase::TBtraceIdBase(const TBtraceIdBase& aId)
+	: iId(aId.Value())
+	{
+	}
+
+EXPORT_C void TBtraceIdBase::Set(TUint aValue)
+	{
+	iId = aValue;
+	}
+
+EXPORT_C TUint TBtraceIdBase::Value() const
+	{
+	return iId;
+	}
+
+EXPORT_C TBool TBtraceIdBase::operator==(const TBtraceIdBase& aId) const
+	{
+	return (aId.iId == iId);
+	}
+
+EXPORT_C TBtraceThreadId::TBtraceThreadId()
+	{
+	}
+
+EXPORT_C TBtraceThreadId::TBtraceThreadId(TUint aId)
+	: TBtraceIdBase(aId)
+	{
+	}
+
+EXPORT_C TBtraceThreadId::TBtraceThreadId(const TBtraceThreadId& aId)
+	: TBtraceIdBase(aId)
+	{
+	}
+
+EXPORT_C TBtraceProcessId::TBtraceProcessId()
+	{
+	}
+
+EXPORT_C TBtraceProcessId::TBtraceProcessId(TUint aId)
+	: TBtraceIdBase(aId)
+	{
+	}
+
+EXPORT_C TBtraceProcessId::TBtraceProcessId(const TBtraceProcessId& aId)
+	: TBtraceIdBase(aId)
+	{
+	}
+
+EXPORT_C TBtraceWindowGroupId::TBtraceWindowGroupId()
+	{
+	}
+
+EXPORT_C TBtraceWindowGroupId::TBtraceWindowGroupId(TUint aId)
+	: TBtraceIdBase(aId)
+	{
+	}
+
+EXPORT_C TBtraceWindowGroupId::TBtraceWindowGroupId(const TBtraceWindowGroupId& aId)
+	: TBtraceIdBase(aId)
+	{
+	}
+
+EXPORT_C void MBtraceContextObserver::HandleThreadSeenL(const TBtraceTickCount&, const TBtraceThreadId&, TUint)
+	{
+	Panic(EBtpPanicUndefinedCallBack);
+	}
+
+EXPORT_C void MBtraceContextObserver::HandleThreadGoneL(const TBtraceTickCount&, const TBtraceThreadId&, TUint)
+	{
+	Panic(EBtpPanicUndefinedCallBack);
+	}
+
+EXPORT_C void MBtraceContextObserver::HandleThreadExitL(const TBtraceTickCount&, const TBtraceThreadId&, TExitType, TInt, const TDesC&, TUint)
+	{
+	Panic(EBtpPanicUndefinedCallBack);
+	}
+
+EXPORT_C void MBtraceContextObserver::HandleWindowGroupSeenL(const TBtraceTickCount&, const TBtraceWindowGroupId&, TUint)
+	{
+	Panic(EBtpPanicUndefinedCallBack);
+	}
+
+EXPORT_C CBtraceContext* CBtraceContext::NewL(CBtraceReader& aReader, TMode aMode)
+	{
+	CBtraceContext* self = new(ELeave) CBtraceContext(aReader, aMode);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+EXPORT_C CBtraceContext::~CBtraceContext()
+	{
+	iWindowGroupSeenNotifs.Close();
+	iThreadExitNotifs.Close();
+	iThreadGoneNotifs.Close();
+	iThreadSeenNotifs.Close();
+	iWindowGroups.Close();
+	iThreads.Close();
+	iProcesses.Close();
+	iReader.RemoveObserver(BTrace::EThreadIdentification, *this);
+	iReader.RemoveObserver(KAmTraceCategory, *this);
+	}
+
+
+TBool CBtraceContext::ThreadMatchesId(const TThread& aLeft, const TThread& aRight)
+	{
+	return (aLeft.iId == aRight.iId);
+	}
+
+TBool CBtraceContext::ThreadMatchesKernelId(const TThread& aLeft, const TThread& aRight)
+	{
+	return (aLeft.iKernelId == aRight.iKernelId);
+	}
+
+TBool CBtraceContext::ThreadMatchesNThreadAddress(const TThread& aLeft, const TThread& aRight)
+	{
+	return (aLeft.iNThreadAddress == aRight.iNThreadAddress);
+	}
+
+TBool CBtraceContext::ProcessMatchesId(const TProcess& aLeft, const TProcess& aRight)
+	{
+	return (aLeft.iId == aRight.iId);
+	}
+
+TBool CBtraceContext::ProcessMatchesDProcessAddress(const TProcess& aLeft, const TProcess& aRight)
+	{
+	return (aLeft.iDProcessAddress == aRight.iDProcessAddress);
+	}
+
+TBool CBtraceContext::WindowGroupMatchesId(const TWindowGroup& aLeft, const TWindowGroup& aRight)
+	{
+	return (aLeft.iId == aRight.iId);
+	}
+
+TBool CBtraceContext::WindowGroupMatchesThreadId(const TWindowGroup& aLeft, const TWindowGroup& aRight)
+	{
+	return (aLeft.iThreadId == aRight.iThreadId);
+	}
+
+TBool CBtraceContext::WindowGroupMatchesWServId(const TWindowGroup& aLeft, const TWindowGroup& aRight)
+	{
+	return (aLeft.iWindowGroupId == aRight.iWindowGroupId);
+	}
+
+EXPORT_C const TDesC& CBtraceContext::ThreadName(const TBtraceThreadId& aId) const
+	{
+	TThread findKey(0, 0, KNullDesC8);
+	findKey.iId = aId;
+	TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesId));
+	if (pos >= 0)
+		{
+		return iThreads[pos].iName;
+		}
+	else
+		{
+		return KUnknown;
+		}
+	}
+
+EXPORT_C void CBtraceContext::GetFullThreadName(const TBtraceThreadId& aId, TDes& aFullName) const
+	{
+	TThread findKey(0, 0, KNullDesC8);
+	findKey.iId = aId;
+	TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesId));
+	if (pos >= 0)
+		{
+		const TThread& thread = iThreads[pos];
+		TProcess findKey(thread.iOwningProcess);
+		TInt processPos = iProcesses.Find(findKey, TIdentityRelation<TProcess>(ProcessMatchesDProcessAddress));
+		__ASSERT_ALWAYS(processPos >= 0, Panic(EBtpPanicFailedToFindProcess));
+		aFullName.Zero();
+		aFullName.Append(ProcessName(iProcesses[processPos].iId));
+		aFullName.Append(_L("::"));
+		aFullName.Append(thread.iName);
+		}
+	else
+		{
+		aFullName = KUnknown;
+		}
+	}
+
+EXPORT_C TThreadId CBtraceContext::ThreadId(const TBtraceThreadId& aId) const
+	{
+	TThread findKey(0, 0, KNullDesC8);
+	findKey.iId = aId;
+	TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesId));
+	__ASSERT_ALWAYS(pos >= 0, Panic(EBtpPanicThreadIdNotFound));
+	return iThreads[pos].iKernelId;
+	}
+
+EXPORT_C const TDesC& CBtraceContext::ProcessName(const TBtraceProcessId& aId) const
+	{
+	TProcess findKey(0);
+	findKey.iId = aId;
+	TInt pos = iProcesses.Find(findKey, TIdentityRelation<TProcess>(ProcessMatchesId));
+	__ASSERT_ALWAYS(pos >= 0, Panic(EBtpPanicProcessNameNotFound));
+	return iProcesses[pos].iName;
+	}
+
+EXPORT_C TInt CBtraceContext::WindowGroupId(const TBtraceWindowGroupId& aId) const
+	{
+	TWindowGroup findKey(0, 0, KNullDesC);
+	findKey.iId = aId;
+	TInt pos = iWindowGroups.Find(findKey, TIdentityRelation<TWindowGroup>(WindowGroupMatchesId));
+	__ASSERT_ALWAYS(pos >= 0, Panic(EBtpPanicWindowGroupIdNotFound));
+	return iWindowGroups[pos].iWindowGroupId;
+	}
+
+EXPORT_C const TDesC& CBtraceContext::WindowGroupName(const TBtraceWindowGroupId& aId) const
+	{
+	TWindowGroup findKey(0, 0, KNullDesC);
+	findKey.iId = aId;
+	TInt pos = iWindowGroups.Find(findKey, TIdentityRelation<TWindowGroup>(WindowGroupMatchesId));
+	__ASSERT_ALWAYS(pos >= 0, Panic(EBtpPanicWindowGroupIdNotFound));
+	return iWindowGroups[pos].iName;
+	}
+
+EXPORT_C const TBtraceThreadId* CBtraceContext::FindThread(TUint32 aNThreadAddress) const
+	{
+	TThread findKey(aNThreadAddress, 0, KNullDesC8);
+	TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesNThreadAddress));
+	if (pos >= 0)
+		{
+		return &iThreads[pos].iId;
+		}
+	else
+		{
+		return NULL;
+		}
+	}
+
+EXPORT_C const TBtraceThreadId* CBtraceContext::FindThread(const TThreadId& aId) const
+	{
+	TThread findKey(0, 0, KNullDesC8);
+	findKey.iKernelId = TUint(aId);
+	TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesKernelId));
+	if (pos >= 0)
+		{
+		return &iThreads[pos].iId;
+		}
+	else
+		{
+		return NULL;
+		}
+	}
+
+EXPORT_C const TBtraceWindowGroupId* CBtraceContext::FindWindowGroup(TInt aWServWgId) const
+	{
+	TWindowGroup findKey(aWServWgId);
+	TInt pos = iWindowGroups.Find(findKey, TIdentityRelation<TWindowGroup>(WindowGroupMatchesWServId));
+	if (pos >= 0)
+		{
+		return &iWindowGroups[pos].iId;
+		}
+	else
+		{
+		return NULL;
+		}
+	}
+
+EXPORT_C void CBtraceContext::FindThreadsL(const TDesC& aPattern, RArray<TBtraceThreadId>& aThreads) const
+	{
+	TInt count = iThreads.Count();
+	while (--count >= 0)
+		{
+		const TThread& thread = iThreads[count];
+		TFullName name;
+		GetFullThreadName(thread.iId, name);
+		if (name.MatchF(aPattern) != KErrNotFound)
+			{
+			aThreads.AppendL(thread.iId);
+			}
+		}
+	}
+
+EXPORT_C void CBtraceContext::FindWindowGroupsL(const TDesC& aPattern, RArray<TBtraceWindowGroupId>& aWindowGroups) const
+	{
+	TInt count = iWindowGroups.Count();
+	while (--count >= 0)
+		{
+		const TWindowGroup& windowGroup = iWindowGroups[count];
+		if (windowGroup.iName.MatchF(aPattern) != KErrNotFound)
+			{
+			aWindowGroups.AppendL(windowGroup.iId);
+			}
+		}
+	}
+
+EXPORT_C void CBtraceContext::FindWindowGroupsByThreadName(const TDesC& aPattern, RArray<TBtraceWindowGroupId>& aWindowGroups) const
+	{
+	TInt count = iThreads.Count();
+	while (--count >= 0)
+		{
+		const TThread& thread = iThreads[count];
+		TFullName name;
+		GetFullThreadName(thread.iId, name);
+		if (name.MatchF(aPattern) != KErrNotFound)
+			{
+			for (TInt i = (iWindowGroups.Count() - 1); i >= 0; --i)
+				{
+				const TWindowGroup& thisWindowGroup = iWindowGroups[i];
+				if (thisWindowGroup.iThreadId.Id() == thread.iKernelId)
+					{
+					aWindowGroups.AppendL(thisWindowGroup.iId);
+					}
+				}
+			}
+		}
+	}
+
+EXPORT_C void CBtraceContext::NotifyThreadSeenL(const TDesC& aPattern, MBtraceContextObserver& aObserver, TUint aId)
+	{
+	NotifyThreadSeenL(aPattern, aObserver, aId, ENotificationOneShot);
+	}
+
+EXPORT_C void CBtraceContext::NotifyThreadSeenL(const TDesC& aPattern, MBtraceContextObserver& aObserver, TUint aId, TBtraceNotificationPersistence aPersistence)
+	{
+	iThreadSeenNotifs.AppendL(TThreadSeenNotif(aId, aPattern, aObserver, aPersistence));
+	}
+
+EXPORT_C void CBtraceContext::CancelNotifyThreadSeen(MBtraceContextObserver& aObserver)
+	{
+	for (TInt i = (iThreadSeenNotifs.Count() - 1); i >= 0; --i)
+		{
+		if (&iThreadSeenNotifs[i].iObserver == &aObserver)
+			{
+			iThreadSeenNotifs.Remove(i);
+			}
+		}
+	}
+
+EXPORT_C void CBtraceContext::NotifyThreadGoneL(const TDesC& aPattern, MBtraceContextObserver& aObserver, TUint aId)
+	{
+	return NotifyThreadGoneL(aPattern, aObserver, aId, ENotificationOneShot);
+	}
+	
+EXPORT_C void CBtraceContext::NotifyThreadGoneL(const TDesC& aPattern, MBtraceContextObserver& aObserver, TUint aId, TBtraceNotificationPersistence aPersistence)
+	{
+	iThreadGoneNotifs.AppendL(TThreadGoneNotif(aId, aPattern, aObserver, aPersistence));
+	}
+
+EXPORT_C void CBtraceContext::CancelNotifyThreadGone(MBtraceContextObserver& aObserver)
+	{
+	for (TInt i = (iThreadGoneNotifs.Count() - 1); i >= 0; --i)
+		{
+		if (&iThreadGoneNotifs[i].iObserver == &aObserver)
+			{
+			iThreadGoneNotifs.Remove(i);
+			}
+		}
+	}
+
+EXPORT_C void CBtraceContext::NotifyThreadExitL(const TDesC& aPattern, TUint aExitTypes, TInt* aReason, const TDesC* aCategory, MBtraceContextObserver& aObserver, TUint aId, TBtraceNotificationPersistence aPersistence)
+	{
+	iThreadExitNotifs.AppendL(TThreadExitNotif(aId, aPattern, aExitTypes, aReason, aCategory, aObserver, aPersistence));
+	}
+
+EXPORT_C void CBtraceContext::CancelNotifyThreadExit(MBtraceContextObserver& aObserver)
+	{
+	for (TInt i = (iThreadExitNotifs.Count() - 1); i >= 0; --i)
+		{
+		if (&iThreadExitNotifs[i].iObserver == &aObserver)
+			{
+			iThreadExitNotifs.Remove(i);
+			}
+		}
+	}
+
+EXPORT_C void CBtraceContext::NotifyWindowGroupSeenL(const TDesC& aPattern, MBtraceContextObserver& aObserver, TUint aId, TBtraceNotificationPersistence aPersistence)
+	{
+	iWindowGroupSeenNotifs.AppendL(TWindowGroupSeenNotif(aId, aPattern, TWindowGroupSeenNotif::EWindowGroupName, aObserver, aPersistence));
+	}
+
+EXPORT_C void CBtraceContext::NotifyWindowGroupSeenByThreadNameL(const TDesC& aPattern, MBtraceContextObserver& aObserver, TUint aId, TBtraceNotificationPersistence aPersistence)
+	{
+	iWindowGroupSeenNotifs.AppendL(TWindowGroupSeenNotif(aId, aPattern, TWindowGroupSeenNotif::EThreadName, aObserver, aPersistence));
+	}
+
+EXPORT_C void CBtraceContext::CancelNotifyWindowGroupSeen(MBtraceContextObserver& aObserver)
+	{
+	for (TInt i = (iWindowGroupSeenNotifs.Count() - 1); i >= 0; --i)
+		{
+		if (&iWindowGroupSeenNotifs[i].iObserver == &aObserver)
+			{
+			iWindowGroupSeenNotifs.Remove(i);
+			}
+		}
+	}
+
+CBtraceContext::CBtraceContext(CBtraceReader& aReader, TMode aMode)
+	: iMode(aMode), iReader(aReader), iNextBtraceThreadId(KMaxTUint), iNextBtraceProcessId(KMaxTUint)
+	{
+	}
+
+void CBtraceContext::ConstructL()
+	{
+	iReader.AddObserverL(BTrace::EThreadIdentification, *this, CBtraceReader::EIncludeSynchronizationFrames);
+	iReader.AddObserverL(KAmTraceCategory, *this);
+	}
+
+TUint CBtraceContext::GetNextThreadId()
+	{
+	TUint id = iNextBtraceThreadId--;
+	__ASSERT_ALWAYS(iNextBtraceThreadId > 0, Panic(EBtpPanicBtraceThreadIdOverflow));
+	return id;
+	}
+
+TUint CBtraceContext::GetNextProcessId()
+	{
+	TUint id = iNextBtraceProcessId--;
+	__ASSERT_ALWAYS(iNextBtraceProcessId > 0, Panic(EBtpPanicBtraceProcessIdOverflow));
+	return id;
+	}
+
+TUint CBtraceContext::GetNextWindowGroupId()
+	{
+	TUint id = iNextBtraceWindowGroupId--;
+	__ASSERT_ALWAYS(iNextBtraceWindowGroupId > 0, Panic(EBtpPanicBtraceWindowGroupIdOverflow));
+	return id;
+	}
+
+void CBtraceContext::SeenL(const TThread& aThread, const TBtraceTickCount& aTickCount)
+	{
+	TFullName name;
+	GetFullThreadName(aThread.iId, name);
+	for (TInt i = (iThreadSeenNotifs.Count() - 1); i >= 0; --i)
+		{
+		const TThreadSeenNotif& thisNotif = iThreadSeenNotifs[i];
+		if (name.MatchF(thisNotif.iPattern) != KErrNotFound)
+			{
+			MBtraceContextObserver& observer = thisNotif.iObserver;
+			TUint id = thisNotif.iId;
+			if (thisNotif.iPersistence == ENotificationOneShot)
+				{
+				iThreadSeenNotifs.Remove(i);
+				}
+			observer.HandleThreadSeenL(aTickCount, aThread.iId, id);
+			}
+		}
+	}
+
+void CBtraceContext::GoneL(const TThread& aThread, const TBtraceTickCount& aTickCount)
+	{
+	TFullName name;
+	GetFullThreadName(aThread.iId, name);
+	for (TInt i = (iThreadGoneNotifs.Count() - 1); i >= 0; --i)
+		{
+		const TThreadGoneNotif& notif = iThreadGoneNotifs[i];
+		if (name.MatchF(notif.iPattern) != KErrNotFound)
+			{
+			MBtraceContextObserver& observer = notif.iObserver;
+			TUint id = notif.iId;
+			if (notif.iPersistence == ENotificationOneShot)
+				{
+				iThreadGoneNotifs.Remove(i);
+				}
+			observer.HandleThreadGoneL(aTickCount, aThread.iId, id);
+			}
+		}
+	}
+
+void CBtraceContext::ExitedL(const TThread& aThread, TExitType aExitType, TInt aReason, const TDesC& aCategory, const TBtraceTickCount& aTickCount)
+	{
+	TFullName name;
+	GetFullThreadName(aThread.iId, name);
+	for (TInt i = (iThreadExitNotifs.Count() - 1); i >= 0; --i)
+		{
+		const TThreadExitNotif& notif = iThreadExitNotifs[i];
+		if (notif.Matches(name, aExitType, aReason, aCategory))
+			{
+			MBtraceContextObserver& observer = notif.iObserver;
+			TUint id = notif.iId;
+			if (notif.iPersistence == ENotificationOneShot)
+				{
+				iThreadExitNotifs.Remove(i);
+				}
+			observer.HandleThreadExitL(aTickCount, aThread.iId, aExitType, aReason, aCategory, id);
+			}
+		}
+	}
+
+void CBtraceContext::SeenL(const TWindowGroup& aWindowGroup, const TBtraceTickCount& aTickCount)
+	{
+	for (TInt i = (iWindowGroupSeenNotifs.Count() - 1); i >= 0; --i)
+		{
+		const TWindowGroupSeenNotif& thisNotif = iWindowGroupSeenNotifs[i];
+		if (thisNotif.iPatternType == TWindowGroupSeenNotif::EWindowGroupName)
+			{
+			if (aWindowGroup.iName.MatchF(thisNotif.iPattern) != KErrNotFound)
+				{
+				MBtraceContextObserver& observer = thisNotif.iObserver;
+				TUint id = thisNotif.iId;
+				if (thisNotif.iPersistence == ENotificationOneShot)
+					{
+					iWindowGroupSeenNotifs.Remove(i);
+					}
+				observer.HandleWindowGroupSeenL(aTickCount, aWindowGroup.iId, id);
+				}
+			}
+		else
+			{
+			TThread findKey(0, 0, KNullDesC8);
+			findKey.iKernelId = TUint(aWindowGroup.iThreadId);
+			TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesKernelId));
+			if (pos >= 0)
+				{
+				TFullName threadName;
+				GetFullThreadName(iThreads[pos].iId, threadName);
+				if (threadName.MatchF(thisNotif.iPattern))
+					{
+					MBtraceContextObserver& observer = thisNotif.iObserver;
+					TUint id = thisNotif.iId;
+					if (thisNotif.iPersistence == ENotificationOneShot)
+						{
+						iWindowGroupSeenNotifs.Remove(i);
+						}
+					observer.HandleWindowGroupSeenL(aTickCount, aWindowGroup.iId, id);
+					}
+				}
+			}
+		}
+	}
+
+void CBtraceContext::HandleBtraceFrameL(const TBtraceFrame& aFrame)
+	{
+	const TUint8* data = aFrame.iData.Ptr();
+
+	if (aFrame.iCategory == BTrace::EThreadIdentification)
+		{
+		switch (aFrame.iSubCategory)
+			{
+			case BTrace::EThreadCreate:
+				{
+				TUint32 nthreadAddress = *(TUint32*)data;
+				TUint32 dprocessAddress = *((TUint32*)data + 1);
+				TPtrC8 name(aFrame.iData.Mid(8));
+
+#ifdef BTRACE_CONTEXT_DEBUG
+				TFullName name16;
+				name16.Copy(name);
+				RDebug::Print(_L("BTrace::EThreadCreate: 0x%08x \"%S\""), nthreadAddress, &name16);
+#endif
+
+				TThread thread(nthreadAddress, dprocessAddress, name);
+				AppendL(thread, aFrame.iTickCount);
+				break;
+				}
+			case BTrace::EThreadDestroy:
+				{
+				TUint32 nthreadAddress = *(TUint32*)data;
+				TThread findKey(nthreadAddress, 0, KNullDesC8);
+				TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesNThreadAddress));
+				if (pos >= 0)
+					{
+#ifdef BTRACE_CONTEXT_DEBUG
+					RDebug::Print(_L("BTrace::EThreadDestroy: %u %u 0x%08x \"%S\""), iThreads[pos].iId.Value(), iThreads[pos].iKernelId, nthreadAddress, &iThreads[pos].iName);
+#endif
+					GoneL(iThreads[pos], aFrame.iTickCount);
+					RemoveThread(pos);
+					}
+				else
+					{
+					// This can happen if a thread is destroyed after the btrace buffer has been enabled but before the BTrace::EThreadIdentification category has been enabled.
+					iReader.Log(_L("Destroyed thread 0x%08x not found\r\n"), nthreadAddress);
+					}
+				break;
+				}
+			case BTrace::EThreadName:
+				{
+				TUint32 nthreadAddress = *(TUint32*)data;
+				TUint32 dprocessAddress = *((TUint32*)data + 1);
+				TPtrC8 name(aFrame.iData.Mid(8));
+
+#ifdef BTRACE_CONTEXT_DEBUG
+				TFullName name16;
+				name16.Copy(name);
+				RDebug::Print(_L("BTrace::EThreadName: 0x%08x \"%S\""), nthreadAddress, &name16);
+#endif				
+				TThread findKey(nthreadAddress, 0, KNullDesC8);
+				TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesNThreadAddress));
+				if (pos >= 0)
+					{
+					iThreads[pos].iName.Copy(name);
+					SeenL(iThreads[pos], aFrame.iTickCount);
+					}
+				else
+					{
+					TThread thread(nthreadAddress, dprocessAddress, name);
+					AppendL(thread, aFrame.iTickCount);
+					}
+				break;
+				}
+			case BTrace::EProcessCreate:
+				{
+				TUint32 dprocessAddress = *(TUint32*)data;
+#ifdef BTRACE_CONTEXT_DEBUG
+				RDebug::Print(_L("BTrace::EProcessCreate: 0x%08x"), dprocessAddress);
+#endif
+				TProcess process(dprocessAddress);
+				AppendL(process, aFrame.iTickCount);
+				break;
+				}
+			case BTrace::EProcessName:
+				{
+				TUint32 dprocessAddress = *((TUint32*)data + 1);
+				TPtrC8 name(aFrame.iData.Mid(8));
+
+#ifdef BTRACE_CONTEXT_DEBUG
+				TFullName name16;
+				name16.Copy(name);
+				RDebug::Print(_L("BTrace::EProcessName: 0x%08x \"%S\""), dprocessAddress, &name16);
+#endif
+				TProcess findKey(dprocessAddress);
+				TInt pos = iProcesses.Find(findKey, TIdentityRelation<TProcess>(ProcessMatchesDProcessAddress));
+				if (pos >= 0)
+					{
+					iProcesses[pos].iName.Copy(name);
+					SeenAllThreadsL(iProcesses[pos], aFrame.iTickCount);
+					}
+				else
+					{
+					TProcess process(dprocessAddress, name);
+					AppendL(process, aFrame.iTickCount);
+					}
+				break;
+				}
+			case BTrace::EThreadId:
+				{
+				TUint32 nthreadAddress = *(TUint32*)data;
+				TUint32 threadId = *((TUint32*)data + 2);
+				TThread findKey(nthreadAddress, 0, KNullDesC8);
+				TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesNThreadAddress));
+				__ASSERT_ALWAYS(pos >= 0, Panic(EBtpPanicThreadNotFoundForId));
+				iThreads[pos].iKernelId = threadId;
+#ifdef BTRACE_CONTEXT_DEBUG
+				RDebug::Print(_L("BTrace::EThreadId: %u 0x%08x \"%S\""), threadId, nthreadAddress, &iThreads[pos].iName);
+#endif
+				break;
+				}
+			default:
+				{
+				// Ignore anything we don't know about.
+				break;
+				}
+			}
+		}
+	else if (aFrame.iCategory == KAmTraceCategory)
+		{
+		if (aFrame.iSubCategory == EAmTraceSubCategoryWindowGroupName)
+			{
+			TUint wgId = *(TUint32*)data;
+			TInt kernelThreadId = *((TInt32*)data + 1);
+			TPtrC8 nameData = aFrame.iData.Mid(8);
+			TPtrC name((TUint16*)nameData.Ptr(), nameData.Length() / 2);
+			TWindowGroup findKey(wgId);
+			TInt pos = iWindowGroups.Find(findKey, TIdentityRelation<TWindowGroup>(WindowGroupMatchesWServId));
+			if (pos >= 0)
+				{
+				TWindowGroup& windowGroup = iWindowGroups[pos];
+				windowGroup.iName = name;
+				SeenL(windowGroup, aFrame.iTickCount);
+				}
+			else
+				{
+				TWindowGroup windowGroup(wgId, TThreadId(kernelThreadId), name);
+				windowGroup.iId.Set(GetNextWindowGroupId());
+				iWindowGroups.AppendL(windowGroup);
+				SeenL(windowGroup, aFrame.iTickCount);
+				}
+			}
+		else if ((aFrame.iSubCategory >= EAmTraceSubCategoryThreadKilled) && (aFrame.iSubCategory <= EAmTraceSubCategoryThreadPanicked))
+			{
+			TUint id = *(TUint32*)data;
+			TInt reason = *((TInt32*)data + 1);
+			TThread findKey(0, 0, KNullDesC8);
+			findKey.iKernelId = id;
+			TInt pos = iThreads.Find(findKey, TIdentityRelation<TThread>(ThreadMatchesKernelId));
+			if (pos >= 0)
+				{
+				const TThread& thread = iThreads[pos];
+				switch (aFrame.iSubCategory)
+					{
+					case EAmTraceSubCategoryThreadKilled:
+						{
+						ExitedL(thread, EExitKill, reason, KNullDesC, aFrame.iTickCount);
+						break;
+						}
+					case EAmTraceSubCategoryThreadTerminated:
+						{
+						ExitedL(thread, EExitTerminate, reason, KNullDesC, aFrame.iTickCount);
+						break;
+						}
+					case EAmTraceSubCategoryThreadPanicked:
+						{
+						TPtrC8 narrowCategory(aFrame.iData.Mid(sizeof(TInt) * 2));
+						TExitCategoryName category;
+						category.Copy(narrowCategory);
+						ExitedL(thread, EExitPanic, reason, category, aFrame.iTickCount);
+						break;
+						}
+					default:
+						{
+						// Ignore anything we don't know about.
+						break;
+						}
+					}
+				}
+			}
+		}
+	}
+
+void CBtraceContext::AppendL(const TThread& aThread, const TBtraceTickCount& aTickCount)
+	{
+	iThreads.AppendL(aThread);
+	TThread& thread = iThreads[iThreads.Count() - 1];
+	thread.iId.Set(GetNextThreadId());
+
+	// Increment the reference count of the owning process.
+	TProcess findKey(thread.iOwningProcess);
+	TInt pos = iProcesses.Find(findKey, TIdentityRelation<TProcess>(ProcessMatchesDProcessAddress));
+	if (pos >= 0)
+		{
+		++(iProcesses[pos].iReferenceCount);
+		}
+
+	SeenL(thread, aTickCount);
+	}
+
+void CBtraceContext::AppendL(const TProcess& aProcess, const TBtraceTickCount& aTickCount)
+	{
+	iProcesses.AppendL(aProcess);
+	TProcess& process = iProcesses[iProcesses.Count() - 1];
+	process.iId.Set(GetNextProcessId());
+
+	// Set the reference count for this process.
+	for (TInt i = (iThreads.Count() - 1); i >= 0; --i)
+		{
+		if (iThreads[i].iOwningProcess == process.iDProcessAddress)
+			{
+			++process.iReferenceCount;
+			}
+		}
+
+	SeenAllThreadsL(process, aTickCount);
+	}
+
+void CBtraceContext::RemoveThread(TInt aPosition)
+	{
+	TProcess findKey(iThreads[aPosition].iOwningProcess);
+	TInt processPos = iProcesses.Find(findKey, TIdentityRelation<TProcess>(ProcessMatchesDProcessAddress));
+	if (processPos >= 0)
+		{
+		if (--(iProcesses[processPos].iReferenceCount) == 0)
+			{
+			iProcesses.Remove(processPos);
+			}
+		}
+	iThreads.Remove(aPosition);
+	}
+
+void CBtraceContext::SeenAllThreadsL(const TProcess& aProcess, const TBtraceTickCount& aTickCount)
+	{
+	// Call SeenL for each thread belonging to this process because. This is called when a process
+	// is created or altered because this change may allow a TThreadSeenNotif to be completed.
+	const TInt numThreads = iThreads.Count();
+	for (TInt i = 0; i < numThreads; ++i)
+		{
+		const TThread& thread = iThreads[i];
+		if (thread.iOwningProcess == aProcess.iDProcessAddress)
+			{
+			SeenL(thread, aTickCount);
+			}
+		}
+	}
+
+void CBtraceContext::BtraceBufferHasBeenReset()
+	{
+	iThreads.Close();
+	iProcesses.Close();
+	}
+
+CBtraceContext::TThread::TThread(TUint32 aNThreadAddress, TUint32 aOwningProcess, const TDesC8& aName)
+	: iNThreadAddress(aNThreadAddress), iOwningProcess(aOwningProcess), iKernelId(0)
+	{
+	iName.Copy(aName);
+	}
+
+CBtraceContext::TProcess::TProcess(TUint32 aDProcessAddress)
+	: iDProcessAddress(aDProcessAddress), iReferenceCount(0)
+	{
+	}
+
+CBtraceContext::TProcess::TProcess(TUint32 aDProcessAddress, const TDesC8& aName)
+	: iDProcessAddress(aDProcessAddress), iReferenceCount(0)
+	{
+	iName.Copy(aName);
+	}
+
+CBtraceContext::TWindowGroup::TWindowGroup(TInt aWindowGroupId)
+	: iWindowGroupId(aWindowGroupId), iThreadId(0)
+	{
+	}
+
+CBtraceContext::TWindowGroup::TWindowGroup(const TDesC& aName)
+	: iWindowGroupId(0), iThreadId(0), iName(aName)
+	{
+	}
+
+CBtraceContext::TWindowGroup::TWindowGroup(TInt aWindowGroupId, TThreadId aThreadId, const TDesC& aName)
+	: iWindowGroupId(aWindowGroupId), iThreadId(aThreadId), iName(aName)
+	{
+	}
+
+CBtraceContext::TThreadSeenNotif::TThreadSeenNotif(TUint aId, const TDesC& aPattern, MBtraceContextObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+	: iId(aId), iPattern(aPattern), iObserver(aObserver), iPersistence(aPersistence)
+	{
+	}
+
+CBtraceContext::TThreadGoneNotif::TThreadGoneNotif(TUint aId, const TDesC& aPattern, MBtraceContextObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+	: iId(aId), iPattern(aPattern), iObserver(aObserver), iPersistence(aPersistence)
+	{
+	}
+
+CBtraceContext::TThreadExitNotif::TThreadExitNotif(TUint aId, const TDesC& aPattern, TUint aExitTypes, TInt* aReason, const TDesC* aCategory, MBtraceContextObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+	: iId(aId), iPattern(aPattern), iExitTypes(aExitTypes), iReason(aReason), iCategory(aCategory), iObserver(aObserver), iPersistence(aPersistence)
+	{
+	}
+
+CBtraceContext::TWindowGroupSeenNotif::TWindowGroupSeenNotif(TUint aId, const TDesC& aPattern, TPatternType aPatternType, MBtraceContextObserver& aObserver, TBtraceNotificationPersistence aPersistence)
+	: iId(aId), iPattern(aPattern), iPatternType(aPatternType), iObserver(aObserver), iPersistence(aPersistence)
+	{
+	}
+
+TBool CBtraceContext::TThreadExitNotif::Matches(const TDesC& aThreadName, TExitType aExitType, TInt aReason, const TDesC& aCategory) const
+	{
+	if (aThreadName.MatchF(iPattern) != KErrNotFound)
+		{
+		if (MatchesType(aExitType))
+			{
+			if ((iReason == NULL) || (*iReason == aReason))
+				{
+				if ((aExitType != EExitPanic) || ((iCategory == NULL) || (*iCategory == aCategory)))
+					{
+					return ETrue;
+					}
+				}
+			}
+		}
+	return EFalse;
+	}
+
+TBool CBtraceContext::TThreadExitNotif::MatchesType(TExitType aExitType) const
+	{
+	switch (aExitType)
+		{
+		case EExitKill:
+			return (iExitTypes & EKill);
+		case EExitTerminate:
+			return (iExitTypes & ETerminate);
+		case EExitPanic:
+			return (iExitTypes & EPanic);
+		default:
+			ASSERT(EFalse);
+			return EFalse;
+		}
+	}