/* 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-2023, 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 #include #include #include #include #include "CommonDef.h" #include "dtrace.h" #include "dtrace_next.h" void Channel::update( std::map< CType, int > state ) { for (std::list::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 rule ) { rule_list.push_back(rule); } static inline std::vector &split( const std::string &s, char delim, std::vector &elems ) { std::stringstream ss(s); std::string item; while (std::getline(ss, item, delim)) { elems.push_back(item); } return elems; } static inline std::vector split( const std::string &s, char delim ) { std::vector elems; split(s, delim, elems); return elems; } CDTrace::CDTrace(const char *filename, vstring channel_names) : copy(false), m_trace_file(nullptr), 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(nullptr), 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 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::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::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( int k, const char *format, /*va_list args*/... ); template void CDTrace::dtrace( 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