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

Chris Johns chrisj at rtems.org
Sat Apr 28 07:08:18 UTC 2018


From: Cillian O'Donnell <cpodonnell8 at gmail.com>

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>
Cp-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(-)
 create mode 100644 tester/rtems/testing/bsps/leon3-qemu-cov.ini
 create mode 100644 tester/rtems/testing/bsps/leon3-qemu.ini
 create mode 100644 tester/rtems/testing/coverage/Categories.txt
 create mode 100644 tester/rtems/testing/coverage/Explanations.txt
 create mode 100644 tester/rtems/testing/coverage/SPARC-Annul-Slot-Explanation.txt
 create mode 100644 tester/rtems/testing/coverage/score-symbols.ini
 create mode 100644 tester/rtems/testing/coverage/style.css

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;
     }
 
@@ -194,22 +261,6 @@ int main(
       throw option;
     }
 
-    /*
-     * 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.
      */
@@ -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..858cac8 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
+
+#
+# Converage, some builds of qemu support coverage.
+#
+%ifn %{defined bsp_qemu_ocv_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'
-- 
2.15.1




More information about the devel mailing list