public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
@ 2012-11-05 17:49 Caroline Tice
  2012-11-07 16:58 ` Xinliang David Li
  2012-11-08  9:36 ` Florian Weimer
  0 siblings, 2 replies; 8+ messages in thread
From: Caroline Tice @ 2012-11-05 17:49 UTC (permalink / raw)
  To: gcc-patches; +Cc: Caroline Tice

[-- Attachment #1: Type: text/plain, Size: 9925 bytes --]

As requested, I have split the original patch into two parts: GCC
changes and runtime library changes.  The attached patch is fore the
gcc changes.

-- Caroline Tice
cmtice@google.com

2012-11-05  Caroline Tice  <cmtice@google.com>

        * tree.h (save_vtable_map_decl): New function decl.
        * tree-pass.h (pass_vtable_verify): New pass declaration.
        * cp/init.c (build_vtbl_address): Remove 'static' qualifier from
        function declaration and definition.
        * cp/class.c (finish_struct_1):  Add call to vtv_save_class_info,
        if the vtable verify flag is set.
        * cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
        files.  Add definition for building vtable-class-hierarchy.o.
        * cp/pt.c (mark_class_instantiated):  Add call to vtv_save_class_info
        if the vtable verify flag is set.
        * cp/decl2 (start_objects): Remove 'static' qualifier from function
        declaratin and definition.  Add new paramater, 'extra_name'.  Change
        'type' var from char array to char *.  Call xmalloc & free for 'type'.
        Add 'extra_name' to 'type' string.
        (finish_objects): Remove 'static' qualifier from function declaration
        and definition. Change return type from void to tree.  Make function
        return early if we're doing vtable verification and the function is
        a vtable verification constructor init function.  Make this function
        return 'fn'.
        (generate_ctor_or_dtor_function):  Add third argument to calls to
        start_objects.
        (cp_write_global_declarations):  Add calls to vtv_recover_class_info,
        vtv_compute_class_hierarchy_transitive_closure, and
        vtv_generate_init_routine, if the vtable verify flag is set.
        * cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
        list of gtfiles.
        * cp/vtable-class-hierarchy.c: New file.
        * cp/mangle.c (get_mangled_id): Remove static qualifier from function
        definition.
        * cp/cp-tree.h:  Add extern function declarations for start_objects,
        finish_objects, build_vtbl_address, get_mangled_id,
        vtv_compute_class_hierarchy_transitive_closure,
        vtv_generate_init_routine, vtv_save_class_info and
        vtv_recover_class_info.
        * timevar.def: Add TV_VTABLE_VERIFICATION.
        * flag-types.h: Add enum vtv_priority defintion.
        * tree-vtable-verify.c: New file.
        * tree-vtable-verify.h: New file.
        * common.opt:  Add definitions for fvtable-verify= and its string
        options (vtv_priority enum values).
        * varasm.c (assemble_variable):  Check to see if the variable is a
        vtable map variable, and if so, put it into the vtable map variable
        section, and make it comdat.
        (assemble_vtv_preinit_initializer): New function, to put the
        vtable verification constructor initialization function in the preinit
        array, if appropriate.
        * output.h: Add extern declaration for
        assemble_vtv_preinit_initializer.
        * Makefile.in: Add tree-vtable-verify.o to list of OBJS.  Add build
        rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
        files.
        * passes.c (init_optimization_passes): Add pass_vtable_verify.

On Thu, Nov 1, 2012 at 1:07 PM, Caroline Tice <cmtice@google.com> wrote:
> We have been developing a new security hardening feature for GCC that
> is designed to detect and handle (during program execution) when a
> vtable pointer that is about to be used for a virtual function call is
> not a valid vtable pointer for that call (i.e. it has become
> corrupted, possibly due to a  hacker attack).  We gave a presentation
> on this work at the Gnu Tools Cauldron in Prague last July.  We now
> have the implementation fully working and are submitting this patch
> for review.  We would like to get this into the next release of GCC if
> possible.
>
> The general idea is to collect class hierarchy and vtable pointer data
> while parsing the classes, then use this data to generate (at runtime)
> sets of valid vtable pointers, one for each class.  We also find every
> virtual function call and insert a verification call before the
> virtual function call.  The verification call takes the set of valid
> vtable pointers for the declared class of the object, and the actual
> vtable pointer in the object.  If the vtable pointer in the object is
> in the set of valid vtable pointers for the object, then verification
> succeeds and the virtual call is allowed.  Otherwise verification
> fails and the program aborts.
>
> We have a written a more detailed design document, which I am also
> attaching to this email (GCCVtableSecurityHardeningProposal.txt).
>
> The implementation can be divided into roughly two parts:
> modifications to the main gcc compiler, for things that happen at
> compile time (collecting the class hierarchy & vtable information;
> generating the runtime calls to build the data sets from this data;
> inserting calls to the verification function); and modifications to
> the runtime, i.e. functions that go into libstdc++ for building the
> data sets, for doing the verification against the data sets, for
> protecting the memory where the data sets reside, etc.).
>
> Please let me know if there is any more information you need, or if
> you have any questions about this patch.
>
> -- Caroline Tice
> cmtice@google.com
>
> libstdc++/ChangeLog
>
> 2012-11-01  Caroline Tice  <cmtice@google.com>
>
>         * src/Makefile.am: Add libvtv___la_LIBDD definition; update CXXLINK
>         to search in libvtv___la_LIBADD and to link in libvtv_init.
>         * src/Makefile.in: Regenerate.
>         * libsupc++/Makefile.am: Add libvtv_init.la and libvtv_stubs.la to
>         toolexeclib_LTLIBRARIES.  Add vtv_rts.cc, vtv_malloc.cc and
>         vtv_utils.cc to sources.  Define vtv_init_sources and
>         vtv_stubs_sources.  Also define libvtv_init_la_SOURCES and
>         libvtv_stubs_la_sources.
>         * libsupc++/Makefile.in: Regenerate.
>         * libsupc++/vtv_rts.cc: New file.
>         * libsupc++/vtv_malloc.h: New file.
>         * libsupc++/vtv_rts.h: New file.
>         * libsupc++/vtv_fail.h: New file.
>         * libsupc++/vtv_set.h: New file.
>         * libsupc++/vtv_stubs.cc: New file.
>         * libsupc++/vtv_utils.cc: New file.
>         * libcupc++/vtv_utils.h: New file.
>         * libsupc++/vtv_init.cc: New file.
>         * libsupc++/vtv_malloc.cc: New file.
>         * config/abi/pre/gnu.ver (GLIBCXX_3.4.18): Add vtable verification
>         functions and vtable map variables to library export list.
>
> gcc/ChangeLog:
>
> 2012-11-01  Caroline Tice  <cmtice@google.com>
>
>         * tree.h (save_vtable_map_decl): New function decl.
>         * tree-pass.h (pass_vtable_verify): New pass declaration.
>         * cp/init.c (build_vtbl_address): Remove 'static' qualifier from
>         function declaration and definition.
>         * cp/class.c (finish_struct_1):  Add call to vtv_save_class_info,
>         if the vtable verify flag is set.
>         * cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
>         files.  Add definition for building vtable-class-hierarchy.o.
>         * cp/pt.c (mark_class_instantiated):  Add call to vtv_save_class_info
>         if the vtable verify flag is set.
>         * cp/decl2 (start_objects): Remove 'static' qualifier from function
>         declaratin and definition.  Add new paramater, 'extra_name'.  Change
>         'type' var from char array to char *.  Call xmalloc & free for 'type'.
>         Add 'extra_name' to 'type' string.
>         (finish_objects): Remove 'static' qualifier from function declaration
>         and definition. Change return type from void to tree.  Make function
>         return early if we're doing vtable verification and the function is
>         a vtable verification constructor init function.  Make this function
>         return 'fn'.
>         (generate_ctor_or_dtor_function):  Add third argument to calls to
>         start_objects.
>         (cp_write_global_declarations):  Add calls to vtv_recover_class_info,
>         vtv_compute_class_hierarchy_transitive_closure, and
>         vtv_generate_init_routine, if the vtable verify flag is set.
>         * cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
>         list of gtfiles.
>         * cp/vtable-class-hierarchy.c: New file.
>         * cp/mangle.c (get_mangled_id): Remove static qualifier from function
>         definition.
>         * cp/cp-tree.h:  Add extern function declarations for start_objects,
>         finish_objects, build_vtbl_address, get_mangled_id,
>         vtv_compute_class_hierarchy_transitive_closure,
>         vtv_generate_init_routine, vtv_save_class_info and
>         vtv_recover_class_info.
>         * timevar.def: Add TV_VTABLE_VERIFICATION.
>         * flag-types.h: Add enum vtv_priority defintion.
>         * tree-vtable-verify.c: New file.
>         * tree-vtable-verify.h: New file.
>         * common.opt:  Add definitions for fvtable-verify= and its string
>         options (vtv_priority enum values).
>         * varasm.c (assemble_variable):  Check to see if the variable is a
>         vtable map variable, and if so, put it into the vtable map variable
>         section, and make it comdat.
>         (assemble_vtv_preinit_initializer): New function, to put the
>         vtable verification constructor initialization function in the preinit
>         array, if appropriate.
>         * output.h: Add extern declaration for
>         assemble_vtv_preinit_initializer.
>         * Makefile.in: Add tree-vtable-verify.o to list of OBJS.  Add build
>         rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
>         files.
>         * passes.c (init_optimization_passes): Add pass_vtable_verify.

[-- Attachment #2: fsf-vtable-verification.gcc.patch --]
[-- Type: application/octet-stream, Size: 92992 bytes --]

Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 192503)
+++ gcc/tree.h	(working copy)
@@ -6437,6 +6437,9 @@ is_lang_specific (tree t)
 /* In gimple-low.c.  */
 extern bool block_may_fallthru (const_tree);
 
+/* In tree-vtable-security.c */
+extern void save_vtable_map_decl (tree);
+
 \f
 /* Functional interface to the builtin functions.  */
 
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h	(revision 192503)
+++ gcc/tree-pass.h	(working copy)
@@ -358,6 +358,7 @@ extern struct gimple_opt_pass pass_tm_ed
 extern struct gimple_opt_pass pass_split_functions;
 extern struct gimple_opt_pass pass_feedback_split_functions;
 extern struct gimple_opt_pass pass_strength_reduction;
+extern struct gimple_opt_pass pass_vtable_verify;
 
 /* IPA Passes */
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 192503)
+++ gcc/cp/init.c	(working copy)
@@ -45,7 +45,6 @@ static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
 static tree build_field_list (tree, tree, int *);
-static tree build_vtbl_address (tree);
 static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
 
 /* We are about to generate some complex initialization code.
@@ -1105,7 +1104,7 @@ emit_mem_initializers (tree mem_inits)
 /* Returns the address of the vtable (i.e., the value that should be
    assigned to the vptr) for BINFO.  */
 
-static tree
+tree
 build_vtbl_address (tree binfo)
 {
   tree binfo_for = binfo;
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 192503)
+++ gcc/cp/class.c	(working copy)
@@ -6251,6 +6251,9 @@ finish_struct_1 (tree t)
 
   maybe_suppress_debug_info (t);
 
+  if (flag_vtable_verify)
+    vtv_save_class_info (t);
+
   dump_class_hierarchy (t);
 
   /* Finish debugging output for this type.  */
Index: gcc/cp/Make-lang.in
===================================================================
--- gcc/cp/Make-lang.in	(revision 192503)
+++ gcc/cp/Make-lang.in	(working copy)
@@ -82,7 +82,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -340,7 +340,12 @@ cp/parser.o: cp/parser.c $(CXX_TREE_H) $
   c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H)
 cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \
 	$(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H)
-
+cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \
+  $(TM_H) $(TIMEVAR_H) $(CXX_TREE_H) intl.h $(CXX_PARSER_H) cp/decl.h \
+  $(FLAGS_H) $(DIAGNOSTIC_CORE_H) output.h $(CGRAPH_H) c-family/c-common.h \
+  c-family/c-objc.h $(PLUGIN_H) \
+  tree-iterator.h tree-vtable-verify.h $(GIMPLE_H) \
+  gt-cp-vtable-class-hierarchy.h
 cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h \
 	$(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 192503)
+++ gcc/cp/pt.c	(working copy)
@@ -17882,6 +17882,10 @@ mark_class_instantiated (tree t, int ext
   if (! extern_p)
     {
       CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+
+      if (flag_vtable_verify)
+        vtv_save_class_info (t);
+
       rest_of_type_compilation (t, 1);
     }
 }
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	(revision 192503)
+++ gcc/cp/decl2.c	(working copy)
@@ -69,8 +69,6 @@ typedef struct priority_info_s {
 static void mark_vtable_entries (tree);
 static bool maybe_emit_vtables (tree);
 static bool acceptable_java_type (tree);
-static tree start_objects (int, int);
-static void finish_objects (int, int, tree);
 static tree start_static_storage_duration_function (unsigned);
 static void finish_static_storage_duration_function (tree);
 static priority_info get_priority_info (int);
@@ -2965,12 +2963,12 @@ generate_tls_wrapper (tree fn)
 /* Start the process of running a particular set of global constructors
    or destructors.  Subroutine of do_[cd]tors.  */
 
-static tree
-start_objects (int method_type, int initp)
+tree
+start_objects (int method_type, int initp, const char *extra_name)
 {
   tree body;
   tree fndecl;
-  char type[14];
+  char *type = NULL;
 
   /* Make ctor or dtor function.  METHOD_TYPE may be 'I' or 'D'.  */
 
@@ -2984,15 +2982,22 @@ start_objects (int method_type, int init
       joiner = '_';
 #endif
 
-      sprintf (type, "sub_%c%c%.5u", method_type, joiner, initp);
+      type = (char *) xmalloc ((17 + strlen (extra_name)) * sizeof (char));
+      sprintf (type, "sub_%c%c%.5u%s", method_type, joiner, initp, extra_name);
     }
   else
-    sprintf (type, "sub_%c", method_type);
+    {
+      type = (char *) xmalloc (5 * sizeof (char));
+      sprintf (type, "sub_%c", method_type);
+    }
 
   fndecl = build_lang_decl (FUNCTION_DECL,
 			    get_file_function_name (type),
 			    build_function_type_list (void_type_node,
 						      NULL_TREE));
+
+  free (type);
+
   start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED);
 
   TREE_PUBLIC (current_function_decl) = 0;
@@ -3018,7 +3023,7 @@ start_objects (int method_type, int init
 /* Finish the process of running a particular set of global constructors
    or destructors.  Subroutine of do_[cd]tors.  */
 
-static void
+tree
 finish_objects (int method_type, int initp, tree body)
 {
   tree fn;
@@ -3031,6 +3036,10 @@ finish_objects (int method_type, int ini
     {
       DECL_STATIC_CONSTRUCTOR (fn) = 1;
       decl_init_priority_insert (fn, initp);
+
+      if (flag_vtable_verify
+          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
+        return fn;
     }
   else
     {
@@ -3039,6 +3048,7 @@ finish_objects (int method_type, int ini
     }
 
   expand_or_defer_fn (fn);
+  return fn;
 }
 
 /* The names of the parameters to the function created to handle
@@ -3561,7 +3571,7 @@ generate_ctor_or_dtor_function (bool con
   if (c_dialect_objc () && (priority == DEFAULT_INIT_PRIORITY)
       && constructor_p && objc_static_init_needed_p ())
     {
-      body = start_objects (function_key, priority);
+      body = start_objects (function_key, priority, "");
       objc_generate_static_init_call (NULL_TREE);
     }
 
@@ -3575,7 +3585,7 @@ generate_ctor_or_dtor_function (bool con
 	  tree call;
 
 	  if (! body)
-	    body = start_objects (function_key, priority);
+	    body = start_objects (function_key, priority, "");
 
 	  call = cp_build_function_call_nary (fndecl, tf_warning_or_error,
 					      build_int_cst (NULL_TREE,
@@ -4283,8 +4293,22 @@ cp_write_global_declarations (void)
   timevar_stop (TV_PHASE_DEFERRED);
   timevar_start (TV_PHASE_OPT_GEN);
 
+  if (flag_vtable_verify)
+    {
+      vtv_recover_class_info ();
+      vtv_compute_class_hierarchy_transitive_closure ();
+    }
+
   finalize_compilation_unit ();
 
+  if (flag_vtable_verify)
+    {
+      /* Generate the special constructor initialization function that
+         calls __VLTRegisterPairs, and give it a very high initialization
+         priority.  */
+      vtv_generate_init_routine (main_input_filename);
+    }
+
   timevar_stop (TV_PHASE_OPT_GEN);
   timevar_start (TV_PHASE_CHECK_DBGINFO);
 
Index: gcc/cp/config-lang.in
===================================================================
--- gcc/cp/config-lang.in	(revision 192503)
+++ gcc/cp/config-lang.in	(working copy)
@@ -30,4 +30,4 @@ compilers="cc1plus\$(exeext)"
 
 target_libs="target-libstdc++-v3"
 
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c"
Index: gcc/cp/vtable-class-hierarchy.c
===================================================================
--- gcc/cp/vtable-class-hierarchy.c	(revision 0)
+++ gcc/cp/vtable-class-hierarchy.c	(revision 0)
@@ -0,0 +1,918 @@
+/* Copyright (C) 2012  Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This file is part of the vtable security implementation.  It collects
+   class hierarchy information about the program being compiled and
+   inserts calls to __VLTRegisterPair, registering this information.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "intl.h"
+#include "c-family/c-pragma.h"
+#include "decl.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+#include "output.h"
+#include "target.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "tree-iterator.h"
+#include "tree-vtable-verify.h"
+#include "gimple.h"
+
+/* Need to mark this one specially since it needs to be stored in
+ * precompiled header IR */
+static GTY(()) tree vlt_saved_class_info = NULL_TREE;
+
+static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
+static GTY (()) tree vlt_change_permission_fndecl = NULL_TREE;
+
+struct work_node {
+  struct vtv_graph_node *node;
+  struct work_node *next;
+};
+
+static void init_functions (void);
+
+static int  guess_num_vtable_pointers (struct vtv_graph_node *);
+static bool register_all_pairs (tree body);
+static void add_hierarchy_pair (struct vtv_graph_node *,
+                                struct vtv_graph_node *);
+static struct vtv_graph_node *find_graph_node (tree);
+static struct vtv_graph_node *
+                  find_and_remove_next_leaf_node (struct work_node **worklist);
+static void create_undef_reference_to_vtv_init(tree register_pairs_body);
+static bool vtv_register_class_hierarchy_information
+                                                    (tree register_pairs_body);
+
+static void update_class_hierarchy_information (tree, tree);
+struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
+
+static void
+init_functions (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree register_pairs_type = void_type_node;
+  tree change_permission_type = void_type_node;
+#ifdef VTV_DEBUG
+  tree char_ptr_type = build_pointer_type (char_type_node);
+#endif
+
+  if (vlt_change_permission_fndecl != NULL_TREE)
+    return;
+
+  gcc_assert(vlt_register_pairs_fndecl == NULL_TREE);
+
+  arg_types = build_tree_list (NULL_TREE, integer_type_node);
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  change_permission_type = build_function_type (change_permission_type,
+                                                arg_types);
+  vlt_change_permission_fndecl = build_fn_decl ("__VLTChangePermission",
+                                                change_permission_type);
+  TREE_NOTHROW (vlt_change_permission_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_change_permission_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_change_permission_fndecl));
+  TREE_PUBLIC (vlt_change_permission_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_change_permission_fndecl) = 1;
+  retrofit_lang_decl (vlt_change_permission_fndecl);
+  SET_DECL_LANGUAGE (vlt_change_permission_fndecl, lang_cplusplus);
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+#ifdef VTV_DEBUG
+  /* Start: Arg types to be removed when we remove debugging parameters from
+     the library function. */
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  /* End: Arg types to be removed...*/
+#endif
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  register_pairs_type = build_function_type (register_pairs_type, arg_types);
+
+#ifdef VTV_DEBUG
+  vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPairDebug",
+                                             register_pairs_type);
+#else
+  vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPair",
+                                             register_pairs_type);
+#endif
+
+  TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
+  TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
+  retrofit_lang_decl (vlt_register_pairs_fndecl);
+  SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
+}
+
+static void
+add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
+                 sbitmap inserted)
+{
+  struct work_node *new_work_node;
+
+  if (TEST_BIT (inserted, node->class_uid))
+    return;
+
+  new_work_node = (struct work_node *) xmalloc (sizeof (struct work_node));
+  new_work_node->next = *worklist;
+  new_work_node->node = node;
+  *worklist = new_work_node;
+
+  SET_BIT (inserted, node->class_uid);
+}
+
+static struct vtv_graph_node *
+find_and_remove_next_leaf_node (struct work_node **worklist)
+{
+  struct work_node *prev, *cur;
+
+  for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+    {
+      if (cur->node->num_children == cur->node->num_processed_children)
+        {
+          if (prev == NULL)
+            (*worklist) = cur->next;
+          else
+            prev->next = cur->next;
+
+          cur->next = NULL;
+          return cur->node;
+        }
+    }
+
+  return NULL;
+}
+
+void
+vtv_compute_class_hierarchy_transitive_closure (void)
+{
+  struct work_node *worklist = NULL;
+  struct vtbl_map_node *cur;
+  sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+  unsigned i;
+
+  /* Note: Every node in the graph gets added to the worklist exactly
+   once and removed from the worklist exactly once (when all of its
+   children have been processed).  Each node's children edges are
+   followed exactly once, and each node's parent edges are followed
+   exactly once.  So this algorithm is roughly O(V + 2E), i.e.
+   O(E + V). */
+
+  /* Set-up:                                                                */
+  /* Find all the "leaf" nodes in the graph, and add them to the worklist.  */
+  sbitmap_zero (inserted);
+  for (cur = vtbl_map_nodes; cur; cur = cur->next)
+    {
+      if (cur->class_info
+          && (cur->class_info->num_children == 0)
+          && ! (TEST_BIT (inserted, cur->class_info->class_uid)))
+        add_to_worklist (&worklist, cur->class_info, inserted);
+    }
+
+
+  /* Main work: pull next leaf node off work list, process it, add its
+     parents to the worklist, where a 'leaf' node is one that has no
+     children, or all of its children have been processed. */
+  while (worklist)
+    {
+      struct vtv_graph_node *temp_node =
+                                  find_and_remove_next_leaf_node (&worklist);
+
+      gcc_assert (temp_node != NULL);
+      temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
+      sbitmap_zero (temp_node->descendants);
+      SET_BIT (temp_node->descendants, temp_node->class_uid);
+      for (i = 0; i < temp_node->num_children; ++i)
+        sbitmap_a_or_b (temp_node->descendants, temp_node->descendants,
+                        temp_node->children[i]->descendants);
+      for (i = 0; i < temp_node->num_parents; ++i)
+        {
+          temp_node->parents[i]->num_processed_children =
+                    temp_node->parents[i]->num_processed_children + 1;
+          if (!TEST_BIT (inserted, temp_node->parents[i]->class_uid))
+            add_to_worklist (&worklist, temp_node->parents[i], inserted);
+        }
+    }
+}
+
+/* Keep track of which pairs we have already created __VLTRegisterPair
+   calls for, to prevent creating duplicate calls within the same
+   compilation unit.  */
+
+static bool
+record_register_pairs (tree vtable_decl, tree vptr_address,
+                       tree base_class)
+{
+  unsigned offset;
+  tree base_id;
+  struct vtbl_map_node *base_vtable_map_node;
+
+  if (TREE_CODE (vptr_address) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
+    vptr_address = TREE_OPERAND (vptr_address, 0);
+
+  offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
+
+  if (TREE_CHAIN (base_class))
+    base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
+  else
+    base_id = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class));
+
+  base_vtable_map_node = vtbl_map_get_node (base_id);
+
+  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
+                                       offset))
+    return true;
+
+  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
+                                       offset);
+  return false;
+}
+
+static void
+register_vptr_fields (tree base_class_decl_arg, tree base_class,
+                      tree record_type, tree body)
+{
+  /* A class may contain secondary vtables in it, for various
+     reasons.  This function goes through the decl chain of a class
+     record looking for any fields that point to secondary vtables,
+     and adding calls to __VLTRegisterPair for the secondary vtable
+     pointers.  */
+
+  tree vtbl_var_decl;
+  tree arg1;
+  tree arg2;
+  int hint = 0;
+
+  if (TREE_CODE (record_type) != RECORD_TYPE)
+    return;
+
+  vtbl_var_decl = get_vtbl_decl_for_binfo (TYPE_BINFO (record_type));
+
+  if (vtbl_var_decl)
+    {
+      tree ztt_decl = DECL_CHAIN (vtbl_var_decl);
+      bool already_registered = false;
+
+      /* construction vtable */
+      if (ztt_decl != NULL_TREE
+          && (DECL_NAME (ztt_decl))
+          && (strncmp (IDENTIFIER_POINTER (DECL_NAME (ztt_decl)),
+                       "_ZTT", 4) == 0))
+        {
+          tree values = DECL_INITIAL (ztt_decl);
+          struct varpool_node * vp_node = varpool_node (ztt_decl);
+          if (vp_node->finalized
+              && TREE_ASM_WRITTEN (ztt_decl)
+              && (values != NULL_TREE)
+              && (TREE_CODE (values) == CONSTRUCTOR)
+              && (TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE))
+            {
+              tree call_expr = NULL_TREE;
+              unsigned HOST_WIDE_INT cnt;
+              constructor_elt *ce;
+
+              for (cnt = 0;
+                   VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (values),
+				cnt, ce);
+                   cnt++)
+                {
+                  tree value = ce->value;
+                  tree val_vtbl_decl = TREE_OPERAND (TREE_OPERAND (value, 0),
+                                                     0);
+                  int len1;
+                  int len2;
+
+                  if (TREE_CODE (val_vtbl_decl) == ADDR_EXPR
+                      && TREE_CODE (TREE_OPERAND (val_vtbl_decl, 0))
+                                                                   == VAR_DECL)
+                    val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
+
+                  gcc_assert (TREE_CODE (val_vtbl_decl) == VAR_DECL);
+
+                  len1 = strlen (IDENTIFIER_POINTER
+				     (DECL_NAME
+				          (TREE_OPERAND
+					     (base_class_decl_arg, 0))));
+                  len2 = strlen (IDENTIFIER_POINTER
+				     (DECL_NAME (val_vtbl_decl)));
+                  arg1 = build_string_literal (len1,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME
+						 (TREE_OPERAND
+						  (base_class_decl_arg, 0))));
+                  arg2 = build_string_literal (len2,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME (val_vtbl_decl)));
+
+                  already_registered = record_register_pairs (val_vtbl_decl,
+                                                              value,
+                                                              base_class);
+
+                  if (already_registered)
+                    continue;
+
+#ifdef VTV_DEBUG
+                  call_expr = build_call_expr
+		                        (vlt_register_pairs_fndecl, 7,
+					 base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint),
+					 arg1,
+					 build_int_cst (integer_type_node,
+							len1),
+					 arg2,
+					 build_int_cst (integer_type_node,
+							len2));
+#else
+                  call_expr = build_call_expr
+                                        (vlt_register_pairs_fndecl, 3,
+                                         base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint));
+#endif
+		  append_to_statement_list (call_expr, &body);
+                }
+            }
+        }
+    }
+}
+
+static void
+register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
+                              int len1, tree str2, int len2, tree base_class)
+{
+  unsigned ix;
+  tree base_binfo;
+  tree vtable_decl;
+  bool already_registered;
+  int hint = 0;
+
+  if (binfo == NULL_TREE)
+    return;
+
+  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+    {
+      if ((!BINFO_PRIMARY_P (base_binfo)
+           || BINFO_VIRTUAL_P (base_binfo))
+          && (vtable_decl=get_vtbl_decl_for_binfo (base_binfo))
+          && !(DECL_VTABLE_OR_VTT_P(vtable_decl)
+               && DECL_CONSTRUCTION_VTABLE_P(vtable_decl)))
+        {
+          tree vtable_address = build_vtbl_address (base_binfo);
+          tree call_expr;
+
+          already_registered = record_register_pairs (vtable_decl,
+                                                      vtable_address,
+                                                      base_class);
+          if (!already_registered)
+            {
+#ifdef VTV_DEBUG
+              call_expr = build_call_expr (vlt_register_pairs_fndecl, 7,
+                                           arg1, vtable_address,
+                                           build_int_cst (integer_type_node,
+                                                          hint),
+                                           str1,
+                                           build_int_cst (integer_type_node,
+                                                          len1),
+                                           str2,
+                                           build_int_cst (integer_type_node,
+                                                          len2));
+#else
+              call_expr = build_call_expr (vlt_register_pairs_fndecl, 3,
+                                           arg1, vtable_address,
+                                           build_int_cst (integer_type_node,
+                                                         hint));
+#endif
+
+              append_to_statement_list (call_expr, &body);
+            }
+        }
+
+      register_other_binfo_vtables (base_binfo, body, arg1, str1, len1, str2,
+                                    len2, base_class);
+    }
+}
+
+static int
+guess_num_vtable_pointers (struct vtv_graph_node *class_node)
+{
+  tree vtbl;
+  int total_num_vtbls = 0;
+  int num_vtbls_power_of_two = 1;
+  unsigned i;
+
+  for (i = 0; i < num_vtable_map_nodes; ++i)
+    if (TEST_BIT (class_node->descendants, i))
+      {
+        tree class_type = vtbl_map_nodes_array[i]->class_info->class_type;
+        for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
+             vtbl = DECL_CHAIN (vtbl))
+          {
+            total_num_vtbls ++;
+            if (total_num_vtbls > num_vtbls_power_of_two)
+              num_vtbls_power_of_two <<= 1;
+          }
+      }
+  return num_vtbls_power_of_two;
+}
+
+/* This function goes through our internal class hierarchy & vtable
+   pointer data structure and outputs calls to __VLTRegisterPair for
+   every class-vptr pair (for those classes whose vtable would be
+   output in the current compilation unit).  These calls get put into
+   our constructor initialization function.  */
+
+static bool
+register_all_pairs (tree body)
+{
+  struct vtbl_map_node *current;
+  tree base_ptr_var_decl;
+
+  bool registered_at_least_one = false;
+
+  for (current = vtbl_map_nodes; current; current = current->next)
+    {
+      unsigned i;
+      tree base_class = current->class_info->class_type;
+      int size_hint = guess_num_vtable_pointers (current->class_info);
+      base_ptr_var_decl = current->vtbl_map_decl;
+
+      gcc_assert (current->class_info != NULL);
+
+      for (i = 0; i < num_vtable_map_nodes; ++i)
+        if (TEST_BIT (current->class_info->descendants, i))
+          {
+            struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_array[i];
+            tree class_type = vtbl_class_node->class_info->class_type;
+
+            if (class_type
+                && (TREE_CODE (class_type) == RECORD_TYPE))
+            {
+              tree new_type;
+              tree arg1;
+              tree call_expr;
+              bool already_registered;
+
+              tree binfo = TYPE_BINFO (class_type);
+              tree vtable_decl;
+              bool vtable_should_be_output = false;
+
+              vtable_decl = CLASSTYPE_VTABLES (class_type);
+
+              /* Handle main vtable for this class. */
+
+              if (vtable_decl)
+                vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
+
+              if (vtable_decl && vtable_should_be_output
+                  && BINFO_VTABLE (binfo))
+                {
+                  tree vtable_address = build_vtbl_address (binfo);
+                  int len1  = IDENTIFIER_LENGTH
+                                               (DECL_NAME (base_ptr_var_decl));
+                  int len2  = IDENTIFIER_LENGTH (DECL_NAME (vtable_decl));
+                  tree str1 = build_string_literal (len1,
+                                                    IDENTIFIER_POINTER
+                                                    (DECL_NAME
+                                                     (base_ptr_var_decl)));
+                  tree str2 = build_string_literal (len2,
+                                                    IDENTIFIER_POINTER
+                                                    (DECL_NAME (vtable_decl)));
+
+                  already_registered = record_register_pairs (vtable_decl,
+                                                              vtable_address,
+                                                              base_class);
+
+                  if (!already_registered)
+                    {
+                      new_type = build_pointer_type (TREE_TYPE
+                                                     (base_ptr_var_decl));
+                      arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+#ifdef VTV_DEBUG
+                      /* This call expr has the 3 "real" arguments, plus 4
+                         debugging arguments.  Eventually it will be replaced
+                         with the one just below it, which only has the 2 real
+                         arguments.  */
+                      call_expr = build_call_expr
+                          (vlt_register_pairs_fndecl, 7,
+                           arg1, vtable_address,
+                           build_int_cst (integer_type_node, size_hint),
+                           str1, build_int_cst (integer_type_node,
+                                                len1),
+                           str2,  build_int_cst (integer_type_node,
+                                                 len2));
+#else
+                      call_expr = build_call_expr
+                          (vlt_register_pairs_fndecl, 3,
+                           arg1, vtable_address,
+                           build_int_cst (integer_type_node, size_hint));
+#endif
+                      append_to_statement_list (call_expr, &body);
+
+                      registered_at_least_one = true;
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via virtual inheritance.   */
+                      register_vptr_fields (arg1, base_class, class_type,
+                                            body);
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via multiple inheritance.   */
+                      register_other_binfo_vtables (binfo, body, arg1, str1,
+                                                    len1, str2, len2,
+                                                    base_class);
+                    }
+                }
+            }
+          }
+    }
+
+  return registered_at_least_one;
+}
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+  tree class_decl = TREE_CHAIN (class_type);
+  tree class_name_id;
+  struct vtbl_map_node *vtbl_node;
+
+  if (class_decl)
+    class_name_id = DECL_ASSEMBLER_NAME (class_decl);
+  else
+    class_name_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
+
+  vtbl_node = vtbl_map_get_node (class_name_id);
+
+  if (vtbl_node)
+    return vtbl_node->class_info;
+
+  return NULL;
+}
+
+static void
+add_edge_to_graph (struct vtv_graph_node ***edge_array, unsigned *num_entries,
+                   unsigned *max_entries, struct vtv_graph_node *new_entry)
+{
+  /* Check array size, and re-size it if necessary.  */
+  if (*num_entries >= ((*max_entries) - 1))
+    {
+      unsigned new_size = 2 * (*max_entries);
+      unsigned i;
+      *edge_array = (struct vtv_graph_node **)
+          xrealloc (*edge_array, new_size * sizeof (struct vtv_graph_node *));
+
+      for (i = *max_entries; i < new_size; ++i)
+        (*edge_array)[i] = NULL;
+      *max_entries = new_size;
+    }
+
+  (*edge_array)[*num_entries] = new_entry;
+  *num_entries = (*num_entries) + 1;
+}
+
+/* Add base class/derived class pair to our internal class hierarchy
+   data structure.  */
+
+static void
+add_hierarchy_pair (struct vtv_graph_node *base_node,
+                    struct vtv_graph_node *derived_node)
+{
+  add_edge_to_graph (&(base_node->children), &(base_node->num_children),
+                     &(base_node->max_children), derived_node);
+  add_edge_to_graph (&(derived_node->parents), &(derived_node->num_parents),
+                     &(derived_node->max_parents), base_node);
+}
+
+static void
+update_class_hierarchy_information (tree base_class,
+                                    tree derived_class)
+{
+  struct vtv_graph_node *base_node = find_graph_node (base_class);
+  struct vtv_graph_node *derived_node = find_graph_node (derived_class);
+
+  add_hierarchy_pair (base_node, derived_node);
+}
+
+/* Generate an undefined variable (a reference) to a varible defined in the
+   vtv_init libraty. In that way, if the a module is not linked with the
+   vtv_init library, the linker will generate an undefined symbol error.
+   Which is much better that getting a segmentation violation at runtime.
+
+   For more information, see comments in libstdc++-v3/libsupc++/vtv_init.cc */
+static void
+create_undef_reference_to_vtv_init(tree register_pairs_body)
+{
+  const char * vtv_init_undef_var = "__vtv_defined_in_vtv_init_lib";
+  tree var_decl;
+  tree init_zero;
+
+  var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                          get_identifier(vtv_init_undef_var),
+                          TREE_TYPE  (integer_zero_node));
+  TREE_PUBLIC (var_decl) = 1;
+  DECL_EXTERNAL (var_decl) = 1;
+  TREE_STATIC (var_decl) = 1;
+  SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier(vtv_init_undef_var));
+  DECL_ARTIFICIAL (var_decl) = 1;
+  TREE_READONLY (var_decl) = 0;
+  DECL_IGNORED_P (var_decl) = 1;
+  DECL_PRESERVE_P(var_decl) = 1;
+  varpool_finalize_decl (var_decl);
+
+  /* Store a value in the undefined variable to force the creation of a
+     a reference */
+  init_zero = build2(MODIFY_EXPR, TREE_TYPE(var_decl), var_decl,
+                     integer_zero_node);
+  append_to_statement_list (init_zero, &register_pairs_body);
+
+}
+
+bool
+vtv_register_class_hierarchy_information (tree register_pairs_body)
+{
+  bool registered_something = false;
+
+  init_functions ();
+
+  /* TODO: Temp fix. Needs to be tighten */
+  if (num_vtable_map_nodes == 0)
+    return registered_something;
+
+  /* Add class hierarchy pairs to the vtable map data structure. */
+  registered_something = register_all_pairs (register_pairs_body);
+
+  if (registered_something)
+  {
+      /* If this function is going into the preinit_array, then we
+         need to manually call __VLTChangePermission, rather than
+         depending on initialization prioritys in vtv_init. */
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          /* Pass __VLTP_READ_WRITE value as defined in vtv_rts.h */
+          tree arg_read_write = build_int_cst (integer_type_node, 1);
+          tree arg_read_only = build_int_cst (integer_type_node, 0);
+
+          tree call_rw_expr = build_call_expr (vlt_change_permission_fndecl,
+                                               1, arg_read_write);
+          tree_stmt_iterator i = tsi_start(register_pairs_body);
+          /* Insert at the beginning of the register pairs routine */
+          tsi_link_before(&i, call_rw_expr, TSI_SAME_STMT);
+
+          tree call_r_expr = build_call_expr (vlt_change_permission_fndecl,
+                                              1, arg_read_only);
+          append_to_statement_list (call_r_expr, &register_pairs_body);
+        }
+
+      if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
+        create_undef_reference_to_vtv_init(register_pairs_body);
+  }
+
+  return registered_something;
+}
+
+
+/* Generate the special constructor function that calls
+   __VLTChangePermission and __VLTRegisterPairs, and give it a very
+   high initialization priority.  */
+
+void
+vtv_generate_init_routine(const char * filename)
+{
+  const char * cwd = filename;
+  char temp_name[58];
+  tree register_pairs_body;
+  char * cptr;
+  int i;
+  bool vtable_classes_found = false;
+
+  /* The last part of the directory tree will be where it
+     differentiates; the first part may be the same. */
+  if (strlen (cwd) > 50)
+    {
+      int pos = (strlen (cwd) - 50);
+      cwd = cwd + pos;
+    }
+
+  /* TODO: Are these all the chars we need to map? */
+  sprintf (temp_name, "%.50s.vtable", cwd);
+  for (cptr = temp_name, i = 0;
+       (cptr[0] != '\0') && (i < 50);
+       cptr++, i++)
+    if ((cptr[0] == '/') || (cptr[0] == '-') || (cptr[0] == '+'))
+      cptr[0] = '_';
+
+  push_lang_context (lang_name_c);
+
+  /* The priority for this init function (constructor) is carefully
+     chosen so that it will happen after the calls to unprotect the
+     memory used for vtable verification and before the memory is
+     protected again */
+  register_pairs_body = start_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1,
+                                       (const char *) temp_name);
+
+  vtable_classes_found =
+      vtv_register_class_hierarchy_information (register_pairs_body);
+
+  if (vtable_classes_found)
+    {
+
+      current_function_decl =
+          finish_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1,
+                          register_pairs_body);
+      allocate_struct_function (current_function_decl, false);
+      TREE_STATIC (current_function_decl) = 1;
+      TREE_USED (current_function_decl) = 1;
+      DECL_PRESERVE_P (current_function_decl) = 1;
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          DECL_STATIC_CONSTRUCTOR (current_function_decl) = 0;
+          assemble_vtv_preinit_initializer (current_function_decl);
+        }
+
+      gimplify_function_tree (current_function_decl);
+      cgraph_add_new_function (current_function_decl, false);
+
+      cgraph_process_new_functions ();
+    }
+  pop_lang_context ();
+}
+
+struct vtbl_map_node *
+vtable_find_or_create_map_decl (tree base_type)
+{
+  tree base_decl = TREE_CHAIN (base_type);
+  tree base_id;
+  tree var_decl = NULL;
+  char *var_name = NULL;
+  struct vtbl_map_node *vtable_map_node = NULL;
+
+
+  /* Verify the type has an associated vtable */
+  if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
+    return NULL;
+
+  if (base_decl)
+    base_id = DECL_ASSEMBLER_NAME (base_decl);
+  else
+    base_id = DECL_ASSEMBLER_NAME (TYPE_NAME (base_type));
+
+  /* Create map lookup symbol for base class */
+  var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
+                       "E12__vtable_mapE", NULL));
+  if (base_id)
+    /* We've already created the variable; just look it.  */
+    vtable_map_node = vtbl_map_get_node (base_id);
+
+  if (!vtable_map_node || (vtable_map_node->vtbl_map_decl == NULL_TREE))
+    {
+      /* If we haven't already created the *__vtable_map
+         global variable for this class, do so now, and
+         add it to the varpool, to make sure it gets saved
+         and written out.  */
+
+      char *sect_name = NULL;
+      tree var_type = build_pointer_type (void_type_node);
+      tree initial_value = build_int_cst (make_node (INTEGER_TYPE), 0);
+
+      var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                              get_identifier (var_name),
+                              var_type);
+      TREE_PUBLIC (var_decl) = 1;
+      DECL_EXTERNAL (var_decl) = 0;
+      TREE_STATIC (var_decl) = 1;
+      SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
+      DECL_ARTIFICIAL (var_decl) = 1;
+      /* We cannot mark this variable as read-only otherwise the gold
+         linker will not put it in the relro section. It seems if it
+         is marked as read-only, gold will put it in the .text
+         segment.  */
+      TREE_READONLY (var_decl) = 0;
+      DECL_IGNORED_P (var_decl) = 1;
+
+      /* Put these mmap variables in to data.rel.ro sections.
+	 It turns out this needs a previous fix in binutils as
+	 explained here:
+         http://sourceware.org/ml/binutils/2011-05/msg00083.html  */
+
+      sect_name = ACONCAT ((".data.rel.ro.", "vtable_map_vars",
+                            NULL));
+      DECL_SECTION_NAME (var_decl) = build_string (strlen (sect_name),
+                                                   sect_name);
+      DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl) = true;
+      DECL_COMDAT_GROUP (var_decl) = get_identifier (var_name);
+      DECL_INITIAL (var_decl) = initial_value;
+
+      varpool_finalize_decl (var_decl);
+      if (!vtable_map_node)
+        vtable_map_node = find_or_create_vtbl_map_node (base_type);
+      if (vtable_map_node->vtbl_map_decl == NULL_TREE)
+        vtable_map_node->vtbl_map_decl = var_decl;
+    }
+
+  gcc_assert (vtable_map_node);
+  return vtable_map_node;
+}
+
+static void
+vtv_save_base_class_info (tree type)
+{
+  if (flag_vtable_verify)
+    {
+      tree binfo =  TYPE_BINFO (type);
+      tree base_binfo;
+      struct vtbl_map_node *own_map;
+      int i;
+
+      /* First make sure to create the map for this record type.  */
+      own_map = vtable_find_or_create_map_decl (type);
+      if (own_map == NULL)
+        return;
+
+      /* Go through the list of all base classes for the current (derived)
+         type, make sure the *__vtable_map global variable for the base class
+	 exists, and add the base class/derived class pair to the class
+	 hierarchy information we are accumulating (for vtable pointer
+	 verification).  */
+      for (i = 0; BINFO_BASE_ITERATE(binfo, i, base_binfo); i++)
+        {
+          tree tree_val = BINFO_TYPE(base_binfo);
+          struct vtbl_map_node *vtable_map_node = NULL;
+
+          vtable_map_node = vtable_find_or_create_map_decl (tree_val);
+
+          if (vtable_map_node != NULL)
+            update_class_hierarchy_information (tree_val, type);
+        }
+    }
+}
+
+void
+vtv_save_class_info (tree record)
+{
+  if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
+    return;
+
+  gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+  vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
+}
+
+
+void
+vtv_recover_class_info (void)
+{
+  tree current_class;
+  tree class_chain = vlt_saved_class_info;
+  while (class_chain != NULL_TREE)
+    {
+      current_class = TREE_VALUE (class_chain);
+      gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+
+      vtv_save_base_class_info (current_class);
+      class_chain = TREE_CHAIN (class_chain);
+    }
+
+  /* Let GC collect the memory associated to the chain */
+  vlt_saved_class_info = NULL_TREE;
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"

Property changes on: gcc/cp/vtable-class-hierarchy.c
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 192503)
+++ gcc/cp/mangle.c	(working copy)
@@ -3364,7 +3364,7 @@ mangle_decl_string (const tree decl)
 
 /* Return an identifier for the external mangled name of DECL.  */
 
