kerneltest/e32test/debug/d_logtofile.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// 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;
	}