One Hat Cyber Team
Your IP :
216.73.216.135
Server IP :
194.44.31.54
Server :
Linux zen.imath.kiev.ua 4.18.0-553.77.1.el8_10.x86_64 #1 SMP Fri Oct 3 14:30:23 UTC 2025 x86_64
Server Software :
Apache/2.4.37 (Rocky Linux) OpenSSL/1.1.1k
PHP Version :
5.6.40
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
include
/
clang
/
Analysis
/
Edit File:
CallGraph.h
//===- CallGraph.h - AST-based Call graph -----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file declares the AST-based CallGraph. // // A call graph for functions whose definitions/bodies are available in the // current translation unit. The graph has a "virtual" root node that contains // edges to all externally available functions. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ANALYSIS_CALLGRAPH_H #define LLVM_CLANG_ANALYSIS_CALLGRAPH_H #include "clang/AST/Decl.h" #include "clang/AST/RecursiveASTVisitor.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" #include <memory> namespace clang { class CallGraphNode; class Decl; class DeclContext; class Stmt; /// The AST-based call graph. /// /// The call graph extends itself with the given declarations by implementing /// the recursive AST visitor, which constructs the graph by visiting the given /// declarations. class CallGraph : public RecursiveASTVisitor<CallGraph> { friend class CallGraphNode; using FunctionMapTy = llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>; /// FunctionMap owns all CallGraphNodes. FunctionMapTy FunctionMap; /// This is a virtual root node that has edges to all the functions. CallGraphNode *Root; public: CallGraph(); ~CallGraph(); /// Populate the call graph with the functions in the given /// declaration. /// /// Recursively walks the declaration to find all the dependent Decls as well. void addToCallGraph(Decl *D) { TraverseDecl(D); } /// Determine if a declaration should be included in the graph. static bool includeInGraph(const Decl *D); /// Determine if a declaration should be included in the graph for the /// purposes of being a callee. This is similar to includeInGraph except /// it permits declarations, not just definitions. static bool includeCalleeInGraph(const Decl *D); /// Lookup the node for the given declaration. CallGraphNode *getNode(const Decl *) const; /// Lookup the node for the given declaration. If none found, insert /// one into the graph. CallGraphNode *getOrInsertNode(Decl *); using iterator = FunctionMapTy::iterator; using const_iterator = FunctionMapTy::const_iterator; /// Iterators through all the elements in the graph. Note, this gives /// non-deterministic order. iterator begin() { return FunctionMap.begin(); } iterator end() { return FunctionMap.end(); } const_iterator begin() const { return FunctionMap.begin(); } const_iterator end() const { return FunctionMap.end(); } /// Get the number of nodes in the graph. unsigned size() const { return FunctionMap.size(); } /// Get the virtual root of the graph, all the functions available externally /// are represented as callees of the node. CallGraphNode *getRoot() const { return Root; } /// Iterators through all the nodes of the graph that have no parent. These /// are the unreachable nodes, which are either unused or are due to us /// failing to add a call edge due to the analysis imprecision. using nodes_iterator = llvm::SetVector<CallGraphNode *>::iterator; using const_nodes_iterator = llvm::SetVector<CallGraphNode *>::const_iterator; void print(raw_ostream &os) const; void dump() const; void viewGraph() const; void addNodesForBlocks(DeclContext *D); /// Part of recursive declaration visitation. We recursively visit all the /// declarations to collect the root functions. bool VisitFunctionDecl(FunctionDecl *FD) { // We skip function template definitions, as their semantics is // only determined when they are instantiated. if (includeInGraph(FD) && FD->isThisDeclarationADefinition()) { // Add all blocks declared inside this function to the graph. addNodesForBlocks(FD); // If this function has external linkage, anything could call it. // Note, we are not precise here. For example, the function could have // its address taken. addNodeForDecl(FD, FD->isGlobal()); } return true; } /// Part of recursive declaration visitation. bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { if (includeInGraph(MD)) { addNodesForBlocks(MD); addNodeForDecl(MD, true); } return true; } // We are only collecting the declarations, so do not step into the bodies. bool TraverseStmt(Stmt *S) { return true; } bool shouldWalkTypesOfTypeLocs() const { return false; } bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return true; } private: /// Add the given declaration to the call graph. void addNodeForDecl(Decl *D, bool IsGlobal); }; class CallGraphNode { public: struct CallRecord { CallGraphNode *Callee; Expr *CallExpr; CallRecord() = default; CallRecord(CallGraphNode *Callee_, Expr *CallExpr_) : Callee(Callee_), CallExpr(CallExpr_) {} // The call destination is the only important data here, // allow to transparently unwrap into it. operator CallGraphNode *() const { return Callee; } }; private: /// The function/method declaration. Decl *FD; /// The list of functions called from this node. SmallVector<CallRecord, 5> CalledFunctions; public: CallGraphNode(Decl *D) : FD(D) {} using iterator = SmallVectorImpl<CallRecord>::iterator; using const_iterator = SmallVectorImpl<CallRecord>::const_iterator; /// Iterators through all the callees/children of the node. iterator begin() { return CalledFunctions.begin(); } iterator end() { return CalledFunctions.end(); } const_iterator begin() const { return CalledFunctions.begin(); } const_iterator end() const { return CalledFunctions.end(); } /// Iterator access to callees/children of the node. llvm::iterator_range<iterator> callees() { return llvm::make_range(begin(), end()); } llvm::iterator_range<const_iterator> callees() const { return llvm::make_range(begin(), end()); } bool empty() const { return CalledFunctions.empty(); } unsigned size() const { return CalledFunctions.size(); } void addCallee(CallRecord Call) { CalledFunctions.push_back(Call); } Decl *getDecl() const { return FD; } FunctionDecl *getDefinition() const { return getDecl()->getAsFunction()->getDefinition(); } void print(raw_ostream &os) const; void dump() const; }; // NOTE: we are comparing based on the callee only. So different call records // (with different call expressions) to the same callee will compare equal! inline bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS) { return LHS.Callee == RHS.Callee; } } // namespace clang namespace llvm { // Specialize DenseMapInfo for clang::CallGraphNode::CallRecord. template <> struct DenseMapInfo<clang::CallGraphNode::CallRecord> { static inline clang::CallGraphNode::CallRecord getEmptyKey() { return clang::CallGraphNode::CallRecord( DenseMapInfo<clang::CallGraphNode *>::getEmptyKey(), DenseMapInfo<clang::Expr *>::getEmptyKey()); } static inline clang::CallGraphNode::CallRecord getTombstoneKey() { return clang::CallGraphNode::CallRecord( DenseMapInfo<clang::CallGraphNode *>::getTombstoneKey(), DenseMapInfo<clang::Expr *>::getTombstoneKey()); } static unsigned getHashValue(const clang::CallGraphNode::CallRecord &Val) { // NOTE: we are comparing based on the callee only. // Different call records with the same callee will compare equal! return DenseMapInfo<clang::CallGraphNode *>::getHashValue(Val.Callee); } static bool isEqual(const clang::CallGraphNode::CallRecord &LHS, const clang::CallGraphNode::CallRecord &RHS) { return LHS == RHS; } }; // Graph traits for iteration, viewing. template <> struct GraphTraits<clang::CallGraphNode*> { using NodeType = clang::CallGraphNode; using NodeRef = clang::CallGraphNode *; using ChildIteratorType = NodeType::iterator; static NodeType *getEntryNode(clang::CallGraphNode *CGN) { return CGN; } static ChildIteratorType child_begin(NodeType *N) { return N->begin(); } static ChildIteratorType child_end(NodeType *N) { return N->end(); } }; template <> struct GraphTraits<const clang::CallGraphNode*> { using NodeType = const clang::CallGraphNode; using NodeRef = const clang::CallGraphNode *; using ChildIteratorType = NodeType::const_iterator; static NodeType *getEntryNode(const clang::CallGraphNode *CGN) { return CGN; } static ChildIteratorType child_begin(NodeType *N) { return N->begin();} static ChildIteratorType child_end(NodeType *N) { return N->end(); } }; template <> struct GraphTraits<clang::CallGraph*> : public GraphTraits<clang::CallGraphNode*> { static NodeType *getEntryNode(clang::CallGraph *CGN) { return CGN->getRoot(); // Start at the external node! } static clang::CallGraphNode * CGGetValue(clang::CallGraph::const_iterator::value_type &P) { return P.second.get(); } // nodes_iterator/begin/end - Allow iteration over all nodes in the graph using nodes_iterator = mapped_iterator<clang::CallGraph::iterator, decltype(&CGGetValue)>; static nodes_iterator nodes_begin(clang::CallGraph *CG) { return nodes_iterator(CG->begin(), &CGGetValue); } static nodes_iterator nodes_end (clang::CallGraph *CG) { return nodes_iterator(CG->end(), &CGGetValue); } static unsigned size(clang::CallGraph *CG) { return CG->size(); } }; template <> struct GraphTraits<const clang::CallGraph*> : public GraphTraits<const clang::CallGraphNode*> { static NodeType *getEntryNode(const clang::CallGraph *CGN) { return CGN->getRoot(); } static clang::CallGraphNode * CGGetValue(clang::CallGraph::const_iterator::value_type &P) { return P.second.get(); } // nodes_iterator/begin/end - Allow iteration over all nodes in the graph using nodes_iterator = mapped_iterator<clang::CallGraph::const_iterator, decltype(&CGGetValue)>; static nodes_iterator nodes_begin(const clang::CallGraph *CG) { return nodes_iterator(CG->begin(), &CGGetValue); } static nodes_iterator nodes_end(const clang::CallGraph *CG) { return nodes_iterator(CG->end(), &CGGetValue); } static unsigned size(const clang::CallGraph *CG) { return CG->size(); } }; } // namespace llvm #endif // LLVM_CLANG_ANALYSIS_CALLGRAPH_H
Simpan