Index: libstdc++-v3/src/Makefile.in
===================================================================
*** libstdc++-v3/src/Makefile.in	(revision 192503)
--- libstdc++-v3/src/Makefile.in	(working copy)
*************** libstdc___la_LDFLAGS = \
*** 370,375 ****
--- 370,378 ----
  	-version-info $(libtool_VERSION) ${version_arg} -lm
  
  libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
+ libvtv___la_LIBADD = \
+ 	$(top_builddir)/libsupc++/.libs
+ 
  
  # A note on compatibility and static libraries.
  # 
*************** CXXLINK = \
*** 448,453 ****
--- 451,457 ----
  	$(LIBTOOL) --tag CXX \
  	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
  	--mode=link $(CXX) \
+ 	-L$(libvtv___la_LIBADD) --whole-archive -lvtv_init --no-whole-archive \
  	$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
  
  @ENABLE_SYMVERS_TRUE@CLEANFILES = libstdc++-symbols.ver $(version_dep)
Index: libstdc++-v3/src/Makefile.am
===================================================================
*** libstdc++-v3/src/Makefile.am	(revision 192503)
--- libstdc++-v3/src/Makefile.am	(working copy)
*************** libstdc___la_LDFLAGS = \
*** 73,78 ****
--- 73,80 ----
  
  libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
  
+ libvtv___la_LIBADD = \
+ 	$(top_builddir)/libsupc++/.libs
  
  # Use special rules for compatibility-ldbl.cc compilation, as we need to
  # pass -mlong-double-64.
*************** CXXLINK = \
*** 175,180 ****
--- 177,183 ----
  	$(LIBTOOL) --tag CXX \
  	$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
  	--mode=link $(CXX) \
+ 	-L$(libvtv___la_LIBADD) --whole-archive -lvtv_init --no-whole-archive \
  	$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
  
  
Index: libstdc++-v3/libsupc++/Makefile.in
===================================================================
*** libstdc++-v3/libsupc++/Makefile.in	(revision 192503)
--- libstdc++-v3/libsupc++/Makefile.in	(working copy)
*************** am__objects_1 = array_type_info.lo atexi
*** 103,109 ****
  	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
  @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)
--- 103,110 ----
  	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 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)
*************** libsupc__convenience_la_LIBADD =
*** 111,116 ****
--- 112,125 ----
  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 =
*************** LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLF
*** 123,129 ****
  CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
  	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
  CXXLD = $(CXX)
! SOURCES = $(libsupc___la_SOURCES) $(libsupc__convenience_la_SOURCES)
  HEADERS = $(bits_HEADERS) $(std_HEADERS)
  ETAGS = etags
  CTAGS = ctags
--- 132,139 ----
  CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
  	$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
  CXXLD = $(CXX)
! 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
*************** AM_CPPFLAGS = $(GLIBCXX_INCLUDES)
*** 347,353 ****
  # Need this library to both be part of libstdc++.a, and installed
  # separately too.
  # 1) separate libsupc++.la
! toolexeclib_LTLIBRARIES = libsupc++.la
  # 2) integrated libsupc++convenience.la that is to be a part of libstdc++.a
  noinst_LTLIBRARIES = libsupc++convenience.la
  std_HEADERS = \
--- 357,363 ----
  # Need this library to both be part of libstdc++.a, and installed
  # separately too.
  # 1) separate 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 = \
*************** sources = \
*** 410,419 ****
  	tinfo2.cc \
  	vec.cc \
  	vmi_class_type_info.cc \
