1/* Classes for working with summaries of function calls.
2 Copyright (C) 2022 David Malcolm <dmalcolm@redhat.com>.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 3, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20#include "config.h"
21#define INCLUDE_MEMORY
22#include "system.h"
23#include "coretypes.h"
24#include "tree.h"
25#include "tree-dfa.h"
26#include "diagnostic-core.h"
27#include "diagnostic.h"
28#include "tree-diagnostic.h"
29#include "analyzer/analyzer.h"
30#include "analyzer/region-model.h"
31#include "analyzer/call-summary.h"
32#include "analyzer/exploded-graph.h"
33
34#if ENABLE_ANALYZER
35
36namespace ana {
37
38/* class call_summary. */
39
40const program_state &
41call_summary::get_state () const
42{
43 return m_enode->get_state ();
44}
45
46tree
47call_summary::get_fndecl () const
48{
49 return m_enode->get_point ().get_fndecl ();
50}
51
52label_text
53call_summary::get_desc () const
54{
55 pretty_printer pp;
56 pp_format_decoder (&pp) = default_tree_printer;
57
58 get_user_facing_desc (pp: &pp);
59 if (flag_analyzer_verbose_edges)
60 pp_printf (&pp, " (call summary; EN: %i)", m_enode->m_index);
61
62 return label_text::take (buffer: xstrdup (pp_formatted_text (&pp)));
63}
64
65/* Generate a user-facing description of this call summary.c
66 This has various heuristics for distinguishing between different
67 summaries.
68 This will help with debugging, too. */
69
70void
71call_summary::get_user_facing_desc (pretty_printer *pp) const
72{
73 tree fndecl = get_fndecl ();
74
75 /* If there are multiple summaries, try to use the return value to
76 distinguish between them. */
77 if (m_per_fn_data->m_summaries.length () > 1)
78 {
79 if (tree result = DECL_RESULT (fndecl))
80 {
81 const region *result_reg
82 = get_state ().m_region_model->get_lvalue (expr: result, NULL);
83 const svalue *result_sval
84 = get_state ().m_region_model->get_store_value (reg: result_reg, NULL);
85 switch (result_sval->get_kind ())
86 {
87 default:
88 break;
89 case SK_REGION:
90 {
91 const region_svalue *region_sval
92 = as_a <const region_svalue *> (p: result_sval);
93 const region *pointee_reg = region_sval->get_pointee ();
94 switch (pointee_reg->get_kind ())
95 {
96 default:
97 break;
98 case RK_HEAP_ALLOCATED:
99 pp_printf (pp,
100 "when %qE returns pointer"
101 " to heap-allocated buffer",
102 fndecl);
103 return;
104 }
105 }
106 break;
107 case SK_CONSTANT:
108 {
109 const constant_svalue *constant_sval
110 = as_a <const constant_svalue *> (p: result_sval);
111 tree cst = constant_sval->get_constant ();
112 if (POINTER_TYPE_P (TREE_TYPE (result))
113 && zerop (cst))
114 pp_printf (pp, "when %qE returns NULL", fndecl);
115 else
116 pp_printf (pp, "when %qE returns %qE", fndecl, cst);
117 return;
118 }
119 }
120 }
121 }
122
123 /* Fallback. */
124 pp_printf (pp, "when %qE returns", fndecl);
125}
126
127/* Dump a multiline representation of this object to PP. */
128
129void
130call_summary::dump_to_pp (const extrinsic_state &ext_state,
131 pretty_printer *pp,
132 bool simple) const
133{
134 label_text desc = get_desc ();
135 pp_printf (pp, "desc: %qs", desc.get ());
136 pp_newline (pp);
137
138 get_state ().dump_to_pp (ext_state, simple, multiline: true, pp);
139}
140
141/* Dump a multiline representation of this object to FILE. */
142
143void
144call_summary::dump (const extrinsic_state &ext_state,
145 FILE *fp,
146 bool simple) const
147{
148 pretty_printer pp;
149 pp_format_decoder (&pp) = default_tree_printer;
150 pp_show_color (&pp) = pp_show_color (global_dc->printer);
151 pp.buffer->stream = fp;
152 dump_to_pp (ext_state, pp: &pp, simple);
153 pp_flush (&pp);
154}
155
156/* Dump a multiline representation of this object to stderr. */
157
158DEBUG_FUNCTION void
159call_summary::dump (const extrinsic_state &ext_state, bool simple) const
160{
161 dump (ext_state, stderr, simple);
162}
163
164/* class call_summary_replay. */
165
166/* call_summary_replay's ctor.
167 Populate the cache with params for the summary based on
168 arguments at the caller. */
169
170call_summary_replay::call_summary_replay (const call_details &cd,
171 const function &called_fn,
172 call_summary *summary,
173 const extrinsic_state &ext_state)
174: m_cd (cd),
175 m_summary (summary),
176 m_ext_state (ext_state)
177{
178 region_model_manager *mgr = cd.get_manager ();
179
180 // populate params based on args
181 tree fndecl = called_fn.decl;
182
183 /* Get a frame_region for use with respect to the summary.
184 This will be a top-level frame, since that's what's in
185 the summary. */
186 const frame_region *summary_frame
187 = mgr->get_frame_region (NULL, fun: called_fn);
188
189 unsigned idx = 0;
190 for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
191 iter_parm = DECL_CHAIN (iter_parm), ++idx)
192 {
193 /* If there's a mismatching declaration, the call stmt might
194 not have enough args. Handle this case by leaving the
195 rest of the params as uninitialized. */
196 if (idx >= cd.num_args ())
197 break;
198 const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
199 tree parm_lval = iter_parm;
200 if (tree parm_default_ssa = get_ssa_default_def (fun: called_fn, var: iter_parm))
201 parm_lval = parm_default_ssa;
202 const region *summary_parm_reg
203 = summary_frame->get_region_for_local (mgr, expr: parm_lval, ctxt: cd.get_ctxt ());
204 const svalue *summary_initial_parm_reg
205 = mgr->get_or_create_initial_value (reg: summary_parm_reg);
206 add_svalue_mapping (summary_sval: summary_initial_parm_reg, caller_sval: caller_arg_sval);
207 }
208
209 /* Handle any variadic args. */
210 unsigned va_arg_idx = 0;
211 for (; idx < cd.num_args (); idx++, va_arg_idx++)
212 {
213 const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
214 const region *summary_var_arg_reg
215 = mgr->get_var_arg_region (parent: summary_frame, idx: va_arg_idx);
216 const svalue *summary_initial_var_arg_reg
217 = mgr->get_or_create_initial_value (reg: summary_var_arg_reg);
218 add_svalue_mapping (summary_sval: summary_initial_var_arg_reg, caller_sval: caller_arg_sval);
219 }
220}
221
222/* Try to convert SUMMARY_SVAL in the summary to a corresponding svalue
223 in the caller, caching the result.
224
225 Return NULL if the conversion is not possible. */
226
227const svalue *
228call_summary_replay::convert_svalue_from_summary (const svalue *summary_sval)
229{
230 gcc_assert (summary_sval);
231
232 if (const svalue **slot
233 = m_map_svalue_from_summary_to_caller.get (k: summary_sval))
234 return *slot;
235
236 const svalue *caller_sval = convert_svalue_from_summary_1 (summary_sval);
237
238 if (caller_sval)
239 if (summary_sval->get_type () && caller_sval->get_type ())
240 gcc_assert (types_compatible_p (summary_sval->get_type (),
241 caller_sval->get_type ()));
242
243 /* Add to cache. */
244 add_svalue_mapping (summary_sval, caller_sval);
245
246 return caller_sval;
247}
248
249/* Implementation of call_summary_replay::convert_svalue_from_summary. */
250
251const svalue *
252call_summary_replay::convert_svalue_from_summary_1 (const svalue *summary_sval)
253{
254 gcc_assert (summary_sval);
255
256 switch (summary_sval->get_kind ())
257 {
258 default:
259 gcc_unreachable ();
260 case SK_REGION:
261 {
262 const region_svalue *region_summary_sval
263 = as_a <const region_svalue *> (p: summary_sval);
264 const region *summary_reg = region_summary_sval->get_pointee ();
265 const region *caller_reg = convert_region_from_summary (summary_reg);
266 if (!caller_reg)
267 return NULL;
268 region_model_manager *mgr = get_manager ();
269 const svalue *caller_ptr
270 = mgr->get_ptr_svalue (ptr_type: summary_sval->get_type (),
271 pointee: caller_reg);
272 return caller_ptr;
273 }
274 break;
275
276 case SK_CONSTANT:
277 case SK_PLACEHOLDER:
278 case SK_POISONED:
279 case SK_UNKNOWN:
280 return summary_sval;
281
282 case SK_SETJMP:
283 return NULL; // TODO
284
285 case SK_INITIAL:
286 {
287 const initial_svalue *initial_summary_sval
288 = as_a <const initial_svalue *> (p: summary_sval);
289 /* Params should already be in the cache, courtesy of the ctor. */
290 gcc_assert (!initial_summary_sval->initial_value_of_param_p ());
291
292 /* Initial value of region within the summary is the value of the
293 region at the point of the call. */
294 const region *summary_reg = initial_summary_sval->get_region ();
295 const region *caller_reg = convert_region_from_summary (summary_reg);
296 if (!caller_reg)
297 return NULL;
298 const svalue *caller_sval
299 = m_cd.get_model ()->get_store_value (reg: caller_reg, ctxt: m_cd.get_ctxt ());
300 return caller_sval;
301 }
302 break;
303 case SK_UNARYOP:
304 {
305 const unaryop_svalue *unaryop_summary_sval
306 = as_a <const unaryop_svalue *> (p: summary_sval);
307 const svalue *summary_arg = unaryop_summary_sval->get_arg ();
308 const svalue *caller_arg = convert_svalue_from_summary (summary_sval: summary_arg);
309 if (!caller_arg)
310 return NULL;
311 region_model_manager *mgr = get_manager ();
312 return mgr->get_or_create_unaryop (type: summary_sval->get_type (),
313 op: unaryop_summary_sval->get_op (),
314 arg: caller_arg);
315 }
316 break;
317 case SK_BINOP:
318 {
319 const binop_svalue *binop_summary_sval
320 = as_a <const binop_svalue *> (p: summary_sval);
321 const svalue *summary_arg0 = binop_summary_sval->get_arg0 ();
322 const svalue *caller_arg0 = convert_svalue_from_summary (summary_sval: summary_arg0);
323 if (!caller_arg0)
324 return NULL;
325 const svalue *summary_arg1 = binop_summary_sval->get_arg1 ();
326 const svalue *caller_arg1 = convert_svalue_from_summary (summary_sval: summary_arg1);
327 if (!caller_arg1)
328 return NULL;
329 region_model_manager *mgr = get_manager ();
330 return mgr->get_or_create_binop (type: summary_sval->get_type (),
331 op: binop_summary_sval->get_op (),
332 arg0: caller_arg0,
333 arg1: caller_arg1);
334 }
335 break;
336 case SK_SUB:
337 {
338 const sub_svalue *sub_summary_sval
339 = as_a <const sub_svalue *> (p: summary_sval);
340 region_model_manager *mgr = get_manager ();
341 const svalue *summary_parent_sval = sub_summary_sval->get_parent ();
342 if (!summary_parent_sval)
343 return NULL;
344 const region *summary_subregion = sub_summary_sval->get_subregion ();
345 if (!summary_subregion)
346 return NULL;
347 return mgr->get_or_create_sub_svalue (type: summary_sval->get_type (),
348 parent_svalue: summary_parent_sval,
349 subregion: summary_subregion);
350 }
351 break;
352 case SK_REPEATED:
353 {
354 const repeated_svalue *repeated_summary_sval
355 = as_a <const repeated_svalue *> (p: summary_sval);
356 const svalue *summary_outer_size
357 = repeated_summary_sval->get_outer_size ();
358 const svalue *caller_outer_size
359 = convert_svalue_from_summary (summary_sval: summary_outer_size);
360 if (!caller_outer_size)
361 return NULL;
362 const svalue *summary_inner_sval
363 = repeated_summary_sval->get_inner_svalue ();
364 const svalue *caller_inner_sval
365 = convert_svalue_from_summary (summary_sval: summary_inner_sval);
366 if (!caller_inner_sval)
367 return NULL;
368 region_model_manager *mgr = get_manager ();
369 return mgr->get_or_create_repeated_svalue (type: summary_sval->get_type (),
370 outer_size: caller_outer_size,
371 inner_svalue: caller_inner_sval);
372 }
373 break;
374 case SK_BITS_WITHIN:
375 {
376 const bits_within_svalue *bits_within_summary_sval
377 = as_a <const bits_within_svalue *> (p: summary_sval);
378 const bit_range &bits = bits_within_summary_sval->get_bits ();
379 const svalue *summary_inner_sval
380 = bits_within_summary_sval->get_inner_svalue ();
381 const svalue *caller_inner_sval
382 = convert_svalue_from_summary (summary_sval: summary_inner_sval);
383 if (!caller_inner_sval)
384 return NULL;
385 region_model_manager *mgr = get_manager ();
386 return mgr->get_or_create_bits_within (type: summary_sval->get_type (),
387 bits,
388 inner_svalue: caller_inner_sval);
389 }
390 break;
391 case SK_UNMERGEABLE:
392 {
393 const unmergeable_svalue *unmergeable_summary_sval
394 = as_a <const unmergeable_svalue *> (p: summary_sval);
395 const svalue *summary_arg_sval = unmergeable_summary_sval->get_arg ();
396 const svalue *caller_arg_sval
397 = convert_svalue_from_summary (summary_sval: summary_arg_sval);
398 if (!caller_arg_sval)
399 return NULL;
400 region_model_manager *mgr = get_manager ();
401 return mgr->get_or_create_unmergeable (arg: caller_arg_sval);
402 }
403 break;
404 case SK_WIDENING:
405 {
406 const widening_svalue *widening_summary_sval
407 = as_a <const widening_svalue *> (p: summary_sval);
408 const function_point &point = widening_summary_sval->get_point ();
409 const svalue *summary_base_sval
410 = widening_summary_sval->get_base_svalue ();
411 const svalue *caller_base_sval
412 = convert_svalue_from_summary (summary_sval: summary_base_sval);
413 if (!(caller_base_sval
414 && caller_base_sval->can_have_associated_state_p ()))
415 return NULL;
416 const svalue *summary_iter_sval
417 = widening_summary_sval->get_iter_svalue ();
418 const svalue *caller_iter_sval
419 = convert_svalue_from_summary (summary_sval: summary_iter_sval);
420 if (!(caller_iter_sval
421 && caller_iter_sval->can_have_associated_state_p ()))
422 return NULL;
423 region_model_manager *mgr = get_manager ();
424 return mgr->get_or_create_widening_svalue
425 (type: summary_iter_sval->get_type (),
426 point,
427 base_svalue: caller_base_sval,
428 iter_svalue: caller_iter_sval);
429 }
430 break;
431 case SK_COMPOUND:
432 {
433 const compound_svalue *compound_summary_sval
434 = as_a <const compound_svalue *> (p: summary_sval);
435 region_model_manager *mgr = get_manager ();
436 store_manager *store_mgr = mgr->get_store_manager ();
437 binding_map caller_map;
438 auto_vec <const binding_key *> summary_keys;
439 for (auto kv : *compound_summary_sval)
440 summary_keys.safe_push (obj: kv.first);
441 summary_keys.qsort (binding_key::cmp_ptrs);
442 for (auto key : summary_keys)
443 {
444 gcc_assert (key->concrete_p ());
445 /* No remapping is needed for concrete binding keys. */
446
447 const svalue *bound_summary_sval
448 = compound_summary_sval->get_map ().get (key);
449 const svalue *caller_sval
450 = convert_svalue_from_summary (summary_sval: bound_summary_sval);
451 if (!caller_sval)
452 caller_sval = mgr->get_or_create_unknown_svalue (NULL_TREE);
453
454 if (const compound_svalue *inner_compound_sval
455 = caller_sval->dyn_cast_compound_svalue ())
456 {
457 const concrete_binding *outer_key
458 = as_a <const concrete_binding *> (p: key);
459 for (auto inner_kv : *inner_compound_sval)
460 {
461 // These should already be mapped to the caller.
462 const binding_key *inner_key = inner_kv.first;
463 const svalue *inner_sval = inner_kv.second;
464 gcc_assert (inner_key->concrete_p ());
465 const concrete_binding *concrete_key
466 = as_a <const concrete_binding *> (p: inner_key);
467 bit_offset_t effective_start
468 = (concrete_key->get_start_bit_offset ()
469 + outer_key->get_start_bit_offset ());
470 const concrete_binding *effective_concrete_key
471 = store_mgr->get_concrete_binding
472 (start_bit_offset: effective_start,
473 size_in_bits: concrete_key->get_size_in_bits ());
474 caller_map.put (k: effective_concrete_key, v: inner_sval);
475 }
476 }
477 else
478 caller_map.put (k: key, v: caller_sval);
479 }
480 return mgr->get_or_create_compound_svalue (type: summary_sval->get_type (),
481 map: caller_map);
482 }
483 break;
484 case SK_CONJURED:
485 {
486 region_model_manager *mgr = get_manager ();
487 return mgr->get_or_create_unknown_svalue (type: summary_sval->get_type ());
488 }
489 break;
490 case SK_ASM_OUTPUT:
491 {
492 const asm_output_svalue *asm_output_summary_sval
493 = as_a <const asm_output_svalue *> (p: summary_sval);
494 const char *asm_string = asm_output_summary_sval->get_asm_string ();
495 unsigned output_idx = asm_output_summary_sval->get_output_idx ();
496 unsigned num_inputs = asm_output_summary_sval->get_num_inputs ();
497 unsigned num_outputs = asm_output_summary_sval->get_num_outputs ();
498 auto_vec<const svalue *> inputs (num_inputs);
499 for (unsigned idx = 0; idx < num_inputs; idx++)
500 {
501 const svalue *summary_input
502 = asm_output_summary_sval->get_input (idx);
503 const svalue *caller_input
504 = convert_svalue_from_summary (summary_sval: summary_input);
505 if (!caller_input)
506 return NULL;
507 inputs.safe_push (obj: caller_input);
508 }
509 region_model_manager *mgr = get_manager ();
510 return mgr->get_or_create_asm_output_svalue (type: summary_sval->get_type (),
511 asm_string,
512 output_idx,
513 num_outputs,
514 inputs);
515 }
516 break;
517 case SK_CONST_FN_RESULT:
518 {
519 const const_fn_result_svalue *const_fn_result_summary_sval
520 = as_a <const const_fn_result_svalue *> (p: summary_sval);
521 tree fndecl = const_fn_result_summary_sval->get_fndecl ();
522 unsigned num_inputs = const_fn_result_summary_sval->get_num_inputs ();
523 auto_vec<const svalue *> inputs (num_inputs);
524 for (unsigned idx = 0; idx < num_inputs; idx++)
525 {
526 const svalue *summary_input
527 = const_fn_result_summary_sval->get_input (idx);
528 const svalue *caller_input
529 = convert_svalue_from_summary (summary_sval: summary_input);
530 if (!caller_input)
531 return NULL;
532 inputs.safe_push (obj: caller_input);
533 }
534 region_model_manager *mgr = get_manager ();
535 return mgr->get_or_create_const_fn_result_svalue
536 (type: summary_sval->get_type (),
537 fndecl,
538 inputs);
539 }
540 break;
541 }
542}
543
544/* Try to convert SUMMARY_REG in the summary to a corresponding region
545 in the caller, caching the result.
546
547 Return NULL if the conversion is not possible. */
548
549const region *
550call_summary_replay::convert_region_from_summary (const region *summary_reg)
551{
552 gcc_assert (summary_reg);
553
554 if (const region **slot
555 = m_map_region_from_summary_to_caller.get (k: summary_reg))
556 return *slot;
557
558 const region *caller_reg = convert_region_from_summary_1 (summary_reg);
559
560 if (caller_reg)
561 if (summary_reg->get_type () && caller_reg->get_type ())
562 gcc_assert (types_compatible_p (summary_reg->get_type (),
563 caller_reg->get_type ()));
564
565 /* Add to cache. */
566 add_region_mapping (summary_sval: summary_reg, caller_sval: caller_reg);
567
568 return caller_reg;
569}
570
571/* Implementation of call_summary_replay::convert_region_from_summary. */
572
573const region *
574call_summary_replay::convert_region_from_summary_1 (const region *summary_reg)
575{
576 gcc_assert (summary_reg);
577
578 region_model_manager *mgr = get_manager ();
579 switch (summary_reg->get_kind ())
580 {
581 default:
582 gcc_unreachable ();
583 /* Top-level regions. */
584 case RK_FRAME:
585 case RK_GLOBALS:
586 case RK_CODE:
587 case RK_STACK:
588 case RK_HEAP:
589 case RK_THREAD_LOCAL:
590 case RK_ROOT:
591 /* These should never be pointed to by a region_svalue. */
592 gcc_unreachable ();
593
594 case RK_FUNCTION:
595 case RK_LABEL:
596 case RK_STRING:
597 case RK_ERRNO:
598 case RK_UNKNOWN:
599 case RK_PRIVATE:
600 /* We can reuse these regions directly. */
601 return summary_reg;
602
603 case RK_SYMBOLIC:
604 {
605 const symbolic_region *summary_symbolic_reg
606 = as_a <const symbolic_region *> (p: summary_reg);
607 const svalue *summary_ptr_sval = summary_symbolic_reg->get_pointer ();
608 const svalue *caller_ptr_sval
609 = convert_svalue_from_summary (summary_sval: summary_ptr_sval);
610 if (!caller_ptr_sval)
611 return NULL;
612 const region *caller_reg
613 = get_caller_model ()->deref_rvalue (ptr_sval: caller_ptr_sval,
614 NULL_TREE,
615 ctxt: get_ctxt ());
616 caller_reg = mgr->get_cast_region (original_region: caller_reg,
617 type: summary_reg->get_type ());
618 return caller_reg;
619 }
620 break;
621
622 case RK_DECL:
623 {
624 const decl_region *summary_decl_reg
625 = as_a <const decl_region *> (p: summary_reg);
626 tree decl = summary_decl_reg->get_decl ();
627 switch (TREE_CODE (decl))
628 {
629 default:
630 gcc_unreachable ();
631 case SSA_NAME:
632 /* We don't care about writes to locals within
633 the summary. */
634 return NULL;
635 case VAR_DECL:
636 /* We don't care about writes to locals within
637 the summary. */
638 if (is_global_var (t: decl))
639 /* If it's a global, we can reuse the region directly. */
640 return summary_reg;
641 else
642 /* Otherwise, we don't care about locals. */
643 return NULL;
644 case RESULT_DECL:
645 return m_cd.get_lhs_region ();
646 case PARM_DECL:
647 /* Writes (by value) to parms should be visible to the caller. */
648 return NULL;
649 }
650 }
651 break;
652 case RK_FIELD:
653 {
654 const field_region *summary_field_reg
655 = as_a <const field_region *> (p: summary_reg);
656 const region *summary_parent_reg = summary_reg->get_parent_region ();
657 const region *caller_parent_reg
658 = convert_region_from_summary (summary_reg: summary_parent_reg);
659 if (!caller_parent_reg)
660 return NULL;
661 tree field = summary_field_reg->get_field ();
662 return mgr->get_field_region (parent: caller_parent_reg, field);
663 }
664 break;
665 case RK_ELEMENT:
666 {
667 const element_region *summary_element_reg
668 = as_a <const element_region *> (p: summary_reg);
669 const region *summary_parent_reg = summary_reg->get_parent_region ();
670 const region *caller_parent_reg
671 = convert_region_from_summary (summary_reg: summary_parent_reg);
672 if (!caller_parent_reg)
673 return NULL;
674 const svalue *summary_index = summary_element_reg->get_index ();
675 const svalue *caller_index
676 = convert_svalue_from_summary (summary_sval: summary_index);
677 if (!caller_index)
678 return NULL;
679 return mgr->get_element_region (parent: caller_parent_reg,
680 element_type: summary_reg->get_type (),
681 index: caller_index);
682 }
683 break;
684 case RK_OFFSET:
685 {
686 const offset_region *summary_offset_reg
687 = as_a <const offset_region *> (p: summary_reg);
688 const region *summary_parent_reg = summary_reg->get_parent_region ();
689 const region *caller_parent_reg
690 = convert_region_from_summary (summary_reg: summary_parent_reg);
691 if (!caller_parent_reg)
692 return NULL;
693 const svalue *summary_byte_offset
694 = summary_offset_reg->get_byte_offset ();
695 const svalue *caller_byte_offset
696 = convert_svalue_from_summary (summary_sval: summary_byte_offset);
697 if (!caller_byte_offset)
698 return NULL;
699 return mgr->get_offset_region (parent: caller_parent_reg,
700 type: summary_reg->get_type (),
701 byte_offset: caller_byte_offset);
702 }
703 break;
704 case RK_SIZED:
705 {
706 const sized_region *summary_sized_reg
707 = as_a <const sized_region *> (p: summary_reg);
708 const region *summary_parent_reg = summary_reg->get_parent_region ();
709 const region *caller_parent_reg
710 = convert_region_from_summary (summary_reg: summary_parent_reg);
711 if (!caller_parent_reg)
712 return NULL;
713 const svalue *summary_byte_size
714 = summary_sized_reg->get_byte_size_sval (mgr);
715 const svalue *caller_byte_size
716 = convert_svalue_from_summary (summary_sval: summary_byte_size);
717 if (!caller_byte_size)
718 return NULL;
719 return mgr->get_sized_region (parent: caller_parent_reg,
720 type: summary_reg->get_type (),
721 byte_size_sval: caller_byte_size);
722 }
723 break;
724 case RK_CAST:
725 {
726 const cast_region *summary_cast_reg
727 = as_a <const cast_region *> (p: summary_reg);
728 const region *summary_original_reg
729 = summary_cast_reg->get_original_region ();
730 const region *caller_original_reg
731 = convert_region_from_summary (summary_reg: summary_original_reg);
732 if (!caller_original_reg)
733 return NULL;
734 return mgr->get_cast_region (original_region: caller_original_reg,
735 type: summary_reg->get_type ());
736 }
737 break;
738 case RK_HEAP_ALLOCATED:
739 {
740 /* If we have a heap-allocated region in the summary, then
741 it was allocated within the callee.
742 Create a new heap-allocated region to summarize this. */
743 auto_bitmap heap_regs_in_use;
744 get_caller_model ()->get_referenced_base_regions (out_ids&: heap_regs_in_use);
745 return mgr->get_or_create_region_for_heap_alloc (base_regs_in_use: heap_regs_in_use);
746 }
747 break;
748 case RK_ALLOCA:
749 return NULL;
750 case RK_BIT_RANGE:
751 {
752 const bit_range_region *summary_bit_range_reg
753 = as_a <const bit_range_region *> (p: summary_reg);
754 const region *summary_parent_reg = summary_reg->get_parent_region ();
755 const region *caller_parent_reg
756 = convert_region_from_summary (summary_reg: summary_parent_reg);
757 if (!caller_parent_reg)
758 return NULL;
759 const bit_range &bits = summary_bit_range_reg->get_bits ();
760 return mgr->get_bit_range (parent: caller_parent_reg,
761 type: summary_reg->get_type (),
762 bits);
763 }
764 break;
765 case RK_VAR_ARG:
766 return NULL;
767 }
768}
769
770/* Try to convert SUMMARY_KEY in the summary to a corresponding binding key
771 in the caller.
772
773 Return NULL if the conversion is not possible. */
774
775const binding_key *
776call_summary_replay::convert_key_from_summary (const binding_key *summary_key)
777{
778 if (summary_key->concrete_p ())
779 return summary_key;
780
781 const symbolic_binding *symbolic_key = (const symbolic_binding *)summary_key;
782 const region *summary_reg = symbolic_key->get_region ();
783 const region *caller_reg = convert_region_from_summary (summary_reg);
784 if (!caller_reg)
785 return NULL;
786 region_model_manager *mgr = get_manager ();
787 store_manager *store_mgr = mgr->get_store_manager ();
788 return store_mgr->get_symbolic_binding (region: caller_reg);
789}
790
791/* Record that SUMMARY_SVAL maps to CALLER_SVAL for this replay. */
792
793void
794call_summary_replay::add_svalue_mapping (const svalue *summary_sval,
795 const svalue *caller_sval)
796{
797 gcc_assert (summary_sval);
798 // CALLER_SVAL can be NULL
799 m_map_svalue_from_summary_to_caller.put (k: summary_sval, v: caller_sval);
800}
801
802/* Record that SUMMARY_REG maps to CALLER_REG for this replay. */
803
804void
805call_summary_replay::add_region_mapping (const region *summary_reg,
806 const region *caller_reg)
807{
808 gcc_assert (summary_reg);
809 // CALLER_REG can be NULL
810 m_map_region_from_summary_to_caller.put (k: summary_reg, v: caller_reg);
811}
812
813/* Dump a multiline representation of this object to PP. */
814
815void
816call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const
817{
818 pp_newline (pp);
819 pp_string (pp, "CALL DETAILS:");
820 pp_newline (pp);
821 m_cd.dump_to_pp (pp, simple);
822
823 pp_newline (pp);
824 pp_string (pp, "CALLEE SUMMARY:");
825 pp_newline (pp);
826 m_summary->dump_to_pp (ext_state: m_ext_state, pp, simple);
827
828 /* Current state of caller (could be in mid-update). */
829 pp_newline (pp);
830 pp_string (pp, "CALLER:");
831 pp_newline (pp);
832 m_cd.get_model ()->dump_to_pp (pp, simple, multiline: true);
833
834 pp_newline (pp);
835 pp_string (pp, "REPLAY STATE:");
836 pp_newline (pp);
837 pp_string (pp, "svalue mappings from summary to caller:");
838 pp_newline (pp);
839 auto_vec <const svalue *> summary_svals;
840 for (auto kv : m_map_svalue_from_summary_to_caller)
841 summary_svals.safe_push (obj: kv.first);
842 summary_svals.qsort (svalue::cmp_ptr_ptr);
843 for (auto summary_sval : summary_svals)
844 {
845 pp_string (pp, "sval in summary: ");
846 summary_sval->dump_to_pp (pp, simple);
847 pp_newline (pp);
848
849 const svalue *caller_sval
850 = *((const_cast<svalue_map_t &>
851 (m_map_svalue_from_summary_to_caller)).get (k: summary_sval));
852 pp_string (pp, " sval in caller: ");
853 caller_sval->dump_to_pp (pp, simple);
854 pp_newline (pp);
855 }
856
857 pp_newline (pp);
858 pp_string (pp, "region mappings from summary to caller:");
859 pp_newline (pp);
860 auto_vec <const region *> summary_regs;
861 for (auto kv : m_map_region_from_summary_to_caller)
862 summary_regs.safe_push (obj: kv.first);
863 summary_regs.qsort (region::cmp_ptr_ptr);
864 for (auto summary_reg : summary_regs)
865 {
866 pp_string (pp, "reg in summary: ");
867 if (summary_reg)
868 summary_reg->dump_to_pp (pp, simple);
869 else
870 pp_string (pp, "(null)");
871 pp_newline (pp);
872
873 const region *caller_reg
874 = *((const_cast<region_map_t &>
875 (m_map_region_from_summary_to_caller)).get (k: summary_reg));
876 pp_string (pp, " reg in caller: ");
877 if (caller_reg)
878 caller_reg->dump_to_pp (pp, simple);
879 else
880 pp_string (pp, "(null)");
881 pp_newline (pp);
882 }
883}
884
885/* Dump a multiline representation of this object to FILE. */
886
887void
888call_summary_replay::dump (FILE *fp, bool simple) const
889{
890 pretty_printer pp;
891 pp_format_decoder (&pp) = default_tree_printer;
892 pp_show_color (&pp) = pp_show_color (global_dc->printer);
893 pp.buffer->stream = fp;
894 dump_to_pp (pp: &pp, simple);
895 pp_flush (&pp);
896}
897
898/* Dump a multiline representation of this object to stderr. */
899
900DEBUG_FUNCTION void
901call_summary_replay::dump (bool simple) const
902{
903 dump (stderr, simple);
904}
905
906} // namespace ana
907
908#endif /* #if ENABLE_ANALYZER */
909

source code of gcc/analyzer/call-summary.cc