Static Value-Flow Analysis
Loading...
Searching...
No Matches
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/CallGraph.h"
36#include "SVFIR/SVFIR.h"
37
38#include <iostream>
39#include <stdio.h>
40#include <iomanip>
41
42using namespace std;
43using namespace SVF;
44
46
47namespace
48{
49
51struct 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).
61static 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.
98};
99
104{
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
133bool ThreadAPI::isTDFork(const CallICFGNode *inst) const
134{
135 return getType(inst->getCalledFunction()) == TD_FORK;
136}
137
138bool ThreadAPI::isTDJoin(const CallICFGNode *inst) const
139{
140 return getType(inst->getCalledFunction()) == TD_JOIN;
141}
142
143bool ThreadAPI::isTDExit(const CallICFGNode *inst) const
144{
145 return getType(inst->getCalledFunction()) == TD_EXIT;
146}
147
149{
150 return getType(inst->getCalledFunction()) == TD_ACQUIRE;
151}
152
154{
155 return getType(inst->getCalledFunction()) == TD_RELEASE;
156}
157
159{
160 return getType(inst->getCalledFunction()) == TD_BAR_WAIT;
161}
162
163
165{
166 assert(isTDFork(inst) && "not a thread fork function!");
167 return inst->getArgument(0);
168}
169
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
185{
186 assert(PAG::getPAG()->hasFunArgsList(F) && "forked function has no args list!");
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
194{
195 assert(isTDJoin(inst) && "not a thread join function!");
196 return inst->getArgument(1);
197}
198
199const 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
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
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
267{
268
270
272
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 {
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 }
339 {
340 tdAPIStatMap["pthread_cond_broadcast"]++;
341 break;
342 }
343 case TD_CONDVAR_INI:
344 {
345 tdAPIStatMap["pthread_cond_init"]++;
346 break;
347 }
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
388 std::string name(module->getModuleIdentifier());
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;
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[]
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 ValVar * getArgument(u32_t ArgNo) const
Parameter operations.
Definition ICFGNode.h:500
const SVFFunction * getCalledFunction() const
Definition ICFGNode.h:518
const std::vector< const ICFGNode * > & getICFGNodeList() const
Definition SVFValue.h:580
const_iterator end() const
Definition SVFValue.h:451
std::vector< constSVFBasicBlock * >::const_iterator const_iterator
Definition SVFValue.h:305
CallGraph * getCallGraph()
Definition SVFIR.h:193
std::vector< const SVFVar * > SVFVarList
Definition SVFIR.h:60
const SVFVarList & getFunArgsList(const SVFFunction *func) const
Get function arguments list.
Definition SVFIR.h:276
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:116
const ValVar * getForkedFun(const CallICFGNode *inst) const
bool isTDFork(const CallICFGNode *inst) const
Return true if this call create a new thread.
static ThreadAPI * tdAPI
Static reference.
Definition ThreadAPI.h:91
@ TD_COND_SIGNAL
wait a condition
Definition ThreadAPI.h:64
@ TD_DETACH
wait for a thread to join
Definition ThreadAPI.h:57
@ TD_CONDVAR_INI
initial a mutex variable
Definition ThreadAPI.h:68
@ HARE_PAR_FOR
Barrier wait.
Definition ThreadAPI.h:72
@ TD_BAR_INIT
initial a mutex variable
Definition ThreadAPI.h:70
@ TD_ACQUIRE
detach a thread directly instead wait for it to join
Definition ThreadAPI.h:58
@ TD_MUTEX_DESTROY
initial a mutex variable
Definition ThreadAPI.h:67
@ TD_FORK
dummy type
Definition ThreadAPI.h:55
@ TD_CONDVAR_DESTROY
initial a mutex variable
Definition ThreadAPI.h:69
@ TD_JOIN
create a new thread
Definition ThreadAPI.h:56
@ TD_BAR_WAIT
Barrier init.
Definition ThreadAPI.h:71
@ TD_COND_BROADCAST
signal a condition
Definition ThreadAPI.h:65
@ TD_COND_WAIT
cancel a thread by another
Definition ThreadAPI.h:63
@ TD_TRY_ACQUIRE
acquire a lock
Definition ThreadAPI.h:59
@ TD_MUTEX_INI
broadcast a condition
Definition ThreadAPI.h:66
@ TD_RELEASE
try to acquire a lock
Definition ThreadAPI.h:60
@ TD_EXIT
release a lock
Definition ThreadAPI.h:61
@ TD_CANCEL
exit/kill a thread
Definition ThreadAPI.h:62
const ValVar * getForkedThread(const CallICFGNode *inst) const
Return arguments/attributes of pthread_create / hare_parallel_for.
TDAPIMap tdAPIMap
API map, from a string to threadAPI type.
Definition ThreadAPI.h:79
bool isTDJoin(const CallICFGNode *inst) const
Return true if this call wait for a worker thread.
void init()
Initialize the map.
const SVFVar * getFormalParmOfForkedFun(const SVFFunction *F) const
Return the formal parm of forked function (the first arg in pthread)
bool isTDRelease(const CallICFGNode *inst) const
Return true if this call release a lock.
void performAPIStat(SVFModule *m)
const SVFVar * getLockVal(const ICFGNode *inst) const
Return lock value.
TD_TYPE getType(const SVFFunction *F) const
Get the function type if it is a threadAPI function.
Definition ThreadAPI.h:94
bool isTDExit(const CallICFGNode *inst) const
Return true if this call exits/terminate a thread.
const SVFVar * getRetParmAtJoinedSite(const CallICFGNode *inst) const
void statInit(Map< std::string, u32_t > &tdAPIStatMap)
const SVFVar * getJoinedThread(const CallICFGNode *inst) const
Return arguments/attributes of pthread_join.
const ValVar * getActualParmAtForkSite(const CallICFGNode *inst) const
bool isTDBarWait(const CallICFGNode *inst) const
Return true if this call waits for a barrier.
bool isTDAcquire(const CallICFGNode *inst) const
Return true if this call acquire a lock.
bool isCallSite(const SVFValue *val)
Whether an instruction is a call or invoke instruction.
Definition SVFUtil.h:175
std::ostream & outs()
Overwrite llvm::outs()
Definition SVFUtil.h:50
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
for isBitcode
Definition BasicTypes.h:68
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74