From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7853) id A4AAC3982432; Wed, 4 Aug 2021 15:50:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A4AAC3982432 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Ankur saini To: gcc-cvs@gcc.gnu.org Subject: [gcc(refs/users/arsenic/heads/polymorphic_call)] analyzer: detect and analyze vfunc calls X-Act-Checkin: gcc X-Git-Author: Ankur Saini X-Git-Refname: refs/users/arsenic/heads/polymorphic_call X-Git-Oldrev: 57120cbe7269e857be179a7adc024ffca618d074 X-Git-Newrev: 7746e93ec6e7248eded75b62e63cc3a882fbb66f Message-Id: <20210804155033.A4AAC3982432@sourceware.org> Date: Wed, 4 Aug 2021 15:50:33 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 04 Aug 2021 15:50:33 -0000 https://gcc.gnu.org/g:7746e93ec6e7248eded75b62e63cc3a882fbb66f commit 7746e93ec6e7248eded75b62e63cc3a882fbb66f Author: Ankur Saini Date: Thu Jul 29 17:20:10 2021 +0530 analyzer: detect and analyze vfunc calls Diff: --- gcc/analyzer/engine.cc | 38 +++++++++++++------- gcc/analyzer/exploded-graph.h | 3 +- gcc/analyzer/program-state.cc | 5 +-- gcc/analyzer/program-state.h | 3 +- gcc/analyzer/region-model.cc | 83 ++++++++++++++++++++++++++++++++++++++++--- gcc/analyzer/region-model.h | 3 +- 6 files changed, 114 insertions(+), 21 deletions(-) diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 60bd46abdff..dd3433a0f11 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -3037,12 +3037,14 @@ void exploded_graph::create_dynamic_call (const gcall *call, tree fn_decl, exploded_node *node, - program_state &next_state, + program_state next_state, program_point &next_point, - uncertainty_t *uncertainty) + uncertainty_t *uncertainty, + logger *logger) { + LOG_FUNC (logger); + const program_point *this_point = &node->get_point (); - // assert for fn_decl ? function *fun = DECL_STRUCT_FUNCTION (fn_decl); if (fun) { @@ -3057,12 +3059,16 @@ exploded_graph::create_dynamic_call (const gcall *call, new_point.push_to_call_stack (sn_exit, next_point.get_supernode()); - next_state.push_call (*this, node, call, uncertainty); + next_state.push_call (*this, node, call, uncertainty, fn_decl); - // TODO: add some logging here regarding dynamic call - if (next_state.m_valid) { + if (logger) + logger->log ("Discovered call to %s [SN: %i -> SN: %i]", + function_name(fun), + this_point->get_supernode ()->m_index, + sn_entry->m_index); + exploded_node *enode = get_or_create_node (new_point, next_state, node); @@ -3312,7 +3318,10 @@ exploded_graph::process_node (exploded_node *node) program_state next_state (state); uncertainty_t uncertainty; - /* Try to discover and analyse indirect function calls. */ + /* Try to discover and analyse indirect function calls. + + Some examples of such calls are virtual function calls + and calls that happen via a function pointer. */ if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL && !(succ->get_any_callgraph_edge ())) { @@ -3327,11 +3336,16 @@ exploded_graph::process_node (exploded_node *node) point.get_stmt()); region_model *model = state.m_region_model; - - /* Call is possibly happening via a function pointer. */ - if (tree fn_decl = model->get_fndecl_for_call(call,&ctxt)) - create_dynamic_call (call, fn_decl, node, next_state, - next_point, &uncertainty); + if (tree fn_decl = model->get_fndecl_for_call (call,&ctxt)) + { + create_dynamic_call (call, + fn_decl, + node, + next_state, + next_point, + &uncertainty, + logger); + } } if (!node->on_edge (*this, succ, &next_point, &next_state, diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 291983ad7dc..c9edb9a4abf 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -818,7 +818,8 @@ public: exploded_node *node, program_state next_state, program_point &next_point, - uncertainty_t *uncertainty); + uncertainty_t *uncertainty, + logger *logger); exploded_node *get_or_create_node (const program_point &point, const program_state &state, diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index eb05994f0ef..b1c1d67bb8b 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -1042,7 +1042,8 @@ void program_state::push_call (exploded_graph &eg, exploded_node *enode, const gcall *call_stmt, - uncertainty_t *uncertainty) + uncertainty_t *uncertainty, + tree fn_decl) { /* Update state. */ const program_point &point = enode->get_point (); @@ -1053,7 +1054,7 @@ program_state::push_call (exploded_graph &eg, this, uncertainty, last_stmt); - m_region_model->update_for_gcall (call_stmt, &ctxt); + m_region_model->update_for_gcall(call_stmt, &ctxt, fn_decl); } /* Update this program_state to reflect a return from function diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index 658dbb69075..f4bd4cbcf49 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -221,7 +221,8 @@ public: void push_call (exploded_graph &eg, exploded_node *enode, const gcall *call_stmt, - uncertainty_t *uncertainty); + uncertainty_t *uncertainty, + tree fn_decl = NULL); void returning_call (exploded_graph &eg, exploded_node *enode, diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 1e86d1f3bf8..300ed3f17d0 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -67,6 +67,7 @@ along with GCC; see the file COPYING3. If not see #include "stor-layout.h" #include "attribs.h" #include "tree-object-size.h" +#include "ipa-utils.h" #if ENABLE_ANALYZER @@ -3140,7 +3141,8 @@ region_model::maybe_update_for_edge (const superedge &edge, void region_model::update_for_gcall (const gcall *call_stmt, - region_model_context *ctxt) + region_model_context *ctxt, + tree fn_decl) { /* Build a vec of argument svalues, using the current top frame for resolving tree expressions. */ @@ -3151,9 +3153,11 @@ region_model::update_for_gcall (const gcall *call_stmt, tree arg = gimple_call_arg (call_stmt, i); arg_svals.quick_push (get_rvalue (arg, ctxt)); } - - /* Get the function * from the call. */ - tree fn_decl = get_fndecl_for_call (call_stmt,ctxt); + + /* Get the fn_decl from the call if not provided as argument. */ + if (!fn_decl) + fn_decl = get_fndecl_for_call (call_stmt,ctxt); + function *fun = DECL_STRUCT_FUNCTION (fn_decl); push_frame (fun, &arg_svals, ctxt); } @@ -3654,6 +3658,77 @@ region_model::get_fndecl_for_call (const gcall *call, } } + /* Call is possibly a polymorphic call. + + In such case, use devirtisation tools to find + possible callees of this function call. */ + + function *fun = get_current_function (); + gcall *stmt = const_cast (call); + cgraph_edge *e = cgraph_node::get (fun->decl)->get_edge (stmt); + if (e->indirect_info->polymorphic) + { + void *cache_token; + bool final; + vec targets + = possible_polymorphic_call_targets (e, &final, &cache_token, true); + if (!targets.is_empty ()) + { + tree most_propbable_taget = NULL_TREE; + if(targets.length () == 1) + return targets[0]->decl; + + /* From the current state, check which subclass the pointer that + is being used to this polymorphic call points to, and use to + filter out correct function call. */ + tree t_val = gimple_call_arg (call, 0); + const svalue *sval = get_rvalue (t_val, ctxt); + + const region *reg + = [&]()->const region * + { + switch (sval->get_kind ()) + { + case SK_INITIAL: + { + const initial_svalue *initial_sval + = sval->dyn_cast_initial_svalue (); + return initial_sval->get_region (); + } + break; + case SK_REGION: + { + const region_svalue *region_sval + = sval->dyn_cast_region_svalue (); + return region_sval->get_pointee (); + } + break; + + default: + return NULL; + } + } (); + + gcc_assert (reg); + + tree known_possible_subclass_type; + known_possible_subclass_type = reg->get_type (); + if (reg->get_kind () == RK_FIELD) + { + const field_region* field_reg = reg->dyn_cast_field_region (); + known_possible_subclass_type + = DECL_CONTEXT (field_reg->get_field ()); + } + + for (cgraph_node *x : targets) + { + if (DECL_CONTEXT (x->decl) == known_possible_subclass_type) + most_propbable_taget = x->decl; + } + return most_propbable_taget; + } + } + return NULL_TREE; } diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index a15bc9e2f6d..f06788771dc 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -590,7 +590,8 @@ class region_model rejected_constraint **out); void update_for_gcall (const gcall *call_stmt, - region_model_context *ctxt); + region_model_context *ctxt, + tree fn_decl = NULL); void update_for_return_gcall (const gcall *call_stmt, region_model_context *ctxt);