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 : : 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 : 274 : set_type_attr (diagnostics::digraphs::node &state_node,
57 : : const_tree type)
58 : : {
59 : 274 : gcc_assert (type);
60 : 274 : pretty_printer pp;
61 : 274 : pp_format_decoder (&pp) = default_tree_printer;
62 : 274 : pp_printf (&pp, "%T", type);
63 : 274 : state_node.set_property (node_properties::type,
64 : : pp_formatted_text (&pp));
65 : 274 : }
66 : :
67 : : static void
68 : 298 : set_bits_attr (diagnostics::digraphs::node & state_node,
69 : : bit_range bits)
70 : : {
71 : 298 : pretty_printer pp;
72 : 298 : bits.dump_to_pp (&pp);
73 : 298 : state_node.set_property (node_properties::bits,
74 : : pp_formatted_text (&pp));
75 : 298 : }
76 : :
77 : : static void
78 : 250 : set_value_attrs (diagnostics::digraphs::node &state_node,
79 : : const svalue &sval)
80 : : {
81 : 250 : state_node.set_property (node_properties::value,
82 : 500 : sval.to_json ());
83 : 250 : pretty_printer pp;
84 : 250 : pp_format_decoder (&pp) = default_tree_printer;
85 : 250 : sval.dump_to_pp (&pp, true);
86 : 250 : state_node.set_property (node_properties::value_str,
87 : : pp_formatted_text (&pp));
88 : 250 : }
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 : 210 : for (auto cluster_iter : *state.m_region_model->get_store ())
104 : 216 : for (auto binding_iter : *cluster_iter.second)
105 : : {
106 : 125 : const svalue *svalue = binding_iter.m_sval;
107 : 125 : if (const region *reg = svalue->maybe_get_region ())
108 : 47 : if (svalue->get_type () && !reg->get_type ())
109 : : {
110 : 47 : tree pointed_to_type = TREE_TYPE (svalue->get_type ());
111 : 47 : if (!VOID_TYPE_P (pointed_to_type))
112 : 47 : 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 : 119 : for (auto iter : *state.m_region_model->get_store ())
132 : : {
133 : 91 : const bool create_all = false; // "true" for verbose, for debugging
134 : 91 : 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 : 75 : while (m_pending_edges.size () > 0)
155 : : {
156 : 47 : pending_edge item = m_pending_edges.back ();
157 : 47 : 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 : 47 : auto &dst_node = get_or_create_state_node (item.m_dst_reg);
162 : 47 : add_edge (nullptr, item.m_src_node, dst_node);
163 : : }
164 : 28 : }
165 : :
166 : : diagnostics::digraphs::node &
167 : 408 : analyzer_state_graph::get_or_create_state_node (const region ®)
168 : : {
169 : 408 : auto existing = m_region_to_state_node_map.find (®);
170 : 408 : if (existing != m_region_to_state_node_map.end ())
171 : 198 : return *existing->second;
172 : :
173 : 210 : auto &state_node = create_and_add_state_node (reg);
174 : 210 : m_region_to_state_node_map[®] = &state_node;
175 : 210 : return state_node;
176 : : }
177 : :
178 : : diagnostics::digraphs::node &
179 : 210 : analyzer_state_graph::create_and_add_state_node (const region ®)
180 : : {
181 : 210 : auto node = create_state_node (reg);
182 : :
183 : 210 : diagnostics::digraphs::node &result = *node;
184 : 210 : if (auto parent_reg = reg.get_parent_region ())
185 : 210 : if (parent_reg->get_kind () != RK_ROOT)
186 : : {
187 : 140 : auto &parent_state_node = get_or_create_state_node (*parent_reg);
188 : 140 : parent_state_node.add_child (std::move (node));
189 : 140 : return result;
190 : : }
191 : 70 : add_node (std::move (node));
192 : 70 : return result;
193 : 210 : }
194 : :
195 : : std::string
196 : 216 : analyzer_state_graph::make_node_id (const char *prefix)
197 : : {
198 : 432 : return std::string (prefix) + "-" + std::to_string (m_next_id++);
199 : : }
200 : :
201 : : std::string
202 : 326 : analyzer_state_graph::make_node_id (const region ®)
203 : : {
204 : 326 : const char *prefix = nullptr;
205 : 326 : 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 : 57 : case RK_DECL:
237 : 57 : prefix = "decl-region";
238 : 57 : 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 : 512 : return std::string (prefix) + "-" + std::to_string (reg.get_id ());
280 : : }
281 : :
282 : : std::unique_ptr<diagnostics::digraphs::node>
283 : 542 : analyzer_state_graph::
284 : : make_state_node (enum node_properties::kind_t kind,
285 : : std::string id)
286 : : {
287 : 542 : auto node = std::make_unique<diagnostics::digraphs::node> (*this, std::move (id));
288 : 542 : node->set_property (node_properties::kind_prop, kind);
289 : 542 : 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 : 210 : analyzer_state_graph::create_state_node (const region ®)
302 : : {
303 : 210 : std::unique_ptr<diagnostics::digraphs::node> node;
304 : :
305 : 210 : 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 : 57 : case RK_DECL:
364 : 57 : {
365 : 114 : node = make_state_node (node_properties::kind_t::variable,
366 : 114 : make_node_id (reg));
367 : 57 : const decl_region &decl_reg
368 : : = static_cast<const decl_region &> (reg);
369 : :
370 : 57 : {
371 : 57 : pretty_printer pp;
372 : 57 : pp_format_decoder (&pp) = default_tree_printer;
373 : 57 : pp_printf (&pp, "%E", decl_reg.get_decl ());
374 : 57 : node->set_property (node_properties::name,
375 : : pp_formatted_text (&pp));
376 : 57 : }
377 : 57 : set_type_attr (*node, TREE_TYPE (decl_reg.get_decl ()));
378 : : }
379 : 57 : 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 : 210 : gcc_assert (node);
410 : :
411 : 210 : if (reg.get_base_region () == ®)
412 : 210 : 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 : 210 : return node;
424 : : }
425 : :
426 : : void
427 : 91 : 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 : 91 : concrete_bindings_t conc_bindings;
436 : 216 : for (auto iter : cluster)
437 : : {
438 : 125 : const binding_key *key = iter.m_key;
439 : 125 : const svalue *svalue = iter.m_sval;
440 : 125 : if (auto conc_key = key->dyn_cast_concrete_binding ())
441 : 125 : conc_bindings[conc_key->get_bit_range ()] = svalue;
442 : 125 : if (const region *reg = svalue->maybe_get_region ())
443 : 47 : get_or_create_state_node (*reg);
444 : : }
445 : :
446 : 91 : auto &ref = get_or_create_state_node (*cluster.get_base_region ());
447 : :
448 : 91 : ref.add_child (create_state_node_for_conc_bindings (conc_bindings));
449 : :
450 : 91 : const region *typed_reg = cluster.get_base_region ();
451 : 91 : 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 : 91 : if (typed_reg->get_type ())
463 : 91 : populate_state_node_for_typed_region (ref,
464 : : *typed_reg,
465 : : conc_bindings,
466 : : create_all);
467 : : else
468 : : {
469 : : // TODO
470 : : }
471 : 91 : }
472 : :
473 : : std::unique_ptr<diagnostics::digraphs::node>
474 : 91 : analyzer_state_graph::create_state_node_for_conc_bindings (const concrete_bindings_t &conc_bindings)
475 : : {
476 : 91 : auto node = make_state_node (node_properties::kind_t::other,
477 : 91 : make_node_id ("concrete-bindings"));
478 : 216 : for (auto iter : conc_bindings)
479 : : {
480 : 125 : const bit_range bits = iter.first;
481 : 125 : const svalue *sval = iter.second;
482 : 125 : auto binding_state_node
483 : : = make_state_node (node_properties::kind_t::other,
484 : 125 : make_node_id ("binding"));
485 : 125 : set_bits_attr (*binding_state_node, bits);
486 : 125 : gcc_assert (sval);
487 : 125 : set_value_attrs (*binding_state_node, *sval);
488 : 125 : node->add_child (std::move (binding_state_node));
489 : 125 : }
490 : 91 : return node;
491 : : }
492 : :
493 : : // Try to get the bit_range of REG within its base region
494 : : bool
495 : 311 : analyzer_state_graph::get_bit_range_within_base_region (const region ®,
496 : : bit_range &out)
497 : : {
498 : 311 : region_offset start_offset = reg.get_offset (&m_mgr);
499 : 311 : if (!start_offset.concrete_p ())
500 : : return false;
501 : 311 : region_offset next_offset = reg.get_next_offset (&m_mgr);
502 : 311 : if (!next_offset.concrete_p ())
503 : : return false;
504 : 622 : out = bit_range (start_offset.get_bit_offset (),
505 : 311 : next_offset.get_bit_offset ()
506 : 622 : - start_offset.get_bit_offset ());
507 : 311 : return true;
508 : : }
509 : :
510 : : void
511 : 173 : 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 : 173 : const_tree reg_type = reg.get_type ();
518 : 173 : gcc_assert (reg_type);
519 : 173 : set_type_attr (state_node, reg_type);
520 : :
521 : 173 : bit_range bits (0, 0);
522 : 173 : if (get_bit_range_within_base_region (reg, bits))
523 : : {
524 : 173 : set_bits_attr (state_node, bits);
525 : :
526 : 173 : auto search = conc_bindings.find (bits);
527 : 173 : if (search != conc_bindings.end ())
528 : : {
529 : 125 : const svalue *bound_sval = search->second;
530 : 125 : gcc_assert (bound_sval);
531 : 125 : set_value_attrs (state_node, *bound_sval);
532 : 125 : if (const region *dst_reg = bound_sval->maybe_get_region ())
533 : 47 : m_pending_edges.push_back ({state_node, *dst_reg});
534 : : }
535 : : }
536 : :
537 : 173 : 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 */
|