-static tree
+tree
 get_mangled_id (tree decl)
 {
   tree id = mangle_decl_string (decl);
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 192503)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -5222,6 +5222,8 @@ extern void note_vague_linkage_fn		(tree
 extern tree build_artificial_parm		(tree, tree);
 extern bool possibly_inlined_p			(tree);
 extern int parm_index                           (tree);
+extern tree start_objects                       (int, int, const char *);
+extern tree finish_objects                      (int, int, tree);
 
 /* in error.c */
 extern void init_error				(void);
@@ -5309,6 +5311,7 @@ extern tree build_java_class_ref		(tree)
 extern tree integral_constant_value		(tree);
 extern tree decl_constant_value_safe	        (tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
+extern tree build_vtbl_address                  (tree);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
@@ -5535,6 +5538,11 @@ extern tree copied_binfo			(tree, tree);
 extern tree original_binfo			(tree, tree);
 extern int shared_member_p			(tree);
 
+/* in vtable-class-hierarchy.c */
+extern void vtv_compute_class_hierarchy_transitive_closure (void);
+extern void vtv_generate_init_routine           (const char *);
+extern void vtv_save_class_info                 (tree);
+extern void vtv_recover_class_info              (void);
 
 /* The representation of a deferred access check.  */
 
@@ -6017,6 +6025,7 @@ extern tree mangle_tls_init_fn			(tree);
 extern tree mangle_tls_wrapper_fn		(tree);
 extern bool decl_tls_wrapper_p			(tree);
 extern tree mangle_ref_init_variable		(tree);
+extern tree get_mangled_id                      (tree);
 
 /* in dump.c */
 extern bool cp_dump_tree			(void *, tree);
Index: gcc/timevar.def
===================================================================
--- gcc/timevar.def	(revision 192503)
+++ gcc/timevar.def	(working copy)
@@ -251,6 +251,7 @@ DEFTIMEVAR (TV_TREE_UNINIT           , "
 DEFTIMEVAR (TV_PLUGIN_INIT           , "plugin initialization")
 DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")
 DEFTIMEVAR (TV_GIMPLE_SLSR           , "straight-line strength reduction")
+DEFTIMEVAR (TV_VTABLE_VERIFICATION   , "tree vtable verification")
 
 /* Everything else in rest_of_compilation not included above.  */
 DEFTIMEVAR (TV_EARLY_LOCAL	     , "early local passes")
Index: gcc/flag-types.h
===================================================================
--- gcc/flag-types.h	(revision 192503)
+++ gcc/flag-types.h	(working copy)
@@ -200,4 +200,10 @@ enum fp_contract_mode {
   FP_CONTRACT_FAST = 2
 };
 
+/* flag_vtable_verify initialization levels. */
+enum vtv_priority {
+  VTV_NO_PRIORITY       = 0,  /* i.E. Do NOT do vtable verification. */
+  VTV_STANDARD_PRIORITY = 1,
+  VTV_PREINIT_PRIORITY  = 2
+};
 #endif /* ! GCC_FLAG_TYPES_H */
Index: gcc/tree-vtable-verify.c
===================================================================
--- gcc/tree-vtable-verify.c	(revision 0)
+++ gcc/tree-vtable-verify.c	(revision 0)
@@ -0,0 +1,1061 @@
+/*   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+/* Interprocedural constant propagation
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security Pass.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "cp/cp-tree.h"
+#include "tm_p.h"
+#include "basic-block.h"
+#include "output.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "flags.h"
+#include "tree-inline.h"
+#include "tree-scalar-evolution.h"
+#include "diagnostic-core.h"
+#include "gimple-pretty-print.h"
+#include "toplev.h"
+#include "langhooks.h"
+
+#include "tree-vtable-verify.h"
+
+unsigned num_vtable_map_nodes = 0;
+bool any_verification_calls_generated = false;
+
+static GTY(()) tree verify_vtbl_ptr_fndecl = NULL_TREE;
+
+unsigned int vtable_verify_main (void);
+static bool gate_tree_vtable_verify (void);
+static void build_vtable_verify_fndecl (void);
+static tree my_build1 (enum tree_code, tree, tree);
+
+bool
+vtbl_map_node_registration_find (struct vtbl_map_node *node,
+                                 tree vtable_decl,
+                                 unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+
+  gcc_assert (node);
+  gcc_assert (node->registered);
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, NO_INSERT);
+
+  if (slot && (*slot) && (*slot)->offsets)
+    {
+      unsigned i;
+      for (i = 0; i < (*slot)->cur_offset; ++i)
+        if ((*slot)->offsets[i] == offset)
+          return true;
+    }
+
+  return false;
+}
+
+void
+vtbl_map_node_registration_insert (struct vtbl_map_node *node,
+                                   tree vtable_decl,
+                                   unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+
+  if (!node || !(node->registered))
+    return;
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, INSERT);
+
+  if (!(*slot))
+    {
+      unsigned i;
+      struct vtable_registration *node;
+      node = (struct vtable_registration *)
+                                 xmalloc (sizeof (struct vtable_registration));
+      node->vtable_decl = vtable_decl;
+      node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));
+      for (i= 0; i < 10; ++i)
+        node->offsets[i] = 0;
+      node->offsets[0] = offset;
+      node->cur_offset = 1;
+      node->max_offsets = 10;
+      *slot = node;
+    }
+  else
+    {
+      /* We found the vtable_decl slot; we need to see if it already
+         contains the offset.  If not, we need to add the offset.  */
+      unsigned i;
+      bool found = false;
+      for (i = 0; (i < (*slot)->cur_offset) && !found; ++i)
+        if ((*slot)->offsets[i] == offset)
+          found = true;
+
+      if (!found)
+        {
+          if ((*slot)->cur_offset == (*slot)->max_offsets)
+            {
+              unsigned new_max = 2 * (*slot)->max_offsets;
+              (*slot)->offsets = (unsigned *)
+                  xrealloc ((*slot)->offsets, new_max * sizeof (unsigned));
+
+              for (i = (*slot)->max_offsets; i < new_max; ++i)
+                (*slot)->offsets[i] = 0;
+              (*slot)->max_offsets = new_max;
+            }
+          (*slot)->offsets[(*slot)->cur_offset] = offset;
+          (*slot)->cur_offset = (*slot)->cur_offset + 1;
+        }
+    }
+}
+
+/* Hashtable functions for vtable_registration hashtables.  */
+
+static hashval_t
+hash_vtable_registration (const void * p)
+{
+  const struct vtable_registration *n = (const struct vtable_registration *) p;
+  return (hashval_t) (DECL_UID (n->vtable_decl));
+}
+
+static int
+eq_vtable_registration (const void *p1, const void *p2)
+{
+  const struct vtable_registration *n1 =
+                                    (const struct vtable_registration *) p1;
+  const struct vtable_registration *n2 =
+                                    (const struct vtable_registration *) p2;
+  return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
+}
+
+/* End of hashtable functions for "registered" hashtables*/
+
+/* Hashtable functions for vtable_map variables hashtable.  */
+
+static htab_t vtbl_map_hash = NULL;
+struct vtbl_map_node *vtbl_map_nodes = NULL;
+struct vtbl_map_node **vtbl_map_nodes_array = NULL;
+
+static void
+vtable_map_array_insert (struct vtbl_map_node *node)
+{
+  static unsigned array_size = 0;
+  unsigned i;
+
+  if (vtbl_map_nodes_array == NULL
+      || array_size == 0)
+    {
+      array_size = 16;
+      vtbl_map_nodes_array = (struct vtbl_map_node **)
+                       xmalloc (array_size * sizeof (struct vtbl_map_node *));
+      memset (vtbl_map_nodes_array, 0,
+              array_size * sizeof (struct vtbl_map_node *));
+    }
+  else if (node->uid >= array_size)
+    {
+      unsigned new_size = 2 * array_size;
+      vtbl_map_nodes_array = (struct vtbl_map_node **)
+          xrealloc (vtbl_map_nodes_array,
+                    new_size * sizeof (struct vtbl_map_node *));
+
+      for (i = array_size; i < new_size; ++i)
+        vtbl_map_nodes_array[i] = NULL;
+
+      array_size = new_size;
+    }
+
+  gcc_assert (node->uid < array_size);
+  gcc_assert (vtbl_map_nodes_array[node->uid] == NULL);
+
+  vtbl_map_nodes_array[node->uid] = node;
+}
+
+/* Returns a hash code for P.  */
+static hashval_t
+hash_vtbl_map_node (const void *p)
+{
+  const struct vtbl_map_node *n = (const struct vtbl_map_node *) p;
+  return (hashval_t) IDENTIFIER_HASH_VALUE (n->class_name);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+static int
+eq_vtbl_map_node (const void *p1, const void *p2)
+{
+  const struct vtbl_map_node *n1 = (const struct vtbl_map_node *) p1;
+  const struct vtbl_map_node *n2 = (const struct vtbl_map_node *) p2;
+  return (IDENTIFIER_HASH_VALUE (n1->class_name) ==
+          IDENTIFIER_HASH_VALUE (n2->class_name));
+}
+
+/* Return vtbl_map node assigned to DECL without creating a new one.  */
+struct vtbl_map_node *
+vtbl_map_get_node (const_tree class_name)
+{
+  struct vtbl_map_node key;
+  struct vtbl_map_node **slot;
+
+  if (!vtbl_map_hash)
+    return NULL;
+
+  key.class_name = CONST_CAST2 (tree, const_tree, class_name);
+  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+                                                   NO_INSERT);
+  if (!slot)
+    return NULL;
+  return *slot;
+}
+
+/* Return vtbl_map node assigned to BASE_CLASS_TYPE.  Create new one
+   when needed.  */
+struct vtbl_map_node *
+find_or_create_vtbl_map_node (tree base_class_type)
+{
+  struct vtbl_map_node key;
+  struct vtbl_map_node *node;
+  struct vtbl_map_node **slot;
+  unsigned i;
+
+  if (!vtbl_map_hash)
+    vtbl_map_hash = htab_create (10, hash_vtbl_map_node,
+                                 eq_vtbl_map_node, NULL);
+
+  if (TREE_CHAIN (base_class_type))
+    key.class_name = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class_type));
+  else
+    key.class_name = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class_type));
+  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+                                                   INSERT);
+  if (*slot)
+    return *slot;
+
+  node = (struct vtbl_map_node *) xmalloc (sizeof (struct vtbl_map_node));
+  node->vtbl_map_decl = NULL_TREE;
+  node->class_name = key.class_name;
+  node->uid = num_vtable_map_nodes++;
+
+  node->class_info = (struct vtv_graph_node *)
+                                      xmalloc (sizeof (struct vtv_graph_node));
+  node->class_info->class_type = base_class_type;
+  node->class_info->class_uid = node->uid;
+  node->class_info->max_parents = 4;
+  node->class_info->max_children = 4;
+  node->class_info->num_parents = 0;
+  node->class_info->num_children = 0;
+  node->class_info->num_processed_children = 0;
+  node->class_info->parents = (struct vtv_graph_node **)
+                                xmalloc (4 * sizeof (struct vtv_graph_node *));
+  node->class_info->children = (struct vtv_graph_node **)
+                                xmalloc (4 * sizeof (struct vtv_graph_node *));
+  for (i = 0; i < 4; ++i)
+    {
+      node->class_info->parents[i] = NULL;
+      node->class_info->children[i] = NULL;
+    }
+
+  node->registered = htab_create (16, hash_vtable_registration,
+                                  eq_vtable_registration, NULL);
+  node->is_used = false;
+  node->next = vtbl_map_nodes;
+  if (vtbl_map_nodes)
+    vtbl_map_nodes->prev = node;
+
+  vtable_map_array_insert (node);
+
+  vtbl_map_nodes = node;
+  *slot = node;
+  return node;
+}
+
+/* End of hashtable functions for vtable_map variables hash table.   */
+
+static tree
+my_build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL)
+{
+  int length = sizeof (struct tree_exp);
+#ifdef GATHER_STATISTICS
+  tree_node_kind kind;
+#endif
+  tree t;
+
+#ifdef GATHER_STATISTICS
+  switch (TREE_CODE_CLASS (code))
+    {
+    case tcc_statement:  /* an expression with side effects */
+      kind = s_kind;
+      break;
+    case tcc_reference:  /* a reference */
+      kind = r_kind;
+      break;
+    default:
+      kind = e_kind;
+      break;
+    }
+
+  tree_node_counts[(int) kind]++;
+  tree_node_sizes[(int) kind] += length;
+#endif
+
+  gcc_assert (TREE_CODE_LENGTH (code) == 1);
+
+  t = ggc_alloc_zone_tree_node_stat (&tree_zone, length PASS_MEM_STAT);
+
+  memset (t, 0, sizeof (struct tree_common));
+
+  TREE_SET_CODE (t, code);
+
+  TREE_TYPE (t) = type;
+  SET_EXPR_LOCATION (t, UNKNOWN_LOCATION);
+  TREE_OPERAND (t, 0) = node;
+  if (node && !TYPE_P (node))
+    {
+      TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node);
+      TREE_READONLY (t) = TREE_READONLY (node);
+    }
+
+  if (TREE_CODE_CLASS (code) == tcc_statement)
+    TREE_SIDE_EFFECTS (t) = 1;
+  else switch (code)
+    {
+    case VA_ARG_EXPR:
+      /* All of these have side-effects, no matter what their
+         operands are.  */
+      TREE_SIDE_EFFECTS (t) = 1;
+      TREE_READONLY (t) = 0;
+      break;
+
+    case INDIRECT_REF:
+      /* Whether a dereference is readonly has nothing to do with whether
+         its operand is readonly.  */
+      TREE_READONLY (t) = 0;
+      break;
+
+    case ADDR_EXPR:
+      if (node)
+        recompute_tree_invariant_for_addr_expr (t);
+      break;
+
+    default:
+      if ((TREE_CODE_CLASS (code) == tcc_unary || code == VIEW_CONVERT_EXPR)
+          && node && !TYPE_P (node)
+          && TREE_CONSTANT (node))
+        TREE_CONSTANT (t) = 1;
+      if (TREE_CODE_CLASS (code) == tcc_reference
+          && node && TREE_THIS_VOLATILE (node))
+        TREE_THIS_VOLATILE (t) = 1;
+      break;
+    }
+
+  return t;
+}
+
+static int
+type_name_is_vtable_pointer (tree node)
+{
+
+  if (TYPE_NAME (node))
+  {
+    if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
+      return (strcmp (IDENTIFIER_POINTER (TYPE_NAME (node)),
+                      "__vtbl_ptr_type") == 0);
+    else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
+             && DECL_NAME (TYPE_NAME (node)))
+      return (strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
+                      "__vtbl_ptr_type") == 0);
+    else
+      return 0;
+  }
+
+  return 0;
+}
+
+static int
+is_vtable_assignment_stmt (gimple stmt)
+{
+
+  if (gimple_code (stmt) != GIMPLE_ASSIGN)
+    return 0;
+  else
+    {
+      tree lhs = gimple_assign_lhs (stmt);
+      tree rhs = gimple_assign_rhs1 (stmt);
+
+      if (TREE_CODE (lhs) != SSA_NAME)
+        return 0;
+
+      if (TREE_CODE (TREE_TYPE (lhs)) != POINTER_TYPE)
+        return 0;
+
+      if (TREE_CODE (TREE_TYPE (TREE_TYPE (lhs))) != POINTER_TYPE)
+        return 0;
+
+      if (! type_name_is_vtable_pointer (TREE_TYPE (TREE_TYPE (lhs))))
+        return 0;
+
+
+      if (TREE_CODE (rhs) != COMPONENT_REF)
+        return 0;
+
+      if (! (TREE_OPERAND (rhs, 1))
+          || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
+        return 0;
+
+      if (! (DECL_NAME (TREE_OPERAND (rhs, 1)))
+          || (strncmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (rhs, 1))),
+                       "_vptr.", 6) != 0))
+        return 0;
+
+      while ((TREE_OPERAND (rhs, 0))
+             && (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF))
+        rhs = TREE_OPERAND (rhs, 0);
+
+      if (! (TREE_OPERAND (rhs, 0))
+          || (TREE_CODE (TREE_OPERAND (rhs, 0)) != MEM_REF))
+        return 0;
+    }
+
+    return 1;
+}
+
+static tree
+my_get_vtbl_decl_for_binfo (tree binfo)
+{
+  tree decl;
+
+  decl = BINFO_VTABLE (binfo);
+  if (decl && TREE_CODE (decl) == POINTER_PLUS_EXPR)
+  {
+    gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR);
+    decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+  }
+  if (decl)
+    gcc_assert (TREE_CODE (decl) == VAR_DECL);
+
+  return decl;
+}
+
+/* STMT is a gimple statment that uses OLD_VAR.  This function finds the
+   use of OLD_VAR in STMT and replaces it with NEW_VAR.  STMT is either
+   an assignment statement or a call statement.  */
+
+static bool
+find_and_replace_var (gimple stmt, tree old_var, tree new_var)
+{
+  bool found = false;
+
+  if (!stmt || ! old_var || !new_var)
+    return found;
+
+  if ((TREE_CODE (old_var) != SSA_NAME)
+      || (TREE_CODE (new_var) != SSA_NAME))
+    return found;
+
+  if (gimple_code (stmt) == GIMPLE_ASSIGN)
+    {
+      if (get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS)
+        {
+          if (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+              && (gimple_assign_rhs1 (stmt) == old_var))
+            {
+              gimple_assign_set_rhs1 (stmt, new_var);
+              found = true;
+            }
+          else if (TREE_CODE (gimple_assign_rhs1 (stmt)) == MEM_REF
+                   && TREE_CODE (TREE_OPERAND (gimple_assign_rhs1 (stmt), 0))
+                                                                   == SSA_NAME)
+            {
+              if (TREE_OPERAND (gimple_assign_rhs1 (stmt), 0) == old_var)
+                {
+                  tree mr_type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+                  tree mem_ref = build2 (MEM_REF, mr_type, new_var,
+                                         TREE_OPERAND
+                                               (gimple_assign_rhs1 (stmt), 1));
+                  gimple_assign_set_rhs1 (stmt, mem_ref);
+                  found = true;
+                }
+            }
+        }
+      else if (get_gimple_rhs_class (gimple_expr_code (stmt))
+                                                          != GIMPLE_SINGLE_RHS)
+        {
+          if (gimple_assign_rhs1 (stmt) == old_var)
+            {
+              gimple_assign_set_rhs1 (stmt, new_var);
+              found = true;
+            }
+          else if (gimple_assign_rhs2 (stmt) == old_var)
+            {
+              gimple_assign_set_rhs2 (stmt, new_var);
+              found = true;
+            }
+        }
+    }
+  else if ((gimple_code (stmt) == GIMPLE_CALL)
+           && (TREE_CODE (gimple_call_fn (stmt)) == OBJ_TYPE_REF)
+           && (TREE_OPERAND (gimple_call_fn (stmt), 0) == old_var))
+    {
+        TREE_OPERAND (gimple_call_fn (stmt), 0) = new_var;
+        found = true;
+    }
+
+  if (found)
+    update_stmt (stmt);
+
+  return found;
+}
+
+/* Given a PHI_STMT, this function searches backwards find a def_stmt for
+   one of the PHI_STMT's args, which defines an SSA_NAME.  It returns the
+   def_stmt.  */
+
+static gimple
+get_phi_def_stmt (gimple phi_stmt)
+{
+  /* This function is based on the assumption that all arguments of a
+     phi variable are really variations of the same variable, and
+     therefore must have the same type, so it doesn't matter which phi
+     argument we use to find the variable's type.  Therefore we will
+     use the first argument that is an SSA_NAME.  */
+
+  phi_arg_d *phi_arg = NULL;
+  tree phi_ssa;
+  unsigned i;
+
+  if (gimple_code (phi_stmt) != GIMPLE_PHI)
+    return NULL;
+
+  for (i = 0; i < gimple_phi_num_args (phi_stmt); i++)
+    {
+      phi_arg = gimple_phi_arg (phi_stmt, i);
+      phi_ssa = phi_arg->def;
+      if (TREE_CODE (phi_ssa) == SSA_NAME)
+	break;
+    }
+
+  gcc_assert (TREE_CODE (phi_ssa) == SSA_NAME);
+
+  return SSA_NAME_DEF_STMT (phi_ssa);
+}
+
+/* Search through all the statements in a basic block, searching for
+   virtual method calls.  For each virtual method dispatch, find the
+   vptr value used, and the statically declared type of the object;
+   retrieve the vtable map variable for the type of the object;
+   generate a call to __VLTVerifyVtablePointer; and insert the
+   generated call into the basic block, after the point where the vptr
+   value is gotten out of the object and before the virtual method
+   dispatch. Make the virtual method dispatch depend on the return
+   value from the verification call, so that subsequent optimizations
+   cannot reorder the two calls.  */
+
+static void
+verify_bb_vtables (basic_block bb)
+{
+  gimple_seq stmts;
+  gimple stmt = NULL;
+  gimple_stmt_iterator gsi_vtbl_assign;
+  gimple_stmt_iterator gsi_virtual_call;
+  tree this_object;
+
+  /* Search the basic block to see if it contains a virtual method
+     call, i.e. a call with the tree code OBJ_TYPE_REF  */
+
+  stmts = bb_seq (bb);
+  gsi_virtual_call = gsi_start (stmts);
+  this_object = NULL_TREE;
+  for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
+    {
+      stmt = gsi_stmt (gsi_virtual_call);
+      if (gimple_code (stmt) == GIMPLE_CALL)
+        {
+          tree fncall = gimple_call_fn (stmt);
+          if (TREE_CODE (fncall) == OBJ_TYPE_REF)
+            {
+              bool found = false;
+              tree vtable_offset_var = NULL_TREE;
+              gimple def_stmt;
+              gimple prev_use = NULL;
+
+              /* The first argument to the function must be "this", a pointer
+                 to the object itself.  */
+
+              this_object = gimple_call_arg (stmt, 0);
+
+              /* Get the SSA variable that contains the dereferenced _vptr
+                 field + table start offset.  */
+
+              if (TREE_OPERAND (fncall, 0)
+                  && TREE_CODE (TREE_OPERAND (fncall, 0)) == SSA_NAME)
+                {
+                  tree rhs = NULL_TREE;
+                  gimple phi_stmt = NULL;
+                  gimple phi_prev_use = NULL;
+                  bool  found_phi = false;
+
+                  vtable_offset_var = TREE_OPERAND (fncall, 0);
+
+                  prev_use = stmt;
+                  def_stmt = SSA_NAME_DEF_STMT (vtable_offset_var);
+
+		  /* Search backwards through the def_stmt chain, to try
+		     to find the assignment statement where the rhs of
+		     the assignment contains the "._vptr" field (the vtable
+		     pointer). */
+
+                  while (gimple_code (def_stmt) == GIMPLE_PHI)
+                    {
+                      if (!found_phi)
+                        {
+                          phi_prev_use = prev_use;
+                          phi_stmt = def_stmt;
+                          found_phi = true;
+                        }
+                      def_stmt = get_phi_def_stmt (def_stmt);
+                    }
+
+                  gcc_assert (def_stmt != NULL);
+                  gcc_assert (gimple_code (def_stmt) == GIMPLE_ASSIGN);
+
+                  if (gimple_assign_lhs (def_stmt)
+                      && TREE_CODE (gimple_assign_lhs (def_stmt)) == SSA_NAME
+                      && get_gimple_rhs_class (gimple_expr_code (def_stmt))
+                                                          == GIMPLE_SINGLE_RHS)
+                    rhs = gimple_assign_rhs1 (def_stmt);
+
+                  if (rhs
+                      && TREE_CODE (rhs) == MEM_REF
+                      && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
+                    {
+                      prev_use = def_stmt;
+                      def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
+                    }
+
+
+                  if (gimple_code (def_stmt) == GIMPLE_PHI)
+                    {
+                      if (!found_phi)
+                        {
+                          phi_prev_use = prev_use;
+                          phi_stmt = def_stmt;
+                          found_phi = true;
+                        }
+                      def_stmt = get_phi_def_stmt (def_stmt);
+                    }
+
+                  while (def_stmt
+                         && !is_vtable_assignment_stmt (def_stmt))
+                    {
+                      tree lhs = gimple_assign_lhs (def_stmt);
+                      if (!lhs
+                          || !TREE_CODE (lhs) == SSA_NAME)
+                        {
+                          def_stmt = NULL;
+                          break;
+                        }
+                      if (! def_stmt)
+                        break;
+
+                      if (gimple_assign_rhs1 (def_stmt)
+                          && TREE_CODE (gimple_assign_rhs1 (def_stmt))
+                                                                   == SSA_NAME)
+                        {
+                          prev_use = def_stmt;
+                          rhs = gimple_assign_rhs1 (def_stmt);
+                          def_stmt = SSA_NAME_DEF_STMT (rhs);
+                        }
+                      else if ((get_gimple_rhs_class
+                                  (gimple_expr_code (def_stmt))
+			                                  != GIMPLE_SINGLE_RHS)
+                               && gimple_assign_rhs2 (def_stmt)
+                               && TREE_CODE (gimple_assign_rhs2 (def_stmt))
+                                                                   == SSA_NAME)
+                        {
+                          prev_use = def_stmt;
+                          rhs = gimple_assign_rhs2 (def_stmt);
+                          def_stmt = SSA_NAME_DEF_STMT (rhs);
+                        }
+                      else
+                        def_stmt = NULL;
+
+                      if (!def_stmt)
+                        break;
+
+                      if (def_stmt != NULL
+                          && gimple_code (def_stmt) == GIMPLE_PHI)
+                        {
+                          if (!found_phi)
+                            {
+                              phi_prev_use = prev_use;
+                              phi_stmt = def_stmt;
+                              found_phi = true;
+                            }
+                          def_stmt = get_phi_def_stmt (def_stmt);
+                        }
+                    }
+
+		  /* If we found the vtable pointer assignment statement by
+		     itself, we also need to find it within the basic block
+		     statement sequence, so that we can insert our statements
+		     into the sequence.
+
+		     The following loop looks for the assignment statement
+		     within the basic block's sequence of statements.  */
+
+                  if (def_stmt
+                      && is_vtable_assignment_stmt (def_stmt))
+                    {
+                      basic_block def_bb;
+                      gimple_seq def_bb_stmts;
+
+                      if (found_phi)
+                        def_bb = gimple_bb (phi_stmt);
+                      else
+                        def_bb = gimple_bb (def_stmt);
+
+                      def_bb_stmts = bb_seq (def_bb);
+
+                      if (found_phi)
+                        {
+                          /* Insertion point is first stmt in bb */
+                          gsi_vtbl_assign = gsi_after_labels (def_bb);
+                          found = true;
+                        }
+                      else
+                        gsi_vtbl_assign = gsi_start (def_bb_stmts);
+
+                      for (; !gsi_end_p (gsi_vtbl_assign) && !found;
+                           gsi_next (&gsi_vtbl_assign))
+                        {
+                          stmt = gsi_stmt (gsi_vtbl_assign);
+                          if (stmt == def_stmt)
+                            {
+                              found = true;
+                              break;
+                            }
+                        }
+
+                      if (found)
+                        {
+                          tree object_rhs = TREE_TYPE (this_object);
+                          tree lhs;
+                          tree vtbl_var_decl = NULL_TREE;
+                          tree vtbl = NULL_TREE;
+                          tree var_id;
+                          gimple_seq pre_p = NULL;
+                          struct vtbl_map_node *vtable_map_node = NULL;
+                          tree vtbl_decl = NULL_TREE;
+
+
+                          if (found_phi)
+                            lhs = gimple_phi_result (phi_stmt);
+                          else
+                            lhs = gimple_assign_lhs (stmt);
+
+                          /* Now we have found the virtual method dispatch
+                             and the preceding access of the _vptr.*
+                             field... Now we need to find the vtable for
+                             the base class (statically declared type) of
+                             the object, so we can use the right vtable
+			     map variable.  */
+
+                          found = true;
+                          rhs = gimple_assign_rhs1 (def_stmt);
+
+			  /* First try to get the type out of the 'this'
+			     object. */
+                          if (TREE_CODE (object_rhs) == POINTER_TYPE
+                              && TREE_CODE (TREE_TYPE (object_rhs))
+                                                                == RECORD_TYPE)
+                            rhs = TREE_TYPE (object_rhs);
+                          else if (TREE_CODE (object_rhs) == REFERENCE_TYPE
+                                   && TREE_CODE (TREE_TYPE (object_rhs))
+                                                                == RECORD_TYPE)
+                            rhs = TREE_TYPE (object_rhs);
+			  /* The type of the 'this' object is not usable
+			     (usually due to optimizations); try to get the
+			     type out of the rhs of the vtable pointer
+			     assignment statement.  */
+                          else if (TREE_CODE (rhs) == COMPONENT_REF)
+                            {
+                              while (TREE_CODE (TREE_OPERAND (rhs, 0))
+                                                              == COMPONENT_REF)
+                                rhs = TREE_OPERAND (rhs, 0);
+                              if (TREE_CODE (rhs) == COMPONENT_REF
+                                  && (TREE_CODE (TREE_OPERAND (rhs, 0))
+                                                                    == MEM_REF)
+                                  && (TREE_CODE (TREE_TYPE
+                                       (TREE_OPERAND (rhs, 0)))
+                                                               == RECORD_TYPE))
+                                rhs = TREE_TYPE (TREE_OPERAND (rhs, 0));
+                              else
+                                rhs = NULL_TREE;
+                            }
+                          else
+                            rhs = NULL_TREE;
+
+			  /* Make sure we found a valid type...*/
+                          if (rhs
+                              && TREE_CODE (rhs) == RECORD_TYPE
+                              && TYPE_BINFO (rhs))
+                            {
+			      /* Get the vtable for the type.  */
+                              vtbl_var_decl = my_get_vtbl_decl_for_binfo
+                                                            (TYPE_BINFO (rhs));
+                              vtbl = BINFO_VTABLE (TYPE_BINFO (rhs));
+
+                              if (!vtbl_var_decl || !vtbl)
+                                /* Problem:  This does NOT end up checking
+                                   virtual functions if there is NO
+                                   inheritance involved.  */
+                                continue;
+
+                              vtbl_decl = vtbl_var_decl;
+
+                              if (TREE_CODE (TREE_TYPE (vtbl)) == POINTER_TYPE)
+                                force_gimple_operand (vtbl, &pre_p, 1, NULL);
+
+                             if (TREE_CHAIN (rhs))
+                                var_id = DECL_ASSEMBLER_NAME (TREE_CHAIN
+                                                                        (rhs));
+                              else
+                                var_id = DECL_ASSEMBLER_NAME (TYPE_NAME (rhs));
+
+                              vtable_map_node = vtbl_map_get_node (var_id);
+                              if (vtable_map_node)
+                                {
+                                  vtbl_var_decl =
+                                                vtable_map_node->vtbl_map_decl;
+                                  vtable_map_node->is_used = true;
+                                }
+                              else
+                                vtbl_var_decl = NULL;
+                            }
+
+                          /* Build  verify_vtbl_ptr_fndecl */
+
+                          build_vtable_verify_fndecl ();
+
+                          /* Given the vtable pointer for the base
+                             class of the object, build the call to
+                             __VLTVerifyVtablePointer to verify that
+                             the object's vtable pointer (contained in
+                             lhs) is in the set of valid vtable
+                             pointers for the base class.  */
+
+                          if (verify_vtbl_ptr_fndecl && vtbl_var_decl)
+                            {
+                              tree expr_tree = NULL_TREE;
+                              struct gimplify_ctx gctx;
+                              const char *vtable_name = "<unknown>";
+                              gimple call_stmt;
+                              gimple assign_stmt;
+                              tree tmp0;
+                              bool status;
+
+                              int len1 = 0;
+                              int len2 = 0;
+
+                              if (TREE_CODE (vtbl_decl) == VAR_DECL)
+                                vtable_name = IDENTIFIER_POINTER
+                                                       (DECL_NAME (vtbl_decl));
+
+                              push_gimplify_context (&gctx);
+                              len1 = strlen (IDENTIFIER_POINTER
+				                  (DECL_NAME (vtbl_var_decl)));
+                              len2 = strlen (vtable_name);
+
+                              /* Call different routines if we are
+                                 interested in trace information to
+                                 triage problems */
+#ifdef VTV_DEBUG
+                              expr_tree = build_call_expr
+			             (verify_vtbl_ptr_fndecl, 6,
+				      my_build1 (ADDR_EXPR,
+						 TYPE_POINTER_TO
+						   (TREE_TYPE (vtbl_var_decl)),
+                                                 vtbl_var_decl),
+				      lhs,
+				      build_string_literal
+				                  (len1,
+						   IDENTIFIER_POINTER
+						       (DECL_NAME
+							    (vtbl_var_decl))),
+				      build_int_cst (integer_type_node,
+						     len1),
+				      build_string_literal (len2, vtable_name),
+				      build_int_cst (integer_type_node,
+						     len2));
+#else
+                              expr_tree = build_call_expr
+		                     (verify_vtbl_ptr_fndecl, 2,
+				      my_build1 (ADDR_EXPR,
+				                 TYPE_POINTER_TO
+                                                   (TREE_TYPE (vtbl_var_decl)),
+                                                 vtbl_var_decl),
+                                      lhs);
+#endif
+
+                              /* Assign the result of the call to the
+                                 original variable receiving the
+                                 assignment of the object's vtable
+                                 pointer; mark that variable to be
+                                 updated by update_ssa.  */
+
+			      cfun->gimple_df->ssa_renaming_needed = 1;
+
+                              /* Insert the new call just after the
+                                 original assignment of the object's
+                                 vtable pointer.  */
+
+                              tmp0 = make_temp_ssa_name (TREE_TYPE (lhs),
+                                                         NULL, "VTV");
+                              assign_stmt = gimplify_assign (tmp0, expr_tree,
+                                                             &pre_p);
+
+                              if (found_phi)
+                                prev_use = phi_prev_use;
+
+                              status = find_and_replace_var (prev_use, lhs,
+                                                             tmp0);
+                              update_stmt (assign_stmt);
+                              gcc_assert (status == true);
+                              pop_gimplify_context (NULL);
+
+                              if (found_phi)
+                                gsi_insert_seq_before (&gsi_vtbl_assign,
+                                                       pre_p, GSI_NEW_STMT);
+                              else
+                                gsi_insert_seq_after (&gsi_vtbl_assign, pre_p,
+                                                      GSI_NEW_STMT);
+                              any_verification_calls_generated = true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+static void
+build_vtable_verify_fndecl (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree type = build_pointer_type (void_type_node);
+  struct lang_decl *ld;
+#ifdef VTV_DEBUG
+  tree char_ptr_type = build_pointer_type (char_type_node);
+#endif
+
+  if (verify_vtbl_ptr_fndecl != NULL_TREE)
+    return;
+
+  ld = ggc_alloc_cleared_lang_decl (sizeof (struct lang_decl_fn));
+  ld->u.base.selector = 1;
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_ptr_type));
+
+#ifdef VTV_DEBUG
+  /* Start: Arg types to be removed when we remove debugging parameters from
+     the library function. */
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  /* End: Arg types to be removed...*/
+#endif
+
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  type = build_function_type (type, arg_types);
+
+#ifdef VTV_DEBUG
+  verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointerDebug",
+                                          type);
+#else
+  verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointer", type);
+#endif
+
+  TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
+  DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
+      = tree_cons (get_identifier ("leaf"), NULL,
+                   DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
+  TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
+  DECL_PRESERVE_P (verify_vtbl_ptr_fndecl) = 1;
+  DECL_LANG_SPECIFIC (verify_vtbl_ptr_fndecl) = ld;
+  SET_DECL_LANGUAGE (verify_vtbl_ptr_fndecl, lang_cplusplus);
+}
+
+unsigned int
+vtable_verify_main (void)
+{
+  unsigned int ret = 1;
+  basic_block bb;
+
+  FOR_ALL_BB (bb)
+      verify_bb_vtables (bb);
+
+  return ret;
+}
+
+static bool
+gate_tree_vtable_verify (void)
+{
+  return (flag_vtable_verify
+          && (strcmp (lang_hooks.name, "GNU C++") == 0));
+}
+
+struct gimple_opt_pass pass_vtable_verify =
+{
+ {
+  GIMPLE_PASS,
+  "vtable-verify",                      /* name */
+  gate_tree_vtable_verify,              /* gate */
+  vtable_verify_main,                   /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_VTABLE_VERIFICATION,               /* tv_id */
+  PROP_cfg | PROP_ssa,                  /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_update_ssa
+    | TODO_ggc_collect                  /* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-vtable-verify.h"

Property changes on: gcc/tree-vtable-verify.c
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: gcc/tree-vtable-verify.h
===================================================================
--- gcc/tree-vtable-verify.h	(revision 0)
+++ gcc/tree-vtable-verify.h	(revision 0)
@@ -0,0 +1,81 @@
+/* Interprocedural constant propagation
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security.  */
+
+#ifndef TREE_VTABLE_VERIFY_H
+#define TREE_VTABLE_VERIFY_H
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "hashtab.h"
+#include "sbitmap.h"
+
+extern unsigned num_vtable_map_nodes;
+extern bool any_verification_calls_generated;
+
+struct vtable_registration
+{
+  tree vtable_decl;
+  unsigned max_offsets;
+  unsigned cur_offset;
+  unsigned *offsets;
+};
+
+struct vtv_graph_node {
+  tree class_type;
+  unsigned class_uid;
+  unsigned max_parents;
+  unsigned max_children;
+  unsigned num_parents;
+  unsigned num_children;
+  unsigned num_processed_children;
+  struct vtv_graph_node **parents;
+  struct vtv_graph_node **children;
+  sbitmap descendants;
+};
+
+struct vtbl_map_node {
+  tree vtbl_map_decl;
+  tree class_name;
+  struct vtv_graph_node *class_info;
+  unsigned uid;
+  struct vtbl_map_node *next, *prev;
+  htab_t registered;
+  bool is_used;
+};
+
+extern struct vtbl_map_node *vtbl_map_nodes;
+extern struct vtbl_map_node **vtbl_map_nodes_array;
+
+extern struct vtbl_map_node *vtbl_map_get_node (const_tree);
+extern struct vtbl_map_node *find_or_create_vtbl_map_node (tree);
+extern void vtbl_map_node_class_insert (struct vtbl_map_node *, unsigned);
+extern bool vtbl_map_node_registration_find (struct vtbl_map_node *,
+                                             tree, unsigned);
+extern void vtbl_map_node_registration_insert (struct vtbl_map_node *,
+                                               tree, unsigned);
+
+#endif /* TREE_VTABLE_VERIFY_H */

Property changes on: gcc/tree-vtable-verify.h
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 192503)
+++ gcc/common.opt	(working copy)
@@ -2253,6 +2253,22 @@ Enum(symbol_visibility) String(hidden) V
 EnumValue
 Enum(symbol_visibility) String(protected) Value(VISIBILITY_PROTECTED)
 
+fvtable-verify=
+Common Joined RejectNegative Enum(vtv_priority) Var(flag_vtable_verify) Init(VTV_NO_PRIORITY)
+Validate vtable pointers before using them.
+
+Enum
+Name(vtv_priority) Type(enum vtv_priority) UnknownError(unknown vtable verify initialization priority %qs)
+
+EnumValue
+Enum(vtv_priority) String(none) Value(VTV_NO_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(std) Value(VTV_STANDARD_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(preinit) Value(VTV_PREINIT_PRIORITY)
+
 fvpt
 Common Report Var(flag_value_profile_transformations) Optimization
 Use expression value profiles in optimizations
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 192503)
+++ gcc/varasm.c	(working copy)
@@ -2018,13 +2018,44 @@ assemble_variable (tree decl, int top_le
     assemble_noswitch_variable (decl, name, sect);
   else
     {
-      switch_to_section (sect);
+      if (flag_vtable_verify)
+        {
+          if (strstr (name, "__vtable_map"))
+            {
+#if defined (OBJECT_FORMAT_ELF)
+              targetm.asm_out.named_section (sect->named.name,
+					     sect->named.common.flags
+					     | SECTION_LINKONCE,
+					     DECL_NAME (decl));
+              in_section = sect;
+#else
+              switch_to_section (sect);
+#endif
+            }
+          else
+            switch_to_section (sect);
+        }
+      else
+        switch_to_section (sect);
       if (DECL_ALIGN (decl) > BITS_PER_UNIT)
 	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
       assemble_variable_contents (decl, name, dont_output_data);
     }
 }
 
+void
+assemble_vtv_preinit_initializer (tree fn_decl)
+{
+  section *sect;
+  unsigned flags = SECTION_WRITE;
+  rtx symbol = XEXP (DECL_RTL (fn_decl), 0);
+
+  flags |= SECTION_NOTYPE;
+  sect = get_section (".preinit_array", flags, fn_decl);
+  switch_to_section (sect);
+  assemble_addr_to_section (symbol, sect);
+}
+
 /* Return 1 if type TYPE contains any pointers.  */
 
 static int
Index: gcc/output.h
===================================================================
--- gcc/output.h	(revision 192503)
+++ gcc/output.h	(working copy)
@@ -199,6 +199,10 @@ extern void assemble_end_function (tree,
    initial value (that will be done by the caller).  */
 extern void assemble_variable (tree, int, int, int);
 
+/* Make sure the vtable verification constructor initialization function
+   goes into the preinit array.  */
+extern void assemble_vtv_preinit_initializer (tree);
+
 /* Compute the alignment of variable specified by DECL.
    DONT_OUTPUT_DATA is from assemble_variable.  */
 extern void align_variable (tree decl, bool dont_output_data);
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 192503)
+++ gcc/Makefile.in	(working copy)
@@ -1424,6 +1424,7 @@ OBJS = \
 	tree-vect-loop-manip.o \
 	tree-vect-slp.o \
 	tree-vectorizer.o \
+	tree-vtable-verify.o \
 	tree-vrp.o \
 	tree.o \
 	valtrack.o \
@@ -2578,6 +2579,11 @@ tree-vectorizer.o: tree-vectorizer.c $(C
    dumpfile.h $(TM_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \
    $(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) \
    $(TREE_PRETTY_PRINT_H)
+tree-vtable-verify.o: tree-vtable-verify.c tree-vtable-verify.h $(CONFIG_H) \
+   $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) cp/cp-tree.h $(TM_P_H) \
+   $(BASIC_BLOCK_H) output.h $(TREE_FLOW_H) $(TREE_DUMP_H) $(TREE_PASS_H) \
+   $(TIMEVAR_H) $(CFGLOOP_H) $(FLAGS_H)  $(TREE_INLINE_H) $(SCEV_H) \
+   $(DIAGNOSTIC_CORE_H) $(GIMPLE_PRETTY_PRINT_H) toplev.h langhooks.h
 tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(TREE_FLOW_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(TREE_PASS_H)
 tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
@@ -3676,6 +3682,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
   $(srcdir)/lto-streamer.h \
   $(srcdir)/target-globals.h \
   $(srcdir)/ipa-inline.h \
+  $(srcdir)/tree-vtable-verify.c \
   @all_gtfiles@
 
 # Compute the list of GT header files from the corresponding C sources,
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 192503)
+++ gcc/passes.c	(working copy)
@@ -1543,6 +1543,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_tm_memopt);
       NEXT_PASS (pass_tm_edges);
     }
+  NEXT_PASS (pass_vtable_verify);
   NEXT_PASS (pass_lower_complex_O0);
   NEXT_PASS (pass_cleanup_eh);
   NEXT_PASS (pass_lower_resx);

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
  2012-11-05 17:49 [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2) Caroline Tice
@ 2012-11-07 16:58 ` Xinliang David Li
  2012-11-16 18:21   ` Caroline Tice
  2012-11-08  9:36 ` Florian Weimer
  1 sibling, 1 reply; 8+ messages in thread
From: Xinliang David Li @ 2012-11-07 16:58 UTC (permalink / raw)
  To: Caroline Tice; +Cc: GCC Patches

See some random comments below.  Some test cases should also be added.
It should be easy to fake the attack by using placement new with
incompatible type ..

David


>  /* Start the process of running a particular set of global constructors
>     or destructors.  Subroutine of do_[cd]tors.  */
>
> -static tree
> -start_objects (int method_type, int initp)
> +tree
> +start_objects (int method_type, int initp, const char *extra_name)


Why do you need to make this global? The name start_objects are too
short and can
cause name conflicts. If you really need it to be global, defining a
wrapper function
with longer name as a global seems better.

The new parameter is not documented.


>  {
>    tree body;
>    tree fndecl;
> -  char type[14];
> +  char *type = NULL;
>
>    /* Make ctor or dtor function.  METHOD_TYPE may be 'I' or 'D'.  */
>
> @@ -2984,15 +2982,22 @@ start_objects (int method_type, int init
>        joiner = '_';
>  #endif
>
> -      sprintf (type, "sub_%c%c%.5u", method_type, joiner, initp);
> +      type = (char *) xmalloc ((17 + strlen (extra_name)) * sizeof (char));
> +      sprintf (type, "sub_%c%c%.5u%s", method_type, joiner, initp, extra_name);


Why changing the type name?


>      }
>    else
> -    sprintf (type, "sub_%c", method_type);
> +    {
> +      type = (char *) xmalloc (5 * sizeof (char));
> +      sprintf (type, "sub_%c", method_type);
> +    }
>
>    fndecl = build_lang_decl (FUNCTION_DECL,
>      get_file_function_name (type),
>      build_function_type_list (void_type_node,
>        NULL_TREE));
> +
> +  free (type);
> +
>    start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED);
>
>    TREE_PUBLIC (current_function_decl) = 0;
> @@ -3018,7 +3023,7 @@ start_objects (int method_type, int init
>  /* Finish the process of running a particular set of global constructors
>     or destructors.  Subroutine of do_[cd]tors.  */
>
> -static void
> +tree

Document the return value.


>  finish_objects (int method_type, int initp, tree body)
>  {
>    tree fn;
> @@ -3031,6 +3036,10 @@ finish_objects (int method_type, int ini
>      {
>        DECL_STATIC_CONSTRUCTOR (fn) = 1;
>        decl_init_priority_insert (fn, initp);
> +
> +      if (flag_vtable_verify
> +          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
> +        return fn;
>      }
>    else
>      {
> @@ -3039,6 +3048,7 @@ finish_objects (int method_type, int ini
>      }
>
>
> ===================================================================
> --- gcc/cp/vtable-class-hierarchy.c (revision 0)
> +++ gcc/cp/vtable-class-hierarchy.c (revision 0)
> @@ -0,0 +1,918 @@

Please add documentation (comments) for all functions defined in this file.

Some high level description of implementation structure at
the top of the file may also be helpful.

>
> --- gcc/tree-vtable-verify.c (revision 0)
> +++ gcc/tree-vtable-verify.c (revision 0)

Same comments as above.

On Mon, Nov 5, 2012 at 9:48 AM, Caroline Tice <cmtice@google.com> wrote:
> As requested, I have split the original patch into two parts: GCC
> changes and runtime library changes.  The attached patch is fore the
> gcc changes.
>
> -- Caroline Tice
> cmtice@google.com
>
> 2012-11-05  Caroline Tice  <cmtice@google.com>
>
>         * tree.h (save_vtable_map_decl): New function decl.
>         * tree-pass.h (pass_vtable_verify): New pass declaration.
>         * cp/init.c (build_vtbl_address): Remove 'static' qualifier from
>         function declaration and definition.
>         * cp/class.c (finish_struct_1):  Add call to vtv_save_class_info,
>         if the vtable verify flag is set.
>         * cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
>         files.  Add definition for building vtable-class-hierarchy.o.
>         * cp/pt.c (mark_class_instantiated):  Add call to vtv_save_class_info
>         if the vtable verify flag is set.
>         * cp/decl2 (start_objects): Remove 'static' qualifier from function
>         declaratin and definition.  Add new paramater, 'extra_name'.  Change
>         'type' var from char array to char *.  Call xmalloc & free for 'type'.
>         Add 'extra_name' to 'type' string.
>         (finish_objects): Remove 'static' qualifier from function declaration
>         and definition. Change return type from void to tree.  Make function
>         return early if we're doing vtable verification and the function is
>         a vtable verification constructor init function.  Make this function
>         return 'fn'.
>         (generate_ctor_or_dtor_function):  Add third argument to calls to
>         start_objects.
>         (cp_write_global_declarations):  Add calls to vtv_recover_class_info,
>         vtv_compute_class_hierarchy_transitive_closure, and
>         vtv_generate_init_routine, if the vtable verify flag is set.
>         * cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
>         list of gtfiles.
>         * cp/vtable-class-hierarchy.c: New file.
>         * cp/mangle.c (get_mangled_id): Remove static qualifier from function
>         definition.
>         * cp/cp-tree.h:  Add extern function declarations for start_objects,
>         finish_objects, build_vtbl_address, get_mangled_id,
>         vtv_compute_class_hierarchy_transitive_closure,
>         vtv_generate_init_routine, vtv_save_class_info and
>         vtv_recover_class_info.
>         * timevar.def: Add TV_VTABLE_VERIFICATION.
>         * flag-types.h: Add enum vtv_priority defintion.
>         * tree-vtable-verify.c: New file.
>         * tree-vtable-verify.h: New file.
>         * common.opt:  Add definitions for fvtable-verify= and its string
>         options (vtv_priority enum values).
>         * varasm.c (assemble_variable):  Check to see if the variable is a
>         vtable map variable, and if so, put it into the vtable map variable
>         section, and make it comdat.
>         (assemble_vtv_preinit_initializer): New function, to put the
>         vtable verification constructor initialization function in the preinit
>         array, if appropriate.
>         * output.h: Add extern declaration for
>         assemble_vtv_preinit_initializer.
>         * Makefile.in: Add tree-vtable-verify.o to list of OBJS.  Add build
>         rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
>         files.
>         * passes.c (init_optimization_passes): Add pass_vtable_verify.
>
> On Thu, Nov 1, 2012 at 1:07 PM, Caroline Tice <cmtice@google.com> wrote:
>> We have been developing a new security hardening feature for GCC that
>> is designed to detect and handle (during program execution) when a
>> vtable pointer that is about to be used for a virtual function call is
>> not a valid vtable pointer for that call (i.e. it has become
>> corrupted, possibly due to a  hacker attack).  We gave a presentation
>> on this work at the Gnu Tools Cauldron in Prague last July.  We now
>> have the implementation fully working and are submitting this patch
>> for review.  We would like to get this into the next release of GCC if
>> possible.
>>
>> The general idea is to collect class hierarchy and vtable pointer data
>> while parsing the classes, then use this data to generate (at runtime)
>> sets of valid vtable pointers, one for each class.  We also find every
>> virtual function call and insert a verification call before the
>> virtual function call.  The verification call takes the set of valid
>> vtable pointers for the declared class of the object, and the actual
>> vtable pointer in the object.  If the vtable pointer in the object is
>> in the set of valid vtable pointers for the object, then verification
>> succeeds and the virtual call is allowed.  Otherwise verification
>> fails and the program aborts.
>>
>> We have a written a more detailed design document, which I am also
>> attaching to this email (GCCVtableSecurityHardeningProposal.txt).
>>
>> The implementation can be divided into roughly two parts:
>> modifications to the main gcc compiler, for things that happen at
>> compile time (collecting the class hierarchy & vtable information;
>> generating the runtime calls to build the data sets from this data;
>> inserting calls to the verification function); and modifications to
>> the runtime, i.e. functions that go into libstdc++ for building the
>> data sets, for doing the verification against the data sets, for
>> protecting the memory where the data sets reside, etc.).
>>
>> Please let me know if there is any more information you need, or if
>> you have any questions about this patch.
>>
>> -- Caroline Tice
>> cmtice@google.com
>>
>> libstdc++/ChangeLog
>>
>> 2012-11-01  Caroline Tice  <cmtice@google.com>
>>
>>         * src/Makefile.am: Add libvtv___la_LIBDD definition; update CXXLINK
>>         to search in libvtv___la_LIBADD and to link in libvtv_init.
>>         * src/Makefile.in: Regenerate.
>>         * libsupc++/Makefile.am: Add libvtv_init.la and libvtv_stubs.la to
>>         toolexeclib_LTLIBRARIES.  Add vtv_rts.cc, vtv_malloc.cc and
>>         vtv_utils.cc to sources.  Define vtv_init_sources and
>>         vtv_stubs_sources.  Also define libvtv_init_la_SOURCES and
>>         libvtv_stubs_la_sources.
>>         * libsupc++/Makefile.in: Regenerate.
>>         * libsupc++/vtv_rts.cc: New file.
>>         * libsupc++/vtv_malloc.h: New file.
>>         * libsupc++/vtv_rts.h: New file.
>>         * libsupc++/vtv_fail.h: New file.
>>         * libsupc++/vtv_set.h: New file.
>>         * libsupc++/vtv_stubs.cc: New file.
>>         * libsupc++/vtv_utils.cc: New file.
>>         * libcupc++/vtv_utils.h: New file.
>>         * libsupc++/vtv_init.cc: New file.
>>         * libsupc++/vtv_malloc.cc: New file.
>>         * config/abi/pre/gnu.ver (GLIBCXX_3.4.18): Add vtable verification
>>         functions and vtable map variables to library export list.
>>
>> gcc/ChangeLog:
>>
>> 2012-11-01  Caroline Tice  <cmtice@google.com>
>>
>>         * tree.h (save_vtable_map_decl): New function decl.
>>         * tree-pass.h (pass_vtable_verify): New pass declaration.
>>         * cp/init.c (build_vtbl_address): Remove 'static' qualifier from
>>         function declaration and definition.
>>         * cp/class.c (finish_struct_1):  Add call to vtv_save_class_info,
>>         if the vtable verify flag is set.
>>         * cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
>>         files.  Add definition for building vtable-class-hierarchy.o.
>>         * cp/pt.c (mark_class_instantiated):  Add call to vtv_save_class_info
>>         if the vtable verify flag is set.
>>         * cp/decl2 (start_objects): Remove 'static' qualifier from function
>>         declaratin and definition.  Add new paramater, 'extra_name'.  Change
>>         'type' var from char array to char *.  Call xmalloc & free for 'type'.
>>         Add 'extra_name' to 'type' string.
>>         (finish_objects): Remove 'static' qualifier from function declaration
>>         and definition. Change return type from void to tree.  Make function
>>         return early if we're doing vtable verification and the function is
>>         a vtable verification constructor init function.  Make this function
>>         return 'fn'.
>>         (generate_ctor_or_dtor_function):  Add third argument to calls to
>>         start_objects.
>>         (cp_write_global_declarations):  Add calls to vtv_recover_class_info,
>>         vtv_compute_class_hierarchy_transitive_closure, and
>>         vtv_generate_init_routine, if the vtable verify flag is set.
>>         * cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
>>         list of gtfiles.
>>         * cp/vtable-class-hierarchy.c: New file.
>>         * cp/mangle.c (get_mangled_id): Remove static qualifier from function
>>         definition.
>>         * cp/cp-tree.h:  Add extern function declarations for start_objects,
>>         finish_objects, build_vtbl_address, get_mangled_id,
>>         vtv_compute_class_hierarchy_transitive_closure,
>>         vtv_generate_init_routine, vtv_save_class_info and
>>         vtv_recover_class_info.
>>         * timevar.def: Add TV_VTABLE_VERIFICATION.
>>         * flag-types.h: Add enum vtv_priority defintion.
>>         * tree-vtable-verify.c: New file.
>>         * tree-vtable-verify.h: New file.
>>         * common.opt:  Add definitions for fvtable-verify= and its string
>>         options (vtv_priority enum values).
>>         * varasm.c (assemble_variable):  Check to see if the variable is a
>>         vtable map variable, and if so, put it into the vtable map variable
>>         section, and make it comdat.
>>         (assemble_vtv_preinit_initializer): New function, to put the
>>         vtable verification constructor initialization function in the preinit
>>         array, if appropriate.
>>         * output.h: Add extern declaration for
>>         assemble_vtv_preinit_initializer.
>>         * Makefile.in: Add tree-vtable-verify.o to list of OBJS.  Add build
>>         rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
>>         files.
>>         * passes.c (init_optimization_passes): Add pass_vtable_verify.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
  2012-11-05 17:49 [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2) Caroline Tice
  2012-11-07 16:58 ` Xinliang David Li
@ 2012-11-08  9:36 ` Florian Weimer
  2012-11-08 16:56   ` Caroline Tice
  1 sibling, 1 reply; 8+ messages in thread
From: Florian Weimer @ 2012-11-08  9:36 UTC (permalink / raw)
  To: Caroline Tice; +Cc: gcc-patches

On 11/05/2012 06:48 PM, Caroline Tice wrote:

> As requested, I have split the original patch into two parts: GCC
> changes and runtime library changes.  The attached patch is fore the
> gcc changes.

Out of curiosity, what's the primary source of wrong vtable values you 
expect?  User-after-free issues, heap spraying, or something else?

-- 
Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
  2012-11-08  9:36 ` Florian Weimer
@ 2012-11-08 16:56   ` Caroline Tice
  0 siblings, 0 replies; 8+ messages in thread
From: Caroline Tice @ 2012-11-08 16:56 UTC (permalink / raw)
  To: Florian Weimer; +Cc: gcc-patches

Most likely use-after-free issues, but any memory use bug lays the
program open to these attacks.

-- Caroline Tice
cmtice@google.com


On Thu, Nov 8, 2012 at 1:36 AM, Florian Weimer <fweimer@redhat.com> wrote:
> On 11/05/2012 06:48 PM, Caroline Tice wrote:
>
>> As requested, I have split the original patch into two parts: GCC
>> changes and runtime library changes.  The attached patch is fore the
>> gcc changes.
>
>
> Out of curiosity, what's the primary source of wrong vtable values you
> expect?  User-after-free issues, heap spraying, or something else?
>
> --
> Florian Weimer / Red Hat Product Security Team

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
  2012-11-07 16:58 ` Xinliang David Li
@ 2012-11-16 18:21   ` Caroline Tice
       [not found]     ` <CABtf2+SnpddRF9kHsY-CyxNbS+3iQrUM7dqtZmbGJMNkS_WvBw@mail.gmail.com>
  2012-11-29 18:34     ` Jason Merrill
  0 siblings, 2 replies; 8+ messages in thread
From: Caroline Tice @ 2012-11-16 18:21 UTC (permalink / raw)
  To: Xinliang David Li; +Cc: GCC Patches

[-- Attachment #1: Type: text/plain, Size: 13857 bytes --]

I have made the requested changes (except for adding test cases) and
attached the updated patch for review.  I am have test cases but they
are not in expect/dejagnu format; I am working on getting them to run
under dejagnu, and will submit them when I have them ready.

-- Caroline Tice
cmtice@google.com


On Wed, Nov 7, 2012 at 8:58 AM, Xinliang David Li <davidxl@google.com> wrote:
> See some random comments below.  Some test cases should also be added.
> It should be easy to fake the attack by using placement new with
> incompatible type ..
>
> David
>
>
>>  /* Start the process of running a particular set of global constructors
>>     or destructors.  Subroutine of do_[cd]tors.  */
>>
>> -static tree
>> -start_objects (int method_type, int initp)
>> +tree
>> +start_objects (int method_type, int initp, const char *extra_name)
>
>
> Why do you need to make this global? The name start_objects are too
> short and can
> cause name conflicts. If you really need it to be global, defining a
> wrapper function
> with longer name as a global seems better.
>
> The new parameter is not documented.
>
>
>>  {
>>    tree body;
>>    tree fndecl;
>> -  char type[14];
>> +  char *type = NULL;
>>
>>    /* Make ctor or dtor function.  METHOD_TYPE may be 'I' or 'D'.  */
>>
>> @@ -2984,15 +2982,22 @@ start_objects (int method_type, int init
>>        joiner = '_';
>>  #endif
>>
>> -      sprintf (type, "sub_%c%c%.5u", method_type, joiner, initp);
>> +      type = (char *) xmalloc ((17 + strlen (extra_name)) * sizeof (char));
>> +      sprintf (type, "sub_%c%c%.5u%s", method_type, joiner, initp, extra_name);
>
>
> Why changing the type name?
>
>
>>      }
>>    else
>> -    sprintf (type, "sub_%c", method_type);
>> +    {
>> +      type = (char *) xmalloc (5 * sizeof (char));
>> +      sprintf (type, "sub_%c", method_type);
>> +    }
>>
>>    fndecl = build_lang_decl (FUNCTION_DECL,
>>      get_file_function_name (type),
>>      build_function_type_list (void_type_node,
>>        NULL_TREE));
>> +
>> +  free (type);
>> +
>>    start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED);
>>
>>    TREE_PUBLIC (current_function_decl) = 0;
>> @@ -3018,7 +3023,7 @@ start_objects (int method_type, int init
>>  /* Finish the process of running a particular set of global constructors
>>     or destructors.  Subroutine of do_[cd]tors.  */
>>
>> -static void
>> +tree
>
> Document the return value.
>
>
>>  finish_objects (int method_type, int initp, tree body)
>>  {
>>    tree fn;
>> @@ -3031,6 +3036,10 @@ finish_objects (int method_type, int ini
>>      {
>>        DECL_STATIC_CONSTRUCTOR (fn) = 1;
>>        decl_init_priority_insert (fn, initp);
>> +
>> +      if (flag_vtable_verify
>> +          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
>> +        return fn;
>>      }
>>    else
>>      {
>> @@ -3039,6 +3048,7 @@ finish_objects (int method_type, int ini
>>      }
>>
>>
>> ===================================================================
>> --- gcc/cp/vtable-class-hierarchy.c (revision 0)
>> +++ gcc/cp/vtable-class-hierarchy.c (revision 0)
>> @@ -0,0 +1,918 @@
>
> Please add documentation (comments) for all functions defined in this file.
>
> Some high level description of implementation structure at
> the top of the file may also be helpful.
>
>>
>> --- gcc/tree-vtable-verify.c (revision 0)
>> +++ gcc/tree-vtable-verify.c (revision 0)
>
> Same comments as above.
>
> On Mon, Nov 5, 2012 at 9:48 AM, Caroline Tice <cmtice@google.com> wrote:
>> As requested, I have split the original patch into two parts: GCC
>> changes and runtime library changes.  The attached patch is fore the
>> gcc changes.
>>
>> -- Caroline Tice
>> cmtice@google.com
>>
>> 2012-11-05  Caroline Tice  <cmtice@google.com>
>>
>>         * tree.h (save_vtable_map_decl): New function decl.
>>         * tree-pass.h (pass_vtable_verify): New pass declaration.
>>         * cp/init.c (build_vtbl_address): Remove 'static' qualifier from
>>         function declaration and definition.
>>         * cp/class.c (finish_struct_1):  Add call to vtv_save_class_info,
>>         if the vtable verify flag is set.
>>         * cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
>>         files.  Add definition for building vtable-class-hierarchy.o.
>>         * cp/pt.c (mark_class_instantiated):  Add call to vtv_save_class_info
>>         if the vtable verify flag is set.
>>         * cp/decl2 (start_objects): Remove 'static' qualifier from function
>>         declaratin and definition.  Add new paramater, 'extra_name'.  Change
>>         'type' var from char array to char *.  Call xmalloc & free for 'type'.
>>         Add 'extra_name' to 'type' string.
>>         (finish_objects): Remove 'static' qualifier from function declaration
>>         and definition. Change return type from void to tree.  Make function
>>         return early if we're doing vtable verification and the function is
>>         a vtable verification constructor init function.  Make this function
>>         return 'fn'.
>>         (generate_ctor_or_dtor_function):  Add third argument to calls to
>>         start_objects.
>>         (cp_write_global_declarations):  Add calls to vtv_recover_class_info,
>>         vtv_compute_class_hierarchy_transitive_closure, and
>>         vtv_generate_init_routine, if the vtable verify flag is set.
>>         * cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
>>         list of gtfiles.
>>         * cp/vtable-class-hierarchy.c: New file.
>>         * cp/mangle.c (get_mangled_id): Remove static qualifier from function
>>         definition.
>>         * cp/cp-tree.h:  Add extern function declarations for start_objects,
>>         finish_objects, build_vtbl_address, get_mangled_id,
>>         vtv_compute_class_hierarchy_transitive_closure,
>>         vtv_generate_init_routine, vtv_save_class_info and
>>         vtv_recover_class_info.
>>         * timevar.def: Add TV_VTABLE_VERIFICATION.
>>         * flag-types.h: Add enum vtv_priority defintion.
>>         * tree-vtable-verify.c: New file.
>>         * tree-vtable-verify.h: New file.
>>         * common.opt:  Add definitions for fvtable-verify= and its string
>>         options (vtv_priority enum values).
>>         * varasm.c (assemble_variable):  Check to see if the variable is a
>>         vtable map variable, and if so, put it into the vtable map variable
>>         section, and make it comdat.
>>         (assemble_vtv_preinit_initializer): New function, to put the
>>         vtable verification constructor initialization function in the preinit
>>         array, if appropriate.
>>         * output.h: Add extern declaration for
>>         assemble_vtv_preinit_initializer.
>>         * Makefile.in: Add tree-vtable-verify.o to list of OBJS.  Add build
>>         rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
>>         files.
>>         * passes.c (init_optimization_passes): Add pass_vtable_verify.
>>
>> On Thu, Nov 1, 2012 at 1:07 PM, Caroline Tice <cmtice@google.com> wrote:
>>> We have been developing a new security hardening feature for GCC that
>>> is designed to detect and handle (during program execution) when a
>>> vtable pointer that is about to be used for a virtual function call is
>>> not a valid vtable pointer for that call (i.e. it has become
>>> corrupted, possibly due to a  hacker attack).  We gave a presentation
>>> on this work at the Gnu Tools Cauldron in Prague last July.  We now
>>> have the implementation fully working and are submitting this patch
>>> for review.  We would like to get this into the next release of GCC if
>>> possible.
>>>
>>> The general idea is to collect class hierarchy and vtable pointer data
>>> while parsing the classes, then use this data to generate (at runtime)
>>> sets of valid vtable pointers, one for each class.  We also find every
>>> virtual function call and insert a verification call before the
>>> virtual function call.  The verification call takes the set of valid
>>> vtable pointers for the declared class of the object, and the actual
>>> vtable pointer in the object.  If the vtable pointer in the object is
>>> in the set of valid vtable pointers for the object, then verification
>>> succeeds and the virtual call is allowed.  Otherwise verification
>>> fails and the program aborts.
>>>
>>> We have a written a more detailed design document, which I am also
>>> attaching to this email (GCCVtableSecurityHardeningProposal.txt).
>>>
>>> The implementation can be divided into roughly two parts:
>>> modifications to the main gcc compiler, for things that happen at
>>> compile time (collecting the class hierarchy & vtable information;
>>> generating the runtime calls to build the data sets from this data;
>>> inserting calls to the verification function); and modifications to
>>> the runtime, i.e. functions that go into libstdc++ for building the
>>> data sets, for doing the verification against the data sets, for
>>> protecting the memory where the data sets reside, etc.).
>>>
>>> Please let me know if there is any more information you need, or if
>>> you have any questions about this patch.
>>>
>>> -- Caroline Tice
>>> cmtice@google.com
>>>
>>> libstdc++/ChangeLog
>>>
>>> 2012-11-01  Caroline Tice  <cmtice@google.com>
>>>
>>>         * src/Makefile.am: Add libvtv___la_LIBDD definition; update CXXLINK
>>>         to search in libvtv___la_LIBADD and to link in libvtv_init.
>>>         * src/Makefile.in: Regenerate.
>>>         * libsupc++/Makefile.am: Add libvtv_init.la and libvtv_stubs.la to
>>>         toolexeclib_LTLIBRARIES.  Add vtv_rts.cc, vtv_malloc.cc and
>>>         vtv_utils.cc to sources.  Define vtv_init_sources and
>>>         vtv_stubs_sources.  Also define libvtv_init_la_SOURCES and
>>>         libvtv_stubs_la_sources.
>>>         * libsupc++/Makefile.in: Regenerate.
>>>         * libsupc++/vtv_rts.cc: New file.
>>>         * libsupc++/vtv_malloc.h: New file.
>>>         * libsupc++/vtv_rts.h: New file.
>>>         * libsupc++/vtv_fail.h: New file.
>>>         * libsupc++/vtv_set.h: New file.
>>>         * libsupc++/vtv_stubs.cc: New file.
>>>         * libsupc++/vtv_utils.cc: New file.
>>>         * libcupc++/vtv_utils.h: New file.
>>>         * libsupc++/vtv_init.cc: New file.
>>>         * libsupc++/vtv_malloc.cc: New file.
>>>         * config/abi/pre/gnu.ver (GLIBCXX_3.4.18): Add vtable verification
>>>         functions and vtable map variables to library export list.
>>>
>>> gcc/ChangeLog:
>>>
>>> 2012-11-01  Caroline Tice  <cmtice@google.com>
>>>
>>>         * tree.h (save_vtable_map_decl): New function decl.
>>>         * tree-pass.h (pass_vtable_verify): New pass declaration.
>>>         * cp/init.c (build_vtbl_address): Remove 'static' qualifier from
>>>         function declaration and definition.
>>>         * cp/class.c (finish_struct_1):  Add call to vtv_save_class_info,
>>>         if the vtable verify flag is set.
>>>         * cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
>>>         files.  Add definition for building vtable-class-hierarchy.o.
>>>         * cp/pt.c (mark_class_instantiated):  Add call to vtv_save_class_info
>>>         if the vtable verify flag is set.
>>>         * cp/decl2 (start_objects): Remove 'static' qualifier from function
>>>         declaratin and definition.  Add new paramater, 'extra_name'.  Change
>>>         'type' var from char array to char *.  Call xmalloc & free for 'type'.
>>>         Add 'extra_name' to 'type' string.
>>>         (finish_objects): Remove 'static' qualifier from function declaration
>>>         and definition. Change return type from void to tree.  Make function
>>>         return early if we're doing vtable verification and the function is
>>>         a vtable verification constructor init function.  Make this function
>>>         return 'fn'.
>>>         (generate_ctor_or_dtor_function):  Add third argument to calls to
>>>         start_objects.
>>>         (cp_write_global_declarations):  Add calls to vtv_recover_class_info,
>>>         vtv_compute_class_hierarchy_transitive_closure, and
>>>         vtv_generate_init_routine, if the vtable verify flag is set.
>>>         * cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
>>>         list of gtfiles.
>>>         * cp/vtable-class-hierarchy.c: New file.
>>>         * cp/mangle.c (get_mangled_id): Remove static qualifier from function
>>>         definition.
>>>         * cp/cp-tree.h:  Add extern function declarations for start_objects,
>>>         finish_objects, build_vtbl_address, get_mangled_id,
>>>         vtv_compute_class_hierarchy_transitive_closure,
>>>         vtv_generate_init_routine, vtv_save_class_info and
>>>         vtv_recover_class_info.
>>>         * timevar.def: Add TV_VTABLE_VERIFICATION.
>>>         * flag-types.h: Add enum vtv_priority defintion.
>>>         * tree-vtable-verify.c: New file.
>>>         * tree-vtable-verify.h: New file.
>>>         * common.opt:  Add definitions for fvtable-verify= and its string
>>>         options (vtv_priority enum values).
>>>         * varasm.c (assemble_variable):  Check to see if the variable is a
>>>         vtable map variable, and if so, put it into the vtable map variable
>>>         section, and make it comdat.
>>>         (assemble_vtv_preinit_initializer): New function, to put the
>>>         vtable verification constructor initialization function in the preinit
>>>         array, if appropriate.
>>>         * output.h: Add extern declaration for
>>>         assemble_vtv_preinit_initializer.
>>>         * Makefile.in: Add tree-vtable-verify.o to list of OBJS.  Add build
>>>         rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
>>>         files.
>>>         * passes.c (init_optimization_passes): Add pass_vtable_verify.

[-- Attachment #2: fsf-vtable-verification.gcc.v2.patch --]
[-- Type: application/octet-stream, Size: 103529 bytes --]

Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h	(revision 193571)
+++ gcc/tree-pass.h	(working copy)
@@ -363,6 +363,7 @@ extern struct gimple_opt_pass pass_tm_ed
 extern struct gimple_opt_pass pass_split_functions;
 extern struct gimple_opt_pass pass_feedback_split_functions;
 extern struct gimple_opt_pass pass_strength_reduction;
+extern struct gimple_opt_pass pass_vtable_verify;
 
 /* IPA Passes */
 extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 193571)
+++ gcc/cp/init.c	(working copy)
@@ -45,7 +45,6 @@ static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
 static tree build_field_list (tree, tree, int *);
-static tree build_vtbl_address (tree);
 static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
 
 /* We are about to generate some complex initialization code.
@@ -1108,7 +1107,7 @@ emit_mem_initializers (tree mem_inits)
 /* Returns the address of the vtable (i.e., the value that should be
    assigned to the vptr) for BINFO.  */
 
-static tree
+tree
 build_vtbl_address (tree binfo)
 {
   tree binfo_for = binfo;
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 193571)
+++ gcc/cp/class.c	(working copy)
@@ -6380,6 +6380,9 @@ finish_struct_1 (tree t)
 
   maybe_suppress_debug_info (t);
 
+  if (flag_vtable_verify)
+    vtv_save_class_info (t);
+
   dump_class_hierarchy (t);
 
   /* Finish debugging output for this type.  */
Index: gcc/cp/Make-lang.in
===================================================================
--- gcc/cp/Make-lang.in	(revision 193571)
+++ gcc/cp/Make-lang.in	(working copy)
@@ -82,7 +82,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -340,7 +340,12 @@ cp/parser.o: cp/parser.c $(CXX_TREE_H) $
   c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H)
 cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \
 	$(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H)
-
+cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \
+  $(TM_H) $(TIMEVAR_H) $(CXX_TREE_H) intl.h $(CXX_PARSER_H) cp/decl.h \
+  $(FLAGS_H) $(DIAGNOSTIC_CORE_H) output.h $(CGRAPH_H) c-family/c-common.h \
+  c-family/c-objc.h $(PLUGIN_H) \
+  tree-iterator.h tree-vtable-verify.h $(GIMPLE_H) \
+  gt-cp-vtable-class-hierarchy.h
 cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h \
 	$(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 193571)
+++ gcc/cp/pt.c	(working copy)
@@ -17889,6 +17889,10 @@ mark_class_instantiated (tree t, int ext
   if (! extern_p)
     {
       CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+
+      if (flag_vtable_verify)
+        vtv_save_class_info (t);
+
       rest_of_type_compilation (t, 1);
     }
 }
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	(revision 193571)
+++ gcc/cp/decl2.c	(working copy)
@@ -69,8 +69,8 @@ typedef struct priority_info_s {
 static void mark_vtable_entries (tree);
 static bool maybe_emit_vtables (tree);
 static bool acceptable_java_type (tree);
-static tree start_objects (int, int);
-static void finish_objects (int, int, tree);
+static tree start_objects (int, int, const char *);
+static tree finish_objects (int, int, tree);
 static tree start_static_storage_duration_function (unsigned);
 static void finish_static_storage_duration_function (tree);
 static priority_info get_priority_info (int);
@@ -2964,14 +2964,22 @@ generate_tls_wrapper (tree fn)
 }
 
 /* Start the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+   or destructors.  Subroutine of do_[cd]tors.  Also called from
+   vtv_start_verification_constructor_init_function.
+
+   The parameter EXTRA_NAME will be an empty string for most calls.
+   It gets appended to the end of the name of the function being
+   created.  When this function is being called to create a
+   vtable verification constructor init function, EXTRA_NAME will
+   contain a string based on the source file path, to help give the
+   vtable constructor init functions unique names.  */
 
 static tree
-start_objects (int method_type, int initp)
+start_objects (int method_type, int initp, const char *extra_name)
 {
   tree body;
   tree fndecl;
-  char type[14];
+  char *type = NULL;
 
   /* Make ctor or dtor function.  METHOD_TYPE may be 'I' or 'D'.  */
 
@@ -2985,15 +2993,22 @@ start_objects (int method_type, int init
       joiner = '_';
 #endif
 
-      sprintf (type, "sub_%c%c%.5u", method_type, joiner, initp);
+      type = (char *) xmalloc ((17 + strlen (extra_name)) * sizeof (char));
+      sprintf (type, "sub_%c%c%.5u%s", method_type, joiner, initp, extra_name);
     }
   else
-    sprintf (type, "sub_%c", method_type);
+    {
+      type = (char *) xmalloc (5 * sizeof (char));
+      sprintf (type, "sub_%c", method_type);
+    }
 
   fndecl = build_lang_decl (FUNCTION_DECL,
 			    get_file_function_name (type),
 			    build_function_type_list (void_type_node,
 						      NULL_TREE));
+
+  free (type);
+
   start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED);
 
   TREE_PUBLIC (current_function_decl) = 0;
@@ -3017,9 +3032,13 @@ start_objects (int method_type, int init
 }
 
 /* Finish the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+   or destructors.  Subroutine of do_[cd]tors.  Also called from
+   vtv_finish_verification_constructor_init_function.
 
-static void
+   This function returns a tree containing the function decl for the function
+   it finished creating.  */
+
+static tree
 finish_objects (int method_type, int initp, tree body)
 {
   tree fn;
@@ -3032,6 +3051,10 @@ finish_objects (int method_type, int ini
     {
       DECL_STATIC_CONSTRUCTOR (fn) = 1;
       decl_init_priority_insert (fn, initp);
+
+      if (flag_vtable_verify
+          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
+        return fn;
     }
   else
     {
@@ -3040,6 +3063,7 @@ finish_objects (int method_type, int ini
     }
 
   expand_or_defer_fn (fn);
+  return fn;
 }
 
 /* The names of the parameters to the function created to handle
@@ -3562,7 +3586,7 @@ generate_ctor_or_dtor_function (bool con
   if (c_dialect_objc () && (priority == DEFAULT_INIT_PRIORITY)
       && constructor_p && objc_static_init_needed_p ())
     {
-      body = start_objects (function_key, priority);
+      body = start_objects (function_key, priority, "");
       objc_generate_static_init_call (NULL_TREE);
     }
 
@@ -3576,7 +3600,7 @@ generate_ctor_or_dtor_function (bool con
 	  tree call;
 
 	  if (! body)
-	    body = start_objects (function_key, priority);
+	    body = start_objects (function_key, priority, "");
 
 	  call = cp_build_function_call_nary (fndecl, tf_warning_or_error,
 					      build_int_cst (NULL_TREE,
@@ -4284,8 +4308,22 @@ cp_write_global_declarations (void)
   timevar_stop (TV_PHASE_DEFERRED);
   timevar_start (TV_PHASE_OPT_GEN);
 
+  if (flag_vtable_verify)
+    {
+      vtv_recover_class_info ();
+      vtv_compute_class_hierarchy_transitive_closure ();
+    }
+
   finalize_compilation_unit ();
 
+  if (flag_vtable_verify)
+    {
+      /* Generate the special constructor initialization function that
+         calls __VLTRegisterPairs, and give it a very high initialization
+         priority.  */
+      vtv_generate_init_routine (main_input_filename);
+    }
+
   timevar_stop (TV_PHASE_OPT_GEN);
   timevar_start (TV_PHASE_CHECK_DBGINFO);
 
@@ -4656,4 +4694,16 @@ mark_used (tree decl)
   return true;
 }
 
+tree
+vtv_start_verification_constructor_init_function (const char *temp_name)
+{
+  return start_objects ('I', MAX_RESERVED_INIT_PRIORITY -1, temp_name);
+}
+
+tree
+vtv_finish_verification_constructor_init_function (tree function_body)
+{
+  return finish_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1, function_body);
+}
+
 #include "gt-cp-decl2.h"
Index: gcc/cp/config-lang.in
===================================================================
--- gcc/cp/config-lang.in	(revision 193571)
+++ gcc/cp/config-lang.in	(working copy)
@@ -30,4 +30,4 @@ compilers="cc1plus\$(exeext)"
 
 target_libs="target-libstdc++-v3"
 
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c"
Index: gcc/cp/vtable-class-hierarchy.c
===================================================================
--- gcc/cp/vtable-class-hierarchy.c	(revision 0)
+++ gcc/cp/vtable-class-hierarchy.c	(revision 0)
@@ -0,0 +1,1005 @@
+/* Copyright (C) 2012  Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* This file is part of the vtable security implementation.  It collects
+   class hierarchy information about the program being compiled and
+   inserts calls to __VLTRegisterPair, registering this information.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "intl.h"
+#include "c-family/c-pragma.h"
+#include "decl.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+#include "output.h"
+#include "target.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "tree-iterator.h"
+#include "tree-vtable-verify.h"
+#include "gimple.h"
+
+/* Need to mark this one specially since it needs to be stored in
+ * precompiled header IR */
+static GTY (()) tree vlt_saved_class_info = NULL_TREE;
+static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
+static GTY (()) tree vlt_change_permission_fndecl = NULL_TREE;
+
+struct work_node {
+  struct vtv_graph_node *node;
+  struct work_node *next;
+};
+
+static void init_functions (void);
+
+static int  guess_num_vtable_pointers (struct vtv_graph_node *);
+static bool register_all_pairs (tree body);
+static void add_hierarchy_pair (struct vtv_graph_node *,
+                                struct vtv_graph_node *);
+static struct vtv_graph_node *find_graph_node (tree);
+static struct vtv_graph_node *
+                  find_and_remove_next_leaf_node (struct work_node **worklist);
+static void create_undef_reference_to_vtv_init(tree register_pairs_body);
+static bool vtv_register_class_hierarchy_information
+                                                    (tree register_pairs_body);
+
+static void update_class_hierarchy_information (tree, tree);
+struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
+
+/* As part of vtable verification the compiler generates and inserts calls
+   to __VLTRegisterPair and __VLTChangePermission, which are in libstdc++.
+   This function builds and initializes the function decls that are used
+   in generating those function calls.
+
+   In addition to __VLTRegisterPair there is also __VLTRegisterPairDebug
+   which can be used in place of __VLTRegisterPair, and which takes extra
+   parameters and outputs extra information, to help debug problems.  The
+   debug version of this function is generated and used if the compiler is
+   built with "-DVTV_DEBUG".
+
+   The signatures for these functions are:
+
+   void __VLTChangePermission (int);
+   void __VLTRegisterPair (void **, void*, int);
+   void __VLTRegisterPairDebug (void**, void *, int, char *, int, char *, int);
+*/
+
+static void
+init_functions (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree register_pairs_type = void_type_node;
+  tree change_permission_type = void_type_node;
+#ifdef VTV_DEBUG
+  tree char_ptr_type = build_pointer_type (char_type_node);
+#endif
+
+  if (vlt_change_permission_fndecl != NULL_TREE)
+    return;
+
+  gcc_assert(vlt_register_pairs_fndecl == NULL_TREE);
+
+  arg_types = build_tree_list (NULL_TREE, integer_type_node);
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  change_permission_type = build_function_type (change_permission_type,
+                                                arg_types);
+  vlt_change_permission_fndecl = build_fn_decl ("__VLTChangePermission",
+                                                change_permission_type);
+  TREE_NOTHROW (vlt_change_permission_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_change_permission_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_change_permission_fndecl));
+  TREE_PUBLIC (vlt_change_permission_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_change_permission_fndecl) = 1;
+  retrofit_lang_decl (vlt_change_permission_fndecl);
+  SET_DECL_LANGUAGE (vlt_change_permission_fndecl, lang_cplusplus);
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+#ifdef VTV_DEBUG
+  /* Start: Arg types that only go into the debug version of the function.  */
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  /* End: Arg types for debugging.  */
+#endif
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  register_pairs_type = build_function_type (register_pairs_type, arg_types);
+
+#ifdef VTV_DEBUG
+  vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPairDebug",
+                                             register_pairs_type);
+#else
+  vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPair",
+                                             register_pairs_type);
+#endif
+
+  TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
+  TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
+  retrofit_lang_decl (vlt_register_pairs_fndecl);
+  SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It adds a
+   vtv_graph_node to the WORKLIST, which is a linked list of
+   seen-but-not-yet-processed nodes.  INSERTED is a bitmap, one bit
+   per node, to help make sure that we don't insert a node into the
+   worklist more than once.  Each node represents a class somewhere in
+   our class hierarchy information. Every node in the graph gets added
+   to the worklist exactly once and removed from the worklist exactly
+   once (when all of its children have been processed).  */
+
+static void
+add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
+                 sbitmap inserted)
+{
+  struct work_node *new_work_node;
+
+  if (bitmap_bit_p (inserted, node->class_uid))
+    return;
+
+  new_work_node = (struct work_node *) xmalloc (sizeof (struct work_node));
+  new_work_node->next = *worklist;
+  new_work_node->node = node;
+  *worklist = new_work_node;
+
+  bitmap_set_bit (inserted, node->class_uid);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It goes through
+   the WORKLIST of class hierarchy nodes looking for a "leaf" node,
+   i.e. a node whose children in the hierarchy have all been
+   processed.  When it finds the next leaf node, it removes it from
+   the linked list (WORKLIST) and returns the node.  */
+
+static struct vtv_graph_node *
+find_and_remove_next_leaf_node (struct work_node **worklist)
+{
+  struct work_node *prev, *cur;
+
+  for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+    {
+      if (cur->node->num_children == cur->node->num_processed_children)
+        {
+          if (prev == NULL)
+            (*worklist) = cur->next;
+          else
+            prev->next = cur->next;
+
+          cur->next = NULL;
+          return cur->node;
+        }
+    }
+
+  return NULL;
+}
+
+/* In our class hirarchy graph, each class node contains a bitmap,
+   with one bit for each class in the hierarchy.  The bits are set for
+   classes that are descendants in the graph of the current node.
+   Initially the desdendants bitmap is only set for immediate
+   descendants.  This function traverses the class hierarchy graph,
+   bottom up, filling in the transitive closures for the descendants
+   as we rise up the graph.  */
+
+void
+vtv_compute_class_hierarchy_transitive_closure (void)
+{
+  struct work_node *worklist = NULL;
+  struct vtbl_map_node *cur;
+  sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+  unsigned i;
+
+  /* Note: Every node in the graph gets added to the worklist exactly
+   once and removed from the worklist exactly once (when all of its
+   children have been processed).  Each node's children edges are
+   followed exactly once, and each node's parent edges are followed
+   exactly once.  So this algorithm is roughly O(V + 2E), i.e.
+   O(E + V). */
+
+  /* Set-up:                                                                */
+  /* Find all the "leaf" nodes in the graph, and add them to the worklist.  */
+  bitmap_clear (inserted);
+  for (cur = vtbl_map_nodes; cur; cur = cur->next)
+    {
+      if (cur->class_info
+          && (cur->class_info->num_children == 0)
+          && ! (bitmap_bit_p (inserted, cur->class_info->class_uid)))
+        add_to_worklist (&worklist, cur->class_info, inserted);
+    }
+
+
+  /* Main work: pull next leaf node off work list, process it, add its
+     parents to the worklist, where a 'leaf' node is one that has no
+     children, or all of its children have been processed. */
+  while (worklist)
+    {
+      struct vtv_graph_node *temp_node =
+                                  find_and_remove_next_leaf_node (&worklist);
+
+      gcc_assert (temp_node != NULL);
+      temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
+      bitmap_clear (temp_node->descendants);
+      bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
+      for (i = 0; i < temp_node->num_children; ++i)
+        bitmap_ior (temp_node->descendants, temp_node->descendants,
+                        temp_node->children[i]->descendants);
+      for (i = 0; i < temp_node->num_parents; ++i)
+        {
+          temp_node->parents[i]->num_processed_children =
+                    temp_node->parents[i]->num_processed_children + 1;
+          if (!bitmap_bit_p (inserted, temp_node->parents[i]->class_uid))
+            add_to_worklist (&worklist, temp_node->parents[i], inserted);
+        }
+    }
+}
+
+/* Keep track of which pairs we have already created __VLTRegisterPair
+   calls for, to prevent creating duplicate calls within the same
+   compilation unit.  */
+
+static bool
+record_register_pairs (tree vtable_decl, tree vptr_address,
+                       tree base_class)
+{
+  unsigned offset;
+  tree base_id;
+  struct vtbl_map_node *base_vtable_map_node;
+
+  if (TREE_CODE (vptr_address) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
+    vptr_address = TREE_OPERAND (vptr_address, 0);
+
+  offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
+
+  if (TREE_CHAIN (base_class))
+    base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
+  else
+    base_id = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class));
+
+  base_vtable_map_node = vtbl_map_get_node (base_id);
+
+  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
+                                       offset))
+    return true;
+
+  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
+				     offset);
+  return false;
+}
+
+/* A class may contain secondary vtables in it, for various reasons.
+     This function goes through the decl chain of a class record
+     looking for any fields that point to secondary vtables, and
+     adding calls to __VLTRegisterPair for the secondary vtable
+     pointers.  */
+
+static void
+register_vptr_fields (tree base_class_decl_arg, tree base_class,
+                      tree record_type, tree body)
+{
+  tree vtbl_var_decl;
+  tree arg1;
+  tree arg2;
+  int hint = 0;
+
+  if (TREE_CODE (record_type) != RECORD_TYPE)
+    return;
+
+  vtbl_var_decl = get_vtbl_decl_for_binfo (TYPE_BINFO (record_type));
+
+  if (vtbl_var_decl)
+    {
+      tree ztt_decl = DECL_CHAIN (vtbl_var_decl);
+      bool already_registered = false;
+
+      /* construction vtable */
+      if (ztt_decl != NULL_TREE
+          && (DECL_NAME (ztt_decl))
+          && (strncmp (IDENTIFIER_POINTER (DECL_NAME (ztt_decl)),
+                       "_ZTT", 4) == 0))
+        {
+          tree values = DECL_INITIAL (ztt_decl);
+          struct varpool_node * vp_node = varpool_node_for_decl (ztt_decl);
+          if (vp_node->finalized
+              && TREE_ASM_WRITTEN (ztt_decl)
+              && (values != NULL_TREE)
+              && (TREE_CODE (values) == CONSTRUCTOR)
+              && (TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE))
+            {
+              tree call_expr = NULL_TREE;
+              unsigned HOST_WIDE_INT cnt;
+              constructor_elt *ce;
+
+              for (cnt = 0;
+                   VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (values),
+				cnt, ce);
+                   cnt++)
+                {
+                  tree value = ce->value;
+                  tree val_vtbl_decl = TREE_OPERAND (TREE_OPERAND (value, 0),
+                                                     0);
+                  int len1;
+                  int len2;
+
+                  if (TREE_CODE (val_vtbl_decl) == ADDR_EXPR
+                      && TREE_CODE (TREE_OPERAND (val_vtbl_decl, 0))
+                                                                   == VAR_DECL)
+                    val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
+
+                  gcc_assert (TREE_CODE (val_vtbl_decl) == VAR_DECL);
+
+                  len1 = strlen (IDENTIFIER_POINTER
+				     (DECL_NAME
+				          (TREE_OPERAND
+					     (base_class_decl_arg, 0))));
+                  len2 = strlen (IDENTIFIER_POINTER
+				     (DECL_NAME (val_vtbl_decl)));
+                  arg1 = build_string_literal (len1,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME
+						 (TREE_OPERAND
+						  (base_class_decl_arg, 0))));
+                  arg2 = build_string_literal (len2,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME (val_vtbl_decl)));
+
+                  already_registered = record_register_pairs (val_vtbl_decl,
+                                                              value,
+                                                              base_class);
+
+                  if (already_registered)
+                    continue;
+
+#ifdef VTV_DEBUG
+                  call_expr = build_call_expr
+		                        (vlt_register_pairs_fndecl, 7,
+					 base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint),
+					 arg1,
+					 build_int_cst (integer_type_node,
+							len1),
+					 arg2,
+					 build_int_cst (integer_type_node,
+							len2));
+#else
+                  call_expr = build_call_expr
+                                        (vlt_register_pairs_fndecl, 3,
+                                         base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint));
+#endif
+		  append_to_statement_list (call_expr, &body);
+                }
+            }
+        }
+    }
+}
+
+/* This function iterates through all the vtable it can find from the
+   BINFO of a class, to make sure we have found ALL of the vtables
+   that an object of that class could point to.  Generate calls to
+   __VLTRegisterPair for those vtable pointers that we find.  */
+
+static void
+register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
+                              int len1, tree str2, int len2, tree base_class)
+{
+  unsigned ix;
+  tree base_binfo;
+  tree vtable_decl;
+  bool already_registered;
+  int hint = 0;
+
+  if (binfo == NULL_TREE)
+    return;
+
+  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+    {
+      if ((!BINFO_PRIMARY_P (base_binfo)
+           || BINFO_VIRTUAL_P (base_binfo))
+          && (vtable_decl=get_vtbl_decl_for_binfo (base_binfo))
+          && !(DECL_VTABLE_OR_VTT_P(vtable_decl)
+               && DECL_CONSTRUCTION_VTABLE_P(vtable_decl)))
+        {
+          tree vtable_address = build_vtbl_address (base_binfo);
+          tree call_expr;
+
+          already_registered = record_register_pairs (vtable_decl,
+                                                      vtable_address,
+                                                      base_class);
+          if (!already_registered)
+            {
+#ifdef VTV_DEBUG
+              call_expr = build_call_expr (vlt_register_pairs_fndecl, 7,
+                                           arg1, vtable_address,
+                                           build_int_cst (integer_type_node,
+                                                          hint),
+                                           str1,
+                                           build_int_cst (integer_type_node,
+                                                          len1),
+                                           str2,
+                                           build_int_cst (integer_type_node,
+                                                          len2));
+#else
+              call_expr = build_call_expr (vlt_register_pairs_fndecl, 3,
+                                           arg1, vtable_address,
+                                           build_int_cst (integer_type_node,
+                                                         hint));
+#endif
+
+              append_to_statement_list (call_expr, &body);
+            }
+        }
+
+      register_other_binfo_vtables (base_binfo, body, arg1, str1, len1, str2,
+                                    len2, base_class);
+    }
+}
+
+/* The set of valid vtable pointers for any given class are stored in
+   a hash table.  For reasons of efficiency, that hash table size is
+   always a power of two.  In order to try to prevent re-sizing the
+   hash tables very often, we pass __VLTRegisterPair an initial guess
+   as to the number of entries the hashtable will eventually need
+   (rounded up to the nearest power of two).  This function take the
+   class information we have collected for a particular class and
+   calculates the hash table size guess.  */
+
+static int
+guess_num_vtable_pointers (struct vtv_graph_node *class_node)
+{
+  tree vtbl;
+  int total_num_vtbls = 0;
+  int num_vtbls_power_of_two = 1;
+  unsigned i;
+
+  for (i = 0; i < num_vtable_map_nodes; ++i)
+    if (bitmap_bit_p (class_node->descendants, i))
+      {
+        tree class_type = vtbl_map_nodes_array[i]->class_info->class_type;
+        for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
+             vtbl = DECL_CHAIN (vtbl))
+          {
+            total_num_vtbls ++;
+            if (total_num_vtbls > num_vtbls_power_of_two)
+              num_vtbls_power_of_two <<= 1;
+          }
+      }
+  return num_vtbls_power_of_two;
+}
+
+/* This function goes through our internal class hierarchy & vtable
+   pointer data structure and outputs calls to __VLTRegisterPair for
+   every class-vptr pair (for those classes whose vtable would be
+   output in the current compilation unit).  These calls get put into
+   our constructor initialization function.  */
+
+static bool
+register_all_pairs (tree body)
+{
+  struct vtbl_map_node *current;
+  tree base_ptr_var_decl;
+
+  bool registered_at_least_one = false;
+
+  for (current = vtbl_map_nodes; current; current = current->next)
+    {
+      unsigned i;
+      tree base_class = current->class_info->class_type;
+      int size_hint = guess_num_vtable_pointers (current->class_info);
+      base_ptr_var_decl = current->vtbl_map_decl;
+
+      gcc_assert (current->class_info != NULL);
+
+      for (i = 0; i < num_vtable_map_nodes; ++i)
+        if (bitmap_bit_p (current->class_info->descendants, i))
+          {
+            struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_array[i];
+            tree class_type = vtbl_class_node->class_info->class_type;
+
+            if (class_type
+                && (TREE_CODE (class_type) == RECORD_TYPE))
+            {
+              tree new_type;
+              tree arg1;
+              tree call_expr;
+              bool already_registered;
+
+              tree binfo = TYPE_BINFO (class_type);
+              tree vtable_decl;
+              bool vtable_should_be_output = false;
+
+              vtable_decl = CLASSTYPE_VTABLES (class_type);
+
+              /* Handle main vtable for this class. */
+
+              if (vtable_decl)
+                vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
+
+              if (vtable_decl && vtable_should_be_output
+                  && BINFO_VTABLE (binfo))
+                {
+                  tree vtable_address = build_vtbl_address (binfo);
+                  int len1  = IDENTIFIER_LENGTH
+                                               (DECL_NAME (base_ptr_var_decl));
+                  int len2  = IDENTIFIER_LENGTH (DECL_NAME (vtable_decl));
+                  tree str1 = build_string_literal (len1,
+                                                    IDENTIFIER_POINTER
+                                                    (DECL_NAME
+                                                     (base_ptr_var_decl)));
+                  tree str2 = build_string_literal (len2,
+                                                    IDENTIFIER_POINTER
+                                                    (DECL_NAME (vtable_decl)));
+
+                  already_registered = record_register_pairs (vtable_decl,
+                                                              vtable_address,
+                                                              base_class);
+
+                  if (!already_registered)
+                    {
+                      new_type = build_pointer_type (TREE_TYPE
+                                                     (base_ptr_var_decl));
+                      arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+#ifdef VTV_DEBUG
+                      /* This call expr has the 3 "real" arguments, plus 4
+                         debugging arguments.  Eventually it will be replaced
+                         with the one just below it, which only has the 2 real
+                         arguments.  */
+                      call_expr = build_call_expr
+                          (vlt_register_pairs_fndecl, 7,
+                           arg1, vtable_address,
+                           build_int_cst (integer_type_node, size_hint),
+                           str1, build_int_cst (integer_type_node,
+                                                len1),
+                           str2,  build_int_cst (integer_type_node,
+                                                 len2));
+#else
+                      call_expr = build_call_expr
+                          (vlt_register_pairs_fndecl, 3,
+                           arg1, vtable_address,
+                           build_int_cst (integer_type_node, size_hint));
+#endif
+                      append_to_statement_list (call_expr, &body);
+
+                      registered_at_least_one = true;
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via virtual inheritance.   */
+                      register_vptr_fields (arg1, base_class, class_type,
+                                            body);
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via multiple inheritance.   */
+                      register_other_binfo_vtables (binfo, body, arg1, str1,
+                                                    len1, str2, len2,
+                                                    base_class);
+                    }
+                }
+            }
+          }
+    }
+
+  return registered_at_least_one;
+}
+
+/* Given a tree containing a class type (RECORD_TYPE), this function
+   finds and returns the class hierarchy node for that class in our
+   data structure.  */
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+  tree class_decl = TREE_CHAIN (class_type);
+  tree class_name_id;
+  struct vtbl_map_node *vtbl_node;
+
+  if (class_decl)
+    class_name_id = DECL_ASSEMBLER_NAME (class_decl);
+  else
+    class_name_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
+
+  vtbl_node = vtbl_map_get_node (class_name_id);
+
+  if (vtbl_node)
+    return vtbl_node->class_info;
+
+  return NULL;
+}
+
+/* This function adds an edge to our class hierarchy graph.  */
+
+static void
+add_edge_to_graph (struct vtv_graph_node ***edge_array, unsigned *num_entries,
+                   unsigned *max_entries, struct vtv_graph_node *new_entry)
+{
+  /* Check array size, and re-size it if necessary.  */
+  if (*num_entries >= ((*max_entries) - 1))
+    {
+      unsigned new_size = 2 * (*max_entries);
+      unsigned i;
+      *edge_array = (struct vtv_graph_node **)
+          xrealloc (*edge_array, new_size * sizeof (struct vtv_graph_node *));
+
+      for (i = *max_entries; i < new_size; ++i)
+        (*edge_array)[i] = NULL;
+      *max_entries = new_size;
+    }
+
+  (*edge_array)[*num_entries] = new_entry;
+  *num_entries = (*num_entries) + 1;
+}
+
+/* Add base class/derived class pair to our internal class hierarchy
+   data structure.  */
+
+static void
+add_hierarchy_pair (struct vtv_graph_node *base_node,
+                    struct vtv_graph_node *derived_node)
+{
+  add_edge_to_graph (&(base_node->children), &(base_node->num_children),
+                     &(base_node->max_children), derived_node);
+  add_edge_to_graph (&(derived_node->parents), &(derived_node->num_parents),
+                     &(derived_node->max_parents), base_node);
+}
+
+/* This functions adds a new base class/derived class relationship to
+   our class hierarchy data structure.  Both parameters are trees
+   representing the class types, i.e. RECORD_TYPE trees.  */
+
+static void
+update_class_hierarchy_information (tree base_class,
+                                    tree derived_class)
+{
+  struct vtv_graph_node *base_node = find_graph_node (base_class);
+  struct vtv_graph_node *derived_node = find_graph_node (derived_class);
+
+  add_hierarchy_pair (base_node, derived_node);
+}
+
+/* Generate an undefined variable (a reference) to a varible defined in the
+   vtv_init libraty. In that way, if the a module is not linked with the
+   vtv_init library, the linker will generate an undefined symbol error.
+   Which is much better that getting a segmentation violation at runtime.
+
+   For more information, see comments in libstdc++-v3/libsupc++/vtv_init.cc */
+static void
+create_undef_reference_to_vtv_init(tree register_pairs_body)
+{
+  const char * vtv_init_undef_var = "__vtv_defined_in_vtv_init_lib";
+  tree var_decl;
+  tree init_zero;
+
+  var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                          get_identifier(vtv_init_undef_var),
+                          TREE_TYPE  (integer_zero_node));
+  TREE_PUBLIC (var_decl) = 1;
+  DECL_EXTERNAL (var_decl) = 1;
+  TREE_STATIC (var_decl) = 1;
+  SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (vtv_init_undef_var));
+  DECL_ARTIFICIAL (var_decl) = 1;
+  TREE_READONLY (var_decl) = 0;
+  DECL_IGNORED_P (var_decl) = 1;
+  DECL_PRESERVE_P (var_decl) = 1;
+  varpool_finalize_decl (var_decl);
+
+  /* Store a value in the undefined variable to force the creation of a
+     a reference */
+  init_zero = build2 (MODIFY_EXPR, TREE_TYPE (var_decl), var_decl,
+                      integer_zero_node);
+  append_to_statement_list (init_zero, &register_pairs_body);
+
+}
+
+/* This function calls register_all_pairs, which actually generates
+   all the calls to __VLTRegisterPair (in the verification constructor
+   init function).  It also generates the calls to
+   __VLTChangePermission, if the verification constructor init
+   function is going into the preinit array.  */
+
+bool
+vtv_register_class_hierarchy_information (tree register_pairs_body)
+{
+  bool registered_something = false;
+
+  init_functions ();
+
+  /* TODO: Temp fix. Needs to be tightened.  */
+  if (num_vtable_map_nodes == 0)
+    return registered_something;
+
+  /* Add class hierarchy pairs to the vtable map data structure. */
+  registered_something = register_all_pairs (register_pairs_body);
+
+  if (registered_something)
+  {
+      /* If this function is going into the preinit_array, then we
+         need to manually call __VLTChangePermission, rather than
+         depending on initialization prioritys in vtv_init. */
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          /* Pass __VLTP_READ_WRITE value as defined in vtv_rts.h */
+          tree arg_read_write = build_int_cst (integer_type_node, 1);
+          tree arg_read_only = build_int_cst (integer_type_node, 0);
+
+          tree call_rw_expr = build_call_expr (vlt_change_permission_fndecl,
+                                               1, arg_read_write);
+          tree_stmt_iterator i = tsi_start(register_pairs_body);
+          /* Insert at the beginning of the register pairs routine */
+          tsi_link_before(&i, call_rw_expr, TSI_SAME_STMT);
+
+          tree call_r_expr = build_call_expr (vlt_change_permission_fndecl,
+                                              1, arg_read_only);
+          append_to_statement_list (call_r_expr, &register_pairs_body);
+        }
+
+      if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
+        create_undef_reference_to_vtv_init(register_pairs_body);
+  }
+
+  return registered_something;
+}
+
+
+/* Generate the special constructor function that calls
+   __VLTChangePermission and __VLTRegisterPairs, and give it a very
+   high initialization priority.  */
+
+void
+vtv_generate_init_routine(const char * filename)
+{
+  const char * cwd = filename;
+  char temp_name[58];
+  tree register_pairs_body;
+  char * cptr;
+  int i;
+  bool vtable_classes_found = false;
+
+  /* The last part of the directory tree will be where it
+     differentiates; the first part may be the same. */
+  if (strlen (cwd) > 50)
+    {
+      int pos = (strlen (cwd) - 50);
+      cwd = cwd + pos;
+    }
+
+  /* TODO: Are these all the chars we need to map? */
+  sprintf (temp_name, "%.50s.vtable", cwd);
+  for (cptr = temp_name, i = 0;
+       (cptr[0] != '\0') && (i < 50);
+       cptr++, i++)
+    if ((cptr[0] == '/') || (cptr[0] == '-') || (cptr[0] == '+'))
+      cptr[0] = '_';
+
+  push_lang_context (lang_name_c);
+
+  /* The priority for this init function (constructor) is carefully
+     chosen so that it will happen after the calls to unprotect the
+     memory used for vtable verification and before the memory is
+     protected again */
+  register_pairs_body =
+   vtv_start_verification_constructor_init_function ((const char *) temp_name);
+
+  vtable_classes_found =
+      vtv_register_class_hierarchy_information (register_pairs_body);
+
+  if (vtable_classes_found)
+    {
+
+      current_function_decl =
+       vtv_finish_verification_constructor_init_function (register_pairs_body);
+      allocate_struct_function (current_function_decl, false);
+      TREE_STATIC (current_function_decl) = 1;
+      TREE_USED (current_function_decl) = 1;
+      DECL_PRESERVE_P (current_function_decl) = 1;
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          DECL_STATIC_CONSTRUCTOR (current_function_decl) = 0;
+          assemble_vtv_preinit_initializer (current_function_decl);
+        }
+
+      gimplify_function_tree (current_function_decl);
+      cgraph_add_new_function (current_function_decl, false);
+
+      cgraph_process_new_functions ();
+    }
+  pop_lang_context ();
+}
+
+/* This funtion takes a tree containing a class type, and it either
+   finds the existing vtbl_map_node for that class in our data
+   structure, or it creates a new node and adds it to the data
+   structure if there is not one for the class already.  As part of
+   this process it also creates the global vtable map variable for the
+   class.  */
+
+struct vtbl_map_node *
+vtable_find_or_create_map_decl (tree base_type)
+{
+  tree base_decl = TREE_CHAIN (base_type);
+  tree base_id;
+  tree var_decl = NULL;
+  char *var_name = NULL;
+  struct vtbl_map_node *vtable_map_node = NULL;
+
+
+  /* Verify the type has an associated vtable */
+  if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
+    return NULL;
+
+  if (base_decl)
+    base_id = DECL_ASSEMBLER_NAME (base_decl);
+  else
+    base_id = DECL_ASSEMBLER_NAME (TYPE_NAME (base_type));
+
+  /* Create map lookup symbol for base class */
+  var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
+                       "E12__vtable_mapE", NULL));
+  if (base_id)
+    /* We've already created the variable; just look it.  */
+    vtable_map_node = vtbl_map_get_node (base_id);
+
+  if (!vtable_map_node || (vtable_map_node->vtbl_map_decl == NULL_TREE))
+    {
+      /* If we haven't already created the *__vtable_map
+         global variable for this class, do so now, and
+         add it to the varpool, to make sure it gets saved
+         and written out.  */
+
+      char *sect_name = NULL;
+      tree var_type = build_pointer_type (void_type_node);
+      tree initial_value = build_int_cst (make_node (INTEGER_TYPE), 0);
+
+      var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                              get_identifier (var_name),
+                              var_type);
+      TREE_PUBLIC (var_decl) = 1;
+      DECL_EXTERNAL (var_decl) = 0;
+      TREE_STATIC (var_decl) = 1;
+      SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
+      DECL_ARTIFICIAL (var_decl) = 1;
+      /* We cannot mark this variable as read-only otherwise the gold
+         linker will not put it in the relro section. It seems if it
+         is marked as read-only, gold will put it in the .text
+         segment.  */
+      TREE_READONLY (var_decl) = 0;
+      DECL_IGNORED_P (var_decl) = 1;
+
+      /* Put these mmap variables in to data.rel.ro sections.
+	 It turns out this needs a previous fix in binutils as
+	 explained here:
+         http://sourceware.org/ml/binutils/2011-05/msg00083.html  */
+
+      sect_name = ACONCAT ((".data.rel.ro.", "vtable_map_vars",
+                            NULL));
+      DECL_SECTION_NAME (var_decl) = build_string (strlen (sect_name),
+                                                   sect_name);
+      DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl) = true;
+      DECL_COMDAT_GROUP (var_decl) = get_identifier (var_name);
+      DECL_INITIAL (var_decl) = initial_value;
+
+      varpool_finalize_decl (var_decl);
+      if (!vtable_map_node)
+        vtable_map_node = find_or_create_vtbl_map_node (base_type);
+      if (vtable_map_node->vtbl_map_decl == NULL_TREE)
+        vtable_map_node->vtbl_map_decl = var_decl;
+    }
+
+  gcc_assert (vtable_map_node);
+  return vtable_map_node;
+}
+
+/* This function is used to build up our class hierarchy data for a
+   particular class.  */
+
+static void
+vtv_save_base_class_info (tree type)
+{
+  if (flag_vtable_verify)
+    {
+      tree binfo =  TYPE_BINFO (type);
+      tree base_binfo;
+      struct vtbl_map_node *own_map;
+      int i;
+
+      /* First make sure to create the map for this record type.  */
+      own_map = vtable_find_or_create_map_decl (type);
+      if (own_map == NULL)
+        return;
+
+      /* Go through the list of all base classes for the current (derived)
+         type, make sure the *__vtable_map global variable for the base class
+	 exists, and add the base class/derived class pair to the class
+	 hierarchy information we are accumulating (for vtable pointer
+	 verification).  */
+      for (i = 0; BINFO_BASE_ITERATE(binfo, i, base_binfo); i++)
+        {
+          tree tree_val = BINFO_TYPE(base_binfo);
+          struct vtbl_map_node *vtable_map_node = NULL;
+
+          vtable_map_node = vtable_find_or_create_map_decl (tree_val);
+
+          if (vtable_map_node != NULL)
+            update_class_hierarchy_information (tree_val, type);
+        }
+    }
+}
+
+/* This function adds classes we are interested in to a list of classes that
+   is saved during pre-compiled header generation.  */
+
+void
+vtv_save_class_info (tree record)
+{
+  if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
+    return;
+
+  gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+  vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
+}
+
+
+/* This function goes through the list of classes we saved before the
+   pre-compiled header generation and calls vtv_save_base_class_info
+   on each one, to build up our class hierarchy data structure.  */
+
+void
+vtv_recover_class_info (void)
+{
+  tree current_class;
+  tree class_chain = vlt_saved_class_info;
+  while (class_chain != NULL_TREE)
+    {
+      current_class = TREE_VALUE (class_chain);
+      gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+
+      vtv_save_base_class_info (current_class);
+      class_chain = TREE_CHAIN (class_chain);
+    }
+
+  /* Let GC collect the memory associated to the chain */
+  vlt_saved_class_info = NULL_TREE;
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"

Property changes on: gcc/cp/vtable-class-hierarchy.c
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 193571)
+++ gcc/cp/mangle.c	(working copy)
@@ -3416,7 +3416,7 @@ mangle_decl_string (const tree decl)
 
 /* Return an identifier for the external mangled name of DECL.  */
 
