kerneltest/e32utils/trace/btrace.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

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