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