/*! @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()
{
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;
}
}