svf-tools 1.0.730 → 1.0.731

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,681 @@
1
+ //===- SVFIR.cpp -- Exteral function IR of SVF ---------------------------------------------//
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
+ * SVFIRExtAPI.cpp
25
+ *
26
+ * Created on: 18, 5, 2023
27
+ * Author: Shuangxiang Kan
28
+ */
29
+
30
+ #include "SVF-LLVM/SVFIRBuilder.h"
31
+
32
+ using namespace std;
33
+ using namespace SVF;
34
+ using namespace SVFUtil;
35
+
36
+
37
+ /*!
38
+ * Add the load/store constraints and temp. nodes for the complex constraint
39
+ * *D = *S (where D/S may point to structs).
40
+ */
41
+ void SVFIRBuilder::addComplexConsForExt(const SVFValue* D, const SVFValue* S, const SVFValue* szValue)
42
+ {
43
+ assert(D && S);
44
+ NodeID vnD= pag->getValueNode(D), vnS= pag->getValueNode(S);
45
+ if(!vnD || !vnS)
46
+ return;
47
+
48
+ std::vector<LocationSet> fields;
49
+
50
+ //Get the max possible size of the copy, unless it was provided.
51
+ const SVFType* stype = pag->getTypeLocSetsMap(vnS).first;
52
+ const SVFType* dtype = pag->getTypeLocSetsMap(vnD).first;
53
+ std::vector<LocationSet> srcFields = pag->getTypeLocSetsMap(vnS).second;
54
+ std::vector<LocationSet> dstFields = pag->getTypeLocSetsMap(vnD).second;
55
+
56
+ if(srcFields.size() > dstFields.size())
57
+ fields = dstFields;
58
+ else
59
+ fields = srcFields;
60
+
61
+ /// If sz is 0, we will add edges for all fields.
62
+ u32_t sz = fields.size();
63
+ if (szValue && SVFUtil::dyn_cast<SVFConstantInt>(szValue))
64
+ {
65
+ const SVFConstantInt* arg2 = SVFUtil::dyn_cast<SVFConstantInt>(szValue);
66
+ sz = (fields.size() > static_cast<u32_t>(arg2->getSExtValue())) ? arg2->getSExtValue() : fields.size();
67
+ }
68
+
69
+ if (fields.size() == 1 && (SVFUtil::isa<SVFConstantData>(D) || SVFUtil::isa<SVFConstantData>(S)))
70
+ {
71
+ NodeID dummy = pag->addDummyValNode();
72
+ addLoadEdge(vnD,dummy);
73
+ addStoreEdge(dummy,vnS);
74
+ return;
75
+ }
76
+
77
+ //For each field (i), add (Ti = *S + i) and (*D + i = Ti).
78
+ for (u32_t index = 0; index < sz; index++)
79
+ {
80
+ const SVFType* dElementType = pag->getSymbolInfo()->getFlatternedElemType(dtype,
81
+ fields[index].getConstantFieldIdx());
82
+ const SVFType* sElementType = pag->getSymbolInfo()->getFlatternedElemType(stype,
83
+ fields[index].getConstantFieldIdx());
84
+ NodeID dField = getGepValVar(D,fields[index],dElementType);
85
+ NodeID sField = getGepValVar(S,fields[index],sElementType);
86
+ NodeID dummy = pag->addDummyValNode();
87
+ addLoadEdge(sField,dummy);
88
+ addStoreEdge(dummy,dField);
89
+ }
90
+ }
91
+
92
+ NodeID SVFIRBuilder::getExtID(ExtAPI::OperationType operationType, const std::string &s, const SVFCallInst* svfCall)
93
+ {
94
+ s32_t nodeIDType = ExtAPI::getExtAPI()->getNodeIDType(s);
95
+
96
+ // return value >= 0 is an argument node
97
+ if (nodeIDType >= 0)
98
+ {
99
+ assert(svfCall->arg_size() > (u32_t) nodeIDType && "Argument out of bounds!");
100
+ if (operationType == ExtAPI::OperationType::Memcpy_like || operationType == ExtAPI::OperationType::Memset_like)
101
+ return nodeIDType;
102
+ else
103
+ return pag->getValueNode(svfCall->getArgOperand(nodeIDType));
104
+ }
105
+ // return value = -1 is an inst node
106
+ else if (nodeIDType == -1)
107
+ return pag->getValueNode(svfCall);
108
+ // return value = -2 is a Dummy node
109
+ else if (nodeIDType == -2)
110
+ return pag->addDummyValNode();
111
+ // return value = -3 is an object node
112
+ else if (nodeIDType == -3)
113
+ {
114
+ assert(svfCall->getType()->isPointerTy() && "The operand should be a pointer type!");
115
+ NodeID objId;
116
+ // Indirect call
117
+ if (getCallee(svfCall) == nullptr)
118
+ objId = pag->addDummyObjNode(svfCall->getType());
119
+ else // Direct call
120
+ objId = pag->getObjectNode(svfCall);
121
+ return objId;
122
+ }
123
+ // return value = -4 is a nullptr node
124
+ else if (nodeIDType == -4)
125
+ return pag->getNullPtr();
126
+ // return value = -5 is an offset
127
+ else if (nodeIDType == -5)
128
+ {
129
+ for (char const &c : s)
130
+ {
131
+ if (std::isdigit(c) == 0)
132
+ assert(false && "Invalid offset!");
133
+ }
134
+ return atoi(s.c_str());
135
+ }
136
+ // return value = -6 is an illegal operand format
137
+ else
138
+ assert(false && "The operand format of function operation is illegal!");
139
+ }
140
+
141
+ void SVFIRBuilder::parseAtomaticOp(SVF::ExtAPI::Operand &atomaticOp, const SVFCallInst* svfCall, std::map<std::string, NodeID> &nodeIDMap)
142
+ {
143
+ // Skip Rb_tree operation, which is handled in extFuncAtomaticOperation()
144
+ if (atomaticOp.getType() == ExtAPI::OperationType::Rb_tree_ops)
145
+ return;
146
+ // Get src and dst node ID
147
+ if (!atomaticOp.getSrcValue().empty())
148
+ {
149
+ const std::string s = atomaticOp.getSrcValue();
150
+ if (nodeIDMap.find(s) != nodeIDMap.end())
151
+ atomaticOp.setSrcID(nodeIDMap[s]);
152
+ else
153
+ {
154
+ NodeID srcId = getExtID(atomaticOp.getType(), atomaticOp.getSrcValue(), svfCall);
155
+ atomaticOp.setSrcID(srcId);
156
+ nodeIDMap[s] = srcId;
157
+ }
158
+ }
159
+ else
160
+ assert(false && "The 'src' operand cannot be empty.");
161
+
162
+ if (!atomaticOp.getDstValue().empty())
163
+ {
164
+ const std::string s = atomaticOp.getDstValue();
165
+ if (nodeIDMap.find(s) != nodeIDMap.end())
166
+ atomaticOp.setDstID(nodeIDMap[s]);
167
+ else
168
+ {
169
+ NodeID dstId = getExtID(atomaticOp.getType(), atomaticOp.getDstValue(), svfCall);
170
+ atomaticOp.setDstID(dstId);
171
+ nodeIDMap[s] = dstId;
172
+ }
173
+ }
174
+ else
175
+ assert(false && "The 'dst' operand cannot be empty.");
176
+
177
+ // Get offset or size
178
+ if (!atomaticOp.getOffsetOrSizeStr().empty())
179
+ {
180
+ std::string s = atomaticOp.getOffsetOrSizeStr();
181
+ if (nodeIDMap.find(s) != nodeIDMap.end())
182
+ atomaticOp.setOffsetOrSize(nodeIDMap[s]);
183
+ else
184
+ {
185
+ NodeID offsetOrSize = getExtID(atomaticOp.getType(), atomaticOp.getOffsetOrSizeStr(), svfCall);
186
+ atomaticOp.setOffsetOrSize(offsetOrSize);
187
+ nodeIDMap[s] = offsetOrSize;
188
+ }
189
+ }
190
+ }
191
+
192
+ void SVFIRBuilder::parseExtFunctionOps(ExtAPI::ExtFunctionOps &extFunctionOps, const SVFCallInst* svfCall)
193
+ {
194
+ // CallStmt operation
195
+ if (extFunctionOps.getCallStmtNum() != 0)
196
+ handleExtCallStat(extFunctionOps, svfCall);
197
+ // Record all dummy nodes
198
+ std::map<std::string, NodeID> nodeIDMap;
199
+ for (ExtAPI::ExtOperation& extOperation : extFunctionOps.getOperations())
200
+ {
201
+ // CondStmt operation
202
+ if(extOperation.isConOp())
203
+ {
204
+ for (ExtAPI::Operand &atomaticOp : extOperation.getTrueBranchOperands())
205
+ parseAtomaticOp(atomaticOp, svfCall, nodeIDMap);
206
+ for (ExtAPI::Operand &atomaticOp : extOperation.getFalseBranchOperands())
207
+ parseAtomaticOp(atomaticOp, svfCall, nodeIDMap);
208
+ }
209
+ // General operation, e.g., "AddrStmt", "CopyStmt", ....
210
+ else if (!extOperation.isCallOp())
211
+ parseAtomaticOp(extOperation.getBasicOp(), svfCall, nodeIDMap);
212
+ }
213
+ }
214
+
215
+ SVFCallInst* SVFIRBuilder::addSVFExtCallInst(const SVFCallInst* svfInst, SVFBasicBlock* svfBB, const SVFFunction* svfCaller, const SVFFunction* svfCallee)
216
+ {
217
+ SVFCallInst* svfCall = new SVFCallInst("ext_inst", svfCallee->getFunctionType(), svfBB, false, false);
218
+ assert(svfCall && "Failed to create External SVFCallInst");
219
+ LLVMModuleSet::getLLVMModuleSet()->SVFValue2LLVMValue[svfCall] = nullptr;
220
+ svfCall->setCalledOperand(svfCallee);
221
+ setCurrentLocation(svfCall, svfBB);
222
+ SymbolTableInfo::ValueToIDMapTy::iterator iter = pag->getSymbolInfo()->valSyms().find(svfCall);
223
+ if (iter == pag->getSymbolInfo()->valSyms().end())
224
+ {
225
+ SymID id = NodeIDAllocator::get()->allocateValueId();
226
+ pag->getSymbolInfo()->valSyms().insert(std::make_pair(svfCall, id));
227
+ DBOUT(DMemModel, outs() << "create a new value sym " << id << "\n");
228
+ pag->addValNode(svfCall, id);
229
+ }
230
+ svfCall->setName(svfCall->getName() + "_" + std::to_string(pag->getValueNode(svfCall)));
231
+
232
+ for(u32_t i = 0; i < svfCallee->arg_size(); i++)
233
+ {
234
+ SVFInstruction* svfArg = addSVFExtInst("ext_inst", svfInst, svfBB, ExtAPI::OperationType::Other, svfCallee->getArg(i)->getType());
235
+ svfArg->setName(svfArg->getName() + "_" + std::to_string(pag->getValueNode(svfArg)));
236
+ svfCall->addArgument(svfArg);
237
+ }
238
+
239
+ svfBB->addInstruction(svfCall);
240
+
241
+ CallICFGNode* callBlockNode = pag->getICFG()->getCallICFGNode(svfCall);
242
+ pag->addCallSite(callBlockNode);
243
+
244
+ if (!svfCallee->isNotRetFunction() && !isExtCall(svfCallee))
245
+ {
246
+ NodeID srcret = getReturnNode(svfCallee);
247
+ NodeID dstrec = pag->getValueNode(svfCall);
248
+ CallICFGNode* callICFGNode = pag->getICFG()->getCallICFGNode(svfCall);
249
+ FunExitICFGNode* exitICFGNode = pag->getICFG()->getFunExitICFGNode(svfCallee);
250
+ RetICFGNode* retBlockNode = pag->getICFG()->getRetICFGNode(svfCall);
251
+ addRetEdge(srcret, dstrec,callICFGNode, exitICFGNode);
252
+ pag->addCallSiteRets(retBlockNode,pag->getGNode(pag->getValueNode(svfCall)));
253
+ }
254
+
255
+ return svfCall;
256
+ }
257
+
258
+ void SVFIRBuilder::addSVFExtRetInst(SVFCallInst* svfCall, SVFBasicBlock* svfBB, SVFFunction* svfCaller)
259
+ {
260
+ SVFInstruction* retInst = addSVFExtInst("ext_inst", svfCall, svfBB, ExtAPI::OperationType::Return, nullptr);
261
+ retInst->setName(retInst->getName() + "_" + std::to_string(pag->getValueNode(retInst)));
262
+ setCurrentLocation(retInst, svfBB);
263
+
264
+ NodeID rnF = getReturnNode(svfCaller);
265
+ NodeID vnS = pag->getValueNode(svfCall);
266
+ const ICFGNode* icfgNode = pag->getICFG()->getICFGNode(retInst);
267
+ //vnS may be null if src is a null ptr
268
+ addPhiStmt(rnF,vnS,icfgNode);
269
+ }
270
+
271
+ SVFInstruction* SVFIRBuilder::addSVFExtInst(const std::string& instName, const SVFCallInst* svfInst, SVFBasicBlock* svfBB, SVF::ExtAPI::OperationType opType, const SVFType* svfType)
272
+ {
273
+ // Get new SVFInstruction type;
274
+ const SVFType* ptType = nullptr;
275
+ if (svfType != nullptr)
276
+ ptType = svfType;
277
+ else
278
+ {
279
+ if (opType == ExtAPI::OperationType::Addr
280
+ || opType == ExtAPI::OperationType::Copy
281
+ || opType == ExtAPI::OperationType::Load
282
+ || opType == ExtAPI::OperationType::Gep)
283
+ {
284
+ for (u32_t i = 0; i < svfInst->arg_size(); ++i)
285
+ if (svfInst->getArgOperand(i)->getType()->isPointerTy())
286
+ {
287
+ ptType = svfInst->getArgOperand(i)->getType();
288
+ break;
289
+ }
290
+ }
291
+ else
292
+ ptType = svfInst->getParent()->getType();
293
+ }
294
+
295
+ assert(ptType != nullptr && "At least one argument of an external call is of pointer type!");
296
+ SVFInstruction* inst = new SVFInstruction(instName, ptType, svfBB, false, false);
297
+ assert(inst && "Failed to create External SVFInstruction!");
298
+ LLVMModuleSet::getLLVMModuleSet()->SVFValue2LLVMValue[inst] = nullptr;
299
+ svfBB->addInstruction(inst);
300
+ SymbolTableInfo::ValueToIDMapTy::iterator iter = pag->getSymbolInfo()->valSyms().find(inst);
301
+ if (iter == pag->getSymbolInfo()->valSyms().end())
302
+ {
303
+ SymID id = NodeIDAllocator::get()->allocateValueId();
304
+ pag->getSymbolInfo()->valSyms().insert(std::make_pair(inst, id));
305
+ DBOUT(DMemModel, outs() << "create a new value sym " << id << "\n");
306
+ pag->addValNode(inst, id);
307
+ }
308
+ inst->setName(inst->getName() + "_" + std::to_string(pag->getValueNode(inst)));
309
+ return inst;
310
+ }
311
+
312
+ SVFBasicBlock* SVFIRBuilder::extFuncInitialization(const SVFCallInst* svfInst, SVFFunction* svfCaller)
313
+ {
314
+ // Initialization, linking actual parameters with formal parameters,
315
+ // adding basic blocks for external functions,
316
+ // and creating return edges (if the external function has a return value)
317
+ CallICFGNode* callSiteICFGNode = pag->getICFG()->getCallICFGNode(svfInst);
318
+ FunEntryICFGNode* funEntryICFGNode = pag->getICFG()->getFunEntryICFGNode(svfCaller);
319
+ FunExitICFGNode* funExitICFGNode = pag->getICFG()->getFunExitICFGNode(svfCaller);
320
+ for(u32_t i = 0; i < svfCaller->arg_size(); i++)
321
+ {
322
+ const SVFValue *AA = svfInst->getArgOperand(i);
323
+ const SVFValue *FA = svfCaller->getArg(i);
324
+ NodeID srcAA = pag->getValueNode(AA);
325
+ NodeID dstFA = pag->getValueNode(FA);
326
+ addCallEdge(srcAA, dstFA, callSiteICFGNode, funEntryICFGNode);
327
+ pag->addFunArgs(svfCaller,pag->getGNode(dstFA));
328
+ }
329
+
330
+ SVFBasicBlock* svfBB = new SVFBasicBlock("ext_bb", svfInst->getParent()->getType(), svfCaller);
331
+ assert(svfBB && "Failed to create External SVFBasicBlock!");
332
+ LLVMModuleSet::getLLVMModuleSet()->SVFValue2LLVMValue[svfBB] = nullptr;
333
+
334
+ if (!svfCaller->isNotRetFunction())
335
+ {
336
+ NodeID srcret = getReturnNode(svfCaller);
337
+ NodeID dstrec = pag->getValueNode(svfInst);
338
+ addRetEdge(srcret, dstrec,callSiteICFGNode, funExitICFGNode);
339
+ pag->addFunRet(svfCaller,pag->getGNode(srcret));
340
+ }
341
+ return svfBB;
342
+ }
343
+
344
+ void SVFIRBuilder::handleExtCallStat(ExtAPI::ExtFunctionOps &extFunctionOps, const SVFCallInst* svfInst)
345
+ {
346
+ SVFFunction* svfCaller = const_cast<SVFFunction *>(svfModule->getSVFFunction(svfInst->getCalledFunction()->getName()));
347
+ SVFBasicBlock* svfBB = extFuncInitialization(svfInst, svfCaller);
348
+ // Map an operand to its new created SVFInstruction
349
+ std::map<std::string, SVFValue*> operandToSVFValueMap;
350
+ for (ExtAPI::ExtOperation& extOperation : extFunctionOps.getOperations())
351
+ {
352
+ if (extOperation.isCallOp())
353
+ {
354
+ // To create a CallInst for the callee
355
+ const SVFFunction* svfCallee = svfModule->getSVFFunction(extOperation.getCalleeName());
356
+ SVFCallInst* svfCall = addSVFExtCallInst(svfInst, svfBB, svfCaller, svfCallee);
357
+ setCurrentLocation(svfCall, getCurrentBB());
358
+ operandToSVFValueMap[svfCallee->getName()] = svfCall;
359
+ CallICFGNode* callBlockNode = pag->getICFG()->getCallICFGNode(svfCall);
360
+
361
+ assert(extOperation.getCalleeOperands().size() >= svfCallee->arg_size()
362
+ && "Number of arguments set in CallStmt in ExtAPI.json is inconsistent with the number of arguments required by the Callee?");
363
+ // To parse the operations contained in ‘CallStmt’, obtain the NodeID, and add the callEdge
364
+ for (ExtAPI::Operand &operand : extOperation.getCalleeOperands())
365
+ {
366
+ std::string src = operand.getSrcValue();
367
+ std::string dst = operand.getDstValue();
368
+ // ReturnStmt
369
+ if (operand.getType() == ExtAPI::OperationType::Return && !svfCaller->isNotRetFunction())
370
+ {
371
+ addSVFExtRetInst(svfCall, svfBB, svfCaller);
372
+ continue;
373
+ }
374
+
375
+ auto getCallStmtOperands = [](const std::string& str) -> std::pair<std::string, std::string>
376
+ {
377
+ size_t pos = str.find('_');
378
+ assert(pos != std::string::npos && "The operand format in CallStmt is incorrect! It should be either 'funName_Argi' or 'funName_Ret'!");
379
+ return std::make_pair(str.substr(0, pos), str.substr(pos + 1));
380
+ };
381
+ // 'src' operand
382
+ if (src.find('_') != std::string::npos)
383
+ {
384
+ std::pair<std::string, std::string> srcRet = getCallStmtOperands(src);
385
+ s32_t argPos = ExtAPI::getExtAPI()->getNodeIDType(srcRet.second);
386
+ // operand like "caller_Argi"
387
+ if (svfCaller->getName() == srcRet.first)
388
+ {
389
+ assert(argPos >= 0 && static_cast<u32_t>(argPos) < svfCaller->arg_size() && "The argument index is out of bounds in CallStmt?");
390
+ operand.setSrcID(pag->getValueNode(svfCaller->getArg(argPos)));
391
+ }
392
+ // operand like "callee_Ret"
393
+ else
394
+ {
395
+ assert(argPos == -1 && "The operand format in CallStmt is incorrect! It should be either 'funName_Argi' or 'funName_Ret'!");
396
+ assert(operandToSVFValueMap.find(srcRet.first) != operandToSVFValueMap.end() && "No created SVFCallInst in external functions?");
397
+ operand.setSrcID(pag->getValueNode(operandToSVFValueMap[srcRet.first]));
398
+ }
399
+ }
400
+ // operand like self-defined "x", which should be created beforehand
401
+ else
402
+ {
403
+ assert(operandToSVFValueMap.find(src) != operandToSVFValueMap.end()
404
+ && "Cannot find manual create ext inst, incorrect invocation order for external functions?");
405
+ operand.setSrcID(pag->getValueNode(operandToSVFValueMap[src]));
406
+ }
407
+ // 'dst' operand
408
+ if (dst.find('_') != std::string::npos)
409
+ {
410
+ // operand like "callee_Argi"
411
+ std::pair<std::string, std::string> dstRet = getCallStmtOperands(dst);
412
+ assert(svfCallee->getName() == dstRet.first && "The operand format of 'dst' in external CallStmt is illegal!");
413
+ s32_t argPos = ExtAPI::getExtAPI()->getNodeIDType(dstRet.second);
414
+ assert(argPos >= 0 && static_cast<u32_t>(argPos) < svfCallee->arg_size() && "The argument index is out of bounds of callee in CallStmt?");
415
+ // Create an new SVFInstruction for "callee_Argi".
416
+ if(operandToSVFValueMap.find(dst) == operandToSVFValueMap.end())
417
+ {
418
+ SVFInstruction* inst = addSVFExtInst("ext_inst", svfInst, svfBB, operand.getType(), nullptr);
419
+ operand.setDstID(pag->getValueNode(inst));
420
+ operandToSVFValueMap[dst] = inst;
421
+ pag->addCallSiteArgs(callBlockNode,pag->getGNode(pag->getValueNode(inst)));
422
+ }
423
+ CallICFGNode* icfgNode = pag->getICFG()->getCallICFGNode(svfCall);
424
+ FunEntryICFGNode* entry = pag->getICFG()->getFunEntryICFGNode(svfCallee);
425
+ addCallEdge(operand.getDstID(), pag->getValueNode(svfCallee->getArg(argPos)), icfgNode, entry);
426
+ }
427
+ else
428
+ {
429
+ // operand like self-defined "x", if there are no SVFInstructions for 'x', create an new SVFInstruction.
430
+ SVFInstruction* inst = addSVFExtInst(dst, svfInst, svfBB, operand.getType(), nullptr);
431
+ operand.setDstID(pag->getValueNode(inst));
432
+ operandToSVFValueMap[dst] = inst;
433
+ }
434
+ }
435
+ }
436
+ }
437
+ svfCaller->addBasicBlock(svfBB);
438
+ }
439
+
440
+ void SVFIRBuilder::extFuncAtomaticOperation(ExtAPI::Operand& atomicOp, const SVFCallInst* svfCall)
441
+ {
442
+ if (atomicOp.getType() == ExtAPI::OperationType::Addr)
443
+ {
444
+ if (!atomicOp.getSrcValue().empty() && !atomicOp.getDstValue().empty())
445
+ addAddrEdge(atomicOp.getSrcID(), atomicOp.getDstID());
446
+ else
447
+ writeWrnMsg("We need two valid NodeIDs to add an Addr edge");
448
+ }
449
+ else if (atomicOp.getType() == ExtAPI::OperationType::Copy)
450
+ {
451
+ if (!atomicOp.getSrcValue().empty() && !atomicOp.getDstValue().empty())
452
+ addCopyEdge(atomicOp.getSrcID(), atomicOp.getDstID());
453
+ else
454
+ writeWrnMsg("We need two valid NodeIDs to add a Copy edge");
455
+ }
456
+ else if (atomicOp.getType() == ExtAPI::OperationType::Load)
457
+ {
458
+ if (!atomicOp.getSrcValue().empty() && !atomicOp.getDstValue().empty())
459
+ addLoadEdge(atomicOp.getSrcID(), atomicOp.getDstID());
460
+ else
461
+ writeWrnMsg("We need two valid NodeIDs to add a Load edge");
462
+ }
463
+ else if (atomicOp.getType() == ExtAPI::OperationType::Store)
464
+ {
465
+ if (!atomicOp.getSrcValue().empty() && !atomicOp.getDstValue().empty())
466
+ addStoreEdge(atomicOp.getSrcID(), atomicOp.getDstID());
467
+ else
468
+ writeWrnMsg("We need two valid NodeIDs to add a Store edge");
469
+ }
470
+ else if (atomicOp.getType() == ExtAPI::OperationType::Gep)
471
+ {
472
+ if (!atomicOp.getSrcValue().empty() && !atomicOp.getDstValue().empty() && !atomicOp.getOffsetOrSizeStr().empty())
473
+ {
474
+ LocationSet ls(atomicOp.getOffsetOrSize());
475
+ addNormalGepEdge(atomicOp.getSrcID(), atomicOp.getDstID(), ls);
476
+ }
477
+ else
478
+ writeWrnMsg("We need two valid NodeIDs and an offset to add a Gep edge");
479
+ }
480
+ else if (atomicOp.getType() == ExtAPI::OperationType::Return)
481
+ return;
482
+ else if (atomicOp.getType() == ExtAPI::OperationType::Memset_like)
483
+ {
484
+ // this is for memset(void *str, int c, size_t n)
485
+ // which copies the character c (an unsigned char) to the first n characters of the string pointed to, by the argument str
486
+ // const SVFConstantInt* arg2 = SVFUtil::dyn_cast<SVFConstantInt>(svfCall->getArgOperand(op.getOperands()[2]));
487
+ NodeID argId = pag->getValueNode(svfCall->getArgOperand(0));
488
+ std::vector<LocationSet> dstFields = pag->getTypeLocSetsMap(argId).second;
489
+ u32_t sz = dstFields.size();
490
+ if (const SVFConstantInt* arg2 = SVFUtil::dyn_cast<SVFConstantInt>(svfCall->getArgOperand(2)))
491
+ sz = (dstFields.size() > static_cast<u32_t>(arg2->getSExtValue())) ? arg2->getSExtValue() : dstFields.size();
492
+ //For each field (i), add store edge *(arg0 + i) = arg1
493
+ for (u32_t index = 0; index < sz; index++)
494
+ {
495
+ const SVFType* dElementType = pag->getSymbolInfo()->getFlatternedElemType(pag->getTypeLocSetsMap(argId).first, dstFields[index].getConstantFieldIdx());
496
+ NodeID dField = getGepValVar(svfCall->getArgOperand(0), dstFields[index], dElementType);
497
+ addStoreEdge(pag->getValueNode(svfCall->getArgOperand(1)),dField);
498
+ }
499
+ if(svfCall->getType()->isPointerTy())
500
+ addCopyEdge(pag->getValueNode(svfCall->getArgOperand(0)), pag->getValueNode(svfCall));
501
+ }
502
+ else if (atomicOp.getType() == ExtAPI::OperationType::Memcpy_like)
503
+ {
504
+ if(svfCall->arg_size() == 3)
505
+ addComplexConsForExt(svfCall->getArgOperand(0), svfCall->getArgOperand(1), svfCall->getArgOperand(2));
506
+ else
507
+ addComplexConsForExt(svfCall->getArgOperand(0), svfCall->getArgOperand(1), nullptr);
508
+ }
509
+ else if (atomicOp.getType() == ExtAPI::OperationType::Rb_tree_ops)
510
+ {
511
+ assert(svfCall->arg_size() == 4 && "_Rb_tree_insert_and_rebalance should have 4 arguments.\n");
512
+
513
+ // We have vArg3 points to the entry of _Rb_tree_node_base { color; parent; left; right; }.
514
+ // Now we calculate the offset from base to vArg3
515
+ NodeID vnArg3 = pag->getValueNode(svfCall->getArgOperand(3));
516
+ s32_t offset = getLocationSetFromBaseNode(vnArg3).getConstantFieldIdx();
517
+
518
+ // We get all flattened fields of base
519
+ vector<LocationSet> fields = pag->getTypeLocSetsMap(vnArg3).second;
520
+
521
+ // We summarize the side effects: arg3->parent = arg1, arg3->left = arg1, arg3->right = arg1
522
+ // Note that arg0 is aligned with "offset".
523
+ for (s32_t i = offset + 1; i <= offset + 3; ++i)
524
+ {
525
+ if((u32_t)i >= fields.size())
526
+ break;
527
+ const SVFType* elementType = pag->getSymbolInfo()->getFlatternedElemType(pag->getTypeLocSetsMap(vnArg3).first,
528
+ fields[i].getConstantFieldIdx());
529
+ NodeID vnD = getGepValVar(svfCall->getArgOperand(3), fields[i], elementType);
530
+ NodeID vnS = pag->getValueNode(svfCall->getArgOperand(1));
531
+ if(vnD && vnS)
532
+ addStoreEdge(vnS,vnD);
533
+ }
534
+ }
535
+ // default
536
+ // illegal function operation of external function
537
+ else
538
+ {
539
+ assert(false && "new type of SVFStmt for external calls?");
540
+ }
541
+ }
542
+
543
+ /*!
544
+ * Handle external calls
545
+ */
546
+ void SVFIRBuilder::handleExtCall(const SVFInstruction* svfInst, const SVFFunction* svfCallee)
547
+ {
548
+ const SVFCallInst* svfCall = SVFUtil::cast<SVFCallInst>(svfInst);
549
+
550
+ if (isHeapAllocOrStaticExtCall(svfInst))
551
+ {
552
+ // case 1: ret = new obj
553
+ if (isHeapAllocExtCallViaRet(svfInst) || isStaticExtCall(svfInst))
554
+ {
555
+ NodeID val = pag->getValueNode(svfInst);
556
+ NodeID obj = pag->getObjectNode(svfInst);
557
+ addAddrEdge(obj, val);
558
+ }
559
+ // case 2: *arg = new obj
560
+ else
561
+ {
562
+ assert(isHeapAllocExtCallViaArg(svfInst) && "Must be heap alloc call via arg.");
563
+ u32_t arg_pos = getHeapAllocHoldingArgPosition(svfCallee);
564
+ const SVFValue* arg = svfCall->getArgOperand(arg_pos);
565
+ if (arg->getType()->isPointerTy())
566
+ {
567
+ NodeID vnArg = pag->getValueNode(arg);
568
+ NodeID dummy = pag->addDummyValNode();
569
+ NodeID obj = pag->addDummyObjNode(arg->getType());
570
+ if (vnArg && dummy && obj)
571
+ {
572
+ addAddrEdge(obj, dummy);
573
+ addStoreEdge(dummy, vnArg);
574
+ }
575
+ }
576
+ else
577
+ {
578
+ writeWrnMsg("Arg receiving new object must be pointer type");
579
+ }
580
+ }
581
+ }
582
+ else
583
+ {
584
+ if (isExtCall(svfCallee))
585
+ {
586
+ std::string funName = ExtAPI::getExtAPI()->get_name(svfCallee);
587
+ ExtAPI::ExtFunctionOps extFunctionOps = ExtAPI::getExtAPI()->getExtFunctionOps(funName);
588
+ if (extFunctionOps.getOperations().size() == 0)
589
+ {
590
+ std::string str;
591
+ std::stringstream rawstr(str);
592
+ rawstr << "function " << funName << " not in the external function summary ExtAPI.json file";
593
+ writeWrnMsg(rawstr.str());
594
+ }
595
+ else
596
+ {
597
+ parseExtFunctionOps(extFunctionOps, svfCall);
598
+ for (ExtAPI::ExtOperation op : extFunctionOps.getOperations())
599
+ {
600
+ if (op.isCallOp())
601
+ for (ExtAPI::Operand atomicOp : op.getCalleeOperands())
602
+ extFuncAtomaticOperation(atomicOp, svfCall);
603
+ else if(op.isConOp())
604
+ {
605
+ for (ExtAPI::Operand atomicOp : op.getTrueBranchOperands())
606
+ extFuncAtomaticOperation(atomicOp, svfCall);
607
+ for (ExtAPI::Operand atomicOp : op.getFalseBranchOperands())
608
+ extFuncAtomaticOperation(atomicOp, svfCall);
609
+ }
610
+ else
611
+ {
612
+ ExtAPI::Operand atomicOp = op.getBasicOp();
613
+ extFuncAtomaticOperation(atomicOp, svfCall);
614
+ }
615
+ }
616
+ }
617
+ }
618
+
619
+ /// create inter-procedural SVFIR edges for thread forks
620
+ if (isThreadForkCall(svfInst))
621
+ {
622
+ if (const SVFFunction* forkedFun = SVFUtil::dyn_cast<SVFFunction>(getForkedFun(svfInst)))
623
+ {
624
+ forkedFun = forkedFun->getDefFunForMultipleModule();
625
+ const SVFValue* actualParm = getActualParmAtForkSite(svfInst);
626
+ /// pthread_create has 1 arg.
627
+ /// apr_thread_create has 2 arg.
628
+ assert((forkedFun->arg_size() <= 2) && "Size of formal parameter of start routine should be one");
629
+ if (forkedFun->arg_size() <= 2 && forkedFun->arg_size() >= 1)
630
+ {
631
+ const SVFArgument* formalParm = forkedFun->getArg(0);
632
+ /// Connect actual parameter to formal parameter of the start routine
633
+ if (actualParm->getType()->isPointerTy() && formalParm->getType()->isPointerTy())
634
+ {
635
+ CallICFGNode *icfgNode = pag->getICFG()->getCallICFGNode(svfInst);
636
+ FunEntryICFGNode *entry = pag->getICFG()->getFunEntryICFGNode(forkedFun);
637
+ addThreadForkEdge(pag->getValueNode(actualParm), pag->getValueNode(formalParm), icfgNode, entry);
638
+ }
639
+ }
640
+ }
641
+ else
642
+ {
643
+ /// handle indirect calls at pthread create APIs e.g., pthread_create(&t1, nullptr, fp, ...);
644
+ /// const Value* fun = ThreadAPI::getThreadAPI()->getForkedFun(inst);
645
+ /// if(!SVFUtil::isa<Function>(fun))
646
+ /// pag->addIndirectCallsites(cs,pag->getValueNode(fun));
647
+ }
648
+ /// If forkedFun does not pass to spawnee as function type but as void pointer
649
+ /// remember to update inter-procedural callgraph/SVFIR/SVFG etc. when indirect call targets are resolved
650
+ /// We don't connect the callgraph here, further investigation is need to hanle mod-ref during SVFG construction.
651
+ }
652
+
653
+ /// create inter-procedural SVFIR edges for hare_parallel_for calls
654
+ else if (isHareParForCall(svfInst))
655
+ {
656
+ if (const SVFFunction* taskFunc = SVFUtil::dyn_cast<SVFFunction>(getTaskFuncAtHareParForSite(svfInst)))
657
+ {
658
+ /// The task function of hare_parallel_for has 3 args.
659
+ assert((taskFunc->arg_size() == 3) && "Size of formal parameter of hare_parallel_for's task routine should be 3");
660
+ const SVFValue* actualParm = getTaskDataAtHareParForSite(svfInst);
661
+ const SVFArgument* formalParm = taskFunc->getArg(0);
662
+ /// Connect actual parameter to formal parameter of the start routine
663
+ if (actualParm->getType()->isPointerTy() && formalParm->getType()->isPointerTy())
664
+ {
665
+ CallICFGNode *icfgNode = pag->getICFG()->getCallICFGNode(svfInst);
666
+ FunEntryICFGNode *entry = pag->getICFG()->getFunEntryICFGNode(taskFunc);
667
+ addThreadForkEdge(pag->getValueNode(actualParm), pag->getValueNode(formalParm), icfgNode, entry);
668
+ }
669
+ }
670
+ else
671
+ {
672
+ /// handle indirect calls at hare_parallel_for (e.g., hare_parallel_for(..., fp, ...);
673
+ /// const Value* fun = ThreadAPI::getThreadAPI()->getForkedFun(inst);
674
+ /// if(!SVFUtil::isa<Function>(fun))
675
+ /// pag->addIndirectCallsites(cs,pag->getValueNode(fun));
676
+ }
677
+ }
678
+
679
+ /// TODO: inter-procedural SVFIR edges for thread joins
680
+ }
681
+ }