public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/arsenic/heads/polymorphic_call)] analyzer: detect and analyze vfunc calls
@ 2021-08-04 15:50 Ankur saini
0 siblings, 0 replies; 2+ messages in thread
From: Ankur saini @ 2021-08-04 15:50 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:7746e93ec6e7248eded75b62e63cc3a882fbb66f
commit 7746e93ec6e7248eded75b62e63cc3a882fbb66f
Author: Ankur Saini <arsenic@sourceware.org>
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<gcall *> (call);
+ cgraph_edge *e = cgraph_node::get (fun->decl)->get_edge (stmt);
+ if (e->indirect_info->polymorphic)
+ {
+ void *cache_token;
+ bool final;
+ vec <cgraph_node *> 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);
^ permalink raw reply [flat|nested] 2+ messages in thread
* [gcc(refs/users/arsenic/heads/polymorphic_call)] analyzer: detect and analyze vfunc calls
@ 2021-08-04 13:58 Ankur saini
0 siblings, 0 replies; 2+ messages in thread
From: Ankur saini @ 2021-08-04 13:58 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:bda6341068a2319bb19a8ef68486bb379be66e48
commit bda6341068a2319bb19a8ef68486bb379be66e48
Author: Ankur Saini <arsenic@sourceware.org>
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 | 82 ++++++++++++++++++++++++++++++++++++++++---
gcc/analyzer/region-model.h | 3 +-
6 files changed, 113 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..69fcdadc7ea 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,76 @@ 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<gcall *> (call);
+ cgraph_edge *e = cgraph_node::get (fun->decl)->get_edge (stmt);
+ if (e->indirect_info->polymorphic)
+ {
+ void *cache_token;
+ bool final;
+ vec <cgraph_node *> 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);
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2021-08-04 15:50 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-04 15:50 [gcc(refs/users/arsenic/heads/polymorphic_call)] analyzer: detect and analyze vfunc calls Ankur saini
-- strict thread matches above, loose matches on Subject: below --
2021-08-04 13:58 Ankur saini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).