diff options
author | Joel Sherrill <joel.sherrill@OARcorp.com> | 2011-12-01 20:24:47 +0000 |
---|---|---|
committer | Joel Sherrill <joel.sherrill@OARcorp.com> | 2011-12-01 20:24:47 +0000 |
commit | 6517cde9f4cbf76e47b9fa96cc1abfffac44a0d4 (patch) | |
tree | 8ede8e3fc7189f13596a9235f2a67311a70c32e0 /covoar | |
parent | 2011-12-01 Joel Sherrill <joel.sherrill@oarcorp.com> (diff) | |
download | rtems-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/ChangeLog | 9 | ||||
-rw-r--r-- | covoar/CoverageMapBase.h | 3 | ||||
-rw-r--r-- | covoar/DesiredSymbols.cc | 5 | ||||
-rw-r--r-- | covoar/ExecutableInfo.cc | 8 | ||||
-rw-r--r-- | covoar/ExecutableInfo.h | 5 | ||||
-rw-r--r-- | covoar/GcovData.cc | 506 | ||||
-rw-r--r-- | covoar/GcovData.h | 204 | ||||
-rw-r--r-- | covoar/GcovFunctionData.cc | 595 | ||||
-rw-r--r-- | covoar/GcovFunctionData.h | 278 | ||||
-rw-r--r-- | covoar/Makefile | 4 | ||||
-rw-r--r-- | covoar/SymbolTable.cc | 15 | ||||
-rw-r--r-- | covoar/SymbolTable.h | 8 | ||||
-rw-r--r-- | covoar/covoar.cc | 49 |
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 , ¬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; + } +} + + 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" ); |