[rtems-tools commit] covoar: Use rld tempfile and add signals to clean up in event of crash.

Chris Johns chrisj at rtems.org
Tue Aug 29 08:10:13 UTC 2017


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

Author:    Cillian O'Donnell <cpodonnell8 at gmail.com>
Date:      Sat Aug 26 09:15:56 2017 +0100

covoar: Use rld tempfile and add signals to clean up in event of crash.

Use rld tempfile for temporary files and add fatal signal handling to clean
them up in the event of a crash.

---

 tester/covoar/ObjdumpProcessor.cc   | 168 +++++++++++++++++-------------------
 tester/covoar/ObjdumpProcessor.h    |  30 ++++---
 tester/covoar/TraceConverter.cc     |  60 ++++++++++---
 tester/covoar/TraceReaderLogQEMU.cc |   9 +-
 tester/covoar/TraceReaderLogQEMU.h  |   2 +
 tester/covoar/TraceWriterQEMU.cc    |  10 +--
 tester/covoar/TraceWriterQEMU.h     |   2 +
 tester/covoar/covoar.cc             |  55 +++++++++++-
 8 files changed, 206 insertions(+), 130 deletions(-)

diff --git a/tester/covoar/ObjdumpProcessor.cc b/tester/covoar/ObjdumpProcessor.cc
index 01692b8..b916984 100644
--- a/tester/covoar/ObjdumpProcessor.cc
+++ b/tester/covoar/ObjdumpProcessor.cc
@@ -21,6 +21,9 @@
 #include "SymbolTable.h"
 #include "TargetFactory.h"
 
