ROSE 0.11.145.202
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
12#include <Sawyer/CommandLine.h>
13#include <Sawyer/Stack.h>
14
15namespace Rose {
16namespace BinaryAnalysis {
17namespace ModelChecker {
18
27namespace PartitionerModel {
28
30// Settings for this model checker
32
34struct Settings {
36 enum class MemoryType {
37 LIST,
38 MAP
39 };
40
41 TestMode nullRead = TestMode::MUST;
42 TestMode nullWrite = TestMode::MUST;
43 TestMode oobRead = TestMode::OFF;
44 TestMode oobWrite = TestMode::OFF;
45 TestMode uninitVar = TestMode::OFF;
46 rose_addr_t maxNullAddress = 4095;
47 bool debugNull = false;
48 Sawyer::Optional<rose_addr_t> initialStackVa;
49 MemoryType memoryType = MemoryType::MAP;
50 bool solverMemoization = false;
51 bool traceSemantics = false;
52};
53
54class SemanticCallbacks;
55
59void commandLineDebugSwitches(Sawyer::CommandLine::SwitchGroup&, Settings&);
60
65Sawyer::CommandLine::SwitchGroup commandLineModelSwitches(Settings&);
66
72
74// Function call stack
76
78class FunctionCall {
79 Partitioner2::FunctionPtr function_;
80 rose_addr_t initialStackPointer_ = 0;
81 rose_addr_t framePointerDelta_ = (rose_addr_t)(-4); // Normal frame pointer w.r.t. initial stack pointer
82 Sawyer::Optional<rose_addr_t> returnAddress_;
83 Variables::StackVariables stackVariables_;
84
85public:
86 ~FunctionCall();
87 FunctionCall(const Partitioner2::FunctionPtr&, rose_addr_t initialSp, Sawyer::Optional<rose_addr_t> returnAddress,
88 const Variables::StackVariables&);
89
91 Partitioner2::FunctionPtr function() const;
92
96 rose_addr_t initialStackPointer() const;
97
99 const Variables::StackVariables& stackVariables() const;
100
106 rose_addr_t framePointerDelta() const;
107 void framePointerDelta(rose_addr_t);
113 rose_addr_t framePointer(size_t nBits) const;
114
118 Sawyer::Optional<rose_addr_t> returnAddress() const;
119 void returnAddress(Sawyer::Optional<rose_addr_t>);
123 std::string printableName(size_t nBits) const;
124};
125
129using FunctionCallStack = Sawyer::Container::Stack<FunctionCall>;
130
132// Instruction semantics value
134
138class SValue: public InstructionSemantics::SymbolicSemantics::SValue {
139public:
141 using Super = InstructionSemantics::SymbolicSemantics::SValue;
142
144 using Ptr = SValuePtr;
145
146private:
147 AddressInterval region_;
148
149#ifdef ROSE_HAVE_BOOST_SERIALIZATION_LIB
150private:
151 friend class boost::serialization::access;
152
153 template<class S>
154 void serialize(S &s, const unsigned /*version*/) {
155 s & BOOST_SERIALIZATION_BASE_OBJECT_NVP(Super);
156 s & BOOST_SERIALIZATION_NVP(region_);
157 }
158#endif
159
160public:
161 ~SValue();
162
163protected:
164 SValue();
165
166 SValue(size_t nBits, uint64_t number);
167
168 explicit SValue(const SymbolicExpression::Ptr&);
169
170public:
174 static Ptr instance();
175
177 static Ptr instanceBottom(size_t nBits);
178
180 static Ptr instanceUndefined(size_t nBits);
181
183 static Ptr instanceUnspecified(size_t nBits);
184
186 static Ptr instanceInteger(size_t nBits, uint64_t value);
187
189 static Ptr instanceSymbolic(const SymbolicExpression::Ptr &value);
190
191public:
192 virtual InstructionSemantics::BaseSemantics::SValuePtr bottom_(size_t nBits) const override;
193 virtual InstructionSemantics::BaseSemantics::SValuePtr undefined_(size_t nBits) const override;
194 virtual InstructionSemantics::BaseSemantics::SValuePtr unspecified_(size_t nBits) const override;
195 virtual InstructionSemantics::BaseSemantics::SValuePtr number_(size_t nBits, uint64_t value) const override;
196 virtual InstructionSemantics::BaseSemantics::SValuePtr boolean_(bool value) const override;
197 virtual InstructionSemantics::BaseSemantics::SValuePtr copy(size_t newNBits = 0) const override;
198
200 createOptionalMerge(const InstructionSemantics::BaseSemantics::SValuePtr &other,
201 const InstructionSemantics::BaseSemantics::MergerPtr&,
202 const SmtSolverPtr&) const override;
203
204public:
208 static Ptr promote(const InstructionSemantics::BaseSemantics::SValuePtr&);
209
210public:
217 AddressInterval region() const;
218 void region(const AddressInterval&);
221public:
222 virtual void print(std::ostream&, InstructionSemantics::BaseSemantics::Formatter&) const override;
223 virtual void hash(Combinatorics::Hasher&) const override;
224};
225
227// Instruction semantics state
229
231using StatePtr = boost::shared_ptr<class State>;
232
234class State: public InstructionSemantics::SymbolicSemantics::State {
235public:
237 using Super = InstructionSemantics::SymbolicSemantics::State;
238
240 using Ptr = StatePtr;
241
242private:
243 FunctionCallStack callStack_;
244
245protected:
246 State();
247 State(const InstructionSemantics::BaseSemantics::RegisterStatePtr&,
248 const InstructionSemantics::BaseSemantics::MemoryStatePtr&);
249
250 // Deep copy
251 State(const State&);
252
253public:
255 static Ptr instance(const InstructionSemantics::BaseSemantics::RegisterStatePtr&,
256 const InstructionSemantics::BaseSemantics::MemoryStatePtr&);
257
259 static Ptr instance(const StatePtr&);
260
262 virtual InstructionSemantics::BaseSemantics::StatePtr
263 create(const InstructionSemantics::BaseSemantics::RegisterStatePtr&,
264 const InstructionSemantics::BaseSemantics::MemoryStatePtr&) const override;
265
267 virtual InstructionSemantics::BaseSemantics::StatePtr clone() const override;
268
270 static Ptr promote(const InstructionSemantics::BaseSemantics::StatePtr&);
271
272public:
278 const FunctionCallStack& callStack() const;
279 FunctionCallStack& callStack();
281};
282
284// Instruction semantics domain
286
288class RiscOperators: public InstructionSemantics::SymbolicSemantics::RiscOperators {
289public:
290 using Super = InstructionSemantics::SymbolicSemantics::RiscOperators;
291
292 using Ptr = RiscOperatorsPtr;
293
294private:
295 const Settings settings_;
296 Partitioner2::PartitionerConstPtr partitioner_; // not null
297 SmtSolver::Ptr modelCheckerSolver_; // solver used for model checking, different than RISC operators
298 size_t nInstructions_ = 0;
299 SemanticCallbacks *semantics_ = nullptr;
300 AddressInterval stackLimits_; // where the stack can exist in memory
301 bool computeMemoryRegions_ = false; // compute memory regions. This is needed for OOB analysis.
302 const Variables::GlobalVariables &gvars_;
303
304 mutable SAWYER_THREAD_TRAITS::Mutex variableFinderMutex_; // protects the following data members
305 Variables::VariableFinderPtr variableFinder_unsync; // shared by all RiscOperator objects
306
307protected:
308 RiscOperators(const Settings&, const Partitioner2::PartitionerConstPtr&, ModelChecker::SemanticCallbacks*,
309 const InstructionSemantics::BaseSemantics::SValuePtr &protoval, const SmtSolverPtr&,
310 const Variables::VariableFinderPtr&, const Variables::GlobalVariables&);
311
312public: // Standard public construction-like functions
313 ~RiscOperators();
314
315 static Ptr instance(const Settings&, const Partitioner2::PartitionerConstPtr&, ModelChecker::SemanticCallbacks*,
316 const InstructionSemantics::BaseSemantics::SValuePtr &protoval, const SmtSolverPtr&,
317 const Variables::VariableFinderPtr&, const Variables::GlobalVariables&);
318
319 virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr
320 create(const InstructionSemantics::BaseSemantics::SValuePtr&, const SmtSolverPtr&) const override;
321
322 virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr
323 create(const InstructionSemantics::BaseSemantics::StatePtr&, const SmtSolverPtr&) const override;
324
325 static Ptr promote(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr &x);
326
327public: // Supporting functions
331 Partitioner2::PartitionerConstPtr partitioner() const;
332
339 SmtSolver::Ptr modelCheckerSolver() const;
340 void modelCheckerSolver(const SmtSolver::Ptr&);
348 bool computeMemoryRegions() const;
349 void computeMemoryRegions(bool);
359 void checkNullAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, IoMode);
360
364 void checkOobAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, IoMode, size_t nBytes);
365
369 void checkUninitVar(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, size_t nBytes);
370
377 size_t nInstructions() const;
378 void nInstructions(size_t);
382 void maybeInitCallStack(rose_addr_t insnVa);
383
385 void pushCallStack(const Partitioner2::FunctionPtr &callee, rose_addr_t initialSp, Sawyer::Optional<rose_addr_t> returnVa);
386
391 void popCallStack();
392
399 size_t pruneCallStack();
400
402 void printCallStack(std::ostream&, const std::string &prefix);
403
418 InstructionSemantics::BaseSemantics::SValuePtr
419 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result);
420
421 InstructionSemantics::BaseSemantics::SValuePtr
422 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
423 const InstructionSemantics::BaseSemantics::SValuePtr &a);
424
425 InstructionSemantics::BaseSemantics::SValuePtr
426 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
427 const InstructionSemantics::BaseSemantics::SValuePtr &a,
428 const InstructionSemantics::BaseSemantics::SValuePtr &b);
431public: // Override RISC operations
432 virtual void finishInstruction(SgAsmInstruction*) override;
433
434 virtual InstructionSemantics::BaseSemantics::SValuePtr
435 number_(size_t nBits, uint64_t value) override;
436
437 virtual InstructionSemantics::BaseSemantics::SValuePtr
438 extract(const InstructionSemantics::BaseSemantics::SValuePtr&, size_t begin, size_t end) override;
439
440 virtual InstructionSemantics::BaseSemantics::SValuePtr
441 concat(const InstructionSemantics::BaseSemantics::SValuePtr &lowBits,
442 const InstructionSemantics::BaseSemantics::SValuePtr &highBits) override;
443
444 virtual InstructionSemantics::BaseSemantics::SValuePtr
445 shiftLeft(const InstructionSemantics::BaseSemantics::SValuePtr &a,
446 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
447
448 virtual InstructionSemantics::BaseSemantics::SValuePtr
449 shiftRight(const InstructionSemantics::BaseSemantics::SValuePtr &a,
450 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
451
452 virtual InstructionSemantics::BaseSemantics::SValuePtr
453 shiftRightArithmetic(const InstructionSemantics::BaseSemantics::SValuePtr &a,
454 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
455
456 virtual InstructionSemantics::BaseSemantics::SValuePtr
457 unsignedExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
458
459 virtual InstructionSemantics::BaseSemantics::SValuePtr
460 signExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
461
462 virtual InstructionSemantics::BaseSemantics::SValuePtr
463 add(const InstructionSemantics::BaseSemantics::SValuePtr &a,
464 const InstructionSemantics::BaseSemantics::SValuePtr &b) override;
465
466 virtual InstructionSemantics::BaseSemantics::SValuePtr
467 addCarry(const InstructionSemantics::BaseSemantics::SValuePtr &a,
468 const InstructionSemantics::BaseSemantics::SValuePtr &b,
469 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/,
470 InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
471
472 virtual InstructionSemantics::BaseSemantics::SValuePtr
473 subtract(const InstructionSemantics::BaseSemantics::SValuePtr &a,
474 const InstructionSemantics::BaseSemantics::SValuePtr &b) override;
475
476 virtual InstructionSemantics::BaseSemantics::SValuePtr
477 subtractCarry(const InstructionSemantics::BaseSemantics::SValuePtr &a,
478 const InstructionSemantics::BaseSemantics::SValuePtr &b,
479 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/,
480 InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
481
482 virtual InstructionSemantics::BaseSemantics::SValuePtr
483 addWithCarries(const InstructionSemantics::BaseSemantics::SValuePtr &a,
484 const InstructionSemantics::BaseSemantics::SValuePtr &b,
485 const InstructionSemantics::BaseSemantics::SValuePtr &c,
486 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/) override;
487
488 virtual InstructionSemantics::BaseSemantics::SValuePtr
489 readRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
490
491 virtual void
492 writeRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
493
494 virtual InstructionSemantics::BaseSemantics::SValuePtr
495 readMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
496 const InstructionSemantics::BaseSemantics::SValuePtr &dflt,
497 const InstructionSemantics::BaseSemantics::SValuePtr &cond) override;
498
499 virtual void
500 writeMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
501 const InstructionSemantics::BaseSemantics::SValuePtr &value,
502 const InstructionSemantics::BaseSemantics::SValuePtr &cond) override;
503};
504
506// High-level semantic operations
508
510class SemanticCallbacks: public Rose::BinaryAnalysis::ModelChecker::SemanticCallbacks {
511public:
512 using Ptr = SemanticCallbacksPtr;
514
515private:
516 Settings settings_; // settings are set by the constructor and not modified thereafter
517 Partitioner2::PartitionerConstPtr partitioner_; // generally shouldn't be changed once model checking starts, non-null
518 SmtSolver::Memoizer::Ptr smtMemoizer_; // memoizer shared among all solvers
519
520 mutable SAWYER_THREAD_TRAITS::Mutex unitsMutex_; // protects only the units_ data member
521 Sawyer::Container::Map<rose_addr_t, ExecutionUnitPtr> units_; // cached execution units
522
523 mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects the following data members
524 std::set<uint64_t> seenStates_; // states we've seen, by hash
525 size_t nDuplicateStates_ = 0; // number of times a previous state is seen again
526 size_t nSolverFailures_ = 0; // number of times the SMT solver failed
527 UnitCounts unitsReached_; // number of times basic blocks were reached
528 Variables::VariableFinderPtr variableFinder_; // also shared by all RiscOperator objects
529 Variables::GlobalVariables gvars_; // all global variables identified by variableFinder_
530
531 // This model is able to follow a single path specified by the user. In order to do that, the user should call
532 // followOnePath to provide the ordered list of execution units. The nextCodeAddresses function is overridden to
533 // return only the address of the next execution unit in this list, or none when the list is empty. The findUnit
534 // function is enhanced to return the next execution unit and remove it from the list.
535 //
536 // These are also protected by mutex_
537 bool followingOnePath_ = false;
538 std::list<ExecutionUnitPtr> onePath_; // execution units yet to be consumed by findUnit
539
540protected:
541 SemanticCallbacks(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
542public:
543 ~SemanticCallbacks();
544
545public:
546 static Ptr instance(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
547
548public:
550 Partitioner2::PartitionerConstPtr partitioner() const;
551
552public:
568 void followOnePath(const std::list<ExecutionUnitPtr>&);
569
581 bool followingOnePath() const;
582 void followingOnePath(bool);
592 SmtSolver::Memoizer::Ptr smtMemoizer() const;
593 void smtMemoizer(const SmtSolver::Memoizer::Ptr&);
603 size_t nDuplicateStates() const;
604
612 size_t nSolverFailures() const;
613
622 size_t nUnitsReached() const;
623
630 UnitCounts unitsReached() const;
631
639 virtual bool filterNullDeref(const InstructionSemantics::BaseSemantics::SValuePtr &addr, SgAsmInstruction*,
640 TestMode testMode, IoMode ioMode);
641
657 virtual bool filterOobAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr,
658 const AddressInterval &referencedRegion, const AddressInterval &accessedRegion,
659 SgAsmInstruction *insn, TestMode testMode, IoMode ioMode,
660 const FoundVariable &intendedVariable, const FoundVariable &accessedVariable);
661
662 virtual bool filterUninitVar(const InstructionSemantics::BaseSemantics::SValuePtr &addr,
663 const AddressInterval &referencedREgion, const AddressInterval &accessedRegion,
664 SgAsmInstruction *insn, TestMode testMode, const FoundVariable &accessedVariable);
665
666public:
667 virtual void reset() override;
668
669 virtual InstructionSemantics::BaseSemantics::SValuePtr protoval() override;
670
671 virtual InstructionSemantics::BaseSemantics::RegisterStatePtr createInitialRegisters() override;
672
673 virtual InstructionSemantics::BaseSemantics::MemoryStatePtr createInitialMemory() override;
674
675 virtual InstructionSemantics::BaseSemantics::StatePtr createInitialState() override;
676
677 virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr createRiscOperators() override;
678
679 virtual void
680 initializeState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
681
682 virtual InstructionSemantics::BaseSemantics::DispatcherPtr
683 createDispatcher(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
684
685 virtual SmtSolver::Ptr createSolver() override;
686
687 virtual void attachModelCheckerSolver(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&,
688 const SmtSolver::Ptr&) override;
689
690 virtual CodeAddresses
691 nextCodeAddresses(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
692
693 virtual std::vector<TagPtr>
694 preExecute(const ExecutionUnitPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
695
696 virtual std::vector<TagPtr>
697 postExecute(const ExecutionUnitPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
698
699 virtual InstructionSemantics::BaseSemantics::SValuePtr
700 instructionPointer(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
701
702 virtual std::vector<NextUnit>
703 nextUnits(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&) override;
704
705#ifdef ROSE_HAVE_YAMLCPP
706 virtual std::list<ExecutionUnitPtr>
707 parsePath(const YAML::Node&, const std::string &sourceName) override;
708#endif
709
710 virtual std::list<ExecutionUnitPtr>
711 parsePath(const Yaml::Node&, const std::string &sourceName) override;
712
713private:
714 // Records the state hash and returns true if we've seen it before.
715 bool seenState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&);
716
717 // Find and cache the execution unit at the specified address.
718 ExecutionUnitPtr findUnit(rose_addr_t va, const Progress::Ptr&);
719};
720
721} // namespace
722} // namespace
723} // namespace
724} // namespace
725
726#endif
727#endif
A collection of related switch declarations.
Container associating values with keys.
Definition Sawyer/Map.h:72
Stack-based container.
Definition Stack.h:22
Holds a value or nothing.
Definition Optional.h:56
Base class for machine instructions.
T shiftRightArithmetic(T value, size_t count)
Shifts bits of value right by count bits with sign extension.
Definition integerOps.h:131
T extract(T bits)
Extract bits from a value.
Definition integerOps.h:255
boost::shared_ptr< class RiscOperators > RiscOperatorsPtr
Shared-ownership pointer to concrete RISC operations.
Sawyer::SharedPointer< class SValue > SValuePtr
Smart-ownership pointer to a concrete semantic value.
Sawyer::SharedPointer< Node > Ptr
Reference counting pointer.
Hash hash(const std::vector< Ptr > &)
Hash zero or more expressions.
Sawyer::CommandLine::SwitchGroup commandLineSwitches(Settings &settings)
Command-line switches for unparser settings.
void print(const GlobalVariables &, const Partitioner2::PartitionerConstPtr &, std::ostream &out, const std::string &prefix="")
Print info about multiple global variables.
Sawyer::Container::Interval< Address > AddressInterval
An interval of addresses.
Unsigned shiftRight(Unsigned src, size_t n, bool b=false)
Right shift a value.
Definition BitOps.h:125
Unsigned signExtend(Unsigned src, size_t n)
Sign extend part of a value to the full width of the src type.
Definition BitOps.h:324
Unsigned shiftLeft(Unsigned src, size_t n, bool b=false)
Left shift a value.
Definition BitOps.h:91
void serialize(std::ostream &output, Graph &graph)
Serialize a graph into a stream of bytes.
The ROSE library.
void copy(const Word *src, const BitRange &srcRange, Word *dst, const BitRange &dstRange)
Copy some bits.
const char * MemoryType(int64_t)
Convert Rose::BinaryAnalysis::ModelChecker::PartitionerModel::Settings::MemoryType enum constant to a...
const char * TestMode(int64_t)
Convert Rose::BinaryAnalysis::ModelChecker::TestMode enum constant to a string.