! 	vterminate.cc
  
  libsupc___la_SOURCES = $(sources) $(c_sources)
  libsupc__convenience_la_SOURCES = $(sources) $(c_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
--- 420,440 ----
  	tinfo2.cc \
  	vec.cc \
  	vmi_class_type_info.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
*************** libsupc++.la: $(libsupc___la_OBJECTS) $(
*** 575,580 ****
--- 596,605 ----
  	$(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 ****
--- 1,614 ----
+ /* 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 the main runtime library functions for vtable
+    verification.  */
+ 
+ #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>
+ 
+ /* 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_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 */
+ 
+ static const int debug_hash = HASHTABLE_STATS;
+ static const int debug_functions = 0;
+ static const int debug_register_pairs = 0;
+ 
+ /* Put the following variables in a rel.ro section so that the are
+    protected.  They are explicitly unprotected and protected again by
+    calls to VTV_unprotect and VTV_protect */
+ 
+ static int log_file_fd VTV_PROTECTED_VAR = -1;
+ #if HASHTABLE_STATS
+ static int set_log_fd VTV_PROTECTED_VAR = -1;
+ #endif
+ 
+ /* types needed by insert_only_hash_sets */
+ typedef uintptr_t int_vptr;
+ 
+ struct vptr_hash {
+   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);
+     }
+ };
+ 
+ struct vptr_set_alloc {
+   void *
+   operator() (size_t n) const
+     {
+       return VTV_malloc (n);
+     }
+ };
+ 
+ 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;
+ 
+ struct mprotect_data {
+   int prot_mode;
+   unsigned long page_size;
+ };
+ 
+ static void __vtv_verify_fail_debug (void **, void *, char *);
+ 
+ static int
+ dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t size_param,
+ 			  void *data)
+ {
+   mprotect_data *mdata = (mprotect_data *) data;
+   int j;
+ 
+   if (debug_functions)
+     fprintf (stderr, "looking at load module %s to change permissions to %s\n",
+ 	     info->dlpi_name,
+ 	     (mdata->prot_mode & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY");
+   for (j = 0; j < info->dlpi_phnum; j++)
+     {
+       ElfW(Addr) relocated_start_addr = 
+                                   info->dlpi_addr + info->dlpi_phdr[j].p_vaddr;
+       ElfW(Addr) unrelocated_start_addr = info->dlpi_phdr[j].p_vaddr;
+       ElfW(Word) size_in_memory = info->dlpi_phdr[j].p_memsz;
+ 
+       if (debug_functions)
+         fprintf (stderr, "Segment info relocated=%p unrelocated=%p size=%u\n",
+ 		 (void *) relocated_start_addr,
+ 		 (void *) unrelocated_start_addr,
+ 		 size_in_memory);
+ 
+       if (info->dlpi_phdr[j].p_type == PT_GNU_RELRO)
+         {
+           if (debug_functions)
+             fprintf (stderr,
+ 		     "Found RELRO segment. relocated=%p unrelocated=%p "
+ 		     "size=%u\n", (void *) relocated_start_addr,
+ 		     (void *) unrelocated_start_addr, size_in_memory);
+ 
+           ElfW(Addr) mp_low = relocated_start_addr & ~(mdata->page_size - 1);
+           size_t mp_size = relocated_start_addr + size_in_memory - mp_low - 1;
+ 
+           if (mprotect ((void *) mp_low, mp_size, mdata->prot_mode) == -1)
+             {
+               if (debug_functions)
+                 {
+                   fprintf (stderr, "Failed called to mprotect for %s error: ",
+ 			   (mdata->prot_mode & PROT_WRITE) ?
+ 			   "READ/WRITE" : "READ-ONLY");
+                   perror (NULL);
+                 }
+               VTV_error ();
+             }
+           else if (debug_functions)
+             fprintf (stderr, "mprotect'ed range [%p, %p]\n",
+ 		     (void *) mp_low, (char *) mp_low + mp_size);
+ 
+           break;
+         }
+     }
+   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);
+ }
+ 
+ 
+ #if defined __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;
+ 
+ static void
+ initialize_change_permissions_mutexes (void)
+ {
+   __GTHREAD_MUTEX_INIT_FUNCTION (&change_permissions_lock);
+ }
+ #endif
+ 
+ /* These 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
+ 
+ static void
+ log_set_stats (void)
+ {
+ #if HASHTABLE_STATS
+   if (set_log_fd == -1)
+     set_log_fd = vtv_open_log ("/tmp/vtv_set_stats.log");
+ 
+   vtv_add_to_log (set_log_fd, "---\n%s\n",
+ 		  insert_only_hash_tables_stats().c_str());
+ #endif
+ }
+ 
+ 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: need 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);
+     }
+ }
+ 
+ /* For some reason, when the char * names get passed into these
+    functions, they are missing the '\0' at the end; therefore we
+    also pass in the length of the string and make sure, when writing
+    out the names, that we only write out the correct number of
+    bytes. */
+ void
+ log_register_pairs (int fd, const char *format_string_dummy, int format_arg1,
+ 		    int format_arg2, char *base_var_name, char *vtable_name,
+ 		    int_vptr vtbl_ptr)
+ {
+   if (fd == -1)
+     return;
+ 
+   char format_string[60];
+ 
+   /* format_string needs to contain something like "%.10s" (for
+      example) to write a vtable_name that is of length
+      10. Unfortunately the length varies with every name, so we need to
+      generate a new format string, with the correct length, EACH TIME.
+      That is what the 'format_string_dummy' parameter is for.  It
+      contains something like '%%.%ds', and we then use that plus the
+      length argument to generate the correct format_string, to allow
+      us to write out the string that is missing the '\0' at it's
+      end. */
+ 
+   snprintf (format_string, sizeof (format_string), format_string_dummy, 
+             format_arg1, format_arg2);
+   vtv_add_to_log (fd, format_string, base_var_name, vtable_name, vtbl_ptr);
+ }
+ 
+ 
+ /* This holds a formatted error logging message, to be written to the
+    vtable verify failures log.  */
+ char debug_log_message[1024];
+ 
+ 
+ /*  Generate a formatted debug message and load it into the global variable
+     'debug_log_message'.  */
+ static void
+ load_debug_log_message (const char *format_string_dummy, int format_arg1,
+                         int format_arg2,
+                         char *str_arg1, char *str_arg2)
+ {
+   char format_string[50];
+ 
+   /* format_string needs to contain something like "%.10s" (for
+      example) to write a vtable_name that is of length
+      10. Unfortunately the length varies with every name, so we need to
+      generate a new format string, with the correct length, EACH TIME.
+      That is what the 'format_string_dummy' parameter is for.  It
+      contains something like '%%.%ds', and we then use that plus the
+      length argument to generate the correct format_string, to allow
+      us to write out the string that is missing the '\0' at it's
+      end. */
+ 
+   snprintf (format_string, sizeof (format_string), format_string_dummy,
+             format_arg1, format_arg2);
+ 
+   snprintf (debug_log_message, sizeof (debug_log_message),
+             format_string, str_arg1, str_arg2);
+ }
+ 
+ static void
+ print_debugging_message (const char *format_string_dummy, int format_arg1,
+ 			 int format_arg2,
+ 			 char *str_arg1, char *str_arg2)
+ {
+   char format_string[50];
+ 
+   /* format_string needs to contain something like "%.10s" (for
+      example) to write a vtable_name that is of length
+      10. Unfortunately the length varies with every name, so we need to
+      generate a new format string, with the correct length, EACH TIME.
+      That is what the 'format_string_dummy' parameter is for.  It
+      contains something like '%%.%ds', and we then use that plus the
+      length argument to generate the correct format_string, to allow
+      us to write out the string that is missing the '\0' at it's
+      end. */
+ 
+   snprintf (format_string, sizeof (format_string), format_string_dummy,
+             format_arg1, format_arg2);
+ 
+   fprintf (stdout, format_string, str_arg1, str_arg2);
+ }
+ 
+ 
+ void
+ __VLTRegisterPairDebug (void **data_pointer, void *test_value, int size_hint,
+                         char *base_ptr_var_name, int len1, char *vtable_name,
+                         int len2)
+ {
+   int_vptr vtbl_ptr = (int_vptr) test_value;
+   vtv_set_handle * handle_ptr = (vtv_set_handle *) data_pointer;
+ 
+   if (*handle_ptr == NULL)
+     {
+       /* TODO: verify return value  */
+       vtv_sets::create (size_hint, handle_ptr);
+       vtv_sets::insert (vtbl_ptr, handle_ptr);
+     }
+   else
+     {
+       /* TODO: verify return value? */
+       vtv_sets::resize (size_hint, handle_ptr);
+       vtv_sets::insert (vtbl_ptr, handle_ptr);
+     }
+ 
+ 
+   if (debug_functions && base_ptr_var_name && vtable_name)
+     print_debugging_message ("Registered %%.%ds : %%.%ds\n", len1, len2,
+ 			     base_ptr_var_name, vtable_name);
+   if (debug_register_pairs)
+     {
+       if (log_file_fd == -1)
+ 	log_file_fd = vtv_open_log ("/tmp/vtv_register_pairs.log");
+ 
+       log_register_pairs (log_file_fd, "Registered %%.%ds : %%.%ds (%%p)\n",
+ 			  len1, len2,
+ 			  base_ptr_var_name, vtable_name, vtbl_ptr);
+     }
+ }
+ 
+ void
+ __VLTRegisterPair (void **data_pointer, void *test_value, int size_hint)
+ {
+   int_vptr vtbl_ptr = (int_vptr) test_value;
+   vtv_set_handle * handle_ptr = (vtv_set_handle *) data_pointer;
+ 
+   if (*handle_ptr == NULL)
+     {
+       /* TODO: verify return value */
+       vtv_sets::create (size_hint, handle_ptr);
+       vtv_sets::insert (vtbl_ptr, handle_ptr);
+     }
+   else
+     {
+       /* TODO: verify return value? */
+       vtv_sets::resize (size_hint, handle_ptr);
+       vtv_sets::insert (vtbl_ptr, handle_ptr);
+     }
+ }
+ 
+ void *
+ __VLTVerifyVtablePointerDebug (void ** data_pointer, void * test_value,
+                                char * base_vtbl_var_name, int len1,
+                                char * vtable_name, int len2)
+ {
+   vtv_set_handle * handle_ptr = (vtv_set_handle *) data_pointer;
+   int_vptr vtbl_ptr = (int_vptr) test_value;
+ 
+   if (vtv_sets::contains (vtbl_ptr, handle_ptr))
+     {
+       if (debug_functions)
+ 	fprintf (stdout, "Verified object vtable pointer = %lx\n",
+                  (unsigned long) vtbl_ptr);
+     }
+   else
+     {
+       /* The data structure is not NULL, but we failed to find our
+          object's vtpr in it.  Write out information and call abort.*/
+       if (base_vtbl_var_name && vtable_name)
+ 	print_debugging_message ("Looking for %%.%ds in %%.%ds \n", len2, len1,
+ 				 vtable_name, base_vtbl_var_name);
+       fprintf (stderr, "FAILED to verify object vtable pointer=%lx!!!\n",
+                (unsigned long) vtbl_ptr);
+ 
+ 
+       load_debug_log_message ("Looking for %%.%ds in %%.%ds \n", len2, len1,
+                               vtable_name, base_vtbl_var_name);
+       __vtv_verify_fail_debug (data_pointer, test_value, debug_log_message);
+ 
+       /* Normally __vtv_verify_fail will call abort (eventually), 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.  */
+       fprintf (stderr, "Returned from __vtv_verify_fail."
+                "  Secondary verification succeeded.\n");
+     }
+ 
+   return test_value;
+ }
+ 
+ void *
+ __VLTVerifyVtablePointer (void ** data_pointer, void * test_value)
+ {
+   vtv_set_handle * handle_ptr = (vtv_set_handle *) data_pointer;
+   int_vptr vtbl_ptr = (int_vptr) test_value;
+ 
+   if (!vtv_sets::contains (vtbl_ptr, handle_ptr))
+     {
+       __vtv_verify_fail (data_pointer, test_value);
+       /* Normally __vtv_verify_fail will call abort (eventually), 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.  */
+     }
+ 
+   return test_value;
+ }
+ 
+ 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 ();
+ }
+ 
+ static void
+ vtv_fail (const char *msg, void **data_set_ptr, void *vtbl_ptr)
+ {
+   int fd;
+ 
+   fd = open ("/dev/tty", O_WRONLY);
+   if (fd != -1)
+     {
+       char buffer[120];
+       int buf_len;
+       const char *format_str =
+             "*** Unable to verify vtable pointer (0x%p) in set (0x%p) *** \n";
+ 
+       snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr, *data_set_ptr);
+       buf_len = strlen (buffer);
+       write (fd, buffer, buf_len);
+       close (fd);
+     }
+ 
+   __vtv_really_fail (msg);
+ }
+ 
+ 
+ /* Open error logging file, if not already open, and write vtable
+    verification failure messages to the log file.  */
+ static void
+ log_error_message (const char *log_msg, bool generate_backtrace)
+ {
+   static int fd = -1;
+ 
+   if (fd == -1)
+     fd = vtv_open_log ("/tmp/vtable-verification-failures.log");
+ 
+   if (fd == -1)
+     return;
+ 
+   vtv_add_to_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, fd);
+     }
+ }
+ 
+ 
+ /* This function is called from __VLTVerifyVtablePointerDebug; it
+    sends as much debugging information as it can to the error log
+    file, then calls vtv_fail.  */
+ static void
+ __vtv_verify_fail_debug (void **data_set_ptr, void *vtbl_ptr, char *debug_msg)
+ {
+   const char *fail_msg = "Potential vtable pointer corruption detected!!";
+   char buffer[120];
+   int buf_len;
+   const char *format_str =
+             "*** Unable to verify vtable pointer (0x%p) in set (0x%p) *** \n";
+ 
+   snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr, *data_set_ptr);
+   log_error_message (debug_msg, false);
+   log_error_message (buffer, false);
+   log_error_message ("  Backtrace: \n", true);
+ 
+   vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
+ }
+ 
+ /* Send information about what we were trying to do when verificataion
+    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.*/
+ void
+ __vtv_verify_fail (void **data_set_ptr, void *vtbl_ptr)
+ {
+   const char *fail_msg = "Potential vtable pointer corruption detected!!";
+   char log_msg[1024];
+ 
+   char buffer[120];
+   int buf_len;
+   const char *format_str =
+             "*** Unable to verify vtable pointer (0x%p) in set (0x%p) *** \n";
+ 
+   snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr, *data_set_ptr);
+   snprintf (log_msg, sizeof (log_msg), "Looking for vtable  %p in set %p.\n",
+             vtbl_ptr, *data_set_ptr);
+   log_error_message (log_msg, false);
+   log_error_message (buffer, false);
+   log_error_message ("  Backtrace: \n", true);
+ 
+   vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
+ }

