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

4.104.11
Last change on this file since 100f517 was 100f517, checked in by Chris Johns <chrisj@…>, on May 9, 2014 at 11:50:37 AM

covoar: Merger the covoar source from rtems-testing.git.

Use waf to build covoar.

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