Added ENotifyKeypresses and ECaptureCtrlC flags to CCommandBase.
Commands can now get keypresses and handle ctrl-C via callbacks instead of having to implement custom active objects. As part of this extended the CCommandBase extension interface to MCommandExtensionsV2 for the new virtual functions KeyPressed(TUint aKeyCode, TUint aModifiers) and CtrlCPressed(). sudo now cleans up correctly by using ECaptureCtrlC.
// 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;
}
}