-static tree
+tree
 get_mangled_id (tree decl)
 {
   tree id = mangle_decl_string (decl);
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 193571)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -5217,6 +5217,8 @@ extern void note_vague_linkage_fn		(tree
 extern tree build_artificial_parm		(tree, tree);
 extern bool possibly_inlined_p			(tree);
 extern int parm_index                           (tree);
+extern tree vtv_start_verification_constructor_init_function (const char *);
+extern tree vtv_finish_verification_constructor_init_function (tree);
 
 /* in error.c */
 extern void init_error				(void);
@@ -5304,6 +5306,7 @@ extern tree build_java_class_ref		(tree)
 extern tree integral_constant_value		(tree);
 extern tree decl_constant_value_safe	        (tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
+extern tree build_vtbl_address                  (tree);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
@@ -5530,6 +5533,11 @@ extern tree copied_binfo			(tree, tree);
 extern tree original_binfo			(tree, tree);
 extern int shared_member_p			(tree);
 
+/* in vtable-class-hierarchy.c */
+extern void vtv_compute_class_hierarchy_transitive_closure (void);
+extern void vtv_generate_init_routine           (const char *);
+extern void vtv_save_class_info                 (tree);
+extern void vtv_recover_class_info              (void);
 
 /* The representation of a deferred access check.  */
 
@@ -6013,6 +6021,7 @@ extern tree mangle_tls_init_fn			(tree);
 extern tree mangle_tls_wrapper_fn		(tree);
 extern bool decl_tls_wrapper_p			(tree);
 extern tree mangle_ref_init_variable		(tree);
+extern tree get_mangled_id                      (tree);
 
 /* in dump.c */
 extern bool cp_dump_tree			(void *, tree);
Index: gcc/timevar.def
===================================================================
--- gcc/timevar.def	(revision 193571)
+++ gcc/timevar.def	(working copy)
@@ -257,6 +257,7 @@ DEFTIMEVAR (TV_TREE_UNINIT           , "
 DEFTIMEVAR (TV_PLUGIN_INIT           , "plugin initialization")
 DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")
 DEFTIMEVAR (TV_GIMPLE_SLSR           , "straight-line strength reduction")
+DEFTIMEVAR (TV_VTABLE_VERIFICATION   , "tree vtable verification")
 
 /* Everything else in rest_of_compilation not included above.  */
 DEFTIMEVAR (TV_EARLY_LOCAL	     , "early local passes")
Index: gcc/flag-types.h
===================================================================
--- gcc/flag-types.h	(revision 193571)
+++ gcc/flag-types.h	(working copy)
@@ -200,4 +200,10 @@ enum fp_contract_mode {
   FP_CONTRACT_FAST = 2
 };
 
+/* flag_vtable_verify initialization levels. */
+enum vtv_priority {
+  VTV_NO_PRIORITY       = 0,  /* i.E. Do NOT do vtable verification. */
+  VTV_STANDARD_PRIORITY = 1,
+  VTV_PREINIT_PRIORITY  = 2
+};
 #endif /* ! GCC_FLAG_TYPES_H */
Index: gcc/tree-vtable-verify.c
===================================================================
--- gcc/tree-vtable-verify.c	(revision 0)
+++ gcc/tree-vtable-verify.c	(revision 0)
@@ -0,0 +1,1053 @@
+/*   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+    Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
+   before using them for virtual method dispatches.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "cp/cp-tree.h"
+#include "tm_p.h"
+#include "basic-block.h"
+#include "output.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "flags.h"
+#include "tree-inline.h"
+#include "tree-scalar-evolution.h"
+#include "diagnostic-core.h"
+#include "gimple-pretty-print.h"
+#include "toplev.h"
+#include "langhooks.h"
+
+#include "tree-vtable-verify.h"
+
+unsigned num_vtable_map_nodes = 0;
+
+static GTY(()) tree verify_vtbl_ptr_fndecl = NULL_TREE;
+
+unsigned int vtable_verify_main (void);
+static bool gate_tree_vtable_verify (void);
+static void build_vtable_verify_fndecl (void);
+
+/* The following few functions are for the vtbl pointer hash table
+   in the 'registered' field of the struct vtable_map_node.  The hash
+   table keeps track of which vtable pointers have been used in
+   calls to __VLTRegisterPair with that particular vtable map variable.  */
+
+/* This function checks to see if a particular VTABLE_DECL and OFFSET are
+   already in the 'registered' hash table for NODE.  */
+
+bool
+vtbl_map_node_registration_find (struct vtbl_map_node *node,
+                                 tree vtable_decl,
+                                 unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+
+  gcc_assert (node);
+  gcc_assert (node->registered);
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, NO_INSERT);
+
+  if (slot && (*slot) && (*slot)->offsets)
+    {
+      unsigned i;
+      for (i = 0; i < (*slot)->cur_offset; ++i)
+        if ((*slot)->offsets[i] == offset)
+          return true;
+    }
+
+  return false;
+}
+
+/* This function inserts VTABLE_DECL and OFFSET into the 'registered' 
+   hash table for NODE.  */
+
+void
+vtbl_map_node_registration_insert (struct vtbl_map_node *node,
+                                   tree vtable_decl,
+                                   unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+
+  if (!node || !(node->registered))
+    return;
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, INSERT);
+
+  if (!(*slot))
+    {
+      unsigned i;
+      struct vtable_registration *node;
+      node = (struct vtable_registration *)
+                                 xmalloc (sizeof (struct vtable_registration));
+      node->vtable_decl = vtable_decl;
+      node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));
+      for (i= 0; i < 10; ++i)
+        node->offsets[i] = 0;
+      node->offsets[0] = offset;
+      node->cur_offset = 1;
+      node->max_offsets = 10;
+      *slot = node;
+    }
+  else
+    {
+      /* We found the vtable_decl slot; we need to see if it already
+         contains the offset.  If not, we need to add the offset.  */
+      unsigned i;
+      bool found = false;
+      for (i = 0; (i < (*slot)->cur_offset) && !found; ++i)
+        if ((*slot)->offsets[i] == offset)
+          found = true;
+
+      if (!found)
+        {
+	  /* Re-size the offset array if necessary.*/
+          if ((*slot)->cur_offset == (*slot)->max_offsets)
+            {
+              unsigned new_max = 2 * (*slot)->max_offsets;
+              (*slot)->offsets = (unsigned *)
+                  xrealloc ((*slot)->offsets, new_max * sizeof (unsigned));
+
+              for (i = (*slot)->max_offsets; i < new_max; ++i)
+                (*slot)->offsets[i] = 0;
+              (*slot)->max_offsets = new_max;
+            }
+	  /* Insert the new offset. */
+          (*slot)->offsets[(*slot)->cur_offset] = offset;
+          (*slot)->cur_offset = (*slot)->cur_offset + 1;
+        }
+    }
+}
+
+/* Hashtable functions for vtable_registration hashtables.  */
+
+static hashval_t
+hash_vtable_registration (const void * p)
+{
+  const struct vtable_registration *n = (const struct vtable_registration *) p;
+  return (hashval_t) (DECL_UID (n->vtable_decl));
+}
+
+static int
+eq_vtable_registration (const void *p1, const void *p2)
+{
+  const struct vtable_registration *n1 =
+                                    (const struct vtable_registration *) p1;
+  const struct vtable_registration *n2 =
+                                    (const struct vtable_registration *) p2;
+  return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
+}
+
+/* End of hashtable functions for "registered" hashtables*/
+
+
+/* Here are the three data structures into which we insert vtable map nodes.
+   We use three data structures because of the vastly different ways we need
+   to find the nodes for various tasks (see comments in tree-vtable-verify.h
+   for more details.  */
+
+/* Vtable map variable nodes stored in a hash table.  */
+static htab_t vtbl_map_hash = NULL;
+
+/* Vtable map variable nodes stored in a linked list.  */
+struct vtbl_map_node *vtbl_map_nodes = NULL;
+
+/* Vtable map variable nodes stored in an array.  */
+struct vtbl_map_node **vtbl_map_nodes_array = NULL;
+
+/* This function inserts a vtable map variable NODE into the array.  */
+
+static void
+vtable_map_array_insert (struct vtbl_map_node *node)
+{
+  static unsigned array_size = 0;
+  unsigned i;
+
+  if (vtbl_map_nodes_array == NULL
+      || array_size == 0)
+    {
+      array_size = 16;
+      vtbl_map_nodes_array = (struct vtbl_map_node **)
+                       xmalloc (array_size * sizeof (struct vtbl_map_node *));
+      memset (vtbl_map_nodes_array, 0,
+              array_size * sizeof (struct vtbl_map_node *));
+    }
+  else if (node->uid >= array_size)
+    {
+      unsigned new_size = 2 * array_size;
+      vtbl_map_nodes_array = (struct vtbl_map_node **)
+          xrealloc (vtbl_map_nodes_array,
+                    new_size * sizeof (struct vtbl_map_node *));
+
+      for (i = array_size; i < new_size; ++i)
+        vtbl_map_nodes_array[i] = NULL;
+
+      array_size = new_size;
+    }
+
+  gcc_assert (node->uid < array_size);
+  gcc_assert (vtbl_map_nodes_array[node->uid] == NULL);
+
+  vtbl_map_nodes_array[node->uid] = node;
+}
+
+/* Hashtable functions for vtbl_map_hash.  */
+
+/* Returns a hash code for P.  */
+static hashval_t
+hash_vtbl_map_node (const void *p)
+{
+  const struct vtbl_map_node *n = (const struct vtbl_map_node *) p;
+  return (hashval_t) IDENTIFIER_HASH_VALUE (n->class_name);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+static int
+eq_vtbl_map_node (const void *p1, const void *p2)
+{
+  const struct vtbl_map_node *n1 = (const struct vtbl_map_node *) p1;
+  const struct vtbl_map_node *n2 = (const struct vtbl_map_node *) p2;
+  return (IDENTIFIER_HASH_VALUE (n1->class_name) ==
+          IDENTIFIER_HASH_VALUE (n2->class_name));
+}
+
+/* Return vtbl_map node for CLASS_NAME  without creating a new one.  */
+struct vtbl_map_node *
+vtbl_map_get_node (const_tree class_name)
+{
+  struct vtbl_map_node key;
+  struct vtbl_map_node **slot;
+
+  if (!vtbl_map_hash)
+    return NULL;
+
+  key.class_name = CONST_CAST2 (tree, const_tree, class_name);
+  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+                                                   NO_INSERT);
+  if (!slot)
+    return NULL;
+  return *slot;
+}
+
+/* Return vtbl_map node assigned to BASE_CLASS_TYPE.  Create new one
+   when needed.  */
+struct vtbl_map_node *
+find_or_create_vtbl_map_node (tree base_class_type)
+{
+  struct vtbl_map_node key;
+  struct vtbl_map_node *node;
+  struct vtbl_map_node **slot;
+  unsigned i;
+
+  if (!vtbl_map_hash)
+    vtbl_map_hash = htab_create (10, hash_vtbl_map_node,
+                                 eq_vtbl_map_node, NULL);
+
+  if (TREE_CHAIN (base_class_type))
+    key.class_name = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class_type));
+  else
+    key.class_name = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class_type));
+  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+                                                   INSERT);
+  if (*slot)
+    return *slot;
+
+  node = (struct vtbl_map_node *) xmalloc (sizeof (struct vtbl_map_node));
+  node->vtbl_map_decl = NULL_TREE;
+  node->class_name = key.class_name;
+  node->uid = num_vtable_map_nodes++;
+
+  node->class_info = (struct vtv_graph_node *)
+                                      xmalloc (sizeof (struct vtv_graph_node));
+  node->class_info->class_type = base_class_type;
+  node->class_info->class_uid = node->uid;
+  node->class_info->max_parents = 4;
+  node->class_info->max_children = 4;
+  node->class_info->num_parents = 0;
+  node->class_info->num_children = 0;
+  node->class_info->num_processed_children = 0;
+  node->class_info->parents = (struct vtv_graph_node **)
+                                xmalloc (4 * sizeof (struct vtv_graph_node *));
+  node->class_info->children = (struct vtv_graph_node **)
+                                xmalloc (4 * sizeof (struct vtv_graph_node *));
+  for (i = 0; i < 4; ++i)
+    {
+      node->class_info->parents[i] = NULL;
+      node->class_info->children[i] = NULL;
+    }
+
+  node->registered = htab_create (16, hash_vtable_registration,
+                                  eq_vtable_registration, NULL);
+  node->is_used = false;
+  node->next = vtbl_map_nodes;
+  if (vtbl_map_nodes)
+    vtbl_map_nodes->prev = node;
+
+  vtable_map_array_insert (node);
+
+  vtbl_map_nodes = node;
+  *slot = node;
+  return node;
+}
+
+/* This function take a tree type, NODE, and checks to see if the name
+   of the type is "__vtbl_ptr_type".  */
+
+static int
+type_name_is_vtable_pointer (tree node)
+{
+
+  if (TYPE_NAME (node))
+  {
+    if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
+      return (strcmp (IDENTIFIER_POINTER (TYPE_NAME (node)),
+                      "__vtbl_ptr_type") == 0);
+    else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
+             && DECL_NAME (TYPE_NAME (node)))
+      return (strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
+                      "__vtbl_ptr_type") == 0);
+    else
+      return 0;
+  }
+
+  return 0;
+}
+
+/* Given a gimple STMT, this function checks to see if the statement
+   is an assignment, the rhs of which is getting the vtable pointer
+   value out of an object.  (i.e. it's the value we need to verify
+   because its the vtable pointer that will be used for a virtual
+   call).  */
+
+static int
+is_vtable_assignment_stmt (gimple stmt)
+{
+
+  if (gimple_code (stmt) != GIMPLE_ASSIGN)
+    return 0;
+  else
+    {
+      tree lhs = gimple_assign_lhs (stmt);
+      tree rhs = gimple_assign_rhs1 (stmt);
+
+      if (TREE_CODE (lhs) != SSA_NAME)
+        return 0;
+
+      if (TREE_CODE (TREE_TYPE (lhs)) != POINTER_TYPE)
+        return 0;
+
+      if (TREE_CODE (TREE_TYPE (TREE_TYPE (lhs))) != POINTER_TYPE)
+        return 0;
+
+      if (! type_name_is_vtable_pointer (TREE_TYPE (TREE_TYPE (lhs))))
+        return 0;
+
+
+      if (TREE_CODE (rhs) != COMPONENT_REF)
+        return 0;
+
+      if (! (TREE_OPERAND (rhs, 1))
+          || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
+        return 0;
+
+      if (! (DECL_NAME (TREE_OPERAND (rhs, 1)))
+          || (strncmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (rhs, 1))),
+                       "_vptr.", 6) != 0))
+        return 0;
+
+      while ((TREE_OPERAND (rhs, 0))
+             && (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF))
+        rhs = TREE_OPERAND (rhs, 0);
+
+      if (! (TREE_OPERAND (rhs, 0))
+          || (TREE_CODE (TREE_OPERAND (rhs, 0)) != MEM_REF))
+        return 0;
+    }
+
+    return 1;
+}
+
+/* This function, given the BINFO for a virtual type, gets the vtable decl
+   for that BINFO.  */
+
+static tree
+my_get_vtbl_decl_for_binfo (tree binfo)
+{
+  tree decl;
+
+  decl = BINFO_VTABLE (binfo);
+  if (decl && TREE_CODE (decl) == POINTER_PLUS_EXPR)
+  {
+    gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR);
+    decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+  }
+  if (decl)
+    gcc_assert (TREE_CODE (decl) == VAR_DECL);
+
+  return decl;
+}
+
+/* STMT is a gimple statment that uses OLD_VAR.  This function finds the
+   use of OLD_VAR in STMT and replaces it with NEW_VAR.  STMT is either
+   an assignment statement or a call statement.  */
+
+static bool
+find_and_replace_var (gimple stmt, tree old_var, tree new_var)
+{
+  bool found = false;
+
+  if (!stmt || ! old_var || !new_var)
+    return found;
+
+  if ((TREE_CODE (old_var) != SSA_NAME)
+      || (TREE_CODE (new_var) != SSA_NAME))
+    return found;
+
+  if (gimple_code (stmt) == GIMPLE_ASSIGN)
+    {
+      if (get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS)
+        {
+          if (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+              && (gimple_assign_rhs1 (stmt) == old_var))
+            {
+              gimple_assign_set_rhs1 (stmt, new_var);
+              found = true;
+            }
+          else if (TREE_CODE (gimple_assign_rhs1 (stmt)) == MEM_REF
+                   && TREE_CODE (TREE_OPERAND (gimple_assign_rhs1 (stmt), 0))
+                                                                   == SSA_NAME)
+            {
+              if (TREE_OPERAND (gimple_assign_rhs1 (stmt), 0) == old_var)
+                {
+                  tree mr_type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+                  tree mem_ref = build2 (MEM_REF, mr_type, new_var,
+                                         TREE_OPERAND
+                                               (gimple_assign_rhs1 (stmt), 1));
+                  gimple_assign_set_rhs1 (stmt, mem_ref);
+                  found = true;
+                }
+            }
+        }
+      else if (get_gimple_rhs_class (gimple_expr_code (stmt))
+                                                          != GIMPLE_SINGLE_RHS)
+        {
+          if (gimple_assign_rhs1 (stmt) == old_var)
+            {
+              gimple_assign_set_rhs1 (stmt, new_var);
+              found = true;
+            }
+          else if (gimple_assign_rhs2 (stmt) == old_var)
+            {
+              gimple_assign_set_rhs2 (stmt, new_var);
+              found = true;
+            }
+        }
+    }
+  else if ((gimple_code (stmt) == GIMPLE_CALL)
+           && (TREE_CODE (gimple_call_fn (stmt)) == OBJ_TYPE_REF)
+           && (TREE_OPERAND (gimple_call_fn (stmt), 0) == old_var))
+    {
+        TREE_OPERAND (gimple_call_fn (stmt), 0) = new_var;
+        found = true;
+    }
+
+  if (found)
+    update_stmt (stmt);
+
+  return found;
+}
+
+/* Given a PHI_STMT, this function searches backwards find a def_stmt for
+   one of the PHI_STMT's args, which defines an SSA_NAME.  It returns the
+   def_stmt.  */
+
+static gimple
+get_phi_def_stmt (gimple phi_stmt)
+{
+  /* This function is based on the assumption that all arguments of a
+     phi variable are really variations of the same variable, and
+     therefore must have the same type, so it doesn't matter which phi
+     argument we use to find the variable's type.  Therefore we will
+     use the first argument that is an SSA_NAME.  */
+
+  phi_arg_d *phi_arg = NULL;
+  tree phi_ssa = NULL_TREE;
+  unsigned i;
+
+  if (gimple_code (phi_stmt) != GIMPLE_PHI)
+    return NULL;
+
+  for (i = 0; i < gimple_phi_num_args (phi_stmt); i++)
+    {
+      phi_arg = gimple_phi_arg (phi_stmt, i);
+      phi_ssa = phi_arg->def;
+      if (TREE_CODE (phi_ssa) == SSA_NAME)
+	break;
+    }
+
+  gcc_assert (TREE_CODE (phi_ssa) == SSA_NAME);
+
+  return SSA_NAME_DEF_STMT (phi_ssa);
+}
+
+/* Search through all the statements in a basic block, searching for
+   virtual method calls.  For each virtual method dispatch, find the
+   vptr value used, and the statically declared type of the object;
+   retrieve the vtable map variable for the type of the object;
+   generate a call to __VLTVerifyVtablePointer; and insert the
+   generated call into the basic block, after the point where the vptr
+   value is gotten out of the object and before the virtual method
+   dispatch. Make the virtual method dispatch depend on the return
+   value from the verification call, so that subsequent optimizations
+   cannot reorder the two calls.  */
+
+static void
+verify_bb_vtables (basic_block bb)
+{
+  gimple_seq stmts;
+  gimple stmt = NULL;
+  gimple_stmt_iterator gsi_vtbl_assign;
+  gimple_stmt_iterator gsi_virtual_call;
+  tree this_object;
+
+  /* Search the basic block to see if it contains a virtual method
+     call, i.e. a call with the tree code OBJ_TYPE_REF  */
+
+  stmts = bb_seq (bb);
+  gsi_virtual_call = gsi_start (stmts);
+  this_object = NULL_TREE;
+  for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
+    {
+      stmt = gsi_stmt (gsi_virtual_call);
+      if (gimple_code (stmt) == GIMPLE_CALL)
+        {
+          tree fncall = gimple_call_fn (stmt);
+          if (TREE_CODE (fncall) == OBJ_TYPE_REF)
+            {
+              bool found = false;
+              tree vtable_offset_var = NULL_TREE;
+              gimple def_stmt;
+              gimple prev_use = NULL;
+
+              /* The first argument to the function must be "this", a pointer
+                 to the object itself.  */
+
+              this_object = gimple_call_arg (stmt, 0);
+
+              /* Get the SSA variable that contains the dereferenced _vptr
+                 field + table start offset.  */
+
+              if (TREE_OPERAND (fncall, 0)
+                  && TREE_CODE (TREE_OPERAND (fncall, 0)) == SSA_NAME)
+                {
+                  tree rhs = NULL_TREE;
+                  gimple phi_stmt = NULL;
+                  gimple phi_prev_use = NULL;
+                  bool  found_phi = false;
+
+                  vtable_offset_var = TREE_OPERAND (fncall, 0);
+
+                  prev_use = stmt;
+                  def_stmt = SSA_NAME_DEF_STMT (vtable_offset_var);
+
+		  /* Search backwards through the def_stmt chain, to try
+		     to find the assignment statement where the rhs of
+		     the assignment contains the "._vptr" field (the vtable
+		     pointer). */
+
+		  /*
+                  while (gimple_code (def_stmt) == GIMPLE_PHI)
+                    {
+                      if (!found_phi)
+                        {
+                          phi_prev_use = prev_use;
+                          phi_stmt = def_stmt;
+                          found_phi = true;
+                        }
+                      def_stmt = get_phi_def_stmt (def_stmt);
+                    }
+		  */
+
+                  gcc_assert (def_stmt != NULL);
+                  gcc_assert (gimple_code (def_stmt) == GIMPLE_ASSIGN);
+
+                  if (gimple_assign_lhs (def_stmt)
+                      && TREE_CODE (gimple_assign_lhs (def_stmt)) == SSA_NAME
+                      && get_gimple_rhs_class (gimple_expr_code (def_stmt))
+                                                          == GIMPLE_SINGLE_RHS)
+                    rhs = gimple_assign_rhs1 (def_stmt);
+
+                  if (rhs
+                      && TREE_CODE (rhs) == MEM_REF
+                      && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
+                    {
+                      prev_use = def_stmt;
+                      def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
+                    }
+
+		  /*
+                  if (gimple_code (def_stmt) == GIMPLE_PHI)
+                    {
+                      if (!found_phi)
+                        {
+                          phi_prev_use = prev_use;
+                          phi_stmt = def_stmt;
+                          found_phi = true;
+                        }
+                      def_stmt = get_phi_def_stmt (def_stmt);
+                    }
+		  */
+                  while (def_stmt
+                         && !is_vtable_assignment_stmt (def_stmt))
+                    {
+                      tree lhs = gimple_assign_lhs (def_stmt);
+                      if (!lhs
+                          || !TREE_CODE (lhs) == SSA_NAME)
+                        {
+                          def_stmt = NULL;
+                          break;
+                        }
+                      if (! def_stmt)
+                        break;
+
+                      if (gimple_assign_rhs1 (def_stmt)
+                          && TREE_CODE (gimple_assign_rhs1 (def_stmt))
+                                                                   == SSA_NAME)
+                        {
+                          prev_use = def_stmt;
+                          rhs = gimple_assign_rhs1 (def_stmt);
+                          def_stmt = SSA_NAME_DEF_STMT (rhs);
+                        }
+                      else if ((get_gimple_rhs_class
+                                  (gimple_expr_code (def_stmt))
+			                                  != GIMPLE_SINGLE_RHS)
+                               && gimple_assign_rhs2 (def_stmt)
+                               && TREE_CODE (gimple_assign_rhs2 (def_stmt))
+                                                                   == SSA_NAME)
+                        {
+                          prev_use = def_stmt;
+                          rhs = gimple_assign_rhs2 (def_stmt);
+                          def_stmt = SSA_NAME_DEF_STMT (rhs);
+                        }
+                      else
+                        def_stmt = NULL;
+
+                      if (!def_stmt)
+                        break;
+
+		      /*
+                      if (def_stmt != NULL
+                          && gimple_code (def_stmt) == GIMPLE_PHI)
+                        {
+                          if (!found_phi)
+                            {
+                              phi_prev_use = prev_use;
+                              phi_stmt = def_stmt;
+                              found_phi = true;
+                            }
+                          def_stmt = get_phi_def_stmt (def_stmt);
+                        }
+		      */
+                    }
+
+		  /* If we found the vtable pointer assignment statement by
+		     itself, we also need to find it within the basic block
+		     statement sequence, so that we can insert our statements
+		     into the sequence.
+
+		     The following loop looks for the assignment statement
+		     within the basic block's sequence of statements.  */
+
+                  if (def_stmt
+                      && is_vtable_assignment_stmt (def_stmt))
+                    {
+                      basic_block def_bb;
+                      gimple_seq def_bb_stmts;
+
+                      if (found_phi)
+                        def_bb = gimple_bb (phi_stmt);
+                      else
+                        def_bb = gimple_bb (def_stmt);
+
+                      def_bb_stmts = bb_seq (def_bb);
+
+                      if (found_phi)
+                        {
+                          /* Insertion point is first stmt in bb */
+                          gsi_vtbl_assign = gsi_after_labels (def_bb);
+                          found = true;
+                        }
+                      else
+                        gsi_vtbl_assign = gsi_start (def_bb_stmts);
+
+                      for (; !gsi_end_p (gsi_vtbl_assign) && !found;
+                           gsi_next (&gsi_vtbl_assign))
+                        {
+                          stmt = gsi_stmt (gsi_vtbl_assign);
+                          if (stmt == def_stmt)
+                            {
+                              found = true;
+                              break;
+                            }
+                        }
+
+                      if (found)
+                        {
+                          tree object_rhs = TREE_TYPE (this_object);
+                          tree lhs;
+                          tree vtbl_var_decl = NULL_TREE;
+                          tree vtbl = NULL_TREE;
+                          tree var_id;
+                          gimple_seq pre_p = NULL;
+                          struct vtbl_map_node *vtable_map_node = NULL;
+                          tree vtbl_decl = NULL_TREE;
+
+
+                          if (found_phi)
+                            lhs = gimple_phi_result (phi_stmt);
+                          else
+                            lhs = gimple_assign_lhs (stmt);
+
+                          /* Now we have found the virtual method dispatch
+                             and the preceding access of the _vptr.*
+                             field... Now we need to find the vtable for
+                             the base class (statically declared type) of
+                             the object, so we can use the right vtable
+			     map variable.  */
+
+                          found = true;
+                          rhs = gimple_assign_rhs1 (def_stmt);
+
+			  /* First try to get the type out of the 'this'
+			     object. */
+                          if (TREE_CODE (object_rhs) == POINTER_TYPE
+                              && TREE_CODE (TREE_TYPE (object_rhs))
+                                                                == RECORD_TYPE)
+                            rhs = TREE_TYPE (object_rhs);
+                          else if (TREE_CODE (object_rhs) == REFERENCE_TYPE
+                                   && TREE_CODE (TREE_TYPE (object_rhs))
+                                                                == RECORD_TYPE)
+                            rhs = TREE_TYPE (object_rhs);
+			  /* The type of the 'this' object is not usable
+			     (usually due to optimizations); try to get the
+			     type out of the rhs of the vtable pointer
+			     assignment statement.  */
+                          else if (TREE_CODE (rhs) == COMPONENT_REF)
+                            {
+                              while (TREE_CODE (TREE_OPERAND (rhs, 0))
+                                                              == COMPONENT_REF)
+                                rhs = TREE_OPERAND (rhs, 0);
+                              if (TREE_CODE (rhs) == COMPONENT_REF
+                                  && (TREE_CODE (TREE_OPERAND (rhs, 0))
+                                                                    == MEM_REF)
+                                  && (TREE_CODE (TREE_TYPE
+                                       (TREE_OPERAND (rhs, 0)))
+                                                               == RECORD_TYPE))
+                                rhs = TREE_TYPE (TREE_OPERAND (rhs, 0));
+                              else
+                                rhs = NULL_TREE;
+                            }
+                          else
+                            rhs = NULL_TREE;
+
+			  /* Make sure we found a valid type...*/
+                          if (rhs
+                              && TREE_CODE (rhs) == RECORD_TYPE
+                              && TYPE_BINFO (rhs))
+                            {
+			      /* Get the vtable for the type.  */
+                              vtbl_var_decl = my_get_vtbl_decl_for_binfo
+                                                            (TYPE_BINFO (rhs));
+                              vtbl = BINFO_VTABLE (TYPE_BINFO (rhs));
+
+                              if (!vtbl_var_decl || !vtbl)
+                                /* Problem:  This does NOT end up checking
+                                   virtual functions if there is NO
+                                   inheritance involved.  */
+                                continue;
+
+                              vtbl_decl = vtbl_var_decl;
+
+                              if (TREE_CODE (TREE_TYPE (vtbl)) == POINTER_TYPE)
+                                force_gimple_operand (vtbl, &pre_p, 1, NULL);
+
+                             if (TREE_CHAIN (rhs))
+                                var_id = DECL_ASSEMBLER_NAME (TREE_CHAIN
+                                                                        (rhs));
+                              else
+                                var_id = DECL_ASSEMBLER_NAME (TYPE_NAME (rhs));
+
+                              vtable_map_node = vtbl_map_get_node (var_id);
+                              if (vtable_map_node)
+                                {
+                                  vtbl_var_decl =
+                                                vtable_map_node->vtbl_map_decl;
+                                  vtable_map_node->is_used = true;
+                                }
+                              else
+                                vtbl_var_decl = NULL;
+                            }
+
+                          /* Build  verify_vtbl_ptr_fndecl */
+
+                          build_vtable_verify_fndecl ();
+
+                          /* Given the vtable pointer for the base
+                             class of the object, build the call to
+                             __VLTVerifyVtablePointer to verify that
+                             the object's vtable pointer (contained in
+                             lhs) is in the set of valid vtable
+                             pointers for the base class.  */
+
+                          if (verify_vtbl_ptr_fndecl && vtbl_var_decl)
+                            {
+                              tree expr_tree = NULL_TREE;
+                              struct gimplify_ctx gctx;
+                              const char *vtable_name = "<unknown>";
+                              gimple assign_stmt;
+                              tree tmp0;
+                              bool status;
+
+                              int len1 = 0;
+                              int len2 = 0;
+
+                              if (TREE_CODE (vtbl_decl) == VAR_DECL)
+                                vtable_name = IDENTIFIER_POINTER
+                                                       (DECL_NAME (vtbl_decl));
+
+                              push_gimplify_context (&gctx);
+                              len1 = strlen (IDENTIFIER_POINTER
+				                  (DECL_NAME (vtbl_var_decl)));
+                              len2 = strlen (vtable_name);
+
+                              /* Call different routines if we are
+                                 interested in trace information to
+                                 triage problems */
+#ifdef VTV_DEBUG
+                              expr_tree = build_call_expr
+			             (verify_vtbl_ptr_fndecl, 6,
+				      build1 (ADDR_EXPR,
+						 TYPE_POINTER_TO
+						   (TREE_TYPE (vtbl_var_decl)),
+                                                 vtbl_var_decl),
+				      lhs,
+				      build_string_literal
+				                  (len1,
+						   IDENTIFIER_POINTER
+						       (DECL_NAME
+							    (vtbl_var_decl))),
+				      build_int_cst (integer_type_node,
+						     len1),
+				      build_string_literal (len2, vtable_name),
+				      build_int_cst (integer_type_node,
+						     len2));
+#else
+                              expr_tree = build_call_expr
+		                     (verify_vtbl_ptr_fndecl, 2,
+				      build1 (ADDR_EXPR,
+				                 TYPE_POINTER_TO
+                                                   (TREE_TYPE (vtbl_var_decl)),
+                                                 vtbl_var_decl),
+                                      lhs);
+#endif
+
+                              /* Assign the result of the call to the
+                                 original variable receiving the
+                                 assignment of the object's vtable
+                                 pointer; mark that variable to be
+                                 updated by update_ssa.  */
+
+			      cfun->gimple_df->ssa_renaming_needed = 1;
+
+                              /* Insert the new call just after the
+                                 original assignment of the object's
+                                 vtable pointer.  */
+
+                              tmp0 = make_temp_ssa_name (TREE_TYPE (lhs),
+                                                         NULL, "VTV");
+                              assign_stmt = gimplify_assign (tmp0, expr_tree,
+                                                             &pre_p);
+
+                              if (found_phi)
+                                prev_use = phi_prev_use;
+
+                              status = find_and_replace_var (prev_use, lhs,
+                                                             tmp0);
+                              update_stmt (assign_stmt);
+                              gcc_assert (status == true);
+                              pop_gimplify_context (NULL);
+
+                              if (found_phi)
+                                gsi_insert_seq_before (&gsi_vtbl_assign,
+                                                       pre_p, GSI_NEW_STMT);
+                              else
+                                gsi_insert_seq_after (&gsi_vtbl_assign, pre_p,
+                                                      GSI_NEW_STMT);
+                            }
+                          else
+                            internal_error ("if (verify_vtbl_ptr_fndecl && vtbl_var_decl) FAILED.");
+                        }
+                      else
+                        internal_error ("if (found) FAILED.");
+                    }
+                }
+              else
+                internal_error ("if fncall...FAILED.");
+            }
+        }
+    }
+}
+
+
+/* As part of vtable verification the compiler generates and inserts
+   calls to __VLTVerifyVtablePointer, which is in libstdc++.  This
+   function builds and initializes the function decl that is used
+   in generating those function calls.
+
+   In addition to __VLTVerifyVtablePointer there is also
+   __VLTVerifyVtablePointerDebug which can be used in place of
+   __VLTVerifyVtablePointer, and which takes extra parameters and
+   outputs extra information, to help debug problems.  The debug
+   version of this function is generated and used if the compiler is
+   built with "-DVTV_DEBUG".
+
+   The signatures for these functions are:
+
+   void * __VLTVerifyVtablePointer (void **, void*);
+   void * __VLTVerifyVtablePointerDebug (void**, void *, char *, int, char *,
+                                         int);
+*/
+
+
+static void
+build_vtable_verify_fndecl (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree type = build_pointer_type (void_type_node);
+  struct lang_decl *ld;
+#ifdef VTV_DEBUG
+  tree char_ptr_type = build_pointer_type (char_type_node);
+#endif
+
+  if (verify_vtbl_ptr_fndecl != NULL_TREE)
+    return;
+
+  ld = ggc_alloc_cleared_lang_decl (sizeof (struct lang_decl_fn));
+  ld->u.base.selector = 1;
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_ptr_type));
+
+#ifdef VTV_DEBUG
+  /* Start: Arg types for debugging version of function.  */
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   integer_type_node));
+  /* End: Arg types for debugging...*/
+#endif
+
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  type = build_function_type (type, arg_types);
+
+#ifdef VTV_DEBUG
+  verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointerDebug",
+                                          type);
+#else
+  verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointer", type);
+#endif
+
+  TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
+  DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
+      = tree_cons (get_identifier ("leaf"), NULL,
+                   DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
+  TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
+  DECL_PRESERVE_P (verify_vtbl_ptr_fndecl) = 1;
+  DECL_LANG_SPECIFIC (verify_vtbl_ptr_fndecl) = ld;
+  SET_DECL_LANGUAGE (verify_vtbl_ptr_fndecl, lang_cplusplus);
+}
+
+/* Main function, called from pass->excute().  Loop through all the
+   basic blocks in the current function, passing them to
+   verify_bb_vtables, which searches for virtual calls, and inserts
+   calls to __VLTVerifyVtablePointer.  */
+
+unsigned int
+vtable_verify_main (void)
+{
+  unsigned int ret = 1;
+  basic_block bb;
+
+  FOR_ALL_BB (bb)
+      verify_bb_vtables (bb);
+
+  return ret;
+}
+
+/* Gate function for the pass.  */
+
+static bool
+gate_tree_vtable_verify (void)
+{
+  return (flag_vtable_verify
+          && (strcmp (lang_hooks.name, "GNU C++") == 0));
+}
+
+/* Definition of this optimization pass.  */
+
+struct gimple_opt_pass pass_vtable_verify =
+{
+ {
+  GIMPLE_PASS,
+  "vtable-verify",                      /* name */
+  OPTGROUP_NONE,                        /* optinfo_flags */
+  gate_tree_vtable_verify,              /* gate */
+  vtable_verify_main,                   /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_VTABLE_VERIFICATION,               /* tv_id */
+  PROP_cfg | PROP_ssa,                  /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  TODO_update_ssa
+    | TODO_ggc_collect                  /* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-vtable-verify.h"

Property changes on: gcc/tree-vtable-verify.c
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: gcc/tree-vtable-verify.h
===================================================================
--- gcc/tree-vtable-verify.h	(revision 0)
+++ gcc/tree-vtable-verify.h	(revision 0)
@@ -0,0 +1,139 @@
+/* Interprocedural constant propagation
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security.  */
+
+#ifndef TREE_VTABLE_VERIFY_H
+#define TREE_VTABLE_VERIFY_H
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "hashtab.h"
+#include "sbitmap.h"
+
+/* Global variable keeping track of how many vtable map variables we
+   have created. */
+extern unsigned num_vtable_map_nodes;
+
+/* Each vtable map variable corresponds to a virtual class.  Each
+   vtable map variable has a hash table associated with it, that keeps
+   track of the vtable pointers for which we have generated a call to
+   __VLTRegisterPair (with the current vtable map variable).  This is
+   the hash table node that is used for each entry in this hash table
+   of vtable pointers.
+
+   Sometimes there are multiple valid vtable pointer entries that use
+   the same vtable pointer decl with different offsets.  Therefore,
+   for each vtable pointer in the hash table, there is also an array
+   of offsets used with that vtable. */
+
+struct vtable_registration
+{
+  tree vtable_decl;            /* The var decl of the vtable.                */
+  unsigned max_offsets;        /* The allocated size of the offsets array.   */
+  unsigned cur_offset;         /* The next availabe entry in the offsets
+				  array.                                     */
+  unsigned *offsets;           /* The offsets array.                         */
+};
+
+/*  This struct is used to represent the class hierarchy information
+    that we need.  Each vtable map variable has an associated class
+    hierarchy node (struct vtv_graph_node).  Note: In this struct,
+    'children' means immediate descendants in the class hierarchy;
+    'descendant' means any descendant however many levels deep. */
+
+struct vtv_graph_node {
+  tree class_type;                  /* The record_type of the class.         */
+  unsigned class_uid;               /* A unique, monotonically
+                                       ascending id for class node.
+                                       Each vtable map node also has
+                                       an id.  The class uid is the
+                                       same as the vtable map node id
+                                       for nodes corresponding to the
+                                       same class.  */
+  unsigned max_parents;             /* Allocated size of the parents array.  */
+  unsigned max_children;            /* Allocated size of the children array. */
+  unsigned num_parents;             /* # of entries in the parents array.    */
+  unsigned num_children;            /* # of entries in the children array.   */
+  unsigned num_processed_children;  /* # of children for whom we have
+                                       computed the class hierarchy
+                                       transitive closure.                   */
+  struct vtv_graph_node **parents;  /* Array of parents in the graph.        */
+  struct vtv_graph_node **children; /* Array of children in the graph.       */
+  sbitmap descendants;              /* Bitmap representing all this node's
+				       descendants in the graph.             */
+};
+
+/* This is the node used for our hashtable of vtable map variable
+   information.  When we create a vtable map variable (var decl) we
+   put it into one of these nodes; create a corresponding
+   vtv_graph_node for our class hierarchy info and store that in this
+   node; generate a unique (monotonically ascending) id for both the
+   vtbl_map_node and the vtv_graph_node; and insert the node into
+   THREE data structures (to make it easy to find in several different
+   ways): 1). A hash table ("vtbl_map_hash" in tree-vtable-verify.c).
+   This gives us an easy way to check to see if we already have a node
+   for the vtable map variable or not.  2).  A linked list of all
+   vtbl_map_nodes ("vtbl_map_nodes") for easy iteration through all of
+   them; and 3). An array of vtbl_map_nodes, where the array index
+   corresponds to the unique id of the vtbl_map_node, which gives us
+   an easy way to use bitmaps to represent and find the vtable map
+   nodes.  */
+
+struct vtbl_map_node {
+  tree vtbl_map_decl;                 /* The var decl for the vtable map
+					 variable.                           */
+  tree class_name;                    /* The DECL_ASSEMBLER_NAME of the
+					 class.                              */
+  struct vtv_graph_node *class_info;  /* Our class hierarchy info for the
+					 class.                              */
+  unsigned uid;                       /* The unique id for the vtable map
+					 variable.                           */
+  struct vtbl_map_node *next, *prev;  /* Pointers for the linked list
+					 structure.                          */
+  htab_t registered;     /* Hashtable of vtable pointers for which we have
+			    generated a _VLTRegisterPair call with this vtable 
+			    map variable.                                    */
+  bool is_used;          /* Boolean indicating if we used this vtable map
+			    variable in a call to __VLTVerifyVtablePointer.  */
+};
+
+/* The global linked list of vtbl_map_nodes.  */
+
+extern struct vtbl_map_node *vtbl_map_nodes;
+
+/* The global array of vtbl_map_nodes.  */ 
+
+extern struct vtbl_map_node **vtbl_map_nodes_array;
+
+extern struct vtbl_map_node *vtbl_map_get_node (const_tree);
+extern struct vtbl_map_node *find_or_create_vtbl_map_node (tree);
+extern void vtbl_map_node_class_insert (struct vtbl_map_node *, unsigned);
+extern bool vtbl_map_node_registration_find (struct vtbl_map_node *,
+                                             tree, unsigned);
+extern void vtbl_map_node_registration_insert (struct vtbl_map_node *,
+                                               tree, unsigned);
+
+#endif /* TREE_VTABLE_VERIFY_H */

Property changes on: gcc/tree-vtable-verify.h
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 193571)
+++ gcc/common.opt	(working copy)
@@ -2257,6 +2257,22 @@ Enum(symbol_visibility) String(hidden) V
 EnumValue
 Enum(symbol_visibility) String(protected) Value(VISIBILITY_PROTECTED)
 
+fvtable-verify=
+Common Joined RejectNegative Enum(vtv_priority) Var(flag_vtable_verify) Init(VTV_NO_PRIORITY)
+Validate vtable pointers before using them.
+
+Enum
+Name(vtv_priority) Type(enum vtv_priority) UnknownError(unknown vtable verify initialization priority %qs)
+
+EnumValue
+Enum(vtv_priority) String(none) Value(VTV_NO_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(std) Value(VTV_STANDARD_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(preinit) Value(VTV_PREINIT_PRIORITY)
+
 fvpt
 Common Report Var(flag_value_profile_transformations) Optimization
 Use expression value profiles in optimizations
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c	(revision 193571)
+++ gcc/varasm.c	(working copy)
@@ -2032,7 +2032,25 @@ assemble_variable (tree decl, int top_le
     assemble_noswitch_variable (decl, name, sect);
   else
     {
-      switch_to_section (sect);
+      if (flag_vtable_verify)
+        {
+          if (strstr (name, "__vtable_map"))
+            {
+#if defined (OBJECT_FORMAT_ELF)
+              targetm.asm_out.named_section (sect->named.name,
+					     sect->named.common.flags
+					     | SECTION_LINKONCE,
+					     DECL_NAME (decl));
+              in_section = sect;
+#else
+              switch_to_section (sect);
+#endif
+            }
+          else
+            switch_to_section (sect);
+        }
+      else
+        switch_to_section (sect);
       if (DECL_ALIGN (decl) > BITS_PER_UNIT)
 	ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
       assemble_variable_contents (decl, name, dont_output_data);
@@ -2045,6 +2063,19 @@ assemble_variable (tree decl, int top_le
     }
 }
 
+void
+assemble_vtv_preinit_initializer (tree fn_decl)
+{
+  section *sect;
+  unsigned flags = SECTION_WRITE;
+  rtx symbol = XEXP (DECL_RTL (fn_decl), 0);
+
+  flags |= SECTION_NOTYPE;
+  sect = get_section (".preinit_array", flags, fn_decl);
+  switch_to_section (sect);
+  assemble_addr_to_section (symbol, sect);
+}
+
 /* Return 1 if type TYPE contains any pointers.  */
 
 static int
Index: gcc/output.h
===================================================================
--- gcc/output.h	(revision 193571)
+++ gcc/output.h	(working copy)
@@ -199,6 +199,10 @@ extern void assemble_end_function (tree,
    initial value (that will be done by the caller).  */
 extern void assemble_variable (tree, int, int, int);
 
+/* Make sure the vtable verification constructor initialization function
+   goes into the preinit array.  */
+extern void assemble_vtv_preinit_initializer (tree);
+
 /* Compute the alignment of variable specified by DECL.
    DONT_OUTPUT_DATA is from assemble_variable.  */
 extern void align_variable (tree decl, bool dont_output_data);
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 193571)
+++ gcc/Makefile.in	(working copy)
@@ -1447,6 +1447,7 @@ OBJS = \
 	tree-vect-loop-manip.o \
 	tree-vect-slp.o \
 	tree-vectorizer.o \
+	tree-vtable-verify.o \
 	tree-vrp.o \
 	tree.o \
 	valtrack.o \
@@ -2605,6 +2606,11 @@ tree-vectorizer.o: tree-vectorizer.c $(C
    dumpfile.h $(TM_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \
    $(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) \
    $(TREE_PRETTY_PRINT_H)
+tree-vtable-verify.o: tree-vtable-verify.c tree-vtable-verify.h $(CONFIG_H) \
+   $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) cp/cp-tree.h $(TM_P_H) \
+   $(BASIC_BLOCK_H) output.h $(TREE_FLOW_H) $(TREE_DUMP_H) $(TREE_PASS_H) \
+   $(TIMEVAR_H) $(CFGLOOP_H) $(FLAGS_H)  $(TREE_INLINE_H) $(SCEV_H) \
+   $(DIAGNOSTIC_CORE_H) $(GIMPLE_PRETTY_PRINT_H) toplev.h langhooks.h
 tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(TREE_FLOW_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(TREE_PASS_H)
 tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
@@ -3740,6 +3746,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
   $(srcdir)/lto-streamer.h \
   $(srcdir)/target-globals.h \
   $(srcdir)/ipa-inline.h \
+  $(srcdir)/tree-vtable-verify.c \
   $(srcdir)/asan.c \
   @all_gtfiles@
 
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 193571)
+++ gcc/passes.c	(working copy)
@@ -1561,6 +1561,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_tm_memopt);
       NEXT_PASS (pass_tm_edges);
     }
+  NEXT_PASS (pass_vtable_verify);
   NEXT_PASS (pass_lower_complex_O0);
   NEXT_PASS (pass_asan_O0);
   NEXT_PASS (pass_cleanup_eh);

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fwd: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
       [not found]     ` <CABtf2+SnpddRF9kHsY-CyxNbS+3iQrUM7dqtZmbGJMNkS_WvBw@mail.gmail.com>
@ 2012-11-28 16:17       ` Diego Novillo
  0 siblings, 0 replies; 8+ messages in thread
From: Diego Novillo @ 2012-11-28 16:17 UTC (permalink / raw)
  To: Caroline Tice, Luis Lozano, gcc-patches, Jason Merrill

On 2012-11-16 13:24 , Caroline Tice wrote:

> Index: gcc/cp/decl2.c
> ===================================================================
> --- gcc/cp/decl2.c	(revision 193571)
> +++ gcc/cp/decl2.c	(working copy)
> @@ -69,8 +69,8 @@ typedef struct priority_info_s {
>  static void mark_vtable_entries (tree);
>  static bool maybe_emit_vtables (tree);
>  static bool acceptable_java_type (tree);
> -static tree start_objects (int, int);
> -static void finish_objects (int, int, tree);
> +static tree start_objects (int, int, const char *);
> +static tree finish_objects (int, int, tree);
>  static tree start_static_storage_duration_function (unsigned);
>  static void finish_static_storage_duration_function (tree);
>  static priority_info get_priority_info (int);
> @@ -2964,14 +2964,22 @@ generate_tls_wrapper (tree fn)
>  }
>
>  /* Start the process of running a particular set of global constructors
> -   or destructors.  Subroutine of do_[cd]tors.  */
> +   or destructors.  Subroutine of do_[cd]tors.  Also called from
> +   vtv_start_verification_constructor_init_function.
> +
> +   The parameter EXTRA_NAME will be an empty string for most calls.
> +   It gets appended to the end of the name of the function being
> +   created.  When this function is being called to create a
> +   vtable verification constructor init function, EXTRA_NAME will
> +   contain a string based on the source file path, to help give the
> +   vtable constructor init functions unique names.  */

Why not use the assembler name of the function here?  That would be a 
uniquely mangled name.


> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +/* This file is part of the vtable security implementation.  It collects
> +   class hierarchy information about the program being compiled and
> +   inserts calls to __VLTRegisterPair, registering this information.  */

Could you include a high-level overview of how vtable security works?  A 
summary based on the design document would be great.  Also, a rough flow 
of how the implementation works.

> +
> +/* Need to mark this one specially since it needs to be stored in
> + * precompiled header IR */

No '*' at the start of the second line.

> +static bool register_all_pairs (tree body);
> +static void add_hierarchy_pair (struct vtv_graph_node *,
> +                                struct vtv_graph_node *);
> +static struct vtv_graph_node *find_graph_node (tree);
> +static struct vtv_graph_node *
> +                  find_and_remove_next_leaf_node (struct work_node **worklist);
> +static void create_undef_reference_to_vtv_init(tree register_pairs_body);
> +static bool vtv_register_class_hierarchy_information
> +                                                    (tree register_pairs_body);
> +
> +static void update_class_hierarchy_information (tree, tree);
> +struct vtbl_map_node *vtable_find_or_create_map_decl (tree);

Unless you are breaking a mutually recursive cycle, it's better not to 
declare static functions in advance.  Makes it easier to change the 
function's signature later.

> +
> +/* As part of vtable verification the compiler generates and inserts calls
> +   to __VLTRegisterPair and __VLTChangePermission, which are in libstdc++.

Don't you mean libsupc++ here?  I thought that's where the runtime 
support was going to go into.


> +static void
> +init_functions (void)
> +{
> +  tree void_ptr_type = build_pointer_type (void_type_node);
> +  tree arg_types = NULL_TREE;
> +  tree register_pairs_type = void_type_node;
> +  tree change_permission_type = void_type_node;
> +#ifdef VTV_DEBUG

Please make this a debug flag.  This kind of #ifdef debugging tends to 
bitrot quickly and it's never available when you need it most (the 
production compiler has made a bad decision and you need to know what's 
happening).

> +  tree char_ptr_type = build_pointer_type (char_type_node);
> +#endif
> +
> +  if (vlt_change_permission_fndecl != NULL_TREE)
> +    return;
> +
> +  gcc_assert(vlt_register_pairs_fndecl == NULL_TREE);

Space before '('.


> +/* This is a helper function for
> +   vtv_compute_class_hierarchy_transitive_closure.  It goes through
> +   the WORKLIST of class hierarchy nodes looking for a "leaf" node,
> +   i.e. a node whose children in the hierarchy have all been
> +   processed.  When it finds the next leaf node, it removes it from
> +   the linked list (WORKLIST) and returns the node.  */
> +
> +static struct vtv_graph_node *
> +find_and_remove_next_leaf_node (struct work_node **worklist)
> +{
> +  struct work_node *prev, *cur;
> +
> +  for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)

Would this be better implemented as a vec + hash table or pointer set? 
How large is this worklist?

> +    {
> +      if (cur->node->num_children == cur->node->num_processed_children)
> +        {
> +          if (prev == NULL)
> +            (*worklist) = cur->next;
> +          else
> +            prev->next = cur->next;
> +
> +          cur->next = NULL;
> +          return cur->node;
> +        }
> +    }
> +
> +  return NULL;
> +}
> +
> +/* In our class hirarchy graph, each class node contains a bitmap,

s/hirarchy/hierarchy/

> +   with one bit for each class in the hierarchy.  The bits are set for
> +   classes that are descendants in the graph of the current node.
> +   Initially the desdendants bitmap is only set for immediate

s/desdendants/descendants/

> +      temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
> +      bitmap_clear (temp_node->descendants);
> +      bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
> +      for (i = 0; i < temp_node->num_children; ++i)
> +        bitmap_ior (temp_node->descendants, temp_node->descendants,
> +                        temp_node->children[i]->descendants);
> +      for (i = 0; i < temp_node->num_parents; ++i)
> +        {
> +          temp_node->parents[i]->num_processed_children =
> +                    temp_node->parents[i]->num_processed_children + 1;
> +          if (!bitmap_bit_p (inserted, temp_node->parents[i]->class_uid))
> +            add_to_worklist (&worklist, temp_node->parents[i], inserted);
> +        }
> +    }
> +}
> +
> +/* Keep track of which pairs we have already created __VLTRegisterPair
> +   calls for, to prevent creating duplicate calls within the same
> +   compilation unit.  */

Need to document VTABLE_DECL, VPTR_ADDRESS and BASE_CLASS.

> +
> +static bool
> +record_register_pairs (tree vtable_decl, tree vptr_address,
> +                       tree base_class)
> +{
> +  unsigned offset;
> +  tree base_id;
> +  struct vtbl_map_node *base_vtable_map_node;
> +
> +  if (TREE_CODE (vptr_address) == ADDR_EXPR
> +      && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
> +    vptr_address = TREE_OPERAND (vptr_address, 0);
> +
> +  offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
> +
> +  if (TREE_CHAIN (base_class))
> +    base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
> +  else
> +    base_id = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class));
> +
> +  base_vtable_map_node = vtbl_map_get_node (base_id);
> +
> +  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
> +                                       offset))
> +    return true;
> +
> +  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
> +				     offset);
> +  return false;
> +}
> +
> +/* A class may contain secondary vtables in it, for various reasons.
> +     This function goes through the decl chain of a class record
> +     looking for any fields that point to secondary vtables, and
> +     adding calls to __VLTRegisterPair for the secondary vtable
> +     pointers.  */

