annotate gcc/vtable-verify.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1 /* Copyright (C) 2013-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2
kono
parents:
diff changeset
3 This file is part of GCC.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
6 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
7 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
8 version.
kono
parents:
diff changeset
9
kono
parents:
diff changeset
10 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
11 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
13 for more details.
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
16 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
17 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
18
kono
parents:
diff changeset
19 /* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
kono
parents:
diff changeset
20 before using them for virtual method dispatches. */
kono
parents:
diff changeset
21
kono
parents:
diff changeset
22 /* This file is part of the vtable security feature implementation.
kono
parents:
diff changeset
23 The vtable security feature is designed to detect when a virtual
kono
parents:
diff changeset
24 call is about to be made through an invalid vtable pointer
kono
parents:
diff changeset
25 (possibly due to data corruption or malicious attacks). The
kono
parents:
diff changeset
26 compiler finds every virtual call, and inserts a verification call
kono
parents:
diff changeset
27 before the virtual call. The verification call takes the actual
kono
parents:
diff changeset
28 vtable pointer value in the object through which the virtual call
kono
parents:
diff changeset
29 is being made, and compares the vtable pointer against a set of all
kono
parents:
diff changeset
30 valid vtable pointers that the object could contain (this set is
kono
parents:
diff changeset
31 based on the declared type of the object). If the pointer is in
kono
parents:
diff changeset
32 the valid set, execution is allowed to continue; otherwise the
kono
parents:
diff changeset
33 program is halted.
kono
parents:
diff changeset
34
kono
parents:
diff changeset
35 There are several pieces needed in order to make this work: 1. For
kono
parents:
diff changeset
36 every virtual class in the program (i.e. a class that contains
kono
parents:
diff changeset
37 virtual methods), we need to build the set of all possible valid
kono
parents:
diff changeset
38 vtables that an object of that class could point to. This includes
kono
parents:
diff changeset
39 vtables for any class(es) that inherit from the class under
kono
parents:
diff changeset
40 consideration. 2. For every such data set we build up, we need a
kono
parents:
diff changeset
41 way to find and reference the data set. This is complicated by the
kono
parents:
diff changeset
42 fact that the real vtable addresses are not known until runtime,
kono
parents:
diff changeset
43 when the program is loaded into memory, but we need to reference the
kono
parents:
diff changeset
44 sets at compile time when we are inserting verification calls into
kono
parents:
diff changeset
45 the program. 3. We need to find every virtual call in the program,
kono
parents:
diff changeset
46 and insert the verification call (with the appropriate arguments)
kono
parents:
diff changeset
47 before the virtual call. 4. We need some runtime library pieces:
kono
parents:
diff changeset
48 the code to build up the data sets at runtime; the code to actually
kono
parents:
diff changeset
49 perform the verification using the data sets; and some code to set
kono
parents:
diff changeset
50 protections on the data sets, so they themselves do not become
kono
parents:
diff changeset
51 hacker targets.
kono
parents:
diff changeset
52
kono
parents:
diff changeset
53 To find and reference the set of valid vtable pointers for any given
kono
parents:
diff changeset
54 virtual class, we create a special global variable for each virtual
kono
parents:
diff changeset
55 class. We refer to this as the "vtable map variable" for that
kono
parents:
diff changeset
56 class. The vtable map variable has the type "void *", and is
kono
parents:
diff changeset
57 initialized by the compiler to NULL. At runtime when the set of
kono
parents:
diff changeset
58 valid vtable pointers for a virtual class, e.g. class Foo, is built,
kono
parents:
diff changeset
59 the vtable map variable for class Foo is made to point to the set.
kono
parents:
diff changeset
60 During compile time, when the compiler is inserting verification
kono
parents:
diff changeset
61 calls into the program, it passes the vtable map variable for the
kono
parents:
diff changeset
62 appropriate class to the verification call, so that at runtime the
kono
parents:
diff changeset
63 verification call can find the appropriate data set.
kono
parents:
diff changeset
64
kono
parents:
diff changeset
65 The actual set of valid vtable pointers for a virtual class,
kono
parents:
diff changeset
66 e.g. class Foo, cannot be built until runtime, when the vtables get
kono
parents:
diff changeset
67 loaded into memory and their addresses are known. But the knowledge
kono
parents:
diff changeset
68 about which vtables belong in which class' hierarchy is only known
kono
parents:
diff changeset
69 at compile time. Therefore at compile time we collect class
kono
parents:
diff changeset
70 hierarchy and vtable information about every virtual class, and we
kono
parents:
diff changeset
71 generate calls to build up the data sets at runtime. To build the
kono
parents:
diff changeset
72 data sets, we call one of the functions we add to the runtime
kono
parents:
diff changeset
73 library, __VLTRegisterPair. __VLTRegisterPair takes two arguments,
kono
parents:
diff changeset
74 a vtable map variable and the address of a vtable. If the vtable
kono
parents:
diff changeset
75 map variable is currently NULL, it creates a new data set (hash
kono
parents:
diff changeset
76 table), makes the vtable map variable point to the new data set, and
kono
parents:
diff changeset
77 inserts the vtable address into the data set. If the vtable map
kono
parents:
diff changeset
78 variable is not NULL, it just inserts the vtable address into the
kono
parents:
diff changeset
79 data set. In order to make sure that our data sets are built before
kono
parents:
diff changeset
80 any verification calls happen, we create a special constructor
kono
parents:
diff changeset
81 initialization function for each compilation unit, give it a very
kono
parents:
diff changeset
82 high initialization priority, and insert all of our calls to
kono
parents:
diff changeset
83 __VLTRegisterPair into our special constructor initialization
kono
parents:
diff changeset
84 function.
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 The vtable verification feature is controlled by the flag
kono
parents:
diff changeset
87 '-fvtable-verify='. There are three flavors of this:
kono
parents:
diff changeset
88 '-fvtable-verify=std', '-fvtable-verify=preinit', and
kono
parents:
diff changeset
89 '-fvtable-verify=none'. If the option '-fvtable-verfy=preinit' is
kono
parents:
diff changeset
90 used, then our constructor initialization function gets put into the
kono
parents:
diff changeset
91 preinit array. This is necessary if there are data sets that need
kono
parents:
diff changeset
92 to be built very early in execution. If the constructor
kono
parents:
diff changeset
93 initialization function gets put into the preinit array, the we also
kono
parents:
diff changeset
94 add calls to __VLTChangePermission at the beginning and end of the
kono
parents:
diff changeset
95 function. The call at the beginning sets the permissions on the
kono
parents:
diff changeset
96 data sets and vtable map variables to read/write, and the one at the
kono
parents:
diff changeset
97 end makes them read-only. If the '-fvtable-verify=std' option is
kono
parents:
diff changeset
98 used, the constructor initialization functions are executed at their
kono
parents:
diff changeset
99 normal time, and the __VLTChangePermission calls are handled
kono
parents:
diff changeset
100 differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
kono
parents:
diff changeset
101 The option '-fvtable-verify=none' turns off vtable verification.
kono
parents:
diff changeset
102
kono
parents:
diff changeset
103 This file contains code for the tree pass that goes through all the
kono
parents:
diff changeset
104 statements in each basic block, looking for virtual calls, and
kono
parents:
diff changeset
105 inserting a call to __VLTVerifyVtablePointer (with appropriate
kono
parents:
diff changeset
106 arguments) before each one. It also contains the hash table
kono
parents:
diff changeset
107 functions for the data structures used for collecting the class
kono
parents:
diff changeset
108 hierarchy data and building/maintaining the vtable map variable data
kono
parents:
diff changeset
109 are defined in gcc/vtable-verify.h. These data structures are
kono
parents:
diff changeset
110 shared with the code in the C++ front end that collects the class
kono
parents:
diff changeset
111 hierarchy & vtable information and generates the vtable map
kono
parents:
diff changeset
112 variables (see cp/vtable-class-hierarchy.c). This tree pass should
kono
parents:
diff changeset
113 run just before the gimple is converted to RTL.
kono
parents:
diff changeset
114
kono
parents:
diff changeset
115 Some implementation details for this pass:
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 To find all of the virtual calls, we iterate through all the
kono
parents:
diff changeset
118 gimple statements in each basic block, looking for any call
kono
parents:
diff changeset
119 statement with the code "OBJ_TYPE_REF". Once we have found the
kono
parents:
diff changeset
120 virtual call, we need to find the vtable pointer through which the
kono
parents:
diff changeset
121 call is being made, and the type of the object containing the
kono
parents:
diff changeset
122 pointer (to find the appropriate vtable map variable). We then use
kono
parents:
diff changeset
123 these to build a call to __VLTVerifyVtablePointer, passing the
kono
parents:
diff changeset
124 vtable map variable, and the vtable pointer. We insert the
kono
parents:
diff changeset
125 verification call just after the gimple statement that gets the
kono
parents:
diff changeset
126 vtable pointer out of the object, and we update the next
kono
parents:
diff changeset
127 statement to depend on the result returned from
kono
parents:
diff changeset
128 __VLTVerifyVtablePointer (the vtable pointer value), to ensure
kono
parents:
diff changeset
129 subsequent compiler phases don't remove or reorder the call (it's no
kono
parents:
diff changeset
130 good to have the verification occur after the virtual call, for
kono
parents:
diff changeset
131 example). To find the vtable pointer being used (and the type of
kono
parents:
diff changeset
132 the object) we search backwards through the def_stmts chain from the
kono
parents:
diff changeset
133 virtual call (see verify_bb_vtables for more details). */
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 #include "config.h"
kono
parents:
diff changeset
136 #include "system.h"
kono
parents:
diff changeset
137 #include "coretypes.h"
kono
parents:
diff changeset
138 #include "backend.h"
kono
parents:
diff changeset
139 #include "tree.h"
kono
parents:
diff changeset
140 #include "gimple.h"
kono
parents:
diff changeset
141 #include "tree-pass.h"
kono
parents:
diff changeset
142 #include "ssa.h"
kono
parents:
diff changeset
143 #include "gimple-iterator.h"
kono
parents:
diff changeset
144
kono
parents:
diff changeset
145 #include "vtable-verify.h"
kono
parents:
diff changeset
146
kono
parents:
diff changeset
147 unsigned num_vtable_map_nodes = 0;
kono
parents:
diff changeset
148 int total_num_virtual_calls = 0;
kono
parents:
diff changeset
149 int total_num_verified_vcalls = 0;
kono
parents:
diff changeset
150
kono
parents:
diff changeset
151 extern GTY(()) tree verify_vtbl_ptr_fndecl;
kono
parents:
diff changeset
152 tree verify_vtbl_ptr_fndecl = NULL_TREE;
kono
parents:
diff changeset
153
kono
parents:
diff changeset
154 /* Keep track of whether or not any virtual call were verified. */
kono
parents:
diff changeset
155 static bool any_verification_calls_generated = false;
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 unsigned int vtable_verify_main (void);
kono
parents:
diff changeset
158
kono
parents:
diff changeset
159
kono
parents:
diff changeset
160 /* The following few functions are for the vtbl pointer hash table
kono
parents:
diff changeset
161 in the 'registered' field of the struct vtable_map_node. The hash
kono
parents:
diff changeset
162 table keeps track of which vtable pointers have been used in
kono
parents:
diff changeset
163 calls to __VLTRegisterPair with that particular vtable map variable. */
kono
parents:
diff changeset
164
kono
parents:
diff changeset
165 /* This function checks to see if a particular VTABLE_DECL and OFFSET are
kono
parents:
diff changeset
166 already in the 'registered' hash table for NODE. */
kono
parents:
diff changeset
167
kono
parents:
diff changeset
168 bool
kono
parents:
diff changeset
169 vtbl_map_node_registration_find (struct vtbl_map_node *node,
kono
parents:
diff changeset
170 tree vtable_decl,
kono
parents:
diff changeset
171 unsigned offset)
kono
parents:
diff changeset
172 {
kono
parents:
diff changeset
173 struct vtable_registration key;
kono
parents:
diff changeset
174 struct vtable_registration **slot;
kono
parents:
diff changeset
175
kono
parents:
diff changeset
176 gcc_assert (node && node->registered);
kono
parents:
diff changeset
177
kono
parents:
diff changeset
178 key.vtable_decl = vtable_decl;
kono
parents:
diff changeset
179 slot = node->registered->find_slot (&key, NO_INSERT);
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 if (slot && (*slot))
kono
parents:
diff changeset
182 {
kono
parents:
diff changeset
183 unsigned i;
kono
parents:
diff changeset
184 for (i = 0; i < ((*slot)->offsets).length (); ++i)
kono
parents:
diff changeset
185 if ((*slot)->offsets[i] == offset)
kono
parents:
diff changeset
186 return true;
kono
parents:
diff changeset
187 }
kono
parents:
diff changeset
188
kono
parents:
diff changeset
189 return false;
kono
parents:
diff changeset
190 }
kono
parents:
diff changeset
191
kono
parents:
diff changeset
192 /* This function inserts VTABLE_DECL and OFFSET into the 'registered'
kono
parents:
diff changeset
193 hash table for NODE. It returns a boolean indicating whether or not
kono
parents:
diff changeset
194 it actually inserted anything. */
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 bool
kono
parents:
diff changeset
197 vtbl_map_node_registration_insert (struct vtbl_map_node *node,
kono
parents:
diff changeset
198 tree vtable_decl,
kono
parents:
diff changeset
199 unsigned offset)
kono
parents:
diff changeset
200 {
kono
parents:
diff changeset
201 struct vtable_registration key;
kono
parents:
diff changeset
202 struct vtable_registration **slot;
kono
parents:
diff changeset
203 bool inserted_something = false;
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 if (!node || !node->registered)
kono
parents:
diff changeset
206 return false;
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 key.vtable_decl = vtable_decl;
kono
parents:
diff changeset
209 slot = node->registered->find_slot (&key, INSERT);
kono
parents:
diff changeset
210
kono
parents:
diff changeset
211 if (! *slot)
kono
parents:
diff changeset
212 {
kono
parents:
diff changeset
213 struct vtable_registration *node;
kono
parents:
diff changeset
214 node = XNEW (struct vtable_registration);
kono
parents:
diff changeset
215 node->vtable_decl = vtable_decl;
kono
parents:
diff changeset
216
kono
parents:
diff changeset
217 (node->offsets).create (10);
kono
parents:
diff changeset
218 (node->offsets).safe_push (offset);
kono
parents:
diff changeset
219 *slot = node;
kono
parents:
diff changeset
220 inserted_something = true;
kono
parents:
diff changeset
221 }
kono
parents:
diff changeset
222 else
kono
parents:
diff changeset
223 {
kono
parents:
diff changeset
224 /* We found the vtable_decl slot; we need to see if it already
kono
parents:
diff changeset
225 contains the offset. If not, we need to add the offset. */
kono
parents:
diff changeset
226 unsigned i;
kono
parents:
diff changeset
227 bool found = false;
kono
parents:
diff changeset
228 for (i = 0; i < ((*slot)->offsets).length () && !found; ++i)
kono
parents:
diff changeset
229 if ((*slot)->offsets[i] == offset)
kono
parents:
diff changeset
230 found = true;
kono
parents:
diff changeset
231
kono
parents:
diff changeset
232 if (!found)
kono
parents:
diff changeset
233 {
kono
parents:
diff changeset
234 ((*slot)->offsets).safe_push (offset);
kono
parents:
diff changeset
235 inserted_something = true;
kono
parents:
diff changeset
236 }
kono
parents:
diff changeset
237 }
kono
parents:
diff changeset
238 return inserted_something;
kono
parents:
diff changeset
239 }
kono
parents:
diff changeset
240
kono
parents:
diff changeset
241 /* Hashtable functions for vtable_registration hashtables. */
kono
parents:
diff changeset
242
kono
parents:
diff changeset
243 inline hashval_t
kono
parents:
diff changeset
244 registration_hasher::hash (const vtable_registration *p)
kono
parents:
diff changeset
245 {
kono
parents:
diff changeset
246 const struct vtable_registration *n = (const struct vtable_registration *) p;
kono
parents:
diff changeset
247 return (hashval_t) (DECL_UID (n->vtable_decl));
kono
parents:
diff changeset
248 }
kono
parents:
diff changeset
249
kono
parents:
diff changeset
250 inline bool
kono
parents:
diff changeset
251 registration_hasher::equal (const vtable_registration *p1,
kono
parents:
diff changeset
252 const vtable_registration *p2)
kono
parents:
diff changeset
253 {
kono
parents:
diff changeset
254 const struct vtable_registration *n1 =
kono
parents:
diff changeset
255 (const struct vtable_registration *) p1;
kono
parents:
diff changeset
256 const struct vtable_registration *n2 =
kono
parents:
diff changeset
257 (const struct vtable_registration *) p2;
kono
parents:
diff changeset
258 return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
kono
parents:
diff changeset
259 }
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 /* End of hashtable functions for "registered" hashtables. */
kono
parents:
diff changeset
262
kono
parents:
diff changeset
263
kono
parents:
diff changeset
264
kono
parents:
diff changeset
265 /* Hashtable definition and functions for vtbl_map_hash. */
kono
parents:
diff changeset
266
kono
parents:
diff changeset
267 struct vtbl_map_hasher : nofree_ptr_hash <struct vtbl_map_node>
kono
parents:
diff changeset
268 {
kono
parents:
diff changeset
269 static inline hashval_t hash (const vtbl_map_node *);
kono
parents:
diff changeset
270 static inline bool equal (const vtbl_map_node *, const vtbl_map_node *);
kono
parents:
diff changeset
271 };
kono
parents:
diff changeset
272
kono
parents:
diff changeset
273 /* Returns a hash code for P. */
kono
parents:
diff changeset
274
kono
parents:
diff changeset
275 inline hashval_t
kono
parents:
diff changeset
276 vtbl_map_hasher::hash (const vtbl_map_node *p)
kono
parents:
diff changeset
277 {
kono
parents:
diff changeset
278 const struct vtbl_map_node n = *((const struct vtbl_map_node *) p);
kono
parents:
diff changeset
279 return (hashval_t) IDENTIFIER_HASH_VALUE (n.class_name);
kono
parents:
diff changeset
280 }
kono
parents:
diff changeset
281
kono
parents:
diff changeset
282 /* Returns nonzero if P1 and P2 are equal. */
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 inline bool
kono
parents:
diff changeset
285 vtbl_map_hasher::equal (const vtbl_map_node *p1, const vtbl_map_node *p2)
kono
parents:
diff changeset
286 {
kono
parents:
diff changeset
287 const struct vtbl_map_node n1 = *((const struct vtbl_map_node *) p1);
kono
parents:
diff changeset
288 const struct vtbl_map_node n2 = *((const struct vtbl_map_node *) p2);
kono
parents:
diff changeset
289 return (IDENTIFIER_HASH_VALUE (n1.class_name) ==
kono
parents:
diff changeset
290 IDENTIFIER_HASH_VALUE (n2.class_name));
kono
parents:
diff changeset
291 }
kono
parents:
diff changeset
292
kono
parents:
diff changeset
293 /* Here are the two structures into which we insert vtable map nodes.
kono
parents:
diff changeset
294 We use two data structures because of the vastly different ways we need
kono
parents:
diff changeset
295 to find the nodes for various tasks (see comments in vtable-verify.h
kono
parents:
diff changeset
296 for more details. */
kono
parents:
diff changeset
297
kono
parents:
diff changeset
298 typedef hash_table<vtbl_map_hasher> vtbl_map_table_type;
kono
parents:
diff changeset
299 typedef vtbl_map_table_type::iterator vtbl_map_iterator_type;
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 /* Vtable map variable nodes stored in a hash table. */
kono
parents:
diff changeset
302 static vtbl_map_table_type *vtbl_map_hash;
kono
parents:
diff changeset
303
kono
parents:
diff changeset
304 /* Vtable map variable nodes stored in a vector. */
kono
parents:
diff changeset
305 vec<struct vtbl_map_node *> vtbl_map_nodes_vec;
kono
parents:
diff changeset
306
kono
parents:
diff changeset
307 /* Vector of mangled names for anonymous classes. */
kono
parents:
diff changeset
308 extern GTY(()) vec<tree, va_gc> *vtbl_mangled_name_types;
kono
parents:
diff changeset
309 extern GTY(()) vec<tree, va_gc> *vtbl_mangled_name_ids;
kono
parents:
diff changeset
310 vec<tree, va_gc> *vtbl_mangled_name_types;
kono
parents:
diff changeset
311 vec<tree, va_gc> *vtbl_mangled_name_ids;
kono
parents:
diff changeset
312
kono
parents:
diff changeset
313 /* Look up class_type (a type decl for record types) in the vtbl_mangled_names_*
kono
parents:
diff changeset
314 vectors. This is a linear lookup. Return the associated mangled name for
kono
parents:
diff changeset
315 the class type. This is for handling types from anonymous namespaces, whose
kono
parents:
diff changeset
316 DECL_ASSEMBLER_NAME ends up being "<anon>", which is useless for our
kono
parents:
diff changeset
317 purposes.
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 We use two vectors of trees to keep track of the mangled names: One is a
kono
parents:
diff changeset
320 vector of class types and the other is a vector of the mangled names. The
kono
parents:
diff changeset
321 assumption is that these two vectors are kept in perfect lock-step so that
kono
parents:
diff changeset
322 vtbl_mangled_name_ids[i] is the mangled name for
kono
parents:
diff changeset
323 vtbl_mangled_name_types[i]. */
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 static tree
kono
parents:
diff changeset
326 vtbl_find_mangled_name (tree class_type)
kono
parents:
diff changeset
327 {
kono
parents:
diff changeset
328 tree result = NULL_TREE;
kono
parents:
diff changeset
329 unsigned i;
kono
parents:
diff changeset
330
kono
parents:
diff changeset
331 if (!vtbl_mangled_name_types or !vtbl_mangled_name_ids)
kono
parents:
diff changeset
332 return result;
kono
parents:
diff changeset
333
kono
parents:
diff changeset
334 if (vtbl_mangled_name_types->length() != vtbl_mangled_name_ids->length())
kono
parents:
diff changeset
335 return result;
kono
parents:
diff changeset
336
kono
parents:
diff changeset
337 for (i = 0; i < vtbl_mangled_name_types->length(); ++i)
kono
parents:
diff changeset
338 if ((*vtbl_mangled_name_types)[i] == class_type)
kono
parents:
diff changeset
339 {
kono
parents:
diff changeset
340 result = (*vtbl_mangled_name_ids)[i];
kono
parents:
diff changeset
341 break;
kono
parents:
diff changeset
342 }
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344 return result;
kono
parents:
diff changeset
345 }
kono
parents:
diff changeset
346
kono
parents:
diff changeset
347 /* Store a class type decl and its mangled name, for an anonymous RECORD_TYPE,
kono
parents:
diff changeset
348 in the vtbl_mangled_names vector. Make sure there is not already an
kono
parents:
diff changeset
349 entry for the class type before adding it. */
kono
parents:
diff changeset
350
kono
parents:
diff changeset
351 void
kono
parents:
diff changeset
352 vtbl_register_mangled_name (tree class_type, tree mangled_name)
kono
parents:
diff changeset
353 {
kono
parents:
diff changeset
354 if (!vtbl_mangled_name_types)
kono
parents:
diff changeset
355 vec_alloc (vtbl_mangled_name_types, 10);
kono
parents:
diff changeset
356
kono
parents:
diff changeset
357 if (!vtbl_mangled_name_ids)
kono
parents:
diff changeset
358 vec_alloc (vtbl_mangled_name_ids, 10);
kono
parents:
diff changeset
359
kono
parents:
diff changeset
360 gcc_assert (vtbl_mangled_name_types->length() ==
kono
parents:
diff changeset
361 vtbl_mangled_name_ids->length());
kono
parents:
diff changeset
362
kono
parents:
diff changeset
363
kono
parents:
diff changeset
364 if (vtbl_find_mangled_name (class_type) == NULL_TREE)
kono
parents:
diff changeset
365 {
kono
parents:
diff changeset
366 vec_safe_push (vtbl_mangled_name_types, class_type);
kono
parents:
diff changeset
367 vec_safe_push (vtbl_mangled_name_ids, mangled_name);
kono
parents:
diff changeset
368 }
kono
parents:
diff changeset
369 }
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 /* Return vtbl_map node for CLASS_NAME without creating a new one. */
kono
parents:
diff changeset
372
kono
parents:
diff changeset
373 struct vtbl_map_node *
kono
parents:
diff changeset
374 vtbl_map_get_node (tree class_type)
kono
parents:
diff changeset
375 {
kono
parents:
diff changeset
376 struct vtbl_map_node key;
kono
parents:
diff changeset
377 struct vtbl_map_node **slot;
kono
parents:
diff changeset
378
kono
parents:
diff changeset
379 tree class_type_decl;
kono
parents:
diff changeset
380 tree class_name;
kono
parents:
diff changeset
381 unsigned int type_quals;
kono
parents:
diff changeset
382
kono
parents:
diff changeset
383 if (!vtbl_map_hash)
kono
parents:
diff changeset
384 return NULL;
kono
parents:
diff changeset
385
kono
parents:
diff changeset
386 gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388
kono
parents:
diff changeset
389 /* Find the TYPE_DECL for the class. */
kono
parents:
diff changeset
390 class_type_decl = TYPE_NAME (class_type);
kono
parents:
diff changeset
391
kono
parents:
diff changeset
392 /* Verify that there aren't any qualifiers on the type. */
kono
parents:
diff changeset
393 type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
kono
parents:
diff changeset
394 gcc_assert (type_quals == TYPE_UNQUALIFIED);
kono
parents:
diff changeset
395
kono
parents:
diff changeset
396 /* Get the mangled name for the unqualified type. */
kono
parents:
diff changeset
397 gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl));
kono
parents:
diff changeset
398 class_name = DECL_ASSEMBLER_NAME (class_type_decl);
kono
parents:
diff changeset
399
kono
parents:
diff changeset
400 if (strstr (IDENTIFIER_POINTER (class_name), "<anon>") != NULL)
kono
parents:
diff changeset
401 class_name = vtbl_find_mangled_name (class_type_decl);
kono
parents:
diff changeset
402
kono
parents:
diff changeset
403 key.class_name = class_name;
kono
parents:
diff changeset
404 slot = (struct vtbl_map_node **) vtbl_map_hash->find_slot (&key, NO_INSERT);
kono
parents:
diff changeset
405 if (!slot)
kono
parents:
diff changeset
406 return NULL;
kono
parents:
diff changeset
407 return *slot;
kono
parents:
diff changeset
408 }
kono
parents:
diff changeset
409
kono
parents:
diff changeset
410 /* Return vtbl_map node assigned to BASE_CLASS_TYPE. Create new one
kono
parents:
diff changeset
411 when needed. */
kono
parents:
diff changeset
412
kono
parents:
diff changeset
413 struct vtbl_map_node *
kono
parents:
diff changeset
414 find_or_create_vtbl_map_node (tree base_class_type)
kono
parents:
diff changeset
415 {
kono
parents:
diff changeset
416 struct vtbl_map_node key;
kono
parents:
diff changeset
417 struct vtbl_map_node *node;
kono
parents:
diff changeset
418 struct vtbl_map_node **slot;
kono
parents:
diff changeset
419 tree class_type_decl;
kono
parents:
diff changeset
420 unsigned int type_quals;
kono
parents:
diff changeset
421
kono
parents:
diff changeset
422 if (!vtbl_map_hash)
kono
parents:
diff changeset
423 vtbl_map_hash = new vtbl_map_table_type (10);
kono
parents:
diff changeset
424
kono
parents:
diff changeset
425 /* Find the TYPE_DECL for the class. */
kono
parents:
diff changeset
426 class_type_decl = TYPE_NAME (base_class_type);
kono
parents:
diff changeset
427
kono
parents:
diff changeset
428 /* Verify that there aren't any type qualifiers on type. */
kono
parents:
diff changeset
429 type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
kono
parents:
diff changeset
430 gcc_assert (type_quals == TYPE_UNQUALIFIED);
kono
parents:
diff changeset
431
kono
parents:
diff changeset
432 gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl));
kono
parents:
diff changeset
433 key.class_name = DECL_ASSEMBLER_NAME (class_type_decl);
kono
parents:
diff changeset
434
kono
parents:
diff changeset
435 if (strstr (IDENTIFIER_POINTER (key.class_name), "<anon>") != NULL)
kono
parents:
diff changeset
436 key.class_name = vtbl_find_mangled_name (class_type_decl);
kono
parents:
diff changeset
437
kono
parents:
diff changeset
438 slot = (struct vtbl_map_node **) vtbl_map_hash->find_slot (&key, INSERT);
kono
parents:
diff changeset
439
kono
parents:
diff changeset
440 if (*slot)
kono
parents:
diff changeset
441 return *slot;
kono
parents:
diff changeset
442
kono
parents:
diff changeset
443 node = XNEW (struct vtbl_map_node);
kono
parents:
diff changeset
444 node->vtbl_map_decl = NULL_TREE;
kono
parents:
diff changeset
445 node->class_name = key.class_name;
kono
parents:
diff changeset
446 node->uid = num_vtable_map_nodes++;
kono
parents:
diff changeset
447
kono
parents:
diff changeset
448 node->class_info = XNEW (struct vtv_graph_node);
kono
parents:
diff changeset
449 node->class_info->class_type = base_class_type;
kono
parents:
diff changeset
450 node->class_info->class_uid = node->uid;
kono
parents:
diff changeset
451 node->class_info->num_processed_children = 0;
kono
parents:
diff changeset
452
kono
parents:
diff changeset
453 (node->class_info->parents).create (4);
kono
parents:
diff changeset
454 (node->class_info->children).create (4);
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 node->registered = new register_table_type (16);
kono
parents:
diff changeset
457
kono
parents:
diff changeset
458 node->is_used = false;
kono
parents:
diff changeset
459
kono
parents:
diff changeset
460 vtbl_map_nodes_vec.safe_push (node);
kono
parents:
diff changeset
461 gcc_assert (vtbl_map_nodes_vec[node->uid] == node);
kono
parents:
diff changeset
462
kono
parents:
diff changeset
463 *slot = node;
kono
parents:
diff changeset
464 return node;
kono
parents:
diff changeset
465 }
kono
parents:
diff changeset
466
kono
parents:
diff changeset
467 /* End of hashtable functions for vtable_map variables hash table. */
kono
parents:
diff changeset
468
kono
parents:
diff changeset
469 /* Given a gimple STMT, this function checks to see if the statement
kono
parents:
diff changeset
470 is an assignment, the rhs of which is getting the vtable pointer
kono
parents:
diff changeset
471 value out of an object. (i.e. it's the value we need to verify
kono
parents:
diff changeset
472 because its the vtable pointer that will be used for a virtual
kono
parents:
diff changeset
473 call). */
kono
parents:
diff changeset
474
kono
parents:
diff changeset
475 static bool
kono
parents:
diff changeset
476 is_vtable_assignment_stmt (gimple *stmt)
kono
parents:
diff changeset
477 {
kono
parents:
diff changeset
478
kono
parents:
diff changeset
479 if (gimple_code (stmt) != GIMPLE_ASSIGN)
kono
parents:
diff changeset
480 return false;
kono
parents:
diff changeset
481 else
kono
parents:
diff changeset
482 {
kono
parents:
diff changeset
483 tree lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
484 tree rhs = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
485
kono
parents:
diff changeset
486 if (TREE_CODE (lhs) != SSA_NAME)
kono
parents:
diff changeset
487 return false;
kono
parents:
diff changeset
488
kono
parents:
diff changeset
489 if (TREE_CODE (rhs) != COMPONENT_REF)
kono
parents:
diff changeset
490 return false;
kono
parents:
diff changeset
491
kono
parents:
diff changeset
492 if (! (TREE_OPERAND (rhs, 1))
kono
parents:
diff changeset
493 || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
kono
parents:
diff changeset
494 return false;
kono
parents:
diff changeset
495
kono
parents:
diff changeset
496 if (! DECL_VIRTUAL_P (TREE_OPERAND (rhs, 1)))
kono
parents:
diff changeset
497 return false;
kono
parents:
diff changeset
498 }
kono
parents:
diff changeset
499
kono
parents:
diff changeset
500 return true;
kono
parents:
diff changeset
501 }
kono
parents:
diff changeset
502
kono
parents:
diff changeset
503 /* This function attempts to recover the declared class of an object
kono
parents:
diff changeset
504 that is used in making a virtual call. We try to get the type from
kono
parents:
diff changeset
505 the type cast in the gimple assignment statement that extracts the
kono
parents:
diff changeset
506 vtable pointer from the object (DEF_STMT). The gimple statement
kono
parents:
diff changeset
507 usually looks something like this:
kono
parents:
diff changeset
508
kono
parents:
diff changeset
509 D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event */
kono
parents:
diff changeset
510
kono
parents:
diff changeset
511 static tree
kono
parents:
diff changeset
512 extract_object_class_type (tree rhs)
kono
parents:
diff changeset
513 {
kono
parents:
diff changeset
514 tree result = NULL_TREE;
kono
parents:
diff changeset
515
kono
parents:
diff changeset
516 /* Try to find and extract the type cast from that stmt. */
kono
parents:
diff changeset
517 if (TREE_CODE (rhs) == COMPONENT_REF)
kono
parents:
diff changeset
518 {
kono
parents:
diff changeset
519 tree op0 = TREE_OPERAND (rhs, 0);
kono
parents:
diff changeset
520 tree op1 = TREE_OPERAND (rhs, 1);
kono
parents:
diff changeset
521
kono
parents:
diff changeset
522 if (TREE_CODE (op1) == FIELD_DECL
kono
parents:
diff changeset
523 && DECL_VIRTUAL_P (op1))
kono
parents:
diff changeset
524 {
kono
parents:
diff changeset
525 if (TREE_CODE (op0) == COMPONENT_REF
kono
parents:
diff changeset
526 && TREE_CODE (TREE_OPERAND (op0, 0)) == MEM_REF
kono
parents:
diff changeset
527 && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))== RECORD_TYPE)
kono
parents:
diff changeset
528 result = TREE_TYPE (TREE_OPERAND (op0, 0));
kono
parents:
diff changeset
529 else
kono
parents:
diff changeset
530 result = TREE_TYPE (op0);
kono
parents:
diff changeset
531 }
kono
parents:
diff changeset
532 else if (TREE_CODE (op0) == COMPONENT_REF)
kono
parents:
diff changeset
533 {
kono
parents:
diff changeset
534 result = extract_object_class_type (op0);
kono
parents:
diff changeset
535 if (result == NULL_TREE
kono
parents:
diff changeset
536 && TREE_CODE (op1) == COMPONENT_REF)
kono
parents:
diff changeset
537 result = extract_object_class_type (op1);
kono
parents:
diff changeset
538 }
kono
parents:
diff changeset
539 }
kono
parents:
diff changeset
540
kono
parents:
diff changeset
541 return result;
kono
parents:
diff changeset
542 }
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 /* This function traces forward through the def-use chain of an SSA
kono
parents:
diff changeset
545 variable to see if it ever gets used in a virtual function call. It
kono
parents:
diff changeset
546 returns a boolean indicating whether or not it found a virtual call in
kono
parents:
diff changeset
547 the use chain. */
kono
parents:
diff changeset
548
kono
parents:
diff changeset
549 static bool
kono
parents:
diff changeset
550 var_is_used_for_virtual_call_p (tree lhs, int *mem_ref_depth,
kono
parents:
diff changeset
551 int *recursion_depth)
kono
parents:
diff changeset
552 {
kono
parents:
diff changeset
553 imm_use_iterator imm_iter;
kono
parents:
diff changeset
554 bool found_vcall = false;
kono
parents:
diff changeset
555 use_operand_p use_p;
kono
parents:
diff changeset
556
kono
parents:
diff changeset
557 if (TREE_CODE (lhs) != SSA_NAME)
kono
parents:
diff changeset
558 return false;
kono
parents:
diff changeset
559
kono
parents:
diff changeset
560 if (*mem_ref_depth > 2)
kono
parents:
diff changeset
561 return false;
kono
parents:
diff changeset
562
kono
parents:
diff changeset
563 if (*recursion_depth > 25)
kono
parents:
diff changeset
564 /* If we've recursed this far the chances are pretty good that
kono
parents:
diff changeset
565 we're not going to find what we're looking for, and that we've
kono
parents:
diff changeset
566 gone down a recursion black hole. Time to stop. */
kono
parents:
diff changeset
567 return false;
kono
parents:
diff changeset
568
kono
parents:
diff changeset
569 *recursion_depth = *recursion_depth + 1;
kono
parents:
diff changeset
570
kono
parents:
diff changeset
571 /* Iterate through the immediate uses of the current variable. If
kono
parents:
diff changeset
572 it's a virtual function call, we're done. Otherwise, if there's
kono
parents:
diff changeset
573 an LHS for the use stmt, add the ssa var to the work list
kono
parents:
diff changeset
574 (assuming it's not already in the list and is not a variable
kono
parents:
diff changeset
575 we've already examined. */
kono
parents:
diff changeset
576
kono
parents:
diff changeset
577 FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
kono
parents:
diff changeset
578 {
kono
parents:
diff changeset
579 gimple *stmt2 = USE_STMT (use_p);
kono
parents:
diff changeset
580
kono
parents:
diff changeset
581 if (is_gimple_call (stmt2))
kono
parents:
diff changeset
582 {
kono
parents:
diff changeset
583 tree fncall = gimple_call_fn (stmt2);
kono
parents:
diff changeset
584 if (fncall && TREE_CODE (fncall) == OBJ_TYPE_REF)
kono
parents:
diff changeset
585 found_vcall = true;
kono
parents:
diff changeset
586 else
kono
parents:
diff changeset
587 return false;
kono
parents:
diff changeset
588 }
kono
parents:
diff changeset
589 else if (gimple_code (stmt2) == GIMPLE_PHI)
kono
parents:
diff changeset
590 {
kono
parents:
diff changeset
591 found_vcall = var_is_used_for_virtual_call_p
kono
parents:
diff changeset
592 (gimple_phi_result (stmt2),
kono
parents:
diff changeset
593 mem_ref_depth,
kono
parents:
diff changeset
594 recursion_depth);
kono
parents:
diff changeset
595 }
kono
parents:
diff changeset
596 else if (is_gimple_assign (stmt2))
kono
parents:
diff changeset
597 {
kono
parents:
diff changeset
598 tree rhs = gimple_assign_rhs1 (stmt2);
kono
parents:
diff changeset
599 if (TREE_CODE (rhs) == ADDR_EXPR
kono
parents:
diff changeset
600 || TREE_CODE (rhs) == MEM_REF)
kono
parents:
diff changeset
601 *mem_ref_depth = *mem_ref_depth + 1;
kono
parents:
diff changeset
602
kono
parents:
diff changeset
603 if (TREE_CODE (rhs) == COMPONENT_REF)
kono
parents:
diff changeset
604 {
kono
parents:
diff changeset
605 while (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF)
kono
parents:
diff changeset
606 rhs = TREE_OPERAND (rhs, 0);
kono
parents:
diff changeset
607
kono
parents:
diff changeset
608 if (TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
kono
parents:
diff changeset
609 || TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF)
kono
parents:
diff changeset
610 *mem_ref_depth = *mem_ref_depth + 1;
kono
parents:
diff changeset
611 }
kono
parents:
diff changeset
612
kono
parents:
diff changeset
613 if (*mem_ref_depth < 3)
kono
parents:
diff changeset
614 found_vcall = var_is_used_for_virtual_call_p
kono
parents:
diff changeset
615 (gimple_assign_lhs (stmt2),
kono
parents:
diff changeset
616 mem_ref_depth,
kono
parents:
diff changeset
617 recursion_depth);
kono
parents:
diff changeset
618 }
kono
parents:
diff changeset
619
kono
parents:
diff changeset
620 else
kono
parents:
diff changeset
621 break;
kono
parents:
diff changeset
622
kono
parents:
diff changeset
623 if (found_vcall)
kono
parents:
diff changeset
624 return true;
kono
parents:
diff changeset
625 }
kono
parents:
diff changeset
626
kono
parents:
diff changeset
627 return false;
kono
parents:
diff changeset
628 }
kono
parents:
diff changeset
629
kono
parents:
diff changeset
630 /* Search through all the statements in a basic block (BB), searching
kono
parents:
diff changeset
631 for virtual method calls. For each virtual method dispatch, find
kono
parents:
diff changeset
632 the vptr value used, and the statically declared type of the
kono
parents:
diff changeset
633 object; retrieve the vtable map variable for the type of the
kono
parents:
diff changeset
634 object; generate a call to __VLTVerifyVtablePointer; and insert the
kono
parents:
diff changeset
635 generated call into the basic block, after the point where the vptr
kono
parents:
diff changeset
636 value is gotten out of the object and before the virtual method
kono
parents:
diff changeset
637 dispatch. Make the virtual method dispatch depend on the return
kono
parents:
diff changeset
638 value from the verification call, so that subsequent optimizations
kono
parents:
diff changeset
639 cannot reorder the two calls. */
kono
parents:
diff changeset
640
kono
parents:
diff changeset
641 static void
kono
parents:
diff changeset
642 verify_bb_vtables (basic_block bb)
kono
parents:
diff changeset
643 {
kono
parents:
diff changeset
644 gimple_seq stmts;
kono
parents:
diff changeset
645 gimple *stmt = NULL;
kono
parents:
diff changeset
646 gimple_stmt_iterator gsi_vtbl_assign;
kono
parents:
diff changeset
647 gimple_stmt_iterator gsi_virtual_call;
kono
parents:
diff changeset
648
kono
parents:
diff changeset
649 stmts = bb_seq (bb);
kono
parents:
diff changeset
650 gsi_virtual_call = gsi_start (stmts);
kono
parents:
diff changeset
651 for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
kono
parents:
diff changeset
652 {
kono
parents:
diff changeset
653 stmt = gsi_stmt (gsi_virtual_call);
kono
parents:
diff changeset
654
kono
parents:
diff changeset
655 /* Count virtual calls. */
kono
parents:
diff changeset
656 if (is_gimple_call (stmt))
kono
parents:
diff changeset
657 {
kono
parents:
diff changeset
658 tree fncall = gimple_call_fn (stmt);
kono
parents:
diff changeset
659 if (fncall && TREE_CODE (fncall) == OBJ_TYPE_REF)
kono
parents:
diff changeset
660 total_num_virtual_calls++;
kono
parents:
diff changeset
661 }
kono
parents:
diff changeset
662
kono
parents:
diff changeset
663 if (is_vtable_assignment_stmt (stmt))
kono
parents:
diff changeset
664 {
kono
parents:
diff changeset
665 tree lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
666 tree vtbl_var_decl = NULL_TREE;
kono
parents:
diff changeset
667 struct vtbl_map_node *vtable_map_node;
kono
parents:
diff changeset
668 tree vtbl_decl = NULL_TREE;
kono
parents:
diff changeset
669 gcall *call_stmt;
kono
parents:
diff changeset
670 const char *vtable_name = "<unknown>";
kono
parents:
diff changeset
671 tree tmp0;
kono
parents:
diff changeset
672 bool found;
kono
parents:
diff changeset
673 int mem_ref_depth = 0;
kono
parents:
diff changeset
674 int recursion_depth = 0;
kono
parents:
diff changeset
675
kono
parents:
diff changeset
676 /* Make sure this vptr field access is for a virtual call. */
kono
parents:
diff changeset
677 if (!var_is_used_for_virtual_call_p (lhs, &mem_ref_depth,
kono
parents:
diff changeset
678 &recursion_depth))
kono
parents:
diff changeset
679 continue;
kono
parents:
diff changeset
680
kono
parents:
diff changeset
681 /* Now we have found the virtual method dispatch and
kono
parents:
diff changeset
682 the preceding access of the _vptr.* field... Next
kono
parents:
diff changeset
683 we need to find the statically declared type of
kono
parents:
diff changeset
684 the object, so we can find and use the right
kono
parents:
diff changeset
685 vtable map variable in the verification call. */
kono
parents:
diff changeset
686 tree class_type = extract_object_class_type
kono
parents:
diff changeset
687 (gimple_assign_rhs1 (stmt));
kono
parents:
diff changeset
688
kono
parents:
diff changeset
689 gsi_vtbl_assign = gsi_for_stmt (stmt);
kono
parents:
diff changeset
690
kono
parents:
diff changeset
691 if (class_type
kono
parents:
diff changeset
692 && (TREE_CODE (class_type) == RECORD_TYPE)
kono
parents:
diff changeset
693 && TYPE_BINFO (class_type))
kono
parents:
diff changeset
694 {
kono
parents:
diff changeset
695 /* Get the vtable VAR_DECL for the type. */
kono
parents:
diff changeset
696 vtbl_var_decl = BINFO_VTABLE (TYPE_BINFO (class_type));
kono
parents:
diff changeset
697
kono
parents:
diff changeset
698 if (TREE_CODE (vtbl_var_decl) == POINTER_PLUS_EXPR)
kono
parents:
diff changeset
699 vtbl_var_decl = TREE_OPERAND (TREE_OPERAND (vtbl_var_decl, 0),
kono
parents:
diff changeset
700 0);
kono
parents:
diff changeset
701
kono
parents:
diff changeset
702 gcc_assert (vtbl_var_decl);
kono
parents:
diff changeset
703
kono
parents:
diff changeset
704 vtbl_decl = vtbl_var_decl;
kono
parents:
diff changeset
705 vtable_map_node = vtbl_map_get_node
kono
parents:
diff changeset
706 (TYPE_MAIN_VARIANT (class_type));
kono
parents:
diff changeset
707
kono
parents:
diff changeset
708 gcc_assert (verify_vtbl_ptr_fndecl);
kono
parents:
diff changeset
709
kono
parents:
diff changeset
710 /* Given the vtable pointer for the base class of the
kono
parents:
diff changeset
711 object, build the call to __VLTVerifyVtablePointer to
kono
parents:
diff changeset
712 verify that the object's vtable pointer (contained in
kono
parents:
diff changeset
713 lhs) is in the set of valid vtable pointers for the
kono
parents:
diff changeset
714 base class. */
kono
parents:
diff changeset
715
kono
parents:
diff changeset
716 if (vtable_map_node && vtable_map_node->vtbl_map_decl)
kono
parents:
diff changeset
717 {
kono
parents:
diff changeset
718 vtable_map_node->is_used = true;
kono
parents:
diff changeset
719 vtbl_var_decl = vtable_map_node->vtbl_map_decl;
kono
parents:
diff changeset
720
kono
parents:
diff changeset
721 if (VAR_P (vtbl_decl))
kono
parents:
diff changeset
722 vtable_name = IDENTIFIER_POINTER (DECL_NAME (vtbl_decl));
kono
parents:
diff changeset
723
kono
parents:
diff changeset
724 /* Call different routines if we are interested in
kono
parents:
diff changeset
725 trace information to debug problems. */
kono
parents:
diff changeset
726 if (flag_vtv_debug)
kono
parents:
diff changeset
727 {
kono
parents:
diff changeset
728 int len1 = IDENTIFIER_LENGTH
kono
parents:
diff changeset
729 (DECL_NAME (vtbl_var_decl));
kono
parents:
diff changeset
730 int len2 = strlen (vtable_name);
kono
parents:
diff changeset
731
kono
parents:
diff changeset
732 call_stmt = gimple_build_call
kono
parents:
diff changeset
733 (verify_vtbl_ptr_fndecl, 4,
kono
parents:
diff changeset
734 build1 (ADDR_EXPR,
kono
parents:
diff changeset
735 TYPE_POINTER_TO
kono
parents:
diff changeset
736 (TREE_TYPE (vtbl_var_decl)),
kono
parents:
diff changeset
737 vtbl_var_decl),
kono
parents:
diff changeset
738 lhs,
kono
parents:
diff changeset
739 build_string_literal
kono
parents:
diff changeset
740 (len1 + 1,
kono
parents:
diff changeset
741 IDENTIFIER_POINTER
kono
parents:
diff changeset
742 (DECL_NAME
kono
parents:
diff changeset
743 (vtbl_var_decl))),
kono
parents:
diff changeset
744 build_string_literal (len2 + 1,
kono
parents:
diff changeset
745 vtable_name));
kono
parents:
diff changeset
746 }
kono
parents:
diff changeset
747 else
kono
parents:
diff changeset
748 call_stmt = gimple_build_call
kono
parents:
diff changeset
749 (verify_vtbl_ptr_fndecl, 2,
kono
parents:
diff changeset
750 build1 (ADDR_EXPR,
kono
parents:
diff changeset
751 TYPE_POINTER_TO
kono
parents:
diff changeset
752 (TREE_TYPE (vtbl_var_decl)),
kono
parents:
diff changeset
753 vtbl_var_decl),
kono
parents:
diff changeset
754 lhs);
kono
parents:
diff changeset
755
kono
parents:
diff changeset
756
kono
parents:
diff changeset
757 /* Create a new SSA_NAME var to hold the call's
kono
parents:
diff changeset
758 return value, and make the call_stmt use the
kono
parents:
diff changeset
759 variable for that purpose. */
kono
parents:
diff changeset
760 tmp0 = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "VTV");
kono
parents:
diff changeset
761 gimple_call_set_lhs (call_stmt, tmp0);
kono
parents:
diff changeset
762 update_stmt (call_stmt);
kono
parents:
diff changeset
763
kono
parents:
diff changeset
764 /* Replace all uses of lhs with tmp0. */
kono
parents:
diff changeset
765 found = false;
kono
parents:
diff changeset
766 imm_use_iterator iterator;
kono
parents:
diff changeset
767 gimple *use_stmt;
kono
parents:
diff changeset
768 FOR_EACH_IMM_USE_STMT (use_stmt, iterator, lhs)
kono
parents:
diff changeset
769 {
kono
parents:
diff changeset
770 use_operand_p use_p;
kono
parents:
diff changeset
771 if (use_stmt == call_stmt)
kono
parents:
diff changeset
772 continue;
kono
parents:
diff changeset
773 FOR_EACH_IMM_USE_ON_STMT (use_p, iterator)
kono
parents:
diff changeset
774 SET_USE (use_p, tmp0);
kono
parents:
diff changeset
775 update_stmt (use_stmt);
kono
parents:
diff changeset
776 found = true;
kono
parents:
diff changeset
777 }
kono
parents:
diff changeset
778
kono
parents:
diff changeset
779 gcc_assert (found);
kono
parents:
diff changeset
780
kono
parents:
diff changeset
781 /* Insert the new verification call just after the
kono
parents:
diff changeset
782 statement that gets the vtable pointer out of the
kono
parents:
diff changeset
783 object. */
kono
parents:
diff changeset
784 gcc_assert (gsi_stmt (gsi_vtbl_assign) == stmt);
kono
parents:
diff changeset
785 gsi_insert_after (&gsi_vtbl_assign, call_stmt,
kono
parents:
diff changeset
786 GSI_NEW_STMT);
kono
parents:
diff changeset
787
kono
parents:
diff changeset
788 any_verification_calls_generated = true;
kono
parents:
diff changeset
789 total_num_verified_vcalls++;
kono
parents:
diff changeset
790 }
kono
parents:
diff changeset
791 }
kono
parents:
diff changeset
792 }
kono
parents:
diff changeset
793 }
kono
parents:
diff changeset
794 }
kono
parents:
diff changeset
795
kono
parents:
diff changeset
796 /* Definition of this optimization pass. */
kono
parents:
diff changeset
797
kono
parents:
diff changeset
798 namespace {
kono
parents:
diff changeset
799
kono
parents:
diff changeset
800 const pass_data pass_data_vtable_verify =
kono
parents:
diff changeset
801 {
kono
parents:
diff changeset
802 GIMPLE_PASS, /* type */
kono
parents:
diff changeset
803 "vtable-verify", /* name */
kono
parents:
diff changeset
804 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
805 TV_VTABLE_VERIFICATION, /* tv_id */
kono
parents:
diff changeset
806 ( PROP_cfg | PROP_ssa ), /* properties_required */
kono
parents:
diff changeset
807 0, /* properties_provided */
kono
parents:
diff changeset
808 0, /* properties_destroyed */
kono
parents:
diff changeset
809 0, /* todo_flags_start */
kono
parents:
diff changeset
810 TODO_update_ssa, /* todo_flags_finish */
kono
parents:
diff changeset
811 };
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 class pass_vtable_verify : public gimple_opt_pass
kono
parents:
diff changeset
814 {
kono
parents:
diff changeset
815 public:
kono
parents:
diff changeset
816 pass_vtable_verify (gcc::context *ctxt)
kono
parents:
diff changeset
817 : gimple_opt_pass (pass_data_vtable_verify, ctxt)
kono
parents:
diff changeset
818 {}
kono
parents:
diff changeset
819
kono
parents:
diff changeset
820 /* opt_pass methods: */
kono
parents:
diff changeset
821 virtual bool gate (function *) { return (flag_vtable_verify); }
kono
parents:
diff changeset
822 virtual unsigned int execute (function *);
kono
parents:
diff changeset
823
kono
parents:
diff changeset
824 }; // class pass_vtable_verify
kono
parents:
diff changeset
825
kono
parents:
diff changeset
826 /* Loop through all the basic blocks in the current function, passing them to
kono
parents:
diff changeset
827 verify_bb_vtables, which searches for virtual calls, and inserts
kono
parents:
diff changeset
828 calls to __VLTVerifyVtablePointer. */
kono
parents:
diff changeset
829
kono
parents:
diff changeset
830 unsigned int
kono
parents:
diff changeset
831 pass_vtable_verify::execute (function *fun)
kono
parents:
diff changeset
832 {
kono
parents:
diff changeset
833 unsigned int ret = 1;
kono
parents:
diff changeset
834 basic_block bb;
kono
parents:
diff changeset
835
kono
parents:
diff changeset
836 FOR_ALL_BB_FN (bb, fun)
kono
parents:
diff changeset
837 verify_bb_vtables (bb);
kono
parents:
diff changeset
838
kono
parents:
diff changeset
839 return ret;
kono
parents:
diff changeset
840 }
kono
parents:
diff changeset
841
kono
parents:
diff changeset
842 } // anon namespace
kono
parents:
diff changeset
843
kono
parents:
diff changeset
844 gimple_opt_pass *
kono
parents:
diff changeset
845 make_pass_vtable_verify (gcc::context *ctxt)
kono
parents:
diff changeset
846 {
kono
parents:
diff changeset
847 return new pass_vtable_verify (ctxt);
kono
parents:
diff changeset
848 }
kono
parents:
diff changeset
849
kono
parents:
diff changeset
850 #include "gt-vtable-verify.h"