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