diff options
author | Chris Johns <chrisj@rtems.org> | 2014-05-09 21:50:37 +1000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2014-06-18 16:48:08 +1200 |
commit | 100f517ab37265acdf067e36b6860020ec8b2184 (patch) | |
tree | 2316c8b888e11dcbcfbfc66a0c1e31991ea20656 /tester/covoar/GcovFunctionData.cc | |
parent | 4.11: Add ntp patch. (diff) | |
download | rtems-tools-100f517ab37265acdf067e36b6860020ec8b2184.tar.bz2 |
covoar: Merger the covoar source from rtems-testing.git.
Use waf to build covoar.
Diffstat (limited to 'tester/covoar/GcovFunctionData.cc')
-rw-r--r-- | tester/covoar/GcovFunctionData.cc | 602 |
1 files changed, 602 insertions, 0 deletions
diff --git a/tester/covoar/GcovFunctionData.cc b/tester/covoar/GcovFunctionData.cc new file mode 100644 index 0000000..f746b12 --- /dev/null +++ b/tester/covoar/GcovFunctionData.cc @@ -0,0 +1,602 @@ +/*! @file GcovFunctionData.cc + * @brief GcovFunctionData Implementation + * + * This file contains the implementation of the class storing information + * about single function. + */ + +#include <stdio.h> +#include <string.h> +//#include <stdlib.h> +//#include <sys/stat.h> + +#include "app_common.h" +#include "GcovFunctionData.h" +#include "ObjdumpProcessor.h" +#include "CoverageMapBase.h" + + +namespace Gcov { + + GcovFunctionData::GcovFunctionData() + { + numberOfArcs = 0; + numberOfBlocks = 0; + coverageMap = 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 char* fcnName ) + { + std::string symbolName; + + symbolName = fcnName; + + if ( strlen(fcnName) >= FUNCTION_NAME_LENGTH ) { + fprintf( + stderr, + "ERROR: Function name is too long to be correctly stored: %u\n", + (unsigned int) strlen(fcnName) + ); + return false; + } + + strcpy (functionName, fcnName); + + // Tie function to its coverage map + symbolInfo = SymbolsToAnalyze->find( symbolName ); + if ( symbolInfo != NULL ) + coverageMap = symbolInfo->unifiedCoverageMap; + +#if 0 + if ( coverageMap == NULL) { + fprintf( + stderr, + "ERROR: Could not find coverage map for: %s\n", + symbolName.c_str() + ); + } else { + fprintf( + stderr, + "SUCCESS: Hound coverage map for: %s\n", + symbolName.c_str() + ); + } +#endif + + return true; + } + + bool GcovFunctionData::setFileName( const char* fileName ) { + if ( strlen(fileName) >= FILE_NAME_LENGTH ){ + fprintf( + stderr, + "ERROR: File name is too long to be correctly stored: %u\n", + (unsigned int) strlen(fileName) + ); + return false; + } + strcpy (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 char * sourceFileName + ) + { + gcov_block_info block; + numberOfBlocks++; + block.id = id; + block.flags = flags; + block.numberOfLines = 0; + block.counter = 0; + strcpy (block.sourceFileName, sourceFileName); + blocks.push_back(block); + } + + void GcovFunctionData::printFunctionInfo( + FILE * textFile, + uint32_t function_number + ) + { + blocks_iterator_t currentBlock; + arcs_iterator_t currentArc; + + fprintf( + textFile, + "\n\n==========================" + "FUNCTION %3d " + "==========================\n\n", + function_number + ); + fprintf( + textFile, + "Name: %s\n" + "File: %s\n" + "Line: %u\n" + "Id: %u\n" + "Checksum: 0x%x\n\n", + functionName, + sourceFileName, + firstLineNumber, + id, + checksum + ); + + // Print arcs info + for ( currentArc = arcs.begin(); currentArc != arcs.end(); currentArc++ ) { + printArcInfo( textFile, currentArc ); + } + fprintf( textFile, "\n"); + + // Print blocks info + for ( currentBlock = blocks.begin(); + currentBlock != blocks.end(); + currentBlock++ + ) { + printBlockInfo( textFile, currentBlock ); + } + } + + void GcovFunctionData::printCoverageInfo( + FILE *textFile, + uint32_t function_number + ) + { + uint32_t baseAddress = 0; + uint32_t baseSize; + uint32_t currentAddress; + std::list<Coverage::ObjdumpProcessor::objdumpLine_t>::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(); + + fprintf( + textFile, + "\nInstructions (Base address: 0x%08x, Size: %4u): \n\n", + baseAddress, + baseSize + ); + for ( instruction = symbolInfo->instructions.begin(); + instruction != symbolInfo->instructions.end(); + instruction++ + ) + { + if ( instruction->isInstruction ) { + currentAddress = instruction->address - baseAddress; + fprintf( textFile, "0x%-70s ", instruction->line.c_str() ); + fprintf( textFile, "| 0x%08x ", currentAddress ); + fprintf( textFile, "*"); + fprintf( textFile, + "| exec: %4u ", + coverageMap->getWasExecuted( currentAddress ) + ); + fprintf( textFile, "| taken/not: %4u/%4u ", + coverageMap->getWasTaken( currentAddress ), + coverageMap->getWasNotTaken( currentAddress ) + ); + + if ( instruction->isBranch ) + fprintf( textFile, "| Branch " ); + else + fprintf( textFile, " " ); + + if ( instruction->isNop ) + fprintf( textFile, "| NOP(%3u) \n", instruction->nopSize ); + else + fprintf( textFile, " \n" ); + } + } + } + } + + void GcovFunctionData::setBlockFileName( + const blocks_iterator_t block, + const char *fileName + ) + { + strcpy(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 { + fprintf( + stderr, + "ERROR: GcovFunctionData::findBlockById() failed, no blocks present\n" + ); + } + return blockIterator; + } + + void GcovFunctionData::printArcInfo( + FILE * textFile, arcs_iterator_t arc + ) + { + fprintf( + textFile, + " > ARC %3u -> %3u ", + arc->sourceBlock, + arc->destinationBlock + ); + + fprintf( textFile, "\tFLAGS: "); + switch ( arc->flags ){ + case 0: + fprintf( textFile, "( ___________ ____ _______ )"); + break; + case 1: + fprintf( textFile, "( ___________ ____ ON_TREE )"); + break; + case 2: + fprintf( textFile, "( ___________ FAKE _______ )"); + break; + case 3: + fprintf( textFile, "( ___________ FAKE ON_TREE )"); + break; + case 4: + fprintf( textFile, "( FALLTHROUGH ____ _______ )"); + break; + case 5: + fprintf( textFile, "( FALLTHROUGH ____ ON_TREE )"); + break; + default: + fprintf( textFile, "( =======FLAGS_ERROR====== )"); + fprintf( stderr, + " ERROR: Unknown arc flag: 0x%x\n", + arcs.back().flags + ); + break; + } + fprintf( textFile, "\tTaken: %5llu\n", (unsigned long long) arc->counter ); + } + + void GcovFunctionData::printBlockInfo( + FILE * textFile, + blocks_iterator_t block + ) + { + std::list<uint32_t>::iterator line; + + fprintf( + textFile, + " > BLOCK %3u from %s\n" + " -counter: %5llu\n" + " -flags: 0x%x\n" + " -lines: ", + block->id, + block->sourceFileName, + (unsigned long long) block->counter, + block->flags + ); + if ( !block->lines.empty( ) ) + for ( line = block->lines.begin() ; line != block->lines.end(); line++ ) + fprintf ( textFile, "%u, ", *line); + fprintf ( textFile, "\n"); + } + + bool GcovFunctionData::processFunctionCounters( void ) { + + uint32_t baseAddress = 0; + uint32_t currentAddress = 0; + std::list<Coverage::ObjdumpProcessor::objdumpLine_t>::iterator instruction; + blocks_iterator_t blockIterator; + blocks_iterator_t blockIterator2; + arcs_iterator_t arcIterator; + arcs_iterator_t arcIterator2; + std::list<uint64_t> taken; // List of taken counts for branches + std::list<uint64_t> notTaken; // List of not taken counts for branches + + //fprintf( stderr, "DEBUG: Processing counters for file: %s\n", sourceFileName ); + if ( blocks.empty() || arcs.empty() || coverageMap == NULL || symbolInfo->instructions.empty()) + { + //fprintf( stderr, + // "DEBUG: sanity check returned false for function: %s from file: %s\n", + // functionName, + // sourceFileName + //); + 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 ) ) + { + //fprintf( stderr, + // "ERROR: Failed to process branches for function: %s from file: %s\n", + // functionName, + // sourceFileName + //); + return false; + }; + + // Process the branching arcs + while ( blockIterator != blocks.end() ) { + //fprintf( stderr, "DEBUG: Processing branches\n" ); + while ( arcIterator->sourceBlock != blockIterator->id ) { + if ( arcIterator == arcs.end() ) { + //fprintf( stderr, "ERROR: Unexpectedly runned out of arcs to analyze\n" ); + 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() ) { + fprintf( + stderr, + "ERROR: Branchess missing for function: %s from file: %s\n", + functionName, + sourceFileName + ); + return false; + } + //fprintf( stderr, "DEBUG: Found true branching arc %3u -> %3u\n", arcIterator->sourceBlock, arcIterator->destinationBlock ); + 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() ) { + fprintf( stderr, "ERROR: Unexpectedly runned out of arcs to analyze\n" ); + return false; + } + arcIterator++; + arcIterator2++; + } + + // If this is the last arc, propagate counter and exit + if ( arcIterator2 == arcs.end() ) { + //fprintf( stderr, + // "DEBUG: Found last arc %3u -> %3u\n", + // arcIterator->sourceBlock, + // arcIterator->destinationBlock + //); + 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 ) { + //fprintf( stderr, "DEBUG: Found simple arc %3u -> %3u\n", arcIterator->sourceBlock, arcIterator->destinationBlock ); + 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 )) + { + //fprintf( stderr, "DEBUG: Found fake branching arc %3u -> %3u\n", arcIterator->sourceBlock, arcIterator->destinationBlock ); + 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<uint64_t> * taken , + std::list<uint64_t> * notTaken + ) + { + uint32_t baseAddress = 0; + uint32_t currentAddress; + std::list<Coverage::ObjdumpProcessor::objdumpLine_t>::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; + } + + //fprintf( stderr, "DEBUG: Processing instructions in search of branches\n" ); + 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 ) ); + //fprintf( stderr, + // "Added branch to list taken/not: %4u/%4u\n", + // coverageMap->getWasTaken( currentAddress ), + // coverageMap->getWasNotTaken( currentAddress ) + //); + } + } + } + return true; + } +} + + |