/*! @file ExecutableInfo.cc * @brief ExecutableInfo Implementation * * This file contains the implementation of the functionality * of the ExecutableInfo class. */ #include #include #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() { ExecutableInfo::CoverageMaps::iterator itr; for ( auto& cm : coverageMaps ) { std::cerr << "Coverage Map for " << cm.first << std::endl; cm.second->dump(); } } void ExecutableInfo::dumpExecutableInfo() { 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() const { return fileName; } const std::string ExecutableInfo::getLibraryName() const { return libraryName; } uint32_t ExecutableInfo::getLoadAddress() const { return loadAddress; } SymbolTable* ExecutableInfo::getSymbolTable() { 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; std::ostringstream ss; mapper.getSource( address, file, lno ); ss << file << ':' << lno; line = ss.str (); } bool ExecutableInfo::hasDynamicLibrary() { return !libraryName.empty(); } void ExecutableInfo::mergeCoverage() { 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; } }