ROSE 0.11.145.281
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/StringUtility/Convert.h>
10#include <Rose/StringUtility/Diagnostics.h>
11#include <Rose/StringUtility/NumberToString.h>
12
13#include <Sawyer/GraphTraversal.h>
14#include <Sawyer/DistinctList.h>
15#include <boost/lexical_cast.hpp>
16#include <list>
17#include <sstream>
18#include <string>
19#include <vector>
20
21namespace Rose {
22namespace BinaryAnalysis {
23
71class DataFlow {
72public:
79
86
88 typedef std::list<Variable> VariableList;
89
96
97public:
99 class Exception: public Rose::Exception {
100 public:
101 explicit Exception(const std::string&);
102 };
103
105 class NotConverging: public Exception {
106 public:
107 explicit NotConverging(const std::string&);
108 };
109
110private:
111 InstructionSemantics::BaseSemantics::RiscOperatorsPtr userOps_; // operators (and state) provided by the user
112 InstructionSemantics::DataFlowSemantics::RiscOperatorsPtr dfOps_; // data-flow operators (which point to user ops)
113 InstructionSemantics::BaseSemantics::DispatcherPtr dispatcher_; // copy of user's dispatcher but with DataFlowSemantics
114
115public:
116 static Sawyer::Message::Facility mlog; // diagnostics for data-flow
117
118public:
119 ~DataFlow();
120
127
131 static void initDiagnostics();
132
133private:
135
136public:
145 Graph buildGraph(const std::vector<SgAsmInstruction*>&);
154 public:
155 typedef std::vector<SgAsmInstruction*> Instructions;
156 Instructions operator()(SgAsmInstruction*);
157 Instructions operator()(SgAsmBlock*);
158 };
159
160public:
172 template<class CFG, class VertexUnpacker>
173 VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex, VertexUnpacker vertexUnpacker) {
174 using namespace Diagnostics;
175 ASSERT_this();
176 ASSERT_require(startVertex < cfg.nVertices());
177 Stream mesg(mlog[WHERE] <<"buildGraphPerVertex startVertex=" <<startVertex);
178
179 VertexFlowGraphs result;
180 result.insert(startVertex, buildGraph(vertexUnpacker(cfg.findVertex(startVertex)->value())));
181 std::vector<InstructionSemantics::BaseSemantics::StatePtr> postState(cfg.nVertices()); // user-defined states
182 postState[startVertex] = userOps_->currentState();
183
185 for (Traversal t(cfg, cfg.findVertex(startVertex)); t; ++t) {
186 typename CFG::ConstVertexIterator source = t->source();
187 typename CFG::ConstVertexIterator target = t->target();
188 InstructionSemantics::BaseSemantics::StatePtr state = postState[target->id()];
189 if (state==NULL) {
190 ASSERT_not_null(postState[source->id()]);
191 state = postState[target->id()] = postState[source->id()]->clone();
192 userOps_->currentState(state);
193 std::vector<SgAsmInstruction*> insns = vertexUnpacker(target->value());
194 result.insert(target->id(), buildGraph(insns));
195 }
196 }
197
198 mesg <<"; processed " <<StringUtility::plural(result.size(), "vertices", "vertex") <<"\n";
199 return result;
200 }
201
202 template<class CFG>
203 VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex) {
204 return buildGraphPerVertex(cfg, startVertex, DefaultVertexUnpacker());
205 }
213
229
234 template<class CFG, class State>
236 public:
237 bool operator()(const CFG&, const typename CFG::Edge&, const State&, const State&) {
238 return true;
239 }
240 };
241
296 template<class Cfg_, class State_, class TransferFunction_, class MergeFunction_,
297 class PathFeasibility_ = PathAlwaysFeasible<Cfg_, State_> >
298 class Engine {
299 public:
300 using Cfg = Cfg_;
301 using State = State_;
302 using TransferFunction = TransferFunction_;
303 using MergeFunction = MergeFunction_;
304 using PathFeasibility = PathFeasibility_;
305 using VertexStates = std::vector<State>;
307 using CFG = Cfg_; // Deprecated [Robb Matzke 2023-01-27]
308
309 private:
310 std::string name_; // optional name for debugging
311 const Cfg &cfg_;
312 TransferFunction &xfer_;
313 MergeFunction merge_;
314 VertexStates incomingState_; // incoming data-flow state per CFG vertex ID
315 VertexStates outgoingState_; // outgoing data-flow state per CFG vertex ID
317 WorkList workList_; // CFG vertex IDs to be visited, last in first out w/out duplicates
318 size_t maxIterations_; // max number of iterations to allow
319 size_t nIterations_; // number of iterations since last reset
320 PathFeasibility isFeasible_; // predicate to test path feasibility
321
322 public:
329 PathFeasibility isFeasible = PathFeasibility())
330 : cfg_(cfg), xfer_(xfer), merge_(merge), maxIterations_(-1), nIterations_(0), isFeasible_(isFeasible) {
331 reset();
332 }
333
338 const Cfg &cfg() const {
339 return cfg_;
340 }
341
343 void reset(State initialState = State()) {
344 ASSERT_this();
345 incomingState_.clear();
346 incomingState_.resize(cfg_.nVertices(), initialState);
347 outgoingState_.clear();
348 outgoingState_.resize(cfg_.nVertices(), initialState);
349 workList_.clear();
350 nIterations_ = 0;
351 }
352
358 const std::string& name() const { return name_; }
359 void name(const std::string &s) { name_ = s; }
363 std::string prefix() const {
364 if (name_.empty()) {
365 return "";
366 } else {
367 return name_ + ": ";
368 }
369 }
370
377 size_t maxIterations() const { return maxIterations_; }
378 void maxIterations(size_t n) { maxIterations_ = n; }
384 size_t nIterations() const { return nIterations_; }
385
391 using namespace Diagnostics;
392 if (!workList_.isEmpty()) {
393 if (++nIterations_ > maxIterations_) {
394 throw NotConverging("data-flow max iterations reached"
395 " (max=" + StringUtility::numberToString(maxIterations_) + ")");
396 }
397 size_t cfgVertexId = workList_.popFront();
398 if (mlog[DEBUG]) {
399 mlog[DEBUG] <<prefix() <<"runOneIteration: vertex #" <<cfgVertexId <<"\n";
400 mlog[DEBUG] <<prefix() <<" remaining worklist is {";
401 for (size_t id: workList_.items())
402 mlog[DEBUG] <<" " <<id;
403 mlog[DEBUG] <<" }\n";
404 }
405
406 ASSERT_require2(cfgVertexId < cfg_.nVertices(),
407 "vertex " + boost::lexical_cast<std::string>(cfgVertexId) + " must be valid within CFG");
408 typename Cfg::ConstVertexIterator vertex = cfg_.findVertex(cfgVertexId);
409 State state = incomingState_[cfgVertexId];
410 if (mlog[DEBUG]) {
411 mlog[DEBUG] <<prefix() <<" incoming state for vertex #" <<cfgVertexId <<":\n"
412 <<StringUtility::prefixLines(xfer_.toString(state), prefix() + " ") <<"\n";
413 }
414
415 state = outgoingState_[cfgVertexId] = xfer_(cfg_, cfgVertexId, state);
416 if (mlog[DEBUG]) {
417 mlog[DEBUG] <<prefix() <<" outgoing state for vertex #" <<cfgVertexId <<":\n"
418 <<StringUtility::prefixLines(xfer_.toString(state), prefix() + " ") <<"\n";
419 }
420
421 // Outgoing state must be merged into the incoming states for the CFG successors. Any such incoming state that
422 // is modified as a result will have its CFG vertex added to the work list.
423 SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" forwarding vertex #" <<cfgVertexId <<" output state to "
424 <<StringUtility::plural(vertex->nOutEdges(), "vertices", "vertex") <<"\n";
425 for (const typename Cfg::Edge &edge: vertex->outEdges()) {
426 const size_t nextVertexId = edge.target()->id();
427 if (!isFeasible_(cfg_, edge, state, incomingState_[nextVertexId])) {
428 SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" path to vertex #" <<nextVertexId
429 <<" is not feasible, thus skipped\n";
430 } else if (merge_(nextVertexId, incomingState_[nextVertexId], cfgVertexId, state)) {
431 if (mlog[DEBUG]) {
432 mlog[DEBUG] <<prefix() <<" merged into vertex #" <<nextVertexId <<" (which changed)\n";
433 mlog[DEBUG] <<prefix() <<" new incoming state for vertex #" <<nextVertexId <<" is:\n"
434 <<prefix() <<" "
435 <<StringUtility::prefixLines(xfer_.toString(incomingState_[nextVertexId]),
436 prefix() + " ", false) <<"\n";
437 }
438 workList_.pushBack(nextVertexId);
439 } else {
440 SAWYER_MESG(mlog[DEBUG]) <<prefix() <<" merged into vertex #" <<nextVertexId <<" (not changed)\n";
441 }
442 }
443 }
444 return !workList_.isEmpty();
445 }
446
448 void insertStartingVertex(size_t startVertexId, const State &initialState) {
449 incomingState_[startVertexId] = initialState;
450 workList_.pushBack(startVertexId);
451 }
452
459 while (runOneIteration()) /*void*/;
460 }
461
465 void runToFixedPoint(size_t startVertexId, const State &initialState) {
466 reset();
467 insertStartingVertex(startVertexId, initialState);
468 while (runOneIteration()) /*void*/;
469 }
470
475 State getInitialState(size_t cfgVertexId) const {
476 return incomingState_[cfgVertexId];
477 }
478
480 void setInitialState(size_t cfgVertexId, State state) {
481 incomingState_[cfgVertexId] = state;
482 }
483
488 State getFinalState(size_t cfgVertexId) const {
489 return outgoingState_[cfgVertexId];
490 }
491
497 return incomingState_;
498 }
499
505 return outgoingState_;
506 }
507 };
508};
509
510} // namespace
511} // namespace
512
513#endif
514#endif
Functor to return instructions for a cfg vertex.
Definition DataFlow.h:153
MergeFunction_ MergeFunction
Type of the function that merges two states into a single state.
Definition DataFlow.h:303
void runToFixedPoint()
Run data-flow until it reaches a fixed point.
Definition DataFlow.h:458
const VertexStates & getInitialStates() const
All incoming states.
Definition DataFlow.h:496
PathFeasibility_ PathFeasibility
Predicate testing whether certain CFG edges should be followed.
Definition DataFlow.h:304
size_t maxIterations() const
Max number of iterations to allow.
Definition DataFlow.h:377
State_ State
Type of the states stored at each CFG vertex.
Definition DataFlow.h:301
const Cfg & cfg() const
Data-flow control flow graph.
Definition DataFlow.h:338
Engine(const Cfg &cfg, TransferFunction &xfer, MergeFunction merge=MergeFunction(), PathFeasibility isFeasible=PathFeasibility())
Constructor.
Definition DataFlow.h:328
const VertexStates & getFinalStates() const
All outgoing states.
Definition DataFlow.h:504
void runToFixedPoint(size_t startVertexId, const State &initialState)
Add starting point and run to fixed point.
Definition DataFlow.h:465
Cfg_ Cfg
Type of the data-flow control flow graph.
Definition DataFlow.h:300
std::string prefix() const
Line prefix for debugging.
Definition DataFlow.h:363
State getInitialState(size_t cfgVertexId) const
Return the incoming state for the specified CFG vertex.
Definition DataFlow.h:475
void name(const std::string &s)
Property: Name for debugging.
Definition DataFlow.h:359
std::vector< State > VertexStates
Vector of states per vertex.
Definition DataFlow.h:305
void setInitialState(size_t cfgVertexId, State state)
Set the initial state for the specified CFG vertex.
Definition DataFlow.h:480
const std::string & name() const
Property: Name for debugging.
Definition DataFlow.h:358
void reset(State initialState=State())
Reset engine to initial state.
Definition DataFlow.h:343
size_t nIterations() const
Number of iterations run.
Definition DataFlow.h:384
void maxIterations(size_t n)
Max number of iterations to allow.
Definition DataFlow.h:378
void insertStartingVertex(size_t startVertexId, const State &initialState)
Add a starting vertex.
Definition DataFlow.h:448
State getFinalState(size_t cfgVertexId) const
Return the outgoing state for the specified CFG vertex.
Definition DataFlow.h:488
TransferFunction_ TransferFunction
Type of the transfer function that creates new states.
Definition DataFlow.h:302
bool runOneIteration()
Runs one iteration.
Definition DataFlow.h:390
Data-flow exception base class.
Definition DataFlow.h:99
Exceptions when a fixed point is not reached.
Definition DataFlow.h:105
Trivial path feasibility predicate.
Definition DataFlow.h:235
Basic merge operation for instruction semantics.
Definition DataFlow.h:217
Various tools for data-flow analysis.
Definition DataFlow.h:71
InstructionSemantics::DataFlowSemantics::DataFlowGraph Graph
Data-flow graph.
Definition DataFlow.h:78
std::list< Variable > VariableList
List of variables.
Definition DataFlow.h:88
VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex)
Compute data-flow per CFG vertex.
Definition DataFlow.h:203
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:173
AbstractLocation Variable
Variable participating in data flow.
Definition DataFlow.h:85
Sawyer::Container::Map< size_t, Graph > VertexFlowGraphs
Map from CFG vertex to data-flow graph.
Definition DataFlow.h:95
DataFlow(const InstructionSemantics::BaseSemantics::DispatcherPtr &userDispatcher)
Constructor.
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.