65 #include <boost/tuple/tuple.hpp> 74 #include "config_HAVE_ASSERTS.hpp" 82 #define ADD_CALL_POINT(g, e, newstmt) get_edge_info<function_graph_edge_info>(e, *(g))->call_points.insert(newstmt) 112 : allow_recursive_functions(_allow_recursive_functions),
113 call_graph_manager(_call_graph_manager),
114 body_functions(_body_functions),
115 library_functions(_library_functions)
121 if(!allow_recursive_functions)
124 const auto source = boost::source(e, g);
127 "Recursive functions not yet supported: " +
128 behaviors.at(call_graph_manager->
get_function(source))->CGetBehavioralHelper()->get_function_name() +
130 behaviors.at(call_graph_manager->
get_function(
target))->CGetBehavioralHelper()->get_function_name());
141 const auto f_id = Cget_node_info<FunctionInfo, graph>(u, g)->nodeID;
142 if(g.
CGetCallGraphInfo()->behaviors.at(f_id)->CGetBehavioralHelper()->has_implementation())
144 body_functions.insert(f_id);
148 library_functions.insert(f_id);
161 debug_level(_Param->get_class_debug_level(
GET_CLASS(*this))),
162 function_expander(_function_expander)
171 "---Adding function: " + fun_behavior->CGetBehavioralHelper()->get_function_name() +
172 " id: " +
STR(new_function_id));
180 call_graph->GetCallGraphInfo()->behaviors[new_function_id] = fun_behavior;
187 "adding a different behavior for " +
STR(new_function_id) +
188 " prev: " +
STR(
call_graph->GetCallGraphInfo()->behaviors.at(new_function_id)) +
189 " new: " +
STR(fun_behavior));
196 #if !defined(NDEBUG) || HAVE_ASSERTS 197 const auto caller_name =
"(" +
STR(caller_id) +
") " +
200 const auto called_name =
"(" +
STR(called_id) +
") " +
205 "---Adding call with id: " +
STR(call_id) +
" from " + caller_name +
" to " + called_name);
206 if(
IsCallPoint(caller_id, called_id, call_id, call_type))
211 "call id " +
STR(call_id) +
" from " + caller_name +
" to " + called_name +
212 " was already in the call graph with the same call type");
220 "---No previous call from " + caller_name +
" to " + called_name);
221 called_by.at(caller_id).insert(called_id);
225 std::list<vertex> topological_sort;
229 catch(std::exception& e)
239 boost::tie(e, found) = boost::edge(src, tgt, *
CGetCallGraph());
240 THROW_ASSERT(found,
"call id " +
STR(call_id) +
" from " + caller_name +
" to " + called_name +
241 " was not in the call graph");
243 const auto functionEdgeInfo = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *
call_graph);
249 functionEdgeInfo->direct_call_points.insert(call_id);
253 functionEdgeInfo->indirect_call_points.insert(call_id);
258 functionEdgeInfo->function_addresses.insert(call_id);
290 boost::tie(e, found) = boost::edge(src, tgt, *
CGetCallGraph());
292 const auto caller_name =
"(" +
STR(caller_id) +
") " +
295 const auto called_name =
"(" +
STR(called_id) +
") " +
299 THROW_ASSERT(found,
"call id " +
STR(call_id) +
" from " + caller_name +
" to " + called_name +
300 " was not in the call graph");
302 const auto functionEdgeInfo = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *
call_graph);
308 res = functionEdgeInfo->direct_call_points.count(call_id);
312 res = functionEdgeInfo->indirect_call_points.count(call_id);
316 res = functionEdgeInfo->function_addresses.count(call_id);
320 res = functionEdgeInfo->direct_call_points.count(call_id) ||
321 functionEdgeInfo->indirect_call_points.count(call_id) ||
322 functionEdgeInfo->function_addresses.count(call_id);
340 unsigned int called_id,
unsigned int call_id,
370 const auto caller_id = Cget_node_info<FunctionInfo, CallGraph>(boost::source(e, *
call_graph), *
call_graph)->nodeID;
372 const auto edge_info = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *
call_graph);
373 auto& direct_calls = edge_info->direct_call_points;
374 auto& indirect_calls = edge_info->indirect_call_points;
375 auto& function_addresses = edge_info->function_addresses;
380 const auto dir_it = direct_calls.find(callid);
381 if(dir_it != direct_calls.end())
383 direct_calls.erase(callid);
388 const auto indir_it = indirect_calls.find(callid);
389 if(indir_it != indirect_calls.end())
391 indirect_calls.erase(callid);
396 const auto addr_it = function_addresses.find(callid);
397 if(addr_it != function_addresses.end())
399 function_addresses.erase(callid);
405 #if !defined(NDEBUG) || HAVE_ASSERTS 406 const auto caller_name =
"(" +
STR(caller_id) +
") " +
410 THROW_ASSERT(found_calls,
"call id " +
STR(callid) +
" is not a call point in function " + caller_name +
411 " for function (" +
STR(called_id) +
") " + called_name);
412 THROW_ASSERT(found_calls == 1,
"call id " +
STR(callid) +
" is a multiple call point in function " + caller_name +
413 " for function (" +
STR(called_id) +
") " + called_name);
415 if(direct_calls.empty() && indirect_calls.empty() && function_addresses.empty())
418 "Removed function call edge: " + caller_name +
" -> (" +
STR(called_id) +
") " + called_name);
421 called_by.at(caller_id).erase(called_id);
436 "There are still " +
STR(direct_calls.size()) +
" direct calls, " +
STR(indirect_calls.size()) +
437 " indirect calls, and " +
STR(function_addresses.size()) +
438 " places where the address is taken");
440 if(indirect_calls.empty() && function_addresses.empty())
447 const unsigned int call_id)
455 const auto caller_vertex =
GetVertex(caller_id);
456 const auto called_vertex =
GetVertex(called_id);
459 boost::tie(e, found) = boost::edge(caller_vertex, called_vertex, *
CGetCallGraph());
461 const auto caller_name =
"(" +
STR(caller_id) +
") " +
465 THROW_ASSERT(found,
"call id " +
STR(call_id) +
" is not a call point in function " + caller_name +
466 " for function (" +
STR(called_id) +
") " + called_name);
472 THROW_ASSERT(orig != repl,
"old call point is replaced with itself");
473 const auto caller_id = Cget_node_info<FunctionInfo, CallGraph>(boost::source(e, *
call_graph), *
call_graph)->nodeID;
477 const auto edge_info = get_edge_info<FunctionEdgeInfo, CallGraph>(e, *
call_graph);
478 const auto& direct_calls = edge_info->direct_call_points;
479 const auto& indirect_calls = edge_info->indirect_call_points;
480 const auto& function_addresses = edge_info->function_addresses;
481 const auto dir_it = direct_calls.find(orig);
482 if(dir_it != direct_calls.end())
486 const auto indir_it = indirect_calls.find(orig);
487 if(indir_it != indirect_calls.end())
491 const auto addr_it = function_addresses.find(orig);
492 if(addr_it != function_addresses.end())
497 AddCallPoint(caller_id, called_id, repl, old_call_type);
518 std::inserter(reachable_addressed_fun_ids, reachable_addressed_fun_ids.begin()));
519 return reachable_addressed_fun_ids;
540 "this vertex does not exist " +
STR(index));
551 return Cget_node_info<FunctionInfo, graph>(node, *
call_graph)->nodeID;
578 std::vector<boost::default_color_type> color_vec(boost::num_vertices(*
call_graph));
580 other_root_functions.erase(root_id);
581 const auto top_vertex =
GetVertex(root_id);
582 boost::depth_first_visit(
584 boost::make_iterator_property_map(color_vec.begin(), boost::get(boost::vertex_index_t(), *
call_graph),
587 return other_root_functions.find(Cget_node_info<FunctionInfo, graph>(u, g)->nodeID) !=
588 other_root_functions.end();
602 "Root functions have not yet been computed");
618 std::vector<boost::default_color_type> color_vec(boost::num_vertices(*
call_graph));
620 other_root_functions.erase(from);
621 boost::depth_first_visit(*
call_graph, top_vertex, vis,
622 boost::make_iterator_property_map(color_vec.begin(),
623 boost::get(boost::vertex_index_t(), *
call_graph),
626 return other_root_functions.find(Cget_node_info<FunctionInfo, graph>(u, g)->nodeID) !=
627 other_root_functions.end();
639 unsigned int parent_fid = 0;
645 std::vector<boost::default_color_type> color_vec(boost::num_vertices(*
call_graph));
647 other_root_functions.erase(fid);
648 boost::depth_first_visit(*
call_graph, top_vertex, vis,
649 boost::make_iterator_property_map(color_vec.begin(),
650 boost::get(boost::vertex_index_t(), *
call_graph),
653 return other_root_functions.find(Cget_node_info<FunctionInfo, graph>(u, g)->nodeID) !=
654 other_root_functions.end();
656 if(f_list.find(fid) != f_list.end())
658 THROW_ASSERT(parent_fid == 0,
"Expected single parent root functions.");
660 parent_fid = root_fid;
677 const auto TM = AM->get_tree_manager();
678 const auto has_body = TM->get_implementation_node(f_id) != 0;
682 const auto fun = TM->CGetTreeNode(f_id);
683 const auto fd = GetPointerS<const function_decl>(
fun);
684 const auto sl = GetPointerS<const statement_list>(
GET_NODE(fd->body));
685 if(sl->list_of_bloc.empty())
687 THROW_ERROR(
"We can only work on CFG provided by GCC/CLANG");
691 for(
const auto& b : sl->list_of_bloc)
693 for(
const auto& stmt : b.second->CGetStmtList())
703 unsigned int caller_id,
unsigned int called_id,
unsigned int call_id,
706 bool has_been_previously_added = AM->GetCallGraphManager()->IsVertex(called_id);
707 AM->GetCallGraphManager()->AddFunctionAndCallPoint(AM, caller_id, called_id, call_id, call_type);
708 if(!has_been_previously_added)
717 unsigned int node_stmt,
723 if(curr_tn->get_kind() != function_decl_K)
725 if(AV.find(ind) != AV.end())
735 "-->Recursive analysis of " +
STR(ind) +
" of type " + curr_tn->get_kind_text() +
"(statement is " +
738 switch(curr_tn->get_kind())
740 case function_decl_K:
749 const auto* fd = GetPointer<const function_decl>(
fun);
750 if(fd->scpe &&
GET_NODE(fd->scpe)->get_kind() == function_decl_K)
755 AM->GetCallGraphManager()->AddFunctionAndCallPoint(AM, current, ind, node_stmt, call_type);
756 if(AV.find(ind) != AV.end())
768 case gimple_return_K:
770 auto* re = GetPointer<gimple_return>(curr_tn);
777 case gimple_assign_K:
779 auto* me = GetPointer<gimple_assign>(curr_tn);
796 case aggr_init_expr_K:
799 auto* ce = GetPointer<call_expr>(curr_tn);
801 if(fun_node->get_kind() == addr_expr_K)
803 auto* ue = GetPointer<unary_expr>(fun_node);
806 else if(fun_node->get_kind() == obj_type_ref_K)
817 for(
auto&
arg : ce->args)
825 auto* ce = GetPointer<gimple_call>(curr_tn);
827 if(fun_node->get_kind() == addr_expr_K)
829 auto* ue = GetPointer<unary_expr>(fun_node);
832 else if(fun_node->get_kind() == obj_type_ref_K)
842 for(
auto&
arg : ce->args)
850 auto* ce = GetPointer<cond_expr>(curr_tn);
858 auto* gc = GetPointer<gimple_cond>(curr_tn);
865 auto* ue = GetPointer<unary_expr>(curr_tn);
871 auto* be = GetPointer<binary_expr>(curr_tn);
877 case gimple_switch_K:
879 auto* se = GetPointer<gimple_switch>(curr_tn);
883 case gimple_multi_way_if_K:
885 auto* gmwi = GetPointer<gimple_multi_way_if>(curr_tn);
886 for(
const auto& cond : gmwi->list_of_cond)
902 case component_ref_K:
903 case bit_field_ref_K:
905 case with_cleanup_expr_K:
906 case vec_cond_expr_K:
907 case vec_perm_expr_K:
908 case dot_prod_expr_K:
909 case ternary_plus_expr_K:
910 case ternary_pm_expr_K:
911 case ternary_mp_expr_K:
912 case ternary_mm_expr_K:
915 case insertvalue_expr_K:
916 case insertelement_expr_K:
917 case bit_ior_concat_expr_K:
919 auto* te = GetPointer<ternary_expr>(curr_tn);
930 auto* qe = GetPointer<quaternary_expr>(curr_tn);
945 auto* le = GetPointer<lut_expr>(curr_tn);
980 auto* c = GetPointer<constructor>(curr_tn);
981 for(
const auto& i : c->list_of_idx_valu)
990 auto* vd = GetPointer<var_decl>(curr_tn);
1007 case template_decl_K:
1008 case gimple_label_K:
1012 case target_mem_ref_K:
1013 case target_mem_ref461_K:
1015 case gimple_pragma_K:
1022 case case_label_expr_K:
1027 case gimple_predict_K:
1029 case gimple_while_K:
1030 case identifier_node_K:
1031 case namespace_decl_K:
1032 case statement_list_K:
1033 case translation_unit_decl_K:
1042 THROW_ERROR(std::string(
"Node not supported (") +
STR(ind) + std::string(
"): ") + curr_tn->get_kind_text());
#define GET_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
#define DEBUG_LEVEL_VERY_PEDANTIC
extremely verbose debugging print is performed.
CustomSet< unsigned int > & body_functions
The list of encountered body functions.
bool IsCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id, enum FunctionEdgeInfo::CallType call_type) const
Returns true if the call point is present.
const CustomSet< unsigned int > & GetReachedBodyFunctions() const
Returns the source code functions called by the root functions.
#define INDENT_DBG_MEX(dbgLevel, curDbgLevel, mex)
We are producing a debug version of the program, so the message is printed;.
static std::string name_function(const tree_managerConstRef &tm, const unsigned int index)
Return the name of the function.
refcount< CallGraph > CallGraphRef
The refcount definition for CallGraph.
File containing functions and utilities to support the printing of debug messagges.
const bool allow_recursive_functions
True if recursive calls are allowed.
std::string ToString() const
Print this node as string in gimple format.
CustomSet< unsigned int > GetRootFunctions() const
Returns the root functions (i.e., the functions that are not called by any other ones.
#define DEBUG_LEVEL_PEDANTIC
very verbose debugging print is performed.
#define CASE_BINARY_EXPRESSION
This macro collects all case labels for binary_expr objects.
#define GET_CLASS(obj)
Macro returning the actual type of an object.
Definition of the class representing a generic C application.
#define GET_NODE_INFO(data, NodeInfo, vertex_index)
CustomSet< unsigned int > reached_body_functions
source code functions directly or indirectly called by the root functions
refcount< BehavioralHelper > BehavioralHelperRef
RefCount type definition of the tree_to_graph class structure.
This class manages the tree structures extracted from the raw file.
CustomSet< unsigned int > addressed_functions
set of functions whose address is taken
Class specification of the graph structures.
exceptions managed by PandA
void back_edge(const EdgeDescriptor &e, const CallGraph &g)
#define BUILTIN_WAIT_CALL
constant defining the builtin wait call intrinsic function
#define GET_INDEX_NODE(t)
Macro used to hide implementation details when accessing a tree_node from another tree_node...
static std::string print_function_name(const tree_managerConstRef &TM, const function_decl *fd)
Return the name of the function in a string.
CallGraphManager(const FunctionExpanderConstRef function_expander, const bool allow_recursive_functions, const tree_managerConstRef tree_manager, const ParameterConstRef Param)
Constructor.
Data structure describing a basic block at tree level.
CustomSet< unsigned int > GetAddressedFunctions() const
Returns a set containing all the reachable addressed_functions.
std::map< unsigned int, vertex > functionID_vertex_map
put into relation function F_i and the vertex in the call graph representing it
Information associated with a call_graph node.
CustomSet< unsigned int > root_functions
Root functions.
const tree_nodeConstRef CGetTreeNode(const unsigned int i) const
virtual enum kind get_kind() const =0
Virtual function returning the type of the actual class.
#define STR(s)
Macro which performs a lexical_cast to a string.
Auxiliary methods for manipulating string.
#define FEEDBACK_SELECTOR
unsigned int get_function(vertex node) const
Given a vertex of the call graph, this returns the index of the corresponding function.
The info associated with the call graph.
static void addCallPointAndExpand(CustomUnorderedSet< unsigned int > &AV, const application_managerRef AM, unsigned int caller_id, unsigned int called_id, unsigned int call_id, enum FunctionEdgeInfo::CallType call_type, int DL)
const tree_nodeRef get_tree_node_const(unsigned int i) const
Return the reference to the i-th tree_node Constant version of get_tree_node.
This class is the view of a call graph.
CalledFunctionsVisitor(const bool _allow_recursive_functions, const CallGraphManager *_call_graph_manager, CustomSet< unsigned int > &_body_functions, CustomSet< unsigned int > &_library_functions)
Constructor.
const OpNodeInfoConstRef CGetOpNodeInfo(const vertex node) const
Returns the info associated with a node.
void finish_vertex(const vertex &u, const CallGraph &g)
Function called when a vertex has been finished.
#define THROW_UNREACHABLE(str_expr)
helper function used to specify that some points should never be reached
const bool allow_recursive_functions
True if recursive calls are allowed.
std::map< unsigned int, CustomSet< unsigned int > > called_by
put into relation function F_i and the list of functions called by F_i
#define CASE_QUATERNARY_EXPRESSION
This macro collects all case labels for quaternary_expr objects.
#define CASE_UNARY_EXPRESSION
This macro collects all case labels for unary_expr objects.
static void call_graph_computation_recursive(CustomUnorderedSet< unsigned int > &AV, const application_managerRef AM, unsigned int current, const tree_managerRef &TM, const tree_nodeRef &tn, unsigned int node_stmt, enum FunctionEdgeInfo::CallType call_type, int DL)
Recursive analysis of the tree nodes looking for call expressions.
CustomSet< unsigned int > reached_library_functions
library functions directly or indirectly called by the root functions
This class collects information concerning the set of functions that will be analyzed by the PandA fr...
void ReplaceCallPoint(const EdgeDescriptor e, const unsigned int orig, const unsigned int repl)
Replaces a call point.
boost::graph_traits< graph >::vertex_descriptor vertex
vertex definition.
void AddCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id, enum FunctionEdgeInfo::CallType call_type)
Creates a new call point.
unsigned int get_implementation_node(unsigned int decl_node) const
Return the index of function_decl node that implements the declaration node.
CallGraphConstRef CGetCallGraph() const
Return the call graph.
Classes specification of the tree_node data structures.
#define THROW_ERROR(str_expr)
helper function used to throw an error in a standard way
refcount< NodeInfo > NodeInfoRef
RefCount type definition of the NodeInfo class structure.
#define CASE_TYPE_NODES
This macro collects all case labels for type objects.
This file collects some utility functions.
refcount< FunctionBehavior > FunctionBehaviorRef
void TopologicalSort(std::list< boost::graph_traits< graphs_collection >::vertex_descriptor > &sorted_vertices) const
Compute the topological order of the graph.
static tree_nodeRef find_obj_type_ref_function(const tree_nodeConstRef &tn)
Given the tree_node of an obj_type_ref return the tree_node of the called function.
bool ExistsAddressedFunction() const
Returns true is there is at least a reachable function that is called through a function pointer or i...
refcount< const CallGraph > CallGraphConstRef
CustomSet< unsigned int > GetReachedFunctionsFrom(unsigned int from_f, bool with_body=true) const
compute the list of reached function starting from a given function
const int debug_level
the debug level
void AddFunctionAndCallPoint(unsigned int caller_id, unsigned int called_id, unsigned int call_id, const FunctionBehaviorRef called_function_behavior, enum FunctionEdgeInfo::CallType call_type)
Creates a new called function and directly adds the call to the call graph.
CustomSet< unsigned int > get_called_by(unsigned int index) const
Returns the set of functions called by a function.
Class specification of the tree_reindex support class.
Visitor to identify the list of called functions.
#define CASE_FAKE_NODES
This macro collects all case labels for fake or empty nodes.
CustomSet< unsigned int > & library_functions
The list of encountered library functions.
CustomSet< unsigned int > GetReachedLibraryFunctions() const
Returns the library functions called by the root functions.
~CallGraphManager()
Destructor.
This class manages the accesses to the CallGraph.
void RemoveCallPoint(const unsigned int caller_id, const unsigned int called_id, const unsigned int call_id)
Remove a function call, like RemoveCallPoint with a different API.
Data structures used in operations graph.
void ComputeRootAndReachedFunctions()
Compute the root and reached functions, maintaining the internal data structures coherent.
#define THROW_ERROR_CODE(code, str_expr)
helper function used to throw an error with a code error
interface of loops finding algorithm
Classes specification of the tree_node data structures not present in the gcc.
this class is used to manage the command-line or XML options.
#define CASE_CPP_NODES
This macro collects all case labels for cpp nodes.
nested functions are not currently supported
unsigned int GetRootFunction(unsigned int fid) const
Get the parent root function.
CallGraphConstRef CGetCallSubGraph(const CustomUnorderedSet< vertex > &vertices) const
Return a subset of the call graph.
void AddFunction(unsigned int new_function_id, const FunctionBehaviorRef fun_behavior)
int fun(float *A, float *invA, float *b, float *x, float *I)
vertex GetVertex(const unsigned int index) const
Return the vertex given the function id.
CallGraphConstRef CGetAcyclicCallGraph() const
Return an acyclic version of the call graph.
bool IsVertex(unsigned int functionID) const
return true in case the vertex has been already created
void SetRootFunctions(const CustomSet< unsigned int > &root_functions)
Set the root functions.
const CallGraphManager * call_graph_manager
The call graph manager.
const CallGraphInfoConstRef CGetCallGraphInfo() const
Return the info associated with the call graph.
const CallGraphsCollectionRef call_graphs_collection
static void expandCallGraphFromFunction(CustomUnorderedSet< unsigned int > &AV, const application_managerRef AM, unsigned int f_id, int DL)
const CallGraphRef call_graph
The view of call graph with all the edges.
Class specification of the manager of the tree structures extracted from the raw file.
A brief description of the C++ Header File.
#define CASE_PRAGMA_NODES
This macro collects all case labels for pragma objects.
boost::graph_traits< graph >::edge_descriptor EdgeDescriptor
edge definition.
#define THROW_ASSERT(cond, str_expr)
helper function used to check an assert and if needed to throw an error in a standard way ...