ROSE 0.11.145.192
ConcolicExecutor.h
1#ifndef ROSE_BinaryAnalysis_Concolic_ConcolicExecutor_H
2#define ROSE_BinaryAnalysis_Concolic_ConcolicExecutor_H
3#include <featureTests.h>
4#ifdef ROSE_ENABLE_CONCOLIC_TESTING
5#include <Rose/BinaryAnalysis/Concolic/Settings.h>
6
7#include <Rose/BinaryAnalysis/BasicTypes.h>
8#include <Rose/Yaml.h>
9
10#include <Sawyer/CommandLine.h>
11#include <Sawyer/FileSystem.h>
12
13#include <ostream>
14#include <string>
15#include <vector>
16
17namespace Rose {
18namespace BinaryAnalysis {
19namespace Concolic {
20
22// Concolic executor.
24
28class ConcolicExecutor: public Sawyer::SharedObject {
29public:
32
34 struct FunctionCall {
35 std::string printableName;
36 rose_addr_t sourceVa;
37 rose_addr_t targetVa;
38 rose_addr_t stackVa;
40 FunctionCall()
41 : sourceVa(0), targetVa(0), stackVa(0) {}
42
43 FunctionCall(const std::string &printableName, rose_addr_t sourceVa, rose_addr_t targetVa, rose_addr_t stackVa)
44 : printableName(printableName), sourceVa(sourceVa), targetVa(targetVa), stackVa(stackVa) {}
45 };
46
47private:
48 ConcolicExecutorSettings settings_;
49 std::vector<FunctionCall> functionCallStack_;
51
52 // These can be configured by the user before calling configureExecution.
53 SmtSolverPtr solver_; // solver used during execution
54
55 // These are initialized by configureExecution
56 TestCasePtr testCase_; // currently executing test case
57 TestCaseId testCaseId_; // database ID for currently executing test case
58 DatabasePtr db_; // database for all this stuff
59 Partitioner2::PartitionerPtr partitioner_; // used during execution
60 ArchitecturePtr process_; // the concrete half of the execution
61 Emulation::DispatcherPtr cpu_; // the symbolic half of the execution
62
63protected:
64 ConcolicExecutor();
65
66public:
67 ~ConcolicExecutor();
68
69public:
71 static Ptr instance();
72
81 const ConcolicExecutorSettings& settings() const;
82 ConcolicExecutorSettings& settings();
83 void settings(const ConcolicExecutorSettings&);
95 SmtSolverPtr solver() const;
96 void solver(const SmtSolverPtr&);
104 DatabasePtr database() const;
105
111 TestCasePtr testCase() const;
112
118 TestCaseId testCaseId() const;
119
125 Partitioner2::PartitionerConstPtr partitioner() const;
126
132 ArchitecturePtr process() const;
133
139 Emulation::DispatcherPtr cpu() const;
140
148 static std::vector<Sawyer::CommandLine::SwitchGroup> commandLineSwitches(ConcolicExecutorSettings &settings /*in,out*/);
149
157 void configureExecution(const DatabasePtr&, const TestCasePtr&, const Yaml::Node &config);
158
165 std::vector<TestCasePtr> execute();
166 std::vector<TestCasePtr> execute(const DatabasePtr&, const TestCasePtr&, const Yaml::Node &config);
169private:
170 // Disassemble the specimen and cache the result in the database. If the specimen has previously been disassembled
171 // then reconstitute the analysis results from the database.
172 Partitioner2::PartitionerPtr partition(const SpecimenPtr&, const ArchitecturePtr&);
173
174 // Create the dispatcher, operators, and memory and register state for the symbolic execution.
175 Emulation::DispatcherPtr makeDispatcher(const ArchitecturePtr&);
176
177 // Create the underlying process and possibly fast forward it to the state at which it was when the test case was created.
178 void startProcess();
179
180 // Start up the symbolic part of the testing. This must happen after startProcess.
181 void startDispatcher();
182
183 // Run the execution
184 void run();
185
186 // Handle function calls. This is mainly for debugging so we have some idea where we are in the execution when an error
187 // occurs. Returns true if the call stack changed.
188 bool updateCallStack(SgAsmInstruction*);
189
190 // Print function call stack on multiple lines
191 void printCallStack(std::ostream&);
192
193 // Handle conditional branches
194 void handleBranch(SgAsmInstruction*);
195
196 // Generae a new test case. This must be called only after the SMT solver's assertions have been checked and found
197 // to be satisfiable.
198 void generateTestCase(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SymbolicExpression::Ptr &childIp);
199
200 // Save the specified symbolic state to the specified test case.
201 void saveSymbolicState(const Emulation::RiscOperatorsPtr&, const TestCaseId&);
202
203 // True if the two test cases are close enough that we only need to run one of them.
204 bool areSimilar(const TestCasePtr&, const TestCasePtr&) const;
205
206public:
207 // TODO: Lots of properties to control the finer aspects of executing a test case!
208};
209
210} // namespace
211} // namespace
212} // namespace
213
214#endif
215#endif
Create a temporary directory.
Base class for reference counted objects.
Reference-counting intrusive smart pointer.
Base class for machine instructions.
Sawyer::SharedPointer< Node > Ptr
Reference counting pointer.
Sawyer::CommandLine::SwitchGroup commandLineSwitches(Settings &settings)
Command-line switches for unparser settings.
std::shared_ptr< SmtSolver > SmtSolverPtr
Reference counting pointer.
The ROSE library.
Settings settings
Command-line settings for the rosebud tool.