commands/btrace/btrace.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/btrace/btrace.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,508 @@
+// btrace.cpp
+// 
+// Copyright (c) 2007 - 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 "btrace.h"
+
+#if defined(FSHELL_MEMORY_ACCESS_SUPPORT)
+#define TEXT_TRACE_MODE_SUPPORTED
+#endif
+
+const TInt KMaxCategories = 256;
+const TUint KPrimingStopped = 0x102864BC;
+
+
+
+CCommandBase* CCmdBtrace::NewLC()
+	{
+	CCmdBtrace* self = new(ELeave) CCmdBtrace();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	return self;
+	}
+
+CCmdBtrace::~CCmdBtrace()
+	{
+	iPrimaryFilters.Close();
+	iSecondaryFilters.Close();
+	iBtrace.Close();
+	}
+
+CCmdBtrace::CCmdBtrace()
+	: iThreshold(50)
+	{
+	}
+
+void CCmdBtrace::ConstructL()
+	{
+	BaseConstructL();
+	}
+
+const TDesC& CCmdBtrace::Name() const
+	{
+#ifdef BUILDING_ATRACE
+	_LIT(KName, "atrace");
+#else
+	_LIT(KName, "btrace");
+#endif
+	return KName;
+	}
+
+#define CASE_LIT(x) case BTrace:: x : { _LIT(KName, #x); return &KName; }
+#define CASE_REALLY_LIT(x) case x : { _LIT(KName, #x); return &KName; }
+
+const TDesC* BtraceCategoryName(TInt aCategory)
+	{
+	switch (aCategory)
+		{
+		CASE_LIT(ERDebugPrintf)
+		CASE_LIT(EKernPrintf)
+		CASE_LIT(EPlatsecPrintf)
+		CASE_LIT(EThreadIdentification)
+		CASE_LIT(ECpuUsage)
+		CASE_LIT(EKernPerfLog)
+		CASE_LIT(EClientServer)
+		CASE_LIT(ERequests)
+		CASE_LIT(EChunks)
+		CASE_LIT(ECodeSegs)
+		CASE_LIT(EPaging)
+		CASE_LIT(EThreadPriority)
+		CASE_LIT(EPagingMedia)
+		CASE_LIT(EKernelMemory)
+		CASE_LIT(EHeap)
+		CASE_LIT(EMetaTrace)
+		CASE_LIT(ERamAllocator)
+		CASE_LIT(EFastMutex)
+		CASE_LIT(EProfiling)
+		CASE_REALLY_LIT(ExtraBTrace::EPubSub)
+		CASE_REALLY_LIT(ExtraBTrace::EFfsTrace)
+		CASE_LIT(EPlatformSpecificFirst)
+		CASE_LIT(EPlatformSpecificLast)
+		CASE_LIT(ESymbianExtentionsFirst)
+		CASE_LIT(ESymbianExtentionsLast)
+		CASE_LIT(ETest1)
+		CASE_LIT(ETest2)
+		default:
+			{
+			_LIT(KUnknown, "?");
+			return &KUnknown;
+			}
+		}
+	}
+
+void CCmdBtrace::DoRunL()
+	{
+#ifdef TEXT_TRACE_MODE_SUPPORTED
+	if (iOptions.IsPresent(&iTextTraceMode))
+		{
+		LoadMemoryAccessL();
+		const TInt ESerialOutMask = 3; // As per kernel.h
+		TInt err = iMemAccess.SetTextTraceMode(iTextTraceMode, ESerialOutMask);
+		LeaveIfErr(err, _L("Couldn't set text trace mode"));
+		}
+#endif
+
+	TInt i;
+	LeaveIfErr(iBtrace.Open(), _L("Couldn't open RBTrace"));
+
+	if (iOptions.IsPresent(&iReset))
+		{
+		ResetL();
+		}
+
+	if (iOptions.IsPresent(&iBufferSize))
+		{
+		iBtrace.ResizeBuffer(iBufferSize * 1024);
+		}
+
+	if (iOptions.IsPresent(&iMode))
+		{
+		SetMode(iMode);
+		}
+
+	iBtrace.SetTimestamp2Enabled(iEnableTimestamp2);
+
+	const TInt numPrimaryFilters = iPrimaryFilters.Count();
+	if (numPrimaryFilters > 0)
+		{
+		RemovePrimaryFilters();
+		EmptyBuffer();
+
+		// Enable the specified categories.
+		for (i = 0; i < numPrimaryFilters; ++i)
+			{
+			iBtrace.SetFilter(iPrimaryFilters[i], 1);
+			}
+		}
+	if (iTest)
+		{
+		TestL();
+		return;
+		}
+
+	const TInt numSecondaryFilters = iSecondaryFilters.Count();
+	if (numSecondaryFilters > 0)
+		{
+		TUint32* filterArray = new(ELeave) TUint32[iSecondaryFilters.Count()];
+		for (i = 0; i < numSecondaryFilters; ++i)
+			{
+			filterArray[i] = iSecondaryFilters[i];
+			}
+
+		TInt err = iBtrace.SetFilter2(filterArray, numSecondaryFilters);
+		if (err)
+			{
+			PrintError(err, _L("Couldn't set secondary filter"));
+			}
+		else
+			{
+			// Discard old data.
+			EmptyBuffer();
+			}
+
+		delete[] filterArray;
+		}
+
+	if (numPrimaryFilters > 0 || numSecondaryFilters > 0) 
+		{
+		BTrace8(BTrace::EMetaTrace, BTrace::EMetaTraceMeasurementEnd, KPrimingStopped, KPrimingStopped);
+		}
+
+	if (iFileName.Length())
+		{
+		RFile file;
+		User::LeaveIfError(file.Replace(FsL(), iFileName, EFileWrite));
+		file.Close();
+		}
+
+	if (iFileName.Length() || iDumpToRdebug)
+		{
+		if (iFollow)
+			{
+			if (iThreshold > 100)
+				{
+				PrintError(KErrArgument, _L("Invalid threshold percentage"));
+				User::Leave(KErrArgument);
+				}
+			Printf(_L("Hit any key to abort waiting and flush buffer...\r\n"));
+			TInt bytesRequired = (iBtrace.BufferSize() * iThreshold) / 100;
+			TBool finished(EFalse);
+			while (!finished)
+				{
+				TRequestStatus btraceStatus;
+				iBtrace.RequestData(btraceStatus, bytesRequired);
+				TRequestStatus keyStatus;
+				Stdin().WaitForKey(keyStatus);
+				if (iVerbose)
+					{
+					Printf(_L("Waiting for %d bytes in buffer\r\n"), bytesRequired);
+					}
+				User::WaitForRequest(btraceStatus, keyStatus);
+				if (keyStatus == KRequestPending)
+					{
+					Stdin().WaitForKeyCancel();
+					User::WaitForRequest(keyStatus);
+					User::LeaveIfError(btraceStatus.Int());
+					}
+				else
+					{
+					iBtrace.CancelRequestData();
+					User::WaitForRequest(btraceStatus);
+					finished = ETrue;
+					}
+
+				DumpL();
+				}
+			}
+		else
+			{
+			DumpL();
+			}
+		}
+
+	if (iVerbose || (iFileName.Length() == 0))
+		{
+		Printf(_L("Buffer size: %d\r\n"), iBtrace.BufferSize());
+		Printf(_L("Mode: %S (%u)\r\n"), ModeText(iBtrace.Mode()), iBtrace.Mode());
+#ifdef TEXT_TRACE_MODE_SUPPORTED
+		LoadMemoryAccessL();
+		TUint traceMode = 0;
+		TInt err = iMemAccess.SetTextTraceMode(traceMode, 0);
+		if (err)
+			{
+			PrintWarning(_L("Couldn't read text trace mode: err=%d"), err);
+			}
+		else
+			{
+			_LIT(KHuh, "<?>");
+			const TDesC* name = &KHuh;
+#define CASE_LIT2(x, y) case x: { _LIT(KName, #y); name = &KName; break; }
+			switch (traceMode)
+				{
+				CASE_LIT2(0, ESerialOutDefault)
+				CASE_LIT2(1, ESerialOutNever)
+				CASE_LIT2(2, ESerialOutAlways)
+				default:
+					break;
+				}
+			Printf(_L("Text trace mode: %S (%d)\r\n"), name, traceMode);
+			}
+#endif
+		Printf(_L("Primary filters:\r\n"));
+		TBool foundOne(EFalse);
+		for (TInt i = 0; i < KMaxCategories; ++i)
+			{
+			if (iBtrace.Filter(i) == 1)
+				{
+				Printf(_L("\t%d (%S)\r\n"), i, BtraceCategoryName(i));
+				foundOne = ETrue;
+				}
+			}
+		if (!foundOne)
+			{
+			Write(_L("\tnone\r\n"));
+			}
+		Printf(_L("Secondary filters: "));
+		TInt globalFilter;
+		TUint32* uids;
+		TInt ret = iBtrace.Filter2(uids, globalFilter);
+		if (ret >= 0)
+			{
+			if (globalFilter)
+				{
+				Printf(_L("[Secondary filters accept]\r\n"));
+				}
+			else
+				{
+				Printf(_L("[Secondary filters reject]\r\n"));
+				}
+			if (ret > 0)
+				{
+				for (TInt i = 0; i < ret; ++i)
+					{
+					Printf(_L("\t0x%08x\r\n"), uids[i]);
+					}
+				}
+			else
+				{
+				Write(_L("\tnone\r\n"));
+				}
+			delete uids;
+			}
+		else
+			{
+			PrintError(ret, _L("Unable to read secondary filters"));
+			}
+		}
+	}
+
+void CCmdBtrace::DumpL()
+	{
+	RFile file;
+	if (iFileName.Length())
+		{
+		if (iVerbose)
+			{
+			Printf(_L("Opening \"%S\"\r\n"), &iFileName);
+			}
+		User::LeaveIfError(file.Open(FsL(), iFileName, EFileWrite));
+		CleanupClosePushL(file);
+		TInt pos = 0;
+		User::LeaveIfError(file.Seek(ESeekEnd, pos));
+		}
+
+	TUint8* data;
+	TInt size;
+	TInt err = KErrNone;
+	while ((size = iBtrace.GetData(data)) != 0)
+		{
+		if (file.SubSessionHandle() && (err == KErrNone))
+			{
+			if (iVerbose)
+				{
+				Printf(_L("Writing %d bytes to \"%S\"\r\n"), size, &iFileName);
+				}
+			err = file.Write(TPtrC8(data,size));
+			if (err)
+				{
+				PrintError(err, _L("Couldn't write to file"));
+				}
+			}
+
+		if (iDumpToRdebug)
+			{
+			if (iVerbose)
+				{
+				Printf(_L("Writing %d bytes to LtkUtils::HexDumpToRDebug\r\n"), size);
+				}
+			LtkUtils::HexDumpToRDebug(TPtrC8(data, size));
+			}
+
+		iBtrace.DataUsed();
+		}
+
+	User::LeaveIfError(err);
+	if (iFileName.Length())
+		{
+		CleanupStack::PopAndDestroy(&file);
+		}
+	}
+
+void CCmdBtrace::ArgumentsL(RCommandArgumentList& aArguments)
+	{
+	_LIT(KArgFiles, "file_name");
+	aArguments.AppendFileNameL(iFileName, KArgFiles);
+	}
+
+void CCmdBtrace::OptionsL(RCommandOptionList& aOptions)
+	{
+	_LIT(KOptPrimaryFilter, "filter");
+	aOptions.AppendUintL(iPrimaryFilters, KOptPrimaryFilter);
+
+	_LIT(KOptSecondaryFilter, "secondary");
+	aOptions.AppendUintL(iSecondaryFilters, KOptSecondaryFilter);
+
+	_LIT(KOptMode, "mode");
+	aOptions.AppendUintL(iMode, KOptMode);
+
+	_LIT(KOptBufferSize, "buffer");
+	aOptions.AppendUintL(iBufferSize, KOptBufferSize);
+
+	_LIT(KOptDump, "dump");
+	aOptions.AppendBoolL(iDumpToRdebug, KOptDump);
+
+	_LIT(KOptFollow, "follow");
+	aOptions.AppendBoolL(iFollow, KOptFollow);
+
+	_LIT(KOptThreshold, "threshold");
+	aOptions.AppendUintL(iThreshold, KOptThreshold);
+
+	_LIT(KOptTimestamp2, "timestamp2");
+	aOptions.AppendBoolL(iEnableTimestamp2, KOptTimestamp2);
+
+	_LIT(KOptVerbose, "verbose");
+	aOptions.AppendBoolL(iVerbose, KOptVerbose);
+
+	_LIT(KOptTest, "test");
+	aOptions.AppendBoolL(iTest, KOptTest);
+
+	_LIT(KOptReset, "reset");
+	aOptions.AppendBoolL(iReset, KOptReset);
+
+#ifdef TEXT_TRACE_MODE_SUPPORTED
+	_LIT(KOptTextTraceMode, "text-trace-mode");
+	aOptions.AppendUintL(iTextTraceMode, KOptTextTraceMode);
+#endif
+	}
+
+#ifdef EXE_BUILD
+EXE_BOILER_PLATE(CCmdBtrace)
+#endif
+
+void CCmdBtrace::TestL()
+	{
+	SetMode(RBTrace::EEnable);
+	EmptyBuffer();
+	iBtrace.SetFilter(BTrace::ESymbianExtentionsFirst, 1);
+	_LIT8(KHello, "Hello world of btrace!!!");
+	TInt res = BTraceBig(BTrace::ESymbianExtentionsFirst, 0, 0, KHello().Ptr(), KHello().Size());
+	Printf(_L8("Writing text '%S' to btrace returned %d...\r\n"), &KHello, res);
+
+	TUint8* data;
+	TInt size;
+	TInt err = KErrNotFound;
+	while ((size = iBtrace.GetData(data)) != 0 && err == KErrNotFound)
+		{
+		Printf(_L("Read a buffer of size %d\r\n"), size);
+		TPtrC8 ptr(data, size);
+		if (ptr.Find(KHello) >= 0)
+			{
+			Printf(_L("Found text ok.\r\n"));
+			err = KErrNone;
+			}
+		}
+	if (err == KErrNotFound)
+		{
+		Printf(_L("Failed to find the test data\r\n"));
+		}
+	}
+
+void CCmdBtrace::ResetL()
+	{
+	SetMode(0);
+	EmptyBuffer();
+	RemovePrimaryFilters();
+	RemoveSecondaryFiltersL();
+	}
+
+void CCmdBtrace::SetMode(TUint aMode)
+	{
+	if (iVerbose)
+		{
+		Printf(_L("Setting mode to \"%S\" (%u)\r\n"), ModeText(aMode), aMode);
+		}
+
+	iBtrace.SetMode(aMode);
+	}
+
+void CCmdBtrace::EmptyBuffer()
+	{
+	if (iVerbose)
+		{
+		Write(_L("Discarding contents of trace buffer...\r\n"));
+		}
+
+	iBtrace.Empty();
+	}
+
+void CCmdBtrace::RemovePrimaryFilters()
+	{
+	if (iVerbose)
+		{
+		Write(_L("Removing all primary filters...\r\n"));
+		}
+
+	for (TInt i = 0; i < KMaxCategories; ++i)
+		{
+		iBtrace.SetFilter(i, 0);
+		}
+	}
+
+void CCmdBtrace::RemoveSecondaryFiltersL()
+	{
+	if (iVerbose)
+		{
+		Write(_L("Removing all secondary filters...\r\n"));
+		}
+
+	LeaveIfErr(iBtrace.SetFilter2((const TUint32*)NULL, 0), _L("Couldn't remove all secondary filters"));
+	}
+
+const TDesC* CCmdBtrace::ModeText(TUint aMode) const
+	{
+	_LIT(KDisabled, "disabled");
+	_LIT(KEnabled, "enabled");
+	_LIT(KFreeRunning, "enabled and free running");
+	_LIT(KUnknown, "unknown");
+
+	switch (aMode)
+		{
+		case 0:
+			return &KDisabled;
+		case RBTrace::EEnable:
+			return &KEnabled;
+		case RBTrace::EEnable | RBTrace::EFreeRunning:
+			return &KFreeRunning;
+		default:
+			return &KUnknown;
+		}
+	}
+