LCOV - code coverage report
Current view: top level - gcc/analyzer - ana-state-to-diagnostic-state.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 77.8 % 396 308
Test Date: 2026-02-28 14:20:25 Functions: 95.0 % 20 19
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Creating diagnostic state graphs from ana::program_state.
       2              :    Copyright (C) 2025-2026 Free Software Foundation, Inc.
       3              :    Contributed by David Malcolm <dmalcolm@redhat.com>.
       4              : 
       5              : This file is part of GCC.
       6              : 
       7              : GCC is free software; you can redistribute it and/or modify it
       8              : under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but
      13              : WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              : General Public License for more details.
      16              : 
      17              : You should have received a copy of the GNU General Public License
      18              : along with GCC; see the file COPYING3.  If not see
      19              : <http://www.gnu.org/licenses/>.  */
      20              : 
      21              : #define INCLUDE_ALGORITHM
      22              : #define INCLUDE_MAP
      23              : #define INCLUDE_SET
      24              : #include "analyzer/common.h"
      25              : 
      26              : #include "diagnostics/state-graphs.h"
      27              : #include "diagnostics/sarif-sink.h"
      28              : 
      29              : #include "analyzer/region-model.h"
      30              : #include "analyzer/program-state.h"
      31              : #include "analyzer/record-layout.h"
      32              : #include "analyzer/ana-state-to-diagnostic-state.h"
      33              : 
      34              : #if ENABLE_ANALYZER
      35              : 
      36              : #if __GNUC__ >= 10
      37              : #pragma GCC diagnostic ignored "-Wformat"
      38              : #endif
      39              : 
      40              : namespace ana {
      41              : 
      42              : namespace node_properties = custom_sarif_properties::state_graphs::node;
      43              : 
      44              : static void
      45           42 : set_wi_attr (diagnostics::digraphs::node &state_node,
      46              :              const json::string_property &property,
      47              :              const wide_int_ref &w,
      48              :              signop sgn)
      49              : {
      50           42 :   pretty_printer pp;
      51           42 :   pp_wide_int (&pp, w, sgn);
      52           42 :   state_node.set_property (property, pp_formatted_text (&pp));
      53           42 : }
      54              : 
      55              : static void
      56          248 : set_type_attr (diagnostics::digraphs::node &state_node,
      57              :                const_tree type)
      58              : {
      59          248 :   gcc_assert (type);
      60          248 :   pretty_printer pp;
      61          248 :   pp_format_decoder (&pp) = default_tree_printer;
      62          248 :   pp_printf (&pp, "%T", type);
      63          248 :   state_node.set_property (node_properties::type,
      64              :                            pp_formatted_text (&pp));
      65          248 : }
      66              : 
      67              : static void
      68          272 : set_bits_attr (diagnostics::digraphs::node & state_node,
      69              :                bit_range bits)
      70              : {
      71          272 :   pretty_printer pp;
      72          272 :   bits.dump_to_pp (&pp);
      73          272 :   state_node.set_property (node_properties::bits,
      74              :                            pp_formatted_text (&pp));
      75          272 : }
      76              : 
      77              : static void
      78          224 : set_value_attrs (diagnostics::digraphs::node &state_node,
      79              :                  const svalue &sval)
      80              : {
      81          224 :   state_node.set_property (node_properties::value,
      82          448 :                            sval.to_json ());
      83          224 :   pretty_printer pp;
      84          224 :   pp_format_decoder (&pp) = default_tree_printer;
      85          224 :   sval.dump_to_pp (&pp, true);
      86          224 :   state_node.set_property (node_properties::value_str,
      87              :                            pp_formatted_text (&pp));
      88          224 : }
      89              : 
      90              : 
      91              : // class analyzer_state_graph : public diagnostics::digraphs::digraph
      92              : 
      93           28 : analyzer_state_graph::analyzer_state_graph (const program_state &state,
      94           28 :                                             const extrinsic_state &ext_state)
      95           28 : : m_state (state),
      96           28 :   m_ext_state (ext_state),
      97           28 :   m_mgr (*ext_state.get_engine ()->get_model_manager ()),
      98           28 :   m_next_id (0)
      99              : {
     100              :   /* Find pointers to heap-allocated regions, and record their types,
     101              :      so that we have a user-friendly way of showing the memory
     102              :      (by field, rather than by byte offset).  */
     103          184 :   for (auto cluster_iter : *state.m_region_model->get_store ())
     104          190 :     for (auto binding_iter : *cluster_iter.second)
     105              :       {
     106          112 :         const svalue *svalue = binding_iter.m_sval;
     107          112 :         if (const region *reg = svalue->maybe_get_region ())
     108           48 :           if (svalue->get_type () && !reg->get_type ())
     109              :             {
     110           48 :               tree pointed_to_type = TREE_TYPE (svalue->get_type ());
     111           48 :               if (!VOID_TYPE_P (pointed_to_type))
     112           48 :                 m_types_for_untyped_regions[reg] = pointed_to_type;
     113              :             }
     114              :       }
     115              : 
     116              :   /* TODO: look for vtable pointers at the top of dynamically-allocated
     117              :      regions and use that type as a fallback.  */
     118              : 
     119              :   /* Find regions of interest.
     120              :      Create elements per region, and build into hierarchy.
     121              :      Add edges for pointers.  */
     122              : 
     123              :   /* Create stack, from top to bottom.  */
     124           67 :   for (int i = state.m_region_model->get_stack_depth () - 1; i >= 0; --i)
     125              :     {
     126           39 :       const frame_region *reg = state.m_region_model->get_frame_at_index (i);
     127           39 :       get_or_create_state_node (*reg);
     128              :     }
     129              : 
     130              :   /* Create bound memory.  */
     131          106 :   for (auto iter : *state.m_region_model->get_store ())
     132              :     {
     133           78 :       const bool create_all = false; // "true" for verbose, for debugging
     134           78 :       create_state_nodes_for_binding_cluster (*iter.second, create_all);
     135              :     }
     136              : 
     137              :   /* TODO: Constraints.  */
     138              : 
     139              :   /* Annotate with information from state machines.  */
     140           28 :   {
     141           28 :     int i;
     142           28 :     sm_state_map *smap;
     143          224 :     FOR_EACH_VEC_ELT (state.m_checker_states, i, smap)
     144              :       {
     145          196 :         auto &sm = ext_state.get_sm (i);
     146          240 :         for (const auto &iter : *smap)
     147           44 :           sm.add_state_to_state_graph (*this, *iter.first, iter.second.m_state);
     148          196 :         if (auto s = smap->get_global_state ())
     149          196 :           sm.add_global_state_to_state_graph (*this, s);
     150              :       }
     151              :   }
     152              : 
     153              :   /* Process pending edges.  */
     154           76 :   while (m_pending_edges.size () > 0)
     155              :     {
     156           48 :       pending_edge item = m_pending_edges.back ();
     157           48 :       m_pending_edges.pop_back ();
     158              : 
     159              :       /* Ensure we have a node for the dst region.  This
     160              :          could lead to additional pending edges.  */
     161           48 :       auto &dst_node = get_or_create_state_node (item.m_dst_reg);
     162           48 :       add_edge (nullptr, item.m_src_node, dst_node);
     163              :     }
     164           28 : }
     165              : 
     166              : diagnostics::digraphs::node &
     167          384 : analyzer_state_graph::get_or_create_state_node (const region &reg)
     168              : {
     169          384 :   auto existing = m_region_to_state_node_map.find (&reg);
     170          384 :   if (existing != m_region_to_state_node_map.end ())
     171          187 :     return *existing->second;
     172              : 
     173          197 :   auto &state_node = create_and_add_state_node (reg);
     174          197 :   m_region_to_state_node_map[&reg] = &state_node;
     175          197 :   return state_node;
     176              : }
     177              : 
     178              : diagnostics::digraphs::node &
     179          197 : analyzer_state_graph::create_and_add_state_node (const region &reg)
     180              : {
     181          197 :   auto node = create_state_node (reg);
     182              : 
     183          197 :   diagnostics::digraphs::node &result = *node;
     184          197 :   if (auto parent_reg = reg.get_parent_region ())
     185          197 :     if (parent_reg->get_kind () != RK_ROOT)
     186              :       {
     187          127 :         auto &parent_state_node = get_or_create_state_node (*parent_reg);
     188          127 :         parent_state_node.add_child (std::move (node));
     189          127 :         return result;
     190              :       }
     191           70 :   add_node (std::move (node));
     192           70 :   return result;
     193          197 : }
     194              : 
     195              : std::string
     196          190 : analyzer_state_graph::make_node_id (const char *prefix)
     197              : {
     198          380 :   return std::string (prefix) + "-" + std::to_string (m_next_id++);
     199              : }
     200              : 
     201              : std::string
     202          313 : analyzer_state_graph::make_node_id (const region &reg)
     203              : {
     204          313 :   const char *prefix = nullptr;
     205          313 :   switch (reg.get_kind ())
     206              :     {
     207            0 :     case RK_ROOT:
     208            0 :     default:
     209            0 :       gcc_unreachable ();
     210           19 :       break;
     211              : 
     212           19 :     case RK_GLOBALS:
     213           19 :       return "globals";
     214            0 :     case RK_CODE:
     215            0 :       return "code";
     216           28 :     case RK_STACK:
     217           28 :       return "stack";
     218           23 :     case RK_HEAP:
     219           23 :       return "heap";
     220              : 
     221              :     case RK_FRAME:
     222              :       prefix = "frame-region";
     223              :       break;
     224            0 :     case RK_FUNCTION:
     225            0 :       prefix = "function-region";
     226            0 :       break;
     227            0 :     case RK_LABEL:
     228            0 :       prefix = "label-region";
     229            0 :       break;
     230            0 :     case RK_THREAD_LOCAL:
     231            0 :       prefix = "thread-local-region";
     232            0 :       break;
     233            0 :     case RK_SYMBOLIC:
     234            0 :       prefix = "symbolic-region";
     235            0 :       break;
     236           44 :     case RK_DECL:
     237           44 :       prefix = "decl-region";
     238           44 :       break;
     239           74 :     case RK_FIELD:
     240           74 :       prefix = "field-region";
     241           74 :       break;
     242            8 :     case RK_ELEMENT:
     243            8 :       prefix = "element-region";
     244            8 :       break;
     245            0 :     case RK_OFFSET:
     246            0 :       prefix = "offset-region";
     247            0 :       break;
     248            0 :     case RK_SIZED:
     249            0 :       prefix = "sized-region";
     250            0 :       break;
     251            0 :     case RK_CAST:
     252            0 :       prefix = "cast-region";
     253            0 :       break;
     254           44 :     case RK_HEAP_ALLOCATED:
     255           44 :       prefix = "heap-allocated-region";
     256           44 :       break;
     257            0 :     case RK_ALLOCA:
     258            0 :       prefix = "alloca-region";
     259            0 :       break;
     260            0 :     case RK_STRING:
     261            0 :       prefix = "string-region";
     262            0 :       break;
     263           34 :     case RK_BIT_RANGE:
     264           34 :       prefix = "bit-range-region";
     265           34 :       break;
     266            0 :     case RK_VAR_ARG:
     267            0 :       prefix = "var-arg-region";
     268            0 :       break;
     269            0 :     case RK_ERRNO:
     270            0 :       prefix = "errno-region";
     271            0 :       break;
     272            0 :     case RK_PRIVATE:
     273            0 :       prefix = "private-region";
     274            0 :       break;
     275            0 :     case RK_UNKNOWN:
     276            0 :       prefix = "unknown-region";
     277            0 :       break;
     278              :     }
     279          486 :   return std::string (prefix) + "-" + std::to_string (reg.get_id ());
     280              : }
     281              : 
     282              : std::unique_ptr<diagnostics::digraphs::node>
     283          503 : analyzer_state_graph::
     284              : make_state_node (enum node_properties::kind_t kind,
     285              :                  std::string id)
     286              : {
     287          503 :   auto node = std::make_unique<diagnostics::digraphs::node> (*this, std::move (id));
     288          503 :   node->set_property (node_properties::kind_prop, kind);
     289          503 :   return node;
     290              : }
     291              : 
     292              : std::unique_ptr<diagnostics::digraphs::node>
     293          114 : analyzer_state_graph::
     294              : make_memspace_state_node (const region &reg,
     295              :                           enum node_properties::kind_t kind)
     296              : {
     297          114 :   return make_state_node (kind, make_node_id (reg));
     298              : }
     299              : 
     300              : std::unique_ptr<diagnostics::digraphs::node>
     301          197 : analyzer_state_graph::create_state_node (const region &reg)
     302              : {
     303          197 :   std::unique_ptr<diagnostics::digraphs::node> node;
     304              : 
     305          197 :   switch (reg.get_kind ())
     306              :     {
     307            0 :     default:
     308            0 :       gcc_unreachable ();
     309              : 
     310           39 :     case RK_FRAME:
     311           39 :       {
     312           39 :         const frame_region &frame_reg
     313              :           = static_cast<const frame_region &> (reg);
     314              : 
     315           78 :         node = make_state_node (node_properties::kind_t::stack_frame,
     316           78 :                                 make_node_id (reg));
     317           39 :         node->set_logical_loc
     318           39 :           (m_logical_loc_mgr.key_from_tree (frame_reg.get_fndecl ()));
     319           39 :         {
     320           39 :           pretty_printer pp;
     321           39 :           pp_format_decoder (&pp) = default_tree_printer;
     322           39 :           pp_printf (&pp, "%E", frame_reg.get_fndecl ());
     323           39 :           node->set_property (node_properties::function,
     324              :                               pp_formatted_text (&pp));
     325           39 :         }
     326              :       }
     327           39 :       break;
     328              : 
     329           19 :     case RK_GLOBALS:
     330           19 :       node = make_memspace_state_node (reg,
     331           19 :                                        node_properties::kind_t::globals);
     332           19 :       break;
     333            0 :     case RK_CODE:
     334            0 :       node = make_memspace_state_node (reg,
     335            0 :                                        node_properties::kind_t::code);
     336            0 :       break;
     337            0 :     case RK_FUNCTION:
     338            0 :       node = make_memspace_state_node (reg,
     339            0 :                                        node_properties::kind_t::function);
     340              :       // TODO
     341            0 :       break;
     342              : 
     343           28 :     case RK_STACK:
     344           28 :       node = make_memspace_state_node (reg,
     345           28 :                                        node_properties::kind_t::stack);
     346           28 :       break;
     347           23 :     case RK_HEAP:
     348           23 :       node = make_memspace_state_node (reg,
     349           23 :                                        node_properties::kind_t::heap_);
     350           23 :       break;
     351            0 :     case RK_THREAD_LOCAL:
     352            0 :       node = make_memspace_state_node (reg,
     353            0 :                                        node_properties::kind_t::thread_local_);
     354            0 :       break;
     355            0 :     case RK_ROOT:
     356            0 :       gcc_unreachable ();
     357            0 :       break;
     358            0 :     case RK_SYMBOLIC:
     359            0 :       node = make_memspace_state_node (reg,
     360            0 :                                        node_properties::kind_t::other);
     361            0 :       break;
     362              : 
     363           44 :     case RK_DECL:
     364           44 :       {
     365           88 :         node = make_state_node (node_properties::kind_t::variable,
     366           88 :                                 make_node_id (reg));
     367           44 :         const decl_region &decl_reg
     368              :           = static_cast<const decl_region &> (reg);
     369              : 
     370           44 :         {
     371           44 :           pretty_printer pp;
     372           44 :           pp_format_decoder (&pp) = default_tree_printer;
     373           44 :           pp_printf (&pp, "%E", decl_reg.get_decl ());
     374           44 :           node->set_property (node_properties::name,
     375              :                               pp_formatted_text (&pp));
     376           44 :         }
     377           44 :         set_type_attr (*node, TREE_TYPE (decl_reg.get_decl ()));
     378              :       }
     379           44 :       break;
     380              : 
     381            0 :     case RK_FIELD:
     382            0 :     case RK_ELEMENT:
     383              :       /* These should be handled in populate_state_node_for_typed_region.  */
     384            0 :       gcc_unreachable ();
     385            0 :       break;
     386              : 
     387            0 :     case RK_LABEL:
     388            0 :     case RK_OFFSET:
     389            0 :     case RK_SIZED:
     390            0 :     case RK_CAST:
     391            0 :     case RK_STRING:
     392            0 :     case RK_BIT_RANGE:
     393            0 :     case RK_VAR_ARG:
     394            0 :     case RK_ERRNO:
     395            0 :     case RK_PRIVATE:
     396            0 :     case RK_UNKNOWN:
     397            0 :       node = make_state_node (node_properties::kind_t::other,
     398            0 :                                 make_node_id (reg));
     399            0 :       break;
     400              : 
     401           44 :     case RK_HEAP_ALLOCATED:
     402           44 :     case RK_ALLOCA:
     403           44 :       node
     404           44 :         = make_memspace_state_node (reg,
     405           44 :                                     node_properties::kind_t::dynalloc_buffer);
     406           44 :       set_attr_for_dynamic_extents (reg, *node);
     407           44 :       break;
     408              :     }
     409          197 :   gcc_assert (node);
     410              : 
     411          197 :   if (reg.get_base_region () == &reg)
     412          197 :     if (!reg.get_type ())
     413              :       {
     414          153 :         auto search
     415          153 :           = m_types_for_untyped_regions.find (&reg);
     416          153 :         if (search != m_types_for_untyped_regions.end ())
     417              :           {
     418           44 :             tree type_to_use = search->second;
     419           44 :             set_type_attr (*node, type_to_use);
     420              :           }
     421              :       }
     422              : 
     423          197 :   return node;
     424              : }
     425              : 
     426              : void
     427           78 : analyzer_state_graph::
     428              : create_state_nodes_for_binding_cluster (const binding_cluster &cluster,
     429              :                                         bool create_all)
     430              : {
     431              :   /* TODO:
     432              :      - symbolic bindings
     433              :      - get current svalue, so as to get "zeros" and "uninitialized".  */
     434              : 
     435           78 :   concrete_bindings_t conc_bindings;
     436          190 :   for (auto iter : cluster)
     437              :     {
     438          112 :       const binding_key *key = iter.m_key;
     439          112 :       const svalue *svalue = iter.m_sval;
     440          112 :       if (auto conc_key = key->dyn_cast_concrete_binding ())
     441          112 :         conc_bindings[conc_key->get_bit_range ()] = svalue;
     442          112 :       if (const region *reg = svalue->maybe_get_region ())
     443           48 :         get_or_create_state_node (*reg);
     444              :     }
     445              : 
     446           78 :   auto &ref = get_or_create_state_node (*cluster.get_base_region ());
     447              : 
     448           78 :   ref.add_child (create_state_node_for_conc_bindings (conc_bindings));
     449              : 
     450           78 :   const region *typed_reg = cluster.get_base_region ();
     451           78 :   if (!typed_reg->get_type ())
     452              :     {
     453           34 :       auto search
     454           34 :         = m_types_for_untyped_regions.find (cluster.get_base_region ());
     455           34 :       if (search != m_types_for_untyped_regions.end ())
     456              :         {
     457           34 :           tree type_to_use = search->second;
     458           34 :           typed_reg = m_mgr.get_cast_region (typed_reg, type_to_use);
     459              :         }
     460              :     }
     461              : 
     462           78 :   if (typed_reg->get_type ())
     463           78 :     populate_state_node_for_typed_region (ref,
     464              :                                           *typed_reg,
     465              :                                           conc_bindings,
     466              :                                           create_all);
     467              :   else
     468              :     {
     469              :       // TODO
     470              :     }
     471           78 : }
     472              : 
     473              : std::unique_ptr<diagnostics::digraphs::node>
     474           78 : analyzer_state_graph::create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings)
     475              : {
     476           78 :   auto node = make_state_node (node_properties::kind_t::other,
     477           78 :                                make_node_id ("concrete-bindings"));
     478          190 :   for (auto iter : conc_bindings)
     479              :     {
     480          112 :       const bit_range bits = iter.first;
     481          112 :       const svalue *sval = iter.second;
     482          112 :       auto binding_state_node
     483              :         = make_state_node (node_properties::kind_t::other,
     484          112 :                            make_node_id ("binding"));
     485          112 :       set_bits_attr (*binding_state_node, bits);
     486          112 :       gcc_assert (sval);
     487          112 :       set_value_attrs (*binding_state_node, *sval);
     488          112 :       node->add_child (std::move (binding_state_node));
     489          112 :     }
     490           78 :   return node;
     491              : }
     492              : 
     493              : // Try to get the bit_range of REG within its base region
     494              : bool
     495          298 : analyzer_state_graph::get_bit_range_within_base_region (const region &reg,
     496              :                                                         bit_range &out)
     497              : {
     498          298 :   region_offset start_offset = reg.get_offset (&m_mgr);
     499          298 :   if (!start_offset.concrete_p ())
     500              :     return false;
     501          298 :   region_offset next_offset = reg.get_next_offset (&m_mgr);
     502          298 :   if (!next_offset.concrete_p ())
     503              :     return false;
     504          596 :   out = bit_range (start_offset.get_bit_offset (),
     505          298 :                    next_offset.get_bit_offset ()
     506          596 :                    - start_offset.get_bit_offset ());
     507          298 :   return true;
     508              : }
     509              : 
     510              : void
     511          160 : analyzer_state_graph::
     512              : populate_state_node_for_typed_region (diagnostics::digraphs::node &state_node,
     513              :                                       const region &reg,
     514              :                                       const concrete_bindings_t &conc_bindings,
     515              :                                       bool create_all)
     516              : {
     517          160 :   const_tree reg_type = reg.get_type ();
     518          160 :   gcc_assert (reg_type);
     519          160 :   set_type_attr (state_node, reg_type);
     520              : 
     521          160 :   bit_range bits (0, 0);
     522          160 :   if (get_bit_range_within_base_region (reg, bits))
     523              :     {
     524          160 :       set_bits_attr (state_node, bits);
     525              : 
     526          160 :       auto search = conc_bindings.find (bits);
     527          160 :       if (search != conc_bindings.end ())
     528              :         {
     529          112 :           const svalue *bound_sval = search->second;
     530          112 :           gcc_assert (bound_sval);
     531          112 :           set_value_attrs (state_node, *bound_sval);
     532          112 :           if (const region *dst_reg = bound_sval->maybe_get_region ())
     533           48 :             m_pending_edges.push_back ({state_node, *dst_reg});
     534              :         }
     535              :     }
     536              : 
     537          160 :   switch (TREE_CODE (reg_type))
     538              :     {
     539              :     default:
     540              :       break;
     541              : 
     542            8 :     case ARRAY_TYPE:
     543            8 :       {
     544            8 :         tree domain = TYPE_DOMAIN (reg_type);
     545            8 :         if (!domain)
     546            0 :           return;
     547            8 :         const_tree max_idx = TYPE_MAX_VALUE (domain);
     548            8 :         if (!max_idx)
     549              :           return;
     550            8 :         if (TREE_CODE (max_idx) != INTEGER_CST)
     551              :           return;
     552            8 :         const_tree min_idx = TYPE_MIN_VALUE (domain);
     553            8 :         if (TREE_CODE (min_idx) != INTEGER_CST)
     554              :           return;
     555           30 :         for (offset_int idx = wi::to_offset (min_idx);
     556           30 :              idx <= wi::to_offset (max_idx);
     557           22 :              ++idx)
     558              :           {
     559           22 :             const_tree element_type = TREE_TYPE (reg_type);
     560           22 :             const svalue *sval_index
     561           22 :               = m_mgr.get_or_create_int_cst (domain, idx);
     562           22 :             const region *child_reg
     563           22 :               = m_mgr.get_element_region (&reg,
     564              :                                           const_cast<tree> (element_type),
     565              :                                           sval_index);
     566           22 :             if (show_child_state_node_for_child_region_p (*child_reg,
     567              :                                                        conc_bindings,
     568              :                                                        create_all))
     569              :               {
     570            8 :                 auto child_state_node
     571              :                   = make_state_node
     572              :                       (node_properties::kind_t::element,
     573            8 :                        make_node_id (*child_reg));
     574            8 :                 set_wi_attr (*child_state_node,
     575            8 :                              node_properties::index, idx, UNSIGNED);
     576              : 
     577              :                 // Recurse:
     578            8 :                 gcc_assert (element_type);
     579            8 :                 populate_state_node_for_typed_region (*child_state_node,
     580              :                                                       *child_reg,
     581              :                                                       conc_bindings,
     582              :                                                       create_all);
     583            8 :                 state_node.add_child (std::move (child_state_node));
     584            8 :               }
     585              :           }
     586              :       }
     587            8 :       break;
     588              : 
     589           40 :     case RECORD_TYPE:
     590           40 :       {
     591           40 :         const record_layout layout (reg_type);
     592          236 :         for (auto item : layout)
     593              :           {
     594          116 :             if (item.m_is_padding)
     595              :               {
     596           36 :                 const bit_range bits (0, item.m_bit_range.m_size_in_bits);
     597           36 :                 const region *child_reg
     598           36 :                   = m_mgr.get_bit_range (&reg, NULL_TREE, bits);
     599           36 :                 if (show_child_state_node_for_child_region_p (*child_reg,
     600              :                                                               conc_bindings,
     601              :                                                               create_all))
     602              :                   {
     603           34 :                     auto child_state_node
     604              :                       = make_state_node
     605              :                           (node_properties::kind_t::padding,
     606           34 :                            make_node_id (*child_reg));
     607           34 :                     set_wi_attr (*child_state_node,
     608              :                                  node_properties::num_bits,
     609           34 :                                  item.m_bit_range.m_size_in_bits, SIGNED);
     610           34 :                     state_node.add_child (std::move (child_state_node));
     611           34 :                   }
     612              :               }
     613              :             else
     614              :               {
     615           80 :                 const region *child_reg
     616          160 :                   = m_mgr.get_field_region (&reg,
     617           80 :                                             const_cast<tree> (item.m_field));
     618           80 :                 if (show_child_state_node_for_child_region_p (*child_reg,
     619              :                                                               conc_bindings,
     620              :                                                               create_all))
     621              :                   {
     622           74 :                     auto child_state_node
     623              :                       = make_state_node
     624              :                           (node_properties::kind_t::field,
     625           74 :                            make_node_id (*child_reg));
     626           74 :                     {
     627           74 :                       pretty_printer pp;
     628           74 :                       pp_format_decoder (&pp) = default_tree_printer;
     629           74 :                       pp_printf (&pp, "%D", item.m_field);
     630           74 :                       child_state_node->set_property (node_properties::name,
     631              :                                                       pp_formatted_text (&pp));
     632           74 :                     }
     633              : 
     634              :                     // Recurse:
     635           74 :                     populate_state_node_for_typed_region (*child_state_node,
     636              :                                                           *child_reg,
     637              :                                                           conc_bindings,
     638              :                                                           create_all);
     639           74 :                     state_node.add_child (std::move (child_state_node));
     640           74 :                   }
     641              :               }
     642              :           }
     643           40 :       }
     644           40 :       break;
     645              :     }
     646              : }
     647              : 
     648              : void
     649           44 : analyzer_state_graph::
     650              : set_attr_for_dynamic_extents (const region &reg,
     651              :                               diagnostics::digraphs::node &state_node)
     652              : {
     653           44 :   const svalue *sval = m_state.m_region_model->get_dynamic_extents (&reg);
     654           44 :   if (sval)
     655              :     {
     656           42 :       pretty_printer pp;
     657           42 :       pp_format_decoder (&pp) = default_tree_printer;
     658           42 :       if (auto cst = sval->maybe_get_constant ())
     659           42 :         pp_wide_int (&pp, wi::to_wide (cst), UNSIGNED);
     660              :       else
     661            0 :         sval->dump_to_pp (&pp, true);
     662           42 :       state_node.set_property (state_node_properties::dynamic_extents,
     663              :                                pp_formatted_text (&pp));
     664           42 :     }
     665           44 : }
     666              : 
     667              : bool
     668          138 : analyzer_state_graph::
     669              : show_child_state_node_for_child_region_p (const region &reg,
     670              :                                           const concrete_bindings_t &conc_bindings,
     671              :                                           bool create_all)
     672              : {
     673          138 :   if (create_all)
     674              :     return true;
     675          138 :   bit_range reg_bits (0, 0);
     676          138 :   if (!get_bit_range_within_base_region (reg, reg_bits))
     677              :     return true;
     678              : 
     679              :   /* Is any of "bits" bound?
     680              :      TODO: ideally there would be a more efficient way to do this, using
     681              :      spatial relationships.  */
     682          194 :   for (auto iter : conc_bindings)
     683              :     {
     684          172 :       const bit_range bound_bits = iter.first;
     685          172 :       if (bound_bits.intersects_p (reg_bits))
     686          116 :         return true;
     687              :     }
     688              :   return false;
     689              : }
     690              : 
     691              : std::unique_ptr<diagnostics::digraphs::digraph>
     692           28 : program_state::
     693              : make_diagnostic_state_graph (const extrinsic_state &ext_state) const
     694              : {
     695           28 :   return std::make_unique<analyzer_state_graph> (*this, ext_state);
     696              : }
     697              : 
     698              : void
     699            0 : program_state::dump_sarif (const extrinsic_state &ext_state) const
     700              : {
     701            0 :   auto g = make_diagnostic_state_graph (ext_state);
     702            0 :   g->dump ();
     703            0 : }
     704              : 
     705              : } // namespace ana
     706              : 
     707              : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.