xref: /netbsd-src/external/gpl3/gcc/dist/gcc/analyzer/analyzer.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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 class conjured_purge;
74 struct model_merger;
75 class store_manager;
76 class store;
77 class region_model;
78 class region_model_context;
79   class impl_region_model_context;
80 class call_details;
81 class rejected_constraint;
82 class constraint_manager;
83 class equiv_class;
84 class reachable_regions;
85 class bounded_ranges;
86 class bounded_ranges_manager;
87 
88 class pending_diagnostic;
89 class pending_note;
90 class state_change_event;
91 class checker_path;
92 class extrinsic_state;
93 class sm_state_map;
94 class stmt_finder;
95 class program_point;
96 class function_point;
97 class program_state;
98 class exploded_graph;
99 class exploded_node;
100 class exploded_edge;
101 class feasibility_problem;
102 class exploded_cluster;
103 class exploded_path;
104 class analysis_plan;
105 class state_purge_map;
106 class state_purge_per_ssa_name;
107 class state_purge_per_decl;
108 class state_change;
109 class rewind_info_t;
110 
111 class engine;
112 class state_machine;
113 class logger;
114 class visitor;
115 
116 /* Forward decls of functions.  */
117 
118 extern void dump_tree (pretty_printer *pp, tree t);
119 extern void dump_quoted_tree (pretty_printer *pp, tree t);
120 extern void print_quoted_type (pretty_printer *pp, tree t);
121 extern int readability_comparator (const void *p1, const void *p2);
122 extern int tree_cmp (const void *p1, const void *p2);
123 extern tree fixup_tree_for_diagnostic (tree);
124 extern tree get_diagnostic_tree_for_gassign (const gassign *);
125 
126 /* A tree, extended with stack frame information for locals, so that
127    we can distinguish between different values of locals within a potentially
128    recursive callstack.  */
129 
130 class path_var
131 {
132 public:
path_var(tree t,int stack_depth)133   path_var (tree t, int stack_depth)
134   : m_tree (t), m_stack_depth (stack_depth)
135   {
136     // TODO: ignore stack depth for globals and constants
137   }
138 
139   bool operator== (const path_var &other) const
140   {
141     return (m_tree == other.m_tree
142 	    && m_stack_depth == other.m_stack_depth);
143   }
144 
145   operator bool () const
146   {
147     return m_tree != NULL_TREE;
148   }
149 
150   void dump (pretty_printer *pp) const;
151 
152   tree m_tree;
153   int m_stack_depth; // or -1 for globals?
154 };
155 
156 typedef offset_int bit_offset_t;
157 typedef offset_int bit_size_t;
158 typedef offset_int byte_offset_t;
159 typedef offset_int byte_size_t;
160 
161 extern bool int_size_in_bits (const_tree type, bit_size_t *out);
162 
163 extern tree get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset);
164 
165 /* The location of a region expressesd as an offset relative to a
166    base region.  */
167 
168 class region_offset
169 {
170 public:
make_concrete(const region * base_region,bit_offset_t offset)171   static region_offset make_concrete (const region *base_region,
172 				      bit_offset_t offset)
173   {
174     return region_offset (base_region, offset, false);
175   }
make_symbolic(const region * base_region)176   static region_offset make_symbolic (const region *base_region)
177   {
178     return region_offset (base_region, 0, true);
179   }
180 
get_base_region()181   const region *get_base_region () const { return m_base_region; }
182 
symbolic_p()183   bool symbolic_p () const { return m_is_symbolic; }
184 
get_bit_offset()185   bit_offset_t get_bit_offset () const
186   {
187     gcc_assert (!symbolic_p ());
188     return m_offset;
189   }
190 
191   bool operator== (const region_offset &other) const
192   {
193     return (m_base_region == other.m_base_region
194 	    && m_offset == other.m_offset
195 	    && m_is_symbolic == other.m_is_symbolic);
196   }
197 
198 private:
region_offset(const region * base_region,bit_offset_t offset,bool is_symbolic)199   region_offset (const region *base_region, bit_offset_t offset,
200 		 bool is_symbolic)
201   : m_base_region (base_region), m_offset (offset), m_is_symbolic (is_symbolic)
202   {}
203 
204   const region *m_base_region;
205   bit_offset_t m_offset;
206   bool m_is_symbolic;
207 };
208 
209 extern location_t get_stmt_location (const gimple *stmt, function *fun);
210 
211 extern bool compat_types_p (tree src_type, tree dst_type);
212 
213 /* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks.  */
214 
215 class plugin_analyzer_init_iface
216 {
217 public:
218   virtual void register_state_machine (state_machine *) = 0;
219   virtual logger *get_logger () const = 0;
220 };
221 
222 /* An enum for describing the direction of an access to memory.  */
223 
224 enum access_direction
225 {
226   DIR_READ,
227   DIR_WRITE
228 };
229 
230 /* Abstract base class for associating custom data with an
231    exploded_edge, for handling non-standard edges such as
232    rewinding from a longjmp, signal handlers, etc.
233    Also used when "bifurcating" state: splitting the execution
234    path in non-standard ways (e.g. for simulating the various
235    outcomes of "realloc").  */
236 
237 class custom_edge_info
238 {
239 public:
~custom_edge_info()240   virtual ~custom_edge_info () {}
241 
242   /* Hook for making .dot label more readable.  */
243   virtual void print (pretty_printer *pp) const = 0;
244 
245   /* Hook for updating MODEL within exploded_path::feasible_p
246      and when handling bifurcation.  */
247   virtual bool update_model (region_model *model,
248 			     const exploded_edge *eedge,
249 			     region_model_context *ctxt) const = 0;
250 
251   virtual void add_events_to_path (checker_path *emission_path,
252 				   const exploded_edge &eedge) const = 0;
253 };
254 
255 /* Abstract base class for splitting state.
256 
257    Most of the state-management code in the analyzer involves
258    modifying state objects in-place, which assumes a single outcome.
259 
260    This class provides an escape hatch to allow for multiple outcomes
261    for such updates e.g. for modelling multiple outcomes from function
262    calls, such as the various outcomes of "realloc".  */
263 
264 class path_context
265 {
266 public:
~path_context()267   virtual ~path_context () {}
268 
269   /* Hook for clients to split state with a non-standard path.
270      Take ownership of INFO.  */
271   virtual void bifurcate (custom_edge_info *info) = 0;
272 
273   /* Hook for clients to terminate the standard path.  */
274   virtual void terminate_path () = 0;
275 
276   /* Hook for clients to determine if the standard path has been
277      terminated.  */
278   virtual bool terminate_path_p () const = 0;
279 };
280 
281 } // namespace ana
282 
283 extern bool is_special_named_call_p (const gcall *call, const char *funcname,
284 				     unsigned int num_args);
285 extern bool is_named_call_p (const_tree fndecl, const char *funcname);
286 extern bool is_named_call_p (const_tree fndecl, const char *funcname,
287 			     const gcall *call, unsigned int num_args);
288 extern bool is_std_named_call_p (const_tree fndecl, const char *funcname);
289 extern bool is_std_named_call_p (const_tree fndecl, const char *funcname,
290 				 const gcall *call, unsigned int num_args);
291 extern bool is_setjmp_call_p (const gcall *call);
292 extern bool is_longjmp_call_p (const gcall *call);
293 
294 extern const char *get_user_facing_name (const gcall *call);
295 
296 extern void register_analyzer_pass ();
297 
298 extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
299 
300 extern bool fndecl_has_gimple_body_p (tree fndecl);
301 
302 /* An RAII-style class for pushing/popping cfun within a scope.
303    Doing so ensures we get "In function " announcements
304    from the diagnostics subsystem.  */
305 
306 class auto_cfun
307 {
308 public:
auto_cfun(function * fun)309   auto_cfun (function *fun) { push_cfun (fun); }
~auto_cfun()310   ~auto_cfun () { pop_cfun (); }
311 };
312 
313 /* A template for creating hash traits for a POD type.  */
314 
315 template <typename Type>
316 struct pod_hash_traits : typed_noop_remove<Type>
317 {
318   typedef Type value_type;
319   typedef Type compare_type;
320   static inline hashval_t hash (value_type);
321   static inline bool equal (const value_type &existing,
322 			    const value_type &candidate);
323   static inline void mark_deleted (Type &);
324   static inline void mark_empty (Type &);
325   static inline bool is_deleted (Type);
326   static inline bool is_empty (Type);
327 };
328 
329 /* A hash traits class that uses member functions to implement
330    the various required ops.  */
331 
332 template <typename Type>
333 struct member_function_hash_traits : public typed_noop_remove<Type>
334 {
335   typedef Type value_type;
336   typedef Type compare_type;
hashmember_function_hash_traits337   static inline hashval_t hash (value_type v) { return v.hash (); }
equalmember_function_hash_traits338   static inline bool equal (const value_type &existing,
339 			    const value_type &candidate)
340   {
341     return existing == candidate;
342   }
mark_deletedmember_function_hash_traits343   static inline void mark_deleted (Type &t) { t.mark_deleted (); }
mark_emptymember_function_hash_traits344   static inline void mark_empty (Type &t) { t.mark_empty (); }
is_deletedmember_function_hash_traits345   static inline bool is_deleted (Type t) { return t.is_deleted (); }
is_emptymember_function_hash_traits346   static inline bool is_empty (Type t) { return t.is_empty (); }
347 };
348 
349 /* A map from T::key_t to T* for use in consolidating instances of T.
350    Owns all instances of T.
351    T::key_t should have operator== and be hashable.  */
352 
353 template <typename T>
354 class consolidation_map
355 {
356 public:
357   typedef typename T::key_t key_t;
358   typedef T instance_t;
359   typedef hash_map<key_t, instance_t *> inner_map_t;
360   typedef typename inner_map_t::iterator iterator;
361 
362   /* Delete all instances of T.  */
363 
~consolidation_map()364   ~consolidation_map ()
365   {
366     for (typename inner_map_t::iterator iter = m_inner_map.begin ();
367 	 iter != m_inner_map.end (); ++iter)
368       delete (*iter).second;
369   }
370 
371   /* Get the instance of T for K if one exists, or NULL.  */
372 
get(const key_t & k)373   T *get (const key_t &k) const
374   {
375     if (instance_t **slot = const_cast<inner_map_t &> (m_inner_map).get (k))
376       return *slot;
377     return NULL;
378   }
379 
380   /* Take ownership of INSTANCE.  */
381 
put(const key_t & k,T * instance)382   void put (const key_t &k, T *instance)
383   {
384     m_inner_map.put (k, instance);
385   }
386 
elements()387   size_t elements () const { return m_inner_map.elements (); }
388 
begin()389   iterator begin () const { return m_inner_map.begin (); }
end()390   iterator end () const { return m_inner_map.end (); }
391 
392 private:
393   inner_map_t m_inner_map;
394 };
395 
396 /* Disable -Wformat-diag; we want to be able to use pp_printf
397    for logging/dumping without complying with the rules for diagnostics.  */
398 #if __GNUC__ >= 10
399 #pragma GCC diagnostic ignored "-Wformat-diag"
400 #endif
401 
402 #if !ENABLE_ANALYZER
403 extern void sorry_no_analyzer ();
404 #endif /* #if !ENABLE_ANALYZER */
405 
406 #endif /* GCC_ANALYZER_ANALYZER_H */
407