tracesrv/tracecore/btrace_handler/src/BTraceKernelCategoryHandler.cpp
changeset 56 aa2539c91954
--- /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