/* The copyright in this software is being made available under the BSD * License, included below. This software may be subject to other third party * and contributor rights, including patent rights, and no such rights are * granted under this license. * * Copyright (c) 2010-2019, ITU/ISO/IEC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the ITU/ISO/IEC nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /** \file dtrace.cpp * \brief Implementation of trace messages support for debugging */ #include <string> #include <iostream> #include <sstream> #include <vector> #include <cstdlib> #include "CommonDef.h" #include "dtrace.h" #include "dtrace_next.h" void Channel::update( std::map< CType, int > state ) { for( std::list<Rule>::iterator rules_iter = rule_list.begin(); rules_iter != rule_list.end(); ++rules_iter ) { /* iterate over conditions, get the state of the condition type * and check if contion is met: * if not -> go to next rule * yes -> go to next condition * if all conditions are met: set channel active and return */ bool probe = true; for( Rule::iterator cond_iter = rules_iter->begin(); cond_iter != rules_iter->end(); ++cond_iter ) { int sVal = state[cond_iter->type]; if( !cond_iter->eval( cond_iter->rval, sVal ) ) { probe = false; break; } } if( probe ) { _active = true; return; } } _active = false; } void Channel::add( std::vector<Condition> rule ) { rule_list.push_back( rule ); } static inline std::vector<std::string> &split( const std::string &s, char delim, std::vector<std::string> &elems ) { std::stringstream ss( s ); std::string item; while ( std::getline( ss, item, delim ) ) { elems.push_back( item ); } return elems; } static inline std::vector<std::string> split( const std::string &s, char delim ) { std::vector<std::string> elems; split( s, delim, elems ); return elems; } CDTrace::CDTrace( const char *filename, vstring channel_names ) : copy(false), m_trace_file(NULL), m_error_code( 0 ) { if( filename ) m_trace_file = fopen( filename, "w" ); int i = 0; for( vstring::iterator ci = channel_names.begin(); ci != channel_names.end(); ++ci ) { deserializationTable[*ci] = i++; chanRules.push_back( Channel() ); } } CDTrace::CDTrace( const char *filename, const dtrace_channels_t& channels ) : copy( false ), m_trace_file( NULL ), m_error_code( 0 ) { if( filename ) m_trace_file = fopen( filename, "w" ); //int i = 0; for( dtrace_channels_t::const_iterator ci = channels.begin(); ci != channels.end(); ++ci ) { deserializationTable[ci->channel_name] = ci->channel_number/*i++*/; chanRules.push_back( Channel() ); } } CDTrace::CDTrace( const CDTrace& other ) { copy = true; m_trace_file = other.m_trace_file; chanRules = other.chanRules; condition_types = other.condition_types; state = other.state; deserializationTable = other.deserializationTable; m_error_code = other.m_error_code; } CDTrace::CDTrace( const std::string& sTracingFile, const std::string& sTracingRule, const dtrace_channels_t& channels ) : CDTrace( sTracingFile.c_str(), channels ) { //CDTrace::CDTrace( sTracingFile.c_str(), channels ); if( !sTracingRule.empty() ) { m_error_code = addRule( sTracingRule ); } } void CDTrace::swap( CDTrace& other ) { using std::swap; CDTrace& first = *this; CDTrace& second = other; swap(first.copy,second.copy); swap(first.m_trace_file,second.m_trace_file); swap(first.chanRules,second.chanRules); swap(first.condition_types,second.condition_types); swap(first.state,second.state); swap(first.deserializationTable,second.deserializationTable); } CDTrace& CDTrace::operator=( const CDTrace& other ) { CDTrace tmp(other); swap( tmp ); return *this; } CDTrace::~CDTrace() { if( !copy && m_trace_file ) fclose( m_trace_file ); } bool _cf_eq ( int bound, int val ) { return ( val==bound ); } bool _cf_neq( int bound, int val ) { return ( val!=bound ); } bool _cf_le ( int bound, int val ) { return ( val<=bound ); } bool _cf_ge ( int bound, int val ) { return ( val>=bound ); } int CDTrace::addRule( std::string rulestring ) { vstring chans_conds = split( rulestring, ':' ); vstring channels = split( chans_conds[0], ',' ); vstring conditions = split( chans_conds[1], ',' ); /* parse the rules first */ std::vector<Condition> rule; for( vstring::iterator ci = conditions.begin(); ci != conditions.end(); ++ci ) { /* find one of "==", "!=", "<=", ">=" */ const char *ops_[] = { "==", "!=", "<=", ">=" }; vstring operators( ops_,&ops_[sizeof( ops_ )/sizeof( ops_[0] )] ); vstring::iterator oi = operators.begin(); std::size_t pos = std::string::npos; do { if( ( pos = ci->find( *oi ) ) != std::string::npos ) break; } while( ++oi != operators.end() ); /* No operator found, malformed rules string -> abort */ if( pos == std::string::npos ) return -2; CType ctype( *ci,0,pos ); int value = std::atoi( ci->substr( pos+2, ci->length()-( pos+2 ) ).c_str() ); //if( condition_types.find( ctype ) == condition_types.end() ) return 0; /* partially apply the condition value to the associated * condtion function and append it to the rule */ bool ( *cfunc )( int,int ); if( "==" == *oi ) cfunc = _cf_eq; else if( "!=" == *oi ) cfunc = _cf_neq; else if( "<=" == *oi ) cfunc = _cf_le; else if( ">=" == *oi ) cfunc = _cf_ge; else return 0; // this is already taken care of rule.push_back( Condition( ctype, cfunc, value ) ); } /* add the rule to each channel */ for( vstring::iterator chan_iter = channels.begin(); chan_iter != channels.end(); ++chan_iter ) { std::map< Key, int>::iterator ichan = deserializationTable.find(*chan_iter); if( ichan != deserializationTable.end() ) chanRules[ichan->second].add( rule ); else return -3; } //return (int)channels.size(); return 0; } bool CDTrace::update( state_type stateval ) { state[stateval.first] = stateval.second; /* pass over all the channel rules */ for( std::vector< Channel >::iterator citer = chanRules.begin(); citer != chanRules.end(); ++citer ) { citer->update( state ); } return true; } void CDTrace::getChannelsList( std::string& sChannels ) { sChannels.clear(); /* pass over all the channel rules */ if( deserializationTable.size() > 0 ) { for( channel_map_t::iterator it = deserializationTable.begin(); it != deserializationTable.end(); ++it ) sChannels += it->first + "\n"; } } const char* CDTrace::getChannelName( int channel_number ) { static const char not_found[] = ""; if( deserializationTable.size() > 0 ) { for( channel_map_t::iterator it = deserializationTable.begin(); it != deserializationTable.end(); ++it ) if( it->second == channel_number ) return it->first.c_str(); } return not_found; } std::string CDTrace::getErrMessage() { std::string str = ""; if( m_error_code ) { if( m_error_code == -2 ) str = ( " - DTrace ERROR: Add tracing rule failed: DECERR_DTRACE_BAD_RULE" ); else if( m_error_code == -3 ) str = ( " - DTrace ERROR: Add tracing rule failed: DECERR_DTRACE_UNKNOWN_CHANNEL" ); else { str = " - DTrace ERROR: Undefined error"; } } return str; } template< bool bCount> void CDTrace::dtrace( int k, const char *format, /*va_list args*/... ) { if( m_trace_file && chanRules[k].active() ) { va_list args; va_start ( args, format ); vfprintf ( m_trace_file, format, args ); fflush( m_trace_file ); va_end ( args ); if( bCount ) chanRules[k].incrementCounter(); } return; } template void CDTrace::dtrace<true>( int k, const char *format, /*va_list args*/... ); template void CDTrace::dtrace<false>( int k, const char *format, /*va_list args*/... ); void CDTrace::dtrace_repeat( int k, int i_times, const char *format, /*va_list args*/... ) { if( m_trace_file && chanRules[k].active() ) { va_list args; va_start( args, format ); while( i_times > 0 ) { i_times--; vfprintf( m_trace_file, format, args ); } fflush( m_trace_file ); va_end( args ); } return; } #if K0149_BLOCK_STATISTICS void CDTrace::dtrace_header( const char *format, /*va_list args*/... ) { if( m_trace_file ) { va_list args; va_start ( args, format ); vfprintf ( m_trace_file, format, args ); fflush( m_trace_file ); va_end ( args ); } return; } #endif