Home | History | Annotate | Line # | Download | only in gcc
      1  1.1  mrg /* Copyright (C) 2013-2022 Free Software Foundation, Inc.
      2  1.1  mrg 
      3  1.1  mrg This file is part of GCC.
      4  1.1  mrg 
      5  1.1  mrg GCC is free software; you can redistribute it and/or modify it under
      6  1.1  mrg the terms of the GNU General Public License as published by the Free
      7  1.1  mrg Software Foundation; either version 3, or (at your option) any later
      8  1.1  mrg version.
      9  1.1  mrg 
     10  1.1  mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     11  1.1  mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     12  1.1  mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     13  1.1  mrg for more details.
     14  1.1  mrg 
     15  1.1  mrg You should have received a copy of the GNU General Public License
     16  1.1  mrg along with GCC; see the file COPYING3.  If not see
     17  1.1  mrg <http://www.gnu.org/licenses/>.  */
     18  1.1  mrg 
     19  1.1  mrg /* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
     20  1.1  mrg    before using them for virtual method dispatches.  */
     21  1.1  mrg 
     22  1.1  mrg /* This file is part of the vtable security feature implementation.
     23  1.1  mrg    The vtable security feature is designed to detect when a virtual
     24  1.1  mrg    call is about to be made through an invalid vtable pointer
     25  1.1  mrg    (possibly due to data corruption or malicious attacks). The
     26  1.1  mrg    compiler finds every virtual call, and inserts a verification call
     27  1.1  mrg    before the virtual call.  The verification call takes the actual
     28  1.1  mrg    vtable pointer value in the object through which the virtual call
     29  1.1  mrg    is being made, and compares the vtable pointer against a set of all
     30  1.1  mrg    valid vtable pointers that the object could contain (this set is
     31  1.1  mrg    based on the declared type of the object).  If the pointer is in
     32  1.1  mrg    the valid set, execution is allowed to continue; otherwise the
     33  1.1  mrg    program is halted.
     34  1.1  mrg 
     35  1.1  mrg   There are several pieces needed in order to make this work: 1. For
     36  1.1  mrg   every virtual class in the program (i.e. a class that contains
     37  1.1  mrg   virtual methods), we need to build the set of all possible valid
     38  1.1  mrg   vtables that an object of that class could point to.  This includes
     39  1.1  mrg   vtables for any class(es) that inherit from the class under
     40  1.1  mrg   consideration.  2. For every such data set we build up, we need a
     41  1.1  mrg   way to find and reference the data set.  This is complicated by the
     42  1.1  mrg   fact that the real vtable addresses are not known until runtime,
     43  1.1  mrg   when the program is loaded into memory, but we need to reference the
     44  1.1  mrg   sets at compile time when we are inserting verification calls into
     45  1.1  mrg   the program.  3.  We need to find every virtual call in the program,
     46  1.1  mrg   and insert the verification call (with the appropriate arguments)
     47  1.1  mrg   before the virtual call.  4. We need some runtime library pieces:
     48  1.1  mrg   the code to build up the data sets at runtime; the code to actually
     49  1.1  mrg   perform the verification using the data sets; and some code to set
     50  1.1  mrg   protections on the data sets, so they themselves do not become
     51  1.1  mrg   hacker targets.
     52  1.1  mrg 
     53  1.1  mrg   To find and reference the set of valid vtable pointers for any given
     54  1.1  mrg   virtual class, we create a special global variable for each virtual
     55  1.1  mrg   class.  We refer to this as the "vtable map variable" for that
     56  1.1  mrg   class.  The vtable map variable has the type "void *", and is
     57  1.1  mrg   initialized by the compiler to NULL.  At runtime when the set of
     58  1.1  mrg   valid vtable pointers for a virtual class, e.g. class Foo, is built,
     59  1.1  mrg   the vtable map variable for class Foo is made to point to the set.
     60  1.1  mrg   During compile time, when the compiler is inserting verification
     61  1.1  mrg   calls into the program, it passes the vtable map variable for the
     62  1.1  mrg   appropriate class to the verification call, so that at runtime the
     63  1.1  mrg   verification call can find the appropriate data set.
     64  1.1  mrg 
     65  1.1  mrg   The actual set of valid vtable pointers for a virtual class,
     66  1.1  mrg   e.g. class Foo, cannot be built until runtime, when the vtables get
     67  1.1  mrg   loaded into memory and their addresses are known.  But the knowledge
     68  1.1  mrg   about which vtables belong in which class' hierarchy is only known
     69  1.1  mrg   at compile time.  Therefore at compile time we collect class
     70  1.1  mrg   hierarchy and vtable information about every virtual class, and we
     71  1.1  mrg   generate calls to build up the data sets at runtime.  To build the
     72  1.1  mrg   data sets, we call one of the functions we add to the runtime
     73  1.1  mrg   library, __VLTRegisterPair.  __VLTRegisterPair takes two arguments,
     74  1.1  mrg   a vtable map variable and the address of a vtable.  If the vtable
     75  1.1  mrg   map variable is currently NULL, it creates a new data set (hash
     76  1.1  mrg   table), makes the vtable map variable point to the new data set, and
     77  1.1  mrg   inserts the vtable address into the data set.  If the vtable map
     78  1.1  mrg   variable is not NULL, it just inserts the vtable address into the
     79  1.1  mrg   data set.  In order to make sure that our data sets are built before
     80  1.1  mrg   any verification calls happen, we create a special constructor
     81  1.1  mrg   initialization function for each compilation unit, give it a very
     82  1.1  mrg   high initialization priority, and insert all of our calls to
     83  1.1  mrg   __VLTRegisterPair into our special constructor initialization
     84  1.1  mrg   function.
     85  1.1  mrg 
     86  1.1  mrg   The vtable verification feature is controlled by the flag
     87  1.1  mrg   '-fvtable-verify='.  There are three flavors of this:
     88  1.1  mrg   '-fvtable-verify=std', '-fvtable-verify=preinit', and
     89  1.1  mrg   '-fvtable-verify=none'.  If the option '-fvtable-verfy=preinit' is
     90  1.1  mrg   used, then our constructor initialization function gets put into the
     91  1.1  mrg   preinit array.  This is necessary if there are data sets that need
     92  1.1  mrg   to be built very early in execution.  If the constructor
     93  1.1  mrg   initialization function gets put into the preinit array, the we also
     94  1.1  mrg   add calls to __VLTChangePermission at the beginning and end of the
     95  1.1  mrg   function.  The call at the beginning sets the permissions on the
     96  1.1  mrg   data sets and vtable map variables to read/write, and the one at the
     97  1.1  mrg   end makes them read-only.  If the '-fvtable-verify=std' option is
     98  1.1  mrg   used, the constructor initialization functions are executed at their
     99  1.1  mrg   normal time, and the __VLTChangePermission calls are handled
    100  1.1  mrg   differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
    101  1.1  mrg   The option '-fvtable-verify=none' turns off vtable verification.
    102  1.1  mrg 
    103  1.1  mrg   This file contains code for the tree pass that goes through all the
    104  1.1  mrg   statements in each basic block, looking for virtual calls, and
    105  1.1  mrg   inserting a call to __VLTVerifyVtablePointer (with appropriate
    106  1.1  mrg   arguments) before each one.  It also contains the hash table
    107  1.1  mrg   functions for the data structures used for collecting the class
    108  1.1  mrg   hierarchy data and building/maintaining the vtable map variable data
    109  1.1  mrg   are defined in gcc/vtable-verify.h.  These data structures are
    110  1.1  mrg   shared with the code in the C++ front end that collects the class
    111  1.1  mrg   hierarchy & vtable information and generates the vtable map
    112  1.1  mrg   variables (see cp/vtable-class-hierarchy.cc).  This tree pass should
    113  1.1  mrg   run just before the gimple is converted to RTL.
    114  1.1  mrg 
    115  1.1  mrg   Some implementation details for this pass:
    116  1.1  mrg 
    117  1.1  mrg   To find all of the virtual calls, we iterate through all the
    118  1.1  mrg   gimple statements in each basic block, looking for any call
    119  1.1  mrg   statement with the code "OBJ_TYPE_REF".  Once we have found the
    120  1.1  mrg   virtual call, we need to find the vtable pointer through which the
    121  1.1  mrg   call is being made, and the type of the object containing the
    122  1.1  mrg   pointer (to find the appropriate vtable map variable).  We then use
    123  1.1  mrg   these to build a call to __VLTVerifyVtablePointer, passing the
    124  1.1  mrg   vtable map variable, and the vtable pointer.  We insert the
    125  1.1  mrg   verification call just after the gimple statement that gets the
    126  1.1  mrg   vtable pointer out of the object, and we update the next
    127  1.1  mrg   statement to depend on the result returned from
    128  1.1  mrg   __VLTVerifyVtablePointer (the vtable pointer value), to ensure
    129  1.1  mrg   subsequent compiler phases don't remove or reorder the call (it's no
    130  1.1  mrg   good to have the verification occur after the virtual call, for
    131  1.1  mrg   example).  To find the vtable pointer being used (and the type of
    132  1.1  mrg   the object) we search backwards through the def_stmts chain from the
    133  1.1  mrg   virtual call (see verify_bb_vtables for more details).  */
    134  1.1  mrg 
    135  1.1  mrg #include "config.h"
    136  1.1  mrg #include "system.h"
    137  1.1  mrg #include "coretypes.h"
    138  1.1  mrg #include "backend.h"
    139  1.1  mrg #include "tree.h"
    140  1.1  mrg #include "gimple.h"
    141  1.1  mrg #include "tree-pass.h"
    142  1.1  mrg #include "ssa.h"
    143  1.1  mrg #include "gimple-iterator.h"
    144  1.1  mrg 
    145  1.1  mrg #include "vtable-verify.h"
    146  1.1  mrg 
    147  1.1  mrg unsigned num_vtable_map_nodes = 0;
    148  1.1  mrg int total_num_virtual_calls = 0;
    149  1.1  mrg int total_num_verified_vcalls = 0;
    150  1.1  mrg 
    151  1.1  mrg extern GTY(()) tree verify_vtbl_ptr_fndecl;
    152  1.1  mrg tree verify_vtbl_ptr_fndecl = NULL_TREE;
    153  1.1  mrg 
    154  1.1  mrg /* Keep track of whether or not any virtual call were verified.  */
    155  1.1  mrg static bool any_verification_calls_generated = false;
    156  1.1  mrg 
    157  1.1  mrg unsigned int vtable_verify_main (void);
    158  1.1  mrg 
    159  1.1  mrg 
    160  1.1  mrg /* The following few functions are for the vtbl pointer hash table
    161  1.1  mrg    in the 'registered' field of the struct vtable_map_node.  The hash
    162  1.1  mrg    table keeps track of which vtable pointers have been used in
    163  1.1  mrg    calls to __VLTRegisterPair with that particular vtable map variable.  */
    164  1.1  mrg 
    165  1.1  mrg /* This function checks to see if a particular VTABLE_DECL and OFFSET are
    166  1.1  mrg    already in the 'registered' hash table for NODE.  */
    167  1.1  mrg 
    168  1.1  mrg bool
    169  1.1  mrg vtbl_map_node_registration_find (struct vtbl_map_node *node,
    170  1.1  mrg                                  tree vtable_decl,
    171  1.1  mrg                                  unsigned offset)
    172  1.1  mrg {
    173  1.1  mrg   struct vtable_registration key;
    174  1.1  mrg   struct vtable_registration **slot;
    175  1.1  mrg 
    176  1.1  mrg   gcc_assert (node && node->registered);
    177  1.1  mrg 
    178  1.1  mrg   key.vtable_decl = vtable_decl;
    179  1.1  mrg   slot = node->registered->find_slot (&key, NO_INSERT);
    180  1.1  mrg 
    181  1.1  mrg   if (slot && (*slot))
    182  1.1  mrg     {
    183  1.1  mrg       unsigned i;
    184  1.1  mrg       for (i = 0; i < ((*slot)->offsets).length (); ++i)
    185  1.1  mrg         if ((*slot)->offsets[i] == offset)
    186  1.1  mrg           return true;
    187  1.1  mrg     }
    188  1.1  mrg 
    189  1.1  mrg   return false;
    190  1.1  mrg }
    191  1.1  mrg 
    192  1.1  mrg /* This function inserts VTABLE_DECL and OFFSET into the 'registered'
    193  1.1  mrg    hash table for NODE.  It returns a boolean indicating whether or not
    194  1.1  mrg    it actually inserted anything.  */
    195  1.1  mrg 
    196  1.1  mrg bool
    197  1.1  mrg vtbl_map_node_registration_insert (struct vtbl_map_node *node,
    198  1.1  mrg                                    tree vtable_decl,
    199  1.1  mrg                                    unsigned offset)
    200  1.1  mrg {
    201  1.1  mrg   struct vtable_registration key;
    202  1.1  mrg   struct vtable_registration **slot;
    203  1.1  mrg   bool inserted_something = false;
    204  1.1  mrg 
    205  1.1  mrg   if (!node || !node->registered)
    206  1.1  mrg     return false;
    207  1.1  mrg 
    208  1.1  mrg   key.vtable_decl = vtable_decl;
    209  1.1  mrg   slot = node->registered->find_slot (&key, INSERT);
    210  1.1  mrg 
    211  1.1  mrg   if (! *slot)
    212  1.1  mrg     {
    213  1.1  mrg       struct vtable_registration *node;
    214  1.1  mrg       node = XNEW (struct vtable_registration);
    215  1.1  mrg       node->vtable_decl = vtable_decl;
    216  1.1  mrg 
    217  1.1  mrg       (node->offsets).create (10);
    218  1.1  mrg       (node->offsets).safe_push (offset);
    219  1.1  mrg       *slot = node;
    220  1.1  mrg       inserted_something = true;
    221  1.1  mrg     }
    222  1.1  mrg   else
    223  1.1  mrg     {
    224  1.1  mrg       /* We found the vtable_decl slot; we need to see if it already
    225  1.1  mrg          contains the offset.  If not, we need to add the offset.  */
    226  1.1  mrg       unsigned i;
    227  1.1  mrg       bool found = false;
    228  1.1  mrg       for (i = 0; i < ((*slot)->offsets).length () && !found; ++i)
    229  1.1  mrg         if ((*slot)->offsets[i] == offset)
    230  1.1  mrg           found = true;
    231  1.1  mrg 
    232  1.1  mrg       if (!found)
    233  1.1  mrg         {
    234  1.1  mrg           ((*slot)->offsets).safe_push (offset);
    235  1.1  mrg           inserted_something = true;
    236  1.1  mrg         }
    237  1.1  mrg      }
    238  1.1  mrg   return inserted_something;
    239  1.1  mrg }
    240  1.1  mrg 
    241  1.1  mrg /* Hashtable functions for vtable_registration hashtables.  */
    242  1.1  mrg 
    243  1.1  mrg inline hashval_t
    244  1.1  mrg registration_hasher::hash (const vtable_registration *p)
    245  1.1  mrg {
    246  1.1  mrg   const struct vtable_registration *n = (const struct vtable_registration *) p;
    247  1.1  mrg   return (hashval_t) (DECL_UID (n->vtable_decl));
    248  1.1  mrg }
    249  1.1  mrg 
    250  1.1  mrg inline bool
    251  1.1  mrg registration_hasher::equal (const vtable_registration *p1,
    252  1.1  mrg 			    const vtable_registration *p2)
    253  1.1  mrg {
    254  1.1  mrg   const struct vtable_registration *n1 =
    255  1.1  mrg                                     (const struct vtable_registration *) p1;
    256  1.1  mrg   const struct vtable_registration *n2 =
    257  1.1  mrg                                     (const struct vtable_registration *) p2;
    258  1.1  mrg   return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
    259  1.1  mrg }
    260  1.1  mrg 
    261  1.1  mrg /* End of hashtable functions for "registered" hashtables.  */
    262  1.1  mrg 
    263  1.1  mrg 
    264  1.1  mrg 
    265  1.1  mrg /* Hashtable definition and functions for vtbl_map_hash.  */
    266  1.1  mrg 
    267  1.1  mrg struct vtbl_map_hasher : nofree_ptr_hash <struct vtbl_map_node>
    268  1.1  mrg {
    269  1.1  mrg   static inline hashval_t hash (const vtbl_map_node *);
    270  1.1  mrg   static inline bool equal (const vtbl_map_node *, const vtbl_map_node *);
    271  1.1  mrg };
    272  1.1  mrg 
    273  1.1  mrg /* Returns a hash code for P.  */
    274  1.1  mrg 
    275  1.1  mrg inline hashval_t
    276  1.1  mrg vtbl_map_hasher::hash (const vtbl_map_node *p)
    277  1.1  mrg {
    278  1.1  mrg   const struct vtbl_map_node n = *((const struct vtbl_map_node *) p);
    279  1.1  mrg   return (hashval_t) IDENTIFIER_HASH_VALUE (n.class_name);
    280  1.1  mrg }
    281  1.1  mrg 
    282  1.1  mrg /* Returns nonzero if P1 and P2 are equal.  */
    283  1.1  mrg 
    284  1.1  mrg inline bool
    285  1.1  mrg vtbl_map_hasher::equal (const vtbl_map_node *p1, const vtbl_map_node *p2)
    286  1.1  mrg {
    287  1.1  mrg   const struct vtbl_map_node n1 = *((const struct vtbl_map_node *) p1);
    288  1.1  mrg   const struct vtbl_map_node n2 = *((const struct vtbl_map_node *) p2);
    289  1.1  mrg   return (IDENTIFIER_HASH_VALUE (n1.class_name) ==
    290  1.1  mrg           IDENTIFIER_HASH_VALUE (n2.class_name));
    291  1.1  mrg }
    292  1.1  mrg 
    293  1.1  mrg /* Here are the two structures into which we insert vtable map nodes.
    294  1.1  mrg    We use two data structures because of the vastly different ways we need
    295  1.1  mrg    to find the nodes for various tasks (see comments in vtable-verify.h
    296  1.1  mrg    for more details.  */
    297  1.1  mrg 
    298  1.1  mrg typedef hash_table<vtbl_map_hasher> vtbl_map_table_type;
    299  1.1  mrg typedef vtbl_map_table_type::iterator vtbl_map_iterator_type;
    300  1.1  mrg 
    301  1.1  mrg /* Vtable map variable nodes stored in a hash table.  */
    302  1.1  mrg static vtbl_map_table_type *vtbl_map_hash;
    303  1.1  mrg 
    304  1.1  mrg /* Vtable map variable nodes stored in a vector.  */
    305  1.1  mrg vec<struct vtbl_map_node *> vtbl_map_nodes_vec;
    306  1.1  mrg 
    307  1.1  mrg /* Vector of mangled names for anonymous classes.  */
    308  1.1  mrg extern GTY(()) vec<tree, va_gc> *vtbl_mangled_name_types;
    309  1.1  mrg extern GTY(()) vec<tree, va_gc> *vtbl_mangled_name_ids;
    310  1.1  mrg vec<tree, va_gc> *vtbl_mangled_name_types;
    311  1.1  mrg vec<tree, va_gc> *vtbl_mangled_name_ids;
    312  1.1  mrg 
    313  1.1  mrg /* Look up class_type (a type decl for record types) in the vtbl_mangled_names_*
    314  1.1  mrg    vectors.  This is a linear lookup.  Return the associated mangled name for
    315  1.1  mrg    the class type.  This is for handling types from anonymous namespaces, whose
    316  1.1  mrg    DECL_ASSEMBLER_NAME ends up being "<anon>", which is useless for our
    317  1.1  mrg    purposes.
    318  1.1  mrg 
    319  1.1  mrg    We use two vectors of trees to keep track of the mangled names:  One is a
    320  1.1  mrg    vector of class types and the other is a vector of the mangled names.  The
    321  1.1  mrg    assumption is that these two vectors are kept in perfect lock-step so that
    322  1.1  mrg    vtbl_mangled_name_ids[i] is the mangled name for
    323  1.1  mrg    vtbl_mangled_name_types[i].  */
    324  1.1  mrg 
    325  1.1  mrg static tree
    326  1.1  mrg vtbl_find_mangled_name (tree class_type)
    327  1.1  mrg {
    328  1.1  mrg   tree result = NULL_TREE;
    329  1.1  mrg   unsigned i;
    330  1.1  mrg 
    331  1.1  mrg   if (!vtbl_mangled_name_types or !vtbl_mangled_name_ids)
    332  1.1  mrg     return result;
    333  1.1  mrg 
    334  1.1  mrg   if (vtbl_mangled_name_types->length() != vtbl_mangled_name_ids->length())
    335  1.1  mrg     return result;
    336  1.1  mrg 
    337  1.1  mrg   for (i = 0; i < vtbl_mangled_name_types->length(); ++i)
    338  1.1  mrg     if ((*vtbl_mangled_name_types)[i] == class_type)
    339  1.1  mrg       {
    340  1.1  mrg 	result = (*vtbl_mangled_name_ids)[i];
    341  1.1  mrg 	break;
    342  1.1  mrg       }
    343  1.1  mrg 
    344  1.1  mrg   return result;
    345  1.1  mrg }
    346  1.1  mrg 
    347  1.1  mrg /* Store a class type decl and its mangled name, for an anonymous RECORD_TYPE,
    348  1.1  mrg    in the vtbl_mangled_names vector.  Make sure there is not already an
    349  1.1  mrg    entry for the class type before adding it.  */
    350  1.1  mrg 
    351  1.1  mrg void
    352  1.1  mrg vtbl_register_mangled_name (tree class_type, tree mangled_name)
    353  1.1  mrg {
    354  1.1  mrg   if (!vtbl_mangled_name_types)
    355  1.1  mrg     vec_alloc (vtbl_mangled_name_types, 10);
    356  1.1  mrg 
    357  1.1  mrg   if (!vtbl_mangled_name_ids)
    358  1.1  mrg     vec_alloc (vtbl_mangled_name_ids, 10);
    359  1.1  mrg 
    360  1.1  mrg   gcc_assert (vtbl_mangled_name_types->length() ==
    361  1.1  mrg 	      vtbl_mangled_name_ids->length());
    362  1.1  mrg 
    363  1.1  mrg 
    364  1.1  mrg   if (vtbl_find_mangled_name (class_type) == NULL_TREE)
    365  1.1  mrg     {
    366  1.1  mrg       vec_safe_push (vtbl_mangled_name_types, class_type);
    367  1.1  mrg       vec_safe_push (vtbl_mangled_name_ids, mangled_name);
    368  1.1  mrg     }
    369  1.1  mrg }
    370  1.1  mrg 
    371  1.1  mrg /* Return vtbl_map node for CLASS_NAME  without creating a new one.  */
    372  1.1  mrg 
    373  1.1  mrg struct vtbl_map_node *
    374  1.1  mrg vtbl_map_get_node (tree class_type)
    375  1.1  mrg {
    376  1.1  mrg   struct vtbl_map_node key;
    377  1.1  mrg   struct vtbl_map_node **slot;
    378  1.1  mrg 
    379  1.1  mrg   tree class_type_decl;
    380  1.1  mrg   tree class_name;
    381  1.1  mrg   unsigned int type_quals;
    382  1.1  mrg 
    383  1.1  mrg   if (!vtbl_map_hash)
    384  1.1  mrg     return NULL;
    385  1.1  mrg 
    386  1.1  mrg   gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
    387  1.1  mrg 
    388  1.1  mrg 
    389  1.1  mrg   /* Find the TYPE_DECL for the class.  */
    390  1.1  mrg   class_type_decl = TYPE_NAME (class_type);
    391  1.1  mrg 
    392  1.1  mrg   /* Verify that there aren't any qualifiers on the type.  */
    393  1.1  mrg   type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
    394  1.1  mrg   gcc_assert (type_quals == TYPE_UNQUALIFIED);
    395  1.1  mrg 
    396  1.1  mrg   /* Get the mangled name for the unqualified type.  */
    397  1.1  mrg   gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl));
    398  1.1  mrg   class_name = DECL_ASSEMBLER_NAME (class_type_decl);
    399  1.1  mrg 
    400  1.1  mrg   if (strstr (IDENTIFIER_POINTER (class_name), "<anon>") != NULL)
    401  1.1  mrg     class_name = vtbl_find_mangled_name (class_type_decl);
    402  1.1  mrg 
    403  1.1  mrg   key.class_name = class_name;
    404  1.1  mrg   slot = (struct vtbl_map_node **) vtbl_map_hash->find_slot (&key, NO_INSERT);
    405  1.1  mrg   if (!slot)
    406  1.1  mrg     return NULL;
    407  1.1  mrg   return *slot;
    408  1.1  mrg }
    409  1.1  mrg 
    410  1.1  mrg /* Return vtbl_map node assigned to BASE_CLASS_TYPE.  Create new one
    411  1.1  mrg    when needed.  */
    412  1.1  mrg 
    413  1.1  mrg struct vtbl_map_node *
    414  1.1  mrg find_or_create_vtbl_map_node (tree base_class_type)
    415  1.1  mrg {
    416  1.1  mrg   struct vtbl_map_node key;
    417  1.1  mrg   struct vtbl_map_node *node;
    418  1.1  mrg   struct vtbl_map_node **slot;
    419  1.1  mrg   tree class_type_decl;
    420  1.1  mrg   unsigned int type_quals;
    421  1.1  mrg 
    422  1.1  mrg   if (!vtbl_map_hash)
    423  1.1  mrg     vtbl_map_hash = new vtbl_map_table_type (10);
    424  1.1  mrg 
    425  1.1  mrg   /* Find the TYPE_DECL for the class.  */
    426  1.1  mrg   class_type_decl = TYPE_NAME (base_class_type);
    427  1.1  mrg 
    428  1.1  mrg   /* Verify that there aren't any type qualifiers on type.  */
    429  1.1  mrg   type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
    430  1.1  mrg   gcc_assert (type_quals == TYPE_UNQUALIFIED);
    431  1.1  mrg 
    432  1.1  mrg   gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl));
    433  1.1  mrg   key.class_name = DECL_ASSEMBLER_NAME (class_type_decl);
    434  1.1  mrg 
    435  1.1  mrg   if (strstr (IDENTIFIER_POINTER (key.class_name), "<anon>") != NULL)
    436  1.1  mrg     key.class_name = vtbl_find_mangled_name (class_type_decl);
    437  1.1  mrg 
    438  1.1  mrg   slot = (struct vtbl_map_node **) vtbl_map_hash->find_slot (&key, INSERT);
    439  1.1  mrg 
    440  1.1  mrg   if (*slot)
    441  1.1  mrg     return *slot;
    442  1.1  mrg 
    443  1.1  mrg   node = XNEW (struct vtbl_map_node);
    444  1.1  mrg   node->vtbl_map_decl = NULL_TREE;
    445  1.1  mrg   node->class_name = key.class_name;
    446  1.1  mrg   node->uid = num_vtable_map_nodes++;
    447  1.1  mrg 
    448  1.1  mrg   node->class_info = XNEW (struct vtv_graph_node);
    449  1.1  mrg   node->class_info->class_type = base_class_type;
    450  1.1  mrg   node->class_info->class_uid = node->uid;
    451  1.1  mrg   node->class_info->num_processed_children = 0;
    452  1.1  mrg 
    453  1.1  mrg   (node->class_info->parents).create (4);
    454  1.1  mrg   (node->class_info->children).create (4);
    455  1.1  mrg 
    456  1.1  mrg   node->registered = new register_table_type (16);
    457  1.1  mrg 
    458  1.1  mrg   node->is_used = false;
    459  1.1  mrg 
    460  1.1  mrg   vtbl_map_nodes_vec.safe_push (node);
    461  1.1  mrg   gcc_assert (vtbl_map_nodes_vec[node->uid] == node);
    462  1.1  mrg 
    463  1.1  mrg   *slot = node;
    464  1.1  mrg   return node;
    465  1.1  mrg }
    466  1.1  mrg 
    467  1.1  mrg /* End of hashtable functions for vtable_map variables hash table.   */
    468  1.1  mrg 
    469  1.1  mrg /* Given a gimple STMT, this function checks to see if the statement
    470  1.1  mrg    is an assignment, the rhs of which is getting the vtable pointer
    471  1.1  mrg    value out of an object.  (i.e. it's the value we need to verify
    472  1.1  mrg    because its the vtable pointer that will be used for a virtual
    473  1.1  mrg    call).  */
    474  1.1  mrg 
    475  1.1  mrg static bool
    476  1.1  mrg is_vtable_assignment_stmt (gimple *stmt)
    477  1.1  mrg {
    478  1.1  mrg 
    479  1.1  mrg   if (gimple_code (stmt) != GIMPLE_ASSIGN)
    480  1.1  mrg     return false;
    481  1.1  mrg   else
    482  1.1  mrg     {
    483  1.1  mrg       tree lhs = gimple_assign_lhs (stmt);
    484  1.1  mrg       tree rhs = gimple_assign_rhs1 (stmt);
    485  1.1  mrg 
    486  1.1  mrg       if (TREE_CODE (lhs) != SSA_NAME)
    487  1.1  mrg         return false;
    488  1.1  mrg 
    489  1.1  mrg       if (TREE_CODE (rhs) != COMPONENT_REF)
    490  1.1  mrg         return false;
    491  1.1  mrg 
    492  1.1  mrg       if (! (TREE_OPERAND (rhs, 1))
    493  1.1  mrg           || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
    494  1.1  mrg         return false;
    495  1.1  mrg 
    496  1.1  mrg       if (! DECL_VIRTUAL_P (TREE_OPERAND (rhs, 1)))
    497  1.1  mrg         return false;
    498  1.1  mrg     }
    499  1.1  mrg 
    500  1.1  mrg     return true;
    501  1.1  mrg }
    502  1.1  mrg 
    503  1.1  mrg /* This function attempts to recover the declared class of an object
    504  1.1  mrg    that is used in making a virtual call.  We try to get the type from
    505  1.1  mrg    the type cast in the gimple assignment statement that extracts the
    506  1.1  mrg    vtable pointer from the object (DEF_STMT).  The gimple statement
    507  1.1  mrg    usually looks something like this:
    508  1.1  mrg 
    509  1.1  mrg    D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event    */
    510  1.1  mrg 
    511  1.1  mrg static tree
    512  1.1  mrg extract_object_class_type (tree rhs)
    513  1.1  mrg {
    514  1.1  mrg   tree result = NULL_TREE;
    515  1.1  mrg 
    516  1.1  mrg   /* Try to find and extract the type cast from that stmt.  */
    517  1.1  mrg   if (TREE_CODE (rhs) == COMPONENT_REF)
    518  1.1  mrg     {
    519  1.1  mrg       tree op0 = TREE_OPERAND (rhs, 0);
    520  1.1  mrg       tree op1 = TREE_OPERAND (rhs, 1);
    521  1.1  mrg 
    522  1.1  mrg       if (TREE_CODE (op1) == FIELD_DECL
    523  1.1  mrg           && DECL_VIRTUAL_P (op1))
    524  1.1  mrg         {
    525  1.1  mrg           if (TREE_CODE (op0) == COMPONENT_REF
    526  1.1  mrg               && TREE_CODE (TREE_OPERAND (op0, 0)) == MEM_REF
    527  1.1  mrg               && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))== RECORD_TYPE)
    528  1.1  mrg             result = TREE_TYPE (TREE_OPERAND (op0, 0));
    529  1.1  mrg           else
    530  1.1  mrg             result = TREE_TYPE (op0);
    531  1.1  mrg         }
    532  1.1  mrg       else if (TREE_CODE (op0) == COMPONENT_REF)
    533  1.1  mrg         {
    534  1.1  mrg           result = extract_object_class_type (op0);
    535  1.1  mrg           if (result == NULL_TREE
    536  1.1  mrg               && TREE_CODE (op1) == COMPONENT_REF)
    537  1.1  mrg             result = extract_object_class_type (op1);
    538  1.1  mrg         }
    539  1.1  mrg     }
    540  1.1  mrg 
    541  1.1  mrg   return result;
    542  1.1  mrg }
    543  1.1  mrg 
    544  1.1  mrg /* This function traces forward through the def-use chain of an SSA
    545  1.1  mrg    variable to see if it ever gets used in a virtual function call.  It
    546  1.1  mrg    returns a boolean indicating whether or not it found a virtual call in
    547  1.1  mrg    the use chain.  */
    548  1.1  mrg 
    549  1.1  mrg static bool
    550  1.1  mrg var_is_used_for_virtual_call_p (tree lhs, int *mem_ref_depth,
    551  1.1  mrg 				int *recursion_depth)
    552  1.1  mrg {
    553  1.1  mrg   imm_use_iterator imm_iter;
    554  1.1  mrg   bool found_vcall = false;
    555  1.1  mrg   use_operand_p use_p;
    556  1.1  mrg 
    557  1.1  mrg   if (TREE_CODE (lhs) != SSA_NAME)
    558  1.1  mrg     return false;
    559  1.1  mrg 
    560  1.1  mrg   if (*mem_ref_depth > 2)
    561  1.1  mrg     return false;
    562  1.1  mrg 
    563  1.1  mrg   if (*recursion_depth > 25)
    564  1.1  mrg     /* If we've recursed this far the chances are pretty good that
    565  1.1  mrg        we're not going to find what we're looking for, and that we've
    566  1.1  mrg        gone down a recursion black hole. Time to stop.  */
    567  1.1  mrg     return false;
    568  1.1  mrg 
    569  1.1  mrg   *recursion_depth = *recursion_depth + 1;
    570  1.1  mrg 
    571  1.1  mrg   /* Iterate through the immediate uses of the current variable.  If
    572  1.1  mrg      it's a virtual function call, we're done.  Otherwise, if there's
    573  1.1  mrg      an LHS for the use stmt, add the ssa var to the work list
    574  1.1  mrg      (assuming it's not already in the list and is not a variable
    575  1.1  mrg      we've already examined.  */
    576  1.1  mrg 
    577  1.1  mrg   FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
    578  1.1  mrg     {
    579  1.1  mrg       gimple *stmt2 = USE_STMT (use_p);
    580  1.1  mrg 
    581  1.1  mrg       if (is_gimple_call (stmt2))
    582  1.1  mrg         {
    583  1.1  mrg           tree fncall = gimple_call_fn (stmt2);
    584  1.1  mrg           if (fncall && TREE_CODE (fncall) == OBJ_TYPE_REF)
    585  1.1  mrg             found_vcall = true;
    586  1.1  mrg 	  else
    587  1.1  mrg 	    return false;
    588  1.1  mrg         }
    589  1.1  mrg       else if (gimple_code (stmt2) == GIMPLE_PHI)
    590  1.1  mrg         {
    591  1.1  mrg           found_vcall = var_is_used_for_virtual_call_p
    592  1.1  mrg 	                                            (gimple_phi_result (stmt2),
    593  1.1  mrg 	                                             mem_ref_depth,
    594  1.1  mrg 						     recursion_depth);
    595  1.1  mrg         }
    596  1.1  mrg       else if (is_gimple_assign (stmt2))
    597  1.1  mrg         {
    598  1.1  mrg 	  tree rhs = gimple_assign_rhs1 (stmt2);
    599  1.1  mrg 	  if (TREE_CODE (rhs) == ADDR_EXPR
    600  1.1  mrg 	      || TREE_CODE (rhs) == MEM_REF)
    601  1.1  mrg 	    *mem_ref_depth = *mem_ref_depth + 1;
    602  1.1  mrg 
    603  1.1  mrg 	  if (TREE_CODE (rhs) == COMPONENT_REF)
    604  1.1  mrg 	    {
    605  1.1  mrg 	      while (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF)
    606  1.1  mrg 		rhs = TREE_OPERAND (rhs, 0);
    607  1.1  mrg 
    608  1.1  mrg 	      if (TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
    609  1.1  mrg 		  || TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF)
    610  1.1  mrg 		*mem_ref_depth = *mem_ref_depth + 1;
    611  1.1  mrg 	    }
    612  1.1  mrg 
    613  1.1  mrg 	  if (*mem_ref_depth < 3)
    614  1.1  mrg 	    found_vcall = var_is_used_for_virtual_call_p
    615  1.1  mrg 	                                            (gimple_assign_lhs (stmt2),
    616  1.1  mrg 						     mem_ref_depth,
    617  1.1  mrg 						     recursion_depth);
    618  1.1  mrg         }
    619  1.1  mrg 
    620  1.1  mrg       else
    621  1.1  mrg         break;
    622  1.1  mrg 
    623  1.1  mrg       if (found_vcall)
    624  1.1  mrg         return true;
    625  1.1  mrg     }
    626  1.1  mrg 
    627  1.1  mrg   return false;
    628  1.1  mrg }
    629  1.1  mrg 
    630  1.1  mrg /* Search through all the statements in a basic block (BB), searching
    631  1.1  mrg    for virtual method calls.  For each virtual method dispatch, find
    632  1.1  mrg    the vptr value used, and the statically declared type of the
    633  1.1  mrg    object; retrieve the vtable map variable for the type of the
    634  1.1  mrg    object; generate a call to __VLTVerifyVtablePointer; and insert the
    635  1.1  mrg    generated call into the basic block, after the point where the vptr
    636  1.1  mrg    value is gotten out of the object and before the virtual method
    637  1.1  mrg    dispatch. Make the virtual method dispatch depend on the return
    638  1.1  mrg    value from the verification call, so that subsequent optimizations
    639  1.1  mrg    cannot reorder the two calls.  */
    640  1.1  mrg 
    641  1.1  mrg static void
    642  1.1  mrg verify_bb_vtables (basic_block bb)
    643  1.1  mrg {
    644  1.1  mrg   gimple_seq stmts;
    645  1.1  mrg   gimple *stmt = NULL;
    646  1.1  mrg   gimple_stmt_iterator gsi_vtbl_assign;
    647  1.1  mrg   gimple_stmt_iterator gsi_virtual_call;
    648  1.1  mrg 
    649  1.1  mrg   stmts = bb_seq (bb);
    650  1.1  mrg   gsi_virtual_call = gsi_start (stmts);
    651  1.1  mrg   for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
    652  1.1  mrg     {
    653  1.1  mrg       stmt = gsi_stmt (gsi_virtual_call);
    654  1.1  mrg 
    655  1.1  mrg       /* Count virtual calls.  */
    656  1.1  mrg       if (is_gimple_call (stmt))
    657  1.1  mrg         {
    658  1.1  mrg           tree fncall = gimple_call_fn (stmt);
    659  1.1  mrg           if (fncall && TREE_CODE (fncall) == OBJ_TYPE_REF)
    660  1.1  mrg             total_num_virtual_calls++;
    661  1.1  mrg         }
    662  1.1  mrg 
    663  1.1  mrg       if (is_vtable_assignment_stmt (stmt))
    664  1.1  mrg         {
    665  1.1  mrg           tree lhs = gimple_assign_lhs (stmt);
    666  1.1  mrg           tree vtbl_var_decl = NULL_TREE;
    667  1.1  mrg           struct vtbl_map_node *vtable_map_node;
    668  1.1  mrg           tree vtbl_decl = NULL_TREE;
    669  1.1  mrg           gcall *call_stmt;
    670  1.1  mrg           const char *vtable_name = "<unknown>";
    671  1.1  mrg           tree tmp0;
    672  1.1  mrg           bool found;
    673  1.1  mrg 	  int mem_ref_depth = 0;
    674  1.1  mrg 	  int recursion_depth = 0;
    675  1.1  mrg 
    676  1.1  mrg           /* Make sure this vptr field access is for a virtual call.  */
    677  1.1  mrg           if (!var_is_used_for_virtual_call_p (lhs, &mem_ref_depth,
    678  1.1  mrg 					       &recursion_depth))
    679  1.1  mrg             continue;
    680  1.1  mrg 
    681  1.1  mrg           /* Now we have found the virtual method dispatch and
    682  1.1  mrg              the preceding access of the _vptr.* field... Next
    683  1.1  mrg              we need to find the statically declared type of
    684  1.1  mrg              the object, so we can find and use the right
    685  1.1  mrg              vtable map variable in the verification call.  */
    686  1.1  mrg           tree class_type = extract_object_class_type
    687  1.1  mrg                                                    (gimple_assign_rhs1 (stmt));
    688  1.1  mrg 
    689  1.1  mrg           gsi_vtbl_assign = gsi_for_stmt (stmt);
    690  1.1  mrg 
    691  1.1  mrg           if (class_type
    692  1.1  mrg               && (TREE_CODE (class_type) == RECORD_TYPE)
    693  1.1  mrg               && TYPE_BINFO (class_type))
    694  1.1  mrg             {
    695  1.1  mrg               /* Get the vtable VAR_DECL for the type.  */
    696  1.1  mrg               vtbl_var_decl = BINFO_VTABLE (TYPE_BINFO (class_type));
    697  1.1  mrg 
    698  1.1  mrg               if (TREE_CODE (vtbl_var_decl) == POINTER_PLUS_EXPR)
    699  1.1  mrg                 vtbl_var_decl = TREE_OPERAND (TREE_OPERAND (vtbl_var_decl, 0),
    700  1.1  mrg                                               0);
    701  1.1  mrg 
    702  1.1  mrg               gcc_assert (vtbl_var_decl);
    703  1.1  mrg 
    704  1.1  mrg               vtbl_decl = vtbl_var_decl;
    705  1.1  mrg               vtable_map_node = vtbl_map_get_node
    706  1.1  mrg                                                (TYPE_MAIN_VARIANT (class_type));
    707  1.1  mrg 
    708  1.1  mrg               gcc_assert (verify_vtbl_ptr_fndecl);
    709  1.1  mrg 
    710  1.1  mrg               /* Given the vtable pointer for the base class of the
    711  1.1  mrg                  object, build the call to __VLTVerifyVtablePointer to
    712  1.1  mrg                  verify that the object's vtable pointer (contained in
    713  1.1  mrg                  lhs) is in the set of valid vtable pointers for the
    714  1.1  mrg                  base class.  */
    715  1.1  mrg 
    716  1.1  mrg               if (vtable_map_node && vtable_map_node->vtbl_map_decl)
    717  1.1  mrg                 {
    718  1.1  mrg                   vtable_map_node->is_used = true;
    719  1.1  mrg                   vtbl_var_decl = vtable_map_node->vtbl_map_decl;
    720  1.1  mrg 
    721  1.1  mrg                   if (VAR_P (vtbl_decl))
    722  1.1  mrg                     vtable_name = IDENTIFIER_POINTER (DECL_NAME (vtbl_decl));
    723  1.1  mrg 
    724  1.1  mrg                   /* Call different routines if we are interested in
    725  1.1  mrg                      trace information to debug problems.  */
    726  1.1  mrg                   if (flag_vtv_debug)
    727  1.1  mrg                     {
    728  1.1  mrg                       int len1 = IDENTIFIER_LENGTH
    729  1.1  mrg                                                  (DECL_NAME (vtbl_var_decl));
    730  1.1  mrg                       int len2 = strlen (vtable_name);
    731  1.1  mrg 
    732  1.1  mrg                       call_stmt = gimple_build_call
    733  1.1  mrg                                      (verify_vtbl_ptr_fndecl, 4,
    734  1.1  mrg                                       build1 (ADDR_EXPR,
    735  1.1  mrg                                                 TYPE_POINTER_TO
    736  1.1  mrg                                                   (TREE_TYPE (vtbl_var_decl)),
    737  1.1  mrg                                               vtbl_var_decl),
    738  1.1  mrg                                       lhs,
    739  1.1  mrg                                       build_string_literal
    740  1.1  mrg                                                   (len1 + 1,
    741  1.1  mrg                                                    IDENTIFIER_POINTER
    742  1.1  mrg                                                        (DECL_NAME
    743  1.1  mrg                                                             (vtbl_var_decl))),
    744  1.1  mrg                                       build_string_literal (len2 + 1,
    745  1.1  mrg                                                             vtable_name));
    746  1.1  mrg                     }
    747  1.1  mrg                   else
    748  1.1  mrg                     call_stmt = gimple_build_call
    749  1.1  mrg                                      (verify_vtbl_ptr_fndecl, 2,
    750  1.1  mrg                                       build1 (ADDR_EXPR,
    751  1.1  mrg                                                 TYPE_POINTER_TO
    752  1.1  mrg                                                   (TREE_TYPE (vtbl_var_decl)),
    753  1.1  mrg                                                  vtbl_var_decl),
    754  1.1  mrg                                       lhs);
    755  1.1  mrg 
    756  1.1  mrg 
    757  1.1  mrg                   /* Create a new SSA_NAME var to hold the call's
    758  1.1  mrg                      return value, and make the call_stmt use the
    759  1.1  mrg                      variable for that purpose.  */
    760  1.1  mrg                   tmp0 = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "VTV");
    761  1.1  mrg                   gimple_call_set_lhs (call_stmt, tmp0);
    762  1.1  mrg                   update_stmt (call_stmt);
    763  1.1  mrg 
    764  1.1  mrg                   /* Replace all uses of lhs with tmp0. */
    765  1.1  mrg                   found = false;
    766  1.1  mrg                   imm_use_iterator iterator;
    767  1.1  mrg 		  gimple *use_stmt;
    768  1.1  mrg                   FOR_EACH_IMM_USE_STMT (use_stmt, iterator, lhs)
    769  1.1  mrg                     {
    770  1.1  mrg                       use_operand_p use_p;
    771  1.1  mrg                       if (use_stmt == call_stmt)
    772  1.1  mrg                         continue;
    773  1.1  mrg                       FOR_EACH_IMM_USE_ON_STMT (use_p, iterator)
    774  1.1  mrg                         SET_USE (use_p, tmp0);
    775  1.1  mrg                       update_stmt (use_stmt);
    776  1.1  mrg                       found = true;
    777  1.1  mrg                     }
    778  1.1  mrg 
    779  1.1  mrg                   gcc_assert (found);
    780  1.1  mrg 
    781  1.1  mrg                   /* Insert the new verification call just after the
    782  1.1  mrg                      statement that gets the vtable pointer out of the
    783  1.1  mrg                      object.  */
    784  1.1  mrg                   gcc_assert (gsi_stmt (gsi_vtbl_assign) == stmt);
    785  1.1  mrg                   gsi_insert_after (&gsi_vtbl_assign, call_stmt,
    786  1.1  mrg                                     GSI_NEW_STMT);
    787  1.1  mrg 
    788  1.1  mrg                   any_verification_calls_generated = true;
    789  1.1  mrg                   total_num_verified_vcalls++;
    790  1.1  mrg                 }
    791  1.1  mrg             }
    792  1.1  mrg         }
    793  1.1  mrg     }
    794  1.1  mrg }
    795  1.1  mrg 
    796  1.1  mrg /* Definition of this optimization pass.  */
    797  1.1  mrg 
    798  1.1  mrg namespace {
    799  1.1  mrg 
    800  1.1  mrg const pass_data pass_data_vtable_verify =
    801  1.1  mrg {
    802  1.1  mrg   GIMPLE_PASS, /* type */
    803  1.1  mrg   "vtable-verify", /* name */
    804  1.1  mrg   OPTGROUP_NONE, /* optinfo_flags */
    805  1.1  mrg   TV_VTABLE_VERIFICATION, /* tv_id */
    806  1.1  mrg   ( PROP_cfg | PROP_ssa ), /* properties_required */
    807  1.1  mrg   0, /* properties_provided */
    808  1.1  mrg   0, /* properties_destroyed */
    809  1.1  mrg   0, /* todo_flags_start */
    810  1.1  mrg   TODO_update_ssa, /* todo_flags_finish */
    811  1.1  mrg };
    812  1.1  mrg 
    813  1.1  mrg class pass_vtable_verify : public gimple_opt_pass
    814  1.1  mrg {
    815  1.1  mrg public:
    816  1.1  mrg   pass_vtable_verify (gcc::context *ctxt)
    817  1.1  mrg     : gimple_opt_pass (pass_data_vtable_verify, ctxt)
    818  1.1  mrg   {}
    819  1.1  mrg 
    820  1.1  mrg   /* opt_pass methods: */
    821  1.1  mrg   virtual bool gate (function *) { return (flag_vtable_verify); }
    822  1.1  mrg   virtual unsigned int execute (function *);
    823  1.1  mrg 
    824  1.1  mrg }; // class pass_vtable_verify
    825  1.1  mrg 
    826  1.1  mrg /* Loop through all the basic blocks in the current function, passing them to
    827  1.1  mrg    verify_bb_vtables, which searches for virtual calls, and inserts
    828  1.1  mrg    calls to __VLTVerifyVtablePointer.  */
    829  1.1  mrg 
    830  1.1  mrg unsigned int
    831  1.1  mrg pass_vtable_verify::execute (function *fun)
    832  1.1  mrg {
    833  1.1  mrg   unsigned int ret = 1;
    834  1.1  mrg   basic_block bb;
    835  1.1  mrg 
    836  1.1  mrg   FOR_ALL_BB_FN (bb, fun)
    837  1.1  mrg       verify_bb_vtables (bb);
    838  1.1  mrg 
    839  1.1  mrg   return ret;
    840  1.1  mrg }
    841  1.1  mrg 
    842  1.1  mrg } // anon namespace
    843  1.1  mrg 
    844  1.1  mrg gimple_opt_pass *
    845  1.1  mrg make_pass_vtable_verify (gcc::context *ctxt)
    846  1.1  mrg {
    847  1.1  mrg   return new pass_vtable_verify (ctxt);
    848  1.1  mrg }
    849  1.1  mrg 
    850  1.1  mrg #include "gt-vtable-verify.h"
    851