68 return n.raw !=
nullptr ?
n.raw->toString() :
"";
73 std::string str =
"shape=record";
76 str +=
",color=yellow";
78 str +=
",color=green";
84 str +=
",color=purple";
86 str +=
",color=black";
91 template <
class EdgeIter>
96 return "style=dashed,color=gray";
98 return "style=solid,color=red";
100 return "style=solid,color=blue";
101 return "style=solid";
117 return "SlicedThreadCallGraph";
127 return n.raw !=
nullptr ?
n.raw->getName() :
"";
132 return "shape=record,color=black";
135 template <
class EdgeIter>
140 return "color=green";
143 return "color=black";
169 return n.raw !=
nullptr ?
n.raw->toString() :
"";
174 return "shape=record,color=black";
177 template <
class EdgeIter>
180 const SVFStmt* s = EI.currentEdge().underlying;
186 return "color=purple";
188 return "color=green";
190 return "color=orange";
193 return "color=black";
219 return n.raw !=
nullptr ?
n.raw->toString() :
"";
225 return "shape=record,color=red";
227 return "shape=record,color=blue";
228 return "shape=record,color=black";
231 template <
class EdgeIter>
234 const SVFGEdge* e = EI.currentEdge().underlying;
236 return "style=dashed";
237 return "style=solid";
259 assert(
svfg !=
nullptr &&
"SlicedSVFGView: bind the SVFG before dumping");
279 const ICFGNode* node, std::vector<const ICFGNode*>& out)
const
288 for (
auto it = GT::child_begin(
n), e = GT::child_end(
n); it != e; ++it)
289 out.push_back((*it).raw);
293 const ICFGNode* node, std::vector<const ICFGNode*>& out)
const
302 for (
auto it = GT::child_begin(
n), e = GT::child_end(
n); it != e; ++it)
303 out.push_back((*it).raw);
323 keptNodes.insert(keepNodes.begin(), keepNodes.end());
339 std::vector<const ICFGNode*> removed;
347 removedNodeIndex[node] =
static_cast<int>(removed.size());
348 removed.push_back(node);
350 const int removedNodeCount =
static_cast<int>(removed.size());
372 std::vector<std::vector<int>> removedSuccessors(removedNodeCount);
373 std::vector<std::vector<const ICFGNode*>>
374 keptSuccessors(removedNodeCount);
375 std::vector<const ICFGNode*> successors;
376 for (
int nodeIndex = 0; nodeIndex < removedNodeCount; ++nodeIndex)
379 for (
const ICFGNode* successor : successors)
382 keptSuccessors[nodeIndex].push_back(successor);
385 const auto found = removedNodeIndex.find(successor);
386 if (found != removedNodeIndex.end())
387 removedSuccessors[nodeIndex].push_back(found->second);
394 std::vector<int> discoveryIndex(removedNodeCount, -1);
395 std::vector<int> lowLink(removedNodeCount, 0);
396 std::vector<int> component(removedNodeCount, -1);
397 std::vector<char> onStack(removedNodeCount, 0);
398 std::vector<int> tarjanStack;
399 int nextDiscoveryIndex = 0;
400 int componentCount = 0;
401 for (
int root = 0; root < removedNodeCount; ++root)
403 if (discoveryIndex[root] != -1)
405 std::vector<std::pair<int, size_t>> work;
406 work.emplace_back(root, 0);
407 while (!work.empty())
409 const int nodeIndex = work.back().first;
410 size_t& successorPosition = work.back().second;
411 if (successorPosition == 0)
413 discoveryIndex[nodeIndex] =
414 lowLink[nodeIndex] = nextDiscoveryIndex++;
415 tarjanStack.push_back(nodeIndex);
416 onStack[nodeIndex] = 1;
418 bool descend =
false;
419 while (successorPosition < removedSuccessors[nodeIndex].size())
421 const int successorIndex =
422 removedSuccessors[nodeIndex][successorPosition++];
423 if (discoveryIndex[successorIndex] == -1)
425 work.emplace_back(successorIndex, 0);
429 if (onStack[successorIndex] &&
430 discoveryIndex[successorIndex] < lowLink[nodeIndex])
431 lowLink[nodeIndex] = discoveryIndex[successorIndex];
435 if (lowLink[nodeIndex] == discoveryIndex[nodeIndex])
439 const int componentNode = tarjanStack.back();
440 tarjanStack.pop_back();
441 onStack[componentNode] = 0;
442 component[componentNode] = componentCount;
443 if (componentNode == nodeIndex)
451 const int parentIndex = work.back().first;
452 if (lowLink[nodeIndex] < lowLink[parentIndex])
453 lowLink[parentIndex] = lowLink[nodeIndex];
459 std::vector<OrderedSet<const ICFGNode*>> baseKept(componentCount);
460 std::vector<OrderedSet<int>> componentSuccessors(componentCount);
461 for (
int nodeIndex = 0; nodeIndex < removedNodeCount; ++nodeIndex)
463 const int componentIndex = component[nodeIndex];
464 for (
const ICFGNode* keptSuccessor : keptSuccessors[nodeIndex])
465 baseKept[componentIndex].insert(keptSuccessor);
466 for (
int successorIndex : removedSuccessors[nodeIndex])
467 if (component[successorIndex] != componentIndex)
468 componentSuccessors[componentIndex].insert(
469 component[successorIndex]);
473 std::vector<OrderedSet<const ICFGNode*>>
474 reachableKeptNodes(componentCount);
475 for (
int componentIndex = 0; componentIndex < componentCount;
479 reachableKeptNodes[componentIndex];
480 reachable = baseKept[componentIndex];
481 for (
int successorComponent : componentSuccessors[componentIndex])
483 reachableKeptNodes[successorComponent].begin(),
484 reachableKeptNodes[successorComponent].end());
492 const auto seedReturn = seedRet.find(source);
493 for (
const ICFGNode* successor : successors)
499 if (seedReturn != seedRet.end() &&
500 seedReturn->second == successor)
507 const auto removedIndex = removedNodeIndex.find(successor);
508 if (removedIndex == removedNodeIndex.end())
511 <<
"[ERROR] Local ICFG successor is neither kept nor indexed\n";
515 reachableKeptNodes[component[removedIndex->second]])
523 size_t totalBridgedEdges = 0;
525 totalBridgedEdges += pair.second.size();
526 SVFUtil::outs() <<
"[SlicedICFGView] Built " << totalBridgedEdges
528 <<
" source nodes\n";
534 std::vector<const ICFGNode*>& successors)
539 edge->getDstNode() !=
nullptr)
540 successors.push_back(edge->getDstNode());
542 const auto returnNode = callsiteReturnNodes.find(node);
543 if (returnNode != callsiteReturnNodes.end())
544 successors.push_back(returnNode->second);
573 for (
u32_t i = 0; i < multi->getOpVarNum(); ++i)
596 for (
const FunObjVar* fun : keptFunctions)
613 if (node !=
nullptr && node->
getFunction() !=
nullptr &&
622 const CallGraphNode* node, std::vector<const CallGraphEdge*>& out)
const
632 for (
auto it = GT::child_edge_begin(
n), e = GT::child_edge_end(
n); it != e; ++it)
633 out.push_back((*it).underlying);
637 const CallGraphNode* node, std::vector<const CallGraphEdge*>& out)
const
646 for (
auto it = GT::child_edge_begin(
n), e = GT::child_edge_end(
n); it != e; ++it)
647 out.push_back((*it).underlying);
651 const CallGraphEdge* edge, std::vector<const CallICFGNode*>& out)
const
656 out.insert(out.end(), found->second.begin(), found->second.end());
660 const CallGraphEdge* edge, std::vector<const CallICFGNode*>& out)
const
665 out.insert(out.end(), found->second.begin(), found->second.end());
676 indirect->second.count(callSite);
688 std::vector<const CallGraphEdge*> outEdges;
694 callees.insert(edge->getDstNode()->getFunction());
701 std::vector<const CallGraphEdge*>& out)
const
705 !
tcg->hasThreadForkEdge(callSite))
707 for (
auto it =
tcg->getForkEdgeBegin(callSite),
708 end =
tcg->getForkEdgeEnd(callSite); it != end; ++it)
720 std::vector<const CallGraphEdge*>& out)
const
724 !
tcg->hasThreadJoinEdge(callSite))
726 for (
auto it =
tcg->getJoinEdgeBegin(callSite),
727 end =
tcg->getJoinEdgeEnd(callSite); it != end; ++it)
754 const CallGraphNode* dstNode = edge ? edge->getDstNode() :
nullptr;
755 if (dstNode ==
nullptr || !
keptNodes.count(dstNode))
761 for (
const CallICFGNode* callSite : edge->getDirectCalls())
763 retainedDirect.insert(callSite);
766 for (
const CallICFGNode* callSite : edge->getIndirectCalls())
768 retainedIndirect.insert(callSite);
770 const bool hasOriginalCallSites =
771 !edge->getDirectCalls().empty() || !edge->getIndirectCalls().empty();
772 if (hasOriginalCallSites && retainedDirect.empty() && retainedIndirect.empty())
788 if (callSite ==
nullptr || !
tcg->hasIndCSCallees(callSite))
821 for (
const ICFGNode* node : keepNodes)
823 if (node !=
nullptr && node->getFun() !=
nullptr)
825 keptFunctions.insert(node->getFun());
828 for (
const FunObjVar* fun : keptFunctions)
834 tcgView = std::make_unique<SlicedThreadCallGraphView>(
835 &callGraph, keptFunctions, extendedKeepNodes);
838 icfgView = std::make_unique<SlicedICFGView>(
839 icfg, extendedKeepNodes);
853 keptStmts.insert(stmts.begin(), stmts.end());
855 pagView = std::make_unique<SlicedPAGView>(
svfir, keptStmts);
861 tcgView->dump(prefix +
"_threadcallgraph");
867 std::string label = prefix.empty() ?
"[SlicedSVFIRView]" :
"[" + prefix +
"]";
874 SVFUtil::outs() <<
" Indirect callsites that lost all targets: "
892 if (
const ICFGNode* fe =
icfg->getFunEntryICFGNode(fun))
918 std::vector<const ICFGNode*>& out)
const
Set< const CallICFGNode * > CallInstSet
const FunObjVar * getFunction() const
Get function of this call node.
Set< const FunObjVar * > FunctionSet
const RetICFGNode * getRetICFGNode() const
Return callsite.
const SVFBasicBlock * getEntryBlock() const
NodeType * getSrcNode() const
NodeType * getDstNode() const
GEdgeKind getEdgeKind() const
IDToNodeMapTy::iterator iterator
const GEdgeSetTy & getOutEdges() const
static void WriteGraphToFile(SVF::OutStream &O, const std::string &GraphName, const GraphType >, bool simple=false)
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
std::list< const SVFStmt * > SVFStmtList
ICFGNodeIDToNodeMapTy::iterator iterator
FunExitICFGNode * getFunExitICFGNode(const FunObjVar *fun)
Add a function exit node.
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
const std::vector< const ICFGNode * > & getICFGNodeList() const
const ICFGNode * front() const
static void getLocalSuccessors(const ICFGNode *node, const Map< const ICFGNode *, const ICFGNode * > &callsiteReturnNodes, std::vector< const ICFGNode * > &successors)
const ICFGNode * getFunExit(const FunObjVar *fun) const
Kept synthetic exit node of fun, or null when fun is outside the view.
Set< const ICFGNode * > keptNodesSet
void getPredNodes(const ICFGNode *node, std::vector< const ICFGNode * > &out) const
Get predecessor nodes (including bridged edges).
Map< const ICFGNode *, OrderedSet< const ICFGNode * > > bridgedPreds
void dump(const std::string &filename) const
Dump sliced ICFG to dot file.
bool isKeptNode(const ICFGNode *node) const
Check if a node is in the sliced view.
SlicedICFGView(ICFG *icfg, const OrderedSet< const ICFGNode * > &keepNodes)
Build an ICFG view from its explicit node membership.
void getSuccNodes(const ICFGNode *node, std::vector< const ICFGNode * > &out) const
Get successor nodes (including bridged edges).
Map< const ICFGNode *, OrderedSet< const ICFGNode * > > bridgedEdges
const ICFGNode * getFunEntry(const FunObjVar *fun) const
First kept node of fun's entry, or null when fun is outside the view.
void buildICFGSets(const OrderedSet< const ICFGNode * > &keepNodes)
void getFunICFGNodes(const FunObjVar *fun, std::vector< const ICFGNode * > &out) const
Kept ICFG nodes of fun.
OrderedSet< const ICFGNode * > keptNodes
SlicedPAGView(SVFIR *pag, const OrderedSet< const SVFStmt * > &keptStmts)
Set< NodeID > keptNodeIds
void dump(const std::string &filename) const
Dump the sliced PAG to a dot file.
OrderedSet< const SVFStmt * > keptStmts
size_t getKeptNodeCount() const
bool isKeptNode(const SVFGNode *n) const
Whether the node is retained (see the class comment for the rule).
void dump(const std::string &filename) const
Dump the sliced SVFG (retained nodes/edges only) via GraphWriter.
const Set< const FunObjVar * > & getKeptFunctions() const
Get all kept functions.
std::unique_ptr< SlicedPAGView > pagView
std::unique_ptr< SlicedThreadCallGraphView > tcgView
void dumpAll(const std::string &prefix) const
Dump all views to files.
std::unique_ptr< SlicedICFGView > icfgView
const SlicedPAGView * getPAG() const
Get SlicedPAGView.
void dumpStats(const std::string &prefix="") const
Output statistics.
SlicedSVFIRView(SVFIR *svfir, ThreadCallGraph &callGraph, ICFG *icfg, const OrderedSet< const ICFGNode * > &keepNodes)
const OrderedSet< const SVFStmt * > & getKeptStatements() const
Get all kept statements.
void ensurePAGView() const
const Set< const CallICFGNode * > & getIndirectSitesWithEmptyTargets() const
Get indirect call sites that lost all targets after filtering.
void getCalleesOf(const CallICFGNode *callSite, CallGraph::FunctionSet &callees) const
Retained callees of a callsite.
void getDirectCallsOf(const CallGraphEdge *edge, std::vector< const CallICFGNode * > &out) const
Retained callsites carried by an aggregated call-graph edge.
void buildCallGraphSets()
bool isKeptNode(const CallGraphNode *node) const
Check if a node is in the sliced view.
void dump(const std::string &filename) const
Dump sliced ThreadCallGraph to dot file.
OrderedSet< const CallGraphNode * > keptNodes
Set< const CallGraphEdge * > keptEdges
bool containsCallSite(const CallGraphEdge *edge, const CallICFGNode *callSite) const
Whether this precise callsite-to-callee relation is retained.
void getIndirectCallsOf(const CallGraphEdge *edge, std::vector< const CallICFGNode * > &out) const
Set< const FunObjVar * > keptFunctionsSet
Map< const CallGraphEdge *, CallGraphEdge::CallInstSet > keptDirectCalls
void getForkEdgesOf(const CallICFGNode *callSite, std::vector< const CallGraphEdge * > &out) const
void getOutEdgesOf(const CallGraphNode *node, std::vector< const CallGraphEdge * > &out) const
Get out edges of a node (only returns kept edges and target nodes).
Set< const CallICFGNode * > indirectSitesWithEmptyTargets
void getInEdgesOf(const CallGraphNode *node, std::vector< const CallGraphEdge * > &out) const
Get in edges of a node (only returns kept edges and source nodes).
void getJoinEdgesOf(const CallICFGNode *callSite, std::vector< const CallGraphEdge * > &out) const
Map< const CallGraphEdge *, CallGraphEdge::CallInstSet > keptIndirectCalls
OrderedSet< const ICFGNode * > extendedKeptNodes
SlicedThreadCallGraphView(ThreadCallGraph *tcg, const OrderedSet< const FunObjVar * > &keptFunctions, const OrderedSet< const ICFGNode * > &extendedKeptNodes)
LLVM_NODISCARD bool isa(const Y &Val)
std::ostream & errs()
Overwrite llvm::errs().
std::ostream & outs()
Overwrite llvm::outs().
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
SlicedNodeRef< SlicedSVFGView, SVFGNode > SlicedSVFGNodeRef
SlicedNodeRef< SlicedThreadCallGraphView, CallGraphNode > SlicedCallGraphNodeRef
std::set< Key, Compare, Allocator > OrderedSet
SlicedNodeRef< SlicedICFGView, ICFGNode > SlicedICFGNodeRef
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
SlicedNodeRef< SlicedPAGView, SVFVar > SlicedPAGNodeRef
std::string getNodeLabel(SlicedICFGNodeRef n, const SlicedICFGView *)
static std::string getNodeAttributes(SlicedICFGNodeRef n, const SlicedICFGView *)
static std::string getEdgeAttributes(SlicedICFGNodeRef, EdgeIter EI, const SlicedICFGView *)
static std::string getGraphName(const SlicedICFGView *)
static const void * getNodeIdentifier(SlicedICFGNodeRef n)
DOTGraphTraits(bool isSimple=false)
std::string getNodeLabel(SlicedPAGNodeRef n, const SlicedPAGView *)
static std::string getEdgeAttributes(SlicedPAGNodeRef, EdgeIter EI, const SlicedPAGView *)
static std::string getNodeAttributes(SlicedPAGNodeRef, const SlicedPAGView *)
DOTGraphTraits(bool isSimple=false)
static const void * getNodeIdentifier(SlicedPAGNodeRef n)
static std::string getGraphName(const SlicedPAGView *)
static const void * getNodeIdentifier(SlicedSVFGNodeRef n)
static std::string getNodeAttributes(SlicedSVFGNodeRef n, const SlicedSVFGView *)
DOTGraphTraits(bool isSimple=false)
static std::string getEdgeAttributes(SlicedSVFGNodeRef, EdgeIter EI, const SlicedSVFGView *)
std::string getNodeLabel(SlicedSVFGNodeRef n, const SlicedSVFGView *)
static std::string getGraphName(const SlicedSVFGView *)
static std::string getNodeAttributes(SlicedCallGraphNodeRef, const SlicedThreadCallGraphView *)
std::string getNodeLabel(SlicedCallGraphNodeRef n, const SlicedThreadCallGraphView *)
static const void * getNodeIdentifier(SlicedCallGraphNodeRef n)
DOTGraphTraits(bool isSimple=false)
static std::string getGraphName(const SlicedThreadCallGraphView *)
static std::string getEdgeAttributes(SlicedCallGraphNodeRef, EdgeIter EI, const SlicedThreadCallGraphView *)
DefaultDOTGraphTraits(bool simple=false)
const ICFGEdge * underlying