Need to document BASE_CLASS_DECL_ARG, BASE_CLASS, RECORD_TYPE and BODY.

> +
> +static void
> +register_vptr_fields (tree base_class_decl_arg, tree base_class,
> +                      tree record_type, tree body)
> +{
> +  tree vtbl_var_decl;
> +  tree arg1;
> +  tree arg2;
> +  int hint = 0;
> +
> +  if (TREE_CODE (record_type) != RECORD_TYPE)
> +    return;
> +
> +  vtbl_var_decl = get_vtbl_decl_for_binfo (TYPE_BINFO (record_type));
> +
> +  if (vtbl_var_decl)
> +    {
> +      tree ztt_decl = DECL_CHAIN (vtbl_var_decl);
> +      bool already_registered = false;
> +
> +      /* construction vtable */

What does this comment mean?  Please make comments full sentences that 
clarify what is happening in the code.

> +      if (ztt_decl != NULL_TREE
> +          && (DECL_NAME (ztt_decl))
> +          && (strncmp (IDENTIFIER_POINTER (DECL_NAME (ztt_decl)),
> +                       "_ZTT", 4) == 0))
> +        {
> +          tree values = DECL_INITIAL (ztt_decl);
> +          struct varpool_node * vp_node = varpool_node_for_decl (ztt_decl);
> +          if (vp_node->finalized
> +              && TREE_ASM_WRITTEN (ztt_decl)
> +              && (values != NULL_TREE)
> +              && (TREE_CODE (values) == CONSTRUCTOR)
> +              && (TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE))
> +            {
> +              tree call_expr = NULL_TREE;
> +              unsigned HOST_WIDE_INT cnt;
> +              constructor_elt *ce;
> +
> +              for (cnt = 0;
> +                   VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (values),
> +				cnt, ce);
> +                   cnt++)
> +                {
> +                  tree value = ce->value;
> +                  tree val_vtbl_decl = TREE_OPERAND (TREE_OPERAND (value, 0),
> +                                                     0);
> +                  int len1;
> +                  int len2;
> +
> +                  if (TREE_CODE (val_vtbl_decl) == ADDR_EXPR
> +                      && TREE_CODE (TREE_OPERAND (val_vtbl_decl, 0))
> +                                                                   == VAR_DECL)
> +                    val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
> +
> +                  gcc_assert (TREE_CODE (val_vtbl_decl) == VAR_DECL);
> +
> +                  len1 = strlen (IDENTIFIER_POINTER
> +				     (DECL_NAME
> +				          (TREE_OPERAND
> +					     (base_class_decl_arg, 0))));
> +                  len2 = strlen (IDENTIFIER_POINTER
> +				     (DECL_NAME (val_vtbl_decl)));
> +                  arg1 = build_string_literal (len1,
> +                                               IDENTIFIER_POINTER
> +					        (DECL_NAME
> +						 (TREE_OPERAND
> +						  (base_class_decl_arg, 0))));
> +                  arg2 = build_string_literal (len2,
> +                                               IDENTIFIER_POINTER
> +					        (DECL_NAME (val_vtbl_decl)));
> +
> +                  already_registered = record_register_pairs (val_vtbl_decl,
> +                                                              value,
> +                                                              base_class);
> +
> +                  if (already_registered)
> +                    continue;
> +

Can you add some commentary about what's going on in this loop?  Seems 
pretty obscure.

> +#ifdef VTV_DEBUG
> +                  call_expr = build_call_expr
> +		                        (vlt_register_pairs_fndecl, 7,
> +					 base_class_decl_arg, value,
> +                                         build_int_cst (integer_type_node,
> +                                                        hint),
> +					 arg1,
> +					 build_int_cst (integer_type_node,
> +							len1),
> +					 arg2,
> +					 build_int_cst (integer_type_node,
> +							len2));
> +#else
> +                  call_expr = build_call_expr
> +                                        (vlt_register_pairs_fndecl, 3,
> +                                         base_class_decl_arg, value,
> +                                         build_int_cst (integer_type_node,
> +                                                        hint));
> +#endif
> +		  append_to_statement_list (call_expr, &body);
> +                }
> +            }
> +        }
> +    }
> +}
> +
> +/* This function iterates through all the vtable it can find from the

s/vtable/vtables/

> +   BINFO of a class, to make sure we have found ALL of the vtables
> +   that an object of that class could point to.  Generate calls to
> +   __VLTRegisterPair for those vtable pointers that we find.  */
> +
> +static void
> +register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
> +                              int len1, tree str2, int len2, tree base_class)

