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