Property changes on: libstdc++-v3/libsupc++/vtv_rts.cc
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_malloc.h
===================================================================
*** libstdc++-v3/libsupc++/vtv_malloc.h	(revision 0)
--- libstdc++-v3/libsupc++/vtv_malloc.h	(revision 0)
***************
*** 0 ****
--- 1,49 ----
+ // 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_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 */

Property changes on: libstdc++-v3/libsupc++/vtv_malloc.h
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_rts.h
===================================================================
*** libstdc++-v3/libsupc++/vtv_rts.h	(revision 0)
--- libstdc++-v3/libsupc++/vtv_rts.h	(revision 0)
***************
*** 0 ****
--- 1,59 ----
+ // 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
+ 
+ /* 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
+ 
+ void
+ __VLTChangePermission (int);
+ 
+ #ifdef VTV_DEBUG
+ 
+ void
+ __VLTRegisterPairDebug (void **, void *, int,
+                         char *, int, char *, int);
+ void *
+ __VLTVerifyVtablePointerDebug (void **, void *,
+ 			       char *, int, char *, int);
+ 
+ #else
+ 
+ void
+ __VLTRegisterPair (void **, void *, int);
+ 
+ void *
+ __VLTVerifyVtablePointer (void **, void *);
+ 
+ #endif
+ 
+ 
+ #endif /* _VTV_RTS_H */

