public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [google/gcc-4_7-mobile] Port vtable verification from google/gcc-4_7-mobile-vtable-verification branch
@ 2013-02-09 19:48 Caroline Tice
  0 siblings, 0 replies; only message in thread
From: Caroline Tice @ 2013-02-09 19:48 UTC (permalink / raw)
  To: Ahmad Sharif, Han Shen, GCC Patches
  Cc: Luis Lozano, Yunlian Jiang, Guozhi Wei, Bhaskar Janakiraman

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

Hi Ahmad, Han,

I would like you to review the attached patch for the
google/gcc-4_7-mobile branch.  It implements the vtable verification
feature in gcc 4.7 (this is porting it over form the
google/gcc-4_7-mobile-vtable-verification branch, were it has already
been tested).

-- Caroline Tice
cmtice@google.com

2013-02-09  Caroline Tice  <cmtice@google.com>

        Migrate vtable verification work from GCC 4.6.3.
        * gcc/tree-pass.h (pass_vtable_verify):  Declare new pass.
	* gcc/tree-vtable-verify.c: New file.
	* gcc/tree-vtable-verify.h: New file.
	* gcc/timevr.def (TV_VTABLE_VERIFICATION): New timevar def.
	* gcc/varasm.c (assemble_variable):  Check to see if the variable
	goes into the .vtable_map_vars section and make sure it gets the
	appropriate link flags if so.
	(assemble_vtv_preinit_initializer):  New function.
	(default_sectino_type_flags):  Make sure the .vtable_map_vars section
	is LINK_ONCE.
	* gcc/config/gun-user.h: Add vtv_start.o to the
	GNU_USER_TARGET_STARTFILE_SPEC, and add vtv_end.o to the
	GNU_USER_TARGET_ENDFILE_SPEC.
	* gcc/config/i386/gnu-user.h: Add vtv_end.o to the ENDFILE_SPEC.
	* gcc/config/i386/gnu-user64.h: Ditto.
	* gcc/output.h (assemble_vtv_preinit_initializer):  New function decl.
	* gcc/flag-types.h (enum vtv_priority):  New enum, declaring the
	values for the new '-fvtable-verify=' option.
	* gcc/common.opt: Add the '-fvtable-verify=' option, along with the
	valid arguments for the option.
	* gcc/tree-ssa-copyrename.c (copy_rename_partition_coalesce):  Use
        gimple_types_compativle_p rather than types_compatible_p.
        * gcc/gimple.c (gimple_types_compatible_p): Remove 'static' function
        qualifier.
        * gcc/gimple.h (gimple_types_compatible_p):  Add extern function decl.
	* gcc/passes.c (init_optimization_passes):  Add call to
	pass_vtable_verify.
	* gcc/cp/g++spec.c (VTABLE_LOAD_MODULE_INIT): New macro definition
	for adding -lvtv_init to the link line.
	(lang_specific_driver): New global variable, saw_vtable_verify; add
	code to check for '-fvtable-verify=' and update the variable
	appropriately.  Also update num_args, and add VTABLE_LOAD_MODULE_INIT,
	and -u_vtable_map_vars_start and -u_vtable_map_vars_end to the link
	line.
	* gcc/cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
	list.
	* gcc/cp/Make-lang.in (CXX_AND_OBJCXX_OBJS): Add
	vtable-class-hierarchy.o to the list.  Also add rule for making
	vtable-class-hierarchy.o.
	* gcc/cp/class.c (finish_struct_1):  Add call to vtv_save_class_info.
	* gcc/cp/pt.c (makr_class_instantiated):  Ditto.
	* gcc/cp/init.c (build_vtbl_address):  Remove static qualifier.
	* gcc/cp/cp-tree.h (vtv_start_verification_constructor_init_function,
	vtv_finish_verification_constructor_init_function, build_vtbl_address,
	get_mangled_id, vtv_comput_class_hierarchy_transitive_closure,
	vtv_generate_init_routine,vtv_save_class_info, vtv_recover_class_info)
	Add extern function decls.
	* gcc/cp/decl2.c (cp_write_global_declarations):  Add calls to
	vtv_recover_class_info and
	vtv_computer_class_hierarchy_transitive_closure before the call to
	cgraph_finalize_compilation_unit.  Add call to
	vtv_generate_init_routine after the call to
	cgraph_finalize_compilation_unit.
	(vtv_start_verification_constructor_init_function):  New function.
	(vtv_finish_verification_constructor_init_function):  New function.
	* gcc/cp/vtable-class-hierarchy.c: New file.
	* gcc/cp/mangle.c (get_mangled_id): Remove static function qualifier.
         (mangle_decl):  Make sure the decl is a VAR_DECL before
         calling varpool_extra_name_alias.
	* gcc/tree.h (save_vtable_map_decl):  New function decl.
	* gcc/Makefile.in (OBJS): Add tree-vtable-verify.o to the list.  Also
	add the rule for making tree-vtable-verify.o
	* gcc/cgraph.c (cgraph_add_new_function):  Change call to
	cgraph_create_node to a call to cgraph_get_create_node.
	* libstdc++-v3/configure:  Add vtv_start.o to predep_objects; add
	vtv_end.o to postdep_objects.
	* libstdc++-v3/src/Makefile.am:  Add "-Wl,-u_vtable_map_vars_start,
	-u_vtable_map_vars_end" to libstdc___la_LDFLAGS.  Add definitions
        for libvtv___la_LIBADD and LIBVTV_FLAGS.
	* libstdc++-v3/src/Makefile.in: Regenerate from Makefile.am.
	* libstdc++-v3/config/abi/pre/gnu.ver:  Add __VLT* and __vtv functions
	to the exported symbols list.
	* libstdc++-v3/libsupc++/vtv_utils.cc:  New file.
	* libstdc++-v3/libsupc++/vtv_utils.h:  New file.
	* libstdc++-v3/libsupc++/vtv_init.cc:  New file.
	* libstdc++-v3/libsupc++/vtv_malloc.cc:  New file.
	* libstdc++-v3/libsupc++/Makefile.am:  Add vtv_rts.cc,
	vtv_malloc.cc and vtv_utils.cc to sources list.  Define
	vtv_init_sources and vtv_stubs_sources.  Add libvtv_init.la and
	libvtv_stubs.la to toolexeclib_LTLIBRARIES.  Add definitions for
	libvtv_init_la_SOURCES and libvtv_stubs_la_SOURCES.
	* libstdc++-v3/libsupc++/Makefile.in:  Regenerate from Makefile.am.
	* libstdc++-v3/libsupc++/vtv_rts.cc:  New file.
	* libstdc++-v3/libsupc++/vtv_rts.h:  New file.
	* libstdc++-v3/libsupc++/vtv_fail.h:  New file.
	* libstdc++-v3/libsupc++/vtv_map.h:  New file.
	* libstdc++-v3/libsupc++/vtv_set.h:  New file.
	* libstdc++-v3/libsupc++/vtv_stubs.cc:  New file.
	* libgcc/config.host (extra_parts): Add vtv_start.o and vtv_end.o
	* libgcc/Makefile.in:  Add rules for building vtv_start.o and
        vtv_end.o.
	* libgcc/vtv_end.c:  New file.
	* libgcc/vtv_start.c:  New file.

[-- Attachment #2: gcc-4.7-mobile.patch --]
[-- Type: application/octet-stream, Size: 260045 bytes --]

Index: libstdc++-v3/configure
===================================================================
--- libstdc++-v3/configure	(revision 195903)
+++ libstdc++-v3/configure	(working copy)
@@ -13205,8 +13205,8 @@ $as_echo "$ld_shlibs_CXX" >&6; }
     ## the running order or otherwise move them around unless you know exactly
     ## what you are doing...
     # Dependencies to place before and after the object being linked:
-predep_objects_CXX=
-postdep_objects_CXX=
+predep_objects_CXX="${glibcxx_builddir}/../libgcc/vtv_start.o"
+postdep_objects_CXX="${glibcxx_builddir}/../libgcc/vtv_end.o"
 predeps_CXX=
 postdeps_CXX=
 compiler_lib_search_path_CXX=
Index: libstdc++-v3/src/Makefile.in
===================================================================
--- libstdc++-v3/src/Makefile.in	(revision 195903)
+++ libstdc++-v3/src/Makefile.in	(working copy)
@@ -367,9 +367,15 @@ libstdc___la_DEPENDENCIES = \
 	$(top_builddir)/src/c++11/libc++11convenience.la
 
 libstdc___la_LDFLAGS = \
-	-version-info $(libtool_VERSION) ${version_arg} -lm
+	-version-info $(libtool_VERSION) ${version_arg} -lm -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
 
 libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
+libvtv___la_LIBADD = \
+        $(top_builddir)/libsupc++/.libs
+
+LIBVTV_FLAGS = \
+        -L$(libvtv___la_LIBADD) --whole-archive -lvtv_init --no-whole-archive
+
 
 # Use special rules for parallel mode compilation.
 PARALLEL_FLAGS = -fopenmp -D_GLIBCXX_PARALLEL -I$(glibcxx_builddir)/../libgomp
Index: libstdc++-v3/src/Makefile.am
===================================================================
--- libstdc++-v3/src/Makefile.am	(revision 195903)
+++ libstdc++-v3/src/Makefile.am	(working copy)
@@ -74,9 +74,13 @@ libstdc___la_DEPENDENCIES = \
 	$(top_builddir)/src/c++11/libc++11convenience.la
 
 libstdc___la_LDFLAGS = \
-	-version-info $(libtool_VERSION) ${version_arg} -lm
+	-version-info $(libtool_VERSION) ${version_arg} -lm -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
 
 libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
+libvtv___la_LIBADD = \
+        $(top_builddir)/libsupc++/.libs
+LIBVTV_FLAGS = \
+        -L$(libvtv___la_LIBADD) --whole-archive -lvtv_init --no-whole-archive
 
 
 # Use special rules for parallel mode compilation.
