kerneltest/e32utils/trace/btrace.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32utils/trace/btrace.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,455 @@
+// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32utils\trace\btrace.cpp
+// 
+//
+
+#include <e32cons.h>
+#include <f32file.h>
+#include <d32btrace.h>
+
+CConsoleBase* Console;
+extern RBTrace Trace;
+
+#undef ASSERT
+#define ASSERT(c) (void)((c)||(AssertFailed(__LINE__)))
+
+TInt AssertFailed(TInt aLine)
+	{
+	_LIT(KPanicCategory,"ASSERT");
+	User::Panic(KPanicCategory,aLine);
+	return 0;
+	}
+
+
+int strlen(const char* string)
+	{
+	int len=0;
+	while(string[len]) ++len;
+	return len;
+	}
+
+
+class TDesTruncate : public TDes8Overflow { void Overflow(TDes8&) {}; } IgnoreOverflow;
+
+void printf(const char* aFormat,...)
+	{
+	TPtrC8 formatDes((TUint8*)aFormat,strlen(aFormat));
+	VA_LIST list;
+	VA_START(list, aFormat);
+	TBuf16<0x100> buffer;
+	// coverity[uninit_use_in_call]
+	((TDes8&)buffer).AppendFormatList(formatDes, list, &IgnoreOverflow);
+	Console->Write(((TDes8&)buffer).Expand());
+	}
+
+
+TInt getch()
+	{
+	TRequestStatus keyStat;
+	Console->Read(keyStat);
+	User::WaitForRequest(keyStat);
+	return Console->KeyCode();
+	}
+
+
+TInt getch(TInt aTimeout)
+	{
+	TRequestStatus keyStat;
+	Console->Read(keyStat);
+	RTimer timer;
+	TInt r=timer.CreateLocal();
+	ASSERT(r==KErrNone);
+	TRequestStatus timerStat;
+	timer.After(timerStat,aTimeout*1000000);
+	User::WaitForRequest(timerStat,keyStat);
+	TInt key = -1;
+	if(keyStat!=KRequestPending)
+		key = Console->KeyCode();
+	timer.Cancel();
+	Console->ReadCancel();
+	User::WaitForAnyRequest();
+	return key;
+	}
+
+
+int Main(int argc, char** argv);
+
+
+void exit_btrace(int result)
+	{
+	User::Exit(result);
+	}
+
+
+TInt E32Main()
+	{
+	// create console...
+	TFileName exeFile = RProcess().FileName();
+	TRAPD(r, Console = Console::NewL(exeFile,TSize(KConsFullScreen,KConsFullScreen)));
+	ASSERT(r==KErrNone);
+
+	// get command-line...
+	RBuf clDes;
+	ASSERT(clDes.Create(User::CommandLineLength()+1)==KErrNone);
+	User::CommandLine(clDes);
+	char* cl = (char*)clDes.Collapse().PtrZ(); // convert to null terminated C string
+
+	// split up args...
+	RPointerArray<TAny> argArray;
+	ASSERT(KErrNone==argArray.Append(exeFile.Collapse().Ptr())); // first arg is program name
+	for(;;)
+		{
+		while((unsigned)(*cl-1)<(unsigned)' ') ++cl; // skip whitespace
+		if(!*cl) break;
+		ASSERT(KErrNone==argArray.Append(cl));
+		while(*++cl>' ') {}; // skip non-whitespace
+		if(!*cl) break;
+		*cl++ = 0; // add null terminator to arg
+		}
+
+	// call main...
+	return Main(argArray.Count(),(char**)&argArray[0]);
+	}
+
+
+int Error()
+	{
+	getch(5); // pause for a while
+	exit_btrace(-1);
+	return 0;
+	}
+
+
+char* FileName = 0;
+char* PrimaryFilterArg = NULL;
+bool SetFilter2 = false;
+RArray<TUint32> Filter2;
+bool SetMode = false;
+unsigned Mode = 0;
+bool SetBufferSize = false;
+unsigned BufferSize = 0;
+bool DumpToDebugPort = false;
+TInt AnalysisLevel = 0;
+bool Analyse = false;
+bool DiscardOldData = true;
+
+RFs Fs;
+RFile File;
+void RePrime();
+
+void Dump()
+	{
+	TUint oldMode = Trace.Mode();
+	Trace.SetMode(0); // turn off trace capture while we dump
+
+	TUint8* data;
+	TInt size;
+	while((size=Trace.GetData(data))!=0)
+		{
+		if(FileName)
+			{
+			TInt r=File.Write(TPtrC8(data,size));
+			if(r!=KErrNone)
+				{
+				printf("Error writing to file (1). (Code %d)",r);
+				Error();
+				}
+			}
+		if(DumpToDebugPort)
+			{
+			do
+				{
+				int s = size;
+				if(s>256) s=256;
+				RDebug::RawPrint(TPtrC8(data,s));
+				data += s;
+				size -= s;
+				}
+			while(size);
+			}
+		Trace.DataUsed();
+		}
+	// Flush the file here so we can be sure to detect whether the btrace data 
+	// has been written successfully to the file.
+	if (FileName)
+		{
+		// Flush the file here so we can be sure to detect whether the btrace data 
+		// has been written successfully to the file.
+		TInt r = File.Flush();
+		if (r != KErrNone)
+			{
+			printf("Error writing to file (2). (Code %d)",r);
+			Error();
+			}
+		File.Close();
+		}
+
+	Trace.SetMode(oldMode);
+	RePrime();
+	}
+
+bool SetFilter(char* args);
+void DoAnalyse(TInt aAnalysisLevel);
+
+int DoCommand()
+	{
+
+	if(SetBufferSize)
+		Trace.ResizeBuffer(BufferSize*1024);
+
+	if(SetMode)
+		Trace.SetMode(Mode);
+
+	if (PrimaryFilterArg)
+		SetFilter(PrimaryFilterArg);
+
+	if(SetFilter2)
+		{
+		TInt r = Trace.SetFilter2(&Filter2[0], Filter2.Count());
+		if(r<0)
+			{
+			printf("Error setting secondary filter. (%d)",r);
+			Error();
+			}
+		if (DiscardOldData)
+			Trace.Empty(); // discard old data
+		}
+
+	if(FileName || DumpToDebugPort)
+		Dump();
+
+	if(Analyse)
+		DoAnalyse(AnalysisLevel);
+
+	return 0;
+	}
+
+
+unsigned int ParseDecimal(char*& args)
+	{
+	unsigned int i=0;
+	unsigned int d;
+	while((d=*args-'0')<10u)
+		{
+		++args;
+		i = i*10+d;
+		}
+	return i;
+	}
+
+
+bool SetFilter(char* args)
+	{
+	unsigned i;
+	// Turn everything off and discard old data
+	for(i=0; i<256; i++)
+		{			
+		Trace.SetFilter(i,0); 
+		}
+	if (DiscardOldData)
+		Trace.Empty();
+
+	// Iterate over comma-seperated filter numbers
+	bool set_metatrace = false;
+	while((unsigned)(*args-'0')<10u)
+		{
+		unsigned int i = ParseDecimal(args);
+		if(i>=256)
+			{
+			printf("Primary filter value out of range");
+			Error();
+			}
+		if (!set_metatrace) 
+			{
+			set_metatrace = true;
+			Trace.SetFilter(BTrace::EMetaTrace,1);
+			}
+		Trace.SetFilter(i,1);
+		if(*args==',')
+			++args;
+		}
+	return (*args==0);
+	}
+
+
+bool ParseFilter2(char* args)
+	{
+	while((unsigned)(*args-'0') < 10u)
+		{
+		unsigned int i = ParseDecimal(args);
+		TInt r = Filter2.Append(i);
+		if(r<0)
+			{
+			printf("Error parsing secondary filter. (%d)",r);
+			Error();
+			}
+		if(*args==',')
+			{
+			++args;
+			}
+		}
+	return SetFilter2=(*args==0);
+	}
+
+
+bool ParseMode(char* args)
+	{
+	Mode = ParseDecimal(args);
+	return SetMode=(*args==0);
+	}
+
+
+bool ParseBufferSize(char* args)
+	{
+	BufferSize = ParseDecimal(args);
+	return SetBufferSize=(*args==0);
+	}
+
+
+bool ParseAnalyse(char* args)
+	{
+	AnalysisLevel = ParseDecimal(args);
+	return Analyse=(*args==0);
+	}
+
+
+int CreateFile(char* name)
+	{
+	if(FileName)
+		{
+		printf("Too many arguments");
+		return Error();
+		}
+
+	FileName = name;
+	unsigned nameLen = strlen(name);
+	if(nameLen>(unsigned)KMaxFileName)
+		{
+		printf("File name too long.\n");
+		return Error();
+		}
+
+	TInt r;
+	if(!Fs.Handle())
+		{
+		r = Fs.Connect();
+		if(r!=KErrNone)
+			{
+			printf("Couldn't connect to file server. (%d)\n",r);
+			return Error();
+			}
+		}
+
+	TBuf8<KMaxFileName*2> fn = TPtrC8((TUint8*)name,nameLen);
+	r = File.Replace(Fs,fn.Expand(),EFileWrite);
+	if(r!=KErrNone)
+		{
+		printf("Couldn't create file: %s. (%d)\n",name,r);
+		return Error();
+		}
+
+	return 0;
+	}
+
+
+int Help()
+	{
+	printf("Usage: BTRACE [options] [filename]\n");
+	printf("\n");
+	printf("Options:\n");
+	printf("-fLIST   Set primary filter to a LIST of comma separated category numbers.\n");
+	printf("         This argument may be used more than once e.g. -f1,22,3 -f44 \n");
+	printf("-sLIST   Set secondary filter to a LIST of comma separated UID values.\n");
+	printf("         This argument may be used more than once e.g. -s1221,22,343243 -s3242344 \n");
+	printf("-mN      Set capture mode to value N (See RBTrace::TMode)\n");
+	printf("-bN      Set capture buffer size to N kBytes\n");
+	printf("-d       Dump contents of trace buffer to debug port\n");
+	printf("-tsNAME  Output a test measurement start trace with text NAME. This text\n");
+	printf("         may be between 0 and 80 non-whitespace characters.\n");
+	printf("-te      Output a test measurement end trace\n");
+	printf("-aLEVEL  Analyse trace buffer and produce a report. UNSUPPORTED!\n");
+	printf("-k       Keep old contents of trace buffer when enabling a new filter\n");
+	printf("filename File to dump contents of trace buffer to.\n");
+	getch();
+	return 0;
+	}
+
+
+int Main(int argc, char** argv)
+	{
+	if(argc<=1)
+		return Help();
+
+	TInt r = Trace.Open();
+	if(r!=KErrNone)
+		{
+		printf("Couldn't open BTrace driver. (Code %d)",r);
+		Error();
+		return r;
+		}
+
+	char* a;
+	while(--argc)
+		{
+		a = *++argv;
+		if(a[0]!='-')
+			{
+			CreateFile(a);
+			continue;
+			}
+
+		int r=0;
+		switch(a[1])
+			{
+		case 'f': PrimaryFilterArg = a+2; r = true; break;
+		case 's': r=ParseFilter2(a+2); break;
+		case 'm': r=ParseMode(a+2); break;
+		case 'b': r=ParseBufferSize(a+2); break;
+		case 'd': r=a[2]==0; DumpToDebugPort = true; break;
+		case 't': 
+			{
+			if (a[2]=='s') 
+				{
+				TUint cch=strlen(a);
+				if (cch > KMaxBTraceDataArray)
+					cch = KMaxBTraceDataArray;
+				int buff[KMaxBTraceDataArray/sizeof(int)];
+				a+=3;
+				memcpy(buff, a, cch);
+				BTraceContextN(BTrace::EMetaTrace, BTrace::EMetaTraceMeasurementStart, 0,0, buff, cch);
+				r=1;
+				}
+			else if (a[2]=='e')
+				{
+				BTraceContext8(BTrace::EMetaTrace, BTrace::EMetaTraceMeasurementEnd, 0,0);
+				r=1;
+				}
+			}
+			break;
+		case 'a': r=ParseAnalyse(a+2); break;
+		case 'k': DiscardOldData = false; r = true; break;
+		default: break;
+			}
+
+		if(!r)
+			{
+			printf("Bad command line argument: %s",a);
+			Error();
+			}
+		}
+
+	return DoCommand();
+	}
+