ROSE  0.11.145.0
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/Diagnostics.h>
8 #include <Rose/Exception.h>
9 #include <Rose/BinaryAnalysis/InstructionSemantics/SymbolicSemantics.h>
10 
11 #include <boost/lexical_cast.hpp>
12 #include <list>
13 #include <Sawyer/GraphTraversal.h>
14 #include <Sawyer/DistinctList.h>
15 #include <sstream>
16 #include <string>
17 #include <vector>
18 
19 namespace Rose {
20 namespace BinaryAnalysis {
21 
69 class DataFlow {
70 public:
77 
84 
86  typedef std::list<Variable> VariableList;
87 
94 
95 public:
97  class Exception: public Rose::Exception {
98  public:
99  explicit Exception(const std::string &s): Rose::Exception(s) {}
100  };
101 
103  class NotConverging: public Exception {
104  public:
105  explicit NotConverging(const std::string &s): Exception(s) {}
106  };
107 
108 private:
109  InstructionSemantics::BaseSemantics::RiscOperatorsPtr userOps_; // operators (and state) provided by the user
110  InstructionSemantics::DataFlowSemantics::RiscOperatorsPtr dfOps_; // data-flow operators (which point to user ops)
111  InstructionSemantics::BaseSemantics::DispatcherPtr dispatcher_; // copy of user's dispatcher but with DataFlowSemantics
112 
113 public:
114  static Sawyer::Message::Facility mlog; // diagnostics for data-flow
115 
116 public:
123  init(userDispatcher);
124  }
125 
129  static void initDiagnostics();
130 
131 private:
133 
134 public:
143  Graph buildGraph(const std::vector<SgAsmInstruction*>&);
152  public:
153  typedef std::vector<SgAsmInstruction*> Instructions;
154  Instructions operator()(SgAsmInstruction *insn) { return Instructions(1, insn); }
155  Instructions operator()(SgAsmBlock *blk);
156  };
157 
158 public:
170  template<class CFG, class VertexUnpacker>
171  VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex, VertexUnpacker vertexUnpacker) {
172  using namespace Diagnostics;
173  ASSERT_this();
174  ASSERT_require(startVertex < cfg.nVertices());
175  Stream mesg(mlog[WHERE] <<"buildGraphPerVertex startVertex=" <<startVertex);
176 
177  VertexFlowGraphs result;
178  result.insert(startVertex, buildGraph(vertexUnpacker(cfg.findVertex(startVertex)->value())));
179  std::vector<InstructionSemantics::BaseSemantics::StatePtr> postState(cfg.nVertices()); // user-defined states
180  postState[startVertex] = userOps_->currentState();
181 
183  for (Traversal t(cfg, cfg.findVertex(startVertex)); t; ++t) {
184  typename CFG::ConstVertexIterator source = t->source();
185  typename CFG::ConstVertexIterator target = t->target();
186  InstructionSemantics::BaseSemantics::StatePtr state = postState[target->id()];
187  if (state==NULL) {
188  ASSERT_not_null(postState[source->id()]);
189  state = postState[target->id()] = postState[source->id()]->clone();
190  userOps_->currentState(state);
191  std::vector<SgAsmInstruction*> insns = vertexUnpacker(target->value());
192  result.insert(target->id(), buildGraph(insns));
193  }
194  }
195 
196  mesg <<"; processed " <<StringUtility::plural(result.size(), "vertices", "vertex") <<"\n";
197  return result;
198  }
199 
200  template<class CFG>
201  VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex) {
202  return buildGraphPerVertex(cfg, startVertex, DefaultVertexUnpacker());
203  }
210  VariableList getUniqueVariables(const VertexFlowGraphs&);
211 
217  public:
219  explicit SemanticsMerge(const InstructionSemantics::BaseSemantics::DispatcherPtr &cpu): ops_(cpu->operators()) {}
220 
221  bool operator()(InstructionSemantics::BaseSemantics::StatePtr &dst /*in,out*/,
223  struct PreserveCurrentState {
226  PreserveCurrentState(const InstructionSemantics::BaseSemantics::RiscOperatorsPtr &ops)
227  : ops(ops), state(ops->currentState()) {}
228  ~PreserveCurrentState() { ops->currentState(state); }
229  } t(ops_);
230 
231  if (!dst) {
232  dst = src->clone();
233  return true;
234  } else {
235  ops_->currentState(src);
236  return dst->merge(src, ops_.get());
237  }
238  }
239  };
240 
245  template<class CFG, class State>
247  public:
248  bool operator()(const CFG&, const typename CFG::Edge&, const State&, const State&) {
249  return true;
250  }
251  };
252 
310  template<class Cfg_, class State_, class TransferFunction_, class MergeFunction_,
311  class PathFeasibility_ = PathAlwaysFeasible<Cfg_, State_> >
312  class Engine {
313  public:
314  using Cfg = Cfg_;
315  using State = State_;
316  using TransferFunction = TransferFunction_;
317  using MergeFunction = MergeFunction_;
318  using PathFeasibility = PathFeasibility_;
319  using VertexStates = std::vector<State>;
321  using CFG = Cfg_; // Deprecated [Robb Matzke 2023-01-27]
322 
323  private:
324  std::string name_; // optional name for debugging
325  const Cfg &cfg_;
326  TransferFunction &xfer_;
327  MergeFunction merge_;
328  VertexStates incomingState_; // incoming data-flow state per CFG vertex ID
329  VertexStates outgoingState_; // outgoing data-flow state per CFG vertex ID
331  WorkList workList_; // CFG vertex IDs to be visited, last in first out w/out duplicates
332  size_t maxIterations_; // max number of iterations to allow
333  size_t nIterations_; // number of iterations since last reset
334  PathFeasibility isFeasible_; // predicate to test path feasibility
335 
336  public:
343  PathFeasibility isFeasible = PathFeasibility())
344  : cfg_(cfg), xfer_(xfer), merge_(merge), maxIterations_(-1), nIterations_(0), isFeasible_(isFeasible) {
345  reset();
346  }
347 
352  const Cfg &cfg() const {
353  return cfg_;
354  }
355 
357  void reset(State initialState = State()) {
358  ASSERT_this();
359  incomingState_.clear();
360  incomingState_.resize(cfg_.nVertices(), initialState);
361  outgoingState_.clear();
362  outgoingState_.resize(cfg_.nVertices(), initialState);
363  workList_.clear();
364  nIterations_ = 0;
365  }
366 
372  const std::string& name() const { return name_; }
373  void name(const std::string &s) { name_ = s; }
377  std::string prefix() const {
378  if (name_.empty()) {
379  return "";
380  } else {
381  return name_ + ": ";
382  }
383  }
384 
391  size_t maxIterations() const { return maxIterations_; }
392  void maxIterations(size_t n) { maxIterations_ = n; }
398  size_t nIterations() const { return nIterations_; }
399 
405  using namespace Diagnostics;
406  if (!workList_.isEmpty()) {
407  if (++nIterations_ > maxIterations_) {
408  throw NotConverging("data-flow max iterations reached"
409  " (max=" + StringUtility::numberToString(maxIterations_) + ")");
410  }
411  size_t cfgVertexId = workList_.popFront();
412  if (mlog[DEBUG]) {
413  mlog[DEBUG] <<prefix() <<"runOneIteration: vertex #" <<cfgVertexId <<"\n";
414  mlog[DEBUG] <<prefix() <<" remaining worklist is {";
415  for (size_t id: workList_.items())
416  mlog[DEBUG] <<" " <<id;
417  mlog[DEBUG] <<" }\n";
418  }
419 
420  ASSERT_require2(cfgVertexId < cfg_.nVertices(),
421  "vertex " + boost::lexical_cast<std::string>(cfgVertexId) + " must be valid within CFG");
422  typename Cfg::ConstVertexIterator vertex = cfg_.findVertex(cfgVertexId);
423  State state = incomingState_[cfgVertexId];
424  if (mlog[DEBUG]) {
425  mlog[DEBUG] <<prefix() <<" incoming state for vertex #" <<cfgVertexId <<":\n"
426  <<StringUtility::prefixLines(xfer_.toString(state), prefix() + " ") <<"\n";
427  }
428 
429  state = outgoingState_[cfgVertexId] = xfer_(cfg_, cfgVertexId, state);
430  if (mlog[DEBUG]) {
431  mlog[DEBUG] <<prefix() <<" outgoing state for vertex #" <<cfgVertexId <<":\n"
432  <<StringUtility::prefixLines(xfer_.toString(state), prefix() + " ") <<"\n";
433  }
434 
435  // Outgoing state must be merged into the incoming states for the CFG successors. Any such incoming state that
436  // is modified as a result will have its CFG vertex added to the work list.
437  SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" forwarding vertex #" <<cfgVertexId <<" output state to "
438  <<StringUtility::plural(vertex->nOutEdges(), "vertices", "vertex") <<"\n";
439  for (const typename Cfg::Edge &edge: vertex->outEdges()) {
440  size_t nextVertexId = edge.target()->id();
441  if (!isFeasible_(cfg_, edge, state, incomingState_[nextVertexId])) {
442  SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" path to vertex #" <<nextVertexId
443  <<" is not feasible, thus skipped\n";
444  } else if (merge_(incomingState_[nextVertexId], state)) {
445  if (mlog[DEBUG]) {
446  mlog[DEBUG] <<prefix() <<" merged with vertex #" <<nextVertexId <<" (which changed as a result)\n";
447  mlog[DEBUG] <<prefix() <<" merge state is:\n"
448  <<StringUtility::prefixLines(xfer_.toString(incomingState_[nextVertexId]),
449  prefix() + " ", false) <<"\n";
450  }
451  workList_.pushBack(nextVertexId);
452  } else {
453  SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" merged with vertex #" <<nextVertexId <<" (no change)\n";
454  }
455  }
456  }
457  return !workList_.isEmpty();
458  }
459 
461  void insertStartingVertex(size_t startVertexId, const State &initialState) {
462  incomingState_[startVertexId] = initialState;
463  workList_.pushBack(startVertexId);
464  }
465 
472  while (runOneIteration()) /*void*/;
473  }
474 
478  void runToFixedPoint(size_t startVertexId, const State &initialState) {
479  reset();
480  insertStartingVertex(startVertexId, initialState);
481  while (runOneIteration()) /*void*/;
482  }
483 
488  State getInitialState(size_t cfgVertexId) const {
489  return incomingState_[cfgVertexId];
490  }
491 
493  void setInitialState(size_t cfgVertexId, State state) {
494  incomingState_[cfgVertexId] = state;
495  }
496 
501  State getFinalState(size_t cfgVertexId) const {
502  return outgoingState_[cfgVertexId];
503  }
504 
510  return incomingState_;
511  }
512 
517  const VertexStates& getFinalStates() const {
518  return outgoingState_;
519  }
520  };
521 };
522 
523 } // namespace
524 } // namespace
525 
526 #endif
527 #endif
const VertexStates & getFinalStates() const
All outgoing states.
Definition: DataFlow.h:517
Sawyer::Container::Map< size_t, Graph > VertexFlowGraphs
Map from CFG vertex to data-flow graph.
Definition: DataFlow.h:93
ROSE_UTIL_API std::string numberToString(long long)
Convert an integer to a string.
size_t nIterations() const
Number of iterations run.
Definition: DataFlow.h:398
Instruction basic block.
std::string plural(T n, const std::string &plural_phrase, const std::string &singular_phrase="")
Helpful way to print singular or plural words.
Basic merge operation for instruction semantics.
Definition: DataFlow.h:215
size_t maxIterations() const
Max number of iterations to allow.
Definition: DataFlow.h:391
State getInitialState(size_t cfgVertexId) const
Return the incoming state for the specified CFG vertex.
Definition: DataFlow.h:488
Engine(const Cfg &cfg, TransferFunction &xfer, MergeFunction merge=MergeFunction(), PathFeasibility isFeasible=PathFeasibility())
Constructor.
Definition: DataFlow.h:342
MergeFunction_ MergeFunction
Type of the function that merges two states into a single state.
Definition: DataFlow.h:317
boost::shared_ptr< RiscOperators > RiscOperatorsPtr
Shared-ownership pointer to a RISC operators object.
Base class for machine instructions.
Collection of streams.
Definition: Message.h:1606
Cfg_ Cfg
Type of the data-flow control flow graph.
Definition: DataFlow.h:314
AbstractLocation Variable
Variable participating in data flow.
Definition: DataFlow.h:83
void runToFixedPoint()
Run data-flow until it reaches a fixed point.
Definition: DataFlow.h:471
Depth-first, forward traversal for edges.
static void initDiagnostics()
Initialize diagnostics.
std::list< Variable > VariableList
List of variables.
Definition: DataFlow.h:86
void runToFixedPoint(size_t startVertexId, const State &initialState)
Add starting point and run to fixed point.
Definition: DataFlow.h:478
std::vector< State > VertexStates
Vector of states per vertex.
Definition: DataFlow.h:319
void maxIterations(size_t n)
Max number of iterations to allow.
Definition: DataFlow.h:392
Main namespace for the ROSE library.
bool isEmpty() const
Determines whether list is empty.
Definition: DistinctList.h:66
Graph buildGraph(const std::vector< SgAsmInstruction * > &)
Compute data-flow.
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.
InstructionSemantics::DataFlowSemantics::DataFlowGraph Graph
Data-flow graph.
Definition: DataFlow.h:76
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.
DataFlow(const InstructionSemantics::BaseSemantics::DispatcherPtr &userDispatcher)
Constructor.
Definition: DataFlow.h:122
VariableList getUniqueVariables(const VertexFlowGraphs &)
Get list of unique variables.
std::string prefix() const
Line prefix for debugging.
Definition: DataFlow.h:377
void reset(State initialState=State())
Reset engine to initial state.
Definition: DataFlow.h:357
const std::string & name() const
Property: Name for debugging.
Definition: DataFlow.h:372
VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex)
Compute data-flow per CFG vertex.
Definition: DataFlow.h:201
Exceptions when a fixed point is not reached.
Definition: DataFlow.h:103
bool runOneIteration()
Runs one iteration.
Definition: DataFlow.h:404
Trivial path feasibility predicate.
Definition: DataFlow.h:246
const Items & items() const
Return all items as a list.
Definition: DistinctList.h:181
void pushBack(const Item &item)
Insert item at back of list if distinct.
Definition: DistinctList.h:133
const Cfg & cfg() const
Data-flow control flow graph.
Definition: DataFlow.h:352
Item popFront()
Return and erase item at front of list.
Definition: DistinctList.h:145
Data-flow exception base class.
Definition: DataFlow.h:97
Various tools for data-flow analysis.
Definition: DataFlow.h:69
Map & insert(const Key &key, const Value &value)
Insert or update a key/value pair.
Definition: Sawyer/Map.h:628
const VertexStates & getInitialStates() const
All incoming states.
Definition: DataFlow.h:509
void insertStartingVertex(size_t startVertexId, const State &initialState)
Add a starting vertex.
Definition: DataFlow.h:461
Functor to return instructions for a cfg vertex.
Definition: DataFlow.h:151
void name(const std::string &s)
Property: Name for debugging.
Definition: DataFlow.h:373
State getFinalState(size_t cfgVertexId) const
Return the outgoing state for the specified CFG vertex.
Definition: DataFlow.h:501
Base class for all ROSE exceptions.
Definition: Rose/Exception.h:9
VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex, VertexUnpacker vertexUnpacker)
Compute data-flow per CFG vertex.
Definition: DataFlow.h:171
State_ State
Type of the states stored at each CFG vertex.
Definition: DataFlow.h:315
size_t size() const
Number of nodes, keys, or values in this container.
Definition: Sawyer/Map.h:420
void setInitialState(size_t cfgVertexId, State state)
Set the initial state for the specified CFG vertex.
Definition: DataFlow.h:493
void clear()
Clear the list.
Definition: DistinctList.h:58
PathFeasibility_ PathFeasibility
Predicate testing whether certain CFG edges should be followed.
Definition: DataFlow.h:318
TransferFunction_ TransferFunction
Type of the transfer function that creates new states.
Definition: DataFlow.h:316