//
// 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());
    }
  }
}
Exemple #2
0
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);
}