From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7853) id 97EE3397280F; Tue, 27 Jul 2021 08:38:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 97EE3397280F 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/analyzer_extension)] custom edge info for dynamic calls X-Act-Checkin: gcc X-Git-Author: Ankur Saini X-Git-Refname: refs/users/arsenic/heads/analyzer_extension X-Git-Oldrev: a0eee7ebbe450095800878e0945ab30a91debbf4 X-Git-Newrev: 274c619a435007989725b58cda992eb8935a2fec Message-Id: <20210727083839.97EE3397280F@sourceware.org> Date: Tue, 27 Jul 2021 08:38:39 +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: Tue, 27 Jul 2021 08:38:39 -0000 https://gcc.gnu.org/g:274c619a435007989725b58cda992eb8935a2fec commit 274c619a435007989725b58cda992eb8935a2fec Author: Ankur Saini Date: Thu Jul 22 11:23:47 2021 +0530 custom edge info for dynamic calls Diff: --- gcc/analyzer/analysis-plan.cc | 2 +- gcc/analyzer/checker-path.cc | 28 ++++++++++------ gcc/analyzer/checker-path.h | 6 ++++ gcc/analyzer/diagnostic-manager.cc | 19 ++++------- gcc/analyzer/engine.cc | 68 ++++++++++++++++++++++++++++++++------ gcc/analyzer/exploded-graph.h | 28 ++++++++++++++++ gcc/analyzer/program-state.h | 18 +++++----- gcc/analyzer/region-model.cc | 66 ++++++++++++------------------------ gcc/analyzer/region-model.h | 1 + gcc/analyzer/supergraph.cc | 5 ++- 10 files changed, 151 insertions(+), 90 deletions(-) diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc index 1c7e4d2cc84..57a6dcb1f6e 100644 --- a/gcc/analyzer/analysis-plan.cc +++ b/gcc/analyzer/analysis-plan.cc @@ -110,7 +110,7 @@ analysis_plan::use_summary_p (const cgraph_edge *edge) const return false; /* Don't use call summaries if there is no callgraph edge */ - if(!edge || !edge->callee) + if (!edge || !edge->callee) return false; /* TODO: don't count callsites each time. */ diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc index e10c8e2bb7c..b7304e234cc 100644 --- a/gcc/analyzer/checker-path.cc +++ b/gcc/analyzer/checker-path.cc @@ -614,7 +614,11 @@ call_event::call_event (const exploded_edge &eedge, location_t loc, tree fndecl, int depth) : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth) { - gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL); + if (eedge.m_sedge) + gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL); + + m_src_snode = eedge.m_src->get_supernode (); + m_dest_snode = eedge.m_dest->get_supernode (); } /* Implementation of diagnostic_event::get_desc vfunc for @@ -638,8 +642,8 @@ call_event::get_desc (bool can_colorize) const label_text custom_desc = m_pending_diagnostic->describe_call_with_state (evdesc::call_with_state (can_colorize, - m_sedge->m_src->m_fun->decl, - m_sedge->m_dest->m_fun->decl, + m_src_snode->m_fun->decl, + m_dest_snode->m_fun->decl, var, m_critical_state)); if (custom_desc.m_buffer) @@ -648,8 +652,8 @@ call_event::get_desc (bool can_colorize) const return make_label_text (can_colorize, "calling %qE from %qE", - m_sedge->m_dest->m_fun->decl, - m_sedge->m_src->m_fun->decl); + m_dest_snode->m_fun->decl, + m_src_snode->m_fun->decl); } /* Override of checker_event::is_call_p for calls. */ @@ -668,7 +672,11 @@ return_event::return_event (const exploded_edge &eedge, location_t loc, tree fndecl, int depth) : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth) { - gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN); + if (eedge.m_sedge) + gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN); + + m_src_snode = eedge.m_src->get_supernode (); + m_dest_snode = eedge.m_dest->get_supernode (); } /* Implementation of diagnostic_event::get_desc vfunc for @@ -694,16 +702,16 @@ return_event::get_desc (bool can_colorize) const label_text custom_desc = m_pending_diagnostic->describe_return_of_state (evdesc::return_of_state (can_colorize, - m_sedge->m_dest->m_fun->decl, - m_sedge->m_src->m_fun->decl, + m_dest_snode->m_fun->decl, + m_src_snode->m_fun->decl, m_critical_state)); if (custom_desc.m_buffer) return custom_desc; } return make_label_text (can_colorize, "returning to %qE from %qE", - m_sedge->m_dest->m_fun->decl, - m_sedge->m_src->m_fun->decl); + m_dest_snode->m_fun->decl, + m_src_snode->m_fun->decl); } /* Override of checker_event::is_return_p for returns. */ diff --git a/gcc/analyzer/checker-path.h b/gcc/analyzer/checker-path.h index 1843c4bc7b4..27634c20864 100644 --- a/gcc/analyzer/checker-path.h +++ b/gcc/analyzer/checker-path.h @@ -338,6 +338,9 @@ public: label_text get_desc (bool can_colorize) const FINAL OVERRIDE; bool is_call_p () const FINAL OVERRIDE; + + const supernode *m_src_snode; + const supernode *m_dest_snode; }; /* A concrete event subclass for an interprocedural return. */ @@ -351,6 +354,9 @@ public: label_text get_desc (bool can_colorize) const FINAL OVERRIDE; bool is_return_p () const FINAL OVERRIDE; + + const supernode *m_src_snode; + const supernode *m_dest_snode; }; /* A concrete event subclass for the start of a consolidated run of CFG diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 631fef6ad78..d7d9fa4c3d8 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -2060,18 +2060,17 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, case EK_CALL_EDGE: { call_event *event = (call_event *)base_event; - const callgraph_superedge& cg_superedge - = event->get_callgraph_superedge (); const region_model *callee_model = event->m_eedge.m_dest->get_state ().m_region_model; + const region_model *caller_model + = event->m_eedge.m_src->get_state ().m_region_model; tree callee_var = callee_model->get_representative_tree (sval); /* We could just use caller_model->get_representative_tree (sval); to get the caller_var, but for now use map_expr_from_callee_to_caller so as to only record critical state for parms and the like. */ callsite_expr expr; - tree caller_var - = cg_superedge.map_expr_from_callee_to_caller (callee_var, &expr); + tree caller_var = caller_model->get_representative_tree (sval); if (caller_var) { if (get_logger ()) @@ -2093,15 +2092,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, if (sval) { return_event *event = (return_event *)base_event; - const callgraph_superedge& cg_superedge - = event->get_callgraph_superedge (); - const region_model *caller_model - = event->m_eedge.m_dest->get_state ().m_region_model; - tree caller_var = caller_model->get_representative_tree (sval); callsite_expr expr; - tree callee_var - = cg_superedge.map_expr_from_caller_to_callee (caller_var, - &expr); + + const region_model *callee_model + = event->m_eedge.m_src->get_state ().m_region_model; + tree callee_var = callee_model->get_representative_tree (sval); if (callee_var) { if (get_logger ()) diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index c0d55bbcaba..d6de8094dde 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1627,6 +1627,50 @@ exploded_node::dump_succs_and_preds (FILE *outf) const } } +/* class dynamic_call_info_t : public exploded_edge::custom_info_t. */ + +/* Implementation of exploded_edge::custom_info_t::update_model vfunc + for dynamic_call_info_t. + + Update state for the dynamically discorverd calls */ + +void +dynamic_call_info_t::update_model (region_model *model, + const exploded_edge &eedge) +{ + const program_state &dest_state = eedge.m_dest->get_state (); + *model = *dest_state.m_region_model; +} + +/* Implementation of exploded_edge::custom_info_t::add_events_to_path vfunc + for dynamic_call_info_t. */ + +void +dynamic_call_info_t::add_events_to_path (checker_path *emission_path, + const exploded_edge &eedge) +{ + const exploded_node *src_node = eedge.m_src; + const program_point &src_point = src_node->get_point (); + const int src_stack_depth = src_point.get_stack_depth (); + const exploded_node *dest_node = eedge.m_dest; + const program_point &dest_point = dest_node->get_point (); + const int dest_stack_depth = dest_point.get_stack_depth (); + + if (m_is_returning_call) + emission_path->add_event (new return_event (eedge, (m_dynamic_call + ? m_dynamic_call->location + : UNKNOWN_LOCATION), + dest_point.get_fndecl (), + dest_stack_depth)); + else + emission_path->add_event (new call_event (eedge, (m_dynamic_call + ? m_dynamic_call->location + : UNKNOWN_LOCATION), + src_point.get_fndecl (), + src_stack_depth)); + +} + /* class rewind_info_t : public exploded_edge::custom_info_t. */ /* Implementation of exploded_edge::custom_info_t::update_model vfunc @@ -3221,8 +3265,8 @@ exploded_graph::process_node (exploded_node *node) /* Check if now the analyzer know about the call via function pointer or not. */ - if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL && - !(succ->get_any_callgraph_edge())) + if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL + && !(succ->get_any_callgraph_edge ())) { const program_point *this_point = &node->get_point(); const program_state *this_state = &node->get_state (); @@ -3241,9 +3285,9 @@ exploded_graph::process_node (exploded_node *node) function *fun = DECL_STRUCT_FUNCTION(fn_decl); if(fun) { - const supergraph *sg = &(this->get_supergraph()); - supernode * sn_entry = sg->get_node_for_function_entry (fun); - supernode * sn_exit = sg->get_node_for_function_exit (fun); + const supergraph &sg = this->get_supergraph(); + supernode * sn_entry = sg.get_node_for_function_entry (fun); + supernode * sn_exit = sg.get_node_for_function_exit (fun); program_point new_point = program_point::before_supernode (sn_entry, @@ -3255,13 +3299,15 @@ exploded_graph::process_node (exploded_node *node) next_state.push_call(*this, node, call, &uncertainty); + // TODO: add some logging here regarding dynamic call + if (next_state.m_valid) { exploded_node *enode = get_or_create_node (new_point, next_state, node); if (enode) - add_edge (node,enode, NULL); + add_edge (node,enode, NULL, new dynamic_call_info_t (call)); } } } @@ -3284,10 +3330,10 @@ exploded_graph::process_node (exploded_node *node) /* Return from the calls which doesn't have a return superedge. Such case occurs when GCC's middle end didn't knew which function to call but analyzer did */ - if((is_an_exit_block && !found_a_superedge) && - (!point.get_call_string().empty_p())) + if((is_an_exit_block && !found_a_superedge) + && (!point.get_call_string ().empty_p ())) { - const call_string cs = point.get_call_string(); + const call_string cs = point.get_call_string (); program_point next_point = program_point::before_supernode (cs.get_caller_node (), NULL, @@ -3304,12 +3350,12 @@ exploded_graph::process_node (exploded_node *node) if (next_state.m_valid) { - next_point.pop_from_call_stack(); + next_point.pop_from_call_stack (); exploded_node *enode = get_or_create_node (next_point, next_state, node); if (enode) - add_edge (node,enode, NULL); + add_edge (node, enode, NULL, new dynamic_call_info_t (call, true)); } } } diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 8f48d8a286c..cf4a6bfea1e 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -362,6 +362,34 @@ private: DISABLE_COPY_AND_ASSIGN (exploded_edge); }; +/* Extra data for an exploded_edge that represents a dynamic call info ( calls + that doesn't have a superedge representing the call ). */ + +class dynamic_call_info_t : public exploded_edge::custom_info_t +{ +public: + dynamic_call_info_t (const gcall *dynamic_call, + const bool is_returning_call = false) + : m_dynamic_call (dynamic_call), + m_is_returning_call (is_returning_call) + {} + + void print (pretty_printer *pp) FINAL OVERRIDE + { + pp_string (pp, "dynamic_call"); + } + + void update_model (region_model *model, + const exploded_edge &eedge) FINAL OVERRIDE; + + void add_events_to_path (checker_path *emission_path, + const exploded_edge &eedge) FINAL OVERRIDE; +private: + const gcall *m_dynamic_call; + const bool m_is_returning_call; +}; + + /* Extra data for an exploded_edge that represents a rewind from a longjmp to a setjmp (or from a siglongjmp to a sigsetjmp). */ diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index e91381a6d7d..658dbb69075 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -217,14 +217,16 @@ public: void push_frame (const extrinsic_state &ext_state, function *fun); function * get_current_function () const; - void push_call(exploded_graph &eg, - exploded_node *enode, - const gcall *call_stmt, - uncertainty_t *uncertainty); - void returning_call(exploded_graph &eg, - exploded_node *enode, - const gcall *call_stmt, - uncertainty_t *uncertainty); + + void push_call (exploded_graph &eg, + exploded_node *enode, + const gcall *call_stmt, + uncertainty_t *uncertainty); + + void returning_call (exploded_graph &eg, + exploded_node *enode, + const gcall *call_stmt, + uncertainty_t *uncertainty); bool on_edge (exploded_graph &eg, diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 1a6f4e1abc4..5dfe7a0f487 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -3139,28 +3139,6 @@ region_model::maybe_update_for_edge (const superedge &edge, caller's frame. */ void -region_model::update_for_call_superedge (const call_superedge &call_edge, - region_model_context *ctxt) -{ - /* Build a vec of argument svalues, using the current top - frame for resolving tree expressions. */ - const gcall *call_stmt = call_edge.get_call_stmt (); - auto_vec arg_svals (gimple_call_num_args (call_stmt)); - - for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++) - { - tree arg = gimple_call_arg (call_stmt, i); - arg_svals.quick_push (get_rvalue (arg, ctxt)); - } - - push_frame (call_edge.get_callee_function (), &arg_svals, ctxt); -} - -/* Push a new frame_region on to the stack region. - works in similar manner of that of region_model::update_for_call_superedge() - but it get the call info from CALL_STMT instead from a suerpedge and - is availabe publicically */ -void region_model::update_for_gcall (const gcall *call_stmt, region_model_context *ctxt) { @@ -3183,30 +3161,7 @@ region_model::update_for_gcall (const gcall *call_stmt, /* Pop the top-most frame_region from the stack, and copy the return region's values (if any) into the region for the lvalue of the LHS of the call (if any). */ -void -region_model::update_for_return_superedge (const return_superedge &return_edge, - region_model_context *ctxt) -{ - /* Get the region for the result of the call, within the caller frame. */ - const region *result_dst_reg = NULL; - const gcall *call_stmt = return_edge.get_call_stmt (); - tree lhs = gimple_call_lhs (call_stmt); - if (lhs) - { - /* Normally we access the top-level frame, which is: - path_var (expr, get_stack_depth () - 1) - whereas here we need the caller frame, hence "- 2" here. */ - gcc_assert (get_stack_depth () >= 2); - result_dst_reg = get_lvalue (path_var (lhs, get_stack_depth () - 2), - ctxt); - } - pop_frame (result_dst_reg, NULL, ctxt); -} - -/* do exatly what region_model::update_for_return_superedge() do - but get the call info from CALL_STMT instead from a suerpedge and - is availabe publicically */ void region_model::update_for_return_gcall (const gcall *call_stmt, region_model_context *ctxt) @@ -3227,6 +3182,27 @@ region_model::update_for_return_gcall (const gcall *call_stmt, pop_frame (result_dst_reg, NULL, ctxt); } +/* Extract calling infromation from the superedge and update the model for the + call */ + +void +region_model::update_for_call_superedge (const call_superedge &call_edge, + region_model_context *ctxt) +{ + const gcall *call_stmt = call_edge.get_call_stmt (); + update_for_gcall (call_stmt,ctxt); +} + +/* Extract calling infromation from the return superedge and update the model + for the returning call */ + +void +region_model::update_for_return_superedge (const return_superedge &return_edge, + region_model_context *ctxt) +{ + const gcall *call_stmt = return_edge.get_call_stmt (); + update_for_return_gcall (call_stmt, ctxt); +} /* Update this region_model with a summary of the effect of calling and returning from CG_SEDGE. diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index 05acb8240b1..a15bc9e2f6d 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -591,6 +591,7 @@ class region_model void update_for_gcall (const gcall *call_stmt, region_model_context *ctxt); + void update_for_return_gcall (const gcall *call_stmt, region_model_context *ctxt); diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index ace9e7b128a..598965dd7fc 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -189,11 +189,10 @@ supergraph::supergraph (logger *logger) NULL); m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts); } - else + else { // maybe call is via a function pointer - gcall *call = dyn_cast (stmt); - if (call) + if (gcall *call = dyn_cast (stmt)) { cgraph_edge *edge = cgraph_node::get (fun->decl)->get_edge (stmt);