// // 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()); } } }
void DSCallGraph::buildRoots() { FuncSet knownCallees; FuncSet knownCallers; for (SimpleCalleesTy::iterator ii = SimpleCallees.begin(), ee = SimpleCallees.end(); ii != ee; ++ii) { knownCallees.insert(ii->second.begin(), ii->second.end()); knownCallers.insert(ii->first); } knownRoots.clear(); std::set_difference(knownCallers.begin(), knownCallers.end(), knownCallees.begin(), knownCallees.end(), std::inserter(knownRoots, knownRoots.begin())); }
/** * @brief Tries to find functions that can be called by indirect call. * * @par Preconditions * - @a callInst is a call that calls some function indirectly. * * @param[in] call We try to find functions for this indirect call. * @param[in] funcsToCheck We are finding functions that can be indirectly called * only in this functions. * * @return Found functions that can be called indirectly. */ FuncSet IndirectlyCalledFuncsAnalysis::getFuncsForIndirectCall( const CallInst &call, const FuncVec &funcsToCheck) { assert(isIndirectCall(call) && "Expected an indirect call."); FuncSet result; Type *callReturnType = call.getType(); for (Function *func : funcsToCheck) { if (func->getReturnType() != callReturnType) { continue; } if (!func->isVarArg()) { if (!hasEqArgsAndParams(call, *func)) { continue; } } result.insert(func); } return result; }
/** * @brief Visits the given node in the call graph. * * @param[in] calledFunc The given node. * @param[in,out] calledFuncInfo Information about @a calledFunc. * * Corresponds to the strongconnect(v) function from * http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm */ void CallInfoObtainer::SCCComputer::visit(ShPtr<CG::CalledFuncs> calledFunc, CalledFuncInfo &calledFuncInfo) { // Set the depth index for calledFunc to the smallest unused index. calledFuncInfo.index = calledFuncInfo.lowlink = index; index++; // Push calledFunc onto the stack. stack.push(calledFunc); calledFuncInfo.onStack = true; // Consider the successors of calledFunc. for (const auto &callee : calledFunc->callees) { ShPtr<CG::CalledFuncs> succ(cg->getCalledFuncs(callee)); CalledFuncInfo &succInfo(calledFuncInfoMap[succ]); if (succInfo.index < 0) { // '< 0' means 'undefined' // The successor has not yet been visited; recurse on it. visit(succ, succInfo); calledFuncInfo.lowlink = std::min(calledFuncInfo.lowlink, succInfo.lowlink); } else if (succInfo.onStack) { // The successor is on the stack and hence in the current SCC. calledFuncInfo.lowlink = std::min(calledFuncInfo.lowlink, succInfo.index); } } // If calledFunc is a root node, pop the stack and generate an SCC. if (calledFuncInfo.lowlink == calledFuncInfo.index) { // Generate a new SCC. FuncSet scc; ShPtr<CG::CalledFuncs> poppedCalledFunc; do { poppedCalledFunc = stack.top(); stack.pop(); calledFuncInfoMap[cg->getCalledFuncs( poppedCalledFunc->caller)].onStack = false; scc.insert(poppedCalledFunc->caller); } while (calledFunc != poppedCalledFunc); // Store the generated SCC. However, if the SCC contains just a single // function, do this only if it calls itself (see the description of // computeSCCs()). if (scc.size() != 1 || hasItem(calledFunc->callees, calledFunc->caller)) { sccs.insert(scc); } } }
/** * @brief Finds a next SCC and its represent and returns them. * * @param[in] sccs All SCCs in the call graph. * @param[in] computedFuncs Functions that already have been included in * FuncInfoCompOrder::order. * @param[in] remainingFuncs Functions that haven't been included in * FuncInfoCompOrder::order. * * @par Preconditions * - @a remainingFuncs is non-empty * - @a remainingFuncs doesn't contain a function which calls just functions * from @a computedFuncs. */ CallInfoObtainer::SCCWithRepresent CallInfoObtainer::findNextSCC(const FuncSetSet &sccs, const FuncSet &computedFuncs, const FuncSet &remainingFuncs) const { PRECONDITION(!remainingFuncs.empty(), "it should not be empty"); // // We try to locate an SCC whose members call just the functions in // the SCC or in computedFuncs. Then, if the found SCC contains a function // from remainingFuncs, return the function. // // For every SCC... for (const auto &scc : sccs) { bool sccFound = true; ShPtr<Function> funcFromRemainingFuncs; // For every function in the SCC... for (const auto &func : scc) { // Check whether the function calls just the functions in the SCC // or in computedFuncs. ShPtr<CG::CalledFuncs> calledFuncs(cg->getCalledFuncs(func)); FuncSet mayCall(setUnion(scc, computedFuncs)); if (!setDifference(calledFuncs->callees, mayCall).empty()) { sccFound = false; } else { // Have we encountered a function from remainingFuncs? if (hasItem(remainingFuncs, func)) { funcFromRemainingFuncs = func; } } } if (sccFound && funcFromRemainingFuncs) { return SCCWithRepresent(scc, funcFromRemainingFuncs); } } // TODO Can this happen? printWarningMessage("[SCCComputer] No viable SCC has been found."); FuncSet scc; ShPtr<Function> func(*(remainingFuncs.begin())); scc.insert(func); return SCCWithRepresent(scc, func); }