diff -r a151135b0cf9 -r aa2539c91954 tracesrv/tracecore/btrace_handler/src/BTraceKernelCategoryHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tracesrv/tracecore/btrace_handler/src/BTraceKernelCategoryHandler.cpp Fri Oct 08 14:56:39 2010 +0300 @@ -0,0 +1,575 @@ +// Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "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: +// Trace Core +// + +// Include files +#include "BTraceKernelCategoryHandler.h" +#include "BTraceOstCategoryBitmap.h" +#include "TraceCore.h" +#include "TraceCoreDebug.h" +#include "TraceCoreConstants.h" + +#include "OstTraceDefinitions.h" + +#ifdef OST_TRACE_COMPILER_IN_USE +#include "BTraceKernelCategoryHandlerTraces.h" +#endif + +#include "TraceCoreTComArgMacro.h" + +//Split: These needed from TraceCoreAutogen.h (which is removed): +#define SYMBIAN_CF_SERVERDEN 0xC2 +#define SYMBIAN_CF_MESHMACHINE 0xC3 +#define SYMBIAN_CF_FACTORIES 0xC4 + +/** + * Length of BTrace header + */ +const TUint KBTraceHeaderLen = 4; + +/** + * Length of single BTrace variable + */ +const TUint KBTraceVariableLen = 4; + +/** + * Four bytes + */ +const TUint KFourBytes = 4; + +// Trace group shift when checking if group is active +#define GRP_SHIFT 16 + +// BTrace category shift for unknown categories +#define CATEGORY_SHIFT 8 + +/** + * Constructor + */ +DBTraceKernelCategoryHandler::DBTraceKernelCategoryHandler() +: iPrimeDfc( DBTraceKernelCategoryHandler::PrimeDfc, this, DTraceCore::GetActivationQ(), KDefaultDfcPriority ) +, iMultiPartActivationInfos(2, _FOFF( TMultiPartActivationInfo, iMultiPartId )) + { + } + + +/** + * Destructor + */ +DBTraceKernelCategoryHandler::~DBTraceKernelCategoryHandler() + { + iMultiPartActivationInfos.Close(); + } + + +/** + * Initializes this handler + * + * @param aHandler The BTrace handler + */ +TInt DBTraceKernelCategoryHandler::Init() + { + TInt ret( KErrGeneral ); + + DTraceCore* traceCore = DTraceCore::GetInstance(); + if ( traceCore != NULL ) + { + // Gets the Autogen category bitmap from the list of registered activation interfaces + iTraceBitmap = static_cast< DBTraceOstCategoryBitmap* >( + traceCore->GetActivation( KKernelHooksOSTComponentUID ) ); + if ( iTraceBitmap != NULL ) + { + // Registers to bitmap for change notifications. The primary BTrace filters are + // updated when the bitmap changes + iTraceBitmap->RegisterActivationNotification( *this ); + ret = KErrNone; + } + } + + // Registers kernel categories to BTrace + if ( ret == KErrNone ) + { + for ( TInt i = KMinKernelCategory; ( ret == KErrNone ) && ( i <= KMaxKernelCategory ); i++ ) + { + ret = AddCategory( i ); + } + + if ( ret == KErrNone ) + { + ret = Register(); + } + } + TC_TRACE( ETraceLevelFlow, Kern::Printf( " DBTraceKernelCategoryHandler::PrepareSetWriter 0x%x", ( TUint )( aWriter ) ); + if ( iWriter == NULL && aWriter != NULL ) + { + DBTraceCategoryHandler::PrepareSetWriter( aWriter ); + // When writer is set, the kernel categories are primed + // Priming is done via DFC. + PrimeKernelCategories(); + } + else + { + DBTraceCategoryHandler::PrepareSetWriter( aWriter ); + if ( aWriter == NULL ) + { + // If writer is set to NULL, the kernel categories are disabled. + // This needs to be done immediately, not via timer + PrimeDfc(); + } + } + if ( aWriter != NULL && aWriter->GetWriterType() == EWriterTypeUSBPhonet ) + { + // CPU events must be disabled when using media writer + PrimeCategory( BTrace::ECpuUsage ); + } + } + + +/** + * Handler for KCategoryNokiaAutogen + * + * @param aHeader BTrace header + * @param aHeader2 Extra header data + * @param aContext The thread context in which this function was called + * @param a1 The first trace parameter + * @param a2 The second trace parameter + * @param a3 The third trace parameter + * @param aExtra Extra trace data + * @param aPc The program counter value + * @return ETrue if trace was processed, EFalse if not + */ +TBool DBTraceKernelCategoryHandler::HandleFrame( TUint32 aHeader, TUint32 aHeader2, const TUint32 aContext, + const TUint32 a1, const TUint32 a2, const TUint32 a3, + const TUint32 aExtra, const TUint32 aPc ) + { + TBool retval; + if ( iWriter != NULL ) + { + //deal with any possible missing traces + DTraceCore* tracecore = DTraceCore::GetInstance(); + if(!tracecore) + return EFalse; + + // Check if tracing is certified + if (!tracecore->IsTraceCertified()) + return EFalse; + + if ((tracecore->PreviousTraceDropped())) //if previous trace was dropped + { + //set flags back to EFalse first + tracecore->SetPreviousTraceDropped(EFalse); + + //set missing flag in BTrace + aHeader |= BTrace::EMissingRecord<<(BTrace::EFlagsIndex * KByteSize); + } + + TUint8 category = ( aHeader >> ( BTrace::ECategoryIndex * KByteSize ) ) & KByteMask; + TUint8 subCategory = ( aHeader >> ( BTrace::ESubCategoryIndex * KByteSize ) ) & KByteMask; + TUint32 traceWord = MapCategoryToID( category, subCategory ); + if ( traceWord > 0 ) + { + + // Check if the trace is a multipart trace + TBool isMultiPart = CheckMultiPart(aHeader, aHeader2); + if (isMultiPart) + { + // Handle the multipart trace + retval = HandleMultiPart(aHeader, aHeader2, aContext, traceWord, a2, a3, aExtra, aPc); + } + + // Not a multipart trace + else + { + // If previous trace was discarded, add info about it to the header + if (tracecore->PreviousTraceDropped()) + { + aHeader |= BTrace::EMissingRecord<<(BTrace::EFlagsIndex * KByteSize); + tracecore->SetPreviousTraceDropped(EFalse); + } + + TUint8 recordSize = static_cast< TUint8 >( ( aHeader >> ( BTrace::ESizeIndex * KByteSize ) ) & KByteMask ); + iWriter->WriteTraceCoreFrame( KKernelHooksOSTComponentUID, + traceWord, aHeader, aHeader2, aContext, a1, a2, a3, aExtra, aPc, recordSize ); + + retval = ETrue; + } + } + else + { + retval = EFalse; + } + } + else + { + retval = EFalse; + } + TC_TRACE( ETraceLevelTraceFlow, Kern::Printf(" DBTraceKernelCategoryHandler::ActivationChanged 0x%x. FromSettings:%d",( TUint )( &aActivation ), aFromSettings ); + + // Kernel categories are primed when activation bitmap changes + if (aComponentId == KOldNokiaAutogenOSTComponentUID || aComponentId == KKernelHooksOSTComponentUID) + { + PrimeKernelCategories(); + } + } + + +/** + * Primes the kernel categories + */ +void DBTraceKernelCategoryHandler::PrimeKernelCategories() + { + // Priming is done asynchronously to avoid blocking this thread + iPrimeDfc.Enque(); + } + + +/** + * Dfc function to prime kernel categories + */ +void DBTraceKernelCategoryHandler::PrimeDfc( TAny* aHandler ) + { + OstTrace1( TRACE_FLOW, DBTRACEKERNELCATEGORYHANDLER_PRIMEDFC_ENTRY,"> DBTraceKernelCategoryHandler::PrimeDfc 0x%x", ( TUint )( aHandler ) ); + + // Get handler and prime kernel categories + DBTraceKernelCategoryHandler* handler = static_cast< DBTraceKernelCategoryHandler* >( aHandler ); + handler->PrimeDfc(); + } + + +/** + * Called from the static DFC callback function + */ +void DBTraceKernelCategoryHandler::PrimeDfc() + { + OstTrace0( TRACE_FLOW, DBTRACEKERNELCATEGORYHANDLER_PRIMEDFC, + "> DBTraceKernelCategoryHandler::PrimeDfc" ); + + // Start from Thread Identification as we don't want to active Printfs from the BTrace + for ( TInt i = KMinKernelCategory; i <= KMaxKernelCategory; i++ ) + { + PrimeCategory( i ); + } + } + + +/** + * Primes a category + * + * @param aCategory the category to be primed + */ +void DBTraceKernelCategoryHandler::PrimeCategory( TUint8 aCategory ) + { + TUint32 traceWord = MapCategoryToID( aCategory, 0 ); + // CPU events are not possible when using USB phonet writer + // They result in context switch trace loop + if ( iWriter != NULL && + (iTraceBitmap->IsTraceActivated( KKernelHooksOSTComponentUID, traceWord ) ) + && ( aCategory != BTrace::ECpuUsage || iWriter->GetWriterType() != EWriterTypeUSBPhonet ) ) + { + TInt ret = BTrace::SetFilter( aCategory, 1 ); + if ( ret == KErrNone ) + { + OstTrace1( TRACE_NORMAL, DBTRACEKERNELCATEGORYHANDLER_PRIMEDFC__,"DBTraceKernelCategoryHandler::PrimeDfc - Priming 0x%x", aCategory ); + BTrace::Prime( aCategory ); + } + else if ( ret == KErrNotSupported ) + { + OstTrace1( TRACE_INTERNAL, DBTRACEKERNELCATEGORYHANDLER_PRIMEDFC_NOT_SUPPORTED,"DBTraceKernelCategoryHandler::PrimeDfc - Category not supported 0x%x", aCategory ); + } + } + else + { + (void) BTrace::SetFilter( aCategory, 0 ); + } + } + +/** + * Handles this Multipart trace + * + * @param aHeader BTrace header + * @param aHeader2 Extra header data + * @param aContext The thread context in which this function was called + * @param aTraceWord Trace Word + * @param a1 First parameter + * @param aData The data + * @param aExtra Extra trace data + * @param aPc The program counter value + * @return ETrue if trace was processed + */ +TBool DBTraceKernelCategoryHandler::HandleMultiPart( TUint32 aHeader, TUint32 aHeader2, const TUint32 aContext, + const TUint32 aTraceWord, const TUint32 a1, const TUint32 aData, const TUint32 aExtra, + const TUint32 aPc) + { + TC_TRACE( ETraceLevelTraceFlow, Kern::Printf( ">DBTraceOstCategoryHandler::HandleMultiPart" ) ); + TBool retval = ETrue; + TInt multiPartOffset = aHeader2 & BTrace::EMultipartFlagMask; + TUint8 recordSize = static_cast< TUint8 >( ( aHeader >> ( BTrace::ESizeIndex * KByteSize ) ) & KByteMask ); + + // First part of multipart trace + if (multiPartOffset == BTrace::EMultipartFirst) + { + // Create new MultiPart activation info and save it to the array + TMultiPartActivationInfo activationInfo; + activationInfo.iComponentId = KKernelHooksOSTComponentUID; + activationInfo.iTraceWord = aTraceWord; + activationInfo.iMultiPartId = aExtra; + + // Insert the item to the array + TInt ret = iMultiPartActivationInfos.InsertInUnsignedKeyOrder(activationInfo); + + if (KErrNone == ret) + { + TUint32* ptr = reinterpret_cast< TUint32* >(aData); + TUint32 a2 = *ptr++; + + // Write the trace. Move pointer by 4 bytes because first 4 bytes is moved from aData + // to a2. Decrease record size by 4 bytes because the original a2 is not written + iWriter->WriteTraceCoreFrame( activationInfo.iComponentId, activationInfo.iTraceWord, + aHeader, aHeader2, aContext, a1, a2, + aData + 4, aExtra, aPc, recordSize - 4); + } + else + { + retval = EFalse; + DTraceCore* tcore = DTraceCore::GetInstance(); + if(tcore) + tcore->SetPreviousTraceDropped(ETrue); + } + } + + // Middle or last part of multipart trace + else if (multiPartOffset == BTrace::EMultipartMiddle || multiPartOffset == BTrace::EMultipartLast) + { + // Check index of component id in array + TMultiPartActivationInfo tempInfo; + tempInfo.iMultiPartId = aExtra; + TInt index = iMultiPartActivationInfos.FindInUnsignedKeyOrder(tempInfo); + + if (index != KErrNotFound) + { + TMultiPartActivationInfo activationInfo = iMultiPartActivationInfos[index]; + + TUint32 a1 = 0; + TUint32 a2 = 0; + TUint32 movePointerOffset = 0; + + // Calculate if we can move data from the aData to a1 and a2 + TUint32 dataStartOffset = CalculateDataStartOffset(aHeader); + if ( recordSize - dataStartOffset >= 4 ) + { + TUint32* ptr = reinterpret_cast< TUint32* >(aData); + a1 = *ptr++; + movePointerOffset += 4; + + if ( recordSize - dataStartOffset >= 8 ) + { + a2 = *ptr++; + movePointerOffset += 4; + } + } + + // Write the trace. Decrease the record size by 8 because of the original a1 and a2 + // are not written + iWriter->WriteTraceCoreFrame( activationInfo.iComponentId, activationInfo.iTraceWord, + aHeader, aHeader2, aContext, a1, a2, + aData + movePointerOffset, aExtra, aPc, recordSize - 8); + + // Last part, remove the item from the array + if (multiPartOffset == BTrace::EMultipartLast) + { + iMultiPartActivationInfos.Remove(index); + } + } + } + TC_TRACE( ETraceLevelTraceFlow, Kern::Printf( " return %d", retval ) ); + return retval; + } + +/** + * Checks if the given trace is a Multipart trace + * + * @param aHeader Header data + * @param aHeader2 Extra header data + * @return ETrue if trace is a Multipart trace, EFalse if not + */ +inline TBool DBTraceKernelCategoryHandler::CheckMultiPart( TUint32 aHeader, TUint32 aHeader2 ) + { + TC_TRACE( ETraceLevelTraceFlow, Kern::Printf( ">DBTraceKernelCategoryHandler::CheckMultiPart()" ) ); + TBool retval = EFalse; + TUint8 flags = static_cast< TUint8 >( ( aHeader >> ( BTrace::EFlagsIndex * KByteSize ) ) & KByteMask ); + if (flags & BTrace::EHeader2Present) + { + // First, middle or last part of Multipart trace + if (aHeader2 & BTrace::EMultipartFlagMask) + { + retval = ETrue; + } + } + TC_TRACE( ETraceLevelTraceFlow, Kern::Printf( " return %d", retval ) ); + return retval; + } + +/** + * Calculates data start offset + * + * @param aHeader BTrace header + */ +TUint32 DBTraceKernelCategoryHandler::CalculateDataStartOffset( TUint32 aHeader ) + { + TC_TRACE( ETraceLevelTraceFlow, Kern::Printf( ">DBTraceOstCategoryHandler::CalculateDataStartOffset()" ) ); + TUint32 offset = 0; + TUint8 flags = static_cast< TUint8 >( ( aHeader >> ( BTrace::EFlagsIndex * KByteSize ) ) & KByteMask ); + + // First add header length + offset += KBTraceHeaderLen; + + // Header2 is present + if ( flags & BTrace::EHeader2Present ) + { + offset += KBTraceVariableLen; + } + // Timestamp is present + if ( flags & BTrace::ETimestampPresent ) + { + offset += KBTraceVariableLen; + } + // Timestamp2 is present + if ( flags & BTrace::ETimestamp2Present ) + { + offset += KBTraceVariableLen; + } + // Context ID is present + if ( flags & BTrace::EContextIdPresent ) + { + offset += KBTraceVariableLen; + } + // Program counter is present + if ( flags & BTrace::EPcPresent ) + { + offset += KBTraceVariableLen; + } + // Extra value is present + if ( flags & BTrace::EExtraPresent ) + { + offset += KBTraceVariableLen; + } + + // Next 8 bytes came with first and second parameter of the multipart trace + offset += KFourBytes; + offset += KFourBytes; + + TC_TRACE( ETraceLevelTraceFlow, Kern::Printf( " return %d", offset ) ); + return offset; + } + +// End of File