]>
Commit | Line | Data |
---|---|---|
e9751143 | 1 | /* Regions of memory. |
83ffe9cd | 2 | Copyright (C) 2019-2023 Free Software Foundation, Inc. |
e9751143 DM |
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 | #ifndef GCC_ANALYZER_REGION_H | |
22 | #define GCC_ANALYZER_REGION_H | |
23 | ||
24 | #include "analyzer/complexity.h" | |
25 | ||
26 | namespace ana { | |
27 | ||
33255ad3 DM |
28 | /* An enum for identifying different spaces within memory. */ |
29 | ||
30 | enum memory_space | |
31 | { | |
32 | MEMSPACE_UNKNOWN, | |
33 | MEMSPACE_CODE, | |
34 | MEMSPACE_GLOBALS, | |
35 | MEMSPACE_STACK, | |
36 | MEMSPACE_HEAP, | |
3d2d04cd DM |
37 | MEMSPACE_READONLY_DATA, |
38 | MEMSPACE_THREAD_LOCAL | |
33255ad3 DM |
39 | }; |
40 | ||
e9751143 DM |
41 | /* An enum for discriminating between the different concrete subclasses |
42 | of region. */ | |
43 | ||
44 | enum region_kind | |
45 | { | |
46 | RK_FRAME, | |
47 | RK_GLOBALS, | |
48 | RK_CODE, | |
49 | RK_FUNCTION, | |
50 | RK_LABEL, | |
51 | RK_STACK, | |
52 | RK_HEAP, | |
3d2d04cd | 53 | RK_THREAD_LOCAL, |
e9751143 DM |
54 | RK_ROOT, |
55 | RK_SYMBOLIC, | |
56 | RK_DECL, | |
57 | RK_FIELD, | |
58 | RK_ELEMENT, | |
59 | RK_OFFSET, | |
e61ffa20 | 60 | RK_SIZED, |
e9751143 DM |
61 | RK_CAST, |
62 | RK_HEAP_ALLOCATED, | |
63 | RK_ALLOCA, | |
64 | RK_STRING, | |
93e759fc | 65 | RK_BIT_RANGE, |
2402dc6b | 66 | RK_VAR_ARG, |
3d2d04cd | 67 | RK_ERRNO, |
2402dc6b | 68 | RK_UNKNOWN, |
e9751143 DM |
69 | }; |
70 | ||
71 | /* Region and its subclasses. | |
72 | ||
73 | The class hierarchy looks like this (using indentation to show | |
74 | inheritance, and with region_kinds shown for the concrete subclasses): | |
75 | ||
76 | region | |
77 | space_region | |
9cac6811 DM |
78 | frame_region (RK_FRAME): a function frame on the stack |
79 | globals_region (RK_GLOBALS): holds globals variables (data and bss) | |
80 | code_region (RK_CODE): represents the code segment, containing functions | |
81 | stack_region (RK_STACK): a stack, containing all stack frames | |
82 | heap_region (RK_HEAP): the heap, containing heap_allocated_regions | |
3d2d04cd DM |
83 | thread_local_region (RK_THREAD_LOCAL): thread-local data for the thread |
84 | being analyzed | |
9cac6811 DM |
85 | root_region (RK_ROOT): the top-level region |
86 | function_region (RK_FUNCTION): the code for a particular function | |
87 | label_region (RK_LABEL): a particular label within a function | |
88 | symbolic_region (RK_SYMBOLIC): dereferencing a symbolic pointer | |
89 | decl_region (RK_DECL): the memory occupied by a particular global, local, | |
90 | or SSA name | |
91 | field_region (RK_FIELD): the memory occupied by a field within a struct | |
92 | or union | |
93 | element_region (RK_ELEMENT): an element within an array | |
94 | offset_region (RK_OFFSET): a byte-offset within another region, for | |
95 | handling pointer arithmetic as a region | |
96 | sized_region (RK_SIZED): a subregion of symbolic size (in bytes) | |
97 | within its parent | |
98 | cast_region (RK_CAST): a region that views another region using a | |
99 | different type | |
100 | heap_allocated_region (RK_HEAP_ALLOCATED): an untyped region dynamically | |
101 | allocated on the heap via | |
102 | "malloc" or similar | |
103 | alloca_region (RK_ALLOCA): an untyped region dynamically allocated on the | |
104 | stack via "alloca" | |
105 | string_region (RK_STRING): a region for a STRING_CST | |
106 | bit_range_region (RK_BIT_RANGE): a region for a specific range of bits | |
107 | within another region | |
108 | var_arg_region (RK_VAR_ARG): a region for the N-th vararg within a | |
109 | frame_region for a variadic call | |
3d2d04cd | 110 | errno_region (RK_ERRNO): a region for holding "errno" |
9cac6811 | 111 | unknown_region (RK_UNKNOWN): for handling unimplemented tree codes. */ |
e9751143 DM |
112 | |
113 | /* Abstract base class for representing ways of accessing chunks of memory. | |
114 | ||
115 | Regions form a tree-like hierarchy, with a root region at the base, | |
116 | with memory space regions within it, representing the stack and | |
117 | globals, with frames within the stack, and regions for variables | |
118 | within the frames and the "globals" region. Regions for structs | |
119 | can have subregions for fields. */ | |
120 | ||
121 | class region | |
122 | { | |
123 | public: | |
124 | virtual ~region (); | |
125 | ||
126 | unsigned get_id () const { return m_id; } | |
127 | static int cmp_ids (const region *reg1, const region *reg2); | |
128 | ||
129 | virtual enum region_kind get_kind () const = 0; | |
130 | virtual const frame_region * | |
131 | dyn_cast_frame_region () const { return NULL; } | |
132 | virtual const function_region * | |
133 | dyn_cast_function_region () const { return NULL; } | |
134 | virtual const symbolic_region * | |
135 | dyn_cast_symbolic_region () const { return NULL; } | |
136 | virtual const decl_region * | |
137 | dyn_cast_decl_region () const { return NULL; } | |
138 | virtual const field_region * | |
139 | dyn_cast_field_region () const { return NULL; } | |
140 | virtual const element_region * | |
141 | dyn_cast_element_region () const { return NULL; } | |
142 | virtual const offset_region * | |
143 | dyn_cast_offset_region () const { return NULL; } | |
e61ffa20 DM |
144 | virtual const sized_region * |
145 | dyn_cast_sized_region () const { return NULL; } | |
e9751143 DM |
146 | virtual const cast_region * |
147 | dyn_cast_cast_region () const { return NULL; } | |
148 | virtual const string_region * | |
149 | dyn_cast_string_region () const { return NULL; } | |
93e759fc DM |
150 | virtual const bit_range_region * |
151 | dyn_cast_bit_range_region () const { return NULL; } | |
2402dc6b DM |
152 | virtual const var_arg_region * |
153 | dyn_cast_var_arg_region () const { return NULL; } | |
e9751143 DM |
154 | |
155 | virtual void accept (visitor *v) const; | |
156 | ||
157 | const region *get_parent_region () const { return m_parent; } | |
158 | const region *get_base_region () const; | |
159 | bool base_region_p () const; | |
160 | bool descendent_of_p (const region *elder) const; | |
161 | const frame_region *maybe_get_frame_region () const; | |
33255ad3 DM |
162 | enum memory_space get_memory_space () const; |
163 | bool can_have_initial_svalue_p () const; | |
e9751143 DM |
164 | |
165 | tree maybe_get_decl () const; | |
166 | ||
167 | tree get_type () const { return m_type; } | |
168 | ||
169 | void print (const region_model &model, | |
170 | pretty_printer *pp) const; | |
171 | label_text get_desc (bool simple=true) const; | |
172 | ||
e9751143 DM |
173 | virtual void dump_to_pp (pretty_printer *pp, bool simple) const = 0; |
174 | void dump (bool simple) const; | |
175 | ||
176 | json::value *to_json () const; | |
177 | ||
178 | bool non_null_p () const; | |
179 | ||
180 | static int cmp_ptr_ptr (const void *, const void *); | |
181 | ||
33255ad3 DM |
182 | bool involves_p (const svalue *sval) const; |
183 | ||
7a6564c9 | 184 | region_offset get_offset (region_model_manager *mgr) const; |
e61ffa20 DM |
185 | |
186 | /* Attempt to get the size of this region as a concrete number of bytes. | |
187 | If successful, return true and write the size to *OUT. | |
188 | Otherwise return false. */ | |
189 | virtual bool get_byte_size (byte_size_t *out) const; | |
190 | ||
191 | /* Attempt to get the size of this region as a concrete number of bits. | |
192 | If successful, return true and write the size to *OUT. | |
193 | Otherwise return false. */ | |
194 | virtual bool get_bit_size (bit_size_t *out) const; | |
195 | ||
196 | /* Get a symbolic value describing the size of this region in bytes | |
197 | (which could be "unknown"). */ | |
198 | virtual const svalue *get_byte_size_sval (region_model_manager *mgr) const; | |
199 | ||
200 | /* Attempt to get the offset in bits of this region relative to its parent. | |
201 | If successful, return true and write to *OUT. | |
202 | Otherwise return false. */ | |
203 | virtual bool get_relative_concrete_offset (bit_offset_t *out) const; | |
e9751143 | 204 | |
7a6564c9 TL |
205 | /* Get the offset in bytes of this region relative to its parent as a svalue. |
206 | Might return an unknown_svalue. */ | |
207 | virtual const svalue * | |
208 | get_relative_symbolic_offset (region_model_manager *mgr) const; | |
209 | ||
2ac7b19f DM |
210 | /* Attempt to get the position and size of this region expressed as a |
211 | concrete range of bytes relative to its parent. | |
212 | If successful, return true and write to *OUT. | |
213 | Otherwise return false. */ | |
214 | bool get_relative_concrete_byte_range (byte_range *out) const; | |
215 | ||
e9751143 DM |
216 | void |
217 | get_subregions_for_binding (region_model_manager *mgr, | |
218 | bit_offset_t start_bit_offset, | |
219 | bit_size_t size_in_bits, | |
220 | tree type, | |
221 | auto_vec <const region *> *out) const; | |
222 | ||
223 | bool symbolic_for_unknown_ptr_p () const; | |
224 | ||
7e3b45be TL |
225 | bool symbolic_p () const; |
226 | ||
5f6197d7 DM |
227 | /* For most base regions it makes sense to track the bindings of the region |
228 | within the store. As an optimization, some are not tracked (to avoid | |
229 | bloating the store object with redundant binding clusters). */ | |
230 | virtual bool tracked_p () const { return true; } | |
231 | ||
e9751143 DM |
232 | const complexity &get_complexity () const { return m_complexity; } |
233 | ||
c1b7d28a DM |
234 | bool is_named_decl_p (const char *decl_name) const; |
235 | ||
dfe2ef7f DM |
236 | bool empty_p () const; |
237 | ||
e9751143 DM |
238 | protected: |
239 | region (complexity c, unsigned id, const region *parent, tree type); | |
240 | ||
241 | private: | |
7a6564c9 | 242 | region_offset calc_offset (region_model_manager *mgr) const; |
e9751143 DM |
243 | |
244 | complexity m_complexity; | |
245 | unsigned m_id; // purely for deterministic sorting at this stage, for dumps | |
246 | const region *m_parent; | |
247 | tree m_type; | |
248 | ||
249 | mutable region_offset *m_cached_offset; | |
250 | }; | |
251 | ||
252 | } // namespace ana | |
253 | ||
254 | template <> | |
255 | template <> | |
256 | inline bool | |
257 | is_a_helper <const region *>::test (const region *) | |
258 | { | |
259 | return true; | |
260 | } | |
261 | ||
262 | namespace ana { | |
263 | ||
264 | /* Abstract subclass of region, for regions that represent an untyped | |
265 | space within memory, such as the stack or the heap. */ | |
266 | ||
267 | class space_region : public region | |
268 | { | |
269 | protected: | |
270 | space_region (unsigned id, const region *parent) | |
271 | : region (complexity (parent), id, parent, NULL_TREE) | |
272 | {} | |
273 | }; | |
274 | ||
275 | /* Concrete space_region subclass, representing a function frame on the stack, | |
276 | to contain the locals. | |
277 | The parent is the stack region; there's also a hierarchy of call-stack | |
278 | prefixes expressed via m_calling_frame. | |
279 | For example, given "oldest" calling "middle" called "newest" we would have | |
280 | - a stack depth of 3 | |
281 | - frame (A) for "oldest" with index 0 for depth 1, calling_frame == NULL | |
282 | - frame (B) for "middle" with index 1 for depth 2, calling_frame == (A) | |
283 | - frame (C) for "newest" with index 2 for depth 3, calling_frame == (B) | |
284 | where the parent region for each of the frames is the "stack" region. | |
285 | The index is the count of frames earlier than this in the stack. */ | |
286 | ||
287 | class frame_region : public space_region | |
288 | { | |
289 | public: | |
290 | /* A support class for uniquifying instances of frame_region. */ | |
291 | struct key_t | |
292 | { | |
293 | key_t (const frame_region *calling_frame, function *fun) | |
294 | : m_calling_frame (calling_frame), m_fun (fun) | |
295 | { | |
296 | /* calling_frame can be NULL. */ | |
297 | gcc_assert (fun); | |
298 | } | |
299 | ||
300 | hashval_t hash () const | |
301 | { | |
302 | inchash::hash hstate; | |
303 | hstate.add_ptr (m_calling_frame); | |
304 | hstate.add_ptr (m_fun); | |
305 | return hstate.end (); | |
306 | } | |
307 | ||
308 | bool operator== (const key_t &other) const | |
309 | { | |
310 | return (m_calling_frame == other.m_calling_frame && m_fun == other.m_fun); | |
311 | } | |
312 | ||
313 | void mark_deleted () { m_fun = reinterpret_cast<function *> (1); } | |
314 | void mark_empty () { m_fun = NULL; } | |
315 | bool is_deleted () const | |
316 | { | |
317 | return m_fun == reinterpret_cast<function *> (1); | |
318 | } | |
319 | bool is_empty () const { return m_fun == NULL; } | |
320 | ||
321 | const frame_region *m_calling_frame; | |
322 | function *m_fun; | |
323 | }; | |
324 | ||
325 | frame_region (unsigned id, const region *parent, | |
326 | const frame_region *calling_frame, | |
327 | function *fun, int index) | |
328 | : space_region (id, parent), m_calling_frame (calling_frame), | |
329 | m_fun (fun), m_index (index) | |
330 | {} | |
331 | ~frame_region (); | |
332 | ||
333 | /* region vfuncs. */ | |
ff171cb1 DM |
334 | enum region_kind get_kind () const final override { return RK_FRAME; } |
335 | const frame_region * dyn_cast_frame_region () const final override | |
e9751143 DM |
336 | { |
337 | return this; | |
338 | } | |
ff171cb1 DM |
339 | void accept (visitor *v) const final override; |
340 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
e9751143 DM |
341 | |
342 | /* Accessors. */ | |
343 | const frame_region *get_calling_frame () const { return m_calling_frame; } | |
344 | function *get_function () const { return m_fun; } | |
00e7d024 | 345 | tree get_fndecl () const { return get_function ()->decl; } |
e9751143 DM |
346 | int get_index () const { return m_index; } |
347 | int get_stack_depth () const { return m_index + 1; } | |
348 | ||
4cebae09 DM |
349 | const decl_region * |
350 | get_region_for_local (region_model_manager *mgr, | |
351 | tree expr, | |
352 | const region_model_context *ctxt) const; | |
e9751143 DM |
353 | |
354 | unsigned get_num_locals () const { return m_locals.elements (); } | |
355 | ||
5f6197d7 DM |
356 | /* Implemented in region-model-manager.cc. */ |
357 | void dump_untracked_regions () const; | |
358 | ||
e9751143 DM |
359 | private: |
360 | const frame_region *m_calling_frame; | |
361 | function *m_fun; | |
362 | int m_index; | |
363 | ||
364 | /* The regions for the decls within this frame are managed by this | |
365 | object, rather than the region_model_manager, to make it a simple | |
366 | lookup by tree. */ | |
367 | typedef hash_map<tree, decl_region *> map_t; | |
368 | map_t m_locals; | |
369 | }; | |
370 | ||
371 | } // namespace ana | |
372 | ||
373 | template <> | |
374 | template <> | |
375 | inline bool | |
376 | is_a_helper <const frame_region *>::test (const region *reg) | |
377 | { | |
378 | return reg->get_kind () == RK_FRAME; | |
379 | } | |
380 | ||
381 | template <> struct default_hash_traits<frame_region::key_t> | |
382 | : public member_function_hash_traits<frame_region::key_t> | |
383 | { | |
384 | static const bool empty_zero_p = true; | |
385 | }; | |
386 | ||
387 | namespace ana { | |
388 | ||
389 | /* Concrete space_region subclass, to hold global variables (data and bss). */ | |
390 | ||
391 | class globals_region : public space_region | |
392 | { | |
393 | public: | |
394 | globals_region (unsigned id, const region *parent) | |
395 | : space_region (id, parent) | |
396 | {} | |
397 | ||
398 | /* region vfuncs. */ | |
ff171cb1 DM |
399 | enum region_kind get_kind () const final override { return RK_GLOBALS; } |
400 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
e9751143 DM |
401 | }; |
402 | ||
403 | } // namespace ana | |
404 | ||
405 | template <> | |
406 | template <> | |
407 | inline bool | |
408 | is_a_helper <const globals_region *>::test (const region *reg) | |
409 | { | |
410 | return reg->get_kind () == RK_GLOBALS; | |
411 | } | |
412 | ||
413 | namespace ana { | |
414 | ||
415 | /* Concrete space_region subclass, representing the code segment | |
416 | containing functions. */ | |
417 | ||
418 | class code_region : public space_region | |
419 | { | |
420 | public: | |
421 | code_region (unsigned id, const region *parent) | |
422 | : space_region (id, parent) | |
423 | {} | |
424 | ||
425 | /* region vfuncs. */ | |
ff171cb1 DM |
426 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
427 | enum region_kind get_kind () const final override { return RK_CODE; } | |
e9751143 DM |
428 | }; |
429 | ||
430 | } // namespace ana | |
431 | ||
432 | template <> | |
433 | template <> | |
434 | inline bool | |
435 | is_a_helper <const code_region *>::test (const region *reg) | |
436 | { | |
437 | return reg->get_kind () == RK_CODE; | |
438 | } | |
439 | ||
440 | namespace ana { | |
441 | ||
442 | /* Concrete region subclass. A region representing the code for | |
443 | a particular function. */ | |
444 | ||
445 | class function_region : public region | |
446 | { | |
447 | public: | |
448 | function_region (unsigned id, const code_region *parent, tree fndecl) | |
449 | : region (complexity (parent), id, parent, TREE_TYPE (fndecl)), | |
450 | m_fndecl (fndecl) | |
451 | { | |
452 | gcc_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndecl))); | |
453 | } | |
454 | ||
455 | /* region vfuncs. */ | |
ff171cb1 DM |
456 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
457 | enum region_kind get_kind () const final override { return RK_FUNCTION; } | |
e9751143 | 458 | const function_region * |
ff171cb1 | 459 | dyn_cast_function_region () const final override{ return this; } |
e9751143 DM |
460 | |
461 | tree get_fndecl () const { return m_fndecl; } | |
462 | ||
e9751143 DM |
463 | private: |
464 | tree m_fndecl; | |
465 | }; | |
466 | ||
467 | } // namespace ana | |
468 | ||
469 | template <> | |
470 | template <> | |
471 | inline bool | |
472 | is_a_helper <const function_region *>::test (const region *reg) | |
473 | { | |
474 | return reg->get_kind () == RK_FUNCTION; | |
475 | } | |
476 | ||
477 | namespace ana { | |
478 | ||
479 | /* Concrete region subclass. A region representing a particular label | |
480 | within a function. */ | |
481 | ||
482 | class label_region : public region | |
483 | { | |
484 | public: | |
485 | label_region (unsigned id, const function_region *parent, tree label) | |
486 | : region (complexity (parent), id, parent, NULL_TREE), m_label (label) | |
487 | { | |
488 | gcc_assert (TREE_CODE (label) == LABEL_DECL); | |
489 | } | |
490 | ||
491 | /* region vfuncs. */ | |
ff171cb1 DM |
492 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
493 | enum region_kind get_kind () const final override { return RK_LABEL; } | |
e9751143 DM |
494 | |
495 | tree get_label () const { return m_label; } | |
496 | ||
497 | private: | |
498 | tree m_label; | |
499 | }; | |
500 | ||
501 | } // namespace ana | |
502 | ||
503 | template <> | |
504 | template <> | |
505 | inline bool | |
506 | is_a_helper <const label_region *>::test (const region *reg) | |
507 | { | |
508 | return reg->get_kind () == RK_LABEL; | |
509 | } | |
510 | ||
511 | namespace ana { | |
512 | ||
513 | /* Concrete space_region subclass representing a stack, containing all stack | |
514 | frames. */ | |
515 | ||
516 | class stack_region : public space_region | |
517 | { | |
518 | public: | |
519 | stack_region (unsigned id, region *parent) | |
520 | : space_region (id, parent) | |
521 | {} | |
522 | ||
ff171cb1 | 523 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 | 524 | |
ff171cb1 | 525 | enum region_kind get_kind () const final override { return RK_STACK; } |
e9751143 DM |
526 | }; |
527 | ||
528 | } // namespace ana | |
529 | ||
530 | template <> | |
531 | template <> | |
532 | inline bool | |
533 | is_a_helper <const stack_region *>::test (const region *reg) | |
534 | { | |
535 | return reg->get_kind () == RK_STACK; | |
536 | } | |
537 | ||
538 | namespace ana { | |
539 | ||
540 | /* Concrete space_region subclass: a region within which regions can be | |
541 | dynamically allocated. */ | |
542 | ||
543 | class heap_region : public space_region | |
544 | { | |
545 | public: | |
546 | heap_region (unsigned id, region *parent) | |
547 | : space_region (id, parent) | |
548 | {} | |
549 | ||
ff171cb1 DM |
550 | enum region_kind get_kind () const final override { return RK_HEAP; } |
551 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
e9751143 DM |
552 | }; |
553 | ||
554 | } // namespace ana | |
555 | ||
556 | template <> | |
557 | template <> | |
558 | inline bool | |
559 | is_a_helper <const heap_region *>::test (const region *reg) | |
560 | { | |
561 | return reg->get_kind () == RK_HEAP; | |
562 | } | |
563 | ||
564 | namespace ana { | |
565 | ||
3d2d04cd DM |
566 | /* Concrete space_region subclass: thread-local data for the thread |
567 | being analyzed. */ | |
568 | ||
569 | class thread_local_region : public space_region | |
570 | { | |
571 | public: | |
572 | thread_local_region (unsigned id, region *parent) | |
573 | : space_region (id, parent) | |
574 | {} | |
575 | ||
576 | enum region_kind get_kind () const final override { return RK_THREAD_LOCAL; } | |
577 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
578 | }; | |
579 | ||
580 | } // namespace ana | |
581 | ||
582 | template <> | |
583 | template <> | |
584 | inline bool | |
585 | is_a_helper <const thread_local_region *>::test (const region *reg) | |
586 | { | |
587 | return reg->get_kind () == RK_THREAD_LOCAL; | |
588 | } | |
589 | ||
590 | namespace ana { | |
591 | ||
e9751143 DM |
592 | /* Concrete region subclass. The root region, containing all regions |
593 | (either directly, or as descendents). | |
594 | Unique within a region_model_manager. */ | |
595 | ||
596 | class root_region : public region | |
597 | { | |
598 | public: | |
599 | root_region (unsigned id); | |
600 | ||
ff171cb1 DM |
601 | enum region_kind get_kind () const final override { return RK_ROOT; } |
602 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
e9751143 DM |
603 | }; |
604 | ||
605 | } // namespace ana | |
606 | ||
607 | template <> | |
608 | template <> | |
609 | inline bool | |
610 | is_a_helper <const root_region *>::test (const region *reg) | |
611 | { | |
612 | return reg->get_kind () == RK_ROOT; | |
613 | } | |
614 | ||
615 | namespace ana { | |
616 | ||
617 | /* Concrete region subclass: a region to use when dereferencing an unknown | |
618 | pointer. */ | |
619 | ||
620 | class symbolic_region : public region | |
621 | { | |
622 | public: | |
623 | /* A support class for uniquifying instances of symbolic_region. */ | |
624 | struct key_t | |
625 | { | |
626 | key_t (const region *parent, const svalue *sval_ptr) | |
627 | : m_parent (parent), m_sval_ptr (sval_ptr) | |
628 | { | |
629 | gcc_assert (sval_ptr); | |
630 | } | |
631 | ||
632 | hashval_t hash () const | |
633 | { | |
634 | inchash::hash hstate; | |
635 | hstate.add_ptr (m_parent); | |
636 | hstate.add_ptr (m_sval_ptr); | |
637 | return hstate.end (); | |
638 | } | |
639 | ||
640 | bool operator== (const key_t &other) const | |
641 | { | |
642 | return (m_parent == other.m_parent && m_sval_ptr == other.m_sval_ptr); | |
643 | } | |
644 | ||
645 | void mark_deleted () { m_sval_ptr = reinterpret_cast<const svalue *> (1); } | |
646 | void mark_empty () { m_sval_ptr = NULL; } | |
647 | bool is_deleted () const | |
648 | { | |
649 | return m_sval_ptr == reinterpret_cast<const svalue *> (1); | |
650 | } | |
651 | bool is_empty () const { return m_sval_ptr == NULL; } | |
652 | ||
653 | const region *m_parent; | |
654 | const svalue *m_sval_ptr; | |
655 | }; | |
656 | ||
657 | symbolic_region (unsigned id, region *parent, const svalue *sval_ptr); | |
658 | ||
659 | const symbolic_region * | |
ff171cb1 | 660 | dyn_cast_symbolic_region () const final override { return this; } |
e9751143 | 661 | |
ff171cb1 DM |
662 | enum region_kind get_kind () const final override { return RK_SYMBOLIC; } |
663 | void accept (visitor *v) const final override; | |
664 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
e9751143 DM |
665 | |
666 | const svalue *get_pointer () const { return m_sval_ptr; } | |
667 | ||
668 | private: | |
669 | const svalue *m_sval_ptr; | |
670 | }; | |
671 | ||
672 | } // namespace ana | |
673 | ||
674 | template <> | |
675 | template <> | |
676 | inline bool | |
677 | is_a_helper <const symbolic_region *>::test (const region *reg) | |
678 | { | |
679 | return reg->get_kind () == RK_SYMBOLIC; | |
680 | } | |
681 | ||
682 | template <> struct default_hash_traits<symbolic_region::key_t> | |
683 | : public member_function_hash_traits<symbolic_region::key_t> | |
684 | { | |
685 | static const bool empty_zero_p = true; | |
686 | }; | |
687 | ||
688 | namespace ana { | |
689 | ||
690 | /* Concrete region subclass representing the memory occupied by a | |
5f6197d7 DM |
691 | variable (whether for a global or a local). |
692 | Also used for representing SSA names, as if they were locals. */ | |
e9751143 DM |
693 | |
694 | class decl_region : public region | |
695 | { | |
696 | public: | |
697 | decl_region (unsigned id, const region *parent, tree decl) | |
5f6197d7 DM |
698 | : region (complexity (parent), id, parent, TREE_TYPE (decl)), m_decl (decl), |
699 | m_tracked (calc_tracked_p (decl)) | |
e9751143 DM |
700 | {} |
701 | ||
ff171cb1 | 702 | enum region_kind get_kind () const final override { return RK_DECL; } |
e9751143 | 703 | const decl_region * |
ff171cb1 | 704 | dyn_cast_decl_region () const final override { return this; } |
e9751143 | 705 | |
ff171cb1 | 706 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 | 707 | |
ff171cb1 | 708 | bool tracked_p () const final override { return m_tracked; } |
5f6197d7 | 709 | |
e9751143 DM |
710 | tree get_decl () const { return m_decl; } |
711 | int get_stack_depth () const; | |
712 | ||
713 | const svalue *maybe_get_constant_value (region_model_manager *mgr) const; | |
714 | const svalue *get_svalue_for_constructor (tree ctor, | |
715 | region_model_manager *mgr) const; | |
716 | const svalue *get_svalue_for_initializer (region_model_manager *mgr) const; | |
717 | ||
718 | private: | |
5f6197d7 DM |
719 | static bool calc_tracked_p (tree decl); |
720 | ||
e9751143 | 721 | tree m_decl; |
5f6197d7 DM |
722 | |
723 | /* Cached result of calc_tracked_p, so that we can quickly determine when | |
724 | we don't to track a binding_cluster for this decl (to avoid bloating | |
725 | store objects). | |
726 | This can be debugged using -fdump-analyzer-untracked. */ | |
727 | bool m_tracked; | |
e9751143 DM |
728 | }; |
729 | ||
730 | } // namespace ana | |
731 | ||
732 | template <> | |
733 | template <> | |
734 | inline bool | |
735 | is_a_helper <const decl_region *>::test (const region *reg) | |
736 | { | |
737 | return reg->get_kind () == RK_DECL; | |
738 | } | |
739 | ||
740 | namespace ana { | |
741 | ||
742 | /* Concrete region subclass representing the memory occupied by a | |
743 | field within a struct or union. */ | |
744 | ||
745 | class field_region : public region | |
746 | { | |
747 | public: | |
748 | /* A support class for uniquifying instances of field_region. */ | |
749 | struct key_t | |
750 | { | |
751 | key_t (const region *parent, tree field) | |
752 | : m_parent (parent), m_field (field) | |
753 | { | |
754 | gcc_assert (field); | |
755 | } | |
756 | ||
757 | hashval_t hash () const | |
758 | { | |
759 | inchash::hash hstate; | |
760 | hstate.add_ptr (m_parent); | |
761 | hstate.add_ptr (m_field); | |
762 | return hstate.end (); | |
763 | } | |
764 | ||
765 | bool operator== (const key_t &other) const | |
766 | { | |
767 | return (m_parent == other.m_parent && m_field == other.m_field); | |
768 | } | |
769 | ||
770 | void mark_deleted () { m_field = reinterpret_cast<tree> (1); } | |
771 | void mark_empty () { m_field = NULL_TREE; } | |
772 | bool is_deleted () const { return m_field == reinterpret_cast<tree> (1); } | |
773 | bool is_empty () const { return m_field == NULL_TREE; } | |
774 | ||
775 | const region *m_parent; | |
776 | tree m_field; | |
777 | }; | |
778 | ||
779 | field_region (unsigned id, const region *parent, tree field) | |
780 | : region (complexity (parent), id, parent, TREE_TYPE (field)), | |
781 | m_field (field) | |
782 | {} | |
783 | ||
ff171cb1 | 784 | enum region_kind get_kind () const final override { return RK_FIELD; } |
e9751143 | 785 | |
ff171cb1 | 786 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 | 787 | const field_region * |
ff171cb1 | 788 | dyn_cast_field_region () const final override { return this; } |
e9751143 DM |
789 | |
790 | tree get_field () const { return m_field; } | |
791 | ||
ff171cb1 | 792 | bool get_relative_concrete_offset (bit_offset_t *out) const final override; |
7a6564c9 TL |
793 | const svalue *get_relative_symbolic_offset (region_model_manager *mgr) |
794 | const final override; | |
e61ffa20 | 795 | |
e9751143 DM |
796 | private: |
797 | tree m_field; | |
798 | }; | |
799 | ||
800 | } // namespace ana | |
801 | ||
802 | template <> | |
803 | template <> | |
804 | inline bool | |
805 | is_a_helper <const field_region *>::test (const region *reg) | |
806 | { | |
807 | return reg->get_kind () == RK_FIELD; | |
808 | } | |
809 | ||
810 | template <> struct default_hash_traits<field_region::key_t> | |
811 | : public member_function_hash_traits<field_region::key_t> | |
812 | { | |
813 | static const bool empty_zero_p = true; | |
814 | }; | |
815 | ||
816 | namespace ana { | |
817 | ||
818 | /* An element within an array. */ | |
819 | ||
820 | class element_region : public region | |
821 | { | |
822 | public: | |
823 | /* A support class for uniquifying instances of element_region. */ | |
824 | struct key_t | |
825 | { | |
826 | key_t (const region *parent, tree element_type, const svalue *index) | |
827 | : m_parent (parent), m_element_type (element_type), m_index (index) | |
828 | { | |
829 | gcc_assert (index); | |
830 | } | |
831 | ||
832 | hashval_t hash () const | |
833 | { | |
834 | inchash::hash hstate; | |
835 | hstate.add_ptr (m_parent); | |
836 | hstate.add_ptr (m_element_type); | |
837 | hstate.add_ptr (m_index); | |
838 | return hstate.end (); | |
839 | } | |
840 | ||
841 | bool operator== (const key_t &other) const | |
842 | { | |
843 | return (m_parent == other.m_parent | |
844 | && m_element_type == other.m_element_type | |
845 | && m_index == other.m_index); | |
846 | } | |
847 | ||
848 | void mark_deleted () { m_index = reinterpret_cast<const svalue *> (1); } | |
849 | void mark_empty () { m_index = NULL; } | |
850 | bool is_deleted () const | |
851 | { | |
852 | return m_index == reinterpret_cast<const svalue *> (1); | |
853 | } | |
854 | bool is_empty () const { return m_index == NULL; } | |
855 | ||
856 | const region *m_parent; | |
857 | tree m_element_type; | |
858 | const svalue *m_index; | |
859 | }; | |
860 | ||
861 | element_region (unsigned id, const region *parent, tree element_type, | |
862 | const svalue *index) | |
863 | : region (complexity::from_pair (parent, index), id, parent, element_type), | |
864 | m_index (index) | |
865 | {} | |
866 | ||
ff171cb1 | 867 | enum region_kind get_kind () const final override { return RK_ELEMENT; } |
e9751143 | 868 | const element_region * |
ff171cb1 | 869 | dyn_cast_element_region () const final override { return this; } |
e9751143 | 870 | |
ff171cb1 | 871 | void accept (visitor *v) const final override; |
e9751143 | 872 | |
ff171cb1 | 873 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 DM |
874 | |
875 | const svalue *get_index () const { return m_index; } | |
876 | ||
e61ffa20 | 877 | virtual bool |
ff171cb1 | 878 | get_relative_concrete_offset (bit_offset_t *out) const final override; |
7a6564c9 TL |
879 | const svalue *get_relative_symbolic_offset (region_model_manager *mgr) |
880 | const final override; | |
e61ffa20 | 881 | |
e9751143 DM |
882 | private: |
883 | const svalue *m_index; | |
884 | }; | |
885 | ||
886 | } // namespace ana | |
887 | ||
888 | template <> | |
889 | template <> | |
890 | inline bool | |
891 | is_a_helper <const element_region *>::test (const region *reg) | |
892 | { | |
893 | return reg->get_kind () == RK_ELEMENT; | |
894 | } | |
895 | ||
896 | template <> struct default_hash_traits<element_region::key_t> | |
897 | : public member_function_hash_traits<element_region::key_t> | |
898 | { | |
899 | static const bool empty_zero_p = true; | |
900 | }; | |
901 | ||
902 | namespace ana { | |
903 | ||
904 | /* A byte-offset within another region, for handling pointer arithmetic | |
905 | as a region. */ | |
906 | ||
907 | class offset_region : public region | |
908 | { | |
909 | public: | |
910 | /* A support class for uniquifying instances of offset_region. */ | |
911 | struct key_t | |
912 | { | |
913 | key_t (const region *parent, tree element_type, const svalue *byte_offset) | |
914 | : m_parent (parent), m_element_type (element_type), m_byte_offset (byte_offset) | |
915 | { | |
916 | gcc_assert (byte_offset); | |
917 | } | |
918 | ||
919 | hashval_t hash () const | |
920 | { | |
921 | inchash::hash hstate; | |
922 | hstate.add_ptr (m_parent); | |
923 | hstate.add_ptr (m_element_type); | |
924 | hstate.add_ptr (m_byte_offset); | |
925 | return hstate.end (); | |
926 | } | |
927 | ||
928 | bool operator== (const key_t &other) const | |
929 | { | |
930 | return (m_parent == other.m_parent | |
931 | && m_element_type == other.m_element_type | |
932 | && m_byte_offset == other.m_byte_offset); | |
933 | } | |
934 | ||
935 | void mark_deleted () { m_byte_offset = reinterpret_cast<const svalue *> (1); } | |
936 | void mark_empty () { m_byte_offset = NULL; } | |
937 | bool is_deleted () const | |
938 | { | |
939 | return m_byte_offset == reinterpret_cast<const svalue *> (1); | |
940 | } | |
941 | bool is_empty () const { return m_byte_offset == NULL; } | |
942 | ||
943 | const region *m_parent; | |
944 | tree m_element_type; | |
945 | const svalue *m_byte_offset; | |
946 | }; | |
947 | ||
948 | offset_region (unsigned id, const region *parent, tree type, | |
949 | const svalue *byte_offset) | |
950 | : region (complexity::from_pair (parent, byte_offset), id, parent, type), | |
951 | m_byte_offset (byte_offset) | |
952 | {} | |
953 | ||
ff171cb1 | 954 | enum region_kind get_kind () const final override { return RK_OFFSET; } |
e9751143 | 955 | const offset_region * |
ff171cb1 | 956 | dyn_cast_offset_region () const final override { return this; } |
e9751143 | 957 | |
ff171cb1 | 958 | void accept (visitor *v) const final override; |
e9751143 | 959 | |
ff171cb1 | 960 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 DM |
961 | |
962 | const svalue *get_byte_offset () const { return m_byte_offset; } | |
963 | ||
ff171cb1 | 964 | bool get_relative_concrete_offset (bit_offset_t *out) const final override; |
7a6564c9 TL |
965 | const svalue *get_relative_symbolic_offset (region_model_manager *mgr) |
966 | const final override; | |
bdd385b2 ML |
967 | const svalue * get_byte_size_sval (region_model_manager *mgr) |
968 | const final override; | |
7e3b45be | 969 | |
e61ffa20 | 970 | |
e9751143 DM |
971 | private: |
972 | const svalue *m_byte_offset; | |
973 | }; | |
974 | ||
975 | } // namespace ana | |
976 | ||
977 | template <> | |
978 | template <> | |
979 | inline bool | |
980 | is_a_helper <const offset_region *>::test (const region *reg) | |
981 | { | |
982 | return reg->get_kind () == RK_OFFSET; | |
983 | } | |
984 | ||
985 | template <> struct default_hash_traits<offset_region::key_t> | |
986 | : public member_function_hash_traits<offset_region::key_t> | |
987 | { | |
988 | static const bool empty_zero_p = true; | |
989 | }; | |
990 | ||
991 | namespace ana { | |
992 | ||
e61ffa20 DM |
993 | /* A region that is size BYTES_SIZE_SVAL in size within its parent |
994 | region (or possibly larger, which would lead to an overflow. */ | |
995 | ||
996 | class sized_region : public region | |
997 | { | |
998 | public: | |
999 | /* A support class for uniquifying instances of sized_region. */ | |
1000 | struct key_t | |
1001 | { | |
1002 | key_t (const region *parent, tree element_type, | |
1003 | const svalue *byte_size_sval) | |
1004 | : m_parent (parent), m_element_type (element_type), | |
1005 | m_byte_size_sval (byte_size_sval) | |
1006 | { | |
1007 | gcc_assert (byte_size_sval); | |
1008 | } | |
1009 | ||
1010 | hashval_t hash () const | |
1011 | { | |
1012 | inchash::hash hstate; | |
1013 | hstate.add_ptr (m_parent); | |
1014 | hstate.add_ptr (m_element_type); | |
1015 | hstate.add_ptr (m_byte_size_sval); | |
1016 | return hstate.end (); | |
1017 | } | |
1018 | ||
1019 | bool operator== (const key_t &other) const | |
1020 | { | |
1021 | return (m_parent == other.m_parent | |
1022 | && m_element_type == other.m_element_type | |
1023 | && m_byte_size_sval == other.m_byte_size_sval); | |
1024 | } | |
1025 | ||
1026 | void mark_deleted () { m_byte_size_sval = reinterpret_cast<const svalue *> (1); } | |
1027 | void mark_empty () { m_byte_size_sval = NULL; } | |
1028 | bool is_deleted () const | |
1029 | { | |
1030 | return m_byte_size_sval == reinterpret_cast<const svalue *> (1); | |
1031 | } | |
1032 | bool is_empty () const { return m_byte_size_sval == NULL; } | |
1033 | ||
1034 | const region *m_parent; | |
1035 | tree m_element_type; | |
1036 | const svalue *m_byte_size_sval; | |
1037 | const svalue *m_end_offset; | |
1038 | }; | |
1039 | ||
1040 | sized_region (unsigned id, const region *parent, tree type, | |
1041 | const svalue *byte_size_sval) | |
1042 | : region (complexity::from_pair (parent, byte_size_sval), | |
1043 | id, parent, type), | |
1044 | m_byte_size_sval (byte_size_sval) | |
1045 | {} | |
1046 | ||
ff171cb1 | 1047 | enum region_kind get_kind () const final override { return RK_SIZED; } |
e61ffa20 | 1048 | const sized_region * |
ff171cb1 | 1049 | dyn_cast_sized_region () const final override { return this; } |
e61ffa20 | 1050 | |
ff171cb1 | 1051 | void accept (visitor *v) const final override; |
e61ffa20 | 1052 | |
ff171cb1 | 1053 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e61ffa20 | 1054 | |
ff171cb1 DM |
1055 | bool get_byte_size (byte_size_t *out) const final override; |
1056 | bool get_bit_size (bit_size_t *out) const final override; | |
e61ffa20 DM |
1057 | |
1058 | const svalue * | |
ff171cb1 | 1059 | get_byte_size_sval (region_model_manager *) const final override |
e61ffa20 DM |
1060 | { |
1061 | return m_byte_size_sval; | |
1062 | } | |
1063 | ||
1064 | private: | |
1065 | const svalue *m_byte_size_sval; | |
1066 | }; | |
1067 | ||
1068 | } // namespace ana | |
1069 | ||
1070 | template <> | |
1071 | template <> | |
1072 | inline bool | |
1073 | is_a_helper <const sized_region *>::test (const region *reg) | |
1074 | { | |
1075 | return reg->get_kind () == RK_SIZED; | |
1076 | } | |
1077 | ||
1078 | template <> struct default_hash_traits<sized_region::key_t> | |
1079 | : public member_function_hash_traits<sized_region::key_t> | |
1080 | { | |
1081 | static const bool empty_zero_p = true; | |
1082 | }; | |
1083 | ||
1084 | namespace ana { | |
1085 | ||
e9751143 DM |
1086 | /* A region that views another region using a different type. */ |
1087 | ||
1088 | class cast_region : public region | |
1089 | { | |
1090 | public: | |
1091 | /* A support class for uniquifying instances of cast_region. */ | |
1092 | struct key_t | |
1093 | { | |
1094 | key_t (const region *original_region, tree type) | |
1095 | : m_original_region (original_region), m_type (type) | |
1096 | { | |
1097 | gcc_assert (type); | |
1098 | } | |
1099 | ||
1100 | hashval_t hash () const | |
1101 | { | |
1102 | inchash::hash hstate; | |
1103 | hstate.add_ptr (m_original_region); | |
1104 | hstate.add_ptr (m_type); | |
1105 | return hstate.end (); | |
1106 | } | |
1107 | ||
1108 | bool operator== (const key_t &other) const | |
1109 | { | |
1110 | return (m_original_region == other.m_original_region | |
1111 | && m_type == other.m_type); | |
1112 | } | |
1113 | ||
1114 | void mark_deleted () { m_type = reinterpret_cast<tree> (1); } | |
1115 | void mark_empty () { m_type = NULL_TREE; } | |
1116 | bool is_deleted () const { return m_type == reinterpret_cast<tree> (1); } | |
1117 | bool is_empty () const { return m_type == NULL_TREE; } | |
1118 | ||
1119 | const region *m_original_region; | |
1120 | tree m_type; | |
1121 | }; | |
1122 | ||
1123 | cast_region (unsigned id, const region *original_region, tree type) | |
1124 | : region (complexity (original_region), id, | |
1125 | original_region->get_parent_region (), type), | |
1126 | m_original_region (original_region) | |
1127 | {} | |
1128 | ||
ff171cb1 | 1129 | enum region_kind get_kind () const final override { return RK_CAST; } |
e9751143 | 1130 | const cast_region * |
ff171cb1 DM |
1131 | dyn_cast_cast_region () const final override { return this; } |
1132 | void accept (visitor *v) const final override; | |
1133 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
e9751143 | 1134 | |
1cc7e31c TL |
1135 | bool get_relative_concrete_offset (bit_offset_t *out) const final override; |
1136 | ||
e9751143 DM |
1137 | const region *get_original_region () const { return m_original_region; } |
1138 | ||
1139 | private: | |
1140 | const region *m_original_region; | |
1141 | }; | |
1142 | ||
1143 | } // namespace ana | |
1144 | ||
1145 | template <> | |
1146 | template <> | |
1147 | inline bool | |
1148 | is_a_helper <const cast_region *>::test (const region *reg) | |
1149 | { | |
1150 | return reg->get_kind () == RK_CAST; | |
1151 | } | |
1152 | ||
1153 | template <> struct default_hash_traits<cast_region::key_t> | |
1154 | : public member_function_hash_traits<cast_region::key_t> | |
1155 | { | |
1156 | static const bool empty_zero_p = true; | |
1157 | }; | |
1158 | ||
1159 | namespace ana { | |
1160 | ||
1161 | /* An untyped region dynamically allocated on the heap via "malloc" | |
1162 | or similar. */ | |
1163 | ||
1164 | class heap_allocated_region : public region | |
1165 | { | |
1166 | public: | |
1167 | heap_allocated_region (unsigned id, const region *parent) | |
1168 | : region (complexity (parent), id, parent, NULL_TREE) | |
1169 | {} | |
1170 | ||
1171 | enum region_kind | |
ff171cb1 | 1172 | get_kind () const final override { return RK_HEAP_ALLOCATED; } |
e9751143 | 1173 | |
ff171cb1 | 1174 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 DM |
1175 | }; |
1176 | ||
1177 | /* An untyped region dynamically allocated on the stack via "alloca". */ | |
1178 | ||
1179 | class alloca_region : public region | |
1180 | { | |
1181 | public: | |
1182 | alloca_region (unsigned id, const frame_region *parent) | |
1183 | : region (complexity (parent), id, parent, NULL_TREE) | |
1184 | {} | |
1185 | ||
ff171cb1 | 1186 | enum region_kind get_kind () const final override { return RK_ALLOCA; } |
e9751143 | 1187 | |
ff171cb1 | 1188 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 DM |
1189 | }; |
1190 | ||
1191 | /* A region for a STRING_CST. */ | |
1192 | ||
1193 | class string_region : public region | |
1194 | { | |
1195 | public: | |
1196 | string_region (unsigned id, const region *parent, tree string_cst) | |
1197 | : region (complexity (parent), id, parent, TREE_TYPE (string_cst)), | |
1198 | m_string_cst (string_cst) | |
1199 | {} | |
1200 | ||
1201 | const string_region * | |
ff171cb1 | 1202 | dyn_cast_string_region () const final override { return this; } |
e9751143 | 1203 | |
ff171cb1 | 1204 | enum region_kind get_kind () const final override { return RK_STRING; } |
e9751143 | 1205 | |
ff171cb1 | 1206 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 | 1207 | |
68871a00 DM |
1208 | /* We assume string literals are immutable, so we don't track them in |
1209 | the store. */ | |
1210 | bool tracked_p () const final override { return false; } | |
1211 | ||
e9751143 DM |
1212 | tree get_string_cst () const { return m_string_cst; } |
1213 | ||
1214 | private: | |
1215 | tree m_string_cst; | |
1216 | }; | |
1217 | ||
1218 | } // namespace ana | |
1219 | ||
1220 | template <> | |
1221 | template <> | |
1222 | inline bool | |
1223 | is_a_helper <const string_region *>::test (const region *reg) | |
1224 | { | |
1225 | return reg->get_kind () == RK_STRING; | |
1226 | } | |
1227 | ||
1228 | namespace ana { | |
1229 | ||
93e759fc DM |
1230 | /* A region for a specific range of bits within another region. */ |
1231 | ||
1232 | class bit_range_region : public region | |
1233 | { | |
1234 | public: | |
1235 | /* A support class for uniquifying instances of bit_range_region. */ | |
1236 | struct key_t | |
1237 | { | |
1238 | key_t (const region *parent, tree type, const bit_range &bits) | |
1239 | : m_parent (parent), m_type (type), m_bits (bits) | |
1240 | { | |
1241 | gcc_assert (parent); | |
1242 | } | |
1243 | ||
1244 | hashval_t hash () const | |
1245 | { | |
1246 | inchash::hash hstate; | |
1247 | hstate.add_ptr (m_parent); | |
1248 | hstate.add_ptr (m_type); | |
391512ad DM |
1249 | hstate.add_wide_int (m_bits.m_start_bit_offset); |
1250 | hstate.add_wide_int (m_bits.m_size_in_bits); | |
93e759fc DM |
1251 | return hstate.end (); |
1252 | } | |
1253 | ||
1254 | bool operator== (const key_t &other) const | |
1255 | { | |
1256 | return (m_parent == other.m_parent | |
1257 | && m_type == other.m_type | |
1258 | && m_bits == other.m_bits); | |
1259 | } | |
1260 | ||
1261 | void mark_deleted () { m_parent = reinterpret_cast<const region *> (1); } | |
1262 | void mark_empty () { m_parent = NULL; } | |
1263 | bool is_deleted () const | |
1264 | { | |
1265 | return m_parent == reinterpret_cast<const region *> (1); | |
1266 | } | |
1267 | bool is_empty () const { return m_parent == NULL; } | |
1268 | ||
1269 | const region *m_parent; | |
1270 | tree m_type; | |
1271 | bit_range m_bits; | |
1272 | }; | |
1273 | ||
1274 | bit_range_region (unsigned id, const region *parent, tree type, | |
1275 | const bit_range &bits) | |
1276 | : region (complexity (parent), id, parent, type), | |
1277 | m_bits (bits) | |
1278 | {} | |
1279 | ||
1280 | const bit_range_region * | |
ff171cb1 | 1281 | dyn_cast_bit_range_region () const final override { return this; } |
93e759fc | 1282 | |
ff171cb1 | 1283 | enum region_kind get_kind () const final override { return RK_BIT_RANGE; } |
93e759fc | 1284 | |
ff171cb1 | 1285 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
93e759fc DM |
1286 | |
1287 | const bit_range &get_bits () const { return m_bits; } | |
1288 | ||
ff171cb1 DM |
1289 | bool get_byte_size (byte_size_t *out) const final override; |
1290 | bool get_bit_size (bit_size_t *out) const final override; | |
1291 | const svalue *get_byte_size_sval (region_model_manager *mgr) const final override; | |
1292 | bool get_relative_concrete_offset (bit_offset_t *out) const final override; | |
7a6564c9 TL |
1293 | const svalue *get_relative_symbolic_offset (region_model_manager *mgr) |
1294 | const final override; | |
93e759fc DM |
1295 | |
1296 | private: | |
1297 | bit_range m_bits; | |
1298 | }; | |
1299 | ||
1300 | } // namespace ana | |
1301 | ||
1302 | template <> | |
1303 | template <> | |
1304 | inline bool | |
1305 | is_a_helper <const bit_range_region *>::test (const region *reg) | |
1306 | { | |
1307 | return reg->get_kind () == RK_BIT_RANGE; | |
1308 | } | |
1309 | ||
1310 | template <> struct default_hash_traits<bit_range_region::key_t> | |
1311 | : public member_function_hash_traits<bit_range_region::key_t> | |
1312 | { | |
1313 | static const bool empty_zero_p = true; | |
1314 | }; | |
1315 | ||
1316 | namespace ana { | |
1317 | ||
2402dc6b DM |
1318 | /* A region for the N-th vararg within a frame_region for a variadic call. */ |
1319 | ||
1320 | class var_arg_region : public region | |
1321 | { | |
1322 | public: | |
1323 | /* A support class for uniquifying instances of var_arg_region. */ | |
1324 | struct key_t | |
1325 | { | |
1326 | key_t (const frame_region *parent, unsigned idx) | |
1327 | : m_parent (parent), m_idx (idx) | |
1328 | { | |
1329 | gcc_assert (parent); | |
1330 | } | |
1331 | ||
1332 | hashval_t hash () const | |
1333 | { | |
1334 | inchash::hash hstate; | |
1335 | hstate.add_ptr (m_parent); | |
1336 | hstate.add_int (m_idx); | |
1337 | return hstate.end (); | |
1338 | } | |
1339 | ||
1340 | bool operator== (const key_t &other) const | |
1341 | { | |
1342 | return (m_parent == other.m_parent | |
1343 | && m_idx == other.m_idx); | |
1344 | } | |
1345 | ||
1346 | void mark_deleted () | |
1347 | { | |
1348 | m_parent = reinterpret_cast<const frame_region *> (1); | |
1349 | } | |
1350 | void mark_empty () { m_parent = NULL; } | |
1351 | bool is_deleted () const | |
1352 | { | |
1353 | return m_parent == reinterpret_cast<const frame_region *> (1); | |
1354 | } | |
1355 | bool is_empty () const { return m_parent == NULL; } | |
1356 | ||
1357 | const frame_region *m_parent; | |
1358 | unsigned m_idx; | |
1359 | }; | |
1360 | ||
1361 | var_arg_region (unsigned id, const frame_region *parent, | |
1362 | unsigned idx) | |
1363 | : region (complexity (parent), id, parent, NULL_TREE), | |
1364 | m_idx (idx) | |
1365 | {} | |
1366 | ||
1367 | const var_arg_region * | |
ff171cb1 | 1368 | dyn_cast_var_arg_region () const final override { return this; } |
2402dc6b | 1369 | |
ff171cb1 | 1370 | enum region_kind get_kind () const final override { return RK_VAR_ARG; } |
2402dc6b | 1371 | |
ff171cb1 | 1372 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
2402dc6b DM |
1373 | |
1374 | const frame_region *get_frame_region () const; | |
1375 | unsigned get_index () const { return m_idx; } | |
1376 | ||
1377 | private: | |
1378 | unsigned m_idx; | |
1379 | }; | |
1380 | ||
1381 | } // namespace ana | |
1382 | ||
1383 | template <> | |
1384 | template <> | |
1385 | inline bool | |
1386 | is_a_helper <const var_arg_region *>::test (const region *reg) | |
1387 | { | |
1388 | return reg->get_kind () == RK_VAR_ARG; | |
1389 | } | |
1390 | ||
1391 | template <> struct default_hash_traits<var_arg_region::key_t> | |
1392 | : public member_function_hash_traits<var_arg_region::key_t> | |
1393 | { | |
1394 | static const bool empty_zero_p = true; | |
1395 | }; | |
1396 | ||
1397 | namespace ana { | |
1398 | ||
3d2d04cd DM |
1399 | /* A region for errno for the current thread. */ |
1400 | ||
1401 | class errno_region : public region | |
1402 | { | |
1403 | public: | |
1404 | errno_region (unsigned id, const thread_local_region *parent) | |
1405 | : region (complexity (parent), id, parent, integer_type_node) | |
1406 | {} | |
1407 | ||
1408 | enum region_kind get_kind () const final override { return RK_ERRNO; } | |
1409 | ||
1410 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; | |
1411 | }; | |
1412 | ||
1413 | } // namespace ana | |
1414 | ||
1415 | template <> | |
1416 | template <> | |
1417 | inline bool | |
1418 | is_a_helper <const errno_region *>::test (const region *reg) | |
1419 | { | |
1420 | return reg->get_kind () == RK_ERRNO; | |
1421 | } | |
1422 | ||
1423 | namespace ana { | |
1424 | ||
e9751143 DM |
1425 | /* An unknown region, for handling unimplemented tree codes. */ |
1426 | ||
1427 | class unknown_region : public region | |
1428 | { | |
1429 | public: | |
1430 | unknown_region (unsigned id, const region *parent, tree type) | |
1431 | : region (complexity (parent), id, parent, type) | |
1432 | {} | |
1433 | ||
ff171cb1 | 1434 | enum region_kind get_kind () const final override { return RK_UNKNOWN; } |
e9751143 | 1435 | |
ff171cb1 | 1436 | void dump_to_pp (pretty_printer *pp, bool simple) const final override; |
e9751143 DM |
1437 | }; |
1438 | ||
1439 | } // namespace ana | |
1440 | ||
1441 | #endif /* GCC_ANALYZER_REGION_H */ |