LCOV - code coverage report
Current view: top level - gcc/cp - vtable-class-hierarchy.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 68.9 % 498 343
Test Date: 2026-02-28 14:20:25 Functions: 70.4 % 27 19
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.