1 /* Utility functions for the analyzer.
2    Copyright (C) 2019-2021 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 unmergeable_svalue;
50   class placeholder_svalue;
51   class widening_svalue;
52   class compound_svalue;
53   class conjured_svalue;
54 typedef hash_set<const svalue *> svalue_set;
55 class region;
56   class frame_region;
57   class function_region;
58   class label_region;
59   class decl_region;
60   class symbolic_region;
61   class element_region;
62   class offset_region;
63   class cast_region;
64   class field_region;
65   class string_region;
66 class region_model_manager;
67 struct model_merger;
68 class store_manager;
69 class store;
70 class region_model;
71 class region_model_context;
72   class impl_region_model_context;
73 class call_details;
74 struct rejected_constraint;
75 class constraint_manager;
76 class equiv_class;
77 
78 class pending_diagnostic;
79 class state_change_event;
80 class checker_path;
81 class extrinsic_state;
82 class sm_state_map;
83 class stmt_finder;
84 class program_point;
85 class function_point;
86 class program_state;
87 class exploded_graph;
88 class exploded_node;
89 class exploded_edge;
90 class feasibility_problem;
91 class exploded_cluster;
92 class exploded_path;
93 class analysis_plan;
94 class state_purge_map;
95 class state_purge_per_ssa_name;
96 class state_change;
97 class rewind_info_t;
98 
99 class engine;
100 class state_machine;
101 class logger;
102 class visitor;
103 
104 /* Forward decls of functions.  */
105 
106 extern void dump_tree (pretty_printer *pp, tree t);
107 extern void dump_quoted_tree (pretty_printer *pp, tree t);
108 extern void print_quoted_type (pretty_printer *pp, tree t);
109 extern int readability_comparator (const void *p1, const void *p2);
110 extern int tree_cmp (const void *p1, const void *p2);
111 extern tree fixup_tree_for_diagnostic (tree);
112 
113 /* A tree, extended with stack frame information for locals, so that
114    we can distinguish between different values of locals within a potentially
115    recursive callstack.  */
116 
117 class path_var
118 {
119 public:
path_var(tree t,int stack_depth)120   path_var (tree t, int stack_depth)
121   : m_tree (t), m_stack_depth (stack_depth)
122   {
123     // TODO: ignore stack depth for globals and constants
124   }
125 
126   bool operator== (const path_var &other) const
127   {
128     return (m_tree == other.m_tree
129 	    && m_stack_depth == other.m_stack_depth);
130   }
131 
132   operator bool () const
133   {
134     return m_tree != NULL_TREE;
135   }
136 
137   void dump (pretty_printer *pp) const;
138 
139   tree m_tree;
140   int m_stack_depth; // or -1 for globals?
141 };
142 
143 typedef offset_int bit_offset_t;
144 typedef offset_int bit_size_t;
145 typedef offset_int byte_size_t;
146 
147 extern bool int_size_in_bits (const_tree type, bit_size_t *out);
148 
149 /* The location of a region expressesd as an offset relative to a
150    base region.  */
151 
152 class region_offset
153 {
154 public:
make_concrete(const region * base_region,bit_offset_t offset)155   static region_offset make_concrete (const region *base_region,
156 				      bit_offset_t offset)
157   {
158     return region_offset (base_region, offset, false);
159   }
make_symbolic(const region * base_region)160   static region_offset make_symbolic (const region *base_region)
161   {
162     return region_offset (base_region, 0, true);
163   }
164 
get_base_region()165   const region *get_base_region () const { return m_base_region; }
166 
symbolic_p()167   bool symbolic_p () const { return m_is_symbolic; }
168 
get_bit_offset()169   bit_offset_t get_bit_offset () const
170   {
171     gcc_assert (!symbolic_p ());
172     return m_offset;
173   }
174 
175   bool operator== (const region_offset &other) const
176   {
177     return (m_base_region == other.m_base_region
178 	    && m_offset == other.m_offset
179 	    && m_is_symbolic == other.m_is_symbolic);
180   }
181 
182 private:
region_offset(const region * base_region,bit_offset_t offset,bool is_symbolic)183   region_offset (const region *base_region, bit_offset_t offset,
184 		 bool is_symbolic)
185   : m_base_region (base_region), m_offset (offset), m_is_symbolic (is_symbolic)
186   {}
187 
188   const region *m_base_region;
189   bit_offset_t m_offset;
190   bool m_is_symbolic;
191 };
192 
193 extern location_t get_stmt_location (const gimple *stmt, function *fun);
194 
195 /* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks.  */
196 
197 class plugin_analyzer_init_iface
198 {
199 public:
200   virtual void register_state_machine (state_machine *) = 0;
201   virtual logger *get_logger () const = 0;
202 };
203 
204 } // namespace ana
205 
206 extern bool is_special_named_call_p (const gcall *call, const char *funcname,
207 				     unsigned int num_args);
208 extern bool is_named_call_p (tree fndecl, const char *funcname);
209 extern bool is_named_call_p (tree fndecl, const char *funcname,
210 			     const gcall *call, unsigned int num_args);
211 extern bool is_std_named_call_p (tree fndecl, const char *funcname);
212 extern bool is_std_named_call_p (tree fndecl, const char *funcname,
213 				 const gcall *call, unsigned int num_args);
214 extern bool is_setjmp_call_p (const gcall *call);
215 extern bool is_longjmp_call_p (const gcall *call);
216 
217 extern const char *get_user_facing_name (const gcall *call);
218 
219 extern void register_analyzer_pass ();
220 
221 extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
222 
223 extern bool fndecl_has_gimple_body_p (tree fndecl);
224 
225 /* An RAII-style class for pushing/popping cfun within a scope.
226    Doing so ensures we get "In function " announcements
227    from the diagnostics subsystem.  */
228 
229 class auto_cfun
230 {
231 public:
auto_cfun(function * fun)232   auto_cfun (function *fun) { push_cfun (fun); }
~auto_cfun()233   ~auto_cfun () { pop_cfun (); }
234 };
235 
236 /* A template for creating hash traits for a POD type.  */
237 
238 template <typename Type>
239 struct pod_hash_traits : typed_noop_remove<Type>
240 {
241   typedef Type value_type;
242   typedef Type compare_type;
243   static inline hashval_t hash (value_type);
244   static inline bool equal (const value_type &existing,
245 			    const value_type &candidate);
246   static inline void mark_deleted (Type &);
247   static inline void mark_empty (Type &);
248   static inline bool is_deleted (Type);
249   static inline bool is_empty (Type);
250 };
251 
252 /* A hash traits class that uses member functions to implement
253    the various required ops.  */
254 
255 template <typename Type>
256 struct member_function_hash_traits : public typed_noop_remove<Type>
257 {
258   typedef Type value_type;
259   typedef Type compare_type;
hashmember_function_hash_traits260   static inline hashval_t hash (value_type v) { return v.hash (); }
equalmember_function_hash_traits261   static inline bool equal (const value_type &existing,
262 			    const value_type &candidate)
263   {
264     return existing == candidate;
265   }
mark_deletedmember_function_hash_traits266   static inline void mark_deleted (Type &t) { t.mark_deleted (); }
mark_emptymember_function_hash_traits267   static inline void mark_empty (Type &t) { t.mark_empty (); }
is_deletedmember_function_hash_traits268   static inline bool is_deleted (Type t) { return t.is_deleted (); }
is_emptymember_function_hash_traits269   static inline bool is_empty (Type t) { return t.is_empty (); }
270 };
271 
272 /* A map from T::key_t to T* for use in consolidating instances of T.
273    Owns all instances of T.
274    T::key_t should have operator== and be hashable.  */
275 
276 template <typename T>
277 class consolidation_map
278 {
279 public:
280   typedef typename T::key_t key_t;
281   typedef T instance_t;
282   typedef hash_map<key_t, instance_t *> inner_map_t;
283   typedef typename inner_map_t::iterator iterator;
284 
285   /* Delete all instances of T.  */
286 
~consolidation_map()287   ~consolidation_map ()
288   {
289     for (typename inner_map_t::iterator iter = m_inner_map.begin ();
290 	 iter != m_inner_map.end (); ++iter)
291       delete (*iter).second;
292   }
293 
294   /* Get the instance of T for K if one exists, or NULL.  */
295 
get(const key_t & k)296   T *get (const key_t &k) const
297   {
298     if (instance_t **slot = const_cast<inner_map_t &> (m_inner_map).get (k))
299       return *slot;
300     return NULL;
301   }
302 
303   /* Take ownership of INSTANCE.  */
304 
put(const key_t & k,T * instance)305   void put (const key_t &k, T *instance)
306   {
307     m_inner_map.put (k, instance);
308   }
309 
elements()310   size_t elements () const { return m_inner_map.elements (); }
311 
begin()312   iterator begin () const { return m_inner_map.begin (); }
end()313   iterator end () const { return m_inner_map.end (); }
314 
315 private:
316   inner_map_t m_inner_map;
317 };
318 
319 /* Disable -Wformat-diag; we want to be able to use pp_printf
320    for logging/dumping without complying with the rules for diagnostics.  */
321 #if __GNUC__ >= 10
322 #pragma GCC diagnostic ignored "-Wformat-diag"
323 #endif
324 
325 #if !ENABLE_ANALYZER
326 extern void sorry_no_analyzer ();
327 #endif /* #if !ENABLE_ANALYZER */
328 
329 #endif /* GCC_ANALYZER_ANALYZER_H */
330