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