1 /* Classes for representing locations within the program. 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_PROGRAM_POINT_H 22 #define GCC_ANALYZER_PROGRAM_POINT_H 23 24 namespace ana { 25 26 class exploded_graph; 27 28 /* An enum for distinguishing the various kinds of program_point. */ 29 30 enum point_kind { 31 /* A "fake" node which has edges to all entrypoints. */ 32 PK_ORIGIN, 33 34 PK_BEFORE_SUPERNODE, 35 PK_BEFORE_STMT, 36 PK_AFTER_SUPERNODE, 37 38 /* Special values used for hash_map: */ 39 PK_EMPTY, 40 PK_DELETED, 41 42 NUM_POINT_KINDS 43 }; 44 45 extern const char *point_kind_to_string (enum point_kind pk); 46 47 class format 48 { 49 public: format(bool newlines)50 format (bool newlines) : m_newlines (newlines) {} 51 spacer(pretty_printer * pp)52 void spacer (pretty_printer *pp) const 53 { 54 if (m_newlines) 55 pp_newline (pp); 56 else 57 pp_space (pp); 58 } 59 60 bool m_newlines; 61 }; 62 63 /* A class for representing a location within the program, without 64 interprocedural information. 65 66 This represents a fine-grained location within the supergraph (or 67 within one of its nodes). */ 68 69 class function_point 70 { 71 public: 72 function_point (const supernode *supernode, 73 const superedge *from_edge, 74 unsigned stmt_idx, 75 enum point_kind kind); 76 77 void print (pretty_printer *pp, const format &f) const; 78 void print_source_line (pretty_printer *pp) const; 79 void dump () const; 80 81 hashval_t hash () const; 82 bool operator== (const function_point &other) const 83 { 84 return (m_supernode == other.m_supernode 85 && m_from_edge == other.m_from_edge 86 && m_stmt_idx == other.m_stmt_idx 87 && m_kind == other.m_kind); 88 } 89 90 /* Accessors. */ 91 get_supernode()92 const supernode *get_supernode () const { return m_supernode; } 93 function *get_function () const; 94 const gimple *get_stmt () const; 95 location_t get_location () const; get_kind()96 enum point_kind get_kind () const { return m_kind; } get_from_edge()97 const superedge *get_from_edge () const 98 { 99 return m_from_edge; 100 } get_stmt_idx()101 unsigned get_stmt_idx () const 102 { 103 gcc_assert (m_kind == PK_BEFORE_STMT); 104 return m_stmt_idx; 105 } 106 107 bool final_stmt_p () const; 108 109 /* Factory functions for making various kinds of program_point. */ 110 111 static function_point from_function_entry (const supergraph &sg, 112 function *fun); 113 114 static function_point before_supernode (const supernode *supernode, 115 const superedge *from_edge); 116 before_stmt(const supernode * supernode,unsigned stmt_idx)117 static function_point before_stmt (const supernode *supernode, 118 unsigned stmt_idx) 119 { 120 return function_point (supernode, NULL, stmt_idx, PK_BEFORE_STMT); 121 } 122 after_supernode(const supernode * supernode)123 static function_point after_supernode (const supernode *supernode) 124 { 125 return function_point (supernode, NULL, 0, PK_AFTER_SUPERNODE); 126 } 127 128 /* Support for hash_map. */ 129 empty()130 static function_point empty () 131 { 132 return function_point (NULL, NULL, 0, PK_EMPTY); 133 } deleted()134 static function_point deleted () 135 { 136 return function_point (NULL, NULL, 0, PK_DELETED); 137 } 138 139 static int cmp_within_supernode_1 (const function_point &point_a, 140 const function_point &point_b); 141 static int cmp_within_supernode (const function_point &point_a, 142 const function_point &point_b); 143 static int cmp (const function_point &point_a, 144 const function_point &point_b); 145 static int cmp_ptr (const void *p1, const void *p2); 146 147 /* For before_stmt, go to next stmt. */ 148 void next_stmt (); 149 150 function_point get_next () const; 151 152 private: 153 const supernode *m_supernode; 154 155 /* For PK_BEFORE_SUPERNODE, and only for CFG edges. */ 156 const superedge *m_from_edge; 157 158 /* Only for PK_BEFORE_STMT. */ 159 unsigned m_stmt_idx; 160 161 enum point_kind m_kind; 162 }; 163 164 /* A class for representing a location within the program, including 165 interprocedural information. 166 167 This represents a fine-grained location within the supergraph (or 168 within one of its nodes), along with a call string giving the 169 interprocedural context. */ 170 171 class program_point 172 { 173 public: program_point(const function_point & fn_point,const call_string & call_string)174 program_point (const function_point &fn_point, 175 const call_string &call_string) 176 : m_function_point (fn_point), 177 m_call_string (call_string) 178 { 179 } 180 181 void print (pretty_printer *pp, const format &f) const; 182 void dump () const; 183 184 json::object *to_json () const; 185 186 hashval_t hash () const; 187 bool operator== (const program_point &other) const 188 { 189 return (m_function_point == other.m_function_point 190 && m_call_string == other.m_call_string); 191 } 192 bool operator!= (const program_point &other) const 193 { 194 return !(*this == other); 195 } 196 197 /* Accessors. */ 198 get_function_point()199 const function_point &get_function_point () const { return m_function_point; } get_call_string()200 const call_string &get_call_string () const { return m_call_string; } 201 get_supernode()202 const supernode *get_supernode () const 203 { 204 return m_function_point.get_supernode (); 205 } get_function()206 function *get_function () const 207 { 208 return m_function_point.get_function (); 209 } 210 function *get_function_at_depth (unsigned depth) const; get_fndecl()211 tree get_fndecl () const 212 { 213 gcc_assert (get_kind () != PK_ORIGIN); 214 return get_function ()->decl; 215 } get_stmt()216 const gimple *get_stmt () const 217 { 218 return m_function_point.get_stmt (); 219 } get_location()220 location_t get_location () const 221 { 222 return m_function_point.get_location (); 223 } get_kind()224 enum point_kind get_kind () const 225 { 226 return m_function_point.get_kind (); 227 } get_from_edge()228 const superedge *get_from_edge () const 229 { 230 return m_function_point.get_from_edge (); 231 } get_stmt_idx()232 unsigned get_stmt_idx () const 233 { 234 return m_function_point.get_stmt_idx (); 235 } 236 237 /* Get the number of frames we expect at this program point. 238 This will be one more than the length of the call_string 239 (which stores the parent callsites), apart from the origin 240 node, which doesn't have any frames. */ get_stack_depth()241 int get_stack_depth () const 242 { 243 if (get_kind () == PK_ORIGIN) 244 return 0; 245 return m_call_string.length () + 1; 246 } 247 248 /* Factory functions for making various kinds of program_point. */ origin()249 static program_point origin () 250 { 251 return program_point (function_point (NULL, NULL, 252 0, PK_ORIGIN), 253 call_string ()); 254 } 255 from_function_entry(const supergraph & sg,function * fun)256 static program_point from_function_entry (const supergraph &sg, 257 function *fun) 258 { 259 return program_point (function_point::from_function_entry (sg, fun), 260 call_string ()); 261 } 262 before_supernode(const supernode * supernode,const superedge * from_edge,const call_string & call_string)263 static program_point before_supernode (const supernode *supernode, 264 const superedge *from_edge, 265 const call_string &call_string) 266 { 267 return program_point (function_point::before_supernode (supernode, 268 from_edge), 269 call_string); 270 } 271 before_stmt(const supernode * supernode,unsigned stmt_idx,const call_string & call_string)272 static program_point before_stmt (const supernode *supernode, 273 unsigned stmt_idx, 274 const call_string &call_string) 275 { 276 return program_point (function_point::before_stmt (supernode, stmt_idx), 277 call_string); 278 } 279 after_supernode(const supernode * supernode,const call_string & call_string)280 static program_point after_supernode (const supernode *supernode, 281 const call_string &call_string) 282 { 283 return program_point (function_point::after_supernode (supernode), 284 call_string); 285 } 286 287 /* Support for hash_map. */ 288 empty()289 static program_point empty () 290 { 291 return program_point (function_point::empty (), call_string ()); 292 } deleted()293 static program_point deleted () 294 { 295 return program_point (function_point::deleted (), call_string ()); 296 } 297 298 bool on_edge (exploded_graph &eg, const superedge *succ); 299 void push_to_call_stack (const supernode *caller, const supernode *callee); 300 void pop_from_call_stack (); 301 void validate () const; 302 303 /* For before_stmt, go to next stmt. */ next_stmt()304 void next_stmt () { m_function_point.next_stmt (); } 305 306 program_point get_next () const; 307 308 private: 309 function_point m_function_point; 310 call_string m_call_string; 311 }; 312 313 } // namespace ana 314 315 #endif /* GCC_ANALYZER_PROGRAM_POINT_H */ 316