@@ -160,7 +164,7 @@ LTLDFLAGS = $(shell $(SHELL) $(top_srcdi
 CXXLINK = \
 	$(LIBTOOL) --tag CXX \
 	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
-	--mode=link $(CXX) \
+	--mode=link $(CXX) \ 
 	$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
 
 
Index: libstdc++-v3/libsupc++/Makefile.in
===================================================================
--- libstdc++-v3/libsupc++/Makefile.in	(revision 195903)
+++ libstdc++-v3/libsupc++/Makefile.in	(working copy)
@@ -102,7 +102,8 @@ am__objects_1 = array_type_info.lo atexi
 	new_handler.lo new_op.lo new_opnt.lo new_opv.lo new_opvnt.lo \
 	pbase_type_info.lo pmem_type_info.lo pointer_type_info.lo \
 	pure.lo si_class_type_info.lo tinfo.lo tinfo2.lo vec.lo \
-	vmi_class_type_info.lo vterminate.lo
+	vmi_class_type_info.lo vterminate.lo vtv_rts.lo vtv_malloc.lo \
+	vtv_utils.lo
 @GLIBCXX_HOSTED_TRUE@am__objects_2 = cp-demangle.lo
 am_libsupc___la_OBJECTS = $(am__objects_1) $(am__objects_2)
 libsupc___la_OBJECTS = $(am_libsupc___la_OBJECTS)
@@ -110,6 +111,14 @@ libsupc__convenience_la_LIBADD =
 am_libsupc__convenience_la_OBJECTS = $(am__objects_1) $(am__objects_2)
 libsupc__convenience_la_OBJECTS =  \
 	$(am_libsupc__convenience_la_OBJECTS)
+libvtv_init_la_LIBADD =
+am__objects_3 = vtv_init.lo
+am_libvtv_init_la_OBJECTS = $(am__objects_3)
+libvtv_init_la_OBJECTS = $(am_libvtv_init_la_OBJECTS)
+libvtv_stubs_la_LIBADD =
+am__objects_4 = vtv_stubs.lo
+am_libvtv_stubs_la_OBJECTS = $(am__objects_4)
+libvtv_stubs_la_OBJECTS = $(am_libvtv_stubs_la_OBJECTS)
 DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
 depcomp =
 am__depfiles_maybe =
@@ -122,7 +131,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLF
 CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
 	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
 CXXLD = $(CXX)
-SOURCES = $(libsupc___la_SOURCES) $(libsupc__convenience_la_SOURCES)
+SOURCES = $(libsupc___la_SOURCES) $(libsupc__convenience_la_SOURCES) \
+	$(libvtv_init_la_SOURCES) $(libvtv_stubs_la_SOURCES)
 HEADERS = $(bits_HEADERS) $(std_HEADERS)
 ETAGS = etags
 CTAGS = ctags
@@ -340,7 +350,7 @@ AM_CPPFLAGS = $(GLIBCXX_INCLUDES)
 # Need this library to both be part of libstdc++.a, and installed
 # separately too.
 # 1) separate libsupc++.la
-toolexeclib_LTLIBRARIES = libsupc++.la
+toolexeclib_LTLIBRARIES = libsupc++.la libvtv_init.la libvtv_stubs.la
 # 2) integrated libsupc++convenience.la that is to be a part of libstdc++.a
 noinst_LTLIBRARIES = libsupc++convenience.la
 std_HEADERS = \
@@ -402,10 +412,21 @@ sources = \
 	tinfo2.cc \
 	vec.cc \
 	vmi_class_type_info.cc \
-	vterminate.cc
+	vterminate.cc \
+        vtv_rts.cc \
+        vtv_malloc.cc \
+        vtv_utils.cc
+
+vtv_init_sources = \
+        vtv_init.cc
+
+vtv_stubs_sources = \
+        vtv_stubs.cc
 
 libsupc___la_SOURCES = $(sources) $(c_sources)
 libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+libvtv_init_la_SOURCES = $(vtv_init_sources)
+libvtv_stubs_la_SOURCES = $(vtv_stubs_sources)
 
 # AM_CXXFLAGS needs to be in each subdirectory so that it can be
 # modified in a per-library or per-sub-library way.  Need to manually
@@ -569,6 +590,10 @@ libsupc++.la: $(libsupc___la_OBJECTS) $(
 	$(CXXLINK) -rpath $(toolexeclibdir) $(libsupc___la_OBJECTS) $(libsupc___la_LIBADD) $(LIBS)
 libsupc++convenience.la: $(libsupc__convenience_la_OBJECTS) $(libsupc__convenience_la_DEPENDENCIES) 
 	$(CXXLINK)  $(libsupc__convenience_la_OBJECTS) $(libsupc__convenience_la_LIBADD) $(LIBS)
+libvtv_init.la: $(libvtv_init_la_OBJECTS) $(libvtv_init_la_DEPENDENCIES) 
+	$(CXXLINK) -rpath $(toolexeclibdir) $(libvtv_init_la_OBJECTS) $(libvtv_init_la_LIBADD) $(LIBS)
+libvtv_stubs.la: $(libvtv_stubs_la_OBJECTS) $(libvtv_stubs_la_DEPENDENCIES) 
+	$(CXXLINK) -rpath $(toolexeclibdir) $(libvtv_stubs_la_OBJECTS) $(libvtv_stubs_la_LIBADD) $(LIBS)
 
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
Index: libstdc++-v3/libsupc++/vtv_rts.cc
===================================================================
--- libstdc++-v3/libsupc++/vtv_rts.cc	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_rts.cc	(revision 0)
@@ -0,0 +1,1314 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ 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.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+ <http://www.gnu.org/licenses/>.  */
+
+/* This file is part of the vtable security feature implementation.
+   The vtable security feature is designed to detect when a virtual
+   call is about to be made through an invalid vtable pointer
+   (possibly due to data corruption or malicious attacks). The
+   compiler finds every virtual call, and inserts a verification call
+   before the virtual call.  The verification call takes the actual
+   vtable pointer value in the object through which the virtual call
+   is being made, and compares the vtable pointer against a set of all
+   valid vtable pointers that the object could contain (this set is
+   based on the declared type of the object).  If the pointer is in
+   the valid set, execution is allowed to continue; otherwise the
+   program is halted.
+
+  There are several pieces needed in order to make this work: 1. For
+  every virtual class in the program (i.e. a class that contains
+  virtual methods), we need to build the set of all possible valid
+  vtables that an object of that class could point to.  This includes
+  vtables for any class(es) that inherit from the class under
+  consideration.  2. For every such data set we build up, we need a
+  way to find and reference the data set.  This is complicated by the
+  fact that the real vtable addresses are not known until runtime,
+  when the program is loaded into memory, but we need to reference the
+  sets at compile time when we are inserting verification calls into
+  the program.  3.  We need to find every virtual call in the program,
+  and insert the verification call (with the appropriate arguments)
+  before the virtual call.  4. We need some runtime library pieces:
+  the code to build up the data sets at runtime; the code to actually
+  perform the verification using the data sets; and some code to set
+  protections on the data sets, so they themselves do not become
+  hacker targets.
+
+  To find and reference the set of valid vtable pointers for any given
+  virtual class, we create a special global varible for each virtual
+  class.  We refer to this as the "vtable map variable" for that
+  class.  The vtable map variable has the type "void *", and is
+  initialized by the compiler to NULL.  At runtime when the set of
+  valid vtable pointers for a virtual class, e.g. class Foo, is built,
+  the vtable map variable for class Foo is made to point to the set.
+  During compile time, when the compiler is inserting verification
+  calls into the program, it passes the vtable map variable for the
+  appropriate class to the verification call, so that at runtime the
+  verification call can find the appropriate data set.
+
+  The actual set of valid vtable pointers for a virtual class,
+  e.g. class Foo, cannot be built until runtime, when the vtables get
+  loaded into memory and their addresses are known.  But the knowledge
+  about which vtables belong in which class' hierarchy is only known
+  at compile time.  Therefore at compile time we collect class
+  hierarchy and vtable information about every virtual class, and we
+  generate calls to build up the data sets at runtime.  To build the
+  data sets, we call one of the functions we add to the runtime
+  library, __VLTRegisterPair.  __VLTRegisterPair takes two arguments,
+  a vtable map variable and the address of a vtable.  If the vtable
+  map variable is currently NULL, it creates a new data set (hash
+  table), makes the vtable map variable point to the new data set, and
+  inserts the vtable address into the data set.  If the vtable map
+  variable is not NULL, it just inserts the vtable address into the
+  data set.  In order to make sure that our data sets are built before
+  any verification calls happen, we create a special constructor
+  initialization function for each compilation unit, give it a very
+  high initialization priority, and insert all of our calls to
+  __VLTRegisterPair into our special constructor initialization
+  function.  */
+
+/* This file contains the main externally visible runtime library
+   functions for vtable verification: __VLTChangePermission,
+   __VLTRegisterPair, and __VLTVerifyVtablePointer.  It also contains
+   debug versions __VLTRegisterPairDebug and
+   __VLTVerifyVtablePointerDebug, which have extra parameters in order
+   to make it easier to debug verification failures.
+
+   This file also contains the failure functions that get called when
+   a vtable pointer is not found in the data set.  Two particularly
+   important functions are __vtv_verify_fail and __vtv_really_fail.
+   They are both externally visible.  __vtv_verify_fail is defined in
+   such a way that it can be replaced by a programmer, if desired.  It
+   is the function that __VLTVerifyVtablePointer calls if it can't
+   find the pointer in the data set.  Allowing the programmer to
+   overwrite this function means that he/she can do some alternate
+   verification, including NOT failing in certain specific cases, if
+   desired.  This may be the case if the programmer has to deal wtih
+   unverified third party software, for example.  __vtv_really_fail is
+   available for the programmer to call from his version of
+   __vtv_verify_fail, if he decides the failure is real.
+
+   The final piece of functionality implemented in this file is symbol
+   resolution for multiple instances of the same vtable map variable.
+   If the same virtual class is used in two different compilation
+   units, then each compilation unit will create a vtable map variable
+   for the class.  We need all instances of the same vtable map
+   variable to point to the same (single) set of valid vtable
+   pointters for the class, so we wrote our own hashtable-based symbol
+   resolution for vtable map variables (with a tiny optimization in
+   the case where there is only one instance of the variable).
+
+   There are two other important pieces to the runtime for vtable
+   verification besides the main pieces that go into libstdc++.so: two
+   special tiny shared libraries, libvtv_init.so and libvtv_stubs.so.
+   libvtv_init.so is built from vtv_init.cc.  It is designed to hel[p
+   minimize the calls made to mprotect (see the comments in
+   vtv_init.cc for more details).  Anything compiled with
+   "-fvtable-verify=std" must be linked with libvtv_init.so (the gcc
+   driver has been modified to do this).  vtv_stubs.so is built from
+   vtv_stubs.cc.  It replaces the main runtime functions
+   (__VLTChangePermissino, __VLTRegisterPair and
+   __VLTVerifyVtablePoitner) with stub functions that do nothing.  If
+   a programmer has a library that was built with verification, but
+   wishes to not have verification turned on, the programmer can link
+   in the vtv_stubs.so library.  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <execinfo.h>
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <link.h>
+#include <fcntl.h>
+#include <limits.h>
+
+/* For gthreads suppport */
+#include <bits/c++config.h>
+#include <ext/concurrence.h>
+
+#include "vtv_utils.h"
+#include "vtv_malloc.h"
+#include "vtv_set.h"
+#include "vtv_map.h"
+#include "vtv_rts.h"
+#include "vtv_fail.h"
+
+extern "C" {
+
+  /* __fortify_fail is a function in glibc that calls __libc_message,
+     causing it to print out a program termination error message
+     (including the name of the binary being terminated), a stack
+     trace where the error occurred, and a memory map dump.  Ideally
+     we would have called __libc_message directly, but that function
+     does not appear to be accessible to functions outside glibc,
+     whereas __fortify_fail is.  We call __fortify_fail from
+     __vtv_really_fail.  We looked at calling __libc_fatal, which is
+     externally accessible, but it does not do the back trace and
+     memory dump.  */
+
+  extern void __fortify_fail (const char *) __attribute__((noreturn));
+
+} /* extern "C" */
+
+
+/* Be careful about initialization of statics in this file.  Some of
+   the routines below are called before any runtime initialization for
+   statics in this file will be done. For example, dont try to
+   initialize any of these statics with a runtime call (for ex:
+   sysconf. The initialization will happen after calls to the routines
+   to protect/unprotec the vtabla_map variables */
+
+/* No need to mark the following variables with VTV_PROTECTED_VAR.
+   These are either const or are only used for debugging/tracing.
+   debugging/tracing will not be ON on production environments */
+
+static const bool debug_hash = HASHTABLE_STATS;
+
+/* TODO: Make sure debugging messages under this guard dont use malloc!  */
+static const int debug_functions = 0;
+static const int debug_init = 0;
+static const int debug_verify_vtable = 0;
+
+
+#ifdef VTV_DEBUG
+/* Global file descriptor variables for logging, tracing and debugging.  */
+static int init_log_fd = -1;
+static int verify_vtable_log_fd = -1;
+
+/* This holds a formatted error logging message, to be written to the
+   vtable verify failures log.  */
+static char debug_log_message[1024];
+#endif 
+
+/* TODO: should this be under VTV_DEBUG?  */
+static int vtv_failures_log_fd = -1;
+
+#if HASHTABLE_STATS
+static int set_log_fd = -1;
+#endif
+
+
+#ifdef __GTHREAD_MUTEX_INIT
+/* TODO: NEED TO PROTECT THIS VAR  !!!!!!!!!!!!!!!!!!!  */
+static __gthread_mutex_t change_permissions_lock = __GTHREAD_MUTEX_INIT;
+#else
+/* TODO: NEED TO PROTECT THIS VAR  !!!!!!!!!!!!!!!!!!!  */
+static __gthread_mutex_t change_permissions_lock;
+#endif
+
+/* Types needed by insert_only_hash_sets.  */
+typedef uintptr_t int_vptr;
+
+/* The set of valid vtable pointers for each virtual class is stored
+   in a hash table.  This is the hashing function used for the hash
+   table.  For more information on the implementation of the hash
+   table, see the class insert_only_hash_sets in vtv_set.h.  */
+
+struct vptr_hash
+  {
+    /* Hash function, used to convert vtable pointer, V, (a memory
+       address) into an index into the hash table.  */
+    size_t
+    operator() (int_vptr v) const
+      {
+        const uint32_t x = 0x7a35e4d9;
+        const int shift = (sizeof (v) == 8) ? 23 : 21;
+        v = x * v;
+        return v ^ (v >> shift);
+      }
+  };
+
+/* This is the memory allocator used to create the hash table data
+   sets of valid vtable pointers.  We use VTV_malloc in order to keep
+   track of which pages have been allocated, so we can update the
+   protections on those pages appropriately.  See the class
+   insert_only_hash_sets in vtv_set.h for more information.  */
+
+struct vptr_set_alloc
+  {
+    /* Memory allocator operator.  N is the number of bytes to be
+       allocated.  */
+    void *
+    operator() (size_t n) const
+      {
+        return VTV_malloc (n);
+      }
+  };
+
+/* Instantiate the template classes (in vtv_set.h) for our particular
+   hash table needs.  */
+typedef insert_only_hash_sets<int_vptr, vptr_hash, vptr_set_alloc> vtv_sets;
+typedef vtv_sets::insert_only_hash_set vtv_set;
+typedef vtv_set * vtv_set_handle;
+typedef vtv_set_handle * vtv_set_handle_handle; 
+
+/* Data structure passed to our dl_iterate_phdr callback function,
+   indicating whether mprotect should make the pages readonly or
+   read/write, and what page size to use.  */
+
+struct mprotect_data
+  {
+    int prot_mode;
+    unsigned long page_size;
+  };
+
+/* Records for caching teh section header information that we have
+   read out of the file(s) on disk (in dl_iterate_phdr_callback), to
+   avoid having to re-open and re-read the same file multiple
+   times.  */
+
+struct sect_hdr_data
+{
+  ElfW (Addr) dlpi_addr; /* The header address in the INFO record,
+                            passed in from dl_iterate_phdr.  */
+  ElfW (Addr) mp_low;    /* Start address of the .vtable_map_vars
+                            section in memory.  */
+  size_t mp_size;        /* Size of the .vtable_map_vars section in
+                            memory.  */
+};
+
+/* Array for caching the section header information, read from file,
+   to avoid re-opening and re-reading the same file over-and-over
+   again.  */
+
+#define MAX_ENTRIES 250
+struct sect_hdr_data sect_info_cache[MAX_ENTRIES];
+
+unsigned int num_cache_entries = 0;
+
+/* This function takes the LOAD_ADDR for an object opened by the
+   dynamic loader, and checks the array of cached file data to see if
+   there is an entry with the same addres.  If it finds such an entry,
+   it returns the record for that entry; otherwise it returns
+   NULL.  */
+
+struct sect_hdr_data *
+search_cached_file_data (ElfW (Addr) load_addr)
+{
+  unsigned int i;
+  for (i = 0; i < num_cache_entries; ++i)
+    {
+      if (sect_info_cache[i].dlpi_addr == load_addr)
+        return &(sect_info_cache[i]);
+    }
+
+  return NULL;
+}
+
+/* This function tries to read COUNT bytes out of the file referred to
+   by FD into the buffer BUF.  It returns the actual number of bytes
+   it succeeded in reading.  */
+
+static ssize_t
+ReadPersistent (int fd, void *buf, size_t count)
+{
+  char *buf0 = (char *) buf;
+  size_t num_bytes = 0;
+  while (num_bytes < count)
+    {
+      int len;
+      len = read (fd, buf0 + num_bytes, count - num_bytes);
+      if (len < 0)
+        return -1;
+      if (len == 0)
+        break;
+      num_bytes += len;
+    }
+
+  return num_bytes;
+}
+
+/* This function tries to read COUNT bytes, starting at OFFSET from
+   the file referred to by FD, and put them into BUF.  It calls
+   ReadPersistent to help it do so.  It returns the actual number of
+   bytes read, or -1 if it fails altogether.  */
+
+static ssize_t
+ReadFromOffset (int fd, void *buf, const size_t count, const off_t offset)
+{
+  off_t off = lseek (fd, offset, SEEK_SET);
+  if (off != (off_t) -1)
+    return ReadPersistent (fd, buf, count);
+  return -1;
+}
+
+/* The function takes a MESSAGE and attempts to write it to the vtable
+   memory protection log (for debugging purposes).  If the file is not
+   open, it attempts to open the file first.  Sometimes multiple
+   processes may be attempting to write to the log file at the same
+   time, so we may attempt to open multiple log files (with versioned
+   names) if the first open fails.  */
+
+static void
+log_memory_protection_data (char *message)
+{
+  static int log_fd = -1;
+
+  if (log_fd == -1)
+    log_fd = vtv_open_log ("vtv_memory_protection_data.log");
+
+  vtv_add_to_log (log_fd, "%s", message);
+}
+
+/* This is the callback function used by dl_iterate_phdr (which is
+   called from VTV_unprotect_vtable_vars and VTV_protect_vtable_vars).
+   It attempts to find the binary file on disk for the INFO record
+   that dl_iterate_phdr passes in; open the binary file, and read its
+   section header information.  If the file contains a
+   ".vtable_map_vars" section, read the section offset and size.  Use
+   the secttion offset and size, in conjunction with the data in INFO
+   to locate the pages in memory where the section is.  Call
+   'mprotect' on those pages, setting the protection either to
+   read-only or read-write, depending on what's in DATA.  */
+
+static int
+dl_iterate_phdr_callback (struct dl_phdr_info *info,
+			  size_t unused __attribute__((__unused__)),
+			  void *data)
+{
+  mprotect_data * mdata = (mprotect_data *) data;
+  off_t map_sect_offset = 0;
+  ElfW (Word) map_sect_len = 0;
+  ElfW (Addr) start_addr = 0;
+  struct sect_hdr_data *cached_data = NULL;
+  bool found = false;
+  char buffer[PATH_MAX];
+  char program_name[PATH_MAX];
+  char *cptr;
+  static bool first_time = true;
+  const ElfW (Phdr) *phdr_info = info->dlpi_phdr;
+  const ElfW (Ehdr) *ehdr_info =
+    (const ElfW (Ehdr) *) (info->dlpi_addr + info->dlpi_phdr[0].p_vaddr
+                           - info->dlpi_phdr[0].p_offset);
+
+  /* Check to see if this is the record for the Linux Virtual Dynamic
+     Shared Object (linux-vdso.so.1), which exists only in memory (and
+     therefore cannot be read from disk).  */
+
+  if (strcmp (info->dlpi_name, "linux-vdso.so.1") == 0)
+    return 0;
+
+  if (strlen (info->dlpi_name) == 0
+      && info->dlpi_addr != 0)
+    return 0;
+
+  if (first_time)
+    {
+      int i;
+      for (i = 0; i < MAX_ENTRIES; ++i)
+        {
+          sect_info_cache[i].dlpi_addr = (ElfW (Addr)) 0;
+          sect_info_cache[i].dlpi_addr = (ElfW (Addr)) 0;
+          sect_info_cache[i].dlpi_addr =  0;
+        }
+      first_time = false;
+    }
+
+  /* Get the name of the main executable.  This may or may not include
+     arguments passed to the program.  Find the first space, assume it
+     is the start of the argument list, and change it to a '\0'. */
+  snprintf (program_name, sizeof (program_name), program_invocation_name);
+
+  /* Check to see if we already have the data for this file.  */
+  cached_data = search_cached_file_data (info->dlpi_addr);
+
+  if (cached_data)
+    {
+      /* We already read the section header data and calculated the
+         appropriate addresses; use the cached data to set the
+         appropriate protections and return.  */
+      if (mprotect ((void *) cached_data->mp_low, cached_data->mp_size,
+                    mdata->prot_mode) == -1)
+        {
+          if (debug_functions)
+            {
+              snprintf (buffer, sizeof (buffer),
+                        "Failed called to mprotect for %s error: ",
+                        (mdata->prot_mode & PROT_WRITE) ?
+                        "READ/WRITE" : "READ-ONLY");
+              log_memory_protection_data (buffer);
+              perror(NULL);
+            }
+          VTV_error();
+        }
+      else if (debug_functions)
+        {
+          snprintf (buffer, sizeof (buffer),
+                    "mprotect'ed range [%p, %p]\n",
+                    (void *) cached_data->mp_low,
+		    (char *) cached_data->mp_low + cached_data->mp_size);
+          log_memory_protection_data (buffer);
+        }
+      return 0;
+    }
+
+  /* Find the first non-escaped space in the program name and make it
+     the end of the string.  */
+  cptr = strchr (program_name, ' ');
+  if (cptr != NULL && cptr[-1] != '\\')
+    cptr[0] = '\0';
+
+  if ((phdr_info->p_type == PT_PHDR || phdr_info->p_type == PT_LOAD)
+      && (ehdr_info->e_shoff && ehdr_info->e_shnum))
+    {
+      const char *map_sect_name = ".vtable_map_vars";
+      int name_len = strlen (map_sect_name);
+      int fd = -1;
+
+      /* Attempt to open the binary file on disk.  */
+      if (strlen (info->dlpi_name) == 0)
+        {
+          /* If the constructor initialization function was put into
+             the preinit array, then this function will get called
+             while handling preinit array stuff, in which case
+             program_invocation_name has not been initialized.  In
+             that case we can get the filename of the executable from
+             "/proc/self/exe".  */
+          if (strlen (program_name) > 0)
+            {
+              if (phdr_info->p_type == PT_PHDR)
+                fd = open (program_name, O_RDONLY);
+            }
+          else
+            fd = open ("/proc/self/exe", O_RDONLY);
+        }
+      else
+        fd = open (info->dlpi_name, O_RDONLY);
+
+      /* VTV_ASSERT (fd != -1); */
+      if (fd != -1)
+      {
+
+      /* Find the section header information in the file.  */
+      ElfW (Half) strtab_idx = ehdr_info->e_shstrndx;
+      ElfW (Shdr) shstrtab;
+      off_t shstrtab_offset = ehdr_info->e_shoff +
+                                         (ehdr_info->e_shentsize * strtab_idx);
+      size_t bytes_read = ReadFromOffset (fd, &shstrtab, sizeof (shstrtab),
+                                          shstrtab_offset);
+      VTV_ASSERT (bytes_read == sizeof (shstrtab));
+
+      ElfW (Shdr) sect_hdr;
+
+      /* Loop through all the section headers, looking for one whose
+         name is ".vtable_map_vars".  */
+
+      for (int i = 0; i < ehdr_info->e_shnum && !found; ++i)
+        {
+          off_t offset = ehdr_info->e_shoff + (ehdr_info->e_shentsize * i);
+
+          bytes_read = ReadFromOffset (fd, &sect_hdr, sizeof (sect_hdr),
+                                       offset);
+
+          VTV_ASSERT (bytes_read == sizeof (sect_hdr));
+
+          char header_name[64];
+          off_t name_offset = shstrtab.sh_offset +  sect_hdr.sh_name;
+
+          bytes_read = ReadFromOffset (fd, &header_name, 64, name_offset);
+
+          VTV_ASSERT (bytes_read > 0);
+
+          if (memcmp (header_name, map_sect_name, name_len) == 0)
+            {
+              /* We found the section; get its load offset and
+                 size.  */
+              map_sect_offset = sect_hdr.sh_addr;
+              map_sect_len = sect_hdr.sh_size - mdata->page_size;
+              found = true;
+            }
+        }
+      close (fd);
+
+      }
+      /* Calculate the start address of the section in memory.  */
+      start_addr = (const ElfW (Addr)) info->dlpi_addr + map_sect_offset;
+    }
+
+  if (debug_functions)
+    {
+      snprintf (buffer, sizeof(buffer),
+                "  Looking at load module %s to change permissions to %s\n",
+                ((strlen (info->dlpi_name) == 0) ? program_name
+                                                 : info->dlpi_name),
+                (mdata->prot_mode & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY");
+      log_memory_protection_data (buffer);
+    }
+
+  /* See if we actually found the section.  */
+  if (start_addr && map_sect_len)
+    {
+      ElfW (Addr) relocated_start_addr = start_addr;
+      ElfW (Word) size_in_memory = map_sect_len;
+
+      if ((relocated_start_addr != 0)
+          && (size_in_memory != 0))
+        {
+          /* Calculate the address & size to pass to mprotect. */
+          ElfW (Addr) mp_low = relocated_start_addr & ~(mdata->page_size - 1);
+          size_t mp_size = size_in_memory - 1;
+
+          if (debug_functions)
+            {
+              snprintf (buffer, sizeof (buffer),
+                        "  (%s): Protecting %p to %p\n",
+                       ((strlen (info->dlpi_name) == 0) ? program_name
+                                                        : info->dlpi_name),
+                       (void *) mp_low,
+                       ((void *) mp_low + mp_size));
+              log_memory_protection_data (buffer);
+            }
+
+          /* Change the protections on the pages for the section.  */
+          if (mprotect ((void *) mp_low, mp_size, mdata->prot_mode) == -1)
+            {
+              if (debug_functions)
+                {
+                  snprintf (buffer, sizeof (buffer),
+                            "Failed called to mprotect for %s error: ",
+                            (mdata->prot_mode & PROT_WRITE) ?
+                            "READ/WRITE" : "READ-ONLY");
+                  log_memory_protection_data (buffer);
+                  perror(NULL);
+                }
+              VTV_error();
+            }
+          else if (debug_functions)
+            {
+              if (num_cache_entries < MAX_ENTRIES)
+                {
+                  sect_info_cache[num_cache_entries].dlpi_addr =
+                                                               info->dlpi_addr;
+                  sect_info_cache[num_cache_entries].mp_low = mp_low;
+                  sect_info_cache[num_cache_entries].mp_size = mp_size;
+                  num_cache_entries++;
+                }
+              snprintf (buffer, sizeof (buffer),
+                        "mprotect'ed range [%p, %p]\n",
+                        (void *) mp_low, (char *) mp_low + mp_size);
+              log_memory_protection_data (buffer);
+            }
+        }
+    }
+
+  return 0;
+}
+
+/* Unprotect all the vtable map vars and other side data that is used
+   to keep the core hash_map data. All of these data have been put
+   into relro sections */
+
+static void
+VTV_unprotect_vtable_vars (void)
+{
+  mprotect_data mdata;
+
+  mdata.prot_mode = PROT_READ | PROT_WRITE;
+  mdata.page_size = sysconf (_SC_PAGE_SIZE);
+  dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mdata);
+}
+
+/* Protect all the vtable map vars and other side data that is used
+   to keep the core hash_map data. All of these data have been put
+   into relro sections */
+
+static void
+VTV_protect_vtable_vars (void)
+{
+  mprotect_data mdata;
+
+  mdata.prot_mode = PROT_READ;
+  mdata.page_size = sysconf (_SC_PAGE_SIZE);
+  dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mdata);
+}
+
+#ifndef __GTHREAD_MUTEX_INIT
+static void
+initialize_change_permissions_mutexes ()
+{
+  __GTHREAD_MUTEX_INIT_FUNCTION (&change_permissions_lock);
+}
+#endif
+
+/*  Variables needed for getting the statistics about the hashtable set.  */
+#if HASHTABLE_STATS
+_AtomicStatCounter stat_contains = 0;
+_AtomicStatCounter stat_insert = 0;
+_AtomicStatCounter stat_resize = 0;
+_AtomicStatCounter stat_create = 0;
+_AtomicStatCounter stat_probes_in_non_trivial_set = 0;
+_AtomicStatCounter stat_contains_size0 = 0;
+_AtomicStatCounter stat_contains_size1 = 0;
+_AtomicStatCounter stat_contains_size2 = 0;
+_AtomicStatCounter stat_contains_size3 = 0;
+_AtomicStatCounter stat_contains_size4 = 0;
+_AtomicStatCounter stat_contains_size5 = 0;
+_AtomicStatCounter stat_contains_size6 = 0;
+_AtomicStatCounter stat_contains_size7 = 0;
+_AtomicStatCounter stat_contains_size8 = 0;
+_AtomicStatCounter stat_contains_size9 = 0;
+_AtomicStatCounter stat_contains_size10 = 0;
+_AtomicStatCounter stat_contains_size11 = 0;
+_AtomicStatCounter stat_contains_size12 = 0;
+_AtomicStatCounter stat_contains_size13_or_more = 0;
+_AtomicStatCounter stat_contains_sizes = 0;
+_AtomicStatCounter stat_grow_from_size0_to_1 = 0;
+_AtomicStatCounter stat_grow_from_size1_to_2 = 0;
+_AtomicStatCounter stat_double_the_number_of_buckets = 0;
+_AtomicStatCounter stat_insert_found_hash_collision = 0;
+_AtomicStatCounter stat_contains_in_non_trivial_set = 0;
+_AtomicStatCounter stat_insert_key_that_was_already_present = 0;
+#endif
+
+/* Record statistics about the hash table sets, for debugging.  */
+
+static void
+log_set_stats (void)
+{
+#if HASHTABLE_STATS
+      if (set_log_fd == -1)
+        set_log_fd = vtv_open_log ("vtv_set_stats.log");
+
+      vtv_add_to_log (set_log_fd, "---\n%s\n",
+                      insert_only_hash_tables_stats().c_str());
+#endif
+}
+
+/* Change the permissions on all the pages we have allocated for the
+   data sets and all the ".vtable_map_var" sections in memory (which
+   contain our vtable map variables).  PERM indicates whether to make
+   the permissions read-only or read-write.  */
+
+void
+__VLTChangePermission (int perm)
+{
+  if (debug_functions)
+    {
+      if (perm == __VLTP_READ_WRITE)
+        fprintf (stdout, "Changing VLT permisisons to Read-Write.\n");
+      else if (perm == __VLTP_READ_ONLY)
+        fprintf (stdout, "Changing VLT permissions to Read-only.\n");
+      else
+        fprintf (stdout, "Unrecognized permissions value: %d\n", perm);
+    }
+
+#ifndef __GTHREAD_MUTEX_INIT
+  static __gthread_once_t mutex_once VTV_PROTECTED_VAR = __GTHREAD_ONCE_INIT;
+
+  __gthread_once (&mutex_once, initialize_change_permissions_mutexes);
+#endif
+
+  /* Ordering of these unprotect/protect calls is very important.
+     You first need to unprotect all the map vars and side
+     structures before you do anything with the core data
+     structures (hash_maps) */
+
+  if (perm == __VLTP_READ_WRITE)
+    {
+      /* TODO: Meed to revisit this code for dlopen. It most probably
+         is not unlocking the protected vtable vars after for a load
+         module that is not the first load module.  */
+      __gthread_mutex_lock (&change_permissions_lock);
+
+      VTV_unprotect_vtable_vars ();
+      VTV_malloc_init ();
+      VTV_malloc_unprotect ();
+
+    }
+  else if (perm == __VLTP_READ_ONLY)
+    {
+      if (debug_hash)
+        log_set_stats();
+
+      VTV_malloc_protect ();
+      VTV_protect_vtable_vars ();
+
+      __gthread_mutex_unlock (&change_permissions_lock);
+    }
+}
+
+/* This is the memory allocator used to create the hash table that
+   maps from vtable map variable name to the data set that vtable map
+   variable should point to.  This is part of our vtable map variable
+   symbol resolution, which is necessary because the same vtable map
+   variable may be created by multiple compilation units and we need a
+   method to make sure that all vtable map variables for a particular
+   class point to the same data set at runtime.  */
+
+struct insert_only_hash_map_allocator
+  {
+    /* N is the number of bytes to allocate.  */
+    void *
+    alloc (size_t n) const
+    {  
+      return VTV_malloc (n);
+    }
+
+    /* P points to the memory to be deallocated; N is the number of
+       bytes to deallocate.  */
+    void
+    dealloc (void *p, size_t n __attribute__((__unused__))) const
+    {
+      VTV_free (p);
+    }
+  };
+
+/* Explicitly instantiate this class since this file is compiled with
+   -fno-implicit-templates.  These are for the hash table that is used
+   to do vtable map variable symbol resolution.  */
+template class insert_only_hash_map <vtv_set_handle *, 
+                                     insert_only_hash_map_allocator >;
+typedef insert_only_hash_map <vtv_set_handle *,
+                              insert_only_hash_map_allocator > s2s;
+typedef const s2s::key_type  vtv_symbol_key;
+
+static s2s * vtv_symbol_unification_map VTV_PROTECTED_VAR = NULL;
+
+const unsigned long SET_HANDLE_HANDLE_BIT = 0x2;
+
+/* In the case where a vtable map variable is the only instance of the
+   variable we have seen, it points directly to the set of valid
+   vtable pointers.  All subsequent instances of the 'same' vtable map
+   variable point to the first vtable map variable.  This function,
+   given a vtable map variable PTR, checks a bit to see whether it's
+   pointing directly to the data set or to the first vtable map
+   variable.  */
+
+static inline bool
+is_set_handle_handle (void * ptr)
+{
+  return ((unsigned long) ptr & SET_HANDLE_HANDLE_BIT)
+                                                      == SET_HANDLE_HANDLE_BIT;
+}
+
+/* Returns the actual pointer value of a vtable map variable, PTR (see
+   comments for is_set_handle_handle for more details).  */
+
+static inline vtv_set_handle * 
+ptr_from_set_handle_handle (void * ptr)
+{
+  return (vtv_set_handle *) ((unsigned long) ptr & ~SET_HANDLE_HANDLE_BIT);
+}
+
+/* Given a vtable map variable, PTR, this function sets the bit that
+   says this is the second (or later) instance of a vtable map
+   variable.  */
+
+static inline vtv_set_handle_handle
+set_handle_handle (vtv_set_handle * ptr)
+{
+  return (vtv_set_handle_handle) ((unsigned long) ptr | SET_HANDLE_HANDLE_BIT);
+}
+
+/* Open error logging file, if not already open, and write vtable
+   verification failure messages (LOG_MSG) to the log file.  Also
+   generate a backtrace in the log file, if GENERATE_BACKTRACE is
+   set.  */
+
+static void
+log_error_message (const char *log_msg, bool generate_backtrace)
+{
+  if (vtv_failures_log_fd == -1)
+    vtv_failures_log_fd = vtv_open_log ("vtable_verification_failures.log");
+
+  if (vtv_failures_log_fd == -1)
+    return;
+
+  vtv_add_to_log (vtv_failures_log_fd, "%s", log_msg);
+
+  if (generate_backtrace)
+    {
+#define STACK_DEPTH 20
+      void *callers[STACK_DEPTH];
+      int actual_depth = backtrace (callers, STACK_DEPTH);
+      backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd);
+    }
+}
+
+/* Ideally it would be nice if the library always provided the 2
+   versions of the runtime libraries. However, when we use VTV_DEBUG
+   we want to make sure that only the debug versions are being
+   used. We could change this once the code is more stable.  */
+
+#ifdef VTV_DEBUG
+
+/* This routine initializes a set handle to a vtable set. It makes
+   sure that there is only one set handle for a particular set by
+   using a map from set name to pointer to set handle. Since there
+   will be multiple copies of the pointer to the set handle (one per
+   compilation unit that uses it), it makes sure to initialize all the
+   pointers to the set handle so that the set handle is unique. To
+   make this a little more efficient and avoid a level of indirection
+   in some cases, the first pointer to handle for a particular handle
+   becomes the handle itself and the other pointers will point to the
+   set handle.  This is the debug version of this function, so it
+   outputs extra debugging messages and logging.  SET_HANDLE_PTR is
+   the address of the vtable map variable, SET_SYMBOL_KEY is the hash
+   table key (containing the name of the map variable and the hash
+   value) and SIZE_HINT is a guess for the best initial size for the
+   set of vtable pointers that SET_HANDLE_POINTER will point to.  */
+
+void __VLTInitSetSymbolDebug (void **set_handle_ptr,
+                              const void *set_symbol_key, 
+                              size_t size_hint)
+{
+  VTV_DEBUG_ASSERT (set_handle_ptr);
+
+  if (vtv_symbol_unification_map == NULL)
+    {
+      /* TODO:  For now we have chosen 1024, but we need to come up with a
+         better initial size for this.  */
+      vtv_symbol_unification_map = s2s::create (1024);
+      VTV_DEBUG_ASSERT(vtv_symbol_unification_map);
+    }
+
+  vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
+
+  const s2s::value_type * map_value_ptr = 
+                              vtv_symbol_unification_map->get (symbol_key_ptr);
+  char buffer[200];
+  if (map_value_ptr == NULL)
+    {
+      if (*handle_ptr != NULL)
+        {
+          snprintf (buffer, sizeof(buffer), 
+                    "*** Found non-NULL local set ptr %p missing for symbol"
+                    " %.*s",
+                    *handle_ptr, symbol_key_ptr->n, symbol_key_ptr->bytes);
+          log_error_message (buffer, true);
+          VTV_DEBUG_ASSERT (0);
+        }
+    }
+  else if (*handle_ptr != NULL && 
+           (handle_ptr != *map_value_ptr && 
+            ptr_from_set_handle_handle (*handle_ptr) != *map_value_ptr))
+    {
+      VTV_DEBUG_ASSERT (*map_value_ptr != NULL);
+      snprintf (buffer, sizeof(buffer), 
+                "*** Found diffence between local set ptr %p and set ptr %p"
+                "for symbol %.*s", 
+                *handle_ptr, *map_value_ptr, 
+                symbol_key_ptr->n, symbol_key_ptr->bytes);
+      log_error_message (buffer, true);
+      VTV_DEBUG_ASSERT (0);
+    }
+  else if (*handle_ptr == NULL)
+    {
+      /* Execution should not reach this point.  */
+    }
+
+  if (*handle_ptr != NULL)
+    {
+      if (!is_set_handle_handle (*set_handle_ptr))
+        handle_ptr = (vtv_set_handle *) set_handle_ptr;
+      else
+        handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+      vtv_sets::resize (size_hint, handle_ptr);
+      return;
+    }
+
+  VTV_DEBUG_ASSERT (*handle_ptr == NULL);
+  if (map_value_ptr != NULL)
+    {
+      if (*map_value_ptr == handle_ptr)
+        vtv_sets::resize (size_hint, *map_value_ptr);
+      else
+        {
+          /* The one level handle to the set already exists. So, we
+             are adding one level of indirection here and we will
+             store a pointer to the one level handle here.  */
+
+          vtv_set_handle_handle * handle_handle_ptr = 
+                                           (vtv_set_handle_handle *)handle_ptr;
+          *handle_handle_ptr = set_handle_handle(*map_value_ptr);
+          VTV_DEBUG_ASSERT(*handle_handle_ptr != NULL);
+
+          /* The handle can itself be NULL if the set has only
+             been initiazlied with size hint == 1. */
+          vtv_sets::resize (size_hint, *map_value_ptr);
+        }
+    }
+  else
+    {
+      /* We will create a new set. So, in this case handle_ptr is the
+         one level pointer to the set handle.  Create copy of map name
+         in case the memory where this comes from gets unmapped by
+         dlclose.  */
+      size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
+      void *map_key = VTV_malloc (map_key_len);
+
+      memcpy (map_key, symbol_key_ptr, map_key_len);
+
+      s2s::value_type *value_ptr;
+      vtv_symbol_unification_map = 
+        vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
+                                                     &value_ptr);              
+      *value_ptr = handle_ptr;
+
+      /*  TODO: We should verify the return value. */
+      vtv_sets::create (size_hint, handle_ptr);
+      VTV_DEBUG_ASSERT (size_hint <= 1 || *handle_ptr != NULL);
+    }
+
+  if (debug_init)
+    {
+      if (init_log_fd == -1)
+        init_log_fd = vtv_open_log ("vtv_init.log");
+
+      vtv_add_to_log (init_log_fd, 
+                      "Init handle:%p for symbol:%.*s hash:%u size_hint:%lu"
+                      "number of symbols:%lu \n",
+                      set_handle_ptr, symbol_key_ptr->n,
+                      symbol_key_ptr->bytes, symbol_key_ptr->hash, size_hint, 
+                      vtv_symbol_unification_map->size ());
+    }
+}
+
+/* This function takes a the address of a vtable map variable
+   (SET_HANDLE_PTR), a VTABLE_PTR to add to the data set, the name of
+   the vtable map variable (SET_SYMBOL_NAME) and the name of the
+   vtable (VTABLE_NAME) being pointed to.  If the vtable map variable
+   is NULL it creates a new data set and initializes the variable,
+   otherwise it uses our symbol unification to find the right data
+   set; in either case it then adds the vtable pointer to the set.
+   The other two parameters are used for debugging information.  */
+
+void
+__VLTRegisterPairDebug (void **set_handle_ptr, const void *vtable_ptr,
+                        const char *set_symbol_name, const char *vtable_name)
+                        
+{
+  VTV_DEBUG_ASSERT(set_handle_ptr != NULL);
+  /* set_handle_ptr can be NULL if the call to InitSetSymbol had a
+     size hint of 1.  */
+
+  int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+  VTV_DEBUG_ASSERT (vtv_symbol_unification_map != NULL);
+  vtv_set_handle *handle_ptr;
+  if (!is_set_handle_handle (*set_handle_ptr))
+    handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  else
+    handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+  /* TODO: We should verify the return value.  */
+  vtv_sets::insert (vtbl_ptr, handle_ptr);
+
+  if (debug_init)
+    {
+      if (init_log_fd == -1)
+        init_log_fd = vtv_open_log("vtv_init.log");
+
+      vtv_add_to_log(init_log_fd, 
+                     "Registered %s : %s (%p) 2 level deref = %s\n",
+                     set_symbol_name, vtable_name, vtbl_ptr, 
+                     is_set_handle_handle(*set_handle_ptr) ? "yes" : "no" );
+    }
+}
+
+/* This function is called from __VLTVerifyVtablePointerDebug; it
+   sends as much debugging information as it can to the error log
+   file, then calls __vtv_verify_fail.  SET_HANDLE_PTR is the pointer
+   to the set of valid vtable pointers, VTBL_PTR is the pointer that
+   was not found in the set, and DEBUG_MSG is the message to be
+   written to the log file before failing. n */
+
+static void
+__vtv_verify_fail_debug (void **set_handle_ptr, const void *vtbl_ptr, 
+                         const char *debug_msg)
+{
+  log_error_message (debug_msg, false);
+
+  /* Call the public interface in case it has been overwritten by
+     user.  */
+  __vtv_verify_fail (set_handle_ptr, vtbl_ptr);
+
+  log_error_message ("Returned from __vtv_verify_fail."
+                     " Secondary verification succeeded.\n", false);
+}
+
+#ifndef VTV_STATIC_VERIFY
+
+/* This is the debug version of the verification function.  It takes
+   the address of a vtable map variable (SET_HANDLE_PTR) and a
+   VTABLE_PTR to validate, as well as the name of the vtable map
+   variable (SET_SYMBOL_NAME) and VTABLE_NAME, which are used for
+   debugging messages.  It checks to see if VTABLE_PTR is in the set
+   pointed to by SET_HANDLE_PTR.  If so, it returns VTABLE_PTR,
+   otherwise it calls __vtv_verify_fail, which usually logs error
+   messages and calls abort.  */
+
+const void *
+__VLTVerifyVtablePointerDebug (void **set_handle_ptr, const void *vtable_ptr,
+                               const char *set_symbol_name,
+                               const char *vtable_name)
+{
+#ifndef VTV_EMPTY_VERIFY
+  VTV_DEBUG_ASSERT (set_handle_ptr != NULL && *set_handle_ptr != NULL);
+  int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+  vtv_set_handle *handle_ptr;
+  if (!is_set_handle_handle (*set_handle_ptr))
+    handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  else
+    handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+  if (vtv_sets::contains (vtbl_ptr, handle_ptr))
+    {
+      if (debug_verify_vtable)
+        {
+          if (verify_vtable_log_fd == -1)
+            vtv_open_log ("vtv_verify_vtable.log");
+          vtv_add_to_log (verify_vtable_log_fd,
+                          "Verified %s %s value = %p\n",
+                          set_symbol_name, vtable_name, vtable_ptr);
+        }
+    }
+  else
+    {
+      /* We failed to find the vtable pointer in the set of valid
+         pointers.  Log the error data and call the failure
+         function.  */
+      snprintf (debug_log_message, sizeof (debug_log_message),
+                "Looking for %s in %s\n", vtable_name, set_symbol_name);
+      __vtv_verify_fail_debug (set_handle_ptr, vtable_ptr, debug_log_message);
+
+      /* Normally __vtv_verify_fail_debug will call abort, so we won't
+         execute the return below.  If we get this far, the assumption
+         is that the programmer has replaced __vtv_verify_fail_debug
+         with some kind of secondary verification AND this secondary
+         verification succeeded, so the vtable pointer is valid.  */
+    }
+#endif /* ifndef VTV_EMPTY_VERIFY*/
+
+  return vtable_ptr;
+}
+
+#endif /* ifndef VTV_STATIC_VERIFY */
+
+#else /* ifdef VTV_DEBUG */
+
+/* This routine initializes a set handle to a vtable set. It makes
+   sure that there is only one set handle for a particular set by
+   using a map from set name to pointer to set handle. Since there
+   will be multiple copies of the pointer to the set handle (one per
+   compilation unit that uses it), it makes sure to initialize all the
+   pointers to the set handle so that the set handle is unique. To
+   make this a little more efficient and avoid a level of indirection
+   in some cases, the first pointer to handle for a particular handle
+   becomes the handle itself and the other pointers will point to the
+   set handle.  SET_HANDLE_PTR is the address of the vtable map
+   variable, SET_SYMBOL_KEY is the hash table key (containing the name
+   of the map variable and the hash value) and SIZE_HINT is a guess
+   for the best initial size for the set of vtable pointers that
+   SET_HANDLE_POINTER will point to.*/
+
+void __VLTInitSetSymbol (void **set_handle_ptr, const void *set_symbol_key,
+                         size_t size_hint)
+{
+  vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  if (*handle_ptr != NULL)
+    {
+      if (!is_set_handle_handle (*set_handle_ptr))
+        handle_ptr = (vtv_set_handle *) set_handle_ptr;
+      else
+        handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+      vtv_sets::resize (size_hint, handle_ptr);
+      return;
+    }
+
+  if (vtv_symbol_unification_map == NULL)
+    vtv_symbol_unification_map = s2s::create (1024);
+
+  vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
+  const s2s::value_type *map_value_ptr = 
+                              vtv_symbol_unification_map->get (symbol_key_ptr);
+
+  if (map_value_ptr != NULL)
+    {
+      if (*map_value_ptr == handle_ptr)
+        vtv_sets::resize (size_hint, *map_value_ptr);
+      else
+        {
+          /* The one level handle to the set already exists. So, we
+             are adding one level of indirection here and we will
+             store a pointer to the one level pointer here.  */
+          vtv_set_handle_handle *handle_handle_ptr = 
+                                          (vtv_set_handle_handle *) handle_ptr;
+          *handle_handle_ptr = set_handle_handle (*map_value_ptr);
+          vtv_sets::resize (size_hint, *map_value_ptr);
+        }
+    }
+  else
+    {
+      /* We will create a new set. So, in this case handle_ptr is the
+         one level pointer to the set handle.  Create copy of map name
+         in case the memory where this comes from gets unmapped by
+         dlclose.  */
+      size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
+      void * map_key = VTV_malloc (map_key_len);
+      memcpy (map_key, symbol_key_ptr, map_key_len);
+
+      s2s::value_type * value_ptr;
+      vtv_symbol_unification_map = 
+        vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
+                                                     &value_ptr);
+            
+      *value_ptr = handle_ptr;
+
+      /* TODO: We should verify the return value.  */
+      vtv_sets::create (size_hint, handle_ptr);
+    }
+}
+
+/* This function takes a the address of a vtable map variable
+   (SET_HANDLE_PTR) and a VTABLE_PTR.  If the vtable map variable is
+   NULL it creates a new data set and initializes the variable,
+   otherwise it uses our symbol unification to find the right data
+   set; in either case it then adds the vtable pointer to the set.  */
+
+void 
+__VLTRegisterPair (void **set_handle_ptr, const void *vtable_ptr)
+{
+  int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+  vtv_set_handle *handle_ptr;
+  if (!is_set_handle_handle (*set_handle_ptr))
+    handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  else
+    handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+  /* TODO: We should verify the return value.  */
+  vtv_sets::insert (vtbl_ptr, handle_ptr);
+}
+
+#ifndef VTV_STATIC_VERIFY
+
+/* This is the main verification function.  It takes the address of a
+   vtable map variable (SET_HANDLE_PTR) and a VTABLE_PTR to validate.
+   It checks to see if VTABLE_PTR is in the set pointed to by
+   SET_HANDLE_PTR.  If so, it returns VTABLE_PTR, otherwise it calls
+   __vtv_verify_fail, which usually logs error messages and calls
+   abort.  Since this function gets called VERY frequently, it is
+   important for it to be as efficient as possible.  */
+
+const void *
+__VLTVerifyVtablePointer (void ** set_handle_ptr, const void * vtable_ptr)
+{
+#ifndef VTV_EMPTY_VERIFY
+  int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+  vtv_set_handle *handle_ptr;
+  if (!is_set_handle_handle (*set_handle_ptr))
+    handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  else
+    handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+  if (!vtv_sets::contains (vtbl_ptr, handle_ptr))
+    {
+      __vtv_verify_fail ((void **) handle_ptr, vtable_ptr);
+      /* Normally __vtv_verify_fail will call abort, so we won't
+         execute the return below.  If we get this far, the assumption
+         is that the programmer has replaced __vtv_verify_fail with
+         some kind of secondary verification AND this secondary
+         verification succeeded, so the vtable pointer is valid.  */
+    }
+#endif /* ifndef VTV_EMPTY_VERIFY  */
+
+  return vtable_ptr;
+}
+
+#endif /* ifndef VTV_STATIC_VERIFY  */
+
+#endif /* else-clause of ifdef VTV_DEBUG  */
+
+/* This function calls __fortify_fail with a FAILURE_MSG and then
+   calls abort.  */
+
+void
+__vtv_really_fail (const char *failure_msg)
+{
+  __fortify_fail (failure_msg);
+
+  /* We should never get this far; __fortify_fail calls __libc_message
+     which prints out a back trace and a memory dump and then is
+     supposed to call abort, but let's play it safe anyway and call abort
+     ourselves.  */
+  abort ();
+}
+
+/* This function takes an error MSG, a vtable map variable
+   (DATA_SET_PTR) and a vtable pointer (VTBL_PTR).  It is called when
+   an attempt to verify VTBL_PTR with the set pointed to by
+   DATA_SET_PTR failed.  It outputs a failure message with the
+   addresses involved, and calls __vtv_really_fail.  */
+
+static void
+vtv_fail (const char *msg, void **data_set_ptr, const void *vtbl_ptr)
+{
+  char buffer[128];
+  int buf_len;
+  const char *format_str =
+                 "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
+
+  snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr,
+            is_set_handle_handle(*data_set_ptr) ?
+              ptr_from_set_handle_handle (*data_set_ptr) :
+              *data_set_ptr);
+  buf_len = strlen (buffer);
+  /*  Send this to to stderr.  */
+  write (2, buffer, buf_len);
+
+#ifndef VTV_NO_ABORT
+    __vtv_really_fail (msg);
+#endif
+}
+
+/* Send information about what we were trying to do when verification
+   failed to the error log, then call vtv_fail.  This function can be
+   overwritten/replaced by the user, to implement a secondary
+   verification function instead.  DATA_SET_PTR is the vtable map
+   variable used for the failed verification, and VTBL_PTR is the
+   vtable pointer that was not found in the set.  */
+
+void
+__vtv_verify_fail (void **data_set_ptr, const void *vtbl_ptr)
+{
+  char log_msg[256];
+  snprintf (log_msg, sizeof (log_msg), "Looking for vtable %p in set %p.\n",
+            vtbl_ptr,
+            is_set_handle_handle (*data_set_ptr) ?
+              ptr_from_set_handle_handle (*data_set_ptr) :
+              *data_set_ptr);
+  log_error_message (log_msg, false);
+
+  const char *format_str =
+            "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
+  snprintf (log_msg, sizeof (log_msg), format_str, vtbl_ptr, *data_set_ptr);
+  log_error_message (log_msg, false);
+  log_error_message ("  Backtrace: \n", true);
+
+  const char *fail_msg = "Potential vtable pointer corruption detected!!\n";
+  vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
+}
Index: libstdc++-v3/libsupc++/vtv_malloc.h
===================================================================
--- libstdc++-v3/libsupc++/vtv_malloc.h	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_malloc.h	(revision 0)
@@ -0,0 +1,49 @@
+/* Copyright (C) 2012, 2013
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _VTV_MALLOC_H
+#define _VTV_MALLOC_H 1
+
+#include <stdlib.h>
+
+/* Alignment mask for any object returned by the VTV memory pool */
+#ifdef __LP64__
+#define VTV_ALIGNMENT_MASK (0x7)
+#else
+#define VTV_ALIGNMENT_MASK (0x3)
+#endif
+
+extern void VTV_malloc_init (void);
+
+extern void *VTV_malloc (size_t size);
+extern void VTV_free (void * ptr);
+
+
+extern void VTV_malloc_protect (void);
+extern void VTV_malloc_unprotect (void);
+
+extern void VTV_malloc_stats (void);
+extern void VTV_malloc_dump_stats (void);
+
+#endif /* vtv_malloc.h */
Index: libstdc++-v3/libsupc++/vtv_rts.h
===================================================================
--- libstdc++-v3/libsupc++/vtv_rts.h	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_rts.h	(revision 0)
@@ -0,0 +1,56 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+  
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _VTV_RTS_H
+#define _VTV_RTS_H 1
+
+#include <cstdlib>
+
+/* This prototype needs to be kept in sync with the compiler-
+   generated declaration in vtable-class-hierarchy.c.  */
+
+/* We could have used an enumeration here but it just makes it more
+   difficult for the compiler to generate a call to this.  */
+#define __VLTP_READ_ONLY  0
+#define __VLTP_READ_WRITE 1
+
+extern void __VLTChangePermission (int);
+
+#ifdef VTV_DEBUG
+
+extern void __VLTInitSetSymbolDebug (void **, const void *, std::size_t);
+extern void __VLTRegisterPairDebug (void **, const void *, const char *,
+				    const char *);
+extern const void *__VLTVerifyVtablePointerDebug (void **, const void *,
+						  const char *, const char *);
+
+#else
+
+extern void __VLTRegisterPair      (void **, const void *);
+extern const void *__VLTVerifyVtablePointer      (void **, const void *);
+extern void __VLTInitSetSymbol      (void **, const void *, std::size_t );
+
+#endif
+
+#endif /* _VTV_RTS_H */
Index: libstdc++-v3/libsupc++/vtv_fail.h
===================================================================
--- libstdc++-v3/libsupc++/vtv_fail.h	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_fail.h	(revision 0)
@@ -0,0 +1,53 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+  
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _VTV_FAIL_H
+#define _VTV_FAIL_H 1
+
+/* __vtv_really_fail prints a backtrace and a memory dump, then calls
+  abort.  It is here for programmers to call, presumably from
+  __vtv_verify_fail, if they choose to overwrite the standard
+  __vtv_verify_fail with one of their own.  Programmers should NOT
+  attempt to rewrite __vtv_really_fail. */
+
+extern void
+__vtv_really_fail (const char *fail_msg) __attribute__ ((noreturn));
+
+/* __vtv_verify_fail is the function that gets called if the vtable
+  verification code discovers a vtable pointer that it cannot verify
+  as valid.  Normally __vtv_verify_fail calls __vtv_really_fail.
+  However programmers can write and link in their own version of
+  __vtv_verify_fail, if they wish to do some kind of secondary
+  verification, for example.  The main verification code assumes that
+  IF __vtv_verify_fail returns, then some kind of secondary
+  verification was done AND that the secondary verification succeeded,
+  i.e. that the vtable pointer is actually valid and ok to use.  If
+  the secondary verification fails, then __vtv_verify_fail should not
+  return.  */
+
+extern void
+__vtv_verify_fail (void **data_set_ptr, const void *vtbl_pointer)
+                                 __attribute__((visibility ("default")));
+
+#endif /* _VTV_FAIL_H */
Index: libstdc++-v3/libsupc++/vtv_map.h
===================================================================
--- libstdc++-v3/libsupc++/vtv_map.h	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_map.h	(revision 0)
@@ -0,0 +1,311 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _VTV_MAP_H
+#define _VTV_MAP_H 1
+
+#include <string.h>
+#include <vtv_utils.h>
+
+inline uint64_t
+load8bytes (const void *p)
+{
+  uint64_t result;
+  memcpy (&result, p, 8);
+  return result;
+}
+
+/* Insert_only_hash_map maps keys to values.  The implementation is a
+   basic hash table with open addressing.  The keys are not "owned" by
+   the table; it only stores pointers to keys.  The key type is
+   specified below (see insert_only_hash_map::key_type) and is,
+   roughly speaking, a string of any length with the string length and
+   a hash code stored at the front.  The code here does not compute
+   any hash codes, but rather uses what's given.  */
+
+template<typename T, typename Alloc>
+class insert_only_hash_map
+  {
+    public:
+      typedef size_t size_type;
+      typedef T value_type;
+      typedef Alloc alloc_type;
+      enum { min_capacity = 4 };
+#if HASHMAP_STATS
+  enum { stats = true };
+#else
+  enum { stats = false };
+#endif
+
+  /* Keys are a byte string (up to 2^32 - 1 long) plus a uint32_t
+     that's used as a hash code.  The latter can encode arbitrary
+     information at the client's discretion, so, e.g., multiple keys
+     that are the same string still "differ" if the hash codes differ.
+     Keys are equal if the first 8 bytes are equal and the next n
+     bytes are equal.  */
+  struct key_type
+  {
+    uint32_t n;
+    uint32_t hash;
+    char bytes[0];
+
+    bool
+    equals (const key_type *k) const;
+  };
+
+  /* Create an empty map with a reasonable number of buckets for the
+     expected size.  Returns NULL if the allocator fails.  */
+
+  static insert_only_hash_map *
+  create (size_type expected_size);
+
+  /* The opposite of create().  Free the memory for the given map.  */
+
+  static void
+  destroy (insert_only_hash_map *m)
+  { Alloc().dealloc (m, m->size_in_bytes_); }
+
+  /* Return a map identical to this except that *k is mapped to v.
+     Typcially it's done by modifying this in place, but if a resize
+     is necessary then this is deallocated and a new map is returned.
+     Requires k to be non-NULL.  Does nothing and returns NULL if the
+     allocator fails.  */
+
+  insert_only_hash_map*
+  put (const key_type *k, const value_type &v)
+  { return this->put_internal (k, v, false); }
+
+  /* If *k is a key in this then set *v to point to the corresponding
+     value.  Otherwise, do the equivalent of insert(k, value_type())
+     and, if that succeeds, set *v to point to the inserted value.
+     Requires k to be non-NULL.  Does nothing and returns NULL if the
+     allocator fails.  Typically returns this, but will return a new
+     insert_only_hash_map if a resize occurs.  If the return value is
+     non-NULL, *v is set and it's valid until a resize of the map that
+     is the return value.  */
+
+  insert_only_hash_map *
+  find_or_add_key (const key_type *k, value_type **v);
+
+  /* Get the value corresponding to *k.  Returns NULL if there is
+     none.  Requires k to be non-NULL.  The return value is valid
+     until any resize.  */
+  const value_type *get (const key_type *k) const;
+
+  size_type
+  size () const
+  { return num_entries_; }
+
+  bool
+  empty () const
+  { return this->size () == 0; }
+
+  size_type
+  bucket_count () const
+  { return num_buckets_; }
+
+ private:
+  typedef std::pair <const key_type *, value_type> bucket_type;
+
+  insert_only_hash_map *put_internal (const key_type *, const value_type &,
+				      bool);
+
+  /* This function determines when to resize the table.  */
+  bool
+  is_too_full (size_type entries) const
+  { return entries > (this->bucket_count () * 0.7); }
+
+  /* Return a copy with double the number of buckets.  Returns NULL if
+     the allocator fails.  Otherwise, calls destroy (this).  */
+  insert_only_hash_map *destructive_copy ();
+
+ /* Must be a power of 2 not less than min_capacity. */
+  size_type num_buckets_; 
+  size_type num_entries_;
+  size_type size_in_bytes_;
+  bucket_type buckets[0];  /* Actual array size is num_buckets.  */
+};
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc> *
+insert_only_hash_map <T, Alloc>::create (size_type expected_size)
+{
+  size_t cap = min_capacity;
+  while (expected_size >= cap)
+    {
+      cap *= 2;
+    }
+  size_t size_in_bytes = sizeof (insert_only_hash_map <T, Alloc>)
+                                                  + cap * sizeof (bucket_type);
+  insert_only_hash_map <T, Alloc>* result =
+      static_cast <insert_only_hash_map <T, Alloc>*> (Alloc ()
+                                                       .alloc (size_in_bytes));
+  if (result != NULL)
+    {
+      result->size_in_bytes_ = size_in_bytes;
+      result->num_buckets_ = cap;
+      result->num_entries_ = 0;
+      memset (result->buckets, 0, cap * sizeof (bucket_type));
+    }
+  return result;
+}
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc>*
+insert_only_hash_map <T, Alloc>::destructive_copy ()
+{
+  insert_only_hash_map* copy = create (this->bucket_count ());
+  if (copy == NULL)
+    return NULL;
+  VTV_DEBUG_ASSERT (copy->bucket_count () == 2 * this->bucket_count ());
+  for (size_type i = 0; i < this->bucket_count (); i++)
+    if (this->buckets[i].first != NULL)
+      copy->put_internal (this->buckets[i].first, this->buckets[i].second,
+			  true);
+  VTV_DEBUG_ASSERT (copy->size () == this->size ());
+  destroy (this);
+  return copy;
+}
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc>*
+insert_only_hash_map <T, Alloc>::find_or_add_key (const key_type *k,
+						  value_type **v)
+{
+  /* Table size is always a power of 2.  */
+  const size_type mask = this->bucket_count () - 1;
+  size_type bucket_index = k->hash & mask;
+  size_type step = 1;
+  for (;;)
+    {
+      bucket_type &bucket = this->buckets[bucket_index];
+      if (bucket.first == NULL)
+        {
+          /* Key was not present. */
+          if (this->is_too_full (this->size () + 1))
+            {
+              insert_only_hash_map <T, Alloc>* result =
+		                                     this->destructive_copy ();
+              return result == NULL
+                  ? NULL
+                  : result->find_or_add_key (k, v);
+            }
+          else
+            {
+              bucket.first = k;
+              bucket.second = T ();
+              this->num_entries_++;
+              *v = &bucket.second;
+              return this;
+            }
+        }
+      else if (bucket.first->equals (k))
+        {
+          /* Key was present. */
+          *v = &bucket.second;
+          return this;
+        }
+      else
+        bucket_index = (bucket_index + step++) & mask;
+    }
+}
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc>*
+insert_only_hash_map <T, Alloc>::put_internal (
+				     const insert_only_hash_map::key_type *k,
+				     const insert_only_hash_map::value_type &v,
+				     bool unique_key_and_resize_not_needed)
+{
+  /* Table size is always a power of 2.  */
+  const size_type mask = this->bucket_count () - 1;
+  size_type bucket_index = k->hash & mask;
+  size_type step = 1;
+  for (;;)
+    {
+      bucket_type &bucket = this->buckets[bucket_index];
+      if (bucket.first == NULL)
+        {
+          /* Key was not present.  */
+          if (!unique_key_and_resize_not_needed
+              && this->is_too_full (this->size () + 1))
+            {
+              insert_only_hash_map <T, Alloc>* result =
+                                                     this->destructive_copy ();
+              return result == NULL
+                  ? NULL
+                  : result->put_internal (k, v, true);
+            }
+          else
+            {
+              bucket.first = k;
+              bucket.second = v;
+              this->num_entries_++;
+              return this;
+            }
+        }
+      else if (!unique_key_and_resize_not_needed && bucket.first->equals (k))
+        {
+          /* Key was present.  Just change the value.  */
+          bucket.second = v;
+          return this;
+        }
+      else
+        bucket_index = (bucket_index + step++) & mask;
+    }
+}
+
+template <typename T, typename Alloc>
+const typename insert_only_hash_map <T, Alloc>::value_type*
+insert_only_hash_map <T, Alloc>::get (const insert_only_hash_map::key_type *k)
+                                                                          const
+{
+  /* Table size is always a power of 2.  */
+  const size_type mask = this->bucket_count () - 1;
+  size_type bucket_index = k->hash & mask;
+  size_type step = 1;
+  for (;;)
+    {
+      const bucket_type &bucket = this->buckets[bucket_index];
+      if (bucket.first == NULL)
+        return NULL;
+      else if (bucket.first->equals (k))
+        return &bucket.second;
+      else
+        bucket_index = (bucket_index + step++) & mask;
+    }
+}
+
+template <typename T, typename Alloc>
+bool
+insert_only_hash_map <T, Alloc>::key_type::equals (
+             const typename insert_only_hash_map <T, Alloc>::key_type *k) const
+{
+  const char* x = reinterpret_cast <const char *> (k);
+  const char* y = reinterpret_cast <const char *> (this);
+  return (load8bytes (x) == load8bytes (y)
+          && memcmp (x + 8, y + 8, this->n) == 0);
+}
+
+#endif  /* _VTV_MAP_H  */
Index: libstdc++-v3/libsupc++/vtv_set.h
===================================================================
--- libstdc++-v3/libsupc++/vtv_set.h	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_set.h	(revision 0)
@@ -0,0 +1,652 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License
+   and a copy of the GCC Runtime Library Exception along with this
+   program; see the files COPYING3 and COPYING.RUNTIME respectively.
+   If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _VTV_SET_H
+#define _VTV_SET_H 1
+
+/* Code in this file manages a collection of insert-only sets.  We
+   have only tested the case where Key is uintptr_t, though it
+   theoretically should work for some other cases.  All odd keys are
+   reserved, and must not be inserted into any of the sets.  This code
+   is intended primarily for sets of pointers, and the code is
+   optimized for small sets (including size 0 and 1), but regardless
+   of the set size, insert() and contains() have close to O(1) speed
+   in practice.
+
+   TODO(gpike): fix this comment.
+
+   Recommended multithreaded use of a set:
+
+   For speed, we want to use a lock-free test for set membership.  The
+   code handles simultaneous reads and inserts, as long as at most one
+   insertion is in progress at a time.  After an insert, other threads
+   may not immediately "see" the inserted key if they perform a
+   lock-free read, so we recommend retrying, as explained below.
+
+   Also, to make data corruption less likely, we recommend using a
+   "normal" RW page as well as one or pages that are typically RO
+   but that can be switched to RW and back as needed.  The latter
+   pages should contain sets.  The former should contain a lock, L,
+   and an int or similar, num_writers.  Then, to insert, something
+   like this would be safe:
+    o Acquire L.
+    o Increment num_writers; if that made it 1, change pages to RW.
+    o Release L.
+    o while (there are insertions to do in some set, S) {
+        acquire L;
+        do some insertions in S;
+        release L;
+      }
+    o Acquire L.
+    o Decrement num_writers; if that made it 0, change pages to RO.
+    o Release L.
+
+   And to check if the set contains some key, one could use
+     set.contains(key) ||
+       ({ Acquire L; bool b = set.contains(key); Release L; b; })
+
+   In this scheme, the number of threads with reads in progress isn't
+   tracked, so old sets can never be deleted.  In addition, on some
+   architectures the intentionally racy reads might cause contains()
+   to return true when it should have returned false.  This should be
+   no problem on x86, and most other machines, where reading or
+   writing an aligned uintptr_t is atomic.  E.g., on those machines,
+   if *p is 0 and one thread does *p = x while another reads *p, the
+   read will see either 0 or x.
+
+   To make the above easier, the insert_only_hash_sets class provides
+   an interface to manipulate any number of hash sets.  One shouldn't
+   create objects of that class, as it has no member data and its
+   methods are static.
+
+   So the recommended model is to have a single lock, a single
+   num_writers variable, and some number of sets.  If lock contention
+   becomes a problem then the sets can be divided into k groups, each
+   of which has a lock and a num_writers variable; or each set can be
+   represented as a set of values that equal 0 mod m, a set of values
+   that equal 1 mod m, ..., plus a set of values that equal m-1 mod m.
+
+   However, we expect most or all uses of this code to call contains()
+   much more frequently than anything else, so lock contention is
+   likely to be low.  */
+
+#include <algorithm>
+
+#ifndef HASHTABLE_STATS
+#define HASHTABLE_STATS 0
+#endif
+
+#ifndef HASHTABLE_STATS_ATOMIC
+#define HASHTABLE_STATS_ATOMIC 0
+#endif
+
+#if HASHTABLE_STATS
+#if HASHTABLE_STATS_ATOMIC
+/* Stat counters, with atomics. */
+#include <bits/atomic_word.h>
+
+typedef _Atomic_word _AtomicStatCounter;
+
+void
+inc_by (_AtomicStatCounter &stat, int amount)
+{ 
+  __atomic_add_fetch (&stat, amount,  __ATOMIC_ACQ_REL);
+}
+
+#else
+
+/* Stat counters, but without atomics. */
+typedef int _AtomicStatCounter;
+
+void
+inc_by (_AtomicStatCounter& stat, int amount)
+{ 
+  stat += amount;
+}
+
+#endif
+
+
+/* Number of calls to contains(), insert(), etc. */
+extern _AtomicStatCounter stat_insert;
+extern _AtomicStatCounter stat_contains;
+extern _AtomicStatCounter stat_resize;
+extern _AtomicStatCounter stat_create;
+
+/* Sum of set size over all calls to contains().  */
+extern _AtomicStatCounter stat_contains_sizes;
+
+/* contains() calls in a set whose capacity is more than 1. */
+extern _AtomicStatCounter stat_contains_in_non_trivial_set;
+
+/* Probes in a set whose capacity is more than 1.  Ideally, this will
+   be pretty close to stat_contains_in_non_trivial_set.  That will
+   happen if our hash function is good and/or important keys were
+   inserted before unimportant keys.  */
+extern _AtomicStatCounter stat_probes_in_non_trivial_set;
+
+/* number of calls to contains() with size=0, 1, etc. */
+extern _AtomicStatCounter stat_contains_size0;
+extern _AtomicStatCounter stat_contains_size1;
+extern _AtomicStatCounter stat_contains_size2;
+extern _AtomicStatCounter stat_contains_size3;
+extern _AtomicStatCounter stat_contains_size4;
+extern _AtomicStatCounter stat_contains_size5;
+extern _AtomicStatCounter stat_contains_size6;
+extern _AtomicStatCounter stat_contains_size7;
+extern _AtomicStatCounter stat_contains_size8;
+extern _AtomicStatCounter stat_contains_size9;
+extern _AtomicStatCounter stat_contains_size10;
+extern _AtomicStatCounter stat_contains_size11;
+extern _AtomicStatCounter stat_contains_size12;
+extern _AtomicStatCounter stat_contains_size13_or_more;
+extern _AtomicStatCounter stat_grow_from_size0_to_1;
+extern _AtomicStatCounter stat_grow_from_size1_to_2;
+extern _AtomicStatCounter stat_double_the_number_of_buckets;
+extern _AtomicStatCounter stat_insert_key_that_was_already_present;
+
+/* Hash collisions detected during insert_no_resize().  Only counts
+   hasher(k) == hasher(k'); hasher(k) % tablesize == hasher(k') %
+   tablesize is not sufficient.  Will count collisions that are
+   detected during table resizes etc., so the same two keys may add to
+   this stat multiple times.  */
+extern _AtomicStatCounter stat_insert_found_hash_collision;
+
+#include <string>
+
+struct insert_only_hash_sets_logger
+{
+  static char *
+  log (char c, char *buf)
+  {
+    *buf++ = c;
+    return buf;
+  }
+
+  static char *
+  log (const char *s, char *buf)
+  { return strcpy (buf, s) + strlen (s); }
+
+  static char *
+  log (_AtomicStatCounter i, char *buf)
+  {
+    if (i < 10)
+      return log ((char) ('0' + i), buf);
+    else
+      return log ((char) ('0' + i % 10), log (i / 10, buf));
+  }
+
+  static char *
+  log (const char *label, _AtomicStatCounter i, char *buf)
+  {
+    buf = log (label, buf);
+    buf = log (": ", buf);
+    buf = log (i, buf);
+    return log ('\n', buf);
+  }
+};
+
+// Write stats to the given buffer, which should be at least 4000 bytes.
+static inline void
+insert_only_hash_tables_stats (char *buf)
+{
+  buf = insert_only_hash_sets_logger::log ("insert", stat_insert, buf);
+  buf = insert_only_hash_sets_logger::log ("contains", stat_contains, buf);
+  buf = insert_only_hash_sets_logger::log ("resize", stat_resize, buf);
+  buf = insert_only_hash_sets_logger::log ("create", stat_create, buf);
+  buf = insert_only_hash_sets_logger::log ("insert_key_that_was_already_"
+				      "present",
+				      stat_insert_key_that_was_already_present,
+				      buf);
+  buf = insert_only_hash_sets_logger::log ("contains_sizes",
+					   stat_contains_sizes, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_in_non_trivial_set",
+					   stat_contains_in_non_trivial_set,
+					   buf);
+  buf = insert_only_hash_sets_logger::log ("probes_in_non_trivial_set",
+					   stat_probes_in_non_trivial_set,
+					   buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size0",
+					   stat_contains_size0, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size1",
+					   stat_contains_size1, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size2",
+					   stat_contains_size2, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size3",
+					   stat_contains_size3, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size4",
+					   stat_contains_size4, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size5",
+					   stat_contains_size5, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size6",
+					   stat_contains_size6, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size7",
+					   stat_contains_size7, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size8",
+					   stat_contains_size8, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size9",
+					   stat_contains_size9, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size10",
+					   stat_contains_size10, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size11",
+					   stat_contains_size11, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size12",
+					   stat_contains_size12, buf);
+  buf = insert_only_hash_sets_logger::log ("contains_size13_or_more",
+					   stat_contains_size13_or_more, buf);
+  buf = insert_only_hash_sets_logger::log ("grow_from_size0_to_1",
+					   stat_grow_from_size0_to_1, buf);
+  buf = insert_only_hash_sets_logger::log ("grow_from_size1_to_2",
+					   stat_grow_from_size1_to_2, buf);
+  buf = insert_only_hash_sets_logger::log ("insert_found_hash_collision",
+					   stat_insert_found_hash_collision,
+					   buf);
+  buf = insert_only_hash_sets_logger::log ("double_the_number_of_buckets",
+					   stat_double_the_number_of_buckets,
+					   buf);
+  *buf = '\0';
+}
+
+#else
+
+/* No stats. */
+#define inc_by(statname, amount) do { } while (false && (amount))
+
+#endif
+
+#define inc(statname) inc_by (statname, 1)
+
+template <typename Key, class HashFcn, class Alloc>
+class insert_only_hash_sets
+{
+ public:
+  typedef Key key_type;
+  typedef size_t size_type;
+  typedef Alloc alloc_type;
+  enum { illegal_key = 1 };
+  enum { min_capacity = 4 };
+#if HASHTABLE_STATS
+  enum { stats = true };
+#else
+  enum { stats = false };
+#endif
+
+  /* Do not directly use insert_only_hash_set.  Instead, use the
+     static methods below to create and manipulate objects of the
+     following class.
+  
+     Implementation details: each set is represented by a pointer
+     plus, perhaps, out-of-line data, which would be an object of type
+     insert_only_hash_set.  For a pointer, s, the interpretation is: s
+     == NULL means empty set, lsb(s) == 1 means a set with one
+     element, which is (uintptr_t)s - 1, and otherwise s is a pointer
+     of type insert_only_hash_set*.  So, to increase the size of a set
+     we have to change s and/or *s.  To check if a set contains some
+     key we have to examine s and possibly *s.  */
+  class insert_only_hash_set
+  {
+   public:
+    /* Insert a key.  The key must not be a reserved key.  */
+    static inline insert_only_hash_set *insert (key_type key,
+						insert_only_hash_set *s);
+    
+
+    /* Create an empty set.  */
+    static inline insert_only_hash_set *create (size_type capacity);
+
+    /* Return whether the given key is present.  If key is illegal_key
+       then either true or false may be returned, but for all other
+       reserved keys false will be returned.  */
+    static bool
+    contains (key_type key, const insert_only_hash_set *s)
+    {
+      if (stats)
+	{
+	  inc (stat_contains);
+	  switch (size (s))
+	    {
+	      case 0: inc (stat_contains_size0); break;
+	      case 1: inc (stat_contains_size1); break;
+	      case 2: inc (stat_contains_size2); break;
+	      case 3: inc (stat_contains_size3); break;
+	      case 4: inc (stat_contains_size4); break;
+	      case 5: inc (stat_contains_size5); break;
+	      case 6: inc (stat_contains_size6); break;
+	      case 7: inc (stat_contains_size7); break;
+	      case 8: inc (stat_contains_size8); break;
+	      case 9: inc (stat_contains_size9); break;
+	      case 10: inc (stat_contains_size10); break;
+	      case 11: inc (stat_contains_size11); break;
+	      case 12: inc (stat_contains_size12); break;
+	      default: inc (stat_contains_size13_or_more); break;
+	    }
+          inc_by (stat_contains_sizes, size (s));
+	}
+
+      return (singleton (s) ?
+              singleton_key (key) == s :
+              ((s != NULL) && s->contains (key)));
+    }
+
+    /* Return a set's size.  */
+    static size_type
+    size (const insert_only_hash_set *s)
+    { return (s == NULL) ? 0 : (singleton (s) ? 1 : s->num_entries); }
+
+    static inline insert_only_hash_set *resize (size_type target_num_buckets,
+						insert_only_hash_set *s);
+    
+
+   private:
+    /* Return whether a set has size 1. */
+    static bool
+    singleton (const insert_only_hash_set *s)
+    { return (uintptr_t) s & 1; }
+
+    /* Return the representation of a singleton set containing the
+       given key.  */
+    static insert_only_hash_set *
+    singleton_key (key_type key)
+    { return (insert_only_hash_set *) ((uintptr_t) key + 1); }
+
+    /* Given a singleton set, what key does it contain?  */
+    static key_type
+    extract_singleton_key (const insert_only_hash_set *s)
+    {
+      VTV_DEBUG_ASSERT (singleton (s));
+      return (key_type) ((uintptr_t) s - 1);
+    }
+
+    volatile key_type &
+    key_at_index (size_type index)
+    { return buckets[index]; }
+
+    key_type
+    key_at_index (size_type index) const
+    { return buckets[index]; }
+
+    size_type
+    next_index (size_type index, size_type indices_examined) const
+    { return (index + indices_examined) & (num_buckets - 1); }
+
+    inline void insert_no_resize (key_type key);
+    
+    inline bool contains (key_type key) const;
+    
+    inline insert_only_hash_set *resize_if_necessary (void);
+    
+    size_type num_buckets;  /* Must be a power of 2 not less than
+			       min_capacity.  */
+    volatile size_type num_entries;
+    volatile key_type buckets[0];  /* Actual array size is num_buckets.  */
+  };
+
+  /* Create an empty set with the given capacity.  Requires that n be
+     0 or a power of 2.  If 1 < n < min_capacity then treat n as
+     min_capacity.  Sets *handle.  Returns true unless the allocator
+     fails.  Subsequent operations on this set should use the same
+     handle. */
+
+  static inline bool create (size_type n, insert_only_hash_set **handle);
+
+  /* Force the capacity of a set to be n, unless it was more than n
+     already.  Requires that n be 0 or a power of 2.  Sets *handle
+     unless the current capacity is n or more.  Returns true unless
+     the allocator fails.  */
+
+  static inline bool resize (size_type n, insert_only_hash_set **handle);
+
+  /* Insert a key.  *handle is unmodified unless (1) a resize occurs,
+     or (2) the set was initially empty. Returns true unless the
+     allocator fails during a resize.  If the allocator fails during a
+     resize then the set is reset to be the empty set.  The key must
+     not be a reserved key.  */
+
+  static inline bool insert (key_type key, insert_only_hash_set **handle);
+
+  /* Check for the presence of a key.  If key is illegal_key then
+     either true or false may be returned, but for all other reserved
+     keys false will be returned.  */
+
+  static inline bool
+  contains (key_type key, /* const */ insert_only_hash_set **handle)
+  { return insert_only_hash_set::contains (key, *handle); }
+
+  /* Return the size of the given set.  */
+  static size_type
+  size (const insert_only_hash_set **handle)
+  { return insert_only_hash_set::size (*handle); }
+
+  static bool
+  is_reserved_key (key_type key)
+  { return ((uintptr_t) key % 2) == 1; }
+};
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::resize
+                                         (size_type n, insert_only_hash_set *s)
+{
+  if (s == NULL)
+    return create (n);
+
+  size_type capacity = singleton (s) ? 1 : s->num_buckets;
+
+  if (n <= capacity)
+    return s;
+
+  insert_only_hash_set *result =
+                                create (std::max<size_type> (n, min_capacity));
+  if (result != NULL)
+    {
+      if (singleton (s))
+        {
+          result->insert_no_resize (extract_singleton_key (s));
+        }
+      else
+        {
+          for (size_type i = 0; i < s->num_buckets; i++)
+            if (s->buckets[i] != (key_type) illegal_key)
+              result->insert_no_resize (s->buckets[i]);
+        }
+      VTV_DEBUG_ASSERT (size (result) == size (s));
+    }
+  return result;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::insert 
+                                        (key_type key, insert_only_hash_set *s)
+{
+  VTV_DEBUG_ASSERT (!is_reserved_key (key));
+  inc_by (stat_grow_from_size0_to_1, s == NULL);
+
+  if (s == NULL)
+    return singleton_key (key);
+
+  if (singleton (s))
+    {
+      const key_type old_key = extract_singleton_key (s);
+      if (old_key == key)
+	return s;
+
+      /* Grow from size 1 to size 2.  */
+      inc (stat_grow_from_size1_to_2);
+      s = create (2);
+      if (s == NULL)
+	return NULL;
+
+      s->insert_no_resize (old_key);
+      s->insert_no_resize (key);
+      VTV_DEBUG_ASSERT (size (s) == 2);
+      return s;
+    }
+  s = s->resize_if_necessary();
+  if (s != NULL)
+    s->insert_no_resize (key);
+  return s;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::create
+                                                           (size_type capacity)
+{
+  if (capacity <= 1)
+    return NULL;
+
+  VTV_DEBUG_ASSERT (capacity > 1 && (capacity & (capacity - 1)) == 0);
+  VTV_DEBUG_ASSERT (sizeof (insert_only_hash_set) == 2 * sizeof (size_type));
+  capacity = std::max <size_type> (capacity, min_capacity);
+  const size_t num_bytes = sizeof (insert_only_hash_set) +
+                                                  sizeof (key_type) * capacity;
+  alloc_type alloc;
+  insert_only_hash_set *result = (insert_only_hash_set *) alloc (num_bytes);
+  result->num_buckets = capacity;
+  result->num_entries = 0;
+  for (size_type i = 0; i < capacity; i++)
+    result->buckets[i] = (key_type) illegal_key;
+  return result;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+void
+insert_only_hash_sets<Key, HashFcn,
+                                 Alloc>::insert_only_hash_set::insert_no_resize
+                                                                 (key_type key)
+{
+  HashFcn hasher;
+  const size_type capacity = num_buckets;
+  VTV_DEBUG_ASSERT (capacity >= min_capacity);
+  VTV_DEBUG_ASSERT (!is_reserved_key (key));
+  size_type index = hasher (key) & (capacity - 1);
+  key_type k = key_at_index (index);
+  size_type indices_examined = 0;
+  while (k != key)
+    {
+      ++indices_examined;
+      if (k == (key_type) illegal_key)
+        {
+          key_at_index (index) = key;
+          ++num_entries;
+          return;
+        }
+      else
+	{
+	  inc_by (stat_insert_found_hash_collision,
+		  hasher (k) == hasher (key));
+	}
+      VTV_DEBUG_ASSERT (indices_examined < capacity);
+      index = next_index (index, indices_examined);
+      k = key_at_index (index);
+    }
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::insert_only_hash_set::contains
+                                                           (key_type key) const
+{
+  inc (stat_contains_in_non_trivial_set);
+  HashFcn hasher;
+  const size_type capacity = num_buckets;
+  size_type index = hasher (key) & (capacity - 1);
+  key_type k = key_at_index (index);
+  size_type indices_examined = 0;
+  inc (stat_probes_in_non_trivial_set);
+  while (k != key)
+    {
+      ++indices_examined;
+      if (/*UNLIKELY*/(k == (key_type) illegal_key
+		       || indices_examined == capacity))
+	return false;
+
+      index = next_index (index, indices_examined);
+      k = key_at_index (index);
+      inc (stat_probes_in_non_trivial_set);
+    }
+  return true;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+   insert_only_hash_sets<Key, HashFcn,
+                       Alloc>::insert_only_hash_set::resize_if_necessary (void)
+{
+  VTV_DEBUG_ASSERT (num_buckets >= min_capacity);
+  size_type unused = num_buckets - num_entries;
+  if (unused < (num_buckets >> 2))
+    {
+      inc (stat_double_the_number_of_buckets);
+      size_type new_num_buckets = num_buckets * 2;
+      insert_only_hash_set *s = create (new_num_buckets);
+      for (size_type i = 0; i < num_buckets; i++)
+        if (buckets[i] != (key_type) illegal_key)
+          s->insert_no_resize (buckets[i]);
+      VTV_DEBUG_ASSERT (size (this) == size (s));
+      return s;
+    }
+  else
+    return this;
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::create (size_type n,
+						 insert_only_hash_set **handle)
+  
+{
+  inc (stat_create);
+  *handle = insert_only_hash_set::create (n);
+  return (n <= 1) || (*handle != NULL);
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::resize (size_type n,
+					         insert_only_hash_set **handle)
+{
+  inc (stat_resize);
+  *handle = insert_only_hash_set::resize (n, *handle);
+  return (n <= 1) || (*handle != NULL);
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::insert (key_type key,
+                                                 insert_only_hash_set **handle)
+{
+  inc (stat_insert);
+  const size_type old_size = insert_only_hash_set::size (*handle);
+  *handle = insert_only_hash_set::insert (key, *handle);
+  if (*handle != NULL)
+    {
+      const size_type delta = insert_only_hash_set::size (*handle) - old_size;
+      inc_by (stat_insert_key_that_was_already_present, delta == 0);
+    }
+  return *handle != NULL;
+}
+
+#endif /* VTV_SET_H  */
Index: libstdc++-v3/libsupc++/vtv_stubs.cc
===================================================================
--- libstdc++-v3/libsupc++/vtv_stubs.cc	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_stubs.cc	(revision 0)
@@ -0,0 +1,97 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional  
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "vtv_rts.h"
+
+/* The is part of the vtable verification runtime library.  For more
+   information about this feature, see the comments in vtv_rts.cc.  */
+
+/* The functions in this file are used to create the libvtv_stubs
+   library, as part of the vtable verification feature.  When building
+   a binary without vtable verification, and linking it with a
+   (possibly pre-built third-party) library that was built with
+   verification, it is possible that vtable verification will fail due
+   to incomplete data (rather than due to corrupt vtable pointers).  In
+   this case we need to give programmers a way of turning off the
+   vtable verification in their libraries.  They can do so by linking
+   with the libvtv_stubs library, which (as you can see) will replace
+   the real verification functions with a set of functions that do
+   nothing (so no more verification failures/aborts).  */
+
+void
+__VLTChangePermission (int perm __attribute__((__unused__)))
+{
+}
+
+#ifdef VTV_DEBUG
+
+void __VLTInitSetSymbolDebug
+                      (void **set_handle_ptr __attribute__((__unused__)),
+		       const void *set_symbol_key __attribute__((__unused__)),
+		       std::size_t size_hint __attribute__((__unused__)))
+{
+}
+
+void
+__VLTRegisterPairDebug (void **set_handle_ptrr __attribute__((__unused__)),
+                      const void *vtable_ptr __attribute__((__unused__)),
+                      const char *set_symbol_name __attribute__((__unused__)),
+		      const char *vtable_name __attribute__((__unused__)))
+{
+}
+
+const void *
+__VLTVerifyVtablePointerDebug
+                     (void **set_handle_ptr  __attribute__((__unused__)),
+	       	      const void *vtable_ptr,
+		      const char *set_symbol_name __attribute__((__unused__)),
+		      const char *vtable_name __attribute__((__unused__)))
+
+{
+  return vtable_ptr;
+}
+
+#else
+
+void __VLTInitSetSymbol
+                      (void **set_handle_ptr __attribute__((__unused__)),
+                       const void *set_symbol_key __attribute__((__unused__)),
+		       std::size_t size_hint __attribute__((__unused__)))
+{
+}
+
+void
+__VLTRegisterPair (void **set_handle_ptr __attribute__((__unused__)),
+                   const void *vtable_ptr __attribute__((__unused__)))
+{
+}
+
+const void *
+__VLTVerifyVtablePointer (void **set_handle_ptr __attribute__((__unused__)),
+                          const void *vtable_ptr)
+{
+  return vtable_ptr;
+}
+
+#endif 
Index: libstdc++-v3/libsupc++/vtv_utils.cc
===================================================================
--- libstdc++-v3/libsupc++/vtv_utils.cc	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_utils.cc	(revision 0)
@@ -0,0 +1,122 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file is part of the vtable verication runtime library (see
+   comments in vtv_rts.cc for more information about vtable
+   verification).  This file contains log file utilities.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "vtv_utils.h"
+
+/* This is the directory into which all vtable verication log files
+   get written, if possible.  */
+static const char * const logs_dir = "/var/log/chrome/vtv_logs";
+
+
+/* This is the directory into which the vtable verification log files
+   will get written if they can't be written to the directory
+   above.  */
+static const char * const alt_logs_dir = "/tmp/vtv_logs";
+
+
+/* This function takes the NAME of a log file to open, attempts to
+   open it in the logs_dir directory, and returns the resulting file
+   decriptor.  */
+
+int
+vtv_open_log (const char *name)
+{
+  /* Try to create the logs under /var/log/chrome first, which is
+     persistent across reboots.  This location only exists on
+     ChromeOS. This code should not be commited upstream GCC.  */
+  char log_name[256];
+  snprintf (log_name, sizeof (log_name), "%s/%s", logs_dir, name);
+  mkdir (logs_dir, S_IRWXU);
+  int fd = open (log_name, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
+  if (fd != -1)
+    return fd;
+
+  /* Otherwise, try to open in /tmp.  */
+  snprintf(log_name, sizeof(log_name), "%s/%s", alt_logs_dir, name);
+  mkdir(alt_logs_dir, S_IRWXU);
+  fd = open(log_name, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
+  if (fd == -1)
+    vtv_add_to_log (2, "Cannot open log file %s %s\n", name,
+                    strerror (errno));
+  return fd;
+}
+
+/* This function takes a file descriptor (FD) and a string (STR) and
+   tries to write the string to the file.  */
+
+static int
+vtv_log_write (int fd, const char *str)
+{
+  if (write (fd, str, strlen (str)) != -1)
+    return 0;
+
+  if (fd != 2) /* Make sure we dont get in a loop.  */
+    vtv_add_to_log (2, "Error writing to log: %s\n", strerror (errno));
+  return -1;
+}
+
+
+/* This function takes a file decriptor (LOG_FILE) and an output
+ format string (FORMAT), followed by zero or more print format
+ arguments (the same as fprintf, for example).  It gets the current
+ process ID and PPID, pre-pends them to the formatted message, and
+ writes write it out to the log file referenced by LOG_FILE via calles
+ to vtv_log_write.  */
+
+int
+vtv_add_to_log (int log_file, const char * format, ...)
+{
+  /* We dont want to dynamically allocate this buffer. This should be
+     more than enough in most cases. It if isn't we are careful not to
+     do a buffer overflow.  */
+  char output[1024];
+
+  va_list ap;
+  va_start (ap, format);
+
+  snprintf (output, sizeof (output), "VTV: PID=%d PPID=%d ", getpid (),
+            getppid ());
+  vtv_log_write (log_file, output);
+  vsnprintf (output, sizeof (output), format, ap);
+  vtv_log_write (log_file, output);
+
+  /* fdatasync is quite expensive. Only enable if you suspect you are
+     loosing log data in in a program crash?  */
+  /*  fdatasync(log_file);  */
+
+  return 0;
+}
Index: libstdc++-v3/libsupc++/vtv_utils.h
===================================================================
--- libstdc++-v3/libsupc++/vtv_utils.h	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_utils.h	(revision 0)
@@ -0,0 +1,55 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _VTV_UTILS_H
+#define _VTV_UTILS_H 1
+
+#include <stdlib.h>
+
+/* Handler for verification runtime errors.  */
+#define VTV_error abort
+
+/* Assertion macros used in vtable verification runtime.  */
+#define VTV_ASSERT(EXPR) \
+  if (!(EXPR)) VTV_error();
+
+#ifdef VTV_DEBUG
+#define VTV_DEBUG_ASSERT(EXPR) ((bool) (!(EXPR)) ? VTV_error() : (void) 0)
+#else
+#define VTV_DEBUG_ASSERT(EXPR) ((void) 0)
+#endif
+
+/* Name of the section where we put general VTV variables for protection */
+#define VTV_PROTECTED_VARS_SECTION ".vtable_map_vars"
+#define VTV_PROTECTED_VAR \
+                       __attribute__ ((section (VTV_PROTECTED_VARS_SECTION)))
+
+/* The following logging routines try to use low level file access
+   routines and avoid calling malloc. We need this so that we dont
+   disturb the order of calls to dlopen.  Changing the order of dlopen
+   calls may lead to deadlocks */
+int vtv_open_log (const char * name);
+int vtv_add_to_log (int log, const char * format, ...);
+
+#endif /* VTV_UTILS_H */
Index: libstdc++-v3/libsupc++/vtv_init.cc
===================================================================
--- libstdc++-v3/libsupc++/vtv_init.cc	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_init.cc	(revision 0)
@@ -0,0 +1,179 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+/* This file contains all the definitions that go into the libvtv_init
+   library, which is part of the vtable verification feature.  This
+   library should contain exactly two functionsa (__VLTunprotect and
+   __VLTprotect) and one global variable definition
+   (__vtv_defined_in_vtv_init_lib).  Any program that was compiled
+   with the option "-fvtable-verify=std" MUST also be linked with
+   libvtv_init, because the two functions defined here are used by the
+   vtable verification code.  The reason they are in a separate
+   library rather than in libstdc++ with all the rest of the vtable
+   verification runtime code is as follows.  Each .o file that was
+   compiled with vtable verification will contain calls into the
+   runtime (made from constructor initialization functions) to build
+   the data structures needed for verification.  At all times except
+   when they are being constructed, these data structures need to be
+   in protected memory, so that attackers cannot corrupt them.
+   __VLTunprotect sets the memory containing these data structures to
+   be writable, for updates.  __VLTprotect makes the memory read-only,
+   for all other times.  This memory protection and unprotection is
+   done via calls to mprotect, which are costly.  So instead of
+   calling __VLTunprotect and __VLTprotect once per object file we
+   want to call them once per executable.  Therefore instead of
+   putting calls to them directly into each object file, we put the
+   calls to them only in __VLTRegisterPair, in the libstdc++ library.
+   We give __VLTunprotect an initialization priority to make it run
+   before all of our data structure construction functions, and we
+   give __VLTprotect an initialization priority to make it run after
+   all of our data structure constructiion functions.  We put them
+   into a separate library and link that library with the
+   "--whole-archive" linker option, to make sure that both functions get
+   linked in (since the actual calls to them are in the libstdc++
+   runtime).  We can't put them into libstdc++ because linking
+   libstdc++ with "--whole-archive" is probably not a good idea.
+
+   The __vtv_defined_in_vtv_lib variable is referenced, but not
+   defined, in the constructor initialization functions where we have
+   the calls to build our data structures.  The purpose of this
+   variable is to cause a linker error to occur if the programmer
+   compiled with -fvtable-verify=std and did not link with the vtv_int
+   library (better a link-time error than a run-time error).  */
+
+
+/* Needs to build with C++ because the definition of
+   __VLTChangePermission is in C++.  */
+#ifndef __cplusplus
+#error "This file must be compiled with a C++ compiler"
+#endif
+
+#include "vtv_rts.h"
+
+/* Define this dummy symbol to detect at link time the cases where
+   user is compiling with -fvtable-verify=std and not linking with the
+   vtv_init library. Note that the visibility needs to be hidden. Each
+   object module is supposed to link with the vtv_init library and we
+   don't want this definition to come from a different library */
+unsigned int
+__vtv_defined_in_vtv_init_lib __attribute__ ((visibility ("hidden"))) = 0;
+
+void __VLTunprotect (void) __attribute__ ((constructor(98)));
+void __VLTprotect (void) __attribute__ ((constructor(100)));
+
+void
+__VLTunprotect (void)
+{
+  __VLTChangePermission (__VLTP_READ_WRITE);
+}
+
+void
+__VLTprotect (void)
+{
+  __VLTChangePermission (__VLTP_READ_ONLY);
+}
+
+/* This VTV_STATIC_VERIFY macro is experimental for now. If we are
+   going to use it we need to put the code below in a common
+   place. Right now it is a copy of the code in vtv_rts.cc */
+#ifdef VTV_STATIC_VERIFY
+
+#ifdef VTV_DEBUG
+
+const void *
+__VLTVerifyVtablePointerDebug (void **set_handle_ptr,
+                               const void *vtable_ptr,
+                               const char *set_symbol_name,
+                               const char *vtable_name)
+{
+#ifndef VTV_EMPTY_VERIFY
+  VTV_DEBUG_ASSERT(set_handle_ptr != NULL && *set_handle_ptr != NULL);
+  int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+  vtv_set_handle *handle_ptr;
+  if (!is_set_handle_handle (*set_handle_ptr))
+    handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  else
+    handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+  if (vtv_sets::contains (vtbl_ptr, handle_ptr))
+    {
+      if (debug_verify_vtable)
+        {
+          if (verify_vtable_log_fd == -1)
+            vtv_open_log ("vtv_verify_vtable.log");
+          vtv_add_to_log (verify_vtable_log_fd,
+                          "Verified %s %s value = %p\n",
+                          set_symbol_name, vtable_name, vtable_ptr);
+        }
+    }
+  else
+    {
+      snprintf (debug_log_message, sizeof (debug_log_message),
+                "Looking for %s in %s\n", vtable_name, set_symbol_name);
+      __vtv_verify_fail_debug (set_handle_ptr, vtable_ptr, debug_log_message);
+
+      /* Normally __vtv_verify_fail will call abort, so we won't
+         execute the return below.  If we get this far, the assumption
+         is that the programmer has replace __vtv_verify_fail with
+         some kind of secondary verification AND this secondary
+         verification succeeded, so the vtable pointer is valid.  */
+    }
+#endif  /* VTV_EMPTY_VERIFY  */
+
+  return vtable_ptr;
+}
+
+#else /* VTV_DEBUG  */
+
+const void *
+__VLTVerifyVtablePointer (void **set_handle_ptr, const void *vtable_ptr)
+{
+#ifndef VTV_EMPTY_VERIFY
+  int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+  vtv_set_handle *handle_ptr;
+  if (!is_set_handle_handle (*set_handle_ptr))
+    handle_ptr = (vtv_set_handle *) set_handle_ptr;
+  else
+    handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+  if (!vtv_sets::contains (vtbl_ptr, handle_ptr))
+    {
+      __vtv_verify_fail ((void **) handle_ptr, vtable_ptr);
+      /* Normally __vtv_verify_fail will call abort, so we won't
+         execute the return below.  If we get this far, the assumption
+         is that the programmer has replaced __vtv_verify_fail with
+         some kind of secondary verification AND this secondary
+         verification succeeded, so the vtable pointer is valid.  */
+    }
+#endif  /* VTV_EMPTY_VERIFY*/
+
+  return vtable_ptr;
+}
+
+#endif /* else-clause VTV_DEBUG */
+
+#endif /* VTV_STATIC_VERIFY  */
Index: libstdc++-v3/libsupc++/vtv_malloc.cc
===================================================================
--- libstdc++-v3/libsupc++/vtv_malloc.cc	(revision 0)
+++ libstdc++-v3/libsupc++/vtv_malloc.cc	(revision 0)
@@ -0,0 +1,210 @@
+/* Copyright (C) 2012
+   Free Software Foundation
+
+   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.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* This file is part of the vtable verification runtime library.  It
+   contains our memory allocation and deallocation routines, which we
+   use in order to keep track of the pages in memory in which our sets
+   of valid vtable pointes are stored.  (We need to know the pages so
+   we can set the protections on them appropriately).  For more
+   information about the vtable verification feature, see the comments
+   in vtv_rts.cc.  We use the existing obstack implementation in our
+   memory allocation scheme.  */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "vtv_utils.h"
+#include "vtv_malloc.h"
+#include "obstack.h"
+
+/* Put the following variables in our ".vtable_map_vars" section so
+   that they are protected.  They are explicitly unprotected and
+   protected again by calls to VTV_unprotect and VTV_protect */
+
+static struct obstack VTV_obstack VTV_PROTECTED_VAR;
+static unsigned long page_size VTV_PROTECTED_VAR = 0;
+static void *current_chunk VTV_PROTECTED_VAR = 0;
+static size_t current_chunk_size VTV_PROTECTED_VAR = 0;
+static int malloc_initialized VTV_PROTECTED_VAR = 0;
+
+/* This function goes through all of the pages we have allocated so
+   far and calls mprotect to make each page read-only.  */
+
+void
+VTV_malloc_protect (void)
+{
+  struct _obstack_chunk *ci;
+  ci = (struct _obstack_chunk *) current_chunk;
+  while (ci)
+    {
+      VTV_DEBUG_ASSERT (((unsigned long) ci & (page_size - 1)) == 0);
+      if (mprotect (ci, (ci->limit - (char *) ci), PROT_READ) == -1)
+	VTV_error ();
+      ci = ci->prev;
+    }
+
+#if (VTV_DEBUG_MALLOC == 1)
+    VTV_malloc_dump_stats ();
+#endif
+}
+
+/* This function goes through all of the pages we have allocated so
+   far and calls mrpotect to make each page read-write.  */
+
+void
+VTV_malloc_unprotect (void)
+{
+  struct _obstack_chunk * ci;
+  ci = (struct _obstack_chunk *) current_chunk;
+  while (ci)
+    {
+      VTV_DEBUG_ASSERT (((unsigned long) ci & (page_size - 1)) == 0);
+      if (mprotect (ci, (ci->limit - (char *) ci), PROT_READ | PROT_WRITE)
+                                                                         == -1)
+	VTV_error ();
+      ci = ci->prev;
+    }
+}
+
+/* Allocates a SIZE-sized chunk of memory that is aligned to a page
+   boundary.  The amount of memory requested (SIZE) must be a multiple
+   of the page size.  Note: We must use mmap to allocate the memory;
+   using malloc here will cause problems.  */
+
+static void *
+obstack_chunk_alloc (size_t size)
+{
+  /* Increase size to the next multiple of page_size.   */
+  size = (size + (page_size - 1)) & (~(page_size - 1));
+  VTV_DEBUG_ASSERT ((size & (page_size - 1)) == 0);
+  void *allocated;
+
+  if ((allocated = mmap (NULL, size, PROT_READ | PROT_WRITE,
+                         MAP_PRIVATE | MAP_ANONYMOUS,  -1, 0)) == 0)
+    VTV_error ();
+
+  VTV_DEBUG_ASSERT (((unsigned long) allocated & (page_size - 1)) == 0);
+
+  current_chunk = allocated;
+  current_chunk_size = size;
+  return allocated;
+}
+
+static void
+obstack_chunk_free (size_t size)
+{
+  /* Do nothing. For our purposes there should be very little
+     de-allocation. */
+}
+
+/* This function sets up and initializes the obstack pieces for our
+   memory allocation scheme.  */
+
+void
+VTV_malloc_init (void)
+{
+  /* Make sure we only execute the main body of this function ONCE.  */
+  if (malloc_initialized)
+    return;
+
+  page_size = sysconf (_SC_PAGE_SIZE);
+  if (page_size != 4096)
+    VTV_error ();
+
+  obstack_chunk_size (&VTV_obstack) = page_size;
+  obstack_alignment_mask (&VTV_obstack) = sizeof (long) - 1;
+  /* We guarantee that the obstack alloc failed handler will never be
+     called because in case the allocation of the chunk fails, it will
+     never return */
+  obstack_alloc_failed_handler = NULL;
+
+  obstack_init (&VTV_obstack);
+  malloc_initialized = 1;
+}
+
+/* This is our external interface for the memory allocation.  SIZE is
+   the requested number of bytes to be allocated/  */
+
+void *
+VTV_malloc (size_t size)
+{
+  return obstack_alloc (&VTV_obstack, size);
+}
+
+
+/* This is our external interface for memory deallocation.  */
+
+void
+VTV_free (void *)
+{
+  /* Do nothing. We dont care about recovering unneded memory at this
+     time.  */
+}
+
+
+/* This is a debugging function tat collects statistics about our
+   memory allocation.  */
+void
+VTV_malloc_stats (void)
+{
+  int count = 0;
+  struct _obstack_chunk * ci = (struct _obstack_chunk *) current_chunk;
+  while (ci)
+    {
+      count++;
+      ci = ci->prev;
+    }
+  fprintf (stderr,
+	   "VTV_malloc_stats:\n  Page Size = %lu bytes\n  "
+	   "Number of pages = %d\n", page_size, count);
+}
+
+/* This is a debugging function.  It writes out our memory allocation
+   statistics to a log file.  */
+
+void
+VTV_malloc_dump_stats (void)
+{
+  static int fd = -1;
+
+  if (fd == -1)
+    fd = vtv_open_log ("/tmp/vtv_mem_protection.log");
+  if (fd == -1)
+    return;
+
+  int count = 0;
+  struct _obstack_chunk * ci = (struct _obstack_chunk *) current_chunk;
+  while (ci)
+    {
+      count++;
+      ci = ci->prev;
+    }
+
+  vtv_add_to_log (fd, "VTV_malloc_protect protected=%d pages\n", count);
+}
Index: libstdc++-v3/libsupc++/Makefile.am
===================================================================
--- libstdc++-v3/libsupc++/Makefile.am	(revision 195903)
+++ libstdc++-v3/libsupc++/Makefile.am	(working copy)
@@ -27,7 +27,7 @@ include $(top_srcdir)/fragment.am
 # Need this library to both be part of libstdc++.a, and installed
 # separately too.
 # 1) separate libsupc++.la
-toolexeclib_LTLIBRARIES = libsupc++.la
+toolexeclib_LTLIBRARIES = libsupc++.la libvtv_init.la libvtv_stubs.la
 # 2) integrated libsupc++convenience.la that is to be a part of libstdc++.a
 noinst_LTLIBRARIES = libsupc++convenience.la
 
@@ -93,10 +93,21 @@ sources = \
 	tinfo2.cc \
 	vec.cc \
 	vmi_class_type_info.cc \
-	vterminate.cc
+	vterminate.cc \
+        vtv_rts.cc \
+        vtv_malloc.cc \
+        vtv_utils.cc
+
+vtv_init_sources = \
+        vtv_init.cc
+
+vtv_stubs_sources = \
+        vtv_stubs.cc
 
 libsupc___la_SOURCES = $(sources) $(c_sources)
 libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+libvtv_init_la_SOURCES = $(vtv_init_sources)
+libvtv_stubs_la_SOURCES = $(vtv_stubs_sources)
 
 # AM_CXXFLAGS needs to be in each subdirectory so that it can be
 # modified in a per-library or per-sub-library way.  Need to manually
Index: libstdc++-v3/config/abi/pre/gnu.ver
===================================================================
--- libstdc++-v3/config/abi/pre/gnu.ver	(revision 195903)
+++ libstdc++-v3/config/abi/pre/gnu.ver	(working copy)
@@ -1326,6 +1326,20 @@ GLIBCXX_3.4.18 {
     # operator delete(void*, , unsigned long)
     _ZdlPv[jmy];
 
+    # Virtual table verification symbols
+    _Z12__VLTprotectv;
+    _Z14__VLTunprotectv;
+    _Z18__VLTInitSetSymbol*;
+    _Z23__VLTInitSetSymbolDebug*;
+    _Z17__VLTRegisterPair*;
+    _Z22__VLTRegisterPairDebug*;
+    _Z21__VLTChangePermission*;
+    _Z24__VLTVerifyVtablePointer*;
+    _Z29__VLTVerifyVtablePointerDebug*;
+    _Z17__vtv_verify_fail*;
+    _Z17__vtv_really_fail*;
+
+
 } GLIBCXX_3.4.17;
 
 # Symbols in the support library (libsupc++) have their own tag.
Index: libgcc/config.host
===================================================================
--- libgcc/config.host	(revision 195903)
+++ libgcc/config.host	(working copy)
@@ -195,7 +195,7 @@ case ${host} in
   ;;
 *-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu)
   tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux"
-  extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
+  extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o vtv_start.o vtv_end.o"
   ;;
 *-*-lynxos*)
   tmake_file="$tmake_file t-lynx $cpu_type/t-crtstuff t-crtstuff-pic t-libgcc-pic"
Index: libgcc/Makefile.in
===================================================================
--- libgcc/Makefile.in	(revision 195903)
+++ libgcc/Makefile.in	(working copy)
@@ -976,6 +976,14 @@ crtendS$(objext): $(srcdir)/crtstuff.c
 # This is a version of crtbegin for -static links.
 crtbeginT$(objext): $(srcdir)/crtstuff.c
 	$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
+
+# These are used in vtable verification; see comments in source files for
+# more details.
+vtv_start$(objext): $(srcdir)/vtv_start.c
+	$(crt_compile) $(CRTSTUFF_T_CFLAGS_S) -c $(srcdir)/vtv_start.c
+
+vtv_end$(objext): $(srcdir)/vtv_end.c
+	$(crt_compile) $(CRTSTUFF_T_CFLAGS_S) -c $(srcdir)/vtv_end.c
 endif
 
 ifeq ($(CUSTOM_CRTIN),)
Index: libgcc/vtv_start.c
===================================================================
--- libgcc/vtv_start.c	(revision 0)
+++ libgcc/vtv_start.c	(revision 0)
@@ -0,0 +1,59 @@
+/*  Copyright (C) 2012, 2013
+    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 verification feature (for a
+   detailed description of the feature, see comments in
+   tree-vtable-verify.c).  The vtable verification feature creates
+   certain global symbols that need to be read-write sometimes during
+   program execution, and read-only at others.  It uses 'mprotect' to
+   change the memory protections of the pages on which these variables
+   are stored.  In order to not affect the protections of other
+   program variables, these variables are put into a special named
+   section, ".vtable_map_vars", which is page-aligned at the start,
+   and which is padded with a page-sized amount of zeros at the end.
+   To make this section page aligned, we create a special symbol,
+   "_vtable_map_vars_start" which we make the very first thing that
+   goes into the section.  This file defines that symbol (and only
+   that symbol).  GCC compiles this file into vtv_start.o, and
+   inserts vtv_start.o into the link line immediately after
+   crtbegin.o, if the program is compiled with -fvtable.verify.
+
+   In order to pad the ".vtable_map_vars" section with a page-sized
+   amount of zeros at the end, there is a second symbol,
+   _vtable_map_vars_end, which is defined in another file, vtv_end.c.
+   This second symbol is a page-sized array of chars, zero-filled, and
+   is the very last thing to go into the section.  When the GCC driver
+   inserts vtv_start.o into the link line (just after crtbegin.o) it
+   also inserts vtv_end.o into the link line, just before crtend.o.
+   This has the desired effect of making our section page-aligned and
+   page-size paded, ensuring that no other program data lands on our
+   pages.  */
+
+#ifdef BIG_PAGE_SIZE
+/* TODO - Replace '4096' below with correct big page size.  */
+#define VTV_PAGE_SIZE 4096
+#else 
+#define VTV_PAGE_SIZE 4096
+#endif
+
+/* Page-aligned symbol to mark beginning of .vtable_map_vars section.  */
+char _vtable_map_vars_start []
+__attribute__ ((__visibility__ ("protected"), used, aligned(VTV_PAGE_SIZE),
+		section(".vtable_map_vars")))
+  = { };
Index: libgcc/vtv_end.c
===================================================================
--- libgcc/vtv_end.c	(revision 0)
+++ libgcc/vtv_end.c	(revision 0)
@@ -0,0 +1,59 @@
+/*  Copyright (C) 2012, 2013
+    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 verification feature (for a
+   detailed description of the feature, see comments in
+   tree-vtable-verify.c).  The vtable verification feature creates
+   certain global symbols that need to be read-write sometimes during
+   program execution, and read-only at others.  It uses 'mprotect' to
+   change the memory protections of the pages on which these variables
+   are stored.  In order to not affect the protections of other
+   program variables, these variables are put into a special named
+   section, ".vtable_map_vars", which is page-aligned at the start,
+   and which is padded with a page-sized amount of zeros at the end.
+   To make this section page aligned, we create a special symbol,
+   "_vtable_map_vars_start" which we make the very first thing that
+   goes into the section.  That is defined in vtv_start.c (which
+   contains nothing else).  vtv_start.c gest compiled into
+   vtv_start.o, and vtv_start.o gets inserted into the link line
+   immediately after crtbegin.o, if the program is compiled with
+   -fvtable.verify.
+
+   In order to pad the ".vtable_map_vars" section with a page-sized
+   amount of zeros at the end, there is a second symbol,
+   _vtable_map_vars_end.  This file defines that symbol (and only this
+   symbol).  This second symbol is a page-sized array of chars,
+   zero-filled, and is the very last thing to go into the section.
+   When the GCC driver inserts vtv_start.o into the link line (just
+   after crtbegin.o) it also inserts vtv_end.o into the link line,
+   just before crtend.o.  This has the desired effect of making our
+   section page-aligned and page-size paded, ensuring that no other
+   program data lands on our pages.  */
+
+#ifdef BIG_PAGE_SIZE
+/* TODO - Replace '4096' below with correct big page size.  */
+#define VTV_PAGE_SIZE 4096
+#else
+#define VTV_PAGE_SIZE 4096
+#endif
+
+/* Page-sized variable to mark end of .vtable_map_vars section.  */
+char _vtable_map_vars_end[VTV_PAGE_SIZE]
+  __attribute__ ((__visibility__ ("protected"), used,
+		  section(".vtable_map_vars")));
Index: gcc/cgraph.c
===================================================================
--- gcc/cgraph.c	(revision 195903)
+++ gcc/cgraph.c	(working copy)
@@ -2498,7 +2498,7 @@ cgraph_add_new_function (tree fndecl, bo
       case CGRAPH_STATE_FINISHED:
 	/* At the very end of compilation we have to do all the work up
 	   to expansion.  */
-	node = cgraph_create_node (fndecl);
+	node = cgraph_get_create_node (fndecl);
 	if (lowered)
 	  node->lowered = true;
 	cgraph_analyze_function (node);
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 195903)
+++ gcc/tree.h	(working copy)
@@ -5913,6 +5913,9 @@ is_tm_safe_or_pure (const_tree x)
 
 void init_inline_once (void);
 
+/* In tree-vtable-verify.c */
+extern void save_vtable_map_decl (tree);
+
 /* Compute the number of operands in an expression node NODE.  For
    tcc_vl_exp nodes like CALL_EXPRs, this is stored in the node itself,
    otherwise it is looked up from the node's code.  */
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h	(revision 195903)
+++ gcc/tree-pass.h	(working copy)
@@ -460,6 +460,7 @@ extern struct gimple_opt_pass pass_split
 extern struct gimple_opt_pass pass_feedback_split_functions;
 extern struct gimple_opt_pass pass_threadsafe_analyze;
 extern struct gimple_opt_pass pass_tree_convert_builtin_dispatch;
+extern struct gimple_opt_pass pass_vtable_verify;
 
 /* IPA Passes */
 extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 195903)
+++ gcc/cp/init.c	(working copy)
@@ -46,7 +46,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 195903)
+++ gcc/cp/class.c	(working copy)
@@ -6136,6 +6136,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 195903)
+++ 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 tree-mudflap.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o tree-mudflap.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) $
   tree-threadsafe-analyze.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/g++spec.c
===================================================================
--- gcc/cp/g++spec.c	(revision 195903)
+++ gcc/cp/g++spec.c	(working copy)
@@ -51,6 +51,8 @@ along with GCC; see the file COPYING3.  
 #define LIBSTDCXX_STATIC NULL
 #endif
 
+#define VTABLE_LOAD_MODULE_INIT "--whole-archive,-lvtv_init,--no-whole-archive"
+
 void
 lang_specific_driver (struct cl_decoded_option **in_decoded_options,
 		      unsigned int *in_decoded_options_count,
@@ -112,6 +114,11 @@ lang_specific_driver (struct cl_decoded_
   /* The total number of arguments with the new stuff.  */
   unsigned int num_args = 1;
 
+  /* The command line contains a -fvtable_verify. We need to add the
+     init library if we are linking and if we are adding the stdc++
+     library.  */
+  int saw_vtable_verify = 0;
+
   argc = *in_decoded_options_count;
   decoded_options = *in_decoded_options;
   added_libraries = *in_added_libraries;
@@ -237,6 +244,13 @@ lang_specific_driver (struct cl_decoded_
 	      }
 	  }
 	  break;
+
+	case OPT_fvtable_verify_:
+          if (strcmp (arg, "std") == 0)
+            saw_vtable_verify = 1;
+          else if (strcmp (arg, "preinit") == 0)
+            saw_vtable_verify = 2;
+          break;
 	}
     }
 
@@ -248,6 +262,12 @@ lang_specific_driver (struct cl_decoded_
 
   /* Add one for shared_libgcc or extra static library.  */
   num_args = argc + added + need_math + (library > 0) * 4 + 1;
+
+  /* Add two more linker args, '-Wl,-u_vtable_map_vars_start and
+     '-Wl,-u_vtable_map_vars_end.  */
+  if (saw_vtable_verify && library > 0)
+    num_args += 2;
+
   new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);
 
   i = 0;
@@ -310,6 +330,33 @@ lang_specific_driver (struct cl_decoded_
       j++;
     }
 
+  /* Add option to make sure that if we are doing 'std' vtable
+     verification then we link with the libvtv_init library.  */
+
+  if (saw_vtable_verify == 1 && library > 0)
+    {
+      generate_option(OPT_Wl_, VTABLE_LOAD_MODULE_INIT, 1,
+                      CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+    }
+
+  /* If we are doing vtable verification, make sure the linker does
+     not garbage-collect the special symbols that mark the start and
+     end of the ".vtable_map_vars" section in the binary.  (See
+     comments in vtv_start.c and vtv_end.c for more details).  */
+
+  if (saw_vtable_verify > 0 && library > 0)
+    {
+      generate_option (OPT_Wl_,"-u_vtable_map_vars_start", 1,
+                       CL_DRIVER, &new_decoded_options[j]);
+      j++;
+
+      generate_option (OPT_Wl_,"-u_vtable_map_vars_end", 1,
+                       CL_DRIVER, &new_decoded_options[j]);
+      j++;
+    }
+
   /* Add `-lstdc++' if we haven't already done so.  */
   if (library > 0)
     {
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 195903)
+++ gcc/cp/pt.c	(working copy)
@@ -18124,6 +18124,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 195903)
+++ gcc/cp/decl2.c	(working copy)
@@ -2782,7 +2782,8 @@ set_guard (tree guard)
 }
 
 /* Start the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+   or destructors.  Subroutine of do_[cd]tors.  Also called from
+   vtv_start_verification_constructor_init_function.  */
 
 static tree
 start_objects (int method_type, int initp)
@@ -2834,8 +2835,12 @@ start_objects (int method_type, int init
   return body;
 }
 
-/* Finish the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+/* Finish the process of running a particular set of global
+   constructors or destructors.  Subroutine of do_[cd]tors.  Also
+   called from vtv_finish_verification_constructor_init_function.
+
+   This function returns a tree containing the functino decl for the
+   functin it finished creating.  */
 
 static void
 finish_objects (int method_type, int initp, tree body)
@@ -4125,8 +4130,22 @@ cp_write_global_declarations (void)
 
   timevar_start (TV_PHASE_CGRAPH);
 
+  if (flag_vtable_verify)
+    {
+      vtv_recover_class_info ();
+      vtv_compute_class_hierarchy_transitive_closure ();
+    }
+
   cgraph_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 ();
+    }
+
   timevar_stop (TV_PHASE_CGRAPH);
   timevar_start (TV_PHASE_CHECK_DBGINFO);
 
@@ -4475,4 +4494,24 @@ mark_used (tree decl)
   return true;
 }
 
