ROSE 0.11.145.192
DataFlow.h
1#ifndef ROSE_BinaryAnalysis_DataFlow_H
2#define ROSE_BinaryAnalysis_DataFlow_H
3#include <featureTests.h>
4#ifdef ROSE_ENABLE_BINARY_ANALYSIS
5
6#include <Rose/BinaryAnalysis/InstructionSemantics/DataFlowSemantics.h>
7#include <Rose/BinaryAnalysis/InstructionSemantics/SymbolicSemantics.h>
8#include <Rose/Diagnostics.h>
9#include <Rose/Exception.h>
10#include <Rose/StringUtility/Convert.h>
11#include <Rose/StringUtility/Diagnostics.h>
12#include <Rose/StringUtility/NumberToString.h>
13
14#include <Sawyer/GraphTraversal.h>
15#include <Sawyer/DistinctList.h>
16#include <boost/lexical_cast.hpp>
17#include <list>
18#include <sstream>
19#include <string>
20#include <vector>
21
22namespace Rose {
23namespace BinaryAnalysis {
24
72class DataFlow {
73public:
80
87
89 typedef std::list<Variable> VariableList;
90
97
98public:
101 public:
102 explicit Exception(const std::string &s): Rose::Exception(s) {}
103 };
104
106 class NotConverging: public Exception {
107 public:
108 explicit NotConverging(const std::string &s): Exception(s) {}
109 };
110
111private:
112 InstructionSemantics::BaseSemantics::RiscOperatorsPtr userOps_; // operators (and state) provided by the user
113 InstructionSemantics::DataFlowSemantics::RiscOperatorsPtr dfOps_; // data-flow operators (which point to user ops)
114 InstructionSemantics::BaseSemantics::DispatcherPtr dispatcher_; // copy of user's dispatcher but with DataFlowSemantics
115
116public:
117 static Sawyer::Message::Facility mlog; // diagnostics for data-flow
118
119public:
126 init(userDispatcher);
127 }
128
132 static void initDiagnostics();
133
134private:
136
137public:
146 Graph buildGraph(const std::vector<SgAsmInstruction*>&);
155 public:
156 typedef std::vector<SgAsmInstruction*> Instructions;
157 Instructions operator()(SgAsmInstruction *insn) { return Instructions(1, insn); }
158 Instructions operator()(SgAsmBlock *blk);
159 };
160
161public:
173 template<class CFG, class VertexUnpacker>
174 VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex, VertexUnpacker vertexUnpacker) {
175 using namespace Diagnostics;
176 ASSERT_this();
177 ASSERT_require(startVertex < cfg.nVertices());
178 Stream mesg(mlog[WHERE] <<"buildGraphPerVertex startVertex=" <<startVertex);
179
180 VertexFlowGraphs result;
181 result.insert(startVertex, buildGraph(vertexUnpacker(cfg.findVertex(startVertex)->value())));
182 std::vector<InstructionSemantics::BaseSemantics::StatePtr> postState(cfg.nVertices()); // user-defined states
183 postState[startVertex] = userOps_->currentState();
184
186 for (Traversal t(cfg, cfg.findVertex(startVertex)); t; ++t) {
187 typename CFG::ConstVertexIterator source = t->source();
188 typename CFG::ConstVertexIterator target = t->target();
189 InstructionSemantics::BaseSemantics::StatePtr state = postState[target->id()];
190 if (state==NULL) {
191 ASSERT_not_null(postState[source->id()]);
192 state = postState[target->id()] = postState[source->id()]->clone();
193 userOps_->currentState(state);
194 std::vector<SgAsmInstruction*> insns = vertexUnpacker(target->value());
195 result.insert(target->id(), buildGraph(insns));
196 }
197 }
198
199 mesg <<"; processed " <<StringUtility::plural(result.size(), "vertices", "vertex") <<"\n";
200 return result;
201 }
202
203 template<class CFG>
204 VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex) {
205 return buildGraphPerVertex(cfg, startVertex, DefaultVertexUnpacker());
206 }
214
220 public:
222 explicit SemanticsMerge(const InstructionSemantics::BaseSemantics::DispatcherPtr &cpu): ops_(cpu->operators()) {}
223
224 bool operator()(InstructionSemantics::BaseSemantics::StatePtr &dst /*in,out*/,
226 struct PreserveCurrentState {
229 PreserveCurrentState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr &ops)
230 : ops(ops), state(ops->currentState()) {}
231 ~PreserveCurrentState() { ops->currentState(state); }
232 } t(ops_);
233
234 if (!dst) {
235 dst = src->clone();
236 return true;
237 } else {
238 ops_->currentState(src);
239 return dst->merge(src, ops_.get(), ops_.get());
240 }
241 }
242 };
243
248 template<class CFG, class State>
250 public:
251 bool operator()(const CFG&, const typename CFG::Edge&, const State&, const State&) {
252 return true;
253 }
254 };
255
313 template<class Cfg_, class State_, class TransferFunction_, class MergeFunction_,
314 class PathFeasibility_ = PathAlwaysFeasible<Cfg_, State_> >
315 class Engine {
316 public:
317 using Cfg = Cfg_;
318 using State = State_;
319 using TransferFunction = TransferFunction_;
320 using MergeFunction = MergeFunction_;
321 using PathFeasibility = PathFeasibility_;
322 using VertexStates = std::vector<State>;
324 using CFG = Cfg_; // Deprecated [Robb Matzke 2023-01-27]
325
326 private:
327 std::string name_; // optional name for debugging
328 const Cfg &cfg_;
329 TransferFunction &xfer_;
330 MergeFunction merge_;
331 VertexStates incomingState_; // incoming data-flow state per CFG vertex ID
332 VertexStates outgoingState_; // outgoing data-flow state per CFG vertex ID
334 WorkList workList_; // CFG vertex IDs to be visited, last in first out w/out duplicates
335 size_t maxIterations_; // max number of iterations to allow
336 size_t nIterations_; // number of iterations since last reset
337 PathFeasibility isFeasible_; // predicate to test path feasibility
338
339 public:
346 PathFeasibility isFeasible = PathFeasibility())
347 : cfg_(cfg), xfer_(xfer), merge_(merge), maxIterations_(-1), nIterations_(0), isFeasible_(isFeasible) {
348 reset();
349 }
350
355 const Cfg &cfg() const {
356 return cfg_;
357 }
358
360 void reset(State initialState = State()) {
361 ASSERT_this();
362 incomingState_.clear();
363 incomingState_.resize(cfg_.nVertices(), initialState);
364 outgoingState_.clear();
365 outgoingState_.resize(cfg_.nVertices(), initialState);
366 workList_.clear();
367 nIterations_ = 0;
368 }
369
375 const std::string& name() const { return name_; }
376 void name(const std::string &s) { name_ = s; }
380 std::string prefix() const {
381 if (name_.empty()) {
382 return "";
383 } else {
384 return name_ + ": ";
385 }
386 }
387
394 size_t maxIterations() const { return maxIterations_; }
395 void maxIterations(size_t n) { maxIterations_ = n; }
401 size_t nIterations() const { return nIterations_; }
402
408 using namespace Diagnostics;
409 if (!workList_.isEmpty()) {
410 if (++nIterations_ > maxIterations_) {
411 throw NotConverging("data-flow max iterations reached"
412 " (max=" + StringUtility::numberToString(maxIterations_) + ")");
413 }
414 size_t cfgVertexId = workList_.popFront();
415 if (mlog[DEBUG]) {
416 mlog[DEBUG] <<prefix() <<"runOneIteration: vertex #" <<cfgVertexId <<"\n";
417 mlog[DEBUG] <<prefix() <<" remaining worklist is {";
418 for (size_t id: workList_.items())
419 mlog[DEBUG] <<" " <<id;
420 mlog[DEBUG] <<" }\n";
421 }
422
423 ASSERT_require2(cfgVertexId < cfg_.nVertices(),
424 "vertex " + boost::lexical_cast<std::string>(cfgVertexId) + " must be valid within CFG");
425 typename Cfg::ConstVertexIterator vertex = cfg_.findVertex(cfgVertexId);
426 State state = incomingState_[cfgVertexId];
427 if (mlog[DEBUG]) {
428 mlog[DEBUG] <<prefix() <<" incoming state for vertex #" <<cfgVertexId <<":\n"
429 <<StringUtility::prefixLines(xfer_.toString(state), prefix() + " ") <<"\n";
430 }
431
432 state = outgoingState_[cfgVertexId] = xfer_(cfg_, cfgVertexId, state);
433 if (mlog[DEBUG]) {
434 mlog[DEBUG] <<prefix() <<" outgoing state for vertex #" <<cfgVertexId <<":\n"
435 <<StringUtility::prefixLines(xfer_.toString(state), prefix() + " ") <<"\n";
436 }
437
438 // Outgoing state must be merged into the incoming states for the CFG successors. Any such incoming state that
439 // is modified as a result will have its CFG vertex added to the work list.
440 SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" forwarding vertex #" <<cfgVertexId <<" output state to "
441 <<StringUtility::plural(vertex->nOutEdges(), "vertices", "vertex") <<"\n";
442 for (const typename Cfg::Edge &edge: vertex->outEdges()) {
443 size_t nextVertexId = edge.target()->id();
444 if (!isFeasible_(cfg_, edge, state, incomingState_[nextVertexId])) {
445 SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" path to vertex #" <<nextVertexId
446 <<" is not feasible, thus skipped\n";
447 } else if (merge_(incomingState_[nextVertexId], state)) {
448 if (mlog[DEBUG]) {
449 mlog[DEBUG] <<prefix() <<" merged with vertex #" <<nextVertexId <<" (which changed as a result)\n";
450 mlog[DEBUG] <<prefix() <<" merge state is:\n"
451 <<StringUtility::prefixLines(xfer_.toString(incomingState_[nextVertexId]),
452 prefix() + " ", false) <<"\n";
453 }
454 workList_.pushBack(nextVertexId);
455 } else {
456 SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" merged with vertex #" <<nextVertexId <<" (no change)\n";
457 }
458 }
459 }
460 return !workList_.isEmpty();
461 }
462
464 void insertStartingVertex(size_t startVertexId, const State &initialState) {
465 incomingState_[startVertexId] = initialState;
466 workList_.pushBack(startVertexId);
467 }
468
475 while (runOneIteration()) /*void*/;
476 }
477
481 void runToFixedPoint(size_t startVertexId, const State &initialState) {
482 reset();
483 insertStartingVertex(startVertexId, initialState);
484 while (runOneIteration()) /*void*/;
485 }
486
491 State getInitialState(size_t cfgVertexId) const {
492 return incomingState_[cfgVertexId];
493 }
494
496 void setInitialState(size_t cfgVertexId, State state) {
497 incomingState_[cfgVertexId] = state;
498 }
499
504 State getFinalState(size_t cfgVertexId) const {
505 return outgoingState_[cfgVertexId];
506 }
507
513 return incomingState_;
514 }
515
521 return outgoingState_;
522 }
523 };
524};
525
526} // namespace
527} // namespace
528
529#endif
530#endif
Functor to return instructions for a cfg vertex.
Definition DataFlow.h:154
MergeFunction_ MergeFunction
Type of the function that merges two states into a single state.
Definition DataFlow.h:320
void runToFixedPoint()
Run data-flow until it reaches a fixed point.
Definition DataFlow.h:474
const VertexStates & getInitialStates() const
All incoming states.
Definition DataFlow.h:512
PathFeasibility_ PathFeasibility
Predicate testing whether certain CFG edges should be followed.
Definition DataFlow.h:321
size_t maxIterations() const
Max number of iterations to allow.
Definition DataFlow.h:394
State_ State
Type of the states stored at each CFG vertex.
Definition DataFlow.h:318
const Cfg & cfg() const
Data-flow control flow graph.
Definition DataFlow.h:355
Engine(const Cfg &cfg, TransferFunction &xfer, MergeFunction merge=MergeFunction(), PathFeasibility isFeasible=PathFeasibility())
Constructor.
Definition DataFlow.h:345
const VertexStates & getFinalStates() const
All outgoing states.
Definition DataFlow.h:520
void runToFixedPoint(size_t startVertexId, const State &initialState)
Add starting point and run to fixed point.
Definition DataFlow.h:481
Cfg_ Cfg
Type of the data-flow control flow graph.
Definition DataFlow.h:317
std::string prefix() const
Line prefix for debugging.
Definition DataFlow.h:380
State getInitialState(size_t cfgVertexId) const
Return the incoming state for the specified CFG vertex.
Definition DataFlow.h:491
void name(const std::string &s)
Property: Name for debugging.
Definition DataFlow.h:376
std::vector< State > VertexStates
Vector of states per vertex.
Definition DataFlow.h:322
void setInitialState(size_t cfgVertexId, State state)
Set the initial state for the specified CFG vertex.
Definition DataFlow.h:496
const std::string & name() const
Property: Name for debugging.
Definition DataFlow.h:375
void reset(State initialState=State())
Reset engine to initial state.
Definition DataFlow.h:360
size_t nIterations() const
Number of iterations run.
Definition DataFlow.h:401
void maxIterations(size_t n)
Max number of iterations to allow.
Definition DataFlow.h:395
void insertStartingVertex(size_t startVertexId, const State &initialState)
Add a starting vertex.
Definition DataFlow.h:464
State getFinalState(size_t cfgVertexId) const
Return the outgoing state for the specified CFG vertex.
Definition DataFlow.h:504
TransferFunction_ TransferFunction
Type of the transfer function that creates new states.
Definition DataFlow.h:319
bool runOneIteration()
Runs one iteration.
Definition DataFlow.h:407
Data-flow exception base class.
Definition DataFlow.h:100
Exceptions when a fixed point is not reached.
Definition DataFlow.h:106
Trivial path feasibility predicate.
Definition DataFlow.h:249
Basic merge operation for instruction semantics.
Definition DataFlow.h:218
Various tools for data-flow analysis.
Definition DataFlow.h:72
InstructionSemantics::DataFlowSemantics::DataFlowGraph Graph
Data-flow graph.
Definition DataFlow.h:79
std::list< Variable > VariableList
List of variables.
Definition DataFlow.h:89
VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex)
Compute data-flow per CFG vertex.
Definition DataFlow.h:204
VariableList getUniqueVariables(const VertexFlowGraphs &)
Get list of unique variables.
static void initDiagnostics()
Initialize diagnostics.
VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex, VertexUnpacker vertexUnpacker)
Compute data-flow per CFG vertex.
Definition DataFlow.h:174
AbstractLocation Variable
Variable participating in data flow.
Definition DataFlow.h:86
Sawyer::Container::Map< size_t, Graph > VertexFlowGraphs
Map from CFG vertex to data-flow graph.
Definition DataFlow.h:96
DataFlow(const InstructionSemantics::BaseSemantics::DispatcherPtr &userDispatcher)
Constructor.
Definition DataFlow.h:125
Graph buildGraph(const std::vector< SgAsmInstruction * > &)
Compute data-flow.
Base class for all ROSE exceptions.
A doubly-linked list of distinct items.
void clear()
Clear the list.
const Items & items() const
Return all items as a list.
void pushBack(const Item &item)
Insert item at back of list if distinct.
Item popFront()
Return and erase item at front of list.
bool isEmpty() const
Determines whether list is empty.
Container associating values with keys.
Definition Sawyer/Map.h:72
size_t size() const
Number of nodes, keys, or values in this container.
Definition Sawyer/Map.h:438
Map & insert(const Key &key, const Value &value)
Insert or update a key/value pair.
Definition Sawyer/Map.h:646
Collection of streams.
Definition Message.h:1606
Instruction basic block.
Base class for machine instructions.
boost::shared_ptr< RiscOperators > RiscOperatorsPtr
Shared-ownership pointer to a RISC operators object.
boost::shared_ptr< Dispatcher > DispatcherPtr
Shared-ownership pointer to a semantics instruction dispatcher.
ROSE_UTIL_API std::string numberToString(long long)
Convert an integer to a string.
ROSE_UTIL_API std::string prefixLines(const std::string &lines, const std::string &prefix, bool prefixAtFront=true, bool prefixAtBack=false)
Insert a prefix string before every line.
std::string plural(T n, const std::string &plural_phrase, const std::string &singular_phrase="")
Helpful way to print singular or plural words.
The ROSE library.