Beispiel #1
0
//
// 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());
    }
  }
}
/**
* @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;
}
Beispiel #3
0
//
// 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);
    }
  }
}
/**
* @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);
		}
	}
}
Beispiel #5
0
//
// Function: getAllAuxCallees()
//
// Description:
//  Return a list containing all of the resolvable callees in the auxiliary
//  list for the specified graph in the Callees vector.
//
// Inputs:
//  G - The DSGraph for which the callers wants a list of resolvable call
//      sites.
//
// Outputs:
//  Callees - A list of all functions that can be called from resolvable call
//            sites.  This list is always cleared by this function before any
//            functions are added to it.
//
void BUDataStructures::
getAllAuxCallees (DSGraph* G, FuncSet & Callees) {
  //
  // Clear out the list of callees.
  //
  Callees.clear();
  for (DSGraph::afc_iterator I = G->afc_begin(), E = G->afc_end(); I != E; ++I)
    getAllCallees(*I, Callees);
}
Beispiel #6
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 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);
}
Beispiel #8
0
//
// Method: calculateGraphs()
//
// Description:
//  Perform recursive bottom-up inlining of DSGraphs from callee to caller.
//
// Inputs:
//  F - The function which should have its callees' DSGraphs merged into its
//      own DSGraph.
//  Stack - The stack used for Tarjan's SCC-finding algorithm.
//  NextID - The nextID value used for Tarjan's SCC-finding algorithm.
//  ValMap - The map used for Tarjan's SCC-finding algorithm.
//
// Return value:
//
unsigned
BUDataStructures::calculateGraphs (const Function *F,
                                   TarjanStack & Stack,
                                   unsigned & NextID,
                                   TarjanMap & ValMap) {
  assert(!ValMap.count(F) && "Shouldn't revisit functions!");
  unsigned Min = NextID++, MyID = Min;
  ValMap[F] = Min;
  Stack.push_back(F);

  //
  // FIXME: This test should be generalized to be any function that we have
  // already processed in the case when there isn't a main() or there are
  // unreachable functions!
  //
  if (F->isDeclaration()) {   // sprintf, fprintf, sscanf, etc...
    // No callees!
    Stack.pop_back();
    ValMap[F] = ~0;
    return Min;
  }

  //
  // Get the DSGraph of the current function.  Make one if one doesn't exist.
  //
  DSGraph* Graph = getOrCreateGraph(F);

  //
  // Find all callee functions.  Use the DSGraph for this (do not use the call
  // graph (DSCallgraph) as we're still in the process of constructing it).
  //
  FuncSet CalleeFunctions;
  getAllAuxCallees(Graph, CalleeFunctions);

  //
  // Iterate through each call target (these are the edges out of the current
  // node (i.e., the current function) in Tarjan graph parlance).  Find the
  // minimum assigned ID.
  //
  for (FuncSet::iterator I = CalleeFunctions.begin(), E = CalleeFunctions.end();
       I != E; ++I) {
    const Function *Callee = *I;
    unsigned M;
    //
    // If we have not visited this callee before, visit it now (this is the
    // post-order component of the Bottom-Up algorithm).  Otherwise, look up
    // the assigned ID value from the Tarjan Value Map.
    //
    TarjanMap::iterator It = ValMap.find(Callee);
    if (It == ValMap.end())  // No, visit it now.
      M = calculateGraphs(Callee, Stack, NextID, ValMap);
    else                    // Yes, get it's number.
      M = It->second;

    //
    // If we've found a function with a smaller ID than this funtion, record
    // that ID as the minimum ID.
    //
    if (M < Min) Min = M;
  }

  assert(ValMap[F] == MyID && "SCC construction assumption wrong!");

  //
  // If the minimum ID found is not this function's ID, then this function is
  // part of a larger SCC.
  //
  if (Min != MyID)
    return Min;

  //
  // If this is a new SCC, process it now.
  //
  if (Stack.back() == F) {           // Special case the single "SCC" case here.
    DEBUG(errs() << "Visiting single node SCC #: " << MyID << " fn: "
	  << F->getName() << "\n");
    Stack.pop_back();
    DEBUG(errs() << "  [BU] Calculating graph for: " << F->getName()<< "\n");
    DSGraph* G = getOrCreateGraph(F);
    calculateGraph(G);
    DEBUG(errs() << "  [BU] Done inlining: " << F->getName() << " ["
	  << G->getGraphSize() << "+" << G->getAuxFunctionCalls().size()
	  << "]\n");

    if (MaxSCC < 1) MaxSCC = 1;

    //
    // Should we revisit the graph?  Only do it if there are now new resolvable
    // callees.
    FuncSet NewCallees;
    getAllAuxCallees(G, NewCallees);
    if (!NewCallees.empty()) {
      if (hasNewCallees(NewCallees, CalleeFunctions)) {
        DEBUG(errs() << "Recalculating " << F->getName() << " due to new knowledge\n");
        ValMap.erase(F);
        ++NumRecalculations;
        return calculateGraphs(F, Stack, NextID, ValMap);
      }
      ++NumRecalculationsSkipped;
    }
    ValMap[F] = ~0U;
    return MyID;
  } else {
    unsigned SCCSize = 1;
    const Function *NF = Stack.back();
    if(NF != F)
      ValMap[NF] = ~0U;
    DSGraph* SCCGraph = getDSGraph(*NF);

    //
    // First thing first: collapse all of the DSGraphs into a single graph for
    // the entire SCC.  Splice all of the graphs into one and discard all of
    // the old graphs.
    //
    while (NF != F) {
      Stack.pop_back();
      NF = Stack.back();
      if(NF != F)
        ValMap[NF] = ~0U;

      DSGraph* NFG = getDSGraph(*NF);

      if (NFG != SCCGraph) {
        // Update the Function -> DSG map.
        for (DSGraph::retnodes_iterator I = NFG->retnodes_begin(),
               E = NFG->retnodes_end(); I != E; ++I)
          setDSGraph(*I->first, SCCGraph);

        SCCGraph->spliceFrom(NFG);
        delete NFG;
        ++SCCSize;
      }
    }
    Stack.pop_back();

    DEBUG(errs() << "Calculating graph for SCC #: " << MyID << " of size: "
	  << SCCSize << "\n");

    // Compute the Max SCC Size.
    if (MaxSCC < SCCSize)
      MaxSCC = SCCSize;

    // Clean up the graph before we start inlining a bunch again...
    SCCGraph->removeDeadNodes(DSGraph::KeepUnreachableGlobals);

    // Now that we have one big happy family, resolve all of the call sites in
    // the graph...
    calculateGraph(SCCGraph);
    DEBUG(errs() << "  [BU] Done inlining SCC  [" << SCCGraph->getGraphSize()
	  << "+" << SCCGraph->getAuxFunctionCalls().size() << "]\n"
	  << "DONE with SCC #: " << MyID << "\n");
    FuncSet NewCallees;
    getAllAuxCallees(SCCGraph, NewCallees);
    if (!NewCallees.empty()) {
      if (hasNewCallees(NewCallees, CalleeFunctions)) {
        DEBUG(errs() << "Recalculating SCC Graph " << F->getName() << " due to new knowledge\n");
        ValMap.erase(F);
        ++NumRecalculations;
        return calculateGraphs(F, Stack, NextID, ValMap);
      }
      ++NumRecalculationsSkipped;
    }
    ValMap[F] = ~0U;
    return MyID;
  }
}