/*! @file GcovFunctionData.cc * @brief GcovFunctionData Implementation * * This file contains the implementation of the class storing information * about single function. */ #include #include #include #include "GcovFunctionData.h" #include "ObjdumpProcessor.h" #include "CoverageMapBase.h" #include "DesiredSymbols.h" #include "rtems-utils.h" namespace Gcov { GcovFunctionData::GcovFunctionData() { id = 0; checksum = 0; firstLineNumber = 0; numberOfBlocks = 0; numberOfArcs = 0; coverageMap = NULL; symbolInfo = NULL; } GcovFunctionData::~GcovFunctionData() { } void GcovFunctionData::setChecksum( const uint32_t chk ) { checksum = chk; } void GcovFunctionData::setId( const uint32_t idNumber ) { id = idNumber; } void GcovFunctionData::setFirstLineNumber( const uint32_t lineNo ) { firstLineNumber = lineNo; } bool GcovFunctionData::setFunctionName( const std::string& fcnName, Coverage::DesiredSymbols& symbolsToAnalyze ) { std::string symbolName; symbolName = fcnName; if ( fcnName.length() >= FUNCTION_NAME_LENGTH ) { std::cerr << "ERROR: Function name is too long to be correctly stored: " << fcnName.length() << std::endl; return false; } functionName = fcnName; // Tie function to its coverage map symbolInfo = symbolsToAnalyze.find( symbolName ); if ( symbolInfo != NULL ) { coverageMap = symbolInfo->unifiedCoverageMap; } #if 0 if ( coverageMap == NULL ) { std::cerr << "ERROR: Could not find coverage map for: " << symbolName << std::endl; } else { std::cerr << "SUCCESS: Found coverage map for: " << symbolName << std::endl; } #endif return true; } bool GcovFunctionData::setFileName( const std::string& fileName ) { if ( fileName.length() >= FILE_NAME_LENGTH ) { std::cerr << "ERROR: File name is too long to be correctly stored: " << fileName.length() << std::endl; return false; } sourceFileName = fileName; return true; } arcs_t GcovFunctionData::getArcs() const { return arcs; } uint32_t GcovFunctionData::getChecksum() const { return checksum; } uint32_t GcovFunctionData::getId() const { return id; } void GcovFunctionData::getCounters( uint64_t* counterValues, uint32_t& countersFound, uint64_t& countersSum, uint64_t& countersMax ) { arcs_iterator_t currentArc; int i; countersFound = 0; countersSum = 0; countersMax = 0; // Locate relevant counters and copy their values i = 0; for ( currentArc = arcs.begin(); currentArc != arcs.end(); currentArc++ ) { if ( currentArc->flags == 0 || currentArc->flags == 2 || currentArc->flags == 4 ) { countersFound++; countersSum += currentArc->counter; counterValues[i] = currentArc->counter; if ( countersMax <= currentArc->counter ) { countersMax = currentArc->counter; } i++; } } } blocks_t GcovFunctionData::getBlocks() const { return blocks; } void GcovFunctionData::addArc( uint32_t source, uint32_t destination, uint32_t flags ) { gcov_arc_info arc; numberOfArcs++; arc.sourceBlock = source; arc.destinationBlock = destination; arc.flags = flags; arc.counter = 0; arcs.push_back( arc ); } void GcovFunctionData::addBlock( const uint32_t id, const uint32_t flags, const std::string& sourceFileName ) { gcov_block_info block; numberOfBlocks++; block.id = id; block.flags = flags; block.numberOfLines = 0; block.counter = 0; block.sourceFileName = sourceFileName; blocks.push_back( block ); } void GcovFunctionData::printFunctionInfo( std::ofstream& textFile, uint32_t function_number ) { blocks_iterator_t currentBlock; arcs_iterator_t currentArc; textFile << std::endl << std::endl << "==========================" << "FUNCTION " << std::setw( 3 ) << function_number << "==========================" << std::endl << std::endl << "Name: " << functionName << std::endl << "File: " << sourceFileName << std::endl << "Line: " << firstLineNumber << std::endl << "Id: " << id << std::endl << "Checksum: 0x" << std::hex << checksum << std::dec << std::endl << std::endl; // Print arcs info for ( currentArc = arcs.begin(); currentArc != arcs.end(); currentArc++ ) { printArcInfo( textFile, currentArc ); } textFile << std::endl; // Print blocks info for ( currentBlock = blocks.begin(); currentBlock != blocks.end(); currentBlock++ ) { printBlockInfo( textFile, currentBlock ); } } void GcovFunctionData::printCoverageInfo( std::ofstream& textFile, uint32_t function_number ) { uint32_t baseAddress = 0; uint32_t baseSize; uint32_t currentAddress; std::list::iterator instruction; if ( coverageMap != NULL ) { for ( instruction = symbolInfo->instructions.begin(); instruction != symbolInfo->instructions.end(); instruction++ ) { if( instruction->isInstruction ) { baseAddress = instruction->address; break; } } baseSize = coverageMap->getSize(); textFile << std::endl << "Instructions (Base address: 0x" << std::setfill( '0' ) << std::setw( 8 ) << std::hex << baseAddress << std::dec << std::setfill( ' ' ) << ", Size: " << std::setw( 4 ) << baseSize << "):" << std::endl << std::endl; for ( instruction = symbolInfo->instructions.begin(); instruction != symbolInfo->instructions.end(); instruction++ ) { if ( instruction->isInstruction ) { currentAddress = instruction->address - baseAddress; textFile << std::left << "0x" << std::setw( 70 ) << instruction->line.c_str() << " " << std::right << "| 0x" << std::hex << std::setfill( '0' ) << std::setw( 8 ) << currentAddress << " " << std::dec << std::setfill( ' ' ) << "*| exec: " << std::setw( 4 ) << coverageMap->getWasExecuted( currentAddress ) << " | taken/not: " << std::setw( 4 ) << coverageMap->getWasTaken( currentAddress ) << "/" << std::setw( 4 ) << coverageMap->getWasNotTaken( currentAddress ) << " "; if ( instruction->isBranch ) textFile << "| Branch "; else textFile << " "; if ( instruction->isNop ) textFile << "| NOP(" << std::setw( 3 ) << instruction->nopSize << ") " << std::endl; else textFile << " " << std::endl; } } } } void GcovFunctionData::setBlockFileName( const blocks_iterator_t block, const std::string& fileName ) { block->sourceFileName = fileName; } void GcovFunctionData::addBlockLine( const blocks_iterator_t block, const uint32_t line ) { block->lines.push_back( line ); (block->numberOfLines)++; } blocks_iterator_t GcovFunctionData::findBlockById( const uint32_t id ) { blocks_iterator_t blockIterator; if ( !blocks.empty() ) { blockIterator = blocks.begin(); while ( blockIterator != blocks.end() ) { if ( blockIterator->id == id) { break; } blockIterator++; } } else { std::cerr << "ERROR: GcovFunctionData::findBlockById() failed" << ", no blocks present" << std::endl; } return blockIterator; } void GcovFunctionData::printArcInfo( std::ofstream& textFile, arcs_iterator_t arc ) { textFile << " > ARC " << std::setw( 3 ) << arc->sourceBlock << " -> " << arc->destinationBlock << " "; textFile << "\tFLAGS: "; switch ( arc->flags ) { case 0: textFile << "( ___________ ____ _______ )"; break; case 1: textFile << "( ___________ ____ ON_TREE )"; break; case 2: textFile << "( ___________ FAKE _______ )"; break; case 3: textFile << "( ___________ FAKE ON_TREE )"; break; case 4: textFile << "( FALLTHROUGH ____ _______ )"; break; case 5: textFile << "( FALLTHROUGH ____ ON_TREE )"; break; default: textFile << "( =======FLAGS_ERROR====== )"; std::cerr << " ERROR: Unknown arc flag: 0x" << std::hex << arcs.back().flags << std::endl << std::dec; break; } textFile << "\tTaken: " << std::setw( 5 ) << arc->counter << std::endl; } void GcovFunctionData::printBlockInfo( std::ofstream& textFile, blocks_iterator_t block ) { std::list::iterator line; rtems::utils::ostream_guard old_state( textFile ); textFile << " > BLOCK " << std::setw( 3 ) << block->id << " from " << block->sourceFileName << std::endl << " -counter: " << std::setw( 5 ) << block->counter << std::endl << " -flags: 0x" << std::hex << block->flags << std::endl << " -lines: "; if ( !block->lines.empty() ) for ( line = block->lines.begin(); line != block->lines.end(); line++ ) { textFile << *line << ", "; } textFile << std::endl; } bool GcovFunctionData::processFunctionCounters() { uint32_t baseAddress = 0; uint32_t currentAddress = 0; blocks_iterator_t blockIterator; blocks_iterator_t blockIterator2; arcs_iterator_t arcIterator; arcs_iterator_t arcIterator2; std::list taken; // List of taken counts for branches std::list notTaken; // List of not taken counts for branches std::list::iterator instruction; //std::cerr << "DEBUG: Processing counters for file: " << sourceFileName // << std::endl; if ( blocks.empty() || arcs.empty() || coverageMap == NULL || symbolInfo->instructions.empty() ) { //std::cerr << "DEBUG: sanity check returned false for function: " // << functionName << " from file: " << sourceFileName // << std::endl; return false; } // Reset iterators and variables blockIterator = blocks.begin(); arcIterator = arcs.begin(); arcIterator2 = arcIterator; arcIterator2++; instruction = symbolInfo->instructions.begin(); baseAddress = coverageMap->getFirstLowAddress(); //symbolInfo->baseAddress; currentAddress = baseAddress; // Find taken/not taken values for branches if ( !processBranches( &taken , ¬Taken ) ) { //std::cerr << "ERROR: Failed to process branches for function: " // << functionName << " from file: " << sourceFileName // << std::endl; return false; }; // Process the branching arcs while ( blockIterator != blocks.end() ) { //std::cerr << "DEBUG: Processing branches" << std::endl; while ( arcIterator->sourceBlock != blockIterator->id ) { if ( arcIterator == arcs.end() ) { //std::cerr << "ERROR: Unexpectedly runned out of arcs to analyze" // << std::endl; return false; } arcIterator++; arcIterator2++; } // If no more branches break; if ( arcIterator2 == arcs.end() ) { break; } // If this is a branch without FAKE arcs process it if ( ( arcIterator->sourceBlock == arcIterator2->sourceBlock ) && !( arcIterator->flags & FAKE_ARC_FLAG ) && !( arcIterator2->flags & FAKE_ARC_FLAG ) ) { if ( taken.empty() || notTaken.empty() ) { std::cerr << "ERROR: Branches missing for function: " << functionName << " from file: " << sourceFileName << std::endl; return false; } //std::cerr << "DEBUG: Found true branching arc " // << std::setw( 3 ) << arcIterator->sourceBlock << " -> " // << std::setw( 3 ) << arcIteratior->destinationBlock // << std::endl; if ( arcIterator->flags & FALLTHROUGH_ARC_FLAG ) { arcIterator->counter = notTaken.front(); notTaken.pop_front(); arcIterator2->counter = taken.front(); taken.pop_front(); } else { arcIterator2->counter = notTaken.front(); notTaken.pop_front(); arcIterator->counter = taken.front(); taken.pop_front(); } blockIterator2 = blocks.begin(); //TODO: ADD FAILSAFE while ( arcIterator->destinationBlock != blockIterator2->id ) { blockIterator2++; } blockIterator2->counter += arcIterator->counter; blockIterator2 = blocks.begin(); //TODO: ADD FAILSAFE while ( arcIterator2->destinationBlock != blockIterator2->id ) { blockIterator2++; } blockIterator2->counter += arcIterator2->counter; } blockIterator++; } // Reset iterators and variables blockIterator = blocks.begin(); arcIterator = arcs.begin(); arcIterator2 = arcIterator; arcIterator2++; // Set the first block blockIterator->counter = coverageMap->getWasExecuted( currentAddress ); // Analyze remaining arcs and blocks while ( blockIterator != blocks.end() ) { while ( arcIterator->sourceBlock != blockIterator->id ) { if ( arcIterator == arcs.end() ) { std::cerr << "ERROR: Unexpectedly runned out of arcs to analyze" << std::endl; return false; } arcIterator++; arcIterator2++; } // If this is the last arc, propagate counter and exit if ( arcIterator2 == arcs.end() ) { //std::cerr << "DEBUG: Found last arc " << std::setw( 3 ) // << arcIterator->sourceBlock << " -> " << std::setw( 3 ) // << arcIterator->destinationBlock << std::endl; arcIterator->counter = blockIterator->counter; blockIterator2 = blocks.begin(); while ( arcIterator->destinationBlock != blockIterator2->id ) { //TODO: ADD FAILSAFE blockIterator2++; } blockIterator2->counter += arcIterator->counter; return true; } // If this is not a branch, propagate counter and continue if ( arcIterator->sourceBlock != arcIterator2->sourceBlock ) { //std::cerr << "DEBUG: Found simple arc " << std::setw( 3 ) // << arcIterator->sourceBlock << " -> " << std::setw( 3 ) // << arcIterator->destinationBlock << std::endl; arcIterator->counter = blockIterator->counter; blockIterator2 = blocks.begin(); while ( arcIterator->destinationBlock != blockIterator2->id ) { //TODO: ADD FAILSAFE blockIterator2++; } blockIterator2->counter += arcIterator->counter; } // If this is a branch with FAKE arc else if ( ( arcIterator->sourceBlock == arcIterator2->sourceBlock ) && ( arcIterator2->flags & FAKE_ARC_FLAG ) ) { //std::cerr << "DEBUG: Found fake branching arc " << std::setw( 3 ) // << arcIterator->sourceBlock << " -> " << std::setw( 3 ) // << arcIterator->destinationBlock << std::endl; arcIterator->counter = blockIterator->counter; blockIterator2 = blocks.begin(); while ( arcIterator->destinationBlock != blockIterator2->id ) { //TODO: ADD FAILSAFE blockIterator2++; } blockIterator2->counter += arcIterator->counter; } // If this is a legitimate branch blockIterator++; } return true; } bool GcovFunctionData::processBranches( std::list* taken , std::list* notTaken ) { uint32_t baseAddress = 0; uint32_t currentAddress; std::list::iterator instruction; if ( coverageMap == NULL ) { return false; } //baseAddress = coverageMap->getFirstLowAddress(); //symbolInfo->baseAddress; for ( instruction = symbolInfo->instructions.begin(); instruction != symbolInfo->instructions.end(); instruction++ ) { if( instruction->isInstruction ) { baseAddress = instruction->address; break; } } // std::cerr << "DEBUG: Processing instructions in search of branches" // << std::endl; for ( instruction = symbolInfo->instructions.begin(); instruction != symbolInfo->instructions.end(); instruction++ ) { if ( instruction->isInstruction ) { currentAddress = instruction-> address - baseAddress; if ( instruction->isBranch ) { taken->push_back( (uint64_t) coverageMap->getWasTaken( currentAddress ) ); notTaken->push_back( (uint64_t) coverageMap->getWasNotTaken( currentAddress ) ); //std::cerr << "Added branch to list taken/not: " << std::setw( 4 ) // << coverageMap->getWasTaken( currentAddress ) // << "/" << std::setw( 4 ) // << coverageMap->getWasNotTaken( currentAddress ) // << std::endl; } } } return true; } }