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