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.
- package/package.json +1 -1
- package/svf/include/SVFIR/SVFValue.h +7 -0
- package/svf/include/Util/ExtAPI.h +209 -19
- package/svf/include/Util/ExtAPI.json +125 -22
- package/svf/lib/Util/ExtAPI.cpp +90 -18
- package/svf-llvm/include/SVF-LLVM/LLVMModule.h +1 -0
- package/svf-llvm/include/SVF-LLVM/SVFIRBuilder.h +10 -5
- package/svf-llvm/lib/LLVMUtil.cpp +21 -11
- package/svf-llvm/lib/SVFIRBuilder.cpp +1 -423
- package/svf-llvm/lib/SVFIRExtAPI.cpp +681 -0
|
@@ -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
|
+
}
|