Static Value-Flow Analysis
ThreadCallGraph.cpp
Go to the documentation of this file.
1 //===- ThreadCallGraph.cpp -- Call graph considering thread fork/join---------//
2 //
3 // SVF: Static Value-Flow Analysis
4 //
5 // Copyright (C) <2013-2017> <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  * ThreadCallGraph.cpp
25  *
26  * Created on: Jul 12, 2014
27  * Author: Yulei Sui, Peng Di, Ding Ye
28  */
29 
30 #include "SVFIR/SVFModule.h"
31 #include "Graphs/ThreadCallGraph.h"
32 #include "Util/ThreadAPI.h"
33 #include "SVFIR/SVFIR.h"
35 
36 using namespace SVF;
37 using namespace SVFUtil;
38 
43  PTACallGraph(cg), tdAPI(ThreadAPI::getThreadAPI())
44 {
46  DBOUT(DGENERAL, outs() << SVFUtil::pasMsg("Building ThreadCallGraph\n"));
47 }
48 
49 
50 /*
51  * Update call graph using pointer analysis results
52  * (1) resolve function pointers for non-fork calls
53  * (2) resolve function pointers for fork sites
54  * (3) resolve function pointers for parallel_for sites
55  */
57 {
58 
59  PointerAnalysis::CallEdgeMap::const_iterator iter = pta->getIndCallMap().begin();
60  PointerAnalysis::CallEdgeMap::const_iterator eiter = pta->getIndCallMap().end();
61  for (; iter != eiter; iter++)
62  {
63  const CallICFGNode* cs = iter->first;
64  const PTACallGraph::FunctionSet &functions = iter->second;
65  for (PTACallGraph::FunctionSet::const_iterator func_iter =
66  functions.begin(); func_iter != functions.end(); func_iter++)
67  {
68  const SVFFunction* callee = *func_iter;
69  this->addIndirectCallGraphEdge(cs, cs->getCaller(), callee);
70  }
71  }
72 
73  // Fork sites
74  for (CallSiteSet::const_iterator it = forksitesBegin(), eit = forksitesEnd(); it != eit; ++it)
75  {
76  const SVFVar* forkedval = tdAPI->getForkedFun(*it);
77  if(SVFUtil::dyn_cast<SVFFunction>(forkedval->getValue())==nullptr)
78  {
79  SVFIR* pag = pta->getPAG();
80  const NodeBS targets = pta->getPts(forkedval->getId()).toNodeBS();
81  for (NodeBS::iterator ii = targets.begin(), ie = targets.end(); ii != ie; ii++)
82  {
83  if(ObjVar* objPN = SVFUtil::dyn_cast<ObjVar>(pag->getGNode(*ii)))
84  {
85  const MemObj* obj = pag->getObject(objPN);
86  if(obj->isFunction())
87  {
88  const SVFFunction* svfCallee = SVFUtil::cast<SVFFunction>(obj->getValue());
89  this->addIndirectForkEdge(*it, svfCallee);
90  }
91  }
92  }
93  }
94  }
95 }
96 
97 
102 {
103 
104  for (CallSiteSet::const_iterator it = joinsitesBegin(), eit = joinsitesEnd(); it != eit; ++it)
105  {
106  const SVFVar* jointhread = tdAPI->getJoinedThread(*it);
107  // find its corresponding fork sites first
108  CallSiteSet forkset;
109  for (CallSiteSet::const_iterator it = forksitesBegin(), eit = forksitesEnd(); it != eit; ++it)
110  {
111  const SVFVar* forkthread = tdAPI->getForkedThread(*it);
112  if (pta->alias(jointhread->getId(), forkthread->getId()))
113  {
114  forkset.insert(*it);
115  }
116  }
117  assert(!forkset.empty() && "Can't find a forksite for this join!!");
118  addDirectJoinEdge(*it,forkset);
119  }
120 }
121 
126 {
127 
129  const SVFFunction* forkee = SVFUtil::dyn_cast<SVFFunction>(tdAPI->getForkedFun(cs)->getValue());
130  assert(forkee && "callee does not exist");
132  CallSiteID csId = addCallSite(cs, callee->getFunction());
133 
134  if (!hasGraphEdge(caller, callee, PTACallGraphEdge::TDForkEdge, csId))
135  {
136  assert(cs->getCaller() == caller->getFunction() && "callee instruction not inside caller??");
137 
138  ThreadForkEdge* edge = new ThreadForkEdge(caller, callee, csId);
139  edge->addDirectCallSite(cs);
140 
141  addEdge(edge);
142  addThreadForkEdgeSetMap(cs, edge);
143  return true;
144  }
145  else
146  return false;
147 }
148 
153 {
155  PTACallGraphNode* callee = getCallGraphNode(calleefun);
156 
157  CallSiteID csId = addCallSite(cs, callee->getFunction());
158 
159  if (!hasGraphEdge(caller, callee, PTACallGraphEdge::TDForkEdge, csId))
160  {
161  assert(cs->getCaller() == caller->getFunction() && "callee instruction not inside caller??");
162 
163  ThreadForkEdge* edge = new ThreadForkEdge(caller, callee, csId);
164  edge->addInDirectCallSite(cs);
165 
166  addEdge(edge);
167  addThreadForkEdgeSetMap(cs, edge);
168  return true;
169  }
170  else
171  return false;
172 }
173 
181 {
182 
183  PTACallGraphNode* joinFunNode = getCallGraphNode(cs->getCaller());
184 
185  for (CallSiteSet::const_iterator it = forkset.begin(), eit = forkset.end(); it != eit; ++it)
186  {
187 
188  const SVFFunction* threadRoutineFun = SVFUtil::dyn_cast<SVFFunction>(tdAPI->getForkedFun(*it)->getValue());
189  assert(threadRoutineFun && "thread routine function does not exist");
190  PTACallGraphNode* threadRoutineFunNode = getCallGraphNode(threadRoutineFun);
191  CallSiteID csId = addCallSite(cs, threadRoutineFun);
192 
193  if (!hasThreadJoinEdge(cs,joinFunNode,threadRoutineFunNode, csId))
194  {
195  assert(cs->getCaller() == joinFunNode->getFunction() && "callee instruction not inside caller??");
196  ThreadJoinEdge* edge = new ThreadJoinEdge(joinFunNode,threadRoutineFunNode,csId);
197  edge->addDirectCallSite(cs);
198 
199  addThreadJoinEdgeSetMap(cs, edge);
200  }
201  }
202 }
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition: SVFType.h:484
#define DGENERAL
Definition: SVFType.h:490
const SVFFunction * getCaller() const
Return callsite.
Definition: ICFGNode.h:470
NodeType * getGNode(NodeID id) const
Get a node.
Definition: GenericGraph.h:653
const SVFValue * getValue() const
Get the reference value to this object.
bool isFunction() const
object attributes methods
void addDirectCallSite(const CallICFGNode *call)
Add direct and indirect callsite.
void addInDirectCallSite(const CallICFGNode *call)
const SVFFunction * getFunction() const
Get function of this call node.
Definition: PTACallGraph.h:198
void addEdge(PTACallGraphEdge *edge)
Add call graph edge.
Definition: PTACallGraph.h:443
void addIndirectCallGraphEdge(const CallICFGNode *cs, const SVFFunction *callerFun, const SVFFunction *calleeFun)
Set< const SVFFunction * > FunctionSet
Definition: PTACallGraph.h:251
PTACallGraphEdge * hasGraphEdge(PTACallGraphNode *src, PTACallGraphNode *dst, PTACallGraphEdge::CEDGEK kind, CallSiteID csId) const
Whether we have already created this call graph edge.
CallSiteID addCallSite(const CallICFGNode *cs, const SVFFunction *callee)
Add/Get CallSiteID.
Definition: PTACallGraph.h:354
PTACallGraphNode * getCallGraphNode(NodeID id) const
Get call graph node.
Definition: PTACallGraph.h:339
CallEdgeMap & getIndCallMap()
Get callees from an indirect callsite.
SVFIR * getPAG() const
virtual const PointsTo & getPts(NodeID ptr)=0
Get points-to targets of a pointer. It needs to be implemented in child class.
virtual AliasResult alias(const SVFValue *V1, const SVFValue *V2)=0
Interface exposed to users of our pointer analysis, given Value infos.
NodeBS toNodeBS() const
Returns this points-to set as a NodeBS.
Definition: PointsTo.cpp:313
NodeID getId() const
Get ID.
Definition: GenericGraph.h:260
const SVFFunction * getDefFunForMultipleModule() const
Definition: SVFValue.h:393
const MemObj * getObject(NodeID id) const
Definition: SVFIR.h:395
const SVFValue * getValue() const
Get/has methods of the components.
Definition: SVFVariables.h:83
iterator end() const
iterator begin() const
const SVFVar * getForkedFun(const CallICFGNode *inst) const
Definition: ThreadAPI.cpp:170
const SVFVar * getJoinedThread(const CallICFGNode *inst) const
Return arguments/attributes of pthread_join.
Definition: ThreadAPI.cpp:207
const SVFVar * getForkedThread(const CallICFGNode *inst) const
Return arguments/attributes of pthread_create / hare_parallel_for.
Definition: ThreadAPI.cpp:164
CallSiteSet::const_iterator forksitesEnd() const
bool addIndirectForkEdge(const CallICFGNode *cs, const SVFFunction *callee)
bool addDirectForkEdge(const CallICFGNode *cs)
Add direct/indirect thread fork edges.
CallSiteSet::const_iterator forksitesBegin() const
Fork sites iterators.
void updateJoinEdge(PointerAnalysis *pta)
Update join edge using pointer analysis results.
CallSiteSet::const_iterator joinsitesEnd() const
bool hasThreadJoinEdge(const CallICFGNode *cs) const
Get call graph edge via call instruction.
void addThreadJoinEdgeSetMap(const CallICFGNode *cs, ThreadJoinEdge *edge)
map call instruction to its PTACallGraphEdge map
void addDirectJoinEdge(const CallICFGNode *cs, const CallSiteSet &forksite)
Add thread join edges.
CallSiteSet::const_iterator joinsitesBegin() const
Join sites iterators.
ThreadCallGraph(const PTACallGraph &cg)
Constructor.
void addThreadForkEdgeSetMap(const CallICFGNode *cs, ThreadForkEdge *edge)
map call instruction to its PTACallGraphEdge map
void updateCallGraph(PointerAnalysis *pta)
Update call graph using pointer results.
ThreadAPI * tdAPI
Thread API.
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition: SVFUtil.cpp:99
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
unsigned CallSiteID
Definition: GeneralType.h:58