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

Last change on this file since 0333442 was 0333442, checked in by Joel Sherrill <joel@…>, on Jan 2, 2018 at 10:59:31 PM

tester/covoar/covoar.cc: Add missing throw keyword

Why clang caught this and gcc didn't is a mystery.

Updates #3191.

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