kerneltest/e32test/debug/d_logtofile.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/debug/d_logtofile.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,323 @@
+// 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:
+// e32test\debug\d_logtofile.cpp
+// d_logtofile.ldd is kernel side of t_logtofile application that tests *
+// trace handler hook (TTraceHandler). See t_logtofile.cpp for details. *
+// 
+//
+
+#include "d_logtofile.h"
+#include <kernel/kern_priv.h>
+
+_LIT(PatternInfo, "Pattern:");
+_LIT(BufferInfo, "Buffer Size:");
+_LIT(FastCounterInfo, "Fast couner freq:");
+const TInt MaxLogSize=300;
+///////////////////////////////////////////////////////////////////////
+class DLogToFile : public DLogicalChannelBase
+	{
+public:
+	DLogToFile();
+	~DLogToFile();
+	static TBool Handler (const TDesC8& aText, TTraceSource aTraceSource);
+protected:
+	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+private:
+	TInt CreateChunk();
+	void Start();
+	TInt Stop();
+	void RemoveChunk();
+
+private:
+    DChunk* iChunk;					/**Shared chunk*/
+    TLinAddr iChunkKernelAddr;		/**Kernel base address of the chunk*/
+    TUint32 iChunkMapAttr;			/**Mapping attributes of the chunk*/
+	TBool iBufferFull;				/**Chunk full indication*/
+	TText8* iCurrent;				/**Current pointer to the chunk space*/
+	TChunkCreateStr iChunkCreateStr;/**Input arguments(matching pattern and the chunk size) from user side*/
+	TTraceHandler iOldHook;			/**Previous trace logging hook*/
+	};
+
+DLogToFile* Logger;
+
+DLogToFile::DLogToFile() 
+	{
+	}
+
+DLogToFile::~DLogToFile()
+	{
+	Logger = NULL;
+	}
+
+/*
+Trace handler hook.
+Should be able to run in any content (including ISR).
+@return EFalse, always and that way suppresses debug logging to serial port.
+*/
+TBool DLogToFile::Handler (const TDesC8& aText, TTraceSource aTraceSource)
+	{
+	if(Logger->iBufferFull)
+		return ETrue;
+
+	TInt irq=NKern::DisableAllInterrupts(); //Disable interrupts to prevent loggings overlapping each other.
+
+	if (aText.Length() < Logger->iChunkCreateStr.iPattern.Length())
+		{
+		NKern::RestoreInterrupts(irq);
+		return ETrue; //The log is too short to match the pattern
+		}
+	TPtrC8 ptr( aText.Ptr(), Logger->iChunkCreateStr.iPattern.Length());
+	if (ptr != Logger->iChunkCreateStr.iPattern) //Compare the pattern against the start of the log
+		{
+		NKern::RestoreInterrupts(irq);
+		return ETrue; //Does not match
+		}
+
+	TBuf8<20> fcBuffer;
+	fcBuffer.AppendNum(NKern::FastCounter());//If it was a real tool, we should not do this here.
+
+	memcpy (Logger->iCurrent, fcBuffer.Ptr(), fcBuffer.Length());
+	Logger->iCurrent+=fcBuffer.Length();
+	*(Logger->iCurrent++) = '\t';
+
+	switch(aTraceSource)
+		{
+		case EKernelTrace:
+			{
+			*(Logger->iCurrent++) = 'K';
+			*(Logger->iCurrent++) = '\t';
+			memcpy (Logger->iCurrent, aText.Ptr(),aText.Length());
+			break;	
+			}
+
+		case EPlatSecTrace:
+			{
+			*(Logger->iCurrent++) = 'P';
+			*(Logger->iCurrent++) = '\t';
+			//PlatSec log could be of any size. Additional checking required:
+			if ((TInt)Logger->iCurrent > (TInt)(Logger->iChunkKernelAddr + Logger->iChunkCreateStr.iSize - aText.Length()))
+				{
+				Logger->iBufferFull = ETrue;
+				break;
+				}
+			memcpy (Logger->iCurrent, aText.Ptr(),aText.Length());
+			break;	
+			}
+		
+		case EUserTrace:
+			{
+			*(Logger->iCurrent++) = 'U';
+			*(Logger->iCurrent++) = '\t';
+			memcpy(Logger->iCurrent, aText.Ptr(),aText.Length());
+			break;	
+			}
+		
+		default:
+			break;
+		}
+
+	Logger->iCurrent+=aText.Length();
+	*(Logger->iCurrent++) = '\n';
+
+	if ((TInt)Logger->iCurrent > (TInt)(Logger->iChunkKernelAddr + Logger->iChunkCreateStr.iSize - MaxLogSize))
+		Logger->iBufferFull = ETrue;
+
+	NKern::RestoreInterrupts(irq);
+
+	return ETrue;
+	}
+
+/**
+Creates the channel
+*/
+TInt DLogToFile::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/)
+	{
+	return KErrNone;
+	}
+
+/*
+Creates chunk and opens another chunk handle for user side.
+Returns user side handle.
+*/
+TInt DLogToFile::CreateChunk()
+{
+	TInt r;
+    TChunkCreateInfo info;
+    info.iType         = TChunkCreateInfo::ESharedKernelSingle;
+    info.iMaxSize      = iChunkCreateStr.iSize;//This is hard coded to 64K. No need to round to page size.
+#ifdef __EPOC32__
+    info.iMapAttr      = (TInt)EMapAttrFullyBlocking; // Full caching
+#endif
+    info.iOwnsMemory   = ETrue; // Use memory from system's free pool
+    info.iDestroyedDfc = NULL;
+
+	NKern::ThreadEnterCS();
+    if (KErrNone != (r = Kern::ChunkCreate(info, iChunk, iChunkKernelAddr, iChunkMapAttr)))
+		{
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	r = Kern::ChunkCommit(iChunk,0,iChunkCreateStr.iSize);
+    if(r!=KErrNone)
+        {
+		Kern::ChunkClose(iChunk);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	r = Kern::MakeHandleAndOpen(NULL, iChunk); 
+    if(r < KErrNone)
+        {
+		Kern::ChunkClose(iChunk);
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	NKern::ThreadLeaveCS();
+	iCurrent = (TText8*)iChunkKernelAddr;
+	return r;
+}
+
+
+/*
+Logs input parameters info into chunk and starts logging.
+*/
+void DLogToFile::Start()
+	{
+	//Log pattern info
+	memcpy (Logger->iCurrent, ((const TDesC&)PatternInfo).Ptr(), ((const TDesC&)PatternInfo).Length());
+	iCurrent+=((const TDesC&)PatternInfo).Length();
+	*(Logger->iCurrent++) = '\t';
+	memcpy (Logger->iCurrent, iChunkCreateStr.iPattern.Ptr(), iChunkCreateStr.iPattern.Length());
+	Logger->iCurrent += iChunkCreateStr.iPattern.Length();
+	*(iCurrent++) = '\n';
+
+	//Log buffern info
+	memcpy (iCurrent, ((const TDesC&)BufferInfo).Ptr(), ((const TDesC&)BufferInfo).Length());
+	iCurrent+=((const TDesC&)BufferInfo).Length();
+	*(Logger->iCurrent++) = '\t';
+	TBuf8<20> buf;
+	buf.AppendNum(iChunkCreateStr.iSize);
+	memcpy (iCurrent, buf.Ptr(), buf.Length());
+	iCurrent+=buf.Length();
+	*(iCurrent++) = '\n';
+
+	//Log fast counter info
+	memcpy (iCurrent, ((const TDesC&)FastCounterInfo).Ptr(), ((const TDesC&)FastCounterInfo).Length());
+	iCurrent+=((const TDesC&)FastCounterInfo).Length();
+	*(iCurrent++) = '\t';
+	buf.SetLength(0);
+	buf.AppendNum(NKern::FastCounterFrequency());
+	memcpy (iCurrent, buf.Ptr(), buf.Length());
+	iCurrent+=buf.Length();
+	*(iCurrent++) = '\n';
+
+	//Start logging	
+	iOldHook = Kern::SetTraceHandler(DLogToFile::Handler);
+	}
+
+/*
+Stops logging into chunk. Returns the size of the log.
+*/
+TInt DLogToFile::Stop()
+	{
+	//Setting the old hook is always risky. Is the old hook still valid?
+	//We'll do it for the sake of testing.
+	Kern::SetTraceHandler(iOldHook);
+	return (TInt)Logger->iCurrent  - Logger->iChunkKernelAddr;
+	}
+
+/*
+Closes the shared chunk
+*/
+void DLogToFile::RemoveChunk()
+{
+	NKern::ThreadEnterCS();
+	//It has been a while since we removed the hook. It should be safe to close the chunk now. 
+	Kern::ChunkClose(iChunk);
+	NKern::ThreadLeaveCS();
+}
+
+/**
+User side request entry point.
+*/
+TInt DLogToFile::Request(TInt aFunction, TAny* a1, TAny* /*a2*/)
+	{
+	TInt r = KErrNone;
+	switch (aFunction)
+	{
+		case RLogToFileDevice::EControlCreateChunk:
+			{
+			kumemget(&iChunkCreateStr, a1,sizeof(TChunkCreateStr));
+			r = CreateChunk();
+			break;
+			}
+		case RLogToFileDevice::EControlStart:
+			{
+			Start();
+			break;
+			}
+		case RLogToFileDevice::EControlStop:
+			{
+			r = Stop();
+			break;
+			}
+		case RLogToFileDevice::EControlRemoveChunk:
+			{
+			RemoveChunk();
+			break;
+			}
+		default:
+			r=KErrNotSupported;
+			break;
+		}
+	return r;
+	}
+
+//////////////////////////////////////////
+class DTestFactory : public DLogicalDevice
+	{
+public:
+	DTestFactory();
+	// from DLogicalDevice
+	virtual TInt Install();
+	virtual void GetCaps(TDes8& aDes) const;
+	virtual TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+DTestFactory::DTestFactory()
+    {
+    iParseMask = KDeviceAllowUnit;
+    iUnitsMask = 0x3;
+    }
+
+TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
+    {
+	Logger = new DLogToFile;
+	aChannel = Logger;
+	return (aChannel ? KErrNone : KErrNoMemory);
+    }
+
+TInt DTestFactory::Install()
+    {
+    return SetName(&KLogToFileName);
+    }
+
+void DTestFactory::GetCaps(TDes8& /*aDes*/) const
+    {
+    }
+
+DECLARE_STANDARD_LDD()
+	{
+    return new DTestFactory;
+	}