Static Value-Flow Analysis
ThreadAPI.cpp
Go to the documentation of this file.
1 //===- ThreadAPI.cpp -- Thread API-------------------------------------------//
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  * ThreadAPI.cpp
25  *
26  * Created on: Jan 21, 2014
27  * Author: Yulei Sui, dye
28  */
29 
30 #ifndef THREADAPI_CPP_
31 #define THREADAPI_CPP_
32 
33 #include "Util/ThreadAPI.h"
34 #include "Util/SVFUtil.h"
35 #include "Graphs/PTACallGraph.h"
36 #include "SVFIR/SVFIR.h"
37 
38 #include <iostream>
39 #include <stdio.h>
40 #include <iomanip>
41 
42 using namespace std;
43 using namespace SVF;
44 
45 ThreadAPI* ThreadAPI::tdAPI = nullptr;
46 
47 namespace
48 {
49 
51 struct ei_pair
52 {
53  const char *n;
55 };
56 
57 } // End anonymous namespace
58 
59 //Each (name, type) pair will be inserted into the map.
60 //All entries of the same type must occur together (for error detection).
61 static const ei_pair ei_pairs[]=
62 {
63  //The current llvm-gcc puts in the \01.
64  {"pthread_create", ThreadAPI::TD_FORK},
65  {"apr_thread_create", ThreadAPI::TD_FORK},
66  {"pthread_join", ThreadAPI::TD_JOIN},
67  {"\01_pthread_join", ThreadAPI::TD_JOIN},
68  {"pthread_cancel", ThreadAPI::TD_JOIN},
69  {"pthread_mutex_lock", ThreadAPI::TD_ACQUIRE},
70  {"pthread_rwlock_rdlock", ThreadAPI::TD_ACQUIRE},
71  {"sem_wait", ThreadAPI::TD_ACQUIRE},
72  {"_spin_lock", ThreadAPI::TD_ACQUIRE},
73  {"SRE_SplSpecLockEx", ThreadAPI::TD_ACQUIRE},
74  {"pthread_mutex_trylock", ThreadAPI::TD_TRY_ACQUIRE},
75  {"pthread_mutex_unlock", ThreadAPI::TD_RELEASE},
76  {"pthread_rwlock_unlock", ThreadAPI::TD_RELEASE},
77  {"sem_post", ThreadAPI::TD_RELEASE},
78  {"_spin_unlock", ThreadAPI::TD_RELEASE},
79  {"SRE_SplSpecUnlockEx", ThreadAPI::TD_RELEASE},
80 // {"pthread_cancel", ThreadAPI::TD_CANCEL},
81  {"pthread_exit", ThreadAPI::TD_EXIT},
82  {"pthread_detach", ThreadAPI::TD_DETACH},
83  {"pthread_cond_wait", ThreadAPI::TD_COND_WAIT},
84  {"pthread_cond_signal", ThreadAPI::TD_COND_SIGNAL},
85  {"pthread_cond_broadcast", ThreadAPI::TD_COND_BROADCAST},
86  {"pthread_cond_init", ThreadAPI::TD_CONDVAR_INI},
87  {"pthread_cond_destroy", ThreadAPI::TD_CONDVAR_DESTROY},
88  {"pthread_mutex_init", ThreadAPI::TD_MUTEX_INI},
89  {"pthread_mutex_destroy", ThreadAPI::TD_MUTEX_DESTROY},
90  {"pthread_barrier_init", ThreadAPI::TD_BAR_INIT},
91  {"pthread_barrier_wait", ThreadAPI::TD_BAR_WAIT},
92 
93  // Hare APIs
94  {"hare_parallel_for", ThreadAPI::HARE_PAR_FOR},
95 
96  //This must be the last entry.
97  {0, ThreadAPI::TD_DUMMY}
98 };
99 
103 void ThreadAPI::init()
104 {
105  set<TD_TYPE> t_seen;
106  TD_TYPE prev_t= TD_DUMMY;
107  t_seen.insert(TD_DUMMY);
108  for(const ei_pair *p= ei_pairs; p->n; ++p)
109  {
110  if(p->t != prev_t)
111  {
112  //This will detect if you move an entry to another block
113  // but forget to change the type.
114  if(t_seen.count(p->t))
115  {
116  fputs(p->n, stderr);
117  putc('\n', stderr);
118  assert(!"ei_pairs not grouped by type");
119  }
120  t_seen.insert(p->t);
121  prev_t= p->t;
122  }
123  if(tdAPIMap.count(p->n))
124  {
125  fputs(p->n, stderr);
126  putc('\n', stderr);
127  assert(!"duplicate name in ei_pairs");
128  }
129  tdAPIMap[p->n]= p->t;
130  }
131 }
132 
133 bool ThreadAPI::isTDFork(const CallICFGNode *inst) const
134 {
135  return getType(inst->getCalledFunction()) == TD_FORK;
136 }
137 
138 bool ThreadAPI::isTDJoin(const CallICFGNode *inst) const
139 {
140  return getType(inst->getCalledFunction()) == TD_JOIN;
141 }
142 
143 bool ThreadAPI::isTDExit(const CallICFGNode *inst) const
144 {
145  return getType(inst->getCalledFunction()) == TD_EXIT;
146 }
147 
148 bool ThreadAPI::isTDAcquire(const CallICFGNode* inst) const
149 {
150  return getType(inst->getCalledFunction()) == TD_ACQUIRE;
151 }
152 
153 bool ThreadAPI::isTDRelease(const CallICFGNode *inst) const
154 {
155  return getType(inst->getCalledFunction()) == TD_RELEASE;
156 }
157 
158 bool ThreadAPI::isTDBarWait(const CallICFGNode *inst) const
159 {
160  return getType(inst->getCalledFunction()) == TD_BAR_WAIT;
161 }
162 
163 
164 const SVFVar* ThreadAPI::getForkedThread(const CallICFGNode *inst) const
165 {
166  assert(isTDFork(inst) && "not a thread fork function!");
167  return inst->getArgument(0);
168 }
169 
170 const SVFVar* ThreadAPI::getForkedFun(const CallICFGNode *inst) const
171 {
172  assert(isTDFork(inst) && "not a thread fork function!");
173  return inst->getArgument(2);
174 }
175 
179 {
180  assert(isTDFork(inst) && "not a thread fork function!");
181  return inst->getArgument(3);
182 }
183 
184 const SVFVar* ThreadAPI::getFormalParmOfForkedFun(const SVFFunction* F) const
185 {
186  assert(PAG::getPAG()->hasFunArgsList(F) && "forked function has no args list!");
187  const SVFIR::SVFVarList& funArgList = PAG::getPAG()->getFunArgsList(F);
188  // in pthread, forked functions are of type void *()(void *args)
189  assert(funArgList.size() == 1 && "num of pthread forked function args is not 1!");
190  return funArgList[0];
191 }
192 
193 const SVFVar* ThreadAPI::getRetParmAtJoinedSite(const CallICFGNode *inst) const
194 {
195  assert(isTDJoin(inst) && "not a thread join function!");
196  return inst->getArgument(1);
197 }
198 
199 const SVFVar* ThreadAPI::getLockVal(const ICFGNode *cs) const
200 {
201  const CallICFGNode* call = SVFUtil::dyn_cast<CallICFGNode>(cs);
202  assert(call && "not a call ICFGNode?");
203  assert((isTDAcquire(call) || isTDRelease(call)) && "not a lock acquire or release function");
204  return call->getArgument(0);
205 }
206 
207 const SVFVar* ThreadAPI::getJoinedThread(const CallICFGNode *cs) const
208 {
209  assert(isTDJoin(cs) && "not a thread join function!");
210  const SVFVar* join = cs->getArgument(0);
211  for(const SVFStmt* stmt : join->getInEdges())
212  {
213  if(SVFUtil::isa<LoadStmt>(stmt))
214  return stmt->getSrcNode();
215  }
216  if(SVFUtil::isa<SVFArgument>(join->getValue()))
217  return join;
218 
219  assert(false && "the value of the first argument at join is not a load instruction?");
220  return nullptr;
221 }
222 
226 void ThreadAPI::statInit(Map<std::string, u32_t>& tdAPIStatMap)
227 {
228 
229  tdAPIStatMap["pthread_create"] = 0;
230 
231  tdAPIStatMap["pthread_join"] = 0;
232 
233  tdAPIStatMap["pthread_mutex_lock"] = 0;
234 
235  tdAPIStatMap["pthread_mutex_trylock"] = 0;
236 
237  tdAPIStatMap["pthread_mutex_unlock"] = 0;
238 
239  tdAPIStatMap["pthread_cancel"] = 0;
240 
241  tdAPIStatMap["pthread_exit"] = 0;
242 
243  tdAPIStatMap["pthread_detach"] = 0;
244 
245  tdAPIStatMap["pthread_cond_wait"] = 0;
246 
247  tdAPIStatMap["pthread_cond_signal"] = 0;
248 
249  tdAPIStatMap["pthread_cond_broadcast"] = 0;
250 
251  tdAPIStatMap["pthread_cond_init"] = 0;
252 
253  tdAPIStatMap["pthread_cond_destroy"] = 0;
254 
255  tdAPIStatMap["pthread_mutex_init"] = 0;
256 
257  tdAPIStatMap["pthread_mutex_destroy"] = 0;
258 
259  tdAPIStatMap["pthread_barrier_init"] = 0;
260 
261  tdAPIStatMap["pthread_barrier_wait"] = 0;
262 
263  tdAPIStatMap["hare_parallel_for"] = 0;
264 }
265 
266 void ThreadAPI::performAPIStat(SVFModule* module)
267 {
268 
269  Map<std::string, u32_t> tdAPIStatMap;
270 
271  statInit(tdAPIStatMap);
272 
273  PTACallGraph* svfirCallGraph = PAG::getPAG()->getCallGraph();
274  for (const auto& item: *svfirCallGraph)
275  {
276  for (SVFFunction::const_iterator bit = (item.second)->getFunction()->begin(), ebit = (item.second)->getFunction()->end(); bit != ebit; ++bit)
277  {
278  const SVFBasicBlock* bb = *bit;
279  for (const auto& svfInst: bb->getICFGNodeList())
280  {
281  if (!SVFUtil::isCallSite(svfInst))
282  continue;
283 
284  const SVFFunction* fun = SVFUtil::cast<CallICFGNode>(svfInst)->getCalledFunction();
285  TD_TYPE type = getType(fun);
286  switch (type)
287  {
288  case TD_FORK:
289  {
290  tdAPIStatMap["pthread_create"]++;
291  break;
292  }
293  case TD_JOIN:
294  {
295  tdAPIStatMap["pthread_join"]++;
296  break;
297  }
298  case TD_ACQUIRE:
299  {
300  tdAPIStatMap["pthread_mutex_lock"]++;
301  break;
302  }
303  case TD_TRY_ACQUIRE:
304  {
305  tdAPIStatMap["pthread_mutex_trylock"]++;
306  break;
307  }
308  case TD_RELEASE:
309  {
310  tdAPIStatMap["pthread_mutex_unlock"]++;
311  break;
312  }
313  case TD_CANCEL:
314  {
315  tdAPIStatMap["pthread_cancel"]++;
316  break;
317  }
318  case TD_EXIT:
319  {
320  tdAPIStatMap["pthread_exit"]++;
321  break;
322  }
323  case TD_DETACH:
324  {
325  tdAPIStatMap["pthread_detach"]++;
326  break;
327  }
328  case TD_COND_WAIT:
329  {
330  tdAPIStatMap["pthread_cond_wait"]++;
331  break;
332  }
333  case TD_COND_SIGNAL:
334  {
335  tdAPIStatMap["pthread_cond_signal"]++;
336  break;
337  }
338  case TD_COND_BROADCAST:
339  {
340  tdAPIStatMap["pthread_cond_broadcast"]++;
341  break;
342  }
343  case TD_CONDVAR_INI:
344  {
345  tdAPIStatMap["pthread_cond_init"]++;
346  break;
347  }
348  case TD_CONDVAR_DESTROY:
349  {
350  tdAPIStatMap["pthread_cond_destroy"]++;
351  break;
352  }
353  case TD_MUTEX_INI:
354  {
355  tdAPIStatMap["pthread_mutex_init"]++;
356  break;
357  }
358  case TD_MUTEX_DESTROY:
359  {
360  tdAPIStatMap["pthread_mutex_destroy"]++;
361  break;
362  }
363  case TD_BAR_INIT:
364  {
365  tdAPIStatMap["pthread_barrier_init"]++;
366  break;
367  }
368  case TD_BAR_WAIT:
369  {
370  tdAPIStatMap["pthread_barrier_wait"]++;
371  break;
372  }
373  case HARE_PAR_FOR:
374  {
375  tdAPIStatMap["hare_parallel_for"]++;
376  break;
377  }
378  case TD_DUMMY:
379  {
380  break;
381  }
382  }
383  }
384  }
385 
386  }
387 
389  std::vector<std::string> fullNames = SVFUtil::split(name,'/');
390  if (fullNames.size() > 1)
391  {
392  name = fullNames[fullNames.size() - 1];
393  }
394  SVFUtil::outs() << "################ (program : " << name
395  << ")###############\n";
396  SVFUtil::outs().flags(std::ios::left);
397  unsigned field_width = 20;
398  for (Map<std::string, u32_t>::iterator it = tdAPIStatMap.begin(), eit =
399  tdAPIStatMap.end(); it != eit; ++it)
400  {
401  std::string apiName = it->first;
402  // format out put with width 20 space
403  SVFUtil::outs() << std::setw(field_width) << apiName << " : " << it->second
404  << "\n";
405  }
406  SVFUtil::outs() << "#######################################################"
407  << std::endl;
408 
409 }
410 
411 #endif /* THREADAPI_CPP_ */
#define F(f)
static const ei_pair ei_pairs[]
Definition: ThreadAPI.cpp:61
cJSON * p
Definition: cJSON.cpp:2559
newitem type
Definition: cJSON.cpp:2739
cJSON * n
Definition: cJSON.cpp:2558
const char *const name
Definition: cJSON.h:264
cJSON * item
Definition: cJSON.h:222
const char *const string
Definition: cJSON.h:172
const SVFFunction * getCalledFunction() const
Definition: ICFGNode.h:518
const SVFVar * getArgument(u32_t ArgNo) const
Parameter operations.
Definition: ICFGNode.h:500
const GEdgeSetTy & getInEdges() const
Definition: GenericGraph.h:434
const std::vector< const ICFGNode * > & getICFGNodeList() const
Definition: SVFValue.h:569
std::vector< const SVFBasicBlock * >::const_iterator const_iterator
Definition: SVFValue.h:305
std::vector< const SVFVar * > SVFVarList
Definition: SVFIR.h:59
const std::string & getModuleIdentifier() const
Definition: SVFModule.h:185
const SVFValue * getValue() const
Get/has methods of the components.
Definition: SVFVariables.h:83
bool isCallSite(const Instruction *inst)
Whether an instruction is a call or invoke instruction.
Definition: LLVMUtil.h:45
const SVFVar * getActualParmAtForkSite(const CallICFGNode *cs)
Return sole argument of the thread routine.
Definition: SVFUtil.h:435
const SVFVar * getForkedFun(const CallICFGNode *inst)
Return thread fork function.
Definition: SVFUtil.h:356
std::vector< std::string > split(const std::string &s, char separator)
Split into two substrings around the first occurrence of a separator string.
Definition: SVFUtil.h:203
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition: GeneralType.h:101