LCOV - code coverage report
Current view: top level - gcc/cp - vtable-class-hierarchy.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 69.2 % 496 343
Test Date: 2024-04-20 14:03:02 Functions: 70.4 % 27 19
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Copyright (C) 2012-2024 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                 :          12 : vtv_build_vtable_verify_fndecl (void)
     162                 :             : {
     163                 :          12 :   tree func_type = NULL_TREE;
     164                 :             : 
     165                 :          12 :   if (verify_vtbl_ptr_fndecl != NULL_TREE
     166                 :           0 :       && TREE_CODE (verify_vtbl_ptr_fndecl) != ERROR_MARK)
     167                 :             :     return;
     168                 :             : 
     169                 :          12 :   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                 :          12 :       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                 :          12 :       verify_vtbl_ptr_fndecl =
     189                 :          12 :         build_lang_decl (FUNCTION_DECL,
     190                 :             :                          get_identifier ("__VLTVerifyVtablePointer"),
     191                 :             :                          func_type);
     192                 :             :     }
     193                 :             : 
     194                 :          12 :   TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
     195                 :          12 :   DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
     196                 :          12 :       = tree_cons (get_identifier ("leaf"), NULL,
     197                 :          12 :                    DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
     198                 :          12 :   DECL_PURE_P (verify_vtbl_ptr_fndecl) = 1;
     199                 :          12 :   TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
     200                 :          12 :   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                 :          12 : init_functions (void)
     224                 :             : {
     225                 :          12 :   tree register_set_type;
     226                 :          12 :   tree register_pairs_type;
     227                 :             : 
     228                 :          12 :   if (vlt_register_set_fndecl != NULL_TREE)
     229                 :             :     return;
     230                 :             : 
     231                 :          12 :   gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
     232                 :          12 :   gcc_assert (vlt_register_set_fndecl == NULL_TREE);
     233                 :             : 
     234                 :             :   /* Build function decl for __VLTRegisterSet*.  */
     235                 :             : 
     236                 :          12 :   register_set_type = build_function_type_list
     237                 :          12 :                                              (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                 :          12 :   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                 :          12 :     vlt_register_set_fndecl = build_lang_decl
     252                 :          12 :                                        (FUNCTION_DECL,
     253                 :             :                                         get_identifier ("__VLTRegisterSet"),
     254                 :             :                                         register_set_type);
     255                 :             : 
     256                 :             : 
     257                 :          12 :   TREE_NOTHROW (vlt_register_set_fndecl) = 1;
     258                 :          12 :   DECL_ATTRIBUTES (vlt_register_set_fndecl) =
     259                 :          12 :                     tree_cons (get_identifier ("leaf"), NULL,
     260                 :          12 :                                DECL_ATTRIBUTES (vlt_register_set_fndecl));
     261                 :          12 :   DECL_EXTERNAL(vlt_register_set_fndecl) = 1;
     262                 :          12 :   TREE_PUBLIC (vlt_register_set_fndecl) = 1;
     263                 :          12 :   DECL_PRESERVE_P (vlt_register_set_fndecl) = 1;
     264                 :          12 :   SET_DECL_LANGUAGE (vlt_register_set_fndecl, lang_cplusplus);
     265                 :             : 
     266                 :             :   /* Build function decl for __VLTRegisterPair*.  */
     267                 :             : 
     268                 :          12 :   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                 :          12 :       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                 :          12 :       vlt_register_pairs_fndecl = build_lang_decl
     296                 :          12 :                                       (FUNCTION_DECL,
     297                 :             :                                        get_identifier ("__VLTRegisterPair"),
     298                 :             :                                        register_pairs_type);
     299                 :             :     }
     300                 :             : 
     301                 :          12 :   TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
     302                 :          12 :   DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
     303                 :          12 :                     tree_cons (get_identifier ("leaf"), NULL,
     304                 :          12 :                                DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
     305                 :          12 :   DECL_EXTERNAL(vlt_register_pairs_fndecl) = 1;
     306                 :          12 :   TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
     307                 :          12 :   DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
     308                 :          12 :   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                 :           8 : add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
     324                 :             :                  sbitmap inserted)
     325                 :             : {
     326                 :           8 :   struct work_node *new_work_node;
     327                 :             : 
     328                 :           8 :   if (bitmap_bit_p (inserted, node->class_uid))
     329                 :             :     return;
     330                 :             : 
     331                 :           8 :   new_work_node = XNEW (struct work_node);
     332                 :           8 :   new_work_node->next = *worklist;
     333                 :           8 :   new_work_node->node = node;
     334                 :           8 :   *worklist = new_work_node;
     335                 :             : 
     336                 :           8 :   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                 :           8 : find_and_remove_next_leaf_node (struct work_node **worklist)
     348                 :             : {
     349                 :           8 :   struct work_node *prev, *cur;
     350                 :           8 :   struct vtv_graph_node *ret_val = NULL;
     351                 :             : 
     352                 :           8 :   for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
     353                 :             :     {
     354                 :          16 :       if ((cur->node->children).length() == cur->node->num_processed_children)
     355                 :             :         {
     356                 :           8 :           if (prev == NULL)
     357                 :           8 :             (*worklist) = cur->next;
     358                 :             :           else
     359                 :           0 :             prev->next = cur->next;
     360                 :             : 
     361                 :           8 :           cur->next = NULL;
     362                 :           8 :           ret_val = cur->node;
     363                 :           8 :           free (cur);
     364                 :           8 :           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                 :          12 : vtv_compute_class_hierarchy_transitive_closure (void)
     381                 :             : {
     382                 :          12 :   struct work_node *worklist = NULL;
     383                 :          12 :   sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
     384                 :          12 :   unsigned i;
     385                 :          12 :   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                 :          12 :   bitmap_clear (inserted);
     397                 :          20 :   for (j = 0; j < num_vtable_map_nodes; ++j)
     398                 :             :     {
     399                 :           8 :       struct vtbl_map_node *cur = vtbl_map_nodes_vec[j];
     400                 :           8 :       if (cur->class_info
     401                 :           8 :           && ((cur->class_info->children).length() == 0)
     402                 :          16 :           && ! (bitmap_bit_p (inserted, cur->class_info->class_uid)))
     403                 :           8 :         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                 :          20 :   while (worklist)
     410                 :             :     {
     411                 :           8 :       struct vtv_graph_node *temp_node =
     412                 :           8 :                                   find_and_remove_next_leaf_node (&worklist);
     413                 :             : 
     414                 :           8 :       gcc_assert (temp_node != NULL);
     415                 :           8 :       temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
     416                 :           8 :       bitmap_clear (temp_node->descendants);
     417                 :           8 :       bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
     418                 :          24 :       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                 :          16 :       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                 :          12 : }
     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                 :           8 : check_and_record_registered_pairs (tree vtable_decl, tree vptr_address,
     445                 :             :                                    tree base_class)
     446                 :             : {
     447                 :           8 :   unsigned offset;
     448                 :           8 :   struct vtbl_map_node *base_vtable_map_node;
     449                 :           8 :   bool inserted_something = false;
     450                 :             : 
     451                 :             : 
     452                 :           8 :   if (TREE_CODE (vptr_address) == ADDR_EXPR
     453                 :           8 :       && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
     454                 :           4 :     vptr_address = TREE_OPERAND (vptr_address, 0);
     455                 :             : 
     456                 :           8 :   if (TREE_OPERAND_LENGTH (vptr_address) > 1)
     457                 :           8 :     offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
     458                 :             :   else
     459                 :             :     offset = 0;
     460                 :             : 
     461                 :           8 :   base_vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_class));
     462                 :             : 
     463                 :           8 :   inserted_something = vtbl_map_node_registration_insert
     464                 :           8 :                                                         (base_vtable_map_node,
     465                 :             :                                                          vtable_decl,
     466                 :             :                                                          offset);
     467                 :           8 :   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                 :           4 : register_construction_vtables (tree base_class, tree record_type,
     485                 :             :                                vec<tree> *vtable_ptr_array)
     486                 :             : {
     487                 :           4 :   tree vtbl_var_decl;
     488                 :             : 
     489                 :           4 :   if (TREE_CODE (record_type) != RECORD_TYPE)
     490                 :             :     return;
     491                 :             : 
     492                 :           4 :   vtbl_var_decl = CLASSTYPE_VTABLES (record_type);
     493                 :             : 
     494                 :           4 :   if (CLASSTYPE_VBASECLASSES (record_type))
     495                 :             :     {
     496                 :           4 :       tree vtt_decl;
     497                 :           4 :       bool already_registered = false;
     498                 :           4 :       tree val_vtbl_decl = NULL_TREE;
     499                 :             : 
     500                 :           4 :       vtt_decl = DECL_CHAIN (vtbl_var_decl);
     501                 :             : 
     502                 :             :       /* Check to see if we have found a VTT.  Add its data if appropriate.  */
     503                 :           4 :       if (vtt_decl)
     504                 :             :         {
     505                 :           4 :           tree values = DECL_INITIAL (vtt_decl);
     506                 :           4 :           if (TREE_ASM_WRITTEN (vtt_decl)
     507                 :           4 :               && values != NULL_TREE
     508                 :           4 :               && TREE_CODE (values) == CONSTRUCTOR
     509                 :           8 :               && 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                 :           4 :               for (cnt = 0;
     524                 :           8 :                    vec_safe_iterate (CONSTRUCTOR_ELTS (values),
     525                 :             :                                      cnt, &ce);
     526                 :             :                    cnt++)
     527                 :             :                 {
     528                 :           4 :                   tree value = ce->value;
     529                 :             : 
     530                 :             :                   /* Search for the ADDR_EXPR operand within the value.  */
     531                 :             : 
     532                 :           4 :                   while (value
     533                 :           4 :                          && TREE_OPERAND (value, 0)
     534                 :           8 :                          && 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                 :           4 :                   if (TREE_OPERAND (value, 0))
     542                 :           4 :                     val_vtbl_decl = TREE_OPERAND (value, 0);
     543                 :             : 
     544                 :          12 :                   while (!VAR_P (val_vtbl_decl)
     545                 :          12 :                          && TREE_OPERAND (val_vtbl_decl, 0))
     546                 :           8 :                     val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
     547                 :             : 
     548                 :           4 :                   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                 :           4 :                   already_registered = check_and_record_registered_pairs
     554                 :           4 :                                                                (val_vtbl_decl,
     555                 :             :                                                                 value,
     556                 :             :                                                                 base_class);
     557                 :             : 
     558                 :           4 :                   if (already_registered)
     559                 :           4 :                     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                 :           8 : register_other_binfo_vtables (tree binfo, tree base_class,
     591                 :             :                               vec<tree> *vtable_ptr_array)
     592                 :             : {
     593                 :           8 :   unsigned ix;
     594                 :           8 :   tree base_binfo;
     595                 :           8 :   tree vtable_decl;
     596                 :           8 :   bool already_registered;
     597                 :             : 
     598                 :           8 :   if (binfo == NULL_TREE)
     599                 :           8 :     return;
     600                 :             : 
     601                 :          12 :   for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
     602                 :             :     {
     603                 :           4 :       if ((!BINFO_PRIMARY_P (base_binfo)
     604                 :           0 :            || BINFO_VIRTUAL_P (base_binfo))
     605                 :           4 :           && (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                 :           4 :       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                 :           8 : guess_num_vtable_pointers (struct vtv_graph_node *class_node)
     635                 :             : {
     636                 :           8 :   tree vtbl;
     637                 :           8 :   int total_num_vtbls = 0;
     638                 :           8 :   int num_vtbls_power_of_two = 1;
     639                 :           8 :   unsigned i;
     640                 :             : 
     641                 :          16 :   for (i = 0; i < num_vtable_map_nodes; ++i)
     642                 :           8 :     if (bitmap_bit_p (class_node->descendants, i))
     643                 :             :       {
     644                 :           8 :         tree class_type = vtbl_map_nodes_vec[i]->class_info->class_type;
     645                 :          24 :         for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
     646                 :          16 :              vtbl = DECL_CHAIN (vtbl))
     647                 :             :           {
     648                 :          16 :             total_num_vtbls++;
     649                 :          16 :             if (total_num_vtbls > num_vtbls_power_of_two)
     650                 :           8 :               num_vtbls_power_of_two <<= 1;
     651                 :             :           }
     652                 :             :       }
     653                 :           8 :   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                 :           8 : vtv_string_hash (const char *in)
     663                 :             : {
     664                 :           8 :   const char *s = in;
     665                 :           8 :   uint32_t h = 0;
     666                 :             : 
     667                 :           8 :   gcc_assert (in != NULL);
     668                 :         236 :   for ( ; *s; ++s)
     669                 :         228 :     h = 5 * h + *s;
     670                 :           8 :   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                 :           8 : build_key_buffer_arg (tree base_ptr_var_decl)
     718                 :             : {
     719                 :           8 :   const int key_type_fixed_size = 8;
     720                 :           8 :   uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl));
     721                 :           8 :   uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
     722                 :             :                                               (DECL_NAME (base_ptr_var_decl)));
     723                 :           8 :   void *key_buffer = xmalloc (len1 + key_type_fixed_size);
     724                 :           8 :   uint32_t *value_ptr = (uint32_t *) key_buffer;
     725                 :           8 :   tree ret_value;
     726                 :             : 
     727                 :             :   /* Set the len and hash for the string.  */
     728                 :           8 :   *value_ptr = len1;
     729                 :           8 :   value_ptr++;
     730                 :           8 :   *value_ptr = hash_value;
     731                 :             : 
     732                 :             :   /* Now copy the string representation of the vtbl map name...  */
     733                 :          16 :   memcpy ((char *) key_buffer + key_type_fixed_size,
     734                 :           8 :           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                 :           8 :   ret_value = build_string_literal (len1 + key_type_fixed_size,
     740                 :             :                                     (char *) key_buffer);
     741                 :           8 :   free (key_buffer);
     742                 :           8 :   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                 :             :                                                 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                 :             :                                                              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                 :           8 : 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                 :           8 :   tree call_expr;
     810                 :           8 :   int num_args = vtbl_ptr_array->length();
     811                 :          12 :   tree vtable_address = NULL_TREE;
     812                 :             : 
     813                 :           8 :   if (num_args == 0)
     814                 :           4 :     vtable_address = build_int_cst (build_pointer_type (void_type_node), 0);
     815                 :             :   else
     816                 :           4 :     vtable_address = (*vtbl_ptr_array)[0];
     817                 :             : 
     818                 :           8 :   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                 :           8 :     call_expr = build_call_expr (vlt_register_pairs_fndecl, 4, arg1, arg2,
     823                 :             :                                  size_hint_arg, vtable_address);
     824                 :             :     
     825                 :           8 :   append_to_statement_list (call_expr, &body);
     826                 :           8 :   num_calls_to_regpair++;
     827                 :           8 : }
     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                 :           8 : register_all_pairs (tree body)
     887                 :             : {
     888                 :           8 :   bool registered_at_least_one = false;
     889                 :           8 :   vec<tree> *vtbl_ptr_array = NULL;
     890                 :           8 :   unsigned j;
     891                 :             : 
     892                 :          16 :   for (j = 0; j < num_vtable_map_nodes; ++j)
     893                 :             :     {
     894                 :           8 :       struct vtbl_map_node *current = vtbl_map_nodes_vec[j];
     895                 :           8 :       unsigned i = 0;
     896                 :           8 :       tree base_class = current->class_info->class_type;
     897                 :           8 :       tree base_ptr_var_decl = current->vtbl_map_decl;
     898                 :           8 :       tree arg1;
     899                 :           8 :       tree arg2;
     900                 :           8 :       tree new_type;
     901                 :           8 :       tree str1 = NULL_TREE;
     902                 :           8 :       tree str2 = NULL_TREE;
     903                 :           8 :       size_t size_hint;
     904                 :           8 :       tree size_hint_arg;
     905                 :             : 
     906                 :           8 :       gcc_assert (current->class_info != NULL);
     907                 :             : 
     908                 :             : 
     909                 :           8 :       if (flag_vtv_debug)
     910                 :           0 :         str1 = build_string_literal (DECL_NAME (base_ptr_var_decl));
     911                 :             : 
     912                 :           8 :       new_type = build_pointer_type (TREE_TYPE (base_ptr_var_decl));
     913                 :           8 :       arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
     914                 :             : 
     915                 :             :       /* We need a fresh vector for each iteration.  */
     916                 :           8 :       if (vtbl_ptr_array)
     917                 :           0 :         vec_free (vtbl_ptr_array);
     918                 :             : 
     919                 :           8 :       vec_alloc (vtbl_ptr_array, 10);
     920                 :             : 
     921                 :          16 :       for (i = 0; i < num_vtable_map_nodes; ++i)
     922                 :           8 :         if (bitmap_bit_p (current->class_info->descendants, i))
     923                 :             :           {
     924                 :           8 :             struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_vec[i];
     925                 :           8 :             tree class_type = vtbl_class_node->class_info->class_type;
     926                 :             : 
     927                 :           8 :             if (class_type
     928                 :           8 :                 && (TREE_CODE (class_type) == RECORD_TYPE))
     929                 :             :               {
     930                 :           8 :                 bool already_registered;
     931                 :             : 
     932                 :           8 :                 tree binfo = TYPE_BINFO (class_type);
     933                 :           8 :                 tree vtable_decl;
     934                 :           8 :                 bool vtable_should_be_output = false;
     935                 :             : 
     936                 :           8 :                 vtable_decl = CLASSTYPE_VTABLES (class_type);
     937                 :             : 
     938                 :             :                 /* Handle main vtable for this class.  */
     939                 :             : 
     940                 :           8 :                 if (vtable_decl)
     941                 :             :                   {
     942                 :           8 :                     vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
     943                 :           8 :                     str2 = build_string_literal (DECL_NAME (vtable_decl));
     944                 :             :                   }
     945                 :             : 
     946                 :           8 :                 if (vtable_decl && vtable_should_be_output)
     947                 :             :                   {
     948                 :           4 :                     tree vtable_address = build_vtbl_address (binfo);
     949                 :             : 
     950                 :           4 :                     already_registered = check_and_record_registered_pairs
     951                 :           4 :                                                               (vtable_decl,
     952                 :             :                                                                vtable_address,
     953                 :             :                                                                base_class);
     954                 :             : 
     955                 :             : 
     956                 :           4 :                     if (!already_registered)
     957                 :             :                       {
     958                 :           4 :                         vtbl_ptr_array->safe_push (vtable_address);
     959                 :             : 
     960                 :             :                         /* Find and handle any 'extra' vtables associated
     961                 :             :                            with this class, via virtual inheritance.   */
     962                 :           4 :                         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                 :           4 :                         register_other_binfo_vtables (binfo, base_class,
     968                 :             :                                                       vtbl_ptr_array);
     969                 :             :                       }
     970                 :             :                   }
     971                 :             :               }
     972                 :             :           }
     973                 :           8 :       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                 :           8 :       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                 :           8 :       if (vtbl_ptr_array->length() > 0)
     988                 :             :         {
     989                 :             :           unsigned len = vtbl_ptr_array->length();
     990                 :           4 :           while ((size_t) len > size_hint)
     991                 :           0 :             size_hint <<= 1;
     992                 :             :         }
     993                 :           8 :       size_hint_arg = build_int_cst (size_type_node, size_hint);
     994                 :             : 
     995                 :             :       /* Get the key-buffer argument.  */
     996                 :           8 :       arg2 = build_key_buffer_arg (base_ptr_var_decl);
     997                 :             : 
     998                 :           8 :       if (str2 == NULL_TREE)
     999                 :           0 :         str2 = build_string_literal ("unknown");
    1000                 :             : 
    1001                 :           8 :       if (flag_vtv_debug)
    1002                 :           0 :         output_set_info (current->class_info->class_type,
    1003                 :             :                          *vtbl_ptr_array);
    1004                 :             : 
    1005                 :           8 :       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                 :           8 :           if (vtbl_ptr_array->length() > 0
    1016                 :           8 :               || (current->is_used
    1017                 :           4 :                   || (current->registered->size() > 0)))
    1018                 :             :             {
    1019                 :           8 :               insert_call_to_register_pair (vtbl_ptr_array,
    1020                 :             :                                             arg1, arg2, size_hint_arg, str1,
    1021                 :             :                                             str2, body);
    1022                 :           8 :               registered_at_least_one = true;
    1023                 :             :             }
    1024                 :             :         }
    1025                 :             : 
    1026                 :           8 :       if (flag_vtv_counts && current_set_size > 0)
    1027                 :           0 :         write_out_current_set_data (base_class, current_set_size);
    1028                 :             : 
    1029                 :             :     }
    1030                 :             : 
    1031                 :           8 :   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                 :          12 : vtv_register_class_hierarchy_information (tree init_routine_body)
    1125                 :             : {
    1126                 :          12 :   bool registered_something = false;
    1127                 :             :  
    1128                 :          12 :   init_functions ();
    1129                 :             : 
    1130                 :          12 :   if (num_vtable_map_nodes == 0)
    1131                 :             :     return false;
    1132                 :             : 
    1133                 :             :   /* Add class hierarchy pairs to the vtable map data structure.  */
    1134                 :           8 :   registered_something = register_all_pairs (init_routine_body);
    1135                 :             : 
    1136                 :           8 :   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                 :          12 : vtv_generate_init_routine (void)
    1149                 :             : {
    1150                 :          12 :   tree init_routine_body;
    1151                 :          12 :   bool vtable_classes_found = false;
    1152                 :             : 
    1153                 :          12 :   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                 :          12 :   init_routine_body = vtv_start_verification_constructor_init_function ();
    1160                 :             : 
    1161                 :          12 :   vtable_classes_found =
    1162                 :          12 :                  vtv_register_class_hierarchy_information (init_routine_body);
    1163                 :             : 
    1164                 :          12 :   if (vtable_classes_found)
    1165                 :             :     {
    1166                 :           8 :       tree vtv_fndecl =
    1167                 :           8 :         vtv_finish_verification_constructor_init_function (init_routine_body);
    1168                 :           8 :       TREE_STATIC (vtv_fndecl) = 1;
    1169                 :           8 :       TREE_USED (vtv_fndecl) = 1;
    1170                 :           8 :       DECL_PRESERVE_P (vtv_fndecl) = 1;
    1171                 :             :       /* We are running too late to generate any meaningful debug information
    1172                 :             :          for this routine.  */
    1173                 :           8 :       DECL_IGNORED_P (vtv_fndecl) = 1;
    1174                 :           8 :       if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
    1175                 :           4 :         DECL_STATIC_CONSTRUCTOR (vtv_fndecl) = 0;
    1176                 :             : 
    1177                 :           8 :       gimplify_function_tree (vtv_fndecl);
    1178                 :           8 :       cgraph_node::add_new_function (vtv_fndecl, false);
    1179                 :             : 
    1180                 :           8 :       if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF)
    1181                 :             :         {
    1182                 :           4 :           tree vtv_var
    1183                 :           4 :             = build_decl (BUILTINS_LOCATION, VAR_DECL,
    1184                 :             :                           get_identifier ("__vtv_preinit"),
    1185                 :           4 :                           build_pointer_type (TREE_TYPE (vtv_fndecl)));
    1186                 :           4 :           TREE_STATIC (vtv_var) = 1;
    1187                 :           4 :           DECL_ARTIFICIAL (vtv_var) = 1;
    1188                 :           4 :           DECL_INITIAL (vtv_var) = build_fold_addr_expr (vtv_fndecl);
    1189                 :           4 :           set_decl_section_name (vtv_var, ".preinit_array");
    1190                 :             : 
    1191                 :           4 :           varpool_node::add (vtv_var);
    1192                 :             :         }
    1193                 :             :     }
    1194                 :          12 :   pop_lang_context ();
    1195                 :          12 : }
    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                 :          24 : vtable_find_or_create_map_decl (tree base_type)
    1206                 :             : {
    1207                 :          24 :   char *var_name = NULL;
    1208                 :          24 :   struct vtbl_map_node *vtable_map_node = NULL;
    1209                 :             : 
    1210                 :             :   /* Verify the type has an associated vtable.  */
    1211                 :          24 :   if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
    1212                 :             :     return NULL;
    1213                 :             : 
    1214                 :             :   /* Create map lookup symbol for base class */
    1215                 :           8 :   var_name = get_mangled_vtable_map_var_name (base_type);
    1216                 :             : 
    1217                 :             :   /* We've already created the variable; just look it.  */
    1218                 :           8 :   vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_type));
    1219                 :             : 
    1220                 :           8 :   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                 :           8 :       tree var_decl = NULL;
    1227                 :           8 :       tree var_type = build_pointer_type (void_type_node);
    1228                 :           8 :       tree initial_value = integer_zero_node;
    1229                 :             : 
    1230                 :           8 :       var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
    1231                 :             :                               get_identifier (var_name), var_type);
    1232                 :             : 
    1233                 :           8 :       DECL_EXTERNAL (var_decl) = 0;
    1234                 :           8 :       TREE_STATIC (var_decl) = 1;
    1235                 :           8 :       DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
    1236                 :           8 :       SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
    1237                 :           8 :       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                 :           8 :       TREE_READONLY (var_decl) = 0;
    1241                 :           8 :       DECL_IGNORED_P (var_decl) = 1;
    1242                 :           8 :       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                 :           8 :       set_decl_section_name (var_decl, ".vtable_map_vars");
    1248                 :           8 :       symtab_node::get (var_decl)->implicit_section = true;
    1249                 :           8 :       DECL_INITIAL (var_decl) = initial_value;
    1250                 :             : 
    1251                 :           8 :       comdat_linkage (var_decl);
    1252                 :             : 
    1253                 :           8 :       varpool_node::finalize_decl (var_decl);
    1254                 :           8 :       if (!vtable_map_node)
    1255                 :           8 :         vtable_map_node =
    1256                 :           8 :                    find_or_create_vtbl_map_node (TYPE_MAIN_VARIANT (base_type));
    1257                 :           8 :       if (vtable_map_node->vtbl_map_decl == NULL_TREE)
    1258                 :           8 :         vtable_map_node->vtbl_map_decl = var_decl;
    1259                 :             :     }
    1260                 :             : 
    1261                 :           8 :   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                 :          16 : vtv_insert_single_class_info (tree type)
    1271                 :             : {
    1272                 :          16 :   if (flag_vtable_verify)
    1273                 :             :     {
    1274                 :          16 :       tree binfo =  TYPE_BINFO (type);
    1275                 :          16 :       tree base_binfo;
    1276                 :          16 :       struct vtbl_map_node *own_map;
    1277                 :          16 :       int i;
    1278                 :             : 
    1279                 :             :       /* First make sure to create the map for this record type.  */
    1280                 :          16 :       own_map = vtable_find_or_create_map_decl (type);
    1281                 :          16 :       if (own_map == NULL)
    1282                 :          16 :         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                 :          16 :       for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
    1290                 :             :         {
    1291                 :           8 :           tree tree_val = BINFO_TYPE (base_binfo);
    1292                 :           8 :           struct vtbl_map_node *vtable_map_node = NULL;
    1293                 :             : 
    1294                 :           8 :           vtable_map_node = vtable_find_or_create_map_decl (tree_val);
    1295                 :             : 
    1296                 :           8 :           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                 :          16 : vtv_save_class_info (tree record)
    1308                 :             : {
    1309                 :          16 :   if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
    1310                 :             :     return;
    1311                 :             : 
    1312                 :          16 :   if (!vlt_saved_class_info)
    1313                 :           8 :     vec_alloc (vlt_saved_class_info, 10);
    1314                 :             : 
    1315                 :          16 :   gcc_assert (TREE_CODE (record) == RECORD_TYPE);
    1316                 :             : 
    1317                 :          16 :   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                 :          12 : vtv_recover_class_info (void)
    1327                 :             : {
    1328                 :          12 :   tree current_class;
    1329                 :          12 :   unsigned i;
    1330                 :             : 
    1331                 :          12 :   if (vlt_saved_class_info)
    1332                 :             :     {
    1333                 :          24 :       for (i = 0; i < vlt_saved_class_info->length(); ++i)
    1334                 :             :         {
    1335                 :          16 :           current_class = (*vlt_saved_class_info)[i];
    1336                 :          16 :           gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
    1337                 :          16 :           vtv_insert_single_class_info (current_class);
    1338                 :             :         }
    1339                 :             :     }
    1340                 :          12 : }
    1341                 :             : 
    1342                 :             : #include "gt-cp-vtable-class-hierarchy.h"
        

Generated by: LCOV version 2.1-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.