ROSE  0.9.10.91
BinaryConcolic.h
1 #ifndef ROSE_BinaryAnalysis_Concolic_H
2 #define ROSE_BinaryAnalysis_Concolic_H
3 
4 #include <boost/filesystem.hpp>
5 #include <boost/serialization/access.hpp>
6 #include <boost/serialization/nvp.hpp>
7 #include <Sawyer/BiMap.h>
8 #include <Sawyer/SharedObject.h>
9 #include <Sawyer/SharedPointer.h>
10 #include <Sawyer/Synchronization.h>
11 #include <memory>
12 #include <rose_isnan.h>
13 #include <stdexcept>
14 #include <string>
15 #include <vector>
16 
17 namespace Rose {
18 namespace BinaryAnalysis {
19 
41 namespace Concolic {
42 
44 // Flags and enums
46 
47 namespace Update {
48 enum Flag { NO, YES };
49 } // namespace
50 
52 // Exceptions, errors, etc.
54 
55 extern Sawyer::Message::Facility mlog;
56 
58 class Exception: public std::runtime_error {
59 public:
60  explicit Exception(const std::string &mesg): std::runtime_error(mesg) {}
61  ~Exception() throw () {}
62 };
63 
64 
66 // Specimens
68 
71 public:
74 
75 private:
76  mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects the following data members
77  std::string name_; // name of specimen (e.g., for debugging)
78  std::vector<uint8_t> specimen_; // content of the binary executable file
79 
80 private:
81  friend class boost::serialization::access;
82 
83  template<class S>
84  void serialize(S &s, const unsigned /*version*/) {
85  s & BOOST_SERIALIZATION_NVP(specimen_);
86  }
87 
88 protected:
89  Specimen() {}
90 
91 public:
93  static Ptr instance(const boost::filesystem::path &executableName);
94 
101  void open(const boost::filesystem::path &executableName);
102 
109  void close();
110 
116  bool isEmpty() const { return specimen_.empty(); }
117 
126  std::string name() const; // value return is intentional for thread safety
127  void name(const std::string&);
129 };
130 
131 
133 // Test cases
135 
138 public:
141 
142 private:
143  mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects the following data members
144  std::string name_; // name for debugging
145  Specimen::Ptr specimen_; // the thing to run
146 
147 protected:
148  TestCase() {}
149 
150 public:
152  static Ptr instance() {
153  return Ptr(new TestCase);
154  }
155 
157  static Ptr instance(const Specimen::Ptr &specimen);
158 
167  std::string name() const; // value return is intentional for thread safety
168  void name(const std::string&);
178  Specimen::Ptr specimen() const;
179  void specimen(const Specimen::Ptr&);
181 };
182 
183 
185 // Concrete executors and their results
187 
199 public:
202 
213  class Result {
214  private:
215  double rank_;
216 
217  public:
218  explicit Result(double rank): rank_(rank) {
219  ASSERT_forbid(rose_isnan(rank));
220  }
221  virtual ~Result() {}
222 
223  private:
224  friend class boost::serialization::access;
225 
226  template<class S>
227  void serialize(S &s, const unsigned /*version*/) {
228  s & BOOST_SERIALIZATION_NVP(rank_);
229  }
230  };
231 
232 protected:
233  // Allocating constructors should be implemente by the non-abstract subclasses.
234  ConcreteExecutor() {}
235 
236 public:
241  virtual std::unique_ptr<Result> execute(const TestCase::Ptr&) = 0;
242 };
243 
244 
247 public:
250 
253  protected:
256  private:
257  friend class boost::serialization::access;
258 
259  template<class S>
260  void serialize(S &s, const unsigned /*version*/) {
261  s & BOOST_SERIALIZATION_BASE_OBJECT_NVP(ConcreteExecutor::Result);
262  s & BOOST_SERIALIZATION_NVP(exitStatus_);
263  }
264 
265  public:
266  Result(int exitStatus);
267 
275  int exitStatus() const { return exitStatus_; }
276  void exitStatus(int x) { exitStatus_ = x; }
278  };
279 
280 protected:
281  bool useAddressRandomization_; // enable/disable address space randomization in the OS
282 
283 protected:
284  LinuxExecutor()
285  : useAddressRandomization_(false) {}
286 
287 public:
289  static Ptr instance() {
290  return Ptr(new LinuxExecutor);
291  }
292 
299  bool useAddressRandomization() const { return useAddressRandomization_; }
300  void useAddressRandomization(bool b) { useAddressRandomization_ = b; }
303  virtual std::unique_ptr<ConcreteExecutor::Result> execute(const TestCase::Ptr&) ROSE_OVERRIDE;
304 };
305 
306 
308 // Symbolic executors
310 
312 public:
315 
316 protected:
317  SymbolicExecutor() {}
318 
319 public:
321  static Ptr instance() {
322  return Ptr(new SymbolicExecutor);
323  }
324 
328  std::vector<TestCase::Ptr> execute(const TestCase::Ptr&);
329 
330  // TODO: Lots of properties to control the finer aspects of executing a test case!
331 };
332 
333 
335 // Test suites
337 
347 public:
350 
351 private:
352  mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects the following data members
353  std::string name_; // unique and non-empty within a database
354 
355 protected:
356  TestSuite() {}
357 
358 public:
360  static Ptr instance(const std::string &name = "");
361 
370  std::string name() const; // value return is intentional for thread safety
371  void name(const std::string&);
373 };
374 
376 // Databases
378 
391 class Database: public Sawyer::SharedObject, boost::noncopyable {
392 public:
395 
398 
400  struct TestSuiteId: ObjectId {};
401 
403  struct SpecimenId: ObjectId {};
404 
406  struct TestCaseId: ObjectId {};
407 
408 private:
412  TestSuiteId testSuiteId_; // database scope is restricted to this single test suite
413 
414 protected:
415  Database() {}
416 
417 public:
421  static Ptr instance(const std::string &url);
422 
431  static Ptr create(const std::string &url, const std::string &testSuiteName);
432 
433  //------------------------------------------------------------------------------------------------------------------------
434  // Test suites
435  //------------------------------------------------------------------------------------------------------------------------
436 
441  std::vector<TestSuiteId> testSuites();
442 
450  TestSuite::Ptr testSuite();
451  TestSuiteId testSuite(const TestSuite::Ptr&);
454  //------------------------------------------------------------------------------------------------------------------------
455  // Specimens
456  //------------------------------------------------------------------------------------------------------------------------
457 
462  std::vector<SpecimenId> specimens();
463 
464  //------------------------------------------------------------------------------------------------------------------------
465  // Test cases
466  //------------------------------------------------------------------------------------------------------------------------
467 
472  std::vector<TestCaseId> testCases();
473 
474  //------------------------------------------------------------------------------------------------------------------------
475  // Overloaded methods for all objects.
476  //------------------------------------------------------------------------------------------------------------------------
477 
484  TestSuite::Ptr object(TestSuiteId, Update::Flag update = Update::YES);
485  TestCase::Ptr object(TestCaseId, Update::Flag update = Update::YES);
486  Specimen::Ptr object(SpecimenId, Update::Flag update = Update::YES);
497  TestSuiteId id(const TestSuite::Ptr&, Update::Flag update = Update::YES);
498  TestCaseId id(const TestCase::Ptr&, Update::Flag update = Update::YES);
499  SpecimenId id(const Specimen::Ptr&, Update::Flag update = Update::YES);
501 };
502 
503 
505 // Execution manager
507 
512 class ExecutionManager: boost::noncopyable, public Sawyer::SharedObject {
513 public:
516 
517 private:
518  Database::Ptr database_;
519 
520 protected:
521  // Subclasses should implement allocating constructors
522  explicit ExecutionManager(const Database::Ptr &db)
523  : database_(db) {
524  ASSERT_not_null(db);
525  }
526 
527 public:
528  virtual ~ExecutionManager() {}
529 
533  Database::Ptr database() const;
534 
541  virtual std::vector<Database::TestCaseId> pendingConcreteResults(size_t n = (size_t)(-1));
542  Database::TestCaseId pendingConcreteResult() /*final*/;
550  virtual void insertConcreteResults(const TestCase::Ptr&, const ConcreteExecutor::Result &details);
551 
558  virtual std::vector<Database::TestCaseId> pendingSymbolicResults(size_t n = (size_t)(-1));
559  Database::TestCaseId pendingSymbolicResult() /*final*/;
567  virtual void insertSymbolicResults(const TestCase::Ptr &original, const std::vector<TestCase::Ptr> &newCases);
568 
572  virtual bool isFinished() const;
573 
578  virtual void run() = 0;
579 };
580 
581 // Example execution manager...
582 
588 public:
591 
592 protected:
593  explicit LinuxExitStatus(const Database::Ptr &db): ExecutionManager(db) {}
594 
595 public:
600  static Ptr create(const std::string databaseUrl, const boost::filesystem::path &executableName,
601  const std::vector<std::string> &arguments);
602 
608  static Ptr instance(const std::string databaseUri, const std::string &testSuiteName = "");
609 
610  virtual void run() ROSE_OVERRIDE;
611 };
612 
613 } // namespace
614 } // namespace
615 } // namespace
616 #endif
int exitStatus_
Exit status as returned by waitpid[2].
SharedObject()
Default constructor.
Definition: SharedObject.h:28
Collection of streams.
Definition: Message.h:1579
bool useAddressRandomization() const
Property: Address space randomization.
Sawyer::SharedPointer< Database > Ptr
Reference counting pointer to Database.
static Ptr instance(const boost::filesystem::path &executableName)
Allocating constructor.
Sawyer::SharedPointer< ExecutionManager > Ptr
Reference counting pointer to an ExecutionManager.
static Ptr instance()
Allocating default constructor.
Main namespace for the ROSE library.
static Ptr instance()
Allocating constructor.
virtual std::unique_ptr< Result > execute(const TestCase::Ptr &)=0
Execute one test case synchronously.
One-to-one mapping between source and target values.
Definition: BiMap.h:26
void open(const boost::filesystem::path &executableName)
Open an executable file.
std::string name() const
Property: Specimen name.
Sawyer::SharedPointer< TestSuite > Ptr
Reference counting pointer to TestSuite.
Name space for the entire library.
Definition: Access.h:13
virtual std::unique_ptr< ConcreteExecutor::Result > execute(const TestCase::Ptr &) ROSE_OVERRIDE
Execute one test case synchronously.
Sawyer::SharedPointer< TestCase > Ptr
Reference counting pointer to a TestCase.
void useAddressRandomization(bool b)
Property: Address space randomization.
static Ptr instance()
Allcoating constructor.
Base class for exceptions for concolic testing.
Sawyer::SharedPointer< ConcreteExecutor > Ptr
Reference counting pointer to a ConcreteExecutor.
Base class for user-defined Linux concrete execution results.
Specimen::Ptr specimen() const
Property: Specimen.
Information about how to run a specimen.
Concolic teting of Linux executables.
int exitStatus() const
Property: Exit status of the executable.
void exitStatus(int x)
Property: Exit status of the executable.
Concrete executor for Linux ELF executables.
Base class for user-defined concrete execution results.
Sawyer::SharedPointer< Specimen > Ptr
Referenc-counting pointer to a Specimen.
bool isEmpty() const
Test whether this object is empty.
Sawyer::SharedPointer< LinuxExecutor > Ptr
Reference counting pointer to a LinuxExecutor.
void close()
Close the executable file.
Base class for managing an entire concolic testing run.
Base class for reference counted objects.
Definition: SharedObject.h:22
Sawyer::SharedPointer< SymbolicExecutor > Ptr
Reference counting pointer to SymbolicExecutor.
Sawyer::SharedPointer< LinuxExitStatus > Ptr
Reference counting pointer to LinuxExitStatus.
Sawyer::Optional< int > ObjectId
Base class for object IDs.
std::string name() const
Property: Test case name.
Base class for executing test cases concretely.