+#include "rld.h"
+#include "rld-process.h"
+
 namespace Coverage {
 
   void finalizeSymbol(
@@ -231,49 +234,33 @@ namespace Coverage {
     return TargetInfo->isNopLine( line, size );
   }
 
-  FILE* ObjdumpProcessor::getFile( std::string fileName )
+  void ObjdumpProcessor::getFile(
+    std::string fileName,
+    rld::process::tempfile& objdumpFile,
+    rld::process::tempfile& err
+    )
   {
-    char               dumpFile[128];
-    FILE*              objdumpFile;
-    char               buffer[ 512 ];
-    int                status;
-
-    sprintf( dumpFile, "%s.dmp", fileName.c_str() );
-
-    // Generate the objdump.
-    if (FileIsNewer( fileName.c_str(), dumpFile )) {
-      sprintf(
-        buffer,
-        "%s -Cda --section=.text --source %s | sed -e \'s/ *$//\' >%s",
-        TargetInfo->getObjdump(),
-        fileName.c_str(),
-        dumpFile
-      );
-
-      status = system( buffer );
-      if (status) {
-        fprintf(
-          stderr,
-          "ERROR: ObjdumpProcessor::getFile - command (%s) failed with %d\n",
-          buffer,
-          status
-        );
-        exit( -1 );
+    rld::process::status        status;
+    rld::process::arg_container args = { TargetInfo->getObjdump(),
+                                         "-Cda", "--section=.text", "--source",
+                                         fileName };
+    try
+    {
+      status = rld::process::execute( TargetInfo->getObjdump(),
+               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 << err.what << " in " << err.where << std::endl;
+        return;
       }
-    }
-
-    // Open the objdump file.
-    objdumpFile = fopen( dumpFile, "r" );
-    if (!objdumpFile) {
-      fprintf(
-        stderr,
-        "ERROR: ObjdumpProcessor::getFile - unable to open %s\n",
-        dumpFile
-      );
-      exit(-1);
-    }
 
-    return objdumpFile;
+    objdumpFile.open( true );
   }
 
   uint32_t ObjdumpProcessor::getAddressAfter( uint32_t address )
@@ -295,40 +282,40 @@ namespace Coverage {
   }
 
   void ObjdumpProcessor::loadAddressTable (
-    ExecutableInfo* const executableInformation
+    ExecutableInfo* const    executableInformation,
+    rld::process::tempfile&  objdumpFile,
+    rld::process::tempfile&  err
   )
   {
-    char*              cStatus;
-    int                items;
-    FILE*              objdumpFile;
-    uint32_t           offset;
-    char               terminator;
+    int          items;
+    uint32_t     offset;
+    char         terminator;
+    std::string  line;
 
     // Obtain the objdump file.
-    if (!executableInformation->hasDynamicLibrary())
-      objdumpFile = getFile( executableInformation->getFileName() );
+    if ( !executableInformation->hasDynamicLibrary() )
+      getFile( executableInformation->getFileName(), objdumpFile, err );
     else
-      objdumpFile = getFile( executableInformation->getLibraryName() );
+      getFile( executableInformation->getLibraryName(), objdumpFile, err );
 
     // Process all lines from the objdump file.
-    while ( 1 ) {
+    while ( true ) {
 
       // Get the line.
-      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile );
-      if (cStatus == NULL) {
+      objdumpFile.read_line( line );
+      if ( line.empty() ) {
         break;
       }
-      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
 
       // See if it is the dump of an instruction.
       items = sscanf(
-        inputBuffer,
+        line.c_str(),
         "%x%c",
         &offset, &terminator
       );
 
       // If it looks like an instruction ...
-      if ((items == 2) && (terminator == ':')){
+      if ((items == 2) && (terminator == ':')) {
         objdumpList.push_back(
           executableInformation->getLoadAddress() + offset
         );
@@ -337,42 +324,42 @@ namespace Coverage {
   }
 
   void ObjdumpProcessor::load(
-    ExecutableInfo* const executableInformation
+    ExecutableInfo* const    executableInformation,
+    rld::process::tempfile&  objdumpFile,
+    rld::process::tempfile&  err
   )
   {
-    char*              cStatus;
-    std::string        currentSymbol = "";
-    uint32_t           endAddress;
-    uint32_t           instructionOffset;
-    int                items;
-    int                found;
-    objdumpLine_t      lineInfo;
-    FILE*              objdumpFile;
-    uint32_t           offset;
-    bool               processSymbol = false;
-    uint32_t           startAddress = 0;
-    char               symbol[ MAX_LINE_LENGTH ];
-    char               terminator1;
-    char               terminatorOne;
-    char               terminator2;
-    objdumpLines_t     theInstructions;
-    char               instruction[ MAX_LINE_LENGTH ];
-    char               ID[ MAX_LINE_LENGTH ];
-    std::string        call = "";
-    std::string        jumpTableID = "";
+    std::string     currentSymbol = "";
+    uint32_t        endAddress;
+    uint32_t        instructionOffset;
+    int             items;
+    int             found;
+    objdumpLine_t   lineInfo;
+    uint32_t        offset;
+    bool            processSymbol = false;
+    uint32_t        startAddress = 0;
+    char            symbol[ MAX_LINE_LENGTH ];
+    char            terminator1;
+    char            terminatorOne;
+    char            terminator2;
+    objdumpLines_t  theInstructions;
+    char            instruction[ MAX_LINE_LENGTH ];
+    char            ID[ MAX_LINE_LENGTH ];
+    std::string     call = "";
+    std::string     jumpTableID = "";
+    std::string     line = "";
 
     // Obtain the objdump file.
-    if (!executableInformation->hasDynamicLibrary())
-      objdumpFile = getFile( executableInformation->getFileName() );
+    if ( !executableInformation->hasDynamicLibrary() )
+      getFile( executableInformation->getFileName(), objdumpFile, err );
     else
-      objdumpFile = getFile( executableInformation->getLibraryName() );
+      getFile( executableInformation->getLibraryName(), objdumpFile, err );
 
-    // Process all lines from the objdump file.
-    while ( 1 ) {
+    while ( true ) {
 
       // Get the line.
-      cStatus = fgets( inputBuffer, MAX_LINE_LENGTH, objdumpFile );
-      if (cStatus == NULL) {
+      objdumpFile.read_line( line );
+      if ( line.empty() ) {
 
         // If we are currently processing a symbol, finalize it.
         if (processSymbol) {
@@ -393,12 +380,11 @@ namespace Coverage {
             executableInformation->getFileName().c_str()
           );
         }
+        objdumpFile.close();
         break;
       }
 
-      inputBuffer[ strlen(inputBuffer) - 1] = '\0';
-
-      lineInfo.line          = inputBuffer;
+      lineInfo.line          = line;
       lineInfo.address       = 0xffffffff;
       lineInfo.isInstruction = false;
       lineInfo.isNop         = false;
@@ -408,14 +394,14 @@ namespace Coverage {
       // Look for the start of a symbol's objdump and extract
       // offset and symbol (i.e. offset <symbolname>:).
       items = sscanf(
-        inputBuffer,
+        line.c_str(),
         "%x <%[^>]>%c",
         &offset, symbol, &terminator1
       );
 
       // See if it is a jump table.
       found = sscanf(
-        inputBuffer,
+        line.c_str(),
         "%x%c\t%*[^\t]%c%s %*x %*[^+]%s",
         &instructionOffset, &terminatorOne, &terminator2, instruction, ID
       );
@@ -477,7 +463,7 @@ namespace Coverage {
 
         // See if it is the dump of an instruction.
         items = sscanf(
-          inputBuffer,
+          line.c_str(),
           "%x%c\t%*[^\t]%c",
           &instructionOffset, &terminator1, &terminator2
         );
@@ -489,8 +475,8 @@ namespace Coverage {
           lineInfo.address =
            executableInformation->getLoadAddress() + instructionOffset;
           lineInfo.isInstruction = true;
-          lineInfo.isNop         = isNop( inputBuffer, lineInfo.nopSize );
-          lineInfo.isBranch      = isBranchLine( inputBuffer );
+          lineInfo.isNop         = isNop( line.c_str(), lineInfo.nopSize );
+          lineInfo.isBranch      = isBranchLine( line.c_str() );
         }
 
         // Always save the line.
diff --git a/tester/covoar/ObjdumpProcessor.h b/tester/covoar/ObjdumpProcessor.h
index 283ac73..c75755d 100644
--- a/tester/covoar/ObjdumpProcessor.h
+++ b/tester/covoar/ObjdumpProcessor.h
@@ -13,6 +13,8 @@
 #include "ExecutableInfo.h"
 #include "TargetBase.h"
 
+#include "rld-process.h"
+
 namespace Coverage {
 
   /*! @class ObjdumpProcessor
@@ -74,11 +76,11 @@ namespace Coverage {
      */
     typedef std::list<objdumpLine_t> objdumpLines_t;
 
-   
+
     /*!
      *  This object defines a list of instruction addresses
      *  that will be extracted from the objdump file.
-     */ 
+     */
     typedef std::list<uint32_t> objdumpFile_t;
 
     /*!
@@ -96,17 +98,21 @@ namespace Coverage {
     );
 
     /*!
-     *  This method returns a file pointer to the objdump file
-     *  for the given file name.  
+     *  This method fills a tempfile with the .text section of objdump
+     *  for the given file name.
      */
-    FILE* getFile( std::string fileName ); 
+    void getFile( std::string fileName,
+                  rld::process::tempfile& dmp,
+                  rld::process::tempfile& err );
 
     /*!
-     *  This method fills the objdumpList list with all the 
+     *  This method fills the objdumpList list with all the
      *  instruction addresses in the object dump file.
      */
     void loadAddressTable (
-      ExecutableInfo* const executableInformation
+      ExecutableInfo* const executableInformation,
+      rld::process::tempfile& dmp,
+      rld::process::tempfile& err
     );
 
     /*!
@@ -114,23 +120,25 @@ namespace Coverage {
      *  the specified executable.
      */
     void load(
-      ExecutableInfo* const executableInformation
+      ExecutableInfo* const executableInformation,
+      rld::process::tempfile& dmp,
+      rld::process::tempfile& err
     );
 
     /*!
-     *  This method returns the next address in othe objdumpList.
+     *  This method returns the next address in the objdumpList.
      */
     uint32_t getAddressAfter( uint32_t address );
 
     /*!
-     *  This method returns true if the instrucation is
+     *  This method returns true if the instruction is
      *  an instruction that results in a code branch, otherwise
      *  it returns false.
      */
     bool IsBranch( const char *instruction );
 
     /*!
-     *  This method returns true if the instruction from 
+     *  This method returns true if the instruction from
      *  the given line in the objdmp file is a branch instruction,
      *  otherwise it returns false.
      */
diff --git a/tester/covoar/TraceConverter.cc b/tester/covoar/TraceConverter.cc
index 0f7a44e..22b0f81 100644
--- a/tester/covoar/TraceConverter.cc
+++ b/tester/covoar/TraceConverter.cc
@@ -10,9 +10,10 @@
 #include <sys/stat.h>
 #include <string.h>
 #include <getopt.h>
+#include <signal.h>
+#include <unistd.h>
 
 #include "qemu-log.h"
-
 #include "TraceReaderLogQEMU.h"
 #include "TraceWriterQEMU.h"
 #include "TraceList.h"
@@ -20,6 +21,9 @@
 #include "app_common.h"
 #include "TargetFactory.h"
 
+#include "rld.h"
+#include "rld-process.h"
+
 char*       progname;
 
 void usage()
@@ -32,6 +36,40 @@ void usage()
   exit(1);
 }
 
+static void
+fatal_signal( int signum )
+{
+  signal( signum, SIG_DFL );
+
+  rld::process::temporaries_clean_up();
+
+  /*
+   * Get the same signal again, this time not handled, so its normal effect
+   * occurs.
+   */
+  kill( getpid(), signum );
+}
+
+static void
+setup_signals( void )
+{
+  if ( signal (SIGINT, SIG_IGN) != SIG_IGN )
+    signal( SIGINT, fatal_signal );
+#ifdef SIGHUP
+  if ( signal( SIGHUP, SIG_IGN ) != SIG_IGN )
+    signal( SIGHUP, fatal_signal );
+#endif
+  if ( signal( SIGTERM, SIG_IGN ) != SIG_IGN )
+    signal( SIGTERM, fatal_signal );
+#ifdef SIGPIPE
+  if ( signal( SIGPIPE, SIG_IGN ) != SIG_IGN )
+    signal( SIGPIPE, fatal_signal );
+#endif
+#ifdef SIGCHLD
+  signal( SIGCHLD, SIG_DFL );
+#endif
+}
+
 int main(
   int    argc,
   char** argv
@@ -45,10 +83,14 @@ int main(
   const char                  *tracefile  =  "";
   const char                  *logname = "/tmp/qemu.log";
   Coverage::ExecutableInfo*    executableInfo;
-   
-  //
-  // Process command line options.
-  //
+  rld::process::tempfile       objdumpFile( ".dmp" );
+  rld::process::tempfile       err( ".err" );
+
+  setup_signals();
+
+   //
+   // Process command line options.
+   //
   progname = argv[0];
 
   while ((opt = getopt(argc, argv, "c:e:l:L:t:v")) != -1) {
@@ -88,17 +130,13 @@ int main(
     executableInfo = new Coverage::ExecutableInfo( executable );
 
   objdumpProcessor = new Coverage::ObjdumpProcessor();
- 
+
   // If a dynamic library was specified, determine the load address.
   if (dynamicLibrary)
     executableInfo->setLoadAddress(
       objdumpProcessor->determineLoadAddress( executableInfo )
     );
-
-  objdumpProcessor->loadAddressTable( executableInfo );
-
+  objdumpProcessor->loadAddressTable( executableInfo, objdumpFile, err );
   log.processFile( logname );
-
   trace.writeFile( tracefile, &log );
-
 }
diff --git a/tester/covoar/TraceReaderLogQEMU.cc b/tester/covoar/TraceReaderLogQEMU.cc
index 2250d2b..508074a 100644
--- a/tester/covoar/TraceReaderLogQEMU.cc
+++ b/tester/covoar/TraceReaderLogQEMU.cc
@@ -35,25 +35,20 @@
  *  reading the QEMU coverage data files.
  */
 
-#include "covoar-config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
 #include <string.h>
 
 #include "qemu-log.h"
-
 #include "app_common.h"
 #include "TraceReaderBase.h"
 #include "TraceReaderLogQEMU.h"
 #include "TraceList.h"
-
-/* XXX really not always right */
-typedef uint32_t target_ulong;
-
 #include "qemu-traces.h"
 
+#include "rld-process.h"
+
 #if HAVE_STAT64
 #define STAT stat64
 #else
diff --git a/tester/covoar/TraceReaderLogQEMU.h b/tester/covoar/TraceReaderLogQEMU.h
index c4877fd..e7b03f0 100644
--- a/tester/covoar/TraceReaderLogQEMU.h
+++ b/tester/covoar/TraceReaderLogQEMU.h
@@ -9,6 +9,8 @@
 
 #include "TraceReaderBase.h"
 
+#include "rld-process.h"
+
 namespace Trace {
 
   /*! @class TraceReaderLogQEMU
diff --git a/tester/covoar/TraceWriterQEMU.cc b/tester/covoar/TraceWriterQEMU.cc
index 29ad2b9..9a8affc 100644
--- a/tester/covoar/TraceWriterQEMU.cc
+++ b/tester/covoar/TraceWriterQEMU.cc
@@ -34,8 +34,6 @@
  *  reading the QEMU coverage data files.
  */
 
-#include "covoar-config.h"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
@@ -44,12 +42,10 @@
 #include "TraceWriterQEMU.h"
 #include "ExecutableInfo.h"
 #include "CoverageMap.h"
-
-/* XXX really not always right */
-typedef uint32_t target_ulong;
-
 #include "qemu-traces.h"
 
+#include "rld-process.h"
+
 #if HAVE_STAT64
 #define STAT stat64
 #else
@@ -167,7 +163,7 @@ namespace Trace {
 
       status = fwrite( &entry, sizeof(entry), 1, traceFile );
       if (status != 1) {
-        fprintf( stderr, "Unable to emtry to %s\n", file );
+        fprintf( stderr, "Unable to write entry to %s\n", file );
         return false;
       }
     }
diff --git a/tester/covoar/TraceWriterQEMU.h b/tester/covoar/TraceWriterQEMU.h
index 3b1c254..254c292 100644
--- a/tester/covoar/TraceWriterQEMU.h
+++ b/tester/covoar/TraceWriterQEMU.h
@@ -11,6 +11,8 @@
 #include "TraceReaderBase.h"
 #include "TraceWriterBase.h"
 
+#include "rld-process.h"
+
 namespace Trace {
 
   /*! @class TraceWriterQEMU
diff --git a/tester/covoar/covoar.cc b/tester/covoar/covoar.cc
index a3f137e..005cb8e 100644
--- a/tester/covoar/covoar.cc
+++ b/tester/covoar/covoar.cc
@@ -23,6 +23,8 @@
 #include "TargetFactory.h"
 #include "GcovData.h"
 
+#include "rld-process.h"
+
 /*
  *  Variables to control general behavior
  */
@@ -45,7 +47,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
@@ -146,6 +148,40 @@ void check_configuration(void)
     coverageFormat = Coverage::CoverageFormatToEnum( format );
 }
 
+static void
+fatal_signal( int signum )
+{
+  signal( signum, SIG_DFL );
+
+  rld::process::temporaries_clean_up();
+
+  /*
+   * Get the same signal again, this time not handled, so its normal effect
+   * occurs.
+   */
+  kill( getpid(), signum );
+}
+
+static void
+setup_signals( void )
+{
+  if ( signal( SIGINT, SIG_IGN ) != SIG_IGN )
+    signal( SIGINT, fatal_signal );
+#ifdef SIGHUP
+  if ( signal( SIGHUP, SIG_IGN ) != SIG_IGN )
+    signal( SIGHUP, fatal_signal );
+#endif
+  if ( signal( SIGTERM, SIG_IGN ) != SIG_IGN )
+    signal( SIGTERM, fatal_signal );
+#ifdef SIGPIPE
+  if ( signal( SIGPIPE, SIG_IGN ) != SIG_IGN )
+    signal( SIGPIPE, fatal_signal );
+#endif
+#ifdef SIGCHLD
+  signal( SIGCHLD, SIG_DFL );
+#endif
+}
+
 int main(
   int    argc,
   char** argv
@@ -158,6 +194,11 @@ int main(
   int                                            i;
   int                                            opt;
   const char*                                    singleExecutable = NULL;
+  rld::process::tempfile                         objdumpFile( ".dmp" );
+  rld::process::tempfile                         err( ".err" );
+  bool                                           debug = false;
+
+  setup_signals();
 
   CoverageConfiguration = new Configuration::FileReader(Options);
 
@@ -166,7 +207,7 @@ int main(
   //
   progname = argv[0];
 
-  while ((opt = getopt(argc, argv, "C:1:L:e:c:g:E:f:s:T:O:p:v")) != -1) {
+  while ((opt = getopt(argc, argv, "C:1:L:e:c:g:E:f:s:T:O:p:v:d")) != -1) {
     switch (opt) {
       case 'C': CoverageConfiguration->processFile( optarg ); break;
       case '1': singleExecutable      = optarg; break;
@@ -181,6 +222,7 @@ int main(
       case 'O': outputDirectory       = optarg; break;
       case 'v': Verbose               = true;   break;
       case 'p': projectName           = optarg; break;
+      case 'd': debug                 = true;   break;
       default: /* '?' */
         usage();
         exit( -1 );
@@ -394,7 +436,7 @@ int main(
       );
 
     // Load the objdump for the symbols in this executable.
-    objdumpProcessor->load( *eitr );
+    objdumpProcessor->load( *eitr, objdumpFile, err );
   }
 
   //
@@ -503,5 +545,12 @@ int main(
     AllExplanations->writeNotFound( notFound.c_str() );
   }
 
+  //Leave tempfiles around if debug flag (-d) is enabled.
+  if ( debug ) {
+	objdumpFile.override( "objdump_file" );
+	objdumpFile.keep();
+	err.override( "objdump_exec_log" );
+	err.keep();
+  }
   return 0;
 }




More information about the vc mailing list