From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7853) id 587143847821; Sun, 4 Jul 2021 12:54:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 587143847821 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)] analyzer: refactor analyzer to detect calls via function pointer X-Act-Checkin: gcc X-Git-Author: Ankur Saini X-Git-Refname: refs/users/arsenic/heads/analyzer_extension X-Git-Oldrev: 52ca8da41899fc56fafab2fb740ad6e3a5117c0c X-Git-Newrev: 8091a33c6d4ca99f9c46204d9d3743ce6ee6ea4a Message-Id: <20210704125452.587143847821@sourceware.org> Date: Sun, 4 Jul 2021 12:54:52 +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: Sun, 04 Jul 2021 12:54:52 -0000 https://gcc.gnu.org/g:8091a33c6d4ca99f9c46204d9d3743ce6ee6ea4a commit 8091a33c6d4ca99f9c46204d9d3743ce6ee6ea4a Author: Ankur Saini Date: Sun Jul 4 18:01:10 2021 +0530 analyzer: refactor analyzer to detect calls via function pointer 2021-07-4 Ankur Saini gcc/analyzer/ * engine.cc (exploded_graph::process_node): handle calls via function pointers. * program-point.cc (program_point::push_to_call_stack): New function. * program-point.h (program_point::push_to_call_stack): New decl. * program-state.cc (program_state::push_call): New function. * program-state.h (program_state::push_call): New decl. * region-model.cc (region_model::update_for_gcall): New function. * region-model.h (region_model::update_for_gcall): New decl. * supergraph.cc (supergraph::supergraph): split nodes even for function that doesn't have a cgraph_edge * call-string.cc (call_string::validate): fix validation process Diff: --- gcc/analyzer/call-string.cc | 2 +- gcc/analyzer/engine.cc | 41 +++++++++++++++++++++++++++++++++++++++++ gcc/analyzer/program-point.cc | 10 ++++++++++ gcc/analyzer/program-point.h | 3 ++- gcc/analyzer/program-state.cc | 22 ++++++++++++++++++++++ gcc/analyzer/program-state.h | 4 ++++ gcc/analyzer/region-model.cc | 24 ++++++++++++++++++++++++ gcc/analyzer/region-model.h | 3 +++ gcc/analyzer/supergraph.cc | 31 ++++++++++++++++++++++++++----- 9 files changed, 133 insertions(+), 7 deletions(-) diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc index 50dfb9e8c7c..a7cde397a8f 100644 --- a/gcc/analyzer/call-string.cc +++ b/gcc/analyzer/call-string.cc @@ -249,7 +249,7 @@ call_string::validate () const FOR_EACH_VEC_ELT (m_supernodes, i, e) if (i > 0) { - gcc_assert (e->second->get_function () == m_supernodes[i - 1]->second->get_function()); + gcc_assert (e->second->get_function () == m_supernodes[i - 1]->first->get_function()); } } diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 4456d9b828b..5d981963b7e 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -3194,6 +3194,47 @@ exploded_graph::process_node (exploded_node *node) point.get_call_string ()); program_state next_state (state); uncertainty_t uncertainty; + + // 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())) + { + const program_point *this_point = &node->get_point(); + const program_state *this_state = &node->get_state (); + const gcall *call = this_point->get_supernode ()->get_final_call (); + + impl_region_model_context ctxt (*this, + node, + this_state, + &next_state, + &uncertainty, + this_point->get_stmt()); + + region_model *model = this_state->m_region_model; + tree fn_decl = model->get_fndecl_for_call(call,&ctxt); + 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); + //logger->log("found supernode = SN: %i",sn->m_index); + + program_point new_point = program_point::before_supernode (sn_entry, NULL, + point.get_call_string ()); + + // update callstring for returing back + new_point.push_to_call_stack (sn_exit,this_point->get_supernode()); + + next_state.push_call(*this, node, call, &uncertainty); + + if (next_state.m_valid) + { + exploded_node *enode = get_or_create_node (new_point, next_state, node); + if (enode) + add_edge (node,enode, NULL); + } + } + } if (!node->on_edge (*this, succ, &next_point, &next_state, &uncertainty)) { diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc index 40afafc7ad0..f2ba7463c79 100644 --- a/gcc/analyzer/program-point.cc +++ b/gcc/analyzer/program-point.cc @@ -323,6 +323,16 @@ program_point::to_json () const return point_obj; } +/* update the callstack to represent a call from caller to callee + genrally used to push a custom call to a perticular program point + where we don't have a superedge representing the call. */ +void +program_point::push_to_call_stack(const supernode *caller, + const supernode *callee) +{ + m_call_string.push_call(callee,caller); +} + /* Generate a hash value for this program_point. */ hashval_t diff --git a/gcc/analyzer/program-point.h b/gcc/analyzer/program-point.h index 5f86745cd1e..e08cebd750d 100644 --- a/gcc/analyzer/program-point.h +++ b/gcc/analyzer/program-point.h @@ -293,7 +293,8 @@ public: } bool on_edge (exploded_graph &eg, const superedge *succ); - + void push_to_call_stack(const supernode *caller, + const supernode *callee); void validate () const; /* For before_stmt, go to next stmt. */ diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc index 6d60c0449ce..1d25bc15212 100644 --- a/gcc/analyzer/program-state.cc +++ b/gcc/analyzer/program-state.cc @@ -1000,6 +1000,28 @@ program_state::on_edge (exploded_graph &eg, return true; } +/* Update this program_state to reflect a call to function + represented by CALL_STMT. + currently used only when the call doesn't have a superedge representing + the call ( like call via a function pointer ) */ +void +program_state::push_call(exploded_graph &eg, + exploded_node *enode, + const gcall *call_stmt, + uncertainty_t *uncertainty) +{ + /* Update state. */ + const program_point &point = enode->get_point (); + const gimple *last_stmt = point.get_supernode ()->get_last_stmt (); + + impl_region_model_context ctxt (eg, enode, + &enode->get_state (), + this, + uncertainty, + last_stmt); + m_region_model->update_for_gcall(call_stmt, &ctxt); +} + /* Generate a simpler version of THIS, discarding state that's no longer relevant at POINT. The idea is that we're more likely to be able to consolidate diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h index f16fe6ba984..ef52de4f63f 100644 --- a/gcc/analyzer/program-state.h +++ b/gcc/analyzer/program-state.h @@ -215,6 +215,10 @@ 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); bool on_edge (exploded_graph &eg, exploded_node *enode, diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 4fb6bc9f747..dbaab3b770a 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -2875,6 +2875,30 @@ region_model::update_for_call_superedge (const call_superedge &call_edge, 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) +{ + /* Build a vec of argument svalues, using the current top + frame for resolving tree expressions. */ + 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)); + } + + /* get the function * from the call */ + tree fn_decl = get_fndecl_for_call(call_stmt,ctxt); + function *fun = DECL_STRUCT_FUNCTION(fn_decl); + push_frame (fun, &arg_svals, ctxt); +} + /* 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). */ diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index b42852b3db9..fd1ab6efc6d 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -574,6 +574,9 @@ class region_model region_model_context *ctxt, rejected_constraint **out); + void update_for_gcall (const gcall *call_stmt, + region_model_context *ctxt); + const region *push_frame (function *fun, const vec *arg_sids, region_model_context *ctxt); const frame_region *get_current_frame () const { return m_current_frame; } diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc index 8611d0f8689..4792592cf86 100644 --- a/gcc/analyzer/supergraph.cc +++ b/gcc/analyzer/supergraph.cc @@ -183,11 +183,32 @@ supergraph::supergraph (logger *logger) m_stmt_to_node_t.put (stmt, node_for_stmts); m_stmt_uids.make_uid_unique (stmt); if (cgraph_edge *edge = supergraph_call_edge (fun, stmt)) - { - m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts); - node_for_stmts = add_node (fun, bb, as_a (stmt), NULL); - m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts); - } + { + m_cgraph_edge_to_caller_prev_node.put(edge, node_for_stmts); + node_for_stmts = add_node (fun, bb, as_a (stmt), NULL); + m_cgraph_edge_to_caller_next_node.put (edge, node_for_stmts); + } + else + { + // maybe call is via a function pointer + gcall *call = dyn_cast (stmt); + if (call) + { + cgraph_edge *edge = cgraph_node::get (fun->decl)->get_edge (stmt); + if (!edge || !edge->callee) + { + supernode *old_node_for_stmts = node_for_stmts; + node_for_stmts = add_node (fun, bb, call, NULL); + + // add edge for such calls right away as it would not be added later + superedge *sedge = new callgraph_superedge (old_node_for_stmts, + node_for_stmts, + SUPEREDGE_INTRAPROCEDURAL_CALL, + NULL); + add_edge (sedge); + } + } + } } m_bb_to_final_node.put (bb, node_for_stmts);