1 | /* Classes for working with summaries of function calls. |
2 | Copyright (C) 2022 David Malcolm <dmalcolm@redhat.com>. |
3 | |
4 | This file is part of GCC. |
5 | |
6 | GCC is free software; you can redistribute it and/or modify it |
7 | under the terms of the GNU General Public License as published by |
8 | the Free Software Foundation; either version 3, or (at your option) |
9 | any later version. |
10 | |
11 | GCC is distributed in the hope that it will be useful, but |
12 | WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU General Public License |
17 | along 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 | |
36 | namespace ana { |
37 | |
38 | /* class call_summary. */ |
39 | |
40 | const program_state & |
41 | call_summary::get_state () const |
42 | { |
43 | return m_enode->get_state (); |
44 | } |
45 | |
46 | tree |
47 | call_summary::get_fndecl () const |
48 | { |
49 | return m_enode->get_point ().get_fndecl (); |
50 | } |
51 | |
52 | label_text |
53 | call_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 | |
70 | void |
71 | call_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 | |
129 | void |
130 | call_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 | |
143 | void |
144 | call_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 | |
158 | DEBUG_FUNCTION void |
159 | call_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 | |
170 | call_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 | |
227 | const svalue * |
228 | call_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 | |
251 | const svalue * |
252 | call_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 | |
549 | const region * |
550 | call_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 | |
573 | const region * |
574 | call_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 | |
775 | const binding_key * |
776 | call_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 | |
793 | void |
794 | call_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 | |
804 | void |
805 | call_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 | |
815 | void |
816 | call_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 | |
887 | void |
888 | call_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 | |
900 | DEBUG_FUNCTION void |
901 | call_summary_replay::dump (bool simple) const |
902 | { |
903 | dump (stderr, simple); |
904 | } |
905 | |
906 | } // namespace ana |
907 | |
908 | #endif /* #if ENABLE_ANALYZER */ |
909 | |