public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] Vtable pointer verification (corruption/attach detection -- new feature
@ 2012-11-01 20:07 Caroline Tice
  2012-11-05  6:03 ` Xinliang David Li
  2013-01-30 10:09 ` Florian Weimer
  0 siblings, 2 replies; 4+ messages in thread
From: Caroline Tice @ 2012-11-01 20:07 UTC (permalink / raw)
  To: gcc-patches

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

We have been developing a new security hardening feature for GCC that
is designed to detect and handle (during program execution) when a
vtable pointer that is about to be used for a virtual function call is
not a valid vtable pointer for that call (i.e. it has become
corrupted, possibly due to a  hacker attack).  We gave a presentation
on this work at the Gnu Tools Cauldron in Prague last July.  We now
have the implementation fully working and are submitting this patch
for review.  We would like to get this into the next release of GCC if
possible.

The general idea is to collect class hierarchy and vtable pointer data
while parsing the classes, then use this data to generate (at runtime)
sets of valid vtable pointers, one for each class.  We also find every
virtual function call and insert a verification call before the
virtual function call.  The verification call takes the set of valid
vtable pointers for the declared class of the object, and the actual
vtable pointer in the object.  If the vtable pointer in the object is
in the set of valid vtable pointers for the object, then verification
succeeds and the virtual call is allowed.  Otherwise verification
fails and the program aborts.

We have a written a more detailed design document, which I am also
attaching to this email (GCCVtableSecurityHardeningProposal.txt).

The implementation can be divided into roughly two parts:
modifications to the main gcc compiler, for things that happen at
compile time (collecting the class hierarchy & vtable information;
generating the runtime calls to build the data sets from this data;
inserting calls to the verification function); and modifications to
the runtime, i.e. functions that go into libstdc++ for building the
data sets, for doing the verification against the data sets, for
protecting the memory where the data sets reside, etc.).

Please let me know if there is any more information you need, or if
you have any questions about this patch.

-- Caroline Tice
cmtice@google.com

libstdc++/ChangeLog

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

        * src/Makefile.am: Add libvtv___la_LIBDD definition; update CXXLINK
        to search in libvtv___la_LIBADD and to link in libvtv_init.
        * src/Makefile.in: Regenerate.
        * libsupc++/Makefile.am: Add libvtv_init.la and libvtv_stubs.la to
        toolexeclib_LTLIBRARIES.  Add vtv_rts.cc, vtv_malloc.cc and
        vtv_utils.cc to sources.  Define vtv_init_sources and
        vtv_stubs_sources.  Also define libvtv_init_la_SOURCES and
        libvtv_stubs_la_sources.
        * libsupc++/Makefile.in: Regenerate.
        * libsupc++/vtv_rts.cc: New file.
        * libsupc++/vtv_malloc.h: New file.
        * libsupc++/vtv_rts.h: New file.
        * libsupc++/vtv_fail.h: New file.
        * libsupc++/vtv_set.h: New file.
        * libsupc++/vtv_stubs.cc: New file.
        * libsupc++/vtv_utils.cc: New file.
        * libcupc++/vtv_utils.h: New file.
        * libsupc++/vtv_init.cc: New file.
        * libsupc++/vtv_malloc.cc: New file.
        * config/abi/pre/gnu.ver (GLIBCXX_3.4.18): Add vtable verification
        functions and vtable map variables to library export list.

gcc/ChangeLog:

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

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

[-- Attachment #2: GCCVtableSecurityHardeningProposal.txt --]
[-- Type: text/plain, Size: 13129 bytes --]

GCC Vtable Security Hardening Proposal






Problem Description
Solution Constraints
Proposed Solution
General Overview
More Details - Collecting the Data and Accessing the Data Structures
More Details - Building the Data Structures
More Details - Verifying the Virtual Method Dispatches
Security Analysis
Miscellaneous implementation notes
Other



Problem Description


We would like to improve the security of certain programs and ‘harden’ them against some types of security attacks, where by ‘harden’ we mean ‘make it much more difficult for attacks to succeed’ (but not impossible).    The particular types of attacks we are concerned with in this proposal are attacks where the attacker manages to hijack control flow of a program, thereby allowing his or her own malicious code to be executed. In particular, the attacker might overwrite the contents of a function pointer in the program, again making it go someplace other than its original target, and eventually allowing the attacker to gain control of the program.  Programs written in C++ are particularly vulnerable to such attacks, as they contain many function pointers in its vtables.


A common type of attack against some of these programs is to exploit use-after-free (or similar) bugs in the code.  In this case there are objects that get freed but to which there still exist valid pointers in the program, so the program will attempt to use these objects as if they are still valid.  Once the object has been freed, an attacker can cause the same bit of memory to be reallocated, and overwrite the vtable pointer in the object to point to the attacker’s fake vtable.  Then when the object is accessed by the program, it goes and executes the attacker’s code.


The purpose of this document is to describe an approach whereby the compiler can harden programs against such attacks, allowing corruption of vtable pointers in objects to be detected before any attempt to call through the invalid pointer, and for execution to be halted if such a corruption is detected.


Proposed Solution
General Overview


For any given object, the set of legal vtables to which it can point can be derived based on inheritance relationship information that the compiler can collect at compile time.  Therefore we will have the compiler collect this information by building a set of mappings from the base classes to derived classes, and recording all the vtable pointers for all these classes.  At run time these mappings will be compiled into a data structure that indicates, for every potential polymorphic class (where “polymorphic” means a class that needs a virtual table), the complete set of valid vtable pointers that an object declared to be of that class might legally contain.  At each virtual call site we will insert a call to a verification function before we dereference the vtable pointer for the virtual call.  The verification function will take an indicator of the statically declared type of the object and the actual vtable pointer in the object.  It will use the data structure previously mentioned to verify that the vtable pointer in the object is a valid vtable pointer for the declared type.  If verification succeeds, then the virtual method dispatch is allowed to take place.  If verification fails, execution is immediately halted.  This will guarantee that for any virtual dispatch in the program, the vtable being used is for the virtual dispatch is 1).  a valid vtable for the current program; and 2). a member of the set of valid vtables for the call site.


