summaryrefslogtreecommitdiffstats
path: root/covoar
diff options
context:
space:
mode:
authorJoel Sherrill <joel.sherrill@OARcorp.com>2011-12-01 20:24:47 +0000
committerJoel Sherrill <joel.sherrill@OARcorp.com>2011-12-01 20:24:47 +0000
commit6517cde9f4cbf76e47b9fa96cc1abfffac44a0d4 (patch)
tree8ede8e3fc7189f13596a9235f2a67311a70c32e0 /covoar
parent2011-12-01 Joel Sherrill <joel.sherrill@oarcorp.com> (diff)
downloadrtems-testing-6517cde9f4cbf76e47b9fa96cc1abfffac44a0d4.tar.bz2
2011-11-06 Pawel Zagorski <pzagor@agh.edu.pl>
* DesiredSymbols.cc, ExecutableInfo.cc, SymbolTable.cc, covoar.cc: Added methods dumpExecutableInfo( void ) and dumpSymbolTable( void ) that can dump cointainers to stdout for debug purposes. Covoar now accepts aditional command line argument -g GCNOS_LIST with list of xxx.gcno files. If non-empty list is provided gcov outputs will be craeated based on each file in the list.
Diffstat (limited to 'covoar')
-rw-r--r--covoar/ChangeLog9
-rw-r--r--covoar/CoverageMapBase.h3
-rw-r--r--covoar/DesiredSymbols.cc5
-rw-r--r--covoar/ExecutableInfo.cc8
-rw-r--r--covoar/ExecutableInfo.h5
-rw-r--r--covoar/GcovData.cc506
-rw-r--r--covoar/GcovData.h204
-rw-r--r--covoar/GcovFunctionData.cc595
-rw-r--r--covoar/GcovFunctionData.h278
-rw-r--r--covoar/Makefile4
-rw-r--r--covoar/SymbolTable.cc15
-rw-r--r--covoar/SymbolTable.h8
-rw-r--r--covoar/covoar.cc49
13 files changed, 1683 insertions, 6 deletions
diff --git a/covoar/ChangeLog b/covoar/ChangeLog
index 0d1379d..e4f9ed4 100644
--- a/covoar/ChangeLog
+++ b/covoar/ChangeLog
@@ -1,3 +1,12 @@
+2011-11-06 Pawel Zagorski <pzagor@agh.edu.pl>
+
+ * DesiredSymbols.cc, ExecutableInfo.cc, SymbolTable.cc, covoar.cc:
+ Added methods dumpExecutableInfo( void ) and dumpSymbolTable( void )
+ that can dump cointainers to stdout for debug purposes. Covoar now
+ accepts aditional command line argument -g GCNOS_LIST with list of
+ xxx.gcno files. If non-empty list is provided gcov outputs will be
+ craeated based on each file in the list.
+
2011-11-04 Joel Sherrill <joel.sherrill@oarcorp.com>
* DesiredSymbols.cc, ReportsBase.h, ReportsText.cc, ReportsText.h,
diff --git a/covoar/CoverageMapBase.h b/covoar/CoverageMapBase.h
index ab21a5c..b20d603 100644
--- a/covoar/CoverageMapBase.h
+++ b/covoar/CoverageMapBase.h
@@ -46,7 +46,8 @@ namespace Coverage {
/*
* This type identifies a list of ranges.
*/
- typedef std::list< AddressRange_t > AddressRange;
+ typedef std::list< AddressRange_t > AddressRange;
+ typedef std::list< AddressRange_t >::iterator AddressRangeIterator_t;
/*!
* This method constructs a CoverageMapBase instance.
diff --git a/covoar/DesiredSymbols.cc b/covoar/DesiredSymbols.cc
index 9ac6ae3..845fdef 100644
--- a/covoar/DesiredSymbols.cc
+++ b/covoar/DesiredSymbols.cc
@@ -72,7 +72,6 @@ namespace Coverage {
inputBuffer[0] = '\0';
inputBuffer2[0] = '\0';
cStatus = fscanf( sFile, "%s %s", inputBuffer, inputBuffer2 );
- //TODO: Store inputBuffer2 value containing symbol source file
if ( cStatus == EOF ) {
done = true;
}
@@ -97,9 +96,8 @@ namespace Coverage {
}
// Add this to the set of symbols.
- else {
+ else
set[ inputBuffer ] = *symInfo;
- }
}
}
}
@@ -462,6 +460,7 @@ namespace Coverage {
"ranges1.tmp",
"ranges2.tmp"
);
+
if (system( command )) {
fprintf(
stderr,
diff --git a/covoar/ExecutableInfo.cc b/covoar/ExecutableInfo.cc
index 26a1e50..770e54d 100644
--- a/covoar/ExecutableInfo.cc
+++ b/covoar/ExecutableInfo.cc
@@ -47,6 +47,14 @@ namespace Coverage {
}
}
+ void ExecutableInfo::dumpExecutableInfo( void ){
+ fprintf( stdout, "\n== Executable info ==\n");
+ fprintf( stdout, "executableName = %s\n", executableName.c_str());
+ fprintf( stdout, "libraryName = %s\n", libraryName.c_str());
+ fprintf( stdout, "loadAddress = %u\n", loadAddress);
+ theSymbolTable->dumpSymbolTable();
+ }
+
CoverageMapBase* ExecutableInfo::getCoverageMap ( uint32_t address )
{
CoverageMapBase* aCoverageMap = NULL;
diff --git a/covoar/ExecutableInfo.h b/covoar/ExecutableInfo.h
index 37c72e5..f468494 100644
--- a/covoar/ExecutableInfo.h
+++ b/covoar/ExecutableInfo.h
@@ -52,6 +52,11 @@ namespace Coverage {
void dumpCoverageMaps( void );
/*!
+ * This method prints the contents of Executable info containers
+ */
+ void dumpExecutableInfo( void );
+
+ /*!
* This method returns a pointer to the executable's coverage map
* that contains the specified address.
*
diff --git a/covoar/GcovData.cc b/covoar/GcovData.cc
new file mode 100644
index 0000000..0b29493
--- /dev/null
+++ b/covoar/GcovData.cc
@@ -0,0 +1,506 @@
+/*
+ * $Id$
+ *
+ * TODO: use strings instead of cstrings for reliability and saving memory
+ * TODO: use global buffers
+ *
+ */
+
+/*! @file GcovData.cc
+ * @brief GcovData Implementation
+ *
+ * This file contains the implementation of the functions supporting
+ * reading *.gcno and writing *.gcda files for gcov support
+ */
+
+#include <libgen.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+//#include <sys/stat.h>
+
+//#include "app_common.h"
+#include "GcovData.h"
+//#include "ExecutableInfo.h"
+//#include "CoverageMap.h"
+//#include "qemu-traces.h"
+
+
+namespace Gcov {
+
+ GcovData::GcovData()
+ {
+ numberOfFunctions = 0;
+ }
+
+ GcovData::~GcovData()
+ {
+ }
+
+ bool GcovData::readGcnoFile( const char* const fileName )
+ {
+ int status;
+ FILE* gcovFile;
+ char* tempString;
+ char* tempString2;
+ char* tempString3;
+
+ if ( strlen(fileName) >= FILE_NAME_LENGTH ){
+ fprintf( stderr, "ERROR: File name is to long to be correctly stored: %u\n", strlen(fileName) );
+ return false;
+ }
+ strcpy( gcnoFileName, fileName );
+ strcpy( gcdaFileName, fileName );
+ strcpy( textFileName, fileName );
+ strcpy( cFileName, fileName );
+ tempString = strstr( gcdaFileName,".gcno" );
+ tempString2 = strstr( textFileName,".gcno" );
+ tempString3 = strstr( cFileName,".gcno" );
+
+ if ( (tempString == NULL) && (tempString2 == NULL) ){
+ fprintf(stderr, "ERROR: incorrect name of *.gcno file\n");
+ }
+ else
+ {
+ strcpy( tempString, ".gcda"); // construct gcda file name
+ strcpy( tempString2, ".txt"); // construct report file name
+ strcpy( tempString3, ".c"); // construct source file name
+ }
+
+ // Debug message
+ // fprintf( stderr, "Readning file: %s\n", gcnoFileName);
+
+ // Open the notes file.
+ gcovFile = fopen( gcnoFileName, "r" );
+ if ( !gcovFile ) {
+ fprintf( stderr, "Unable to open %s\n", gcnoFileName );
+ return false;
+ }
+
+ // Read and validate the gcnoPreamble (magic, version, timestamp) from the file
+ status = readFilePreamble( &gcnoPreamble, gcovFile, GCNO_MAGIC );
+ if ( status <= 0 ){
+ fprintf( stderr, "Unable to read %s\n", gcnoFileName );
+ fclose( gcovFile );
+ return false;
+ }
+
+ //Read all remaining frames from file
+ while( readFrame(gcovFile) ){}
+
+ fclose( gcovFile );
+ return true;
+ }
+
+
+ bool GcovData::writeGcdaFile ()
+ {
+ gcov_preamble preamble;
+ gcov_frame_header header;
+ FILE* gcdaFile;
+ functions_iterator_t currentFunction;
+ arcs_iterator_t currentArc;
+ uint32_t buffer;
+ uint32_t countersFound;
+ uint32_t countersFoundSum;
+ uint64_t countersSum;
+ uint64_t countersMax;
+ uint64_t llBuffer[4096]; // TODO: Use common buffer
+ gcov_statistics objectStats;
+ gcov_statistics programStats;
+ size_t status;
+
+ // Debug message
+ // fprintf( stderr, "Writing file: %s\n", gcdaFileName);
+
+ // Lets clear counters sumators
+ countersSum = 0;
+ countersMax = 0;
+ countersFoundSum = 0;
+
+ // Open the data file.
+ gcdaFile = fopen( gcdaFileName, "w" );
+ if ( !gcdaFile ) {
+ fprintf( stderr, "Unable to create %s\n", gcdaFileName );
+ return false;
+ }
+
+ //Form preamble
+ preamble.magic = GCDA_MAGIC;
+ preamble.version = gcnoPreamble.version;
+ preamble.timestamp = gcnoPreamble.timestamp;
+
+ //Write preamble
+ status = fwrite (&preamble , sizeof( preamble ), 1 , gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing gcda preamble to a file %s\n", gcdaFileName );
+
+ //Write function info and counter counts
+ for (
+ currentFunction = functions.begin();
+ currentFunction != functions.end();
+ currentFunction++
+ )
+ {
+ //Write function announcement frame header (length always equals 2)
+ header.tag = GCOV_TAG_FUNCTION;
+ header.length = 2;
+ status = fwrite (&header, sizeof(header), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing function announcement to a file %s\n", gcdaFileName );
+
+ //Write function id
+ buffer = (*currentFunction)->getId();
+ status = fwrite (&buffer, sizeof( buffer ), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing function id to a file %s\n", gcdaFileName );
+
+ //Write function checksum
+ buffer = (*currentFunction)->getChecksum();
+ status = fwrite (&buffer, sizeof( buffer ), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing function checksum to a file %s\n", gcdaFileName );
+
+ // Determine how many counters there are
+ // and store their counts in buffer
+ countersFound = 0;
+ (*currentFunction)->getCounters( llBuffer, countersFound, countersSum, countersMax );
+ countersFoundSum += countersFound;
+
+ //Write info about counters
+ header.tag = GCOV_TAG_COUNTER;
+ header.length = countersFound * 2;
+ status = fwrite (&header, sizeof( header ), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing counter header to a file %s\n", gcdaFileName );
+
+ status = fwrite (llBuffer, sizeof( uint64_t ), countersFound , gcdaFile );
+ if ( status != countersFound )
+ fprintf( stderr, "Error while writing counter data to a file %s\n", gcdaFileName );
+ }
+
+ // Prepare frame with object file statistics
+ header.tag = GCOV_TAG_OBJECT_SUMMARY;
+ header.length = 9;
+ objectStats.checksum = 0; // TODO: have no idea hov to calculates it :)
+ objectStats.counters = countersFoundSum;
+ objectStats.runs = 1; // We are lying for now, we have no means of figuring this out
+ objectStats.sum = countersSum; // Sum of all counters
+ objectStats.max = countersMax; // max value for counter on last run, we have no clue
+ objectStats.sumMax = countersMax; // we have no clue
+
+ // Write data
+ status = fwrite (&header, sizeof( header ), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing stats header to a file %s\n", gcdaFileName );
+ status = fwrite (&objectStats, sizeof( objectStats ), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing object stats to a file %s\n", gcdaFileName );
+
+
+ // Prepare frame with program statistics
+ header.tag = GCOV_TAG_PROGRAM_SUMMARY;
+ header.length = 9;
+ programStats.checksum = 0; // TODO: have no idea hov to calculate it :)
+ programStats.counters = countersFoundSum;
+ programStats.runs = 1; // We are lying for now, we have no clue
+ programStats.sum = countersSum; // Sum of all counters
+ programStats.max = countersMax; // max value for counter on last run, we have no clue
+ programStats.sumMax = countersMax; // we have no clue
+
+ // Write data
+ status = fwrite (&header, sizeof( header ), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing stats header to a file %s\n", gcdaFileName );
+ status = fwrite (&programStats, sizeof( programStats ), 1, gcdaFile );
+ if ( status != 1 )
+ fprintf( stderr, "Error while writing program stats to a file %s\n", gcdaFileName );
+
+ fclose( gcdaFile );
+
+ return true;
+ }
+
+ bool GcovData::readFrame(
+ FILE* gcovFile
+ )
+ {
+ gcov_frame_header header;
+ char buffer[512];
+ uint32_t intBuffer[4096];
+ uint32_t tempBlockId;
+ blocks_iterator_t tempBlockIterator;
+ int status;
+ GcovFunctionData* newFunction;
+
+ status = readFrameHeader( &header, gcovFile);
+
+ if ( status <= 0 ){
+ // Not printing error message because this
+ // happenns at the end of each file
+ return false;
+ }
+
+ switch (header.tag){
+
+ case GCOV_TAG_FUNCTION:
+
+ numberOfFunctions++;
+ newFunction = new GcovFunctionData;
+ if ( !readFunctionFrame(header, gcovFile, newFunction) ){
+ fprintf( stderr, "Error while reading FUNCTION from gcov file...\n" );
+ return false;
+ }
+ functions.push_back(newFunction);
+ break;
+
+ case GCOV_TAG_BLOCKS:
+
+ status = fread( &intBuffer, 4, header.length, gcovFile );
+ if ( status != (int) header.length){
+ fprintf(
+ stderr, "Error while reading BLOCKS from gcov file...\n"
+ "Header lenght is %u instead of %u\n",
+ header.length,
+ status
+ );
+ return false;
+ }
+
+ for( uint32_t i = 0; i < header.length; i++ )
+ functions.back()->addBlock(i, intBuffer[i], "");
+
+ break;
+
+ case GCOV_TAG_ARCS:
+
+ status = fread( &intBuffer, 4, header.length, gcovFile );
+ if (status != (int) header.length){
+ return false;
+ }
+
+ for ( int i = 1; i < (int) header.length; i += 2 )
+ functions.back()->addArc(intBuffer[0], intBuffer[i], intBuffer[i+1]);
+
+ break;
+
+ case GCOV_TAG_LINES:
+
+ status = fread( &intBuffer, 4, 2, gcovFile );
+ if (status != 2 || intBuffer[1] != 0){
+ fprintf(
+ stderr,
+ "Error while reading block id for LINES from gcov file..."
+ );
+ return false;
+ }
+ tempBlockId = intBuffer[0];
+ header.length -= 2;
+
+ // Find the right block
+ tempBlockIterator =functions.back()->findBlockById(tempBlockId);
+
+ header.length -= readString(buffer, gcovFile);
+ functions.back()->setBlockFileName( tempBlockIterator, buffer );
+
+ status = fread( &intBuffer, 4, header.length, gcovFile );
+ if (status != (int) header.length){
+ fprintf( stderr, "Error while reading LINES from gcov file..." );
+ return false;
+ }
+
+ else
+ for (int i = 0; i < (int) (header.length - 2); i++)
+ functions.back()->addBlockLine( tempBlockIterator, intBuffer[i] );
+
+ break;
+
+ default:
+
+ fprintf( stderr, "\n\nERROR - encountered unknown *.gcno tag : 0x%x\n", header.tag );
+ break;
+ }
+
+ return true;
+ }
+
+ int GcovData::readString(
+ char* buffer, //TODO: use global buffer here
+ FILE* gcovFile
+ )
+ {
+ int status;
+ int length;
+
+ status = fread( &length, sizeof(int), 1, gcovFile );
+ if (status != 1){
+ fprintf( stderr, "ERROR: Unable to read string length from gcov file\n" );
+ return -1;
+ }
+
+ status = fread( buffer, length * 4 , 1, gcovFile );
+ if (status != 1){
+ fprintf( stderr, "ERROR: Unable to read string from gcov file\n" );
+ return -1;
+ }
+
+ buffer[length * 4] = '\0';
+
+ return length +1;
+ }
+
+ int GcovData::readFrameHeader(
+ gcov_frame_header* header,
+ FILE* gcovFile
+ )
+ {
+ int status;
+ int length;
+
+ length = sizeof(gcov_frame_header);
+ status = fread( header, length, 1, gcovFile );
+ if (status != 1){
+ //fprintf( stderr, "ERROR: Unable to read frame header from gcov file\n" );
+ return -1;
+ }
+
+ return length / 4;
+ }
+
+ int GcovData::readFilePreamble(
+ gcov_preamble* preamble,
+ FILE* gcovFile,
+ uint32_t desiredMagic
+ )
+ {
+ int status;
+ int length;
+
+ length = sizeof( gcov_preamble );
+ status = fread( preamble, sizeof( gcov_preamble), 1, gcovFile );
+ if (status <= 0) {
+ fprintf( stderr, "Error while reading file preamble\n" );
+ return -1;
+ }
+
+ if ( preamble->magic != GCNO_MAGIC ) {
+ fprintf( stderr, "File is not a valid *.gcno output (magic: 0x%4x)\n", preamble->magic );
+ return -1;
+ }
+
+ return length / 4;
+ }
+
+ bool GcovData::readFunctionFrame(
+ gcov_frame_header header,
+ FILE* gcovFile,
+ GcovFunctionData* function
+ )
+ {
+ char buffer[512]; //TODO: use common buffers
+ uint32_t intBuffer[4096];
+ int status;
+
+ status = fread( &intBuffer, 8, 1, gcovFile );
+ if (status != 1){
+ fprintf( stderr, "ERROR: Unable to read Function ID & checksum\n" );
+ return false;
+ }
+ header.length -= 2;
+ function->setId( intBuffer[0] );
+ function->setChecksum( intBuffer[1] );
+
+ header.length -= readString( buffer, gcovFile );
+ function->setFunctionName( buffer );
+ header.length -= readString( buffer, gcovFile );
+ function->setFileName( buffer );
+ status = fread( &intBuffer, 4, header.length, gcovFile );
+ if (status <= 0){
+ fprintf( stderr, "ERROR: Unable to read Function starting line number\n" );
+ return false;
+ }
+ function->setFirstLineNumber( intBuffer[0] );
+
+ return true;
+ }
+
+ bool GcovData::writeReportFile()
+ {
+ functions_iterator_t currentFunction;
+ uint32_t i = 1; //iterator
+ FILE* textFile;
+
+ // Debug message
+ // fprintf( stderr, "Writing file: %s\n", textFileName);
+
+ // Open the data file.
+ textFile = fopen( textFileName, "w" );
+ if ( !textFile ) {
+ fprintf( stderr, "Unable to create %s\n", textFileName );
+ return false;
+ }
+
+ printGcnoFileInfo( textFile );
+
+ for (
+ currentFunction = functions.begin();
+ currentFunction != functions.end();
+ currentFunction++
+ )
+ {
+ (*currentFunction)->printFunctionInfo( textFile, i );
+ (*currentFunction)->printCoverageInfo( textFile, i );
+ i++;
+ }
+
+ fclose ( textFile );
+ return true;
+ }
+
+ void GcovData::printGcnoFileInfo( FILE * textFile )
+ {
+ fprintf(
+ textFile,
+ "\nFILE:\t\t\t%s\n"
+ "magic:\t\t\t%x\n"
+ "version:\t\t%x\n"
+ "timestamp:\t\t%x\n"
+ "functions found: \t%u\n\n",
+ gcnoFileName,
+ gcnoPreamble.magic,
+ gcnoPreamble.version,
+ gcnoPreamble.timestamp,
+ numberOfFunctions
+ );
+ }
+
+ void GcovData::writeGcovFile( )
+ {
+ char path[512];
+ char command[512];
+
+ //fprintf (stderr, "Attempting to run gcov for: %s\n", cFileName );
+ strcpy( path, cFileName );
+ dirname( path );
+ sprintf( command, "( cd %s && gcov %s &>> gcov.log)", path, basename( cFileName ) );
+ //fprintf (stderr, "> %s\n", command );
+ system( command );
+ }
+
+ bool GcovData::processCounters( )
+ {
+ functions_iterator_t currentFunction;
+ bool status = true;
+ for (
+ currentFunction = functions.begin();
+ currentFunction != functions.end();
+ currentFunction++
+ )
+ {
+ if ( !(*currentFunction)->processFunctionCounters( ) )
+ status = false;
+ }
+
+ return status;
+ }
+}
diff --git a/covoar/GcovData.h b/covoar/GcovData.h
new file mode 100644
index 0000000..f1fd0b8
--- /dev/null
+++ b/covoar/GcovData.h
@@ -0,0 +1,204 @@
+/*
+ * $Id$
+ */
+
+/*! @file GcovData.h
+ * @brief GcovData Specification
+ *
+ * This file contains the specification of the GcovGcnoWriter class.
+ */
+
+#ifndef __GCOV_DATA_H__
+#define __GCOV_DATA_H__
+
+#include <stdint.h>
+#include <list>
+#include <iostream>
+#include "GcovFunctionData.h"
+
+namespace Gcov {
+
+#define GCDA_MAGIC ((uint32_t) 0x67636461 ) /* "gcda" */
+#define GCNO_MAGIC ((uint32_t) 0x67636e6f ) /* "gcno" */
+
+/* we are using gcc 4.6 release format, coded as "406R" */
+#define GCNO_VERSION ((uint32_t) 0x34303652 )
+
+/* GCOV tags */
+#define GCOV_TAG_FUNCTION ((uint32_t)0x01000000)
+#define GCOV_TAG_BLOCKS ((uint32_t)0x01410000)
+#define GCOV_TAG_ARCS ((uint32_t)0x01430000)
+#define GCOV_TAG_LINES ((uint32_t)0x01450000)
+#define GCOV_TAG_COUNTER ((uint32_t)0x01a10000)
+#define GCOV_TAG_OBJECT_SUMMARY ((uint32_t)0xa1000000)
+#define GCOV_TAG_PROGRAM_SUMMARY ((uint32_t)0xa3000000)
+
+
+typedef std::list<Gcov::GcovFunctionData*> functions_t;
+typedef std::list<Gcov::GcovFunctionData*>::iterator functions_iterator_t;
+
+struct gcov_preamble
+{
+ uint32_t magic;
+ uint32_t version;
+ uint32_t timestamp;
+};
+
+struct gcov_frame_header
+{
+ uint32_t tag;
+ uint32_t length;
+};
+
+struct gcov_statistics
+{
+ uint32_t checksum; // checksum
+ uint32_t counters; // number of counters
+ uint32_t runs; // number of runs
+ uint64_t sum; // sum of all couter values
+ uint64_t max; // max value on a single run
+ uint64_t sumMax; // sum of individual runs max values
+};
+
+ /*! @class GcovData
+ *
+ * This is the specification of the GcovData class.
+ */
+ class GcovData {
+
+ public:
+
+ /*!
+ * This method constructs a GcnoReader instance.
+ */
+ GcovData();
+
+ /*!
+ * This method destructs a GcnoReader instance.
+ */
+ virtual ~GcovData();
+
+ /*!
+ * This method reads the *.gcno file
+ *
+ * @param[in] fileName name of the file to read
+ *
+ * @return Returns TRUE if the method succeeded and FALSE if it failed.
+ */
+ bool readGcnoFile( const char* const fileName );
+
+ /*!
+ * This method writes the *.gcda file. It also produces and stores
+ * gcda and txt file names for future outputs.
+ *
+ * @return Returns TRUE if the method succeeded and FALSE if it failed.
+ */
+ bool writeGcdaFile ();
+
+ /*!
+ * This method writes all contained information to stdout file
+ *
+ * @return Returns TRUE if the method succeeded and FALSE if it failed.
+ */
+ bool writeReportFile();
+
+ /*!
+ * This method runs gcov to generate report. This method should
+ * be used only when gcno and gcda files are already generated.
+ */
+ void writeGcovFile( );
+
+ /*!
+ * This method calculates values of counters for all functions
+ */
+ bool processCounters( void );
+
+ private:
+
+ uint32_t numberOfFunctions;
+ gcov_preamble gcdaPreamble;
+ gcov_preamble gcnoPreamble;
+ char gcnoFileName[FILE_NAME_LENGTH];
+ char gcdaFileName[FILE_NAME_LENGTH];
+ char textFileName[FILE_NAME_LENGTH];
+ char cFileName[FILE_NAME_LENGTH];
+ functions_t functions;
+
+
+ /*!
+ * This method reads a frame from *.gcno file
+ *
+ * @param[in] file points to a file to read
+ *
+ * @return true if read was succesfull, false otherwise
+ */
+ bool readFrame(
+ FILE* gcovFile
+ );
+
+ /*!
+ * This method reads a string from gcov file
+ *
+ * @param[in] buffer stores the string
+ * @param[in] file specifies the name of the file to read
+ *
+ * @return Returns length of words read (word = 32bit) or -1 if error ocurred
+ */
+ int readString(
+ char* buffer,
+ FILE* gcovFile
+ );
+
+ /*!
+ * This method reads a frame header from gcov file
+ *
+ * @param[in] header stores the header
+ * @param[in] file specifies the name of the file to read
+ *
+ * @return Returns length of words read (word = 32bit)
+ * or -1 if error ocurred
+ */
+ int readFrameHeader(
+ gcov_frame_header* header,
+ FILE* gcovFile
+ );
+
+ /*!
+ * This method reads a frame header from gcov file
+ *
+ * @param[in] preamble stores the preamble
+ * @param[in] gcovFile specifies the name of the file to read
+ * @param[in] desiredMagic stores the expected magic of a file
+ *
+ * @return Returns length of words read (word = 32bit)
+ * or -1 if error ocurred
+ */
+ int readFilePreamble(
+ gcov_preamble* preamble,
+ FILE* gcovFile,
+ const uint32_t desiredMagic
+ );
+
+ /*!
+ * This method reads a function frame from gcov file
+ *
+ * @param[in] header passes frame header
+ * @param[in] gcovFile specifies the name of the file to read
+ * @param[in] function stores the expected magic of a file
+ *
+ * @return Returns true if operation was succesfull
+ */
+ bool readFunctionFrame(
+ gcov_frame_header header,
+ FILE* gcovFile,
+ GcovFunctionData* function
+ );
+
+ /*!
+ * This method prints info about previously read *.gcno file
+ * to a specified report file
+ */
+ void printGcnoFileInfo( FILE * textFile );
+ };
+}
+#endif
diff --git a/covoar/GcovFunctionData.cc b/covoar/GcovFunctionData.cc
new file mode 100644
index 0000000..051c5a6
--- /dev/null
+++ b/covoar/GcovFunctionData.cc
@@ -0,0 +1,595 @@
+/*
+ * $Id$
+ */
+
+/*! @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"
+//#include "ExecutableInfo.h"
+//#include "CoverageMap.h"
+//#include "qemu-traces.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 to long to be correctly stored: %u\n",
+ strlen(fcnName)
+ );
+ return false;
+ }
+
+ strcpy (functionName, fcnName);
+
+ // Tie function to its coverage map
+ symbolInfo = SymbolsToAnalyze->find( symbolName );
+ if ( symbolInfo != NULL )
+ coverageMap = symbolInfo->unifiedCoverageMap;
+
+ //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() );
+
+ return true;
+ }
+
+ bool GcovFunctionData::setFileName( const char* fileName ) {
+ if ( strlen(fileName) >= FILE_NAME_LENGTH ){
+ fprintf( stderr,
+ "ERROR: File name is to long to be correctly stored: %u\n",
+ 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", 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,
+ 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 , &notTaken ) )
+ {
+ //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;
+ }
+}
+
+
diff --git a/covoar/GcovFunctionData.h b/covoar/GcovFunctionData.h
new file mode 100644
index 0000000..3a98a98
--- /dev/null
+++ b/covoar/GcovFunctionData.h
@@ -0,0 +1,278 @@
+/*
+ * $Id$
+ */
+
+/*! @file GcovFunctionData.h
+ * @brief GcovFunctionData Specification
+ *
+ * This file contains the specification of the GcovGcnoWriter class.
+ */
+
+#ifndef __GCOV_FUNCTION_DATA_H__
+#define __GCOV_FUNCTION_DATA_H__
+
+#include <stdint.h>
+#include <list>
+#include "CoverageMapBase.h"
+#include "DesiredSymbols.h"
+
+namespace Gcov {
+
+#define FUNCTION_NAME_LENGTH 64
+#define FILE_NAME_LENGTH 256
+
+#define ON_TREE_ARC_FLAG 0x1
+#define FAKE_ARC_FLAG 0x2
+#define FALLTHROUGH_ARC_FLAG 0x4
+
+struct gcov_arc_info
+{
+ uint32_t sourceBlock;
+ uint32_t destinationBlock;
+ uint32_t flags;
+ uint64_t counter;
+};
+
+struct gcov_block_info
+{
+ uint32_t id;
+ uint32_t flags;
+ uint32_t numberOfLines;
+ uint64_t counter;
+ char sourceFileName[FILE_NAME_LENGTH];
+ std::list<uint32_t> lines;
+};
+
+typedef std::list<gcov_arc_info> arcs_t;
+typedef std::list<gcov_arc_info>::iterator arcs_iterator_t;
+typedef std::list<gcov_block_info> blocks_t;
+typedef std::list<gcov_block_info>::iterator blocks_iterator_t;
+
+ /*! @class GcovFunctionData
+ *
+ * This is the specification of the GcovFunctionData class.
+ */
+ class GcovFunctionData {
+
+ public:
+
+ /*!
+ * This method constructs a GcovFunctionData instance.
+ */
+ GcovFunctionData();
+
+ /*!
+ * This method destructs a GcovFunctionData instance.
+ */
+ virtual ~GcovFunctionData();
+
+ /*!
+ * This method stores checksum related to function
+ *
+ * @param[in] chk stores the checksum value
+ */
+ void setChecksum(
+ const uint32_t chk
+ );
+
+ /*!
+ * This method stores id of function
+ *
+ * @param[in] idNumber stores the id value
+ */
+ void setId(
+ const uint32_t idNumber
+ );
+
+ /*!
+ * This method stores checksum related to function
+ *
+ * @param[in] lineNo passes number of the line begining the function
+ */
+ void setFirstLineNumber(
+ const uint32_t lineNo
+ );
+
+ /*!
+ * This method stores name of the function and ties it to its
+ * unified coverage map.
+ *
+ * @param[in] functionName passes name of the the function
+ *
+ * @return Returns TRUE if the method succeeded and FALSE if it failed.
+ */
+ bool setFunctionName(
+ const char* fcnName
+ );
+
+ /*!
+ * This method stores name of the source file where function is located
+ *
+ * @param[in] fileName passes name of the the file
+ *
+ * @return Returns TRUE if the method succeeded and FALSE if it failed.
+ */
+ bool setFileName(
+ const char* fileName
+ );
+
+ /*!
+ * This method stores name of the source file where block is located
+ *
+ * @param[in] block identifies block
+ * @param[in] fileName passes name of the the file
+ *
+ * @return Returns TRUE if the method succeeded and FALSE if it failed.
+ */
+ void setBlockFileName(
+ const blocks_iterator_t block,
+ const char* fileName
+ );
+
+ /*!
+ * This method returns arcs list
+ */
+ arcs_t getArcs() const;
+
+ /*!
+ * This method returns blocks list
+ */
+ blocks_t getBlocks() const;
+
+ /*!
+ * This method returns checksum
+ */
+ uint32_t getChecksum() const;
+
+ /*!
+ * This method returns id
+ */
+ uint32_t getId() const;
+
+ /*!
+ * This method returns counters
+ *
+ * @param[out] counterValues array of counter values
+ * @param[out] countersFound used to return counters number
+ * @param[out] countersSum used to return sum counters values
+ * @param[out] countersMax used to return max counter value
+ */
+ void getCounters( uint64_t* counterValues, uint32_t &countersFound, uint64_t &countersSum, uint64_t &countersMax );
+
+ /*!
+ * This method adds new arc to arc list
+ *
+ * @param[in] source passes source block number
+ * @param[in] destination passes destination block number
+ */
+ void addArc(
+ uint32_t source,
+ uint32_t destination,
+ uint32_t flags
+ );
+
+ /*!
+ * This method adds new arc to arc list
+ *
+ * @param[in] block identifies block
+ * @param[in] line passes the line number
+ */
+ void addBlockLine(
+ const blocks_iterator_t block,
+ const uint32_t line
+ );
+
+ /*!
+ * This method finds block by its ID
+ *
+ * @param[in] id passes block id number
+ *
+ * @return Returns iterator to a matching block or NULL for error.
+ */
+ blocks_iterator_t findBlockById(
+ const uint32_t id
+ );
+
+ /*!
+ * This method adds new block to block list
+ *
+ * @param[in] id passes block id number
+ * @param[in] flags passes per block flags
+ * @param[in] sourceFileName passes containing file name
+ */
+ void addBlock(
+ const uint32_t id,
+ const uint32_t flags,
+ const char * sourceFileName
+ );
+
+ /*!
+ * This method prints info about function
+ */
+ void printFunctionInfo( FILE * textFile, uint32_t function_number );
+
+ /*!
+ * This method prints info about coverage of this function
+ */
+ void printCoverageInfo( FILE * textFile, uint32_t function_number );
+
+ /*!
+ * This method prints info about chosen arc in arcs list
+ *
+ * @param[in] textFile specifies output file
+ * @param[in] arc passes iterator identifying arc
+ */
+ void printArcInfo(
+ FILE * textFile,
+ arcs_iterator_t arc
+ );
+
+ /*!
+ * This method prints info about chosen block in blocks list
+ *
+ * @param[in] block passes iterator identifying block
+ */
+ void printBlockInfo(
+ FILE * textFile,
+ blocks_iterator_t block
+ );
+
+ /*!
+ * This method calculates values of arc counters
+ */
+ bool processFunctionCounters( void );
+
+ private:
+
+ uint32_t id;
+ uint32_t checksum;
+ uint32_t firstLineNumber;
+ uint32_t numberOfBlocks;
+ uint32_t numberOfArcs;
+ arcs_t arcs;
+ blocks_t blocks;
+ char functionName[FUNCTION_NAME_LENGTH];
+ char sourceFileName[FILE_NAME_LENGTH];
+
+ /*!
+ * This member contains the unified or merged coverage map
+ * and symbol info for the symbol.
+ */
+ Coverage::CoverageMapBase* coverageMap;
+ Coverage::SymbolInformation* symbolInfo;
+
+ /*!
+ * This method creates list of taken/not taken values
+ * for branches
+ *
+ * @param[in] taken used to return taken counts list
+ * @param[in] notTaken used to return not taken counts list
+ */
+ bool processBranches(
+ std::list<uint64_t> * taken ,
+ std::list<uint64_t> * notTaken
+ );
+ };
+
+}
+#endif
diff --git a/covoar/Makefile b/covoar/Makefile
index 5cad1f9..73cc7d0 100644
--- a/covoar/Makefile
+++ b/covoar/Makefile
@@ -24,6 +24,8 @@ COMMON_OBJS= app_common.o \
DesiredSymbols.o \
ExecutableInfo.o \
Explanations.o \
+ GcovData.o \
+ GcovFunctionData.o \
ObjdumpProcessor.o \
ReportsBase.o \
ReportsText.o \
@@ -125,6 +127,8 @@ DesiredSymbols.o: DesiredSymbols.cc DesiredSymbols.h CoverageMap.h
ExecutableInfo.o: ExecutableInfo.cc ExecutableInfo.h CoverageMap.h \
DesiredSymbols.h SymbolTable.h
Explanations.o: Explanations.cc Explanations.h
+GcovData.o: GcovData.h GcovData.cc
+GcovFunctionData.o: GcovFunctionData.h GcovFunctionData.cc
ObjdumpProcessor.o: ObjdumpProcessor.cc ObjdumpProcessor.h ExecutableInfo.h \
TargetBase.h TargetFactory.h
ReportsBase.o: ReportsBase.cc ReportsBase.h CoverageRanges.h DesiredSymbols.h \
diff --git a/covoar/SymbolTable.cc b/covoar/SymbolTable.cc
index c7ed638..7b75e28 100644
--- a/covoar/SymbolTable.cc
+++ b/covoar/SymbolTable.cc
@@ -104,4 +104,19 @@ namespace Coverage {
return "";
}
+ void SymbolTable::dumpSymbolTable( void )
+ {
+ symbolInfo symbolTable;
+ symbolInfoIterator_t symbolIterator;
+ infoIterator_t infoIterator;
+
+ for (infoIterator = info.begin() ; infoIterator != info.end(); infoIterator++)
+ {
+ for (symbolIterator = infoIterator->second.begin() ; symbolIterator != infoIterator->second.end(); symbolIterator++)
+ {
+ fprintf( stdout, "%s:\tStarting address = %#x\tLength = %u\n", infoIterator->first.c_str(), symbolIterator->startingAddress, symbolIterator->length );
+ }
+ }
+ }
+
}
diff --git a/covoar/SymbolTable.h b/covoar/SymbolTable.h
index 792731a..3532133 100644
--- a/covoar/SymbolTable.h
+++ b/covoar/SymbolTable.h
@@ -37,6 +37,7 @@ namespace Coverage {
} symbolInfo_t;
typedef std::list< symbolInfo_t > symbolInfo;
+ typedef std::list< symbolInfo_t >::iterator symbolInfoIterator_t;
@@ -98,6 +99,12 @@ namespace Coverage {
uint32_t address
);
+ /*!
+ * This method prints SymbolTable content to stdout
+ *
+ */
+ void dumpSymbolTable( void );
+
private:
/*!
@@ -117,6 +124,7 @@ namespace Coverage {
* the symbol's information.
*/
typedef std::map<std::string, symbolInfo> info_t;
+ typedef std::map<std::string, symbolInfo>::iterator infoIterator_t;
info_t info;
};
diff --git a/covoar/covoar.cc b/covoar/covoar.cc
index 5c9cfec..fd8ec9f 100644
--- a/covoar/covoar.cc
+++ b/covoar/covoar.cc
@@ -25,6 +25,7 @@
#include "ObjdumpProcessor.h"
#include "ReportsBase.h"
#include "TargetFactory.h"
+#include "GcovData.h"
/*
* Variables to control general behavior
@@ -41,8 +42,14 @@ std::list<Coverage::ExecutableInfo*> executablesToAnalyze;
const char* explanations = NULL;
char* progname;
const char* symbolsFile = NULL;
+const char* gcnosFileName = NULL;
+char gcnoFileName[FILE_NAME_LENGTH];
+char gcdaFileName[FILE_NAME_LENGTH];
+char gcovBashCommand[256];
const char* target = NULL;
const char* format = NULL;
+FILE* gcnosFile = NULL;
+Gcov::GcovData* gcovFile;
/*
* Print program usage message
@@ -64,6 +71,7 @@ void usage()
" -1 EXECUTABLE - name of executable to get symbols from\n"
" -e EXE_EXTENSION - extension of the executables to analyze\n"
" -c COVERAGEFILE_EXTENSION - extension of the coverage files to analyze\n"
+ " -g GCNOS_LIST - name of file with list of *.gcno files\n"
" -p PROJECT_NAME - name of the project\n"
" -C ConfigurationFileName - name of configuration file\n"
" -O Output_Directory - name of output directory (default=."
@@ -88,6 +96,7 @@ Configuration::Options_t Options[] = {
{ "outputDirectory", NULL },
{ "executableExtension", NULL },
{ "coverageExtension", NULL },
+ { "gcnosFile", NULL },
{ "target", NULL },
{ "verbose", NULL },
{ "projectName", NULL },
@@ -127,6 +136,7 @@ void check_configuration(void)
GET_STRING( "outputDirectory", outputDirectory );
GET_STRING( "executableExtension", executableExtension );
GET_STRING( "coverageExtension", coverageFileExtension );
+ GET_STRING( "gcnosFile", gcnosFileName );
GET_STRING( "projectName", projectName );
// Now calculate some values
@@ -160,13 +170,14 @@ int main(
//
progname = argv[0];
- while ((opt = getopt(argc, argv, "C:1:L:e:c:E:f:s:T:O:p:v")) != -1) {
+ while ((opt = getopt(argc, argv, "C:1:L:e:c:g:E:f:s:T:O:p:v")) != -1) {
switch (opt) {
case 'C': CoverageConfiguration->processFile( optarg ); break;
case '1': singleExecutable = optarg; break;
case 'L': dynamicLibrary = optarg; break;
case 'e': executableExtension = optarg; break;
case 'c': coverageFileExtension = optarg; break;
+ case 'g': gcnosFileName = optarg; break;
case 'E': explanations = optarg; break;
case 'f': format = optarg; break;
case 's': symbolsFile = optarg; break;
@@ -348,7 +359,7 @@ int main(
SymbolsToAnalyze->load( symbolsFile );
if (Verbose)
fprintf(
- stderr, "Analyzing %ld symbols\n", SymbolsToAnalyze->set.size()
+ stderr, "Analyzing %u symbols\n", SymbolsToAnalyze->set.size()
);
// Create explanations.
@@ -412,6 +423,9 @@ int main(
// Merge each symbols coverage map into a unified coverage map.
(*eitr)->mergeCoverage();
+ // DEBUG Print ExecutableInfo content
+ //(*eitr)->dumpExecutableInfo();
+
if (!singleExecutable)
eitr++;
}
@@ -421,6 +435,37 @@ int main(
fprintf( stderr, "Preprocess uncovered ranges and branches\n" );
SymbolsToAnalyze->preprocess();
+ //
+ // Generate Gcov reports
+ //
+ if (Verbose)
+ fprintf( stderr, "Generating Gcov reports...\n");
+ gcnosFile = fopen ( gcnosFileName , "r" );
+
+ if ( !gcnosFile ) {
+ fprintf( stderr, "Unable to open %s\n", gcnosFileName );
+ }
+ else {
+ while ( fscanf( gcnosFile, "%s", inputBuffer ) != EOF) {
+ gcovFile = new Gcov::GcovData();
+ strcpy( gcnoFileName, inputBuffer );
+
+ if ( Verbose )
+ fprintf( stderr, "Processing file: %s\n", gcnoFileName );
+
+ if ( gcovFile->readGcnoFile( gcnoFileName ) ) {
+ // Those need to be in this order
+ gcovFile->processCounters();
+ gcovFile->writeReportFile();
+ gcovFile->writeGcdaFile();
+ gcovFile->writeGcovFile();
+ }
+
+ delete gcovFile;
+ }
+ fclose( gcnosFile );
+ }
+
// Determine the uncovered ranges and branches.
if (Verbose)
fprintf( stderr, "Computing uncovered ranges and branches\n" );