ROSE  0.11.145.0
PartitionerModel.h
1 #ifndef ROSE_BinaryAnalysis_ModelChecker_PartitionerModel_H
2 #define ROSE_BinaryAnalysis_ModelChecker_PartitionerModel_H
3 #include <featureTests.h>
4 #ifdef ROSE_ENABLE_MODEL_CHECKER
5 
6 #include <Rose/BinaryAnalysis/InstructionSemantics/SymbolicSemantics.h>
7 #include <Rose/BinaryAnalysis/ModelChecker/SemanticCallbacks.h>
8 #include <Rose/BinaryAnalysis/ModelChecker/Variables.h>
9 #include <Rose/BinaryAnalysis/Partitioner2/BasicTypes.h>
10 #include <Rose/BinaryAnalysis/Variables.h>
11 #include <Sawyer/CommandLine.h>
12 #include <Sawyer/Stack.h>
13 
14 namespace Rose {
15 namespace BinaryAnalysis {
16 namespace ModelChecker {
17 
26 namespace PartitionerModel {
27 
29 // Settings for this model checker
31 
33 struct Settings {
35  enum class MemoryType {
36  LIST,
37  MAP
38  };
39 
40  TestMode nullRead = TestMode::MUST;
41  TestMode nullWrite = TestMode::MUST;
42  TestMode oobRead = TestMode::OFF;
43  TestMode oobWrite = TestMode::OFF;
44  TestMode uninitVar = TestMode::OFF;
45  rose_addr_t maxNullAddress = 4095;
46  bool debugNull = false;
47  Sawyer::Optional<rose_addr_t> initialStackVa;
48  MemoryType memoryType = MemoryType::MAP;
49  bool solverMemoization = false;
50  bool traceSemantics = false;
51 };
52 
53 class SemanticCallbacks;
54 
58 void commandLineDebugSwitches(Sawyer::CommandLine::SwitchGroup&, Settings&);
59 
64 Sawyer::CommandLine::SwitchGroup commandLineModelSwitches(Settings&);
65 
71 
73 // Function call stack
75 
77 class FunctionCall {
78  Partitioner2::FunctionPtr function_;
79  rose_addr_t initialStackPointer_ = 0;
80  rose_addr_t framePointerDelta_ = (rose_addr_t)(-4); // Normal frame pointer w.r.t. initial stack pointer
81  Sawyer::Optional<rose_addr_t> returnAddress_;
82  Variables::StackVariables stackVariables_;
83 
84 public:
85  ~FunctionCall();
86  FunctionCall(const Partitioner2::FunctionPtr&, rose_addr_t initialSp, Sawyer::Optional<rose_addr_t> returnAddress,
88 
90  Partitioner2::FunctionPtr function() const;
91 
95  rose_addr_t initialStackPointer() const;
96 
98  const Variables::StackVariables& stackVariables() const;
99 
105  rose_addr_t framePointerDelta() const;
106  void framePointerDelta(rose_addr_t);
112  rose_addr_t framePointer(size_t nBits) const;
113 
117  Sawyer::Optional<rose_addr_t> returnAddress() const;
118  void returnAddress(Sawyer::Optional<rose_addr_t>);
122  std::string printableName(size_t nBits) const;
123 };
124 
128 using FunctionCallStack = Sawyer::Container::Stack<FunctionCall>;
129 
131 // Instruction semantics value
133 
137 class SValue: public InstructionSemantics::SymbolicSemantics::SValue {
138 public:
140  using Super = InstructionSemantics::SymbolicSemantics::SValue;
141 
143  using Ptr = SValuePtr;
144 
145 private:
146  AddressInterval region_;
147 
148 #ifdef ROSE_HAVE_BOOST_SERIALIZATION_LIB
149 private:
150  friend class boost::serialization::access;
151 
152  template<class S>
153  void serialize(S &s, const unsigned /*version*/) {
154  s & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Super);
155  s & BOOST_SERIALIZATION_NVP(region_);
156  }
157 #endif
158 
159 public:
160  ~SValue();
161 
162 protected:
163  SValue();
164 
165  SValue(size_t nBits, uint64_t number);
166 
167  explicit SValue(const SymbolicExpression::Ptr&);
168 
169 public:
173  static Ptr instance();
174 
176  static Ptr instanceBottom(size_t nBits);
177 
179  static Ptr instanceUndefined(size_t nBits);
180 
182  static Ptr instanceUnspecified(size_t nBits);
183 
185  static Ptr instanceInteger(size_t nBits, uint64_t value);
186 
188  static Ptr instanceSymbolic(const SymbolicExpression::Ptr &value);
189 
190 public:
191  virtual InstructionSemantics::BaseSemantics::SValuePtr bottom_(size_t nBits) const override {
192  return instanceBottom(nBits);
193  }
194 
195  virtual InstructionSemantics::BaseSemantics::SValuePtr undefined_(size_t nBits) const override {
196  return instanceUndefined(nBits);
197  }
198 
199  virtual InstructionSemantics::BaseSemantics::SValuePtr unspecified_(size_t nBits) const override {
200  return instanceUnspecified(nBits);
201  }
202 
203  virtual InstructionSemantics::BaseSemantics::SValuePtr number_(size_t nBits, uint64_t value) const override {
204  return instanceInteger(nBits, value);
205  }
206 
207  virtual InstructionSemantics::BaseSemantics::SValuePtr boolean_(bool value) const override {
208  return instanceInteger(1, value ? 1 : 0);
209  }
210 
211  virtual InstructionSemantics::BaseSemantics::SValuePtr copy(size_t newNBits = 0) const override;
212 
214  createOptionalMerge(const InstructionSemantics::BaseSemantics::SValuePtr &other,
216  const SmtSolverPtr&) const override;
217 
218 public:
222  static Ptr promote(const InstructionSemantics::BaseSemantics::SValuePtr &v) { // hot
223  Ptr retval = v.dynamicCast<SValue>();
224  ASSERT_not_null(retval);
225  return retval;
226  }
227 
228 public:
235  AddressInterval region() const;
236  void region(const AddressInterval&);
239 public:
240  virtual void print(std::ostream&, InstructionSemantics::BaseSemantics::Formatter&) const override;
241  virtual void hash(Combinatorics::Hasher&) const override;
242 };
243 
245 // Instruction semantics state
247 
249 using StatePtr = boost::shared_ptr<class State>;
250 
252 class State: public InstructionSemantics::SymbolicSemantics::State {
253 public:
255  using Super = InstructionSemantics::SymbolicSemantics::State;
256 
258  using Ptr = StatePtr;
259 
260 private:
261  FunctionCallStack callStack_;
262 
263 protected:
264  State();
267 
268  // Deep copy
269  State(const State&);
270 
271 public:
275 
277  static Ptr instance(const StatePtr&);
278 
282  const InstructionSemantics::BaseSemantics::MemoryStatePtr &memory) const override {
283  return instance(registers, memory);
284  }
285 
287  virtual InstructionSemantics::BaseSemantics::StatePtr clone() const override;
288 
290  static Ptr promote(const InstructionSemantics::BaseSemantics::StatePtr&);
291 
292 public:
298  const FunctionCallStack& callStack() const;
299  FunctionCallStack& callStack();
301 };
302 
304 // Instruction semantics domain
306 
308 class RiscOperators: public InstructionSemantics::SymbolicSemantics::RiscOperators {
309 public:
310  using Super = InstructionSemantics::SymbolicSemantics::RiscOperators;
311 
312  using Ptr = RiscOperatorsPtr;
313 
314 private:
315  const Settings settings_;
316  Partitioner2::PartitionerConstPtr partitioner_; // not null
317  SmtSolver::Ptr modelCheckerSolver_; // solver used for model checking, different than RISC operators
318  size_t nInstructions_ = 0;
319  SemanticCallbacks *semantics_ = nullptr;
320  AddressInterval stackLimits_; // where the stack can exist in memory
321  bool computeMemoryRegions_ = false; // compute memory regions. This is needed for OOB analysis.
322  const Variables::GlobalVariables &gvars_;
323 
324  mutable SAWYER_THREAD_TRAITS::Mutex variableFinderMutex_; // protects the following data members
325  Variables::VariableFinderPtr variableFinder_unsync; // shared by all RiscOperator objects
326 
327 protected:
328  RiscOperators(const Settings&, const Partitioner2::PartitionerConstPtr&, ModelChecker::SemanticCallbacks*,
331 
332 public: // Standard public construction-like functions
333  ~RiscOperators();
334 
335  static Ptr instance(const Settings&, const Partitioner2::PartitionerConstPtr&, ModelChecker::SemanticCallbacks*,
338 
340  create(const InstructionSemantics::BaseSemantics::SValuePtr&, const SmtSolverPtr&) const override;
341 
343  create(const InstructionSemantics::BaseSemantics::StatePtr&, const SmtSolverPtr&) const override;
344 
346 
347 public: // Supporting functions
351  Partitioner2::PartitionerConstPtr partitioner() const;
352 
359  SmtSolver::Ptr modelCheckerSolver() const;
360  void modelCheckerSolver(const SmtSolver::Ptr&);
368  bool computeMemoryRegions() const;
369  void computeMemoryRegions(bool);
379  void checkNullAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, IoMode);
380 
384  void checkOobAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, IoMode, size_t nBytes);
385 
389  void checkUninitVar(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, size_t nBytes);
390 
397  size_t nInstructions() const;
398  void nInstructions(size_t);
402  void maybeInitCallStack(rose_addr_t insnVa);
403 
405  void pushCallStack(const Partitioner2::FunctionPtr &callee, rose_addr_t initialSp, Sawyer::Optional<rose_addr_t> returnVa);
406 
411  void popCallStack();
412 
419  size_t pruneCallStack();
420 
422  void printCallStack(std::ostream&, const std::string &prefix);
423 
439  assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result);
440 
442  assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
444 
446  assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
451 public: // Override RISC operations
452  virtual void finishInstruction(SgAsmInstruction*) override;
453 
455  number_(size_t nBits, uint64_t value) override;
456 
458  extract(const InstructionSemantics::BaseSemantics::SValuePtr&, size_t begin, size_t end) override;
459 
462  const InstructionSemantics::BaseSemantics::SValuePtr &highBits) override;
463 
466  const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
467 
470  const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
471 
474  const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
475 
477  unsignedExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
478 
480  signExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
481 
485 
490  InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
491 
495 
497  subtractCarry(const InstructionSemantics::BaseSemantics::SValuePtr &a,
500  InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
501 
503  addWithCarries(const InstructionSemantics::BaseSemantics::SValuePtr &a,
506  InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/) override;
507 
509  readRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
510 
511  virtual void
512  writeRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
513 
515  readMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
518 
519  virtual void
520  writeMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
523 };
524 
526 // High-level semantic operations
528 
530 class SemanticCallbacks: public Rose::BinaryAnalysis::ModelChecker::SemanticCallbacks {
531 public:
532  using Ptr = SemanticCallbacksPtr;
534 
535 private:
536  Settings settings_; // settings are set by the constructor and not modified thereafter
537  Partitioner2::PartitionerConstPtr partitioner_; // generally shouldn't be changed once model checking starts, non-null
538  SmtSolver::Memoizer::Ptr smtMemoizer_; // memoizer shared among all solvers
539 
540  mutable SAWYER_THREAD_TRAITS::Mutex unitsMutex_; // protects only the units_ data member
541  Sawyer::Container::Map<rose_addr_t, ExecutionUnitPtr> units_; // cached execution units
542 
543  mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects the following data members
544  std::set<uint64_t> seenStates_; // states we've seen, by hash
545  size_t nDuplicateStates_ = 0; // number of times a previous state is seen again
546  size_t nSolverFailures_ = 0; // number of times the SMT solver failed
547  UnitCounts unitsReached_; // number of times basic blocks were reached
548  Variables::VariableFinderPtr variableFinder_; // also shared by all RiscOperator objects
549  Variables::GlobalVariables gvars_; // all global variables identified by variableFinder_
550 
551  // This model is able to follow a single path specified by the user. In order to do that, the user should call
552  // followOnePath to provide the ordered list of execution units. The nextCodeAddresses function is overridden to
553  // return only the address of the next execution unit in this list, or none when the list is empty. The findUnit
554  // function is enhanced to return the next execution unit and remove it from the list.
555  //
556  // These are also protected by mutex_
557  bool followingOnePath_ = false;
558  std::list<ExecutionUnitPtr> onePath_; // execution units yet to be consumed by findUnit
559 
560 protected:
561  SemanticCallbacks(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
562 public:
563  ~SemanticCallbacks();
564 
565 public:
566  static Ptr instance(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
567 
568 public:
570  Partitioner2::PartitionerConstPtr partitioner() const;
571 
572 public:
588  void followOnePath(const std::list<ExecutionUnitPtr>&);
589 
601  bool followingOnePath() const;
602  void followingOnePath(bool);
612  SmtSolver::Memoizer::Ptr smtMemoizer() const;
613  void smtMemoizer(const SmtSolver::Memoizer::Ptr&);
623  size_t nDuplicateStates() const;
624 
632  size_t nSolverFailures() const;
633 
642  size_t nUnitsReached() const;
643 
650  UnitCounts unitsReached() const;
651 
659  virtual bool filterNullDeref(const InstructionSemantics::BaseSemantics::SValuePtr &addr, SgAsmInstruction*,
660  TestMode testMode, IoMode ioMode);
661 
677  virtual bool filterOobAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr,
678  const AddressInterval &referencedRegion, const AddressInterval &accessedRegion,
679  SgAsmInstruction *insn, TestMode testMode, IoMode ioMode,
680  const FoundVariable &intendedVariable, const FoundVariable &accessedVariable);
681 
682  virtual bool filterUninitVar(const InstructionSemantics::BaseSemantics::SValuePtr &addr,
683  const AddressInterval &referencedREgion, const AddressInterval &accessedRegion,
684  SgAsmInstruction *insn, TestMode testMode, const FoundVariable &accessedVariable);
685 
686 public:
687  virtual void reset() override;
688 
689  virtual InstructionSemantics::BaseSemantics::SValuePtr protoval() override;
690 
691  virtual InstructionSemantics::BaseSemantics::RegisterStatePtr createInitialRegisters() override;
692 
693  virtual InstructionSemantics::BaseSemantics::MemoryStatePtr createInitialMemory() override;
694 
695  virtual InstructionSemantics::BaseSemantics::StatePtr createInitialState() override;
696 
697  virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr createRiscOperators() override;
698 
699  virtual void
700  initializeState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
701 
703  createDispatcher(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
704 
705  virtual SmtSolver::Ptr createSolver() override;
706 
707  virtual void attachModelCheckerSolver(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&,
708  const SmtSolver::Ptr&) override;
709 
710  virtual CodeAddresses
711  nextCodeAddresses(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
712 
713  virtual std::vector<TagPtr>
714  preExecute(const ExecutionUnitPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
715 
716  virtual std::vector<TagPtr>
717  postExecute(const ExecutionUnitPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
718 
720  instructionPointer(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
721 
722  virtual std::vector<NextUnit>
723  nextUnits(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&) override;
724 
725 #ifdef ROSE_HAVE_YAMLCPP
726  virtual std::list<ExecutionUnitPtr>
727  parsePath(const YAML::Node&, const std::string &sourceName) override;
728 #endif
729 
730  virtual std::list<ExecutionUnitPtr>
731  parsePath(const Yaml::Node&, const std::string &sourceName) override;
732 
733 private:
734  // Records the state hash and returns true if we've seen it before.
736 
737  // Find and cache the execution unit at the specified address.
738  ExecutionUnitPtr findUnit(rose_addr_t va, const Progress::Ptr&);
739 };
740 
741 } // namespace
742 } // namespace
743 } // namespace
744 } // namespace
745 
746 #endif
747 #endif
SmtSolverPtr Ptr
Reference counting pointer for SMT solvers.
Definition: SmtSolver.h:45
Unsigned shiftRight(Unsigned src, size_t n, bool b=false)
Right shift a value.
Definition: BitOps.h:106
const char * TestMode(int64_t)
Convert Rose::BinaryAnalysis::ModelChecker::TestMode enum constant to a string.
void copy(const Word *src, const BitRange &srcRange, Word *dst, const BitRange &dstRange)
Copy some bits.
void serialize(std::ostream &output, Graph &graph)
Serialize a graph into a stream of bytes.
Definition: GraphUtility.h:17
Sawyer::SharedPointer< Merger > MergerPtr
Shared-ownership pointer for Merger classes.
Sawyer::Container::IntervalMap< OffsetInterval, StackVariable > StackVariables
Collection of local variables organized by frame offsets.
Definition: Variables.h:289
boost::shared_ptr< RiscOperators > RiscOperatorsPtr
Shared-ownership pointer to a RISC operators object.
Base class for machine instructions.
Sawyer::SharedPointer< class SValue > SValuePtr
Smart-ownership pointer to a concrete semantic value.
Sawyer::SharedPointer< Memoizer > Ptr
Reference counting pointer.
Definition: SmtSolver.h:231
Unsigned signExtend(Unsigned src, size_t n)
Sign extend part of a value to the full width of the src type.
Definition: BitOps.h:272
Sawyer::CommandLine::SwitchGroup commandLineSwitches(Settings &settings)
Command-line switches for unparser settings.
Unsigned shiftLeft(Unsigned src, size_t n, bool b=false)
Left shift a value.
Definition: BitOps.h:76
Sawyer::SharedPointer< VariableFinder > VariableFinderPtr
Reference counting pointer.
A collection of related switch declarations.
boost::shared_ptr< RegisterState > RegisterStatePtr
Shared-ownership pointer to a register state.
Main namespace for the ROSE library.
boost::shared_ptr< State > StatePtr
Shared-ownership pointer to a semantic state.
boost::shared_ptr< Dispatcher > DispatcherPtr
Shared-ownership pointer to a semantics instruction dispatcher.
Sawyer::SharedPointer< Function > FunctionPtr
Shared-ownership pointer for Function.
boost::shared_ptr< MemoryState > MemoryStatePtr
Shared-ownership pointer to a memory state.
void print(const StackVariables &, const Partitioner2::PartitionerConstPtr &, std::ostream &out, const std::string &prefix="")
Print info about multiple local variables.
const char * MemoryType(int64_t)
Convert Rose::BinaryAnalysis::ModelChecker::PartitionerModel::Settings::MemoryType enum constant to a...
T shiftRightArithmetic(T value, size_t count)
Shifts bits of value right by count bits with sign extension.
Definition: integerOps.h:131
boost::shared_ptr< class RiscOperators > RiscOperatorsPtr
Shared-ownership pointer to concrete RISC operations.
Sawyer::SharedPointer< const Partitioner > PartitionerConstPtr
Shared-ownership pointer for Partitioner.
SharedPointer< U > dynamicCast() const
Dynamic cast.
Sawyer::SharedPointer< SValue > SValuePtr
Shared-ownership pointer to a semantic value in any domain.
Sawyer::SharedPointer< Node > Ptr
Reference counting pointer.
std::shared_ptr< SmtSolver > SmtSolverPtr
Reference counting pointer.
Stack-based container.
Definition: Stack.h:22
Sawyer::Container::IntervalMap< AddressInterval, GlobalVariable > GlobalVariables
Maps virtual addresses to global variables.
Definition: Variables.h:389
T extract(T bits)
Extract bits from a value.
Definition: integerOps.h:255
ProgressPtr Ptr
Progress objects are reference counted.
Definition: Progress.h:169
Hash hash(const std::vector< Ptr > &)
Hash zero or more expressions.
State
Decoder state.
Definition: String.h:198