]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/analyzer.h
36db4f2b53855ee91523e9ce50a86b6e101a1885
[thirdparty/gcc.git] / gcc / analyzer / analyzer.h
1 /* Utility functions for the analyzer.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #ifndef GCC_ANALYZER_ANALYZER_H
22 #define GCC_ANALYZER_ANALYZER_H
23
24 class graphviz_out;
25
26 namespace ana {
27
28 /* Forward decls of common types, with indentation to show inheritance. */
29
30 class supergraph;
31 class supernode;
32 class superedge;
33 class cfg_superedge;
34 class switch_cfg_superedge;
35 class callgraph_superedge;
36 class call_superedge;
37 class return_superedge;
38
39 class svalue;
40 class region_svalue;
41 class constant_svalue;
42 class unknown_svalue;
43 class poisoned_svalue;
44 class setjmp_svalue;
45 class initial_svalue;
46 class unaryop_svalue;
47 class binop_svalue;
48 class sub_svalue;
49 class repeated_svalue;
50 class bits_within_svalue;
51 class unmergeable_svalue;
52 class placeholder_svalue;
53 class widening_svalue;
54 class compound_svalue;
55 class conjured_svalue;
56 class asm_output_svalue;
57 class const_fn_result_svalue;
58 typedef hash_set<const svalue *> svalue_set;
59 class region;
60 class frame_region;
61 class function_region;
62 class label_region;
63 class decl_region;
64 class symbolic_region;
65 class element_region;
66 class offset_region;
67 class sized_region;
68 class cast_region;
69 class field_region;
70 class string_region;
71 class bit_range_region;
72 class region_model_manager;
73 struct model_merger;
74 class store_manager;
75 class store;
76 class region_model;
77 class region_model_context;
78 class impl_region_model_context;
79 class call_details;
80 class rejected_constraint;
81 class constraint_manager;
82 class equiv_class;
83 class reachable_regions;
84 class bounded_ranges;
85 class bounded_ranges_manager;
86
87 class pending_diagnostic;
88 class state_change_event;
89 class checker_path;
90 class extrinsic_state;
91 class sm_state_map;
92 class stmt_finder;
93 class program_point;
94 class function_point;
95 class program_state;
96 class exploded_graph;
97 class exploded_node;
98 class exploded_edge;
99 class feasibility_problem;
100 class exploded_cluster;
101 class exploded_path;
102 class analysis_plan;
103 class state_purge_map;
104 class state_purge_per_ssa_name;
105 class state_change;
106 class rewind_info_t;
107
108 class engine;
109 class state_machine;
110 class logger;
111 class visitor;
112
113 /* Forward decls of functions. */
114
115 extern void dump_tree (pretty_printer *pp, tree t);
116 extern void dump_quoted_tree (pretty_printer *pp, tree t);
117 extern void print_quoted_type (pretty_printer *pp, tree t);
118 extern int readability_comparator (const void *p1, const void *p2);
119 extern int tree_cmp (const void *p1, const void *p2);
120 extern tree fixup_tree_for_diagnostic (tree);
121 extern tree get_diagnostic_tree_for_gassign (const gassign *);
122
123 /* A tree, extended with stack frame information for locals, so that
124 we can distinguish between different values of locals within a potentially
125 recursive callstack. */
126
127 class path_var
128 {
129 public:
130 path_var (tree t, int stack_depth)
131 : m_tree (t), m_stack_depth (stack_depth)
132 {
133 // TODO: ignore stack depth for globals and constants
134 }
135
136 bool operator== (const path_var &other) const
137 {
138 return (m_tree == other.m_tree
139 && m_stack_depth == other.m_stack_depth);
140 }
141
142 operator bool () const
143 {
144 return m_tree != NULL_TREE;
145 }
146
147 void dump (pretty_printer *pp) const;
148
149 tree m_tree;
150 int m_stack_depth; // or -1 for globals?
151 };
152
153 typedef offset_int bit_offset_t;
154 typedef offset_int bit_size_t;
155 typedef offset_int byte_offset_t;
156 typedef offset_int byte_size_t;
157
158 extern bool int_size_in_bits (const_tree type, bit_size_t *out);
159
160 extern tree get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset);
161
162 /* The location of a region expressesd as an offset relative to a
163 base region. */
164
165 class region_offset
166 {
167 public:
168 static region_offset make_concrete (const region *base_region,
169 bit_offset_t offset)
170 {
171 return region_offset (base_region, offset, false);
172 }
173 static region_offset make_symbolic (const region *base_region)
174 {
175 return region_offset (base_region, 0, true);
176 }
177
178 const region *get_base_region () const { return m_base_region; }
179
180 bool symbolic_p () const { return m_is_symbolic; }
181
182 bit_offset_t get_bit_offset () const
183 {
184 gcc_assert (!symbolic_p ());
185 return m_offset;
186 }
187
188 bool operator== (const region_offset &other) const
189 {
190 return (m_base_region == other.m_base_region
191 && m_offset == other.m_offset
192 && m_is_symbolic == other.m_is_symbolic);
193 }
194
195 private:
196 region_offset (const region *base_region, bit_offset_t offset,
197 bool is_symbolic)
198 : m_base_region (base_region), m_offset (offset), m_is_symbolic (is_symbolic)
199 {}
200
201 const region *m_base_region;
202 bit_offset_t m_offset;
203 bool m_is_symbolic;
204 };
205
206 extern location_t get_stmt_location (const gimple *stmt, function *fun);
207
208 extern bool compat_types_p (tree src_type, tree dst_type);
209
210 /* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks. */
211
212 class plugin_analyzer_init_iface
213 {
214 public:
215 virtual void register_state_machine (state_machine *) = 0;
216 virtual logger *get_logger () const = 0;
217 };
218
219 /* An enum for describing the direction of an access to memory. */
220
221 enum access_direction
222 {
223 DIR_READ,
224 DIR_WRITE
225 };
226
227 /* Abstract base class for associating custom data with an
228 exploded_edge, for handling non-standard edges such as
229 rewinding from a longjmp, signal handlers, etc.
230 Also used when "bifurcating" state: splitting the execution
231 path in non-standard ways (e.g. for simulating the various
232 outcomes of "realloc"). */
233
234 class custom_edge_info
235 {
236 public:
237 virtual ~custom_edge_info () {}
238
239 /* Hook for making .dot label more readable. */
240 virtual void print (pretty_printer *pp) const = 0;
241
242 /* Hook for updating MODEL within exploded_path::feasible_p
243 and when handling bifurcation. */
244 virtual bool update_model (region_model *model,
245 const exploded_edge *eedge,
246 region_model_context *ctxt) const = 0;
247
248 virtual void add_events_to_path (checker_path *emission_path,
249 const exploded_edge &eedge) const = 0;
250 };
251
252 /* Abstract base class for splitting state.
253
254 Most of the state-management code in the analyzer involves
255 modifying state objects in-place, which assumes a single outcome.
256
257 This class provides an escape hatch to allow for multiple outcomes
258 for such updates e.g. for modelling multiple outcomes from function
259 calls, such as the various outcomes of "realloc". */
260
261 class path_context
262 {
263 public:
264 virtual ~path_context () {}
265
266 /* Hook for clients to split state with a non-standard path.
267 Take ownership of INFO. */
268 virtual void bifurcate (custom_edge_info *info) = 0;
269
270 /* Hook for clients to terminate the standard path. */
271 virtual void terminate_path () = 0;
272
273 /* Hook for clients to determine if the standard path has been
274 terminated. */
275 virtual bool terminate_path_p () const = 0;
276 };
277
278 } // namespace ana
279
280 extern bool is_special_named_call_p (const gcall *call, const char *funcname,
281 unsigned int num_args);
282 extern bool is_named_call_p (const_tree fndecl, const char *funcname);
283 extern bool is_named_call_p (const_tree fndecl, const char *funcname,
284 const gcall *call, unsigned int num_args);
285 extern bool is_std_named_call_p (const_tree fndecl, const char *funcname);
286 extern bool is_std_named_call_p (const_tree fndecl, const char *funcname,
287 const gcall *call, unsigned int num_args);
288 extern bool is_setjmp_call_p (const gcall *call);
289 extern bool is_longjmp_call_p (const gcall *call);
290
291 extern const char *get_user_facing_name (const gcall *call);
292
293 extern void register_analyzer_pass ();
294
295 extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
296
297 extern bool fndecl_has_gimple_body_p (tree fndecl);
298
299 /* An RAII-style class for pushing/popping cfun within a scope.
300 Doing so ensures we get "In function " announcements
301 from the diagnostics subsystem. */
302
303 class auto_cfun
304 {
305 public:
306 auto_cfun (function *fun) { push_cfun (fun); }
307 ~auto_cfun () { pop_cfun (); }
308 };
309
310 /* A template for creating hash traits for a POD type. */
311
312 template <typename Type>
313 struct pod_hash_traits : typed_noop_remove<Type>
314 {
315 typedef Type value_type;
316 typedef Type compare_type;
317 static inline hashval_t hash (value_type);
318 static inline bool equal (const value_type &existing,
319 const value_type &candidate);
320 static inline void mark_deleted (Type &);
321 static inline void mark_empty (Type &);
322 static inline bool is_deleted (Type);
323 static inline bool is_empty (Type);
324 };
325
326 /* A hash traits class that uses member functions to implement
327 the various required ops. */
328
329 template <typename Type>
330 struct member_function_hash_traits : public typed_noop_remove<Type>
331 {
332 typedef Type value_type;
333 typedef Type compare_type;
334 static inline hashval_t hash (value_type v) { return v.hash (); }
335 static inline bool equal (const value_type &existing,
336 const value_type &candidate)
337 {
338 return existing == candidate;
339 }
340 static inline void mark_deleted (Type &t) { t.mark_deleted (); }
341 static inline void mark_empty (Type &t) { t.mark_empty (); }
342 static inline bool is_deleted (Type t) { return t.is_deleted (); }
343 static inline bool is_empty (Type t) { return t.is_empty (); }
344 };
345
346 /* A map from T::key_t to T* for use in consolidating instances of T.
347 Owns all instances of T.
348 T::key_t should have operator== and be hashable. */
349
350 template <typename T>
351 class consolidation_map
352 {
353 public:
354 typedef typename T::key_t key_t;
355 typedef T instance_t;
356 typedef hash_map<key_t, instance_t *> inner_map_t;
357 typedef typename inner_map_t::iterator iterator;
358
359 /* Delete all instances of T. */
360
361 ~consolidation_map ()
362 {
363 for (typename inner_map_t::iterator iter = m_inner_map.begin ();
364 iter != m_inner_map.end (); ++iter)
365 delete (*iter).second;
366 }
367
368 /* Get the instance of T for K if one exists, or NULL. */
369
370 T *get (const key_t &k) const
371 {
372 if (instance_t **slot = const_cast<inner_map_t &> (m_inner_map).get (k))
373 return *slot;
374 return NULL;
375 }
376
377 /* Take ownership of INSTANCE. */
378
379 void put (const key_t &k, T *instance)
380 {
381 m_inner_map.put (k, instance);
382 }
383
384 size_t elements () const { return m_inner_map.elements (); }
385
386 iterator begin () const { return m_inner_map.begin (); }
387 iterator end () const { return m_inner_map.end (); }
388
389 private:
390 inner_map_t m_inner_map;
391 };
392
393 /* Disable -Wformat-diag; we want to be able to use pp_printf
394 for logging/dumping without complying with the rules for diagnostics. */
395 #if __GNUC__ >= 10
396 #pragma GCC diagnostic ignored "-Wformat-diag"
397 #endif
398
399 #if !ENABLE_ANALYZER
400 extern void sorry_no_analyzer ();
401 #endif /* #if !ENABLE_ANALYZER */
402
403 #endif /* GCC_ANALYZER_ANALYZER_H */