/* * Trace Recorder for Tracealyzer v4.6.0 * Copyright 2021 Percepio AB * www.percepio.com * * SPDX-License-Identifier: Apache-2.0 * * The implementation of the entry table. */ #include #if ( TRC_USE_TRACEALYZER_RECORDER == 1 ) #if ( TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING ) #define VALIDATE_ENTRY_HANDLE( xEntryHandle ) ( ( ( ( TraceUnsignedBaseType_t ) ( xEntryHandle ) >= ( TraceUnsignedBaseType_t ) pxEntryTable ) && ( ( TraceUnsignedBaseType_t ) ( xEntryHandle ) < ( ( TraceUnsignedBaseType_t ) pxEntryTable + sizeof( TraceEntryTable_t ) ) ) ) ) #define GIVE_ENTRY_INDEX( xIndex ) xIndexTable.axFreeIndexes[ xIndexTable.uiFreeIndexCount ] = ( xIndex ); xIndexTable.uiFreeIndexCount++ #define GET_FREE_INDEX_COUNT() xIndexTable.uiFreeIndexCount #define CALCULATE_ENTRY_INDEX( xEntryHandle ) ( TraceEntryIndex_t ) ( ( ( TraceUnsignedBaseType_t ) ( ( TraceUnsignedBaseType_t ) ( xEntryHandle ) - ( TraceUnsignedBaseType_t ) pxEntryTable ) / sizeof( TraceEntry_t ) ) ) #if ( TRC_ENTRY_TABLE_SLOTS > 256 ) typedef uint16_t TraceEntryIndex_t; #else typedef uint8_t TraceEntryIndex_t; #endif /* (TRC_CFG_ENTRY_TABLE_SLOTS > 256) */ typedef struct EntryIndexTable { TraceEntryIndex_t axFreeIndexes[ TRC_ENTRY_TABLE_SLOTS ]; uint32_t uiFreeIndexCount; } TraceEntryIndexTable_t; typedef struct TraceEntryTable { uint32_t uiSlots; uint32_t uiEntrySymbolLength; uint32_t uiEntryStateCount; TraceEntry_t axEntries[ TRC_ENTRY_TABLE_SLOTS ]; } TraceEntryTable_t; /* Private function definitions */ traceResult prvEntryIndexInitialize( TraceEntryIndexTable_t * pxIndexTable ); traceResult prvEntryIndexTake( TraceEntryIndex_t * pxIndex ); /* Variables */ static TraceEntryTable_t * pxEntryTable; static TraceEntryIndexTable_t xIndexTable; traceResult xTraceEntryTableInitialize( TraceEntryTableBuffer_t * pxBuffer ) { uint32_t i, j; TRC_ASSERT_EQUAL_SIZE( TraceEntryTableBuffer_t, TraceEntryTable_t ); /* This should never fail */ TRC_ASSERT( pxBuffer != 0 ); /* This should never fail */ TRC_ASSERT( ( TRC_ENTRY_TABLE_SLOTS ) != 0 ); pxEntryTable = ( TraceEntryTable_t * ) pxBuffer; pxEntryTable->uiSlots = TRC_ENTRY_TABLE_SLOTS; pxEntryTable->uiEntrySymbolLength = TRC_ENTRY_TABLE_SLOT_SYMBOL_SIZE; pxEntryTable->uiEntryStateCount = TRC_ENTRY_TABLE_STATE_COUNT; for( i = 0; i < TRC_ENTRY_TABLE_SLOTS; i++ ) { pxEntryTable->axEntries[ i ].pvAddress = 0; for( j = 0; j < TRC_ENTRY_TABLE_STATE_COUNT; j++ ) { pxEntryTable->axEntries[ i ].xStates[ j ] = 0; } pxEntryTable->axEntries[ i ].szSymbol[ 0 ] = 0; } prvEntryIndexInitialize( &xIndexTable ); xTraceSetComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ); return TRC_SUCCESS; } traceResult xTraceEntryCreate( TraceEntryHandle_t * pxEntryHandle ) { uint32_t i; TraceEntryIndex_t xIndex; TraceEntry_t * pxEntry; TRACE_ALLOC_CRITICAL_SECTION(); /* We always check this */ if( !xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ) { return TRC_FAIL; } /* This should never fail */ TRC_ASSERT( pxEntryHandle != 0 ); TRACE_ENTER_CRITICAL_SECTION(); if( prvEntryIndexTake( &xIndex ) != TRC_SUCCESS ) { xTraceDiagnosticsIncrease( TRC_DIAGNOSTICS_ENTRY_SLOTS_NO_ROOM ); TRACE_EXIT_CRITICAL_SECTION(); return TRC_FAIL; } pxEntry = &pxEntryTable->axEntries[ xIndex ]; pxEntry->pvAddress = ( void * ) pxEntry; /* We set a temporary address */ for( i = 0; i < TRC_ENTRY_TABLE_STATE_COUNT; i++ ) { pxEntry->xStates[ i ] = 0; } pxEntry->uiOptions = 0; pxEntry->szSymbol[ 0 ] = 0; *pxEntryHandle = ( TraceEntryHandle_t ) pxEntry; TRACE_EXIT_CRITICAL_SECTION(); return TRC_SUCCESS; } traceResult xTraceEntryDelete( TraceEntryHandle_t xEntryHandle ) { TraceEntryIndex_t xIndex; TRACE_ALLOC_CRITICAL_SECTION(); /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); /* Calculate the index based on the entry address */ /* Does not need to be locked. */ /* This should never fail */ xIndex = CALCULATE_ENTRY_INDEX( xEntryHandle ); TRC_ASSERT( xIndex < TRC_ENTRY_TABLE_SLOTS ); TRACE_ENTER_CRITICAL_SECTION(); if( ( ( TraceEntry_t * ) xEntryHandle )->pvAddress == 0 ) { /* Someone else has deleted this already? */ TRACE_EXIT_CRITICAL_SECTION(); return TRC_FAIL; } /* A valid address, so we assume it is OK. */ /* For good measure, we clear the address field */ ( ( TraceEntry_t * ) xEntryHandle )->pvAddress = 0; /* Give back the index */ GIVE_ENTRY_INDEX( xIndex ); TRACE_EXIT_CRITICAL_SECTION(); return TRC_SUCCESS; } traceResult xTraceEntryFind( void * pvAddress, TraceEntryHandle_t * pxEntryHandle ) { uint32_t i; TraceEntry_t * pxEntry; /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( pxEntryHandle != 0 ); /* This should never fail */ TRC_ASSERT( pvAddress != 0 ); for( i = 0; i < TRC_ENTRY_TABLE_SLOTS; i++ ) { pxEntry = ( TraceEntry_t * ) ( ( ( uint32_t ) pxEntryTable->axEntries ) + ( i * sizeof( TraceEntry_t ) ) ); if( pxEntry->pvAddress == pvAddress ) { *pxEntryHandle = ( TraceEntryHandle_t ) pxEntry; return TRC_SUCCESS; } } return TRC_FAIL; } traceResult xTraceEntrySetSymbol( TraceEntryHandle_t xEntryHandle, const char * szSymbol ) { uint32_t i; /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); if( szSymbol == 0 ) { szSymbol = ""; } /* Does not need to be locked. */ /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); for( i = 0; i < ( TRC_ENTRY_TABLE_SYMBOL_LENGTH ); i++ ) { ( ( TraceEntry_t * ) xEntryHandle )->szSymbol[ i ] = szSymbol[ i ]; /* We do this first to ensure we also get the 0 termination, if there is one */ if( szSymbol[ i ] == 0 ) { break; } } /* Check the length of "name", if longer than TRC_ENTRY_TABLE_SYMBOL_LENGTH */ while( ( szSymbol[ i ] != 0 ) && i < 128 ) { i++; } /* Remember the longest symbol name */ xTraceDiagnosticsSetIfHigher( TRC_DIAGNOSTICS_ENTRY_SYMBOL_LONGEST_LENGTH, i ); return TRC_SUCCESS; } traceResult xTraceEntryGetCount( uint32_t * puiCount ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( puiCount != 0 ); *puiCount = TRC_ENTRY_TABLE_SLOTS - GET_FREE_INDEX_COUNT(); return TRC_SUCCESS; } traceResult xTraceEntryGetAtIndex( uint32_t index, TraceEntryHandle_t * pxEntryHandle ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( index < TRC_ENTRY_TABLE_SLOTS ); /* This should never fail */ TRC_ASSERT( pxEntryHandle != 0 ); *pxEntryHandle = ( TraceEntryHandle_t ) ( ( uint32_t ) ( pxEntryTable->axEntries ) + ( index * sizeof( TraceEntry_t ) ) ); return TRC_SUCCESS; } #if ( ( TRC_CFG_USE_TRACE_ASSERT ) == 1 ) traceResult xTraceEntryCreateWithAddress( void * pvAddress, TraceEntryHandle_t * pxEntryHandle ) { /* This should never fail */ TRC_ASSERT( pvAddress != 0 ); return TRC_ENTRY_CREATE_WITH_ADDRESS( pvAddress, pxEntryHandle ); } traceResult xTraceEntrySetState( TraceEntryHandle_t xEntryHandle, uint32_t uiStateIndex, TraceUnsignedBaseType_t uxState ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( uiStateIndex < ( TRC_ENTRY_TABLE_STATE_COUNT ) ); /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); return TRC_ENTRY_SET_STATE( xEntryHandle, uiStateIndex, uxState ); } traceResult xTraceEntrySetOptions( TraceEntryHandle_t xEntryHandle, uint32_t uiMask ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* Does not need to be locked. */ /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); return TRC_ENTRY_SET_OPTIONS( xEntryHandle, uiMask ); } traceResult xTraceEntryClearOptions( TraceEntryHandle_t xEntryHandle, uint32_t uiMask ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* Does not need to be locked. */ /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); return TRC_ENTRY_CLEAR_OPTIONS( xEntryHandle, uiMask ); } traceResult xTraceEntryGetAddress( TraceEntryHandle_t xEntryHandle, void ** ppvAddress ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( ppvAddress != 0 ); /* Does not need to be locked. */ /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); return TRC_ENTRY_GET_ADDRESS( xEntryHandle, ppvAddress ); } traceResult xTraceEntryGetSymbol( TraceEntryHandle_t xEntryHandle, const char ** pszSymbol ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( pszSymbol != 0 ); /* Does not need to be locked. */ /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); return TRC_ENTRY_GET_SYMBOL( xEntryHandle, pszSymbol ); } traceResult xTraceEntryGetState( TraceEntryHandle_t xEntryHandle, uint32_t uiStateIndex, TraceUnsignedBaseType_t * puxState ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( puxState != 0 ); /* This should never fail */ TRC_ASSERT( uiStateIndex < TRC_ENTRY_TABLE_STATE_COUNT ); /* Does not need to be locked. */ /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); return TRC_ENTRY_GET_STATE( xEntryHandle, uiStateIndex, puxState ); } traceResult xTraceEntryGetOptions( TraceEntryHandle_t xEntryHandle, uint32_t * puiOptions ) { /* This should never fail */ TRC_ASSERT( xTraceIsComponentInitialized( TRC_RECORDER_COMPONENT_ENTRY ) ); /* This should never fail */ TRC_ASSERT( puiOptions != 0 ); /* Does not need to be locked. */ /* This should never fail */ TRC_ASSERT( VALIDATE_ENTRY_HANDLE( xEntryHandle ) ); return TRC_ENTRY_GET_OPTIONS( xEntryHandle, puiOptions ); } #endif /* ((TRC_CFG_USE_TRACE_ASSERT) == 1) */ /* PRIVATE FUNCTIONS */ traceResult prvEntryIndexInitialize( TraceEntryIndexTable_t * pxIndexTable ) { uint32_t i; for( i = 0; i < TRC_ENTRY_TABLE_SLOTS; i++ ) { pxIndexTable->axFreeIndexes[ i ] = ( TraceEntryIndex_t ) i; } xIndexTable.uiFreeIndexCount = TRC_ENTRY_TABLE_SLOTS; return TRC_SUCCESS; } traceResult prvEntryIndexTake( TraceEntryIndex_t * pxIndex ) { /* Critical Section must be active! */ TraceEntryIndex_t xIndex; if( xIndexTable.uiFreeIndexCount == 0 ) { return TRC_FAIL; } /* Always take the first item */ xIndex = xIndexTable.axFreeIndexes[ 0 ]; xIndexTable.uiFreeIndexCount--; /* Move the last item to the first slot, to avoid holes */ xIndexTable.axFreeIndexes[ 0 ] = xIndexTable.axFreeIndexes[ xIndexTable.uiFreeIndexCount ]; #if ( TRC_ENTRY_TABLE_SLOTS > 256 ) xIndexTable.axFreeIndexes[ xIndexTable.uiFreeIndexCount ] = UINT16_MAX; #else xIndexTable.axFreeIndexes[ xIndexTable.uiFreeIndexCount ] = UINT8_MAX; #endif *pxIndex = xIndex; return TRC_SUCCESS; } #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */ #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */