source: rtems-tools/tester/covoar/covoar.cc @ 69c955d

4.104.11
Last change on this file since 69c955d was f381f26, checked in by Chris Johns <chrisj@…>, on Jan 19, 2015 at 9:56:14 PM

Fix covoar so it builds for Windows.

  • Property mode set to 100644
File size: 14.1 KB
Line 
1#include <ctype.h>
2#include <errno.h>
3#include <fcntl.h>
4#include <limits.h>
5#include <signal.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/types.h>
10#include <sys/stat.h>
11#include <unistd.h>
12
13#include <list>
14
15#include "app_common.h"
16#include "CoverageFactory.h"
17#include "CoverageMap.h"
18#include "DesiredSymbols.h"
19#include "ExecutableInfo.h"
20#include "Explanations.h"
21#include "ObjdumpProcessor.h"
22#include "ReportsBase.h"
23#include "TargetFactory.h"
24#include "GcovData.h"
25
26/*
27 *  Variables to control general behavior
28 */
29const char*                          coverageFileExtension = NULL;
30std::list<std::string>               coverageFileNames;
31int                                  coverageExtensionLength = 0;
32Coverage::CoverageFormats_t          coverageFormat;
33Coverage::CoverageReaderBase*        coverageReader = NULL;
34char*                                executable = NULL;
35const char*                          executableExtension = NULL;
36int                                  executableExtensionLength = 0;
37std::list<Coverage::ExecutableInfo*> executablesToAnalyze;
38const char*                          explanations = NULL;
39char*                                progname;
40const char*                          symbolsFile = NULL;
41const char*                          gcnosFileName = NULL;
42char                                 gcnoFileName[FILE_NAME_LENGTH];
43char                                 gcdaFileName[FILE_NAME_LENGTH];
44char                                 gcovBashCommand[256];
45const char*                          target = NULL;
46const char*                          format = NULL;
47FILE*                                gcnosFile = NULL;
48Gcov::GcovData*                      gcovFile;
49
50/*
51 *  Print program usage message
52 */
53void usage()
54{
55  fprintf(
56    stderr,
57    "Usage: %s [-v] -T TARGET -f FORMAT [-E EXPLANATIONS] -1 EXECUTABLE coverage1 ... coverageN\n"
58    "--OR--\n"
59    "Usage: %s [-v] -T TARGET -f FORMAT [-E EXPLANATIONS] -e EXE_EXTENSION -c COVERAGEFILE_EXTENSION EXECUTABLE1 ... EXECUTABLE2\n"
60    "\n"
61    "  -v                        - verbose at initialization\n"
62    "  -T TARGET                 - target name\n"
63    "  -f FORMAT                 - coverage file format "
64           "(RTEMS, QEMU, TSIM or Skyeye)\n"
65    "  -E EXPLANATIONS           - name of file with explanations\n"
66    "  -s SYMBOLS_FILE           - name of file with symbols of interest\n"
67    "  -1 EXECUTABLE             - name of executable to get symbols from\n"
68    "  -e EXE_EXTENSION          - extension of the executables to analyze\n"
69    "  -c COVERAGEFILE_EXTENSION - extension of the coverage files to analyze\n"
70    "  -g GCNOS_LIST             - name of file with list of *.gcno files\n"
71    "  -p PROJECT_NAME           - name of the project\n"
72    "  -C ConfigurationFileName  - name of configuration file\n"
73    "  -O Output_Directory       - name of output directory (default=."
74    "\n",
75    progname,
76    progname
77  );
78}
79
80#define PrintableString(_s) \
81       ((!(_s)) ? "NOT SET" : (_s))
82
83/*
84 *  Configuration File Support
85 */
86#include "ConfigFile.h"
87Configuration::FileReader *CoverageConfiguration;
88Configuration::Options_t Options[] = {
89  { "explanations",         NULL },
90  { "format",               NULL },
91  { "symbolsFile",          NULL },
92  { "outputDirectory",      NULL },
93  { "executableExtension",  NULL },
94  { "coverageExtension",    NULL },
95  { "gcnosFile",            NULL },
96  { "target",               NULL },
97  { "verbose",              NULL },
98  { "projectName",          NULL },
99  { NULL,                   NULL }
100};
101
102bool isTrue(const char *value)
103{
104  if ( !value )                  return false;
105  if ( !strcmp(value, "true") )  return true;
106  if ( !strcmp(value, "TRUE") )  return true;
107  if ( !strcmp(value, "yes") )   return true;
108  if ( !strcmp(value, "YES") )   return true;
109  return false;
110}
111
112#define GET_BOOL(_opt, _val) \
113  if (isTrue(CoverageConfiguration->getOption(_opt))) \
114    _val = true;
115
116#define GET_STRING(_opt, _val) \
117  do { \
118    const char *_t; \
119    _t = CoverageConfiguration->getOption(_opt); \
120    if ( _t ) _val = _t; \
121  } while(0)
122
123
124void check_configuration(void)
125{
126  GET_BOOL( "verbose", Verbose );
127
128  GET_STRING( "format",               format );
129  GET_STRING( "target",               target );
130  GET_STRING( "explanations",         explanations );
131  GET_STRING( "symbolsFile",          symbolsFile );
132  GET_STRING( "outputDirectory",      outputDirectory );
133  GET_STRING( "executableExtension",  executableExtension );
134  GET_STRING( "coverageExtension",    coverageFileExtension );
135  GET_STRING( "gcnosFile",            gcnosFileName );
136  GET_STRING( "projectName",          projectName );
137
138  // Now calculate some values
139  if ( coverageFileExtension )
140    coverageExtensionLength = strlen( coverageFileExtension );
141
142  if ( executableExtension )
143    executableExtensionLength = strlen( executableExtension );
144
145  if ( format )
146    coverageFormat = Coverage::CoverageFormatToEnum( format );
147}
148
149int main(
150  int    argc,
151  char** argv
152)
153{
154  std::list<std::string>::iterator               citr;
155  std::string                                    coverageFileName;
156  std::list<Coverage::ExecutableInfo*>::iterator eitr;
157  Coverage::ExecutableInfo*                      executableInfo = NULL;
158  int                                            i;
159  int                                            opt;
160  const char*                                    singleExecutable = NULL;
161
162  CoverageConfiguration = new Configuration::FileReader(Options);
163
164  //
165  // Process command line options.
166  //
167  progname = argv[0];
168
169  while ((opt = getopt(argc, argv, "C:1:L:e:c:g:E:f:s:T:O:p:v")) != -1) {
170    switch (opt) {
171      case 'C': CoverageConfiguration->processFile( optarg ); break;
172      case '1': singleExecutable      = optarg; break;
173      case 'L': dynamicLibrary        = optarg; break;
174      case 'e': executableExtension   = optarg; break;
175      case 'c': coverageFileExtension = optarg; break;
176      case 'g': gcnosFileName         = optarg; break;
177      case 'E': explanations          = optarg; break;
178      case 'f': format                = optarg; break;
179      case 's': symbolsFile           = optarg; break;
180      case 'T': target                = optarg; break;
181      case 'O': outputDirectory       = optarg; break;
182      case 'v': Verbose               = true;   break;
183      case 'p': projectName           = optarg; break;
184      default: /* '?' */
185        usage();
186        exit( -1 );
187    }
188  }
189
190  // Do not trust any arguments until after this point.
191  check_configuration();
192
193  // XXX We need to verify that all of the needed arguments are non-NULL.
194
195  // If a single executable was specified, process the remaining
196  // arguments as coverage file names.
197  if (singleExecutable) {
198
199    // Ensure that the executable is readable.
200    if (!FileIsReadable( singleExecutable )) {
201      fprintf(
202        stderr,
203        "WARNING: Unable to read executable %s\n",
204        singleExecutable
205      );
206    }
207
208    else {
209
210      for (i=optind; i < argc; i++) {
211
212        // Ensure that the coverage file is readable.
213        if (!FileIsReadable( argv[i] )) {
214          fprintf(
215            stderr,
216            "WARNING: Unable to read coverage file %s\n",
217            argv[i]
218          );
219        }
220
221        else
222          coverageFileNames.push_back( argv[i] );
223      }
224
225      // If there was at least one coverage file, create the
226      // executable information.
227      if (!coverageFileNames.empty()) {
228        if (dynamicLibrary)
229          executableInfo = new Coverage::ExecutableInfo(
230            singleExecutable, dynamicLibrary
231          );
232        else
233          executableInfo = new Coverage::ExecutableInfo( singleExecutable );
234
235        executablesToAnalyze.push_back( executableInfo );
236      }
237    }
238  }
239
240  // If not invoked with a single executable, process the remaining
241  // arguments as executables and derive the coverage file names.
242  else {
243    for (i = optind; i < argc; i++) {
244
245      // Ensure that the executable is readable.
246      if (!FileIsReadable( argv[i] )) {
247        fprintf(
248          stderr,
249          "WARNING: Unable to read executable %s\n",
250          argv[i]
251        );
252      }
253
254      else {
255        coverageFileName = argv[i];
256        coverageFileName.replace(
257          coverageFileName.length() - executableExtensionLength,
258          executableExtensionLength,
259          coverageFileExtension
260        );
261
262        if (!FileIsReadable( coverageFileName.c_str() )) {
263          fprintf(
264            stderr,
265            "WARNING: Unable to read coverage file %s\n",
266            coverageFileName.c_str()
267          );
268        }
269
270        else {
271          executableInfo = new Coverage::ExecutableInfo( argv[i] );
272          executablesToAnalyze.push_back( executableInfo );
273          coverageFileNames.push_back( coverageFileName );
274        }
275      }
276    }
277  }
278
279  // Ensure that there is at least one executable to process.
280  if (executablesToAnalyze.empty()) {
281    fprintf(
282      stderr, "ERROR: No information to analyze\n"
283    );
284    exit( -1 );
285  }
286
287  if (Verbose) {
288    if (singleExecutable)
289      fprintf(
290        stderr,
291        "Processing a single executable and multiple coverage files\n"
292      );
293    else
294      fprintf(
295        stderr,
296        "Processing multiple executable/coverage file pairs\n"
297      );
298    fprintf( stderr, "Coverage Format : %s\n", format );
299    fprintf( stderr, "Target          : %s\n", PrintableString(target) );
300    fprintf( stderr, "\n" );
301#if 1
302    // Process each executable/coverage file pair.
303    eitr = executablesToAnalyze.begin();
304    for (citr = coverageFileNames.begin();
305         citr != coverageFileNames.end();
306         citr++) {
307
308        fprintf(
309          stderr,
310          "Coverage file %s for executable %s\n",
311          (*citr).c_str(),
312          ((*eitr)->getFileName()).c_str()
313        );
314
315        if (!singleExecutable)
316          eitr++;
317    }
318#endif
319  }
320
321  //
322  // Validate inputs.
323  //
324
325  // Target name must be set.
326  if (!target) {
327    fprintf( stderr, "ERROR: target not specified\n" );
328    usage();
329    exit(-1);
330  }
331
332  // Validate format.
333  if (!format) {
334    fprintf( stderr, "ERROR: coverage format report not specified\n" );
335    usage();
336    exit(-1);
337  }
338
339  // Validate that we have a symbols of interest file.
340  if (!symbolsFile) {
341    fprintf( stderr, "ERROR: symbols of interest file not specified\n" );
342    usage();
343    exit(-1);
344  }
345
346  //
347  // Create data to support analysis.
348  //
349
350  // Create data based on target.
351  TargetInfo = Target::TargetFactory( target );
352
353  // Create the set of desired symbols.
354  SymbolsToAnalyze = new Coverage::DesiredSymbols();
355  SymbolsToAnalyze->load( symbolsFile );
356  if (Verbose)
357    fprintf(
358      stderr,
359      "Analyzing %u symbols\n",
360      (unsigned int) SymbolsToAnalyze->set.size()
361    );
362
363  // Create explanations.
364  AllExplanations = new Coverage::Explanations();
365  if ( explanations )
366    AllExplanations->load( explanations );
367
368  // Create coverage map reader.
369  coverageReader = Coverage::CreateCoverageReader(coverageFormat);
370  if (!coverageReader) {
371    fprintf( stderr, "ERROR: Unable to create coverage file reader\n" );
372    exit(-1);
373  }
374
375  // Create the objdump processor.
376  objdumpProcessor = new Coverage::ObjdumpProcessor();
377
378  // Prepare each executable for analysis.
379  for (eitr = executablesToAnalyze.begin();
380       eitr != executablesToAnalyze.end();
381       eitr++) {
382
383    if (Verbose)
384      fprintf(
385        stderr,
386        "Extracting information from %s\n",
387        ((*eitr)->getFileName()).c_str()
388      );
389
390    // If a dynamic library was specified, determine the load address.
391    if (dynamicLibrary)
392      (*eitr)->setLoadAddress(
393        objdumpProcessor->determineLoadAddress( *eitr )
394      );
395
396    // Load the objdump for the symbols in this executable.
397    objdumpProcessor->load( *eitr );
398  }
399
400  //
401  // Analyze the coverage data.
402  //
403
404  // Process each executable/coverage file pair.
405  eitr = executablesToAnalyze.begin();
406  for (citr = coverageFileNames.begin();
407       citr != coverageFileNames.end();
408       citr++) {
409
410    if (Verbose)
411      fprintf(
412        stderr,
413        "Processing coverage file %s for executable %s\n",
414        (*citr).c_str(),
415        ((*eitr)->getFileName()).c_str()
416      );
417
418    // Process its coverage file.
419    coverageReader->processFile( (*citr).c_str(), *eitr );
420
421    // Merge each symbols coverage map into a unified coverage map.
422    (*eitr)->mergeCoverage();
423
424    // DEBUG Print ExecutableInfo content
425    //(*eitr)->dumpExecutableInfo();
426
427    if (!singleExecutable)
428      eitr++;
429  }
430
431  // Do necessary preprocessing of uncovered ranges and branches
432  if (Verbose)
433    fprintf( stderr, "Preprocess uncovered ranges and branches\n" );
434  SymbolsToAnalyze->preprocess();
435
436  //
437  // Generate Gcov reports
438  //
439  if (Verbose)
440    fprintf( stderr, "Generating Gcov reports...\n");
441  gcnosFile = fopen ( gcnosFileName , "r" );
442
443  if ( !gcnosFile ) {
444    fprintf( stderr, "Unable to open %s\n", gcnosFileName );
445  }
446  else {
447    while ( fscanf( gcnosFile, "%s", inputBuffer ) != EOF) {
448      gcovFile = new Gcov::GcovData();
449      strcpy( gcnoFileName, inputBuffer );
450
451      if ( Verbose )
452        fprintf( stderr, "Processing file: %s\n", gcnoFileName );
453
454      if ( gcovFile->readGcnoFile( gcnoFileName ) ) {
455        // Those need to be in this order
456        gcovFile->processCounters();
457        gcovFile->writeReportFile();
458        gcovFile->writeGcdaFile();
459        gcovFile->writeGcovFile();
460      }
461
462      delete gcovFile;
463    }
464  fclose( gcnosFile );
465  }
466
467  // Determine the uncovered ranges and branches.
468  if (Verbose)
469    fprintf( stderr, "Computing uncovered ranges and branches\n" );
470  SymbolsToAnalyze->computeUncovered();
471
472  // Calculate remainder of statistics.
473  if (Verbose)
474    fprintf( stderr, "Calculate statistics\n" );
475  SymbolsToAnalyze->calculateStatistics();
476
477  // Look up the source lines for any uncovered ranges and branches.
478  if (Verbose)
479    fprintf(
480      stderr, "Looking up source lines for uncovered ranges and branches\n"
481    );
482  SymbolsToAnalyze->findSourceForUncovered();
483
484  //
485  // Report the coverage data.
486  //
487  if (Verbose)
488    fprintf(
489      stderr, "Generate Reports\n"
490    );
491  Coverage::GenerateReports();
492
493  // Write explanations that were not found.
494  if ( explanations ) {
495    std::string notFound;
496
497    notFound = outputDirectory;
498    notFound += "/";
499    notFound += "ExplanationsNotFound.txt";
500
501    if (Verbose)
502      fprintf( stderr, "Writing Not Found Report (%s)\n", notFound.c_str() );
503    AllExplanations->writeNotFound( notFound.c_str() );
504  }
505
506  return 0;
507}
Note: See TracBrowser for help on using the repository browser.