// Get the arg nodes in CalleeGraph for the callee of DSCS. Like // DSGraph::getFunctionArgumentsForCall, but for indirect calls gets the most // non-null nodes from all functions callable from that callsite. void CSDataRando::getArgNodesForCall(DSGraph *CalleeGraph, DSCallSite DSCS, std::vector<DSNodeHandle> &ArgNodes) { ArgNodes.clear(); if (DSCS.isDirectCall()) { CalleeGraph->getFunctionArgumentsForCall(DSCS.getCalleeFunc(), ArgNodes); return; } // Handle indirect calls. const DSCallGraph &CG = DSA->getCallGraph(); CallSite OriginalCS = DSCS.getCallSite(); std::vector<DSNodeHandle> TempArgNodes; // Get as many non-null arg nodes as possible. We don't know what the actual // caller will be, and there can be some mismatch between which arguments have // nodes for the different functions which may be called from this callsite. // TODO: It should be possible to cache the result of this to use for all // calls within the function equivalence class. for (auto i = CG.callee_begin(OriginalCS), e = CG.callee_end(OriginalCS); i != e; i++) { TempArgNodes.clear(); CalleeGraph->getFunctionArgumentsForCall(*i, TempArgNodes); for (unsigned int i = 0, e = TempArgNodes.size(); i < e; i++) { if (i < ArgNodes.size()) { if (ArgNodes[i].isNull() && (!TempArgNodes[i].isNull())) { ArgNodes[i] = TempArgNodes[i]; } } else { ArgNodes.push_back(TempArgNodes[i]); } } } }
static void GetAnyCallees(const DSCallSite &CS, std::vector<const Function*> &Callees) { if (CS.isDirectCall()) { if (!CS.getCalleeFunc()->isDeclaration()) Callees.push_back(CS.getCalleeFunc()); } else { // Get all callees. unsigned OldSize = Callees.size(); CS.getCalleeNode()->addFullFunctionList(Callees); // If any of the callees are unresolvable, remove them for (unsigned i = OldSize; i != Callees.size(); ) if (Callees[i]->isDeclaration()) { Callees.erase(Callees.begin()+i); } else ++i; } }
/// ResolveFunctionCall - Resolve the actual arguments of a call to function F /// with the specified call site descriptor. This function links the arguments /// and the return value for the call site context-insensitively. /// void SteensgaardDataStructures::ResolveFunctionCall(const Function *F, const DSCallSite &Call, DSNodeHandle &RetVal) { assert(ResultGraph != 0 && "Result graph not allocated!"); DSGraph::ScalarMapTy &ValMap = ResultGraph->getScalarMap(); // Handle the return value of the function... if (Call.getRetVal().getNode() && RetVal.getNode()) RetVal.mergeWith(Call.getRetVal()); // Loop over all pointer arguments, resolving them to their provided pointers unsigned PtrArgIdx = 0; for (Function::const_arg_iterator AI = F->arg_begin(), AE = F->arg_end(); AI != AE && PtrArgIdx < Call.getNumPtrArgs(); ++AI) { DSGraph::ScalarMapTy::iterator I = ValMap.find(AI); if (I != ValMap.end()) // If its a pointer argument... I->second.mergeWith(Call.getPtrArg(PtrArgIdx++)); } }
// // Function: getAllCallees() // // Description: // Given a DSCallSite, add to the list the functions that can be called by // the call site *if* it is resolvable. Uses 'applyCallsiteFilter' to // only add the functions that are valid targets of this callsite. // void BUDataStructures:: getAllCallees(const DSCallSite &CS, FuncSet &Callees) { // // FIXME: Should we check for the Unknown flag on indirect call sites? // // Direct calls to functions that have bodies are always resolvable. // Indirect function calls that are for a complete call site (the analysis // knows everything about the call site) and do not target external functions // are also resolvable. // if (CS.isDirectCall()) { if (!CS.getCalleeFunc()->isDeclaration()) Callees.insert(CS.getCalleeFunc()); } else if (CS.getCalleeNode()->isCompleteNode()) { // Get all callees. if (!CS.getCalleeNode()->isExternFuncNode()) { // Get all the callees for this callsite FuncSet TempCallees; CS.getCalleeNode()->addFullFunctionSet(TempCallees); // Filter out the ones that are invalid targets with respect // to this particular callsite. applyCallsiteFilter(CS, TempCallees); // Insert the remaining callees (legal ones, if we're filtering) // into the master 'Callees' list Callees.insert(TempCallees.begin(), TempCallees.end()); } } }
// // Function: applyCallsiteFilter // // Description: // Given a DSCallSite, and a list of functions, filter out the ones // that aren't callable from the given Callsite. // // Does no filtering if 'filterCallees' is set to false. // void BUDataStructures:: applyCallsiteFilter(const DSCallSite &DCS, FuncSet &Callees) { if (!filterCallees) return; FuncSet::iterator I = Callees.begin(); CallSite CS = DCS.getCallSite(); while (I != Callees.end()) { if (functionIsCallable(CS, *I)) { ++I; } else { I = Callees.erase(I); } } }
static void GetAllCallees(const DSCallSite &CS, std::vector<const Function*> &Callees) { if (CS.isDirectCall()) { if (!CS.getCalleeFunc()->isDeclaration()) Callees.push_back(CS.getCalleeFunc()); } else if (!CS.getCalleeNode()->NodeType.isIncompleteNode()) { // Get all callees. if (!CS.getCalleeNode()->NodeType.isExternFunctionNode()) CS.getCalleeNode()->addFullFunctionList(Callees); } }
bool CSDataRando::processCallSite(CallSite CS, FuncInfo &FI, PointerEquivalenceAnalysis &P, DSGraph *G) { bool IndirectCall = !isa<Function>(CS.getCalledValue()->stripPointerCasts()); if (IndirectCall) { NumIndirectCalls++; } CallSite OriginalCS = originalCallSite(FI, CS); if (!DSA->canEncryptCall(OriginalCS)) { if (IndirectCall) { NumIndirectCantEncrypt++; } return false; } DSCallSite DSCS = G->getDSCallSiteForCallSite(OriginalCS); const Function *Callee = getEffectiveCallee(DSCS, FI, G); if (!Callee) { if (IndirectCall) { NumIndirectCantEncrypt++; } return false; } FuncInfo &CalleeInfo = FunctionInfo[Callee]; Value *Clone = getCloneCalledValue(CS, CalleeInfo); if (!Clone || CalleeInfo.ArgNodes.empty()) { if (IndirectCall) { NumIndirectCantEncrypt++; } return false; } // We create a mapping of the formal argument nodes in the callee function and // actual argument nodes in the caller function's graph. DSGraph::NodeMapTy NodeMap; DSGraph *CalleeG = DSA->getDSGraph(*Callee); // getArgNodesForCall places the return node and the vanode in the // first two slots of the vector, followed by the nodes for the regular // pointer arguments. std::vector<DSNodeHandle> ArgNodes; getArgNodesForCall(CalleeG, DSCS, ArgNodes); // First the return value DSNodeHandle CalleeRetNode = ArgNodes[0]; DSGraph::computeNodeMapping(CalleeRetNode, DSCS.getRetVal(), NodeMap); // Then VarArgs DSNodeHandle CalleeVarArgNode = ArgNodes[1]; DSGraph::computeNodeMapping(CalleeVarArgNode, DSCS.getVAVal(), NodeMap); // And last the regular arguments. for (unsigned int i = 0; i < DSCS.getNumPtrArgs() && i + 2 < ArgNodes.size(); i++) { DSGraph::computeNodeMapping(ArgNodes[i + 2], DSCS.getPtrArg(i), NodeMap); } // Collect the arguments and masks to pass to call SmallVector<Value*, 8> Args; unsigned int i = 0; for (unsigned int e = CS.getFunctionType()->getNumParams(); i < e; i++) { Args.push_back(CS.getArgOperand(i)); } for (const DSNode *N : CalleeInfo.ArgNodes) { Value *Mask = P.getMaskForNode(NodeMap[N]); Args.push_back(Mask); } // VarArgs go after masks for (unsigned int e = CS.arg_size(); i < e; i++) { Args.push_back(CS.getArgOperand(i)); } // Do replacement Instruction *CI = CS.getInstruction(); Value *Call; if (CS.isCall()) { Call = CallInst::Create(Clone, Args, "", CI); } else { InvokeInst *II = cast<InvokeInst>(CI); Call = InvokeInst::Create(Clone, II->getNormalDest(), II->getUnwindDest(), Args, "", II); } CallSite NewCS(Call); NewCS.setCallingConv(CS.getCallingConv()); CI->replaceAllUsesWith(Call); P.replace(CI, Call); CI->eraseFromParent(); return true; }