]>
Commit | Line | Data |
---|---|---|
e9751143 | 1 | /* Regions of memory. |
99dee823 | 2 | Copyright (C) 2019-2021 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 | ||
28 | /* An enum for discriminating between the different concrete subclasses | |
29 | of region. */ | |
30 | ||
31 | enum region_kind | |
32 | { | |
33 | RK_FRAME, | |
34 | RK_GLOBALS, | |
35 | RK_CODE, | |
36 | RK_FUNCTION, | |
37 | RK_LABEL, | |
38 | RK_STACK, | |
39 | RK_HEAP, | |
40 | RK_ROOT, | |
41 | RK_SYMBOLIC, | |
42 | RK_DECL, | |
43 | RK_FIELD, | |
44 | RK_ELEMENT, | |
45 | RK_OFFSET, | |
46 | RK_CAST, | |
47 | RK_HEAP_ALLOCATED, | |
48 | RK_ALLOCA, | |
49 | RK_STRING, | |
50 | RK_UNKNOWN | |
51 | }; | |
52 | ||
53 | /* Region and its subclasses. | |
54 | ||
55 | The class hierarchy looks like this (using indentation to show | |
56 | inheritance, and with region_kinds shown for the concrete subclasses): | |
57 | ||
58 | region | |
59 | space_region | |
60 | frame_region (RK_FRAME) | |
61 | globals_region (RK_GLOBALS) | |
62 | code_region (RK_CODE) | |
63 | stack_region (RK_STACK) | |
64 | heap_region (RK_HEAP) | |
65 | root_region (RK_ROOT) | |
66 | function_region (RK_FUNCTION) | |
67 | label_region (RK_LABEL) | |
68 | symbolic_region (RK_SYMBOLIC) | |
69 | decl_region (RK_DECL), | |
70 | field_region (RK_FIELD) | |
71 | element_region (RK_ELEMENT) | |
72 | offset_region (RK_OFFSET) | |
73 | cast_region (RK_CAST) | |
74 | heap_allocated_region (RK_HEAP_ALLOCATED) | |
75 | alloca_region (RK_ALLOCA) | |
76 | string_region (RK_STRING) | |
77 | unknown_region (RK_UNKNOWN). */ | |
78 | ||
79 | /* Abstract base class for representing ways of accessing chunks of memory. | |
80 | ||
81 | Regions form a tree-like hierarchy, with a root region at the base, | |
82 | with memory space regions within it, representing the stack and | |
83 | globals, with frames within the stack, and regions for variables | |
84 | within the frames and the "globals" region. Regions for structs | |
85 | can have subregions for fields. */ | |
86 | ||
87 | class region | |
88 | { | |
89 | public: | |
90 | virtual ~region (); | |
91 | ||
92 | unsigned get_id () const { return m_id; } | |
93 | static int cmp_ids (const region *reg1, const region *reg2); | |
94 | ||
95 | virtual enum region_kind get_kind () const = 0; | |
96 | virtual const frame_region * | |
97 | dyn_cast_frame_region () const { return NULL; } | |
98 | virtual const function_region * | |
99 | dyn_cast_function_region () const { return NULL; } | |
100 | virtual const symbolic_region * | |
101 | dyn_cast_symbolic_region () const { return NULL; } | |
102 | virtual const decl_region * | |
103 | dyn_cast_decl_region () const { return NULL; } | |
104 | virtual const field_region * | |
105 | dyn_cast_field_region () const { return NULL; } | |
106 | virtual const element_region * | |
107 | dyn_cast_element_region () const { return NULL; } | |
108 | virtual const offset_region * | |
109 | dyn_cast_offset_region () const { return NULL; } | |
110 | virtual const cast_region * | |
111 | dyn_cast_cast_region () const { return NULL; } | |
112 | virtual const string_region * | |
113 | dyn_cast_string_region () const { return NULL; } | |
114 | ||
115 | virtual void accept (visitor *v) const; | |
116 | ||
117 | const region *get_parent_region () const { return m_parent; } | |
118 | const region *get_base_region () const; | |
119 | bool base_region_p () const; | |
120 | bool descendent_of_p (const region *elder) const; | |
121 | const frame_region *maybe_get_frame_region () const; | |
122 | ||
123 | tree maybe_get_decl () const; | |
124 | ||
125 | tree get_type () const { return m_type; } | |
126 | ||
127 | void print (const region_model &model, | |
128 | pretty_printer *pp) const; | |
129 | label_text get_desc (bool simple=true) const; | |
130 | ||
131 | void dump_to_pp (const region_model &model, | |
132 | pretty_printer *pp, | |
133 | const char *prefix, | |
134 | bool is_last_child) const; | |
135 | ||
136 | virtual void dump_to_pp (pretty_printer *pp, bool simple) const = 0; | |
137 | void dump (bool simple) const; | |
138 | ||
139 | json::value *to_json () const; | |
140 | ||
141 | bool non_null_p () const; | |
142 | ||
143 | static int cmp_ptr_ptr (const void *, const void *); | |
144 | ||
145 | region_offset get_offset () const; | |
146 | bool get_byte_size (byte_size_t *out) const; | |
147 | bool get_bit_size (bit_size_t *out) const; | |
148 | ||
149 | void | |
150 | get_subregions_for_binding (region_model_manager *mgr, | |
151 | bit_offset_t start_bit_offset, | |
152 | bit_size_t size_in_bits, | |
153 | tree type, | |
154 | auto_vec <const region *> *out) const; | |
155 | ||
156 | bool symbolic_for_unknown_ptr_p () const; | |
157 | ||
158 | const complexity &get_complexity () const { return m_complexity; } | |
159 | ||
160 | protected: | |
161 | region (complexity c, unsigned id, const region *parent, tree type); | |
162 | ||
163 | private: | |
164 | region_offset calc_offset () const; | |
165 | ||
166 | complexity m_complexity; | |
167 | unsigned m_id; // purely for deterministic sorting at this stage, for dumps | |
168 | const region *m_parent; | |
169 | tree m_type; | |
170 | ||
171 | mutable region_offset *m_cached_offset; | |
172 | }; | |
173 | ||
174 | } // namespace ana | |
175 | ||
176 | template <> | |
177 | template <> | |
178 | inline bool | |
179 | is_a_helper <const region *>::test (const region *) | |
180 | { | |
181 | return true; | |
182 | } | |
183 | ||
184 | namespace ana { | |
185 | ||
186 | /* Abstract subclass of region, for regions that represent an untyped | |
187 | space within memory, such as the stack or the heap. */ | |
188 | ||
189 | class space_region : public region | |
190 | { | |
191 | protected: | |
192 | space_region (unsigned id, const region *parent) | |
193 | : region (complexity (parent), id, parent, NULL_TREE) | |
194 | {} | |
195 | }; | |
196 | ||
197 | /* Concrete space_region subclass, representing a function frame on the stack, | |
198 | to contain the locals. | |
199 | The parent is the stack region; there's also a hierarchy of call-stack | |
200 | prefixes expressed via m_calling_frame. | |
201 | For example, given "oldest" calling "middle" called "newest" we would have | |
202 | - a stack depth of 3 | |
203 | - frame (A) for "oldest" with index 0 for depth 1, calling_frame == NULL | |
204 | - frame (B) for "middle" with index 1 for depth 2, calling_frame == (A) | |
205 | - frame (C) for "newest" with index 2 for depth 3, calling_frame == (B) | |
206 | where the parent region for each of the frames is the "stack" region. | |
207 | The index is the count of frames earlier than this in the stack. */ | |
208 | ||
209 | class frame_region : public space_region | |
210 | { | |
211 | public: | |
212 | /* A support class for uniquifying instances of frame_region. */ | |
213 | struct key_t | |
214 | { | |
215 | key_t (const frame_region *calling_frame, function *fun) | |
216 | : m_calling_frame (calling_frame), m_fun (fun) | |
217 | { | |
218 | /* calling_frame can be NULL. */ | |
219 | gcc_assert (fun); | |
220 | } | |
221 | ||
222 | hashval_t hash () const | |
223 | { | |
224 | inchash::hash hstate; | |
225 | hstate.add_ptr (m_calling_frame); | |
226 | hstate.add_ptr (m_fun); | |
227 | return hstate.end (); | |
228 | } | |
229 | ||
230 | bool operator== (const key_t &other) const | |
231 | { | |
232 | return (m_calling_frame == other.m_calling_frame && m_fun == other.m_fun); | |
233 | } | |
234 | ||
235 | void mark_deleted () { m_fun = reinterpret_cast<function *> (1); } | |
236 | void mark_empty () { m_fun = NULL; } | |
237 | bool is_deleted () const | |
238 | { | |
239 | return m_fun == reinterpret_cast<function *> (1); | |
240 | } | |
241 | bool is_empty () const { return m_fun == NULL; } | |
242 | ||
243 | const frame_region *m_calling_frame; | |
244 | function *m_fun; | |
245 | }; | |
246 | ||
247 | frame_region (unsigned id, const region *parent, | |
248 | const frame_region *calling_frame, | |
249 | function *fun, int index) | |
250 | : space_region (id, parent), m_calling_frame (calling_frame), | |
251 | m_fun (fun), m_index (index) | |
252 | {} | |
253 | ~frame_region (); | |
254 | ||
255 | /* region vfuncs. */ | |
256 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_FRAME; } | |
257 | const frame_region * dyn_cast_frame_region () const FINAL OVERRIDE | |
258 | { | |
259 | return this; | |
260 | } | |
261 | void accept (visitor *v) const FINAL OVERRIDE; | |
262 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
263 | ||
264 | /* Accessors. */ | |
265 | const frame_region *get_calling_frame () const { return m_calling_frame; } | |
266 | function *get_function () const { return m_fun; } | |
267 | int get_index () const { return m_index; } | |
268 | int get_stack_depth () const { return m_index + 1; } | |
269 | ||
270 | const decl_region *get_region_for_local (region_model_manager *mgr, | |
271 | tree expr) const; | |
272 | ||
273 | unsigned get_num_locals () const { return m_locals.elements (); } | |
274 | ||
275 | private: | |
276 | const frame_region *m_calling_frame; | |
277 | function *m_fun; | |
278 | int m_index; | |
279 | ||
280 | /* The regions for the decls within this frame are managed by this | |
281 | object, rather than the region_model_manager, to make it a simple | |
282 | lookup by tree. */ | |
283 | typedef hash_map<tree, decl_region *> map_t; | |
284 | map_t m_locals; | |
285 | }; | |
286 | ||
287 | } // namespace ana | |
288 | ||
289 | template <> | |
290 | template <> | |
291 | inline bool | |
292 | is_a_helper <const frame_region *>::test (const region *reg) | |
293 | { | |
294 | return reg->get_kind () == RK_FRAME; | |
295 | } | |
296 | ||
297 | template <> struct default_hash_traits<frame_region::key_t> | |
298 | : public member_function_hash_traits<frame_region::key_t> | |
299 | { | |
300 | static const bool empty_zero_p = true; | |
301 | }; | |
302 | ||
303 | namespace ana { | |
304 | ||
305 | /* Concrete space_region subclass, to hold global variables (data and bss). */ | |
306 | ||
307 | class globals_region : public space_region | |
308 | { | |
309 | public: | |
310 | globals_region (unsigned id, const region *parent) | |
311 | : space_region (id, parent) | |
312 | {} | |
313 | ||
314 | /* region vfuncs. */ | |
315 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_GLOBALS; } | |
316 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
317 | }; | |
318 | ||
319 | } // namespace ana | |
320 | ||
321 | template <> | |
322 | template <> | |
323 | inline bool | |
324 | is_a_helper <const globals_region *>::test (const region *reg) | |
325 | { | |
326 | return reg->get_kind () == RK_GLOBALS; | |
327 | } | |
328 | ||
329 | namespace ana { | |
330 | ||
331 | /* Concrete space_region subclass, representing the code segment | |
332 | containing functions. */ | |
333 | ||
334 | class code_region : public space_region | |
335 | { | |
336 | public: | |
337 | code_region (unsigned id, const region *parent) | |
338 | : space_region (id, parent) | |
339 | {} | |
340 | ||
341 | /* region vfuncs. */ | |
342 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
343 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_CODE; } | |
344 | ||
345 | const region *get_element (region_model *model, | |
346 | const svalue *index, | |
347 | region_model_context *ctxt); | |
348 | }; | |
349 | ||
350 | } // namespace ana | |
351 | ||
352 | template <> | |
353 | template <> | |
354 | inline bool | |
355 | is_a_helper <const code_region *>::test (const region *reg) | |
356 | { | |
357 | return reg->get_kind () == RK_CODE; | |
358 | } | |
359 | ||
360 | namespace ana { | |
361 | ||
362 | /* Concrete region subclass. A region representing the code for | |
363 | a particular function. */ | |
364 | ||
365 | class function_region : public region | |
366 | { | |
367 | public: | |
368 | function_region (unsigned id, const code_region *parent, tree fndecl) | |
369 | : region (complexity (parent), id, parent, TREE_TYPE (fndecl)), | |
370 | m_fndecl (fndecl) | |
371 | { | |
372 | gcc_assert (FUNC_OR_METHOD_TYPE_P (TREE_TYPE (fndecl))); | |
373 | } | |
374 | ||
375 | /* region vfuncs. */ | |
376 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
377 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_FUNCTION; } | |
378 | const function_region * | |
379 | dyn_cast_function_region () const FINAL OVERRIDE{ return this; } | |
380 | ||
381 | tree get_fndecl () const { return m_fndecl; } | |
382 | ||
383 | region *get_element (region_model *model, | |
384 | const svalue *index_sid, | |
385 | region_model_context *ctxt); | |
386 | ||
387 | private: | |
388 | tree m_fndecl; | |
389 | }; | |
390 | ||
391 | } // namespace ana | |
392 | ||
393 | template <> | |
394 | template <> | |
395 | inline bool | |
396 | is_a_helper <const function_region *>::test (const region *reg) | |
397 | { | |
398 | return reg->get_kind () == RK_FUNCTION; | |
399 | } | |
400 | ||
401 | namespace ana { | |
402 | ||
403 | /* Concrete region subclass. A region representing a particular label | |
404 | within a function. */ | |
405 | ||
406 | class label_region : public region | |
407 | { | |
408 | public: | |
409 | label_region (unsigned id, const function_region *parent, tree label) | |
410 | : region (complexity (parent), id, parent, NULL_TREE), m_label (label) | |
411 | { | |
412 | gcc_assert (TREE_CODE (label) == LABEL_DECL); | |
413 | } | |
414 | ||
415 | /* region vfuncs. */ | |
416 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
417 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_LABEL; } | |
418 | ||
419 | tree get_label () const { return m_label; } | |
420 | ||
421 | private: | |
422 | tree m_label; | |
423 | }; | |
424 | ||
425 | } // namespace ana | |
426 | ||
427 | template <> | |
428 | template <> | |
429 | inline bool | |
430 | is_a_helper <const label_region *>::test (const region *reg) | |
431 | { | |
432 | return reg->get_kind () == RK_LABEL; | |
433 | } | |
434 | ||
435 | namespace ana { | |
436 | ||
437 | /* Concrete space_region subclass representing a stack, containing all stack | |
438 | frames. */ | |
439 | ||
440 | class stack_region : public space_region | |
441 | { | |
442 | public: | |
443 | stack_region (unsigned id, region *parent) | |
444 | : space_region (id, parent) | |
445 | {} | |
446 | ||
447 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
448 | ||
449 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_STACK; } | |
450 | }; | |
451 | ||
452 | } // namespace ana | |
453 | ||
454 | template <> | |
455 | template <> | |
456 | inline bool | |
457 | is_a_helper <const stack_region *>::test (const region *reg) | |
458 | { | |
459 | return reg->get_kind () == RK_STACK; | |
460 | } | |
461 | ||
462 | namespace ana { | |
463 | ||
464 | /* Concrete space_region subclass: a region within which regions can be | |
465 | dynamically allocated. */ | |
466 | ||
467 | class heap_region : public space_region | |
468 | { | |
469 | public: | |
470 | heap_region (unsigned id, region *parent) | |
471 | : space_region (id, parent) | |
472 | {} | |
473 | ||
474 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_HEAP; } | |
475 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
476 | }; | |
477 | ||
478 | } // namespace ana | |
479 | ||
480 | template <> | |
481 | template <> | |
482 | inline bool | |
483 | is_a_helper <const heap_region *>::test (const region *reg) | |
484 | { | |
485 | return reg->get_kind () == RK_HEAP; | |
486 | } | |
487 | ||
488 | namespace ana { | |
489 | ||
490 | /* Concrete region subclass. The root region, containing all regions | |
491 | (either directly, or as descendents). | |
492 | Unique within a region_model_manager. */ | |
493 | ||
494 | class root_region : public region | |
495 | { | |
496 | public: | |
497 | root_region (unsigned id); | |
498 | ||
499 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_ROOT; } | |
500 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
501 | }; | |
502 | ||
503 | } // namespace ana | |
504 | ||
505 | template <> | |
506 | template <> | |
507 | inline bool | |
508 | is_a_helper <const root_region *>::test (const region *reg) | |
509 | { | |
510 | return reg->get_kind () == RK_ROOT; | |
511 | } | |
512 | ||
513 | namespace ana { | |
514 | ||
515 | /* Concrete region subclass: a region to use when dereferencing an unknown | |
516 | pointer. */ | |
517 | ||
518 | class symbolic_region : public region | |
519 | { | |
520 | public: | |
521 | /* A support class for uniquifying instances of symbolic_region. */ | |
522 | struct key_t | |
523 | { | |
524 | key_t (const region *parent, const svalue *sval_ptr) | |
525 | : m_parent (parent), m_sval_ptr (sval_ptr) | |
526 | { | |
527 | gcc_assert (sval_ptr); | |
528 | } | |
529 | ||
530 | hashval_t hash () const | |
531 | { | |
532 | inchash::hash hstate; | |
533 | hstate.add_ptr (m_parent); | |
534 | hstate.add_ptr (m_sval_ptr); | |
535 | return hstate.end (); | |
536 | } | |
537 | ||
538 | bool operator== (const key_t &other) const | |
539 | { | |
540 | return (m_parent == other.m_parent && m_sval_ptr == other.m_sval_ptr); | |
541 | } | |
542 | ||
543 | void mark_deleted () { m_sval_ptr = reinterpret_cast<const svalue *> (1); } | |
544 | void mark_empty () { m_sval_ptr = NULL; } | |
545 | bool is_deleted () const | |
546 | { | |
547 | return m_sval_ptr == reinterpret_cast<const svalue *> (1); | |
548 | } | |
549 | bool is_empty () const { return m_sval_ptr == NULL; } | |
550 | ||
551 | const region *m_parent; | |
552 | const svalue *m_sval_ptr; | |
553 | }; | |
554 | ||
555 | symbolic_region (unsigned id, region *parent, const svalue *sval_ptr); | |
556 | ||
557 | const symbolic_region * | |
558 | dyn_cast_symbolic_region () const FINAL OVERRIDE { return this; } | |
559 | ||
560 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_SYMBOLIC; } | |
561 | void accept (visitor *v) const FINAL OVERRIDE; | |
562 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
563 | ||
564 | const svalue *get_pointer () const { return m_sval_ptr; } | |
565 | ||
566 | private: | |
567 | const svalue *m_sval_ptr; | |
568 | }; | |
569 | ||
570 | } // namespace ana | |
571 | ||
572 | template <> | |
573 | template <> | |
574 | inline bool | |
575 | is_a_helper <const symbolic_region *>::test (const region *reg) | |
576 | { | |
577 | return reg->get_kind () == RK_SYMBOLIC; | |
578 | } | |
579 | ||
580 | template <> struct default_hash_traits<symbolic_region::key_t> | |
581 | : public member_function_hash_traits<symbolic_region::key_t> | |
582 | { | |
583 | static const bool empty_zero_p = true; | |
584 | }; | |
585 | ||
586 | namespace ana { | |
587 | ||
588 | /* Concrete region subclass representing the memory occupied by a | |
589 | variable (whether for a global or a local). */ | |
590 | ||
591 | class decl_region : public region | |
592 | { | |
593 | public: | |
594 | decl_region (unsigned id, const region *parent, tree decl) | |
595 | : region (complexity (parent), id, parent, TREE_TYPE (decl)), m_decl (decl) | |
596 | {} | |
597 | ||
598 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_DECL; } | |
599 | const decl_region * | |
600 | dyn_cast_decl_region () const FINAL OVERRIDE { return this; } | |
601 | ||
602 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
603 | ||
604 | tree get_decl () const { return m_decl; } | |
605 | int get_stack_depth () const; | |
606 | ||
607 | const svalue *maybe_get_constant_value (region_model_manager *mgr) const; | |
608 | const svalue *get_svalue_for_constructor (tree ctor, | |
609 | region_model_manager *mgr) const; | |
610 | const svalue *get_svalue_for_initializer (region_model_manager *mgr) const; | |
611 | ||
612 | private: | |
613 | tree m_decl; | |
614 | }; | |
615 | ||
616 | } // namespace ana | |
617 | ||
618 | template <> | |
619 | template <> | |
620 | inline bool | |
621 | is_a_helper <const decl_region *>::test (const region *reg) | |
622 | { | |
623 | return reg->get_kind () == RK_DECL; | |
624 | } | |
625 | ||
626 | namespace ana { | |
627 | ||
628 | /* Concrete region subclass representing the memory occupied by a | |
629 | field within a struct or union. */ | |
630 | ||
631 | class field_region : public region | |
632 | { | |
633 | public: | |
634 | /* A support class for uniquifying instances of field_region. */ | |
635 | struct key_t | |
636 | { | |
637 | key_t (const region *parent, tree field) | |
638 | : m_parent (parent), m_field (field) | |
639 | { | |
640 | gcc_assert (field); | |
641 | } | |
642 | ||
643 | hashval_t hash () const | |
644 | { | |
645 | inchash::hash hstate; | |
646 | hstate.add_ptr (m_parent); | |
647 | hstate.add_ptr (m_field); | |
648 | return hstate.end (); | |
649 | } | |
650 | ||
651 | bool operator== (const key_t &other) const | |
652 | { | |
653 | return (m_parent == other.m_parent && m_field == other.m_field); | |
654 | } | |
655 | ||
656 | void mark_deleted () { m_field = reinterpret_cast<tree> (1); } | |
657 | void mark_empty () { m_field = NULL_TREE; } | |
658 | bool is_deleted () const { return m_field == reinterpret_cast<tree> (1); } | |
659 | bool is_empty () const { return m_field == NULL_TREE; } | |
660 | ||
661 | const region *m_parent; | |
662 | tree m_field; | |
663 | }; | |
664 | ||
665 | field_region (unsigned id, const region *parent, tree field) | |
666 | : region (complexity (parent), id, parent, TREE_TYPE (field)), | |
667 | m_field (field) | |
668 | {} | |
669 | ||
670 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_FIELD; } | |
671 | ||
672 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
673 | const field_region * | |
674 | dyn_cast_field_region () const FINAL OVERRIDE { return this; } | |
675 | ||
676 | tree get_field () const { return m_field; } | |
677 | ||
678 | private: | |
679 | tree m_field; | |
680 | }; | |
681 | ||
682 | } // namespace ana | |
683 | ||
684 | template <> | |
685 | template <> | |
686 | inline bool | |
687 | is_a_helper <const field_region *>::test (const region *reg) | |
688 | { | |
689 | return reg->get_kind () == RK_FIELD; | |
690 | } | |
691 | ||
692 | template <> struct default_hash_traits<field_region::key_t> | |
693 | : public member_function_hash_traits<field_region::key_t> | |
694 | { | |
695 | static const bool empty_zero_p = true; | |
696 | }; | |
697 | ||
698 | namespace ana { | |
699 | ||
700 | /* An element within an array. */ | |
701 | ||
702 | class element_region : public region | |
703 | { | |
704 | public: | |
705 | /* A support class for uniquifying instances of element_region. */ | |
706 | struct key_t | |
707 | { | |
708 | key_t (const region *parent, tree element_type, const svalue *index) | |
709 | : m_parent (parent), m_element_type (element_type), m_index (index) | |
710 | { | |
711 | gcc_assert (index); | |
712 | } | |
713 | ||
714 | hashval_t hash () const | |
715 | { | |
716 | inchash::hash hstate; | |
717 | hstate.add_ptr (m_parent); | |
718 | hstate.add_ptr (m_element_type); | |
719 | hstate.add_ptr (m_index); | |
720 | return hstate.end (); | |
721 | } | |
722 | ||
723 | bool operator== (const key_t &other) const | |
724 | { | |
725 | return (m_parent == other.m_parent | |
726 | && m_element_type == other.m_element_type | |
727 | && m_index == other.m_index); | |
728 | } | |
729 | ||
730 | void mark_deleted () { m_index = reinterpret_cast<const svalue *> (1); } | |
731 | void mark_empty () { m_index = NULL; } | |
732 | bool is_deleted () const | |
733 | { | |
734 | return m_index == reinterpret_cast<const svalue *> (1); | |
735 | } | |
736 | bool is_empty () const { return m_index == NULL; } | |
737 | ||
738 | const region *m_parent; | |
739 | tree m_element_type; | |
740 | const svalue *m_index; | |
741 | }; | |
742 | ||
743 | element_region (unsigned id, const region *parent, tree element_type, | |
744 | const svalue *index) | |
745 | : region (complexity::from_pair (parent, index), id, parent, element_type), | |
746 | m_index (index) | |
747 | {} | |
748 | ||
749 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_ELEMENT; } | |
750 | const element_region * | |
751 | dyn_cast_element_region () const FINAL OVERRIDE { return this; } | |
752 | ||
753 | void accept (visitor *v) const FINAL OVERRIDE; | |
754 | ||
755 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
756 | ||
757 | const svalue *get_index () const { return m_index; } | |
758 | ||
759 | private: | |
760 | const svalue *m_index; | |
761 | }; | |
762 | ||
763 | } // namespace ana | |
764 | ||
765 | template <> | |
766 | template <> | |
767 | inline bool | |
768 | is_a_helper <const element_region *>::test (const region *reg) | |
769 | { | |
770 | return reg->get_kind () == RK_ELEMENT; | |
771 | } | |
772 | ||
773 | template <> struct default_hash_traits<element_region::key_t> | |
774 | : public member_function_hash_traits<element_region::key_t> | |
775 | { | |
776 | static const bool empty_zero_p = true; | |
777 | }; | |
778 | ||
779 | namespace ana { | |
780 | ||
781 | /* A byte-offset within another region, for handling pointer arithmetic | |
782 | as a region. */ | |
783 | ||
784 | class offset_region : public region | |
785 | { | |
786 | public: | |
787 | /* A support class for uniquifying instances of offset_region. */ | |
788 | struct key_t | |
789 | { | |
790 | key_t (const region *parent, tree element_type, const svalue *byte_offset) | |
791 | : m_parent (parent), m_element_type (element_type), m_byte_offset (byte_offset) | |
792 | { | |
793 | gcc_assert (byte_offset); | |
794 | } | |
795 | ||
796 | hashval_t hash () const | |
797 | { | |
798 | inchash::hash hstate; | |
799 | hstate.add_ptr (m_parent); | |
800 | hstate.add_ptr (m_element_type); | |
801 | hstate.add_ptr (m_byte_offset); | |
802 | return hstate.end (); | |
803 | } | |
804 | ||
805 | bool operator== (const key_t &other) const | |
806 | { | |
807 | return (m_parent == other.m_parent | |
808 | && m_element_type == other.m_element_type | |
809 | && m_byte_offset == other.m_byte_offset); | |
810 | } | |
811 | ||
812 | void mark_deleted () { m_byte_offset = reinterpret_cast<const svalue *> (1); } | |
813 | void mark_empty () { m_byte_offset = NULL; } | |
814 | bool is_deleted () const | |
815 | { | |
816 | return m_byte_offset == reinterpret_cast<const svalue *> (1); | |
817 | } | |
818 | bool is_empty () const { return m_byte_offset == NULL; } | |
819 | ||
820 | const region *m_parent; | |
821 | tree m_element_type; | |
822 | const svalue *m_byte_offset; | |
823 | }; | |
824 | ||
825 | offset_region (unsigned id, const region *parent, tree type, | |
826 | const svalue *byte_offset) | |
827 | : region (complexity::from_pair (parent, byte_offset), id, parent, type), | |
828 | m_byte_offset (byte_offset) | |
829 | {} | |
830 | ||
831 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_OFFSET; } | |
832 | const offset_region * | |
833 | dyn_cast_offset_region () const FINAL OVERRIDE { return this; } | |
834 | ||
835 | void accept (visitor *v) const FINAL OVERRIDE; | |
836 | ||
837 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
838 | ||
839 | const svalue *get_byte_offset () const { return m_byte_offset; } | |
840 | ||
841 | private: | |
842 | const svalue *m_byte_offset; | |
843 | }; | |
844 | ||
845 | } // namespace ana | |
846 | ||
847 | template <> | |
848 | template <> | |
849 | inline bool | |
850 | is_a_helper <const offset_region *>::test (const region *reg) | |
851 | { | |
852 | return reg->get_kind () == RK_OFFSET; | |
853 | } | |
854 | ||
855 | template <> struct default_hash_traits<offset_region::key_t> | |
856 | : public member_function_hash_traits<offset_region::key_t> | |
857 | { | |
858 | static const bool empty_zero_p = true; | |
859 | }; | |
860 | ||
861 | namespace ana { | |
862 | ||
863 | /* A region that views another region using a different type. */ | |
864 | ||
865 | class cast_region : public region | |
866 | { | |
867 | public: | |
868 | /* A support class for uniquifying instances of cast_region. */ | |
869 | struct key_t | |
870 | { | |
871 | key_t (const region *original_region, tree type) | |
872 | : m_original_region (original_region), m_type (type) | |
873 | { | |
874 | gcc_assert (type); | |
875 | } | |
876 | ||
877 | hashval_t hash () const | |
878 | { | |
879 | inchash::hash hstate; | |
880 | hstate.add_ptr (m_original_region); | |
881 | hstate.add_ptr (m_type); | |
882 | return hstate.end (); | |
883 | } | |
884 | ||
885 | bool operator== (const key_t &other) const | |
886 | { | |
887 | return (m_original_region == other.m_original_region | |
888 | && m_type == other.m_type); | |
889 | } | |
890 | ||
891 | void mark_deleted () { m_type = reinterpret_cast<tree> (1); } | |
892 | void mark_empty () { m_type = NULL_TREE; } | |
893 | bool is_deleted () const { return m_type == reinterpret_cast<tree> (1); } | |
894 | bool is_empty () const { return m_type == NULL_TREE; } | |
895 | ||
896 | const region *m_original_region; | |
897 | tree m_type; | |
898 | }; | |
899 | ||
900 | cast_region (unsigned id, const region *original_region, tree type) | |
901 | : region (complexity (original_region), id, | |
902 | original_region->get_parent_region (), type), | |
903 | m_original_region (original_region) | |
904 | {} | |
905 | ||
906 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_CAST; } | |
907 | const cast_region * | |
908 | dyn_cast_cast_region () const FINAL OVERRIDE { return this; } | |
909 | void accept (visitor *v) const FINAL OVERRIDE; | |
910 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
911 | ||
912 | const region *get_original_region () const { return m_original_region; } | |
913 | ||
914 | private: | |
915 | const region *m_original_region; | |
916 | }; | |
917 | ||
918 | } // namespace ana | |
919 | ||
920 | template <> | |
921 | template <> | |
922 | inline bool | |
923 | is_a_helper <const cast_region *>::test (const region *reg) | |
924 | { | |
925 | return reg->get_kind () == RK_CAST; | |
926 | } | |
927 | ||
928 | template <> struct default_hash_traits<cast_region::key_t> | |
929 | : public member_function_hash_traits<cast_region::key_t> | |
930 | { | |
931 | static const bool empty_zero_p = true; | |
932 | }; | |
933 | ||
934 | namespace ana { | |
935 | ||
936 | /* An untyped region dynamically allocated on the heap via "malloc" | |
937 | or similar. */ | |
938 | ||
939 | class heap_allocated_region : public region | |
940 | { | |
941 | public: | |
942 | heap_allocated_region (unsigned id, const region *parent) | |
943 | : region (complexity (parent), id, parent, NULL_TREE) | |
944 | {} | |
945 | ||
946 | enum region_kind | |
947 | get_kind () const FINAL OVERRIDE { return RK_HEAP_ALLOCATED; } | |
948 | ||
949 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
950 | }; | |
951 | ||
952 | /* An untyped region dynamically allocated on the stack via "alloca". */ | |
953 | ||
954 | class alloca_region : public region | |
955 | { | |
956 | public: | |
957 | alloca_region (unsigned id, const frame_region *parent) | |
958 | : region (complexity (parent), id, parent, NULL_TREE) | |
959 | {} | |
960 | ||
961 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_ALLOCA; } | |
962 | ||
963 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
964 | }; | |
965 | ||
966 | /* A region for a STRING_CST. */ | |
967 | ||
968 | class string_region : public region | |
969 | { | |
970 | public: | |
971 | string_region (unsigned id, const region *parent, tree string_cst) | |
972 | : region (complexity (parent), id, parent, TREE_TYPE (string_cst)), | |
973 | m_string_cst (string_cst) | |
974 | {} | |
975 | ||
976 | const string_region * | |
977 | dyn_cast_string_region () const FINAL OVERRIDE { return this; } | |
978 | ||
979 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_STRING; } | |
980 | ||
981 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
982 | ||
983 | tree get_string_cst () const { return m_string_cst; } | |
984 | ||
985 | private: | |
986 | tree m_string_cst; | |
987 | }; | |
988 | ||
989 | } // namespace ana | |
990 | ||
991 | template <> | |
992 | template <> | |
993 | inline bool | |
994 | is_a_helper <const string_region *>::test (const region *reg) | |
995 | { | |
996 | return reg->get_kind () == RK_STRING; | |
997 | } | |
998 | ||
999 | namespace ana { | |
1000 | ||
1001 | /* An unknown region, for handling unimplemented tree codes. */ | |
1002 | ||
1003 | class unknown_region : public region | |
1004 | { | |
1005 | public: | |
1006 | unknown_region (unsigned id, const region *parent, tree type) | |
1007 | : region (complexity (parent), id, parent, type) | |
1008 | {} | |
1009 | ||
1010 | enum region_kind get_kind () const FINAL OVERRIDE { return RK_UNKNOWN; } | |
1011 | ||
1012 | void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; | |
1013 | }; | |
1014 | ||
1015 | } // namespace ana | |
1016 | ||
1017 | #endif /* GCC_ANALYZER_REGION_H */ |