+tree
+vtv_start_verification_constructor_init_function (void)
+{
+  return start_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1);
+}
+
+tree
+vtv_finish_verification_constructor_init_function (tree function_body)
+{
+  /* return finish_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1, function_body); */
+  tree fn;
+
+  finish_compound_stmt (function_body);
+  fn = finish_function (0);
+  DECL_STATIC_CONSTRUCTOR (fn) = 1;
+  decl_init_priority_insert (fn, MAX_RESERVED_INIT_PRIORITY - 1);
+
+  return fn;
+}
+
 #include "gt-cp-decl2.h"
Index: gcc/cp/config-lang.in
===================================================================
--- gcc/cp/config-lang.in	(revision 195903)
+++ 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,1265 @@
+/* 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/>.  */
+
+/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
+   before using them for virtual method dispatches.  */
+
+/* This file is part of the vtable security feature implementation.
+   The vtable security feature is designed to detect when a virtual
+   call is about to be made through an invalid vtable pointer
+   (possibly due to data corruption or malicious attacks). The
+   compiler finds every virtual call, and inserts a verification call
+   before the virtual call.  The verification call takes the actual
+   vtable pointer value in the object through which the virtual call
+   is being made, and compares the vtable pointer against a set of all
+   valid vtable pointers that the object could contain (this set is
+   based on the declared type of the object).  If the pointer is in
+   the valid set, execution is allowed to continue; otherwise the
+   program is halted.
+
+  There are several pieces needed in order to make this work: 1. For
+  every virtual class in the program (i.e. a class that contains
+  virtual methods), we need to build the set of all possible valid
+  vtables that an object of that class could point to.  This includes
+  vtables for any class(es) that inherit from the class under
+  consideration.  2. For every such data set we build up, we need a
+  way to find and reference the data set.  This is complicated by the
+  fact that the real vtable addresses are not known until runtime,
+  when the program is loaded into memory, but we need to reference the
+  sets at compile time when we are inserting verification calls into
+  the program.  3.  We need to find every virtual call in the program,
+  and insert the verification call (with the appropriate arguments)
+  before the virtual call.  4. We need some runtime library pieces:
+  the code to build up the data sets at runtime; the code to actually
+  perform the verification using the data sets; and some code to set
+  protections on the data sets, so they themselves do not become
+  hacker targets.
+
+  To find and reference the set of valid vtable pointers for any given
+  virtual class, we create a special global varible for each virtual
+  class.  We refer to this as the "vtable map variable" for that
+  class.  The vtable map variable has the type "void *", and is
+  initialized by the compiler to NULL.  At runtime when the set of
+  valid vtable pointers for a virtual class, e.g. class Foo, is built,
+  the vtable map variable for class Foo is made to point to the set.
+  During compile time, when the compiler is inserting verification
+  calls into the program, it passes the vtable map variable for the
+  appropriate class to the verification call, so that at runtime the
+  verification call can find the appropriate data set.
+
+  The actual set of valid vtable pointers for a virtual class,
+  e.g. class Foo, cannot be built until runtime, when the vtables get
+  loaded into memory and their addresses are known.  But the knowledge
+  about which vtables belong in which class' hierarchy is only known
+  at compile time.  Therefore at compile time we collect class
+  hierarchy and vtable information about every virtual class, and we
+  generate calls to build up the data sets at runtime.  To build the
+  data sets, we call one of the functions we add to the runtime
+  library, __VLTRegisterPair.  __VLTRegisterPair takes two arguments,
+  a vtable map variable and the address of a vtable.  If the vtable
+  map variable is currently NULL, it creates a new data set (hash
+  table), makes the vtable map variable point to the new data set, and
+  inserts the vtable address into the data set.  If the vtable map
+  variable is not NULL, it just inserts the vtable address into the
+  data set.  In order to make sure that our data sets are built before
+  any verification calls happen, we create a special constructor
+  initialization function for each compilation unit, give it a very
+  high initialization priority, and insert all of our calls to
+  __VLTRegisterPair into our special constructor initialization
+  function.
+
+  The vtable verification feature is controlled by the flag
+  '-fvtable-verify='.  There are three flavors of this:
+  '-fvtable-verify=std', '-fvtable-verify=preinit', and
+  '-fvtable-verify=none'.  If the option '-fvtable-verfy=preinit' is
+  used, then our constructor initialization function gets put into the
+  preinit array.  This is necessary if there are data sets that need
+  to be built very early in execution.  If the constructor
+  initialization function gets put into the preinit array, the we also
+  add calls to __VLTChangePermission at the beginning and end of the
+  function.  The call at the beginning sets the permissions on the
+  data sets and vtable map variables to read/write, and the one at the
+  end makes them read-only.  If the '-fvtable-verify=std' option is
+  used, the constructor initialization functions are executed at their
+  normal time, and the __VLTChangePermission calls are handled
+  differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
+  The option '-fvtable-verify=none' turns off vtable verification.
+
+  This file contains code to find and record the class hierarchies for
+  the virtual classes in a program, and all the vtables associated
+  with each such class; to generate the vtable map variables; and to
+  generate the constructor initialization function (with the calls to
+  __VLTRegisterPair, and __VLTChangePermission).  The main data
+  structures used for collecting the class hierarchy data and
+  building/maintaining the vtable map variable data are defined in
+  gcc/tree-vtable-verify.h, because they are used both here and in
+  gcc/tree-vtable-verify.c.  */
+
+#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"
+
+/* Mark these specially since they need 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_init_set_symbol_fndecl = NULL_TREE;
+static GTY (()) tree vlt_change_permission_fndecl = NULL_TREE;
+
+struct work_node {
+  struct vtv_graph_node *node;
+  struct work_node *next;
+};
+
+struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
+
+/* As part of vtable verification the compiler generates and inserts calls
+   to __VLTRegisterPair and __VLTChangePermission, which are in libsupc++.
+   This function builds and initializes the function decls that are used
+   in generating those function calls.
+
+   In addition to __VLTRegisterPair there is also __VLTRegisterPairDebug
+   which can be used in place of __VLTRegisterPair, and which takes extra
+   parameters and outputs extra information, to help debug problems.  The
+   debug version of this function is generated and used if VTV_DEBUG is
+   defined.
+
+   The signatures for these functions are:
+
+   void __VLTChangePermission (int);
+   void __VLTRegisterPair (void **, void*, int);
+   void __VLTRegisterPairDebug (void**, void *, int, char *, int, char *, int);
+*/
+
+static void
+init_functions (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree change_permission_type = void_type_node;
+  tree register_pairs_type = void_type_node;
+  tree init_set_symbol_type = void_type_node;
+#ifdef VTV_DEBUG
+  tree const_char_ptr_type = build_pointer_type (build_qualified_type
+                                                           (char_type_node,
+                                                            TYPE_QUAL_CONST));
+#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,
+                                                   const_ptr_type_node));
+
+#ifdef VTV_DEBUG
+  /* These arguments are only used by the debug version of RegisterPair */
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   const_char_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   const_char_ptr_type));
+#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
+  /* void
+     __VLTRegisterPairDebug (void ** set_handle_ptr, const void * vtable_ptr,
+                        const char * set_symbol_name, const char * vtable_name)
+  */
+
+  vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPairDebug",
+                                             register_pairs_type);
+#else
+   /* void __VLTRegisterPair (void **set_handle_ptr, const void *vtable_ptr) */
+ 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);
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   const_ptr_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   size_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  init_set_symbol_type = build_function_type (init_set_symbol_type, arg_types);
+
+#ifdef VTV_DEBUG
+  /* void __VLTInitSetSymbolDebug(void ** set_handle_ptr, 
+                                 const void * set_symbol_key,
+                                 size_t size_hint)
+  */
+  vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbolDebug",
+                                              init_set_symbol_type);
+#else
+  /* void __VLTInitSetSymbol(void ** set_handle_ptr, 
+                             const void * set_symbol_key,
+                             size_t size_hint)
+  */
+  vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbol",
+                                              init_set_symbol_type);
+#endif
+
+  TREE_NOTHROW (vlt_init_set_symbol_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl));
+  TREE_PUBLIC (vlt_init_set_symbol_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_init_set_symbol_fndecl) = 1;
+  retrofit_lang_decl (vlt_init_set_symbol_fndecl);
+  SET_DECL_LANGUAGE (vlt_init_set_symbol_fndecl, lang_cplusplus);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It adds a
+   vtv_graph_node to the WORKLIST, which is a linked list of
+   seen-but-not-yet-processed nodes.  INSERTED is a bitmap, one bit
+   per node, to help make sure that we don't insert a node into the
+   worklist more than once.  Each node represents a class somewhere in
+   our class hierarchy information. Every node in the graph gets added
+   to the worklist exactly once and removed from the worklist exactly
+   once (when all of its children have been processed).  */
+
+static void
+add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
+                 sbitmap inserted)
+{
+  struct work_node *new_work_node;
+
+  if (TEST_BIT (inserted, node->class_uid))
+    return;
+
+  new_work_node = XNEW (struct work_node);
+  new_work_node->next = *worklist;
+  new_work_node->node = node;
+  *worklist = new_work_node;
+
+  SET_BIT (inserted, node->class_uid);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It goes through
+   the WORKLIST of class hierarchy nodes looking for a "leaf" node,
+   i.e. a node whose children in the hierarchy have all been
+   processed.  When it finds the next leaf node, it removes it from
+   the linked list (WORKLIST) and returns the node.  */
+
+static struct vtv_graph_node *
+find_and_remove_next_leaf_node (struct work_node **worklist)
+{
+  struct work_node *prev, *cur;
+
+  for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+    {
+      if (cur->node->num_children == cur->node->num_processed_children)
+        {
+          if (prev == NULL)
+            (*worklist) = cur->next;
+          else
+            prev->next = cur->next;
+
+          cur->next = NULL;
+          return cur->node;
+        }
+    }
+
+  return NULL;
+}
+
+/* In our class hierarchy graph, each class node contains a bitmap,
+   with one bit for each class in the hierarchy.  The bits are set for
+   classes that are descendants in the graph of the current node.
+   Initially the descendants bitmap is only set for immediate
+   descendants.  This function traverses the class hierarchy graph,
+   bottom up, filling in the transitive closures for the descendants
+   as we rise up the graph.  */
+
+void
+vtv_compute_class_hierarchy_transitive_closure (void)
+{
+  struct work_node *worklist = NULL;
+  struct vtbl_map_node *cur;
+  sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+  unsigned i;
+
+  /* Note: Every node in the graph gets added to the worklist exactly
+   once and removed from the worklist exactly once (when all of its
+   children have been processed).  Each node's children edges are
+   followed exactly once, and each node's parent edges are followed
+   exactly once.  So this algorithm is roughly O(V + 2E), i.e.
+   O(E + V).  */
+
+  /* Set-up:                                                                */
+  /* Find all the "leaf" nodes in the graph, and add them to the worklist.  */
+  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.  VTABLE_DECL is the var decl for the vtable of
+   the (descendant) class that we are adding to our class hierarchy
+   data.  VPTR_ADDRESS is and expression for calculating the correct
+   offset into the vtable (VTABLE_DECL).  It is the actual vtable
+   pointer address that will be stored in our list of valid vtable
+   pointers for BASE_CLASS.  BASE_CLASS is the record_type node for
+   the base class to whose hiearchy we want to add
+   VPTR_ADDRESS. (VTABLE_DECL should be the vtable for BASE_CLASS or
+   one of BASE_CLASS' descendents.  */
+
+static bool
+record_register_pairs (tree vtable_decl, tree vptr_address,
+                       tree base_class)
+{
+  unsigned offset;
+  struct vtbl_map_node *base_vtable_map_node;
+
+  if (TREE_OPERAND_LENGTH (vptr_address) == 1)
+    {
+      tree tmp_address = TREE_OPERAND (vptr_address, 0);
+      offset = TREE_INT_CST_LOW (TREE_OPERAND (tmp_address, 1));
+    }
+  else
+    offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
+  
+  base_vtable_map_node = vtbl_map_get_node (base_class);
+
+  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
+                                       offset))
+    return true;
+
+  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
+                                     offset);
+  return false;
+}
+
+/* A class may contain secondary vtables in it, for various reasons.
+   This function goes through the decl chain of a class record looking
+   for any fields that point to secondary vtables, and adding calls to
+   __VLTRegisterPair for the secondary vtable pointers.
+
+   BASE_CLASS_DECL_ARG is an expression for the address of the vtable
+   map variable for the BASE_CLASS (whose hierarchy we are currently
+   updating).  BASE_CLASS is the record_type node for the base class.
+   RECORD_TYPE is the record_type node for the descendant class that
+   we are possibly adding to BASE_CLASS's hierarchy.  BODY is the
+   function body for the constructor init function to which we are
+   adding our calls to __VLTRegisterPair.  */
+
+static void
+register_vptr_fields (tree base_class_decl_arg, tree base_class,
+                      tree record_type, tree body)
+{
+  tree vtbl_var_decl;
+
+  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;
+
+      /* Check to see if we have found a constructor vtable.  Add its
+         data if appropriate.  */
+      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;
+#ifdef VTV_DEBUG
+              int len1 = strlen (IDENTIFIER_POINTER
+                                 (DECL_NAME (TREE_OPERAND (base_class_decl_arg,
+                                                           0))));
+              tree arg1 = build_string_literal (len1 + 1,
+                                                IDENTIFIER_POINTER
+                                                  (DECL_NAME
+                                                     (TREE_OPERAND
+                                                        (base_class_decl_arg,
+                                                         0))));
+#endif
+              /* Loop through the initialization values for this vtable to
+                 get all the correct vtable pointer addresses that we need
+                 to add to our set of valid vtable pointers for the current
+                 base class.  */
+
+              for (cnt = 0;
+                   VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (values),
+				cnt, ce);
+                   cnt++)
+                {
+                  tree value = ce->value;
+                  tree val_vtbl_decl;
+
+		  /* We need to check value and find the bit where we have
+		     something with 2 arguments, the first argument of which
+		     is an ADDR_EXPR and the second argument of which is
+		     an INTEGER_CST.  */
+
+		  while (value && TREE_OPERAND_LENGTH (value) == 1
+			 && TREE_CODE (TREE_OPERAND (value, 0)) == ADDR_EXPR)
+		    value = TREE_OPERAND (value, 0);
+
+		  /*
+		  gcc_assert (TREE_OPERAND_LENGTH (value) >= 2
+			      && TREE_CODE (TREE_OPERAND (value, 0)) == ADDR_EXPR
+			      && TREE_CODE (TREE_OPERAND (value, 1)) == INTEGER_CST);
+		  */
+		  /* The VAR_DECL for the vtable should be the first argument of
+		     the ADDR_EXPR, which is the first argument of value.*/
+
+		  if (TREE_OPERAND (value, 0))
+		    val_vtbl_decl = TREE_OPERAND (value, 0);
+
+		  while (TREE_CODE (val_vtbl_decl) != VAR_DECL
+			 && TREE_OPERAND (val_vtbl_decl, 0))
+		    val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
+
+                  gcc_assert (TREE_CODE (val_vtbl_decl) == VAR_DECL);
+
+                  /* Check to see if we already have this vtable pointer in
+                     our valid set for this base class.  */
+                  already_registered = record_register_pairs (val_vtbl_decl,
+                                                              value,
+                                                              base_class);
+
+                  if (already_registered)
+                    continue;
+#ifdef VTV_DEBUG
+                  {
+                    int len2 = strlen (IDENTIFIER_POINTER
+                                                (DECL_NAME (val_vtbl_decl)));
+                    tree arg2 = build_string_literal (len2 + 1,
+                                                      IDENTIFIER_POINTER
+                                                        (DECL_NAME
+                                                           (val_vtbl_decl)));
+
+                    /* Generate the call to __VLTRegisterPairDebug to
+                       add this vtable pointer to our set of valid
+                       pointers for the base class.  */
+
+                    call_expr = build_call_expr (vlt_register_pairs_fndecl, 4,
+                                                 base_class_decl_arg, value,
+                                                 arg1, arg2);
+                  }
+#else
+                  /* Generate the call to __VLTRegisterPair to add
+                     this vtable pointer to our set of valid pointers
+                     for the base class.  */
+
+                  call_expr = build_call_expr (vlt_register_pairs_fndecl, 2,
+                                               base_class_decl_arg, value);
+#endif
+                  append_to_statement_list (call_expr, &body);
+                }
+            }
+        }
+    }
+}
+
+/* This function iterates through all the vtables it can find from the
+   BINFO of a class, to make sure we have found ALL of the vtables
+   that an object of that class could point to.  Generate calls to
+   __VLTRegisterPair for those vtable pointers that we find.
+
+   BINFO is the tree_binfo node for the BASE_CLASS.  BODY is the
+   function body for the constructor init function to which we are
+   adding calls to __VLTRegisterPair.  ARG1 is an expression for the
+   address of the vtable map variable (for the BASE_CLASS), that will
+   point to the updated data set.  BASE_CLASS is the record_type node
+   for the base class whose set of valid vtable pointers we are
+   updating. STR1 and STR2 are all debugging information, to be passed
+   as parameters to __VLTRegisterPairDebug.  STR1 represents the name
+   of the vtable map variable to be updated by the call.  Similarly,
+   STR2 represents the name of the class whose vtable pointer is being
+   added to the hierarchy.  */
+
+static void
+register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
+                              tree str2, tree base_class)
+{
+  unsigned ix;
+  tree base_binfo;
+  tree vtable_decl;
+  bool already_registered;
+
+  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, 4,
+                                             arg1, vtable_address,
+                                             str1, str2);
+#else
+                call_expr = build_call_expr (vlt_register_pairs_fndecl, 2,
+                                             arg1, vtable_address);
+#endif
+              append_to_statement_list (call_expr, &body);
+            }
+        }
+
+      register_other_binfo_vtables (base_binfo, body, arg1, str1, str2,
+                                    base_class);
+    }
+}
+
+/* The set of valid vtable pointers for any given class are stored in
+   a hash table.  For reasons of efficiency, that hash table size is
+   always a power of two.  In order to try to prevent re-sizing the
+   hash tables very often, we pass __VLTRegisterPair an initial guess
+   as to the number of entries the hashtable will eventually need
+   (rounded up to the nearest power of two).  This function takes the
+   class information we have collected for a particular class,
+   CLASS_NODE, and calculates the hash table size guess.  */
+
+static int
+guess_num_vtable_pointers (struct vtv_graph_node *class_node)
+{
+  tree vtbl;
+  int total_num_vtbls = 0;
+  int num_vtbls_power_of_two = 1;
+  unsigned i;
+
+  for (i = 0; i < num_vtable_map_nodes; ++i)
+    if (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.  BODY is the function
+   body, so far, of our constructor initialization function, to which we
+   add the calls.  */
+
+static bool
+register_all_pairs (tree body)
+{
+  struct vtbl_map_node *current;
+  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;
+      tree base_ptr_var_decl = current->vtbl_map_decl;
+      tree str1 = NULL_TREE;
+
+      gcc_assert (current->class_info != NULL);
+
+
+#ifdef VTV_DEBUG
+        str1 = build_string_literal
+                        (IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl)) + 1,
+                         IDENTIFIER_POINTER (DECL_NAME (base_ptr_var_decl)));
+#endif
+
+      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);
+
+                  already_registered = record_register_pairs (vtable_decl,
+                                                              vtable_address,
+                                                              base_class);
+
+                  if (!already_registered)
+                    {
+                      tree str2 = NULL_TREE;
+                      new_type = build_pointer_type (TREE_TYPE
+                                                     (base_ptr_var_decl));
+                      arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+#ifdef VTV_DEBUG
+                      str2 = build_string_literal (IDENTIFIER_LENGTH
+                                                   (DECL_NAME (vtable_decl))
+                                                                            + 1,
+                                                   IDENTIFIER_POINTER
+                                                    (DECL_NAME (vtable_decl)));
+
+                        /* This call expr has the 2 "real" arguments,
+                           plus 2 debugging arguments.   */
+                      call_expr = build_call_expr (vlt_register_pairs_fndecl,
+                                                   4, arg1, vtable_address,
+                                                   str1, str2);
+#else                      
+                      call_expr = build_call_expr (vlt_register_pairs_fndecl,
+                                                   2, arg1, vtable_address);
+#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,
+                                                    str2, base_class);
+                    }
+                }
+            }
+          }
+    }
+
+  return registered_at_least_one;
+}
+
+/* Given a tree containing a class type (CLASS_TYPE), this function
+   finds and returns the class hierarchy node for that class in our
+   data structure.  */
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+  struct vtbl_map_node *vtbl_node;
+
+  vtbl_node = vtbl_map_get_node (class_type);
+  if (vtbl_node)
+    return vtbl_node->class_info;
+
+  return NULL;
+}
+
+/* This function adds an edge to our class hierarchy graph.
+   EDGE_ARRAY will either be an array of parent nodes or an array of
+   children nodes for a particular class.  NUM_ENTRIES is the current
+   number of entries in the array.  MAX_WENTRIES is the maximum number
+   of entries the array can hold.  NEW_ENTRY is a vtv_graph_node
+   representing the new child or parent node to be added to the
+   EDGE_ARRAY.  */
+
+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.  BASE_NODE is our vtv_graph_node that corresponds
+   to a base class.  DERIVED_NODE is our vtv_graph_node that
+   corresponds to a class that is a descendant of the base class
+   (possibly the base class itself).  */
+
+static void
+add_hierarchy_pair (struct vtv_graph_node *base_node,
+                    struct vtv_graph_node *derived_node)
+{
+  add_edge_to_graph (&(base_node->children), &(base_node->num_children),
+                     &(base_node->max_children), derived_node);
+  add_edge_to_graph (&(derived_node->parents), &(derived_node->num_parents),
+                     &(derived_node->max_parents), base_node);
+}
+
+/* This functions adds a new base class/derived class relationship to
+   our class hierarchy data structure.  Both parameters are trees
+   representing the class types, i.e. RECORD_TYPE trees.
+   DERIVED_CLASS can be the same as BASE_CLASS.  */
+
+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.  The parameter, INIT_ROUTINE_BODY, is the
+   function body of our constructor initialization function, to which
+   we add the reference to this symbol (and all of our calls to
+   __VLTRegisterPair).
+
+   For more information, see comments in
+   libstdc++-v3/libsupc++/vtv_init.cc.  */
+
+static void
+create_undef_reference_to_vtv_init (tree init_routine_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),
+                          int32_type_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, &init_routine_body);
+
+}
+
+/* A simple hash function on strings */
+/* Be careful about changing this routine. The values generated will
+   be stored in the calls to InitSet. So, changing this routine may
+   cause a binary incompatibility.  */
+
+static uint32_t
+vtv_string_hash(const char *in)
+{
+  const char *s = in;
+  uint32_t h = 0;
+
+  gcc_assert (in != NULL);
+  for ( ; *s; ++s)
+    h = 5 * h + *s;
+  return h;
+}
+
+/* This function goes through all of our vtable map nodes, and for
+   each one that is actually used, it generates a call to
+   __VLTInitSetSymbol, with the appropriate arguments, and inserts the
+   calls as the start of our constructor initialization function
+   (INIT_ROUTINE_BODY).  */
+
+static bool
+init_all_sets (tree init_routine_body)
+{
+  struct vtbl_map_node *current;
+  bool inited_at_least_one = false;
+  tree_stmt_iterator i = tsi_start (init_routine_body);
+
+  for (current = vtbl_map_nodes; current; current = current->next)
+    {
+      if (!(current->is_used || (htab_elements (current->registered) > 0)))
+        continue;
+
+      size_t size_hint = guess_num_vtable_pointers (current->class_info);
+      tree set_handle_var_decl = current->vtbl_map_decl;
+
+      tree void_ptr_type = build_pointer_type (TREE_TYPE (set_handle_var_decl));
+      tree arg1 = build1 (ADDR_EXPR, void_ptr_type, set_handle_var_decl);
+
+      uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (set_handle_var_decl));
+      uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
+                                            (DECL_NAME (set_handle_var_decl)));
+      tree arg2, arg3, init_set_call;
+
+      /* Build a buffer with the memory representation of
+         insert_only_hash_map::key_value as defined in vtv_map.h. This
+         will be passed as the second argument to InitSet.  */
+      #define KEY_TYPE_FIXED_SIZE 8
+
+      void *key_buffer = xmalloc (len1 + KEY_TYPE_FIXED_SIZE);
+      uint32_t *value_ptr = (uint32_t *) key_buffer;
+
+      /* Set the len and hash for the string.  */
+      *value_ptr = len1;
+      value_ptr++;
+      *value_ptr = hash_value;
+
+      /* Now copy the string representation of the vtbl map name...  */
+      memcpy ((char *) key_buffer + KEY_TYPE_FIXED_SIZE,
+              IDENTIFIER_POINTER (DECL_NAME (set_handle_var_decl)),
+              len1);
+
+      /* ... and build a string literal from it. This will make a copy
+         so the key_bufffer is not needed anymore after this.  */
+      arg2 = build_string_literal (len1 + KEY_TYPE_FIXED_SIZE,
+                                   (char *) key_buffer);
+      free (key_buffer);
+
+      /* size_t maybe different at compile time vs at runtime but
+         there should not be a problem in here. We dont expect such
+         large number of elements in the set.  */
+      arg3 = build_int_cst (size_type_node, size_hint);
+      init_set_call = build_call_expr (vlt_init_set_symbol_fndecl,
+                                       3, arg1, arg2, arg3);
+      gcc_assert (size_hint != 0);
+      tsi_link_before (&i, init_set_call, TSI_SAME_STMT);
+
+      inited_at_least_one = true;
+    }
+  return inited_at_least_one;
+}
+
+
+/* This function calls register_all_pairs, which actually generates
+   all the calls to __VLTRegisterPair (in the verification constructor
+   init function).  It also generates the calls to
+   __VLTChangePermission, if the verification constructor init
+   function is going into the preinit array.  INIT_ROUTINE_BODY is
+   the body of our constructior initialization function, to which we
+   add our function calls.*/
+
+static bool
+vtv_register_class_hierarchy_information (tree init_routine_body)
+{
+  bool registered_something = false;
+  bool inited_some_sets = true;
+
+  init_functions ();
+
+  /* TODO: Temp fix. Needs to be tightened.  */
+  if (num_vtable_map_nodes == 0)
+    return false;;
+
+  /* Add class hierarchy pairs to the vtable map data structure.  */
+  registered_something = register_all_pairs (init_routine_body);
+
+  /* Initialialize all vtable map variables (pointers to our data
+     sets.  */
+  inited_some_sets = init_all_sets (init_routine_body);
+
+  if (registered_something || inited_some_sets)
+  {
+      /* 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 call_r_expr = build_call_expr (vlt_change_permission_fndecl,
+                                              1, arg_read_only);
+          tree_stmt_iterator i = tsi_start (init_routine_body);
+          /* Insert the call to make permissions read-write at the
+             beginning of the init routine.  */
+          tsi_link_before (&i, call_rw_expr, TSI_SAME_STMT);
+
+          /* Append the call to make permissions read-only at the
+             end of the init routine.  */
+          append_to_statement_list (call_r_expr, &init_routine_body);
+        }
+
+      if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
+        create_undef_reference_to_vtv_init (init_routine_body);
+  }
+
+  return registered_something || inited_some_sets;
+}
+
+/* This function writes records data about the number of virtual calls
+   we found and the number of verification calls we generated.  It is
+   primarily for debugging purposes.  */
+
+static void
+write_out_counters (void)
+{
+  if (total_num_virtual_calls == 0)
+    return;
+
+  FILE *fp = fopen ("/tmp/vtable-verification-counters.log", "a");
+  double pct_done = (total_num_verified_vcalls * 100) / total_num_virtual_calls;
+
+  if (fp)
+    {
+      fprintf (fp, "%s %d %d (%.2f %%)\n", main_input_filename,
+               total_num_virtual_calls, total_num_verified_vcalls,
+               pct_done);
+      fclose (fp);
+    }
+}
+
+/* Generate the special constructor function that calls
+   __VLTChangePermission and __VLTRegisterPairs, and give it a very
+   high initialization priority.  */
+
+void
+vtv_generate_init_routine (void)
+{
+  tree init_routine_body;
+  bool vtable_classes_found = false;
+#ifdef VTV_COUNT
+  bool debug_num_verified = true;
+#else
+  bool debug_num_verified = false;
+#endif
+
+  if (debug_num_verified)
+    write_out_counters ();
+
+  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.  */
+  init_routine_body = vtv_start_verification_constructor_init_function ();
+
+  vtable_classes_found =
+                 vtv_register_class_hierarchy_information (init_routine_body);
+
+  if (vtable_classes_found)
+    {
+      current_function_decl =
+       vtv_finish_verification_constructor_init_function (init_routine_body);
+      allocate_struct_function (current_function_decl, false);
+      TREE_STATIC (current_function_decl) = 1;
+      TREE_USED (current_function_decl) = 1;
+      DECL_PRESERVE_P (current_function_decl) = 1;
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          DECL_STATIC_CONSTRUCTOR (current_function_decl) = 0;
+          assemble_vtv_preinit_initializer (current_function_decl);
+        }
+
+      gimplify_function_tree (current_function_decl);
+      cgraph_add_new_function (current_function_decl, false);
+
+      cgraph_process_new_functions ();
+    }
+  pop_lang_context ();
+}
+
+/* This funtion takes a tree containing a class type (BASE_TYPE), and
+   it either finds the existing vtbl_map_node for that class in our
+   data structure, or it creates a new node and adds it to the data
+   structure if there is not one for the class already.  As part of
+   this process it also creates the global vtable map variable for the
+   class.  */
+
+struct vtbl_map_node *
+vtable_find_or_create_map_decl (tree base_type)
+{
+  tree base_decl = TREE_CHAIN (base_type);
+  tree base_id;
+  struct vtbl_map_node *vtable_map_node = NULL;
+  tree base_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  /* Verify the type has an associated vtable.  */
+  if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
+    return NULL;
+
+  if (!base_decl)
+    base_decl = TYPE_NAME (base_type);
+
+  /* Temporarily remove any type qualifiers on the type. */
+  base_decl_type = TREE_TYPE (base_decl);
+  save_quals = TYPE_QUALS (base_decl_type);
+  reset_type_qualifiers (null_quals, base_decl_type);
+
+  base_id = DECL_ASSEMBLER_NAME (base_decl);
+
+  /* Restore the type qualifiers. */
+  reset_type_qualifiers (save_quals, base_decl_type);
+
+  /* We've already created the variable; just look it.  */
+  vtable_map_node = vtbl_map_get_node (base_type);
+
+  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 *var_name = NULL;
+      tree var_decl = NULL;
+      tree var_type = build_pointer_type (void_type_node);
+      tree initial_value = build_int_cst (make_node (INTEGER_TYPE), 0);
+
+      /* Create map lookup symbol for base class */
+      var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
+                           "E12__vtable_mapE", NULL));
+      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;
+      DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
+      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 .vtable_map_vars sections, so
+         we can find and protect them.  */
+
+      DECL_SECTION_NAME (var_decl) = build_string (strlen (".vtable_map_vars"),
+                                                   ".vtable_map_vars");
+      DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl) = true;
+      DECL_COMDAT_GROUP (var_decl) = get_identifier (var_name);
+      DECL_INITIAL (var_decl) = initial_value;
+
+      varpool_finalize_decl (var_decl);
+      if (!vtable_map_node)
+        vtable_map_node = find_or_create_vtbl_map_node (base_type);
+      if (vtable_map_node->vtbl_map_decl == NULL_TREE)
+        vtable_map_node->vtbl_map_decl = var_decl;
+    }
+
+  gcc_assert (vtable_map_node);
+  return vtable_map_node;
+}
+
+/* This function is used to build up our class hierarchy data for a
+   particular class.  TYPE is the record_type tree node for the
+   class.  */
+
+static void
+vtv_save_base_class_info (tree type)
+{
+  if (flag_vtable_verify)
+    {
+      tree binfo =  TYPE_BINFO (type);
+      tree base_binfo;
+      struct vtbl_map_node *own_map;
+      int i;
+
+      /* First make sure to create the map for this record type.  */
+      own_map = vtable_find_or_create_map_decl (type);
+      if (own_map == NULL)
+        return;
+
+      /* Go through the list of all base classes for the current
+         (derived) type, make sure the *__vtable_map global variable
+         for the base class exists, and add the base class/derived
+         class pair to the class hierarchy information we are
+         accumulating (for vtable pointer verification).  */
+      for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+        {
+          tree tree_val = BINFO_TYPE (base_binfo);
+          struct vtbl_map_node *vtable_map_node = NULL;
+
+          vtable_map_node = vtable_find_or_create_map_decl (tree_val);
+
+          if (vtable_map_node != NULL)
+            update_class_hierarchy_information (tree_val, type);
+        }
+    }
+}
+
+/* This function adds classes we are interested in to a list of
+   classes that is saved during pre-compiled header generation.
+   RECORD is the record_type node for the class we are adding to the
+   list.  */
+
+void
+vtv_save_class_info (tree record)
+{
+  if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
+    return;
+
+  gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+  vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
+}
+
+
+/* This function goes through the list of classes we saved before the
+   pre-compiled header generation and calls vtv_save_base_class_info
+   on each one, to build up our class hierarchy data structure.  */
+
+void
+vtv_recover_class_info (void)
+{
+  tree current_class;
+  tree class_chain = vlt_saved_class_info;
+  while (class_chain != NULL_TREE)
+    {
+      current_class = TREE_VALUE (class_chain);
+      gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+
+      vtv_save_base_class_info (current_class);
+      class_chain = TREE_CHAIN (class_chain);
+    }
+
+  /* Let the garbabe collector collect the memory associated with the
+     chain.  */
+  vlt_saved_class_info = NULL_TREE;
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 195903)
+++ gcc/cp/mangle.c	(working copy)
@@ -3347,7 +3347,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);
@@ -3413,7 +3413,7 @@ mangle_decl (const tree decl)
 	DECL_WEAK (alias) = 1;
       if (TREE_CODE (decl) == FUNCTION_DECL)
 	cgraph_same_body_alias (cgraph_get_create_node (decl), alias, decl);
