[rtems-tools commit] covoar: Add symbol set reader and ELF data parser to covoar.

Chris Johns chrisj at rtems.org
Mon Apr 30 23:01:07 UTC 2018


Module:    rtems-tools
Branch:    master
Commit:    3e187baeb9f706b729b2760a51e63a7703a30679
Changeset: http://git.rtems.org/rtems-tools/commit/?id=3e187baeb9f706b729b2760a51e63a7703a30679

Author:    Cillian O'Donnell <cpodonnell8 at gmail.com>
Date:      Wed Apr 25 21:33:58 2018 +0100

covoar: Add symbol set reader and ELF data parser to covoar.

Add ability to organize symbol sets of libraries in INI file
and then read them with covoar and load the symbols directly from the
libraries.

rtems-tools/../testing: Add configuration files for coverage analysis.

A number of covoar options are not required and are defaulted.

Co-author: Krzysztof Miesowicz <krzysztof.miesowicz at gmail.com>
Co-author: Vijay Kumar Banerjee <vijaykumar9597 at gmail.com>
Co-author: Chris Johns <chrisj at rtems.org>

---

 tester/covoar/DesiredSymbols.cc                    | 144 +++++-----
 tester/covoar/DesiredSymbols.h                     |  14 +-
 tester/covoar/ExecutableInfo.cc                    |   4 +-
 tester/covoar/ExecutableInfo.h                     |   6 +-
 tester/covoar/ObjdumpProcessor.cc                  |   6 +-
 tester/covoar/app_common.h                         |   9 +-
 tester/covoar/covoar.cc                            | 300 +++++++++++++--------
 tester/covoar/wscript                              |   2 +
 tester/rtems/testing/bsps/leon3-qemu-cov.ini       |  39 +++
 tester/rtems/testing/bsps/leon3-qemu.ini           |  38 +++
 tester/rtems/testing/coverage/Categories.txt       |  19 ++
 tester/rtems/testing/coverage/Explanations.txt     |  35 +++
 .../coverage/SPARC-Annul-Slot-Explanation.txt      |  56 ++++
 tester/rtems/testing/coverage/score-symbols.ini    |  35 +++
 tester/rtems/testing/coverage/style.css            | 197 ++++++++++++++
 tester/rtems/testing/qemu.cfg                      |  11 +-
 tester/rtems/testing/testing.mc                    |   8 +
 17 files changed, 737 insertions(+), 186 deletions(-)

diff --git a/tester/covoar/DesiredSymbols.cc b/tester/covoar/DesiredSymbols.cc
index 00d1984..9957b28 100644
--- a/tester/covoar/DesiredSymbols.cc
+++ b/tester/covoar/DesiredSymbols.cc
@@ -16,6 +16,13 @@
 #include <string.h>
 #include <unistd.h>
 
+#include <iostream>
+
+#include "rld.h"
+#include <rld-config.h>
+#include "rld-symbols.h"
+#include "rld-files.h"
+
 #include "DesiredSymbols.h"
 #include "app_common.h"
 #include "CoverageMap.h"
