summaryrefslogblamecommitdiffstats
path: root/tester/covoar/ExecutableInfo.cc
blob: 418a7f4f7d20e13841be7363ce9825cbc5f9baa4 (plain) (tree)
1
2
3
4
5
6
7
8
9








                                                              

                
                           
                             
                        




                                 

                                         

                                       
                                    

                                            
   
                                  
                                   
 

                                                              
                                    



                                                   

                                                     


                                     
 

                           

                                  
                           
 






                                                                              
 




                                             
                                                         







                                                                  

           

                                    

           


                                                                         

                     
         
 


                                                 
         


                                                               

       

   



                                   
                                                 
                                                
 


                                                                



                                                  





                                                               



                                                                      


                                               

                                                                
                                                    
                          
                                                 




                        
                                                               
   
                    

   
                                                                








                                                       
                                                      
   
                           

   





                                                                 
                                                 



                                          
                                




                                  

                                   
 









                                                                    

                                          
                                                                    




                                             

   






                                        
                                          




                             

                                                
                                


                                              
                                   

                                                                   








                                                         
/*! @file ExecutableInfo.cc
 *  @brief ExecutableInfo Implementation
 *
 *  This file contains the implementation of the functionality
 *  of the ExecutableInfo class.
 */

#include <stdio.h>

#include <rld.h>

#include "ExecutableInfo.h"
#include "ObjdumpProcessor.h"
#include "CoverageMap.h"
#include "SymbolTable.h"

namespace Coverage {

  ExecutableInfo::ExecutableInfo(
    const char* const  theExecutableName,
    const std::string& theLibraryName,
    bool               verbose,
    DesiredSymbols&    symbolsToAnalyze
    ) : fileName(theExecutableName),
        loadAddress(0),
        symbolsToAnalyze_m(symbolsToAnalyze)
  {
    if ( !theLibraryName.empty() )
      libraryName = theLibraryName;

    if (verbose) {
      std::cerr << "Loading executable " << theExecutableName;
      if ( !theLibraryName.empty() )
        std::cerr << " (" << theLibraryName << ')';
      std::cerr << std::endl;
    }

    rld::files::object executable(theExecutableName);

    executable.open();
    executable.begin();
    executable.load_symbols(symbols);

    rld::dwarf::file debug;

    debug.begin(executable.elf());
    debug.load_debug();
    debug.load_functions();

    for (auto& cu : debug.get_cus()) {
      AddressLineRange& range = mapper.makeRange(cu.pc_low(), cu.pc_high());
      // Does not filter on desired symbols under the assumption that the test
      // code and any support code is small relative to what is being tested.
      for (const auto &address : cu.get_addresses()) {
        range.addSourceLine(address);
      }

      for (auto& func : cu.get_functions()) {
        if (!func.has_machine_code()) {
          continue;
        }

        if (!symbolsToAnalyze_m.isDesired(func.name())) {
          continue;
        }

        if (func.is_inlined()) {
          if (func.is_external()) {
            // Flag it
            std::cerr << "Function is both external and inlined: "
                      << func.name() << std::endl;
          }

          if (func.has_entry_pc()) {
            continue;
          }

          // If the low PC address is zero, the symbol does not appear in
          // this executable.
          if (func.pc_low() == 0) {
            continue;
          }
        }

        // We can't process a zero size function.
        if (func.pc_high() == 0) {
          continue;
        }

        createCoverageMap (cu.name(), func.name(),
                            func.pc_low(), func.pc_high() - 1);
      }
    }
  }

  ExecutableInfo::~ExecutableInfo()
  {
  }

  void ExecutableInfo::dumpCoverageMaps( void ) {
    ExecutableInfo::CoverageMaps::iterator  itr;

    for (auto& cm : coverageMaps) {
      std::cerr << "Coverage Map for " << cm.first << std::endl;
      cm.second->dump();
    }
  }

  void ExecutableInfo::dumpExecutableInfo( void ){
    std::cout << std::endl
              << "== Executable info ==" << std::endl
              << "executable = " << getFileName () << std::endl
              << "library = " << libraryName << std::endl
              << "loadAddress = " << loadAddress << std::endl;
    theSymbolTable.dumpSymbolTable();
  }

  CoverageMapBase* ExecutableInfo::getCoverageMap ( uint32_t address )
  {
    CoverageMapBase*       aCoverageMap = NULL;
    CoverageMaps::iterator it;
    std::string            itsSymbol;

    // Obtain the coverage map containing the specified address.
    itsSymbol = theSymbolTable.getSymbol( address );
    if (itsSymbol != "") {
      aCoverageMap = &findCoverageMap(itsSymbol);
    }

    return aCoverageMap;
  }

  const std::string& ExecutableInfo::getFileName ( void ) const
  {
    return fileName;
  }

  const std::string ExecutableInfo::getLibraryName( void ) const
  {
    return libraryName;
  }

  uint32_t ExecutableInfo::getLoadAddress( void ) const
  {
    return loadAddress;
  }

  SymbolTable* ExecutableInfo::getSymbolTable ( void )
  {
    return &theSymbolTable;
  }

  CoverageMapBase& ExecutableInfo::findCoverageMap(
    const std::string& symbolName
  )
  {
    CoverageMaps::iterator cmi = coverageMaps.find( symbolName );
    if ( cmi == coverageMaps.end() )
      throw CoverageMapNotFoundError(symbolName);
    return *(cmi->second);
  }

  void ExecutableInfo::createCoverageMap (
    const std::string& fileName,
    const std::string& symbolName,
    uint32_t           lowAddress,
    uint32_t           highAddress
  )
  {
    CoverageMapBase        *theMap;
    CoverageMaps::iterator  itr;

    if ( lowAddress > highAddress ) {
      std::ostringstream what;
      what << "Low address is greater than high address for symbol "
            << symbolName
            << " (" << lowAddress
            << " and " << highAddress
            << ")";
      throw rld::error( what, "ExecutableInfo::createCoverageMap" );
    }

    itr = coverageMaps.find( symbolName );
    if ( itr == coverageMaps.end() ) {
      theMap = new CoverageMap( fileName, lowAddress, highAddress );
      coverageMaps[ symbolName ] = theMap;
    } else {
      theMap = itr->second;
      theMap->Add( lowAddress, highAddress );
    }
  }

  void ExecutableInfo::getSourceAndLine(
    const unsigned int address,
    std::string&       line
  )
  {
    std::string file;
    int         lno;
    mapper.getSource (address, file, lno);
    std::ostringstream ss;
    ss << file << ':' << lno;
    line = ss.str ();
  }

  bool ExecutableInfo::hasDynamicLibrary( void )
  {
    return !libraryName.empty();
  }

  void ExecutableInfo::mergeCoverage( void ) {
    for (auto& cm : coverageMaps) {
      if (symbolsToAnalyze_m.isDesired( cm.first ))
        symbolsToAnalyze_m.mergeCoverageMap( cm.first, cm.second );
    }
  }

  void ExecutableInfo::setLoadAddress( uint32_t address )
  {
    loadAddress = address;
  }

}