All these parameters need documentation.


> +/* The set of valid vtable pointers for any given class are stored in
> +   a hash table.  For reasons of efficiency, that hash table size is
> +   always a power of two.  In order to try to prevent re-sizing the
> +   hash tables very often, we pass __VLTRegisterPair an initial guess
> +   as to the number of entries the hashtable will eventually need
> +   (rounded up to the nearest power of two).  This function take the

s/take/takes/

> +   class information we have collected for a particular class and
> +   calculates the hash table size guess.  */
> +
> +static int
> +guess_num_vtable_pointers (struct vtv_graph_node *class_node)

CLASS_NODE needs to be documented.


> +/* This function goes through our internal class hierarchy & vtable
> +   pointer data structure and outputs calls to __VLTRegisterPair for
> +   every class-vptr pair (for those classes whose vtable would be
> +   output in the current compilation unit).  These calls get put into
> +   our constructor initialization function.  */
> +
> +static bool
> +register_all_pairs (tree body)
> +{

BODY needs to be documented.


> +      /* If this function is going into the preinit_array, then we
> +         need to manually call __VLTChangePermission, rather than
> +         depending on initialization prioritys in vtv_init. */
> +      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
> +        {
> +          /* Pass __VLTP_READ_WRITE value as defined in vtv_rts.h */
> +          tree arg_read_write = build_int_cst (integer_type_node, 1);
> +          tree arg_read_only = build_int_cst (integer_type_node, 0);
> +
> +          tree call_rw_expr = build_call_expr (vlt_change_permission_fndecl,
> +                                               1, arg_read_write);
> +          tree_stmt_iterator i = tsi_start(register_pairs_body);
> +          /* Insert at the beginning of the register pairs routine */
> +          tsi_link_before(&i, call_rw_expr, TSI_SAME_STMT);

Space before '(' and blank line before comment.

> +
> +          tree call_r_expr = build_call_expr (vlt_change_permission_fndecl,
> +                                              1, arg_read_only);
> +          append_to_statement_list (call_r_expr, &register_pairs_body);
> +        }
> +
> +      if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
> +        create_undef_reference_to_vtv_init(register_pairs_body);

Space before '('.

> +  }
> +
> +  return registered_something;
> +}
> +
> +
> +/* Generate the special constructor function that calls
> +   __VLTChangePermission and __VLTRegisterPairs, and give it a very
> +   high initialization priority.  */
> +
> +void
> +vtv_generate_init_routine(const char * filename)