Property changes on: libstdc++-v3/libsupc++/vtv_rts.h
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_fail.h
===================================================================
*** libstdc++-v3/libsupc++/vtv_fail.h	(revision 0)
--- libstdc++-v3/libsupc++/vtv_fail.h	(revision 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, void *vtbl_pointer)
+                                  __attribute__((visibility ("default")));
+ 
+ #endif /* _VTV_FAIL_H */

Property changes on: libstdc++-v3/libsupc++/vtv_fail.h
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_set.h
===================================================================
*** libstdc++-v3/libsupc++/vtv_set.h	(revision 0)
--- libstdc++-v3/libsupc++/vtv_set.h	(revision 0)
***************
*** 0 ****
--- 1,589 ----
+ // 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/>.
+ 
+ //
+ // 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>
+ #include <sstream>
+ 
+ std::string
+ insert_only_hash_tables_stats (void)
+ {
+   std::stringstream s;
+   s << "insert: " << stat_insert << '\n'
+     << "contains: " << stat_contains << '\n'
+     << "resize: " << stat_resize << '\n'
+     << "create: " << stat_create << '\n'
+     << "insert_key_that_was_already_present: "
+     << stat_insert_key_that_was_already_present << '\n'
+     << "contains_sizes: " << stat_contains_sizes << '\n'
+     << "contains_in_non_trivial_set: " << stat_contains_in_non_trivial_set
+     << '\n'
+     << "probes_in_non_trivial_set: " << stat_probes_in_non_trivial_set << '\n'
+     << "contains_size0: " << stat_contains_size0 << '\n'
+     << "contains_size1: " << stat_contains_size1 << '\n'
+     << "contains_size2: " << stat_contains_size2 << '\n'
+     << "contains_size3: " << stat_contains_size3 << '\n'
+     << "contains_size4: " << stat_contains_size4 << '\n'
+     << "contains_size5: " << stat_contains_size5 << '\n'
+     << "contains_size6: " << stat_contains_size6 << '\n'
+     << "contains_size7: " << stat_contains_size7 << '\n'
+     << "contains_size8: " << stat_contains_size8 << '\n'
+     << "contains_size9: " << stat_contains_size9 << '\n'
+     << "contains_size10: " << stat_contains_size10 << '\n'
+     << "contains_size11: " << stat_contains_size11 << '\n'
+     << "contains_size12: " << stat_contains_size12 << '\n'
+     << "contains_size13_or_more: " << stat_contains_size13_or_more << '\n'
+     << "grow_from_size0_to_1: " << stat_grow_from_size0_to_1 << '\n'
+     << "grow_from_size1_to_2: " << stat_grow_from_size1_to_2 << '\n'
+     << "insert_found_hash_collision: " << stat_insert_found_hash_collision
+     << '\n'
+     << "double_the_number_of_buckets: " << stat_double_the_number_of_buckets
+     << '\n';
+   return s.str ();
+ }
+ 
+ #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;
+         }
+       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;
+ }

