1 /* Classes for representing locations within the program. 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_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 /* Factory functions for making various kinds of program_point. */ 108 109 static function_point from_function_entry (const supergraph &sg, 110 function *fun); 111 112 static function_point before_supernode (const supernode *supernode, 113 const superedge *from_edge); 114 before_stmt(const supernode * supernode,unsigned stmt_idx)115 static function_point before_stmt (const supernode *supernode, 116 unsigned stmt_idx) 117 { 118 return function_point (supernode, NULL, stmt_idx, PK_BEFORE_STMT); 119 } 120 after_supernode(const supernode * supernode)121 static function_point after_supernode (const supernode *supernode) 122 { 123 return function_point (supernode, NULL, 0, PK_AFTER_SUPERNODE); 124 } 125 126 /* Support for hash_map. */ 127 empty()128 static function_point empty () 129 { 130 return function_point (NULL, NULL, 0, PK_EMPTY); 131 } deleted()132 static function_point deleted () 133 { 134 return function_point (NULL, NULL, 0, PK_DELETED); 135 } 136 137 static int cmp_within_supernode_1 (const function_point &point_a, 138 const function_point &point_b); 139 static int cmp_within_supernode (const function_point &point_a, 140 const function_point &point_b); 141 static int cmp (const function_point &point_a, 142 const function_point &point_b); 143 static int cmp_ptr (const void *p1, const void *p2); 144 145 /* For before_stmt, go to next stmt. */ 146 void next_stmt (); 147 148 private: 149 const supernode *m_supernode; 150 151 /* For PK_BEFORE_SUPERNODE, and only for CFG edges. */ 152 const superedge *m_from_edge; 153 154 /* Only for PK_BEFORE_STMT. */ 155 unsigned m_stmt_idx; 156 157 enum point_kind m_kind; 158 }; 159 160 /* A class for representing a location within the program, including 161 interprocedural information. 162 163 This represents a fine-grained location within the supergraph (or 164 within one of its nodes), along with a call string giving the 165 interprocedural context. */ 166 167 class program_point 168 { 169 public: program_point(const function_point & fn_point,const call_string & call_string)170 program_point (const function_point &fn_point, 171 const call_string &call_string) 172 : m_function_point (fn_point), 173 m_call_string (call_string) 174 { 175 } 176 177 void print (pretty_printer *pp, const format &f) const; 178 void print_source_line (pretty_printer *pp) const; 179 void dump () const; 180 181 json::object *to_json () const; 182 183 hashval_t hash () const; 184 bool operator== (const program_point &other) const 185 { 186 return (m_function_point == other.m_function_point 187 && m_call_string == other.m_call_string); 188 } 189 bool operator!= (const program_point &other) const 190 { 191 return !(*this == other); 192 } 193 194 /* Accessors. */ 195 get_function_point()196 const function_point &get_function_point () const { return m_function_point; } get_call_string()197 const call_string &get_call_string () const { return m_call_string; } 198 get_supernode()199 const supernode *get_supernode () const 200 { 201 return m_function_point.get_supernode (); 202 } get_function()203 function *get_function () const 204 { 205 return m_function_point.get_function (); 206 } 207 function *get_function_at_depth (unsigned depth) const; get_fndecl()208 tree get_fndecl () const 209 { 210 gcc_assert (get_kind () != PK_ORIGIN); 211 return get_function ()->decl; 212 } get_stmt()213 const gimple *get_stmt () const 214 { 215 return m_function_point.get_stmt (); 216 } get_location()217 location_t get_location () const 218 { 219 return m_function_point.get_location (); 220 } get_kind()221 enum point_kind get_kind () const 222 { 223 return m_function_point.get_kind (); 224 } get_from_edge()225 const superedge *get_from_edge () const 226 { 227 return m_function_point.get_from_edge (); 228 } get_stmt_idx()229 unsigned get_stmt_idx () const 230 { 231 return m_function_point.get_stmt_idx (); 232 } 233 234 /* Get the number of frames we expect at this program point. 235 This will be one more than the length of the call_string 236 (which stores the parent callsites), apart from the origin 237 node, which doesn't have any frames. */ get_stack_depth()238 int get_stack_depth () const 239 { 240 if (get_kind () == PK_ORIGIN) 241 return 0; 242 return m_call_string.length () + 1; 243 } 244 245 /* Factory functions for making various kinds of program_point. */ origin()246 static program_point origin () 247 { 248 return program_point (function_point (NULL, NULL, 249 0, PK_ORIGIN), 250 call_string ()); 251 } 252 from_function_entry(const supergraph & sg,function * fun)253 static program_point from_function_entry (const supergraph &sg, 254 function *fun) 255 { 256 return program_point (function_point::from_function_entry (sg, fun), 257 call_string ()); 258 } 259 before_supernode(const supernode * supernode,const superedge * from_edge,const call_string & call_string)260 static program_point before_supernode (const supernode *supernode, 261 const superedge *from_edge, 262 const call_string &call_string) 263 { 264 return program_point (function_point::before_supernode (supernode, 265 from_edge), 266 call_string); 267 } 268 before_stmt(const supernode * supernode,unsigned stmt_idx,const call_string & call_string)269 static program_point before_stmt (const supernode *supernode, 270 unsigned stmt_idx, 271 const call_string &call_string) 272 { 273 return program_point (function_point::before_stmt (supernode, stmt_idx), 274 call_string); 275 } 276 after_supernode(const supernode * supernode,const call_string & call_string)277 static program_point after_supernode (const supernode *supernode, 278 const call_string &call_string) 279 { 280 return program_point (function_point::after_supernode (supernode), 281 call_string); 282 } 283 284 /* Support for hash_map. */ 285 empty()286 static program_point empty () 287 { 288 return program_point (function_point::empty (), call_string ()); 289 } deleted()290 static program_point deleted () 291 { 292 return program_point (function_point::deleted (), call_string ()); 293 } 294 295 bool on_edge (exploded_graph &eg, const superedge *succ); 296 297 void validate () const; 298 299 /* For before_stmt, go to next stmt. */ next_stmt()300 void next_stmt () { m_function_point.next_stmt (); } 301 302 program_point get_next () const; 303 304 private: 305 function_point m_function_point; 306 call_string m_call_string; 307 }; 308 309 } // namespace ana 310 311 #endif /* GCC_ANALYZER_PROGRAM_POINT_H */ 312