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 ®)
168 : {
169 384 : auto existing = m_region_to_state_node_map.find (®);
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[®] = &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 ®)
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 ®)
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 ®,
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 ®)
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 () == ®)
412 197 : if (!reg.get_type ())
413 : {
414 153 : auto search
415 153 : = m_types_for_untyped_regions.find (®);
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 ®,
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 ®,
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 (®,
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 (®, 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 (®,
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 ®,
651 : diagnostics::digraphs::node &state_node)
652 : {
653 44 : const svalue *sval = m_state.m_region_model->get_dynamic_extents (®);
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 ®,
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 */
|