public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3)
@ 2013-01-23 22:35 Caroline Tice
  0 siblings, 0 replies; 4+ messages in thread
From: Caroline Tice @ 2013-01-23 22:35 UTC (permalink / raw)
  To: GCC Patches

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

I have made the requested changes to the previous patches I submitted
for the vtable verification feature. As requested, I have broken this
into three patches:  the C++ front end changes, the main gcc changes,
and the runtime library changes.  Here are the C++ front end changes
for the vtable verification feature.

-- Caroline Tice
cmtice@google.com

ChangeLog:

2013-01-23  Caroline Tice  <cmtice@google.com>

	* init.c (build_vtbl_address):  Make function not static (externally
	visible).
	* class.c (finish_struct_1):  Add call to vtv_save_class_info if vtable
	verification is turned on.
	* Make-lang.in: (CXX_AND_OBJCXX_OBJS):  Add vtable-class-hierarchy.o to
	list of object files.
	(vtable-class-hierarchy.o):  Add rule for building object file.
	* g++spec.c (VTABLE_LOAD_MODULE_UNIT): New macro for link option needed
	with vtable verification.
	(lang_specific_driver): Added variable to indicate if vtable
	verification option is used, and which flavor. Process -fvtable-verify
	option, update num_args if option is present, and add appropriate
	driver options if fvtable-verify is present.
	* pt.c (mark_class_instantiated):  Add call to vtv_save_class_info if
	vtable verification is turned on.
	* decl2.c (finish_objects):  Change the return type from void to tree;
	make it return the function decl is is working on.  Make it return
	early if the function is a vtable verification constructor init
	function.
	(cp_write_global_declarations):  If vtable verification is turned on,
	call vtv_recover_class_info and
	vtv_compute_class_hierarchy_transitive_closure before calling
	finalize_compilation_unit.  Call vtv_generate_init_routine after.
	(vtv_start_verification_constructor_init_function): New externally
	visible wrapper function to call start_objects for vtable verification.
	(vtv_finish_verification_constructor_init_functin):  New externally
	visible wrapper function to call finish_objects for vtable
	verification.
	* config-lang.in: Add vtable-class-hierarchy.c to the list of files
	that use GCC's garbage collector.
	* vtable-class-hierarchy.c:  New file, containing the bulk of vtable
	verification's front-end work.
	* mangle.c (get_mangled_id): Make the function not static (externally
	visible).
	* cp-tree.h: Add extern function declaratins for
	vtv_start_verification_constructor_init_function,
	vtv_finish_verification_constructor_init_function, build_vtbl_address,
	vtv_compute_class_hierarchy_transitive_closure,
	vtv_generate_init_routine, vtv_save_class_info,
	vtv_recover_class_info and get_mangled_id.

[-- Attachment #2: fsf-vtable-verification.v4.c++front-end.patch --]
[-- Type: application/octet-stream, Size: 64224 bytes --]

Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c	(revision 195313)
+++ gcc/cp/init.c	(working copy)
@@ -43,7 +43,6 @@ static tree initializing_context (tree);
 static void expand_cleanup_for_base (tree, tree);
 static tree dfs_initialize_vtbl_ptrs (tree, void *);
 static tree build_field_list (tree, tree, int *);
-static tree build_vtbl_address (tree);
 static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
 
 /* We are about to generate some complex initialization code.
@@ -1105,7 +1104,7 @@ emit_mem_initializers (tree mem_inits)
 /* Returns the address of the vtable (i.e., the value that should be
    assigned to the vptr) for BINFO.  */
 
-static tree
+tree
 build_vtbl_address (tree binfo)
 {
   tree binfo_for = binfo;
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 195313)
+++ gcc/cp/class.c	(working copy)
@@ -6381,6 +6381,9 @@ finish_struct_1 (tree t)
 
   maybe_suppress_debug_info (t);
 
+  if (flag_vtable_verify)
+    vtv_save_class_info (t);
+
   dump_class_hierarchy (t);
 
   /* Finish debugging output for this type.  */
Index: gcc/cp/Make-lang.in
===================================================================
--- gcc/cp/Make-lang.in	(revision 195313)
+++ gcc/cp/Make-lang.in	(working copy)
@@ -80,7 +80,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.
  cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
  cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
  cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
 
 # Language-specific object files for C++.
 CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -338,7 +338,12 @@ cp/parser.o: cp/parser.c $(CXX_TREE_H) $
   c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H)
 cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \
 	$(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H)
-
+cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \
+  $(TM_H) $(TIMEVAR_H) $(CXX_TREE_H) intl.h $(CXX_PARSER_H) cp/decl.h \
+  $(FLAGS_H) $(DIAGNOSTIC_CORE_H) output.h $(CGRAPH_H) c-family/c-common.h \
+  c-family/c-objc.h $(PLUGIN_H) \
+  tree-iterator.h tree-vtable-verify.h $(GIMPLE_H) \
+  gt-cp-vtable-class-hierarchy.h
 cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
 	$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h $(PARAMS_H) \
 	$(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
Index: gcc/cp/g++spec.c
===================================================================
--- gcc/cp/g++spec.c	(revision 195313)
+++ gcc/cp/g++spec.c	(working copy)
@@ -50,6 +50,11 @@ along with GCC; see the file COPYING3.  
 #define LIBSTDCXX_STATIC NULL
 #endif
 
+/* Link command for linking in libvtv_inint when doing 'std' vtable
+   verification.  */
+
+#define VTABLE_LOAD_MODULE_INIT "--whole-archive,-lvtv_init,--no-whole-archive"
+
 void
 lang_specific_driver (struct cl_decoded_option **in_decoded_options,
 		      unsigned int *in_decoded_options_count,
@@ -111,6 +116,11 @@ lang_specific_driver (struct cl_decoded_
   /* The total number of arguments with the new stuff.  */
   unsigned int num_args = 1;
 
+  /* The command line contains a -fvtable_verify. We need to add the
+     init library if we are linking and if we are adding the stdc++
+     library.  */
+  int saw_vtable_verify = 0;
+
   argc = *in_decoded_options_count;
   decoded_options = *in_decoded_options;
   added_libraries = *in_added_libraries;
@@ -236,6 +246,14 @@ lang_specific_driver (struct cl_decoded_
 	      }
 	  }
 	  break;
+
+        case OPT_fvtable_verify_:
+          if (strcmp (arg, "std") == 0)
+            saw_vtable_verify = 1;
+          else if (strcmp (arg, "preinit") == 0)
+            saw_vtable_verify = 2;
+          break;
+
 	}
     }
 
@@ -247,6 +265,12 @@ lang_specific_driver (struct cl_decoded_
 
   /* Add one for shared_libgcc or extra static library.  */
   num_args = argc + added + need_math + (library > 0) * 4 + 1;
+
+  /* Add two more linker args, '-Wl,-u_vtable_map_vars_start and
+     '-Wl,-u_vtable_map_vars_end.  */
+  if (saw_vtable_verify)
+    num_args += 2;
+
   new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);
 
   i = 0;