This solution can be divided roughly into three main pieces:
1. Collecting the class hierarchy and vtable pointer data.
2. Building data structures which will be used for verification from the data collected in part 1.
3. Doing the actual verification of vtable pointers using the data structures built in part 2.


Each of these pieces is discussed in more detail below.


Note:  This work is predicated on the fact that the vtables themselves are normally loaded into read-only memory, so attackers cannot modify the vtables directly.  On the other hand, program objects get allocated (and deallocated) in read-write memory, so that is where the vulnerability is.


More Details - Collecting the Data and Accessing the Data Structures


The compiler, while parsing classes, builds up a graph of class hierarchies, for those classes that have vtables (or any of their descendant classes), and also records all the vtable pointers for those classes.


For each class in the graph, the compiler generates a global pointer variable, which we refer to as the vtable map variable for that class.  The vtable map variable for a class will, at run time, be set to point to the data structure containing the set of valid vtable pointers for that class.  When the compiler initially creates these variables, they are set to NULL.


Since these vtable map variables will be used by the verification process to verify that the vtable pointers in objects are valid, it is important that the vtable map variables themselves be safe and not vulnerable to being overwritten by attackers.  For this purpose, when the compiler creates the vtable map variables, it puts them all in a special named section in the object file.  Once the vtable map variables are set to point to the data structures (which happens very early in program start up, before ‘main’), the section containing the vtable map variables is found and set to be read-only (via a call to ‘mprotect’).  Unless a dlopen necessitates a vtable map variable being updated (explained later in this document), vtable map variables remain read-only for the rest of the program execution.


Since multiple source files (and object files) may see the same class definitions, there may be multiple definitions of any particular vtable map variable.  For that reason, vtable map variables are created as COMDAT variables, which tells the linker that it is ok for there to be multiple definitions of the same variable, and the linker just picks one and uses that.


More Details - Building the Data Structures


In order for the compiler to cause the data structures to be built at run time (rather than compile time), which is a requirement because the actual values of the vtable pointers won’t be known until run time,  we use two mechanisms.  First, we wrote a library function (to go into libstdc++), to which we can pass a vtable map variable for a class and a valid vtable pointer for the class.  The library function (called __VLTRegisterPair) then does two things.  First it checks to see if the vtable map variable is still NULL, in which case it creates an empty hash table and sets the vtable map variable to point to it.  Then it puts the vtable pointer into the hash table.  Below is a rough idea of the function:


void
__VLTRegisterPair (void **vtable_map_var, void *vtbl_ptr)
{
        if (*vtable_map_var == NULL)
           *vtable_map_var = init_hash_table ();
        hash_table_insert (*vtable_map_var, vtbl_ptr);
}


The second mechanism we use are constructor init functions.   In each object file, we add a constructor init function for constructing our data structures.  For each class hierarchy graph that the compiler built during the data collection phase, it traverses the graph and inserts a call to __VLTRegisterPair into the constructor init function, passing in the vtable map variable for the class whose set we are building, and the vtable pointer to be inserted in the set of valid pointers for that set.


In order to make sure that the data structure itself is safe from attack we wrote our own memory allocation scheme (based on mmap) so we can keep track of which pages are used for our data structures.  Once our constructor init functions have all run (and before any other constructor init functions have run,) we call another library function we wrote, __VLTChangePermission.  This function uses mprotect to make all the pages containing our data structures readonly.  This is also when/where the vtable map variables are found and set to readonly. 