Property changes on: libstdc++-v3/libsupc++/vtv_set.h
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_stubs.cc
===================================================================
*** libstdc++-v3/libsupc++/vtv_stubs.cc	(revision 0)
--- libstdc++-v3/libsupc++/vtv_stubs.cc	(revision 0)
***************
*** 0 ****
--- 1,88 ----
+ // 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 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
+ __VLTRegisterPairDebug (void ** data_pointer __attribute__((__unused__)),
+                         void * test_value __attribute__((__unused__)),
+                         int size_hint __attribute__((__unused__)),
+                         char * base_ptr_var_name __attribute__((__unused__)),
+                         int len1 __attribute__((__unused__)),
+                         char * vtable_name __attribute__((__unused__)),
+                         int len2 __attribute__((__unused__)))
+ {
+ }
+ 
+ void *
+ __VLTVerifyVtablePointerDebug
+                         (void ** data_pointer __attribute__((__unused__)),
+ 			 void * test_value,
+ 			 char * base_vtbl_var_name __attribute__((__unused__)),
+ 			 int len1 __attribute__((__unused__)),
+ 			 char * vtable_name __attribute__((__unused__)),
+ 			 int len2 __attribute__((__unused__)))
+ 
+ {
+   return test_value;
+ }
+ 
+ #else
+ 
+ void
+ __VLTRegisterPair (void ** data_pointer __attribute__((__unused__)),
+                    void * test_value __attribute__((__unused__)),
+                    int size_hint __attribute__((__unused__)))
+ 
+ {
+ }
+ 
+ void *
+ __VLTVerifyVtablePointer (void ** data_pointer __attribute__((__unused__)),
+                           void * test_value)
+ {
+   return test_value;
+ }
+ 
+ #endif

