/* Helper class for handling a call with specific arguments. Copyright (C) 2020-2023 Free Software Foundation, Inc. Contributed by David Malcolm . This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "tree.h" #include "function.h" #include "basic-block.h" #include "gimple.h" #include "diagnostic-core.h" #include "analyzer/analyzer.h" #include "analyzer/analyzer-logging.h" #include "diagnostic.h" #include "tree-diagnostic.h" /* for default_tree_printer. */ #include "gimple-pretty-print.h" #include "analyzer/region-model.h" #include "analyzer/call-details.h" #if ENABLE_ANALYZER namespace ana { /* class call_details. */ /* call_details's ctor. */ call_details::call_details (const gcall *call, region_model *model, region_model_context *ctxt) : m_call (call), m_model (model), m_ctxt (ctxt), m_lhs_type (NULL_TREE), m_lhs_region (NULL) { m_lhs_type = NULL_TREE; if (tree lhs = gimple_call_lhs (call)) { m_lhs_region = model->get_lvalue (lhs, ctxt); m_lhs_type = TREE_TYPE (lhs); } } /* Get the manager from m_model. */ region_model_manager * call_details::get_manager () const { return m_model->get_manager (); } /* Get any logger associated with this object. */ logger * call_details::get_logger () const { if (m_ctxt) return m_ctxt->get_logger (); else return NULL; } /* Get any uncertainty_t associated with the region_model_context. */ uncertainty_t * call_details::get_uncertainty () const { if (m_ctxt) return m_ctxt->get_uncertainty (); else return NULL; } /* If the callsite has a left-hand-side region, set it to RESULT and return true. Otherwise do nothing and return false. */ bool call_details::maybe_set_lhs (const svalue *result) const { gcc_assert (result); if (m_lhs_region) { m_model->set_value (m_lhs_region, result, m_ctxt); return true; } else return false; } /* Return the number of arguments used by the call statement. */ unsigned call_details::num_args () const { return gimple_call_num_args (m_call); } /* Return true if argument IDX is a size_t (or compatible with it). */ bool call_details::arg_is_size_p (unsigned idx) const { return types_compatible_p (get_arg_type (idx), size_type_node); } /* Get the location of the call statement. */ location_t call_details::get_location () const { return m_call->location; } /* Get argument IDX at the callsite as a tree. */ tree call_details::get_arg_tree (unsigned idx) const { return gimple_call_arg (m_call, idx); } /* Get the type of argument IDX. */ tree call_details::get_arg_type (unsigned idx) const { return TREE_TYPE (gimple_call_arg (m_call, idx)); } /* Get argument IDX at the callsite as an svalue. */ const svalue * call_details::get_arg_svalue (unsigned idx) const { tree arg = get_arg_tree (idx); return m_model->get_rvalue (arg, m_ctxt); } /* Attempt to get the string literal for argument IDX, or return NULL otherwise. For use when implementing "__analyzer_*" functions that take string literals. */ const char * call_details::get_arg_string_literal (unsigned idx) const { const svalue *str_arg = get_arg_svalue (idx); if (const region *pointee = str_arg->maybe_get_region ()) if (const string_region *string_reg = pointee->dyn_cast_string_region ()) { tree string_cst = string_reg->get_string_cst (); return TREE_STRING_POINTER (string_cst); } return NULL; } /* Attempt to get the fndecl used at this call, if known, or NULL_TREE otherwise. */ tree call_details::get_fndecl_for_call () const { return m_model->get_fndecl_for_call (m_call, m_ctxt); } /* Dump a multiline representation of this call to PP. */ void call_details::dump_to_pp (pretty_printer *pp, bool simple) const { pp_string (pp, "gcall: "); pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */); pp_newline (pp); pp_string (pp, "return region: "); if (m_lhs_region) m_lhs_region->dump_to_pp (pp, simple); else pp_string (pp, "NULL"); pp_newline (pp); for (unsigned i = 0; i < gimple_call_num_args (m_call); i++) { const svalue *arg_sval = get_arg_svalue (i); pp_printf (pp, "arg %i: ", i); arg_sval->dump_to_pp (pp, simple); pp_newline (pp); } } /* Dump a multiline representation of this call to stderr. */ DEBUG_FUNCTION void call_details::dump (bool simple) const { pretty_printer pp; pp_format_decoder (&pp) = default_tree_printer; pp_show_color (&pp) = pp_show_color (global_dc->printer); pp.buffer->stream = stderr; dump_to_pp (&pp, simple); pp_flush (&pp); } /* Get a conjured_svalue for this call for REG, and purge any state already relating to that conjured_svalue. */ const svalue * call_details::get_or_create_conjured_svalue (const region *reg) const { region_model_manager *mgr = m_model->get_manager (); return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg, conjured_purge (m_model, m_ctxt)); } } // namespace ana #endif /* #if ENABLE_ANALYZER */