--- /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::Init() - %d", ret ) );
+ return ret;
+ }
+
+
+/**
+ * Called before SetWriter with interrupts enabled
+ *
+ * @param aWriter The new writer
+ */
+void DBTraceKernelCategoryHandler::PrepareSetWriter( DTraceCoreWriter* aWriter )
+ {
+ OstTrace1( TRACE_FLOW, DBTRACEKERNELCATEGORYHANDLER_PREPARESETWRITER_ENTRY,"> 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::HandleFrame - return %d", retval ) );
+ return retval;
+ }
+
+
+/**
+ * Maps a BTrace category / sub-category to group / trace ID
+ *
+ * @param aCategory The BTrace category
+ * @param aSubCategory The BTrace sub-categoory
+ * @return The group / trace ID combination
+ */
+TUint32 DBTraceKernelCategoryHandler::MapCategoryToID( TUint8 aCategory, TUint8 aSubCategory )
+ {
+ TUint32 ret;
+
+ switch( aCategory )
+ {
+ case BTrace::EThreadIdentification:
+ case BTrace::ECpuUsage:
+ case BTrace::EClientServer:
+ case BTrace::ERequests:
+ case BTrace::EChunks:
+ case BTrace::ECodeSegs:
+ case BTrace::EPaging:
+ case BTrace::EThreadPriority:
+ case BTrace::EPagingMedia:
+ ret = ( aCategory << GRP_SHIFT ) | aSubCategory;
+ break;
+
+ // Symbian 9.4 categories
+ case BTrace::EKernelMemory:
+ case BTrace::EHeap:
+ case BTrace::EMetaTrace:
+ case BTrace::ERamAllocator:
+ case BTrace::EFastMutex:
+ case BTrace::EProfiling:
+ ret = ( aCategory << GRP_SHIFT ) | aSubCategory;
+ break;
+
+ // Symbian 9.5 categories
+ case BTrace::EResourceManager:
+ case BTrace::EResourceManagerUs:
+ case BTrace::ERawEvent:
+ case BTrace::EUsb:
+ case BTrace::ESymbianKernelSync:
+ case BTrace::EFlexibleMemModel:
+ ret = ( aCategory << GRP_SHIFT ) | aSubCategory;
+ break;
+
+ // Symbian 9.6 categories
+ case BTrace::EIic:
+ ret = ( aCategory << GRP_SHIFT ) | aSubCategory;
+ break;
+
+ // These are for Symbian for debugging purposes
+ case 194:
+ ret = ( SYMBIAN_CF_SERVERDEN << GRP_SHIFT ) | aSubCategory;
+ break;
+ case 195:
+ ret = ( SYMBIAN_CF_MESHMACHINE << GRP_SHIFT ) | aSubCategory;
+ break;
+ case 196:
+ ret = ( SYMBIAN_CF_FACTORIES << GRP_SHIFT ) | aSubCategory;
+ break;
+
+ default:
+ // Unknown category but let's still use the same ID as we received
+ ret = ( aCategory << GRP_SHIFT ) | aSubCategory;
+ break;
+ }
+
+ return ret;
+ }
+
+
+/**
+ * Called when an activation bitmap state changes
+ *
+ * @param aActivation the activation object
+ * @param aFromSettings ETrue if changes was due to settings read
+ * @param aComponentId Component ID of the activation
+ */
+void DBTraceKernelCategoryHandler::ActivationChanged( MTraceCoreActivation& TCOM_ARG(aActivation), TBool TCOM_ARG(aFromSettings),
+ TUint32 aComponentId)
+ {
+ OstTraceExt2( TRACE_FLOW, DBTRACEKERNELCATEGORYHANDLER_ACTIVATIONCHANGED_ENTRY,"> 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( "<DBTraceOstCategoryHandler::HandleMultiPart > 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( "<DBTraceKernelCategoryHandler::CheckMultiPart > 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( "<DBTraceOstCategoryHandler::CalculateDataStartOffset > return %d", offset ) );
+ return offset;
+ }
+
+// End of File