commands/showdebug/showdebug.cpp
changeset 73 dc41da2f70a4
equal deleted inserted replaced
69:849a0b46c767 73:dc41da2f70a4
       
     1 // showdebug.cpp
       
     2 // 
       
     3 // Copyright (c) 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include <fshell/ioutils.h>
       
    14 #include <fshell/common.mmh>
       
    15 #include <fshell/debugrouter.h>
       
    16 #include <HAL.h>
       
    17 
       
    18 using namespace IoUtils;
       
    19 
       
    20 class CCmdShowDebug : public CCommandBase, public MCommandExtensionsV2
       
    21 	{
       
    22 public:
       
    23 	static CCommandBase* NewLC();
       
    24 	~CCmdShowDebug();
       
    25 private:
       
    26 	CCmdShowDebug();
       
    27 	void Log(TUint8 aWhere, TUint32 aTickCount, TUint aThreadId, const TDesC8& aMsg);
       
    28 	inline TTime TickCountToTime(TUint32 aTickCount) const;
       
    29 
       
    30 private: // From CCommandBase.
       
    31 	virtual const TDesC& Name() const;
       
    32 	virtual void DoRunL();
       
    33 	virtual void ArgumentsL(RCommandArgumentList& aArguments);
       
    34 	virtual void OptionsL(RCommandOptionList& aOptions);
       
    35 	virtual void DoCancel();
       
    36 	virtual void RunL();
       
    37 
       
    38 private: // From MCommandExtensionsV2
       
    39 	virtual void CtrlCPressed();
       
    40 
       
    41 
       
    42 	class CLogonCompleter : public CActive
       
    43 		{
       
    44 	public:
       
    45 		CLogonCompleter(CCmdShowDebug* aCommand) : CActive(CActive::EPriorityStandard), iCommand(aCommand)
       
    46 			{
       
    47 			CActiveScheduler::Add(this);
       
    48 			iCommand->iProcess.Process().Logon(iStatus);
       
    49 			SetActive();
       
    50 			}
       
    51 		void RunL() { iCommand->Complete(iStatus.Int()); }
       
    52 		void DoCancel() { iCommand->iProcess.Process().LogonCancel(iStatus); }
       
    53 		~CLogonCompleter() { Cancel(); }
       
    54 
       
    55 	private:
       
    56 		CCmdShowDebug* iCommand;
       
    57 		};
       
    58 
       
    59 private:
       
    60 	RCloggerDebugRouter iRouter;
       
    61 	RChunk iChunk;
       
    62 	TBuf8<2048> iTempBuf;
       
    63 	TBuf<2048> iTempWideBuf;
       
    64 	RChildProcess iProcess;
       
    65 	CLogonCompleter* iCompleter;
       
    66 	TInt64 iStartupTickInMicroseconds;
       
    67 	TTime iTimeAtStartup;
       
    68 	TInt iTickFreq;
       
    69 
       
    70 	HBufC* iProcessName;
       
    71 	HBufC* iArgs;
       
    72 	RArray<TBool> iVerbose;
       
    73 	TBool iFilter;
       
    74 	};
       
    75 
       
    76 EXE_BOILER_PLATE(CCmdShowDebug)
       
    77 
       
    78 CCommandBase* CCmdShowDebug::NewLC()
       
    79 	{
       
    80 	CCmdShowDebug* self = new(ELeave) CCmdShowDebug();
       
    81 	CleanupStack::PushL(self);
       
    82 	self->BaseConstructL();
       
    83 	return self;
       
    84 	}
       
    85 
       
    86 CCmdShowDebug::~CCmdShowDebug()
       
    87 	{
       
    88 	Cancel();
       
    89 	if (iRouter.Handle())
       
    90 		{
       
    91 		iRouter.EnableDebugRouting(RCloggerDebugRouter::EDisable);
       
    92 		}
       
    93 	iRouter.Close();
       
    94 	iChunk.Close();
       
    95 	delete iCompleter;
       
    96 	if (iProcess.Process().Handle() && iProcess.Process().ExitType() == EExitPending)
       
    97 		{
       
    98 		iProcess.Process().Kill(KErrAbort);
       
    99 		}
       
   100 	iProcess.Close();
       
   101 	delete iProcessName;
       
   102 	delete iArgs;
       
   103 	}
       
   104 
       
   105 CCmdShowDebug::CCmdShowDebug()
       
   106 	: CCommandBase(EManualComplete | ECaptureCtrlC)
       
   107 	{
       
   108 	SetExtension(this);
       
   109 	}
       
   110 
       
   111 const TDesC& CCmdShowDebug::Name() const
       
   112 	{
       
   113 	_LIT(KName, "showdebug");	
       
   114 	return KName;
       
   115 	}
       
   116 
       
   117 void CCmdShowDebug::ArgumentsL(RCommandArgumentList& aArguments)
       
   118 	{
       
   119 	aArguments.AppendStringL(iProcessName, _L("process"));
       
   120 	aArguments.AppendStringL(iArgs, _L("arguments"));
       
   121 	}
       
   122 
       
   123 void CCmdShowDebug::OptionsL(RCommandOptionList& aOptions)
       
   124 	{
       
   125 	aOptions.AppendBoolL(iVerbose, _L("verbose"));
       
   126 	aOptions.AppendBoolL(iFilter, _L("filter"));
       
   127 	}
       
   128 
       
   129 void CCmdShowDebug::DoRunL()
       
   130 	{
       
   131 	TInt err = RCloggerDebugRouter::LoadDriver();
       
   132 	if (err != KErrAlreadyExists) LeaveIfErr(err, _L("Couldn't load clogger debug router"));
       
   133 	LeaveIfErr(iRouter.Open(), _L("Couldn't open debug router"));
       
   134 	LeaveIfErr(iRouter.OpenChunk(iChunk), _L("Couldn't open debug router shared chunk"));
       
   135 	LeaveIfErr(iRouter.EnableDebugRouting(RCloggerDebugRouter::EEnableRouting), _L("Couldn't enable routing"));
       
   136 
       
   137 	iRouter.ReceiveData(iStatus);
       
   138 	SetActive();
       
   139 
       
   140 	if (iProcessName)
       
   141 		{
       
   142 		TRAPL(iProcess.CreateL(*iProcessName, iArgs ? *iArgs : KNullDesC(), IoSession(), Stdin(), Stdout(), Stderr(), Env()), _L("Failed to execute %S"), iProcessName);
       
   143 		iCompleter = new(ELeave) CLogonCompleter(this);
       
   144 		SetErrorReported(ETrue); // So that if iProcess completes with an error it doesn't cause a strange printout when we complete with its error code
       
   145 		iProcess.Process().Resume();
       
   146 		}
       
   147 
       
   148 	if (iVerbose.Count())
       
   149 		{
       
   150 		// Need to do some maths to figure out how to translate tick counts to time
       
   151 		TUint32 tickCount = User::NTickCount();
       
   152 		iTimeAtStartup.UniversalTime();
       
   153 		TInt tickPeriod;
       
   154 		User::LeaveIfError(HAL::Get(HAL::ENanoTickPeriod, tickPeriod));
       
   155 		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
       
   156 
       
   157 		iStartupTickInMicroseconds = ((TInt64)tickCount * 1000000) / (TInt64)iTickFreq; // Just making damn sure we're using 64bit math
       
   158 		}
       
   159 	}
       
   160 
       
   161 void CCmdShowDebug::DoCancel()
       
   162 	{
       
   163 	iRouter.CancelReceive();
       
   164 	}
       
   165 
       
   166 TPtrC8 Read(TDes8& aTempBuf, TPtrC8& aData, TInt aLength, TPtrC8& aOverflowData)
       
   167 	{
       
   168 	if (aLength <= aData.Length())
       
   169 		{
       
   170 		// Can read it from this buffer
       
   171 		TPtrC8 res(aData.Left(aLength));
       
   172 		aData.Set(aData.Mid(aLength));
       
   173 		return res;
       
   174 		}
       
   175 	else /*if (aLength > aData.Length())*/
       
   176 		{
       
   177 		// Descriptor spans wrap point, so need to copy into temp buf
       
   178 		aTempBuf.Copy(aData.Left(aTempBuf.MaxLength())); // If anyone's crazy enough to write a platsec diagnostic string longer than 2k, it gets truncated
       
   179 		TInt overflowLen = aLength - aData.Length();
       
   180 		aData.Set(aOverflowData); // Wrap aData
       
   181 		aOverflowData.Set(TPtrC8());
       
   182 		if (overflowLen > aData.Length())
       
   183 			{
       
   184 			ASSERT(EFalse); // Shouldn't happen
       
   185 			// in urel, return everything we've got
       
   186 			return aData;
       
   187 			}
       
   188 		aTempBuf.Append(aData.Left(overflowLen));
       
   189 		aData.Set(aData.Mid(overflowLen));
       
   190 		return TPtrC8(aTempBuf);
       
   191 		}
       
   192 	}
       
   193 
       
   194 void CCmdShowDebug::RunL()
       
   195 	{
       
   196 	TUint chunkSize = iChunk.Size();
       
   197 	const TUint KDataStartOffset = sizeof(SDebugChunkHeader);
       
   198 	SDebugChunkHeader* chunkHeader = (SDebugChunkHeader*)iChunk.Base();
       
   199 	TUint start = chunkHeader->iStartOffset;
       
   200 	TUint end = chunkHeader->iEndOffset;
       
   201 	TUint overflows = chunkHeader->iOverflows;
       
   202 
       
   203 	TBool wrap = (start > end);
       
   204 	TUint endLen = wrap ? chunkSize - start : end - start;
       
   205 	TUint startLen = wrap ? end - KDataStartOffset : 0;
       
   206 
       
   207 	TPtrC8 endData(iChunk.Base() + start, endLen);
       
   208 	TPtrC8 startData;
       
   209 	if (wrap) startData.Set(iChunk.Base() + KDataStartOffset, startLen);
       
   210 	TPtrC8 data(endData);
       
   211 
       
   212 	while (data.Length())
       
   213 		{
       
   214 		TPtrC8 header = Read(iTempBuf, data, sizeof(SCloggerTraceInfo), startData);
       
   215 		if (header.Length() < (TInt)sizeof(SCloggerTraceInfo))
       
   216 			{
       
   217 			ASSERT(EFalse); // for udeb
       
   218 			break; // Something's broken
       
   219 			}
       
   220 		SCloggerTraceInfo info;
       
   221 		Mem::Copy(&info, header.Ptr(), sizeof(SCloggerTraceInfo));
       
   222 		ASSERT(info.iTraceType == 'K' || info.iTraceType == 'U' || info.iTraceType == 'P');
       
   223 		TPtrC8 msg = Read(iTempBuf, data, info.iLength, startData);
       
   224 		Log(info.iTraceType, info.iTickCount, info.iThreadId, msg);
       
   225 		}
       
   226 	if (overflows)
       
   227 		{
       
   228 		_LIT(KErr, "RDebug::Print buffer overflowed, %u calls not logged");
       
   229 		PrintWarning(KErr, overflows);
       
   230 		}
       
   231 
       
   232 	iRouter.ReceiveData(iStatus);
       
   233 	SetActive();
       
   234 	}
       
   235 
       
   236 void CCmdShowDebug::Log(TUint8 /*aWhere*/, TUint32 aTickCount, TUint aThreadId, const TDesC8& aMsg)
       
   237 	{
       
   238 	RThread thread; thread.SetHandle(0);
       
   239 	if (iVerbose.Count() > 1 || iFilter)
       
   240 		{
       
   241 		// Need to open the thread in those cases
       
   242 		thread.Open(aThreadId);
       
   243 		}
       
   244 
       
   245 	if (iFilter && thread.Handle())
       
   246 		{
       
   247 		RProcess proc;
       
   248 		TInt err = thread.Process(proc);
       
   249 		if (!err)
       
   250 			{
       
   251 			if (proc.Id() != iProcess.Process().Id())
       
   252 				{
       
   253 				// Trace definitely doesn't belong to our process, skip it
       
   254 				proc.Close();
       
   255 				thread.Close();
       
   256 				return;
       
   257 				}
       
   258 			}
       
   259 		}
       
   260 	
       
   261 	if (iVerbose.Count())
       
   262 		{
       
   263 		TDateTime dt = TickCountToTime(aTickCount).DateTime();
       
   264 		_LIT(KFormat, "%i-%02i-%02i %02i:%02i:%02i.%03i: ");
       
   265 		// Have to add 1 to Month and Day, as these are zero-based
       
   266 		iTempWideBuf.Format(KFormat, dt.Year(), dt.Month()+1, dt.Day()+1, dt.Hour(), dt.Minute(), dt.Second(), dt.MicroSecond()/1000);
       
   267 		if (iVerbose.Count() > 1 && thread.Handle())
       
   268 			{
       
   269 			TFullName name = thread.FullName();
       
   270 			iTempWideBuf.AppendFormat(_L("%S "), &name);
       
   271 			}
       
   272 		else
       
   273 			{
       
   274 			// Just use thread id
       
   275 			iTempWideBuf.AppendFormat(_L("[%d] "), aThreadId);
       
   276 			}
       
   277 		Write(iTempWideBuf);
       
   278 		}
       
   279 
       
   280 	thread.Close();
       
   281 	
       
   282 	iTempWideBuf.Copy(aMsg);
       
   283 	Write(iTempWideBuf);
       
   284 	Write(_L("\r\n"));
       
   285 	}
       
   286 
       
   287 void CCmdShowDebug::CtrlCPressed()
       
   288 	{
       
   289 	// TODO clean up iProcess
       
   290 
       
   291 	Printf(_L("CTRL-C received, exiting.\r\n"));
       
   292 	Complete();
       
   293 	}
       
   294 
       
   295 inline TTime CCmdShowDebug::TickCountToTime(TUint32 aTickCount) const
       
   296 	{
       
   297 	return TTime(iTimeAtStartup.Int64() + (((TInt64)aTickCount*1000000) / (TInt64)iTickFreq) - iStartupTickInMicroseconds);
       
   298 	}