@@ -309,6 +333,33 @@ lang_specific_driver (struct cl_decoded_
       j++;
     }
 
+  /* Add option to make sure that if we are doing 'std' vtable
+     verification then we link with the libvtv_init library.  */
+
+  if (saw_vtable_verify == 1 && library > 0)
+    {
+      generate_option(OPT_Wl_, VTABLE_LOAD_MODULE_INIT, 1,
+                      CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+    }
+
+  /* If we are doing vtable verification, make sure the linker does
+     not garbage-collect the special symbols that mark the start and
+     end of the ".vtable_map_vars" section in the binary.  (See
+     comments in vtv_start.c and vtv_end.c for more details).  */
+
+  if (saw_vtable_verify > 0)
+    {
+      generate_option (OPT_Wl_,"-u_vtable_map_vars_start", 1,
+                       CL_DRIVER, &new_decoded_options[j]);
+      j++;
+
+      generate_option (OPT_Wl_,"-u_vtable_map_vars_end", 1,
+                       CL_DRIVER, &new_decoded_options[j]);
+      j++;
+    }
+
   /* Add `-lstdc++' if we haven't already done so.  */
   if (library > 0)
     {
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c	(revision 195313)
+++ gcc/cp/pt.c	(working copy)
@@ -17954,6 +17954,10 @@ mark_class_instantiated (tree t, int ext
   if (! extern_p)
     {
       CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+
+      if (flag_vtable_verify)
+        vtv_save_class_info (t);
+
       rest_of_type_compilation (t, 1);
     }
 }
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c	(revision 195313)
+++ gcc/cp/decl2.c	(working copy)
@@ -68,7 +68,7 @@ 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 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);
@@ -3000,7 +3000,8 @@ generate_tls_wrapper (tree fn)
 }
 
 /* Start the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+   or destructors.  Subroutine of do_[cd]tors.  Also called from
+   vtv_start_verification_constructor_init_function.  */
 
 static tree
 start_objects (int method_type, int initp)
@@ -3053,9 +3054,13 @@ start_objects (int method_type, int init
 }
 
 /* Finish the process of running a particular set of global constructors
-   or destructors.  Subroutine of do_[cd]tors.  */
+   or destructors.  Subroutine of do_[cd]tors.  Also called from
+   vtv_finish_verification_constructor_init_function.
 
-static void
+   This function returns a tree containing the function decl for the function
+   it finished creating.  */
+
+static tree
 finish_objects (int method_type, int initp, tree body)
 {
   tree fn;
@@ -3068,6 +3073,10 @@ finish_objects (int method_type, int ini
     {
       DECL_STATIC_CONSTRUCTOR (fn) = 1;
       decl_init_priority_insert (fn, initp);
+
+      if (flag_vtable_verify
+          && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
+        return fn;
     }
   else
     {
@@ -3076,6 +3085,7 @@ finish_objects (int method_type, int ini
     }
 
   expand_or_defer_fn (fn);
+  return fn;
 }
 
 /* The names of the parameters to the function created to handle
@@ -4315,8 +4325,22 @@ cp_write_global_declarations (void)
   timevar_stop (TV_PHASE_DEFERRED);
   timevar_start (TV_PHASE_OPT_GEN);
 
+  if (flag_vtable_verify)
+    {
+      vtv_recover_class_info ();
+      vtv_compute_class_hierarchy_transitive_closure ();
+    }
+
   finalize_compilation_unit ();
 
+  if (flag_vtable_verify)
+    {
+      /* Generate the special constructor initialization function that
+         calls __VLTRegisterPairs, and give it a very high initialization
+         priority.  */
+      vtv_generate_init_routine ();
+    }
+
   timevar_stop (TV_PHASE_OPT_GEN);
   timevar_start (TV_PHASE_CHECK_DBGINFO);
 
@@ -4687,4 +4711,16 @@ mark_used (tree decl)
   return true;
 }
 
+tree
+vtv_start_verification_constructor_init_function (void)
+{
+  return start_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1);
+}
+
+tree
+vtv_finish_verification_constructor_init_function (tree function_body)
+{
+  return finish_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1, function_body);
+}
+
 #include "gt-cp-decl2.h"
