source: rtems-tools/tester/covoar/covoar.cc @ f9a4b2c

5
Last change on this file since f9a4b2c was f9a4b2c, checked in by Cillian O'Donnell <cpodonnell8@…>, on 08/26/17 at 08:15:58

covoar: Remove config file and test critical options are valid.

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