1#ifndef ROSE_BinaryAnalysis_DataFlow_H
2#define ROSE_BinaryAnalysis_DataFlow_H
3#include <featureTests.h>
4#ifdef ROSE_ENABLE_BINARY_ANALYSIS
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>
13#include <Sawyer/GraphTraversal.h>
14#include <Sawyer/DistinctList.h>
15#include <boost/lexical_cast.hpp>
22namespace BinaryAnalysis {
112 InstructionSemantics::DataFlowSemantics::RiscOperatorsPtr dfOps_;
155 typedef std::vector<SgAsmInstruction*> Instructions;
172 template<
class CFG,
class VertexUnpacker>
174 using namespace Diagnostics;
176 ASSERT_require(startVertex < cfg.nVertices());
177 Stream mesg(mlog[WHERE] <<
"buildGraphPerVertex startVertex=" <<startVertex);
180 result.
insert(startVertex,
buildGraph(vertexUnpacker(cfg.findVertex(startVertex)->value())));
181 std::vector<InstructionSemantics::BaseSemantics::StatePtr> postState(cfg.nVertices());
182 postState[startVertex] = userOps_->currentState();
185 for (Traversal t(cfg, cfg.findVertex(startVertex)); t; ++t) {
186 typename CFG::ConstVertexIterator source = t->source();
187 typename CFG::ConstVertexIterator target = t->target();
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());
234 template<
class CFG,
class State>
237 bool operator()(
const CFG&,
const typename CFG::Edge&,
const State&,
const State&) {
296 template<
class Cfg_,
class State_,
class TransferFunction_,
class MergeFunction_,
318 size_t maxIterations_;
330 : cfg_(
cfg), xfer_(xfer), merge_(merge), maxIterations_(-1), nIterations_(0), isFeasible_(isFeasible) {
345 incomingState_.clear();
346 incomingState_.resize(cfg_.nVertices(), initialState);
347 outgoingState_.clear();
348 outgoingState_.resize(cfg_.nVertices(), initialState);
358 const std::string&
name()
const {
return name_; }
359 void name(
const std::string &s) { name_ = s; }
391 using namespace Diagnostics;
393 if (++nIterations_ > maxIterations_) {
397 size_t cfgVertexId = workList_.
popFront();
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";
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];
411 mlog[DEBUG] <<
prefix() <<
" incoming state for vertex #" <<cfgVertexId <<
":\n"
415 state = outgoingState_[cfgVertexId] = xfer_(cfg_, cfgVertexId, state);
417 mlog[DEBUG] <<
prefix() <<
" outgoing state for vertex #" <<cfgVertexId <<
":\n"
423 SAWYER_MESG(mlog[DEBUG]) <<
prefix() <<
" forwarding vertex #" <<cfgVertexId <<
" output state to "
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)) {
432 mlog[DEBUG] <<
prefix() <<
" merged into vertex #" <<nextVertexId <<
" (which changed)\n";
433 mlog[DEBUG] <<
prefix() <<
" new incoming state for vertex #" <<nextVertexId <<
" is:\n"
436 prefix() +
" ",
false) <<
"\n";
440 SAWYER_MESG(mlog[DEBUG]) <<
prefix() <<
" merged into vertex #" <<nextVertexId <<
" (not changed)\n";
449 incomingState_[startVertexId] = initialState;
476 return incomingState_[cfgVertexId];
481 incomingState_[cfgVertexId] = state;
489 return outgoingState_[cfgVertexId];
497 return incomingState_;
505 return outgoingState_;
Functor to return instructions for a cfg vertex.
MergeFunction_ MergeFunction
Type of the function that merges two states into a single state.
void runToFixedPoint()
Run data-flow until it reaches a fixed point.
const VertexStates & getInitialStates() const
All incoming states.
PathFeasibility_ PathFeasibility
Predicate testing whether certain CFG edges should be followed.
size_t maxIterations() const
Max number of iterations to allow.
State_ State
Type of the states stored at each CFG vertex.
const Cfg & cfg() const
Data-flow control flow graph.
Engine(const Cfg &cfg, TransferFunction &xfer, MergeFunction merge=MergeFunction(), PathFeasibility isFeasible=PathFeasibility())
Constructor.
const VertexStates & getFinalStates() const
All outgoing states.
void runToFixedPoint(size_t startVertexId, const State &initialState)
Add starting point and run to fixed point.
Cfg_ Cfg
Type of the data-flow control flow graph.
std::string prefix() const
Line prefix for debugging.
State getInitialState(size_t cfgVertexId) const
Return the incoming state for the specified CFG vertex.
void name(const std::string &s)
Property: Name for debugging.
std::vector< State > VertexStates
Vector of states per vertex.
void setInitialState(size_t cfgVertexId, State state)
Set the initial state for the specified CFG vertex.
const std::string & name() const
Property: Name for debugging.
void reset(State initialState=State())
Reset engine to initial state.
size_t nIterations() const
Number of iterations run.
void maxIterations(size_t n)
Max number of iterations to allow.
void insertStartingVertex(size_t startVertexId, const State &initialState)
Add a starting vertex.
State getFinalState(size_t cfgVertexId) const
Return the outgoing state for the specified CFG vertex.
TransferFunction_ TransferFunction
Type of the transfer function that creates new states.
bool runOneIteration()
Runs one iteration.
Data-flow exception base class.
Exceptions when a fixed point is not reached.
Trivial path feasibility predicate.
Basic merge operation for instruction semantics.
Various tools for data-flow analysis.
InstructionSemantics::DataFlowSemantics::DataFlowGraph Graph
Data-flow graph.
std::list< Variable > VariableList
List of variables.
VertexFlowGraphs buildGraphPerVertex(const CFG &cfg, size_t startVertex)
Compute data-flow per CFG vertex.
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.
AbstractLocation Variable
Variable participating in data flow.
Sawyer::Container::Map< size_t, Graph > VertexFlowGraphs
Map from CFG vertex to data-flow graph.
DataFlow(const InstructionSemantics::BaseSemantics::DispatcherPtr &userDispatcher)
Constructor.
Graph buildGraph(const std::vector< SgAsmInstruction * > &)
Compute data-flow.
Base class for all ROSE exceptions.
Depth-first, forward traversal for edges.
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.
size_t size() const
Number of nodes, keys, or values in this container.
Map & insert(const Key &key, const Value &value)
Insert or update a key/value pair.
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.
boost::shared_ptr< State > StatePtr
Shared-ownership pointer to a semantic state.
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.