Index: gcc/cp/config-lang.in
===================================================================
--- gcc/cp/config-lang.in	(revision 195313)
+++ gcc/cp/config-lang.in	(working copy)
@@ -29,4 +29,4 @@ compilers="cc1plus\$(exeext)"
 
 target_libs="target-libstdc++-v3"
 
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c"
Index: gcc/cp/vtable-class-hierarchy.c
===================================================================
--- gcc/cp/vtable-class-hierarchy.c	(revision 0)
+++ gcc/cp/vtable-class-hierarchy.c	(revision 0)
@@ -0,0 +1,1257 @@
+/* Copyright (C) 2012  Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
+   before using them for virtual method dispatches.  */
+
+/* This file is part of the vtable security feature implementation.
+   The vtable security feature is designed to detect when a virtual
+   call is about to be made through an invalid vtable pointer
+   (possibly due to data corruption or malicious attacks). The
+   compiler finds every virtual call, and inserts a verification call
+   before the virtual call.  The verification call takes the actual
+   vtable pointer value in the object through which the virtual call
+   is being made, and compares the vtable pointer against a set of all
+   valid vtable pointers that the object could contain (this set is
+   based on the declared type of the object).  If the pointer is in
+   the valid set, execution is allowed to continue; otherwise the
+   program is halted.
+
+  There are several pieces needed in order to make this work: 1. For
+  every virtual class in the program (i.e. a class that contains
+  virtual methods), we need to build the set of all possible valid
+  vtables that an object of that class could point to.  This includes
+  vtables for any class(es) that inherit from the class under
+  consideration.  2. For every such data set we build up, we need a
+  way to find and reference the data set.  This is complicated by the
+  fact that the real vtable addresses are not known until runtime,
+  when the program is loaded into memory, but we need to reference the
+  sets at compile time when we are inserting verification calls into
+  the program.  3.  We need to find every virtual call in the program,
+  and insert the verification call (with the appropriate arguments)
+  before the virtual call.  4. We need some runtime library pieces:
+  the code to build up the data sets at runtime; the code to actually
+  perform the verification using the data sets; and some code to set
+  protections on the data sets, so they themselves do not become
+  hacker targets.
+
+  To find and reference the set of valid vtable pointers for any given
+  virtual class, we create a special global varible for each virtual
+  class.  We refer to this as the "vtable map variable" for that
+  class.  The vtable map variable has the type "void *", and is
+  initialized by the compiler to NULL.  At runtime when the set of
+  valid vtable pointers for a virtual class, e.g. class Foo, is built,
+  the vtable map variable for class Foo is made to point to the set.
+  During compile time, when the compiler is inserting verification
+  calls into the program, it passes the vtable map variable for the
+  appropriate class to the verification call, so that at runtime the
+  verification call can find the appropriate data set.
+
+  The actual set of valid vtable pointers for a virtual class,
+  e.g. class Foo, cannot be built until runtime, when the vtables get
+  loaded into memory and their addresses are known.  But the knowledge
+  about which vtables belong in which class' hierarchy is only known
+  at compile time.  Therefore at compile time we collect class
+  hierarchy and vtable information about every virtual class, and we
+  generate calls to build up the data sets at runtime.  To build the
+  data sets, we call one of the functions we add to the runtime
+  library, __VLTRegisterPair.  __VLTRegisterPair takes two arguments,
+  a vtable map variable and the address of a vtable.  If the vtable
+  map variable is currently NULL, it creates a new data set (hash
+  table), makes the vtable map variable point to the new data set, and
+  inserts the vtable address into the data set.  If the vtable map
+  variable is not NULL, it just inserts the vtable address into the
+  data set.  In order to make sure that our data sets are built before
+  any verification calls happen, we create a special constructor
+  initialization function for each compilation unit, give it a very
+  high initialization priority, and insert all of our calls to
+  __VLTRegisterPair into our special constructor initialization
+  function.
+
+  The vtable verification feature is controlled by the flag
+  '-fvtable-verify='.  There are three flavors of this:
+  '-fvtable-verify=std', '-fvtable-verify=preinit', and
+  '-fvtable-verify=none'.  If the option '-fvtable-verfy=preinit' is
+  used, then our constructor initialization function gets put into the
+  preinit array.  This is necessary if there are data sets that need
+  to be built very early in execution.  If the constructor
+  initialization function gets put into the preinit array, the we also
+  add calls to __VLTChangePermission at the beginning and end of the
+  function.  The call at the beginning sets the permissions on the
+  data sets and vtable map variables to read/write, and the one at the
+  end makes them read-only.  If the '-fvtable-verify=std' option is
+  used, the constructor initialization functions are executed at their
+  normal time, and the __VLTChangePermission calls are handled
+  differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
+  The option '-fvtable-verify=none' turns off vtable verification.
+
+  This file contains code to find and record the class hierarchies for
+  the virtual classes in a program, and all the vtables associated
+  with each such class; to generate the vtable map variables; and to
+  generate the constructor initialization function (with the calls to
+  __VLTRegisterPair, and __VLTChangePermission).  The main data
+  structures used for collecting the class hierarchy data and
+  building/maintaining the vtable map variable data are defined in
+  gcc/tree-vtable-verify.h, because they are used both here and in
+  gcc/tree-vtable-verify.c.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "intl.h"
+#include "c-family/c-pragma.h"
+#include "decl.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+#include "output.h"
+#include "target.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "tree-iterator.h"
+#include "tree-vtable-verify.h"
+#include "gimple.h"
+
+/* Mark these specially since they need to be stored in precompiled
+   header IR.  */
+static GTY (()) tree vlt_saved_class_info = NULL_TREE;
+static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
+static GTY (()) tree vlt_init_set_symbol_fndecl = NULL_TREE;
+static GTY (()) tree vlt_change_permission_fndecl = NULL_TREE;
+
+struct work_node {
+  struct vtv_graph_node *node;
+  struct work_node *next;
+};
+
+struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
+
+/* As part of vtable verification the compiler generates and inserts calls
+   to __VLTRegisterPair and __VLTChangePermission, which are in libsupc++.
+   This function builds and initializes the function decls that are used
+   in generating those function calls.
+
+   In addition to __VLTRegisterPair there is also __VLTRegisterPairDebug
+   which can be used in place of __VLTRegisterPair, and which takes extra
+   parameters and outputs extra information, to help debug problems.  The
+   debug version of this function is generated and used if vtv_debug is true.
+
+   The signatures for these functions are:
+
+   void __VLTChangePermission (int);
+   void __VLTRegisterPair (void **, void*, int);
+   void __VLTRegisterPairDebug (void**, void *, int, char *, int, char *, int);
+*/
+
+static void
+init_functions (void)
+{
+  tree void_ptr_type = build_pointer_type (void_type_node);
+  tree arg_types = NULL_TREE;
+  tree change_permission_type = void_type_node;
+  tree register_pairs_type = void_type_node;
+  tree init_set_symbol_type = void_type_node;
+  tree const_char_ptr_type = build_pointer_type (build_qualified_type
+                                                           (char_type_node,
+                                                            TYPE_QUAL_CONST));
+
+  if (vlt_change_permission_fndecl != NULL_TREE)
+    return;
+
+  gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
+
+  arg_types = build_tree_list (NULL_TREE, integer_type_node);
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  change_permission_type = build_function_type (change_permission_type,
+                                                arg_types);
+  vlt_change_permission_fndecl = build_fn_decl ("__VLTChangePermission",
+                                                change_permission_type);
+  TREE_NOTHROW (vlt_change_permission_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_change_permission_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_change_permission_fndecl));
+  TREE_PUBLIC (vlt_change_permission_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_change_permission_fndecl) = 1;
+  retrofit_lang_decl (vlt_change_permission_fndecl);
+  SET_DECL_LANGUAGE (vlt_change_permission_fndecl, lang_cplusplus);
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   const_ptr_type_node));
+
+  if (vtv_debug)
+    {
+      /* Start: Arg types that only go into the debug version of the
+         function.  */
+      arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                       const_char_ptr_type));
+      arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                       const_char_ptr_type));
+      /* End: Arg types for debugging.  */
+    }
+
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  register_pairs_type = build_function_type (register_pairs_type, arg_types);
+
+  if (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);
+
+  TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
+  TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
+  retrofit_lang_decl (vlt_register_pairs_fndecl);
+  SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
+
+  arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   const_ptr_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+                                                   size_type_node));
+  arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+  init_set_symbol_type = build_function_type (init_set_symbol_type, arg_types);
+
+  if (vtv_debug)
+    vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbolDebug",
+                                                init_set_symbol_type);
+  else
+    vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbol",
+                                                init_set_symbol_type);
+
+  TREE_NOTHROW (vlt_init_set_symbol_fndecl) = 1;
+  DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl) =
+                    tree_cons (get_identifier ("leaf"), NULL,
+                               DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl));
+  TREE_PUBLIC (vlt_init_set_symbol_fndecl) = 1;
+  DECL_PRESERVE_P (vlt_init_set_symbol_fndecl) = 1;
+  retrofit_lang_decl (vlt_init_set_symbol_fndecl);
+  SET_DECL_LANGUAGE (vlt_init_set_symbol_fndecl, lang_cplusplus);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It adds a
+   vtv_graph_node to the WORKLIST, which is a linked list of
+   seen-but-not-yet-processed nodes.  INSERTED is a bitmap, one bit
+   per node, to help make sure that we don't insert a node into the
+   worklist more than once.  Each node represents a class somewhere in
+   our class hierarchy information. Every node in the graph gets added
+   to the worklist exactly once and removed from the worklist exactly
+   once (when all of its children have been processed).  */
+
+static void
+add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
+                 sbitmap inserted)
+{
+  struct work_node *new_work_node;
+
+  if (bitmap_bit_p (inserted, node->class_uid))
+    return;
+
+  new_work_node = XNEW (struct work_node);
+  new_work_node->next = *worklist;
+  new_work_node->node = node;
+  *worklist = new_work_node;
+
+  bitmap_set_bit (inserted, node->class_uid);
+}
+
+/* This is a helper function for
+   vtv_compute_class_hierarchy_transitive_closure.  It goes through
+   the WORKLIST of class hierarchy nodes looking for a "leaf" node,
+   i.e. a node whose children in the hierarchy have all been
+   processed.  When it finds the next leaf node, it removes it from
+   the linked list (WORKLIST) and returns the node.  */
+
+static struct vtv_graph_node *
+find_and_remove_next_leaf_node (struct work_node **worklist)
+{
+  struct work_node *prev, *cur;
+
+  for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+    {
+      if (cur->node->num_children == cur->node->num_processed_children)
+        {
+          if (prev == NULL)
+            (*worklist) = cur->next;
+          else
+            prev->next = cur->next;
+
+          cur->next = NULL;
+          return cur->node;
+        }
+    }
+
+  return NULL;
+}
+
+/* In our class hierarchy graph, each class node contains a bitmap,
+   with one bit for each class in the hierarchy.  The bits are set for
+   classes that are descendants in the graph of the current node.
+   Initially the descendants bitmap is only set for immediate
+   descendants.  This function traverses the class hierarchy graph,
+   bottom up, filling in the transitive closures for the descendants
+   as we rise up the graph.  */
+
+void
+vtv_compute_class_hierarchy_transitive_closure (void)
+{
+  struct work_node *worklist = NULL;
+  struct vtbl_map_node *cur;
+  sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+  unsigned i;
+
+  /* Note: Every node in the graph gets added to the worklist exactly
+   once and removed from the worklist exactly once (when all of its
+   children have been processed).  Each node's children edges are
+   followed exactly once, and each node's parent edges are followed
+   exactly once.  So this algorithm is roughly O(V + 2E), i.e.
+   O(E + V).  */
+
+  /* Set-up:                                                                */
+  /* Find all the "leaf" nodes in the graph, and add them to the worklist.  */
+  bitmap_clear (inserted);
+  for (cur = vtbl_map_nodes; cur; cur = cur->next)
+    {
+      if (cur->class_info
+          && (cur->class_info->num_children == 0)
+          && ! (bitmap_bit_p (inserted, cur->class_info->class_uid)))
+        add_to_worklist (&worklist, cur->class_info, inserted);
+    }
+
+  /* Main work: pull next leaf node off work list, process it, add its
+     parents to the worklist, where a 'leaf' node is one that has no
+     children, or all of its children have been processed.  */
+  while (worklist)
+    {
+      struct vtv_graph_node *temp_node =
+                                  find_and_remove_next_leaf_node (&worklist);
+
+      gcc_assert (temp_node != NULL);
+      temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
+      bitmap_clear (temp_node->descendants);
+      bitmap_set_bit (temp_node->descendants, temp_node->class_uid);
+      for (i = 0; i < temp_node->num_children; ++i)
+        bitmap_ior (temp_node->descendants, temp_node->descendants,
+                        temp_node->children[i]->descendants);
+      for (i = 0; i < temp_node->num_parents; ++i)
+        {
+          temp_node->parents[i]->num_processed_children =
+                    temp_node->parents[i]->num_processed_children + 1;
+          if (!bitmap_bit_p (inserted, temp_node->parents[i]->class_uid))
+            add_to_worklist (&worklist, temp_node->parents[i], inserted);
+        }
+    }
+}
+
+/* Keep track of which pairs we have already created __VLTRegisterPair
+   calls for, to prevent creating duplicate calls within the same
+   compilation unit.  VTABLE_DECL is the var decl for the vtable of
+   the (descendant) class that we are adding to our class hierarchy
+   data.  VPTR_ADDRESS is and expression for calculating the correct
+   offset into the vtable (VTABLE_DECL).  It is the actual vtable
+   pointer address that will be stored in our list of valid vtable
+   pointers for BASE_CLASS.  BASE_CLASS is the record_type node for
+   the base class to whose hiearchy we want to add
+   VPTR_ADDRESS. (VTABLE_DECL should be the vtable for BASE_CLASS or
+   one of BASE_CLASS' descendents.  */
+
+static bool
+record_register_pairs (tree vtable_decl, tree vptr_address,
+                       tree base_class)
+{
+  unsigned offset;
+  tree base_id;
+  struct vtbl_map_node *base_vtable_map_node;
+  tree class_type_decl;
+  tree type_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  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))
+    class_type_decl = TREE_CHAIN (base_class);
+  else
+    class_type_decl = TYPE_NAME (base_class);
+
+  /* Temporarily remove any qualifiers on type.  */
+  type_decl_type = TREE_TYPE (class_type_decl);
+  save_quals = TYPE_QUALS (type_decl_type);
+  reset_type_qualifiers (null_quals, type_decl_type);
+
+  base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
+  base_vtable_map_node = vtbl_map_get_node (base_id);
+
+  /* Restore any type qualifiers.  */
+  reset_type_qualifiers (save_quals, type_decl_type);
+
+  if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
+                                       offset))
+    return true;
+
+  vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
+				     offset);
+  return false;
+}
+
+/* A class may contain secondary vtables in it, for various reasons.
+   This function goes through the decl chain of a class record looking
+   for any fields that point to secondary vtables, and adding calls to
+   __VLTRegisterPair for the secondary vtable pointers.
+
+   BASE_CLASS_DECL_ARG is an expression for the address of the vtable
+   map variable for the BASE_CLASS (whose hierarchy we are currently
+   updating).  BASE_CLASS is the record_type node for the base class.
+   RECORD_TYPE is the record_type node for the descendant class that
+   we are possibly adding to BASE_CLASS's hierarchy.  BODY is the
+   function body for the constructor init function to which we are
+   adding our calls to __VLTRegisterPair.  */
+
+static void
+register_vptr_fields (tree base_class_decl_arg, tree base_class,
+                      tree record_type, tree body)
+{
+  tree vtbl_var_decl;
+  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;
+
+      /* Check to see if we have found a constructor vtable.  Add its
+         data if appropriate.  */
+      if (ztt_decl != NULL_TREE && (DECL_NAME (ztt_decl))
+          && (strncmp (IDENTIFIER_POINTER (DECL_NAME (ztt_decl)),
+                       "_ZTT", 4) == 0))
+        {
+          tree values = DECL_INITIAL (ztt_decl);
+          struct varpool_node *vp_node = varpool_node_for_decl (ztt_decl);
+          if (vp_node->finalized
+              && TREE_ASM_WRITTEN (ztt_decl)
+              && values != NULL_TREE
+              && TREE_CODE (values) == CONSTRUCTOR
+              && TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE)
+            {
+              tree call_expr = NULL_TREE;
+              unsigned HOST_WIDE_INT cnt;
+              constructor_elt *ce;
+
+              /* Loop through the initialization values for this vtable to
+                 get all the correct vtable pointer addresses that we need
+                 to add to our set of valid vtable pointers for the current
+                 base class.  */
+
+              for (cnt = 0;
+                   vec_safe_iterate (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 + 1,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME
+						 (TREE_OPERAND
+						  (base_class_decl_arg, 0))));
+                  arg2 = build_string_literal (len2 + 1,
+                                               IDENTIFIER_POINTER
+					        (DECL_NAME (val_vtbl_decl)));
+
+                  /* Check to see if we already have this vtable pointer in
+                     our valid set for this base class.  */
+
+                  already_registered = record_register_pairs (val_vtbl_decl,
+                                                              value,
+                                                              base_class);
+
+                  if (already_registered)
+                    continue;
+
+                  /* Generate the call to __VLTRegisterPair to add this
+                     vtable pointer to our set of valid pointers for the
+                     base class.  */
+
+                  if (vtv_debug)
+                    {
+                      call_expr = build_call_expr
+		                        (vlt_register_pairs_fndecl, 5,
+					 base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint),
+					 arg1, arg2);
+                    }
+                  else
+                    {
+                        call_expr = build_call_expr
+                                        (vlt_register_pairs_fndecl, 3,
+                                         base_class_decl_arg, value,
+                                         build_int_cst (integer_type_node,
+                                                        hint));
+                    }
+		  append_to_statement_list (call_expr, &body);
+                }
+            }
+        }
+    }
+}
+
+/* This function iterates through all the vtables it can find from the
+   BINFO of a class, to make sure we have found ALL of the vtables
+   that an object of that class could point to.  Generate calls to
+   __VLTRegisterPair for those vtable pointers that we find.
+
+   BINFO is the tree_binfo node for the BASE_CLASS.  BODY is the
+   function body for the constructor init function to which we are
+   adding calls to __VLTRegisterPair.  ARG1 is an expression for the
+   address of the vtable map variable (for the BASE_CLASS), that will
+   point to the updated data set.  BASE_CLASS is the record_type node
+   for the base class whose set of valid vtable pointers we are
+   updating. STR1 and STR2 are all debugging information, to be passed
+   as parameters to __VLTRegisterPairDebug.  STR1 represents the name
+   of the vtable map variable to be updated by the call.  Similarly,
+   STR2 represents the name of the class whose vtable pointer is being
+   added to the hierarchy.  */
+
+static void
+register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
+                              tree str2, tree base_class)
+{
+  unsigned ix;
+  tree base_binfo;
+  tree vtable_decl;
+  bool already_registered;
+
+  if (binfo == NULL_TREE)
+    return;
+
+  for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+    {
+      if ((!BINFO_PRIMARY_P (base_binfo)
+           || BINFO_VIRTUAL_P (base_binfo))
+          && (vtable_decl = get_vtbl_decl_for_binfo (base_binfo))
+          && !(DECL_VTABLE_OR_VTT_P (vtable_decl)
+               && DECL_CONSTRUCTION_VTABLE_P (vtable_decl)))
+        {
+          tree vtable_address = build_vtbl_address (base_binfo);
+          tree call_expr;
+
+          already_registered = record_register_pairs (vtable_decl,
+                                                      vtable_address,
+                                                      base_class);
+          if (!already_registered)
+            {
+              if (vtv_debug)
+                call_expr = build_call_expr (vlt_register_pairs_fndecl, 4,
+                                             arg1, vtable_address,
+                                             str1, str2);
+              else
+                call_expr = build_call_expr (vlt_register_pairs_fndecl, 2,
+                                             arg1, vtable_address);
+
+              append_to_statement_list (call_expr, &body);
+            }
+        }
+
+      register_other_binfo_vtables (base_binfo, body, arg1, str1, str2,
+                                    base_class);
+    }
+}
+
+/* The set of valid vtable pointers for any given class are stored in
+   a hash table.  For reasons of efficiency, that hash table size is
+   always a power of two.  In order to try to prevent re-sizing the
+   hash tables very often, we pass __VLTRegisterPair an initial guess
+   as to the number of entries the hashtable will eventually need
+   (rounded up to the nearest power of two).  This function takes the
+   class information we have collected for a particular class,
+   CLASS_NODE, and calculates the hash table size guess.  */
+
+static int
+guess_num_vtable_pointers (struct vtv_graph_node *class_node)
+{
+  tree vtbl;
+  int total_num_vtbls = 0;
+  int num_vtbls_power_of_two = 1;
+  unsigned i;
+
+  for (i = 0; i < num_vtable_map_nodes; ++i)
+    if (bitmap_bit_p (class_node->descendants, i))
+      {
+        tree class_type = vtbl_map_nodes_vec[i]->class_info->class_type;
+        for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
+             vtbl = DECL_CHAIN (vtbl))
+          {
+            total_num_vtbls++;
+            if (total_num_vtbls > num_vtbls_power_of_two)
+              num_vtbls_power_of_two <<= 1;
+          }
+      }
+  return num_vtbls_power_of_two;
+}
+
+/* This function goes through our internal class hierarchy & vtable
+   pointer data structure and outputs calls to __VLTRegisterPair for
+   every class-vptr pair (for those classes whose vtable would be
+   output in the current compilation unit).  These calls get put into
+   our constructor initialization function.  BODY is the function
+   body, so far, of our constructor initialization function, to which we
+   add the calls.  */
+
+static bool
+register_all_pairs (tree body)
+{
+  struct vtbl_map_node *current;
+  bool registered_at_least_one = false;
+
+  for (current = vtbl_map_nodes; current; current = current->next)
+    {
+      unsigned i;
+      tree base_class = current->class_info->class_type;
+      tree base_ptr_var_decl = current->vtbl_map_decl;
+
+      gcc_assert (current->class_info != NULL);
+
+      tree str1 = NULL_TREE;
+
+      if (vtv_debug)
+        str1 = build_string_literal
+                        (IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl)) + 1,
+                         IDENTIFIER_POINTER (DECL_NAME (base_ptr_var_decl)));
+
+      for (i = 0; i < num_vtable_map_nodes; ++i)
+        if (bitmap_bit_p (current->class_info->descendants, i))
+          {
+            struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_vec[i];
+            tree class_type = vtbl_class_node->class_info->class_type;
+
+            if (class_type
+                && (TREE_CODE (class_type) == RECORD_TYPE))
+            {
+              tree new_type;
+              tree arg1;
+              tree call_expr;
+              bool already_registered;
+
+              tree binfo = TYPE_BINFO (class_type);
+              tree vtable_decl;
+              bool vtable_should_be_output = false;
+
+              vtable_decl = CLASSTYPE_VTABLES (class_type);
+
+              /* Handle main vtable for this class.  */
+
+              if (vtable_decl)
+                vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
+
+              if (vtable_decl && vtable_should_be_output
+                  && BINFO_VTABLE (binfo))
+                {
+                  tree vtable_address = build_vtbl_address (binfo);
+
+                  already_registered = record_register_pairs (vtable_decl,
+                                                              vtable_address,
+                                                              base_class);
+
+                  if (!already_registered)
+                    {
+                      int len2  = IDENTIFIER_LENGTH (DECL_NAME (vtable_decl));
+                      tree str2 = build_string_literal
+                                                   (len2 + 1,
+                                                    IDENTIFIER_POINTER
+                                                    (DECL_NAME (vtable_decl)));
+
+                      new_type = build_pointer_type (TREE_TYPE
+                                                     (base_ptr_var_decl));
+                      arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+                      if (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,
+                                                     4, arg1, vtable_address,
+                                                     str1, str2);
+                      else
+                        call_expr = build_call_expr (vlt_register_pairs_fndecl,
+                                                     2, arg1, vtable_address);
+
+                      append_to_statement_list (call_expr, &body);
+
+                      registered_at_least_one = true;
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via virtual inheritance.   */
+                      register_vptr_fields (arg1, base_class, class_type,
+                                            body);
+
+                      /* Find and handle any 'extra' vtables associated
+                         with this class, via multiple inheritance.   */
+                      register_other_binfo_vtables (binfo, body, arg1, str1,
+                                                    str2, base_class);
+                    }
+                }
+            }
+          }
+    }
+
+  return registered_at_least_one;
+}
+
+/* Given a tree containing a class type (CLASS_TYPE), this function
+   finds and returns the class hierarchy node for that class in our
+   data structure.  */
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+  tree class_decl = TREE_CHAIN (class_type);
+  tree class_name_id;
+  struct vtbl_map_node *vtbl_node;
+  tree class_decl_type;
+  tree type_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  if (class_decl)
+    class_decl_type = class_decl;
+  else
+    class_decl_type = TYPE_NAME (class_type);
+
+  /* Temporarily remove any type qualifiers on the type.  */
+  type_decl_type = TREE_TYPE (class_decl_type);
+  save_quals = TYPE_QUALS (type_decl_type);
+  reset_type_qualifiers (null_quals, type_decl_type);
+
+  class_name_id = DECL_ASSEMBLER_NAME (class_decl_type);
+  vtbl_node = vtbl_map_get_node (class_name_id);
+
+  /* Restore the type qualifiers.  */
+  reset_type_qualifiers (save_quals, type_decl_type);
+
+  if (vtbl_node)
+    return vtbl_node->class_info;
+
+  return NULL;
+}
+
+/* This function adds an edge to our class hierarchy graph.
+   EDGE_ARRAY will either be an array of parent nodes or an array of
+   children nodes for a particular class.  NUM_ENTRIES is the current
+   number of entries in the array.  MAX_WENTRIES is the maximum number
+   of entries the array can hold.  NEW_ENTRY is a vtv_graph_node
+   representing the new child or parent node to be added to the
+   EDGE_ARRAY.  */
+
+static void
+add_edge_to_graph (struct vtv_graph_node ***edge_array, unsigned *num_entries,
+                   unsigned *max_entries, struct vtv_graph_node *new_entry)
+{
+  /* Check array size, and re-size it if necessary.  */
+  if (*num_entries >= ((*max_entries) - 1))
+    {
+      unsigned new_size = 2 * (*max_entries);
+      unsigned i;
+      *edge_array = (struct vtv_graph_node **)
+          xrealloc (*edge_array, new_size * sizeof (struct vtv_graph_node *));
+
+      for (i = *max_entries; i < new_size; ++i)
+        (*edge_array)[i] = NULL;
+      *max_entries = new_size;
+    }
+
+  (*edge_array)[*num_entries] = new_entry;
+  *num_entries = (*num_entries) + 1;
+}
+
+/* Add base class/derived class pair to our internal class hierarchy
+   data structure.  BASE_NODE is our vtv_graph_node that corresponds
+   to a base class.  DERIVED_NODE is our vtv_graph_node that
+   corresponds to a class that is a descendant of the base class
+   (possibly the base class itself).  */
+
+static void
+add_hierarchy_pair (struct vtv_graph_node *base_node,
+                    struct vtv_graph_node *derived_node)
+{
+  add_edge_to_graph (&(base_node->children), &(base_node->num_children),
+                     &(base_node->max_children), derived_node);
+  add_edge_to_graph (&(derived_node->parents), &(derived_node->num_parents),
+                     &(derived_node->max_parents), base_node);
+}
+
+/* This functions adds a new base class/derived class relationship to
+   our class hierarchy data structure.  Both parameters are trees
+   representing the class types, i.e. RECORD_TYPE trees.
+   DERIVED_CLASS can be the same as BASE_CLASS.  */
+
+static void
+update_class_hierarchy_information (tree base_class,
+                                    tree derived_class)
+{
+  struct vtv_graph_node *base_node = find_graph_node (base_class);
+  struct vtv_graph_node *derived_node = find_graph_node (derived_class);
+
+  add_hierarchy_pair (base_node, derived_node);
+}
+
+/* Generate an undefined variable (a reference) to a varible defined
+   in the vtv_init libraty. In that way, if the a module is not linked
+   with the vtv_init library, the linker will generate an undefined
+   symbol error.  Which is much better that getting a segmentation
+   violation at runtime.  The parameter, INIT_ROUTINE_BODY, is the
+   function body of our constructor initialization function, to which
+   we add the reference to this symbol (and all of our calls to
+   __VLTRegisterPair).
+
+   For more information, see comments in
+   libstdc++-v3/libsupc++/vtv_init.cc.  */
+
+static void
+create_undef_reference_to_vtv_init (tree init_routine_body)
+{
+  const char *vtv_init_undef_var = "__vtv_defined_in_vtv_init_lib";
+  tree var_decl;
+  tree init_zero;
+
+  var_decl  = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+                          get_identifier (vtv_init_undef_var),
+                          int32_type_node);
+  TREE_PUBLIC (var_decl) = 1;
+  DECL_EXTERNAL (var_decl) = 1;
+  TREE_STATIC (var_decl) = 1;
+  SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (vtv_init_undef_var));
+  DECL_ARTIFICIAL (var_decl) = 1;
+  TREE_READONLY (var_decl) = 0;
+  DECL_IGNORED_P (var_decl) = 1;
+  DECL_PRESERVE_P (var_decl) = 1;
+  varpool_finalize_decl (var_decl);
+
+  /* Store a value in the undefined variable to force the creation of a
+     a reference.  */
+  init_zero = build2 (MODIFY_EXPR, TREE_TYPE (var_decl), var_decl,
+                      integer_zero_node);
+  append_to_statement_list (init_zero, &init_routine_body);
+
+}
+
+/* A simple hash function on strings */
+/* Be careful about changing this routine. The values generated will
+   be stored in the calls to InitSet. So, changing this routine may
+   cause a binary incompatibility.  */
+
+static uint32_t
+vtv_string_hash(const char *in)
+{
+  const char *s = in;
+  uint32_t h = 0;
+
+  gcc_assert (in != NULL);
+  for ( ; *s; ++s)
+    h = 5 * h + *s;
+  return h;
+}
+
+/* This function goes through all of our vtable map nodes, and for
+   each one that is actually used, it generates a call to
+   __VLTInitSetSymbol, with the appropriate arguments, and inserts the
+   calls as the start of our constructor initialization function
+   (INIT_ROUTINE_BODY).  */
+
+static bool
+init_all_sets (tree init_routine_body)
+{
+  struct vtbl_map_node *current;
+  bool inited_at_least_one = false;
+  tree_stmt_iterator i = tsi_start (init_routine_body);
+
+  for (current = vtbl_map_nodes; current; current = current->next)
+    {
+      if (!(current->is_used || (htab_elements (current->registered) > 0)))
+        continue;
+
+      size_t size_hint = guess_num_vtable_pointers (current->class_info);
+      tree set_handle_var_decl = current->vtbl_map_decl;
+
+      tree void_ptr_type = build_pointer_type
+                                             (TREE_TYPE (set_handle_var_decl));
+      tree arg1 = build1 (ADDR_EXPR, void_ptr_type, set_handle_var_decl);
+
+      uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (set_handle_var_decl));
+      uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
+                                            (DECL_NAME (set_handle_var_decl)));
+      tree arg2, arg3, init_set_call;
+
+      /* Build a buffer with the memory representation of
+         insert_only_hash_map::key_value as defined in vtv_map.h. This
+         will be passed as the second argument to InitSet.  */
+      #define KEY_TYPE_FIXED_SIZE 8
+
+      void *key_buffer = xmalloc (len1 + KEY_TYPE_FIXED_SIZE);
+      uint32_t *value_ptr = (uint32_t *) key_buffer;
+
+      /* Set the len and hash for the string.  */
+      *value_ptr = len1;
+      value_ptr++;
+      *value_ptr = hash_value;
+
+      /* Now copy the string representation of the vtbl map name...  */
+      memcpy ((char *) key_buffer + KEY_TYPE_FIXED_SIZE,
+              IDENTIFIER_POINTER (DECL_NAME (set_handle_var_decl)),
+              len1);
+
+      /* ... and build a string literal from it. This will make a copy
+         so the key_bufffer is not needed anymore after this.  */
+      arg2 = build_string_literal (len1 + KEY_TYPE_FIXED_SIZE,
+                                   (char *) key_buffer);
+      free (key_buffer);
+
+      /* size_t maybe different at compile time vs at runtime but
+         there should not be a problem in here. We dont expect such
+         large number of elements in the set.  */
+      arg3 = build_int_cst (size_type_node, size_hint);
+      init_set_call = build_call_expr (vlt_init_set_symbol_fndecl,
+                                       3, arg1, arg2, arg3);
+      gcc_assert (size_hint != 0);
+      tsi_link_before (&i, init_set_call, TSI_SAME_STMT);
+
+      inited_at_least_one = true;
+    }
+  return inited_at_least_one;
+}
+
+
+/* This function calls register_all_pairs, which actually generates
+   all the calls to __VLTRegisterPair (in the verification constructor
+   init function).  It also generates the calls to
+   __VLTChangePermission, if the verification constructor init
+   function is going into the preinit array.  INIT_ROUTINE_BODY is
+   the body of our constructior initialization function, to which we
+   add our function calls.*/
+
+bool
+vtv_register_class_hierarchy_information (tree init_routine_body)
+{
+  bool registered_something = false;
+  bool inited_some_sets = true;
+
+  init_functions ();
+
+  /* TODO: Temp fix. Needs to be tightened.  */
+  if (num_vtable_map_nodes == 0)
+    return false;;
+
+  /* Add class hierarchy pairs to the vtable map data structure.  */
+  registered_something = register_all_pairs (init_routine_body);
+
+  /* Initialialize all vtable map variables (pointers to our data
+     sets.  */
+  inited_some_sets = init_all_sets (init_routine_body);
+
+  if (registered_something || inited_some_sets)
+  {
+      /* If this function is going into the preinit_array, then we
+         need to manually call __VLTChangePermission, rather than
+         depending on initialization prioritys in vtv_init.  */
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          /* Pass __VLTP_READ_WRITE value as defined in vtv_rts.h.  */
+          tree arg_read_write = build_int_cst (integer_type_node, 1);
+          tree arg_read_only = build_int_cst (integer_type_node, 0);
+
+          tree call_rw_expr = build_call_expr (vlt_change_permission_fndecl,
+                                               1, arg_read_write);
+          tree call_r_expr = build_call_expr (vlt_change_permission_fndecl,
+                                              1, arg_read_only);
+          tree_stmt_iterator i = tsi_start (init_routine_body);
+          /* Insert the call to make permissions read-write at the
+             beginning of the init routine.  */
+          tsi_link_before (&i, call_rw_expr, TSI_SAME_STMT);
+
+          /* Append the call to make permissions read-only at the
+             end of the init routine.  */
+          append_to_statement_list (call_r_expr, &init_routine_body);
+        }
+
+      if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
+        create_undef_reference_to_vtv_init (init_routine_body);
+  }
+
+  return registered_something || inited_some_sets;
+}
+
+
+/* Generate the special constructor function that calls
+   __VLTChangePermission and __VLTRegisterPairs, and give it a very
+   high initialization priority.  */
+
+void
+vtv_generate_init_routine (void)
+{
+  tree init_routine_body;
+  bool vtable_classes_found = false;
+
+  push_lang_context (lang_name_c);
+
+  /* The priority for this init function (constructor) is carefully
+     chosen so that it will happen after the calls to unprotect the
+     memory used for vtable verification and before the memory is
+     protected again.  */
+  init_routine_body = vtv_start_verification_constructor_init_function ();
+
+  vtable_classes_found =
+                 vtv_register_class_hierarchy_information (init_routine_body);
+
+  if (vtable_classes_found)
+    {
+      current_function_decl =
+       vtv_finish_verification_constructor_init_function (init_routine_body);
+      allocate_struct_function (current_function_decl, false);
+      TREE_STATIC (current_function_decl) = 1;
+      TREE_USED (current_function_decl) = 1;
+      DECL_PRESERVE_P (current_function_decl) = 1;
+      if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+        {
+          DECL_STATIC_CONSTRUCTOR (current_function_decl) = 0;
+          assemble_vtv_preinit_initializer (current_function_decl);
+        }
+
+      gimplify_function_tree (current_function_decl);
+      cgraph_add_new_function (current_function_decl, false);
+
+      cgraph_process_new_functions ();
+    }
+  pop_lang_context ();
+}
+
+/* This funtion takes a tree containing a class type (BASE_TYPE), and
+   it either finds the existing vtbl_map_node for that class in our
+   data structure, or it creates a new node and adds it to the data
+   structure if there is not one for the class already.  As part of
+   this process it also creates the global vtable map variable for the
+   class.  */
+
+struct vtbl_map_node *
+vtable_find_or_create_map_decl (tree base_type)
+{
+  tree base_decl = TREE_CHAIN (base_type);
+  tree base_id;
+  char *var_name = NULL;
+  struct vtbl_map_node *vtable_map_node = NULL;
+  tree base_decl_type;
+  unsigned int save_quals;
+  unsigned int null_quals = TYPE_UNQUALIFIED;
+
+  /* Verify the type has an associated vtable.  */
+  if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
+    return NULL;
+
+  if (!base_decl)
+    base_decl = TYPE_NAME (base_type);
+
+  /* Temporarily remove any type qualifiers on the type. */
+  base_decl_type = TREE_TYPE (base_decl);
+  save_quals = TYPE_QUALS (base_decl_type);
+  reset_type_qualifiers (null_quals, base_decl_type);
+
+  base_id = DECL_ASSEMBLER_NAME (base_decl);
+
+  /* Restore the type qualifiers. */
+  reset_type_qualifiers (save_quals, base_decl_type);
+
+  /* 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_decl = 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;
+      DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
+      SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
+      DECL_ARTIFICIAL (var_decl) = 1;
+      /* We cannot mark this variable as read-only otherwise the gold
+         linker will not put it in the relro section. It seems if it
+         is marked as read-only, gold will put it in the .text
+         segment.  */
+      TREE_READONLY (var_decl) = 0;
+      DECL_IGNORED_P (var_decl) = 1;
+
+      /* Put these mmap variables in to 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 ((".vtable_map_vars", NULL));
+
+      DECL_SECTION_NAME (var_decl) = build_string (strlen (sect_name),
+                                                   sect_name);
+      DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl) = true;
+      DECL_COMDAT_GROUP (var_decl) = get_identifier (var_name);
+      DECL_INITIAL (var_decl) = initial_value;
+
+      varpool_finalize_decl (var_decl);
+      if (!vtable_map_node)
+        vtable_map_node = find_or_create_vtbl_map_node (base_type);
+      if (vtable_map_node->vtbl_map_decl == NULL_TREE)
+        vtable_map_node->vtbl_map_decl = var_decl;
+    }
+
+  gcc_assert (vtable_map_node);
+  return vtable_map_node;
+}
+
+/* This function is used to build up our class hierarchy data for a
+   particular class.  TYPE is the record_type tree node for the
+   class.  */
+
+static void
+vtv_save_base_class_info (tree type)
+{
+  if (flag_vtable_verify)
+    {
+      tree binfo =  TYPE_BINFO (type);
+      tree base_binfo;
+      struct vtbl_map_node *own_map;
+      int i;
+
+      /* First make sure to create the map for this record type.  */
+      own_map = vtable_find_or_create_map_decl (type);
+      if (own_map == NULL)
+        return;
+
+      /* Go through the list of all base classes for the current
+         (derived) type, make sure the *__vtable_map global variable
+         for the base class exists, and add the base class/derived
+         class pair to the class hierarchy information we are
+         accumulating (for vtable pointer verification).  */
+      for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+        {
+          tree tree_val = BINFO_TYPE (base_binfo);
+          struct vtbl_map_node *vtable_map_node = NULL;
+
+          vtable_map_node = vtable_find_or_create_map_decl (tree_val);
+
+          if (vtable_map_node != NULL)
+            update_class_hierarchy_information (tree_val, type);
+        }
+    }
+}
+
+/* This function adds classes we are interested in to a list of
+   classes that is saved during pre-compiled header generation.
+   RECORD is the record_type node for the class we are adding to the
+   list.  */
+
+void
+vtv_save_class_info (tree record)
+{
+  if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
+    return;
+
+  gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+  vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
+}
+
+
+/* This function goes through the list of classes we saved before the
+   pre-compiled header generation and calls vtv_save_base_class_info
+   on each one, to build up our class hierarchy data structure.  */
+
+void
+vtv_recover_class_info (void)
+{
+  tree current_class;
+  tree class_chain = vlt_saved_class_info;
+  while (class_chain != NULL_TREE)
+    {
+      current_class = TREE_VALUE (class_chain);
+      gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+
+      vtv_save_base_class_info (current_class);
+      class_chain = TREE_CHAIN (class_chain);
+    }
+
+  /* Let the garbabe collector collect the memory associated with the
+     chain.  */
+  vlt_saved_class_info = NULL_TREE;
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c	(revision 195313)
+++ gcc/cp/mangle.c	(working copy)
@@ -3415,7 +3415,7 @@ mangle_decl_string (const tree decl)
 
 /* Return an identifier for the external mangled name of DECL.  */
 
-static tree
+tree
 get_mangled_id (tree decl)
 {
   tree id = mangle_decl_string (decl);
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 195313)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -5211,6 +5211,8 @@ extern void note_vague_linkage_fn		(tree
 extern tree build_artificial_parm		(tree, tree);
 extern bool possibly_inlined_p			(tree);
 extern int parm_index                           (tree);
+extern tree vtv_start_verification_constructor_init_function (void);
+extern tree vtv_finish_verification_constructor_init_function (tree);
 
 /* in error.c */
 extern void init_error				(void);
@@ -5298,6 +5300,7 @@ extern tree build_java_class_ref		(tree)
 extern tree integral_constant_value		(tree);
 extern tree decl_constant_value_safe	        (tree);
 extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
+extern tree build_vtbl_address                  (tree);
 
 /* in lex.c */
 extern void cxx_dup_lang_specific_decl		(tree);
@@ -5525,6 +5528,11 @@ extern tree copied_binfo			(tree, tree);
 extern tree original_binfo			(tree, tree);
 extern int shared_member_p			(tree);
 
+/* in vtable-class-hierarchy.c */
+extern void vtv_compute_class_hierarchy_transitive_closure (void);
+extern void vtv_generate_init_routine           (void);
+extern void vtv_save_class_info                 (tree);
+extern void vtv_recover_class_info              (void);
 
 /* The representation of a deferred access check.  */
 
@@ -6006,6 +6014,7 @@ extern tree mangle_tls_init_fn			(tree);
 extern tree mangle_tls_wrapper_fn		(tree);
 extern bool decl_tls_wrapper_p			(tree);
 extern tree mangle_ref_init_variable		(tree);
+extern tree get_mangled_id                      (tree);
 
 /* in dump.c */
 extern bool cp_dump_tree			(void *, tree);

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

end of thread, other threads:[~2013-02-01 16:49 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CABtf2+ROV47=LoN7v2=R9ef7WVpwZVhtax6TLUu4vrQ-R0Ci-A@mail.gmail.com>
2013-01-30 17:44 ` [PATCH] Vtable pointer verification, C++ front end changes (patch 1 of 3) Jason Merrill
2013-02-01  0:25   ` Caroline Tice
2013-02-01 16:49     ` Jason Merrill
2013-01-23 22:35 Caroline Tice

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