diff -r 000000000000 -r a41df078684a kerneltest/e32test/debug/d_logtofile.cpp --- /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 + +_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; + }