-      else
+      else if (TREE_CODE (decl) == VAR_DECL)
 	varpool_extra_name_alias (alias, decl);
 #endif
     }
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 195903)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -5151,6 +5151,8 @@ extern void note_vague_linkage_fn		(tree
 extern tree build_artificial_parm		(tree, tree);
 extern bool possibly_inlined_p			(tree);
 extern int parm_index                           (tree);
+extern tree vtv_start_verification_constructor_init_function (void);
+extern tree vtv_finish_verification_constructor_init_function (tree);
 
 /* in error.c */
 extern void init_error				(void);
@@ -5238,6 +5240,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);
@@ -5919,6 +5922,7 @@ extern tree mangle_thunk			(tree, int, t
 extern tree mangle_conv_op_name_for_type	(tree);
 extern tree mangle_guard_variable		(tree);
 extern tree mangle_ref_init_variable		(tree);
+extern tree get_mangled_id                      (tree);
 
 /* in dump.c */
 extern bool cp_dump_tree			(void *, tree);
@@ -5966,6 +5970,12 @@ extern bool cxx_omp_privatize_by_referen
 extern void suggest_alternatives_for            (location_t, tree);
 extern tree strip_using_decl                    (tree);
 
+/* in vtable-class-hierarchy.c */
+extern void vtv_compute_class_hierarchy_transitive_closure (void);
+extern void vtv_generate_init_routine           (void);
+extern void vtv_save_class_info                 (tree);
+extern void vtv_recover_class_info              (void);
+
 /* -- end of C++ */
 
 #endif /* ! GCC_CP_TREE_H */
Index: gcc/tree-ssa-copyrename.c
===================================================================
--- gcc/tree-ssa-copyrename.c	(revision 195903)
+++ gcc/tree-ssa-copyrename.c	(working copy)
@@ -245,7 +245,7 @@ copy_rename_partition_coalesce (var_map 
     }
 
   /* Don't coalesce if the two variables aren't type compatible .  */
-  if (!types_compatible_p (TREE_TYPE (root1), TREE_TYPE (root2))
+  if (!gimple_types_compatible_p (TREE_TYPE (root1), TREE_TYPE (root2))
       /* There is a disconnect between the middle-end type-system and
          VRP, avoid coalescing enum types with different bounds.  */
       || ((TREE_CODE (TREE_TYPE (root1)) == ENUMERAL_TYPE
Index: gcc/timevar.def
===================================================================
--- gcc/timevar.def	(revision 195903)
+++ gcc/timevar.def	(working copy)
@@ -256,6 +256,7 @@ DEFTIMEVAR (TV_TREE_THREADSAFE       , "
 DEFTIMEVAR (TV_PLUGIN_INIT           , "plugin initialization")
 DEFTIMEVAR (TV_PLUGIN_RUN            , "plugin execution")
 DEFTIMEVAR (TV_SIMPLIFY_GOT          , "simplify got")
+DEFTIMEVAR (TV_VTABLE_VERIFICATION   , "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 195903)
+++ gcc/flag-types.h	(working copy)
@@ -223,4 +223,11 @@ enum opt_info_verbosity_levels {
   OPT_INFO_MED  = 2,
   OPT_INFO_MAX  = 3
 };
+
+/* 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,1131 @@
+/*   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+    Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
+   before using them for virtual method dispatches.  */
+
+/* This file is part of the vtable security feature implementation.
+   The vtable security feature is designed to detect when a virtual
+   call is about to be made through an invalid vtable pointer
+   (possibly due to data corruption or malicious attacks). The
+   compiler finds every virtual call, and inserts a verification call
+   before the virtual call.  The verification call takes the actual
+   vtable pointer value in the object through which the virtual call
+   is being made, and compares the vtable pointer against a set of all
+   valid vtable pointers that the object could contain (this set is
+   based on the declared type of the object).  If the pointer is in
+   the valid set, execution is allowed to continue; otherwise the
+   program is halted.
+
+  There are several pieces needed in order to make this work: 1. For
+  every virtual class in the program (i.e. a class that contains
+  virtual methods), we need to build the set of all possible valid
+  vtables that an object of that class could point to.  This includes
+  vtables for any class(es) that inherit from the class under
+  consideration.  2. For every such data set we build up, we need a
+  way to find and reference the data set.  This is complicated by the
+  fact that the real vtable addresses are not known until runtime,
+  when the program is loaded into memory, but we need to reference the
+  sets at compile time when we are inserting verification calls into
+  the program.  3.  We need to find every virtual call in the program,
+  and insert the verification call (with the appropriate arguments)
+  before the virtual call.  4. We need some runtime library pieces:
+  the code to build up the data sets at runtime; the code to actually
+  perform the verification using the data sets; and some code to set
+  protections on the data sets, so they themselves do not become
+  hacker targets.
+
+  To find and reference the set of valid vtable pointers for any given
+  virtual class, we create a special global varible for each virtual
+  class.  We refer to this as the "vtable map variable" for that
+  class.  The vtable map variable has the type "void *", and is
+  initialized by the compiler to NULL.  At runtime when the set of
+  valid vtable pointers for a virtual class, e.g. class Foo, is built,
+  the vtable map variable for class Foo is made to point to the set.
+  During compile time, when the compiler is inserting verification
+  calls into the program, it passes the vtable map variable for the
+  appropriate class to the verification call, so that at runtime the
+  verification call can find the appropriate data set.
+
+  The actual set of valid vtable pointers for a virtual class,
+  e.g. class Foo, cannot be built until runtime, when the vtables get
+  loaded into memory and their addresses are known.  But the knowledge
+  about which vtables belong in which class' hierarchy is only known
+  at compile time.  Therefore at compile time we collect class
+  hierarchy and vtable information about every virtual class, and we
+  generate calls to build up the data sets at runtime.  To build the
+  data sets, we call one of the functions we add to the runtime
+  library, __VLTRegisterPair.  __VLTRegisterPair takes two arguments,
+  a vtable map variable and the address of a vtable.  If the vtable
+  map variable is currently NULL, it creates a new data set (hash
+  table), makes the vtable map variable point to the new data set, and
+  inserts the vtable address into the data set.  If the vtable map
+  variable is not NULL, it just inserts the vtable address into the
+  data set.  In order to make sure that our data sets are built before
+  any verification calls happen, we create a special constructor
+  initialization function for each compilation unit, give it a very
+  high initialization priority, and insert all of our calls to
+  __VLTRegisterPair into our special constructor initialization
+  function.
+
+  The vtable verification feature is controlled by the flag
+  '-fvtable-verify='.  There are three flavors of this:
+  '-fvtable-verify=std', '-fvtable-verify=preinit', and
+  '-fvtable-verify=none'.  If the option '-fvtable-verfy=preinit' is
+  used, then our constructor initialization function gets put into the
+  preinit array.  This is necessary if there are data sets that need
+  to be built very early in execution.  If the constructor
+  initialization function gets put into the preinit array, the we also
+  add calls to __VLTChangePermission at the beginning and end of the
+  function.  The call at the beginning sets the permissions on the
+  data sets and vtable map variables to read/write, and the one at the
+  end makes them read-only.  If the '-fvtable-verify=std' option is
+  used, the constructor initialization functions are executed at their
+  normal time, and the __VLTChangePermission calls are handled
+  differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
+  The option '-fvtable-verify=none' turns off vtable verification.
+
+  This file contains code for the tree pass that goes through all the
+  statements in each basic block, looking for virtual calls, and
+  inserting a call to __VLTVerifyVtablePointer (with appropriate
+  arguments) before each one.  It also contains the hash table
+  functions for the data structures used for collecting the class
+  hierarchy data and building/maintaining the vtable map variable data
+  are defined in gcc/tree-vtable-verify.h.  These data structures are
+  shared with the code in the C++ front end that collects the class
+  hierarchy & vtable information and generates the vtable map
+  variables (see cp/vtable-class-hierarchy.c).  This tree pass should
+  run just before the gimple is converted to RTL.
+
+  Some implementation details for this pass:
+
+  To find the all of the virtual calls, we iterate through all the
+  gimple statements in each basic block, looking for any call
+  statement with the code "OBJ_TYPE_REF".  Once we have found the
+  virtual call, we need to find the vtable pointer through which the
+  call is being made, and the type of the object containing the
+  pointer (to find the appropriate vtable map variable).  We then use
+  these to build a call to __VLTVerifyVtablePointer, passing the
+  vtable map variable, and the vtable pointer.  We insert the
+  verification call just after the gimple statement that gets the
+  vtable pointer out of the object, and we update the next
+  statement to depend on the result returned from
+  __VLTVerifyVtablePointer (the vtable pointer value), to ensure
+  subsequent compiler phases don't remove or reorder the call (it's no
+  good to have the verification occur after the virtual call, for
+  example).  To find the vtable pointer being used (and the type of
+  the object) we search backwards through the def_stmts chain from the
+  virtual call (see verify_bb_vtables for more details).  */
+
+#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"
+
+int total_num_virtual_calls = 0;
+int total_num_verified_vcalls = 0;
+
+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);
+
+/* The following few functions are for the vtbl pointer hash table
+   in the 'registered' field of the struct vtable_map_node.  The hash
+   table keeps track of which vtable pointers have been used in
+   calls to __VLTRegisterPair with that particular vtable map variable.  */
+
+/* This function checks to see if a particular VTABLE_DECL and OFFSET are
+   already in the 'registered' hash table for NODE.  */
+
+bool
+vtbl_map_node_registration_find (struct vtbl_map_node *node,
+                                 tree vtable_decl,
+                                 unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+
+  gcc_assert (node && node->registered);
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, NO_INSERT);
+
+  if (slot && (*slot) && (*slot)->offsets)
+    {
+      unsigned i;
+      for (i = 0; i < (*slot)->cur_offset; ++i)
+        if ((*slot)->offsets[i] == offset)
+          return true;
+    }
+
+  return false;
+}
+
+/* This function inserts VTABLE_DECL and OFFSET into the 'registered'
+   hash table for NODE.  */
+
+void
+vtbl_map_node_registration_insert (struct vtbl_map_node *node,
+                                   tree vtable_decl,
+                                   unsigned offset)
+{
+  struct vtable_registration key;
+  struct vtable_registration **slot;
+
+  if (!node || !node->registered)
+    return;
+
+  key.vtable_decl = vtable_decl;
+  slot = (struct vtable_registration **) htab_find_slot (node->registered,
+                                                         &key, INSERT);
+
+  if (! *slot)
+    {
+      unsigned i;
+      struct vtable_registration *node;
+      node = XNEW (struct vtable_registration);
+      node->vtable_decl = vtable_decl;
+
+      /* We expect the number of different offsets in any given vtable
+         that will be valid vtable pointers to be small (but we know
+         it can be greater than 1).  To avoid having to resize this
+         very often, we randomly chose 10 as a reasonable-seeming
+         size.  */
+      node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));
+      for (i= 0; i < 10; ++i)
+        node->offsets[i] = 0;
+      node->offsets[0] = offset;
+      node->cur_offset = 1;
+      node->max_offsets = 10;
+      *slot = node;
+    }
+  else
+    {
+      /* We found the vtable_decl slot; we need to see if it already
+         contains the offset.  If not, we need to add the offset.  */
+      unsigned i;
+      bool found = false;
+      for (i = 0; i < (*slot)->cur_offset && !found; ++i)
+        if ((*slot)->offsets[i] == offset)
+          found = true;
+
+      if (!found)
+        {
+          /* Re-size the offset array if necessary.  */
+          if ((*slot)->cur_offset == (*slot)->max_offsets)
+            {
+              unsigned new_max = 2 * (*slot)->max_offsets;
+              (*slot)->offsets = (unsigned *)
+                  xrealloc ((*slot)->offsets, new_max * sizeof (unsigned));
+
+              for (i = (*slot)->max_offsets; i < new_max; ++i)
+                (*slot)->offsets[i] = 0;
+              (*slot)->max_offsets = new_max;
+            }
+          /* Insert the new offset.  */
+          (*slot)->offsets[(*slot)->cur_offset] = offset;
+          (*slot)->cur_offset = (*slot)->cur_offset + 1;
+        }
+    }
+}
+
+/* Hashtable functions for vtable_registration hashtables.  */
+
+static hashval_t
+hash_vtable_registration (const void *p)
+{
+  const struct vtable_registration *n = (const struct vtable_registration *) p;
+  return (hashval_t) (DECL_UID (n->vtable_decl));
+}
+
+static int
+eq_vtable_registration (const void *p1, const void *p2)
+{
+  const struct vtable_registration *n1 =
+                                    (const struct vtable_registration *) p1;
+  const struct vtable_registration *n2 =
+                                    (const struct vtable_registration *) p2;
+  return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
+}
+
+/* End of hashtable functions for "registered" hashtables.  */
+
+
+/* Here are the three data structures into which we insert vtable map nodes.
+   We use three data structures because of the vastly different ways we need
+   to find the nodes for various tasks (see comments in tree-vtable-verify.h
+   for more details.  */
+
+/* Vtable map variable nodes stored in a hash table.  */
+static htab_t vtbl_map_hash = NULL;
+
+/* Vtable map variable nodes stored in a linked list.  */
+struct vtbl_map_node *vtbl_map_nodes = NULL;
+
+/* Vtable map variable nodes stored in an array.  */
+struct vtbl_map_node **vtbl_map_nodes_array = NULL;
+
+/* This function take a vtbl_map_node, NODE, and inserts it in the
+   array of vtable map nodes, using it's uid as the position in the
+   array into which to insert it. (The uids are unique and
+   monotonically grow as the nodes are generated.)  */
+
+static void
+vtable_map_array_insert (struct vtbl_map_node *node)
+{
+  static unsigned array_size = 0;
+  unsigned i;
+
+  /* If the array is NULL, allocate it with an initial size of 16.  */
+  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)
+    {
+      /* Check to see if the array is large enough to hold another
+         node; resize it if it is not.  */
+      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
+              && vtbl_map_nodes_array[node->uid] == NULL);
+
+  /* Insert the node into the array.  */
+  vtbl_map_nodes_array[node->uid] = node;
+}
+
+/* Hashtable functions for vtbl_map_hash.  */
+
+/* Returns a hash code for P.  */
+
+static hashval_t
+hash_vtbl_map_node (const void *p)
+{
+  const struct vtbl_map_node *n = (const struct vtbl_map_node *) p;
+  return (hashval_t) IDENTIFIER_HASH_VALUE (n->class_name);
+}
+
+/* Returns nonzero if P1 and P2 are equal.  */
+
+static int
+eq_vtbl_map_node (const void *p1, const void *p2)
+{
+  const struct vtbl_map_node *n1 = (const struct vtbl_map_node *) p1;
+  const struct vtbl_map_node *n2 = (const struct vtbl_map_node *) p2;
+  return (IDENTIFIER_HASH_VALUE (n1->class_name) ==
+          IDENTIFIER_HASH_VALUE (n2->class_name));
+}
+
+/* Return vtbl_map node for CLASS_TYPE without creating a new one.  */
+
+struct vtbl_map_node *
+vtbl_map_get_node (tree class_type)
+{
+  struct vtbl_map_node key;
+  struct vtbl_map_node **slot;
+
+  tree class_type_decl;
+  tree type_decl_type;
+  tree class_name;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  if (!vtbl_map_hash)
+    return NULL;
+
+  gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
+
+  /* Use the mangled name for the *unqualified* class as the key in our
+     hashtable.  First we need to find and temporarily remove any type
+     qualifiers on the type.  */
+
+  /* Find the TYPE_DECL for the class.  */
+  if (TREE_CHAIN (class_type))
+    class_type_decl = TREE_CHAIN (class_type);
+  else
+    class_type_decl = TYPE_NAME (class_type);
+
+  /* Temporarily remove any qualifiers on the type.  */
+  type_decl_type = TREE_TYPE (class_type_decl);
+  save_quals = TYPE_QUALS (type_decl_type);
+  reset_type_qualifiers (null_quals, type_decl_type);
+
+  /* Get the mangled name for the unqualified type.  */
+  class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+
+  /* Restore any type qualifiers.  */
+  reset_type_qualifiers (save_quals, type_decl_type);
+
+  key.class_name = 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;
+  tree class_type_decl;
+  tree type_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+  /* Our data shows 90% of classes have no more than 4 parents or children,
+     so we will use 4 as our default hierarchy array size.  */
+  unsigned int default_array_size = 4;
+
+  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))
+    class_type_decl = TREE_CHAIN (base_class_type);
+  else
+    class_type_decl = TYPE_NAME (base_class_type);
+
+  /* Temporarily remove any type qualifiers on type.  */
+  type_decl_type = TREE_TYPE (class_type_decl);
+  save_quals = TYPE_QUALS (type_decl_type);
+  reset_type_qualifiers (null_quals, type_decl_type);
+
+  key.class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+  slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+                                                   INSERT);
+
+  /* Restore any type qualifiers.  */
+  reset_type_qualifiers (save_quals, type_decl_type);
+
+  if (*slot)
+    return *slot;
+
+  node = XNEW (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 = XNEW (struct vtv_graph_node);
+  node->class_info->class_type = base_class_type;
+  node->class_info->class_uid = node->uid;
+  node->class_info->max_parents = default_array_size;
+  node->class_info->max_children = default_array_size;
+  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 (default_array_size * sizeof (struct vtv_graph_node *));
+  node->class_info->children =
+      (struct vtv_graph_node **)
+               xmalloc (default_array_size * sizeof (struct vtv_graph_node *));
+
+  for (i = 0; i < default_array_size; ++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.   */
+
+/* As part of vtable verification the compiler generates and inserts
+   calls to __VLTVerifyVtablePointer, which is in libstdc++.  This
+   function builds and initializes the function decl that is used
+   in generating those function calls.
+
+   In addition to __VLTVerifyVtablePointer there is also
+   __VLTVerifyVtablePointerDebug which can be used in place of
+   __VLTVerifyVtablePointer, and which takes extra parameters and
+   outputs extra information, to help debug problems.  The debug
+   version of this function is generated and used if vtv_debug is
+   true.
+
+   The signatures for these functions are:
+
+   void * __VLTVerifyVtablePointer (void **, void*);
+   void * __VLTVerifyVtablePointerDebug (void**, void *, char *, int, char *,
+                                         int);
+*/
+
+static void
+build_vtable_verify_fndecl (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree func_type = NULL_TREE;
+  struct lang_decl *ld;
+#ifdef VTV_DEBUG
+  tree const_char_ptr_type = build_pointer_type
+                                  (build_qualified_type (char_type_node,
+                                                         TYPE_QUAL_CONST));
+#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,
+                                                   const_ptr_type_node));
+
+#ifdef VTV_DEBUG
+      /* Arg types for the debugging version of function.  */
+      arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                       const_char_ptr_type));
+      arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                       const_char_ptr_type));
+#endif
+
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+  func_type = build_function_type (const_ptr_type_node, arg_types);
+
+#ifdef VTV_DEBUG
+  /* const void *
+     __VLTVerifyVtablePointerDebug (void ** set_handle_ptr, 
+                                    const void * vtable_ptr,
+                                    const char * set_symbol_name, 
+                                    const char * vtable_name)      */
+
+    verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointerDebug",
+                                            func_type);
+#else
+  /* const void *
+     __VLTVerifyVtablePointerDebug (void ** set_handle_ptr, 
+                                    const void * vtable_ptr)            */
+
+    verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointer",
+                                            func_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));
+  DECL_PURE_P (verify_vtbl_ptr_fndecl) = 1;
+  TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
+#ifdef VTV_STATIC_VERIFY
+  DECL_VISIBILITY (verify_vtbl_ptr_fndecl) = 1;
+#endif
+  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);
+}
+
+/* This function takes a tree type, TYPE_NODE, and a set of type qualifier
+   flags, NEW_QUALS, and set the type qualifiers on TYPE_NODE to those
+   specified in NEW_QUALS.  */
+
+void
+reset_type_qualifiers (unsigned int new_quals, tree type_node)
+{
+  if (new_quals & TYPE_QUAL_CONST)
+    TYPE_READONLY (type_node) = 1;
+  else
+    TYPE_READONLY (type_node) = 0;
+
+  if (new_quals & TYPE_QUAL_VOLATILE)
+    TYPE_VOLATILE (type_node) = 1;
+  else
+    TYPE_VOLATILE (type_node) = 0;
+
+  if (new_quals & TYPE_QUAL_RESTRICT)
+    TYPE_RESTRICT (type_node) = 1;
+  else
+    TYPE_RESTRICT (type_node) = 0;
+}
+
+/* This function takes the LHS of a gimple assignment statement, which
+   has already been verified to be an ssa_name, finds the type name of
+   it, and checks to see if the name of the type is
+   "__vtbl_ptr_type".  */
+
+static bool
+type_name_is_vtable_pointer (tree lhs)
+{
+  tree node;
+
+  if (!POINTER_TYPE_P (TREE_TYPE (lhs))
+      || !POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (lhs))))
+    return false;
+
+  node = TREE_TYPE (TREE_TYPE (lhs));
+
+  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 false;
+    }
+
+  return false;
+}
+
+/* Given a gimple STMT, this function checks to see if the statement
+   is an assignment, the rhs of which is getting the vtable pointer
+   value out of an object.  (i.e. it's the value we need to verify
+   because its the vtable pointer that will be used for a virtual
+   call).  */
+
+static bool
+is_vtable_assignment_stmt (gimple stmt)
+{
+
+  if (gimple_code (stmt) != GIMPLE_ASSIGN)
+    return false;
+  else
+    {
+      tree lhs = gimple_assign_lhs (stmt);
+      tree rhs = gimple_assign_rhs1 (stmt);
+
+      if (TREE_CODE (lhs) != SSA_NAME)
+        return false;
+
+      if (! type_name_is_vtable_pointer (lhs))
+        return false;
+
+      if (TREE_CODE (rhs) != COMPONENT_REF)
+        return false;
+
+      if (! (TREE_OPERAND (rhs, 1))
+          || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
+        return false;
+
+      if (! (DECL_NAME (TREE_OPERAND (rhs, 1)))
+          || (strncmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (rhs, 1))),
+                       "_vptr.", 6) != 0))
+        return false;
+    }
+
+    return true;
+}
+
+/* Given the BINFO for a virtual type, gets the vtable decl for that
+   BINFO.  */
+
+static tree
+my_get_vtbl_decl_for_binfo (tree binfo)
+{
+  tree decl;
+
+  decl = BINFO_VTABLE (binfo);
+  if (decl && TREE_CODE (decl) == POINTER_PLUS_EXPR)
+  {
+    gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR);
+    decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+  }
+  if (decl)
+    gcc_assert (TREE_CODE (decl) == VAR_DECL);
+
+  return decl;
+}
+
+/* Given a virtual funciton call (FNCALL) in gimple STMT, this
+   function chains back through the def stmts of the virtual call,
+   looking for the most recent statement that assigned a _vptr field
+   out of the object used in the function call.  This is the vtable
+   pointer value that needs to be verified.  */
+
+static gimple
+find_vtable_ptr_assignment_stmt (tree fncall, gimple stmt, gimple *prev_use)
+{
+  gimple def_stmt;
+
+  /* Find the first operand of the function call; this should be the
+     SSA_NAME variable that contains the pointer to the virtual
+     function.  */
+  if (TREE_OPERAND (fncall, 0)
+      && TREE_CODE (TREE_OPERAND (fncall, 0)) == SSA_NAME)
+    {
+      tree rhs = NULL_TREE;
+      tree func_ptr_var = NULL_TREE;
+
+      func_ptr_var = TREE_OPERAND (fncall, 0);
+      *prev_use = stmt;
+
+      /* Find the statment that calculated the function pointer, i.e.
+         func_ptr_var = *(vtbl_ptr + offset).  */
+
+      def_stmt = SSA_NAME_DEF_STMT (func_ptr_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).  */
+
+      /* TODO: In the future we need to handle def_stmts that are phi
+         stmts.  For now we punt on them.  */
+
+      if (def_stmt && gimple_code (def_stmt) == GIMPLE_PHI)
+        return NULL;
+
+      gcc_assert ((def_stmt != NULL)
+                  && (gimple_code (def_stmt) == GIMPLE_ASSIGN));
+
+
+      /* def_stmt should now be of the form: var1 = *var2
+         (dereferencding var 2 to get the actual address of the
+         virtual method.  We need to extract 'var2' from the rhs, and
+         find its def_stmt.  */
+
+      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)
+        def_stmt = NULL;
+
+      /* Search backwards, through the SSA_NAME_DEF_STMT statements in
+         the RHS of our def_stmt(s), until we find an assignment
+         statement whose lhs is an SSA_NAME and whose rhs contains a
+         "._vptr" field.  */
+
+      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;
+            }
+
+          /* Try to find the SSA_NAME variable in the RHS; start by trying
+             the first (only) rhs piece.  */
+          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);
+
+              /* Get our new def_stmt.  */
+              def_stmt = SSA_NAME_DEF_STMT (rhs);
+            }
+          /* The first piece didn't work, so try the second piece, if
+             there is one.  */
+          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 && gimple_code (def_stmt) == GIMPLE_PHI)
+            def_stmt = NULL;
+
+          if (!def_stmt)
+            break;
+        }
+    }
+
+  return def_stmt;
+}
+
+/* This function takes a gimple statment (STMT) and an iteratpr
+   (GSI_TEMP) and makes the iterator point to the STMTs location in
+   its basic block's sequence of statements.*/
+
+static bool
+find_stmt_in_bb_stmts (gimple stmt, gimple_stmt_iterator *gsi_temp)
+{
+  basic_block def_bb;
+  gimple_seq def_bb_stmts;
+  gimple tmp_stmt;
+  bool found = false;
+
+  def_bb = gimple_bb (stmt);
+  def_bb_stmts = bb_seq (def_bb);
+  *gsi_temp = gsi_start (def_bb_stmts);
+  for (; !gsi_end_p (*gsi_temp) && !found; gsi_next (gsi_temp))
+    {
+      tmp_stmt = gsi_stmt (*gsi_temp);
+      if (tmp_stmt == stmt)
+        {
+          found = true;
+          break; /* Exit loop immediately; do no do another gsi_next.  */
+        }
+    }
+
+  return found;
+}
+
+/* This function attempts to recover the declared class of an object
+   that is used in making a virtual call.  First we try looking
+   directly at the THIS_OBJECT itself.  If that does not work, we try to
+   get the type from the gimple assignment statement that extracts the
+   vtable pointer from the object (DEF_STMT).  The gimple
+   statment usually looks something like this:
+
+   D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event    */
+
+static tree
+extract_object_class_type (tree this_object, gimple def_stmt)
+{
+  tree object_rhs = TREE_TYPE (this_object);
+  tree rhs = NULL_TREE;
+
+  /* First try to get the type out of the 'this' object.  */
+
+  if (POINTER_TYPE_P (object_rhs)
+      && 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);
+
+  /* Check to see if the type from the 'this' object will work or not.
+     Sometimes the type of the 'this' object is not usable (usually
+     due to optimizations which change the type of the 'this' object
+     to 'void *'); try to get the type out of the type cast in the rhs
+     of the vtable pointer assignment statement.  */
+
+  if (!rhs || TREE_CODE (rhs) != RECORD_TYPE || !TYPE_BINFO (rhs)
+      || !BINFO_VTABLE (TYPE_BINFO (rhs))
+      || !my_get_vtbl_decl_for_binfo (TYPE_BINFO (rhs)))
+    {
+      /* The type of the 'this' object did not work, so try to find
+         the type from the rhs of the def_stmt.  Try to find and
+         extract the type cast from that stmt.  */
+
+      rhs = gimple_assign_rhs1 (def_stmt);
+      if (TREE_CODE (rhs) == COMPONENT_REF)
+        {
+          while (TREE_CODE (rhs) == COMPONENT_REF
+                 && (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;
+    }
+
+  return rhs;
+}
+
+/* Search through all the statements in a basic block (BB), 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;
+
+  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)
+        {
+          /* Found a call; see if it's a virtual call.  */
+          tree fncall = gimple_call_fn (stmt);
+          if (TREE_CODE (fncall) == OBJ_TYPE_REF)
+            {
+              bool found = false;
+              tree lhs = NULL_TREE;
+              gimple vptr_stmt;
+              gimple prev_use = NULL;
+
+              /* We have found a virtual call; search backwards,
+                 through the object's SSA_NAME_DEF_STMTs, to find the place
+                 were the vtable pointer is gotten out of the object
+                 (also need to find the object's declared static
+                 type).  */
+
+	      total_num_virtual_calls++;
+
+              /* The first argument to the function must be "this", a
+                 pointer to the object itself.  */
+              this_object = gimple_call_arg (stmt, 0);
+
+              /* Find the previousg statement that gets the "_vptr"
+                 field out of the object.  */
+              vptr_stmt = find_vtable_ptr_assignment_stmt (fncall,
+                                                           stmt,
+                                                           &prev_use);
+
+              if (!vptr_stmt)
+                continue;
+
+              lhs = gimple_assign_lhs (vptr_stmt);
+
+              /* Find the vptr_stmt in its basic block's sequence, so
+                 we have an insertion point for adding our
+                 verification call.  */
+              found = find_stmt_in_bb_stmts (vptr_stmt, &gsi_vtbl_assign);
+
+              if (found)
+                {
+                  tree vtbl_var_decl = NULL_TREE;
+                  tree vtbl = NULL_TREE;
+                  gimple_seq pre_p = NULL;
+                  struct vtbl_map_node *vtable_map_node = NULL;
+                  tree vtbl_decl = NULL_TREE;
+                  tree expr_tree = NULL_TREE;
+                  struct gimplify_ctx gctx;
+                  const char *vtable_name = "<unknown>";
+                  int len1 = 0;
+                  int len2 = 0;
+
+                  /* Now we have found the virtual method dispatch and
+                     the preceding access of the _vptr.* field... Next
+                     we need to find the statically declared type of
+                     the object, so we can find and use the right
+                     vtable map variable in the verification call.  */
+                  tree class_type = extract_object_class_type (this_object,
+                                                               vptr_stmt);
+
+                  /* Make sure we found a valid type.  */
+                  gcc_assert (class_type
+                              && (TREE_CODE (class_type) == RECORD_TYPE)
+                              && TYPE_BINFO (class_type));
+
+                  /* Get the vtable VAR_DECL for the type.  */
+                  vtbl_var_decl = my_get_vtbl_decl_for_binfo
+                                                     (TYPE_BINFO (class_type));
+                  vtbl = BINFO_VTABLE (TYPE_BINFO (class_type));
+
+                  gcc_assert (vtbl_var_decl && vtbl);
+
+                  vtbl_decl = vtbl_var_decl;
+
+                  if (POINTER_TYPE_P (TREE_TYPE (vtbl)))
+                    force_gimple_operand (vtbl, &pre_p, 1, NULL);
+
+                  vtable_map_node = vtbl_map_get_node (class_type);
+
+                  /* Build the FUNC_DECL to use for the verification
+                     call.  */
+                  build_vtable_verify_fndecl ();
+                  gcc_assert (verify_vtbl_ptr_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 (vtable_map_node && vtable_map_node->vtbl_map_decl)
+                    {
+                      vtable_map_node->is_used = true;
+                      vtbl_var_decl = vtable_map_node->vtbl_map_decl;
+		      if (!var_ann (vtbl_var_decl))
+			add_referenced_var (vtbl_var_decl);
+
+                      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 debug problems.  */
+#ifdef VTV_DEBUG
+                      expr_tree = build_call_expr
+                                     (verify_vtbl_ptr_fndecl, 4,
+                                      build1 (ADDR_EXPR,
+                                                 TYPE_POINTER_TO
+                                                   (TREE_TYPE (vtbl_var_decl)),
+                                                 vtbl_var_decl),
+                                      SSA_NAME_VAR (lhs),
+                                      build_string_literal
+                                                  (len1 + 1,
+                                                   IDENTIFIER_POINTER
+                                                       (DECL_NAME
+                                                            (vtbl_var_decl))),
+                                      build_string_literal (len2 + 1,
+                                                            vtable_name));
+#else
+                      expr_tree = build_call_expr
+                                     (verify_vtbl_ptr_fndecl, 2,
+                                      build1 (ADDR_EXPR,
+                                                 TYPE_POINTER_TO
+                                                   (TREE_TYPE (vtbl_var_decl)),
+                                                 vtbl_var_decl),
+                                      SSA_NAME_VAR (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.  */
+
+                      mark_sym_for_renaming (SSA_NAME_VAR (lhs));
+                      force_gimple_operand (expr_tree, &pre_p, 1,
+                                            SSA_NAME_VAR (lhs));
+                      
+                      /* Insert the new call just after the original
+                         assignment of the object's vtable pointer.  */
+
+                      pop_gimplify_context (NULL);
+                      gsi_insert_seq_after (&gsi_vtbl_assign, pre_p,
+                                            GSI_NEW_STMT);
+                      any_verification_calls_generated = true;
+		      total_num_verified_vcalls++;
+                    }
+                }
+            }
+        }
+    }
+}
+
+/* Main function, called from pass->excute().  Loop through all the
+   basic blocks in the current function, passing them to
+   verify_bb_vtables, which searches for virtual calls, and inserts
+   calls to __VLTVerifyVtablePointer.  */
+
+unsigned int
+vtable_verify_main (void)
+{
+  unsigned int ret = 1;
+  basic_block bb;
+
+  FOR_ALL_BB (bb)
+      verify_bb_vtables (bb);
+
+  return ret;
+}
+
+/* Gate function for the pass.  */
+
+static bool
+gate_tree_vtable_verify (void)
+{
+  return (flag_vtable_verify
+          && (strcmp (lang_hooks.name, "GNU C++") == 0));
+}
+
+/* Definition of this optimization pass.  */
+
+struct gimple_opt_pass pass_vtable_verify =
+{
+ {
+  GIMPLE_PASS,
+  "vtable-verify",                      /* name */
+  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_dump_func | TODO_update_ssa
+    | TODO_ggc_collect                  /* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-vtable-verify.h"
Index: gcc/tree-vtable-verify.h
===================================================================
--- gcc/tree-vtable-verify.h	(revision 0)
+++ gcc/tree-vtable-verify.h	(revision 0)
@@ -0,0 +1,146 @@
+/* Interprocedural constant propagation
+   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security.  */
+
+#ifndef TREE_VTABLE_VERIFY_H
+#define TREE_VTABLE_VERIFY_H
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "hashtab.h"
+#include "sbitmap.h"
+
+/* Global variable keeping track of how many vtable map variables we
+   have created. */
+extern unsigned num_vtable_map_nodes;
+
+/* Global variable that records whether or not any vtable verification
+   calls have been generated.  */
+extern bool any_verification_calls_generated;
+
+/* Keep track of how many virtual calls we are actually verifying.  */
+extern int total_num_virtual_calls;
+extern int total_num_verified_vcalls;
+
+/* Each vtable map variable corresponds to a virtual class.  Each
+   vtable map variable has a hash table associated with it, that keeps
+   track of the vtable pointers for which we have generated a call to
+   __VLTRegisterPair (with the current vtable map variable).  This is
+   the hash table node that is used for each entry in this hash table
+   of vtable pointers.
+
+   Sometimes there are multiple valid vtable pointer entries that use
+   the same vtable pointer decl with different offsets.  Therefore,
+   for each vtable pointer in the hash table, there is also an array
+   of offsets used with that vtable. */
+
+struct vtable_registration
+{
+  tree vtable_decl;            /* The var decl of the vtable.                */
+  unsigned max_offsets;        /* The allocated size of the offsets array.   */
+  unsigned cur_offset;         /* The next availabe entry in the offsets
+				  array.                                     */
+  unsigned *offsets;           /* The offsets array.                         */
+};
+
+/*  This struct is used to represent the class hierarchy information
+    that we need.  Each vtable map variable has an associated class
+    hierarchy node (struct vtv_graph_node).  Note: In this struct,
+    'children' means immediate descendants in the class hierarchy;
+    'descendant' means any descendant however many levels deep. */
+
+struct vtv_graph_node {
+  tree class_type;                  /* The record_type of the class.         */
+  unsigned class_uid;               /* A unique, monotonically
+                                       ascending id for class node.
+                                       Each vtable map node also has
+                                       an id.  The class uid is the
+                                       same as the vtable map node id
+                                       for nodes corresponding to the
+                                       same class.  */
+  unsigned max_parents;             /* Allocated size of the parents array.  */
+  unsigned max_children;            /* Allocated size of the children array. */
+  unsigned num_parents;             /* # of entries in the parents array.    */
+  unsigned num_children;            /* # of entries in the children array.   */
+  unsigned num_processed_children;  /* # of children for whom we have
+                                       computed the class hierarchy
+                                       transitive closure.                   */
+  struct vtv_graph_node **parents;  /* Array of parents in the graph.        */
+  struct vtv_graph_node **children; /* Array of children in the graph.       */
+  sbitmap descendants;              /* Bitmap representing all this node's
+				       descendants in the graph.             */
+};
+
+/* This is the node used for our hashtable of vtable map variable
+   information.  When we create a vtable map variable (var decl) we
+   put it into one of these nodes; create a corresponding
+   vtv_graph_node for our class hierarchy info and store that in this
+   node; generate a unique (monotonically ascending) id for both the
+   vtbl_map_node and the vtv_graph_node; and insert the node into
+   THREE data structures (to make it easy to find in several different
+   ways): 1). A hash table ("vtbl_map_hash" in tree-vtable-verify.c).
+   This gives us an easy way to check to see if we already have a node
+   for the vtable map variable or not.  2).  A linked list of all
+   vtbl_map_nodes ("vtbl_map_nodes") for easy iteration through all of
+   them; and 3). An array of vtbl_map_nodes, where the array index
+   corresponds to the unique id of the vtbl_map_node, which gives us
+   an easy way to use bitmaps to represent and find the vtable map
+   nodes.  */
+
+struct vtbl_map_node {
+  tree vtbl_map_decl;                 /* The var decl for the vtable map
+					 variable.                           */
+  tree class_name;                    /* The DECL_ASSEMBLER_NAME of the
+					 class.                              */
+  struct vtv_graph_node *class_info;  /* Our class hierarchy info for the
+					 class.                              */
+  unsigned uid;                       /* The unique id for the vtable map
+					 variable.                           */
+  struct vtbl_map_node *next, *prev;  /* Pointers for the linked list
+					 structure.                          */
+  htab_t registered;     /* Hashtable of vtable pointers for which we have
+			    generated a _VLTRegisterPair call with this vtable
+			    map variable.                                    */
+  bool is_used;          /* Boolean indicating if we used this vtable map
+			    variable in a call to __VLTVerifyVtablePointer.  */
+};
+
+/* The global linked list of vtbl_map_nodes.  */
+extern struct vtbl_map_node *vtbl_map_nodes;
+
+/* The global array of vtbl_map_nodes.  */
+extern struct vtbl_map_node **vtbl_map_nodes_array;
+
+extern struct vtbl_map_node *vtbl_map_get_node (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);
+extern void reset_type_qualifiers (unsigned int, tree);
+
+#endif /* TREE_VTABLE_VERIFY_H */
Index: gcc/common.opt
===================================================================
--- gcc/common.opt	(revision 195903)
+++ gcc/common.opt	(working copy)
@@ -2368,6 +2368,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 195903)
+++ gcc/varasm.c	(working copy)
@@ -2064,13 +2064,43 @@ assemble_variable (tree decl, int top_le
     assemble_noswitch_variable (decl, name, sect);
   else
     {
-      switch_to_section (sect);
+      if (sect->named.name
+          && (strcmp (sect->named.name, ".vtable_map_vars") == 0))
+        {
+#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);
       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);
     }
 }
 
+/* Given a function declaration (FN_DECL), this function assembles the
+   function into the .preinit_array section.  */
+
+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
@@ -6338,6 +6368,9 @@ default_section_type_flags (tree decl, c
   if (decl && DECL_ONE_ONLY (decl))
     flags |= SECTION_LINKONCE;
 
+  if (strcmp (name, ".vtable_map_vars") == 0)
+    flags |= SECTION_LINKONCE;
+
   if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
     flags |= SECTION_TLS | SECTION_WRITE;
 
Index: gcc/output.h
===================================================================
--- gcc/output.h	(revision 195903)
+++ gcc/output.h	(working copy)
@@ -215,6 +215,10 @@ extern void assemble_end_function (tree,
    initial value (that will be done by the caller).  */
 extern void assemble_variable (tree, int, int, int);
 
+/* Put the vtable verification constructor initialization function
+   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 195903)
+++ gcc/Makefile.in	(working copy)
@@ -866,6 +866,7 @@ TREE_H = tree.h all-tree.def tree.def c-
 	$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
 	double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
 	$(REAL_H) $(FIXED_VALUE_H)
+CP_TREE_H = cp/cp-tree.h
 REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
 BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) cfghooks.h
 GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \
@@ -1446,6 +1447,7 @@ OBJS = \
 	tree-vect-loop-manip.o \
 	tree-vect-slp.o \
 	tree-vectorizer.o \
+        tree-vtable-verify.o \
 	tree-vrp.o \
 	tree.o \
 	value-prof.o \
@@ -2692,6 +2694,12 @@ tree-vectorizer.o: tree-vectorizer.c $(C
    $(TM_H) $(GGC_H) $(TREE_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) \
    $(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) $(TIMEVAR_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_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 \
@@ -3790,6 +3798,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/gimple.c
===================================================================
--- gcc/gimple.c	(revision 195903)
+++ gcc/gimple.c	(working copy)
@@ -3813,7 +3813,8 @@ pop:
    FOR_MERGING_P is true the an incomplete type and a complete type
    are considered different, otherwise they are considered compatible.  */
 
-static bool
+/* static bool */
+bool
 gimple_types_compatible_p (tree t1, tree t2)
 {
   VEC(type_pair_t, heap) *sccstack = NULL;
Index: gcc/gimple.h
===================================================================
--- gcc/gimple.h	(revision 195903)
+++ gcc/gimple.h	(working copy)
@@ -5221,5 +5221,7 @@ extern tree maybe_fold_and_comparisons (
 extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
 				       enum tree_code, tree, tree);
 
+extern bool gimple_types_compatible_p (tree, tree);
+
 bool gimple_val_nonnegative_real_p (tree);
 #endif  /* GCC_GIMPLE_H */
Index: gcc/passes.c
===================================================================
--- gcc/passes.c	(revision 195903)
+++ gcc/passes.c	(working copy)
@@ -1433,6 +1433,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);
Index: gcc/config/i386/gnu-user.h
===================================================================
--- gcc/config/i386/gnu-user.h	(revision 195903)
+++ gcc/config/i386/gnu-user.h	(working copy)
@@ -111,7 +111,8 @@ along with GCC; see the file COPYING3.  
 /* Similar to standard GNU userspace, but adding -ffast-math support.  */
 #undef  ENDFILE_SPEC
 #define ENDFILE_SPEC \
-  "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
+  "%{fvtable-verify*:vtv_end.o%s} \
+   %{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
    %{mpc32:crtprec32.o%s} \
    %{mpc64:crtprec64.o%s} \
    %{mpc80:crtprec80.o%s} \
Index: gcc/config/i386/gnu-user64.h
===================================================================
--- gcc/config/i386/gnu-user64.h	(revision 195903)
+++ gcc/config/i386/gnu-user64.h	(working copy)
@@ -88,7 +88,8 @@ see the files COPYING3 and COPYING.RUNTI
 /* Similar to standard GNU userspace, but adding -ffast-math support.  */
 #undef  ENDFILE_SPEC
 #define ENDFILE_SPEC \
-  "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
+  "%{fvtable-verify*:vtv_end.o%s} \
+   %{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
    %{mpc32:crtprec32.o%s} \
    %{mpc64:crtprec64.o%s} \
    %{mpc80:crtprec80.o%s} \
Index: gcc/config/gnu-user.h
===================================================================
--- gcc/config/gnu-user.h	(revision 195903)
+++ gcc/config/gnu-user.h	(working copy)
@@ -44,11 +44,13 @@ see the files COPYING3 and COPYING.RUNTI
 #if defined HAVE_LD_PIE
 #define GNU_USER_TARGET_STARTFILE_SPEC \
   "%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}} \
-   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} \
+   %{fvtable-verify*:vtv_start.o%s}"
 #else
 #define GNU_USER_TARGET_STARTFILE_SPEC \
   "%{!shared: %{pg|p|profile:gcrt1.o%s;:crt1.o%s}} \
-   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+   crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} \
+   %{fvtable-verify*:vtv_start.o%s}"
 #endif
 #undef  STARTFILE_SPEC
 #define STARTFILE_SPEC GNU_USER_TARGET_STARTFILE_SPEC
@@ -60,7 +62,8 @@ see the files COPYING3 and COPYING.RUNTI
    GNU userspace "finalizer" file, `crtn.o'.  */
 
 #define GNU_USER_TARGET_ENDFILE_SPEC \
-  "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+  "%{fvtable-verify*:vtv_end.o%s} \
+   %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
 #undef  ENDFILE_SPEC
 #define ENDFILE_SPEC GNU_USER_TARGET_ENDFILE_SPEC
 

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2013-02-09 19:48 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-09 19:48 [google/gcc-4_7-mobile] Port vtable verification from google/gcc-4_7-mobile-vtable-verification branch 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).