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

Cillian O'Donnell cpodonnell8 at gmail.com
Wed Apr 25 20:33:58 UTC 2018


Add ability to organize symbol sets of libraries in symbol_set.cfg
and then read them with covoar (Krzysztof Miesowicz))
Also the symbols are now loaded in from ELF data rather than relying
on nm.(Cillian O'Donnell)

Co-author:"Krzysztof Miesowicz <krzysztof.miesowicz at gmail.com>"
---
 tester/covoar/SymbolSet.cpp       | 153 ++++++++++++++++++++++++++++++++++++++
 tester/covoar/SymbolSet.h         |  79 ++++++++++++++++++++
 tester/covoar/SymbolSetReader.cpp |  82 ++++++++++++++++++++
 tester/covoar/SymbolSetReader.h   |  34 +++++++++
 tester/covoar/covoar.cc           |  57 +++++++++++---
 tester/covoar/wscript             |   4 +-
 6 files changed, 398 insertions(+), 11 deletions(-)
 create mode 100644 tester/covoar/SymbolSet.cpp
 create mode 100644 tester/covoar/SymbolSet.h
 create mode 100644 tester/covoar/SymbolSetReader.cpp
 create mode 100644 tester/covoar/SymbolSetReader.h

diff --git a/tester/covoar/SymbolSet.cpp b/tester/covoar/SymbolSet.cpp
new file mode 100644
index 0000000..dfa0fa1
--- /dev/null
+++ b/tester/covoar/SymbolSet.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2014 Krzysztof Miesowicz  (krzysztof.miesowicz at gmail.com)
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#include <iostream>
+#include <fstream>
+#include <cstdio>
+
+#include "SymbolSet.h"
+
+#include "rld.h"
+#include "rld-process.h"
+#include "rld-symbols.h"
+#include "rld-files.h"
+
+namespace Symbols
+{
+  SymbolSet::SymbolSet ()
+  {
+  }
+
+  SymbolSet::~SymbolSet ()
+  {
+  }
+
+  std::string SymbolSet::parseElfDataLine (std::string line)
+  {
+    std::string symbol = "";
+    int funcStartPos = 64;
+    if (line.find ("STT_FUNC") != std::string::npos)
+    {
+      symbol = line.substr (funcStartPos);
+      symbol = symbol.substr (0, symbol.find (' '));
+    }
+    return symbol;
+  }
+
+  std::string SymbolSet::getLibname (std::string libPath)
+  {
+    std::string libname = "", base = "", temp;
+    size_t pos = libPath.find_last_of ('/');
+    if (pos != std::string::npos)
+    {
+      temp = libPath.substr (0, pos);
+      libname = libPath.substr (pos + 1);
+    }
+    pos = temp.find_last_of ('/');
+    if (pos != std::string::npos)
+    {
+      base = temp.substr (pos + 1);
+    }
+    return base + "/" + libname;
+  }
+
+  void SymbolSet::parseElfData (rld::process::tempfile& elfData,
+                                const std::string& lib)
+  {
+    std::string line, symbol;
+    elfData.open( true );
+    while ( true )
+    {
+      elfData.read_line (line);
+      if ( line.empty() ) break;
+      symbol = parseElfDataLine (line);
+      if (symbol.length () > 0)
+      {
+        symbols.push_back (symbol + " " + getLibname (lib));
+      }
+    }
+  }
+
+  void SymbolSet::generateSymbolFile (rld::process::tempfile& filePath,
+                                      std::string target)
+  {
+    rld::files::cache   kernel;
+    rld::symbols::table symbolsTable;
+
+    for (std::string lib : libraries)
+    {
+      /*
+       * Load the symbols from the kernel.
+       */
+      try
+      {
+        /*
+         * Load the kernel ELF file symbol table.
+         */
+        kernel.open ();
+        kernel.add (lib);
+        kernel.load_symbols (symbolsTable, true);
+
+        /*
+         * Create a symbols file.
+         */
+        std::ofstream mout;
+        mout.open (filePath.name().c_str());
+        if (!mout.is_open ())
+          throw rld::error ("map file open failed", "map");
+        mout << "RTEMS Kernel Symbols Map" << std::endl
+             << " kernel: " << lib << std::endl
+             << std::endl;
+        rld::symbols::output (mout, symbolsTable);
+        mout.close ();
+      }
+      catch (...)
+      {
+        kernel.close ();
+        throw;
+      }
+
+      kernel.close ();
+
+      try
+      {
+        parseElfData (filePath, lib);
+      }
+      catch (std::exception& e)
+      {
+        std::cout << "ERROR while parsing symbols output: " << e.what ()
+                  << std::endl;
+      }
+      filePath.close ();
+    }
+
+    std::ofstream outputFile (filePath.name ());
+    for (std::string symbol : symbols)
+      outputFile << symbol << std::endl;
+    outputFile.close ();
+  }
+}
diff --git a/tester/covoar/SymbolSet.h b/tester/covoar/SymbolSet.h
new file mode 100644
index 0000000..20d7327
--- /dev/null
+++ b/tester/covoar/SymbolSet.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 Krzysztof Miesowicz (krzysztof.miesowicz at gmail.com)
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef SYMBOLSET_H_
+#define SYMBOLSET_H_
+
+#include <string>
+#include <vector>
+
+#include "rld-process.h"
+
+namespace Symbols
+{
+  class SymbolSet
+  {
+  public:
+    SymbolSet ();
+    virtual ~SymbolSet ();
+
+    const std::string getName () const
+    {
+      return name;
+    }
+
+    void setName (const std::string& name)
+    {
+      this->name = name;
+    }
+
+    const std::vector<std::string> getLibraries () const
+    {
+      return libraries;
+    }
+
+    void addLibrary (std::string libraryPath)
+    {
+      libraries.push_back (libraryPath);
+    }
+
+    void generateSymbolFile (rld::process::tempfile& filePath,
+                             std::string target);
+
+  private:
+    std::string name;
+    std::vector<std::string> libraries;
+    std::vector<std::string> symbols;
+
+    std::string parseElfDataLine (std::string line);
+    std::string getLibname (std::string libPath);
+    void parseElfData (rld::process::tempfile& elfData,
+                       const std::string& lib);
+  };
+}
+
+#endif /* SYMBOLSET_H_ */
diff --git a/tester/covoar/SymbolSetReader.cpp b/tester/covoar/SymbolSetReader.cpp
new file mode 100644
index 0000000..886e256
--- /dev/null
+++ b/tester/covoar/SymbolSetReader.cpp
@@ -0,0 +1,82 @@
+/*
+ * SymbolSetReader.cpp
+ *
+ *  Created on: Aug 5, 2014
+ *      Author: Krzysztof Mięsowicz <krzysztof.miesowicz at gmail.com>
+ */
+
+#include "SymbolSetReader.h"
+#include "iostream"
+#include "fstream"
+
+namespace Symbols {
+
+SymbolSetReader::SymbolSetReader() {
+	// TODO Auto-generated constructor stub
+
+}
+
+SymbolSetReader::~SymbolSetReader() {
+	// TODO Auto-generated destructor stub
+}
+
+std::vector<SymbolSet> SymbolSetReader::readSetFile(string filepath) {
+	std::vector<SymbolSet> setList { };
+	ifstream file(filepath);
+	string line;
+	while (getline(file, line)) {
+		if (line.find("symbolset:") != std::string::npos) {
+			setList.emplace_back();
+		} else if (line.length() > 0) {
+
+			auto pair = parseLine(line);
+
+			if(pair.first == "name") {
+				if (setList.empty()) {
+					setList.emplace_back();
+				}
+				setList.rbegin()->setName(pair.second);
+				continue;
+			}
+			if(pair.first == "lib") {
+				setList.rbegin()->addLibrary(pair.second);
+				continue;
+			}
+
+			std::cout << "Invalid entry in configuration file : " << line << endl;
+			break;
+		}
+	}
+	file.close();
+	return setList;
+}
+
+std::pair<string, string> SymbolSetReader::parseLine(string line) {
+	size_t delimeterPosition = line.find('=');
+
+	if (delimeterPosition != std::string::npos) {
+		string key = line.substr(0, delimeterPosition);
+		string value = line.substr(delimeterPosition + 1);
+		return {trim(key), trim(value)};
+	}
+
+	return {"",""};
+}
+
+string& SymbolSetReader::trim(string& str) {
+	// trim trailing spaces
+	size_t endpos = str.find_last_not_of(" \t\n\r");
+	if (string::npos != endpos) {
+		str = str.substr(0, endpos + 1);
+	}
+
+	// trim leading spaces
+	size_t startpos = str.find_first_not_of(" \t\n\r");
+	if (string::npos != startpos) {
+		str = str.substr(startpos);
+	}
+
+	return str;
+}
+
+} /* namespace Symbols */
diff --git a/tester/covoar/SymbolSetReader.h b/tester/covoar/SymbolSetReader.h
new file mode 100644
index 0000000..24e83cf
--- /dev/null
+++ b/tester/covoar/SymbolSetReader.h
@@ -0,0 +1,34 @@
+/*
+ * SymbolSetReader.h
+ *
+ *  Created on: Aug 5, 2014
+ *      Author: Krzysztof Mięsowicz <krzysztof.miesowicz at gmail.com>
+ */
+
+#ifndef SYMBOLSETREADER_H_
+#define SYMBOLSETREADER_H_
+
+#include <string>
+#include <vector>
+#include <utility>
+#include "SymbolSet.h"
+
+using namespace std;
+
+namespace Symbols {
+
+class SymbolSetReader {
+public:
+	SymbolSetReader();
+	virtual ~SymbolSetReader();
+
+	vector<SymbolSet> readSetFile(string filepath);
+protected:
+	pair<string, string> parseLine(string line);
+private:
+	string& trim(string& str);
+};
+
+} /* namespace Symbols */
+
+#endif /* SYMBOLSETREADER_H_ */
diff --git a/tester/covoar/covoar.cc b/tester/covoar/covoar.cc
index c36b00a..9d00428 100644
--- a/tester/covoar/covoar.cc
+++ b/tester/covoar/covoar.cc
@@ -22,6 +22,8 @@
 #include "ReportsBase.h"
 #include "TargetFactory.h"
 #include "GcovData.h"
+#include "SymbolSetReader.h"
+#include "SymbolSet.h"
 
 #include "rld-process.h"
 
@@ -44,6 +46,7 @@ std::list<Coverage::ExecutableInfo*> executablesToAnalyze;
 const char*                          explanations = NULL;
 char*                                progname;
 const char*                          symbolsFile = NULL;
+const char*                          symbolSetFile = NULL;
 const char*                          gcnosFileName = NULL;
 char                                 gcnoFileName[FILE_NAME_LENGTH];
 char                                 gcdaFileName[FILE_NAME_LENGTH];
@@ -51,7 +54,7 @@ char                                 gcovBashCommand[256];
 const char*                          target = NULL;
 const char*                          format = NULL;
 FILE*                                gcnosFile = NULL;
-Gcov::GcovData*          gcovFile;
+Gcov::GcovData*                      gcovFile;
 
 /*
  *  Print program usage message
@@ -70,13 +73,15 @@ void usage()
            "(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 symbol_sets.cfg\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
@@ -134,6 +139,7 @@ int main(
   const char*                                    singleExecutable = NULL;
   rld::process::tempfile                         objdumpFile( ".dmp" );
   rld::process::tempfile                         err( ".err" );
+  rld::process::tempfile                         syms( ".syms" );
   bool                                           debug = false;
   std::string                                    option;
 
@@ -144,7 +150,7 @@ int main(
   //
   progname = 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:v:d")) != -1) {
     switch (opt) {
       case '1': singleExecutable      = optarg; break;
       case 'L': dynamicLibrary        = optarg; break;
@@ -154,6 +160,7 @@ int main(
       case 'E': explanations          = optarg; break;
       case 'f': format                = optarg; break;
       case 's': symbolsFile           = optarg; break;
+      case 'S': symbolSetFile         = optarg; break;
       case 'T': target                = optarg; break;
       case 'O': outputDirectory       = optarg; break;
       case 'v': Verbose               = true;   break;
@@ -187,6 +194,14 @@ int main(
     }
 
     /*
+     * Validate that we have a symbols of interest file.
+     */
+     if ( !symbolSetFile ) {
+       option = "symbol set file -S";
+       throw option;
+    }
+
+    /*
      * Has path to explanations.txt been specified.
      */
     if ( !explanations ) {
@@ -354,14 +369,34 @@ int main(
 
   // 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()
-    );
+
+  if ( symbolsFile ) {
+    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 ( symbolSetFile ) {
+     std::cout << "Reading configuration symbol set file: " << symbolSetFile
+               << std::endl;
+     Symbols::SymbolSetReader ssr;
+     std::vector<Symbols::SymbolSet> symbolSets = ssr.readSetFile( symbolSetFile );
+     Symbols::SymbolSet& set = symbolSets[0];
+     std::cout << "Generating symbol file for " + set.getName() << std::endl;
+     set.generateSymbolFile( syms, target );
+     SymbolsToAnalyze->load( syms.name().c_str() );
+   }
+   if ( Verbose )
+     std::cout << "Analyzing " + SymbolsToAnalyze->set.size()
+               << "symbols" << std::endl;
 
   // Create explanations.
   AllExplanations = new Coverage::Explanations();
@@ -524,6 +559,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..1cda734 100644
--- a/tester/covoar/wscript
+++ b/tester/covoar/wscript
@@ -104,7 +104,9 @@ def build(bld):
                         'Target_lm32.cc',
                         'Target_m68k.cc',
                         'Target_powerpc.cc',
-                        'Target_sparc.cc'],
+                        'Target_sparc.cc',
+                        'SymbolSet.cpp',
+                        'SymbolSetReader.cpp'],
               cflags = ['-O2', '-g'],
               cxxflags = ['-std=c++11', '-O2', '-g'],
               includes = ['.'] + rtl_includes)
-- 
2.7.4



More information about the devel mailing list