More Details - Verifying the Virtual Method Dispatches


In order to verify vtable pointers before they are used for virtual method dispatches, we have written a third library function, __VLTVerifyVtablePointer.  This function takes two arguments, a vtable map variable for the statically declared type of the object, and the vtable pointer that is in the object at runtime.  It then looks up the vtable pointer is the data structure pointed to by the vtable map variable (which is supposed to contain the set of all valid vtable pointers for the class or any of its descendants).  If the vtable pointer is found, then it is valid and execution continues; otherwise execution halts.  The code for __VLTVerifyVtablePointer looks roughly like this:


void *
__VLTVerifyVtablePointer (void **vtable_map_var, void *vtbl_ptr)
{
        if (hash_table_find (vtable_map_var, vtbl_ptr))
            return vtbl_ptr;
        else
               {
               __vtv_verify_fail (vtable_map_var, vtbl_ptr);   // By default this calls ‘abort’
                   return vtbl_ptr;                                   // Normally this line will not be reached
               }
}


During the compilation process, when the compiler encounters a virtual method dispatch it first identifies the declared type of the object through which the call is being made.  Then it finds the vtable map variable for that type.  Finally it inserts a call to __VLTVerifyVtablePointer before the virtual method dispatch, and passes in the vtable map variable, and the vptr field from the object.  At runtime, the verification call occurs before the virtual dispatch, and if the vtable pointer has been corrupted the verification will call __vtv_verify_fail, which normally prints an error message and terminates execution.




Miscellaneous implementation notes


This whole mechanism is controlled by a compiler flag, “-fvtable-verify”.  This flag actually comes it two versions “-fvtable-verify=std” and “-fvtable-verify=preinit” (and “-fvtable-verify=none”, to actively turn it off).  The values ‘std’ and ‘preinit’ control when the constructor initialization functions for building our verification data structures get executed.   ‘std’ causes them to get executed in the normal execution order, i.e. after the .so files have been loaded and initialized.  ‘preinit’ causes our constructor initialization functions to be put into the special .preinit_array, which causes them to execute before the .so files get initialized.  


To ensure that our constructor initialization functions run before any ‘regular’ constructor initialization functions when ‘std’ is used, we take advantage of initialization priorities.    Users are allowed to use priorities 101 through 65535.  Priorities 1 through 100 are reserved for the system (including the compiler).  We give our constructor initialization functions the priority 99.  The function that makes our data structures read-write has priority 98, and the one that makes our data structures read-only has the priority 100.


Other


Calls to dlopen.  Any dynamically loaded library that was built with verification will have its own constructor initialization function that will contain calls to update the vtable map data structures.  When  just before the calls to __VLTRegisterPair (to update the data structures), there would be a call to __VLTChangePermission to make the data structures writeable.  As soon as the constructor initialization function is done there would be a call to __VLTChangePermission to make it all readonly again.


There can be problems if there are libraries that are built without verification, and the main program is built with verification (or vice versa), and something on one side of this verification boundary extends a class defined on the other side of the boundary, and passes objects across the boundary.   The best solution, in this case, is for the programmer to write and link in an alternative version of the function __vtv_verify_fail (which gets called from __VLTVerifyVtablePointer when regular verification fails) that can handle these interoperability failures in whatever manner seems best to the programmer (ignore them, do some additional checking, or whatever).  __vtv_verify_fail is declared and written in such a manner as to allow a programmer to statically link in a replacement version.  The arguments that get passed in to this function are the same as those that were passed to __VLTVerifyVtablePointer, i.e. the pointer to the data structure for the statically declared type of the object, and the vtable pointer from the object that needs to be verified.  If execution returns from __vtv_verify_fail, then __VLTVerifyVtablePointer assumes that the secondary verification succeeded, and returns vtbl_pointer to the call site, for use in the virtual method dispatch.