Space before '('.  No space after '*' (happens in other pointer 
declarations as well).  FILENAME needs documenting.


> +  char *var_name = NULL;
> +  struct vtbl_map_node *vtable_map_node = NULL;
> +
> +
> +  /* Verify the type has an associated vtable */

End comments with '.  */'  (my kingdom for a gcc-specific linter!).


> Property changes on: gcc/cp/vtable-class-hierarchy.c
> ___________________________________________________________________
> Added: svn:eol-style
>    + LF

Please remove this svn attribute.



>  /* in dump.c */
>  extern bool cp_dump_tree			(void *, tree);
> Index: gcc/timevar.def
> ===================================================================
> --- gcc/timevar.def	(revision 193571)
> +++ gcc/timevar.def	(working copy)
> @@ -257,6 +257,7 @@ DEFTIMEVAR (TV_TREE_UNINIT           , "
>  DEFTIMEVAR (TV_PLUGIN_INIT           , "plugin initialization")
>  DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")
>  DEFTIMEVAR (TV_GIMPLE_SLSR           , "straight-line strength reduction")
> +DEFTIMEVAR (TV_VTABLE_VERIFICATION   , "tree vtable verification")

Just "vtable verification".


>  #endif /* ! GCC_FLAG_TYPES_H */
> Index: gcc/tree-vtable-verify.c
> ===================================================================
> --- gcc/tree-vtable-verify.c	(revision 0)
> +++ gcc/tree-vtable-verify.c	(revision 0)
> @@ -0,0 +1,1053 @@
> +/*   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
> +    Free Software Foundation, Inc.
> +
> +This file is part of GCC.
> +
> +GCC is free software; you can redistribute it and/or modify it under
> +the terms of the GNU General Public License as published by the Free
> +Software Foundation; either version 3, or (at your option) any later
> +version.
> +
> +GCC is distributed in the hope that it will be useful, but WITHOUT ANY
> +WARRANTY; without even the implied warranty of MERCHANTABILITY or
> +FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3.  If not see
> +<http://www.gnu.org/licenses/>.  */
> +
> +/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
> +   before using them for virtual method dispatches.  */

I'd like to see an overview of the actual checking pass here.  The 
highlights and how it's implemented in the file.

> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "tm.h"
> +#include "tree.h"
> +#include "cp/cp-tree.h"
> +#include "tm_p.h"
> +#include "basic-block.h"
> +#include "output.h"
> +#include "tree-flow.h"
> +#include "tree-dump.h"
> +#include "tree-pass.h"
> +#include "timevar.h"
> +#include "cfgloop.h"
> +#include "flags.h"
> +#include "tree-inline.h"
> +#include "tree-scalar-evolution.h"
> +#include "diagnostic-core.h"
> +#include "gimple-pretty-print.h"
> +#include "toplev.h"
> +#include "langhooks.h"
> +
> +#include "tree-vtable-verify.h"
> +
> +unsigned num_vtable_map_nodes = 0;
> +
> +static GTY(()) tree verify_vtbl_ptr_fndecl = NULL_TREE;
> +
> +unsigned int vtable_verify_main (void);
> +static bool gate_tree_vtable_verify (void);
> +static void build_vtable_verify_fndecl (void);

No forward declaration of static functions, please.

> +
> +/* The following few functions are for the vtbl pointer hash table
> +   in the 'registered' field of the struct vtable_map_node.  The hash
> +   table keeps track of which vtable pointers have been used in
> +   calls to __VLTRegisterPair with that particular vtable map variable.  */
> +
> +/* This function checks to see if a particular VTABLE_DECL and OFFSET are
> +   already in the 'registered' hash table for NODE.  */
> +
> +bool
> +vtbl_map_node_registration_find (struct vtbl_map_node *node,
> +                                 tree vtable_decl,
> +                                 unsigned offset)
> +{
> +  struct vtable_registration key;
> +  struct vtable_registration **slot;
> +
> +  gcc_assert (node);
> +  gcc_assert (node->registered);

gcc_assert (node && node->registered);


> +
> +/* This function inserts VTABLE_DECL and OFFSET into the 'registered'
> +   hash table for NODE.  */
> +
> +void
> +vtbl_map_node_registration_insert (struct vtbl_map_node *node,
> +                                   tree vtable_decl,
> +                                   unsigned offset)
> +{
> +  struct vtable_registration key;
> +  struct vtable_registration **slot;
> +
> +  if (!node || !(node->registered))

No need to surround node->registered in ().

> +    return;
> +
> +  key.vtable_decl = vtable_decl;
> +  slot = (struct vtable_registration **) htab_find_slot (node->registered,
> +                                                         &key, INSERT);
> +
> +  if (!(*slot))

Likewise here.

> +    {
> +      unsigned i;
> +      struct vtable_registration *node;
> +      node = (struct vtable_registration *)
> +                                 xmalloc (sizeof (struct vtable_registration));
> +      node->vtable_decl = vtable_decl;
> +      node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));
> +      for (i= 0; i < 10; ++i)
> +        node->offsets[i] = 0;

Why 10?  Why not 5 or 20?  Can you put a comment here about it?


> +      node->offsets[0] = offset;
> +      node->cur_offset = 1;
> +      node->max_offsets = 10;
> +      *slot = node;
> +    }
> +  else
> +    {
> +      /* We found the vtable_decl slot; we need to see if it already
> +         contains the offset.  If not, we need to add the offset.  */
> +      unsigned i;
> +      bool found = false;
> +      for (i = 0; (i < (*slot)->cur_offset) && !found; ++i)

No need to surround the first part of the && in ().

> +        if ((*slot)->offsets[i] == offset)
> +          found = true;
> +
> +      if (!found)
> +        {
> +	  /* Re-size the offset array if necessary.*/

'.  */'

> +          if ((*slot)->cur_offset == (*slot)->max_offsets)
> +            {
> +              unsigned new_max = 2 * (*slot)->max_offsets;
> +              (*slot)->offsets = (unsigned *)
> +                  xrealloc ((*slot)->offsets, new_max * sizeof (unsigned));
> +
> +              for (i = (*slot)->max_offsets; i < new_max; ++i)
> +                (*slot)->offsets[i] = 0;
> +              (*slot)->max_offsets = new_max;
> +            }
> +	  /* Insert the new offset. */

Likewise.

> +          (*slot)->offsets[(*slot)->cur_offset] = offset;
> +          (*slot)->cur_offset = (*slot)->cur_offset + 1;
> +        }
> +    }
> +}
> +
> +/* Hashtable functions for vtable_registration hashtables.  */
> +
> +static hashval_t
> +hash_vtable_registration (const void * p)
> +{
> +  const struct vtable_registration *n = (const struct vtable_registration *) p;
> +  return (hashval_t) (DECL_UID (n->vtable_decl));
> +}
> +
> +static int
> +eq_vtable_registration (const void *p1, const void *p2)
> +{
> +  const struct vtable_registration *n1 =
> +                                    (const struct vtable_registration *) p1;
> +  const struct vtable_registration *n2 =
> +                                    (const struct vtable_registration *) p2;
> +  return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
> +}
> +
> +/* End of hashtable functions for "registered" hashtables*/

