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

Last change on this file since fb987e8 was fb987e8, checked in by Chris Johns <chrisj@…>, on May 8, 2018 at 5:09:39 AM

covoar: Use DWARF to map addresses to source files and lines.

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