Skip to content
Snippets Groups Projects
dtrace.cpp 10.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • /* 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