From 4407269a719212f6f605edff4a12ae137af8c0e1 Mon Sep 17 00:00:00 2001 From: Marek Trtik Date: Wed, 15 Mar 2017 11:09:04 +0000 Subject: [PATCH 1/3] Added mapping from edges of the call-graph to particular instructions in the caller GOTO programs, where the calls are performed. Added new functions find_direct_or_indirect_callees_of_function and find_nearest_common_callees. Clean up output_dot. --- src/analyses/call_graph.cpp | 140 ++++++++++++++++++++++++++++-------- src/analyses/call_graph.h | 51 ++++++++++--- 2 files changed, 154 insertions(+), 37 deletions(-) diff --git a/src/analyses/call_graph.cpp b/src/analyses/call_graph.cpp index 4413d56c205..215d56ba7de 100644 --- a/src/analyses/call_graph.cpp +++ b/src/analyses/call_graph.cpp @@ -6,10 +6,12 @@ Author: Daniel Kroening, kroening@kroening.com \*******************************************************************/ +#include "call_graph.h" #include #include +#include +#include -#include "call_graph.h" /*******************************************************************\ @@ -70,11 +72,19 @@ void call_grapht::add( { const exprt &function_expr=to_code_function_call(i_it->code).function(); if(function_expr.id()==ID_symbol) - add(function, to_symbol_expr(function_expr).get_identifier()); + add(function, to_symbol_expr(function_expr).get_identifier(), {i_it}); } } } +void call_grapht::swap(call_grapht &other) +{ + std::swap(graph,other.graph); + std::swap(map_from_edges_to_call_locations, + other.map_from_edges_to_call_locations); +} + + /*******************************************************************\ Function: call_grapht::add @@ -94,6 +104,25 @@ void call_grapht::add( graph.insert(std::pair(caller, callee)); } +void call_grapht::add(const irep_idt &caller, const irep_idt &callee, + const map_from_edges_to_call_locationst::mapped_type &call_sites) +{ + bool exists=false; + const call_grapht::call_edges_ranget range=out_edges(caller); + for (auto it=range.first; it!=range.second; ++it) + if(it->second==callee) + { + exists=true; + break; + } + if(!exists) + add(caller,callee); + std::copy( + call_sites.cbegin(),call_sites.cend(), + std::back_inserter(map_from_edges_to_call_locations[{caller,callee}])); +} + + /*******************************************************************\ Function: call_grapht::output_dot @@ -108,35 +137,23 @@ Function: call_grapht::output_dot void call_grapht::output_dot(std::ostream &out) const { - out << "digraph call_graph {\n"; - + out << "digraph call_graph {\n" + << " node [fontsize=12 shape=box];\n"; for(const auto &edge : graph) { out << " \"" << edge.first << "\" -> " << "\"" << edge.second << "\" " - << " [arrowhead=\"vee\"];" - << "\n"; - } - - out << "}\n"; -} - - -void call_grapht::output_dot( - const goto_functionst &functions, - std::ostream &out) const -{ - out << "digraph call_graph {\n"; - for(const auto &elem : functions.function_map) - out << " \"" << elem.first << "\";\n"; - for(grapht::const_iterator it=graph.begin(); - it!=graph.end(); - it++) - { - out << " \"" << it->first << "\" -> " - << "\"" << it->second << "\" " - << " [arrowhead=\"vee\"];" - << "\n"; + << " [label=\"{"; + bool first=true; + for(const auto instr_it : + get_map_from_edges_to_call_locations().at({edge.first,edge.second})) + { + if (!first) + out << ","; + out << instr_it->location_number; + first=false; + } + out << "}\"];\n"; } out << "}\n"; } @@ -382,7 +399,10 @@ void compute_inverted_call_graph( { assert(output_inverted_call_graph.graph.empty()); for(const auto &elem : original_call_graph.graph) - output_inverted_call_graph.add(elem.second, elem.first); + output_inverted_call_graph.add( + elem.second,elem.first, + original_call_graph.get_map_from_edges_to_call_locations().at( + {elem.first, elem.second})); } /*******************************************************************\ @@ -443,3 +463,67 @@ void find_leaves_below_function( std::unordered_set to_avoid; find_leaves_below_function(call_graph, function, to_avoid, output); } + +void find_direct_or_indirect_callees_of_function( + const call_grapht &call_graph, + const irep_idt &function, + std::unordered_set &output) +{ + std::unordered_set leaves; + find_leaves_below_function(call_graph,function,output,leaves); + output.insert(leaves.cbegin(),leaves.cend()); +} + +void find_nearest_common_callees( + const call_grapht &call_graph, + const std::set &functions, + std::set &output) +{ + if(functions.empty()) + return; + if(functions.size()==1UL) + { + output.insert(*functions.cbegin()); + return; + } + + std::map counting; + for(const auto &elem : call_graph.graph) + { + counting[elem.first]=0U; + counting[elem.second]=0U; + } + for(const auto &fn : functions) + { + std::unordered_set callees; + find_direct_or_indirect_callees_of_function(call_graph,fn,callees); + assert(callees.count(fn)==1U); + for(const auto &callee : callees) + ++counting[callee]; + } + + std::set leaves; + for(const auto &elem : counting) + if(elem.second!=0U) + { + const call_grapht::call_edges_ranget range= + call_graph.out_edges(elem.first); + if(range.first==range.second) + leaves.insert(elem.first); + } + + for(auto &elem : counting) + if(leaves.count(elem.first)!=0UL) + output.insert(elem.first); + else if(elem.second!=0U && elem.secondsecond); + if(cit->second==functions.size()) + output.insert(cit->first); + } + } +} diff --git a/src/analyses/call_graph.h b/src/analyses/call_graph.h index f852272b20e..7609a32d236 100644 --- a/src/analyses/call_graph.h +++ b/src/analyses/call_graph.h @@ -23,23 +23,31 @@ class call_grapht explicit call_grapht(const goto_functionst &); void output_dot(std::ostream &out) const; - - /** - * It writes this into the passed stream in the Graphviz's DOT format. - * The method accepts also functions, because the callgraph does not - * store funtions (nodes). It only stores edges (from caller to callee). - * So, the resulting graph would not show not-called functions. - */ - void output_dot(const goto_functionst &functions, std::ostream &out) const; - void output(std::ostream &out) const; void output_xml(std::ostream &out) const; typedef std::multimap grapht; grapht graph; + void swap(call_grapht &other); + void add(const irep_idt &caller, const irep_idt &callee); + /** + * The type provides a mapping from edges of the call-graph to particular + * instructions in the caller GOTO programs, where the calls are performed. + */ + typedef std::map< + std::pair, + std::vector > + map_from_edges_to_call_locationst; + + const map_from_edges_to_call_locationst & + get_map_from_edges_to_call_locations() const + { return map_from_edges_to_call_locations; } + + void add(const irep_idt &caller, const irep_idt &callee, + const map_from_edges_to_call_locationst::mapped_type &call_sites); protected: void add(const irep_idt &function, const goto_programt &body); @@ -74,6 +82,9 @@ class call_grapht * std::cout << it->second << ", "; */ call_edges_ranget out_edges(const irep_idt &caller) const; + +private: + map_from_edges_to_call_locationst map_from_edges_to_call_locations; }; /*******************************************************************\ @@ -160,4 +171,26 @@ void find_leaves_below_function( const irep_idt &function, std::unordered_set &output); +void find_direct_or_indirect_callees_of_function( + const call_grapht &call_graph, + const irep_idt &function, + std::unordered_set &output); + +void find_nearest_common_callees( + const call_grapht &call_graph, + const std::set &functions, + std::set &output); + +/** + * The "callee" must be a DIRECT callee of the "caller" in the "call_graph". + */ +inline const std::vector & +get_call_sites( + call_grapht const& call_graph, + irep_idt const& caller, + irep_idt const& callee) +{ + return call_graph.get_map_from_edges_to_call_locations().at({caller,callee}); +} + #endif // CPROVER_ANALYSES_CALL_GRAPH_H From 0e37d792ec22e15f62224820d9be7bcb6ef76e8d Mon Sep 17 00:00:00 2001 From: Marek Trtik Date: Wed, 15 Mar 2017 15:32:18 +0000 Subject: [PATCH 2/3] CPPLINT --- src/analyses/call_graph.cpp | 30 +++++++++++++++--------------- src/analyses/call_graph.h | 4 ++-- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/analyses/call_graph.cpp b/src/analyses/call_graph.cpp index 215d56ba7de..a0f7847bdf9 100644 --- a/src/analyses/call_graph.cpp +++ b/src/analyses/call_graph.cpp @@ -79,7 +79,7 @@ void call_grapht::add( void call_grapht::swap(call_grapht &other) { - std::swap(graph,other.graph); + std::swap(graph, other.graph); std::swap(map_from_edges_to_call_locations, other.map_from_edges_to_call_locations); } @@ -109,17 +109,17 @@ void call_grapht::add(const irep_idt &caller, const irep_idt &callee, { bool exists=false; const call_grapht::call_edges_ranget range=out_edges(caller); - for (auto it=range.first; it!=range.second; ++it) + for(auto it=range.first; it!=range.second; ++it) if(it->second==callee) { exists=true; break; } if(!exists) - add(caller,callee); + add(caller, callee); std::copy( - call_sites.cbegin(),call_sites.cend(), - std::back_inserter(map_from_edges_to_call_locations[{caller,callee}])); + call_sites.cbegin(), call_sites.cend(), + std::back_inserter(map_from_edges_to_call_locations[{caller, callee}])); } @@ -146,9 +146,9 @@ void call_grapht::output_dot(std::ostream &out) const << " [label=\"{"; bool first=true; for(const auto instr_it : - get_map_from_edges_to_call_locations().at({edge.first,edge.second})) + get_map_from_edges_to_call_locations().at({edge.first, edge.second})) { - if (!first) + if(!first) out << ","; out << instr_it->location_number; first=false; @@ -400,7 +400,7 @@ void compute_inverted_call_graph( assert(output_inverted_call_graph.graph.empty()); for(const auto &elem : original_call_graph.graph) output_inverted_call_graph.add( - elem.second,elem.first, + elem.second, elem.first, original_call_graph.get_map_from_edges_to_call_locations().at( {elem.first, elem.second})); } @@ -467,11 +467,11 @@ void find_leaves_below_function( void find_direct_or_indirect_callees_of_function( const call_grapht &call_graph, const irep_idt &function, - std::unordered_set &output) + std::unordered_set &output) { - std::unordered_set leaves; - find_leaves_below_function(call_graph,function,output,leaves); - output.insert(leaves.cbegin(),leaves.cend()); + std::unordered_set leaves; + find_leaves_below_function(call_graph, function, output, leaves); + output.insert(leaves.cbegin(), leaves.cend()); } void find_nearest_common_callees( @@ -487,7 +487,7 @@ void find_nearest_common_callees( return; } - std::map counting; + std::map counting; for(const auto &elem : call_graph.graph) { counting[elem.first]=0U; @@ -495,8 +495,8 @@ void find_nearest_common_callees( } for(const auto &fn : functions) { - std::unordered_set callees; - find_direct_or_indirect_callees_of_function(call_graph,fn,callees); + std::unordered_set callees; + find_direct_or_indirect_callees_of_function(call_graph, fn, callees); assert(callees.count(fn)==1U); for(const auto &callee : callees) ++counting[callee]; diff --git a/src/analyses/call_graph.h b/src/analyses/call_graph.h index 7609a32d236..554bc2ebf82 100644 --- a/src/analyses/call_graph.h +++ b/src/analyses/call_graph.h @@ -174,7 +174,7 @@ void find_leaves_below_function( void find_direct_or_indirect_callees_of_function( const call_grapht &call_graph, const irep_idt &function, - std::unordered_set &output); + std::unordered_set &output); void find_nearest_common_callees( const call_grapht &call_graph, @@ -190,7 +190,7 @@ get_call_sites( irep_idt const& caller, irep_idt const& callee) { - return call_graph.get_map_from_edges_to_call_locations().at({caller,callee}); + return call_graph.get_map_from_edges_to_call_locations().at({caller, callee}); } #endif // CPROVER_ANALYSES_CALL_GRAPH_H From 3541cd55c35f93511d54f514fc1e4c9f28fd6f11 Mon Sep 17 00:00:00 2001 From: Marek Trtik Date: Thu, 16 Mar 2017 12:22:22 +0000 Subject: [PATCH 3/3] Unimportant: added void comments, some white characters, and one artificial block enclosing an if-statement. --- src/analyses/call_graph.cpp | 54 ++++++++++++++++++++++++++++++++++++- src/analyses/call_graph.h | 6 ++--- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/analyses/call_graph.cpp b/src/analyses/call_graph.cpp index a0f7847bdf9..a4a1ff65ec1 100644 --- a/src/analyses/call_graph.cpp +++ b/src/analyses/call_graph.cpp @@ -77,6 +77,18 @@ void call_grapht::add( } } +/*******************************************************************\ + +Function: call_grapht::swap + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void call_grapht::swap(call_grapht &other) { std::swap(graph, other.graph); @@ -104,17 +116,33 @@ void call_grapht::add( graph.insert(std::pair(caller, callee)); } -void call_grapht::add(const irep_idt &caller, const irep_idt &callee, +/*******************************************************************\ + +Function: call_grapht::add + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + +void call_grapht::add( + const irep_idt &caller, + const irep_idt &callee, const map_from_edges_to_call_locationst::mapped_type &call_sites) { bool exists=false; const call_grapht::call_edges_ranget range=out_edges(caller); for(auto it=range.first; it!=range.second; ++it) + { if(it->second==callee) { exists=true; break; } + } if(!exists) add(caller, callee); std::copy( @@ -464,6 +492,18 @@ void find_leaves_below_function( find_leaves_below_function(call_graph, function, to_avoid, output); } +/*******************************************************************\ + +Function: find_direct_or_indirect_callees_of_function + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void find_direct_or_indirect_callees_of_function( const call_grapht &call_graph, const irep_idt &function, @@ -474,6 +514,18 @@ void find_direct_or_indirect_callees_of_function( output.insert(leaves.cbegin(), leaves.cend()); } +/*******************************************************************\ + +Function: find_nearest_common_callees + + Inputs: + + Outputs: + + Purpose: + +\*******************************************************************/ + void find_nearest_common_callees( const call_grapht &call_graph, const std::set &functions, diff --git a/src/analyses/call_graph.h b/src/analyses/call_graph.h index 554bc2ebf82..5f43aa680e0 100644 --- a/src/analyses/call_graph.h +++ b/src/analyses/call_graph.h @@ -186,9 +186,9 @@ void find_nearest_common_callees( */ inline const std::vector & get_call_sites( - call_grapht const& call_graph, - irep_idt const& caller, - irep_idt const& callee) + const call_grapht &call_graph, + const irep_idt &caller, + const irep_idt &callee) { return call_graph.get_map_from_edges_to_call_locations().at({caller, callee}); }