'.  */'

> +
> +
> +/* Here are the three data structures into which we insert vtable map nodes.
> +   We use three data structures because of the vastly different ways we need
> +   to find the nodes for various tasks (see comments in tree-vtable-verify.h
> +   for more details.  */
> +
> +/* Vtable map variable nodes stored in a hash table.  */
> +static htab_t vtbl_map_hash = NULL;
> +
> +/* Vtable map variable nodes stored in a linked list.  */
> +struct vtbl_map_node *vtbl_map_nodes = NULL;
> +
> +/* Vtable map variable nodes stored in an array.  */
> +struct vtbl_map_node **vtbl_map_nodes_array = NULL;

A vec<> might be easier here.

> +
> +/* This function inserts a vtable map variable NODE into the array.  */
> +
> +static void
> +vtable_map_array_insert (struct vtbl_map_node *node)
> +{
> +  static unsigned array_size = 0;
> +  unsigned i;
> +
> +  if (vtbl_map_nodes_array == NULL
> +      || array_size == 0)
> +    {
> +      array_size = 16;
> +      vtbl_map_nodes_array = (struct vtbl_map_node **)
> +                       xmalloc (array_size * sizeof (struct vtbl_map_node *));
> +      memset (vtbl_map_nodes_array, 0,
> +              array_size * sizeof (struct vtbl_map_node *));

Definitely.  Please make vtbl_map_nodes_array a vec<>.


> +/* Return vtbl_map node for CLASS_NAME  without creating a new one.  */
> +struct vtbl_map_node *
> +vtbl_map_get_node (const_tree class_name)
> +{
> +  struct vtbl_map_node key;
> +  struct vtbl_map_node **slot;
> +
> +  if (!vtbl_map_hash)
> +    return NULL;
> +
> +  key.class_name = CONST_CAST2 (tree, const_tree, class_name);
> +  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
> +                                                   NO_INSERT);
> +  if (!slot)
> +    return NULL;
> +  return *slot;
> +}
> +
> +/* Return vtbl_map node assigned to BASE_CLASS_TYPE.  Create new one
> +   when needed.  */
> +struct vtbl_map_node *

Blank line after comment.

> +find_or_create_vtbl_map_node (tree base_class_type)
> +{
> +  struct vtbl_map_node key;
> +  struct vtbl_map_node *node;
> +  struct vtbl_map_node **slot;
> +  unsigned i;
> +
> +  if (!vtbl_map_hash)
> +    vtbl_map_hash = htab_create (10, hash_vtbl_map_node,
> +                                 eq_vtbl_map_node, NULL);
> +
> +  if (TREE_CHAIN (base_class_type))
> +    key.class_name = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class_type));
> +  else
> +    key.class_name = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class_type));
> +  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
> +                                                   INSERT);
> +  if (*slot)
> +    return *slot;
> +
> +  node = (struct vtbl_map_node *) xmalloc (sizeof (struct vtbl_map_node));
> +  node->vtbl_map_decl = NULL_TREE;
> +  node->class_name = key.class_name;
> +  node->uid = num_vtable_map_nodes++;
> +
> +  node->class_info = (struct vtv_graph_node *)
> +                                      xmalloc (sizeof (struct vtv_graph_node));

