From: Caroline Tice <cmtice@google.com>
To: gcc-patches@gcc.gnu.org
Cc: Caroline Tice <cmtice@google.com>
Subject: [PATCH] Vtable pointer verification, gcc changes (patch 2 of 2)
Date: Mon, 05 Nov 2012 17:49:00 -0000 [thread overview]
Message-ID: <CABtf2+SdU_aWMj-v6J=WM8onenUX0UZY72bdKj2a4JEtUXe-pw@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 9925 bytes --]
As requested, I have split the original patch into two parts: GCC
changes and runtime library changes. The attached patch is fore the
gcc changes.
-- Caroline Tice
cmtice@google.com
2012-11-05 Caroline Tice <cmtice@google.com>
* tree.h (save_vtable_map_decl): New function decl.
* tree-pass.h (pass_vtable_verify): New pass declaration.
* cp/init.c (build_vtbl_address): Remove 'static' qualifier from
function declaration and definition.
* cp/class.c (finish_struct_1): Add call to vtv_save_class_info,
if the vtable verify flag is set.
* cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
files. Add definition for building vtable-class-hierarchy.o.
* cp/pt.c (mark_class_instantiated): Add call to vtv_save_class_info
if the vtable verify flag is set.
* cp/decl2 (start_objects): Remove 'static' qualifier from function
declaratin and definition. Add new paramater, 'extra_name'. Change
'type' var from char array to char *. Call xmalloc & free for 'type'.
Add 'extra_name' to 'type' string.
(finish_objects): Remove 'static' qualifier from function declaration
and definition. Change return type from void to tree. Make function
return early if we're doing vtable verification and the function is
a vtable verification constructor init function. Make this function
return 'fn'.
(generate_ctor_or_dtor_function): Add third argument to calls to
start_objects.
(cp_write_global_declarations): Add calls to vtv_recover_class_info,
vtv_compute_class_hierarchy_transitive_closure, and
vtv_generate_init_routine, if the vtable verify flag is set.
* cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
list of gtfiles.
* cp/vtable-class-hierarchy.c: New file.
* cp/mangle.c (get_mangled_id): Remove static qualifier from function
definition.
* cp/cp-tree.h: Add extern function declarations for start_objects,
finish_objects, build_vtbl_address, get_mangled_id,
vtv_compute_class_hierarchy_transitive_closure,
vtv_generate_init_routine, vtv_save_class_info and
vtv_recover_class_info.
* timevar.def: Add TV_VTABLE_VERIFICATION.
* flag-types.h: Add enum vtv_priority defintion.
* tree-vtable-verify.c: New file.
* tree-vtable-verify.h: New file.
* common.opt: Add definitions for fvtable-verify= and its string
options (vtv_priority enum values).
* varasm.c (assemble_variable): Check to see if the variable is a
vtable map variable, and if so, put it into the vtable map variable
section, and make it comdat.
(assemble_vtv_preinit_initializer): New function, to put the
vtable verification constructor initialization function in the preinit
array, if appropriate.
* output.h: Add extern declaration for
assemble_vtv_preinit_initializer.
* Makefile.in: Add tree-vtable-verify.o to list of OBJS. Add build
rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
files.
* passes.c (init_optimization_passes): Add pass_vtable_verify.
On Thu, Nov 1, 2012 at 1:07 PM, Caroline Tice <cmtice@google.com> wrote:
> We have been developing a new security hardening feature for GCC that
> is designed to detect and handle (during program execution) when a
> vtable pointer that is about to be used for a virtual function call is
> not a valid vtable pointer for that call (i.e. it has become
> corrupted, possibly due to a hacker attack). We gave a presentation
> on this work at the Gnu Tools Cauldron in Prague last July. We now
> have the implementation fully working and are submitting this patch
> for review. We would like to get this into the next release of GCC if
> possible.
>
> The general idea is to collect class hierarchy and vtable pointer data
> while parsing the classes, then use this data to generate (at runtime)
> sets of valid vtable pointers, one for each class. We also find every
> virtual function call and insert a verification call before the
> virtual function call. The verification call takes the set of valid
> vtable pointers for the declared class of the object, and the actual
> vtable pointer in the object. If the vtable pointer in the object is
> in the set of valid vtable pointers for the object, then verification
> succeeds and the virtual call is allowed. Otherwise verification
> fails and the program aborts.
>
> We have a written a more detailed design document, which I am also
> attaching to this email (GCCVtableSecurityHardeningProposal.txt).
>
> The implementation can be divided into roughly two parts:
> modifications to the main gcc compiler, for things that happen at
> compile time (collecting the class hierarchy & vtable information;
> generating the runtime calls to build the data sets from this data;
> inserting calls to the verification function); and modifications to
> the runtime, i.e. functions that go into libstdc++ for building the
> data sets, for doing the verification against the data sets, for
> protecting the memory where the data sets reside, etc.).
>
> Please let me know if there is any more information you need, or if
> you have any questions about this patch.
>
> -- Caroline Tice
> cmtice@google.com
>
> libstdc++/ChangeLog
>
> 2012-11-01 Caroline Tice <cmtice@google.com>
>
> * src/Makefile.am: Add libvtv___la_LIBDD definition; update CXXLINK
> to search in libvtv___la_LIBADD and to link in libvtv_init.
> * src/Makefile.in: Regenerate.
> * libsupc++/Makefile.am: Add libvtv_init.la and libvtv_stubs.la to
> toolexeclib_LTLIBRARIES. Add vtv_rts.cc, vtv_malloc.cc and
> vtv_utils.cc to sources. Define vtv_init_sources and
> vtv_stubs_sources. Also define libvtv_init_la_SOURCES and
> libvtv_stubs_la_sources.
> * libsupc++/Makefile.in: Regenerate.
> * libsupc++/vtv_rts.cc: New file.
> * libsupc++/vtv_malloc.h: New file.
> * libsupc++/vtv_rts.h: New file.
> * libsupc++/vtv_fail.h: New file.
> * libsupc++/vtv_set.h: New file.
> * libsupc++/vtv_stubs.cc: New file.
> * libsupc++/vtv_utils.cc: New file.
> * libcupc++/vtv_utils.h: New file.
> * libsupc++/vtv_init.cc: New file.
> * libsupc++/vtv_malloc.cc: New file.
> * config/abi/pre/gnu.ver (GLIBCXX_3.4.18): Add vtable verification
> functions and vtable map variables to library export list.
>
> gcc/ChangeLog:
>
> 2012-11-01 Caroline Tice <cmtice@google.com>
>
> * tree.h (save_vtable_map_decl): New function decl.
> * tree-pass.h (pass_vtable_verify): New pass declaration.
> * cp/init.c (build_vtbl_address): Remove 'static' qualifier from
> function declaration and definition.
> * cp/class.c (finish_struct_1): Add call to vtv_save_class_info,
> if the vtable verify flag is set.
> * cp/Make-lang.in: Add vtable-class-hierarchy.o to list of object
> files. Add definition for building vtable-class-hierarchy.o.
> * cp/pt.c (mark_class_instantiated): Add call to vtv_save_class_info
> if the vtable verify flag is set.
> * cp/decl2 (start_objects): Remove 'static' qualifier from function
> declaratin and definition. Add new paramater, 'extra_name'. Change
> 'type' var from char array to char *. Call xmalloc & free for 'type'.
> Add 'extra_name' to 'type' string.
> (finish_objects): Remove 'static' qualifier from function declaration
> and definition. Change return type from void to tree. Make function
> return early if we're doing vtable verification and the function is
> a vtable verification constructor init function. Make this function
> return 'fn'.
> (generate_ctor_or_dtor_function): Add third argument to calls to
> start_objects.
> (cp_write_global_declarations): Add calls to vtv_recover_class_info,
> vtv_compute_class_hierarchy_transitive_closure, and
> vtv_generate_init_routine, if the vtable verify flag is set.
> * cp/config-lang.in (gtfiles): Add vtable-class-hierarchy.c to the
> list of gtfiles.
> * cp/vtable-class-hierarchy.c: New file.
> * cp/mangle.c (get_mangled_id): Remove static qualifier from function
> definition.
> * cp/cp-tree.h: Add extern function declarations for start_objects,
> finish_objects, build_vtbl_address, get_mangled_id,
> vtv_compute_class_hierarchy_transitive_closure,
> vtv_generate_init_routine, vtv_save_class_info and
> vtv_recover_class_info.
> * timevar.def: Add TV_VTABLE_VERIFICATION.
> * flag-types.h: Add enum vtv_priority defintion.
> * tree-vtable-verify.c: New file.
> * tree-vtable-verify.h: New file.
> * common.opt: Add definitions for fvtable-verify= and its string
> options (vtv_priority enum values).
> * varasm.c (assemble_variable): Check to see if the variable is a
> vtable map variable, and if so, put it into the vtable map variable
> section, and make it comdat.
> (assemble_vtv_preinit_initializer): New function, to put the
> vtable verification constructor initialization function in the preinit
> array, if appropriate.
> * output.h: Add extern declaration for
> assemble_vtv_preinit_initializer.
> * Makefile.in: Add tree-vtable-verify.o to list of OBJS. Add build
> rule for tree-vtable-verify.o Add tre-vtable-verify.c to list of source
> files.
> * passes.c (init_optimization_passes): Add pass_vtable_verify.
[-- Attachment #2: fsf-vtable-verification.gcc.patch --]
[-- Type: application/octet-stream, Size: 92992 bytes --]
Index: gcc/tree.h
===================================================================
--- gcc/tree.h (revision 192503)
+++ gcc/tree.h (working copy)
@@ -6437,6 +6437,9 @@ is_lang_specific (tree t)
/* In gimple-low.c. */
extern bool block_may_fallthru (const_tree);
+/* In tree-vtable-security.c */
+extern void save_vtable_map_decl (tree);
+
\f
/* Functional interface to the builtin functions. */
Index: gcc/tree-pass.h
===================================================================
--- gcc/tree-pass.h (revision 192503)
+++ gcc/tree-pass.h (working copy)
@@ -358,6 +358,7 @@ extern struct gimple_opt_pass pass_tm_ed
extern struct gimple_opt_pass pass_split_functions;
extern struct gimple_opt_pass pass_feedback_split_functions;
extern struct gimple_opt_pass pass_strength_reduction;
+extern struct gimple_opt_pass pass_vtable_verify;
/* IPA Passes */
Index: gcc/cp/init.c
===================================================================
--- gcc/cp/init.c (revision 192503)
+++ gcc/cp/init.c (working copy)
@@ -45,7 +45,6 @@ static tree initializing_context (tree);
static void expand_cleanup_for_base (tree, tree);
static tree dfs_initialize_vtbl_ptrs (tree, void *);
static tree build_field_list (tree, tree, int *);
-static tree build_vtbl_address (tree);
static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
/* We are about to generate some complex initialization code.
@@ -1105,7 +1104,7 @@ emit_mem_initializers (tree mem_inits)
/* Returns the address of the vtable (i.e., the value that should be
assigned to the vptr) for BINFO. */
-static tree
+tree
build_vtbl_address (tree binfo)
{
tree binfo_for = binfo;
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c (revision 192503)
+++ gcc/cp/class.c (working copy)
@@ -6251,6 +6251,9 @@ finish_struct_1 (tree t)
maybe_suppress_debug_info (t);
+ if (flag_vtable_verify)
+ vtv_save_class_info (t);
+
dump_class_hierarchy (t);
/* Finish debugging output for this type. */
Index: gcc/cp/Make-lang.in
===================================================================
--- gcc/cp/Make-lang.in (revision 192503)
+++ gcc/cp/Make-lang.in (working copy)
@@ -82,7 +82,7 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.
cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
# Language-specific object files for C++.
CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -340,7 +340,12 @@ cp/parser.o: cp/parser.c $(CXX_TREE_H) $
c-family/c-objc.h tree-pretty-print.h $(CXX_PARSER_H) $(TIMEVAR_H)
cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \
$(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H)
-
+cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \
+ $(TM_H) $(TIMEVAR_H) $(CXX_TREE_H) intl.h $(CXX_PARSER_H) cp/decl.h \
+ $(FLAGS_H) $(DIAGNOSTIC_CORE_H) output.h $(CGRAPH_H) c-family/c-common.h \
+ c-family/c-objc.h $(PLUGIN_H) \
+ tree-iterator.h tree-vtable-verify.h $(GIMPLE_H) \
+ gt-cp-vtable-class-hierarchy.h
cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h \
$(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
Index: gcc/cp/pt.c
===================================================================
--- gcc/cp/pt.c (revision 192503)
+++ gcc/cp/pt.c (working copy)
@@ -17882,6 +17882,10 @@ mark_class_instantiated (tree t, int ext
if (! extern_p)
{
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+
+ if (flag_vtable_verify)
+ vtv_save_class_info (t);
+
rest_of_type_compilation (t, 1);
}
}
Index: gcc/cp/decl2.c
===================================================================
--- gcc/cp/decl2.c (revision 192503)
+++ gcc/cp/decl2.c (working copy)
@@ -69,8 +69,6 @@ typedef struct priority_info_s {
static void mark_vtable_entries (tree);
static bool maybe_emit_vtables (tree);
static bool acceptable_java_type (tree);
-static tree start_objects (int, int);
-static void finish_objects (int, int, tree);
static tree start_static_storage_duration_function (unsigned);
static void finish_static_storage_duration_function (tree);
static priority_info get_priority_info (int);
@@ -2965,12 +2963,12 @@ generate_tls_wrapper (tree fn)
/* Start the process of running a particular set of global constructors
or destructors. Subroutine of do_[cd]tors. */
-static tree
-start_objects (int method_type, int initp)
+tree
+start_objects (int method_type, int initp, const char *extra_name)
{
tree body;
tree fndecl;
- char type[14];
+ char *type = NULL;
/* Make ctor or dtor function. METHOD_TYPE may be 'I' or 'D'. */
@@ -2984,15 +2982,22 @@ start_objects (int method_type, int init
joiner = '_';
#endif
- sprintf (type, "sub_%c%c%.5u", method_type, joiner, initp);
+ type = (char *) xmalloc ((17 + strlen (extra_name)) * sizeof (char));
+ sprintf (type, "sub_%c%c%.5u%s", method_type, joiner, initp, extra_name);
}
else
- sprintf (type, "sub_%c", method_type);
+ {
+ type = (char *) xmalloc (5 * sizeof (char));
+ sprintf (type, "sub_%c", method_type);
+ }
fndecl = build_lang_decl (FUNCTION_DECL,
get_file_function_name (type),
build_function_type_list (void_type_node,
NULL_TREE));
+
+ free (type);
+
start_preparsed_function (fndecl, /*attrs=*/NULL_TREE, SF_PRE_PARSED);
TREE_PUBLIC (current_function_decl) = 0;
@@ -3018,7 +3023,7 @@ start_objects (int method_type, int init
/* Finish the process of running a particular set of global constructors
or destructors. Subroutine of do_[cd]tors. */
-static void
+tree
finish_objects (int method_type, int initp, tree body)
{
tree fn;
@@ -3031,6 +3036,10 @@ finish_objects (int method_type, int ini
{
DECL_STATIC_CONSTRUCTOR (fn) = 1;
decl_init_priority_insert (fn, initp);
+
+ if (flag_vtable_verify
+ && strstr (IDENTIFIER_POINTER (DECL_NAME (fn)), ".vtable"))
+ return fn;
}
else
{
@@ -3039,6 +3048,7 @@ finish_objects (int method_type, int ini
}
expand_or_defer_fn (fn);
+ return fn;
}
/* The names of the parameters to the function created to handle
@@ -3561,7 +3571,7 @@ generate_ctor_or_dtor_function (bool con
if (c_dialect_objc () && (priority == DEFAULT_INIT_PRIORITY)
&& constructor_p && objc_static_init_needed_p ())
{
- body = start_objects (function_key, priority);
+ body = start_objects (function_key, priority, "");
objc_generate_static_init_call (NULL_TREE);
}
@@ -3575,7 +3585,7 @@ generate_ctor_or_dtor_function (bool con
tree call;
if (! body)
- body = start_objects (function_key, priority);
+ body = start_objects (function_key, priority, "");
call = cp_build_function_call_nary (fndecl, tf_warning_or_error,
build_int_cst (NULL_TREE,
@@ -4283,8 +4293,22 @@ cp_write_global_declarations (void)
timevar_stop (TV_PHASE_DEFERRED);
timevar_start (TV_PHASE_OPT_GEN);
+ if (flag_vtable_verify)
+ {
+ vtv_recover_class_info ();
+ vtv_compute_class_hierarchy_transitive_closure ();
+ }
+
finalize_compilation_unit ();
+ if (flag_vtable_verify)
+ {
+ /* Generate the special constructor initialization function that
+ calls __VLTRegisterPairs, and give it a very high initialization
+ priority. */
+ vtv_generate_init_routine (main_input_filename);
+ }
+
timevar_stop (TV_PHASE_OPT_GEN);
timevar_start (TV_PHASE_CHECK_DBGINFO);
Index: gcc/cp/config-lang.in
===================================================================
--- gcc/cp/config-lang.in (revision 192503)
+++ gcc/cp/config-lang.in (working copy)
@@ -30,4 +30,4 @@ compilers="cc1plus\$(exeext)"
target_libs="target-libstdc++-v3"
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c"
Index: gcc/cp/vtable-class-hierarchy.c
===================================================================
--- gcc/cp/vtable-class-hierarchy.c (revision 0)
+++ gcc/cp/vtable-class-hierarchy.c (revision 0)
@@ -0,0 +1,918 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* This file is part of the vtable security implementation. It collects
+ class hierarchy information about the program being compiled and
+ inserts calls to __VLTRegisterPair, registering this information. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "intl.h"
+#include "c-family/c-pragma.h"
+#include "decl.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+#include "output.h"
+#include "target.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "tree-iterator.h"
+#include "tree-vtable-verify.h"
+#include "gimple.h"
+
+/* Need to mark this one specially since it needs to be stored in
+ * precompiled header IR */
+static GTY(()) tree vlt_saved_class_info = NULL_TREE;
+
+static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
+static GTY (()) tree vlt_change_permission_fndecl = NULL_TREE;
+
+struct work_node {
+ struct vtv_graph_node *node;
+ struct work_node *next;
+};
+
+static void init_functions (void);
+
+static int guess_num_vtable_pointers (struct vtv_graph_node *);
+static bool register_all_pairs (tree body);
+static void add_hierarchy_pair (struct vtv_graph_node *,
+ struct vtv_graph_node *);
+static struct vtv_graph_node *find_graph_node (tree);
+static struct vtv_graph_node *
+ find_and_remove_next_leaf_node (struct work_node **worklist);
+static void create_undef_reference_to_vtv_init(tree register_pairs_body);
+static bool vtv_register_class_hierarchy_information
+ (tree register_pairs_body);
+
+static void update_class_hierarchy_information (tree, tree);
+struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
+
+static void
+init_functions (void)
+{
+ tree void_ptr_type = build_pointer_type (void_type_node);
+ tree arg_types = NULL_TREE;
+ tree register_pairs_type = void_type_node;
+ tree change_permission_type = void_type_node;
+#ifdef VTV_DEBUG
+ tree char_ptr_type = build_pointer_type (char_type_node);
+#endif
+
+ if (vlt_change_permission_fndecl != NULL_TREE)
+ return;
+
+ gcc_assert(vlt_register_pairs_fndecl == NULL_TREE);
+
+ arg_types = build_tree_list (NULL_TREE, integer_type_node);
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+ change_permission_type = build_function_type (change_permission_type,
+ arg_types);
+ vlt_change_permission_fndecl = build_fn_decl ("__VLTChangePermission",
+ change_permission_type);
+ TREE_NOTHROW (vlt_change_permission_fndecl) = 1;
+ DECL_ATTRIBUTES (vlt_change_permission_fndecl) =
+ tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (vlt_change_permission_fndecl));
+ TREE_PUBLIC (vlt_change_permission_fndecl) = 1;
+ DECL_PRESERVE_P (vlt_change_permission_fndecl) = 1;
+ retrofit_lang_decl (vlt_change_permission_fndecl);
+ SET_DECL_LANGUAGE (vlt_change_permission_fndecl, lang_cplusplus);
+
+ arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ integer_type_node));
+#ifdef VTV_DEBUG
+ /* Start: Arg types to be removed when we remove debugging parameters from
+ the library function. */
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ integer_type_node));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ integer_type_node));
+ /* End: Arg types to be removed...*/
+#endif
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+ register_pairs_type = build_function_type (register_pairs_type, arg_types);
+
+#ifdef VTV_DEBUG
+ vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPairDebug",
+ register_pairs_type);
+#else
+ vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPair",
+ register_pairs_type);
+#endif
+
+ TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
+ DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
+ tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
+ TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
+ DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
+ retrofit_lang_decl (vlt_register_pairs_fndecl);
+ SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
+}
+
+static void
+add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
+ sbitmap inserted)
+{
+ struct work_node *new_work_node;
+
+ if (TEST_BIT (inserted, node->class_uid))
+ return;
+
+ new_work_node = (struct work_node *) xmalloc (sizeof (struct work_node));
+ new_work_node->next = *worklist;
+ new_work_node->node = node;
+ *worklist = new_work_node;
+
+ SET_BIT (inserted, node->class_uid);
+}
+
+static struct vtv_graph_node *
+find_and_remove_next_leaf_node (struct work_node **worklist)
+{
+ struct work_node *prev, *cur;
+
+ for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+ {
+ if (cur->node->num_children == cur->node->num_processed_children)
+ {
+ if (prev == NULL)
+ (*worklist) = cur->next;
+ else
+ prev->next = cur->next;
+
+ cur->next = NULL;
+ return cur->node;
+ }
+ }
+
+ return NULL;
+}
+
+void
+vtv_compute_class_hierarchy_transitive_closure (void)
+{
+ struct work_node *worklist = NULL;
+ struct vtbl_map_node *cur;
+ sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+ unsigned i;
+
+ /* Note: Every node in the graph gets added to the worklist exactly
+ once and removed from the worklist exactly once (when all of its
+ children have been processed). Each node's children edges are
+ followed exactly once, and each node's parent edges are followed
+ exactly once. So this algorithm is roughly O(V + 2E), i.e.
+ O(E + V). */
+
+ /* Set-up: */
+ /* Find all the "leaf" nodes in the graph, and add them to the worklist. */
+ sbitmap_zero (inserted);
+ for (cur = vtbl_map_nodes; cur; cur = cur->next)
+ {
+ if (cur->class_info
+ && (cur->class_info->num_children == 0)
+ && ! (TEST_BIT (inserted, cur->class_info->class_uid)))
+ add_to_worklist (&worklist, cur->class_info, inserted);
+ }
+
+
+ /* Main work: pull next leaf node off work list, process it, add its
+ parents to the worklist, where a 'leaf' node is one that has no
+ children, or all of its children have been processed. */
+ while (worklist)
+ {
+ struct vtv_graph_node *temp_node =
+ find_and_remove_next_leaf_node (&worklist);
+
+ gcc_assert (temp_node != NULL);
+ temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
+ sbitmap_zero (temp_node->descendants);
+ SET_BIT (temp_node->descendants, temp_node->class_uid);
+ for (i = 0; i < temp_node->num_children; ++i)
+ sbitmap_a_or_b (temp_node->descendants, temp_node->descendants,
+ temp_node->children[i]->descendants);
+ for (i = 0; i < temp_node->num_parents; ++i)
+ {
+ temp_node->parents[i]->num_processed_children =
+ temp_node->parents[i]->num_processed_children + 1;
+ if (!TEST_BIT (inserted, temp_node->parents[i]->class_uid))
+ add_to_worklist (&worklist, temp_node->parents[i], inserted);
+ }
+ }
+}
+
+/* Keep track of which pairs we have already created __VLTRegisterPair
+ calls for, to prevent creating duplicate calls within the same
+ compilation unit. */
+
+static bool
+record_register_pairs (tree vtable_decl, tree vptr_address,
+ tree base_class)
+{
+ unsigned offset;
+ tree base_id;
+ struct vtbl_map_node *base_vtable_map_node;
+
+ if (TREE_CODE (vptr_address) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
+ vptr_address = TREE_OPERAND (vptr_address, 0);
+
+ offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
+
+ if (TREE_CHAIN (base_class))
+ base_id = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class));
+ else
+ base_id = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class));
+
+ base_vtable_map_node = vtbl_map_get_node (base_id);
+
+ if (vtbl_map_node_registration_find (base_vtable_map_node, vtable_decl,
+ offset))
+ return true;
+
+ vtbl_map_node_registration_insert (base_vtable_map_node, vtable_decl,
+ offset);
+ return false;
+}
+
+static void
+register_vptr_fields (tree base_class_decl_arg, tree base_class,
+ tree record_type, tree body)
+{
+ /* A class may contain secondary vtables in it, for various
+ reasons. This function goes through the decl chain of a class
+ record looking for any fields that point to secondary vtables,
+ and adding calls to __VLTRegisterPair for the secondary vtable
+ pointers. */
+
+ tree vtbl_var_decl;
+ tree arg1;
+ tree arg2;
+ int hint = 0;
+
+ if (TREE_CODE (record_type) != RECORD_TYPE)
+ return;
+
+ vtbl_var_decl = get_vtbl_decl_for_binfo (TYPE_BINFO (record_type));
+
+ if (vtbl_var_decl)
+ {
+ tree ztt_decl = DECL_CHAIN (vtbl_var_decl);
+ bool already_registered = false;
+
+ /* construction vtable */
+ if (ztt_decl != NULL_TREE
+ && (DECL_NAME (ztt_decl))
+ && (strncmp (IDENTIFIER_POINTER (DECL_NAME (ztt_decl)),
+ "_ZTT", 4) == 0))
+ {
+ tree values = DECL_INITIAL (ztt_decl);
+ struct varpool_node * vp_node = varpool_node (ztt_decl);
+ if (vp_node->finalized
+ && TREE_ASM_WRITTEN (ztt_decl)
+ && (values != NULL_TREE)
+ && (TREE_CODE (values) == CONSTRUCTOR)
+ && (TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE))
+ {
+ tree call_expr = NULL_TREE;
+ unsigned HOST_WIDE_INT cnt;
+ constructor_elt *ce;
+
+ for (cnt = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (values),
+ cnt, ce);
+ cnt++)
+ {
+ tree value = ce->value;
+ tree val_vtbl_decl = TREE_OPERAND (TREE_OPERAND (value, 0),
+ 0);
+ int len1;
+ int len2;
+
+ if (TREE_CODE (val_vtbl_decl) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (val_vtbl_decl, 0))
+ == VAR_DECL)
+ val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
+
+ gcc_assert (TREE_CODE (val_vtbl_decl) == VAR_DECL);
+
+ len1 = strlen (IDENTIFIER_POINTER
+ (DECL_NAME
+ (TREE_OPERAND
+ (base_class_decl_arg, 0))));
+ len2 = strlen (IDENTIFIER_POINTER
+ (DECL_NAME (val_vtbl_decl)));
+ arg1 = build_string_literal (len1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (TREE_OPERAND
+ (base_class_decl_arg, 0))));
+ arg2 = build_string_literal (len2,
+ IDENTIFIER_POINTER
+ (DECL_NAME (val_vtbl_decl)));
+
+ already_registered = record_register_pairs (val_vtbl_decl,
+ value,
+ base_class);
+
+ if (already_registered)
+ continue;
+
+#ifdef VTV_DEBUG
+ call_expr = build_call_expr
+ (vlt_register_pairs_fndecl, 7,
+ base_class_decl_arg, value,
+ build_int_cst (integer_type_node,
+ hint),
+ arg1,
+ build_int_cst (integer_type_node,
+ len1),
+ arg2,
+ build_int_cst (integer_type_node,
+ len2));
+#else
+ call_expr = build_call_expr
+ (vlt_register_pairs_fndecl, 3,
+ base_class_decl_arg, value,
+ build_int_cst (integer_type_node,
+ hint));
+#endif
+ append_to_statement_list (call_expr, &body);
+ }
+ }
+ }
+ }
+}
+
+static void
+register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
+ int len1, tree str2, int len2, tree base_class)
+{
+ unsigned ix;
+ tree base_binfo;
+ tree vtable_decl;
+ bool already_registered;
+ int hint = 0;
+
+ if (binfo == NULL_TREE)
+ return;
+
+ for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+ {
+ if ((!BINFO_PRIMARY_P (base_binfo)
+ || BINFO_VIRTUAL_P (base_binfo))
+ && (vtable_decl=get_vtbl_decl_for_binfo (base_binfo))
+ && !(DECL_VTABLE_OR_VTT_P(vtable_decl)
+ && DECL_CONSTRUCTION_VTABLE_P(vtable_decl)))
+ {
+ tree vtable_address = build_vtbl_address (base_binfo);
+ tree call_expr;
+
+ already_registered = record_register_pairs (vtable_decl,
+ vtable_address,
+ base_class);
+ if (!already_registered)
+ {
+#ifdef VTV_DEBUG
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 7,
+ arg1, vtable_address,
+ build_int_cst (integer_type_node,
+ hint),
+ str1,
+ build_int_cst (integer_type_node,
+ len1),
+ str2,
+ build_int_cst (integer_type_node,
+ len2));
+#else
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 3,
+ arg1, vtable_address,
+ build_int_cst (integer_type_node,
+ hint));
+#endif
+
+ append_to_statement_list (call_expr, &body);
+ }
+ }
+
+ register_other_binfo_vtables (base_binfo, body, arg1, str1, len1, str2,
+ len2, base_class);
+ }
+}
+
+static int
+guess_num_vtable_pointers (struct vtv_graph_node *class_node)
+{
+ tree vtbl;
+ int total_num_vtbls = 0;
+ int num_vtbls_power_of_two = 1;
+ unsigned i;
+
+ for (i = 0; i < num_vtable_map_nodes; ++i)
+ if (TEST_BIT (class_node->descendants, i))
+ {
+ tree class_type = vtbl_map_nodes_array[i]->class_info->class_type;
+ for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
+ vtbl = DECL_CHAIN (vtbl))
+ {
+ total_num_vtbls ++;
+ if (total_num_vtbls > num_vtbls_power_of_two)
+ num_vtbls_power_of_two <<= 1;
+ }
+ }
+ return num_vtbls_power_of_two;
+}
+
+/* This function goes through our internal class hierarchy & vtable
+ pointer data structure and outputs calls to __VLTRegisterPair for
+ every class-vptr pair (for those classes whose vtable would be
+ output in the current compilation unit). These calls get put into
+ our constructor initialization function. */
+
+static bool
+register_all_pairs (tree body)
+{
+ struct vtbl_map_node *current;
+ tree base_ptr_var_decl;
+
+ bool registered_at_least_one = false;
+
+ for (current = vtbl_map_nodes; current; current = current->next)
+ {
+ unsigned i;
+ tree base_class = current->class_info->class_type;
+ int size_hint = guess_num_vtable_pointers (current->class_info);
+ base_ptr_var_decl = current->vtbl_map_decl;
+
+ gcc_assert (current->class_info != NULL);
+
+ for (i = 0; i < num_vtable_map_nodes; ++i)
+ if (TEST_BIT (current->class_info->descendants, i))
+ {
+ struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_array[i];
+ tree class_type = vtbl_class_node->class_info->class_type;
+
+ if (class_type
+ && (TREE_CODE (class_type) == RECORD_TYPE))
+ {
+ tree new_type;
+ tree arg1;
+ tree call_expr;
+ bool already_registered;
+
+ tree binfo = TYPE_BINFO (class_type);
+ tree vtable_decl;
+ bool vtable_should_be_output = false;
+
+ vtable_decl = CLASSTYPE_VTABLES (class_type);
+
+ /* Handle main vtable for this class. */
+
+ if (vtable_decl)
+ vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
+
+ if (vtable_decl && vtable_should_be_output
+ && BINFO_VTABLE (binfo))
+ {
+ tree vtable_address = build_vtbl_address (binfo);
+ int len1 = IDENTIFIER_LENGTH
+ (DECL_NAME (base_ptr_var_decl));
+ int len2 = IDENTIFIER_LENGTH (DECL_NAME (vtable_decl));
+ tree str1 = build_string_literal (len1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (base_ptr_var_decl)));
+ tree str2 = build_string_literal (len2,
+ IDENTIFIER_POINTER
+ (DECL_NAME (vtable_decl)));
+
+ already_registered = record_register_pairs (vtable_decl,
+ vtable_address,
+ base_class);
+
+ if (!already_registered)
+ {
+ new_type = build_pointer_type (TREE_TYPE
+ (base_ptr_var_decl));
+ arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+#ifdef VTV_DEBUG
+ /* This call expr has the 3 "real" arguments, plus 4
+ debugging arguments. Eventually it will be replaced
+ with the one just below it, which only has the 2 real
+ arguments. */
+ call_expr = build_call_expr
+ (vlt_register_pairs_fndecl, 7,
+ arg1, vtable_address,
+ build_int_cst (integer_type_node, size_hint),
+ str1, build_int_cst (integer_type_node,
+ len1),
+ str2, build_int_cst (integer_type_node,
+ len2));
+#else
+ call_expr = build_call_expr
+ (vlt_register_pairs_fndecl, 3,
+ arg1, vtable_address,
+ build_int_cst (integer_type_node, size_hint));
+#endif
+ append_to_statement_list (call_expr, &body);
+
+ registered_at_least_one = true;
+
+ /* Find and handle any 'extra' vtables associated
+ with this class, via virtual inheritance. */
+ register_vptr_fields (arg1, base_class, class_type,
+ body);
+
+ /* Find and handle any 'extra' vtables associated
+ with this class, via multiple inheritance. */
+ register_other_binfo_vtables (binfo, body, arg1, str1,
+ len1, str2, len2,
+ base_class);
+ }
+ }
+ }
+ }
+ }
+
+ return registered_at_least_one;
+}
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+ tree class_decl = TREE_CHAIN (class_type);
+ tree class_name_id;
+ struct vtbl_map_node *vtbl_node;
+
+ if (class_decl)
+ class_name_id = DECL_ASSEMBLER_NAME (class_decl);
+ else
+ class_name_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
+
+ vtbl_node = vtbl_map_get_node (class_name_id);
+
+ if (vtbl_node)
+ return vtbl_node->class_info;
+
+ return NULL;
+}
+
+static void
+add_edge_to_graph (struct vtv_graph_node ***edge_array, unsigned *num_entries,
+ unsigned *max_entries, struct vtv_graph_node *new_entry)
+{
+ /* Check array size, and re-size it if necessary. */
+ if (*num_entries >= ((*max_entries) - 1))
+ {
+ unsigned new_size = 2 * (*max_entries);
+ unsigned i;
+ *edge_array = (struct vtv_graph_node **)
+ xrealloc (*edge_array, new_size * sizeof (struct vtv_graph_node *));
+
+ for (i = *max_entries; i < new_size; ++i)
+ (*edge_array)[i] = NULL;
+ *max_entries = new_size;
+ }
+
+ (*edge_array)[*num_entries] = new_entry;
+ *num_entries = (*num_entries) + 1;
+}
+
+/* Add base class/derived class pair to our internal class hierarchy
+ data structure. */
+
+static void
+add_hierarchy_pair (struct vtv_graph_node *base_node,
+ struct vtv_graph_node *derived_node)
+{
+ add_edge_to_graph (&(base_node->children), &(base_node->num_children),
+ &(base_node->max_children), derived_node);
+ add_edge_to_graph (&(derived_node->parents), &(derived_node->num_parents),
+ &(derived_node->max_parents), base_node);
+}
+
+static void
+update_class_hierarchy_information (tree base_class,
+ tree derived_class)
+{
+ struct vtv_graph_node *base_node = find_graph_node (base_class);
+ struct vtv_graph_node *derived_node = find_graph_node (derived_class);
+
+ add_hierarchy_pair (base_node, derived_node);
+}
+
+/* Generate an undefined variable (a reference) to a varible defined in the
+ vtv_init libraty. In that way, if the a module is not linked with the
+ vtv_init library, the linker will generate an undefined symbol error.
+ Which is much better that getting a segmentation violation at runtime.
+
+ For more information, see comments in libstdc++-v3/libsupc++/vtv_init.cc */
+static void
+create_undef_reference_to_vtv_init(tree register_pairs_body)
+{
+ const char * vtv_init_undef_var = "__vtv_defined_in_vtv_init_lib";
+ tree var_decl;
+ tree init_zero;
+
+ var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier(vtv_init_undef_var),
+ TREE_TYPE (integer_zero_node));
+ TREE_PUBLIC (var_decl) = 1;
+ DECL_EXTERNAL (var_decl) = 1;
+ TREE_STATIC (var_decl) = 1;
+ SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier(vtv_init_undef_var));
+ DECL_ARTIFICIAL (var_decl) = 1;
+ TREE_READONLY (var_decl) = 0;
+ DECL_IGNORED_P (var_decl) = 1;
+ DECL_PRESERVE_P(var_decl) = 1;
+ varpool_finalize_decl (var_decl);
+
+ /* Store a value in the undefined variable to force the creation of a
+ a reference */
+ init_zero = build2(MODIFY_EXPR, TREE_TYPE(var_decl), var_decl,
+ integer_zero_node);
+ append_to_statement_list (init_zero, ®ister_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, ®ister_pairs_body);
+ }
+
+ if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
+ create_undef_reference_to_vtv_init(register_pairs_body);
+ }
+
+ return registered_something;
+}
+
+
+/* Generate the special constructor function that calls
+ __VLTChangePermission and __VLTRegisterPairs, and give it a very
+ high initialization priority. */
+
+void
+vtv_generate_init_routine(const char * filename)
+{
+ const char * cwd = filename;
+ char temp_name[58];
+ tree register_pairs_body;
+ char * cptr;
+ int i;
+ bool vtable_classes_found = false;
+
+ /* The last part of the directory tree will be where it
+ differentiates; the first part may be the same. */
+ if (strlen (cwd) > 50)
+ {
+ int pos = (strlen (cwd) - 50);
+ cwd = cwd + pos;
+ }
+
+ /* TODO: Are these all the chars we need to map? */
+ sprintf (temp_name, "%.50s.vtable", cwd);
+ for (cptr = temp_name, i = 0;
+ (cptr[0] != '\0') && (i < 50);
+ cptr++, i++)
+ if ((cptr[0] == '/') || (cptr[0] == '-') || (cptr[0] == '+'))
+ cptr[0] = '_';
+
+ push_lang_context (lang_name_c);
+
+ /* The priority for this init function (constructor) is carefully
+ chosen so that it will happen after the calls to unprotect the
+ memory used for vtable verification and before the memory is
+ protected again */
+ register_pairs_body = start_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1,
+ (const char *) temp_name);
+
+ vtable_classes_found =
+ vtv_register_class_hierarchy_information (register_pairs_body);
+
+ if (vtable_classes_found)
+ {
+
+ current_function_decl =
+ finish_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1,
+ register_pairs_body);
+ allocate_struct_function (current_function_decl, false);
+ TREE_STATIC (current_function_decl) = 1;
+ TREE_USED (current_function_decl) = 1;
+ DECL_PRESERVE_P (current_function_decl) = 1;
+ if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+ {
+ DECL_STATIC_CONSTRUCTOR (current_function_decl) = 0;
+ assemble_vtv_preinit_initializer (current_function_decl);
+ }
+
+ gimplify_function_tree (current_function_decl);
+ cgraph_add_new_function (current_function_decl, false);
+
+ cgraph_process_new_functions ();
+ }
+ pop_lang_context ();
+}
+
+struct vtbl_map_node *
+vtable_find_or_create_map_decl (tree base_type)
+{
+ tree base_decl = TREE_CHAIN (base_type);
+ tree base_id;
+ tree var_decl = NULL;
+ char *var_name = NULL;
+ struct vtbl_map_node *vtable_map_node = NULL;
+
+
+ /* Verify the type has an associated vtable */
+ if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
+ return NULL;
+
+ if (base_decl)
+ base_id = DECL_ASSEMBLER_NAME (base_decl);
+ else
+ base_id = DECL_ASSEMBLER_NAME (TYPE_NAME (base_type));
+
+ /* Create map lookup symbol for base class */
+ var_name = ACONCAT (("_ZN4_VTVI", IDENTIFIER_POINTER (base_id),
+ "E12__vtable_mapE", NULL));
+ if (base_id)
+ /* We've already created the variable; just look it. */
+ vtable_map_node = vtbl_map_get_node (base_id);
+
+ if (!vtable_map_node || (vtable_map_node->vtbl_map_decl == NULL_TREE))
+ {
+ /* If we haven't already created the *__vtable_map
+ global variable for this class, do so now, and
+ add it to the varpool, to make sure it gets saved
+ and written out. */
+
+ char *sect_name = NULL;
+ tree var_type = build_pointer_type (void_type_node);
+ tree initial_value = build_int_cst (make_node (INTEGER_TYPE), 0);
+
+ var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (var_name),
+ var_type);
+ TREE_PUBLIC (var_decl) = 1;
+ DECL_EXTERNAL (var_decl) = 0;
+ TREE_STATIC (var_decl) = 1;
+ SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
+ DECL_ARTIFICIAL (var_decl) = 1;
+ /* We cannot mark this variable as read-only otherwise the gold
+ linker will not put it in the relro section. It seems if it
+ is marked as read-only, gold will put it in the .text
+ segment. */
+ TREE_READONLY (var_decl) = 0;
+ DECL_IGNORED_P (var_decl) = 1;
+
+ /* Put these mmap variables in to data.rel.ro sections.
+ It turns out this needs a previous fix in binutils as
+ explained here:
+ http://sourceware.org/ml/binutils/2011-05/msg00083.html */
+
+ sect_name = ACONCAT ((".data.rel.ro.", "vtable_map_vars",
+ NULL));
+ DECL_SECTION_NAME (var_decl) = build_string (strlen (sect_name),
+ sect_name);
+ DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl) = true;
+ DECL_COMDAT_GROUP (var_decl) = get_identifier (var_name);
+ DECL_INITIAL (var_decl) = initial_value;
+
+ varpool_finalize_decl (var_decl);
+ if (!vtable_map_node)
+ vtable_map_node = find_or_create_vtbl_map_node (base_type);
+ if (vtable_map_node->vtbl_map_decl == NULL_TREE)
+ vtable_map_node->vtbl_map_decl = var_decl;
+ }
+
+ gcc_assert (vtable_map_node);
+ return vtable_map_node;
+}
+
+static void
+vtv_save_base_class_info (tree type)
+{
+ if (flag_vtable_verify)
+ {
+ tree binfo = TYPE_BINFO (type);
+ tree base_binfo;
+ struct vtbl_map_node *own_map;
+ int i;
+
+ /* First make sure to create the map for this record type. */
+ own_map = vtable_find_or_create_map_decl (type);
+ if (own_map == NULL)
+ return;
+
+ /* Go through the list of all base classes for the current (derived)
+ type, make sure the *__vtable_map global variable for the base class
+ exists, and add the base class/derived class pair to the class
+ hierarchy information we are accumulating (for vtable pointer
+ verification). */
+ for (i = 0; BINFO_BASE_ITERATE(binfo, i, base_binfo); i++)
+ {
+ tree tree_val = BINFO_TYPE(base_binfo);
+ struct vtbl_map_node *vtable_map_node = NULL;
+
+ vtable_map_node = vtable_find_or_create_map_decl (tree_val);
+
+ if (vtable_map_node != NULL)
+ update_class_hierarchy_information (tree_val, type);
+ }
+ }
+}
+
+void
+vtv_save_class_info (tree record)
+{
+ if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
+ return;
+
+ gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+ vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
+}
+
+
+void
+vtv_recover_class_info (void)
+{
+ tree current_class;
+ tree class_chain = vlt_saved_class_info;
+ while (class_chain != NULL_TREE)
+ {
+ current_class = TREE_VALUE (class_chain);
+ gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+
+ vtv_save_base_class_info (current_class);
+ class_chain = TREE_CHAIN (class_chain);
+ }
+
+ /* Let GC collect the memory associated to the chain */
+ vlt_saved_class_info = NULL_TREE;
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"
Property changes on: gcc/cp/vtable-class-hierarchy.c
___________________________________________________________________
Added: svn:eol-style
+ LF
Index: gcc/cp/mangle.c
===================================================================
--- gcc/cp/mangle.c (revision 192503)
+++ gcc/cp/mangle.c (working copy)
@@ -3364,7 +3364,7 @@ mangle_decl_string (const tree decl)
/* Return an identifier for the external mangled name of DECL. */
-static tree
+tree
get_mangled_id (tree decl)
{
tree id = mangle_decl_string (decl);
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 192503)
+++ gcc/cp/cp-tree.h (working copy)
@@ -5222,6 +5222,8 @@ extern void note_vague_linkage_fn (tree
extern tree build_artificial_parm (tree, tree);
extern bool possibly_inlined_p (tree);
extern int parm_index (tree);
+extern tree start_objects (int, int, const char *);
+extern tree finish_objects (int, int, tree);
/* in error.c */
extern void init_error (void);
@@ -5309,6 +5311,7 @@ extern tree build_java_class_ref (tree)
extern tree integral_constant_value (tree);
extern tree decl_constant_value_safe (tree);
extern int diagnose_uninitialized_cst_or_ref_member (tree, bool, bool);
+extern tree build_vtbl_address (tree);
/* in lex.c */
extern void cxx_dup_lang_specific_decl (tree);
@@ -5535,6 +5538,11 @@ extern tree copied_binfo (tree, tree);
extern tree original_binfo (tree, tree);
extern int shared_member_p (tree);
+/* in vtable-class-hierarchy.c */
+extern void vtv_compute_class_hierarchy_transitive_closure (void);
+extern void vtv_generate_init_routine (const char *);
+extern void vtv_save_class_info (tree);
+extern void vtv_recover_class_info (void);
/* The representation of a deferred access check. */
@@ -6017,6 +6025,7 @@ extern tree mangle_tls_init_fn (tree);
extern tree mangle_tls_wrapper_fn (tree);
extern bool decl_tls_wrapper_p (tree);
extern tree mangle_ref_init_variable (tree);
+extern tree get_mangled_id (tree);
/* in dump.c */
extern bool cp_dump_tree (void *, tree);
Index: gcc/timevar.def
===================================================================
--- gcc/timevar.def (revision 192503)
+++ gcc/timevar.def (working copy)
@@ -251,6 +251,7 @@ DEFTIMEVAR (TV_TREE_UNINIT , "
DEFTIMEVAR (TV_PLUGIN_INIT , "plugin initialization")
DEFTIMEVAR (TV_PLUGIN_RUN , "plugin execution")
DEFTIMEVAR (TV_GIMPLE_SLSR , "straight-line strength reduction")
+DEFTIMEVAR (TV_VTABLE_VERIFICATION , "tree vtable verification")
/* Everything else in rest_of_compilation not included above. */
DEFTIMEVAR (TV_EARLY_LOCAL , "early local passes")
Index: gcc/flag-types.h
===================================================================
--- gcc/flag-types.h (revision 192503)
+++ gcc/flag-types.h (working copy)
@@ -200,4 +200,10 @@ enum fp_contract_mode {
FP_CONTRACT_FAST = 2
};
+/* flag_vtable_verify initialization levels. */
+enum vtv_priority {
+ VTV_NO_PRIORITY = 0, /* i.E. Do NOT do vtable verification. */
+ VTV_STANDARD_PRIORITY = 1,
+ VTV_PREINIT_PRIORITY = 2
+};
#endif /* ! GCC_FLAG_TYPES_H */
Index: gcc/tree-vtable-verify.c
===================================================================
--- gcc/tree-vtable-verify.c (revision 0)
+++ gcc/tree-vtable-verify.c (revision 0)
@@ -0,0 +1,1061 @@
+/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+/* Interprocedural constant propagation
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Virtual Table Pointer Security Pass. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "cp/cp-tree.h"
+#include "tm_p.h"
+#include "basic-block.h"
+#include "output.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "flags.h"
+#include "tree-inline.h"
+#include "tree-scalar-evolution.h"
+#include "diagnostic-core.h"
+#include "gimple-pretty-print.h"
+#include "toplev.h"
+#include "langhooks.h"
+
+#include "tree-vtable-verify.h"
+
+unsigned num_vtable_map_nodes = 0;
+bool any_verification_calls_generated = false;
+
+static GTY(()) tree verify_vtbl_ptr_fndecl = NULL_TREE;
+
+unsigned int vtable_verify_main (void);
+static bool gate_tree_vtable_verify (void);
+static void build_vtable_verify_fndecl (void);
+static tree my_build1 (enum tree_code, tree, tree);
+
+bool
+vtbl_map_node_registration_find (struct vtbl_map_node *node,
+ tree vtable_decl,
+ unsigned offset)
+{
+ struct vtable_registration key;
+ struct vtable_registration **slot;
+
+ gcc_assert (node);
+ gcc_assert (node->registered);
+
+ key.vtable_decl = vtable_decl;
+ slot = (struct vtable_registration **) htab_find_slot (node->registered,
+ &key, NO_INSERT);
+
+ if (slot && (*slot) && (*slot)->offsets)
+ {
+ unsigned i;
+ for (i = 0; i < (*slot)->cur_offset; ++i)
+ if ((*slot)->offsets[i] == offset)
+ return true;
+ }
+
+ return false;
+}
+
+void
+vtbl_map_node_registration_insert (struct vtbl_map_node *node,
+ tree vtable_decl,
+ unsigned offset)
+{
+ struct vtable_registration key;
+ struct vtable_registration **slot;
+
+ if (!node || !(node->registered))
+ return;
+
+ key.vtable_decl = vtable_decl;
+ slot = (struct vtable_registration **) htab_find_slot (node->registered,
+ &key, INSERT);
+
+ if (!(*slot))
+ {
+ unsigned i;
+ struct vtable_registration *node;
+ node = (struct vtable_registration *)
+ xmalloc (sizeof (struct vtable_registration));
+ node->vtable_decl = vtable_decl;
+ node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));
+ for (i= 0; i < 10; ++i)
+ node->offsets[i] = 0;
+ node->offsets[0] = offset;
+ node->cur_offset = 1;
+ node->max_offsets = 10;
+ *slot = node;
+ }
+ else
+ {
+ /* We found the vtable_decl slot; we need to see if it already
+ contains the offset. If not, we need to add the offset. */
+ unsigned i;
+ bool found = false;
+ for (i = 0; (i < (*slot)->cur_offset) && !found; ++i)
+ if ((*slot)->offsets[i] == offset)
+ found = true;
+
+ if (!found)
+ {
+ if ((*slot)->cur_offset == (*slot)->max_offsets)
+ {
+ unsigned new_max = 2 * (*slot)->max_offsets;
+ (*slot)->offsets = (unsigned *)
+ xrealloc ((*slot)->offsets, new_max * sizeof (unsigned));
+
+ for (i = (*slot)->max_offsets; i < new_max; ++i)
+ (*slot)->offsets[i] = 0;
+ (*slot)->max_offsets = new_max;
+ }
+ (*slot)->offsets[(*slot)->cur_offset] = offset;
+ (*slot)->cur_offset = (*slot)->cur_offset + 1;
+ }
+ }
+}
+
+/* Hashtable functions for vtable_registration hashtables. */
+
+static hashval_t
+hash_vtable_registration (const void * p)
+{
+ const struct vtable_registration *n = (const struct vtable_registration *) p;
+ return (hashval_t) (DECL_UID (n->vtable_decl));
+}
+
+static int
+eq_vtable_registration (const void *p1, const void *p2)
+{
+ const struct vtable_registration *n1 =
+ (const struct vtable_registration *) p1;
+ const struct vtable_registration *n2 =
+ (const struct vtable_registration *) p2;
+ return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
+}
+
+/* End of hashtable functions for "registered" hashtables*/
+
+/* Hashtable functions for vtable_map variables hashtable. */
+
+static htab_t vtbl_map_hash = NULL;
+struct vtbl_map_node *vtbl_map_nodes = NULL;
+struct vtbl_map_node **vtbl_map_nodes_array = NULL;
+
+static void
+vtable_map_array_insert (struct vtbl_map_node *node)
+{
+ static unsigned array_size = 0;
+ unsigned i;
+
+ if (vtbl_map_nodes_array == NULL
+ || array_size == 0)
+ {
+ array_size = 16;
+ vtbl_map_nodes_array = (struct vtbl_map_node **)
+ xmalloc (array_size * sizeof (struct vtbl_map_node *));
+ memset (vtbl_map_nodes_array, 0,
+ array_size * sizeof (struct vtbl_map_node *));
+ }
+ else if (node->uid >= array_size)
+ {
+ unsigned new_size = 2 * array_size;
+ vtbl_map_nodes_array = (struct vtbl_map_node **)
+ xrealloc (vtbl_map_nodes_array,
+ new_size * sizeof (struct vtbl_map_node *));
+
+ for (i = array_size; i < new_size; ++i)
+ vtbl_map_nodes_array[i] = NULL;
+
+ array_size = new_size;
+ }
+
+ gcc_assert (node->uid < array_size);
+ gcc_assert (vtbl_map_nodes_array[node->uid] == NULL);
+
+ vtbl_map_nodes_array[node->uid] = node;
+}
+
+/* Returns a hash code for P. */
+static hashval_t
+hash_vtbl_map_node (const void *p)
+{
+ const struct vtbl_map_node *n = (const struct vtbl_map_node *) p;
+ return (hashval_t) IDENTIFIER_HASH_VALUE (n->class_name);
+}
+
+/* Returns nonzero if P1 and P2 are equal. */
+static int
+eq_vtbl_map_node (const void *p1, const void *p2)
+{
+ const struct vtbl_map_node *n1 = (const struct vtbl_map_node *) p1;
+ const struct vtbl_map_node *n2 = (const struct vtbl_map_node *) p2;
+ return (IDENTIFIER_HASH_VALUE (n1->class_name) ==
+ IDENTIFIER_HASH_VALUE (n2->class_name));
+}
+
+/* Return vtbl_map node assigned to DECL without creating a new one. */
+struct vtbl_map_node *
+vtbl_map_get_node (const_tree class_name)
+{
+ struct vtbl_map_node key;
+ struct vtbl_map_node **slot;
+
+ if (!vtbl_map_hash)
+ return NULL;
+
+ key.class_name = CONST_CAST2 (tree, const_tree, class_name);
+ slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+ NO_INSERT);
+ if (!slot)
+ return NULL;
+ return *slot;
+}
+
+/* Return vtbl_map node assigned to BASE_CLASS_TYPE. Create new one
+ when needed. */
+struct vtbl_map_node *
+find_or_create_vtbl_map_node (tree base_class_type)
+{
+ struct vtbl_map_node key;
+ struct vtbl_map_node *node;
+ struct vtbl_map_node **slot;
+ unsigned i;
+
+ if (!vtbl_map_hash)
+ vtbl_map_hash = htab_create (10, hash_vtbl_map_node,
+ eq_vtbl_map_node, NULL);
+
+ if (TREE_CHAIN (base_class_type))
+ key.class_name = DECL_ASSEMBLER_NAME (TREE_CHAIN (base_class_type));
+ else
+ key.class_name = DECL_ASSEMBLER_NAME (TYPE_NAME (base_class_type));
+ slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+ INSERT);
+ if (*slot)
+ return *slot;
+
+ node = (struct vtbl_map_node *) xmalloc (sizeof (struct vtbl_map_node));
+ node->vtbl_map_decl = NULL_TREE;
+ node->class_name = key.class_name;
+ node->uid = num_vtable_map_nodes++;
+
+ node->class_info = (struct vtv_graph_node *)
+ xmalloc (sizeof (struct vtv_graph_node));
+ node->class_info->class_type = base_class_type;
+ node->class_info->class_uid = node->uid;
+ node->class_info->max_parents = 4;
+ node->class_info->max_children = 4;
+ node->class_info->num_parents = 0;
+ node->class_info->num_children = 0;
+ node->class_info->num_processed_children = 0;
+ node->class_info->parents = (struct vtv_graph_node **)
+ xmalloc (4 * sizeof (struct vtv_graph_node *));
+ node->class_info->children = (struct vtv_graph_node **)
+ xmalloc (4 * sizeof (struct vtv_graph_node *));
+ for (i = 0; i < 4; ++i)
+ {
+ node->class_info->parents[i] = NULL;
+ node->class_info->children[i] = NULL;
+ }
+
+ node->registered = htab_create (16, hash_vtable_registration,
+ eq_vtable_registration, NULL);
+ node->is_used = false;
+ node->next = vtbl_map_nodes;
+ if (vtbl_map_nodes)
+ vtbl_map_nodes->prev = node;
+
+ vtable_map_array_insert (node);
+
+ vtbl_map_nodes = node;
+ *slot = node;
+ return node;
+}
+
+/* End of hashtable functions for vtable_map variables hash table. */
+
+static tree
+my_build1 (enum tree_code code, tree type, tree node MEM_STAT_DECL)
+{
+ int length = sizeof (struct tree_exp);
+#ifdef GATHER_STATISTICS
+ tree_node_kind kind;
+#endif
+ tree t;
+
+#ifdef GATHER_STATISTICS
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_statement: /* an expression with side effects */
+ kind = s_kind;
+ break;
+ case tcc_reference: /* a reference */
+ kind = r_kind;
+ break;
+ default:
+ kind = e_kind;
+ break;
+ }
+
+ tree_node_counts[(int) kind]++;
+ tree_node_sizes[(int) kind] += length;
+#endif
+
+ gcc_assert (TREE_CODE_LENGTH (code) == 1);
+
+ t = ggc_alloc_zone_tree_node_stat (&tree_zone, length PASS_MEM_STAT);
+
+ memset (t, 0, sizeof (struct tree_common));
+
+ TREE_SET_CODE (t, code);
+
+ TREE_TYPE (t) = type;
+ SET_EXPR_LOCATION (t, UNKNOWN_LOCATION);
+ TREE_OPERAND (t, 0) = node;
+ if (node && !TYPE_P (node))
+ {
+ TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (node);
+ TREE_READONLY (t) = TREE_READONLY (node);
+ }
+
+ if (TREE_CODE_CLASS (code) == tcc_statement)
+ TREE_SIDE_EFFECTS (t) = 1;
+ else switch (code)
+ {
+ case VA_ARG_EXPR:
+ /* All of these have side-effects, no matter what their
+ operands are. */
+ TREE_SIDE_EFFECTS (t) = 1;
+ TREE_READONLY (t) = 0;
+ break;
+
+ case INDIRECT_REF:
+ /* Whether a dereference is readonly has nothing to do with whether
+ its operand is readonly. */
+ TREE_READONLY (t) = 0;
+ break;
+
+ case ADDR_EXPR:
+ if (node)
+ recompute_tree_invariant_for_addr_expr (t);
+ break;
+
+ default:
+ if ((TREE_CODE_CLASS (code) == tcc_unary || code == VIEW_CONVERT_EXPR)
+ && node && !TYPE_P (node)
+ && TREE_CONSTANT (node))
+ TREE_CONSTANT (t) = 1;
+ if (TREE_CODE_CLASS (code) == tcc_reference
+ && node && TREE_THIS_VOLATILE (node))
+ TREE_THIS_VOLATILE (t) = 1;
+ break;
+ }
+
+ return t;
+}
+
+static int
+type_name_is_vtable_pointer (tree node)
+{
+
+ if (TYPE_NAME (node))
+ {
+ if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
+ return (strcmp (IDENTIFIER_POINTER (TYPE_NAME (node)),
+ "__vtbl_ptr_type") == 0);
+ else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
+ && DECL_NAME (TYPE_NAME (node)))
+ return (strcmp (IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node))),
+ "__vtbl_ptr_type") == 0);
+ else
+ return 0;
+ }
+
+ return 0;
+}
+
+static int
+is_vtable_assignment_stmt (gimple stmt)
+{
+
+ if (gimple_code (stmt) != GIMPLE_ASSIGN)
+ return 0;
+ else
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+
+ if (TREE_CODE (lhs) != SSA_NAME)
+ return 0;
+
+ if (TREE_CODE (TREE_TYPE (lhs)) != POINTER_TYPE)
+ return 0;
+
+ if (TREE_CODE (TREE_TYPE (TREE_TYPE (lhs))) != POINTER_TYPE)
+ return 0;
+
+ if (! type_name_is_vtable_pointer (TREE_TYPE (TREE_TYPE (lhs))))
+ return 0;
+
+
+ if (TREE_CODE (rhs) != COMPONENT_REF)
+ return 0;
+
+ if (! (TREE_OPERAND (rhs, 1))
+ || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
+ return 0;
+
+ if (! (DECL_NAME (TREE_OPERAND (rhs, 1)))
+ || (strncmp (IDENTIFIER_POINTER (DECL_NAME (TREE_OPERAND (rhs, 1))),
+ "_vptr.", 6) != 0))
+ return 0;
+
+ while ((TREE_OPERAND (rhs, 0))
+ && (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF))
+ rhs = TREE_OPERAND (rhs, 0);
+
+ if (! (TREE_OPERAND (rhs, 0))
+ || (TREE_CODE (TREE_OPERAND (rhs, 0)) != MEM_REF))
+ return 0;
+ }
+
+ return 1;
+}
+
+static tree
+my_get_vtbl_decl_for_binfo (tree binfo)
+{
+ tree decl;
+
+ decl = BINFO_VTABLE (binfo);
+ if (decl && TREE_CODE (decl) == POINTER_PLUS_EXPR)
+ {
+ gcc_assert (TREE_CODE (TREE_OPERAND (decl, 0)) == ADDR_EXPR);
+ decl = TREE_OPERAND (TREE_OPERAND (decl, 0), 0);
+ }
+ if (decl)
+ gcc_assert (TREE_CODE (decl) == VAR_DECL);
+
+ return decl;
+}
+
+/* STMT is a gimple statment that uses OLD_VAR. This function finds the
+ use of OLD_VAR in STMT and replaces it with NEW_VAR. STMT is either
+ an assignment statement or a call statement. */
+
+static bool
+find_and_replace_var (gimple stmt, tree old_var, tree new_var)
+{
+ bool found = false;
+
+ if (!stmt || ! old_var || !new_var)
+ return found;
+
+ if ((TREE_CODE (old_var) != SSA_NAME)
+ || (TREE_CODE (new_var) != SSA_NAME))
+ return found;
+
+ if (gimple_code (stmt) == GIMPLE_ASSIGN)
+ {
+ if (get_gimple_rhs_class (gimple_expr_code (stmt)) == GIMPLE_SINGLE_RHS)
+ {
+ if (TREE_CODE (gimple_assign_rhs1 (stmt)) == SSA_NAME
+ && (gimple_assign_rhs1 (stmt) == old_var))
+ {
+ gimple_assign_set_rhs1 (stmt, new_var);
+ found = true;
+ }
+ else if (TREE_CODE (gimple_assign_rhs1 (stmt)) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (gimple_assign_rhs1 (stmt), 0))
+ == SSA_NAME)
+ {
+ if (TREE_OPERAND (gimple_assign_rhs1 (stmt), 0) == old_var)
+ {
+ tree mr_type = TREE_TYPE (gimple_assign_rhs1 (stmt));
+ tree mem_ref = build2 (MEM_REF, mr_type, new_var,
+ TREE_OPERAND
+ (gimple_assign_rhs1 (stmt), 1));
+ gimple_assign_set_rhs1 (stmt, mem_ref);
+ found = true;
+ }
+ }
+ }
+ else if (get_gimple_rhs_class (gimple_expr_code (stmt))
+ != GIMPLE_SINGLE_RHS)
+ {
+ if (gimple_assign_rhs1 (stmt) == old_var)
+ {
+ gimple_assign_set_rhs1 (stmt, new_var);
+ found = true;
+ }
+ else if (gimple_assign_rhs2 (stmt) == old_var)
+ {
+ gimple_assign_set_rhs2 (stmt, new_var);
+ found = true;
+ }
+ }
+ }
+ else if ((gimple_code (stmt) == GIMPLE_CALL)
+ && (TREE_CODE (gimple_call_fn (stmt)) == OBJ_TYPE_REF)
+ && (TREE_OPERAND (gimple_call_fn (stmt), 0) == old_var))
+ {
+ TREE_OPERAND (gimple_call_fn (stmt), 0) = new_var;
+ found = true;
+ }
+
+ if (found)
+ update_stmt (stmt);
+
+ return found;
+}
+
+/* Given a PHI_STMT, this function searches backwards find a def_stmt for
+ one of the PHI_STMT's args, which defines an SSA_NAME. It returns the
+ def_stmt. */
+
+static gimple
+get_phi_def_stmt (gimple phi_stmt)
+{
+ /* This function is based on the assumption that all arguments of a
+ phi variable are really variations of the same variable, and
+ therefore must have the same type, so it doesn't matter which phi
+ argument we use to find the variable's type. Therefore we will
+ use the first argument that is an SSA_NAME. */
+
+ phi_arg_d *phi_arg = NULL;
+ tree phi_ssa;
+ unsigned i;
+
+ if (gimple_code (phi_stmt) != GIMPLE_PHI)
+ return NULL;
+
+ for (i = 0; i < gimple_phi_num_args (phi_stmt); i++)
+ {
+ phi_arg = gimple_phi_arg (phi_stmt, i);
+ phi_ssa = phi_arg->def;
+ if (TREE_CODE (phi_ssa) == SSA_NAME)
+ break;
+ }
+
+ gcc_assert (TREE_CODE (phi_ssa) == SSA_NAME);
+
+ return SSA_NAME_DEF_STMT (phi_ssa);
+}
+
+/* Search through all the statements in a basic block, searching for
+ virtual method calls. For each virtual method dispatch, find the
+ vptr value used, and the statically declared type of the object;
+ retrieve the vtable map variable for the type of the object;
+ generate a call to __VLTVerifyVtablePointer; and insert the
+ generated call into the basic block, after the point where the vptr
+ value is gotten out of the object and before the virtual method
+ dispatch. Make the virtual method dispatch depend on the return
+ value from the verification call, so that subsequent optimizations
+ cannot reorder the two calls. */
+
+static void
+verify_bb_vtables (basic_block bb)
+{
+ gimple_seq stmts;
+ gimple stmt = NULL;
+ gimple_stmt_iterator gsi_vtbl_assign;
+ gimple_stmt_iterator gsi_virtual_call;
+ tree this_object;
+
+ /* Search the basic block to see if it contains a virtual method
+ call, i.e. a call with the tree code OBJ_TYPE_REF */
+
+ stmts = bb_seq (bb);
+ gsi_virtual_call = gsi_start (stmts);
+ this_object = NULL_TREE;
+ for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
+ {
+ stmt = gsi_stmt (gsi_virtual_call);
+ if (gimple_code (stmt) == GIMPLE_CALL)
+ {
+ tree fncall = gimple_call_fn (stmt);
+ if (TREE_CODE (fncall) == OBJ_TYPE_REF)
+ {
+ bool found = false;
+ tree vtable_offset_var = NULL_TREE;
+ gimple def_stmt;
+ gimple prev_use = NULL;
+
+ /* The first argument to the function must be "this", a pointer
+ to the object itself. */
+
+ this_object = gimple_call_arg (stmt, 0);
+
+ /* Get the SSA variable that contains the dereferenced _vptr
+ field + table start offset. */
+
+ if (TREE_OPERAND (fncall, 0)
+ && TREE_CODE (TREE_OPERAND (fncall, 0)) == SSA_NAME)
+ {
+ tree rhs = NULL_TREE;
+ gimple phi_stmt = NULL;
+ gimple phi_prev_use = NULL;
+ bool found_phi = false;
+
+ vtable_offset_var = TREE_OPERAND (fncall, 0);
+
+ prev_use = stmt;
+ def_stmt = SSA_NAME_DEF_STMT (vtable_offset_var);
+
+ /* Search backwards through the def_stmt chain, to try
+ to find the assignment statement where the rhs of
+ the assignment contains the "._vptr" field (the vtable
+ pointer). */
+
+ while (gimple_code (def_stmt) == GIMPLE_PHI)
+ {
+ if (!found_phi)
+ {
+ phi_prev_use = prev_use;
+ phi_stmt = def_stmt;
+ found_phi = true;
+ }
+ def_stmt = get_phi_def_stmt (def_stmt);
+ }
+
+ gcc_assert (def_stmt != NULL);
+ gcc_assert (gimple_code (def_stmt) == GIMPLE_ASSIGN);
+
+ if (gimple_assign_lhs (def_stmt)
+ && TREE_CODE (gimple_assign_lhs (def_stmt)) == SSA_NAME
+ && get_gimple_rhs_class (gimple_expr_code (def_stmt))
+ == GIMPLE_SINGLE_RHS)
+ rhs = gimple_assign_rhs1 (def_stmt);
+
+ if (rhs
+ && TREE_CODE (rhs) == MEM_REF
+ && TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
+ {
+ prev_use = def_stmt;
+ def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (rhs, 0));
+ }
+
+
+ if (gimple_code (def_stmt) == GIMPLE_PHI)
+ {
+ if (!found_phi)
+ {
+ phi_prev_use = prev_use;
+ phi_stmt = def_stmt;
+ found_phi = true;
+ }
+ def_stmt = get_phi_def_stmt (def_stmt);
+ }
+
+ while (def_stmt
+ && !is_vtable_assignment_stmt (def_stmt))
+ {
+ tree lhs = gimple_assign_lhs (def_stmt);
+ if (!lhs
+ || !TREE_CODE (lhs) == SSA_NAME)
+ {
+ def_stmt = NULL;
+ break;
+ }
+ if (! def_stmt)
+ break;
+
+ if (gimple_assign_rhs1 (def_stmt)
+ && TREE_CODE (gimple_assign_rhs1 (def_stmt))
+ == SSA_NAME)
+ {
+ prev_use = def_stmt;
+ rhs = gimple_assign_rhs1 (def_stmt);
+ def_stmt = SSA_NAME_DEF_STMT (rhs);
+ }
+ else if ((get_gimple_rhs_class
+ (gimple_expr_code (def_stmt))
+ != GIMPLE_SINGLE_RHS)
+ && gimple_assign_rhs2 (def_stmt)
+ && TREE_CODE (gimple_assign_rhs2 (def_stmt))
+ == SSA_NAME)
+ {
+ prev_use = def_stmt;
+ rhs = gimple_assign_rhs2 (def_stmt);
+ def_stmt = SSA_NAME_DEF_STMT (rhs);
+ }
+ else
+ def_stmt = NULL;
+
+ if (!def_stmt)
+ break;
+
+ if (def_stmt != NULL
+ && gimple_code (def_stmt) == GIMPLE_PHI)
+ {
+ if (!found_phi)
+ {
+ phi_prev_use = prev_use;
+ phi_stmt = def_stmt;
+ found_phi = true;
+ }
+ def_stmt = get_phi_def_stmt (def_stmt);
+ }
+ }
+
+ /* If we found the vtable pointer assignment statement by
+ itself, we also need to find it within the basic block
+ statement sequence, so that we can insert our statements
+ into the sequence.
+
+ The following loop looks for the assignment statement
+ within the basic block's sequence of statements. */
+
+ if (def_stmt
+ && is_vtable_assignment_stmt (def_stmt))
+ {
+ basic_block def_bb;
+ gimple_seq def_bb_stmts;
+
+ if (found_phi)
+ def_bb = gimple_bb (phi_stmt);
+ else
+ def_bb = gimple_bb (def_stmt);
+
+ def_bb_stmts = bb_seq (def_bb);
+
+ if (found_phi)
+ {
+ /* Insertion point is first stmt in bb */
+ gsi_vtbl_assign = gsi_after_labels (def_bb);
+ found = true;
+ }
+ else
+ gsi_vtbl_assign = gsi_start (def_bb_stmts);
+
+ for (; !gsi_end_p (gsi_vtbl_assign) && !found;
+ gsi_next (&gsi_vtbl_assign))
+ {
+ stmt = gsi_stmt (gsi_vtbl_assign);
+ if (stmt == def_stmt)
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ tree object_rhs = TREE_TYPE (this_object);
+ tree lhs;
+ tree vtbl_var_decl = NULL_TREE;
+ tree vtbl = NULL_TREE;
+ tree var_id;
+ gimple_seq pre_p = NULL;
+ struct vtbl_map_node *vtable_map_node = NULL;
+ tree vtbl_decl = NULL_TREE;
+
+
+ if (found_phi)
+ lhs = gimple_phi_result (phi_stmt);
+ else
+ lhs = gimple_assign_lhs (stmt);
+
+ /* Now we have found the virtual method dispatch
+ and the preceding access of the _vptr.*
+ field... Now we need to find the vtable for
+ the base class (statically declared type) of
+ the object, so we can use the right vtable
+ map variable. */
+
+ found = true;
+ rhs = gimple_assign_rhs1 (def_stmt);
+
+ /* First try to get the type out of the 'this'
+ object. */
+ if (TREE_CODE (object_rhs) == POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (object_rhs))
+ == RECORD_TYPE)
+ rhs = TREE_TYPE (object_rhs);
+ else if (TREE_CODE (object_rhs) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (object_rhs))
+ == RECORD_TYPE)
+ rhs = TREE_TYPE (object_rhs);
+ /* The type of the 'this' object is not usable
+ (usually due to optimizations); try to get the
+ type out of the rhs of the vtable pointer
+ assignment statement. */
+ else if (TREE_CODE (rhs) == COMPONENT_REF)
+ {
+ while (TREE_CODE (TREE_OPERAND (rhs, 0))
+ == COMPONENT_REF)
+ rhs = TREE_OPERAND (rhs, 0);
+ if (TREE_CODE (rhs) == COMPONENT_REF
+ && (TREE_CODE (TREE_OPERAND (rhs, 0))
+ == MEM_REF)
+ && (TREE_CODE (TREE_TYPE
+ (TREE_OPERAND (rhs, 0)))
+ == RECORD_TYPE))
+ rhs = TREE_TYPE (TREE_OPERAND (rhs, 0));
+ else
+ rhs = NULL_TREE;
+ }
+ else
+ rhs = NULL_TREE;
+
+ /* Make sure we found a valid type...*/
+ if (rhs
+ && TREE_CODE (rhs) == RECORD_TYPE
+ && TYPE_BINFO (rhs))
+ {
+ /* Get the vtable for the type. */
+ vtbl_var_decl = my_get_vtbl_decl_for_binfo
+ (TYPE_BINFO (rhs));
+ vtbl = BINFO_VTABLE (TYPE_BINFO (rhs));
+
+ if (!vtbl_var_decl || !vtbl)
+ /* Problem: This does NOT end up checking
+ virtual functions if there is NO
+ inheritance involved. */
+ continue;
+
+ vtbl_decl = vtbl_var_decl;
+
+ if (TREE_CODE (TREE_TYPE (vtbl)) == POINTER_TYPE)
+ force_gimple_operand (vtbl, &pre_p, 1, NULL);
+
+ if (TREE_CHAIN (rhs))
+ var_id = DECL_ASSEMBLER_NAME (TREE_CHAIN
+ (rhs));
+ else
+ var_id = DECL_ASSEMBLER_NAME (TYPE_NAME (rhs));
+
+ vtable_map_node = vtbl_map_get_node (var_id);
+ if (vtable_map_node)
+ {
+ vtbl_var_decl =
+ vtable_map_node->vtbl_map_decl;
+ vtable_map_node->is_used = true;
+ }
+ else
+ vtbl_var_decl = NULL;
+ }
+
+ /* Build verify_vtbl_ptr_fndecl */
+
+ build_vtable_verify_fndecl ();
+
+ /* Given the vtable pointer for the base
+ class of the object, build the call to
+ __VLTVerifyVtablePointer to verify that
+ the object's vtable pointer (contained in
+ lhs) is in the set of valid vtable
+ pointers for the base class. */
+
+ if (verify_vtbl_ptr_fndecl && vtbl_var_decl)
+ {
+ tree expr_tree = NULL_TREE;
+ struct gimplify_ctx gctx;
+ const char *vtable_name = "<unknown>";
+ gimple call_stmt;
+ gimple assign_stmt;
+ tree tmp0;
+ bool status;
+
+ int len1 = 0;
+ int len2 = 0;
+
+ if (TREE_CODE (vtbl_decl) == VAR_DECL)
+ vtable_name = IDENTIFIER_POINTER
+ (DECL_NAME (vtbl_decl));
+
+ push_gimplify_context (&gctx);
+ len1 = strlen (IDENTIFIER_POINTER
+ (DECL_NAME (vtbl_var_decl)));
+ len2 = strlen (vtable_name);
+
+ /* Call different routines if we are
+ interested in trace information to
+ triage problems */
+#ifdef VTV_DEBUG
+ expr_tree = build_call_expr
+ (verify_vtbl_ptr_fndecl, 6,
+ my_build1 (ADDR_EXPR,
+ TYPE_POINTER_TO
+ (TREE_TYPE (vtbl_var_decl)),
+ vtbl_var_decl),
+ lhs,
+ build_string_literal
+ (len1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (vtbl_var_decl))),
+ build_int_cst (integer_type_node,
+ len1),
+ build_string_literal (len2, vtable_name),
+ build_int_cst (integer_type_node,
+ len2));
+#else
+ expr_tree = build_call_expr
+ (verify_vtbl_ptr_fndecl, 2,
+ my_build1 (ADDR_EXPR,
+ TYPE_POINTER_TO
+ (TREE_TYPE (vtbl_var_decl)),
+ vtbl_var_decl),
+ lhs);
+#endif
+
+ /* Assign the result of the call to the
+ original variable receiving the
+ assignment of the object's vtable
+ pointer; mark that variable to be
+ updated by update_ssa. */
+
+ cfun->gimple_df->ssa_renaming_needed = 1;
+
+ /* Insert the new call just after the
+ original assignment of the object's
+ vtable pointer. */
+
+ tmp0 = make_temp_ssa_name (TREE_TYPE (lhs),
+ NULL, "VTV");
+ assign_stmt = gimplify_assign (tmp0, expr_tree,
+ &pre_p);
+
+ if (found_phi)
+ prev_use = phi_prev_use;
+
+ status = find_and_replace_var (prev_use, lhs,
+ tmp0);
+ update_stmt (assign_stmt);
+ gcc_assert (status == true);
+ pop_gimplify_context (NULL);
+
+ if (found_phi)
+ gsi_insert_seq_before (&gsi_vtbl_assign,
+ pre_p, GSI_NEW_STMT);
+ else
+ gsi_insert_seq_after (&gsi_vtbl_assign, pre_p,
+ GSI_NEW_STMT);
+ any_verification_calls_generated = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+build_vtable_verify_fndecl (void)
+{
+ tree void_ptr_type = build_pointer_type (void_type_node);
+ tree arg_types = NULL_TREE;
+ tree type = build_pointer_type (void_type_node);
+ struct lang_decl *ld;
+#ifdef VTV_DEBUG
+ tree char_ptr_type = build_pointer_type (char_type_node);
+#endif
+
+ if (verify_vtbl_ptr_fndecl != NULL_TREE)
+ return;
+
+ ld = ggc_alloc_cleared_lang_decl (sizeof (struct lang_decl_fn));
+ ld->u.base.selector = 1;
+
+ arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_ptr_type));
+
+#ifdef VTV_DEBUG
+ /* Start: Arg types to be removed when we remove debugging parameters from
+ the library function. */
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ integer_type_node));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, char_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ integer_type_node));
+ /* End: Arg types to be removed...*/
+#endif
+
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+ type = build_function_type (type, arg_types);
+
+#ifdef VTV_DEBUG
+ verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointerDebug",
+ type);
+#else
+ verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointer", type);
+#endif
+
+ TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
+ DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
+ = tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
+ TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
+ DECL_PRESERVE_P (verify_vtbl_ptr_fndecl) = 1;
+ DECL_LANG_SPECIFIC (verify_vtbl_ptr_fndecl) = ld;
+ SET_DECL_LANGUAGE (verify_vtbl_ptr_fndecl, lang_cplusplus);
+}
+
+unsigned int
+vtable_verify_main (void)
+{
+ unsigned int ret = 1;
+ basic_block bb;
+
+ FOR_ALL_BB (bb)
+ verify_bb_vtables (bb);
+
+ return ret;
+}
+
+static bool
+gate_tree_vtable_verify (void)
+{
+ return (flag_vtable_verify
+ && (strcmp (lang_hooks.name, "GNU C++") == 0));
+}
+
+struct gimple_opt_pass pass_vtable_verify =
+{
+ {
+ GIMPLE_PASS,
+ "vtable-verify", /* name */
+ gate_tree_vtable_verify, /* gate */
+ vtable_verify_main, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_VTABLE_VERIFICATION, /* tv_id */
+ PROP_cfg | PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_update_ssa
+ | TODO_ggc_collect /* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-vtable-verify.h"
Property changes on: gcc/tree-vtable-verify.c
___________________________________________________________________
Added: svn:eol-style
+ LF
Index: gcc/tree-vtable-verify.h
===================================================================
--- gcc/tree-vtable-verify.h (revision 0)
+++ gcc/tree-vtable-verify.h (revision 0)
@@ -0,0 +1,81 @@
+/* Interprocedural constant propagation
+ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Virtual Table Pointer Security. */
+
+#ifndef TREE_VTABLE_VERIFY_H
+#define TREE_VTABLE_VERIFY_H
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "hashtab.h"
+#include "sbitmap.h"
+
+extern unsigned num_vtable_map_nodes;
+extern bool any_verification_calls_generated;
+
+struct vtable_registration
+{
+ tree vtable_decl;
+ unsigned max_offsets;
+ unsigned cur_offset;
+ unsigned *offsets;
+};
+
+struct vtv_graph_node {
+ tree class_type;
+ unsigned class_uid;
+ unsigned max_parents;
+ unsigned max_children;
+ unsigned num_parents;
+ unsigned num_children;
+ unsigned num_processed_children;
+ struct vtv_graph_node **parents;
+ struct vtv_graph_node **children;
+ sbitmap descendants;
+};
+
+struct vtbl_map_node {
+ tree vtbl_map_decl;
+ tree class_name;
+ struct vtv_graph_node *class_info;
+ unsigned uid;
+ struct vtbl_map_node *next, *prev;
+ htab_t registered;
+ bool is_used;
+};
+
+extern struct vtbl_map_node *vtbl_map_nodes;
+extern struct vtbl_map_node **vtbl_map_nodes_array;
+
+extern struct vtbl_map_node *vtbl_map_get_node (const_tree);
+extern struct vtbl_map_node *find_or_create_vtbl_map_node (tree);
+extern void vtbl_map_node_class_insert (struct vtbl_map_node *, unsigned);
+extern bool vtbl_map_node_registration_find (struct vtbl_map_node *,
+ tree, unsigned);
+extern void vtbl_map_node_registration_insert (struct vtbl_map_node *,
+ tree, unsigned);
+
+#endif /* TREE_VTABLE_VERIFY_H */
Property changes on: gcc/tree-vtable-verify.h
___________________________________________________________________
Added: svn:eol-style
+ LF
Index: gcc/common.opt
===================================================================
--- gcc/common.opt (revision 192503)
+++ gcc/common.opt (working copy)
@@ -2253,6 +2253,22 @@ Enum(symbol_visibility) String(hidden) V
EnumValue
Enum(symbol_visibility) String(protected) Value(VISIBILITY_PROTECTED)
+fvtable-verify=
+Common Joined RejectNegative Enum(vtv_priority) Var(flag_vtable_verify) Init(VTV_NO_PRIORITY)
+Validate vtable pointers before using them.
+
+Enum
+Name(vtv_priority) Type(enum vtv_priority) UnknownError(unknown vtable verify initialization priority %qs)
+
+EnumValue
+Enum(vtv_priority) String(none) Value(VTV_NO_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(std) Value(VTV_STANDARD_PRIORITY)
+
+EnumValue
+Enum(vtv_priority) String(preinit) Value(VTV_PREINIT_PRIORITY)
+
fvpt
Common Report Var(flag_value_profile_transformations) Optimization
Use expression value profiles in optimizations
Index: gcc/varasm.c
===================================================================
--- gcc/varasm.c (revision 192503)
+++ gcc/varasm.c (working copy)
@@ -2018,13 +2018,44 @@ assemble_variable (tree decl, int top_le
assemble_noswitch_variable (decl, name, sect);
else
{
- switch_to_section (sect);
+ if (flag_vtable_verify)
+ {
+ if (strstr (name, "__vtable_map"))
+ {
+#if defined (OBJECT_FORMAT_ELF)
+ targetm.asm_out.named_section (sect->named.name,
+ sect->named.common.flags
+ | SECTION_LINKONCE,
+ DECL_NAME (decl));
+ in_section = sect;
+#else
+ switch_to_section (sect);
+#endif
+ }
+ else
+ switch_to_section (sect);
+ }
+ else
+ switch_to_section (sect);
if (DECL_ALIGN (decl) > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
assemble_variable_contents (decl, name, dont_output_data);
}
}
+void
+assemble_vtv_preinit_initializer (tree fn_decl)
+{
+ section *sect;
+ unsigned flags = SECTION_WRITE;
+ rtx symbol = XEXP (DECL_RTL (fn_decl), 0);
+
+ flags |= SECTION_NOTYPE;
+ sect = get_section (".preinit_array", flags, fn_decl);
+ switch_to_section (sect);
+ assemble_addr_to_section (symbol, sect);
+}
+
/* Return 1 if type TYPE contains any pointers. */
static int
Index: gcc/output.h
===================================================================
--- gcc/output.h (revision 192503)
+++ gcc/output.h (working copy)
@@ -199,6 +199,10 @@ extern void assemble_end_function (tree,
initial value (that will be done by the caller). */
extern void assemble_variable (tree, int, int, int);
+/* Make sure the vtable verification constructor initialization function
+ goes into the preinit array. */
+extern void assemble_vtv_preinit_initializer (tree);
+
/* Compute the alignment of variable specified by DECL.
DONT_OUTPUT_DATA is from assemble_variable. */
extern void align_variable (tree decl, bool dont_output_data);
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in (revision 192503)
+++ gcc/Makefile.in (working copy)
@@ -1424,6 +1424,7 @@ OBJS = \
tree-vect-loop-manip.o \
tree-vect-slp.o \
tree-vectorizer.o \
+ tree-vtable-verify.o \
tree-vrp.o \
tree.o \
valtrack.o \
@@ -2578,6 +2579,11 @@ tree-vectorizer.o: tree-vectorizer.c $(C
dumpfile.h $(TM_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \
$(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) \
$(TREE_PRETTY_PRINT_H)
+tree-vtable-verify.o: tree-vtable-verify.c tree-vtable-verify.h $(CONFIG_H) \
+ $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) cp/cp-tree.h $(TM_P_H) \
+ $(BASIC_BLOCK_H) output.h $(TREE_FLOW_H) $(TREE_DUMP_H) $(TREE_PASS_H) \
+ $(TIMEVAR_H) $(CFGLOOP_H) $(FLAGS_H) $(TREE_INLINE_H) $(SCEV_H) \
+ $(DIAGNOSTIC_CORE_H) $(GIMPLE_PRETTY_PRINT_H) toplev.h langhooks.h
tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TREE_FLOW_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(TREE_PASS_H)
tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
@@ -3676,6 +3682,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/inp
$(srcdir)/lto-streamer.h \
$(srcdir)/target-globals.h \
$(srcdir)/ipa-inline.h \
+ $(srcdir)/tree-vtable-verify.c \
@all_gtfiles@
# Compute the list of GT header files from the corresponding C sources,
Index: gcc/passes.c
===================================================================
--- gcc/passes.c (revision 192503)
+++ gcc/passes.c (working copy)
@@ -1543,6 +1543,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_tm_memopt);
NEXT_PASS (pass_tm_edges);
}
+ NEXT_PASS (pass_vtable_verify);
NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_cleanup_eh);
NEXT_PASS (pass_lower_resx);
next reply other threads:[~2012-11-05 17:49 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-05 17:49 Caroline Tice [this message]
2012-11-07 16:58 ` Xinliang David Li
2012-11-16 18:21 ` Caroline Tice
[not found] ` <CABtf2+SnpddRF9kHsY-CyxNbS+3iQrUM7dqtZmbGJMNkS_WvBw@mail.gmail.com>
2012-11-28 16:17 ` Fwd: " Diego Novillo
2012-11-29 18:34 ` Jason Merrill
2012-11-29 18:35 ` Jason Merrill
2012-11-08 9:36 ` Florian Weimer
2012-11-08 16:56 ` Caroline Tice
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CABtf2+SdU_aWMj-v6J=WM8onenUX0UZY72bdKj2a4JEtUXe-pw@mail.gmail.com' \
--to=cmtice@google.com \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).