Property changes on: libstdc++-v3/libsupc++/vtv_stubs.cc
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_utils.cc
===================================================================
*** libstdc++-v3/libsupc++/vtv_utils.cc	(revision 0)
--- libstdc++-v3/libsupc++/vtv_utils.cc	(revision 0)
***************
*** 0 ****
--- 1,78 ----
+ // 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 <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"
+ 
+ int
+ vtv_open_log (const char *name)
+ {
+   int fd = open (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;
+ }
+ 
+ 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;
+ }
+ 
+ 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;
+ }

Property changes on: libstdc++-v3/libsupc++/vtv_utils.cc
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_utils.h
===================================================================
*** libstdc++-v3/libsupc++/vtv_utils.h	(revision 0)
--- libstdc++-v3/libsupc++/vtv_utils.h	(revision 0)
***************
*** 0 ****
--- 1,51 ----
+ // 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>
+ 
+ /* TODO: we need to clean up this. Maybe use __glibcxx_assert */
+ 
+ /* TODO: Define what is the expected behavior of assert and error */
+ /* Handling of runtime error */
+ #define VTV_error abort
+ 
+ #define VTV_ASSERT(EXPR) ((void) (!(EXPR) ? VTV_error() : (void) 0))
+ #define VTV_DEBUG_ASSERT(EXPR) ((void) 0)
+ 
+ /* Name of the section where we put general VTV variables for protection */
+ #define VTV_PROTECTED_VARS_SECTION ".data.rel.ro.vtable_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 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 */

