summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog33
-rw-r--r--gcc/Makefile.in8
-rw-r--r--gcc/aclocal.m410
-rw-r--r--gcc/common.opt24
-rw-r--r--gcc/config/gnu-user.h17
-rw-r--r--gcc/cp/ChangeLog32
-rw-r--r--gcc/cp/Make-lang.in10
-rw-r--r--gcc/cp/class.c3
-rw-r--r--gcc/cp/config-lang.in2
-rw-r--r--gcc/cp/cp-tree.h12
-rw-r--r--gcc/cp/decl2.c39
-rw-r--r--gcc/cp/init.c3
-rw-r--r--gcc/cp/mangle.c30
-rw-r--r--gcc/cp/vtable-class-hierarchy.c1353
-rw-r--r--gcc/doc/invoke.texi53
-rw-r--r--gcc/flag-types.h6
-rw-r--r--gcc/gcc.c12
-rw-r--r--gcc/output.h4
-rw-r--r--gcc/passes.def1
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/tree.h4
-rw-r--r--gcc/varasm.c46
-rw-r--r--gcc/vtable-verify.c793
-rw-r--r--gcc/vtable-verify.h141
25 files changed, 2619 insertions, 19 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c62cb892163..f3ce757fd75 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,36 @@
+2013-08-06 Caroline Tice <cmtice@google.com>
+
+ * gcc.c (VTABLE_VERIFICATION_SPEC): New definition.
+ (LINK_COMMAND_SPEC): Add VTABLE_VERIFICATION_SPEC.
+ * tree-pass.h: Add pass_vtable_verify.
+ * varasm.c (assemble_variable): Add code to properly set the comdat
+ section and name for the .vtable_map_vars section.
+ (assemble_vtyv_preinit_initializer): New function.
+ (default_sectin_type_flags): Make sure .vtable_map_vars section has
+ LINK_ONCE flag.
+ * output.h: Add function decl for assemble_vtv_preinit_initializer.
+ * vtable-verify.c: New file.
+ * vtable-verify.h: New file.
+ * flag-types.h (enum vtv_priority): Defintions for flag_vtable_verify
+ initialiation levels.
+ * timevar.def (TV_VTABLE_VERIFICATION): New definition.
+ * passes.def: Insert pass_vtable_verify.
+ * aclocal.m4: Reorder includes.
+ * doc/invoke.texi: Document the -fvtable-verify=, -fvtv-debug, and
+ -fvtv-counts options.
+ * config/gnu-user.h (GNU_USER_TARGET_STARTFILE_SPEC): Add vtv_start*.o,
+ as appropriate, if -fvtable-verify=... is used.
+ (GNU_USER_TARGET_ENDFILE_SPEC): Add vtv_end*.o as appropriate, if
+ -fvtable-verify=... is used.
+ * Makefile.in (OBJS): Add vtable-verify.o to list.
+ (vtable-verify.o): Add new build rule.
+ (GTFILES): Add vtable-verify.c to list.
+ * common.opt (fvtable-verify=): New flag.
+ (vtv_priority): Values for fvtable-verify= flag.
+ (fvtv-counts): New flag.
+ (fvtv-debug): New flag.
+ * tree.h (save_vtable_map_decl): New extern function decl.
+
2013-08-07 David Malcolm <dmalcolm@redhat.com>
* config/rl78/rl78.c (rl78_devirt_pass): Convert from a struct to...
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index afce540eed9..6ddc8534f84 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1473,6 +1473,7 @@ OBJS = \
varasm.o \
varpool.o \
vmsdbgout.o \
+ vtable-verify.o \
web.o \
xcoffout.o \
$(out_object_file) \
@@ -2644,6 +2645,12 @@ tree-vectorizer.o: tree-vectorizer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(DUMPFILE_H) $(TM_H) $(GGC_H) $(TREE_H) $(TREE_FLOW_H) \
$(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) \
$(TREE_PRETTY_PRINT_H)
+vtable-verify.o: vtable-verify.c 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 \
+ gt-vtable-verify.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 \
@@ -3817,6 +3824,7 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
$(srcdir)/lto-streamer.h \
$(srcdir)/target-globals.h \
$(srcdir)/ipa-inline.h \
+ $(srcdir)/vtable-verify.c \
$(srcdir)/asan.c \
$(srcdir)/tsan.c \
@all_gtfiles@
diff --git a/gcc/aclocal.m4 b/gcc/aclocal.m4
index a992c3a96ed..1f3ce9d6935 100644
--- a/gcc/aclocal.m4
+++ b/gcc/aclocal.m4
@@ -99,11 +99,6 @@ m4_define([AC_PROG_CC],
[m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])])
])
-m4_include([../libtool.m4])
-m4_include([../ltoptions.m4])
-m4_include([../ltsugar.m4])
-m4_include([../ltversion.m4])
-m4_include([../lt~obsolete.m4])
m4_include([../config/acx.m4])
m4_include([../config/codeset.m4])
m4_include([../config/dfp.m4])
@@ -119,4 +114,9 @@ m4_include([../config/picflag.m4])
m4_include([../config/progtest.m4])
m4_include([../config/stdint.m4])
m4_include([../config/warnings.m4])
+m4_include([../libtool.m4])
+m4_include([../ltoptions.m4])
+m4_include([../ltsugar.m4])
+m4_include([../ltversion.m4])
+m4_include([../lt~obsolete.m4])
m4_include([acinclude.m4])
diff --git a/gcc/common.opt b/gcc/common.opt
index 4c7933e587c..90822801551 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2311,6 +2311,30 @@ Enum(symbol_visibility) String(hidden) Value(VISIBILITY_HIDDEN)
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)
+
+fvtv-counts
+Common Var(flag_vtv_counts)
+Output vtable verification counters.
+
+fvtv-debug
+Common Var(flag_vtv_debug)
+Output vtable verification pointer sets information.
+
fvpt
Common Report Var(flag_value_profile_transformations) Optimization
Use expression value profiles in optimizations
diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h
index bcdf0e6cc5a..2c48c18655a 100644
--- a/gcc/config/gnu-user.h
+++ b/gcc/config/gnu-user.h
@@ -39,15 +39,21 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
the GNU userspace magical crtbegin.o file (see crtstuff.c) which
provides part of the support for getting C++ file-scope static
object constructed before entering `main'. */
-
+
#if defined HAVE_LD_PIE
#define GNU_USER_TARGET_STARTFILE_SPEC \
"%{!shared: %{pg|p|profile:gcrt1.o%s;pie:Scrt1.o%s;:crt1.o%s}} \
- crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+ crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} \
+ %{fvtable-verify=none:%s; \
+ fvtable-verify=preinit:vtv_start_preinit.o%s; \
+ fvtable-verify=std:vtv_start.o%s}"
#else
#define GNU_USER_TARGET_STARTFILE_SPEC \
"%{!shared: %{pg|p|profile:gcrt1.o%s;:crt1.o%s}} \
- crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s}"
+ crti.o%s %{static:crtbeginT.o%s;shared|pie:crtbeginS.o%s;:crtbegin.o%s} \
+ %{fvtable-verify=none:%s; \
+ fvtable-verify=preinit:vtv_start_preinit.o%s; \
+ fvtable-verify=std:vtv_start.o%s}"
#endif
#undef STARTFILE_SPEC
#define STARTFILE_SPEC GNU_USER_TARGET_STARTFILE_SPEC
@@ -59,7 +65,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
GNU userspace "finalizer" file, `crtn.o'. */
#define GNU_USER_TARGET_ENDFILE_SPEC \
- "%{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
+ "%{fvtable-verify=none:%s; \
+ fvtable-verify=preinit:vtv_end_preinit.o%s; \
+ fvtable-verify=std:vtv_end.o%s} \
+ %{shared|pie:crtendS.o%s;:crtend.o%s} crtn.o%s"
#undef ENDFILE_SPEC
#define ENDFILE_SPEC GNU_USER_TARGET_ENDFILE_SPEC
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 5083f7016cc..624af2b601c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,35 @@
+2013-08-06 Caroline Tice <cmtice@google.com>
+
+ * Make-lang.in (*CXX_AND_OBJCXX_OBJS): Add vtable-class-hierarchy.o to
+ list.
+ (vtable-class-hierarchy.o): Add build rule.
+ * cp-tree.h (vtv_start_verification_constructor_init_function): New
+ extern function decl.
+ (vtv_finish_verification_constructor_init_function): New extern
+ function decl.
+ (build_vtbl_address): New extern function decl.
+ (get_mangled_vtable_map_var_name): New extern function decl.
+ (vtv_compute_class_hierarchy_transitive_closure): New extern function
+ decl.
+ (vtv_generate_init_routine): New extern function decl.
+ (vtv_save_class_info): New extern function decl.
+ (vtv_recover_class_info): New extern function decl.
+ (vtv_build_vtable_verify_fndecl): New extern function decl.
+ * class.c (finish_struct_1): Add call to vtv_save_class_info if
+ flag_vtable_verify is true.
+ * config-lang.in: Add vtable-class-hierarchy.c to gtfiles list.
+ * vtable-class-hierarchy.c: New file.
+ * mangle.c (get_mangled_vtable_map_var_name): New function.
+ * decl2.c (start_objects): Update function comment.
+ (cp_write_global_declarations): Call vtv_recover_class_info,
+ vtv_compute_class_hierarchy_transitive_closure and
+ vtv_build_vtable_verify_fndecl, before calling
+ finalize_compilation_unit, and call vtv_generate_init_rount after, IFF
+ flag_vtable_verify is true.
+ (vtv_start_verification_constructor_init_function): New function.
+ (vtv_finish_verification_constructor_init_function): New function.
+ * init.c (build_vtbl_address): Remove static qualifier from function.
+
2013-08-06 Jason Merrill <jason@redhat.com>
PR c++/57825
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2cb919a2172..2c1774f1e50 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -80,7 +80,8 @@ CXX_AND_OBJCXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \
cp/mangle.o cp/cp-objcp-common.o cp/name-lookup.o cp/cxx-pretty-print.o \
- cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o cp/cp-array-notation.o cp/lambda.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)
@@ -341,7 +342,12 @@ cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_CORE_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 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
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index f0c515269e2..2f08d5f0c7c 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6485,6 +6485,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. */
diff --git a/gcc/cp/config-lang.in b/gcc/cp/config-lang.in
index 1597bf97017..4ea9b4d9a2b 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -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"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e4363903c15..86727398fbc 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5298,6 +5298,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);
@@ -5388,6 +5390,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);
@@ -5617,7 +5620,6 @@ extern tree copied_binfo (tree, tree);
extern tree original_binfo (tree, tree);
extern int shared_member_p (tree);
-
/* The representation of a deferred access check. */
typedef struct GTY(()) deferred_access_check {
@@ -6112,6 +6114,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 char * get_mangled_vtable_map_var_name (tree);
/* in dump.c */
extern bool cp_dump_tree (void *, tree);
@@ -6144,6 +6147,13 @@ extern bool cxx_omp_privatize_by_reference (const_tree);
extern void suggest_alternatives_for (location_t, tree);
extern tree strip_using_decl (tree);
+/* in vtable-class-hierarchy.c */
+extern void vtv_compute_class_hierarchy_transitive_closure (void);
+extern void vtv_generate_init_routine (void);
+extern void vtv_save_class_info (tree);
+extern void vtv_recover_class_info (void);
+extern void vtv_build_vtable_verify_fndecl (void);
+
/* In cp/cp-array-notations.c */
extern tree expand_array_notation_exprs (tree);
bool cilkplus_an_triplet_types_ok_p (location_t, tree, tree, tree,
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 1573cede899..d5d29127cfd 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3039,7 +3039,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)
@@ -4353,8 +4354,25 @@ 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 ();
+ vtv_build_vtable_verify_fndecl ();
+ }
+
finalize_compilation_unit ();
+ if (flag_vtable_verify)
+ {
+ /* Generate the special constructor initialization function that
+ calls __VLTRegisterPairs, and give it a very high
+ initialization priority. This must be done after
+ finalize_compilation_unit so that we have accurate
+ information about which vtable will actually be emitted. */
+ vtv_generate_init_routine ();
+ }
+
timevar_stop (TV_PHASE_OPT_GEN);
timevar_start (TV_PHASE_CHECK_DBGINFO);
@@ -4731,4 +4749,23 @@ mark_used (tree decl)
return mark_used (decl, tf_warning_or_error);
}
+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)
+{
+ tree fn;
+
+ finish_compound_stmt (function_body);
+ fn = finish_function (0);
+ DECL_STATIC_CONSTRUCTOR (fn) = 1;
+ decl_init_priority_insert (fn, MAX_RESERVED_INIT_PRIORITY - 1);
+
+ return fn;
+}
+
#include "gt-cp-decl2.h"
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index f346d2fbff5..3ec32c580ac 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -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.
@@ -1098,7 +1097,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;
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 3cfca583cb0..8c11ba8d394 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3888,4 +3888,34 @@ write_java_integer_type_codes (const tree type)
gcc_unreachable ();
}
+/* Given a CLASS_TYPE, such as a record for std::bad_exception this
+ function generates a mangled name for the vtable map variable of
+ the class type. For example, if the class type is
+ "std::bad_exception", the mangled name for the class is
+ "St13bad_exception". This function would generate the name
+ "_ZN4_VTVISt13bad_exceptionE12__vtable_mapE", which unmangles as:
+ "_VTV<std::bad_exception>::__vtable_map". */
+
+
+char *
+get_mangled_vtable_map_var_name (tree class_type)
+{
+ char *var_name = NULL;
+ const char *prefix = "_ZN4_VTVI";
+ const char *postfix = "E12__vtable_mapE";
+
+ gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
+
+ tree class_id = DECL_ASSEMBLER_NAME (TYPE_NAME (class_type));
+ unsigned int len = strlen (IDENTIFIER_POINTER (class_id)) +
+ strlen (prefix) +
+ strlen (postfix) + 1;
+
+ var_name = (char *) xmalloc (len);
+
+ sprintf (var_name, "%s%s%s", prefix, IDENTIFIER_POINTER (class_id), postfix);
+
+ return var_name;
+}
+
#include "gt-cp-mangle.h"
diff --git a/gcc/cp/vtable-class-hierarchy.c b/gcc/cp/vtable-class-hierarchy.c
new file mode 100644
index 00000000000..479447aa7d0
--- /dev/null
+++ b/gcc/cp/vtable-class-hierarchy.c
@@ -0,0 +1,1353 @@
+/* Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* 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/vtable-verify.h, because they are used both here and in
+ gcc/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 "vtable-verify.h"
+#include "gimple.h"
+#include "bitmap.h"
+#include "libiberty.h"
+
+#define MAX_SET_SIZE 5000
+
+static int num_calls_to_regset = 0;
+static int num_calls_to_regpair = 0;
+static int current_set_size;
+
+/* Mark these specially since they need to be stored in precompiled
+ header IR. */
+static GTY (()) vec<tree, va_gc> *vlt_saved_class_info;
+static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
+static GTY (()) tree vlt_register_set_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 __VLTVerifyVtablePointer, which is in libstdc++. This
+ function builds and initializes the function decl that is used
+ in generating those function calls.
+
+ In addition to __VLTVerifyVtablePointer there is also
+ __VLTVerifyVtablePointerDebug which can be used in place of
+ __VLTVerifyVtablePointer, and which takes extra parameters and
+ outputs extra information, to help debug problems. The debug
+ version of this function is generated and used if flag_vtv_debug is
+ true.
+
+ The signatures for these functions are:
+
+ void * __VLTVerifyVtablePointer (void **, void*);
+ void * __VLTVerifyVtablePointerDebug (void**, void *, char *, char *);
+*/
+
+void
+vtv_build_vtable_verify_fndecl (void)
+{
+ tree func_type = NULL_TREE;
+
+ if (verify_vtbl_ptr_fndecl != NULL_TREE
+ && TREE_CODE (verify_vtbl_ptr_fndecl) != ERROR_MARK)
+ return;
+
+ if (flag_vtv_debug)
+ {
+ func_type = build_function_type_list (const_ptr_type_node,
+ build_pointer_type (ptr_type_node),
+ const_ptr_type_node,
+ const_string_type_node,
+ const_string_type_node,
+ NULL_TREE);
+ verify_vtbl_ptr_fndecl =
+ build_lang_decl (FUNCTION_DECL,
+ get_identifier ("__VLTVerifyVtablePointerDebug"),
+ func_type);
+ }
+ else
+ {
+ func_type = build_function_type_list (const_ptr_type_node,
+ build_pointer_type (ptr_type_node),
+ const_ptr_type_node,
+ NULL_TREE);
+ verify_vtbl_ptr_fndecl =
+ build_lang_decl (FUNCTION_DECL,
+ get_identifier ("__VLTVerifyVtablePointer"),
+ func_type);
+ }
+
+ TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
+ DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
+ = tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
+ DECL_PURE_P (verify_vtbl_ptr_fndecl) = 1;
+ TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
+ DECL_PRESERVE_P (verify_vtbl_ptr_fndecl) = 1;
+}
+
+/* As part of vtable verification the compiler generates and inserts
+ calls to __VLTRegisterSet and __VLTRegisterPair, which are in
+ libsupc++. This function builds and initializes the function decls
+ that are used in generating those function calls.
+
+ The signatures for these functions are:
+
+ void __VLTRegisterSetDebug (void **, const void *, std::size_t,
+ size_t, void **);
+
+ void __VLTRegisterSet (void **, const void *, std::size_t,
+ size_t, void **);
+
+ void __VLTRegisterPairDebug (void **, const void *, size_t,
+ const void *, const char *, const char *);
+
+ void __VLTRegisterPair (void **, const void *, size_t, const void *);
+*/
+
+static void
+init_functions (void)
+{
+ tree register_set_type;
+ tree register_pairs_type;
+
+ if (vlt_register_set_fndecl != NULL_TREE)
+ return;
+
+ gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
+ gcc_assert (vlt_register_set_fndecl == NULL_TREE);
+
+ /* Build function decl for __VLTRegisterSet*. */
+
+ register_set_type = build_function_type_list
+ (void_type_node,
+ build_pointer_type (ptr_type_node),
+ const_ptr_type_node,
+ size_type_node,
+ size_type_node,
+ build_pointer_type (ptr_type_node),
+ NULL_TREE);
+
+ if (flag_vtv_debug)
+ vlt_register_set_fndecl = build_lang_decl
+ (FUNCTION_DECL,
+ get_identifier ("__VLTRegisterSetDebug"),
+ register_set_type);
+ else
+ vlt_register_set_fndecl = build_lang_decl
+ (FUNCTION_DECL,
+ get_identifier ("__VLTRegisterSet"),
+ register_set_type);
+
+
+ TREE_NOTHROW (vlt_register_set_fndecl) = 1;
+ DECL_ATTRIBUTES (vlt_register_set_fndecl) =
+ tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (vlt_register_set_fndecl));
+ TREE_PUBLIC (vlt_register_set_fndecl) = 1;
+ DECL_PRESERVE_P (vlt_register_set_fndecl) = 1;
+ SET_DECL_LANGUAGE (vlt_register_set_fndecl, lang_cplusplus);
+
+ /* Build function decl for __VLTRegisterPair*. */
+
+ if (flag_vtv_debug)
+ {
+ register_pairs_type = build_function_type_list (void_type_node,
+ build_pointer_type
+ (ptr_type_node),
+ const_ptr_type_node,
+ size_type_node,
+ const_ptr_type_node,
+ const_string_type_node,
+ const_string_type_node,
+ NULL_TREE);
+
+ vlt_register_pairs_fndecl = build_lang_decl
+ (FUNCTION_DECL,
+ get_identifier ("__VLTRegisterPairDebug"),
+ register_pairs_type);
+ }
+ else
+ {
+ register_pairs_type = build_function_type_list (void_type_node,
+ build_pointer_type
+ (ptr_type_node),
+ const_ptr_type_node,
+ size_type_node,
+ const_ptr_type_node,
+ NULL_TREE);
+
+ vlt_register_pairs_fndecl = build_lang_decl
+ (FUNCTION_DECL,
+ get_identifier ("__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;
+ SET_DECL_LANGUAGE (vlt_register_pairs_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;
+ struct vtv_graph_node *ret_val = NULL;
+
+ for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+ {
+ if ((cur->node->children).length() == cur->node->num_processed_children)
+ {
+ if (prev == NULL)
+ (*worklist) = cur->next;
+ else
+ prev->next = cur->next;
+
+ cur->next = NULL;
+ ret_val = cur->node;
+ free (cur);
+ return ret_val;
+ }
+ }
+
+ 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;
+ sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+ unsigned i;
+ unsigned j;
+
+ /* 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 (j = 0; j < num_vtable_map_nodes; ++j)
+ {
+ struct vtbl_map_node *cur = vtbl_map_nodes_vec[j];
+ if (cur->class_info
+ && ((cur->class_info->children).length() == 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->children).length(); ++i)
+ bitmap_ior (temp_node->descendants, temp_node->descendants,
+ temp_node->children[i]->descendants);
+ for (i = 0; i < (temp_node->parents).length(); ++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 an 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
+check_and_record_registered_pairs (tree vtable_decl, tree vptr_address,
+ tree base_class)
+{
+ unsigned offset;
+ struct vtbl_map_node *base_vtable_map_node;
+ bool inserted_something = false;
+
+
+ if (TREE_CODE (vptr_address) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (vptr_address, 0)) == MEM_REF)
+ vptr_address = TREE_OPERAND (vptr_address, 0);
+
+ if (TREE_OPERAND_LENGTH (vptr_address) > 1)
+ offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
+ else
+ offset = 0;
+
+ base_vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_class));
+
+ inserted_something = vtbl_map_node_registration_insert
+ (base_vtable_map_node,
+ vtable_decl,
+ offset);
+ return !inserted_something;
+}
+
+/* Given an IDENTIFIER_NODE, build and return a string literal based on it. */
+
+static tree
+build_string_from_id (tree identifier)
+{
+ int len;
+
+ gcc_assert (TREE_CODE (identifier) == IDENTIFIER_NODE);
+
+ len = IDENTIFIER_LENGTH (identifier);
+ return build_string_literal (len + 1, IDENTIFIER_POINTER (identifier));
+}
+
+/* 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_construction_vtables (tree base_class, tree record_type,
+ tree *vtable_ptr_array, int *num_args)
+{
+ tree vtbl_var_decl;
+
+ if (TREE_CODE (record_type) != RECORD_TYPE)
+ return;
+
+ vtbl_var_decl = CLASSTYPE_VTABLES (record_type);
+
+ if (CLASSTYPE_VBASECLASSES (record_type))
+ {
+ tree vtt_decl;
+ bool already_registered = false;
+ tree val_vtbl_decl = NULL_TREE;
+
+ vtt_decl = DECL_CHAIN (vtbl_var_decl);
+
+ /* Check to see if we have found a VTT. Add its data if appropriate. */
+ if (vtt_decl)
+ {
+ tree values = DECL_INITIAL (vtt_decl);
+ if (TREE_ASM_WRITTEN (vtt_decl)
+ && values != NULL_TREE
+ && TREE_CODE (values) == CONSTRUCTOR
+ && TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE)
+ {
+ 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. This may
+ result in adding more than just the element assigned
+ to the primary vptr of the class, so we may end up
+ with more vtable pointers than are strictly
+ necessary. */
+
+ for (cnt = 0;
+ vec_safe_iterate (CONSTRUCTOR_ELTS (values),
+ cnt, &ce);
+ cnt++)
+ {
+ tree value = ce->value;
+
+ /* Search for the ADDR_EXPR operand within the value. */
+
+ while (value
+ && TREE_OPERAND (value, 0)
+ && TREE_CODE (TREE_OPERAND (value, 0)) == ADDR_EXPR)
+ value = TREE_OPERAND (value, 0);
+
+ /* The VAR_DECL for the vtable should be the first
+ argument of the ADDR_EXPR, which is the first
+ argument of value.*/
+
+ if (TREE_OPERAND (value, 0))
+ val_vtbl_decl = TREE_OPERAND (value, 0);
+
+ while (TREE_CODE (val_vtbl_decl) != VAR_DECL
+ && TREE_OPERAND (val_vtbl_decl, 0))
+ val_vtbl_decl = TREE_OPERAND (val_vtbl_decl, 0);
+
+ gcc_assert (TREE_CODE (val_vtbl_decl) == VAR_DECL);
+
+ /* Check to see if we already have this vtable pointer in
+ our valid set for this base class. */
+
+ already_registered = check_and_record_registered_pairs
+ (val_vtbl_decl,
+ value,
+ base_class);
+
+ if (already_registered)
+ continue;
+
+ /* Add this vtable pointer to our set of valid
+ pointers for the base class. */
+
+ gcc_assert (*num_args < (MAX_SET_SIZE - 1));
+
+ vtable_ptr_array[*num_args] = value;
+ *num_args = *num_args + 1;
+ current_set_size++;
+ }
+ }
+ }
+ }
+}
+
+/* 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 base_class,
+ tree *vtable_ptr_array, int *num_args)
+{
+ 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)))
+ {
+ tree vtable_address = build_vtbl_address (base_binfo);
+
+ already_registered = check_and_record_registered_pairs
+ (vtable_decl,
+ vtable_address,
+ base_class);
+ if (!already_registered)
+ {
+ gcc_assert (*num_args < (MAX_SET_SIZE - 1));
+
+ vtable_ptr_array[*num_args] = vtable_address;
+ *num_args = *num_args + 1;
+ current_set_size++;
+ }
+ }
+
+ register_other_binfo_vtables (base_binfo, base_class, vtable_ptr_array,
+ num_args);
+ }
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+static char *
+get_log_file_name (const char *fname)
+{
+ const char *tmp_dir = concat (dump_dir_name, NULL);
+ char *full_name;
+ int dir_len;
+ int fname_len;
+
+ dir_len = strlen (tmp_dir);
+ fname_len = strlen (fname);
+
+ full_name = XNEWVEC (char, dir_len + fname_len + 1);
+ strcpy (full_name, tmp_dir);
+ strcpy (full_name + dir_len, fname);
+
+ return full_name;
+}
+
+static void
+write_out_current_set_data (tree base_class, int set_size)
+{
+ static int class_data_log_fd = -1;
+ char buffer[1024];
+ int bytes_written __attribute__ ((unused));
+ char *file_name = get_log_file_name ("vtv_class_set_sizes.log");
+
+ if (class_data_log_fd == -1)
+ class_data_log_fd = open (file_name,
+ O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
+
+ if (class_data_log_fd == -1)
+ {
+ warning (0, "Unable to open log file 'vtv_class_set_sizes.log'");
+ return;
+ }
+
+ snprintf (buffer, sizeof (buffer), "%s %d\n",
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (base_class))),
+ set_size);
+ bytes_written = write (class_data_log_fd, buffer, strlen (buffer));
+}
+
+static tree
+build_key_buffer_arg (tree base_ptr_var_decl)
+{
+ const int key_type_fixed_size = 8;
+ uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl));
+ uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
+ (DECL_NAME (base_ptr_var_decl)));
+ void *key_buffer = xmalloc (len1 + key_type_fixed_size);
+ uint32_t *value_ptr = (uint32_t *) key_buffer;
+ tree ret_value;
+
+ /* 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 (base_ptr_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. */
+ ret_value = build_string_literal (len1 + key_type_fixed_size,
+ (char *) key_buffer);
+ free (key_buffer);
+ return ret_value;
+}
+
+static void
+insert_call_to_register_set (tree class_name, int num_args,
+ tree *vtbl_ptr_array, tree body, tree arg1,
+ tree arg2, tree size_hint_arg)
+{
+ tree call_expr;
+ char *array_arg_name = ACONCAT (("__vptr_array_",
+ IDENTIFIER_POINTER (class_name), NULL));
+ tree array_arg_type = build_array_type_nelts (build_pointer_type
+ (build_pointer_type
+ (void_type_node)),
+ num_args);
+ tree array_arg = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (array_arg_name),
+ array_arg_type);
+ int k;
+
+ vec<constructor_elt, va_gc> *array_elements;
+ vec_alloc (array_elements, num_args);
+
+ tree initial = NULL_TREE;
+ tree arg3 = NULL_TREE;
+
+ TREE_PUBLIC (array_arg) = 0;
+ DECL_EXTERNAL (array_arg) = 0;
+ TREE_STATIC (array_arg) = 1;
+ DECL_ARTIFICIAL (array_arg) = 0;
+ TREE_READONLY (array_arg) = 1;
+ DECL_IGNORED_P (array_arg) = 0;
+ DECL_PRESERVE_P (array_arg) = 0;
+ DECL_VISIBILITY (array_arg) = VISIBILITY_HIDDEN;
+
+ for (k = 0; k < num_args; ++k)
+ {
+ CONSTRUCTOR_APPEND_ELT (array_elements, NULL_TREE, vtbl_ptr_array[k]);
+ }
+
+ initial = build_constructor (TREE_TYPE (array_arg), array_elements);
+
+ TREE_CONSTANT (initial) = 1;
+ TREE_STATIC (initial) = 1;
+ DECL_INITIAL (array_arg) = initial;
+ relayout_decl (array_arg);
+ varpool_finalize_decl (array_arg);
+
+ arg3 = build1 (ADDR_EXPR, TYPE_POINTER_TO (TREE_TYPE (array_arg)), array_arg);
+
+ TREE_TYPE (arg3) = build_pointer_type (TREE_TYPE (array_arg));
+
+ call_expr = build_call_expr (vlt_register_set_fndecl, 5, arg1,
+ arg2, /* set_symbol_key */
+ size_hint_arg, build_int_cst (size_type_node,
+ num_args),
+ arg3);
+ append_to_statement_list (call_expr, &body);
+ num_calls_to_regset++;
+}
+
+static void
+insert_call_to_register_pair (tree vtable_address, int num_args, tree arg1,
+ tree arg2, tree size_hint_arg, tree str1,
+ tree str2, tree body)
+{
+ tree call_expr;
+
+ if (num_args == 0)
+ vtable_address = build_int_cst (build_pointer_type (void_type_node), 0);
+
+ if (flag_vtv_debug)
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 6, arg1, arg2,
+ size_hint_arg, vtable_address, str1, str2);
+ else
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 4, arg1, arg2,
+ size_hint_arg, vtable_address);
+
+ append_to_statement_list (call_expr, &body);
+ num_calls_to_regpair++;
+}
+
+static void
+output_set_info (tree record_type, tree *vtbl_ptr_array, int array_size)
+{
+ static int vtv_debug_log_fd = -1;
+ char buffer[1024];
+ int bytes_written __attribute__ ((unused));
+ const char *class_name =
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (TYPE_NAME (record_type)));
+ char *file_name = get_log_file_name ("vtv_set_ptr_data.log");
+
+ if (vtv_debug_log_fd == -1)
+ vtv_debug_log_fd = open (file_name,
+ O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
+ if (vtv_debug_log_fd == -1)
+ {
+ warning (0, "Unable to open log file 'vtv_set_ptr_data.log'");
+ return;
+ }
+
+ for (int i = 0; i < array_size; ++i)
+ {
+ const char *vptr_name = "unknown";
+ int vptr_offset = 0;
+
+ if (TREE_CODE (vtbl_ptr_array[i]) == POINTER_PLUS_EXPR)
+ {
+ tree arg0 = TREE_OPERAND (vtbl_ptr_array[i], 0);
+ tree arg1 = TREE_OPERAND (vtbl_ptr_array[i], 1);
+
+ if (TREE_CODE (arg0) == ADDR_EXPR)
+ arg0 = TREE_OPERAND (arg0, 0);
+
+ if (TREE_CODE (arg0) == VAR_DECL)
+ vptr_name = IDENTIFIER_POINTER (DECL_NAME (arg0));
+
+ if (TREE_CODE (arg1) == INTEGER_CST)
+ vptr_offset = TREE_INT_CST_LOW (arg1);
+ }
+
+ snprintf (buffer, sizeof (buffer), "%s %s %s + %d\n",
+ main_input_filename, class_name, vptr_name, vptr_offset);
+ bytes_written = write (vtv_debug_log_fd, buffer, strlen(buffer));
+ }
+
+}
+
+/* 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)
+{
+ bool registered_at_least_one = false;
+ tree vtbl_ptr_array[MAX_SET_SIZE];
+ int num_vtable_args = 0;
+ unsigned j;
+
+ for (j = 0; j < num_vtable_map_nodes; ++j)
+ {
+ struct vtbl_map_node *current = vtbl_map_nodes_vec[j];
+ unsigned i = 0;
+ tree base_class = current->class_info->class_type;
+ tree base_ptr_var_decl = current->vtbl_map_decl;
+ tree arg1;
+ tree arg2;
+ tree new_type;
+ tree str1 = NULL_TREE;
+ tree str2 = NULL_TREE;
+ size_t size_hint;
+ tree size_hint_arg;
+
+ gcc_assert (current->class_info != NULL);
+
+
+ if (flag_vtv_debug)
+ str1 = build_string_from_id (DECL_NAME (base_ptr_var_decl));
+
+ new_type = build_pointer_type (TREE_TYPE (base_ptr_var_decl));
+ arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+ num_vtable_args = 0;
+
+ 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))
+ {
+ 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);
+ str2 = build_string_from_id (DECL_NAME (vtable_decl));
+ }
+
+ if (vtable_decl && vtable_should_be_output)
+ {
+ tree vtable_address = build_vtbl_address (binfo);
+
+ already_registered = check_and_record_registered_pairs
+ (vtable_decl,
+ vtable_address,
+ base_class);
+
+
+ if (!already_registered)
+ {
+
+ vtbl_ptr_array[num_vtable_args++] = vtable_address;
+
+ /* Find and handle any 'extra' vtables associated
+ with this class, via virtual inheritance. */
+ register_construction_vtables (base_class, class_type,
+ vtbl_ptr_array,
+ &num_vtable_args);
+
+ /* Find and handle any 'extra' vtables associated
+ with this class, via multiple inheritance. */
+ register_other_binfo_vtables (binfo, base_class,
+ vtbl_ptr_array,
+ &num_vtable_args);
+ }
+ }
+ }
+ }
+ current_set_size = num_vtable_args;
+
+ /* Sometimes we need to initialize the set symbol even if we are
+ not adding any vtable pointers to the set in the current
+ compilation unit. In that case, we need to initialize the
+ set to our best guess as to what the eventual size of the set
+ hash table will be (to prevent having to re-size the hash
+ table later). */
+
+ size_hint = guess_num_vtable_pointers (current->class_info);
+
+ /* If we have added vtable pointers to the set in this
+ compilation unit, adjust the size hint for the set's hash
+ table appropriately. */
+ if (num_vtable_args > 0)
+ while ((size_t) num_vtable_args > size_hint)
+ size_hint <<= 1;
+ size_hint_arg = build_int_cst (size_type_node, size_hint);
+
+ /* Get the key-buffer argument. */
+ arg2 = build_key_buffer_arg (base_ptr_var_decl);
+
+ if (str2 == NULL_TREE)
+ str2 = build_string_literal (strlen ("unknown") + 1,
+ "unknown");
+
+ if (flag_vtv_debug)
+ output_set_info (current->class_info->class_type,
+ vtbl_ptr_array, num_vtable_args);
+
+ if (num_vtable_args > 1)
+ {
+ insert_call_to_register_set (current->class_name, num_vtable_args,
+ vtbl_ptr_array, body, arg1, arg2,
+ size_hint_arg);
+ registered_at_least_one = true;
+ }
+ else if (num_vtable_args >= 0)
+ {
+
+ if (num_vtable_args > 0
+ || (current->is_used
+ || (current->registered.size() > 0)))
+ {
+ insert_call_to_register_pair (vtbl_ptr_array[0], num_vtable_args,
+ arg1, arg2, size_hint_arg, str1,
+ str2, body);
+ registered_at_least_one = true;
+ }
+ }
+
+ if (flag_vtv_counts && current_set_size > 0)
+ write_out_current_set_data (base_class, current_set_size);
+
+ }
+
+ return registered_at_least_one;
+}
+
+/* Given a tree containing a class type (CLASS_TYPE), this function
+ finds and returns the class hierarchy node for that class in our
+ data structure. */
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+ struct vtbl_map_node *vtbl_node;
+
+ vtbl_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (class_type));
+ if (vtbl_node)
+ return vtbl_node->class_info;
+
+ return NULL;
+}
+
+/* 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)
+{
+ (base_node->children).safe_push (derived_node);
+ (derived_node->parents).safe_push (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);
+}
+
+
+static void
+write_out_vtv_count_data (void)
+{
+ static int vtv_count_log_fd = -1;
+ char buffer[1024];
+ int unused_vtbl_map_vars = 0;
+ int bytes_written __attribute__ ((unused));
+ char *file_name = get_log_file_name ("vtv_count_data.log");
+
+ if (vtv_count_log_fd == -1)
+ vtv_count_log_fd = open (file_name,
+ O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
+ if (vtv_count_log_fd == -1)
+ {
+ warning (0, "Unable to open log file 'vtv_count_data.log'");
+ return;
+ }
+
+ for (unsigned i = 0; i < num_vtable_map_nodes; ++i)
+ {
+ struct vtbl_map_node *current = vtbl_map_nodes_vec[i];
+ if (!current->is_used
+ && current->registered.size() == 0)
+ unused_vtbl_map_vars++;
+ }
+
+ snprintf (buffer, sizeof (buffer), "%s %d %d %d %d %d\n",
+ main_input_filename, total_num_virtual_calls,
+ total_num_verified_vcalls, num_calls_to_regset,
+ num_calls_to_regpair, unused_vtbl_map_vars);
+
+ bytes_written = write (vtv_count_log_fd, buffer, strlen (buffer));
+}
+
+/* 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;
+
+ init_functions ();
+
+ 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);
+
+ if (flag_vtv_counts)
+ write_out_vtv_count_data ();
+
+ 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 (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)
+ {
+ tree vtv_fndecl =
+ vtv_finish_verification_constructor_init_function (init_routine_body);
+ TREE_STATIC (vtv_fndecl) = 1;
+ TREE_USED (vtv_fndecl) = 1;
+ DECL_PRESERVE_P (vtv_fndecl) = 1;
+ if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+ {
+ DECL_STATIC_CONSTRUCTOR (vtv_fndecl) = 0;
+ assemble_vtv_preinit_initializer (vtv_fndecl);
+ }
+
+ gimplify_function_tree (vtv_fndecl);
+ cgraph_add_new_function (vtv_fndecl, 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)
+{
+ 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;
+
+ /* Create map lookup symbol for base class */
+ var_name = get_mangled_vtable_map_var_name (base_type);
+
+ /* We've already created the variable; just look it. */
+ vtable_map_node = vtbl_map_get_node (TYPE_MAIN_VARIANT (base_type));
+
+ if (!vtable_map_node || (vtable_map_node->vtbl_map_decl == NULL_TREE))
+ {
+ /* If we haven't already created the *__vtable_map global
+ variable for this class, do so now, and add it to the
+ varpool, to make sure it gets saved and written out. */
+
+ tree var_decl = NULL;
+ tree var_type = build_pointer_type (void_type_node);
+ tree initial_value = integer_zero_node;
+
+ var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (var_name), var_type);
+
+ 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 because we want to be
+ able to write to it at runtime. */
+ TREE_READONLY (var_decl) = 0;
+ DECL_IGNORED_P (var_decl) = 1;
+ DECL_PRESERVE_P (var_decl) = 1;
+
+ /* Put these mmap variables in thr .vtable_map_vars section, so
+ we can find and protect them. */
+
+ DECL_SECTION_NAME (var_decl) = build_string (strlen (".vtable_map_vars"),
+ ".vtable_map_vars");
+ DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl) = true;
+ DECL_INITIAL (var_decl) = initial_value;
+
+ comdat_linkage (var_decl);
+
+ varpool_finalize_decl (var_decl);
+ if (!vtable_map_node)
+ vtable_map_node =
+ find_or_create_vtbl_map_node (TYPE_MAIN_VARIANT (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_insert_single_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. 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;
+
+ if (!vlt_saved_class_info)
+ vec_alloc (vlt_saved_class_info, 10);
+
+ gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+ vec_safe_push (vlt_saved_class_info, record);
+}
+
+
+/* This function goes through the list of classes we saved and calls
+ vtv_insert_single_class_info on each one, to build up our class
+ hierarchy data structure. */
+
+void
+vtv_recover_class_info (void)
+{
+ tree current_class;
+ unsigned i;
+
+ if (vlt_saved_class_info)
+ {
+ for (i = 0; i < vlt_saved_class_info->length(); ++i)
+ {
+ current_class = (*vlt_saved_class_info)[i];
+ gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+ vtv_insert_single_class_info (current_class);
+ }
+ }
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 92cc25002a3..14955dd1be0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -191,6 +191,8 @@ in the following sections.
-ftemplate-depth=@var{n} @gol
-fno-threadsafe-statics -fuse-cxa-atexit -fno-weak -nostdinc++ @gol
-fno-default-inline -fvisibility-inlines-hidden @gol
+-fvtable-verify=@var{std|preinit|none} @gol
+-fvtv-counts -fvtv-debug @gol
-fvisibility-ms-compat @gol
-fext-numeric-literals @gol
-Wabi -Wconversion-null -Wctor-dtor-privacy @gol
@@ -318,6 +320,7 @@ Objective-C and Objective-C++ Dialects}.
-fdump-tree-sra@r{[}-@var{n}@r{]} @gol
-fdump-tree-forwprop@r{[}-@var{n}@r{]} @gol
-fdump-tree-fre@r{[}-@var{n}@r{]} @gol
+-fdump-tree-vtable-verify @gol
-fdump-tree-vrp@r{[}-@var{n}@r{]} @gol
-ftree-vectorizer-verbose=@var{n} @gol
-fdump-tree-storeccp@r{[}-@var{n}@r{]} @gol
@@ -2302,6 +2305,56 @@ and that pointers to function members defined in different shared
objects may not compare equal. When this flag is given, it is a
violation of the ODR to define types with the same name differently.
+@item -fvtable-verify=@var{std|preinit|none}
+@opindex fvtable-verify
+Turn on (or off, if using @option{-fvtable-verify=none}) the security
+feature that verifies at runtime, for every virtual call that is made, that
+the vtable pointer through which the call is made is valid for the type of
+the object, and has not been corrupted or overwritten. If an invalid vtable
+pointer is detected (at runtime), an error is reported and execution of the
+program is immediately halted.
+
+This option causes runtime data structures to be built, at program start up,
+for verifying the vtable pointers. The options @code{std} and @code{preinit}
+control the timing of when these data structures are built. In both cases the
+data structures are built before execution reaches 'main'. The
+@option{-fvtable-verify=std} causes these data structure to be built after the
+shared libraries have been loaded and initialized.
+@option{-fvtable-verify=preinit} causes them to be built before the shared
+libraries have been loaded and initialized.
+
+If this option appears multiple times in the compiler line, with different
+values specified, 'none' will take highest priority over both 'std' and
+'preinit'; 'preinit' will take priority over 'std'.
+
+@item -fvtv-debug
+@opindex (fvtv-debug)
+Causes debug versions of the runtime functions for the vtable verification
+feature to be called. This assumes the @option{-fvtable-verify=std} or
+@option{-fvtable-verify=preinit} has been used. This flag will also cause the
+compiler to keep track of which vtable pointers it found for each class, and
+record that information in the file ``vtv_set_ptr_data.log'', in the dump
+file directory on the user's machine.
+
+Note: This feature APPENDS data to the log file. If you want a fresh log
+file, be sure to delete any existing one.
+
+@item -fvtv-counts
+@opindex (fvtv-counts)
+This is a debugging flag. When used in conjunction with
+@option{-fvtable-verify=std} or @option{-fvtable-verify=preinit}, this
+causes the compiler to keep track of the total number of virtual calls
+it encountered and the number of verifications it inserted. It also
+counts the number of calls to certain runtime library functions
+that it inserts. This information, for each compilation unit, is written
+to a file named ``vtv_count_data.log'', in the dump_file directory on
+the user's machine. It also counts the size of the vtable pointer sets
+for each class, and writes this information to ``vtv_class_set_sizes.log''
+in the same directory.
+
+Note: This feature APPENDS data to the log files. To get a fresh log
+files, be sure to delete any existing ones.
+
@item -fno-weak
@opindex fno-weak
Do not use weak symbol support, even if it is provided by the linker.
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 4fc5d33348e..8eea9a67079 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -191,4 +191,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 */
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 6ef4e8a1b77..7c15cf3d176 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -722,6 +722,16 @@ proper position among the other output files. */
%{!pie:%{!shared:%e-fsanitize=thread linking must be done with -pie or -shared}}}}}"
#endif
+/* This is the spec to use, once the code for creating the vtable
+ verification runtime library, libvtv.so, has been created. Currently
+ the vtable verification runtime functions are in libstdc++, so we use
+ the spec just below this one. */
+#ifndef VTABLE_VERIFICATION_SPEC
+#define VTABLE_VERIFICATION_SPEC "\
+%{!nostdlib:%{fvtable-verify=std: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}\
+ %{fvtable-verify=preinit: -lvtv -u_vtable_map_vars_start -u_vtable_map_vars_end}}"
+#endif
+
/* -u* was put back because both BSD and SysV seem to support it. */
/* %{static:} simply prevents an error message if the target machine
doesn't handle -static. */
@@ -740,7 +750,7 @@ proper position among the other output files. */
%{flto} %{flto=*} %l " LINK_PIE_SPEC \
"%{fuse-ld=*:-fuse-ld=%*}\
%X %{o*} %{e*} %{N} %{n} %{r}\
- %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}}\
+ %{s} %{t} %{u*} %{z} %{Z} %{!nostdlib:%{!nostartfiles:%S}} " VTABLE_VERIFICATION_SPEC " \
%{static:} %{L*} %(mfwrap) %(link_libgcc) " SANITIZER_EARLY_SPEC " %o\
%{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
%{fgnu-tm:%:include(libitm.spec)%(link_itm)}\
diff --git a/gcc/output.h b/gcc/output.h
index cc48dfbed50..7b262566c2f 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -197,6 +197,10 @@ extern void assemble_end_function (tree, const char *);
initial value (that will be done by the caller). */
extern void assemble_variable (tree, int, int, int);
+/* Put the vtable verification constructor initialization function
+ into the preinit array. */
+extern void assemble_vtv_preinit_initializer (tree);
+
/* Compute the alignment of variable specified by DECL.
DONT_OUTPUT_DATA is from assemble_variable. */
extern void align_variable (tree decl, bool dont_output_data);
diff --git a/gcc/passes.def b/gcc/passes.def
index 61cfd9e7e95..b289713368f 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -292,6 +292,7 @@ along with GCC; see the file COPYING3. If not see
NEXT_PASS (pass_tm_memopt);
NEXT_PASS (pass_tm_edges);
POP_INSERT_PASSES ()
+ NEXT_PASS (pass_vtable_verify);
NEXT_PASS (pass_lower_vector);
NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_asan_O0);
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 44f0eac52c7..8ab9b99eadf 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -255,6 +255,7 @@ DEFTIMEVAR (TV_TREE_UNINIT , "uninit var analysis")
DEFTIMEVAR (TV_PLUGIN_INIT , "plugin initialization")
DEFTIMEVAR (TV_PLUGIN_RUN , "plugin execution")
DEFTIMEVAR (TV_GIMPLE_SLSR , "straight-line strength reduction")
+DEFTIMEVAR (TV_VTABLE_VERIFICATION , "vtable verification")
/* Everything else in rest_of_compilation not included above. */
DEFTIMEVAR (TV_EARLY_LOCAL , "early local passes")
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 41d5d92c8a9..787a49b7c41 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -439,6 +439,7 @@ extern gimple_opt_pass *make_pass_tm_edges (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_split_functions (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_feedback_split_functions (gcc::context *ctxt);
extern gimple_opt_pass *make_pass_strength_reduction (gcc::context *ctxt);
+extern gimple_opt_pass *make_pass_vtable_verify (gcc::context *ctxt);
/* IPA Passes */
extern simple_ipa_opt_pass *make_pass_ipa_lower_emutls (gcc::context *ctxt);
diff --git a/gcc/tree.h b/gcc/tree.h
index 0058a4b17bf..94f112f43d7 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -6496,6 +6496,9 @@ is_lang_specific (tree t)
/* In gimple-low.c. */
extern bool block_may_fallthru (const_tree);
+/* In vtable-verify.c. */
+extern void save_vtable_map_decl (tree);
+
/* Functional interface to the builtin functions. */
@@ -6586,7 +6589,6 @@ builtin_decl_implicit_p (enum built_in_function fncode)
&& builtin_info.implicit_p[uns_fncode]);
}
-
/* For anonymous aggregate types, we need some sort of name to
hold on to. In practice, this should not appear, but it should
not be harmful if it does. */
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 8efd98e0020..69ec26a5e6b 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -2107,7 +2107,31 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
assemble_noswitch_variable (decl, name, sect, align);
else
{
- switch_to_section (sect);
+ /* The following bit of code ensures that vtable_map
+ variables are not only in the comdat section, but that
+ each variable has its own unique comdat name. If this
+ code is removed, the variables end up in the same section
+ with a single comdat name.
+
+ FIXME: resolve_unique_section needs to deal better with
+ decls with both DECL_SECTION_NAME and DECL_ONE_ONLY. Once
+ that is fixed, this if-else statement can be replaced with
+ a single call to "switch_to_section (sect)". */
+ if (sect->named.name
+ && (strcmp (sect->named.name, ".vtable_map_vars") == 0))
+ {
+#if defined (OBJECT_FORMAT_ELF)
+ targetm.asm_out.named_section (sect->named.name,
+ sect->named.common.flags
+ | SECTION_LINKONCE,
+ DECL_NAME (decl));
+ in_section = sect;
+#else
+ switch_to_section (sect);
+#endif
+ }
+ else
+ switch_to_section (sect);
if (align > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
assemble_variable_contents (decl, name, dont_output_data);
@@ -2120,6 +2144,23 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
}
}
+
+/* Given a function declaration (FN_DECL), this function assembles the
+ function into the .preinit_array section. */
+
+void
+assemble_vtv_preinit_initializer (tree fn_decl)
+{
+ section *sect;
+ unsigned flags = SECTION_WRITE;
+ rtx symbol = XEXP (DECL_RTL (fn_decl), 0);
+
+ flags |= SECTION_NOTYPE;
+ sect = get_section (".preinit_array", flags, fn_decl);
+ switch_to_section (sect);
+ assemble_addr_to_section (symbol, sect);
+}
+
/* Return 1 if type TYPE contains any pointers. */
static int
@@ -6046,6 +6087,9 @@ default_section_type_flags (tree decl, const char *name, int reloc)
if (decl && DECL_P (decl) && DECL_ONE_ONLY (decl))
flags |= SECTION_LINKONCE;
+ if (strcmp (name, ".vtable_map_vars") == 0)
+ flags |= SECTION_LINKONCE;
+
if (decl && TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL_P (decl))
flags |= SECTION_TLS | SECTION_WRITE;
diff --git a/gcc/vtable-verify.c b/gcc/vtable-verify.c
new file mode 100644
index 00000000000..b6c5bc3bce4
--- /dev/null
+++ b/gcc/vtable-verify.c
@@ -0,0 +1,793 @@
+/* Copyright (C) 2013
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* 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 variable for each virtual
+ class. We refer to this as the "vtable map variable" for that
+ class. The vtable map variable has the type "void *", and is
+ initialized by the compiler to NULL. At runtime when the set of
+ valid vtable pointers for a virtual class, e.g. class Foo, is built,
+ the vtable map variable for class Foo is made to point to the set.
+ During compile time, when the compiler is inserting verification
+ calls into the program, it passes the vtable map variable for the
+ appropriate class to the verification call, so that at runtime the
+ verification call can find the appropriate data set.
+
+ The actual set of valid vtable pointers for a virtual class,
+ e.g. class Foo, cannot be built until runtime, when the vtables get
+ loaded into memory and their addresses are known. But the knowledge
+ about which vtables belong in which class' hierarchy is only known
+ at compile time. Therefore at compile time we collect class
+ hierarchy and vtable information about every virtual class, and we
+ generate calls to build up the data sets at runtime. To build the
+ data sets, we call one of the functions we add to the runtime
+ library, __VLTRegisterPair. __VLTRegisterPair takes two arguments,
+ a vtable map variable and the address of a vtable. If the vtable
+ map variable is currently NULL, it creates a new data set (hash
+ table), makes the vtable map variable point to the new data set, and
+ inserts the vtable address into the data set. If the vtable map
+ variable is not NULL, it just inserts the vtable address into the
+ data set. In order to make sure that our data sets are built before
+ any verification calls happen, we create a special constructor
+ initialization function for each compilation unit, give it a very
+ high initialization priority, and insert all of our calls to
+ __VLTRegisterPair into our special constructor initialization
+ function.
+
+ The vtable verification feature is controlled by the flag
+ '-fvtable-verify='. There are three flavors of this:
+ '-fvtable-verify=std', '-fvtable-verify=preinit', and
+ '-fvtable-verify=none'. If the option '-fvtable-verfy=preinit' is
+ used, then our constructor initialization function gets put into the
+ preinit array. This is necessary if there are data sets that need
+ to be built very early in execution. If the constructor
+ initialization function gets put into the preinit array, the we also
+ add calls to __VLTChangePermission at the beginning and end of the
+ function. The call at the beginning sets the permissions on the
+ data sets and vtable map variables to read/write, and the one at the
+ end makes them read-only. If the '-fvtable-verify=std' option is
+ used, the constructor initialization functions are executed at their
+ normal time, and the __VLTChangePermission calls are handled
+ differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
+ The option '-fvtable-verify=none' turns off vtable verification.
+
+ This file contains code for the tree pass that goes through all the
+ statements in each basic block, looking for virtual calls, and
+ inserting a call to __VLTVerifyVtablePointer (with appropriate
+ arguments) before each one. It also contains the hash table
+ functions for the data structures used for collecting the class
+ hierarchy data and building/maintaining the vtable map variable data
+ are defined in gcc/vtable-verify.h. These data structures are
+ shared with the code in the C++ front end that collects the class
+ hierarchy & vtable information and generates the vtable map
+ variables (see cp/vtable-class-hierarchy.c). This tree pass should
+ run just before the gimple is converted to RTL.
+
+ Some implementation details for this pass:
+
+ To find all of the virtual calls, we iterate through all the
+ gimple statements in each basic block, looking for any call
+ statement with the code "OBJ_TYPE_REF". Once we have found the
+ virtual call, we need to find the vtable pointer through which the
+ call is being made, and the type of the object containing the
+ pointer (to find the appropriate vtable map variable). We then use
+ these to build a call to __VLTVerifyVtablePointer, passing the
+ vtable map variable, and the vtable pointer. We insert the
+ verification call just after the gimple statement that gets the
+ vtable pointer out of the object, and we update the next
+ statement to depend on the result returned from
+ __VLTVerifyVtablePointer (the vtable pointer value), to ensure
+ subsequent compiler phases don't remove or reorder the call (it's no
+ good to have the verification occur after the virtual call, for
+ example). To find the vtable pointer being used (and the type of
+ the object) we search backwards through the def_stmts chain from the
+ virtual call (see verify_bb_vtables for more details). */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "basic-block.h"
+#include "tree-flow.h"
+#include "tree-pass.h"
+#include "cfgloop.h"
+
+#include "vtable-verify.h"
+
+unsigned num_vtable_map_nodes = 0;
+int total_num_virtual_calls = 0;
+int total_num_verified_vcalls = 0;
+
+extern GTY(()) tree verify_vtbl_ptr_fndecl;
+tree verify_vtbl_ptr_fndecl = NULL_TREE;
+
+/* Keep track of whether or not any virtual call were verified. */
+static bool any_verification_calls_generated = false;
+
+unsigned int vtable_verify_main (void);
+
+
+/* The following few functions are for the vtbl pointer hash table
+ in the 'registered' field of the struct vtable_map_node. The hash
+ table keeps track of which vtable pointers have been used in
+ calls to __VLTRegisterPair with that particular vtable map variable. */
+
+/* This function checks to see if a particular VTABLE_DECL and OFFSET are
+ already in the 'registered' hash table for NODE. */
+
+bool
+vtbl_map_node_registration_find (struct vtbl_map_node *node,
+ tree vtable_decl,
+ unsigned offset)
+{
+ struct vtable_registration key;
+ struct vtable_registration **slot;
+
+ gcc_assert (node && node->registered.is_created());
+
+ key.vtable_decl = vtable_decl;
+ slot = (struct vtable_registration **) node->registered.find_slot (&key,
+ NO_INSERT);
+
+ if (slot && (*slot))
+ {
+ unsigned i;
+ for (i = 0; i < ((*slot)->offsets).length(); ++i)
+ if ((*slot)->offsets[i] == offset)
+ return true;
+ }
+
+ return false;
+}
+
+/* This function inserts VTABLE_DECL and OFFSET into the 'registered'
+ hash table for NODE. It returns a boolean indicating whether or not
+ it actually inserted anything. */
+
+bool
+vtbl_map_node_registration_insert (struct vtbl_map_node *node,
+ tree vtable_decl,
+ unsigned offset)
+{
+ struct vtable_registration key;
+ struct vtable_registration **slot;
+ bool inserted_something = false;
+
+ if (!node || !node->registered.is_created())
+ return false;
+
+ key.vtable_decl = vtable_decl;
+ slot = (struct vtable_registration **) node->registered.find_slot (&key,
+ INSERT);
+
+ if (! *slot)
+ {
+ struct vtable_registration *node;
+ node = XNEW (struct vtable_registration);
+ node->vtable_decl = vtable_decl;
+
+ (node->offsets).create (10);
+ (node->offsets).safe_push (offset);
+ *slot = node;
+ inserted_something = true;
+ }
+ 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)->offsets).length() && !found; ++i)
+ if ((*slot)->offsets[i] == offset)
+ found = true;
+
+ if (!found)
+ {
+ ((*slot)->offsets).safe_push (offset);
+ inserted_something = true;
+ }
+ }
+ return inserted_something;
+}
+
+/* Hashtable functions for vtable_registration hashtables. */
+
+inline hashval_t
+registration_hasher::hash (const value_type *p)
+{
+ const struct vtable_registration *n = (const struct vtable_registration *) p;
+ return (hashval_t) (DECL_UID (n->vtable_decl));
+}
+
+inline bool
+registration_hasher::equal (const value_type *p1, const compare_type *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 definition and functions for vtbl_map_hash. */
+
+struct vtbl_map_hasher : typed_noop_remove <struct vtbl_map_node>
+{
+ typedef struct vtbl_map_node value_type;
+ typedef struct vtbl_map_node compare_type;
+ static inline hashval_t hash (const value_type *);
+ static inline bool equal (const value_type *, const compare_type *);
+};
+
+/* Returns a hash code for P. */
+
+inline hashval_t
+vtbl_map_hasher::hash (const value_type *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. */
+
+inline bool
+vtbl_map_hasher::equal (const value_type *p1, const compare_type *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));
+}
+
+/* Here are the two structures into which we insert vtable map nodes.
+ We use two data structures because of the vastly different ways we need
+ to find the nodes for various tasks (see comments in vtable-verify.h
+ for more details. */
+
+typedef hash_table <vtbl_map_hasher> vtbl_map_table_type;
+typedef vtbl_map_table_type::iterator vtbl_map_iterator_type;
+
+/* Vtable map variable nodes stored in a hash table. */
+static vtbl_map_table_type vtbl_map_hash;
+
+/* Vtable map variable nodes stored in a vector. */
+vec<struct vtbl_map_node *> vtbl_map_nodes_vec;
+
+/* Return vtbl_map node for CLASS_NAME without creating a new one. */
+
+struct vtbl_map_node *
+vtbl_map_get_node (tree class_type)
+{
+ struct vtbl_map_node key;
+ struct vtbl_map_node **slot;
+
+ tree class_type_decl;
+ tree class_name;
+ unsigned int type_quals;
+
+ if (!vtbl_map_hash.is_created())
+ return NULL;
+
+ gcc_assert (TREE_CODE (class_type) == RECORD_TYPE);
+
+
+ /* Find the TYPE_DECL for the class. */
+ class_type_decl = TYPE_NAME (class_type);
+
+ /* Verify that there aren't any qualifiers on the type. */
+ type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
+ gcc_assert (type_quals == TYPE_UNQUALIFIED);
+
+ /* Get the mangled name for the unqualified type. */
+ gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl));
+ class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+
+ key.class_name = class_name;
+ slot = (struct vtbl_map_node **) vtbl_map_hash.find_slot (&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;
+ tree class_type_decl;
+ unsigned int type_quals;
+
+ if (!vtbl_map_hash.is_created())
+ vtbl_map_hash.create (10);
+
+ /* Find the TYPE_DECL for the class. */
+ class_type_decl = TYPE_NAME (base_class_type);
+
+ /* Verify that there aren't any type qualifiers on type. */
+ type_quals = TYPE_QUALS (TREE_TYPE (class_type_decl));
+ gcc_assert (type_quals == TYPE_UNQUALIFIED);
+
+ gcc_assert (HAS_DECL_ASSEMBLER_NAME_P (class_type_decl));
+ key.class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+ slot = (struct vtbl_map_node **) vtbl_map_hash.find_slot (&key,
+ INSERT);
+
+ if (*slot)
+ return *slot;
+
+ node = XNEW (struct vtbl_map_node);
+ node->vtbl_map_decl = NULL_TREE;
+ node->class_name = key.class_name;
+ node->uid = num_vtable_map_nodes++;
+
+ node->class_info = XNEW (struct vtv_graph_node);
+ node->class_info->class_type = base_class_type;
+ node->class_info->class_uid = node->uid;
+ node->class_info->num_processed_children = 0;
+
+ (node->class_info->parents).create (4);
+ (node->class_info->children).create (4);
+
+ node->registered.create (16);
+
+ node->is_used = false;
+
+ vtbl_map_nodes_vec.safe_push (node);
+ gcc_assert (vtbl_map_nodes_vec[node->uid] == node);
+
+ *slot = node;
+ return node;
+}
+
+/* End of hashtable functions for vtable_map variables hash table. */
+
+/* Given a gimple STMT, this function checks to see if the statement
+ is an assignment, the rhs of which is getting the vtable pointer
+ value out of an object. (i.e. it's the value we need to verify
+ because its the vtable pointer that will be used for a virtual
+ call). */
+
+static bool
+is_vtable_assignment_stmt (gimple stmt)
+{
+
+ if (gimple_code (stmt) != GIMPLE_ASSIGN)
+ return false;
+ else
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+
+ if (TREE_CODE (lhs) != SSA_NAME)
+ return false;
+
+ if (TREE_CODE (rhs) != COMPONENT_REF)
+ return false;
+
+ if (! (TREE_OPERAND (rhs, 1))
+ || (TREE_CODE (TREE_OPERAND (rhs, 1)) != FIELD_DECL))
+ return false;
+
+ if (! DECL_VIRTUAL_P (TREE_OPERAND (rhs, 1)))
+ return false;
+ }
+
+ return true;
+}
+
+/* This function attempts to recover the declared class of an object
+ that is used in making a virtual call. We try to get the type from
+ the type cast in the gimple assignment statement that extracts the
+ vtable pointer from the object (DEF_STMT). The gimple statement
+ usually looks something like this:
+
+ D.2201_4 = MEM[(struct Event *)this_1(D)]._vptr.Event */
+
+static tree
+extract_object_class_type (tree rhs)
+{
+ tree result = NULL_TREE;
+
+ /* Try to find and extract the type cast from that stmt. */
+ if (TREE_CODE (rhs) == COMPONENT_REF)
+ {
+ tree op0 = TREE_OPERAND (rhs, 0);
+ tree op1 = TREE_OPERAND (rhs, 1);
+
+ if (TREE_CODE (op1) == FIELD_DECL
+ && DECL_VIRTUAL_P (op1))
+ {
+ if (TREE_CODE (op0) == COMPONENT_REF
+ && TREE_CODE (TREE_OPERAND (op0, 0)) == MEM_REF
+ && TREE_CODE (TREE_TYPE (TREE_OPERAND (op0, 0)))== RECORD_TYPE)
+ result = TREE_TYPE (TREE_OPERAND (op0, 0));
+ else
+ result = TREE_TYPE (op0);
+ }
+ else if (TREE_CODE (op0) == COMPONENT_REF)
+ {
+ result = extract_object_class_type (op0);
+ if (result == NULL_TREE
+ && TREE_CODE (op1) == COMPONENT_REF)
+ result = extract_object_class_type (op1);
+ }
+ }
+
+ return result;
+}
+
+/* This function traces forward through the def-use chain of an SSA
+ variable to see if it ever gets used in a virtual function call. It
+ returns a boolean indicating whether or not it found a virtual call in
+ the use chain. */
+
+static bool
+var_is_used_for_virtual_call_p (tree lhs, int *mem_ref_depth)
+{
+ imm_use_iterator imm_iter;
+ bool found_vcall = false;
+ use_operand_p use_p;
+
+ if (TREE_CODE (lhs) != SSA_NAME)
+ return false;
+
+ if (*mem_ref_depth > 2)
+ return false;
+
+ /* Iterate through the immediate uses of the current variable. If
+ it's a virtual function call, we're done. Otherwise, if there's
+ an LHS for the use stmt, add the ssa var to the work list
+ (assuming it's not already in the list and is not a variable
+ we've already examined. */
+
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+ {
+ gimple stmt2 = USE_STMT (use_p);
+
+ if (gimple_code (stmt2) == GIMPLE_CALL)
+ {
+ tree fncall = gimple_call_fn (stmt2);
+ if (TREE_CODE (fncall) == OBJ_TYPE_REF)
+ found_vcall = true;
+ else
+ return false;
+ }
+ else if (gimple_code (stmt2) == GIMPLE_PHI)
+ {
+ found_vcall = var_is_used_for_virtual_call_p
+ (gimple_phi_result (stmt2),
+ mem_ref_depth);
+ }
+ else if (gimple_code (stmt2) == GIMPLE_ASSIGN)
+ {
+ tree rhs = gimple_assign_rhs1 (stmt2);
+ if (TREE_CODE (rhs) == ADDR_EXPR
+ || TREE_CODE (rhs) == MEM_REF)
+ *mem_ref_depth = *mem_ref_depth + 1;
+
+ if (TREE_CODE (rhs) == COMPONENT_REF)
+ {
+ while (TREE_CODE (TREE_OPERAND (rhs, 0)) == COMPONENT_REF)
+ rhs = TREE_OPERAND (rhs, 0);
+
+ if (TREE_CODE (TREE_OPERAND (rhs, 0)) == ADDR_EXPR
+ || TREE_CODE (TREE_OPERAND (rhs, 0)) == MEM_REF)
+ *mem_ref_depth = *mem_ref_depth + 1;
+ }
+
+ if (*mem_ref_depth < 3)
+ found_vcall = var_is_used_for_virtual_call_p
+ (gimple_assign_lhs (stmt2),
+ mem_ref_depth);
+ }
+
+ else
+ break;
+
+ if (found_vcall)
+ return true;
+ }
+
+ return false;
+}
+
+/* Search through all the statements in a basic block (BB), searching
+ for virtual method calls. For each virtual method dispatch, find
+ the vptr value used, and the statically declared type of the
+ object; retrieve the vtable map variable for the type of the
+ object; generate a call to __VLTVerifyVtablePointer; and insert the
+ generated call into the basic block, after the point where the vptr
+ value is gotten out of the object and before the virtual method
+ dispatch. Make the virtual method dispatch depend on the return
+ value from the verification call, so that subsequent optimizations
+ cannot reorder the two calls. */
+
+static void
+verify_bb_vtables (basic_block bb)
+{
+ gimple_seq stmts;
+ gimple stmt = NULL;
+ gimple_stmt_iterator gsi_vtbl_assign;
+ gimple_stmt_iterator gsi_virtual_call;
+
+ stmts = bb_seq (bb);
+ gsi_virtual_call = gsi_start (stmts);
+ for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
+ {
+ stmt = gsi_stmt (gsi_virtual_call);
+
+ /* Count virtual calls. */
+ if (gimple_code (stmt) == GIMPLE_CALL)
+ {
+ tree fncall = gimple_call_fn (stmt);
+ if (TREE_CODE (fncall) == OBJ_TYPE_REF)
+ total_num_virtual_calls++;
+ }
+
+ if (is_vtable_assignment_stmt (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree vtbl_var_decl = NULL_TREE;
+ struct vtbl_map_node *vtable_map_node;
+ tree vtbl_decl = NULL_TREE;
+ gimple call_stmt;
+ const char *vtable_name = "<unknown>";
+ tree tmp0;
+ bool found;
+ int mem_ref_depth = 0;
+
+ /* Make sure this vptr field access is for a virtual call. */
+ if (!var_is_used_for_virtual_call_p (lhs, &mem_ref_depth))
+ continue;
+
+ /* Now we have found the virtual method dispatch and
+ the preceding access of the _vptr.* field... Next
+ we need to find the statically declared type of
+ the object, so we can find and use the right
+ vtable map variable in the verification call. */
+ tree class_type = extract_object_class_type
+ (gimple_assign_rhs1 (stmt));
+
+ gsi_vtbl_assign = gsi_for_stmt (stmt);
+
+ if (class_type
+ && (TREE_CODE (class_type) == RECORD_TYPE)
+ && TYPE_BINFO (class_type))
+ {
+ /* Get the vtable VAR_DECL for the type. */
+ vtbl_var_decl = BINFO_VTABLE (TYPE_BINFO (class_type));
+
+ if (TREE_CODE (vtbl_var_decl) == POINTER_PLUS_EXPR)
+ vtbl_var_decl = TREE_OPERAND (TREE_OPERAND (vtbl_var_decl, 0),
+ 0);
+
+ gcc_assert (vtbl_var_decl);
+
+ vtbl_decl = vtbl_var_decl;
+ vtable_map_node = vtbl_map_get_node
+ (TYPE_MAIN_VARIANT (class_type));
+
+ gcc_assert (verify_vtbl_ptr_fndecl);
+
+ /* Given the vtable pointer for the base class of the
+ object, build the call to __VLTVerifyVtablePointer to
+ verify that the object's vtable pointer (contained in
+ lhs) is in the set of valid vtable pointers for the
+ base class. */
+
+ if (vtable_map_node && vtable_map_node->vtbl_map_decl)
+ {
+ use_operand_p use_p;
+ ssa_op_iter iter;
+
+ vtable_map_node->is_used = true;
+ vtbl_var_decl = vtable_map_node->vtbl_map_decl;
+
+ if (TREE_CODE (vtbl_decl) == VAR_DECL)
+ vtable_name = IDENTIFIER_POINTER (DECL_NAME (vtbl_decl));
+
+ /* Call different routines if we are interested in
+ trace information to debug problems. */
+ if (flag_vtv_debug)
+ {
+ int len1 = IDENTIFIER_LENGTH
+ (DECL_NAME (vtbl_var_decl));
+ int len2 = strlen (vtable_name);
+
+ call_stmt = gimple_build_call
+ (verify_vtbl_ptr_fndecl, 4,
+ build1 (ADDR_EXPR,
+ TYPE_POINTER_TO
+ (TREE_TYPE (vtbl_var_decl)),
+ vtbl_var_decl),
+ lhs,
+ build_string_literal
+ (len1 + 1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (vtbl_var_decl))),
+ build_string_literal (len2 + 1,
+ vtable_name));
+ }
+ else
+ call_stmt = gimple_build_call
+ (verify_vtbl_ptr_fndecl, 2,
+ build1 (ADDR_EXPR,
+ TYPE_POINTER_TO
+ (TREE_TYPE (vtbl_var_decl)),
+ vtbl_var_decl),
+ lhs);
+
+
+ /* Create a new SSA_NAME var to hold the call's
+ return value, and make the call_stmt use the
+ variable for that purpose. */
+ tmp0 = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "VTV");
+ gimple_call_set_lhs (call_stmt, tmp0);
+ update_stmt (call_stmt);
+
+ /* Find the next stmt, after the vptr assignment
+ statememt, which should use the result of the
+ vptr assignment statement value. */
+ gsi_next (&gsi_vtbl_assign);
+ gimple next_stmt = gsi_stmt (gsi_vtbl_assign);
+
+ if (!next_stmt)
+ return;
+
+ /* Find any/all uses of 'lhs' in next_stmt, and
+ replace them with 'tmp0'. */
+ found = false;
+ FOR_EACH_PHI_OR_STMT_USE (use_p, next_stmt, iter,
+ SSA_OP_ALL_USES)
+ {
+ tree op = USE_FROM_PTR (use_p);
+ if (op == lhs)
+ {
+ SET_USE (use_p, tmp0);
+ found = true;
+ }
+ }
+ update_stmt (next_stmt);
+ gcc_assert (found);
+
+ /* Insert the new verification call just after the
+ statement that gets the vtable pointer out of the
+ object. */
+ gsi_vtbl_assign = gsi_for_stmt (stmt);
+ gsi_insert_after (&gsi_vtbl_assign, call_stmt,
+ GSI_NEW_STMT);
+
+ any_verification_calls_generated = true;
+ total_num_verified_vcalls++;
+ }
+ }
+ }
+ }
+}
+
+/* Main function, called from pass->excute(). Loop through all the
+ basic blocks in the current function, passing them to
+ verify_bb_vtables, which searches for virtual calls, and inserts
+ calls to __VLTVerifyVtablePointer. */
+
+unsigned int
+vtable_verify_main (void)
+{
+ unsigned int ret = 1;
+ basic_block bb;
+
+ FOR_ALL_BB (bb)
+ verify_bb_vtables (bb);
+
+ return ret;
+}
+
+/* Gate function for the pass. */
+
+static bool
+gate_tree_vtable_verify (void)
+{
+ return (flag_vtable_verify);
+}
+
+/* Definition of this optimization pass. */
+
+namespace {
+
+const pass_data pass_data_vtable_verify =
+{
+ GIMPLE_PASS, /* type */
+ "vtable-verify", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ true, /* has_gate */
+ true, /* has_execute */
+ 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_flags_finish */
+};
+
+class pass_vtable_verify : public gimple_opt_pass
+{
+public:
+ pass_vtable_verify(gcc::context *ctxt)
+ : gimple_opt_pass(pass_data_vtable_verify, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ bool gate () { return gate_tree_vtable_verify (); }
+ unsigned int execute () { return vtable_verify_main (); }
+
+}; // class pass_vtable_verify
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_vtable_verify (gcc::context *ctxt)
+{
+ return new pass_vtable_verify (ctxt);
+}
+
+#include "gt-vtable-verify.h"
diff --git a/gcc/vtable-verify.h b/gcc/vtable-verify.h
new file mode 100644
index 00000000000..7ac487bef52
--- /dev/null
+++ b/gcc/vtable-verify.h
@@ -0,0 +1,141 @@
+/* Copyright (C) 2013
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Virtual Table Pointer Security. */
+
+#ifndef VTABLE_VERIFY_H
+#define VTABLE_VERIFY_H
+
+#include "sbitmap.h"
+#include "hash-table.h"
+
+/* The function decl used to create calls to __VLTVtableVerify. It must
+ be global because it needs to be initialized in the C++ front end, but
+ used in the middle end (in the vtable verification pass). */
+
+extern tree verify_vtbl_ptr_fndecl;
+
+/* Global variable keeping track of how many vtable map variables we
+ have created. */
+extern unsigned num_vtable_map_nodes;
+
+/* Keep track of how many virtual calls we are actually verifying. */
+extern int total_num_virtual_calls;
+extern int total_num_verified_vcalls;
+
+/* Each vtable map variable corresponds to a virtual class. Each
+ vtable map variable has a hash table associated with it, that keeps
+ track of the vtable pointers for which we have generated a call to
+ __VLTRegisterPair (with the current vtable map variable). This is
+ the hash table node that is used for each entry in this hash table
+ of vtable pointers.
+
+ Sometimes there are multiple valid vtable pointer entries that use
+ the same vtable pointer decl with different offsets. Therefore,
+ for each vtable pointer in the hash table, there is also an array
+ of offsets used with that vtable. */
+
+struct vtable_registration
+{
+ tree vtable_decl; /* The var decl of the vtable. */
+ vec<unsigned> offsets; /* The offsets array. */
+};
+
+struct registration_hasher : typed_noop_remove <struct vtable_registration>
+{
+ typedef struct vtable_registration value_type;
+ typedef struct vtable_registration compare_type;
+ static inline hashval_t hash (const value_type *);
+ static inline bool equal (const value_type *, const compare_type *);
+};
+
+typedef hash_table <registration_hasher> register_table_type;
+typedef register_table_type::iterator registration_iterator_type;
+
+/* This struct is used to represent the class hierarchy information
+ that we need. Each vtable map variable has an associated class
+ hierarchy node (struct vtv_graph_node). Note: In this struct,
+ 'children' means immediate descendants in the class hierarchy;
+ 'descendant' means any descendant however many levels deep. */
+
+struct vtv_graph_node {
+ tree class_type; /* The record_type of the class. */
+ unsigned class_uid; /* A unique, monotonically
+ ascending id for class node.
+ Each vtable map node also has
+ an id. The class uid is the
+ same as the vtable map node id
+ for nodes corresponding to the
+ same class. */
+ unsigned num_processed_children; /* # of children for whom we have
+ computed the class hierarchy
+ transitive closure. */
+ vec<struct vtv_graph_node *> parents; /* Vector of parents in the graph. */
+ vec<struct vtv_graph_node *> children; /* Vector of children in the graph.*/
+ sbitmap descendants; /* Bitmap representing all this node's
+ descendants in the graph. */
+};
+
+/* This is the node used for our hashtable of vtable map variable
+ information. When we create a vtable map variable (var decl) we
+ put it into one of these nodes; create a corresponding
+ vtv_graph_node for our class hierarchy info and store that in this
+ node; generate a unique (monotonically ascending) id for both the
+ vtbl_map_node and the vtv_graph_node; and insert the node into two
+ data structures (to make it easy to find in several different
+ ways): 1). A hash table ("vtbl_map_hash" in vtable-verify.c).
+ This gives us an easy way to check to see if we already have a node
+ for the vtable map variable or not; and 2). An array (vector) of
+ vtbl_map_nodes, where the array index corresponds to the unique id
+ of the vtbl_map_node, which gives us an easy way to use bitmaps to
+ represent and find the vtable map nodes. */
+
+struct vtbl_map_node {
+ tree vtbl_map_decl; /* The var decl for the vtable map
+ variable. */
+ tree class_name; /* The DECL_ASSEMBLER_NAME of the
+ class. */
+ struct vtv_graph_node *class_info; /* Our class hierarchy info for the
+ class. */
+ unsigned uid; /* The unique id for the vtable map
+ variable. */
+ struct vtbl_map_node *next, *prev; /* Pointers for the linked list
+ structure. */
+ register_table_type registered; /* Hashtable of vtable pointers for which
+ we have generated a _VLTRegisterPair
+ call with this vtable map variable. */
+ bool is_used; /* Boolean indicating if we used this vtable map
+ variable in a call to __VLTVerifyVtablePointer. */
+};
+
+/* Controls debugging for vtable verification. */
+extern bool vtv_debug;
+
+/* The global vector of vtbl_map_nodes. */
+extern vec<struct vtbl_map_node *> vtbl_map_nodes_vec;
+
+extern struct vtbl_map_node *vtbl_map_get_node (tree);
+extern struct vtbl_map_node *find_or_create_vtbl_map_node (tree);
+extern void vtbl_map_node_class_insert (struct vtbl_map_node *, unsigned);
+extern bool vtbl_map_node_registration_find (struct vtbl_map_node *,
+ tree, unsigned);
+extern bool vtbl_map_node_registration_insert (struct vtbl_map_node *,
+ tree, unsigned);
+
+#endif /* VTABLE_VERIFY_H */