LCOV - code coverage report
Current view: top level - gcc/cp - vtable-class-hierarchy.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 338 495 68.3 %
Date: 2020-03-28 11:57:23 Functions: 20 28 71.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

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

Generated by: LCOV version 1.0

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 --enable-host-shared. GCC test suite is run with the built compiler.