ROSE 0.11.145.247
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 Address maxNullAddress = 4095;
47 bool debugNull = false;
48 Sawyer::Optional<Address> 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 Address initialStackPointer_ = 0;
81 Address framePointerDelta_ = (Address)(-4); // Normal frame pointer w.r.t. initial stack pointer
82 Sawyer::Optional<Address> returnAddress_;
83 Variables::StackVariables stackVariables_;
84
85public:
86 ~FunctionCall();
87 FunctionCall(const Partitioner2::FunctionPtr&, Address initialSp, Sawyer::Optional<Address> returnAddress,
88 const Variables::StackVariables&);
89
91 Partitioner2::FunctionPtr function() const;
92
96 Address initialStackPointer() const;
97
99 const Variables::StackVariables& stackVariables() const;
100
106 Address framePointerDelta() const;
107 void framePointerDelta(Address);
113 Address framePointer(size_t nBits) const;
114
118 Sawyer::Optional<Address> returnAddress() const;
119 void returnAddress(Sawyer::Optional<Address>);
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_ENABLE_BOOST_SERIALIZATION
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&);
346 SemanticCallbacks* semanticCallbacks() const;
347
353 bool computeMemoryRegions() const;
354 void computeMemoryRegions(bool);
364 void checkNullAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, IoMode);
365
369 void checkOobAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, IoMode, size_t nBytes);
370
374 void checkUninitVar(const InstructionSemantics::BaseSemantics::SValuePtr &addr, TestMode, size_t nBytes);
375
382 size_t nInstructions() const;
383 void nInstructions(size_t);
387 void maybeInitCallStack(Address insnVa);
388
390 void pushCallStack(const Partitioner2::FunctionPtr &callee, Address initialSp, Sawyer::Optional<Address> returnVa);
391
396 void popCallStack();
397
404 size_t pruneCallStack();
405
407 void printCallStack(std::ostream&, const std::string &prefix);
408
423 InstructionSemantics::BaseSemantics::SValuePtr
424 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result);
425
426 InstructionSemantics::BaseSemantics::SValuePtr
427 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
428 const InstructionSemantics::BaseSemantics::SValuePtr &a);
429
430 InstructionSemantics::BaseSemantics::SValuePtr
431 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
432 const InstructionSemantics::BaseSemantics::SValuePtr &a,
433 const InstructionSemantics::BaseSemantics::SValuePtr &b);
436public: // Override RISC operations
437 virtual void finishInstruction(SgAsmInstruction*) override;
438
439 virtual InstructionSemantics::BaseSemantics::SValuePtr
440 number_(size_t nBits, uint64_t value) override;
441
442 virtual InstructionSemantics::BaseSemantics::SValuePtr
443 extract(const InstructionSemantics::BaseSemantics::SValuePtr&, size_t begin, size_t end) override;
444
445 virtual InstructionSemantics::BaseSemantics::SValuePtr
446 concat(const InstructionSemantics::BaseSemantics::SValuePtr &lowBits,
447 const InstructionSemantics::BaseSemantics::SValuePtr &highBits) override;
448
449 virtual InstructionSemantics::BaseSemantics::SValuePtr
450 shiftLeft(const InstructionSemantics::BaseSemantics::SValuePtr &a,
451 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
452
453 virtual InstructionSemantics::BaseSemantics::SValuePtr
454 shiftRight(const InstructionSemantics::BaseSemantics::SValuePtr &a,
455 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
456
457 virtual InstructionSemantics::BaseSemantics::SValuePtr
458 shiftRightArithmetic(const InstructionSemantics::BaseSemantics::SValuePtr &a,
459 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
460
461 virtual InstructionSemantics::BaseSemantics::SValuePtr
462 unsignedExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
463
464 virtual InstructionSemantics::BaseSemantics::SValuePtr
465 signExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
466
467 virtual InstructionSemantics::BaseSemantics::SValuePtr
468 add(const InstructionSemantics::BaseSemantics::SValuePtr &a,
469 const InstructionSemantics::BaseSemantics::SValuePtr &b) override;
470
471 virtual InstructionSemantics::BaseSemantics::SValuePtr
472 addCarry(const InstructionSemantics::BaseSemantics::SValuePtr &a,
473 const InstructionSemantics::BaseSemantics::SValuePtr &b,
474 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/,
475 InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
476
477 virtual InstructionSemantics::BaseSemantics::SValuePtr
478 subtract(const InstructionSemantics::BaseSemantics::SValuePtr &a,
479 const InstructionSemantics::BaseSemantics::SValuePtr &b) override;
480
481 virtual InstructionSemantics::BaseSemantics::SValuePtr
482 subtractCarry(const InstructionSemantics::BaseSemantics::SValuePtr &a,
483 const InstructionSemantics::BaseSemantics::SValuePtr &b,
484 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/,
485 InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
486
487 virtual InstructionSemantics::BaseSemantics::SValuePtr
488 addWithCarries(const InstructionSemantics::BaseSemantics::SValuePtr &a,
489 const InstructionSemantics::BaseSemantics::SValuePtr &b,
490 const InstructionSemantics::BaseSemantics::SValuePtr &c,
491 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/) override;
492
493 virtual InstructionSemantics::BaseSemantics::SValuePtr
494 readRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
495
496 virtual void
497 writeRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
498
499 virtual InstructionSemantics::BaseSemantics::SValuePtr
500 readMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
501 const InstructionSemantics::BaseSemantics::SValuePtr &dflt,
502 const InstructionSemantics::BaseSemantics::SValuePtr &cond) override;
503
504 virtual void
505 writeMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
506 const InstructionSemantics::BaseSemantics::SValuePtr &value,
507 const InstructionSemantics::BaseSemantics::SValuePtr &cond) override;
508};
509
511// High-level semantic operations
513
515class SemanticCallbacks: public Rose::BinaryAnalysis::ModelChecker::SemanticCallbacks {
516public:
517 using Ptr = SemanticCallbacksPtr;
519
520private:
521 Settings settings_; // settings are set by the constructor and not modified thereafter
522 Partitioner2::PartitionerConstPtr partitioner_; // generally shouldn't be changed once model checking starts, non-null
523 SmtSolver::Memoizer::Ptr smtMemoizer_; // memoizer shared among all solvers
524 AddressInterval stackRegion_; // addresses considered to be in the stack's area of memory
525
526 mutable SAWYER_THREAD_TRAITS::Mutex unitsMutex_; // protects only the units_ data member
527 Sawyer::Container::Map<Address, ExecutionUnitPtr> units_; // cached execution units
528
529 mutable SAWYER_THREAD_TRAITS::Mutex mutex_; // protects the following data members
530 std::set<uint64_t> seenStates_; // states we've seen, by hash
531 size_t nDuplicateStates_ = 0; // number of times a previous state is seen again
532 size_t nSolverFailures_ = 0; // number of times the SMT solver failed
533 UnitCounts unitsReached_; // number of times basic blocks were reached
534 Variables::VariableFinderPtr variableFinder_; // also shared by all RiscOperator objects
535 Variables::GlobalVariables gvars_; // all global variables identified by variableFinder_
536
537 // This model is able to follow a single path specified by the user. In order to do that, the user should call
538 // followOnePath to provide the ordered list of execution units. The nextCodeAddresses function is overridden to
539 // return only the address of the next execution unit in this list, or none when the list is empty. The findUnit
540 // function is enhanced to return the next execution unit and remove it from the list.
541 //
542 // These are also protected by mutex_
543 bool followingOnePath_ = false;
544 std::list<ExecutionUnitPtr> onePath_; // execution units yet to be consumed by findUnit
545
546protected:
547 SemanticCallbacks(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
548public:
549 ~SemanticCallbacks();
550
551public:
552 static Ptr instance(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
553
554public:
556 Partitioner2::PartitionerConstPtr partitioner() const;
557
558public:
560 const Settings& p2Settings() const;
561
577 void followOnePath(const std::list<ExecutionUnitPtr>&);
578
590 bool followingOnePath() const;
591 void followingOnePath(bool);
601 SmtSolver::Memoizer::Ptr smtMemoizer() const;
602 void smtMemoizer(const SmtSolver::Memoizer::Ptr&);
608 AddressInterval stackRegion() const;
609
617 size_t nDuplicateStates() const;
618
626 size_t nSolverFailures() const;
627
636 size_t nUnitsReached() const;
637
644 UnitCounts unitsReached() const;
645
653 virtual bool filterNullDeref(const InstructionSemantics::BaseSemantics::SValuePtr &addr, SgAsmInstruction*,
654 TestMode testMode, IoMode ioMode);
655
671 virtual bool filterOobAccess(const InstructionSemantics::BaseSemantics::SValuePtr &addr,
672 const AddressInterval &referencedRegion, const AddressInterval &accessedRegion,
673 SgAsmInstruction *insn, TestMode testMode, IoMode ioMode,
674 const FoundVariable &intendedVariable, const FoundVariable &accessedVariable);
675
676 virtual bool filterUninitVar(const InstructionSemantics::BaseSemantics::SValuePtr &addr,
677 const AddressInterval &referencedREgion, const AddressInterval &accessedRegion,
678 SgAsmInstruction *insn, TestMode testMode, const FoundVariable &accessedVariable);
679
680public:
681 virtual void reset() override;
682
683 virtual InstructionSemantics::BaseSemantics::SValuePtr protoval() override;
684
685 virtual InstructionSemantics::BaseSemantics::RegisterStatePtr createInitialRegisters() override;
686
687 virtual InstructionSemantics::BaseSemantics::MemoryStatePtr createInitialMemory() override;
688
689 virtual InstructionSemantics::BaseSemantics::StatePtr createInitialState() override;
690
691 virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr createRiscOperators() override;
692
693 virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr
694 configureRiscOperators(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
695
696 virtual void
697 initializeState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
698
699 virtual InstructionSemantics::BaseSemantics::DispatcherPtr
700 createDispatcher(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
701
702 virtual SmtSolver::Ptr createSolver() override;
703
704 virtual void attachModelCheckerSolver(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&,
705 const SmtSolver::Ptr&) override;
706
707 virtual CodeAddresses
708 nextCodeAddresses(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
709
710 virtual std::vector<TagPtr>
711 preExecute(const PathNodePtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
712
713 virtual std::vector<TagPtr>
714 postExecute(const PathNodePtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
715
716 virtual InstructionSemantics::BaseSemantics::SValuePtr
717 instructionPointer(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&) override;
718
719 virtual std::vector<NextUnit>
720 nextUnits(const PathPtr&, const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&, const SmtSolver::Ptr&) override;
721
722#ifdef ROSE_HAVE_YAMLCPP
723 virtual std::list<ExecutionUnitPtr>
724 parsePath(const YAML::Node&, const std::string &sourceName) override;
725#endif
726
727 virtual std::list<ExecutionUnitPtr>
728 parsePath(const Yaml::Node&, const std::string &sourceName) override;
729
730protected:
731 Variables::VariableFinderPtr variableFinder() const;
732 Variables::GlobalVariables& globalVariables();
733
734private:
735 // Records the state hash and returns true if we've seen it before.
736 bool seenState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&);
737
738 // Find and cache the execution unit at the specified address.
739 ExecutionUnitPtr findUnit(Address va, const Progress::Ptr&);
740};
741
742} // namespace
743} // namespace
744} // namespace
745} // namespace
746
747#endif
748#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.
std::uint64_t Address
Address.
Definition Address.h:11
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.