diff --git a/svf-llvm/include/SVF-LLVM/LLVMModule.h b/svf-llvm/include/SVF-LLVM/LLVMModule.h index 7b5a81e38..1ef1184fb 100644 --- a/svf-llvm/include/SVF-LLVM/LLVMModule.h +++ b/svf-llvm/include/SVF-LLVM/LLVMModule.h @@ -54,6 +54,7 @@ class LLVMModuleSet typedef Map GlobalDefToRepMapTy; typedef Map LLVMFun2SVFFunMap; + typedef Map LLVMFun2CallGraphNodeMap; typedef Map LLVMBB2SVFBBMap; typedef Map LLVMInst2SVFInstMap; typedef Map LLVMArgument2SVFArgumentMap; @@ -89,6 +90,7 @@ class LLVMModuleSet GlobalDefToRepMapTy GlobalDefToRepMap; LLVMFun2SVFFunMap LLVMFunc2SVFFunc; ///< Map an LLVM Function to an SVF Function + LLVMFun2CallGraphNodeMap LLVMFunc2CallGraphNode; ///< Map an LLVM Function to an CallGraph Node LLVMBB2SVFBBMap LLVMBB2SVFBB; LLVMInst2SVFInstMap LLVMInst2SVFInst; LLVMArgument2SVFArgumentMap LLVMArgument2SVFArgument; @@ -170,6 +172,8 @@ class LLVMModuleSet LLVMFunc2SVFFunc[func] = svfFunc; setValueAttr(func,svfFunc); } + void addFunctionMap(const Function* func, CallGraphNode* svfFunc); + inline void addBasicBlockMap(const BasicBlock* bb, SVFBasicBlock* svfBB) { LLVMBB2SVFBB[bb] = svfBB; @@ -234,6 +238,13 @@ class LLVMModuleSet return it->second; } + inline CallGraphNode* getCallGraphNode(const Function* fun) const + { + LLVMFun2CallGraphNodeMap::const_iterator it = LLVMFunc2CallGraphNode.find(fun); + assert(it!=LLVMFunc2CallGraphNode.end() && "CallGraph Node not found!"); + return it->second; + } + inline SVFBasicBlock* getSVFBasicBlock(const BasicBlock* bb) const { LLVMBB2SVFBBMap::const_iterator it = LLVMBB2SVFBB.find(bb); diff --git a/svf-llvm/lib/LLVMModule.cpp b/svf-llvm/lib/LLVMModule.cpp index 5ecc89316..0bab01b66 100644 --- a/svf-llvm/lib/LLVMModule.cpp +++ b/svf-llvm/lib/LLVMModule.cpp @@ -41,7 +41,7 @@ #include "SVF-LLVM/ObjTypeInference.h" #include "llvm/Transforms/Utils/Cloning.h" #include "SVF-LLVM/ICFGBuilder.h" -#include "Graphs/PTACallGraph.h" +#include "Graphs/CallGraph.h" #include "Util/CallGraphBuilder.h" using namespace std; @@ -174,6 +174,13 @@ void LLVMModuleSet::build() CallGraphBuilder callGraphBuilder; callgraph = callGraphBuilder.buildSVFIRCallGraph(svfModule); + + for (const auto& it : *callgraph) + { + addFunctionMap( + SVFUtil::cast(getLLVMValue(it.second->getFunction())), + it.second); + } } void LLVMModuleSet::createSVFDataStructure() @@ -1210,6 +1217,12 @@ void LLVMModuleSet::dumpModulesToFile(const std::string& suffix) } } +void LLVMModuleSet::addFunctionMap(const SVF::Function* func, SVF::CallGraphNode* svfFunc) +{ + LLVMFunc2CallGraphNode[func] = svfFunc; + setValueAttr(func,svfFunc); +} + void LLVMModuleSet::setValueAttr(const Value* val, SVFValue* svfvalue) { SVFValue2LLVMValue[svfvalue] = val; diff --git a/svf-llvm/lib/SVFIRBuilder.cpp b/svf-llvm/lib/SVFIRBuilder.cpp index 2db52cf1b..eabf83192 100644 --- a/svf-llvm/lib/SVFIRBuilder.cpp +++ b/svf-llvm/lib/SVFIRBuilder.cpp @@ -39,6 +39,7 @@ #include "SVFIR/SVFModule.h" #include "SVFIR/SVFValue.h" #include "Util/CallGraphBuilder.h" +#include "Graphs/CallGraph.h" #include "Util/Options.h" #include "Util/SVFUtil.h" @@ -77,6 +78,10 @@ SVFIR* SVFIRBuilder::build() { if(llvmModuleSet()->hasICFGNode(inst)) it.second->gNode = llvmModuleSet()->getICFGNode(inst); + } else if (const Function* func = SVFUtil::dyn_cast(llvmModuleSet()->getLLVMValue( + it.second->getValue()))) + { + it.second->gNode = llvmModuleSet()->getCallGraphNode(func); } } @@ -216,16 +221,24 @@ void SVFIRBuilder::initialiseNodes() if(iter->second == symTable->blkPtrSymID() || iter->second == symTable->nullPtrSymID()) continue; - const SVFBaseNode* gNode = nullptr; + const ICFGNode* icfgNode = nullptr; if (const Instruction* inst = SVFUtil::dyn_cast(llvmModuleSet()->getLLVMValue(iter->first))) { if (llvmModuleSet()->hasICFGNode(inst)) { - gNode = llvmModuleSet()->getICFGNode(inst); + icfgNode = llvmModuleSet()->getICFGNode(inst); } } - pag->addValNode(iter->first, iter->second, gNode); + + if (const Function* func = + SVFUtil::dyn_cast(llvmModuleSet()->getLLVMValue(iter->first))) + { + const CallGraphNode* cgn = llvmModuleSet()->getCallGraphNode(func); + pag->addFunValNode(cgn, iter->second, icfgNode); + } else { + pag->addValNode(iter->first, iter->second, icfgNode); + } } for (SymbolTableInfo::ValueToIDMapTy::iterator iter = @@ -235,7 +248,13 @@ void SVFIRBuilder::initialiseNodes() DBOUT(DPAGBuild, outs() << "add obj node " << iter->second << "\n"); if(iter->second == symTable->blackholeSymID() || iter->second == symTable->constantSymID()) continue; - pag->addObjNode(iter->first, iter->second); + if (const Function* func = SVFUtil::dyn_cast( + llvmModuleSet()->getLLVMValue(iter->first))) + { + pag->addFunObjNode(llvmModuleSet()->getCallGraphNode(func), iter->second); + } else { + pag->addObjNode(iter->first, iter->second); + } } for (SymbolTableInfo::FunToIDMapTy::iterator iter = @@ -243,7 +262,10 @@ void SVFIRBuilder::initialiseNodes() ++iter) { DBOUT(DPAGBuild, outs() << "add ret node " << iter->second << "\n"); - pag->addRetNode(iter->first, iter->second); + pag->addRetNode( + llvmModuleSet()->getCallGraphNode(SVFUtil::cast( + llvmModuleSet()->getLLVMValue(iter->first))), + iter->second); } for (SymbolTableInfo::FunToIDMapTy::iterator iter = @@ -251,7 +273,10 @@ void SVFIRBuilder::initialiseNodes() iter != symTable->varargSyms().end(); ++iter) { DBOUT(DPAGBuild, outs() << "add vararg node " << iter->second << "\n"); - pag->addVarargNode(iter->first, iter->second); + pag->addVarargNode( + llvmModuleSet()->getCallGraphNode(SVFUtil::cast( + llvmModuleSet()->getLLVMValue(iter->first))), + iter->second); } /// add address edges for constant nodes. @@ -867,7 +892,9 @@ void SVFIRBuilder::visitCallSite(CallBase* cs) /// Collect callsite arguments and returns for (u32_t i = 0; i < cs->arg_size(); i++) - pag->addCallSiteArgs(callBlockNode,pag->getGNode(getValueNode(cs->getArgOperand(i)))); + pag->addCallSiteArgs( + callBlockNode, + SVFUtil::cast(pag->getGNode(getValueNode(cs->getArgOperand(i))))); if(!cs->getType()->isVoidTy()) pag->addCallSiteRets(retBlockNode,pag->getGNode(getValueNode(cs))); @@ -1319,7 +1346,7 @@ void SVFIRBuilder::setCurrentBBAndValueForPAGEdge(PAGEdge* edge) { assert(srcFun==curInst->getFunction() && "SrcNode of the PAGEdge not in the same function?"); } - if(dstFun!=nullptr && !SVFUtil::isa(edge) && !SVFUtil::isa(edge->getDstNode()->getValue())) + if(dstFun!=nullptr && !SVFUtil::isa(edge) && !SVFUtil::isa(edge->getDstNode())) { assert(dstFun==curInst->getFunction() && "DstNode of the PAGEdge not in the same function?"); } diff --git a/svf-llvm/lib/SVFIRExtAPI.cpp b/svf-llvm/lib/SVFIRExtAPI.cpp index 01930d41b..8c65a9083 100644 --- a/svf-llvm/lib/SVFIRExtAPI.cpp +++ b/svf-llvm/lib/SVFIRExtAPI.cpp @@ -31,6 +31,7 @@ #include "Util/SVFUtil.h" #include "SVF-LLVM/SymbolTableBuilder.h" #include "SVF-LLVM/ObjTypeInference.h" +#include "Graphs/CallGraph.h" using namespace std; using namespace SVF; @@ -256,9 +257,11 @@ void SVFIRBuilder::handleExtCall(const CallBase* cs, const SVFFunction* svfCalle if (isThreadForkCall(callICFGNode)) { - if (const SVFFunction* forkedFun = SVFUtil::dyn_cast(getForkedFun(callICFGNode)->getValue())) + const ValVar* valVar = getForkedFun(callICFGNode); + if (const FunValVar* funcValVar = SVFUtil::dyn_cast(valVar)) { - forkedFun = forkedFun->getDefFunForMultipleModule(); + const SVFFunction* forkedFun = funcValVar->getCallGraphNode()->getFunction() + ->getDefFunForMultipleModule(); const SVFVar* actualParm = getActualParmAtForkSite(callICFGNode); /// pthread_create has 1 arg. /// apr_thread_create has 2 arg. diff --git a/svf/include/Graphs/GenericGraph.h b/svf/include/Graphs/GenericGraph.h index fafd1746e..87fb354b3 100644 --- a/svf/include/Graphs/GenericGraph.h +++ b/svf/include/Graphs/GenericGraph.h @@ -161,6 +161,8 @@ class SVFBaseNode // │ ┌── ValVarKinds: Types of value variable nodes // │ │ ├── Represents a standard value variable ValNode, + // │ │ ├── Represents a Function value variable + FunValNode, // │ │ ├── Represents a GEP value variable GepValNode, // │ │ ├── Represents a return value node @@ -174,8 +176,10 @@ class SVFBaseNode ObjNode, // │ ├── GepObjNode: Represents a GEP object variable GepObjNode, - // │ ├── FIObjNode: Represents a flow-insensitive object node + // │ └── FIObjNode: Represents a flow-insensitive object node FIObjNode, + // │ ├──FunObjNode: Types of function object + FunObjNode, // │ └── DummyObjNode: Dummy node for uninitialized objects DummyObjNode, // └──────── @@ -313,7 +317,7 @@ class SVFBaseNode static inline bool isSVFVarKind(GNodeK n) { - static_assert(DummyObjNode - ValNode == 8, + static_assert(DummyObjNode - ValNode == 10, "The number of SVFVarKinds has changed, make sure the " "range is correct"); @@ -322,7 +326,7 @@ class SVFBaseNode static inline bool isValVarKinds(GNodeK n) { - static_assert(DummyValNode - ValNode == 4, + static_assert(DummyValNode - ValNode == 5, "The number of ValVarKinds has changed, make sure the " "range is correct"); return n <= DummyValNode && n >= ValNode; @@ -330,12 +334,20 @@ class SVFBaseNode static inline bool isObjVarKinds(GNodeK n) { - static_assert(DummyObjNode - ObjNode == 3, + static_assert(DummyObjNode - ObjNode == 4, "The number of ObjVarKinds has changed, make sure the " "range is correct"); return n <= DummyObjNode && n >= ObjNode; } + static inline bool isFIObjVarKinds(GNodeK n) + { + static_assert(FunObjNode - FIObjNode == 1, + "The number of FIObjVarKinds has changed, make sure the " + "range is correct"); + return n <= FunObjNode && n >= FIObjNode; + } + static inline bool isVFGNodeKinds(GNodeK n) { static_assert(MInterPhi - Cmp == 24, diff --git a/svf/include/Graphs/ICFGNode.h b/svf/include/Graphs/ICFGNode.h index 67fccfffe..033660187 100644 --- a/svf/include/Graphs/ICFGNode.h +++ b/svf/include/Graphs/ICFGNode.h @@ -425,7 +425,7 @@ class CallICFGNode : public InterICFGNode friend class SVFIRReader; public: - typedef std::vector ActualParmNodeVec; + typedef std::vector ActualParmNodeVec; protected: const RetICFGNode* ret; @@ -491,13 +491,13 @@ class CallICFGNode : public InterICFGNode } /// Add actual parameters - inline void addActualParms(const SVFVar *ap) + inline void addActualParms(const ValVar *ap) { APNodes.push_back(ap); } /// Parameter operations //@{ - inline const SVFVar* getArgument(u32_t ArgNo) const + inline const ValVar* getArgument(u32_t ArgNo) const { return getActualParms()[ArgNo]; } diff --git a/svf/include/SVFIR/SVFIR.h b/svf/include/SVFIR/SVFIR.h index 96c174712..bf0bfdaa8 100644 --- a/svf/include/SVFIR/SVFIR.h +++ b/svf/include/SVFIR/SVFIR.h @@ -522,7 +522,7 @@ class SVFIR : public IRGraph funRetMap[fun] = ret; } /// Add callsite arguments - inline void addCallSiteArgs(CallICFGNode* callBlockNode,const SVFVar* arg) + inline void addCallSiteArgs(CallICFGNode* callBlockNode,const ValVar* arg) { callBlockNode->addActualParms(arg); callSiteArgsListMap[callBlockNode].push_back(arg); @@ -545,11 +545,17 @@ class SVFIR : public IRGraph /// add node into SVFIR //@{ /// Add a value (pointer) node - inline NodeID addValNode(const SVFValue* val, NodeID i, const SVFBaseNode* gNode) + inline NodeID addValNode(const SVFValue* val, NodeID i, const ICFGNode* icfgNode) { - SVFVar *node = new ValVar(val,i, ValVar::ValNode, gNode); + SVFVar *node = new ValVar(val,i, ValVar::ValNode, icfgNode); return addValNode(val, node, i); } + + NodeID addFunValNode(const CallGraphNode* callGraphNode, NodeID i, const ICFGNode* icfgNode) { + FunValVar* node = new FunValVar(callGraphNode, i, icfgNode); + return addValNode(nullptr, node, i); + } + /// Add a memory obj node inline NodeID addObjNode(const SVFValue* val, NodeID i) { @@ -557,14 +563,16 @@ class SVFIR : public IRGraph assert(mem->getId() == i && "not same object id?"); return addFIObjNode(mem); } + + NodeID addFunObjNode(const CallGraphNode* callGraphNode, NodeID id); /// Add a unique return node for a procedure - inline NodeID addRetNode(const SVFFunction* val, NodeID i) + inline NodeID addRetNode(const CallGraphNode* callGraphNode, NodeID i) { - SVFVar *node = new RetPN(val,i); - return addRetNode(val, node, i); + SVFVar *node = new RetPN(callGraphNode,i); + return addRetNode(callGraphNode, node, i); } /// Add a unique vararg node for a procedure - inline NodeID addVarargNode(const SVFFunction* val, NodeID i) + inline NodeID addVarargNode(const CallGraphNode* val, NodeID i) { SVFVar *node = new VarArgPN(val,i); return addNode(node,i); @@ -576,6 +584,7 @@ class SVFIR : public IRGraph NodeID addGepObjNode(const MemObj* obj, const APOffset& apOffset, const NodeID gepId); /// Add a field-insensitive node, this method can only invoked by getFIGepObjNode NodeID addFIObjNode(const MemObj* obj); + //@} /// Add a dummy value/object node according to node ID (llvm value is null) @@ -628,7 +637,7 @@ class SVFIR : public IRGraph return addNode(node, i); } /// Add a unique return node for a procedure - inline NodeID addRetNode(const SVFFunction*, SVFVar *node, NodeID i) + inline NodeID addRetNode(const CallGraphNode*, SVFVar *node, NodeID i) { return addNode(node,i); } diff --git a/svf/include/SVFIR/SVFVariables.h b/svf/include/SVFIR/SVFVariables.h index 01307c99b..173fbe90e 100644 --- a/svf/include/SVFIR/SVFVariables.h +++ b/svf/include/SVFIR/SVFVariables.h @@ -87,8 +87,7 @@ class SVFVar : public GenericPAGNodeTy "dummy node do not have value!"); assert(!SymbolTableInfo::isBlkObjOrConstantObj(this->getId()) && "blackhole and constant obj do not have value"); - assert(value && - "value is null (GepObjNode whose basenode is a DummyObj?)"); + assert(value && "value is null (GepObjNode whose basenode is a DummyObj?)"); return value; } @@ -112,7 +111,7 @@ class SVFVar : public GenericPAGNodeTy bool isConstDataOrAggDataButNotNullPtr() const; /// Whether this is an isolated node on the SVFIR graph - bool isIsolatedNode() const; + virtual bool isIsolatedNode() const; /// Get name of the LLVM value // TODO: (Optimization) Should it return const reference instead of value? @@ -127,8 +126,6 @@ class SVFVar : public GenericPAGNodeTy return inst->getParent()->getParent(); else if (auto arg = SVFUtil::dyn_cast(value)) return arg->getParent(); - else if (auto fun = SVFUtil::dyn_cast(value)) - return fun; } return nullptr; } @@ -269,10 +266,10 @@ class ValVar: public SVFVar friend class SVFIRReader; private: - const SVFBaseNode* gNode; // constant, gepValvar, retPN, dummy could be null + const ICFGNode* icfgNode; // icfgnode related to valvar protected: /// Constructor to create an empty ValVar (for SVFIRReader/deserialization) - ValVar(NodeID i, PNODEK ty = ValNode) : SVFVar(i, ty), gNode(nullptr) {} + ValVar(NodeID i, PNODEK ty = ValNode) : SVFVar(i, ty), icfgNode(nullptr) {} public: /// Methods for support type inquiry through isa, cast, and dyn_cast: @@ -296,8 +293,8 @@ class ValVar: public SVFVar //@} /// Constructor - ValVar(const SVFValue* val, NodeID i, PNODEK ty = ValNode, const SVFBaseNode* node = nullptr) - : SVFVar(val, i, ty), gNode(node) + ValVar(const SVFValue* val, NodeID i, PNODEK ty = ValNode, const ICFGNode* node = nullptr) + : SVFVar(val, i, ty), icfgNode(node) { } /// Return name of a LLVM value @@ -308,9 +305,9 @@ class ValVar: public SVFVar return ""; } - const SVFBaseNode* getGNode() const + const ICFGNode* getICFGNode() const { - return gNode; + return icfgNode; } virtual const std::string toString() const; @@ -540,7 +537,7 @@ class FIObjVar: public ObjVar friend class SVFIRWriter; friend class SVFIRReader; -private: +protected: /// Constructor to create empty ObjVar (for SVFIRReader/deserialization) FIObjVar(NodeID i, PNODEK ty = FIObjNode) : ObjVar(i, ty) {} @@ -553,19 +550,19 @@ class FIObjVar: public ObjVar } static inline bool classof(const ObjVar* node) { - return node->getNodeKind() == SVFVar::FIObjNode; + return isFIObjVarKinds(node->getNodeKind()); } static inline bool classof(const SVFVar* node) { - return node->getNodeKind() == SVFVar::FIObjNode; + return isFIObjVarKinds(node->getNodeKind()); } static inline bool classof(const GenericPAGNodeTy* node) { - return node->getNodeKind() == SVFVar::FIObjNode; + return isFIObjVarKinds(node->getNodeKind()); } static inline bool classof(const SVFBaseNode* node) { - return node->getNodeKind() == SVFVar::FIObjNode; + return isFIObjVarKinds(node->getNodeKind()); } //@} @@ -587,6 +584,107 @@ class FIObjVar: public ObjVar virtual const std::string toString() const; }; +class CallGraphNode; + +class FunValVar : public ValVar { + friend class SVFIRWriter; + friend class SVFIRReader; +private: + const CallGraphNode* callGraphNode; + +public: + /// Methods for support type inquiry through isa, cast, and dyn_cast: + //@{ + static inline bool classof(const FunValVar*) + { + return true; + } + static inline bool classof(const ValVar* node) + { + return node->getNodeKind() == FunValNode; + } + static inline bool classof(const SVFVar* node) + { + return node->getNodeKind() == FunValNode; + } + static inline bool classof(const GenericPAGNodeTy* node) + { + return node->getNodeKind() == FunValNode; + } + static inline bool classof(const SVFBaseNode* node) + { + return node->getNodeKind() == FunValNode; + } + //@} + + inline const CallGraphNode* getCallGraphNode() const { + return callGraphNode; + } + + /// Constructor + FunValVar(const CallGraphNode* cgn, NodeID i, const ICFGNode* icn, + PNODEK ty = FunValNode) + : ValVar(nullptr, i, ty, icn), callGraphNode(cgn) + { + + } + + virtual const std::string toString() const; +}; + +class FunObjVar : public FIObjVar { + friend class SVFIRWriter; + friend class SVFIRReader; + +private: + const CallGraphNode* callGraphNode; + +private: + /// Constructor to create empty ObjVar (for SVFIRReader/deserialization) + FunObjVar(NodeID i, PNODEK ty = FunObjNode) : FIObjVar(i, ty) {} + +public: + /// Methods for support type inquiry through isa, cast, and dyn_cast: + //@{ + static inline bool classof(const FunObjVar*) + { + return true; + } + static inline bool classof(const FIObjVar* node) + { + return node->getNodeKind() == FunObjNode; + } + static inline bool classof(const ObjVar* node) + { + return node->getNodeKind() == FunObjNode; + } + static inline bool classof(const SVFVar* node) + { + return node->getNodeKind() == FunObjNode; + } + static inline bool classof(const GenericPAGNodeTy* node) + { + return node->getNodeKind() == FunObjNode; + } + static inline bool classof(const SVFBaseNode* node) + { + return node->getNodeKind() == FunObjNode; + } + //@} + + /// Constructor + FunObjVar(const CallGraphNode* cgNode, NodeID i, const MemObj* mem, + PNODEK ty = FunObjNode); + + inline const CallGraphNode* getCallGraphNode() const { + return callGraphNode; + } + + virtual bool isIsolatedNode() const; + + virtual const std::string toString() const; +}; + /* * Unique Return node of a procedure */ @@ -595,6 +693,8 @@ class RetPN: public ValVar friend class SVFIRWriter; friend class SVFIRReader; +private: + const CallGraphNode* callGraphNode; private: /// Constructor to create empty RetPN (for SVFIRReader/deserialization) RetPN(NodeID i) : ValVar(i, RetNode) {} @@ -623,15 +723,19 @@ class RetPN: public ValVar } //@} + /// Constructor - RetPN(const SVFFunction* val, NodeID i) : ValVar(val, i, RetNode) {} + RetPN(const CallGraphNode* node, NodeID i); - /// Return name of a LLVM value - const std::string getValueName() const - { - return value->getName() + "_ret"; + inline const CallGraphNode* getCallGraphNode() const { + return callGraphNode; } + virtual const SVFFunction* getFunction() const; + + /// Return name of a LLVM value + const std::string getValueName() const; + virtual const std::string toString() const; }; @@ -642,6 +746,8 @@ class VarArgPN: public ValVar { friend class SVFIRWriter; friend class SVFIRReader; +private: + const CallGraphNode* callGraphNode; private: /// Constructor to create empty VarArgPN (for SVFIRReader/deserialization) @@ -672,13 +778,12 @@ class VarArgPN: public ValVar //@} /// Constructor - VarArgPN(const SVFFunction* val, NodeID i) : ValVar(val, i, VarargNode) {} + VarArgPN(const CallGraphNode* node, NodeID i) : ValVar(nullptr, i, VarargNode), callGraphNode(node) {} + + virtual const SVFFunction* getFunction() const; /// Return name of a LLVM value - inline const std::string getValueName() const - { - return value->getName() + "_vararg"; - } + const std::string getValueName() const; virtual const std::string toString() const; }; diff --git a/svf/include/Util/SVFUtil.h b/svf/include/Util/SVFUtil.h index a48387692..3ec67b1e2 100644 --- a/svf/include/Util/SVFUtil.h +++ b/svf/include/Util/SVFUtil.h @@ -351,9 +351,11 @@ inline bool isArgOfUncalledFunction(const SVFValue* svfval) return false; } +const ObjVar* getObjVarOfValVar(const ValVar* valVar); + /// Return thread fork function //@{ -inline const SVFVar* getForkedFun(const CallICFGNode *inst) +inline const ValVar* getForkedFun(const CallICFGNode *inst) { return ThreadAPI::getThreadAPI()->getForkedFun(inst); } @@ -432,7 +434,7 @@ inline bool isBarrierWaitCall(const CallICFGNode* cs) /// Return sole argument of the thread routine //@{ -inline const SVFVar* getActualParmAtForkSite(const CallICFGNode* cs) +inline const ValVar* getActualParmAtForkSite(const CallICFGNode* cs) { return ThreadAPI::getThreadAPI()->getActualParmAtForkSite(cs); } diff --git a/svf/include/Util/ThreadAPI.h b/svf/include/Util/ThreadAPI.h index 356bde4db..3acb042b5 100644 --- a/svf/include/Util/ThreadAPI.h +++ b/svf/include/Util/ThreadAPI.h @@ -39,6 +39,8 @@ class SVFModule; class ICFGNode; class CallICFGNode; class SVFVar; +class ValVar; +class ObjVar; /* * ThreadAPI class contains interfaces for pthread programs @@ -124,14 +126,14 @@ class ThreadAPI //@{ /// Return the first argument of the call, /// Note that, it is the pthread_t pointer - const SVFVar* getForkedThread(const CallICFGNode *inst) const; + const ValVar* getForkedThread(const CallICFGNode *inst) const; /// Return the third argument of the call, /// Note that, it could be function type or a void* pointer - const SVFVar* getForkedFun(const CallICFGNode *inst) const; + const ValVar* getForkedFun(const CallICFGNode *inst) const; /// Return the forth argument of the call, /// Note that, it is the sole argument of start routine ( a void* pointer ) - const SVFVar* getActualParmAtForkSite(const CallICFGNode *inst) const; + const ValVar* getActualParmAtForkSite(const CallICFGNode *inst) const; /// Return the formal parm of forked function (the first arg in pthread) const SVFVar* getFormalParmOfForkedFun(const SVFFunction* F) const; diff --git a/svf/lib/AE/Svfexe/AbsExtAPI.cpp b/svf/lib/AE/Svfexe/AbsExtAPI.cpp index bdd11e357..2260d3fba 100644 --- a/svf/lib/AE/Svfexe/AbsExtAPI.cpp +++ b/svf/lib/AE/Svfexe/AbsExtAPI.cpp @@ -130,8 +130,7 @@ void AbsExtAPI::initExtFunMap() assert(lb.getInterval().is_numeral() && ub.getInterval().is_numeral()); num.getInterval().set_to_top(); num.getInterval().meet_with(IntervalValue(lb.getInterval().lb(), ub.getInterval().ub())); - const ICFGNode* node = SVFUtil::cast( - SVFUtil::cast(callNode->getArgument(0))->getGNode()); + const ICFGNode* node = SVFUtil::cast(callNode->getArgument(0))->getICFGNode(); for (const SVFStmt* stmt: node->getSVFStmts()) { if (SVFUtil::isa(stmt)) diff --git a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp index 8ea21a40a..4e34e4d47 100644 --- a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +++ b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp @@ -30,6 +30,7 @@ #include "SVFIR/SVFIR.h" #include "Util/Options.h" #include "Util/WorkList.h" +#include "Graphs/CallGraph.h" #include using namespace SVF; @@ -646,9 +647,9 @@ void AbstractInterpretation::indirectCallFunPass(const SVF::CallICFGNode *callNo AbstractValue Addrs = as[call_id]; NodeID addr = *Addrs.getAddrs().begin(); SVFVar *func_var = svfir->getGNode(AbstractState::getInternalID(addr)); - const SVFFunction *callfun = SVFUtil::dyn_cast(func_var->getValue()); - if (callfun) + if(const FunObjVar*funObjVar = SVFUtil::dyn_cast(func_var)) { + const SVFFunction* callfun = funObjVar->getCallGraphNode()->getFunction(); callSiteStack.push_back(callNode); abstractTrace[callNode] = as; @@ -656,7 +657,7 @@ void AbstractInterpretation::indirectCallFunPass(const SVF::CallICFGNode *callNo handleWTOComponents(wto->getWTOComponents()); callSiteStack.pop_back(); // handle Ret node - const RetICFGNode *retNode = callNode->getRetICFGNode(); + const RetICFGNode* retNode = callNode->getRetICFGNode(); abstractTrace[retNode] = abstractTrace[callNode]; } } diff --git a/svf/lib/Graphs/PTACallGraph.cpp b/svf/lib/Graphs/PTACallGraph.cpp index 7c30f3828..7d24d7644 100644 --- a/svf/lib/Graphs/PTACallGraph.cpp +++ b/svf/lib/Graphs/PTACallGraph.cpp @@ -52,7 +52,8 @@ void PTACallGraphEdge::addDirectCallSite(const CallICFGNode* call) void PTACallGraphEdge::addInDirectCallSite(const CallICFGNode* call) { - assert((nullptr == call->getCalledFunction() || nullptr == SVFUtil::dyn_cast (SVFUtil::getForkedFun(call)->getValue())) && "not an indirect callsite??"); + assert((nullptr == call->getCalledFunction() || !SVFUtil::isa(SVFUtil::getForkedFun(call))) && + "not an indirect callsite??"); indirectCalls.insert(call); } //@} diff --git a/svf/lib/Graphs/ThreadCallGraph.cpp b/svf/lib/Graphs/ThreadCallGraph.cpp index 470293c52..3f924b42e 100644 --- a/svf/lib/Graphs/ThreadCallGraph.cpp +++ b/svf/lib/Graphs/ThreadCallGraph.cpp @@ -32,6 +32,7 @@ #include "Util/ThreadAPI.h" #include "SVFIR/SVFIR.h" #include "MemoryModel/PointerAnalysisImpl.h" +#include "Graphs/CallGraph.h" using namespace SVF; using namespace SVFUtil; @@ -73,8 +74,8 @@ void ThreadCallGraph::updateCallGraph(PointerAnalysis* pta) // Fork sites for (CallSiteSet::const_iterator it = forksitesBegin(), eit = forksitesEnd(); it != eit; ++it) { - const SVFVar* forkedval = tdAPI->getForkedFun(*it); - if(SVFUtil::dyn_cast(forkedval->getValue())==nullptr) + const ValVar* forkedval = tdAPI->getForkedFun(*it); + if(SVFUtil::dyn_cast(forkedval)==nullptr) { SVFIR* pag = pta->getPAG(); const NodeBS targets = pta->getPts(forkedval->getId()).toNodeBS(); @@ -85,7 +86,7 @@ void ThreadCallGraph::updateCallGraph(PointerAnalysis* pta) const MemObj* obj = pag->getObject(objPN); if(obj->isFunction()) { - const SVFFunction* svfCallee = SVFUtil::cast(obj->getValue()); + const SVFFunction* svfCallee = SVFUtil::cast(obj->getGNode())->getFunction(); this->addIndirectForkEdge(*it, svfCallee); } } @@ -126,7 +127,8 @@ bool ThreadCallGraph::addDirectForkEdge(const CallICFGNode* cs) { PTACallGraphNode* caller = getCallGraphNode(cs->getCaller()); - const SVFFunction* forkee = SVFUtil::dyn_cast(tdAPI->getForkedFun(cs)->getValue()); + const SVFFunction* forkee = SVFUtil::dyn_cast(tdAPI->getForkedFun(cs)) + ->getCallGraphNode()->getFunction(); assert(forkee && "callee does not exist"); PTACallGraphNode* callee = getCallGraphNode(forkee->getDefFunForMultipleModule()); CallSiteID csId = addCallSite(cs, callee->getFunction()); @@ -185,7 +187,10 @@ void ThreadCallGraph::addDirectJoinEdge(const CallICFGNode* cs,const CallSiteSet for (CallSiteSet::const_iterator it = forkset.begin(), eit = forkset.end(); it != eit; ++it) { - const SVFFunction* threadRoutineFun = SVFUtil::dyn_cast(tdAPI->getForkedFun(*it)->getValue()); + const SVFFunction* threadRoutineFun = + SVFUtil::dyn_cast(tdAPI->getForkedFun(*it)) + ->getCallGraphNode() + ->getFunction(); assert(threadRoutineFun && "thread routine function does not exist"); PTACallGraphNode* threadRoutineFunNode = getCallGraphNode(threadRoutineFun); CallSiteID csId = addCallSite(cs, threadRoutineFun); diff --git a/svf/lib/Graphs/VFG.cpp b/svf/lib/Graphs/VFG.cpp index c4609c97f..dd0924e82 100644 --- a/svf/lib/Graphs/VFG.cpp +++ b/svf/lib/Graphs/VFG.cpp @@ -1090,7 +1090,7 @@ const SVFValue* BinaryOPVFGNode::getValue() const const SVFValue* PHIVFGNode::getValue() const { - return getRes()->getValue(); + return getRes()->hasValue() ? getRes()->getValue(): nullptr; } const SVFValue* ArgumentVFGNode::getValue() const diff --git a/svf/lib/MTA/MTAStat.cpp b/svf/lib/MTA/MTAStat.cpp index 9abdedaf6..1f6c69456 100644 --- a/svf/lib/MTA/MTAStat.cpp +++ b/svf/lib/MTA/MTAStat.cpp @@ -33,6 +33,7 @@ #include "MTA/MHP.h" #include "MTA/LockAnalysis.h" #include "Graphs/ThreadCallGraph.h" +#include "Graphs/CallGraph.h" using namespace SVF; @@ -49,8 +50,8 @@ void MTAStat::performThreadCallGraphStat(ThreadCallGraph* tcg) for (ThreadCallGraph::CallSiteSet::const_iterator it = tcg->forksitesBegin(), eit = tcg->forksitesEnd(); it != eit; ++it) { bool indirectfork = false; - const SVFFunction* spawnee = SVFUtil::dyn_cast(tcg->getThreadAPI()->getForkedFun(*it)->getValue()); - if(spawnee==nullptr) + const ValVar* pValVar = tcg->getThreadAPI()->getForkedFun(*it); + if(!SVFUtil::isa(pValVar)) { numOfIndForksite++; indirectfork = true; diff --git a/svf/lib/MemoryModel/PointerAnalysis.cpp b/svf/lib/MemoryModel/PointerAnalysis.cpp index 9f4a8122a..3d292fba5 100644 --- a/svf/lib/MemoryModel/PointerAnalysis.cpp +++ b/svf/lib/MemoryModel/PointerAnalysis.cpp @@ -36,6 +36,7 @@ #include "Util/PTAStat.h" #include "Graphs/ThreadCallGraph.h" #include "Graphs/ICFG.h" +#include "Graphs/CallGraph.h" #include "Util/CallGraphBuilder.h" #include @@ -399,7 +400,7 @@ void PointerAnalysis::resolveIndCalls(const CallICFGNode* cs, const PointsTo& ta if(obj->isFunction()) { - const SVFFunction* calleefun = SVFUtil::cast(obj->getValue()); + const SVFFunction* calleefun = SVFUtil::cast(obj->getGNode())->getFunction(); const SVFFunction* callee = calleefun->getDefFunForMultipleModule(); if(SVFUtil::matchArgs(cs, callee) == false) diff --git a/svf/lib/MemoryModel/PointerAnalysisImpl.cpp b/svf/lib/MemoryModel/PointerAnalysisImpl.cpp index 8e57096b8..0d47c1567 100644 --- a/svf/lib/MemoryModel/PointerAnalysisImpl.cpp +++ b/svf/lib/MemoryModel/PointerAnalysisImpl.cpp @@ -34,6 +34,8 @@ #include #include +#include "Graphs/CallGraph.h" + using namespace SVF; using namespace SVFUtil; using namespace std; @@ -521,11 +523,11 @@ void BVDataPTAImpl::onTheFlyThreadCallGraphSolve(const CallSiteToFunPtrMap& call for(CallSiteSet::const_iterator it = tdCallGraph->forksitesBegin(), eit = tdCallGraph->forksitesEnd(); it != eit; ++it) { - const SVFValue* forkedVal =tdCallGraph->getThreadAPI()->getForkedFun(*it)->getValue(); - if(SVFUtil::dyn_cast(forkedVal) == nullptr) + const ValVar* pVar = tdCallGraph->getThreadAPI()->getForkedFun(*it); + if(SVFUtil::dyn_cast(pVar) == nullptr) { SVFIR *pag = this->getPAG(); - const NodeBS targets = this->getPts(pag->getValueNode(forkedVal)).toNodeBS(); + const NodeBS targets = this->getPts(pVar->getId()).toNodeBS(); for(NodeBS::iterator ii = targets.begin(), ie = targets.end(); ii != ie; ++ii) { if(ObjVar *objPN = SVFUtil::dyn_cast(pag->getGNode(*ii))) @@ -533,7 +535,7 @@ void BVDataPTAImpl::onTheFlyThreadCallGraphSolve(const CallSiteToFunPtrMap& call const MemObj *obj = pag->getObject(objPN); if(obj->isFunction()) { - const SVFFunction *svfForkedFun = SVFUtil::cast(obj->getValue()); + const SVFFunction *svfForkedFun = SVFUtil::cast(obj->getGNode())->getFunction(); if(tdCallGraph->addIndirectForkEdge(*it, svfForkedFun)) newForkEdges[*it].insert(svfForkedFun); } diff --git a/svf/lib/SABER/SaberCondAllocator.cpp b/svf/lib/SABER/SaberCondAllocator.cpp index c6d989aad..082d7a52b 100644 --- a/svf/lib/SABER/SaberCondAllocator.cpp +++ b/svf/lib/SABER/SaberCondAllocator.cpp @@ -195,7 +195,7 @@ SaberCondAllocator::evaluateTestNullLikeExpr(const BranchStmt *branchStmt, const // br i1 false, label %44, label %75, !dbg !7669 { "ln": 2033, "cl": 7, "fl": "re_lexer.c" } return Condition::nullExpr(); } - if (isTestNullExpr(SVFUtil::cast(condVar->getGNode()))) + if (isTestNullExpr(SVFUtil::cast(condVar->getICFGNode()))) { // succ is then branch if (succ1 == succ) @@ -204,7 +204,7 @@ SaberCondAllocator::evaluateTestNullLikeExpr(const BranchStmt *branchStmt, const else return getTrueCond(); } - if (isTestNotNullExpr(SVFUtil::cast(condVar->getGNode()))) + if (isTestNotNullExpr(condVar->getICFGNode())) { // succ is then branch if (succ1 == succ) diff --git a/svf/lib/SABER/SaberSVFGBuilder.cpp b/svf/lib/SABER/SaberSVFGBuilder.cpp index b883adbe6..f90d86e36 100644 --- a/svf/lib/SABER/SaberSVFGBuilder.cpp +++ b/svf/lib/SABER/SaberSVFGBuilder.cpp @@ -82,11 +82,8 @@ void SaberSVFGBuilder::collectGlobals(BVDataPTAImpl* pta) if(SVFUtil::isa(pag->getGNode(gepobj->getBaseNode()))) continue; } - if(const SVFValue* val = pagNode->getValue()) - { - if(SVFUtil::isa(val)) - worklist.push_back(it->first); - } + if(pagNode->hasValue() && SVFUtil::isa(pagNode->getValue())) + worklist.push_back(it->first); } NodeToPTSSMap cachedPtsMap; @@ -138,7 +135,7 @@ PointsTo& SaberSVFGBuilder::CollectPtsChain(BVDataPTAImpl* pta, NodeID id, NodeT if(pta->isFIObjNode(baseId) && pag->getGNode(baseId)->hasValue()) { ValVar* valVar = SVFUtil::dyn_cast(pag->getGNode(baseId)); - if(valVar && valVar->getGNode() && SVFUtil::isExtCall(SVFUtil::cast(valVar->getGNode()))) + if(valVar && valVar->getICFGNode() && SVFUtil::isExtCall(valVar->getICFGNode())) { return pts; } diff --git a/svf/lib/SVFIR/SVFFileSystem.cpp b/svf/lib/SVFIR/SVFFileSystem.cpp index 0dfe58ac9..fc1d5fbda 100644 --- a/svf/lib/SVFIR/SVFFileSystem.cpp +++ b/svf/lib/SVFIR/SVFFileSystem.cpp @@ -224,6 +224,8 @@ cJSON* SVFIRWriter::virtToJson(const SVFVar* var) CASE(FIObjNode, FIObjVar); CASE(DummyValNode, DummyValVar); CASE(DummyObjNode, DummyObjVar); + CASE(FunObjNode, FunObjVar); + CASE(FunValNode, FunValVar); #undef CASE } } diff --git a/svf/lib/SVFIR/SVFIR.cpp b/svf/lib/SVFIR/SVFIR.cpp index b79145c27..8465ec763 100644 --- a/svf/lib/SVFIR/SVFIR.cpp +++ b/svf/lib/SVFIR/SVFIR.cpp @@ -472,6 +472,17 @@ NodeID SVFIR::addFIObjNode(const MemObj* obj) return addObjNode(obj->getValue(), node, obj->getId()); } +NodeID SVFIR::addFunObjNode(const CallGraphNode* callGraphNode, NodeID id) +{ + const MemObj* mem = getMemObj(callGraphNode->getFunction()); + assert(mem->getId() == id && "not same object id?"); + //assert(findPAGNode(i) == false && "this node should not be created before"); + NodeID base = mem->getId(); + memToFieldsMap[base].set(mem->getId()); + FunObjVar*node = new FunObjVar(callGraphNode, mem->getId(), mem); + return addObjNode(mem->getValue(), node, mem->getId()); +} + /*! * Get all fields object nodes of an object */ @@ -675,9 +686,14 @@ bool SVFIR::isValidTopLevelPtr(const SVFVar* node) { if (SVFUtil::isa(node)) { - if (isValidPointer(node->getId()) && node->hasValue()) + if (isValidPointer(node->getId())) { - return !SVFUtil::isArgOfUncalledFunction(node->getValue()); + // TODO: after svf value is removed, we use type to determine top level ptr + if (SVFUtil::isa(node) || SVFUtil::isa(node) || SVFUtil::isa(node)) + { + return true; + } else if(node->hasValue()) + return !SVFUtil::isArgOfUncalledFunction(node->getValue()); } } return false; diff --git a/svf/lib/SVFIR/SVFVariables.cpp b/svf/lib/SVFIR/SVFVariables.cpp index 72b406e1f..1d041931b 100644 --- a/svf/lib/SVFIR/SVFVariables.cpp +++ b/svf/lib/SVFIR/SVFVariables.cpp @@ -30,6 +30,7 @@ #include "SVFIR/SVFVariables.h" #include "Util/Options.h" #include "Util/SVFUtil.h" +#include "Graphs/CallGraph.h" using namespace SVF; using namespace SVFUtil; @@ -52,11 +53,12 @@ SVFVar::SVFVar(const SVFValue* val, NodeID i, PNODEK k) : break; } case RetNode: + case FunObjNode: { - assert(val != nullptr && "value is nullptr for RetNode"); - isPtr = SVFUtil::cast(val)->getReturnType()->isPointerTy(); + // to be completed in derived class break; } + case FunValNode: case VarargNode: case DummyValNode: { @@ -85,8 +87,6 @@ bool SVFVar::isIsolatedNode() const return true; else if (isConstDataOrAggDataButNotNullPtr()) return true; - else if (value && SVFUtil::isa(value)) - return SVFUtil::cast(value)->isIntrinsic(); else return false; } @@ -144,6 +144,20 @@ const std::string GepValVar::toString() const return rawstr.str(); } +RetPN::RetPN(const CallGraphNode* node, NodeID i) : ValVar(i, RetNode), callGraphNode(node) { + isPtr = node->getFunction()->getReturnType()->isPointerTy(); +} + +const SVFFunction* RetPN::getFunction() const +{ + return callGraphNode->getFunction(); +} + +const std::string RetPN::getValueName() const +{ + return callGraphNode->getName() + "_ret"; +} + const std::string GepObjVar::toString() const { std::string str; @@ -170,19 +184,66 @@ const std::string FIObjVar::toString() const return rawstr.str(); } +const std::string FunValVar::toString() const +{ + std::string str; + std::stringstream rawstr(str); + rawstr << "FunValVar ID: " << getId(); + if (Options::ShowSVFIRValue()) + { + rawstr << "\n"; + rawstr << callGraphNode->getName(); + } + return rawstr.str(); +} + +FunObjVar::FunObjVar(const CallGraphNode* cgNode, NodeID i, const MemObj* mem, + PNODEK ty) + : FIObjVar(nullptr, i, mem, ty), callGraphNode(cgNode) +{ + isPtr = callGraphNode->getFunction()->getType()->isPointerTy(); +} + +bool FunObjVar::isIsolatedNode() const +{ + return callGraphNode->getFunction()->isIntrinsic(); +} + +const std::string FunObjVar::toString() const +{ + std::string str; + std::stringstream rawstr(str); + rawstr << "FunObjVar ID: " << getId() << " (base object)"; + if (Options::ShowSVFIRValue()) + { + rawstr << "\n"; + rawstr << callGraphNode->getName(); + } + return rawstr.str(); +} + const std::string RetPN::toString() const { std::string str; std::stringstream rawstr(str); - rawstr << "RetPN ID: " << getId() << " unique return node for function " << SVFUtil::cast(value)->getName(); + rawstr << "RetPN ID: " << getId() << " unique return node for function " << callGraphNode->getName(); return rawstr.str(); } +const SVFFunction* VarArgPN::getFunction() const { + return callGraphNode->getFunction(); +} + +const std::string VarArgPN::getValueName() const +{ + return callGraphNode->getName() + "_vararg"; +} + const std::string VarArgPN::toString() const { std::string str; std::stringstream rawstr(str); - rawstr << "VarArgPN ID: " << getId() << " Var arg node for function " << SVFUtil::cast(value)->getName(); + rawstr << "VarArgPN ID: " << getId() << " Var arg node for function " << callGraphNode->getName(); return rawstr.str(); } diff --git a/svf/lib/Util/CallGraphBuilder.cpp b/svf/lib/Util/CallGraphBuilder.cpp index ba01d4d1f..6c7a012db 100644 --- a/svf/lib/Util/CallGraphBuilder.cpp +++ b/svf/lib/Util/CallGraphBuilder.cpp @@ -88,15 +88,15 @@ ThreadCallGraph* CallGraphBuilder::buildThreadCallGraph() { const CallICFGNode* cs = cast(inst); cg->addForksite(cs); - const SVFFunction* forkee = SVFUtil::dyn_cast(tdAPI->getForkedFun(cs)->getValue()); - if (forkee) + const ValVar* svfVar = tdAPI->getForkedFun(cs); + if (SVFUtil::isa(svfVar)) { cg->addDirectForkEdge(cs); } // indirect call to the start routine function else { - cg->addThreadForkEdgeSetMap(cs,nullptr); + cg->addThreadForkEdgeSetMap(cs, nullptr); } } } diff --git a/svf/lib/Util/SVFUtil.cpp b/svf/lib/Util/SVFUtil.cpp index bf7282945..ecaed39fe 100644 --- a/svf/lib/Util/SVFUtil.cpp +++ b/svf/lib/Util/SVFUtil.cpp @@ -423,4 +423,11 @@ const SVFFunction* SVFUtil::getProgEntryFunction() return (fun->getFunction()); } return nullptr; +} + + +const ObjVar* SVFUtil::getObjVarOfValVar(const SVF::ValVar* valVar) +{ + assert(valVar->getInEdges().size() == 1); + return SVFUtil::dyn_cast((*valVar->getInEdges().begin())->getSrcNode()); } \ No newline at end of file diff --git a/svf/lib/Util/ThreadAPI.cpp b/svf/lib/Util/ThreadAPI.cpp index 6e5bbbf9c..2cf335753 100644 --- a/svf/lib/Util/ThreadAPI.cpp +++ b/svf/lib/Util/ThreadAPI.cpp @@ -161,13 +161,13 @@ bool ThreadAPI::isTDBarWait(const CallICFGNode *inst) const } -const SVFVar* ThreadAPI::getForkedThread(const CallICFGNode *inst) const +const ValVar* ThreadAPI::getForkedThread(const CallICFGNode *inst) const { assert(isTDFork(inst) && "not a thread fork function!"); return inst->getArgument(0); } -const SVFVar* ThreadAPI::getForkedFun(const CallICFGNode *inst) const +const ValVar* ThreadAPI::getForkedFun(const CallICFGNode *inst) const { assert(isTDFork(inst) && "not a thread fork function!"); return inst->getArgument(2); @@ -175,7 +175,7 @@ const SVFVar* ThreadAPI::getForkedFun(const CallICFGNode *inst) const /// Return the forth argument of the call, /// Note that, it is the sole argument of start routine ( a void* pointer ) -const SVFVar* ThreadAPI::getActualParmAtForkSite(const CallICFGNode *inst) const +const ValVar* ThreadAPI::getActualParmAtForkSite(const CallICFGNode *inst) const { assert(isTDFork(inst) && "not a thread fork function!"); return inst->getArgument(3);