Static Value-Flow Analysis
Loading...
Searching...
No Matches
SlicedGraphs.cpp
Go to the documentation of this file.
1//===- SlicedGraphs.cpp -- General sliced graph views ----------------------===//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===----------------------------------------------------------------------===//
22
23/*
24 * SlicedGraphs.cpp
25 *
26 * Author: Jiawei Yang
27 *
28 * Implementations of the general sliced graph views (SlicedGraphs.h): view
29 * construction, bridged-edge contraction, and dot dumping.
30 */
31
32#include "Graphs/SlicedGraphs.h"
33#include "Graphs/SVFGNode.h"
34#include "Graphs/GraphPrinter.h"
36#include "Util/SVFUtil.h"
37#include "Util/ThreadAPI.h"
38#include "SVFIR/SVFIR.h"
39#include <algorithm>
40#include <cassert>
41#include <cctype>
42#include <fstream>
43#include <sstream>
44#include <queue>
45#include <iostream>
46
47using namespace SVF;
48
49namespace SVF
50{
51
52//===----------------------------------------------------------------------===//
53// DOTGraphTraits for the sliced ICFG view (used by GraphWriter). Mirrors the
54// placement of DOTGraphTraits<ICFG*> in ICFG.cpp.
55//===----------------------------------------------------------------------===//
56template <>
58{
59 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
60
61 static std::string getGraphName(const SlicedICFGView*)
62 {
63 return "SlicedICFG";
64 }
65
66 // Value NodeRef: identity is the underlying kept node.
68 {
69 return n.raw;
70 }
71
73 {
74 return n.raw != nullptr ? n.raw->toString() : "";
75 }
76
78 {
79 std::string str = "shape=record";
80 const ICFGNode* node = n.raw;
81 if (SVFUtil::isa<FunEntryICFGNode>(node)) str += ",color=yellow";
82 else if (SVFUtil::isa<FunExitICFGNode>(node)) str += ",color=green";
83 else if (SVFUtil::isa<CallICFGNode>(node)) str += ",color=red";
84 else if (SVFUtil::isa<RetICFGNode>(node)) str += ",color=blue";
85 else if (SVFUtil::isa<GlobalICFGNode>(node)) str += ",color=purple";
86 else str += ",color=black";
87 return str;
88 }
89
90 // Bridged edges are drawn dashed; kept original call/ret edges keep their colour.
91 template <class EdgeIter>
93 {
94 const SlicedICFGEdgeRef& e = EI.currentEdge();
95 if (e.bridged) return "style=dashed,color=gray";
96 if (e.underlying != nullptr && SVFUtil::isa<CallCFGEdge>(e.underlying))
97 return "style=solid,color=red";
98 if (e.underlying != nullptr && SVFUtil::isa<RetCFGEdge>(e.underlying))
99 return "style=solid,color=blue";
100 return "style=solid";
101 }
102};
103
104//===----------------------------------------------------------------------===//
105// DOTGraphTraits for the sliced ThreadCallGraph view.
106//===----------------------------------------------------------------------===//
107template <>
109{
110 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
111
112 static std::string getGraphName(const SlicedThreadCallGraphView*)
113 {
114 return "SlicedThreadCallGraph";
115 }
116
118 {
119 return n.raw;
120 }
121
123 {
124 return n.raw != nullptr ? n.raw->getName() : "";
125 }
126
128 {
129 return "shape=record,color=black";
130 }
131
132 template <class EdgeIter>
134 {
135 const CallGraphEdge* e = EI.currentEdge().underlying;
136 if (e != nullptr && e->getEdgeKind() == CallGraphEdge::TDForkEdge) return "color=green";
137 if (e != nullptr && e->getEdgeKind() == CallGraphEdge::CallRetEdge) return "color=blue";
138 return "color=black";
139 }
140};
141
142//===----------------------------------------------------------------------===//
143// DOTGraphTraits for the sliced PAG view.
144//===----------------------------------------------------------------------===//
145template <>
147{
148 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
149
150 static std::string getGraphName(const SlicedPAGView*)
151 {
152 return "SlicedPAG";
153 }
154
156 {
157 return n.raw;
158 }
159
161 {
162 return n.raw != nullptr ? n.raw->toString() : "";
163 }
164
166 {
167 return "shape=record,color=black";
168 }
169
170 template <class EdgeIter>
172 {
173 const SVFStmt* s = EI.currentEdge().underlying;
174 if (SVFUtil::isa<LoadStmt>(s)) return "color=blue";
175 if (SVFUtil::isa<StoreStmt>(s)) return "color=red";
176 if (SVFUtil::isa<GepStmt>(s)) return "color=purple";
177 if (SVFUtil::isa<AddrStmt>(s)) return "color=green";
178 if (SVFUtil::isa<CallPE>(s)) return "color=orange";
179 if (SVFUtil::isa<RetPE>(s)) return "color=cyan";
180 return "color=black";
181 }
182};
183
184//===----------------------------------------------------------------------===//
185// DOTGraphTraits for the sliced SVFG view.
186//===----------------------------------------------------------------------===//
187template <>
189{
190 DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
191
192 static std::string getGraphName(const SlicedSVFGView*)
193 {
194 return "SlicedSVFG";
195 }
196
198 {
199 return n.raw;
200 }
201
203 {
204 return n.raw != nullptr ? n.raw->toString() : "";
205 }
206
208 {
209 if (SVFUtil::isa<StoreSVFGNode>(n.raw)) return "shape=record,color=red";
210 if (SVFUtil::isa<LoadSVFGNode>(n.raw)) return "shape=record,color=blue";
211 return "shape=record,color=black";
212 }
213
214 template <class EdgeIter>
216 {
217 const SVFGEdge* e = EI.currentEdge().underlying;
218 if (e != nullptr && SVFUtil::isa<IndirectSVFGEdge>(e)) return "style=dashed";
219 return "style=solid";
220 }
221};
222
223//===----------------------------------------------------------------------===//
224// SlicedSVFGView
225//===----------------------------------------------------------------------===//
226
227// Retained rule (must mirror the sliced FSAM gate): Load/Store statement nodes
228// whose ICFG node was sliced out are removed; every other node is structural
229// for inter-procedural / memory-SSA flow and remains.
231{
232 if (SVFUtil::isa<StoreSVFGNode, LoadSVFGNode>(n))
233 {
234 const StmtSVFGNode* stmt = SVFUtil::cast<StmtSVFGNode>(n);
235 const ICFGNode* icfg = stmt->getICFGNode();
236 if (icfg != nullptr && !icfgView->isKeptNode(icfg))
237 return false;
238 }
239 return true;
240}
241
242void SlicedSVFGView::dump(const std::string& filename) const
243{
244 assert(svfg != nullptr && "SlicedSVFGView: bind the SVFG before dumping");
246}
247
248//===----------------------------------------------------------------------===//
249// SlicedICFGView
250//===----------------------------------------------------------------------===//
251
263
264// getSuccNodes/getPredNodes and the GenericGraphTraits iterators must agree on the
265// slice topology, so both go through the one traits definition (kept original
266// edges + bridged edges). The sliced MHP/Lock analyses reach the slice here.
267void SlicedICFGView::getSuccNodes(const ICFGNode* node, std::vector<const ICFGNode*>& out) const
268{
269 out.clear();
270 if (!isKeptNode(node))
271 {
272 return;
273 }
275 const SlicedICFGNodeRef n{this, node};
276 for (auto it = GT::child_begin(n), e = GT::child_end(n); it != e; ++it)
277 out.push_back((*it).raw);
278}
279
280void SlicedICFGView::getPredNodes(const ICFGNode* node, std::vector<const ICFGNode*>& out) const
281{
282 out.clear();
283 if (!isKeptNode(node))
284 {
285 return;
286 }
288 const SlicedICFGNodeRef n{this, node};
289 for (auto it = GT::child_begin(n), e = GT::child_end(n); it != e; ++it)
290 out.push_back((*it).raw);
291}
292
294{
295 return keptNodesSet.count(node) > 0;
296}
297
298void SlicedICFGView::dump(const std::string& filename) const
299{
300 // Kept nodes + kept original edges + bridged edges are all produced by the
301 // GenericGraphTraits<const SlicedICFGView*> iterators; GraphWriter styles
302 // bridged edges dashed via DOTGraphTraits::getEdgeAttributes.
304}
305
308{
309 // keepNodes already includes all necessary nodes (call/ret nodes and entry/exit nodes)
310 // so we just need to copy them and build edges.
311
312 // Copy keepNodes to keptNodes
313 keptNodes.clear();
314 keptNodes.insert(keepNodes.begin(), keepNodes.end());
315
316 // Build keptNodesSet for fast lookup
317 keptNodesSet.clear();
318 keptNodesSet.insert(keptNodes.begin(), keptNodes.end());
319
320 // Build edges: only when both src and dst are in keptNodes
321 keptEdges.clear();
322 for (const ICFGNode* node : keptNodes)
323 {
324 for (const ICFGEdge* edge : node->getOutEdges())
325 {
326 if (edge && keptNodesSet.count(edge->getDstNode()))
327 {
328 keptEdges.insert(edge);
329 }
330 }
331 }
332}
333
335{
336 // bridgedEdges[u] (u kept) = kept nodes reachable from u through removed-only
337 // paths = U reachKept(s) over removed successors s of u, where reachKept(r) is
338 // computed by SCC-condensing the removed subgraph (cyclic) and propagating
339 // kept-reachability over the condensation -- linear, vs. node contraction whose
340 // cross-products blow up when the removed region is large (small slices).
341
342 // Index the removed nodes and their removed-only adjacency + kept successors.
343 std::vector<const ICFGNode*> removed;
345 for (ICFG::iterator it = icfg->begin(), eit = icfg->end(); it != eit; ++it)
346 {
347 const ICFGNode* n = it->second;
348 if (n == nullptr || keptNodesSet.count(n)) continue;
349 rid[n] = static_cast<int>(removed.size());
350 removed.push_back(n);
351 }
352 const int R = static_cast<int>(removed.size());
353
354 // call_i -> ret_i summary for call sites with an omitted callee (some resolved
355 // callee entry not retained), for every call site so paths can compose through
356 // removed ones. ret_i is in the same caller, so the seed stays intra-procedural.
358 for (ICFG::iterator it = icfg->begin(), eit = icfg->end(); it != eit; ++it)
359 {
360 const CallICFGNode* call = SVFUtil::dyn_cast<CallICFGNode>(it->second);
361 if (call == nullptr || call->getRetICFGNode() == nullptr) continue;
362 for (const ICFGEdge* e : call->getOutEdges())
363 if (e && SVFUtil::isa<CallCFGEdge>(e) && keptNodesSet.count(e->getDstNode()) == 0)
364 {
365 seedRet[call] = call->getRetICFGNode();
366 break;
367 }
368 }
369 // Local successors = intra edges + matched call->ret seeds; the only edges
370 // contraction may traverse. Original call/ret edges are excluded.
371 auto localSuccs = [&](const ICFGNode* n, std::vector<const ICFGNode*>& out)
372 {
373 out.clear();
374 for (const ICFGEdge* e : n->getOutEdges())
375 if (e && SVFUtil::isa<IntraCFGEdge>(e) && e->getDstNode())
376 out.push_back(e->getDstNode());
377 auto sit = seedRet.find(n);
378 if (sit != seedRet.end()) out.push_back(sit->second);
379 };
380
381 std::vector<std::vector<int>> radj(R); // removed -> removed succ ids
382 std::vector<std::vector<const ICFGNode*>> keptSucc(R); // removed -> kept succs
383 std::vector<const ICFGNode*> succs;
384 for (int i = 0; i < R; ++i)
385 {
387 for (const ICFGNode* d : succs)
388 {
389 if (keptNodesSet.count(d)) keptSucc[i].push_back(d);
390 else radj[i].push_back(rid[d]);
391 }
392 }
393
394 // Iterative Tarjan SCC over the removed subgraph. Components are produced in
395 // reverse-topological order, so comp ids of a node's successors are < its own.
396 std::vector<int> idx(R, -1), low(R, 0), comp(R, -1);
397 std::vector<char> onstk(R, 0);
398 std::vector<int> tstk;
399 int counter = 0, ncomp = 0;
400 for (int s0 = 0; s0 < R; ++s0)
401 {
402 if (idx[s0] != -1) continue;
403 std::vector<std::pair<int, size_t>> work;
404 work.emplace_back(s0, 0);
405 while (!work.empty())
406 {
407 int v = work.back().first;
408 size_t& pi = work.back().second;
409 if (pi == 0)
410 {
411 idx[v] = low[v] = counter++;
412 tstk.push_back(v);
413 onstk[v] = 1;
414 }
415 bool descend = false;
416 while (pi < radj[v].size())
417 {
418 int w = radj[v][pi++];
419 if (idx[w] == -1)
420 {
421 work.emplace_back(w, 0);
422 descend = true;
423 break;
424 }
425 else if (onstk[w] && idx[w] < low[v]) low[v] = idx[w];
426 }
427 if (descend) continue;
428 if (low[v] == idx[v])
429 {
430 while (true)
431 {
432 int w = tstk.back();
433 tstk.pop_back();
434 onstk[w] = 0;
435 comp[w] = ncomp;
436 if (w == v) break;
437 }
438 ++ncomp;
439 }
440 work.pop_back();
441 if (!work.empty())
442 {
443 int p = work.back().first;
444 if (low[v] < low[p]) low[p] = low[v];
445 }
446 }
447 }
448
449 // Condensation: base kept-successors and DAG successors per component.
450 std::vector<OrderedSet<const ICFGNode*>> baseKept(ncomp);
451 std::vector<OrderedSet<int>> dagSucc(ncomp);
452 for (int i = 0; i < R; ++i)
453 {
454 int ci = comp[i];
455 for (const ICFGNode* k : keptSucc[i]) baseKept[ci].insert(k);
456 for (int j : radj[i]) if (comp[j] != ci) dagSucc[ci].insert(comp[j]);
457 }
458
459 // Propagate reachKept in ascending comp order (successors have smaller ids).
460 std::vector<OrderedSet<const ICFGNode*>> reachKept(ncomp);
461 for (int c = 0; c < ncomp; ++c)
462 {
464 acc = baseKept[c];
465 for (int d : dagSucc[c]) acc.insert(reachKept[d].begin(), reachKept[d].end());
466 }
467
468 // bridgedEdges[u] = kept nodes reached from kept u through removed local paths,
469 // plus a matched call->ret summary when u is a seeded call site (kept ret).
470 for (const ICFGNode* u : keptNodesSet)
471 {
473 auto sit = seedRet.find(u);
474 for (const ICFGNode* s : succs)
475 {
476 if (keptNodesSet.count(s))
477 {
478 // Kept seed target: no real edge exists, so record the bridge; a
479 // kept intra target is a real edge handled by getSuccNodes.
480 if (sit != seedRet.end() && sit->second == s)
481 {
482 bridgedEdges[u].insert(s);
483 bridgedPreds[s].insert(u);
484 }
485 continue;
486 }
487 for (const ICFGNode* v : reachKept[comp[rid[s]]])
488 {
489 bridgedEdges[u].insert(v);
490 bridgedPreds[v].insert(u);
491 }
492 }
493 }
494
495 size_t totalBridgedEdges = 0;
496 for (const auto& pair : bridgedEdges) totalBridgedEdges += pair.second.size();
497 SVFUtil::outs() << "[SlicedICFGView] Built " << totalBridgedEdges
498 << " bridged edges across " << bridgedEdges.size() << " source nodes\n";
499}
500
501//===----------------------------------------------------------------------===//
502// SlicedPAGView
503//===----------------------------------------------------------------------===//
504
506 : pag(pag), keptStmts(keptStmts)
507{
509}
510
512{
513 for (const SVFStmt* stmt : keptStmts)
514 {
515 // extract the node IDs involved in the statement
516 const AssignStmt* assignStmt = SVFUtil::dyn_cast<AssignStmt>(stmt);
517 if (assignStmt)
518 {
519 keptNodeIds.insert(assignStmt->getLHSVarID());
520 keptNodeIds.insert(assignStmt->getRHSVarID());
521 continue;
522 }
523
524 const LoadStmt* loadStmt = SVFUtil::dyn_cast<LoadStmt>(stmt);
525 if (loadStmt)
526 {
527 keptNodeIds.insert(loadStmt->getLHSVarID());
528 keptNodeIds.insert(loadStmt->getRHSVarID());
529 continue;
530 }
531
532 const StoreStmt* storeStmt = SVFUtil::dyn_cast<StoreStmt>(stmt);
533 if (storeStmt)
534 {
535 keptNodeIds.insert(storeStmt->getLHSVarID());
536 keptNodeIds.insert(storeStmt->getRHSVarID());
537 continue;
538 }
539
540 const CopyStmt* copyStmt = SVFUtil::dyn_cast<CopyStmt>(stmt);
541 if (copyStmt)
542 {
543 keptNodeIds.insert(copyStmt->getLHSVarID());
544 keptNodeIds.insert(copyStmt->getRHSVarID());
545 continue;
546 }
547
548 const GepStmt* gepStmt = SVFUtil::dyn_cast<GepStmt>(stmt);
549 if (gepStmt)
550 {
551 keptNodeIds.insert(gepStmt->getLHSVarID());
552 keptNodeIds.insert(gepStmt->getRHSVarID());
553 continue;
554 }
555
556 const AddrStmt* addrStmt = SVFUtil::dyn_cast<AddrStmt>(stmt);
557 if (addrStmt)
558 {
559 keptNodeIds.insert(addrStmt->getLHSVarID());
560 keptNodeIds.insert(addrStmt->getRHSVarID());
561 continue;
562 }
563
564 const CallPE* callPE = SVFUtil::dyn_cast<CallPE>(stmt);
565 if (callPE)
566 {
567 // CallPE is a MultiOpndStmt (result + per-call-site operands)
568 // rather than a single-LHS/RHS AssignStmt.
569 keptNodeIds.insert(callPE->getResID());
570 for (u32_t i = 0; i < callPE->getOpVarNum(); ++i)
571 keptNodeIds.insert(callPE->getOpVarID(i));
572 continue;
573 }
574
575 const RetPE* retPE = SVFUtil::dyn_cast<RetPE>(stmt);
576 if (retPE)
577 {
578 keptNodeIds.insert(retPE->getLHSVarID());
579 keptNodeIds.insert(retPE->getRHSVarID());
580 continue;
581 }
582 }
583}
584
585void SlicedPAGView::dump(const std::string& filename) const
586{
587 // Nodes = SVFVars of kept statements; edges = kept SVFStmts via
588 // GenericGraphTraits<const SlicedPAGView*>. MultiOpndStmts use the
589 // underlying src/dst (no operand fan-out).
591}
592
593//===----------------------------------------------------------------------===//
594// SlicedThreadCallGraphView
595//===----------------------------------------------------------------------===//
596
599 const OrderedSet<const ICFGNode*>& extendedKeptNodes)
600 : tcg(tcg)
601{
602 for (const FunObjVar* fun : keptFunctions)
603 {
604 keptFunctionsSet.insert(fun);
605 }
606 this->extendedKeptNodes = extendedKeptNodes;
608 // extendedKeptNodes already includes all necessary nodes from performSpatialSlicing;
609 // buildCallGraphSets builds the kept edges (filtering pruned call sites when it is non-empty).
611}
612
614{
615 for (CallGraph::iterator it = tcg->begin(), eit = tcg->end(); it != eit; ++it)
616 {
617 const CallGraphNode* node = it->second;
618 if (node && node->getFunction() && keptFunctionsSet.count(node->getFunction()))
619 {
620 keptNodes.insert(node);
621 }
622 }
623}
624
625void SlicedThreadCallGraphView::getOutEdgesOf(const CallGraphNode* node, std::vector<const CallGraphEdge*>& out) const
626{
627 out.clear();
628 if (!isKeptNode(node))
629 {
630 return;
631 }
632
634 const SlicedCallGraphNodeRef n{this, node};
635 for (auto it = GT::child_edge_begin(n), e = GT::child_edge_end(n); it != e; ++it)
636 out.push_back((*it).underlying);
637}
638
639void SlicedThreadCallGraphView::getInEdgesOf(const CallGraphNode* node, std::vector<const CallGraphEdge*>& out) const
640{
641 out.clear();
642 if (!isKeptNode(node))
643 {
644 return;
645 }
647 const SlicedCallGraphNodeRef n{this, node};
648 for (auto it = GT::child_edge_begin(n), e = GT::child_edge_end(n); it != e; ++it)
649 out.push_back((*it).underlying);
650}
651
653{
654 return keptNodes.count(node) > 0;
655}
656
658{
659 // rebuild kept edges, accounting for whether the call site is kept
660 keptEdges.clear();
662
663 // CallGraph edge: src/dst both in kept functions and the call site still in the kept ICFG node set
664 for (const CallGraphNode* srcNode : keptNodes)
665 {
666 for (const CallGraphEdge* edge : srcNode->getOutEdges())
667 {
668 const CallGraphNode* dstNode = edge ? edge->getDstNode() : nullptr;
669 if (!dstNode || !keptNodes.count(dstNode))
670 {
671 continue;
672 }
673
674 const CallGraphEdge::CallInstSet &directCalls = edge->getDirectCalls();
675 const CallGraphEdge::CallInstSet &indirectCalls = edge->getIndirectCalls();
676 const CallICFGNode* callSite = nullptr;
677 if (!directCalls.empty())
678 {
679 callSite = *directCalls.begin();
680 }
681 else if (!indirectCalls.empty())
682 {
683 callSite = *indirectCalls.begin();
684 }
685
686 if (!extendedKeptNodes.empty() && callSite && !extendedKeptNodes.count(callSite))
687 {
688 // call site was pruned, skip this edge
689 continue;
690 }
691
692 // indirect call: record if all targets were filtered out
693 if (callSite && edge->getEdgeKind() == CallGraphEdge::CallRetEdge &&
695 {
697 bool hasKeptTarget = false;
698 for (const FunObjVar* tgt : targets)
699 {
700 if (keptFunctionsSet.count(tgt))
701 {
702 hasKeptTarget = true;
703 break;
704 }
705 }
706 if (!hasKeptTarget)
707 {
709 }
710 }
711
712 keptEdges.insert(const_cast<CallGraphEdge*>(edge));
713 }
714 }
715}
716
717void SlicedThreadCallGraphView::dump(const std::string& filename) const
718{
719 // Kept nodes + canonical kept edges via GenericGraphTraits; join edges are
720 // not in the normal adjacency, so they are not drawn here.
722}
723
724//===----------------------------------------------------------------------===//
725// SlicedSVFIRView
726//===----------------------------------------------------------------------===//
727
729 CallGraph* cg,
730 ICFG* icfg,
732 bool buildBridged)
733 : svfIr(svfIr)
734{
735 // Derive keptFunctions from keepNodes
737 for (const ICFGNode* node : keepNodes)
738 {
739 if (node != nullptr && node->getFun() != nullptr)
740 {
741 keptFunctions.insert(node->getFun());
742 }
743 }
744
745 // The MTA pipeline always slices over a ThreadCallGraph.
746 ThreadCallGraph* tcg = SVFUtil::dyn_cast<ThreadCallGraph>(cg);
747 assert(tcg != nullptr && "SlicedSVFIRView expects a ThreadCallGraph");
748 tcgView = std::make_unique<SlicedThreadCallGraphView>(tcg, keptFunctions, keepNodes);
749
750 // Create ICFG view (based on keepNodes and keptFunctions)
751 icfgView = std::make_unique<SlicedICFGView>(icfg, cg, keepNodes, keptFunctions, buildBridged);
752
753 // Create PAG view (extract statements from keepNodes)
755 for (const ICFGNode* node : keepNodes)
756 {
757 const ICFGNode::SVFStmtList& stmts = node->getSVFStmts();
758 keptStmts.insert(stmts.begin(), stmts.end());
759 }
760 pagView = std::make_unique<SlicedPAGView>(svfIr, keptStmts);
761}
762
763void SlicedSVFIRView::dumpAll(const std::string& prefix) const
764{
765 icfgView->dump(prefix + "_icfg");
766 tcgView->dump(prefix + "_threadcallgraph");
767 pagView->dump(prefix + "_pag");
768}
769
770void SlicedSVFIRView::dumpStats(const std::string& prefix) const
771{
772 std::string label = prefix.empty() ? "[SlicedSVFIRView]" : "[" + prefix + "]";
773 SVFUtil::outs() << label << " Statistics:\n";
774 SVFUtil::outs() << " ICFG nodes: " << icfgView->getKeptNodes().size() << "\n";
775 SVFUtil::outs() << " Functions: " << getKeptFunctions().size() << "\n";
776 SVFUtil::outs() << " PAG statements: " << getKeptStatements().size() << "\n";
778 {
779 SVFUtil::outs() << " Indirect callsites that lost all targets: "
780 << getIndirectSitesWithEmptyTargets().size() << "\n";
781 }
782}
783
784//===----------------------------------------------------------------------===//
785// SlicedICFGView traversal helpers used by the sliced analyses.
786//===----------------------------------------------------------------------===//
787
789{
790 // Prefer the kept FunEntryICFGNode: MultiStageSlicer::expandCallDependence keeps it
791 // for every kept function and buildBridgedEdges links it to the kept body, so
792 // the MHP interleaving fixpoint can flow from it to every kept statement.
793 // The entry basic block's first instruction, by contrast, may be sliced out;
794 // returning it (a removed node) would strand the root/thread seed there --
795 // getSuccNodes() yields nothing for a non-kept node -- so the function body
796 // would never receive the thread's interleaving (a soundness bug).
797 if (const ICFGNode* fe = icfg->getFunEntryICFGNode(fun))
798 {
799 if (isKeptNode(fe))
800 return fe;
801 }
802 // Otherwise: first kept node in the entry block, or the original entry.
803 const ICFGNode* entry = fun->getEntryBlock()->front();
804 if (isKeptNode(entry))
805 return entry;
806 for (const ICFGNode* node : fun->getEntryBlock()->getICFGNodeList())
807 {
808 if (isKeptNode(node))
809 return node;
810 }
811 return entry;
812}
813
815 std::vector<const ICFGNode*>& out) const
816{
817 out.clear();
818 for (auto it : *fun)
819 {
820 const SVFBasicBlock* svfbb = it.second;
821 for (const ICFGNode* node : svfbb->getICFGNodeList())
822 if (isKeptNode(node))
823 out.push_back(node);
824 }
825}
826
827//===----------------------------------------------------------------------===//
828// SlicedSVFIRView call-graph helpers used by the sliced analyses.
829//===----------------------------------------------------------------------===//
830
832 std::vector<const CallGraphEdge*>& out) const
833{
834 out.clear();
835 if (getThreadCallGraph() != nullptr)
837 else
838 for (CallGraphEdge* edge : node->getInEdges())
839 out.push_back(edge);
840}
841
843{
844 if (getThreadCallGraph() != nullptr)
846 return PAG::getPAG()->getCallGraph();
847}
848
849} // End namespace SVF
cJSON * p
Definition cJSON.cpp:2559
cJSON * n
Definition cJSON.cpp:2558
NodeID getRHSVarID() const
NodeID getLHSVarID() const
Set< const CallICFGNode * > CallInstSet
Definition CallGraph.h:55
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
bool hasIndCSCallees(const CallICFGNode *cs) const
Definition CallGraph.h:335
const FunctionSet & getIndCSCallees(const CallICFGNode *cs) const
Definition CallGraph.h:339
Set< const FunObjVar * > FunctionSet
Definition CallGraph.h:247
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition ICFGNode.h:440
const SVFBasicBlock * getEntryBlock() const
GEdgeKind getEdgeKind() const
iterator begin()
Iterators.
IDToNodeMapTy::iterator iterator
Node Iterators.
const GEdgeSetTy & getOutEdges() const
const GEdgeSetTy & getInEdges() const
static void WriteGraphToFile(SVF::OutStream &O, const std::string &GraphName, const GraphType &GT, bool simple=false)
std::list< const SVFStmt * > SVFStmtList
Definition ICFGNode.h:65
ICFGNodeIDToNodeMapTy::iterator iterator
Definition ICFG.h:58
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Definition ICFG.cpp:243
NodeID getOpVarID(u32_t pos) const
NodeID getResID() const
u32_t getOpVarNum() const
const std::vector< const ICFGNode * > & getICFGNodeList() const
const ICFGNode * front() const
const CallGraph * getCallGraph()
Get CG.
Definition SVFIR.h:248
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:120
SlicedICFGView(ICFG *icfg, CallGraph *cg, const OrderedSet< const ICFGNode * > &keepNodes, const OrderedSet< const FunObjVar * > &keptFunctions, bool buildBridged=true)
Build complete ICFG view from keepNodes and keptFunctions.
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.
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
OrderedSet< const ICFGEdge * > keptEdges
void buildICFGSets(const OrderedSet< const ICFGNode * > &keepNodes, const OrderedSet< const FunObjVar * > &keptFunctions)
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
bool isKeptNode(const SVFGNode *n) const
Whether the node is retained (see the class comment for the rule).
const SlicedICFGView * icfgView
void dump(const std::string &filename) const
Dump the sliced SVFG (retained nodes/edges only) via GraphWriter.
const CallGraph * getAnalysisCallGraph() const
const Set< const FunObjVar * > & getKeptFunctions() const
Get all kept functions.
const SlicedThreadCallGraphView * getThreadCallGraph() const
Get SlicedThreadCallGraphView.
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
void getInEdgesOfCallGraphNode(const CallGraphNode *node, std::vector< const CallGraphEdge * > &out) const
void dumpStats(const std::string &prefix="") const
Output statistics.
SlicedSVFIRView(SVFIR *svfIr, CallGraph *cg, ICFG *icfg, const OrderedSet< const ICFGNode * > &keepNodes, bool buildBridged=true)
const OrderedSet< const SVFStmt * > & getKeptStatements() const
Get all kept statements.
const Set< const CallICFGNode * > & getIndirectSitesWithEmptyTargets() const
Get indirect call sites that lost all targets after filtering.
SlicedThreadCallGraphView(ThreadCallGraph *tcg, const OrderedSet< const FunObjVar * > &keptFunctions, const OrderedSet< const ICFGNode * > &extendedKeptNodes=OrderedSet< const ICFGNode * >())
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 FunObjVar * > keptFunctionsSet
CallGraph::CallGraphEdgeSet keptEdges
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)
CallGraph * getOriginalCallGraph() const
Get original CallGraph (ThreadCallGraph inherits from CallGraph)
OrderedSet< const ICFGNode * > extendedKeptNodes
virtual const ICFGNode * getICFGNode() const
Return corresponding ICFG node.
Definition VFGNode.h:67
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:52
for isBitcode
Definition BasicTypes.h:70
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
unsigned u32_t
Definition GeneralType.h:67
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)
std::string getNodeLabel(SlicedPAGNodeRef n, const SlicedPAGView *)
static std::string getEdgeAttributes(SlicedPAGNodeRef, EdgeIter EI, const SlicedPAGView *)
static std::string getNodeAttributes(SlicedPAGNodeRef, const SlicedPAGView *)
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 *)
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)
static std::string getGraphName(const SlicedThreadCallGraphView *)
static std::string getEdgeAttributes(SlicedCallGraphNodeRef, EdgeIter EI, const SlicedThreadCallGraphView *)
const ICFGEdge * underlying