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

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).