[-- Attachment #3: fsf-vtable-verification.patch --]
[-- Type: application/octet-stream, Size: 178894 bytes --]

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);
+ 
  \f
  /* 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);

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

* Re: [PATCH] Vtable pointer verification (corruption/attach detection -- new feature
  2012-11-01 20:07 [PATCH] Vtable pointer verification (corruption/attach detection -- new feature Caroline Tice
@ 2012-11-05  6:03 ` Xinliang David Li
  2013-01-30 10:09 ` Florian Weimer
  1 sibling, 0 replies; 4+ messages in thread
From: Xinliang David Li @ 2012-11-05  6:03 UTC (permalink / raw)
  To: Caroline Tice; +Cc: GCC Patches

Can you split the patch into two parts? One for runtime and and one
for GCC ? Please also use -up option in the diff command to generate
the patch file.

thanks,

David

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

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

* Re: [PATCH] Vtable pointer verification (corruption/attach detection -- new feature
  2012-11-01 20:07 [PATCH] Vtable pointer verification (corruption/attach detection -- new feature Caroline Tice
  2012-11-05  6:03 ` Xinliang David Li
@ 2013-01-30 10:09 ` Florian Weimer
       [not found]   ` <CABtf2+RvxiBA-b_-a=NEfYH3km7wkSGe=SgeRVyXcOzXTpkgOg@mail.gmail.com>
  1 sibling, 1 reply; 4+ messages in thread
From: Florian Weimer @ 2013-01-30 10:09 UTC (permalink / raw)
  To: Caroline Tice; +Cc: gcc-patches

On 11/01/2012 09:07 PM, Caroline Tice wrote:
> We have been developing a new security hardening feature for GCC that
> is designed to detect and handle (during program execution) when a
> vtable pointer that is about to be used for a virtual function call is
> not a valid vtable pointer for that call (i.e. it has become
> corrupted, possibly due to a  hacker attack).  We gave a presentation
> on this work at the Gnu Tools Cauldron in Prague last July.  We now
> have the implementation fully working and are submitting this patch
> for review.  We would like to get this into the next release of GCC if
> possible.

Thanks for posting this collection of interesting patches.

As far as I understand it, this changes ABI in the sense that every 
object file needs to contain the constructors that register the vtables, 
otherwise verification will later fail.  If this data could be emitted 
in a declarative fashion, it might be possible to emit it by default, in 
a separate ELF section.  This way, it is always there when needed, and 
it wouldn't have any performance impact if not used.

I didn't look at the actual permitted-vtable set lookup in detail.  How 
expensive is it?  C++ virtual method calls are efficient, but they have 
their problems.  The vtable needs relocation (contributing to startup 
cost), and we have the fragile base class problem (which severely 
constrains the evolution of separately-compiled base classes).  Assuming 
that we need the vtable check and it has non-trivial cost, it might make 
sense to revamp C++ virtual method dispatch altogether, addressing both 
security and modularity issues.

(Yes, I understand these two paragraphs go off in entirely different 
directions. 8-)

-- 
Florian Weimer / Red Hat Product Security Team

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

* Re: [PATCH] Vtable pointer verification (corruption/attach detection -- new feature
       [not found]   ` <CABtf2+RvxiBA-b_-a=NEfYH3km7wkSGe=SgeRVyXcOzXTpkgOg@mail.gmail.com>
@ 2013-03-26 11:12     ` Florian Weimer
  0 siblings, 0 replies; 4+ messages in thread
From: Florian Weimer @ 2013-03-26 11:12 UTC (permalink / raw)
  To: Caroline Tice; +Cc: gcc-patches

On 02/01/2013 12:42 AM, Caroline Tice wrote:
>> If this data could be emitted in a
>> declarative fashion, it might be possible to emit it by default, in a
>> separate ELF section.  This way, it is always there when needed, and it
>> wouldn't have any performance impact if not used.
>
> That might be possible; it would need to be carefully organized
> though.  If is not enough to have a list of all vtable addresses; we
> need to know, for each virtual class (where by virtual class I mean a
> class for which a vtable might be generated) the set of vtables that
> is is legal for an object of that class to point to (i.e. for a base
> class, it can point to its own vtable or to the vtable of any of its
> descendants in the inheritance hierarchy).

At present, you emit calls to the __VLTRegisterPair() function to 
implement the registration, correct?  I wonder if it's possible to list 
the arguments to the calls instead (possibly in such a way that no 
relocations are needed).  Initialization for verification mode would 
pick up this data, performing the registration.  Outside verification 
mode, this data would just be ignored (and no ELF constructor needs to 
be executed).

>> C++ virtual method calls are efficient, but they have
>> their problems.  The vtable needs relocation (contributing to startup cost),
>> and we have the fragile base class problem (which severely constrains the
>> evolution of separately-compiled base classes).  Assuming that we need the
>> vtable check and it has non-trivial cost, it might make sense to revamp C++
>> virtual method dispatch altogether, addressing both security and modularity
>> issues.
>
> That might be best, but we don't have the authority to unilaterally
> make a change of this magnitude to the standard. ;-)

This would only affect the cross-vendor C++ ABI, not the standard itself.

-- 
Florian Weimer / Red Hat Product Security Team

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

end of thread, other threads:[~2013-03-26 11:12 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-01 20:07 [PATCH] Vtable pointer verification (corruption/attach detection -- new feature Caroline Tice
2012-11-05  6:03 ` Xinliang David Li
2013-01-30 10:09 ` Florian Weimer
     [not found]   ` <CABtf2+RvxiBA-b_-a=NEfYH3km7wkSGe=SgeRVyXcOzXTpkgOg@mail.gmail.com>
2013-03-26 11:12     ` Florian Weimer

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