libraries/btrace_parser/src/btrace_context.cpp
author Tom Sutcliffe <thomas.sutcliffe@accenture.com>
Sat, 31 Jul 2010 19:07:57 +0100
changeset 23 092bcc217d9d
parent 0 7f656887cf89
permissions -rw-r--r--
Tidied iocli exports, build macro tweaks. Removed 4 overloads of CCommandBase::RunCommand[L] that are no longer used at all, and changed one more to not be exported as it's only used internally to iocli.dll. fixed builds on platforms that don't support btrace or any form of tracing.

// 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;
		}
	}