LCOV - code coverage report
Current view: top level - gcc/cp - vtable-class-hierarchy.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 343 496 69.2 %
Date: 2023-07-19 08:18:47 Functions: 19 27 70.4 %

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

Generated by: LCOV version 1.16