diff -r 849a0b46c767 -r dc41da2f70a4 commands/showdebug/showdebug.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/commands/showdebug/showdebug.cpp Thu Oct 21 22:32:59 2010 +0100 @@ -0,0 +1,298 @@ +// showdebug.cpp +// +// Copyright (c) 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 +#include +#include +#include + +using namespace IoUtils; + +class CCmdShowDebug : public CCommandBase, public MCommandExtensionsV2 + { +public: + static CCommandBase* NewLC(); + ~CCmdShowDebug(); +private: + CCmdShowDebug(); + void Log(TUint8 aWhere, TUint32 aTickCount, TUint aThreadId, const TDesC8& aMsg); + inline TTime TickCountToTime(TUint32 aTickCount) const; + +private: // From CCommandBase. + virtual const TDesC& Name() const; + virtual void DoRunL(); + virtual void ArgumentsL(RCommandArgumentList& aArguments); + virtual void OptionsL(RCommandOptionList& aOptions); + virtual void DoCancel(); + virtual void RunL(); + +private: // From MCommandExtensionsV2 + virtual void CtrlCPressed(); + + + class CLogonCompleter : public CActive + { + public: + CLogonCompleter(CCmdShowDebug* aCommand) : CActive(CActive::EPriorityStandard), iCommand(aCommand) + { + CActiveScheduler::Add(this); + iCommand->iProcess.Process().Logon(iStatus); + SetActive(); + } + void RunL() { iCommand->Complete(iStatus.Int()); } + void DoCancel() { iCommand->iProcess.Process().LogonCancel(iStatus); } + ~CLogonCompleter() { Cancel(); } + + private: + CCmdShowDebug* iCommand; + }; + +private: + RCloggerDebugRouter iRouter; + RChunk iChunk; + TBuf8<2048> iTempBuf; + TBuf<2048> iTempWideBuf; + RChildProcess iProcess; + CLogonCompleter* iCompleter; + TInt64 iStartupTickInMicroseconds; + TTime iTimeAtStartup; + TInt iTickFreq; + + HBufC* iProcessName; + HBufC* iArgs; + RArray iVerbose; + TBool iFilter; + }; + +EXE_BOILER_PLATE(CCmdShowDebug) + +CCommandBase* CCmdShowDebug::NewLC() + { + CCmdShowDebug* self = new(ELeave) CCmdShowDebug(); + CleanupStack::PushL(self); + self->BaseConstructL(); + return self; + } + +CCmdShowDebug::~CCmdShowDebug() + { + Cancel(); + if (iRouter.Handle()) + { + iRouter.EnableDebugRouting(RCloggerDebugRouter::EDisable); + } + iRouter.Close(); + iChunk.Close(); + delete iCompleter; + if (iProcess.Process().Handle() && iProcess.Process().ExitType() == EExitPending) + { + iProcess.Process().Kill(KErrAbort); + } + iProcess.Close(); + delete iProcessName; + delete iArgs; + } + +CCmdShowDebug::CCmdShowDebug() + : CCommandBase(EManualComplete | ECaptureCtrlC) + { + SetExtension(this); + } + +const TDesC& CCmdShowDebug::Name() const + { + _LIT(KName, "showdebug"); + return KName; + } + +void CCmdShowDebug::ArgumentsL(RCommandArgumentList& aArguments) + { + aArguments.AppendStringL(iProcessName, _L("process")); + aArguments.AppendStringL(iArgs, _L("arguments")); + } + +void CCmdShowDebug::OptionsL(RCommandOptionList& aOptions) + { + aOptions.AppendBoolL(iVerbose, _L("verbose")); + aOptions.AppendBoolL(iFilter, _L("filter")); + } + +void CCmdShowDebug::DoRunL() + { + TInt err = RCloggerDebugRouter::LoadDriver(); + if (err != KErrAlreadyExists) LeaveIfErr(err, _L("Couldn't load clogger debug router")); + LeaveIfErr(iRouter.Open(), _L("Couldn't open debug router")); + LeaveIfErr(iRouter.OpenChunk(iChunk), _L("Couldn't open debug router shared chunk")); + LeaveIfErr(iRouter.EnableDebugRouting(RCloggerDebugRouter::EEnableRouting), _L("Couldn't enable routing")); + + iRouter.ReceiveData(iStatus); + SetActive(); + + if (iProcessName) + { + TRAPL(iProcess.CreateL(*iProcessName, iArgs ? *iArgs : KNullDesC(), IoSession(), Stdin(), Stdout(), Stderr(), Env()), _L("Failed to execute %S"), iProcessName); + iCompleter = new(ELeave) CLogonCompleter(this); + SetErrorReported(ETrue); // So that if iProcess completes with an error it doesn't cause a strange printout when we complete with its error code + iProcess.Process().Resume(); + } + + if (iVerbose.Count()) + { + // Need to do some maths to figure out how to translate tick counts to time + TUint32 tickCount = User::NTickCount(); + iTimeAtStartup.UniversalTime(); + TInt tickPeriod; + User::LeaveIfError(HAL::Get(HAL::ENanoTickPeriod, tickPeriod)); + iTickFreq = 1000000 / tickPeriod; // We work in frequencies because they are the round numbers when using the fast counter, and at some point we might want to again + + iStartupTickInMicroseconds = ((TInt64)tickCount * 1000000) / (TInt64)iTickFreq; // Just making damn sure we're using 64bit math + } + } + +void CCmdShowDebug::DoCancel() + { + iRouter.CancelReceive(); + } + +TPtrC8 Read(TDes8& aTempBuf, TPtrC8& aData, TInt aLength, TPtrC8& aOverflowData) + { + if (aLength <= aData.Length()) + { + // Can read it from this buffer + TPtrC8 res(aData.Left(aLength)); + aData.Set(aData.Mid(aLength)); + return res; + } + else /*if (aLength > aData.Length())*/ + { + // Descriptor spans wrap point, so need to copy into temp buf + aTempBuf.Copy(aData.Left(aTempBuf.MaxLength())); // If anyone's crazy enough to write a platsec diagnostic string longer than 2k, it gets truncated + TInt overflowLen = aLength - aData.Length(); + aData.Set(aOverflowData); // Wrap aData + aOverflowData.Set(TPtrC8()); + if (overflowLen > aData.Length()) + { + ASSERT(EFalse); // Shouldn't happen + // in urel, return everything we've got + return aData; + } + aTempBuf.Append(aData.Left(overflowLen)); + aData.Set(aData.Mid(overflowLen)); + return TPtrC8(aTempBuf); + } + } + +void CCmdShowDebug::RunL() + { + TUint chunkSize = iChunk.Size(); + const TUint KDataStartOffset = sizeof(SDebugChunkHeader); + SDebugChunkHeader* chunkHeader = (SDebugChunkHeader*)iChunk.Base(); + TUint start = chunkHeader->iStartOffset; + TUint end = chunkHeader->iEndOffset; + TUint overflows = chunkHeader->iOverflows; + + TBool wrap = (start > end); + TUint endLen = wrap ? chunkSize - start : end - start; + TUint startLen = wrap ? end - KDataStartOffset : 0; + + TPtrC8 endData(iChunk.Base() + start, endLen); + TPtrC8 startData; + if (wrap) startData.Set(iChunk.Base() + KDataStartOffset, startLen); + TPtrC8 data(endData); + + while (data.Length()) + { + TPtrC8 header = Read(iTempBuf, data, sizeof(SCloggerTraceInfo), startData); + if (header.Length() < (TInt)sizeof(SCloggerTraceInfo)) + { + ASSERT(EFalse); // for udeb + break; // Something's broken + } + SCloggerTraceInfo info; + Mem::Copy(&info, header.Ptr(), sizeof(SCloggerTraceInfo)); + ASSERT(info.iTraceType == 'K' || info.iTraceType == 'U' || info.iTraceType == 'P'); + TPtrC8 msg = Read(iTempBuf, data, info.iLength, startData); + Log(info.iTraceType, info.iTickCount, info.iThreadId, msg); + } + if (overflows) + { + _LIT(KErr, "RDebug::Print buffer overflowed, %u calls not logged"); + PrintWarning(KErr, overflows); + } + + iRouter.ReceiveData(iStatus); + SetActive(); + } + +void CCmdShowDebug::Log(TUint8 /*aWhere*/, TUint32 aTickCount, TUint aThreadId, const TDesC8& aMsg) + { + RThread thread; thread.SetHandle(0); + if (iVerbose.Count() > 1 || iFilter) + { + // Need to open the thread in those cases + thread.Open(aThreadId); + } + + if (iFilter && thread.Handle()) + { + RProcess proc; + TInt err = thread.Process(proc); + if (!err) + { + if (proc.Id() != iProcess.Process().Id()) + { + // Trace definitely doesn't belong to our process, skip it + proc.Close(); + thread.Close(); + return; + } + } + } + + if (iVerbose.Count()) + { + TDateTime dt = TickCountToTime(aTickCount).DateTime(); + _LIT(KFormat, "%i-%02i-%02i %02i:%02i:%02i.%03i: "); + // Have to add 1 to Month and Day, as these are zero-based + iTempWideBuf.Format(KFormat, dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond()/1000); + if (iVerbose.Count() > 1 && thread.Handle()) + { + TFullName name = thread.FullName(); + iTempWideBuf.AppendFormat(_L("%S "), &name); + } + else + { + // Just use thread id + iTempWideBuf.AppendFormat(_L("[%d] "), aThreadId); + } + Write(iTempWideBuf); + } + + thread.Close(); + + iTempWideBuf.Copy(aMsg); + Write(iTempWideBuf); + Write(_L("\r\n")); + } + +void CCmdShowDebug::CtrlCPressed() + { + // TODO clean up iProcess + + Printf(_L("CTRL-C received, exiting.\r\n")); + Complete(); + } + +inline TTime CCmdShowDebug::TickCountToTime(TUint32 aTickCount) const + { + return TTime(iTimeAtStartup.Int64() + (((TInt64)aTickCount*1000000) / (TInt64)iTickFreq) - iStartupTickInMicroseconds); + }