s/xmalloc/XNEW/

> +  node->class_info->class_type = base_class_type;
> +  node->class_info->class_uid = node->uid;
> +  node->class_info->max_parents = 4;
> +  node->class_info->max_children = 4;
> +  node->class_info->num_parents = 0;
> +  node->class_info->num_children = 0;
> +  node->class_info->num_processed_children = 0;
> +  node->class_info->parents = (struct vtv_graph_node **)
> +                                xmalloc (4 * sizeof (struct vtv_graph_node *));
> +  node->class_info->children = (struct vtv_graph_node **)
> +                                xmalloc (4 * sizeof (struct vtv_graph_node *));

Likewise here.

> +  for (i = 0; i < 4; ++i)

Another hard-coded constant.  Maybe a comment of why 4 is the magic number?

> +    {
> +      node->class_info->parents[i] = NULL;
> +      node->class_info->children[i] = NULL;
> +    }
> +
> +  node->registered = htab_create (16, hash_vtable_registration,
> +                                  eq_vtable_registration, NULL);
> +  node->is_used = false;
> +  node->next = vtbl_map_nodes;
> +  if (vtbl_map_nodes)
> +    vtbl_map_nodes->prev = node;
> +
> +  vtable_map_array_insert (node);
> +
> +  vtbl_map_nodes = node;
> +  *slot = node;
> +  return node;
> +}
> +
> +/* This function take a tree type, NODE, and checks to see if the name
> +   of the type is "__vtbl_ptr_type".  */
> +
> +static int
> +type_name_is_vtable_pointer (tree node)

Make it return bool please.


> +/* Given a gimple STMT, this function checks to see if the statement
> +   is an assignment, the rhs of which is getting the vtable pointer
> +   value out of an object.  (i.e. it's the value we need to verify
> +   because its the vtable pointer that will be used for a virtual
> +   call).  */
> +
> +static int
> +is_vtable_assignment_stmt (gimple stmt)

Likewise.

> +{
> +
> +  if (gimple_code (stmt) != GIMPLE_ASSIGN)
> +    return 0;
> +  else
> +    {
> +      tree lhs = gimple_assign_lhs (stmt);
> +      tree rhs = gimple_assign_rhs1 (stmt);
> +
> +      if (TREE_CODE (lhs) != SSA_NAME)
> +        return 0;
> +
> +      if (TREE_CODE (TREE_TYPE (lhs)) != POINTER_TYPE)

POINTER_TYPE_P (TREE_TYPE (lhs))

> +        return 0;
> +
> +      if (TREE_CODE (TREE_TYPE (TREE_TYPE (lhs))) != POINTER_TYPE)

Likewise.

> +        return 0;
> +
> +      if (! type_name_is_vtable_pointer (TREE_TYPE (TREE_TYPE (lhs))))

Why not fold the test above inside type_name_is_vtable_pointer?

> +}
> +
> +/* This function, given the BINFO for a virtual type, gets the vtable decl

Change to "Give the BINFO for a virtual type, this function..."

> +   for that BINFO.  */
> +
> +static tree
> +my_get_vtbl_decl_for_binfo (tree binfo)
> +{
> +  tree decl;
> +
> +  decl = BINFO_VTABLE (binfo);
> +  if (decl && TREE_CODE (decl) == POINTER_PLUS_EXPR)
> +  {
> +    gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR);
> +    decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
> +  }
> +  if (decl)
> +    gcc_assert (TREE_CODE (decl) == VAR_DECL);
> +
> +  return decl;
> +}
> +
> +/* STMT is a gimple statment that uses OLD_VAR.  This function finds the
> +   use of OLD_VAR in STMT and replaces it with NEW_VAR.  STMT is either
> +   an assignment statement or a call statement.  */
> +
> +static bool
> +find_and_replace_var (gimple stmt, tree old_var, tree new_var)
> +{
> +  bool found = false;
> +
> +  if (!stmt || ! old_var || !new_var)
> +    return found;
> +
> +  if ((TREE_CODE (old_var) != SSA_NAME)
> +      || (TREE_CODE (new_var) != SSA_NAME))
> +    return found;
> +
> +  if (gimple_code (stmt) == GIMPLE_ASSIGN)
> +    {

This looks too convoluted.  Why not just traverse all the gimple 
operands and replace OLD_VAR with NEW_VAR?

You can either use the visitor pattern with walk_gimple_op() or knowing 
that you only want to walk GIMPLE_ASSIGNs, simply loop over the operands 
with for (i = 0; i < gimple_num_ops (stmt); i++).

You also want to handle GIMPLE_CALLs, so walk_gimple_op() may be the 
easiest way.


> +/* Search through all the statements in a basic block, searching for
> +   virtual method calls.  For each virtual method dispatch, find the
> +   vptr value used, and the statically declared type of the object;
> +   retrieve the vtable map variable for the type of the object;
> +   generate a call to __VLTVerifyVtablePointer; and insert the
> +   generated call into the basic block, after the point where the vptr
> +   value is gotten out of the object and before the virtual method
> +   dispatch. Make the virtual method dispatch depend on the return
> +   value from the verification call, so that subsequent optimizations
> +   cannot reorder the two calls.  */
> +
> +static void
> +verify_bb_vtables (basic_block bb)
> +{
> +  gimple_seq stmts;
> +  gimple stmt = NULL;
> +  gimple_stmt_iterator gsi_vtbl_assign;
> +  gimple_stmt_iterator gsi_virtual_call;
> +  tree this_object;
> +
> +  /* Search the basic block to see if it contains a virtual method
> +     call, i.e. a call with the tree code OBJ_TYPE_REF  */

Please describe a bit more how you go about finding this.  The 
description seems to imply a simple pattern matching, but the code in 
the loop body is doing a whole bunch of seemingly unrelated checks.

> +
> +  stmts = bb_seq (bb);
> +  gsi_virtual_call = gsi_start (stmts);
> +  this_object = NULL_TREE;
> +  for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
> +    {
> +      stmt = gsi_stmt (gsi_virtual_call);
> +      if (gimple_code (stmt) == GIMPLE_CALL)
> +        {
> +          tree fncall = gimple_call_fn (stmt);
> +          if (TREE_CODE (fncall) == OBJ_TYPE_REF)
> +            {
> +              bool found = false;
> +              tree vtable_offset_var = NULL_TREE;
> +              gimple def_stmt;
> +              gimple prev_use = NULL;
> +
> +              /* The first argument to the function must be "this", a pointer
> +                 to the object itself.  */
> +
> +              this_object = gimple_call_arg (stmt, 0);
> +
> +              /* Get the SSA variable that contains the dereferenced _vptr
> +                 field + table start offset.  */
> +
> +              if (TREE_OPERAND (fncall, 0)
> +                  && TREE_CODE (TREE_OPERAND (fncall, 0)) == SSA_NAME)
> +                {
> +                  tree rhs = NULL_TREE;
> +                  gimple phi_stmt = NULL;
> +                  gimple phi_prev_use = NULL;
> +                  bool  found_phi = false;
> +
> +                  vtable_offset_var = TREE_OPERAND (fncall, 0);
> +
> +                  prev_use = stmt;
> +                  def_stmt = SSA_NAME_DEF_STMT (vtable_offset_var);
> +
> +		  /* Search backwards through the def_stmt chain, to try
> +		     to find the assignment statement where the rhs of
> +		     the assignment contains the "._vptr" field (the vtable
> +		     pointer). */
> +
> +		  /*
> +                  while (gimple_code (def_stmt) == GIMPLE_PHI)
> +                    {
> +                      if (!found_phi)
> +                        {
> +                          phi_prev_use = prev_use;
> +                          phi_stmt = def_stmt;
> +                          found_phi = true;
> +                        }
> +                      def_stmt = get_phi_def_stmt (def_stmt);
> +                    }
> +		  */

What is this?

> +
> +                  gcc_assert (def_stmt != NULL);
> +                  gcc_assert (gimple_code (def_stmt) == GIMPLE_ASSIGN);
> +
> +                  if (gimple_assign_lhs (def_stmt)
> +                      && TREE_CODE (gimple_assign_lhs (def_stmt)) == SSA_NAME
> +                      && get_gimple_rhs_class (gimple_expr_code (def_stmt))
> +                                                          == GIMPLE_SINGLE_RHS)
> +                    rhs = gimple_assign_rhs1 (def_stmt);
> +
> +                  if (rhs
> +                      && TREE_CODE (rhs) == MEM_REF
> +                      && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
> +                    {
> +                      prev_use = def_stmt;
> +                      def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
> +                    }
> +
> +		  /*
> +                  if (gimple_code (def_stmt) == GIMPLE_PHI)
> +                    {
> +                      if (!found_phi)
> +                        {
> +                          phi_prev_use = prev_use;
> +                          phi_stmt = def_stmt;
> +                          found_phi = true;
> +                        }
> +                      def_stmt = get_phi_def_stmt (def_stmt);
> +                    }
> +		  */

What is this?

> +                  while (def_stmt
> +                         && !is_vtable_assignment_stmt (def_stmt))
> +                    {
> +                      tree lhs = gimple_assign_lhs (def_stmt);
> +                      if (!lhs
> +                          || !TREE_CODE (lhs) == SSA_NAME)

Only indent predicates if they don't fit on the line.

> +                        {
> +                          def_stmt = NULL;
> +                          break;
> +                        }
> +                      if (! def_stmt)
> +                        break;
> +
> +                      if (gimple_assign_rhs1 (def_stmt)
> +                          && TREE_CODE (gimple_assign_rhs1 (def_stmt))
> +                                                                   == SSA_NAME)
> +                        {
> +                          prev_use = def_stmt;
> +                          rhs = gimple_assign_rhs1 (def_stmt);
> +                          def_stmt = SSA_NAME_DEF_STMT (rhs);
> +                        }
> +                      else if ((get_gimple_rhs_class
> +                                  (gimple_expr_code (def_stmt))
> +			                                  != GIMPLE_SINGLE_RHS)
> +                               && gimple_assign_rhs2 (def_stmt)
> +                               && TREE_CODE (gimple_assign_rhs2 (def_stmt))
> +                                                                   == SSA_NAME)
> +                        {
> +                          prev_use = def_stmt;
> +                          rhs = gimple_assign_rhs2 (def_stmt);
> +                          def_stmt = SSA_NAME_DEF_STMT (rhs);
> +                        }
> +                      else
> +                        def_stmt = NULL;
> +
> +                      if (!def_stmt)
> +                        break;
> +
> +		      /*
> +                      if (def_stmt != NULL
> +                          && gimple_code (def_stmt) == GIMPLE_PHI)
> +                        {
> +                          if (!found_phi)
> +                            {
> +                              phi_prev_use = prev_use;
> +                              phi_stmt = def_stmt;
> +                              found_phi = true;
> +                            }
> +                          def_stmt = get_phi_def_stmt (def_stmt);
> +                        }
> +		      */
> +                    }

Please factor out this logic into one or more function helpers.


> +                      if (found)
> +                        {
> +                          tree object_rhs = TREE_TYPE (this_object);
> +                          tree lhs;
> +                          tree vtbl_var_decl = NULL_TREE;
> +                          tree vtbl = NULL_TREE;
> +                          tree var_id;
> +                          gimple_seq pre_p = NULL;
> +                          struct vtbl_map_node *vtable_map_node = NULL;
> +                          tree vtbl_decl = NULL_TREE;

All this should be factored into a helper function.  By the amount of 
code you have here, I would say that you will want more than one.  This 
is the main logic of the transformation.  It should be very readable. 
Right now, all the logic is intermixed with low-level details, it's hard 
to follow.


> +                          else
> +                            internal_error ("if (verify_vtbl_ptr_fndecl && vtbl_var_decl) FAILED.");

gcc_unreachable () or make the message mean something more.

> +                        }
> +                      else
> +                        internal_error ("if (found) FAILED.");

Likewise.

> +                    }
> +                }
> +              else
> +                internal_error ("if fncall...FAILED.");

Likewise.


> Property changes on: gcc/tree-vtable-verify.c
> ___________________________________________________________________
> Added: svn:eol-style
>    + LF

Remove this attribute.


> Property changes on: gcc/tree-vtable-verify.h
> ___________________________________________________________________
> Added: svn:eol-style
>    + LF

Remove this attribute.


>
> +void
> +assemble_vtv_preinit_initializer (tree fn_decl)
> +{

Missing documentation.


The pass should also be documented in doc/invoke.texi.

I can continue reviewing the changes to the middle end, but you'll need 
a C++ reviewer to go over the changes to the C++ FE.  I have only made 
cosmetic comments in the C++ bits.  Please split the patch in two, to 
simplify reviewing (i.e., separate the C++ from the ME parts)


Thanks.  Diego.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
  2012-11-16 18:21   ` Caroline Tice
       [not found]     ` <CABtf2+SnpddRF9kHsY-CyxNbS+3iQrUM7dqtZmbGJMNkS_WvBw@mail.gmail.com>
@ 2012-11-29 18:34     ` Jason Merrill
  2012-11-29 18:35       ` Jason Merrill
  1 sibling, 1 reply; 8+ messages in thread
From: Jason Merrill @ 2012-11-29 18:34 UTC (permalink / raw)
  To: Caroline Tice; +Cc: Xinliang David Li, GCC Patches

On 11/16/2012 01:21 PM, Caroline Tice wrote:
> -start_objects (int method_type, int initp)
> +start_objects (int method_type, int initp, const char *extra_name)

I don't think we want to mess with start_objects and such here.  Can't 
you just use

       DECL_STATIC_CONSTRUCTOR (decl) = 1;
       SET_DECL_INIT_PRIORITY (decl, priority);

on your initialization function instead?

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
  2012-11-29 18:34     ` Jason Merrill
@ 2012-11-29 18:35       ` Jason Merrill
  0 siblings, 0 replies; 8+ messages in thread
From: Jason Merrill @ 2012-11-29 18:35 UTC (permalink / raw)
  To: gcc-patches; +Cc: Xinliang David Li, GCC Patches

On 11/16/2012 01:21 PM, Caroline Tice wrote:
> -start_objects (int method_type, int initp)
> +start_objects (int method_type, int initp, const char *extra_name)

I don't think we want to mess with start_objects and such here.  Can't 
you just use

       DECL_STATIC_CONSTRUCTOR (decl) = 1;
       SET_DECL_INIT_PRIORITY (decl, priority);

on your initialization function instead?

Jason

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-11-29 18:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-05 17:49 [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2) Caroline Tice
2012-11-07 16:58 ` Xinliang David Li
2012-11-16 18:21   ` Caroline Tice
     [not found]     ` <CABtf2+SnpddRF9kHsY-CyxNbS+3iQrUM7dqtZmbGJMNkS_WvBw@mail.gmail.com>
2012-11-28 16:17       ` Fwd: " Diego Novillo
2012-11-29 18:34     ` Jason Merrill
2012-11-29 18:35       ` Jason Merrill
2012-11-08  9:36 ` Florian Weimer
2012-11-08 16:56   ` Caroline Tice

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).