Property changes on: libstdc++-v3/libsupc++/vtv_utils.h
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_init.cc
===================================================================
*** libstdc++-v3/libsupc++/vtv_init.cc	(revision 0)
--- libstdc++-v3/libsupc++/vtv_init.cc	(revision 0)
***************
*** 0 ****
--- 1,111 ----
+ // 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"
+ 
+ /* Set the following macro to 1 to get internal debugging messages */
+ #define VTV_DEBUG 0
+ 
+ #if (VTV_DEBUG == 1)
+ #include <stdio.h>
+ #endif
+ 
+ /* 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)
+ {
+ #if (VTV_DEBUG == 1)
+   fprintf (stderr, "in __VLTunprotect\n");
+ #endif
+ 
+   __VLTChangePermission (__VLTP_READ_WRITE);
+ }
+ 
+ void
+ __VLTprotect (void)
+ {
+ #if (VTV_DEBUG == 1)
+   fprintf (stderr, "in __VLTprotect\n");
+ #endif
+ 
+   __VLTChangePermission (__VLTP_READ_ONLY);
+ }

Property changes on: libstdc++-v3/libsupc++/vtv_init.cc
___________________________________________________________________
Added: svn:eol-style
   + LF

Index: libstdc++-v3/libsupc++/vtv_malloc.cc
===================================================================
*** libstdc++-v3/libsupc++/vtv_malloc.cc	(revision 0)
--- libstdc++-v3/libsupc++/vtv_malloc.cc	(revision 0)
***************
*** 0 ****
--- 1,178 ----
+ // 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 <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"
+ 
+ /* Set the following macro to 1 to get internal debugging messages */
+ #define VTV_DEBUG 0
+ 
+ /* Put the following variables in a rel.ro section so that the 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;
+ 
+ 
+ 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 == 1)
+   VTV_malloc_dump_stats ();
+ #endif
+ }
+ 
+ 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 chunk of memory that is aligned to a page boundary.
+    The amount of memory requested must be a multiple of the page size */
+ static void *
+ obstack_chunk_alloc (size_t size)
+ {
+   /* TODO: Why do we need to support chunk sizes less that page size? */
+   /* Get size to 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. */
+ }
+ 
+ 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);
+ 
+   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;
+ }
+ 
+ void *
+ VTV_malloc (size_t size)
+ {
+   return obstack_alloc (&VTV_obstack, size);
+ }
+ 
+ void
+ VTV_free (void *)
+ {
+   /* Do nothing. We dont care about recovering unneded memory */
+ }
+ 
+ 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);
+ }
+ 
+ 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);
+ }

Property changes on: libstdc++-v3/libsupc++/vtv_malloc.cc
___________________________________________________________________
Added: svn:eol-style
   + LF

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

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

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

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

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

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

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