@@ -31,75 +38,90 @@ namespace Coverage {
   {
   }
 
-  void DesiredSymbols::load(
-    const char* const symbolsFile
+  bool DesiredSymbols::load(
+    const std::string& symbolsSet,
+    const std::string& buildTarget,
+    const std::string& buildBSP,
+    bool               verbose
   )
   {
-    int                     cStatus;
-    bool                    done = false;
-    FILE*                   sFile;
-    SymbolInformation*      symInfo;
-    int                     line = 1;
-    std::string             symbol;
-
-    // Ensure that symbols file name is given.
-    if ( !symbolsFile ) {
-      fprintf(
-        stderr,
-        "ERROR: DesiredSymbols::load - no symbols file specified\n"
-      );
-      exit(-1);
-    }
-
-    // Open symbols file.
-    sFile = fopen( symbolsFile, "r" );
-    if ( !sFile ) {
-      fprintf(
-        stderr,
-        "ERROR: DesiredSymbols::load - unable to open symbols file %s\n",
-        symbolsFile
-      );
-      exit(-1);
-    }
-
-    // Process symbols file.
-    while ( !done ) {
-
-      symInfo = new SymbolInformation;
-
-      // Skip blank lines between symbols
-      do {
-        inputBuffer[0] = '\0';
-        inputBuffer2[0] = '\0';
-        cStatus = fscanf( sFile, "%s %s", inputBuffer, inputBuffer2 );
-        if ( cStatus == EOF ) {
-          done = true;
+    rld::files::cache cache;
+    bool              r = true;
+
+    //
+    // Load the INI file looking for a top level:
+    //
+    //  [symbols-sets]
+    //  sets = A, B, C
+    //
+    // For each set read the libraries from the configuration file and load.
+    //
+    //  [A]
+    //  libraries = @BUILD-PREFIX@/c/@BSP@/A/libA.a
+    //
+    //  [B]
+    //  libraries = @BUILD-PREFIX@/c/@BSP@/B/libB.a
+    //
+    try {
+      cache.open();
+
+      rld::config::config config;
+
+      if (verbose)
+        std::cerr << "Loading symbol sets: " << symbolsSet << std::endl;
+
+      config.load (symbolsSet);
+
+      const rld::config::section& sym_section = config.get_section("symbol-sets");
+
+      rld::strings sets;
+      rld::config::parse_items (sym_section, "sets", sets, true);
+
+      for (const std::string set : sets) {
+        if (verbose)
+          std::cerr << " Symbol set: " << set << std::endl;
+        const rld::config::section& set_section = config.get_section(set);
+        rld::strings libs;
+        rld::config::parse_items (set_section, "libraries", libs, true);
+        for (std::string lib : libs) {
+          lib = rld::find_replace(lib, "@BUILD-TARGET@", buildTarget);
+          lib = rld::find_replace(lib, "@BSP@", buildBSP);
+          if (verbose)
+            std::cerr << " Loading library: " << lib << std::endl;
+          cache.add(lib);
         }
-        else {
-          //inputBuffer[ strlen(inputBuffer) - 1] = '\0';
-          line++;
-        }
-      } while ( !done && (inputBuffer[0] == '\0') );
+      }
 
-      // Have we already seen this one?
-      if ( !done ) {
-        if (set.find( inputBuffer ) != set.end()) {
-          fprintf(
-            stderr,
-            "File: %s, Line %d: Duplicate symbol: %s\n",
-            symbolsFile,
-            line,
-            inputBuffer
-          );
+      rld::symbols::table symbols;
 
-          delete symInfo;
-        }
+      cache.load_symbols (symbols, true);
 
-        // Add this to the set of symbols.
-        else
-          set[ inputBuffer ] = *symInfo;
+      for (auto& kv : symbols.globals()) {
+        const rld::symbols::symbol& sym = *(kv.second);
+        set[sym.name()] = *(new SymbolInformation);
+      }
+      for (auto& kv : symbols.weaks()) {
+        const rld::symbols::symbol& sym = *(kv.second);
+        set[sym.name()] = *(new SymbolInformation);
+      }
+      for (auto& kv : symbols.locals()) {
+        const rld::symbols::symbol& sym = *(kv.second);
+        set[sym.name()] = *(new SymbolInformation);
       }
+
+    } catch (rld::error re) {
+      std::cerr << "error: "
+                << re.where << ": " << re.what
+                << std::endl;
+      r = false;
+    } catch (...) {
+      cache.close();
+      throw;
     }
+
+    cache.close();
+
+    return r;
   }
 
   void DesiredSymbols::preprocess( void )
diff --git a/tester/covoar/DesiredSymbols.h b/tester/covoar/DesiredSymbols.h
index 9524c64..21c5602 100644
--- a/tester/covoar/DesiredSymbols.h
+++ b/tester/covoar/DesiredSymbols.h
@@ -293,9 +293,17 @@ namespace Coverage {
     /*!
      *  This method creates the set of symbols to analyze from the symbols
      *  listed in the specified file.
-     */
-    void load(
-      const char* const symbolsFile
+     *
+     *  @param[in] symbolsSet An INI format file of the symbols to be loaded.
+     *  @param[in] buildTarget The build target
+     *  @param[in] buildBSP The BSP
+     *  @return Returns false if the load fails.
+     */
+    bool load(
+      const std::string& symbolsSet,
+      const std::string& buildTarget,
+      const std::string& buildBSP,
+      bool               verbose
     );
 
     /*!
diff --git a/tester/covoar/ExecutableInfo.cc b/tester/covoar/ExecutableInfo.cc
index d71c435..c41d931 100644
--- a/tester/covoar/ExecutableInfo.cc
+++ b/tester/covoar/ExecutableInfo.cc
@@ -67,12 +67,12 @@ namespace Coverage {
     return aCoverageMap;
   }
 
-  std::string ExecutableInfo::getFileName ( void ) const
+  const std::string& ExecutableInfo::getFileName ( void ) const
   {
     return executableName;
   }
 
-  std::string ExecutableInfo::getLibraryName( void ) const
+  const std::string& ExecutableInfo::getLibraryName( void ) const
   {
     return libraryName;
   }
diff --git a/tester/covoar/ExecutableInfo.h b/tester/covoar/ExecutableInfo.h
index 7242715..20ea9bf 100644
--- a/tester/covoar/ExecutableInfo.h
+++ b/tester/covoar/ExecutableInfo.h
@@ -67,14 +67,14 @@ namespace Coverage {
      *
      *  @return Returns the executable's file name
      */
-    std::string getFileName( void ) const;
+    const std::string& getFileName( void ) const;
 
     /*!
      *  This method returns the library name associated with the executable.
      *
      *  @return Returns the executable's library name
      */
-    std::string getLibraryName( void ) const;
+    const std::string& getLibraryName( void ) const;
 
     /*!
      *  This method returns the load address of the dynamic library
@@ -111,7 +111,7 @@ namespace Coverage {
      *  This method indicates whether a dynamic library has been
      *  associated with the executable.
      *
-     *  @return Returns TRUE if 
+     *  @return Returns TRUE if
      */
     bool hasDynamicLibrary( void );
 
diff --git a/tester/covoar/ObjdumpProcessor.cc b/tester/covoar/ObjdumpProcessor.cc
index b916984..d41906c 100644
--- a/tester/covoar/ObjdumpProcessor.cc
+++ b/tester/covoar/ObjdumpProcessor.cc
@@ -247,15 +247,15 @@ namespace Coverage {
     try
     {
       status = rld::process::execute( TargetInfo->getObjdump(),
-               args, objdumpFile.name(), err.name() );
+                                      args, objdumpFile.name(), err.name() );
       if ( (status.type != rld::process::status::normal)
            || (status.code != 0) ) {
         throw rld::error( "Objdump error", "generating objdump" );
       }
     } catch( rld::error& err )
       {
-        std::cout << "Error while running" << TargetInfo->getObjdump()
-                  << "for" << fileName << std::endl;
+        std::cout << "Error while running " << TargetInfo->getObjdump()
+                  << " on " << fileName << std::endl;
         std::cout << err.what << " in " << err.where << std::endl;
         return;
       }
diff --git a/tester/covoar/app_common.h b/tester/covoar/app_common.h
index d28bfd0..ac32bbd 100644
--- a/tester/covoar/app_common.h
+++ b/tester/covoar/app_common.h
@@ -1,6 +1,11 @@
 #ifndef __APP_COMMON_h
 #define __APP_COMMON_h
 
+/*
+ * This file needs to be removed and these globals removed from the
+ * global scope. For example SymbolsToAnalyze is never destructed.
+ */
+
 #include <list>
 
 #include "DesiredSymbols.h"
@@ -22,8 +27,8 @@ extern char                         inputBuffer[MAX_LINE_LENGTH];
 extern char                         inputBuffer2[MAX_LINE_LENGTH];
 
 
-bool FileIsNewer( const char *f1, const char *f2 ); 
-bool FileIsReadable( const char *f1 ); 
+bool FileIsNewer( const char *f1, const char *f2 );
+bool FileIsReadable( const char *f1 );
 bool ReadUntilFound( FILE *file, const char *line );
 
 #endif
diff --git a/tester/covoar/covoar.cc b/tester/covoar/covoar.cc
index c36b00a..81c90d2 100644
--- a/tester/covoar/covoar.cc
+++ b/tester/covoar/covoar.cc
@@ -29,34 +29,92 @@
   #define kill(p,s) raise(s)
 #endif
 
+typedef std::list<std::string> CoverageNames;
+typedef std::list<Coverage::ExecutableInfo*> Executables;
+
 /*
- *  Variables to control general behavior
+ * Create a build path from the executable paths. Also extract the build prefix
+ * and BSP names.
  */
-const char*                          coverageFileExtension = NULL;
-std::list<std::string>               coverageFileNames;
-int                                  coverageExtensionLength = 0;
-Coverage::CoverageFormats_t          coverageFormat;
-Coverage::CoverageReaderBase*        coverageReader = NULL;
-char*                                executable = NULL;
-const char*                          executableExtension = NULL;
-int                                  executableExtensionLength = 0;
-std::list<Coverage::ExecutableInfo*> executablesToAnalyze;
-const char*                          explanations = NULL;
-char*                                progname;
-const char*                          symbolsFile = NULL;
-const char*                          gcnosFileName = NULL;
-char                                 gcnoFileName[FILE_NAME_LENGTH];
-char                                 gcdaFileName[FILE_NAME_LENGTH];
-char                                 gcovBashCommand[256];
-const char*                          target = NULL;
-const char*                          format = NULL;
-FILE*                                gcnosFile = NULL;
-Gcov::GcovData*          gcovFile;
+static void createBuildPath(Executables& executablesToAnalyze,
+                            std::string& buildPath,
+                            std::string& buildPrefix,
+                            std::string& buildBSP)
+{
+  for (const auto& exe : executablesToAnalyze) {
+    rld::strings eparts;
+    rld::split(eparts, rld::path::path_abs(exe->getFileName()), RLD_PATH_SEPARATOR);
+    std::string fail; // empty means all is OK else an error string
+    for (rld::path::paths::reverse_iterator pri = eparts.rbegin();
+         pri != eparts.rend();
+         ++pri) {
+      if (*pri == "testsuites") {
+        ++pri;
+        if (pri == eparts.rend()) {
+          fail = "invalid executable path, no BSP";
+          break;
+        }
+        if (buildBSP.empty()) {
+          buildBSP = *pri;
+        } else {
+          if (buildBSP != *pri) {
+            fail = "executable BSP does not match: " + buildBSP;
+            break;
+          }
+        }
+        ++pri;
+        if (pri == eparts.rend() || *pri != "c") {
+          fail = "invalid executable path, no 'c'";
+          break;
+        }
+        ++pri;
+        if (pri == eparts.rend()) {
+          fail = "invalid executable path, no arch prefix";
+          break;
+        }
+        if (buildPrefix.empty()) {
+          buildPrefix = *pri;
+        } else {
+          if (buildBSP != *pri) {
+            fail = "executable build prefix does not match: " + buildPrefix;
+            break;
+          }
+        }
+        ++pri;
+        if (pri == eparts.rend()) {
+          fail = "invalid executable path, no build top";
+          break;
+        }
+        //
+        // The remaining parts of the path is the build path. Iterator over them
+        // and collect into a new paths variable to join to make a path.
+        //
+        rld::path::paths bparts;
+        for (; pri != eparts.rend(); ++pri)
+          bparts.insert(bparts.begin(), *pri);
+        std::string thisBuildPath;
+        rld::path::path_join(thisBuildPath, bparts, thisBuildPath);
+        if (buildPath.empty()) {
+          buildPath = thisBuildPath;
+        } else {
+          if (buildBSP != *pri) {
+            fail = "executable build path does not match: " + buildPath;
+          }
+        }
+        break;
+      }
+    }
+    if (!fail.empty()) {
+      std::cerr << "ERROR: " << fail << std::endl;
+      exit(EXIT_FAILURE);
+    }
+  }
+}
 
 /*
  *  Print program usage message
  */
-void usage()
+void usage(const std::string& progname)
 {
   fprintf(
     stderr,
@@ -69,17 +127,18 @@ void usage()
     "  -f FORMAT                 - coverage file format "
            "(RTEMS, QEMU, TSIM or Skyeye)\n"
     "  -E EXPLANATIONS           - name of file with explanations\n"
-    "  -s SYMBOLS_FILE           - name of file with symbols of interest\n"
+    "  -s SYMBOL_SET_FILE        - path to the INI format symbol sets\n"
     "  -1 EXECUTABLE             - name of executable to get symbols from\n"
     "  -e EXE_EXTENSION          - extension of the executables to analyze\n"
     "  -c COVERAGEFILE_EXTENSION - extension of the coverage files to analyze\n"
     "  -g GCNOS_LIST             - name of file with list of *.gcno files\n"
     "  -p PROJECT_NAME           - name of the project\n"
     "  -C ConfigurationFileName  - name of configuration file\n"
-    "  -O Output_Directory       - name of output directory (default=."
+    "  -O Output_Directory       - name of output directory (default=.\n"
+    "  -d debug                  - disable cleaning of tempfiles."
     "\n",
-    progname,
-    progname
+    progname.c_str(),
+    progname.c_str()
   );
 }
 
@@ -125,42 +184,58 @@ int main(
   char** argv
 )
 {
-  std::list<std::string>::iterator               citr;
-  std::string                                    coverageFileName;
-  std::list<Coverage::ExecutableInfo*>::iterator eitr;
-  Coverage::ExecutableInfo*                      executableInfo = NULL;
-  int                                            i;
-  int                                            opt;
-  const char*                                    singleExecutable = NULL;
-  rld::process::tempfile                         objdumpFile( ".dmp" );
-  rld::process::tempfile                         err( ".err" );
-  bool                                           debug = false;
-  std::string                                    option;
+  CoverageNames                 coverageFileNames;
+  std::string                   coverageFileName;
+  Executables                   executablesToAnalyze;
+  Coverage::ExecutableInfo*     executableInfo = NULL;
+  std::string                   executableExtension = "exe";
+  std::string                   coverageExtension = "cov";
+  Coverage::CoverageFormats_t   coverageFormat;
+  Coverage::CoverageReaderBase* coverageReader = NULL;
+  char*                         executable = NULL;
+  const char*                   explanations = NULL;
+  const char*                   gcnosFileName = NULL;
+  char                          gcnoFileName[FILE_NAME_LENGTH];
+  char                          gcdaFileName[FILE_NAME_LENGTH];
+  char                          gcovBashCommand[256];
+  std::string                   target;
+  const char*                   format = "html";
+  FILE*                         gcnosFile = NULL;
+  Gcov::GcovData*               gcovFile;
+  const char*                   singleExecutable = NULL;
+  rld::process::tempfile        objdumpFile( ".dmp" );
+  rld::process::tempfile        err( ".err" );
+  rld::process::tempfile        syms( ".syms" );
+  bool                          debug = false;
+  std::string                   symbolSet;
+  std::string                   progname;
+  std::string                   option;
+  int                           opt;
 
   setup_signals();
 
   //
   // Process command line options.
   //
-  progname = argv[0];
+  progname = rld::path::basename(argv[0]);
 
-  while ((opt = getopt(argc, argv, "1:L:e:c:g:E:f:s:T:O:p:v:d")) != -1) {
+  while ((opt = getopt(argc, argv, "1:L:e:c:g:E:f:s:S:T:O:p:vd")) != -1) {
     switch (opt) {
-      case '1': singleExecutable      = optarg; break;
-      case 'L': dynamicLibrary        = optarg; break;
-      case 'e': executableExtension   = optarg; break;
-      case 'c': coverageFileExtension = optarg; break;
-      case 'g': gcnosFileName         = optarg; break;
-      case 'E': explanations          = optarg; break;
-      case 'f': format                = optarg; break;
-      case 's': symbolsFile           = optarg; break;
-      case 'T': target                = optarg; break;
-      case 'O': outputDirectory       = optarg; break;
-      case 'v': Verbose               = true;   break;
-      case 'p': projectName           = optarg; break;
-      case 'd': debug                 = true;   break;
+      case '1': singleExecutable    = optarg; break;
+      case 'L': dynamicLibrary      = optarg; break;
+      case 'e': executableExtension = optarg; break;
+      case 'c': coverageExtension   = optarg; break;
+      case 'g': gcnosFileName       = optarg; break;
+      case 'E': explanations        = optarg; break;
+      case 'f': format              = optarg; break;
+      case 'S': symbolSet           = optarg; break;
+      case 'T': target              = optarg; break;
+      case 'O': outputDirectory     = optarg; break;
+      case 'v': Verbose             = true;   break;
+      case 'p': projectName         = optarg; break;
+      case 'd': debug               = true;   break;
       default: /* '?' */
-        usage();
+        usage(progname);
         exit(EXIT_FAILURE);
     }
   }
@@ -171,18 +246,10 @@ int main(
      */
 
     /*
-     * Target name must be set.
+     * Validate that we have a symbols of interest file.
      */
-    if ( !target ) {
-      option = "target -T";
-      throw option;
-    }
-
-    /*
-     * Validate simulator format.
-     */
-    if ( !format ) {
-      option = "format -f";
+    if ( symbolSet.empty() ) {
+      option = "symbol set file -S";
       throw option;
     }
 
@@ -195,22 +262,6 @@ int main(
     }
 
     /*
-     * Has coverage file extension been specified.
-     */
-    if ( !coverageFileExtension ) {
-      option = "coverage extension -c";
-      throw option;
-    }
-
-    /*
-     * Has executable extension been specified.
-     */
-    if ( !executableExtension ) {
-      option = "executable extension -e";
-      throw option;
-    }
-
-    /*
      * Check for project name.
      */
     if ( !projectName ) {
@@ -220,8 +271,8 @@ int main(
   }
   catch( std::string option )
   {
-    std::cout << "error missing option: " + option << std::endl;
-    usage();
+    std::cerr << "error missing option: " + option << std::endl;
+    usage(progname);
     exit(EXIT_FAILURE);
   }
 
@@ -238,7 +289,7 @@ int main(
       );
     } else {
 
-      for (i=optind; i < argc; i++) {
+      for (int i = optind; i < argc; i++) {
         // Ensure that the coverage file is readable.
         if (!FileIsReadable( argv[i] )) {
           fprintf(
@@ -266,11 +317,10 @@ int main(
       }
     }
   }
-
-  // If not invoked with a single executable, process the remaining
-  // arguments as executables and derive the coverage file names.
   else {
-    for (i = optind; i < argc; i++) {
+    // If not invoked with a single executable, process the remaining
+    // arguments as executables and derive the coverage file names.
+    for (int i = optind; i < argc; i++) {
 
       // Ensure that the executable is readable.
       if (!FileIsReadable( argv[i] )) {
@@ -282,9 +332,9 @@ int main(
       } else {
         coverageFileName = argv[i];
         coverageFileName.replace(
-          coverageFileName.length() - executableExtensionLength,
-          executableExtensionLength,
-          coverageFileExtension
+          coverageFileName.length() - executableExtension.size(),
+          executableExtension.size(),
+          coverageExtension
         );
 
         if (!FileIsReadable( coverageFileName.c_str() )) {
@@ -310,6 +360,33 @@ int main(
     exit(EXIT_FAILURE);
   }
 
+  // The executablesToAnalyze and coverageFileNames containers need
+  // to be the name size of some of the code below breaks. Lets
+  // check and make sure.
+  if (executablesToAnalyze.size() != coverageFileNames.size()) {
+    std::cerr << "ERROR: executables and coverage name size mismatch" << std::endl;
+    exit(EXIT_FAILURE);
+  }
+
+  //
+  // Find the top of the BSP's build tree and if we have found the top
+  // check the executable is under the same path and BSP.
+  //
+  std::string buildPath;
+  std::string buildTarget;
+  std::string buildBSP;
+  createBuildPath(executablesToAnalyze,
+                  buildPath,
+                  buildTarget,
+                  buildBSP);
+
+  //
+  // Use a command line target if provided.
+  //
+  if (!target.empty()) {
+    buildTarget = target;
+  }
+
   if (Verbose) {
     if (singleExecutable) {
       fprintf(
@@ -323,12 +400,12 @@ int main(
       );
     }
     fprintf( stderr, "Coverage Format : %s\n", format );
-    fprintf( stderr, "Target          : %s\n", PrintableString(target) );
+    fprintf( stderr, "Target          : %s\n", buildTarget.c_str() );
     fprintf( stderr, "\n" );
-#if 1
+
     // Process each executable/coverage file pair.
-    eitr = executablesToAnalyze.begin();
-    for (citr = coverageFileNames.begin();
+    Executables::iterator eitr = executablesToAnalyze.begin();
+    for (CoverageNames::iterator citr = coverageFileNames.begin();
          citr != coverageFileNames.end();
          citr++) {
 
@@ -342,7 +419,6 @@ int main(
       if (!singleExecutable)
         eitr++;
     }
-#endif
   }
 
   //
@@ -350,19 +426,22 @@ int main(
   //
 
   // Create data based on target.
-  TargetInfo = Target::TargetFactory( target );
+  TargetInfo = Target::TargetFactory( buildTarget );
 
   // Create the set of desired symbols.
   SymbolsToAnalyze = new Coverage::DesiredSymbols();
-  SymbolsToAnalyze->load( symbolsFile );
-  if (Verbose) {
-    fprintf(
-      stderr,
-      "Analyzing %u symbols\n",
-      (unsigned int) SymbolsToAnalyze->set.size()
-    );
+
+  //
+  // Read symbol configuration file and load needed symbols.
+  //
+  if (!SymbolsToAnalyze->load( symbolSet, buildTarget, buildBSP, Verbose )) {
+      exit(EXIT_FAILURE);
   }
 
+  if ( Verbose )
+    std::cout << "Analyzing " << SymbolsToAnalyze->set.size()
+              << " symbols" << std::endl;
+
   // Create explanations.
   AllExplanations = new Coverage::Explanations();
   if ( explanations )
@@ -379,7 +458,7 @@ int main(
   objdumpProcessor = new Coverage::ObjdumpProcessor();
 
   // Prepare each executable for analysis.
-  for (eitr = executablesToAnalyze.begin();
+  for (Executables::iterator eitr = executablesToAnalyze.begin();
        eitr != executablesToAnalyze.end();
        eitr++) {
 
@@ -407,22 +486,19 @@ int main(
   //
 
   // Process each executable/coverage file pair.
-  eitr = executablesToAnalyze.begin();
-  for (citr = coverageFileNames.begin();
-       citr != coverageFileNames.end();
-       citr++) {
-
+  Executables::iterator eitr = executablesToAnalyze.begin();
+  for (const auto& cname : coverageFileNames) {
     if (Verbose) {
       fprintf(
         stderr,
         "Processing coverage file %s for executable %s\n",
-        (*citr).c_str(),
+        cname.c_str(),
         ((*eitr)->getFileName()).c_str()
       );
     }
 
     // Process its coverage file.
-    coverageReader->processFile( (*citr).c_str(), *eitr );
+    coverageReader->processFile( cname.c_str(), *eitr );
 
     // Merge each symbols coverage map into a unified coverage map.
     (*eitr)->mergeCoverage();
@@ -524,6 +600,8 @@ int main(
     objdumpFile.keep();
     err.override( "objdump_exec_log" );
     err.keep();
+    syms.override( "symbols_list" );
+    syms.keep();
   }
   return 0;
 }
diff --git a/tester/covoar/wscript b/tester/covoar/wscript
index 9db4815..c0270d8 100644
--- a/tester/covoar/wscript
+++ b/tester/covoar/wscript
@@ -118,10 +118,12 @@ def build(bld):
                           'TraceWriterQEMU.cc'],
                 use = ['ccovoar'] + modules,
                 cflags = ['-O2', '-g'],
+                cxxflags = ['-std=c++11', '-O2', '-g'],
                 includes = ['.'] + rtl_includes)
 
     bld.program(target = 'covoar',
                 source = ['covoar.cc'],
                 use = ['ccovoar'] + modules,
                 cflags = ['-O2', '-g'],
+                cxxflags = ['-std=c++11', '-O2', '-g'],
                 includes = ['.'] + rtl_includes)
diff --git a/tester/rtems/testing/bsps/leon3-qemu-cov.ini b/tester/rtems/testing/bsps/leon3-qemu-cov.ini
new file mode 100644
index 0000000..6b5e7e6
--- /dev/null
+++ b/tester/rtems/testing/bsps/leon3-qemu-cov.ini
@@ -0,0 +1,39 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2018 Chris Johns (chrisj at rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# The Leon 3 QEMU BSP
+#
+[leon3-qemu]
+bsp               = leon3-qemu
+arch              = sparc
+tester            = %{_rtscripts}/qemu.cfg
+bsp_qemu_opts     = %{qemu_opts_base} -M leon3_generic
+bsp_qemu_cov_opts = -exec-trace %{test_executable}.cov
diff --git a/tester/rtems/testing/bsps/leon3-qemu.ini b/tester/rtems/testing/bsps/leon3-qemu.ini
new file mode 100644
index 0000000..9e8854c
--- /dev/null
+++ b/tester/rtems/testing/bsps/leon3-qemu.ini
@@ -0,0 +1,38 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2010-2014 Chris Johns (chrisj at rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+#
+# The Leon 3 QEMU BSP
+#
+[leon3-qemu]
+bsp           = leon3-qemu
+arch          = sparc
+tester        = %{_rtscripts}/qemu.cfg
+bsp_qemu_opts = %{qemu_opts_base} -M leon3_generic
diff --git a/tester/rtems/testing/coverage/Categories.txt b/tester/rtems/testing/coverage/Categories.txt
new file mode 100644
index 0000000..e19a456
--- /dev/null
+++ b/tester/rtems/testing/coverage/Categories.txt
@@ -0,0 +1,19 @@
+This is the list of Explanation Categories used when analyzing RTEMS
+Coverage report.  By using standard categories, the table filter on
+the web site works better.
+
+Simple Test Case
+
+Hard Test Tase
+
+Uncalled Routine
+
+Interrupt Critical Section
+
+Simple Error Case
+
+Hard Error Case
+
+Allocation Error
+
+Bharath Suri
diff --git a/tester/rtems/testing/coverage/Explanations.txt b/tester/rtems/testing/coverage/Explanations.txt
new file mode 100644
index 0000000..a5917f6
--- /dev/null
+++ b/tester/rtems/testing/coverage/Explanations.txt
@@ -0,0 +1,35 @@
+schedulerpriorityyield.c:47
+Simple Test Case
+Branch Never Taken
+New test where there is more than one thread at a priority with the
+executing thread being non-preemptive.  Create a higher priority thread
+and then yield.
+
+   init task at priority 2, non-preemptive
+   create task at priority 2
+   create task at priority 1
+   yield
++++
+
+schedulerpriorityyield.c:51
+Simple Test Case
+Branch Always Taken
+New test where only one thread at a priority (non-preemptive), create a
+thread at higher priority, then yield.
+
+   init task at priority 2, non-preemptive
+   create task at priority 1
+   yield
++++
+
+schedulerpriorityyield.c:52
+Simple Test Case
+Not Executed
+Same test case as schedulerpriorityyield.c:51
++++
+
+coremsg.c:86
+Simple Test Case
+We need to request enough messages of a certain size that the math
+overflows to less than a single message.
++++
diff --git a/tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt b/tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt
new file mode 100644
index 0000000..ef740d3
--- /dev/null
+++ b/tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt
@@ -0,0 +1,56 @@
+The SPARC assembly is often hard to understand because a single
+instruction will show up as not executed.  The instructions before
+and after it will be marked as executed.  The instruction before
+the one not executed should be a "bxx,a" instruction which means
+that the instruction following the branch instruction is executed
+ONLY if the branch is taken.  Otherwise it is "annulled" or skipped.
+
+So when you see these cases, it means the branch was NOT taken.
+
+===================================================================
+Subject: <offlist> annul slot explanation
+From: Jiri Gaisler <jiri at gaisler.com>
+Date: Wed, 3 Jun 2009 14:57:48 -0500
+To: Joel Sherrill <Joel.Sherrill at OARcorp.com>
+
+
+Joel Sherrill wrote:
+> > Hi,
+> >
+> > I am trying to look at more coverage cases and
+> > wanted to make sure I am reading things correctly.
+> >
+> > The code in question is:
+> >
+> >
+> >      if ( the_thread->current_priority > interested_priority )
+> > 200fd00:    d8 00 e0 14     ld  [ %g3 + 0x14 ], %o4
+> > 200fd04:    80 a3 00 04     cmp  %o4, %g4
+> > 200fd08:    38 80 00 1c     bgu,a   200fd78 <killinfo+0x224>
+> > 200fd0c:    98 10 00 04     mov  %g4,
+> > %o4                                            <== NOT EXECUTED
+> >
+> >      /*
+> >       *  If this thread is not interested, then go on to the next thread.
+> >       */
+> >
+> >      api = the_thread->API_Extensions[ THREAD_API_POSIX ];
+> > 200fd10:    d4 00 e1 6c     ld  [ %g3 + 0x16c ], %o2
+> >
+> > Am I correct in interpreting this as meaning 0x200fd0c
+> > is not executed because the bgu,a is never taken. And it
+> > is not executed as part of falling through.
+
+Yes, this is correct. The branch delay slot is only executed
+when the branch is taken.
+
+Jiri.
+
+> >
+> > So in this case we need a test where the "if" condition
+> > is true if I am reading things correctly.
+> >
+> > Thanks.  There are a number of these 4 byte cases which
+> > are probably easy to hit if I read the code correctly.
+> >
+> >
diff --git a/tester/rtems/testing/coverage/score-symbols.ini b/tester/rtems/testing/coverage/score-symbols.ini
new file mode 100644
index 0000000..b3c8b18
--- /dev/null
+++ b/tester/rtems/testing/coverage/score-symbols.ini
@@ -0,0 +1,35 @@
+#
+# RTEMS Tools Project (http://www.rtems.org/)
+# Copyright 2018 Chris Johns (chrisj at rtems.org)
+# All rights reserved.
+#
+# This file is part of the RTEMS Tools package in 'rtems-tools'.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+[symbol-sets]
+sets = score
+
+[score]
+libraries=@BUILD-TARGET@/c/@BSP@/cpukit/score/libscore.a
diff --git a/tester/rtems/testing/coverage/style.css b/tester/rtems/testing/coverage/style.css
new file mode 100644
index 0000000..c715518
--- /dev/null
+++ b/tester/rtems/testing/coverage/style.css
@@ -0,0 +1,197 @@
+body {
+    background: rgb(253,253,253);
+    color: rgb(0,0,0);
+    font-family: helvetica, sans-serif;
+    font-size: 1em;
+    line-height: 1.4;
+    margin: 5px, 5px, 5px, 5px;
+    padding: 0;
+}
+
+a:link {
+    color: rgb(180, 50, 50);
+    font-family: helvetica, sans-serif;
+    font-size: 1.0em;
+}
+
+a:visited {
+    color: purple;
+    font-family: helvetica, sans-serif;
+    font-size: 1.0em;
+}
+
+a:hover {
+    color: rgb(0, 0, 0);
+    font-family: helvetica, sans-serif;
+    font-size: 1.0em;
+}
+
+a:active {
+    color: red;
+    font-family: helvetica, sans-serif;
+    font-size: 1.0em;
+}
+
+.heading {
+    background: rgb(250,250,250);
+    background-image: url("http://www.rtems.org/logos/rtems_logo.jpg");
+    background-repeat: no-repeat;
+    color: rgb(55,55,55);
+    font-size: 1.5em;
+    height: 140px;
+    padding-top: 20px;
+    padding-left: 300px;
+}
+
+.heading-title {
+    text-align:  center;
+    color: rgb(0,0,0);
+    font-size: 0.9em;
+    font-weight: bold;
+    padding-top: 5px;
+    padding-left: 0px;
+    text-align:  center;
+    width: 100%;
+}
+
+.datetime {
+    color: rgb(55,55,55);
+    font-size: 0.8em;
+    padding-top: 5px;
+    padding-left: 0px;
+    text-align:  center;
+    width: 100%;
+}
+
+.info {
+    color: rgb(55,55,55);
+    font-size: 0.6em;
+    padding-top: 5px;
+    padding-left: 00px;
+    text-align:  center;
+    width: 100%;
+}
+
+.stats-table {
+    background: rgb(225,225,225);
+    font-size: 0.9em;
+    border: 1px solid rgb(200, 200, 200);
+    padding: 0;
+    margin-top: 3px;
+    margin-left: 10px;
+    width: 70%;
+}
+
+.stats-table-target {
+    background: rgb(243,243,243);
+    font-size: 1.2em;
+    padding-left: 10px;
+    text-align: left;
+}
+
+.stats-target-results {
+    background: rgb(243,243,243);
+    font-size: 0.9em;
+    text-align: right;
+    padding-right: 10px;
+}
+
+.stats-target-good {
+    background: rgb(30,230,30);
+    font-size: 0.9em;
+    text-align: right;
+    padding-right: 10px;
+}
+
+.stats-target-good {
+    background: rgb(50,180,50);
+    color: rgb(230,230,230);
+    font-size: 0.9em;
+    text-align: center;
+    padding-right: 10px;
+}
+
+.stats-target-bad {
+    background: rgb(180,50,50);
+    color: rgb(230,230,230);
+    font-size: 0.9em;
+    text-align: center;
+    padding-right: 10px;
+}
+
+.stats-table-top {
+    background: rgb(243,243,243);
+    color: rgb(0,0,0);
+    font-size: 0.9em;
+    padding-left: 2px;
+}
+
+.stats-table-row {
+    background: rgb(253,253,253);
+    font-size: 0.9em;
+    padding: 1px;
+    text-align: right;
+}
+
+.error-table {
+    font-size: 0.9em;
+    border: 1px solid rgb(200, 200, 200);
+    padding: 0;
+    margin-left: 10px;
+    width: 96%;
+}
+
+.error-table-top {
+    background: rgb(225,225,225);
+    color: rgb(0,0,0);
+    font-size: 0.9em;
+    padding-left: 2px;
+}
+
+.error-table-on {
+    background: rgb(225,225,225);
+    font-size: 0.9em;
+    padding-left: 2px;
+}
+
+.error-table-off {
+    background: rgb(253,253,253);
+    font-size: 0.9em;
+    padding-left: 2px;
+}
+
+.error-table-dups {
+    text-align: right;
+    padding-right: 2px;
+}
+
+.error-table-error {
+    background: rgb(255,150,150);
+    font-size: 0.9em;
+    padding-left: 2px;
+}
+
+.error-table-warning {
+    font-size: 0.9em;
+    padding-left: 2px;
+}
+
+.navbar {
+    margin-left: auto;
+    margin-right: auto;
+    margin-top: 10px;
+    width: 40%;
+}
+th.table-sortable {
+  background-image:url("unsorted.gif");
+  cursor: pointer;
+  background-position: center left;
+  background-repeat: no-repeat;
+  padding-left: 15px;
+}
+th.table-sorted-asc {
+  background-image:url("descending.gif");
+}
+th.table-sorted-desc {
+  background-image:url("ascending.gif");
+}
\ No newline at end of file
diff --git a/tester/rtems/testing/qemu.cfg b/tester/rtems/testing/qemu.cfg
index db5b6b2..bfcd2f5 100644
--- a/tester/rtems/testing/qemu.cfg
+++ b/tester/rtems/testing/qemu.cfg
@@ -54,14 +54,23 @@
 #%define qemu_opts_base   -no-reboot -monitor none -serial stdio -nographic
 %define qemu_opts_base   -no-reboot -serial null -serial mon:stdio -nographic
 %define qemu_opts_no_net -net none
+
+#
+# Coverage, some builds of qemu support coverage.
+#
+%ifn %{defined bsp_qemu_cov_opts}
+ %define bsp_qemu_cov_opts %{nil}
+%endif
+
 #
 # Qemu executable
 #
 %ifn %{defined bsp_qemu_opts}
  %define bsp_qemu_opts %{nil}
 %endif
+
 %define qemu_cmd  qemu-system-%{bsp_arch}
-%define qemu_opts %{bsp_qemu_opts}
+%define qemu_opts %{bsp_qemu_opts} %{bsp_qemu_cov_opts}
 
 #
 # Executable
diff --git a/tester/rtems/testing/testing.mc b/tester/rtems/testing/testing.mc
index 77f8419..662b352 100644
--- a/tester/rtems/testing/testing.mc
+++ b/tester/rtems/testing/testing.mc
@@ -55,3 +55,11 @@ timeout:              none,    none,     '180'
 
 # Tests detected as invalid that are valid
 invalid_tests:        none,    none,     '''minimum.exe'''
+
+# Coverage defaults
+cov_format:           none,    none,     'QEMU'
+cov_explanations:     none,    none,     '%{_rtscripts}/coverage/Explanations.txt'
+cov_extension:        none,    none,     'cov'
+cov_gcnos_file:       none,    none,     '%{_rtscripts}/coverage/rtems.gcnos'
+cov_exe_ext:          none,    none,     'exe'
+cov_report_format:    none,    none,     'html'




More information about the vc mailing list