source: rtems-tools/tester/covoar/GcovData.cc

Last change on this file was b4245dd, checked in by Chris Johns <chrisj@…>, on 09/03/21 at 04:43:47

tester/covoar: Fix clang compile errors, revert uneeded changes

  • Property mode set to 100644
File size: 15.5 KB
Line 
1/*! @file GcovData.cc
2 *  @brief GcovData Implementation
3 *
4 *  This file contains the implementation of the functions supporting
5 *  reading *.gcno and writing *.gcda files for gcov support
6 */
7
8#include <stdio.h>
9#include <string.h>
10#include <stdlib.h>
11//#include <sys/stat.h>
12
13//#include "app_common.h"
14#include "GcovData.h"
15//#include "ExecutableInfo.h"
16//#include "CoverageMap.h"
17//#include "qemu-traces.h"
18
19#include "rtems-utils.h"
20
21namespace Gcov {
22
23  GcovData::GcovData( Coverage::DesiredSymbols& symbolsToAnalyze ):
24    numberOfFunctions( 0 ),
25    gcnoPreamble(),
26    symbolsToAnalyze_m( symbolsToAnalyze )
27  {
28  }
29
30  GcovData::~GcovData()
31  {
32  }
33
34  bool GcovData::readGcnoFile( const std::string& fileName )
35  {
36    int           status;
37    std::ifstream gcovFile;
38    std::string   tempString;
39    std::string   tempString2;
40    std::string   tempString3;
41    size_t        index;
42
43    if ( fileName.length() >= FILE_NAME_LENGTH ) {
44      std::cerr << "ERROR: File name is too long to be correctly stored: "
45                << fileName.length() << std::endl;
46      return false;
47    }
48
49    gcnoFileName = fileName;
50    gcdaFileName = fileName;
51    textFileName = fileName;
52    cFileName    = fileName;
53    tempString   = gcdaFileName;
54    tempString2  = textFileName;
55    tempString3  = cFileName;
56
57    index = tempString.find( ".gcno" );
58    if ( index == std::string::npos ) {
59      std::cerr << "ERROR: incorrect name of *.gcno file" << std::endl;
60      return false;
61    } else {
62      // construct gcda file name
63      tempString = tempString.replace( index, strlen( ".gcno" ), ".gcda" );
64
65      // construct report file name
66      tempString2 = tempString2.replace( index, strlen( ".gcno" ), ".txt" );
67
68      // construct source file name
69      tempString3 = tempString3.replace( index, strlen( ".gcno" ), ".c" );
70    }
71
72    // Debug message
73    // std::cerr << "Reading file: " << gcnoFileName << std::endl;
74
75    // Open the notes file.
76    gcovFile.open( gcnoFileName );
77    if ( !gcovFile ) {
78      std::cerr << "Unable to open " << gcnoFileName << std::endl;
79      return false;
80    }
81
82    // Read and validate the gcnoPreamble (magic, version, timestamp) from the file
83    status = readFilePreamble( &gcnoPreamble, gcovFile, GCNO_MAGIC );
84    if ( status <= 0 ) {
85      std::cerr << "Unable to read " << gcnoFileName << std::endl;
86      return false;
87    }
88
89    //Read all remaining frames from file
90    while( readFrame( gcovFile ) ) {}
91
92    return true;
93  }
94
95
96  bool GcovData::writeGcdaFile()
97  {
98    gcov_preamble           preamble;
99    gcov_frame_header       header;
100    std::ofstream           gcdaFile;
101    functions_iterator_t    currentFunction;
102    arcs_iterator_t         currentArc;
103    uint32_t                buffer;
104    uint32_t                countersFound;
105    uint32_t                countersFoundSum;
106    uint64_t                countersSum;
107    uint64_t                countersMax;
108    uint64_t                llBuffer[4096];    // TODO: Use common buffer
109    gcov_statistics         objectStats;
110    gcov_statistics         programStats;
111    std::ofstream::pos_type bytes_before;
112
113    // Debug message
114    //std::cerr << "Writing file: " <<  gcdaFileName << std::endl;
115
116    // Lets clear counters sumators
117    countersSum      = 0;
118    countersMax      = 0;
119    countersFoundSum = 0;
120
121    // Open the data file.
122    gcdaFile.open( gcdaFileName );
123    if ( !gcdaFile ) {
124      std::cerr << "Unable to create " << gcdaFileName << std::endl;
125      return false;
126    }
127
128    //Form preamble
129    preamble.magic     = GCDA_MAGIC;
130    preamble.version   = gcnoPreamble.version;
131    preamble.timestamp = gcnoPreamble.timestamp;
132
133    //Write preamble
134    gcdaFile.write( (char *) &preamble , sizeof( preamble ) );
135    if ( gcdaFile.fail() ) {
136      std::cerr << "Error while writing gcda preamble to a file "
137                << gcdaFileName << std::endl;
138    }
139
140    //Write function info and counter counts
141    for (
142      currentFunction = functions.begin();
143      currentFunction != functions.end();
144      currentFunction++
145    ) {
146      //Write function announcement frame header (length always equals 2)
147      header.tag = GCOV_TAG_FUNCTION;
148      header.length = 2;
149      gcdaFile.write( (char *) &header, sizeof( header ) );
150      if ( gcdaFile.fail() ) {
151        std::cerr << "Error while writing function announcement to a file "
152                  << gcdaFileName << std::endl;
153      }
154
155      //Write function id
156      buffer = (*currentFunction).getId();
157      gcdaFile.write( (char *) &buffer, sizeof( buffer ) );
158      if ( gcdaFile.fail() ) {
159        std::cerr << "Error while writing function id to a file "
160                  << gcdaFileName << std::endl;
161      }
162
163      //Write function checksum
164      buffer = (*currentFunction).getChecksum();
165      gcdaFile.write( (char *) &buffer, sizeof( buffer ) );
166      if ( gcdaFile.fail() ) {
167        std::cerr << "Error while writing function checksum to a file "
168                  << gcdaFileName << std::endl;
169      }
170
171      // Determine how many counters there are
172      // and store their counts in buffer
173      countersFound = 0;
174      (*currentFunction).getCounters(
175        llBuffer,
176        countersFound,
177        countersSum,
178        countersMax
179      );
180      countersFoundSum += countersFound;
181
182      //Write info about counters
183      header.tag = GCOV_TAG_COUNTER;
184      header.length = countersFound * 2;
185      gcdaFile.write( (char *) &header, sizeof( header ) );
186      if ( gcdaFile.fail() ) {
187        std::cerr << "Error while writing counter header to a file "
188                  << gcdaFileName << std::endl;
189      }
190
191      bytes_before = gcdaFile.tellp();
192
193      gcdaFile.write( (char *) llBuffer, sizeof( uint64_t ) * countersFound );
194      if ( gcdaFile.tellp() - bytes_before != countersFound ) {
195        std::cerr << "Error while writing counter data to a file "
196                  << gcdaFileName << std::endl;
197      }
198    }
199
200    // Prepare frame with object file statistics
201    header.tag = GCOV_TAG_OBJECT_SUMMARY;
202    header.length = 9;
203    objectStats.checksum = 0;      // TODO: have no idea hov to calculates it :)
204    objectStats.counters = countersFoundSum;
205    objectStats.runs = 1;        // We are lying for now, we have no means of figuring this out
206    objectStats.sum = countersSum;    // Sum of all counters
207    objectStats.max = countersMax;    // max value for counter on last run, we have no clue
208    objectStats.sumMax = countersMax;    // we have no clue
209
210    // Write data
211    gcdaFile.write( (char *) &header, sizeof( header ) );
212    if ( gcdaFile.fail() ) {
213      std::cerr << "Error while writing stats header to a file "
214                << gcdaFileName << std::endl;
215    }
216
217    gcdaFile.write( (char *) &objectStats, sizeof( objectStats ) );
218    if ( gcdaFile.fail() ) {
219      std::cerr << "Error while writing object stats to a file "
220                << gcdaFileName << std::endl;
221    }
222
223
224    // Prepare frame with program statistics
225    header.tag = GCOV_TAG_PROGRAM_SUMMARY;
226    header.length = 9;
227    programStats.checksum = 0;      // TODO: have no idea hov to calculate it :)
228    programStats.counters = countersFoundSum;
229    programStats.runs = 1;      // We are lying for now, we have no clue
230    programStats.sum = countersSum;    // Sum of all counters
231    programStats.max = countersMax;    // max value for counter on last run, we have no clue
232    programStats.sumMax = countersMax;    // we have no clue
233
234    // Write data
235    gcdaFile.write( (char *) &header, sizeof( header ) );
236    if ( gcdaFile.fail() ) {
237      std::cerr << "Error while writing stats header to a file "
238                << gcdaFileName << std::endl;
239    }
240
241    gcdaFile.write( (char *) &programStats, sizeof( programStats ) );
242    if ( gcdaFile.fail() ) {
243      std::cerr << "Error while writing program stats to a file "
244                << gcdaFileName << std::endl;
245    }
246
247    return true;
248  }
249
250  bool GcovData::readFrame( std::ifstream& gcovFile )
251  {
252    gcov_frame_header header;
253    char              buffer[512];
254    char              intBuffer[16384];
255    uint32_t          tempBlockId;
256    blocks_iterator_t tempBlockIterator;
257    int               status;
258
259    status = readFrameHeader( &header, gcovFile );
260    if ( status <= 0 ) {
261      // Not printing error message because this
262      // happenns at the end of each file
263      return false;
264    }
265
266    switch ( header.tag ) {
267
268      case GCOV_TAG_FUNCTION:
269
270        {
271          numberOfFunctions++;
272          GcovFunctionData newFunction;
273
274          if ( !readFunctionFrame(header, gcovFile, &newFunction) ) {
275            std::cerr << "Error while reading FUNCTION from gcov file..."
276                      << std::endl;
277            return false;
278          }
279
280          functions.push_back( newFunction );
281        }
282
283        break;
284
285      case GCOV_TAG_BLOCKS:
286
287        gcovFile.read( intBuffer, header.length );
288        if ( gcovFile.gcount() != (int) header.length ) {
289          std::cerr << "Error while reading BLOCKS from gcov file..."
290                    << std::endl
291                    << "Header length is " << header.length
292                    << " instead of " << gcovFile.gcount()
293                    << std::endl;
294          return false;
295        }
296
297        for( uint32_t i = 0; i < header.length; i++ ) {
298          functions.back().addBlock( i, intBuffer[i], "" );
299        }
300
301        break;
302
303      case GCOV_TAG_ARCS:
304
305        gcovFile.read( intBuffer, header.length );
306        if ( gcovFile.gcount() != (int) header.length ) {
307          return false;
308        }
309
310        for ( int i = 1; i < (int) header.length; i += 2 ) {
311          functions.back().addArc(intBuffer[0], intBuffer[i], intBuffer[i+1]);
312        }
313
314        break;
315
316      case GCOV_TAG_LINES:
317
318        gcovFile.read( intBuffer, 2 );
319        if ( gcovFile.gcount() != 2 || intBuffer[1] != 0 ) {
320          std::cerr << "Error while reading block id for LINES from gcov "
321                    << "file..." << std::endl;
322          return false;
323        }
324        tempBlockId = intBuffer[0];
325        header.length -= 2;
326
327        // Find the right block
328        tempBlockIterator =functions.back().findBlockById( tempBlockId );
329
330        header.length -= readString( buffer, gcovFile );
331        functions.back().setBlockFileName( tempBlockIterator, buffer );
332
333        gcovFile.read( intBuffer, header.length );
334        if ( gcovFile.gcount() != (int) header.length ) {
335          std::cerr << "Error while reading LINES from gcov file..."
336                    << std::endl;
337          return false;
338        } else {
339          for ( int i = 0; i < (int) (header.length - 2); i++ ) {
340            functions.back().addBlockLine( tempBlockIterator, intBuffer[i] );
341          }
342        }
343
344        break;
345
346      default:
347
348        std::cerr << std::endl << std::endl
349                  << "ERROR - encountered unknown *.gcno tag : 0x"
350                  << std::hex << header.tag << std::dec << std::endl;
351        break;
352      }
353
354      return true;
355  }
356
357  int GcovData::readString( char* buffer, std::ifstream& gcovFile )
358  {
359    int length;
360
361    gcovFile.read( (char *) &length, sizeof( int ) );
362    if ( gcovFile.gcount() != sizeof( int ) ) {
363      std::cerr << "ERROR: Unable to read string length from gcov file"
364                << std::endl;
365      return -1;
366    }
367
368    gcovFile.read( buffer, length * 4 );
369    if ( gcovFile.gcount() != length * 4 ) {
370      std::cerr << "ERROR: Unable to read string from gcov file"
371                << std::endl;
372      return -1;
373    }
374
375    buffer[length * 4] = '\0';
376
377    return length +1;
378  }
379
380  int GcovData::readFrameHeader(
381    gcov_frame_header* header,
382    std::ifstream&     gcovFile
383  )
384  {
385    int length;
386
387    length = sizeof( gcov_frame_header );
388    gcovFile.read( (char *) header, length );
389    if ( gcovFile.gcount() != length ) {
390      std::cerr << "ERROR: Unable to read frame header from gcov file"
391                << std::endl;
392      return -1;
393    }
394
395      return length / 4;
396  }
397
398  int GcovData::readFilePreamble(
399     gcov_preamble* preamble,
400     std::ifstream& gcovFile,
401     uint32_t       desiredMagic
402  )
403  {
404    rtems::utils::ostream_guard old_state( std::cerr );
405
406    // Read the gcov preamble and make sure it is the right length and has the
407    // magic number
408    gcovFile.read( (char *) preamble, sizeof( gcov_preamble ) );
409    if ( gcovFile.gcount() != sizeof( gcov_preamble ) ) {
410      std::cerr << "Error while reading file preamble" << std::endl;
411      return -1;
412    }
413
414    if ( preamble->magic != GCNO_MAGIC ) {
415      std::cerr << "File is not a valid *.gcno output (magic: 0x"
416                << std::hex << std::setw( 4 ) << preamble->magic
417                << ")" << std::endl;
418      return -1;
419    }
420
421    return sizeof( gcov_preamble ) / 4;
422  }
423
424  bool GcovData::readFunctionFrame(
425    gcov_frame_header header,
426    std::ifstream&    gcovFile,
427    GcovFunctionData* function
428  )
429  {
430    char buffer[512];
431    char intBuffer[16384];
432
433    gcovFile.read( (char *) intBuffer, 8 );
434    if ( gcovFile.gcount() != 8 ) {
435      std::cerr << "ERROR: Unable to read Function ID & checksum" << std::endl;
436      return false;
437    }
438
439    header.length -= 2;
440    function->setId( intBuffer[0] );
441    function->setChecksum( intBuffer[1] );
442
443    header.length -= readString( buffer, gcovFile );
444    function->setFunctionName( buffer, symbolsToAnalyze_m );
445    header.length -= readString( buffer, gcovFile );
446    function->setFileName( buffer );
447    gcovFile.read( (char*) intBuffer, 4 * header.length );
448    if (gcovFile.gcount() != 4 * header.length ) {
449      std::cerr << "ERROR: Unable to read Function starting line number"
450                << std::endl;
451      return false;
452    }
453
454    function->setFirstLineNumber( intBuffer[0] );
455
456    return true;
457  }
458
459  bool GcovData::writeReportFile()
460  {
461    functions_iterator_t currentFunction;
462    uint32_t             i = 1;          //iterator
463    std::ofstream        textFile;
464
465    // Debug message
466    // std::cerr << "Writing file: " << textFileName << std::endl;
467
468    // Open the data file.
469    textFile.open( textFileName );
470    if ( !textFile.is_open() ) {
471      std::cerr << "Unable to create " << textFileName << std::endl;
472      return false;
473    }
474
475    printGcnoFileInfo( textFile );
476
477    for (
478      currentFunction = functions.begin();
479      currentFunction != functions.end();
480      currentFunction++
481    ) {
482      (*currentFunction).printFunctionInfo( textFile, i );
483      (*currentFunction).printCoverageInfo( textFile, i );
484      i++;
485    }
486
487    return true;
488  }
489
490  void GcovData::printGcnoFileInfo( std::ofstream& textFile )
491  {
492    textFile << std::endl << "FILE:\t\t\t" << gcnoFileName
493             << std::endl << std::hex
494             << "magic:\t\t\t" << gcnoPreamble.magic << std::endl
495             << "version:\t\t" << gcnoPreamble.version << std::endl
496             << "timestamp:\t\t" << gcnoPreamble.timestamp << std::endl
497             << std::dec
498             << "functions found: \t"
499             << std::endl << std::endl << gcnoPreamble.timestamp
500             << std::endl << std::endl;
501  }
502
503  void GcovData::writeGcovFile()
504  {
505    //std::cerr << "Attempting to run gcov for: " << cFileName << std::endl;
506    std::ostringstream command;
507
508    command << "(  cd " << rld::path::dirname( cFileName )
509            << " && gcov " << rld::path::basename( cFileName )
510            << " &>> gcov.log)";
511    //std::cerr << "> " << command << std::endl;
512    system( command.str().c_str() );
513  }
514
515  bool GcovData::processCounters()
516  {
517    functions_iterator_t currentFunction;
518    bool                 status = true;
519
520    for (
521      currentFunction = functions.begin();
522      currentFunction != functions.end();
523      currentFunction++
524    ) {
525      if ( !(*currentFunction).processFunctionCounters() ) {
526        status = false;
527      }
528    }
529
530    return status;
531  }
532}
Note: See TracBrowser for help on using the repository browser.