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