ROSE 0.11.145.147
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
14namespace Rose {
15namespace BinaryAnalysis {
16namespace ModelChecker {
17
26namespace PartitionerModel {
27
29// Settings for this model checker
31
33struct 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
53class SemanticCallbacks;
54
58void commandLineDebugSwitches(Sawyer::CommandLine::SwitchGroup&, Settings&);
59
64Sawyer::CommandLine::SwitchGroup commandLineModelSwitches(Settings&);
65
71
73// Function call stack
75
77class 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
84public:
85 ~FunctionCall();
86 FunctionCall(const Partitioner2::FunctionPtr&, rose_addr_t initialSp, Sawyer::Optional<rose_addr_t> returnAddress,
87 const Variables::StackVariables&);
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
128using FunctionCallStack = Sawyer::Container::Stack<FunctionCall>;
129
131// Instruction semantics value
133
137class SValue: public InstructionSemantics::SymbolicSemantics::SValue {
138public:
140 using Super = InstructionSemantics::SymbolicSemantics::SValue;
141
143 using Ptr = SValuePtr;
144
145private:
146 AddressInterval region_;
147
148#ifdef ROSE_HAVE_BOOST_SERIALIZATION_LIB
149private:
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
159public:
160 ~SValue();
161
162protected:
163 SValue();
164
165 SValue(size_t nBits, uint64_t number);
166
167 explicit SValue(const SymbolicExpression::Ptr&);
168
169public:
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
190public:
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,
215 const InstructionSemantics::BaseSemantics::MergerPtr&,
216 const SmtSolverPtr&) const override;
217
218public:
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
228public:
235 AddressInterval region() const;
236 void region(const AddressInterval&);
239public:
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
249using StatePtr = boost::shared_ptr<class State>;
250
252class State: public InstructionSemantics::SymbolicSemantics::State {
253public:
255 using Super = InstructionSemantics::SymbolicSemantics::State;
256
258 using Ptr = StatePtr;
259
260private:
261 FunctionCallStack callStack_;
262
263protected:
264 State();
265 State(const InstructionSemantics::BaseSemantics::RegisterStatePtr&,
266 const InstructionSemantics::BaseSemantics::MemoryStatePtr&);
267
268 // Deep copy
269 State(const State&);
270
271public:
273 static Ptr instance(const InstructionSemantics::BaseSemantics::RegisterStatePtr&,
274 const InstructionSemantics::BaseSemantics::MemoryStatePtr&);
275
277 static Ptr instance(const StatePtr&);
278
280 virtual InstructionSemantics::BaseSemantics::StatePtr
281 create(const InstructionSemantics::BaseSemantics::RegisterStatePtr &registers,
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
292public:
298 const FunctionCallStack& callStack() const;
299 FunctionCallStack& callStack();
301};
302
304// Instruction semantics domain
306
308class RiscOperators: public InstructionSemantics::SymbolicSemantics::RiscOperators {
309public:
310 using Super = InstructionSemantics::SymbolicSemantics::RiscOperators;
311
312 using Ptr = RiscOperatorsPtr;
313
314private:
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
327protected:
328 RiscOperators(const Settings&, const Partitioner2::PartitionerConstPtr&, ModelChecker::SemanticCallbacks*,
329 const InstructionSemantics::BaseSemantics::SValuePtr &protoval, const SmtSolverPtr&,
330 const Variables::VariableFinderPtr&, const Variables::GlobalVariables&);
331
332public: // Standard public construction-like functions
333 ~RiscOperators();
334
335 static Ptr instance(const Settings&, const Partitioner2::PartitionerConstPtr&, ModelChecker::SemanticCallbacks*,
336 const InstructionSemantics::BaseSemantics::SValuePtr &protoval, const SmtSolverPtr&,
337 const Variables::VariableFinderPtr&, const Variables::GlobalVariables&);
338
339 virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr
340 create(const InstructionSemantics::BaseSemantics::SValuePtr&, const SmtSolverPtr&) const override;
341
342 virtual InstructionSemantics::BaseSemantics::RiscOperatorsPtr
343 create(const InstructionSemantics::BaseSemantics::StatePtr&, const SmtSolverPtr&) const override;
344
345 static Ptr promote(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr &x);
346
347public: // 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
438 InstructionSemantics::BaseSemantics::SValuePtr
439 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result);
440
441 InstructionSemantics::BaseSemantics::SValuePtr
442 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
443 const InstructionSemantics::BaseSemantics::SValuePtr &a);
444
445 InstructionSemantics::BaseSemantics::SValuePtr
446 assignRegion(const InstructionSemantics::BaseSemantics::SValuePtr &result,
447 const InstructionSemantics::BaseSemantics::SValuePtr &a,
448 const InstructionSemantics::BaseSemantics::SValuePtr &b);
451public: // Override RISC operations
452 virtual void finishInstruction(SgAsmInstruction*) override;
453
454 virtual InstructionSemantics::BaseSemantics::SValuePtr
455 number_(size_t nBits, uint64_t value) override;
456
457 virtual InstructionSemantics::BaseSemantics::SValuePtr
458 extract(const InstructionSemantics::BaseSemantics::SValuePtr&, size_t begin, size_t end) override;
459
460 virtual InstructionSemantics::BaseSemantics::SValuePtr
461 concat(const InstructionSemantics::BaseSemantics::SValuePtr &lowBits,
462 const InstructionSemantics::BaseSemantics::SValuePtr &highBits) override;
463
464 virtual InstructionSemantics::BaseSemantics::SValuePtr
465 shiftLeft(const InstructionSemantics::BaseSemantics::SValuePtr &a,
466 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
467
468 virtual InstructionSemantics::BaseSemantics::SValuePtr
469 shiftRight(const InstructionSemantics::BaseSemantics::SValuePtr &a,
470 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
471
472 virtual InstructionSemantics::BaseSemantics::SValuePtr
473 shiftRightArithmetic(const InstructionSemantics::BaseSemantics::SValuePtr &a,
474 const InstructionSemantics::BaseSemantics::SValuePtr &nBits) override;
475
476 virtual InstructionSemantics::BaseSemantics::SValuePtr
477 unsignedExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
478
479 virtual InstructionSemantics::BaseSemantics::SValuePtr
480 signExtend(const InstructionSemantics::BaseSemantics::SValue::Ptr &a, size_t newWidth) override;
481
482 virtual InstructionSemantics::BaseSemantics::SValuePtr
483 add(const InstructionSemantics::BaseSemantics::SValuePtr &a,
484 const InstructionSemantics::BaseSemantics::SValuePtr &b) override;
485
486 virtual InstructionSemantics::BaseSemantics::SValuePtr
487 addCarry(const InstructionSemantics::BaseSemantics::SValuePtr &a,
488 const InstructionSemantics::BaseSemantics::SValuePtr &b,
489 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/,
490 InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
491
492 virtual InstructionSemantics::BaseSemantics::SValuePtr
493 subtract(const InstructionSemantics::BaseSemantics::SValuePtr &a,
494 const InstructionSemantics::BaseSemantics::SValuePtr &b) override;
495
496 virtual InstructionSemantics::BaseSemantics::SValuePtr
497 subtractCarry(const InstructionSemantics::BaseSemantics::SValuePtr &a,
498 const InstructionSemantics::BaseSemantics::SValuePtr &b,
499 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/,
500 InstructionSemantics::BaseSemantics::SValuePtr &overflowed /*out*/) override;
501
502 virtual InstructionSemantics::BaseSemantics::SValuePtr
503 addWithCarries(const InstructionSemantics::BaseSemantics::SValuePtr &a,
504 const InstructionSemantics::BaseSemantics::SValuePtr &b,
505 const InstructionSemantics::BaseSemantics::SValuePtr &c,
506 InstructionSemantics::BaseSemantics::SValuePtr &carryOut /*out*/) override;
507
508 virtual InstructionSemantics::BaseSemantics::SValuePtr
509 readRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
510
511 virtual void
512 writeRegister(RegisterDescriptor, const InstructionSemantics::BaseSemantics::SValuePtr&) override;
513
514 virtual InstructionSemantics::BaseSemantics::SValuePtr
515 readMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
516 const InstructionSemantics::BaseSemantics::SValuePtr &dflt,
517 const InstructionSemantics::BaseSemantics::SValuePtr &cond) override;
518
519 virtual void
520 writeMemory(RegisterDescriptor segreg, const InstructionSemantics::BaseSemantics::SValuePtr &addr,
521 const InstructionSemantics::BaseSemantics::SValuePtr &value,
522 const InstructionSemantics::BaseSemantics::SValuePtr &cond) override;
523};
524
526// High-level semantic operations
528
530class SemanticCallbacks: public Rose::BinaryAnalysis::ModelChecker::SemanticCallbacks {
531public:
532 using Ptr = SemanticCallbacksPtr;
534
535private:
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
560protected:
561 SemanticCallbacks(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
562public:
563 ~SemanticCallbacks();
564
565public:
566 static Ptr instance(const ModelChecker::SettingsPtr&, const Settings&, const Partitioner2::PartitionerConstPtr&);
567
568public:
570 Partitioner2::PartitionerConstPtr partitioner() const;
571
572public:
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
686public:
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
702 virtual InstructionSemantics::BaseSemantics::DispatcherPtr
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
719 virtual InstructionSemantics::BaseSemantics::SValuePtr
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
733private:
734 // Records the state hash and returns true if we've seen it before.
735 bool seenState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr&);
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
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
SharedPointer< U > dynamicCast() const
Dynamic cast.
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 StackVariables &, const Partitioner2::PartitionerConstPtr &, std::ostream &out, const std::string &prefix="")
Print info about multiple local 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.