131
|
1 /* Copyright (C) 2012-2018 Free Software Foundation, Inc.
|
111
|
2
|
|
3 This file is part of GCC.
|
|
4
|
|
5 GCC is free software; you can redistribute it and/or modify it
|
|
6 under the terms of the GNU General Public License as published by
|
|
7 the Free Software Foundation; either version 3, or (at your option)
|
|
8 any later version.
|
|
9
|
|
10 GCC is distributed in the hope that it will be useful, but
|
|
11 WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13 General Public License for more details.
|
|
14
|
|
15 You should have received a copy of the GNU General Public License
|
|
16 along with GCC; see the file COPYING3. If not see
|
|
17 <http://www.gnu.org/licenses/>. */
|
|
18
|
|
19 /* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
|
|
20 before using them for virtual method dispatches. */
|
|
21
|
|
22 /* This file is part of the vtable security feature implementation.
|
|
23 The vtable security feature is designed to detect when a virtual
|
|
24 call is about to be made through an invalid vtable pointer
|
|
25 (possibly due to data corruption or malicious attacks). The
|
|
26 compiler finds every virtual call, and inserts a verification call
|
|
27 before the virtual call. The verification call takes the actual
|
|
28 vtable pointer value in the object through which the virtual call
|
|
29 is being made, and compares the vtable pointer against a set of all
|
|
30 valid vtable pointers that the object could contain (this set is
|
|
31 based on the declared type of the object). If the pointer is in
|
|
32 the valid set, execution is allowed to continue; otherwise the
|
|
33 program is halted.
|
|
34
|
|
35 There are several pieces needed in order to make this work: 1. For
|
|
36 every virtual class in the program (i.e. a class that contains
|
|
37 virtual methods), we need to build the set of all possible valid
|
|
38 vtables that an object of that class could point to. This includes
|
|
39 vtables for any class(es) that inherit from the class under
|
|
40 consideration. 2. For every such data set we build up, we need a
|
|
41 way to find and reference the data set. This is complicated by the
|
|
42 fact that the real vtable addresses are not known until runtime,
|
|
43 when the program is loaded into memory, but we need to reference the
|
|
44 sets at compile time when we are inserting verification calls into
|
|
45 the program. 3. We need to find every virtual call in the program,
|
|
46 and insert the verification call (with the appropriate arguments)
|
|
47 before the virtual call. 4. We need some runtime library pieces:
|
|
48 the code to build up the data sets at runtime; the code to actually
|
|
49 perform the verification using the data sets; and some code to set
|
|
50 protections on the data sets, so they themselves do not become
|
|
51 hacker targets.
|
|
52
|
|
53 To find and reference the set of valid vtable pointers for any given
|
|
54 virtual class, we create a special global varible for each virtual
|
|
55 class. We refer to this as the "vtable map variable" for that
|
|
56 class. The vtable map variable has the type "void *", and is
|
|
57 initialized by the compiler to NULL. At runtime when the set of
|
|
58 valid vtable pointers for a virtual class, e.g. class Foo, is built,
|
|
59 the vtable map variable for class Foo is made to point to the set.
|
|
60 During compile time, when the compiler is inserting verification
|
|
61 calls into the program, it passes the vtable map variable for the
|
|
62 appropriate class to the verification call, so that at runtime the
|
|
63 verification call can find the appropriate data set.
|
|
64
|
|
65 The actual set of valid vtable pointers for a virtual class,
|
|
66 e.g. class Foo, cannot be built until runtime, when the vtables get
|
|
67 loaded into memory and their addresses are known. But the knowledge
|
|
68 about which vtables belong in which class' hierarchy is only known
|
|
69 at compile time. Therefore at compile time we collect class
|
|
70 hierarchy and vtable information about every virtual class, and we
|
|
71 generate calls to build up the data sets at runtime. To build the
|
|
72 data sets, we call one of the functions we add to the runtime
|
|
73 library, __VLTRegisterPair. __VLTRegisterPair takes two arguments,
|
|
74 a vtable map variable and the address of a vtable. If the vtable
|
|
75 map variable is currently NULL, it creates a new data set (hash
|
|
76 table), makes the vtable map variable point to the new data set, and
|
|
77 inserts the vtable address into the data set. If the vtable map
|
|
78 variable is not NULL, it just inserts the vtable address into the
|
|
79 data set. In order to make sure that our data sets are built before
|
|
80 any verification calls happen, we create a special constructor
|
|
81 initialization function for each compilation unit, give it a very
|
|
82 high initialization priority, and insert all of our calls to
|
|
83 __VLTRegisterPair into our special constructor initialization
|
|
84 function.
|
|
85
|
|
86 The vtable verification feature is controlled by the flag
|
|
87 '-fvtable-verify='. There are three flavors of this:
|
|
88 '-fvtable-verify=std', '-fvtable-verify=preinit', and
|
|
89 '-fvtable-verify=none'. If the option '-fvtable-verfy=preinit' is
|
|
90 used, then our constructor initialization function gets put into the
|
|
91 preinit array. This is necessary if there are data sets that need
|
|
92 to be built very early in execution. If the constructor
|
|
93 initialization function gets put into the preinit array, the we also
|
|
94 add calls to __VLTChangePermission at the beginning and end of the
|
|
95 function. The call at the beginning sets the permissions on the
|
|
96 data sets and vtable map variables to read/write, and the one at the
|
|
97 end makes them read-only. If the '-fvtable-verify=std' option is
|
|
98 used, the constructor initialization functions are executed at their
|
|
99 normal time, and the __VLTChangePermission calls are handled
|
|
100 differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
|
|
101 The option '-fvtable-verify=none' turns off vtable verification.
|
|
102
|
|
103 This file contains code to find and record the class hierarchies for
|
|
104 the virtual classes in a program, and all the vtables associated
|
|
105 with each such class; to generate the vtable map variables; and to
|
|
106 generate the constructor initialization function (with the calls to
|
|
107 __VLTRegisterPair, and __VLTChangePermission). The main data
|
|
108 structures used for collecting the class hierarchy data and
|
|
109 building/maintaining the vtable map variable data are defined in
|
|
110 gcc/vtable-verify.h, because they are used both here and in
|
|
111 gcc/vtable-verify.c. */
|
|
112
|
|
113 #include "config.h"
|
|
114 #include "system.h"
|
|
115 #include "coretypes.h"
|
|
116 #include "vtable-verify.h"
|
|
117 #include "cp-tree.h"
|
|
118 #include "stringpool.h"
|
|
119 #include "cgraph.h"
|
|
120 #include "output.h"
|
|
121 #include "tree-iterator.h"
|
|
122 #include "gimplify.h"
|
|
123 #include "stor-layout.h"
|
|
124
|
|
125 static int num_calls_to_regset = 0;
|
|
126 static int num_calls_to_regpair = 0;
|
|
127 static int current_set_size;
|
|
128
|
|
129 /* Mark these specially since they need to be stored in precompiled
|
|
130 header IR. */
|
|
131 static GTY (()) vec<tree, va_gc> *vlt_saved_class_info;
|
|
132 static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
|
|
133 static GTY (()) tree vlt_register_set_fndecl = NULL_TREE;
|
|
134
|
|
135 struct work_node {
|
|
136 struct vtv_graph_node *node;
|
|
137 struct work_node *next;
|
|
138 };
|
|
139
|
|
140 struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
|
|
141
|
|
142 /* As part of vtable verification the compiler generates and inserts
|
|
143 calls to __VLTVerifyVtablePointer, which is in libstdc++. This
|
|
144 function builds and initializes the function decl that is used
|
|
145 in generating those function calls.
|
|
146
|
|
147 In addition to __VLTVerifyVtablePointer there is also
|
|
148 __VLTVerifyVtablePointerDebug which can be used in place of
|
|
149 __VLTVerifyVtablePointer, and which takes extra parameters and
|
|
150 outputs extra information, to help debug problems. The debug
|
|
151 version of this function is generated and used if flag_vtv_debug is
|
|
152 true.
|
|
153
|
|
154 The signatures for these functions are:
|
|
155
|
|
156 void * __VLTVerifyVtablePointer (void **, void*);
|
|
157 void * __VLTVerifyVtablePointerDebug (void**, void *, char *, char *);
|
|
158 */
|
|
159
|
|
160 void
|
|
161 vtv_build_vtable_verify_fndecl (void)
|
|
162 {
|
|
163 tree func_type = NULL_TREE;
|
|
164
|
|
165 if (verify_vtbl_ptr_fndecl != NULL_TREE
|
|
166 && TREE_CODE (verify_vtbl_ptr_fndecl) != ERROR_MARK)
|
|
167 return;
|
|
168
|
|
169 if (flag_vtv_debug)
|
|
170 {
|
|
171 func_type = build_function_type_list (const_ptr_type_node,
|
|
172 build_pointer_type (ptr_type_node),
|
|
173 const_ptr_type_node,
|
|
174 const_string_type_node,
|
|
175 const_string_type_node,
|
|
176 NULL_TREE);
|
|
177 verify_vtbl_ptr_fndecl =
|
|
178 build_lang_decl (FUNCTION_DECL,
|
|
179 get_identifier ("__VLTVerifyVtablePointerDebug"),
|
|
180 func_type);
|
|
181 }
|
|
182 else
|
|
183 {
|
|
184 func_type = build_function_type_list (const_ptr_type_node,
|
|
185 build_pointer_type (ptr_type_node),
|
|
186 const_ptr_type_node,
|
|
187 NULL_TREE);
|
|
188 verify_vtbl_ptr_fndecl =
|
|
189 build_lang_decl (FUNCTION_DECL,
|
|
190 get_identifier ("__VLTVerifyVtablePointer"),
|
|
191 func_type);
|
|
192 }
|
|
193
|
|
194 TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
|
|
195 DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
|
|
196 = tree_cons (get_identifier ("leaf"), NULL,
|
|
197 DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
|
|
198 DECL_PURE_P (verify_vtbl_ptr_fndecl) = 1;
|
|
199 TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
|
|
200 DECL_PRESERVE_P (verify_vtbl_ptr_fndecl) = 1;
|
|
201 }
|
|
202
|
|
203 /* As part of vtable verification the compiler generates and inserts
|
|
204 calls to __VLTRegisterSet and __VLTRegisterPair, which are in
|
|
205 libsupc++. This function builds and initializes the function decls
|
|
206 that are used in generating those function calls.
|
|
207
|
|
208 The signatures for these functions are:
|
|
209
|
|
210 void __VLTRegisterSetDebug (void **, const void *, std::size_t,
|
|
211 size_t, void **);
|
|
212
|
|
213 void __VLTRegisterSet (void **, const void *, std::size_t,
|
|
214 size_t, void **);
|
|
215
|
|
216 void __VLTRegisterPairDebug (void **, const void *, size_t,
|
|
217 const void *, const char *, const char *);
|
|
218
|
|
219 void __VLTRegisterPair (void **, const void *, size_t, const void *);
|
|
220 */
|
|
221
|
|
222 static void
|
|
223 init_functions (void)
|
|
224 {
|
|
225 tree register_set_type;
|
|
226 tree register_pairs_type;
|
|
227
|
|
228 if (vlt_register_set_fndecl != NULL_TREE)
|
|
229 return;
|
|
230
|
|
231 gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
|
|
232 gcc_assert (vlt_register_set_fndecl == NULL_TREE);
|
|
233
|
|
234 /* Build function decl for __VLTRegisterSet*. */
|
|
235
|
|
236 register_set_type = build_function_type_list
|
|
237 (void_type_node,
|
|
238 build_pointer_type (ptr_type_node),
|
|
239 const_ptr_type_node,
|
|
240 size_type_node,
|
|
241 size_type_node,
|
|
242 build_pointer_type (ptr_type_node),
|
|
243 NULL_TREE);
|
|
244
|
|
245 if (flag_vtv_debug)
|
|
246 vlt_register_set_fndecl = build_lang_decl
|
|
247 (FUNCTION_DECL,
|
|
248 get_identifier ("__VLTRegisterSetDebug"),
|
|
249 register_set_type);
|
|
250 else
|
|
251 vlt_register_set_fndecl = build_lang_decl
|
|
252 (FUNCTION_DECL,
|
|
253 get_identifier ("__VLTRegisterSet"),
|
|
254 register_set_type);
|
|
255
|
|
256
|
|
257 TREE_NOTHROW (vlt_register_set_fndecl) = 1;
|
|
258 DECL_ATTRIBUTES (vlt_register_set_fndecl) =
|
|
259 tree_cons (get_identifier ("leaf"), NULL,
|
|
260 DECL_ATTRIBUTES (vlt_register_set_fndecl));
|
|
261 DECL_EXTERNAL(vlt_register_set_fndecl) = 1;
|
|
262 TREE_PUBLIC (vlt_register_set_fndecl) = 1;
|
|
263 DECL_PRESERVE_P (vlt_register_set_fndecl) = 1;
|
|
264 SET_DECL_LANGUAGE (vlt_register_set_fndecl, lang_cplusplus);
|
|
265
|
|
266 /* Build function decl for __VLTRegisterPair*. */
|
|
267
|
|
268 if (flag_vtv_debug)
|
|
269 {
|
|
270 register_pairs_type = build_function_type_list (void_type_node,
|
|
271 build_pointer_type
|
|
272 (ptr_type_node),
|
|
273 const_ptr_type_node,
|
|
274 size_type_node,
|
|
275 const_ptr_type_node,
|
|
276 const_string_type_node,
|
|
277 const_string_type_node,
|
|
278 NULL_TREE);
|
|
279
|
|
280 vlt_register_pairs_fndecl = build_lang_decl
|
|
281 (FUNCTION_DECL,
|
|
282 get_identifier ("__VLTRegisterPairDebug"),
|
|
283 register_pairs_type);
|
|
284 }
|
|
285 else
|
|
286 {
|
|
287 register_pairs_type = build_function_type_list (void_type_node,
|
|
288 build_pointer_type
|
|
289 (ptr_type_node),
|
|
290 const_ptr_type_node,
|
|
291 size_type_node,
|
|
292 const_ptr_type_node,
|
|
293 NULL_TREE);
|
|
294
|
|
295 vlt_register_pairs_fndecl = build_lang_decl
|
|
296 (FUNCTION_DECL,
|
|
297 get_identifier ("__VLTRegisterPair"),
|
|
298 register_pairs_type);
|
|
299 }
|
|
300
|
|
301 TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
|
|
302 DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
|
|
303 tree_cons (get_identifier ("leaf"), NULL,
|
|
304 DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
|
|
305 DECL_EXTERNAL(vlt_register_pairs_fndecl) = 1;
|
|
306 TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
|
|
307 DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
|
|
308 SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
|
|
309
|
|
310 }
|
|
311
|
|
312 /* This is a helper function for
|
|
313 vtv_compute_class_hierarchy_transitive_closure. It adds a
|
|
314 vtv_graph_node to the WORKLIST, which is a linked list of
|
|
315 seen-but-not-yet-processed nodes. INSERTED is a bitmap, one bit
|
|
316 per node, to help make sure that we don't insert a node into the
|
|
317 worklist more than once. Each node represents a class somewhere in
|
|
318 our class hierarchy information. Every node in the graph gets added
|
|
319 to the worklist exactly once and removed from the worklist exactly
|
|
320 once (when all of its children have been processed). */
|
|
321
|
|
322 static void
|
|
323 add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
|
|
324 sbitmap inserted)
|
|
325 {
|
|
326 struct work_node *new_work_node;
|
|
327
|
|
328 if (bitmap_bit_p (inserted, node->class_uid))
|
|
329 return;
|
|
330
|
|
331 new_work_node = XNEW (struct work_node);
|
|
332 new_work_node->next = *worklist;
|
|
333 new_work_node->node = node;
|
|
334 *worklist = new_work_node;
|
|
335
|
|
336 bitmap_set_bit (inserted, node->class_uid);
|
|
337 }
|
|
338
|
|
339 /* This is a helper function for
|
|
340 vtv_compute_class_hierarchy_transitive_closure. It goes through
|
|
341 the WORKLIST of class hierarchy nodes looking for a "leaf" node,
|
|
342 i.e. a node whose children in the hierarchy have all been
|
|
343 processed. When it finds the next leaf node, it removes it from
|
|
344 the linked list (WORKLIST) and returns the node. */
|
|
345
|
|
346 static struct vtv_graph_node *
|
|
347 find_and_remove_next_leaf_node (struct work_node **worklist)
|
|
348 {
|
|
349 struct work_node *prev, *cur;
|
|
350 struct vtv_graph_node *ret_val = NULL;
|
|
351
|
|
352 for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
|
|
353 {
|
|
354 if ((cur->node->children).length() == cur->node->num_processed_children)
|
|
355 {
|
|
356 if (prev == NULL)
|
|
357 (*worklist) = cur->next;
|
|
358 else
|
|
359 prev->next = cur->next;
|
|
360
|
|
361 cur->next = NULL;
|
|
362 ret_val = cur->node;
|
|
363 free (cur);
|
|
364 return ret_val;
|
|
365 }
|
|
366 }
|
|
367
|
|
368 return NULL;
|
|
369 }
|
|
370
|
|
371 /* In our class hierarchy graph, each class node contains a bitmap,
|
|
372 with one bit for each class in the hierarchy. The bits are set for
|
|
373 classes that are descendants in the graph of the current node.
|
|
374 Initially the descendants bitmap is only set for immediate
|
|
375 descendants. This function traverses the class hierarchy graph,
|
|
376 bottom up, filling in the transitive closures for the descendants
|
|
377 as we rise up the graph. */
|
|
378
|
|
379 void
|
|
380 vtv_compute_class_hierarchy_transitive_closure (void)
|
|
381 {
|
|
382 struct work_node *worklist = NULL;
|
|
383 sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
|
|
384 unsigned i;
|
|
385 unsigned j;
|
|
386
|
|
387 /* Note: Every node in the graph gets added to the worklist exactly
|
|
388 once and removed from the worklist exactly once (when all of its
|
|
389 children have been processed). Each node's children edges are
|
|
390 followed exactly once, and each node's parent edges are followed
|
|
391 exactly once. So this algorithm is roughly O(V + 2E), i.e.
|
|
392 O(E + V). */
|
|
393
|
|
394 /* Set-up: */
|
|
395 /* Find all the "leaf" nodes in the graph, and add them to the worklist. */
|
|
396 bitmap_clear (inserted);
|
|
397 for (j = 0; j < num_vtable_map_nodes; ++j)
|
|
398 {
|
|
399 struct vtbl_map_node *cur = vtbl_map_nodes_vec[j];
|
|
400 if (cur->class_info
|
|
401 && ((cur->class_info->children).length() == 0)
|
|
402 && ! (bitmap_bit_p (inserted, cur->class_info->class_uid)))
|
|
403 add_to_worklist (&worklist, cur->class_info, inserted);
|
|
404 }
|
|
405
|
|
406 /* Main work: pull next leaf node off work list, process it, add its
|
|
407 parents to the worklist, where a 'leaf' node is one that has no
|
|
408 children, or all of its children have been processed. */
|
|
409 while (worklist)
|
|
410 {
|
|
411 struct vtv_graph_node *temp_node =
|
|
412 find_and_remove_next_leaf_node (&worklist);
|
|
413
|
|
414 gcc_assert (temp_node != NULL);
|
|
415 temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
|
|
416 bitmap_clear (temp_node->descendants);
|
|
417 bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
|
|
418 for (i = 0; i < (temp_node->children).length(); ++i)
|
|
419 bitmap_ior (temp_node->descendants, temp_node->descendants,
|
|
420 temp_node->children[i]->descendants);
|
|
421 for (i = 0; i < (temp_node->parents).length(); ++i)
|
|
422 {
|
|
423 temp_node->parents[i]->num_processed_children =
|
|
424 temp_node->parents[i]->num_processed_children + 1;
|
|
425 if (!bitmap_bit_p (inserted, temp_node->parents[i]->class_uid))
|
|
426 add_to_worklist (&worklist, temp_node->parents[i], inserted);
|
|
427 }
|
|
428 }
|
|
429 }
|
|
430
|
|
431 /* Keep track of which pairs we have already created __VLTRegisterPair
|
|
432 calls for, to prevent creating duplicate calls within the same
|
|
433 compilation unit. VTABLE_DECL is the var decl for the vtable of
|
|
434 the (descendant) class that we are adding to our class hierarchy
|
|
435 data. VPTR_ADDRESS is an expression for calculating the correct
|
|
436 offset into the vtable (VTABLE_DECL). It is the actual vtable
|
|
437 pointer address that will be stored in our list of valid vtable
|
|
438 pointers for BASE_CLASS. BASE_CLASS is the record_type node for
|
|
439 the base class to whose hiearchy we want to add
|
|
440 VPTR_ADDRESS. (VTABLE_DECL should be the vtable for BASE_CLASS or
|
|
441 one of BASE_CLASS' descendents. */
|
|
442
|
|
443 static bool
|
|
444 check_and_record_registered_pairs (tree vtable_decl, tree vptr_address,
|
|
445 tree base_class)
|
|
446 {
|
|
447 unsigned offset;
|
|
448 struct vtbl_map_node *base_vtable_map_node;
|
|
449 bool inserted_something = false;
|
|
450
|
|
451
|
|
452 if (TREE_CODE (vptr_address) == ADDR_EXPR
|
|
453 && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
|
|
454 vptr_address = TREE_OPERAND (vptr_address, 0);
|
|
455
|
|
456 if (TREE_OPERAND_LENGTH (vptr_address) > 1)
|
|
457 offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
|
|
458 else
|
|
459 offset = 0;
|
|
460
|
|
461 base_vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_class));
|
|
462
|
|
463 inserted_something = vtbl_map_node_registration_insert
|
|
464 (base_vtable_map_node,
|
|
465 vtable_decl,
|
|
466 offset);
|
|
467 return !inserted_something;
|
|
468 }
|
|
469
|
|
470 /* Given an IDENTIFIER_NODE, build and return a string literal based on it. */
|
|
471
|
|
472 static tree
|
|
473 build_string_from_id (tree identifier)
|
|
474 {
|
|
475 int len;
|
|
476
|
|
477 gcc_assert (TREE_CODE (identifier) == IDENTIFIER_NODE);
|
|
478
|
|
479 len = IDENTIFIER_LENGTH (identifier);
|
|
480 return build_string_literal (len + 1, IDENTIFIER_POINTER (identifier));
|
|
481 }
|
|
482
|
|
483 /* A class may contain secondary vtables in it, for various reasons.
|
|
484 This function goes through the decl chain of a class record looking
|
|
485 for any fields that point to secondary vtables, and adding calls to
|
|
486 __VLTRegisterPair for the secondary vtable pointers.
|
|
487
|
|
488 BASE_CLASS_DECL_ARG is an expression for the address of the vtable
|
|
489 map variable for the BASE_CLASS (whose hierarchy we are currently
|
|
490 updating). BASE_CLASS is the record_type node for the base class.
|
|
491 RECORD_TYPE is the record_type node for the descendant class that
|
|
492 we are possibly adding to BASE_CLASS's hierarchy. BODY is the
|
|
493 function body for the constructor init function to which we are
|
|
494 adding our calls to __VLTRegisterPair. */
|
|
495
|
|
496 static void
|
|
497 register_construction_vtables (tree base_class, tree record_type,
|
|
498 vec<tree> *vtable_ptr_array)
|
|
499 {
|
|
500 tree vtbl_var_decl;
|
|
501
|
|
502 if (TREE_CODE (record_type) != RECORD_TYPE)
|
|
503 return;
|
|
504
|
|
505 vtbl_var_decl = CLASSTYPE_VTABLES (record_type);
|
|
506
|
|
507 if (CLASSTYPE_VBASECLASSES (record_type))
|
|
508 {
|
|
509 tree vtt_decl;
|
|
510 bool already_registered = false;
|
|
511 tree val_vtbl_decl = NULL_TREE;
|
|
512
|
|
513 vtt_decl = DECL_CHAIN (vtbl_var_decl);
|
|
514
|
|
515 /* Check to see if we have found a VTT. Add its data if appropriate. */
|
|
516 if (vtt_decl)
|
|
517 {
|
|
518 tree values = DECL_INITIAL (vtt_decl);
|
|
519 if (TREE_ASM_WRITTEN (vtt_decl)
|
|
520 && values != NULL_TREE
|
|
521 && TREE_CODE (values) == CONSTRUCTOR
|
|
522 && TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE)
|
|
523 {
|
|
524 unsigned HOST_WIDE_INT cnt;
|
|
525 constructor_elt *ce;
|
|
526
|
|
527 /* Loop through the initialization values for this
|
|
528 vtable to get all the correct vtable pointer
|
|
529 addresses that we need to add to our set of valid
|
|
530 vtable pointers for the current base class. This may
|
|
531 result in adding more than just the element assigned
|
|
532 to the primary vptr of the class, so we may end up
|
|
533 with more vtable pointers than are strictly
|
|
534 necessary. */
|
|
535
|
|
536 for (cnt = 0;
|
|
537 vec_safe_iterate (CONSTRUCTOR_ELTS (values),
|
|
538 cnt, &ce);
|
|
539 cnt++)
|
|
540 {
|
|
541 tree value = ce->value;
|
|
542
|
|
543 /* Search for the ADDR_EXPR operand within the value. */
|
|
544
|
|
545 while (value
|
|
546 && TREE_OPERAND (value, 0)
|
|
547 && TREE_CODE (TREE_OPERAND (value, 0)) == ADDR_EXPR)
|
|
548 value = TREE_OPERAND (value, 0);
|
|
549
|
|
550 /* The VAR_DECL for the vtable should be the first
|
|
551 argument of the ADDR_EXPR, which is the first
|
|
552 argument of value.*/
|
|
553
|
|
554 if (TREE_OPERAND (value, 0))
|
|
555 val_vtbl_decl = TREE_OPERAND (value, 0);
|
|
556
|
|
557 while (!VAR_P (val_vtbl_decl)
|
|
558 && TREE_OPERAND (val_vtbl_decl, 0))
|
|
559 val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
|
|
560
|
|
561 gcc_assert (VAR_P (val_vtbl_decl));
|
|
562
|
|
563 /* Check to see if we already have this vtable pointer in
|
|
564 our valid set for this base class. */
|
|
565
|
|
566 already_registered = check_and_record_registered_pairs
|
|
567 (val_vtbl_decl,
|
|
568 value,
|
|
569 base_class);
|
|
570
|
|
571 if (already_registered)
|
|
572 continue;
|
|
573
|
|
574 /* Add this vtable pointer to our set of valid
|
|
575 pointers for the base class. */
|
|
576
|
|
577 vtable_ptr_array->safe_push (value);
|
|
578 current_set_size++;
|
|
579 }
|
|
580 }
|
|
581 }
|
|
582 }
|
|
583 }
|
|
584
|
|
585 /* This function iterates through all the vtables it can find from the
|
|
586 BINFO of a class, to make sure we have found ALL of the vtables
|
|
587 that an object of that class could point to. Generate calls to
|
|
588 __VLTRegisterPair for those vtable pointers that we find.
|
|
589
|
|
590 BINFO is the tree_binfo node for the BASE_CLASS. BODY is the
|
|
591 function body for the constructor init function to which we are
|
|
592 adding calls to __VLTRegisterPair. ARG1 is an expression for the
|
|
593 address of the vtable map variable (for the BASE_CLASS), that will
|
|
594 point to the updated data set. BASE_CLASS is the record_type node
|
|
595 for the base class whose set of valid vtable pointers we are
|
|
596 updating. STR1 and STR2 are all debugging information, to be passed
|
|
597 as parameters to __VLTRegisterPairDebug. STR1 represents the name
|
|
598 of the vtable map variable to be updated by the call. Similarly,
|
|
599 STR2 represents the name of the class whose vtable pointer is being
|
|
600 added to the hierarchy. */
|
|
601
|
|
602 static void
|
|
603 register_other_binfo_vtables (tree binfo, tree base_class,
|
|
604 vec<tree> *vtable_ptr_array)
|
|
605 {
|
|
606 unsigned ix;
|
|
607 tree base_binfo;
|
|
608 tree vtable_decl;
|
|
609 bool already_registered;
|
|
610
|
|
611 if (binfo == NULL_TREE)
|
|
612 return;
|
|
613
|
|
614 for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
|
|
615 {
|
|
616 if ((!BINFO_PRIMARY_P (base_binfo)
|
|
617 || BINFO_VIRTUAL_P (base_binfo))
|
|
618 && (vtable_decl = get_vtbl_decl_for_binfo (base_binfo)))
|
|
619 {
|
|
620 tree vtable_address = build_vtbl_address (base_binfo);
|
|
621
|
|
622 already_registered = check_and_record_registered_pairs
|
|
623 (vtable_decl,
|
|
624 vtable_address,
|
|
625 base_class);
|
|
626 if (!already_registered)
|
|
627 {
|
|
628 vtable_ptr_array->safe_push (vtable_address);
|
|
629 current_set_size++;
|
|
630 }
|
|
631 }
|
|
632
|
|
633 register_other_binfo_vtables (base_binfo, base_class, vtable_ptr_array);
|
|
634 }
|
|
635 }
|
|
636
|
|
637 /* The set of valid vtable pointers for any given class are stored in
|
|
638 a hash table. For reasons of efficiency, that hash table size is
|
|
639 always a power of two. In order to try to prevent re-sizing the
|
|
640 hash tables very often, we pass __VLTRegisterPair an initial guess
|
|
641 as to the number of entries the hashtable will eventually need
|
|
642 (rounded up to the nearest power of two). This function takes the
|
|
643 class information we have collected for a particular class,
|
|
644 CLASS_NODE, and calculates the hash table size guess. */
|
|
645
|
|
646 static int
|
|
647 guess_num_vtable_pointers (struct vtv_graph_node *class_node)
|
|
648 {
|
|
649 tree vtbl;
|
|
650 int total_num_vtbls = 0;
|
|
651 int num_vtbls_power_of_two = 1;
|
|
652 unsigned i;
|
|
653
|
|
654 for (i = 0; i < num_vtable_map_nodes; ++i)
|
|
655 if (bitmap_bit_p (class_node->descendants, i))
|
|
656 {
|
|
657 tree class_type = vtbl_map_nodes_vec[i]->class_info->class_type;
|
|
658 for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
|
|
659 vtbl = DECL_CHAIN (vtbl))
|
|
660 {
|
|
661 total_num_vtbls++;
|
|
662 if (total_num_vtbls > num_vtbls_power_of_two)
|
|
663 num_vtbls_power_of_two <<= 1;
|
|
664 }
|
|
665 }
|
|
666 return num_vtbls_power_of_two;
|
|
667 }
|
|
668
|
|
669 /* A simple hash function on strings */
|
|
670 /* Be careful about changing this routine. The values generated will
|
|
671 be stored in the calls to InitSet. So, changing this routine may
|
|
672 cause a binary incompatibility. */
|
|
673
|
|
674 static uint32_t
|
|
675 vtv_string_hash (const char *in)
|
|
676 {
|
|
677 const char *s = in;
|
|
678 uint32_t h = 0;
|
|
679
|
|
680 gcc_assert (in != NULL);
|
|
681 for ( ; *s; ++s)
|
|
682 h = 5 * h + *s;
|
|
683 return h;
|
|
684 }
|
|
685
|
|
686 static char *
|
|
687 get_log_file_name (const char *fname)
|
|
688 {
|
|
689 const char *tmp_dir = concat (dump_dir_name, NULL);
|
|
690 char *full_name;
|
|
691 int dir_len;
|
|
692 int fname_len;
|
|
693
|
|
694 dir_len = strlen (tmp_dir);
|
|
695 fname_len = strlen (fname);
|
|
696
|
|
697 full_name = XNEWVEC (char, dir_len + fname_len + 1);
|
|
698 strcpy (full_name, tmp_dir);
|
|
699 strcpy (full_name + dir_len, fname);
|
|
700
|
|
701 return full_name;
|
|
702 }
|
|
703
|
|
704 static void
|
|
705 write_out_current_set_data (tree base_class, int set_size)
|
|
706 {
|
|
707 static int class_data_log_fd = -1;
|
|
708 char buffer[1024];
|
|
709 int bytes_written __attribute__ ((unused));
|
|
710 char *file_name = get_log_file_name ("vtv_class_set_sizes.log");
|
|
711
|
|
712 if (class_data_log_fd == -1)
|
|
713 class_data_log_fd = open (file_name,
|
|
714 O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
|
|
715
|
|
716 if (class_data_log_fd == -1)
|
|
717 {
|
|
718 warning_at (UNKNOWN_LOCATION, 0,
|
|
719 "unable to open log file %<vtv_class_set_sizes.log%>: %m");
|
|
720 return;
|
|
721 }
|
|
722
|
|
723 snprintf (buffer, sizeof (buffer), "%s %d\n",
|
|
724 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (base_class))),
|
|
725 set_size);
|
|
726 bytes_written = write (class_data_log_fd, buffer, strlen (buffer));
|
|
727 }
|
|
728
|
|
729 static tree
|
|
730 build_key_buffer_arg (tree base_ptr_var_decl)
|
|
731 {
|
|
732 const int key_type_fixed_size = 8;
|
|
733 uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl));
|
|
734 uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
|
|
735 (DECL_NAME (base_ptr_var_decl)));
|
|
736 void *key_buffer = xmalloc (len1 + key_type_fixed_size);
|
|
737 uint32_t *value_ptr = (uint32_t *) key_buffer;
|
|
738 tree ret_value;
|
|
739
|
|
740 /* Set the len and hash for the string. */
|
|
741 *value_ptr = len1;
|
|
742 value_ptr++;
|
|
743 *value_ptr = hash_value;
|
|
744
|
|
745 /* Now copy the string representation of the vtbl map name... */
|
|
746 memcpy ((char *) key_buffer + key_type_fixed_size,
|
|
747 IDENTIFIER_POINTER (DECL_NAME (base_ptr_var_decl)),
|
|
748 len1);
|
|
749
|
|
750 /* ... and build a string literal from it. This will make a copy
|
|
751 so the key_bufffer is not needed anymore after this. */
|
|
752 ret_value = build_string_literal (len1 + key_type_fixed_size,
|
|
753 (char *) key_buffer);
|
|
754 free (key_buffer);
|
|
755 return ret_value;
|
|
756 }
|
|
757
|
|
758 static void
|
|
759 insert_call_to_register_set (tree class_name,
|
|
760 vec<tree> *vtbl_ptr_array, tree body, tree arg1,
|
|
761 tree arg2, tree size_hint_arg)
|
|
762 {
|
|
763 tree call_expr;
|
|
764 int num_args = vtbl_ptr_array->length();
|
|
765 char *array_arg_name = ACONCAT (("__vptr_array_",
|
|
766 IDENTIFIER_POINTER (class_name), NULL));
|
|
767 tree array_arg_type = build_array_type_nelts (build_pointer_type
|
|
768 (build_pointer_type
|
|
769 (void_type_node)),
|
|
770 num_args);
|
|
771 tree array_arg = build_decl (UNKNOWN_LOCATION, VAR_DECL,
|
|
772 get_identifier (array_arg_name),
|
|
773 array_arg_type);
|
|
774 int k;
|
|
775
|
|
776 vec<constructor_elt, va_gc> *array_elements;
|
|
777 vec_alloc (array_elements, num_args);
|
|
778
|
|
779 tree initial = NULL_TREE;
|
|
780 tree arg3 = NULL_TREE;
|
|
781
|
|
782 TREE_PUBLIC (array_arg) = 0;
|
|
783 DECL_EXTERNAL (array_arg) = 0;
|
|
784 TREE_STATIC (array_arg) = 1;
|
|
785 DECL_ARTIFICIAL (array_arg) = 0;
|
|
786 TREE_READONLY (array_arg) = 1;
|
|
787 DECL_IGNORED_P (array_arg) = 0;
|
|
788 DECL_PRESERVE_P (array_arg) = 0;
|
|
789 DECL_VISIBILITY (array_arg) = VISIBILITY_HIDDEN;
|
|
790
|
|
791 for (k = 0; k < num_args; ++k)
|
|
792 {
|
|
793 CONSTRUCTOR_APPEND_ELT (array_elements, NULL_TREE, (*vtbl_ptr_array)[k]);
|
|
794 }
|
|
795
|
|
796 initial = build_constructor (TREE_TYPE (array_arg), array_elements);
|
|
797
|
|
798 TREE_CONSTANT (initial) = 1;
|
|
799 TREE_STATIC (initial) = 1;
|
|
800 DECL_INITIAL (array_arg) = initial;
|
|
801 relayout_decl (array_arg);
|
|
802 varpool_node::finalize_decl (array_arg);
|
|
803
|
|
804 arg3 = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (array_arg)), array_arg);
|
|
805
|
|
806 TREE_TYPE (arg3) = build_pointer_type (TREE_TYPE (array_arg));
|
|
807
|
|
808 call_expr = build_call_expr (vlt_register_set_fndecl, 5, arg1,
|
|
809 arg2, /* set_symbol_key */
|
|
810 size_hint_arg, build_int_cst (size_type_node,
|
|
811 num_args),
|
|
812 arg3);
|
|
813 append_to_statement_list (call_expr, &body);
|
|
814 num_calls_to_regset++;
|
|
815 }
|
|
816
|
|
817 static void
|
|
818 insert_call_to_register_pair (vec<tree> *vtbl_ptr_array, tree arg1,
|
|
819 tree arg2, tree size_hint_arg, tree str1,
|
|
820 tree str2, tree body)
|
|
821 {
|
|
822 tree call_expr;
|
|
823 int num_args = vtbl_ptr_array->length();
|
|
824 tree vtable_address = NULL_TREE;
|
|
825
|
|
826 if (num_args == 0)
|
|
827 vtable_address = build_int_cst (build_pointer_type (void_type_node), 0);
|
|
828 else
|
|
829 vtable_address = (*vtbl_ptr_array)[0];
|
|
830
|
|
831 if (flag_vtv_debug)
|
|
832 call_expr = build_call_expr (vlt_register_pairs_fndecl, 6, arg1, arg2,
|
|
833 size_hint_arg, vtable_address, str1, str2);
|
|
834 else
|
|
835 call_expr = build_call_expr (vlt_register_pairs_fndecl, 4, arg1, arg2,
|
|
836 size_hint_arg, vtable_address);
|
|
837
|
|
838 append_to_statement_list (call_expr, &body);
|
|
839 num_calls_to_regpair++;
|
|
840 }
|
|
841
|
|
842 static void
|
|
843 output_set_info (tree record_type, vec<tree> vtbl_ptr_array)
|
|
844 {
|
|
845 static int vtv_debug_log_fd = -1;
|
|
846 char buffer[1024];
|
|
847 int bytes_written __attribute__ ((unused));
|
|
848 int array_len = vtbl_ptr_array.length();
|
|
849 const char *class_name =
|
|
850 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (record_type)));
|
|
851 char *file_name = get_log_file_name ("vtv_set_ptr_data.log");
|
|
852
|
|
853 if (vtv_debug_log_fd == -1)
|
|
854 vtv_debug_log_fd = open (file_name,
|
|
855 O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
|
|
856 if (vtv_debug_log_fd == -1)
|
|
857 {
|
|
858 warning_at (UNKNOWN_LOCATION, 0,
|
|
859 "unable to open log file %<vtv_set_ptr_data.log%>: %m");
|
|
860 return;
|
|
861 }
|
|
862
|
|
863 for (int i = 0; i < array_len; ++i)
|
|
864 {
|
|
865 const char *vptr_name = "unknown";
|
|
866 int vptr_offset = 0;
|
|
867
|
|
868 if (TREE_CODE (vtbl_ptr_array[i]) == POINTER_PLUS_EXPR)
|
|
869 {
|
|
870 tree arg0 = TREE_OPERAND (vtbl_ptr_array[i], 0);
|
|
871 tree arg1 = TREE_OPERAND (vtbl_ptr_array[i], 1);
|
|
872
|
|
873 if (TREE_CODE (arg0) == ADDR_EXPR)
|
|
874 arg0 = TREE_OPERAND (arg0, 0);
|
|
875
|
|
876 if (VAR_P (arg0))
|
|
877 vptr_name = IDENTIFIER_POINTER (DECL_NAME (arg0));
|
|
878
|
|
879 if (TREE_CODE (arg1) == INTEGER_CST)
|
|
880 vptr_offset = TREE_INT_CST_LOW (arg1);
|
|
881 }
|
|
882
|
|
883 snprintf (buffer, sizeof (buffer), "%s %s %s + %d\n",
|
|
884 main_input_filename, class_name, vptr_name, vptr_offset);
|
|
885 bytes_written = write (vtv_debug_log_fd, buffer, strlen(buffer));
|
|
886 }
|
|
887
|
|
888 }
|
|
889
|
|
890 /* This function goes through our internal class hierarchy & vtable
|
|
891 pointer data structure and outputs calls to __VLTRegisterPair for
|
|
892 every class-vptr pair (for those classes whose vtable would be
|
|
893 output in the current compilation unit). These calls get put into
|
|
894 our constructor initialization function. BODY is the function
|
|
895 body, so far, of our constructor initialization function, to which we
|
|
896 add the calls. */
|
|
897
|
|
898 static bool
|
|
899 register_all_pairs (tree body)
|
|
900 {
|
|
901 bool registered_at_least_one = false;
|
|
902 vec<tree> *vtbl_ptr_array = NULL;
|
|
903 unsigned j;
|
|
904
|
|
905 for (j = 0; j < num_vtable_map_nodes; ++j)
|
|
906 {
|
|
907 struct vtbl_map_node *current = vtbl_map_nodes_vec[j];
|
|
908 unsigned i = 0;
|
|
909 tree base_class = current->class_info->class_type;
|
|
910 tree base_ptr_var_decl = current->vtbl_map_decl;
|
|
911 tree arg1;
|
|
912 tree arg2;
|
|
913 tree new_type;
|
|
914 tree str1 = NULL_TREE;
|
|
915 tree str2 = NULL_TREE;
|
|
916 size_t size_hint;
|
|
917 tree size_hint_arg;
|
|
918
|
|
919 gcc_assert (current->class_info != NULL);
|
|
920
|
|
921
|
|
922 if (flag_vtv_debug)
|
|
923 str1 = build_string_from_id (DECL_NAME (base_ptr_var_decl));
|
|
924
|
|
925 new_type = build_pointer_type (TREE_TYPE (base_ptr_var_decl));
|
|
926 arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
|
|
927
|
|
928 /* We need a fresh vector for each iteration. */
|
|
929 if (vtbl_ptr_array)
|
|
930 vec_free (vtbl_ptr_array);
|
|
931
|
|
932 vec_alloc (vtbl_ptr_array, 10);
|
|
933
|
|
934 for (i = 0; i < num_vtable_map_nodes; ++i)
|
|
935 if (bitmap_bit_p (current->class_info->descendants, i))
|
|
936 {
|
|
937 struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_vec[i];
|
|
938 tree class_type = vtbl_class_node->class_info->class_type;
|
|
939
|
|
940 if (class_type
|
|
941 && (TREE_CODE (class_type) == RECORD_TYPE))
|
|
942 {
|
|
943 bool already_registered;
|
|
944
|
|
945 tree binfo = TYPE_BINFO (class_type);
|
|
946 tree vtable_decl;
|
|
947 bool vtable_should_be_output = false;
|
|
948
|
|
949 vtable_decl = CLASSTYPE_VTABLES (class_type);
|
|
950
|
|
951 /* Handle main vtable for this class. */
|
|
952
|
|
953 if (vtable_decl)
|
|
954 {
|
|
955 vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
|
|
956 str2 = build_string_from_id (DECL_NAME (vtable_decl));
|
|
957 }
|
|
958
|
|
959 if (vtable_decl && vtable_should_be_output)
|
|
960 {
|
|
961 tree vtable_address = build_vtbl_address (binfo);
|
|
962
|
|
963 already_registered = check_and_record_registered_pairs
|
|
964 (vtable_decl,
|
|
965 vtable_address,
|
|
966 base_class);
|
|
967
|
|
968
|
|
969 if (!already_registered)
|
|
970 {
|
|
971 vtbl_ptr_array->safe_push (vtable_address);
|
|
972
|
|
973 /* Find and handle any 'extra' vtables associated
|
|
974 with this class, via virtual inheritance. */
|
|
975 register_construction_vtables (base_class, class_type,
|
|
976 vtbl_ptr_array);
|
|
977
|
|
978 /* Find and handle any 'extra' vtables associated
|
|
979 with this class, via multiple inheritance. */
|
|
980 register_other_binfo_vtables (binfo, base_class,
|
|
981 vtbl_ptr_array);
|
|
982 }
|
|
983 }
|
|
984 }
|
|
985 }
|
|
986 current_set_size = vtbl_ptr_array->length();
|
|
987
|
|
988 /* Sometimes we need to initialize the set symbol even if we are
|
|
989 not adding any vtable pointers to the set in the current
|
|
990 compilation unit. In that case, we need to initialize the
|
|
991 set to our best guess as to what the eventual size of the set
|
|
992 hash table will be (to prevent having to re-size the hash
|
|
993 table later). */
|
|
994
|
|
995 size_hint = guess_num_vtable_pointers (current->class_info);
|
|
996
|
|
997 /* If we have added vtable pointers to the set in this
|
|
998 compilation unit, adjust the size hint for the set's hash
|
|
999 table appropriately. */
|
|
1000 if (vtbl_ptr_array->length() > 0)
|
|
1001 {
|
|
1002 unsigned len = vtbl_ptr_array->length();
|
|
1003 while ((size_t) len > size_hint)
|
|
1004 size_hint <<= 1;
|
|
1005 }
|
|
1006 size_hint_arg = build_int_cst (size_type_node, size_hint);
|
|
1007
|
|
1008 /* Get the key-buffer argument. */
|
|
1009 arg2 = build_key_buffer_arg (base_ptr_var_decl);
|
|
1010
|
|
1011 if (str2 == NULL_TREE)
|
|
1012 str2 = build_string_literal (strlen ("unknown") + 1,
|
|
1013 "unknown");
|
|
1014
|
|
1015 if (flag_vtv_debug)
|
|
1016 output_set_info (current->class_info->class_type,
|
|
1017 *vtbl_ptr_array);
|
|
1018
|
|
1019 if (vtbl_ptr_array->length() > 1)
|
|
1020 {
|
|
1021 insert_call_to_register_set (current->class_name,
|
|
1022 vtbl_ptr_array, body, arg1, arg2,
|
|
1023 size_hint_arg);
|
|
1024 registered_at_least_one = true;
|
|
1025 }
|
|
1026 else
|
|
1027 {
|
|
1028
|
|
1029 if (vtbl_ptr_array->length() > 0
|
|
1030 || (current->is_used
|
|
1031 || (current->registered->size() > 0)))
|
|
1032 {
|
|
1033 insert_call_to_register_pair (vtbl_ptr_array,
|
|
1034 arg1, arg2, size_hint_arg, str1,
|
|
1035 str2, body);
|
|
1036 registered_at_least_one = true;
|
|
1037 }
|
|
1038 }
|
|
1039
|
|
1040 if (flag_vtv_counts && current_set_size > 0)
|
|
1041 write_out_current_set_data (base_class, current_set_size);
|
|
1042
|
|
1043 }
|
|
1044
|
|
1045 return registered_at_least_one;
|
|
1046 }
|
|
1047
|
|
1048 /* Given a tree containing a class type (CLASS_TYPE), this function
|
|
1049 finds and returns the class hierarchy node for that class in our
|
|
1050 data structure. */
|
|
1051
|
|
1052 static struct vtv_graph_node *
|
|
1053 find_graph_node (tree class_type)
|
|
1054 {
|
|
1055 struct vtbl_map_node *vtbl_node;
|
|
1056
|
|
1057 vtbl_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (class_type));
|
|
1058 if (vtbl_node)
|
|
1059 return vtbl_node->class_info;
|
|
1060
|
|
1061 return NULL;
|
|
1062 }
|
|
1063
|
|
1064 /* Add base class/derived class pair to our internal class hierarchy
|
|
1065 data structure. BASE_NODE is our vtv_graph_node that corresponds
|
|
1066 to a base class. DERIVED_NODE is our vtv_graph_node that
|
|
1067 corresponds to a class that is a descendant of the base class
|
|
1068 (possibly the base class itself). */
|
|
1069
|
|
1070 static void
|
|
1071 add_hierarchy_pair (struct vtv_graph_node *base_node,
|
|
1072 struct vtv_graph_node *derived_node)
|
|
1073 {
|
|
1074 (base_node->children).safe_push (derived_node);
|
|
1075 (derived_node->parents).safe_push (base_node);
|
|
1076 }
|
|
1077
|
|
1078 /* This functions adds a new base class/derived class relationship to
|
|
1079 our class hierarchy data structure. Both parameters are trees
|
|
1080 representing the class types, i.e. RECORD_TYPE trees.
|
|
1081 DERIVED_CLASS can be the same as BASE_CLASS. */
|
|
1082
|
|
1083 static void
|
|
1084 update_class_hierarchy_information (tree base_class,
|
|
1085 tree derived_class)
|
|
1086 {
|
|
1087 struct vtv_graph_node *base_node = find_graph_node (base_class);
|
|
1088 struct vtv_graph_node *derived_node = find_graph_node (derived_class);
|
|
1089
|
|
1090 add_hierarchy_pair (base_node, derived_node);
|
|
1091 }
|
|
1092
|
|
1093
|
|
1094 static void
|
|
1095 write_out_vtv_count_data (void)
|
|
1096 {
|
|
1097 static int vtv_count_log_fd = -1;
|
|
1098 char buffer[1024];
|
|
1099 int unused_vtbl_map_vars = 0;
|
|
1100 int bytes_written __attribute__ ((unused));
|
|
1101 char *file_name = get_log_file_name ("vtv_count_data.log");
|
|
1102
|
|
1103 if (vtv_count_log_fd == -1)
|
|
1104 vtv_count_log_fd = open (file_name,
|
|
1105 O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
|
|
1106 if (vtv_count_log_fd == -1)
|
|
1107 {
|
|
1108 warning_at (UNKNOWN_LOCATION, 0,
|
|
1109 "unable to open log file %<vtv_count_data.log%>: %m");
|
|
1110 return;
|
|
1111 }
|
|
1112
|
|
1113 for (unsigned i = 0; i < num_vtable_map_nodes; ++i)
|
|
1114 {
|
|
1115 struct vtbl_map_node *current = vtbl_map_nodes_vec[i];
|
|
1116 if (!current->is_used
|
|
1117 && current->registered->size() == 0)
|
|
1118 unused_vtbl_map_vars++;
|
|
1119 }
|
|
1120
|
|
1121 snprintf (buffer, sizeof (buffer), "%s %d %d %d %d %d\n",
|
|
1122 main_input_filename, total_num_virtual_calls,
|
|
1123 total_num_verified_vcalls, num_calls_to_regset,
|
|
1124 num_calls_to_regpair, unused_vtbl_map_vars);
|
|
1125
|
|
1126 bytes_written = write (vtv_count_log_fd, buffer, strlen (buffer));
|
|
1127 }
|
|
1128
|
|
1129 /* This function calls register_all_pairs, which actually generates
|
|
1130 all the calls to __VLTRegisterPair (in the verification constructor
|
|
1131 init function). It also generates the calls to
|
|
1132 __VLTChangePermission, if the verification constructor init
|
|
1133 function is going into the preinit array. INIT_ROUTINE_BODY is
|
|
1134 the body of our constructior initialization function, to which we
|
|
1135 add our function calls.*/
|
|
1136
|
|
1137 bool
|
|
1138 vtv_register_class_hierarchy_information (tree init_routine_body)
|
|
1139 {
|
|
1140 bool registered_something = false;
|
|
1141
|
|
1142 init_functions ();
|
|
1143
|
|
1144 if (num_vtable_map_nodes == 0)
|
|
1145 return false;
|
|
1146
|
|
1147 /* Add class hierarchy pairs to the vtable map data structure. */
|
|
1148 registered_something = register_all_pairs (init_routine_body);
|
|
1149
|
|
1150 if (flag_vtv_counts)
|
|
1151 write_out_vtv_count_data ();
|
|
1152
|
|
1153 return registered_something;
|
|
1154 }
|
|
1155
|
|
1156
|
|
1157 /* Generate the special constructor function that calls
|
|
1158 __VLTChangePermission and __VLTRegisterPairs, and give it a very
|
|
1159 high initialization priority. */
|
|
1160
|
|
1161 void
|
|
1162 vtv_generate_init_routine (void)
|
|
1163 {
|
|
1164 tree init_routine_body;
|
|
1165 bool vtable_classes_found = false;
|
|
1166
|
|
1167 push_lang_context (lang_name_c);
|
|
1168
|
|
1169 /* The priority for this init function (constructor) is carefully
|
|
1170 chosen so that it will happen after the calls to unprotect the
|
|
1171 memory used for vtable verification and before the memory is
|
|
1172 protected again. */
|
|
1173 init_routine_body = vtv_start_verification_constructor_init_function ();
|
|
1174
|
|
1175 vtable_classes_found =
|
|
1176 vtv_register_class_hierarchy_information (init_routine_body);
|
|
1177
|
|
1178 if (vtable_classes_found)
|
|
1179 {
|
|
1180 tree vtv_fndecl =
|
|
1181 vtv_finish_verification_constructor_init_function (init_routine_body);
|
|
1182 TREE_STATIC (vtv_fndecl) = 1;
|
|
1183 TREE_USED (vtv_fndecl) = 1;
|
|
1184 DECL_PRESERVE_P (vtv_fndecl) = 1;
|
|
1185 /* We are running too late to generate any meaningful debug information
|
|
1186 for this routine. */
|
|
1187 DECL_IGNORED_P (vtv_fndecl) = 1;
|
|
1188 if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
|
|
1189 DECL_STATIC_CONSTRUCTOR (vtv_fndecl) = 0;
|
|
1190
|
|
1191 gimplify_function_tree (vtv_fndecl);
|
|
1192 cgraph_node::add_new_function (vtv_fndecl, false);
|
|
1193
|
|
1194 symtab->process_new_functions ();
|
|
1195
|
|
1196 if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
|
|
1197 assemble_vtv_preinit_initializer (vtv_fndecl);
|
|
1198
|
|
1199 }
|
|
1200 pop_lang_context ();
|
|
1201 }
|
|
1202
|
|
1203 /* This funtion takes a tree containing a class type (BASE_TYPE), and
|
|
1204 it either finds the existing vtbl_map_node for that class in our
|
|
1205 data structure, or it creates a new node and adds it to the data
|
|
1206 structure if there is not one for the class already. As part of
|
|
1207 this process it also creates the global vtable map variable for the
|
|
1208 class. */
|
|
1209
|
|
1210 struct vtbl_map_node *
|
|
1211 vtable_find_or_create_map_decl (tree base_type)
|
|
1212 {
|
|
1213 char *var_name = NULL;
|
|
1214 struct vtbl_map_node *vtable_map_node = NULL;
|
|
1215
|
|
1216 /* Verify the type has an associated vtable. */
|
|
1217 if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
|
|
1218 return NULL;
|
|
1219
|
|
1220 /* Create map lookup symbol for base class */
|
|
1221 var_name = get_mangled_vtable_map_var_name (base_type);
|
|
1222
|
|
1223 /* We've already created the variable; just look it. */
|
|
1224 vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_type));
|
|
1225
|
|
1226 if (!vtable_map_node || (vtable_map_node->vtbl_map_decl == NULL_TREE))
|
|
1227 {
|
|
1228 /* If we haven't already created the *__vtable_map global
|
|
1229 variable for this class, do so now, and add it to the
|
|
1230 varpool, to make sure it gets saved and written out. */
|
|
1231
|
|
1232 tree var_decl = NULL;
|
|
1233 tree var_type = build_pointer_type (void_type_node);
|
|
1234 tree initial_value = integer_zero_node;
|
|
1235
|
|
1236 var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
|
|
1237 get_identifier (var_name), var_type);
|
|
1238
|
|
1239 DECL_EXTERNAL (var_decl) = 0;
|
|
1240 TREE_STATIC (var_decl) = 1;
|
|
1241 DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
|
|
1242 SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
|
|
1243 DECL_ARTIFICIAL (var_decl) = 1;
|
|
1244 /* We cannot mark this variable as read-only because we want to be
|
|
1245 able to write to it at runtime. */
|
|
1246 TREE_READONLY (var_decl) = 0;
|
|
1247 DECL_IGNORED_P (var_decl) = 1;
|
|
1248 DECL_PRESERVE_P (var_decl) = 1;
|
|
1249
|
|
1250 /* Put these mmap variables in thr .vtable_map_vars section, so
|
|
1251 we can find and protect them. */
|
|
1252
|
|
1253 set_decl_section_name (var_decl, ".vtable_map_vars");
|
|
1254 symtab_node::get (var_decl)->implicit_section = true;
|
|
1255 DECL_INITIAL (var_decl) = initial_value;
|
|
1256
|
|
1257 comdat_linkage (var_decl);
|
|
1258
|
|
1259 varpool_node::finalize_decl (var_decl);
|
|
1260 if (!vtable_map_node)
|
|
1261 vtable_map_node =
|
|
1262 find_or_create_vtbl_map_node (TYPE_MAIN_VARIANT (base_type));
|
|
1263 if (vtable_map_node->vtbl_map_decl == NULL_TREE)
|
|
1264 vtable_map_node->vtbl_map_decl = var_decl;
|
|
1265 }
|
|
1266
|
|
1267 gcc_assert (vtable_map_node);
|
|
1268 return vtable_map_node;
|
|
1269 }
|
|
1270
|
|
1271 /* This function is used to build up our class hierarchy data for a
|
|
1272 particular class. TYPE is the record_type tree node for the
|
|
1273 class. */
|
|
1274
|
|
1275 static void
|
|
1276 vtv_insert_single_class_info (tree type)
|
|
1277 {
|
|
1278 if (flag_vtable_verify)
|
|
1279 {
|
|
1280 tree binfo = TYPE_BINFO (type);
|
|
1281 tree base_binfo;
|
|
1282 struct vtbl_map_node *own_map;
|
|
1283 int i;
|
|
1284
|
|
1285 /* First make sure to create the map for this record type. */
|
|
1286 own_map = vtable_find_or_create_map_decl (type);
|
|
1287 if (own_map == NULL)
|
|
1288 return;
|
|
1289
|
|
1290 /* Go through the list of all base classes for the current
|
|
1291 (derived) type, make sure the *__vtable_map global variable
|
|
1292 for the base class exists, and add the base class/derived
|
|
1293 class pair to the class hierarchy information we are
|
|
1294 accumulating (for vtable pointer verification). */
|
|
1295 for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
|
|
1296 {
|
|
1297 tree tree_val = BINFO_TYPE (base_binfo);
|
|
1298 struct vtbl_map_node *vtable_map_node = NULL;
|
|
1299
|
|
1300 vtable_map_node = vtable_find_or_create_map_decl (tree_val);
|
|
1301
|
|
1302 if (vtable_map_node != NULL)
|
|
1303 update_class_hierarchy_information (tree_val, type);
|
|
1304 }
|
|
1305 }
|
|
1306 }
|
|
1307
|
|
1308 /* This function adds classes we are interested in to a list of
|
|
1309 classes. RECORD is the record_type node for the class we are
|
|
1310 adding to the list. */
|
|
1311
|
|
1312 void
|
|
1313 vtv_save_class_info (tree record)
|
|
1314 {
|
|
1315 if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
|
|
1316 return;
|
|
1317
|
|
1318 if (!vlt_saved_class_info)
|
|
1319 vec_alloc (vlt_saved_class_info, 10);
|
|
1320
|
|
1321 gcc_assert (TREE_CODE (record) == RECORD_TYPE);
|
|
1322
|
|
1323 vec_safe_push (vlt_saved_class_info, record);
|
|
1324 }
|
|
1325
|
|
1326
|
|
1327 /* This function goes through the list of classes we saved and calls
|
|
1328 vtv_insert_single_class_info on each one, to build up our class
|
|
1329 hierarchy data structure. */
|
|
1330
|
|
1331 void
|
|
1332 vtv_recover_class_info (void)
|
|
1333 {
|
|
1334 tree current_class;
|
|
1335 unsigned i;
|
|
1336
|
|
1337 if (vlt_saved_class_info)
|
|
1338 {
|
|
1339 for (i = 0; i < vlt_saved_class_info->length(); ++i)
|
|
1340 {
|
|
1341 current_class = (*vlt_saved_class_info)[i];
|
|
1342 gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
|
|
1343 vtv_insert_single_class_info (current_class);
|
|
1344 }
|
|
1345 }
|
|
1346 }
|
|
1347
|
|
1348 #include "gt-cp-vtable-class-hierarchy.h"
|