diff options
author | Chris Johns <chrisj@rtems.org> | 2014-05-09 21:50:37 +1000 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2014-06-18 16:48:08 +1200 |
commit | 100f517ab37265acdf067e36b6860020ec8b2184 (patch) | |
tree | 2316c8b888e11dcbcfbfc66a0c1e31991ea20656 /tester/covoar/GcovData.cc | |
parent | 4.11: Add ntp patch. (diff) | |
download | rtems-tools-100f517ab37265acdf067e36b6860020ec8b2184.tar.bz2 |
covoar: Merger the covoar source from rtems-testing.git.
Use waf to build covoar.
Diffstat (limited to 'tester/covoar/GcovData.cc')
-rw-r--r-- | tester/covoar/GcovData.cc | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/tester/covoar/GcovData.cc b/tester/covoar/GcovData.cc new file mode 100644 index 0000000..6d10337 --- /dev/null +++ b/tester/covoar/GcovData.cc @@ -0,0 +1,508 @@ +/* + * 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 too long to be correctly stored: %u\n", + (unsigned int) 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; + } +} |