aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaroline Tice <ctice@apple.com>2013-03-15 23:31:18 +0000
committerCaroline Tice <ctice@apple.com>2013-03-15 23:31:18 +0000
commitd25e34f7584ea8bf1186f727b32d50709cdefdc6 (patch)
tree155947ea5d4445c93ae76e56d9b73c1400253455
parent94f0469389163b7e3b00d3876931cb4cef48174f (diff)
Add vtable verification feature but do not turn it on.google/gcc-4_7-mobile
git-svn-id: https://gcc.gnu.org/svn/gcc/branches/google/gcc-4_7-mobile@196691 138bc75d-0d04-0410-961f-82ee72b054a4
-rwxr-xr-xconfigure4
-rw-r--r--configure.ac4
-rw-r--r--gcc/Makefile.in10
-rw-r--r--gcc/cgraph.c5
-rw-r--r--gcc/common.opt16
-rw-r--r--gcc/config/gnu-user.h9
-rw-r--r--gcc/config/i386/gnu-user.h3
-rw-r--r--gcc/config/i386/gnu-user64.h3
-rw-r--r--gcc/cp/Make-lang.in9
-rw-r--r--gcc/cp/class.c3
-rw-r--r--gcc/cp/config-lang.in2
-rw-r--r--gcc/cp/cp-tree.h10
-rw-r--r--gcc/cp/decl2.c44
-rw-r--r--gcc/cp/g++spec.c47
-rw-r--r--gcc/cp/init.c3
-rw-r--r--gcc/cp/mangle.c32
-rw-r--r--gcc/cp/pt.c1
-rw-r--r--gcc/cp/vtable-class-hierarchy.c1370
-rw-r--r--gcc/flag-types.h7
-rw-r--r--gcc/output.h4
-rw-r--r--gcc/passes.c1
-rw-r--r--gcc/timevar.def1
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/tree-vtable-verify.c754
-rw-r--r--gcc/tree-vtable-verify.h151
-rw-r--r--gcc/tree.h3
-rw-r--r--gcc/varasm.c35
-rw-r--r--libgcc/Makefile.in11
-rw-r--r--libgcc/config.host2
-rw-r--r--libgcc/configure12
-rw-r--r--libgcc/vtv_end.c59
-rw-r--r--libgcc/vtv_start.c59
-rw-r--r--libstdc++-v3/acinclude.m419
-rw-r--r--libstdc++-v3/config/abi/pre/gnu.ver14
-rwxr-xr-xlibstdc++-v3/configure65
-rw-r--r--libstdc++-v3/configure.ac6
-rw-r--r--libstdc++-v3/libsupc++/Makefile.am77
-rw-r--r--libstdc++-v3/libsupc++/Makefile.in277
-rw-r--r--libstdc++-v3/libsupc++/vtv_fail.h53
-rw-r--r--libstdc++-v3/libsupc++/vtv_init.cc179
-rw-r--r--libstdc++-v3/libsupc++/vtv_malloc.cc210
-rw-r--r--libstdc++-v3/libsupc++/vtv_malloc.h49
-rw-r--r--libstdc++-v3/libsupc++/vtv_map.h311
-rw-r--r--libstdc++-v3/libsupc++/vtv_rts.cc1314
-rw-r--r--libstdc++-v3/libsupc++/vtv_rts.h56
-rw-r--r--libstdc++-v3/libsupc++/vtv_set.h652
-rw-r--r--libstdc++-v3/libsupc++/vtv_stubs.cc97
-rw-r--r--libstdc++-v3/libsupc++/vtv_utils.cc122
-rw-r--r--libstdc++-v3/libsupc++/vtv_utils.h55
-rw-r--r--libstdc++-v3/src/Makefile.am16
-rw-r--r--libstdc++-v3/src/Makefile.in19
-rw-r--r--libstdc++-v3/src/c++11/Makefile.am15
-rw-r--r--libstdc++-v3/src/c++11/Makefile.in13
-rw-r--r--libstdc++-v3/src/c++98/Makefile.am15
-rw-r--r--libstdc++-v3/src/c++98/Makefile.in13
55 files changed, 6209 insertions, 113 deletions
diff --git a/configure b/configure
index a51db6ea867..120b23b56c2 100755
--- a/configure
+++ b/configure
@@ -13687,7 +13687,7 @@ else
esac
if test $ok = yes; then
# An in-tree tool is available and we can use it
- CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/g++ -B$$r/$(HOST_SUBDIR)/gcc/ -nostdinc++ `if test -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags; then $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs'
+ CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/g++ -B$$r/$(HOST_SUBDIR)/gcc/ -nostdinc++ `if test -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags; then $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/libsupc++/.libs'
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
$as_echo "just compiled" >&6; }
elif expr "x$CXX_FOR_TARGET" : "x/" > /dev/null; then
@@ -13732,7 +13732,7 @@ else
esac
if test $ok = yes; then
# An in-tree tool is available and we can use it
- RAW_CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/xgcc -shared-libgcc -B$$r/$(HOST_SUBDIR)/gcc -nostdinc++ -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs'
+ RAW_CXX_FOR_TARGET='$$r/$(HOST_SUBDIR)/gcc/xgcc -shared-libgcc -B$$r/$(HOST_SUBDIR)/gcc -nostdinc++ -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/libsupc++/.libs'
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: just compiled" >&5
$as_echo "just compiled" >&6; }
elif expr "x$RAW_CXX_FOR_TARGET" : "x/" > /dev/null; then
diff --git a/configure.ac b/configure.ac
index ad6903ec472..97a68bfff23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3126,10 +3126,10 @@ GCC_TARGET_TOOL(as, AS_FOR_TARGET, AS, [gas/as-new])
GCC_TARGET_TOOL(cc, CC_FOR_TARGET, CC, [gcc/xgcc -B$$r/$(HOST_SUBDIR)/gcc/])
dnl see comments for CXX_FOR_TARGET_FLAG_TO_PASS
GCC_TARGET_TOOL(c++, CXX_FOR_TARGET, CXX,
- [gcc/g++ -B$$r/$(HOST_SUBDIR)/gcc/ -nostdinc++ `if test -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags; then $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs],
+ [gcc/g++ -B$$r/$(HOST_SUBDIR)/gcc/ -nostdinc++ `if test -f $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags; then $(SHELL) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/libsupc++/.libs],
c++)
GCC_TARGET_TOOL(c++ for libstdc++, RAW_CXX_FOR_TARGET, CXX,
- [gcc/xgcc -shared-libgcc -B$$r/$(HOST_SUBDIR)/gcc -nostdinc++ -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs],
+ [gcc/xgcc -shared-libgcc -B$$r/$(HOST_SUBDIR)/gcc -nostdinc++ -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/src/.libs -L$$r/$(TARGET_SUBDIR)/libstdc++-v3/libsupc++/.libs],
c++)
GCC_TARGET_TOOL(dlltool, DLLTOOL_FOR_TARGET, DLLTOOL, [binutils/dlltool])
GCC_TARGET_TOOL(gcc, GCC_FOR_TARGET, , [gcc/xgcc -B$$r/$(HOST_SUBDIR)/gcc/])
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 222282b58a1..4e25c942eb6 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -866,6 +866,7 @@ TREE_H = tree.h all-tree.def tree.def c-family/c-common.def \
$(INPUT_H) statistics.h $(VEC_H) treestruct.def $(HASHTAB_H) \
double-int.h alias.h $(SYMTAB_H) $(FLAGS_H) vecir.h \
$(REAL_H) $(FIXED_VALUE_H)
+CP_TREE_H = cp/cp-tree.h
REGSET_H = regset.h $(BITMAP_H) hard-reg-set.h
BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) cfghooks.h
GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \
@@ -1448,6 +1449,7 @@ OBJS = \
tree-vect-loop-manip.o \
tree-vect-slp.o \
tree-vectorizer.o \
+ tree-vtable-verify.o \
tree-vrp.o \
tree.o \
value-prof.o \
@@ -2694,6 +2696,13 @@ tree-vectorizer.o: tree-vectorizer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(GGC_H) $(TREE_H) $(DIAGNOSTIC_H) $(TREE_FLOW_H) $(TREE_DUMP_H) \
$(CFGLOOP_H) $(TREE_PASS_H) $(TREE_VECTORIZER_H) $(TIMEVAR_H) \
tree-pretty-print.h
+tree-vtable-verify.o: tree-vtable-verify.c tree-vtable-verify.h \
+ gt-tree-vtable-verify.h
+# $(CONFIG_H) \
+# $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(CP_TREE_H) $(TM_P_H) \
+# $(BASIC_BLOCK_H) output.h $(TREE_FLOW_H) $(TREE_DUMP_H) $(TREE_PASS_H) \
+# $(TIMEVAR_H) $(CFGLOOP_H) $(FLAGS_H) $(TREE_INLINE_H) $(SCEV_H) \
+# $(DIAGNOSTIC_CORE_H) gimple-pretty-print.h toplev.h langhooks.h
tree-loop-distribution.o: tree-loop-distribution.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TREE_FLOW_H) $(CFGLOOP_H) $(TREE_DATA_REF_H) $(TREE_PASS_H)
tree-parloops.o: tree-parloops.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
@@ -3796,6 +3805,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)/tree-vtable-verify.c \
@all_gtfiles@
# Compute the list of GT header files from the corresponding C sources,
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 8d2958151b5..e3a59ee77d2 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -2512,7 +2512,10 @@ cgraph_add_new_function (tree fndecl, bool lowered)
case CGRAPH_STATE_FINISHED:
/* At the very end of compilation we have to do all the work up
to expansion. */
- node = cgraph_create_node (fndecl);
+ if (flag_vtable_verify)
+ node = cgraph_get_create_node (fndecl);
+ else
+ node = cgraph_create_node (fndecl);
if (lowered)
node->lowered = true;
cgraph_analyze_function (node);
diff --git a/gcc/common.opt b/gcc/common.opt
index e4e53a94917..6250fe6b2a1 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -2407,6 +2407,22 @@ 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)
+
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 cb457490e7a..ee17b4bf3ad 100644
--- a/gcc/config/gnu-user.h
+++ b/gcc/config/gnu-user.h
@@ -44,11 +44,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#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*: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*:vtv_start.o%s}"
#endif
#undef STARTFILE_SPEC
#define STARTFILE_SPEC GNU_USER_TARGET_STARTFILE_SPEC
@@ -60,7 +62,8 @@ 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*: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/config/i386/gnu-user.h b/gcc/config/i386/gnu-user.h
index e645fad3cf7..692509ef098 100644
--- a/gcc/config/i386/gnu-user.h
+++ b/gcc/config/i386/gnu-user.h
@@ -111,7 +111,8 @@ along with GCC; see the file COPYING3. If not see
/* Similar to standard GNU userspace, but adding -ffast-math support. */
#undef ENDFILE_SPEC
#define ENDFILE_SPEC \
- "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
+ "%{fvtable-verify*:vtv_end.o%s} \
+ %{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
%{mpc32:crtprec32.o%s} \
%{mpc64:crtprec64.o%s} \
%{mpc80:crtprec80.o%s} \
diff --git a/gcc/config/i386/gnu-user64.h b/gcc/config/i386/gnu-user64.h
index 954f3b2ff24..03b8c12d87b 100644
--- a/gcc/config/i386/gnu-user64.h
+++ b/gcc/config/i386/gnu-user64.h
@@ -88,7 +88,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
/* Similar to standard GNU userspace, but adding -ffast-math support. */
#undef ENDFILE_SPEC
#define ENDFILE_SPEC \
- "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
+ "%{fvtable-verify*:vtv_end.o%s} \
+ %{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \
%{mpc32:crtprec32.o%s} \
%{mpc64:crtprec64.o%s} \
%{mpc80:crtprec80.o%s} \
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 26055b632d9..6e8c1354f1f 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -82,7 +82,7 @@ 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 tree-mudflap.o $(CXX_C_OBJS)
+ cp/cp-gimplify.o tree-mudflap.o cp/vtable-class-hierarchy.o $(CXX_C_OBJS)
# Language-specific object files for C++.
CXX_OBJS = cp/cp-lang.o c-family/stub-objc.o $(CXX_AND_OBJCXX_OBJS)
@@ -340,7 +340,12 @@ cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) $(DIAGNOSTIC_CORE_H) \
tree-threadsafe-analyze.h
cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) $(C_COMMON_H) \
$(TM_H) coretypes.h pointer-set.h tree-iterator.h $(SPLAY_TREE_H)
-
+cp/vtable-class-hierarchy.o: cp/vtable-class-hierarchy.c \
+ $(TM_H) $(TIMEVAR_H) $(CXX_TREE_H) intl.h $(CXX_PARSER_H) cp/decl.h \
+ $(FLAGS_H) $(DIAGNOSTIC_CORE_H) output.h $(CGRAPH_H) c-family/c-common.h \
+ c-family/c-objc.h $(PLUGIN_H) \
+ tree-iterator.h tree-vtable-verify.h $(GIMPLE_H) \
+ gt-cp-vtable-class-hierarchy.h
cp/name-lookup.o: cp/name-lookup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) $(CXX_TREE_H) $(TIMEVAR_H) gt-cp-name-lookup.h \
$(DIAGNOSTIC_CORE_H) $(FLAGS_H) debug.h pointer-set.h
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 3f9e2e02639..5ee2e6c4bd9 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6136,6 +6136,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 3ed3d8e880f..3f68601636a 100644
--- a/gcc/cp/config-lang.in
+++ b/gcc/cp/config-lang.in
@@ -30,4 +30,4 @@ compilers="cc1plus\$(exeext)"
target_libs="target-libstdc++-v3"
-gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c"
+gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c"
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5d5a5c86532..91882d089d4 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5149,6 +5149,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);
@@ -5236,6 +5238,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);
@@ -5917,6 +5920,7 @@ extern tree mangle_thunk (tree, int, tree, tree);
extern tree mangle_conv_op_name_for_type (tree);
extern tree mangle_guard_variable (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);
@@ -5964,6 +5968,12 @@ 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);
+
/* -- end of C++ */
#endif /* ! GCC_CP_TREE_H */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index cd02b4521c9..3e156c98bd9 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -2778,7 +2778,8 @@ set_guard (tree guard)
}
/* 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)
@@ -2830,8 +2831,12 @@ start_objects (int method_type, int initp)
return body;
}
-/* Finish the process of running a particular set of global constructors
- or destructors. Subroutine of do_[cd]tors. */
+/* Finish the process of running a particular set of global
+ constructors or destructors. Subroutine of do_[cd]tors. Also
+ called from vtv_finish_verification_constructor_init_function.
+
+ This function returns a tree containing the functino decl for the
+ functin it finished creating. */
static void
finish_objects (int method_type, int initp, tree body)
@@ -4121,8 +4126,22 @@ cp_write_global_declarations (void)
timevar_start (TV_PHASE_CGRAPH);
+ if (flag_vtable_verify)
+ {
+ vtv_recover_class_info ();
+ vtv_compute_class_hierarchy_transitive_closure ();
+ }
+
cgraph_finalize_compilation_unit ();
+ if (flag_vtable_verify)
+ {
+ /* Generate the special constructor initialization function that
+ calls __VLTRegisterPairs, and give it a very high initialization
+ priority. */
+ vtv_generate_init_routine ();
+ }
+
timevar_stop (TV_PHASE_CGRAPH);
timevar_start (TV_PHASE_CHECK_DBGINFO);
@@ -4471,4 +4490,23 @@ mark_used (tree decl)
return true;
}
+tree
+vtv_start_verification_constructor_init_function (void)
+{
+ return start_objects ('I', MAX_RESERVED_INIT_PRIORITY - 1);
+}
+
+tree
+vtv_finish_verification_constructor_init_function (tree function_body)
+{
+ 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/g++spec.c b/gcc/cp/g++spec.c
index 3a9faa9c1e9..9a107b04ae1 100644
--- a/gcc/cp/g++spec.c
+++ b/gcc/cp/g++spec.c
@@ -51,6 +51,8 @@ along with GCC; see the file COPYING3. If not see
#define LIBSTDCXX_STATIC NULL
#endif
+#define VTABLE_LOAD_MODULE_INIT "--whole-archive,-lvtv_init,--no-whole-archive"
+
void
lang_specific_driver (struct cl_decoded_option **in_decoded_options,
unsigned int *in_decoded_options_count,
@@ -112,6 +114,11 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
/* The total number of arguments with the new stuff. */
unsigned int num_args = 1;
+ /* The command line contains a -fvtable_verify. We need to add the
+ init library if we are linking and if we are adding the stdc++
+ library. */
+ int saw_vtable_verify = 0;
+
argc = *in_decoded_options_count;
decoded_options = *in_decoded_options;
added_libraries = *in_added_libraries;
@@ -237,6 +244,13 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
}
}
break;
+
+ case OPT_fvtable_verify_:
+ if (strcmp (arg, "std") == 0)
+ saw_vtable_verify = 1;
+ else if (strcmp (arg, "preinit") == 0)
+ saw_vtable_verify = 2;
+ break;
}
}
@@ -248,6 +262,12 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
/* Add one for shared_libgcc or extra static library. */
num_args = argc + added + need_math + (library > 0) * 4 + 1;
+
+ /* Add two more linker args, '-Wl,-u_vtable_map_vars_start and
+ '-Wl,-u_vtable_map_vars_end. */
+ if (saw_vtable_verify && library > 0)
+ num_args += 2;
+
new_decoded_options = XNEWVEC (struct cl_decoded_option, num_args);
i = 0;
@@ -310,6 +330,33 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
j++;
}
+ /* Add option to make sure that if we are doing 'std' vtable
+ verification then we link with the libvtv_init library. */
+
+ if (saw_vtable_verify == 1 && library > 0)
+ {
+ generate_option(OPT_Wl_, VTABLE_LOAD_MODULE_INIT, 1,
+ CL_DRIVER, &new_decoded_options[j]);
+ added_libraries++;
+ j++;
+ }
+
+ /* If we are doing vtable verification, make sure the linker does
+ not garbage-collect the special symbols that mark the start and
+ end of the ".vtable_map_vars" section in the binary. (See
+ comments in vtv_start.c and vtv_end.c for more details). */
+
+ if (saw_vtable_verify > 0 && library > 0)
+ {
+ generate_option (OPT_Wl_,"-u_vtable_map_vars_start", 1,
+ CL_DRIVER, &new_decoded_options[j]);
+ j++;
+
+ generate_option (OPT_Wl_,"-u_vtable_map_vars_end", 1,
+ CL_DRIVER, &new_decoded_options[j]);
+ j++;
+ }
+
/* Add `-lstdc++' if we haven't already done so. */
if (library > 0)
{
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 4e6d3fb5554..0c998b4ef10 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -46,7 +46,6 @@ static tree initializing_context (tree);
static void expand_cleanup_for_base (tree, tree);
static tree dfs_initialize_vtbl_ptrs (tree, void *);
static tree build_field_list (tree, tree, int *);
-static tree build_vtbl_address (tree);
static int diagnose_uninitialized_cst_or_ref_member_1 (tree, tree, bool, bool);
/* We are about to generate some complex initialization code.
@@ -1105,7 +1104,7 @@ emit_mem_initializers (tree mem_inits)
/* Returns the address of the vtable (i.e., the value that should be
assigned to the vptr) for BINFO. */
-static tree
+tree
build_vtbl_address (tree binfo)
{
tree binfo_for = binfo;
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 98806325d31..a65773311c7 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -3413,7 +3413,8 @@ mangle_decl (const tree decl)
DECL_WEAK (alias) = 1;
if (TREE_CODE (decl) == FUNCTION_DECL)
cgraph_same_body_alias (cgraph_get_create_node (decl), alias, decl);
- else
+ else if (!flag_vtable_verify
+ || TREE_CODE (decl) == VAR_DECL)
varpool_extra_name_alias (alias, decl);
#endif
}
@@ -3739,4 +3740,33 @@ 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;
+
+ 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 ("_ZN4_VTVI") +
+ strlen ("E12__vtable_mapE") + 1;
+
+ var_name = (char *) xmalloc (len);
+
+ sprintf (var_name, "_ZN4_VTVI%sE12__vtable_mapE",
+ IDENTIFIER_POINTER (class_id));
+
+ return var_name;
+}
+
#include "gt-cp-mangle.h"
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 6643047b60f..87c6eec1e08 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -17799,6 +17799,7 @@ mark_class_instantiated (tree t, int extern_p)
if (! extern_p)
{
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+
rest_of_type_compilation (t, 1);
}
}
diff --git a/gcc/cp/vtable-class-hierarchy.c b/gcc/cp/vtable-class-hierarchy.c
new file mode 100644
index 00000000000..a2d999cf44b
--- /dev/null
+++ b/gcc/cp/vtable-class-hierarchy.c
@@ -0,0 +1,1370 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Virtual Table Pointer Security Pass - Detect corruption of vtable pointers
+ before using them for virtual method dispatches. */
+
+/* This file is part of the vtable security feature implementation.
+ The vtable security feature is designed to detect when a virtual
+ call is about to be made through an invalid vtable pointer
+ (possibly due to data corruption or malicious attacks). The
+ compiler finds every virtual call, and inserts a verification call
+ before the virtual call. The verification call takes the actual
+ vtable pointer value in the object through which the virtual call
+ is being made, and compares the vtable pointer against a set of all
+ valid vtable pointers that the object could contain (this set is
+ based on the declared type of the object). If the pointer is in
+ the valid set, execution is allowed to continue; otherwise the
+ program is halted.
+
+ There are several pieces needed in order to make this work: 1. For
+ every virtual class in the program (i.e. a class that contains
+ virtual methods), we need to build the set of all possible valid
+ vtables that an object of that class could point to. This includes
+ vtables for any class(es) that inherit from the class under
+ consideration. 2. For every such data set we build up, we need a
+ way to find and reference the data set. This is complicated by the
+ fact that the real vtable addresses are not known until runtime,
+ when the program is loaded into memory, but we need to reference the
+ sets at compile time when we are inserting verification calls into
+ the program. 3. We need to find every virtual call in the program,
+ and insert the verification call (with the appropriate arguments)
+ before the virtual call. 4. We need some runtime library pieces:
+ the code to build up the data sets at runtime; the code to actually
+ perform the verification using the data sets; and some code to set
+ protections on the data sets, so they themselves do not become
+ hacker targets.
+
+ To find and reference the set of valid vtable pointers for any given
+ virtual class, we create a special global varible for each virtual
+ class. We refer to this as the "vtable map variable" for that
+ class. The vtable map variable has the type "void *", and is
+ initialized by the compiler to NULL. At runtime when the set of
+ valid vtable pointers for a virtual class, e.g. class Foo, is built,
+ the vtable map variable for class Foo is made to point to the set.
+ During compile time, when the compiler is inserting verification
+ calls into the program, it passes the vtable map variable for the
+ appropriate class to the verification call, so that at runtime the
+ verification call can find the appropriate data set.
+
+ The actual set of valid vtable pointers for a virtual class,
+ e.g. class Foo, cannot be built until runtime, when the vtables get
+ loaded into memory and their addresses are known. But the knowledge
+ about which vtables belong in which class' hierarchy is only known
+ at compile time. Therefore at compile time we collect class
+ hierarchy and vtable information about every virtual class, and we
+ generate calls to build up the data sets at runtime. To build the
+ data sets, we call one of the functions we add to the runtime
+ library, __VLTRegisterPair. __VLTRegisterPair takes two arguments,
+ a vtable map variable and the address of a vtable. If the vtable
+ map variable is currently NULL, it creates a new data set (hash
+ table), makes the vtable map variable point to the new data set, and
+ inserts the vtable address into the data set. If the vtable map
+ variable is not NULL, it just inserts the vtable address into the
+ data set. In order to make sure that our data sets are built before
+ any verification calls happen, we create a special constructor
+ initialization function for each compilation unit, give it a very
+ high initialization priority, and insert all of our calls to
+ __VLTRegisterPair into our special constructor initialization
+ function.
+
+ The vtable verification feature is controlled by the flag
+ '-fvtable-verify='. There are three flavors of this:
+ '-fvtable-verify=std', '-fvtable-verify=preinit', and
+ '-fvtable-verify=none'. If the option '-fvtable-verfy=preinit' is
+ used, then our constructor initialization function gets put into the
+ preinit array. This is necessary if there are data sets that need
+ to be built very early in execution. If the constructor
+ initialization function gets put into the preinit array, the we also
+ add calls to __VLTChangePermission at the beginning and end of the
+ function. The call at the beginning sets the permissions on the
+ data sets and vtable map variables to read/write, and the one at the
+ end makes them read-only. If the '-fvtable-verify=std' option is
+ used, the constructor initialization functions are executed at their
+ normal time, and the __VLTChangePermission calls are handled
+ differently (see the comments in libstdc++-v3/libsupc++/vtv_rts.cc).
+ The option '-fvtable-verify=none' turns off vtable verification.
+
+ This file contains code to find and record the class hierarchies for
+ the virtual classes in a program, and all the vtables associated
+ with each such class; to generate the vtable map variables; and to
+ generate the constructor initialization function (with the calls to
+ __VLTRegisterPair, and __VLTChangePermission). The main data
+ structures used for collecting the class hierarchy data and
+ building/maintaining the vtable map variable data are defined in
+ gcc/tree-vtable-verify.h, because they are used both here and in
+ gcc/tree-vtable-verify.c. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "intl.h"
+#include "c-family/c-pragma.h"
+#include "decl.h"
+#include "flags.h"
+#include "diagnostic-core.h"
+#include "output.h"
+#include "target.h"
+#include "cgraph.h"
+#include "c-family/c-common.h"
+#include "c-family/c-objc.h"
+#include "plugin.h"
+#include "tree-iterator.h"
+#include "tree-vtable-verify.h"
+#include "gimple.h"
+
+/* Mark these specially since they need to be stored in precompiled
+ header IR. */
+static GTY (()) tree vlt_saved_class_info = NULL_TREE;
+static GTY (()) tree vlt_register_pairs_fndecl = NULL_TREE;
+static GTY (()) tree vlt_init_set_symbol_fndecl = NULL_TREE;
+static GTY (()) tree vlt_change_permission_fndecl = NULL_TREE;
+
+struct work_node {
+ struct vtv_graph_node *node;
+ struct work_node *next;
+};
+
+struct vtbl_map_node *vtable_find_or_create_map_decl (tree);
+
+/* As part of vtable verification the compiler generates and inserts
+ calls to __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 vtv_debug is
+ true.
+
+ The signatures for these functions are:
+
+ void * __VLTVerifyVtablePointer (void **, void*);
+ void * __VLTVerifyVtablePointerDebug (void**, void *, char *, int, char *,
+ int);
+*/
+
+static void
+build_vtable_verify_fndecl (void)
+{
+ tree void_ptr_type = build_pointer_type (void_type_node);
+ tree arg_types = NULL_TREE;
+ tree func_type = NULL_TREE;
+ struct lang_decl *ld;
+#ifdef VTV_DEBUG
+ tree const_char_ptr_type = build_pointer_type
+ (build_qualified_type (char_type_node,
+ TYPE_QUAL_CONST));
+#endif
+
+ if (verify_vtbl_ptr_fndecl != NULL_TREE)
+ return;
+
+ ld = ggc_alloc_cleared_lang_decl (sizeof (struct lang_decl_fn));
+ ld->u.base.selector = 1;
+
+ arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ const_ptr_type_node));
+
+#ifdef VTV_DEBUG
+ /* Arg types for the debugging version of function. */
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ const_char_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ const_char_ptr_type));
+#endif
+
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+ func_type = build_function_type (const_ptr_type_node, arg_types);
+
+#ifdef VTV_DEBUG
+ /* const void *
+ __VLTVerifyVtablePointerDebug (void ** set_handle_ptr,
+ const void * vtable_ptr,
+ const char * set_symbol_name,
+ const char * vtable_name) */
+
+ verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointerDebug",
+ func_type);
+#else
+ /* const void *
+ __VLTVerifyVtablePointerDebug (void ** set_handle_ptr,
+ const void * vtable_ptr) */
+
+ verify_vtbl_ptr_fndecl = build_fn_decl ("__VLTVerifyVtablePointer",
+ func_type);
+#endif
+
+ TREE_NOTHROW (verify_vtbl_ptr_fndecl) = 1;
+ DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl)
+ = tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (verify_vtbl_ptr_fndecl));
+ DECL_PURE_P (verify_vtbl_ptr_fndecl) = 1;
+ TREE_PUBLIC (verify_vtbl_ptr_fndecl) = 1;
+#ifdef VTV_STATIC_VERIFY
+ DECL_VISIBILITY (verify_vtbl_ptr_fndecl) = 1;
+#endif
+ DECL_PRESERVE_P (verify_vtbl_ptr_fndecl) = 1;
+ DECL_LANG_SPECIFIC (verify_vtbl_ptr_fndecl) = ld;
+ SET_DECL_LANGUAGE (verify_vtbl_ptr_fndecl, lang_cplusplus);
+}
+
+/* As part of vtable verification the compiler generates and inserts calls
+ to __VLTRegisterPair and __VLTChangePermission, which are in libsupc++.
+ This function builds and initializes the function decls that are used
+ in generating those function calls.
+
+ In addition to __VLTRegisterPair there is also __VLTRegisterPairDebug
+ which can be used in place of __VLTRegisterPair, and which takes extra
+ parameters and outputs extra information, to help debug problems. The
+ debug version of this function is generated and used if VTV_DEBUG is
+ defined.
+
+ The signatures for these functions are:
+
+ void __VLTChangePermission (int);
+ void __VLTRegisterPair (void **, void*, int);
+ void __VLTRegisterPairDebug (void**, void *, int, char *, int, char *, int);
+*/
+
+static void
+init_functions (void)
+{
+ tree void_ptr_type = build_pointer_type (void_type_node);
+ tree arg_types = NULL_TREE;
+ tree change_permission_type = void_type_node;
+ tree register_pairs_type = void_type_node;
+ tree init_set_symbol_type = void_type_node;
+#ifdef VTV_DEBUG
+ tree const_char_ptr_type = build_pointer_type (build_qualified_type
+ (char_type_node,
+ TYPE_QUAL_CONST));
+#endif
+
+ if (vlt_change_permission_fndecl != NULL_TREE)
+ return;
+
+ gcc_assert (vlt_register_pairs_fndecl == NULL_TREE);
+
+ arg_types = build_tree_list (NULL_TREE, integer_type_node);
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+ change_permission_type = build_function_type (change_permission_type,
+ arg_types);
+ vlt_change_permission_fndecl = build_fn_decl ("__VLTChangePermission",
+ change_permission_type);
+ TREE_NOTHROW (vlt_change_permission_fndecl) = 1;
+ DECL_ATTRIBUTES (vlt_change_permission_fndecl) =
+ tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (vlt_change_permission_fndecl));
+ TREE_PUBLIC (vlt_change_permission_fndecl) = 1;
+ DECL_PRESERVE_P (vlt_change_permission_fndecl) = 1;
+ retrofit_lang_decl (vlt_change_permission_fndecl);
+ SET_DECL_LANGUAGE (vlt_change_permission_fndecl, lang_cplusplus);
+
+ arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ const_ptr_type_node));
+
+#ifdef VTV_DEBUG
+ /* These arguments are only used by the debug version of RegisterPair */
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ const_char_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ const_char_ptr_type));
+#endif
+
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+ register_pairs_type = build_function_type (register_pairs_type, arg_types);
+
+#ifdef VTV_DEBUG
+ /* void
+ __VLTRegisterPairDebug (void ** set_handle_ptr, const void * vtable_ptr,
+ const char * set_symbol_name, const char * vtable_name)
+ */
+
+ vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPairDebug",
+ register_pairs_type);
+#else
+ /* void __VLTRegisterPair (void **set_handle_ptr, const void *vtable_ptr) */
+ vlt_register_pairs_fndecl = build_fn_decl ("__VLTRegisterPair",
+ register_pairs_type);
+#endif
+
+ TREE_NOTHROW (vlt_register_pairs_fndecl) = 1;
+ DECL_ATTRIBUTES (vlt_register_pairs_fndecl) =
+ tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (vlt_register_pairs_fndecl));
+ TREE_PUBLIC (vlt_register_pairs_fndecl) = 1;
+ DECL_PRESERVE_P (vlt_register_pairs_fndecl) = 1;
+ retrofit_lang_decl (vlt_register_pairs_fndecl);
+ SET_DECL_LANGUAGE (vlt_register_pairs_fndecl, lang_cplusplus);
+
+ arg_types = build_tree_list (NULL_TREE, build_pointer_type (void_ptr_type));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ const_ptr_type_node));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE,
+ size_type_node));
+ arg_types = chainon (arg_types, build_tree_list (NULL_TREE, void_type_node));
+
+ init_set_symbol_type = build_function_type (init_set_symbol_type, arg_types);
+
+#ifdef VTV_DEBUG
+ /* void __VLTInitSetSymbolDebug(void ** set_handle_ptr,
+ const void * set_symbol_key,
+ size_t size_hint)
+ */
+ vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbolDebug",
+ init_set_symbol_type);
+#else
+ /* void __VLTInitSetSymbol(void ** set_handle_ptr,
+ const void * set_symbol_key,
+ size_t size_hint)
+ */
+ vlt_init_set_symbol_fndecl = build_fn_decl ("__VLTInitSetSymbol",
+ init_set_symbol_type);
+#endif
+
+ TREE_NOTHROW (vlt_init_set_symbol_fndecl) = 1;
+ DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl) =
+ tree_cons (get_identifier ("leaf"), NULL,
+ DECL_ATTRIBUTES (vlt_init_set_symbol_fndecl));
+ TREE_PUBLIC (vlt_init_set_symbol_fndecl) = 1;
+ DECL_PRESERVE_P (vlt_init_set_symbol_fndecl) = 1;
+ retrofit_lang_decl (vlt_init_set_symbol_fndecl);
+ SET_DECL_LANGUAGE (vlt_init_set_symbol_fndecl, lang_cplusplus);
+}
+
+/* This is a helper function for
+ vtv_compute_class_hierarchy_transitive_closure. It adds a
+ vtv_graph_node to the WORKLIST, which is a linked list of
+ seen-but-not-yet-processed nodes. INSERTED is a bitmap, one bit
+ per node, to help make sure that we don't insert a node into the
+ worklist more than once. Each node represents a class somewhere in
+ our class hierarchy information. Every node in the graph gets added
+ to the worklist exactly once and removed from the worklist exactly
+ once (when all of its children have been processed). */
+
+static void
+add_to_worklist (struct work_node **worklist, struct vtv_graph_node *node,
+ sbitmap inserted)
+{
+ struct work_node *new_work_node;
+
+ if (TEST_BIT (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;
+
+ SET_BIT (inserted, node->class_uid);
+}
+
+/* This is a helper function for
+ vtv_compute_class_hierarchy_transitive_closure. It goes through
+ the WORKLIST of class hierarchy nodes looking for a "leaf" node,
+ i.e. a node whose children in the hierarchy have all been
+ processed. When it finds the next leaf node, it removes it from
+ the linked list (WORKLIST) and returns the node. */
+
+static struct vtv_graph_node *
+find_and_remove_next_leaf_node (struct work_node **worklist)
+{
+ struct work_node *prev, *cur;
+
+ for (prev = NULL, cur = *worklist; cur; prev = cur, cur = cur->next)
+ {
+ if (cur->node->num_children == cur->node->num_processed_children)
+ {
+ if (prev == NULL)
+ (*worklist) = cur->next;
+ else
+ prev->next = cur->next;
+
+ cur->next = NULL;
+ return cur->node;
+ }
+ }
+
+ return NULL;
+}
+
+/* In our class hierarchy graph, each class node contains a bitmap,
+ with one bit for each class in the hierarchy. The bits are set for
+ classes that are descendants in the graph of the current node.
+ Initially the descendants bitmap is only set for immediate
+ descendants. This function traverses the class hierarchy graph,
+ bottom up, filling in the transitive closures for the descendants
+ as we rise up the graph. */
+
+void
+vtv_compute_class_hierarchy_transitive_closure (void)
+{
+ struct work_node *worklist = NULL;
+ struct vtbl_map_node *cur;
+ sbitmap inserted = sbitmap_alloc (num_vtable_map_nodes);
+ unsigned i;
+
+ /* Note: Every node in the graph gets added to the worklist exactly
+ once and removed from the worklist exactly once (when all of its
+ children have been processed). Each node's children edges are
+ followed exactly once, and each node's parent edges are followed
+ exactly once. So this algorithm is roughly O(V + 2E), i.e.
+ O(E + V). */
+
+ /* Set-up: */
+ /* Find all the "leaf" nodes in the graph, and add them to the worklist. */
+ sbitmap_zero (inserted);
+ for (cur = vtbl_map_nodes; cur; cur = cur->next)
+ {
+ if (cur->class_info
+ && (cur->class_info->num_children == 0)
+ && ! (TEST_BIT (inserted, cur->class_info->class_uid)))
+ add_to_worklist (&worklist, cur->class_info, inserted);
+ }
+
+ /* Main work: pull next leaf node off work list, process it, add its
+ parents to the worklist, where a 'leaf' node is one that has no
+ children, or all of its children have been processed. */
+ while (worklist)
+ {
+ struct vtv_graph_node *temp_node =
+ find_and_remove_next_leaf_node (&worklist);
+
+ gcc_assert (temp_node != NULL);
+ temp_node->descendants = sbitmap_alloc (num_vtable_map_nodes);
+ sbitmap_zero (temp_node->descendants);
+ SET_BIT (temp_node->descendants, temp_node->class_uid);
+ for (i = 0; i < temp_node->num_children; ++i)
+ sbitmap_a_or_b (temp_node->descendants, temp_node->descendants,
+ temp_node->children[i]->descendants);
+ for (i = 0; i < temp_node->num_parents; ++i)
+ {
+ temp_node->parents[i]->num_processed_children =
+ temp_node->parents[i]->num_processed_children + 1;
+ if (!TEST_BIT (inserted, temp_node->parents[i]->class_uid))
+ add_to_worklist (&worklist, temp_node->parents[i], inserted);
+ }
+ }
+
+ build_vtable_verify_fndecl ();
+}
+
+/* Keep track of which pairs we have already created __VLTRegisterPair
+ calls for, to prevent creating duplicate calls within the same
+ compilation unit. VTABLE_DECL is the var decl for the vtable of
+ the (descendant) class that we are adding to our class hierarchy
+ data. VPTR_ADDRESS is and expression for calculating the correct
+ offset into the vtable (VTABLE_DECL). It is the actual vtable
+ pointer address that will be stored in our list of valid vtable
+ pointers for BASE_CLASS. BASE_CLASS is the record_type node for
+ the base class to whose hiearchy we want to add
+ VPTR_ADDRESS. (VTABLE_DECL should be the vtable for BASE_CLASS or
+ one of BASE_CLASS' descendents. */
+
+static bool
+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_OPERAND_LENGTH (vptr_address) == 1)
+ {
+ tree tmp_address = TREE_OPERAND (vptr_address, 0);
+ offset = TREE_INT_CST_LOW (TREE_OPERAND (tmp_address, 1));
+ }
+ else
+ offset = TREE_INT_CST_LOW (TREE_OPERAND (vptr_address, 1));
+
+ base_vtable_map_node = vtbl_map_get_node (base_class);
+
+ inserted_something = vtbl_map_node_registration_insert (base_vtable_map_node,
+ vtable_decl,
+ offset);
+ return !inserted_something;
+}
+
+/* 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_decl_arg, tree base_class,
+ tree record_type, tree body)
+{
+ tree vtbl_var_decl;
+ tree binfo;
+
+ if (TREE_CODE (record_type) != RECORD_TYPE)
+ return;
+
+ binfo = TYPE_BINFO (record_type);
+ vtbl_var_decl = CLASSTYPE_VTABLES (record_type);
+
+ if (CLASSTYPE_VBASECLASSES (record_type))
+ {
+ tree vtt_decl;
+ tree sub_vtt_addr = NULL_TREE;
+ bool already_registered = false;
+ tree val_vtbl_decl = NULL_TREE;
+ tree arg1 = NULL_TREE;
+
+ vtt_decl = DECL_CHAIN (vtbl_var_decl);
+ if (BINFO_SUBVTT_INDEX (binfo))
+ sub_vtt_addr = fold_build_pointer_plus (vtt_decl,
+ BINFO_SUBVTT_INDEX (binfo));
+
+ /* Check to see if we have found a constructor vtable. Add its
+ data if appropriate. */
+ if (vtt_decl)
+ {
+ tree values = DECL_INITIAL (vtt_decl);
+ struct varpool_node *vp_node = varpool_node (vtt_decl);
+ if (vp_node->finalized
+ && TREE_ASM_WRITTEN (vtt_decl)
+ && values != NULL_TREE
+ && TREE_CODE (values) == CONSTRUCTOR
+ && TREE_CODE (TREE_TYPE (values)) == ARRAY_TYPE)
+ {
+ tree call_expr = NULL_TREE;
+ unsigned HOST_WIDE_INT cnt;
+ constructor_elt *ce;
+#ifdef VTV_DEBUG
+ int len1 = strlen (IDENTIFIER_POINTER
+ (DECL_NAME (TREE_OPERAND (base_class_decl_arg,
+ 0))));
+ arg1 = build_string_literal (len1 + 1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (TREE_OPERAND
+ (base_class_decl_arg,
+ 0))));
+#endif
+ /* Loop through the initialization values for this vtable to
+ get all the correct vtable pointer addresses that we need
+ to add to our set of valid vtable pointers for the current
+ base class. */
+
+ for (cnt = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (values),
+ cnt, ce);
+ cnt++)
+ {
+ tree value = ce->value;
+
+ /* We need to check value and find the bit where we
+ have something with 2 arguments, the first
+ argument of which is an ADDR_EXPR and the second
+ argument of which is an INTEGER_CST. */
+
+ while (value && TREE_OPERAND_LENGTH (value) == 1
+ && 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;
+#ifdef VTV_DEBUG
+ {
+ int len2 = strlen (IDENTIFIER_POINTER
+ (DECL_NAME (val_vtbl_decl)));
+ tree arg2 = build_string_literal (len2 + 1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (val_vtbl_decl)));
+
+ /* Generate the call to __VLTRegisterPairDebug to
+ add this vtable pointer to our set of valid
+ pointers for the base class. */
+
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 4,
+ base_class_decl_arg, value,
+ arg1, arg2);
+ }
+#else
+ /* Generate the call to __VLTRegisterPair to add
+ this vtable pointer to our set of valid pointers
+ for the base class. */
+
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 2,
+ base_class_decl_arg, value);
+#endif
+ append_to_statement_list (call_expr, &body);
+ }
+ }
+
+ if (sub_vtt_addr)
+ {
+ already_registered = check_and_record_registered_pairs
+ (vtt_decl,
+ sub_vtt_addr,
+ record_type);
+
+ if (!already_registered)
+ {
+ tree call_expr;
+#ifdef VTV_DEBUG
+ {
+ int len2 = IDENTIFIER_LENGTH (DECL_NAME (val_vtbl_decl));
+ tree arg2 = build_string_literal (len2 + 1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (val_vtbl_decl)));
+
+ call_expr = build_call_expr (vlt_register_pairs_fndecl,
+ 4, base_class_decl_arg,
+ sub_vtt_addr, arg1, arg2);
+ }
+#else
+ {
+ call_expr = build_call_expr (vlt_register_pairs_fndecl,
+ 2, base_class_decl_arg,
+ sub_vtt_addr);
+ }
+#endif
+ append_to_statement_list (call_expr, &body);
+ }
+ }
+ }
+ }
+}
+
+/* This function iterates through all the vtables it can find from the
+ BINFO of a class, to make sure we have found ALL of the vtables
+ that an object of that class could point to. Generate calls to
+ __VLTRegisterPair for those vtable pointers that we find.
+
+ BINFO is the tree_binfo node for the BASE_CLASS. BODY is the
+ function body for the constructor init function to which we are
+ adding calls to __VLTRegisterPair. ARG1 is an expression for the
+ address of the vtable map variable (for the BASE_CLASS), that will
+ point to the updated data set. BASE_CLASS is the record_type node
+ for the base class whose set of valid vtable pointers we are
+ updating. STR1 and STR2 are all debugging information, to be passed
+ as parameters to __VLTRegisterPairDebug. STR1 represents the name
+ of the vtable map variable to be updated by the call. Similarly,
+ STR2 represents the name of the class whose vtable pointer is being
+ added to the hierarchy. */
+
+static void
+register_other_binfo_vtables (tree binfo, tree body, tree arg1, tree str1,
+ tree str2, tree base_class)
+{
+ unsigned ix;
+ tree base_binfo;
+ tree vtable_decl;
+ bool already_registered;
+
+ if (binfo == NULL_TREE)
+ return;
+
+ for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+ {
+ if ((!BINFO_PRIMARY_P (base_binfo)
+ || BINFO_VIRTUAL_P (base_binfo))
+ && (vtable_decl = get_vtbl_decl_for_binfo (base_binfo))
+ && !(DECL_VTABLE_OR_VTT_P (vtable_decl)
+ && DECL_CONSTRUCTION_VTABLE_P (vtable_decl)))
+ {
+ tree vtable_address = build_vtbl_address (base_binfo);
+ tree call_expr;
+
+ already_registered = check_and_record_registered_pairs
+ (vtable_decl,
+ vtable_address,
+ base_class);
+ if (!already_registered)
+ {
+#ifdef VTV_DEBUG
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 4,
+ arg1, vtable_address,
+ str1, str2);
+#else
+ call_expr = build_call_expr (vlt_register_pairs_fndecl, 2,
+ arg1, vtable_address);
+#endif
+ append_to_statement_list (call_expr, &body);
+ }
+ }
+
+ register_other_binfo_vtables (base_binfo, body, arg1, str1, str2,
+ base_class);
+ }
+}
+
+/* The set of valid vtable pointers for any given class are stored in
+ a hash table. For reasons of efficiency, that hash table size is
+ always a power of two. In order to try to prevent re-sizing the
+ hash tables very often, we pass __VLTRegisterPair an initial guess
+ as to the number of entries the hashtable will eventually need
+ (rounded up to the nearest power of two). This function takes the
+ class information we have collected for a particular class,
+ CLASS_NODE, and calculates the hash table size guess. */
+
+static int
+guess_num_vtable_pointers (struct vtv_graph_node *class_node)
+{
+ tree vtbl;
+ int total_num_vtbls = 0;
+ int num_vtbls_power_of_two = 1;
+ unsigned i;
+
+ for (i = 0; i < num_vtable_map_nodes; ++i)
+ if (TEST_BIT (class_node->descendants, i))
+ {
+ tree class_type = vtbl_map_nodes_array[i]->class_info->class_type;
+ for (vtbl = CLASSTYPE_VTABLES (class_type); vtbl;
+ vtbl = DECL_CHAIN (vtbl))
+ {
+ total_num_vtbls++;
+ if (total_num_vtbls > num_vtbls_power_of_two)
+ num_vtbls_power_of_two <<= 1;
+ }
+ }
+ return num_vtbls_power_of_two;
+}
+
+/* This function goes through our internal class hierarchy & vtable
+ pointer data structure and outputs calls to __VLTRegisterPair for
+ every class-vptr pair (for those classes whose vtable would be
+ output in the current compilation unit). These calls get put into
+ our constructor initialization function. BODY is the function
+ body, so far, of our constructor initialization function, to which we
+ add the calls. */
+
+static bool
+register_all_pairs (tree body)
+{
+ struct vtbl_map_node *current;
+ bool registered_at_least_one = false;
+
+ for (current = vtbl_map_nodes; current; current = current->next)
+ {
+ unsigned i;
+ tree base_class = current->class_info->class_type;
+ tree base_ptr_var_decl = current->vtbl_map_decl;
+ tree str1 = NULL_TREE;
+
+ gcc_assert (current->class_info != NULL);
+
+
+#ifdef VTV_DEBUG
+ str1 = build_string_literal
+ (IDENTIFIER_LENGTH (DECL_NAME (base_ptr_var_decl)) + 1,
+ IDENTIFIER_POINTER (DECL_NAME (base_ptr_var_decl)));
+#endif
+
+ for (i = 0; i < num_vtable_map_nodes; ++i)
+ if (TEST_BIT (current->class_info->descendants, i))
+ {
+ struct vtbl_map_node *vtbl_class_node = vtbl_map_nodes_array[i];
+ tree class_type = vtbl_class_node->class_info->class_type;
+
+ if (class_type
+ && (TREE_CODE (class_type) == RECORD_TYPE))
+ {
+ tree new_type;
+ tree arg1;
+ tree call_expr;
+ bool already_registered;
+
+ tree binfo = TYPE_BINFO (class_type);
+ tree vtable_decl;
+ bool vtable_should_be_output = false;
+
+ vtable_decl = CLASSTYPE_VTABLES (class_type);
+
+ /* Handle main vtable for this class. */
+
+ if (vtable_decl)
+ vtable_should_be_output = TREE_ASM_WRITTEN (vtable_decl);
+
+ if (vtable_decl && vtable_should_be_output
+ && BINFO_VTABLE (binfo))
+ {
+ tree vtable_address = build_vtbl_address (binfo);
+
+ already_registered = check_and_record_registered_pairs
+ (vtable_decl,
+ vtable_address,
+ base_class);
+
+ if (!already_registered)
+ {
+ tree str2 = NULL_TREE;
+ new_type = build_pointer_type (TREE_TYPE
+ (base_ptr_var_decl));
+ arg1 = build1 (ADDR_EXPR, new_type, base_ptr_var_decl);
+
+#ifdef VTV_DEBUG
+ str2 = build_string_literal (IDENTIFIER_LENGTH
+ (DECL_NAME (vtable_decl))
+ + 1,
+ IDENTIFIER_POINTER
+ (DECL_NAME (vtable_decl)));
+
+ /* This call expr has the 2 "real" arguments,
+ plus 2 debugging arguments. */
+ call_expr = build_call_expr (vlt_register_pairs_fndecl,
+ 4, arg1, vtable_address,
+ str1, str2);
+#else
+ call_expr = build_call_expr (vlt_register_pairs_fndecl,
+ 2, arg1, vtable_address);
+#endif
+
+ append_to_statement_list (call_expr, &body);
+
+ registered_at_least_one = true;
+
+ /* Find and handle any 'extra' vtables associated
+ with this class, via virtual inheritance. */
+ register_construction_vtables (arg1, base_class, class_type,
+ body);
+
+ /* Find and handle any 'extra' vtables associated
+ with this class, via multiple inheritance. */
+ register_other_binfo_vtables (binfo, body, arg1, str1,
+ str2, base_class);
+ }
+ }
+ }
+ }
+ }
+
+ return registered_at_least_one;
+}
+
+/* Given a tree containing a class type (CLASS_TYPE), this function
+ finds and returns the class hierarchy node for that class in our
+ data structure. */
+
+static struct vtv_graph_node *
+find_graph_node (tree class_type)
+{
+ struct vtbl_map_node *vtbl_node;
+
+ vtbl_node = vtbl_map_get_node (class_type);
+ if (vtbl_node)
+ return vtbl_node->class_info;
+
+ return NULL;
+}
+
+/* This function adds an edge to our class hierarchy graph.
+ EDGE_ARRAY will either be an array of parent nodes or an array of
+ children nodes for a particular class. NUM_ENTRIES is the current
+ number of entries in the array. MAX_WENTRIES is the maximum number
+ of entries the array can hold. NEW_ENTRY is a vtv_graph_node
+ representing the new child or parent node to be added to the
+ EDGE_ARRAY. */
+
+static void
+add_edge_to_graph (struct vtv_graph_node ***edge_array, unsigned *num_entries,
+ unsigned *max_entries, struct vtv_graph_node *new_entry)
+{
+ /* Check array size, and re-size it if necessary. */
+ if (*num_entries >= ((*max_entries) - 1))
+ {
+ unsigned new_size = 2 * (*max_entries);
+ unsigned i;
+ *edge_array = (struct vtv_graph_node **)
+ xrealloc (*edge_array, new_size * sizeof (struct vtv_graph_node *));
+
+ for (i = *max_entries; i < new_size; ++i)
+ (*edge_array)[i] = NULL;
+ *max_entries = new_size;
+ }
+
+ (*edge_array)[*num_entries] = new_entry;
+ *num_entries = (*num_entries) + 1;
+}
+
+/* Add base class/derived class pair to our internal class hierarchy
+ data structure. BASE_NODE is our vtv_graph_node that corresponds
+ to a base class. DERIVED_NODE is our vtv_graph_node that
+ corresponds to a class that is a descendant of the base class
+ (possibly the base class itself). */
+
+static void
+add_hierarchy_pair (struct vtv_graph_node *base_node,
+ struct vtv_graph_node *derived_node)
+{
+ add_edge_to_graph (&(base_node->children), &(base_node->num_children),
+ &(base_node->max_children), derived_node);
+ add_edge_to_graph (&(derived_node->parents), &(derived_node->num_parents),
+ &(derived_node->max_parents), base_node);
+}
+
+/* This functions adds a new base class/derived class relationship to
+ our class hierarchy data structure. Both parameters are trees
+ representing the class types, i.e. RECORD_TYPE trees.
+ DERIVED_CLASS can be the same as BASE_CLASS. */
+
+static void
+update_class_hierarchy_information (tree base_class,
+ tree derived_class)
+{
+ struct vtv_graph_node *base_node = find_graph_node (base_class);
+ struct vtv_graph_node *derived_node = find_graph_node (derived_class);
+
+ add_hierarchy_pair (base_node, derived_node);
+}
+
+/* Generate an undefined variable (a reference) to a varible defined
+ in the vtv_init libraty. In that way, if the a module is not linked
+ with the vtv_init library, the linker will generate an undefined
+ symbol error. Which is much better that getting a segmentation
+ violation at runtime. The parameter, INIT_ROUTINE_BODY, is the
+ function body of our constructor initialization function, to which
+ we add the reference to this symbol (and all of our calls to
+ __VLTRegisterPair).
+
+ For more information, see comments in
+ libstdc++-v3/libsupc++/vtv_init.cc. */
+
+static void
+create_undef_reference_to_vtv_init (tree init_routine_body)
+{
+ const char *vtv_init_undef_var = "__vtv_defined_in_vtv_init_lib";
+ tree var_decl;
+ tree init_zero;
+
+ var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (vtv_init_undef_var),
+ int32_type_node);
+ TREE_PUBLIC (var_decl) = 1;
+ DECL_EXTERNAL (var_decl) = 1;
+ TREE_STATIC (var_decl) = 1;
+ SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (vtv_init_undef_var));
+ DECL_ARTIFICIAL (var_decl) = 1;
+ TREE_READONLY (var_decl) = 0;
+ DECL_IGNORED_P (var_decl) = 1;
+ DECL_PRESERVE_P (var_decl) = 1;
+ varpool_finalize_decl (var_decl);
+
+ /* Store a value in the undefined variable to force the creation of a
+ a reference. */
+ init_zero = build2 (MODIFY_EXPR, TREE_TYPE (var_decl), var_decl,
+ integer_zero_node);
+ append_to_statement_list (init_zero, &init_routine_body);
+
+}
+
+/* A simple hash function on strings */
+/* Be careful about changing this routine. The values generated will
+ be stored in the calls to InitSet. So, changing this routine may
+ cause a binary incompatibility. */
+
+static uint32_t
+vtv_string_hash(const char *in)
+{
+ const char *s = in;
+ uint32_t h = 0;
+
+ gcc_assert (in != NULL);
+ for ( ; *s; ++s)
+ h = 5 * h + *s;
+ return h;
+}
+
+/* This function goes through all of our vtable map nodes, and for
+ each one that is actually used, it generates a call to
+ __VLTInitSetSymbol, with the appropriate arguments, and inserts the
+ calls as the start of our constructor initialization function
+ (INIT_ROUTINE_BODY). */
+
+static bool
+init_all_sets (tree init_routine_body)
+{
+ struct vtbl_map_node *current;
+ bool inited_at_least_one = false;
+ tree_stmt_iterator i = tsi_start (init_routine_body);
+
+ for (current = vtbl_map_nodes; current; current = current->next)
+ {
+ if (!(current->is_used || (htab_elements (current->registered) > 0)))
+ continue;
+
+ size_t size_hint = guess_num_vtable_pointers (current->class_info);
+ tree set_handle_var_decl = current->vtbl_map_decl;
+
+ tree void_ptr_type = build_pointer_type (TREE_TYPE (set_handle_var_decl));
+ tree arg1 = build1 (ADDR_EXPR, void_ptr_type, set_handle_var_decl);
+
+ uint32_t len1 = IDENTIFIER_LENGTH (DECL_NAME (set_handle_var_decl));
+ uint32_t hash_value = vtv_string_hash (IDENTIFIER_POINTER
+ (DECL_NAME (set_handle_var_decl)));
+ tree arg2, arg3, init_set_call;
+
+ /* Build a buffer with the memory representation of
+ insert_only_hash_map::key_value as defined in vtv_map.h. This
+ will be passed as the second argument to InitSet. */
+ #define KEY_TYPE_FIXED_SIZE 8
+
+ void *key_buffer = xmalloc (len1 + KEY_TYPE_FIXED_SIZE);
+ uint32_t *value_ptr = (uint32_t *) key_buffer;
+
+ /* Set the len and hash for the string. */
+ *value_ptr = len1;
+ value_ptr++;
+ *value_ptr = hash_value;
+
+ /* Now copy the string representation of the vtbl map name... */
+ memcpy ((char *) key_buffer + KEY_TYPE_FIXED_SIZE,
+ IDENTIFIER_POINTER (DECL_NAME (set_handle_var_decl)),
+ len1);
+
+ /* ... and build a string literal from it. This will make a copy
+ so the key_bufffer is not needed anymore after this. */
+ arg2 = build_string_literal (len1 + KEY_TYPE_FIXED_SIZE,
+ (char *) key_buffer);
+ free (key_buffer);
+
+ /* size_t maybe different at compile time vs at runtime but
+ there should not be a problem in here. We dont expect such
+ large number of elements in the set. */
+ arg3 = build_int_cst (size_type_node, size_hint);
+ init_set_call = build_call_expr (vlt_init_set_symbol_fndecl,
+ 3, arg1, arg2, arg3);
+ gcc_assert (size_hint != 0);
+ tsi_link_before (&i, init_set_call, TSI_SAME_STMT);
+
+ inited_at_least_one = true;
+ }
+ return inited_at_least_one;
+}
+
+
+/* This function calls register_all_pairs, which actually generates
+ all the calls to __VLTRegisterPair (in the verification constructor
+ init function). It also generates the calls to
+ __VLTChangePermission, if the verification constructor init
+ function is going into the preinit array. INIT_ROUTINE_BODY is
+ the body of our constructior initialization function, to which we
+ add our function calls.*/
+
+static bool
+vtv_register_class_hierarchy_information (tree init_routine_body)
+{
+ bool registered_something = false;
+ bool inited_some_sets = true;
+
+ init_functions ();
+
+ /* TODO: Temp fix. Needs to be tightened. */
+ if (num_vtable_map_nodes == 0)
+ return false;;
+
+ /* Add class hierarchy pairs to the vtable map data structure. */
+ registered_something = register_all_pairs (init_routine_body);
+
+ /* Initialialize all vtable map variables (pointers to our data
+ sets. */
+ inited_some_sets = init_all_sets (init_routine_body);
+
+ if (registered_something || inited_some_sets)
+ {
+ /* If this function is going into the preinit_array, then we
+ need to manually call __VLTChangePermission, rather than
+ depending on initialization prioritys in vtv_init. */
+ if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+ {
+ /* Pass __VLTP_READ_WRITE value as defined in vtv_rts.h. */
+ tree arg_read_write = build_int_cst (integer_type_node, 1);
+ tree arg_read_only = build_int_cst (integer_type_node, 0);
+
+ tree call_rw_expr = build_call_expr (vlt_change_permission_fndecl,
+ 1, arg_read_write);
+ tree call_r_expr = build_call_expr (vlt_change_permission_fndecl,
+ 1, arg_read_only);
+ tree_stmt_iterator i = tsi_start (init_routine_body);
+ /* Insert the call to make permissions read-write at the
+ beginning of the init routine. */
+ tsi_link_before (&i, call_rw_expr, TSI_SAME_STMT);
+
+ /* Append the call to make permissions read-only at the
+ end of the init routine. */
+ append_to_statement_list (call_r_expr, &init_routine_body);
+ }
+
+ if (flag_vtable_verify == VTV_STANDARD_PRIORITY)
+ create_undef_reference_to_vtv_init (init_routine_body);
+ }
+
+ return registered_something || inited_some_sets;
+}
+
+/* This function writes records data about the number of virtual calls
+ we found and the number of verification calls we generated. It is
+ primarily for debugging purposes. */
+
+static void
+write_out_counters (void)
+{
+ if (total_num_virtual_calls == 0)
+ return;
+
+ FILE *fp = fopen ("/tmp/vtable-verification-counters.log", "a");
+ double pct_done = (total_num_verified_vcalls * 100) / total_num_virtual_calls;
+
+ if (fp)
+ {
+ fprintf (fp, "%s %d %d (%.2f %%)\n", main_input_filename,
+ total_num_virtual_calls, total_num_verified_vcalls,
+ pct_done);
+ fclose (fp);
+ }
+}
+
+/* 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;
+#ifdef VTV_COUNT
+ bool debug_num_verified = true;
+#else
+ bool debug_num_verified = false;
+#endif
+
+ if (debug_num_verified)
+ write_out_counters ();
+
+ push_lang_context (lang_name_c);
+
+ /* The priority for this init function (constructor) is carefully
+ chosen so that it will happen after the calls to unprotect the
+ memory used for vtable verification and before the memory is
+ protected again. */
+ init_routine_body = vtv_start_verification_constructor_init_function ();
+
+ vtable_classes_found =
+ vtv_register_class_hierarchy_information (init_routine_body);
+
+ if (vtable_classes_found)
+ {
+ current_function_decl =
+ vtv_finish_verification_constructor_init_function (init_routine_body);
+ allocate_struct_function (current_function_decl, false);
+ TREE_STATIC (current_function_decl) = 1;
+ TREE_USED (current_function_decl) = 1;
+ DECL_PRESERVE_P (current_function_decl) = 1;
+ if (flag_vtable_verify == VTV_PREINIT_PRIORITY)
+ {
+ DECL_STATIC_CONSTRUCTOR (current_function_decl) = 0;
+ assemble_vtv_preinit_initializer (current_function_decl);
+ }
+
+ gimplify_function_tree (current_function_decl);
+ cgraph_add_new_function (current_function_decl, false);
+
+ cgraph_process_new_functions ();
+ }
+ pop_lang_context ();
+}
+
+/* This funtion takes a tree containing a class type (BASE_TYPE), and
+ it either finds the existing vtbl_map_node for that class in our
+ data structure, or it creates a new node and adds it to the data
+ structure if there is not one for the class already. As part of
+ this process it also creates the global vtable map variable for the
+ class. */
+
+struct vtbl_map_node *
+vtable_find_or_create_map_decl (tree base_type)
+{
+ struct vtbl_map_node *vtable_map_node = NULL;
+
+ /* Verify the type has an associated vtable. */
+ if (!TYPE_BINFO (base_type) || !BINFO_VTABLE (TYPE_BINFO (base_type)))
+ return NULL;
+
+ /* If we've already created the variable, just look for it. */
+ vtable_map_node = vtbl_map_get_node (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. */
+ char *var_name = NULL;
+ tree var_decl = NULL;
+ tree var_type = build_pointer_type (void_type_node);
+ tree initial_value = build_int_cst (make_node (INTEGER_TYPE), 0);
+
+ /* Create map lookup symbol for base class */
+ var_name = get_mangled_vtable_map_var_name (base_type);
+ var_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
+ get_identifier (var_name), var_type);
+ TREE_PUBLIC (var_decl) = 1;
+ DECL_EXTERNAL (var_decl) = 0;
+ TREE_STATIC (var_decl) = 1;
+ DECL_VISIBILITY (var_decl) = VISIBILITY_HIDDEN;
+ SET_DECL_ASSEMBLER_NAME (var_decl, get_identifier (var_name));
+ DECL_ARTIFICIAL (var_decl) = 1;
+ /* We cannot mark this variable as read-only otherwise the gold
+ linker will not put it in the relro section. It seems if it
+ is marked as read-only, gold will put it in the .text
+ segment. */
+ TREE_READONLY (var_decl) = 0;
+ DECL_IGNORED_P (var_decl) = 1;
+
+ /* Put these mmap variables in to .vtable_map_vars sections, 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_COMDAT_GROUP (var_decl) = get_identifier (var_name);
+ DECL_INITIAL (var_decl) = initial_value;
+
+ varpool_finalize_decl (var_decl);
+ if (!vtable_map_node)
+ vtable_map_node = find_or_create_vtbl_map_node (base_type);
+ if (vtable_map_node->vtbl_map_decl == NULL_TREE)
+ vtable_map_node->vtbl_map_decl = var_decl;
+ }
+
+ gcc_assert (vtable_map_node);
+ return vtable_map_node;
+}
+
+/* This function is used to build up our class hierarchy data for a
+ particular class. TYPE is the record_type tree node for the
+ class. */
+
+static void
+vtv_save_base_class_info (tree type)
+{
+ if (flag_vtable_verify)
+ {
+ tree binfo = TYPE_BINFO (type);
+ tree base_binfo;
+ struct vtbl_map_node *own_map;
+ int i;
+
+ /* First make sure to create the map for this record type. */
+ own_map = vtable_find_or_create_map_decl (type);
+ if (own_map == NULL)
+ return;
+
+ /* Go through the list of all base classes for the current
+ (derived) type, make sure the *__vtable_map global variable
+ for the base class exists, and add the base class/derived
+ class pair to the class hierarchy information we are
+ accumulating (for vtable pointer verification). */
+ for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
+ {
+ tree tree_val = BINFO_TYPE (base_binfo);
+ struct vtbl_map_node *vtable_map_node = NULL;
+
+ vtable_map_node = vtable_find_or_create_map_decl (tree_val);
+
+ if (vtable_map_node != NULL)
+ update_class_hierarchy_information (tree_val, type);
+ }
+ }
+}
+
+/* This function adds classes we are interested in to a list of
+ classes that is saved during pre-compiled header generation.
+ RECORD is the record_type node for the class we are adding to the
+ list. */
+
+void
+vtv_save_class_info (tree record)
+{
+ if (!flag_vtable_verify || TREE_CODE (record) == UNION_TYPE)
+ return;
+
+ gcc_assert (TREE_CODE (record) == RECORD_TYPE);
+
+ vlt_saved_class_info = tree_cons (NULL_TREE, record, vlt_saved_class_info);
+}
+
+
+/* This function goes through the list of classes we saved before the
+ pre-compiled header generation and calls vtv_save_base_class_info
+ on each one, to build up our class hierarchy data structure. */
+
+void
+vtv_recover_class_info (void)
+{
+ tree current_class;
+ tree class_chain = vlt_saved_class_info;
+ while (class_chain != NULL_TREE)
+ {
+ current_class = TREE_VALUE (class_chain);
+ gcc_assert (TREE_CODE (current_class) == RECORD_TYPE);
+
+ vtv_save_base_class_info (current_class);
+ class_chain = TREE_CHAIN (class_chain);
+ }
+
+ /* Let the garbabe collector collect the memory associated with the
+ chain. */
+ vlt_saved_class_info = NULL_TREE;
+}
+
+#include "gt-cp-vtable-class-hierarchy.h"
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 313e94057fe..281d0aa622d 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -223,4 +223,11 @@ enum opt_info_verbosity_levels {
OPT_INFO_MED = 2,
OPT_INFO_MAX = 3
};
+
+/* 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/output.h b/gcc/output.h
index bd83199b6a9..2f1b20c9ff3 100644
--- a/gcc/output.h
+++ b/gcc/output.h
@@ -215,6 +215,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.c b/gcc/passes.c
index c277d80f0fb..882ac99f511 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -1434,6 +1434,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_tm_memopt);
NEXT_PASS (pass_tm_edges);
}
+ NEXT_PASS (pass_vtable_verify);
NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_cleanup_eh);
NEXT_PASS (pass_lower_resx);
diff --git a/gcc/timevar.def b/gcc/timevar.def
index 9753f09bb22..4daa3233add 100644
--- a/gcc/timevar.def
+++ b/gcc/timevar.def
@@ -257,6 +257,7 @@ DEFTIMEVAR (TV_TREE_THREADSAFE , "thread safety analysis")
DEFTIMEVAR (TV_PLUGIN_INIT , "plugin initialization")
DEFTIMEVAR (TV_PLUGIN_RUN , "plugin execution")
DEFTIMEVAR (TV_SIMPLIFY_GOT , "simplify got")
+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 5d6771ffc5e..d5516053906 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -461,6 +461,7 @@ extern struct gimple_opt_pass pass_split_functions;
extern struct gimple_opt_pass pass_feedback_split_functions;
extern struct gimple_opt_pass pass_threadsafe_analyze;
extern struct gimple_opt_pass pass_tree_convert_builtin_dispatch;
+extern struct gimple_opt_pass pass_vtable_verify;
/* IPA Passes */
extern struct simple_ipa_opt_pass pass_ipa_lower_emutls;
diff --git a/gcc/tree-vtable-verify.c b/gcc/tree-vtable-verify.c
new file mode 100644
index 00000000000..24c8fca9f27
--- /dev/null
+++ b/gcc/tree-vtable-verify.c
@@ -0,0 +1,754 @@
+/* Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Virtual Table Pointer Security 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 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/tree-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 the 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 "tm.h"
+#include "tree.h"
+/* #include "cp/cp-tree.h" */
+#include "tm_p.h"
+#include "basic-block.h"
+#include "output.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "tree-pass.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "flags.h"
+#include "tree-inline.h"
+#include "tree-scalar-evolution.h"
+#include "diagnostic-core.h"
+#include "gimple-pretty-print.h"
+#include "toplev.h"
+#include "langhooks.h"
+
+#include "tree-vtable-verify.h"
+
+int total_num_virtual_calls = 0;
+int total_num_verified_vcalls = 0;
+
+unsigned num_vtable_map_nodes = 0;
+bool any_verification_calls_generated = false;
+
+extern GTY(()) tree verify_vtbl_ptr_fndecl;
+tree verify_vtbl_ptr_fndecl = NULL_TREE;
+
+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);
+
+ key.vtable_decl = vtable_decl;
+ slot = (struct vtable_registration **) htab_find_slot (node->registered,
+ &key, NO_INSERT);
+
+ if (slot && (*slot) && (*slot)->offsets)
+ {
+ unsigned i;
+ for (i = 0; i < (*slot)->cur_offset; ++i)
+ if ((*slot)->offsets[i] == offset)
+ return true;
+ }
+
+ return false;
+}
+
+/* This function inserts VTABLE_DECL and OFFSET into the 'registered'
+ hash table for NODE. */
+
+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)
+ return false;
+
+ key.vtable_decl = vtable_decl;
+ slot = (struct vtable_registration **) htab_find_slot (node->registered,
+ &key, INSERT);
+
+ if (! *slot)
+ {
+ unsigned i;
+ struct vtable_registration *node;
+ node = XNEW (struct vtable_registration);
+ node->vtable_decl = vtable_decl;
+
+ /* We expect the number of different offsets in any given vtable
+ that will be valid vtable pointers to be small (but we know
+ it can be greater than 1). To avoid having to resize this
+ very often, we randomly chose 10 as a reasonable-seeming
+ size. */
+ node->offsets = (unsigned *) xmalloc (10 * sizeof (unsigned));
+ for (i= 0; i < 10; ++i)
+ node->offsets[i] = 0;
+ node->offsets[0] = offset;
+ node->cur_offset = 1;
+ node->max_offsets = 10;
+ *slot = node;
+ 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)->cur_offset && !found; ++i)
+ if ((*slot)->offsets[i] == offset)
+ found = true;
+
+ if (!found)
+ {
+ /* Re-size the offset array if necessary. */
+ if ((*slot)->cur_offset == (*slot)->max_offsets)
+ {
+ unsigned new_max = 2 * (*slot)->max_offsets;
+ (*slot)->offsets = (unsigned *)
+ xrealloc ((*slot)->offsets, new_max * sizeof (unsigned));
+
+ for (i = (*slot)->max_offsets; i < new_max; ++i)
+ (*slot)->offsets[i] = 0;
+ (*slot)->max_offsets = new_max;
+ }
+ /* Insert the new offset. */
+ (*slot)->offsets[(*slot)->cur_offset] = offset;
+ (*slot)->cur_offset = (*slot)->cur_offset + 1;
+ inserted_something = true;
+ }
+ }
+ return inserted_something;
+}
+
+/* Hashtable functions for vtable_registration hashtables. */
+
+static hashval_t
+hash_vtable_registration (const void *p)
+{
+ const struct vtable_registration *n = (const struct vtable_registration *) p;
+ return (hashval_t) (DECL_UID (n->vtable_decl));
+}
+
+static int
+eq_vtable_registration (const void *p1, const void *p2)
+{
+ const struct vtable_registration *n1 =
+ (const struct vtable_registration *) p1;
+ const struct vtable_registration *n2 =
+ (const struct vtable_registration *) p2;
+ return (DECL_UID (n1->vtable_decl) == DECL_UID (n2->vtable_decl));
+}
+
+/* End of hashtable functions for "registered" hashtables. */
+
+
+/* Here are the three data structures into which we insert vtable map nodes.
+ We use three data structures because of the vastly different ways we need
+ to find the nodes for various tasks (see comments in tree-vtable-verify.h
+ for more details. */
+
+/* Vtable map variable nodes stored in a hash table. */
+static htab_t vtbl_map_hash = NULL;
+
+/* Vtable map variable nodes stored in a linked list. */
+struct vtbl_map_node *vtbl_map_nodes = NULL;
+
+/* Vtable map variable nodes stored in an array. */
+struct vtbl_map_node **vtbl_map_nodes_array = NULL;
+
+/* This function take a vtbl_map_node, NODE, and inserts it in the
+ array of vtable map nodes, using it's uid as the position in the
+ array into which to insert it. (The uids are unique and
+ monotonically grow as the nodes are generated.) */
+
+static void
+vtable_map_array_insert (struct vtbl_map_node *node)
+{
+ static unsigned array_size = 0;
+ unsigned i;
+
+ /* If the array is NULL, allocate it with an initial size of 16. */
+ if (vtbl_map_nodes_array == NULL || array_size == 0)
+ {
+ array_size = 16;
+ vtbl_map_nodes_array = (struct vtbl_map_node **)
+ xmalloc (array_size * sizeof (struct vtbl_map_node *));
+ memset (vtbl_map_nodes_array, 0,
+ array_size * sizeof (struct vtbl_map_node *));
+ }
+ else if (node->uid >= array_size)
+ {
+ /* Check to see if the array is large enough to hold another
+ node; resize it if it is not. */
+ unsigned new_size = 2 * array_size;
+ vtbl_map_nodes_array = (struct vtbl_map_node **)
+ xrealloc (vtbl_map_nodes_array,
+ new_size * sizeof (struct vtbl_map_node *));
+
+ for (i = array_size; i < new_size; ++i)
+ vtbl_map_nodes_array[i] = NULL;
+
+ array_size = new_size;
+ }
+
+ gcc_assert (node->uid < array_size
+ && vtbl_map_nodes_array[node->uid] == NULL);
+
+ /* Insert the node into the array. */
+ vtbl_map_nodes_array[node->uid] = node;
+}
+
+/* Hashtable functions for vtbl_map_hash. */
+
+/* Returns a hash code for P. */
+
+static hashval_t
+hash_vtbl_map_node (const void *p)
+{
+ const struct vtbl_map_node *n = (const struct vtbl_map_node *) p;
+ return (hashval_t) IDENTIFIER_HASH_VALUE (n->class_name);
+}
+
+/* Returns nonzero if P1 and P2 are equal. */
+
+static int
+eq_vtbl_map_node (const void *p1, const void *p2)
+{
+ const struct vtbl_map_node *n1 = (const struct vtbl_map_node *) p1;
+ const struct vtbl_map_node *n2 = (const struct vtbl_map_node *) p2;
+ return (IDENTIFIER_HASH_VALUE (n1->class_name) ==
+ IDENTIFIER_HASH_VALUE (n2->class_name));
+}
+
+/* Return vtbl_map node for CLASS_TYPE 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)
+ 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. */
+ class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+
+ key.class_name = class_name;
+ slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &key,
+ NO_INSERT);
+ if (!slot)
+ return NULL;
+ return *slot;
+}
+
+/* Return vtbl_map node assigned to BASE_CLASS_TYPE. Create new one
+ when needed. */
+
+struct vtbl_map_node *
+find_or_create_vtbl_map_node (tree base_class_type)
+{
+ struct vtbl_map_node key;
+ struct vtbl_map_node *node;
+ struct vtbl_map_node **slot;
+ unsigned i;
+ tree class_type_decl;
+ unsigned int type_quals;
+ /* Our data shows 90% of classes have no more than 4 parents or children,
+ so we will use 4 as our default hierarchy array size. */
+ unsigned int default_array_size = 4;
+
+ if (!vtbl_map_hash)
+ vtbl_map_hash = htab_create (10, hash_vtbl_map_node,
+ eq_vtbl_map_node, NULL);
+
+ /* 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);
+
+ key.class_name = DECL_ASSEMBLER_NAME (class_type_decl);
+ slot = (struct vtbl_map_node **) htab_find_slot (vtbl_map_hash, &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->max_parents = default_array_size;
+ node->class_info->max_children = default_array_size;
+ node->class_info->num_parents = 0;
+ node->class_info->num_children = 0;
+ node->class_info->num_processed_children = 0;
+ node->class_info->parents =
+ (struct vtv_graph_node **)
+ xmalloc (default_array_size * sizeof (struct vtv_graph_node *));
+ node->class_info->children =
+ (struct vtv_graph_node **)
+ xmalloc (default_array_size * sizeof (struct vtv_graph_node *));
+
+ for (i = 0; i < default_array_size; ++i)
+ {
+ node->class_info->parents[i] = NULL;
+ node->class_info->children[i] = NULL;
+ }
+
+ node->registered = htab_create (16, hash_vtable_registration,
+ eq_vtable_registration, NULL);
+ node->is_used = false;
+ node->next = vtbl_map_nodes;
+ if (vtbl_map_nodes)
+ vtbl_map_nodes->prev = node;
+
+ vtable_map_array_insert (node);
+
+ vtbl_map_nodes = node;
+ *slot = node;
+ return node;
+}
+
+/* End of hashtable functions for vtable_map variables hash table. */
+
+/* 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. First we try looking
+ directly at the THIS_OBJECT itself. If that does not work, we try to
+ get the type from the gimple assignment statement that extracts the
+ vtable pointer from the object (DEF_STMT). The gimple
+ statment 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;
+
+ 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;
+}
+
+/* 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;
+ tree this_object;
+
+ stmts = bb_seq (bb);
+ gsi_virtual_call = gsi_start (stmts);
+ this_object = NULL_TREE;
+ for (; !gsi_end_p (gsi_virtual_call); gsi_next (&gsi_virtual_call))
+ {
+ stmt = gsi_stmt (gsi_virtual_call);
+ if (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;
+ struct gimplify_ctx gctx;
+ const char *vtable_name = "<unknown>";
+ tree tmp0;
+ bool found;
+
+ gsi_vtbl_assign = gsi_for_stmt (stmt);
+
+ /* 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));
+
+ 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 (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;
+ tree expr_tree;
+ gimple_seq pre_p = NULL;
+
+ vtable_map_node->is_used = true;
+ vtbl_var_decl = vtable_map_node->vtbl_map_decl;
+
+ if (!var_ann (vtbl_var_decl))
+ add_referenced_var (vtbl_var_decl);
+
+ if (TREE_CODE (vtbl_decl) == VAR_DECL)
+ vtable_name = IDENTIFIER_POINTER (DECL_NAME (vtbl_decl));
+
+ push_gimplify_context (&gctx);
+
+ /* Call different routines if we are interested in
+ trace information to debug problems. */
+#ifdef VTV_DEBUG
+ len1 = IDENTIFIER_LENGTH (DECL_NAME (vtbl_var_decl));
+ len2 = strlen (vtable_name);
+
+ expr_tree = build_call_expr
+ (verify_vtbl_ptr_fndecl, 4,
+ build1 (ADDR_EXPR,
+ TYPE_POINTER_TO
+ (TREE_TYPE (vtbl_var_decl)),
+ vtbl_var_decl),
+ SSA_NAME_VAR (lhs),
+ build_string_literal
+ (len1 + 1,
+ IDENTIFIER_POINTER
+ (DECL_NAME
+ (vtbl_var_decl))),
+ build_string_literal (len2 + 1,
+ vtable_name));
+#else
+ expr_tree = build_call_expr
+ (verify_vtbl_ptr_fndecl, 2,
+ build1 (ADDR_EXPR,
+ TYPE_POINTER_TO
+ (TREE_TYPE (vtbl_var_decl)),
+ vtbl_var_decl),
+ SSA_NAME_VAR (lhs));
+#endif
+ /* Assign the result of the call to the original
+ variable receiving the assignment of the
+ object's vtable pointer; mark that variable
+ to be updated by update_ssa. */
+
+ mark_sym_for_renaming (SSA_NAME_VAR (lhs));
+ force_gimple_operand (expr_tree, &pre_p, 1,
+ SSA_NAME_VAR (lhs));
+
+ /* Insert the new call just after the original
+ assignment of the object's vtable pointer. */
+
+ pop_gimplify_context (NULL);
+ gsi_vtbl_assign = gsi_for_stmt (stmt);
+ gsi_insert_seq_after (&gsi_vtbl_assign, pre_p,
+ 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
+ && (strcmp (lang_hooks.name, "GNU C++") == 0));
+}
+
+/* Definition of this optimization pass. */
+
+struct gimple_opt_pass pass_vtable_verify =
+{
+ {
+ GIMPLE_PASS,
+ "vtable-verify", /* name */
+ gate_tree_vtable_verify, /* gate */
+ vtable_verify_main, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_VTABLE_VERIFICATION, /* tv_id */
+ PROP_cfg | PROP_ssa, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ TODO_dump_func | TODO_update_ssa
+ | TODO_ggc_collect /* todo_flags_finish */
+ }
+};
+
+#include "gt-tree-vtable-verify.h"
diff --git a/gcc/tree-vtable-verify.h b/gcc/tree-vtable-verify.h
new file mode 100644
index 00000000000..ed0c05436f0
--- /dev/null
+++ b/gcc/tree-vtable-verify.h
@@ -0,0 +1,151 @@
+/* Interprocedural constant propagation
+ Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+/* Virtual Table Pointer Security. */
+
+#ifndef TREE_VTABLE_VERIFY_H
+#define TREE_VTABLE_VERIFY_H
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "timevar.h"
+#include "cpplib.h"
+#include "tree.h"
+#include "hashtab.h"
+#include "sbitmap.h"
+
+/* 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;
+
+/* Global variable that records whether or not any vtable verification
+ calls have been generated. */
+extern bool any_verification_calls_generated;
+
+/* 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. */
+ unsigned max_offsets; /* The allocated size of the offsets array. */
+ unsigned cur_offset; /* The next availabe entry in the offsets
+ array. */
+ unsigned *offsets; /* The offsets array. */
+};
+
+/* 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 max_parents; /* Allocated size of the parents array. */
+ unsigned max_children; /* Allocated size of the children array. */
+ unsigned num_parents; /* # of entries in the parents array. */
+ unsigned num_children; /* # of entries in the children array. */
+ unsigned num_processed_children; /* # of children for whom we have
+ computed the class hierarchy
+ transitive closure. */
+ struct vtv_graph_node **parents; /* Array of parents in the graph. */
+ struct vtv_graph_node **children; /* Array 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
+ THREE data structures (to make it easy to find in several different
+ ways): 1). A hash table ("vtbl_map_hash" in tree-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. 2). A linked list of all
+ vtbl_map_nodes ("vtbl_map_nodes") for easy iteration through all of
+ them; and 3). An array 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. */
+ htab_t 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. */
+};
+
+/* The global linked list of vtbl_map_nodes. */
+extern struct vtbl_map_node *vtbl_map_nodes;
+
+/* The global array of vtbl_map_nodes. */
+extern struct vtbl_map_node **vtbl_map_nodes_array;
+
+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 /* TREE_VTABLE_VERIFY_H */
diff --git a/gcc/tree.h b/gcc/tree.h
index 592a49813fa..f280f851e7c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5920,6 +5920,9 @@ is_tm_safe_or_pure (const_tree x)
void init_inline_once (void);
+/* In tree-vtable-verify.c */
+extern void save_vtable_map_decl (tree);
+
/* Compute the number of operands in an expression node NODE. For
tcc_vl_exp nodes like CALL_EXPRs, this is stored in the node itself,
otherwise it is looked up from the node's code. */
diff --git a/gcc/varasm.c b/gcc/varasm.c
index bffe9ee6e30..c6cfcd207c0 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -2064,13 +2064,43 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED,
assemble_noswitch_variable (decl, name, sect);
else
{
- 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 (DECL_ALIGN (decl) > BITS_PER_UNIT)
ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (DECL_ALIGN_UNIT (decl)));
assemble_variable_contents (decl, name, dont_output_data);
}
}
+/* 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
@@ -6346,6 +6376,9 @@ default_section_type_flags (tree decl, const char *name, int reloc)
if (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/libgcc/Makefile.in b/libgcc/Makefile.in
index 743960bf4a6..9bf1a6f596e 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -40,6 +40,7 @@ double_type_size = @double_type_size@
long_double_type_size = @long_double_type_size@
decimal_float = @decimal_float@
enable_decimal_float = @enable_decimal_float@
+enable_vtable_verify = @enable_vtable_verify@
fixed_point = @fixed_point@
host_noncanonical = @host_noncanonical@
@@ -980,6 +981,16 @@ crtendS$(objext): $(srcdir)/crtstuff.c
# This is a version of crtbegin for -static links.
crtbeginT$(objext): $(srcdir)/crtstuff.c
$(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O
+
+ifeq ($(enable_vtable_verify),yes)
+# These are used in vtable verification; see comments in source files for
+# more details.
+vtv_start$(objext): $(srcdir)/vtv_start.c
+ $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) -c $(srcdir)/vtv_start.c
+
+vtv_end$(objext): $(srcdir)/vtv_end.c
+ $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) -c $(srcdir)/vtv_end.c
+endif
endif
ifeq ($(CUSTOM_CRTIN),)
diff --git a/libgcc/config.host b/libgcc/config.host
index 19ab4bdf482..68cf0d071f2 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -195,7 +195,7 @@ case ${host} in
;;
*-*-linux* | frv-*-*linux* | *-*-kfreebsd*-gnu | *-*-knetbsd*-gnu | *-*-gnu* | *-*-kopensolaris*-gnu)
tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip t-slibgcc t-slibgcc-gld t-slibgcc-elf-ver t-linux"
- extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o"
+ extra_parts="crtbegin.o crtbeginS.o crtbeginT.o crtend.o crtendS.o vtv_start.o vtv_end.o"
;;
*-*-lynxos*)
tmake_file="$tmake_file t-lynx $cpu_type/t-crtstuff t-crtstuff-pic t-libgcc-pic"
diff --git a/libgcc/configure b/libgcc/configure
index 0751859c8fc..770483ae8a3 100644
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -567,6 +567,7 @@ set_have_cc_tls
vis_hide
fixed_point
enable_decimal_float
+enable_vtable_verify
decimal_float
long_double_type_size
double_type_size
@@ -659,6 +660,7 @@ with_slibdir
enable_maintainer_mode
with_build_libsubdir
enable_decimal_float
+enable_vtable_verify
with_system_libunwind
enable_sjlj_exceptions
enable_tls
@@ -2137,7 +2139,17 @@ else
enable_shared=yes
fi
+# Check whether --enable-vtable-verify was given.
+if test "${enable_vtable_verify+set}" = set; then :
+ enableval=$enable_vtable_verify;
+ case "$enableval" in
+ yes | no) ;;
+ *) as_fn_error "Argument to enable/disable vtable-verify must be yes or no" "$LINENO" 5 ;;
+ esac
+else
+ enable_vtable_verify=no
+fi
# Make sure we can run config.sub.
$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
diff --git a/libgcc/vtv_end.c b/libgcc/vtv_end.c
new file mode 100644
index 00000000000..1a3f0416efc
--- /dev/null
+++ b/libgcc/vtv_end.c
@@ -0,0 +1,59 @@
+/* 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/>. */
+
+/* This file is part of the vtable verification feature (for a
+ detailed description of the feature, see comments in
+ tree-vtable-verify.c). The vtable verification feature creates
+ certain global symbols that need to be read-write sometimes during
+ program execution, and read-only at others. It uses 'mprotect' to
+ change the memory protections of the pages on which these variables
+ are stored. In order to not affect the protections of other
+ program variables, these variables are put into a special named
+ section, ".vtable_map_vars", which is page-aligned at the start,
+ and which is padded with a page-sized amount of zeros at the end.
+ To make this section page aligned, we create a special symbol,
+ "_vtable_map_vars_start" which we make the very first thing that
+ goes into the section. That is defined in vtv_start.c (which
+ contains nothing else). vtv_start.c gest compiled into
+ vtv_start.o, and vtv_start.o gets inserted into the link line
+ immediately after crtbegin.o, if the program is compiled with
+ -fvtable.verify.
+
+ In order to pad the ".vtable_map_vars" section with a page-sized
+ amount of zeros at the end, there is a second symbol,
+ _vtable_map_vars_end. This file defines that symbol (and only this
+ symbol). This second symbol is a page-sized array of chars,
+ zero-filled, and is the very last thing to go into the section.
+ When the GCC driver inserts vtv_start.o into the link line (just
+ after crtbegin.o) it also inserts vtv_end.o into the link line,
+ just before crtend.o. This has the desired effect of making our
+ section page-aligned and page-size paded, ensuring that no other
+ program data lands on our pages. */
+
+#ifdef BIG_PAGE_SIZE
+/* TODO - Replace '4096' below with correct big page size. */
+#define VTV_PAGE_SIZE 4096
+#else
+#define VTV_PAGE_SIZE 4096
+#endif
+
+/* Page-sized variable to mark end of .vtable_map_vars section. */
+char _vtable_map_vars_end[VTV_PAGE_SIZE]
+ __attribute__ ((__visibility__ ("protected"), used,
+ section(".vtable_map_vars")));
diff --git a/libgcc/vtv_start.c b/libgcc/vtv_start.c
new file mode 100644
index 00000000000..7899fdbd643
--- /dev/null
+++ b/libgcc/vtv_start.c
@@ -0,0 +1,59 @@
+/* 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/>. */
+
+/* This file is part of the vtable verification feature (for a
+ detailed description of the feature, see comments in
+ tree-vtable-verify.c). The vtable verification feature creates
+ certain global symbols that need to be read-write sometimes during
+ program execution, and read-only at others. It uses 'mprotect' to
+ change the memory protections of the pages on which these variables
+ are stored. In order to not affect the protections of other
+ program variables, these variables are put into a special named
+ section, ".vtable_map_vars", which is page-aligned at the start,
+ and which is padded with a page-sized amount of zeros at the end.
+ To make this section page aligned, we create a special symbol,
+ "_vtable_map_vars_start" which we make the very first thing that
+ goes into the section. This file defines that symbol (and only
+ that symbol). GCC compiles this file into vtv_start.o, and
+ inserts vtv_start.o into the link line immediately after
+ crtbegin.o, if the program is compiled with -fvtable.verify.
+
+ In order to pad the ".vtable_map_vars" section with a page-sized
+ amount of zeros at the end, there is a second symbol,
+ _vtable_map_vars_end, which is defined in another file, vtv_end.c.
+ This second symbol is a page-sized array of chars, zero-filled, and
+ is the very last thing to go into the section. When the GCC driver
+ inserts vtv_start.o into the link line (just after crtbegin.o) it
+ also inserts vtv_end.o into the link line, just before crtend.o.
+ This has the desired effect of making our section page-aligned and
+ page-size paded, ensuring that no other program data lands on our
+ pages. */
+
+#ifdef BIG_PAGE_SIZE
+/* TODO - Replace '4096' below with correct big page size. */
+#define VTV_PAGE_SIZE 4096
+#else
+#define VTV_PAGE_SIZE 4096
+#endif
+
+/* Page-aligned symbol to mark beginning of .vtable_map_vars section. */
+char _vtable_map_vars_start []
+__attribute__ ((__visibility__ ("protected"), used, aligned(VTV_PAGE_SIZE),
+ section(".vtable_map_vars")))
+ = { };
diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 86f7dfab865..514c5cf7a7f 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -2223,6 +2223,25 @@ AC_DEFUN([GLIBCXX_ENABLE_EXTERN_TEMPLATE], [
])
dnl
+dnl Use vtable verification.
+dnl
+dnl --enable-vtable-verify defines _GLIBCXX_VTABLE_VERIFY to 1
+dnl --disable-vtable-verify defines _GLIBCXX_VTABLE_VERIFY to 0
+
+dnl + Usage: GLIBCXX_ENABLE_VTABLE_VERIFY[(DEFAULT)]
+dnl Where DEFAULT is `yes' or `no'.
+dnl
+AC_DEFUN([GLIBCXX_ENABLE_VTABLE_VERIFY], [
+
+ GLIBCXX_ENABLE(vtable-verify,$1,,[enable vtable verify])
+
+ AC_MSG_CHECKING([for vtable verify support])
+ AC_MSG_RESULT([$enable_vtable_verify])
+
+ GLIBCXX_CONDITIONAL(ENABLE_VTABLE_VERIFY, test $enable_vtable_verify = yes)
+])
+
+dnl
dnl Check for parallel mode pre-requisites, including OpenMP support.
dnl
dnl + Usage: GLIBCXX_ENABLE_PARALLEL
diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver
index 288152cf36d..90eab2fbfd8 100644
--- a/libstdc++-v3/config/abi/pre/gnu.ver
+++ b/libstdc++-v3/config/abi/pre/gnu.ver
@@ -1326,6 +1326,20 @@ GLIBCXX_3.4.18 {
# operator delete(void*, , unsigned long)
_ZdlPv[jmy];
+ # Virtual table verification symbols
+ _Z12__VLTprotectv;
+ _Z14__VLTunprotectv;
+ _Z18__VLTInitSetSymbol*;
+ _Z23__VLTInitSetSymbolDebug*;
+ _Z17__VLTRegisterPair*;
+ _Z22__VLTRegisterPairDebug*;
+ _Z21__VLTChangePermission*;
+ _Z24__VLTVerifyVtablePointer*;
+ _Z29__VLTVerifyVtablePointerDebug*;
+ _Z17__vtv_verify_fail*;
+ _Z17__vtv_really_fail*;
+
+
} GLIBCXX_3.4.17;
# Symbols in the support library (libsupc++) have their own tag.
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index a317514cb2d..f15b3fed32f 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -661,6 +661,8 @@ LIBICONV
OPT_LDFLAGS
SECTION_LDFLAGS
GLIBCXX_LIBS
+ENABLE_VTABLE_VERIFY_FALSE
+ENABLE_VTABLE_VERIFY_TRUE
ENABLE_WERROR_FALSE
ENABLE_WERROR_TRUE
ENABLE_PYTHONDIR_FALSE
@@ -863,6 +865,7 @@ enable_fully_dynamic_string
enable_extern_template
with_python_dir
enable_werror
+enable_vtable_verify
enable_libstdcxx_time
enable_tls
enable_rpath
@@ -1553,6 +1556,7 @@ Optional Features:
--enable-extern-template
enable extern template [default=yes]
--enable-werror turns on -Werror [default=yes]
+ --enable-vtable-verify enable vtable verify [default=no]
--enable-libstdcxx-time[=KIND]
use KIND for check type [default=no]
--enable-tls Use thread-local storage [default=yes]
@@ -11515,7 +11519,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11518 "configure"
+#line 11522 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11621,7 +11625,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11624 "configure"
+#line 11628 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -14907,6 +14911,11 @@ esac
+if test "$enable_vtable_verify" = yes; then
+ predep_objects_CXX="${predep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_start.o"
+ postdep_objects_CXX="${postdep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_end.o"
+fi
+
# libtool variables for C++ shared and position-independent compiles.
#
# Use glibcxx_lt_pic_flag to designate the automake variable
@@ -15011,7 +15020,7 @@ fi
#
# Fake what AC_TRY_COMPILE does. XXX Look at redoing this new-style.
cat > conftest.$ac_ext << EOF
-#line 15014 "configure"
+#line 15023 "configure"
struct S { ~S(); };
void bar();
void foo()
@@ -15346,7 +15355,7 @@ $as_echo "$glibcxx_cv_atomic_long_long" >&6; }
# Fake what AC_TRY_COMPILE does.
cat > conftest.$ac_ext << EOF
-#line 15349 "configure"
+#line 15358 "configure"
int main()
{
typedef bool atomic_type;
@@ -15381,7 +15390,7 @@ $as_echo "$glibcxx_cv_atomic_bool" >&6; }
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15384 "configure"
+#line 15393 "configure"
int main()
{
typedef short atomic_type;
@@ -15416,7 +15425,7 @@ $as_echo "$glibcxx_cv_atomic_short" >&6; }
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15419 "configure"
+#line 15428 "configure"
int main()
{
// NB: _Atomic_word not necessarily int.
@@ -15452,7 +15461,7 @@ $as_echo "$glibcxx_cv_atomic_int" >&6; }
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15455 "configure"
+#line 15464 "configure"
int main()
{
typedef long long atomic_type;
@@ -15531,7 +15540,7 @@ $as_echo "$as_me: WARNING: Performance of certain classes will degrade as a resu
# unnecessary for this test.
cat > conftest.$ac_ext << EOF
-#line 15534 "configure"
+#line 15543 "configure"
int main()
{
_Decimal32 d1;
@@ -15573,7 +15582,7 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
# unnecessary for this test.
cat > conftest.$ac_ext << EOF
-#line 15576 "configure"
+#line 15585 "configure"
template<typename T1, typename T2>
struct same
{ typedef T2 type; };
@@ -15607,7 +15616,7 @@ $as_echo "$enable_int128" >&6; }
rm -f conftest*
cat > conftest.$ac_ext << EOF
-#line 15610 "configure"
+#line 15619 "configure"
template<typename T1, typename T2>
struct same
{ typedef T2 type; };
@@ -17341,6 +17350,29 @@ $as_echo "$enable_werror" >&6; }
+
+ # Check whether --enable-vtable-verify was given.
+if test "${enable_vtable_verify+set}" = set; then :
+ enableval=$enable_vtable_verify;
+ case "$enableval" in
+ yes|no) ;;
+ *) as_fn_error "Argument to enable/disable vtable-verify must be yes or no" "$LINENO" 5 ;;
+ esac
+
+else
+ enable_vtable_verify=no
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for vtable verify support" >&5
+$as_echo_n "checking for vtable verify support... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_vtable_verify" >&5
+$as_echo "$enable_vtable_verify" >&6; }
+
+
+
+
# Checks for operating systems support that doesn't require linking.
@@ -66251,6 +66283,15 @@ else
fi
+ if test $enable_vtable_verify = yes; then
+ ENABLE_VTABLE_VERIFY_TRUE=
+ ENABLE_VTABLE_VERIFY_FALSE='#'
+else
+ ENABLE_VTABLE_VERIFY_TRUE='#'
+ ENABLE_VTABLE_VERIFY_FALSE=
+fi
+
+
if test $enable_symvers != no; then
ENABLE_SYMVERS_TRUE=
ENABLE_SYMVERS_FALSE='#'
@@ -66698,6 +66739,10 @@ if test -z "${ENABLE_WERROR_TRUE}" && test -z "${ENABLE_WERROR_FALSE}"; then
as_fn_error "conditional \"ENABLE_WERROR\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${ENABLE_VTABLE_VERIFY_TRUE}" && test -z "${ENABLE_VTABLE_VERIFY_FALSE}"; then
+ as_fn_error "conditional \"ENABLE_VTABLE_VERIFY\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${ENABLE_SYMVERS_TRUE}" && test -z "${ENABLE_SYMVERS_FALSE}"; then
as_fn_error "conditional \"ENABLE_SYMVERS\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index ce1f6c48165..fb4f5065ae3 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -97,6 +97,11 @@ ACX_LT_HOST_FLAGS
AC_SUBST(enable_shared)
AC_SUBST(enable_static)
+if test "$enable_vtable_verify" = yes; then
+ predep_objects_CXX="${predep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_start.o"
+ postdep_objects_CXX="${postdep_objects_CXX} ${glibcxx_builddir}/../libgcc/vtv_end.o"
+fi
+
# libtool variables for C++ shared and position-independent compiles.
#
# Use glibcxx_lt_pic_flag to designate the automake variable
@@ -165,6 +170,7 @@ GLIBCXX_ENABLE_FULLY_DYNAMIC_STRING([no])
GLIBCXX_ENABLE_EXTERN_TEMPLATE([yes])
GLIBCXX_ENABLE_PYTHON
GLIBCXX_ENABLE_WERROR([yes])
+GLIBCXX_ENABLE_VTABLE_VERIFY([no])
# Checks for operating systems support that doesn't require linking.
GLIBCXX_CHECK_MATH_PROTO
diff --git a/libstdc++-v3/libsupc++/Makefile.am b/libstdc++-v3/libsupc++/Makefile.am
index 0c4339da68d..8b619da41b1 100644
--- a/libstdc++-v3/libsupc++/Makefile.am
+++ b/libstdc++-v3/libsupc++/Makefile.am
@@ -27,7 +27,11 @@ include $(top_srcdir)/fragment.am
# Need this library to both be part of libstdc++.a, and installed
# separately too.
# 1) separate libsupc++.la
+if ENABLE_VTABLE_VERIFY
+toolexeclib_LTLIBRARIES = libsupc++.la libvtv_init.la libvtv_stubs.la
+else
toolexeclib_LTLIBRARIES = libsupc++.la
+endif
# 2) integrated libsupc++convenience.la that is to be a part of libstdc++.a
noinst_LTLIBRARIES = libsupc++convenience.la
@@ -45,7 +49,73 @@ if GLIBCXX_HOSTED
cp-demangle.c
endif
-sources = \
+if ENABLE_VTABLE_VERIFY
+ sources = \
+ array_type_info.cc \
+ atexit_arm.cc \
+ bad_alloc.cc \
+ bad_cast.cc \
+ bad_typeid.cc \
+ class_type_info.cc \
+ del_op.cc \
+ del_opsz.cc \
+ del_opnt.cc \
+ del_opv.cc \
+ del_opvnt.cc \
+ dyncast.cc \
+ eh_alloc.cc \
+ eh_arm.cc \
+ eh_aux_runtime.cc \
+ eh_call.cc \
+ eh_catch.cc \
+ eh_exception.cc \
+ eh_globals.cc \
+ eh_personality.cc \
+ eh_ptr.cc \
+ eh_term_handler.cc \
+ eh_terminate.cc \
+ eh_tm.cc \
+ eh_throw.cc \
+ eh_type.cc \
+ eh_unex_handler.cc \
+ enum_type_info.cc \
+ function_type_info.cc \
+ fundamental_type_info.cc \
+ guard.cc \
+ guard_error.cc \
+ hash_bytes.cc \
+ nested_exception.cc \
+ new_handler.cc \
+ new_op.cc \
+ new_opnt.cc \
+ new_opv.cc \
+ new_opvnt.cc \
+ pbase_type_info.cc \
+ pmem_type_info.cc \
+ pointer_type_info.cc \
+ pure.cc \
+ si_class_type_info.cc \
+ tinfo.cc \
+ tinfo2.cc \
+ vec.cc \
+ vmi_class_type_info.cc \
+ vterminate.cc \
+ vtv_rts.cc \
+ vtv_malloc.cc \
+ vtv_utils.cc
+
+ vtv_init_sources = \
+ vtv_init.cc
+
+ vtv_stubs_sources = \
+ vtv_stubs.cc
+
+ libsupc___la_SOURCES = $(sources) $(c_sources)
+ libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+ libvtv_init_la_SOURCES = $(vtv_init_sources)
+ libvtv_stubs_la_SOURCES = $(vtv_stubs_sources)
+else
+ sources = \
array_type_info.cc \
atexit_arm.cc \
bad_alloc.cc \
@@ -96,8 +166,9 @@ sources = \
vmi_class_type_info.cc \
vterminate.cc
-libsupc___la_SOURCES = $(sources) $(c_sources)
-libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+ libsupc___la_SOURCES = $(sources) $(c_sources)
+ libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+endif
cp-demangle.c:
rm -f $@
diff --git a/libstdc++-v3/libsupc++/Makefile.in b/libstdc++-v3/libsupc++/Makefile.in
index a4f93aad9c5..a6c53227df5 100644
--- a/libstdc++-v3/libsupc++/Makefile.in
+++ b/libstdc++-v3/libsupc++/Makefile.in
@@ -90,26 +90,91 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(bitsdir)" \
"$(DESTDIR)$(stddir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
libsupc___la_LIBADD =
-am__objects_1 = array_type_info.lo atexit_arm.lo bad_alloc.lo \
- bad_cast.lo bad_typeid.lo class_type_info.lo del_op.lo \
- del_opsz.lo del_opnt.lo del_opv.lo del_opvnt.lo dyncast.lo \
- eh_alloc.lo eh_arm.lo eh_aux_runtime.lo eh_call.lo eh_catch.lo \
- eh_exception.lo eh_globals.lo eh_personality.lo eh_ptr.lo \
- eh_term_handler.lo eh_terminate.lo eh_tm.lo eh_throw.lo \
- eh_type.lo eh_unex_handler.lo enum_type_info.lo \
- function_type_info.lo fundamental_type_info.lo guard.lo \
- guard_error.lo hash_bytes.lo nested_exception.lo \
- new_handler.lo new_op.lo new_opnt.lo new_opv.lo new_opvnt.lo \
- pbase_type_info.lo pmem_type_info.lo pointer_type_info.lo \
- pure.lo si_class_type_info.lo tinfo.lo tinfo2.lo vec.lo \
- vmi_class_type_info.lo vterminate.lo
+@ENABLE_VTABLE_VERIFY_FALSE@am__objects_1 = array_type_info.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ atexit_arm.lo bad_alloc.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ bad_cast.lo bad_typeid.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ class_type_info.lo del_op.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ del_opsz.lo del_opnt.lo del_opv.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ del_opvnt.lo dyncast.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_alloc.lo eh_arm.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_aux_runtime.lo eh_call.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_catch.lo eh_exception.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_globals.lo eh_personality.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_ptr.lo eh_term_handler.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_terminate.lo eh_tm.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_throw.lo eh_type.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_unex_handler.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ enum_type_info.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ function_type_info.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ fundamental_type_info.lo guard.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ guard_error.lo hash_bytes.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ nested_exception.lo new_handler.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ new_op.lo new_opnt.lo new_opv.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ new_opvnt.lo pbase_type_info.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ pmem_type_info.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ pointer_type_info.lo pure.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ si_class_type_info.lo tinfo.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ tinfo2.lo vec.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ vmi_class_type_info.lo \
+@ENABLE_VTABLE_VERIFY_FALSE@ vterminate.lo
+@ENABLE_VTABLE_VERIFY_TRUE@am__objects_1 = array_type_info.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ atexit_arm.lo bad_alloc.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ bad_cast.lo bad_typeid.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ class_type_info.lo del_op.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ del_opsz.lo del_opnt.lo del_opv.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ del_opvnt.lo dyncast.lo eh_alloc.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_arm.lo eh_aux_runtime.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_call.lo eh_catch.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_exception.lo eh_globals.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_personality.lo eh_ptr.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_term_handler.lo eh_terminate.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_tm.lo eh_throw.lo eh_type.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_unex_handler.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ enum_type_info.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ function_type_info.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ fundamental_type_info.lo guard.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ guard_error.lo hash_bytes.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ nested_exception.lo new_handler.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ new_op.lo new_opnt.lo new_opv.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ new_opvnt.lo pbase_type_info.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ pmem_type_info.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ pointer_type_info.lo pure.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ si_class_type_info.lo tinfo.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ tinfo2.lo vec.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ vmi_class_type_info.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ vterminate.lo vtv_rts.lo \
+@ENABLE_VTABLE_VERIFY_TRUE@ vtv_malloc.lo vtv_utils.lo
@GLIBCXX_HOSTED_TRUE@am__objects_2 = cp-demangle.lo
-am_libsupc___la_OBJECTS = $(am__objects_1) $(am__objects_2)
+@ENABLE_VTABLE_VERIFY_FALSE@am_libsupc___la_OBJECTS = \
+@ENABLE_VTABLE_VERIFY_FALSE@ $(am__objects_1) $(am__objects_2)
+@ENABLE_VTABLE_VERIFY_TRUE@am_libsupc___la_OBJECTS = $(am__objects_1) \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(am__objects_2)
libsupc___la_OBJECTS = $(am_libsupc___la_OBJECTS)
+@ENABLE_VTABLE_VERIFY_FALSE@am_libsupc___la_rpath = -rpath \
+@ENABLE_VTABLE_VERIFY_FALSE@ $(toolexeclibdir)
+@ENABLE_VTABLE_VERIFY_TRUE@am_libsupc___la_rpath = -rpath \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(toolexeclibdir)
libsupc__convenience_la_LIBADD =
-am_libsupc__convenience_la_OBJECTS = $(am__objects_1) $(am__objects_2)
+@ENABLE_VTABLE_VERIFY_FALSE@am_libsupc__convenience_la_OBJECTS = \
+@ENABLE_VTABLE_VERIFY_FALSE@ $(am__objects_1) $(am__objects_2)
+@ENABLE_VTABLE_VERIFY_TRUE@am_libsupc__convenience_la_OBJECTS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(am__objects_1) $(am__objects_2)
libsupc__convenience_la_OBJECTS = \
$(am_libsupc__convenience_la_OBJECTS)
+libvtv_init_la_LIBADD =
+@ENABLE_VTABLE_VERIFY_TRUE@am__objects_3 = vtv_init.lo
+@ENABLE_VTABLE_VERIFY_TRUE@am_libvtv_init_la_OBJECTS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(am__objects_3)
+libvtv_init_la_OBJECTS = $(am_libvtv_init_la_OBJECTS)
+@ENABLE_VTABLE_VERIFY_TRUE@am_libvtv_init_la_rpath = -rpath \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(toolexeclibdir)
+libvtv_stubs_la_LIBADD =
+@ENABLE_VTABLE_VERIFY_TRUE@am__objects_4 = vtv_stubs.lo
+@ENABLE_VTABLE_VERIFY_TRUE@am_libvtv_stubs_la_OBJECTS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(am__objects_4)
+libvtv_stubs_la_OBJECTS = $(am_libvtv_stubs_la_OBJECTS)
+@ENABLE_VTABLE_VERIFY_TRUE@am_libvtv_stubs_la_rpath = -rpath \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(toolexeclibdir)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp =
am__depfiles_maybe =
@@ -122,7 +187,8 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
CXXLD = $(CXX)
-SOURCES = $(libsupc___la_SOURCES) $(libsupc__convenience_la_SOURCES)
+SOURCES = $(libsupc___la_SOURCES) $(libsupc__convenience_la_SOURCES) \
+ $(libvtv_init_la_SOURCES) $(libvtv_stubs_la_SOURCES)
HEADERS = $(bits_HEADERS) $(std_HEADERS)
ETAGS = etags
CTAGS = ctags
@@ -338,11 +404,12 @@ WARN_CXXFLAGS = \
# -I/-D flags to pass when compiling.
AM_CPPFLAGS = $(GLIBCXX_INCLUDES)
+@ENABLE_VTABLE_VERIFY_FALSE@toolexeclib_LTLIBRARIES = libsupc++.la
# Need this library to both be part of libstdc++.a, and installed
# separately too.
# 1) separate libsupc++.la
-toolexeclib_LTLIBRARIES = libsupc++.la
+@ENABLE_VTABLE_VERIFY_TRUE@toolexeclib_LTLIBRARIES = libsupc++.la libvtv_init.la libvtv_stubs.la
# 2) integrated libsupc++convenience.la that is to be a part of libstdc++.a
noinst_LTLIBRARIES = libsupc++convenience.la
std_HEADERS = \
@@ -356,59 +423,123 @@ headers = $(std_HEADERS) $(bits_HEADERS)
@GLIBCXX_HOSTED_TRUE@c_sources = \
@GLIBCXX_HOSTED_TRUE@ cp-demangle.c
-sources = \
- array_type_info.cc \
- atexit_arm.cc \
- bad_alloc.cc \
- bad_cast.cc \
- bad_typeid.cc \
- class_type_info.cc \
- del_op.cc \
- del_opsz.cc \
- del_opnt.cc \
- del_opv.cc \
- del_opvnt.cc \
- dyncast.cc \
- eh_alloc.cc \
- eh_arm.cc \
- eh_aux_runtime.cc \
- eh_call.cc \
- eh_catch.cc \
- eh_exception.cc \
- eh_globals.cc \
- eh_personality.cc \
- eh_ptr.cc \
- eh_term_handler.cc \
- eh_terminate.cc \
- eh_tm.cc \
- eh_throw.cc \
- eh_type.cc \
- eh_unex_handler.cc \
- enum_type_info.cc \
- function_type_info.cc \
- fundamental_type_info.cc \
- guard.cc \
- guard_error.cc \
- hash_bytes.cc \
- nested_exception.cc \
- new_handler.cc \
- new_op.cc \
- new_opnt.cc \
- new_opv.cc \
- new_opvnt.cc \
- pbase_type_info.cc \
- pmem_type_info.cc \
- pointer_type_info.cc \
- pure.cc \
- si_class_type_info.cc \
- tinfo.cc \
- tinfo2.cc \
- vec.cc \
- vmi_class_type_info.cc \
- vterminate.cc
-
-libsupc___la_SOURCES = $(sources) $(c_sources)
-libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+@ENABLE_VTABLE_VERIFY_FALSE@sources = \
+@ENABLE_VTABLE_VERIFY_FALSE@ array_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ atexit_arm.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ bad_alloc.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ bad_cast.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ bad_typeid.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ class_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ del_op.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ del_opsz.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ del_opnt.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ del_opv.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ del_opvnt.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ dyncast.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_alloc.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_arm.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_aux_runtime.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_call.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_catch.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_exception.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_globals.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_personality.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_ptr.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_term_handler.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_terminate.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_tm.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_throw.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_type.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ eh_unex_handler.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ enum_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ function_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ fundamental_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ guard.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ guard_error.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ hash_bytes.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ nested_exception.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ new_handler.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ new_op.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ new_opnt.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ new_opv.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ new_opvnt.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ pbase_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ pmem_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ pointer_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ pure.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ si_class_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ tinfo.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ tinfo2.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ vec.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ vmi_class_type_info.cc \
+@ENABLE_VTABLE_VERIFY_FALSE@ vterminate.cc
+
+@ENABLE_VTABLE_VERIFY_TRUE@sources = \
+@ENABLE_VTABLE_VERIFY_TRUE@ array_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ atexit_arm.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ bad_alloc.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ bad_cast.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ bad_typeid.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ class_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ del_op.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ del_opsz.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ del_opnt.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ del_opv.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ del_opvnt.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ dyncast.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_alloc.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_arm.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_aux_runtime.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_call.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_catch.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_exception.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_globals.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_personality.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_ptr.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_term_handler.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_terminate.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_tm.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_throw.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_type.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ eh_unex_handler.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ enum_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ function_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ fundamental_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ guard.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ guard_error.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ hash_bytes.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ nested_exception.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ new_handler.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ new_op.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ new_opnt.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ new_opv.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ new_opvnt.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ pbase_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ pmem_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ pointer_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ pure.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ si_class_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ tinfo.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ tinfo2.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ vec.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ vmi_class_type_info.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ vterminate.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ vtv_rts.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ vtv_malloc.cc \
+@ENABLE_VTABLE_VERIFY_TRUE@ vtv_utils.cc
+
+@ENABLE_VTABLE_VERIFY_TRUE@vtv_init_sources = \
+@ENABLE_VTABLE_VERIFY_TRUE@ vtv_init.cc
+
+@ENABLE_VTABLE_VERIFY_TRUE@vtv_stubs_sources = \
+@ENABLE_VTABLE_VERIFY_TRUE@ vtv_stubs.cc
+
+@ENABLE_VTABLE_VERIFY_FALSE@libsupc___la_SOURCES = $(sources) $(c_sources)
+@ENABLE_VTABLE_VERIFY_TRUE@libsupc___la_SOURCES = $(sources) $(c_sources)
+@ENABLE_VTABLE_VERIFY_FALSE@libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+@ENABLE_VTABLE_VERIFY_TRUE@libsupc__convenience_la_SOURCES = $(sources) $(c_sources)
+@ENABLE_VTABLE_VERIFY_TRUE@libvtv_init_la_SOURCES = $(vtv_init_sources)
+@ENABLE_VTABLE_VERIFY_TRUE@libvtv_stubs_la_SOURCES = $(vtv_stubs_sources)
# AM_CXXFLAGS needs to be in each subdirectory so that it can be
# modified in a per-library or per-sub-library way. Need to manually
@@ -575,9 +706,13 @@ clean-toolexeclibLTLIBRARIES:
rm -f "$${dir}/so_locations"; \
done
libsupc++.la: $(libsupc___la_OBJECTS) $(libsupc___la_DEPENDENCIES)
- $(CXXLINK) -rpath $(toolexeclibdir) $(libsupc___la_OBJECTS) $(libsupc___la_LIBADD) $(LIBS)
+ $(CXXLINK) $(am_libsupc___la_rpath) $(libsupc___la_OBJECTS) $(libsupc___la_LIBADD) $(LIBS)
libsupc++convenience.la: $(libsupc__convenience_la_OBJECTS) $(libsupc__convenience_la_DEPENDENCIES)
$(CXXLINK) $(libsupc__convenience_la_OBJECTS) $(libsupc__convenience_la_LIBADD) $(LIBS)
+libvtv_init.la: $(libvtv_init_la_OBJECTS) $(libvtv_init_la_DEPENDENCIES)
+ $(CXXLINK) $(am_libvtv_init_la_rpath) $(libvtv_init_la_OBJECTS) $(libvtv_init_la_LIBADD) $(LIBS)
+libvtv_stubs.la: $(libvtv_stubs_la_OBJECTS) $(libvtv_stubs_la_DEPENDENCIES)
+ $(CXXLINK) $(am_libvtv_stubs_la_rpath) $(libvtv_stubs_la_OBJECTS) $(libvtv_stubs_la_LIBADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
diff --git a/libstdc++-v3/libsupc++/vtv_fail.h b/libstdc++-v3/libsupc++/vtv_fail.h
new file mode 100644
index 00000000000..1048905c639
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_fail.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VTV_FAIL_H
+#define _VTV_FAIL_H 1
+
+/* __vtv_really_fail prints a backtrace and a memory dump, then calls
+ abort. It is here for programmers to call, presumably from
+ __vtv_verify_fail, if they choose to overwrite the standard
+ __vtv_verify_fail with one of their own. Programmers should NOT
+ attempt to rewrite __vtv_really_fail. */
+
+extern void
+__vtv_really_fail (const char *fail_msg) __attribute__ ((noreturn));
+
+/* __vtv_verify_fail is the function that gets called if the vtable
+ verification code discovers a vtable pointer that it cannot verify
+ as valid. Normally __vtv_verify_fail calls __vtv_really_fail.
+ However programmers can write and link in their own version of
+ __vtv_verify_fail, if they wish to do some kind of secondary
+ verification, for example. The main verification code assumes that
+ IF __vtv_verify_fail returns, then some kind of secondary
+ verification was done AND that the secondary verification succeeded,
+ i.e. that the vtable pointer is actually valid and ok to use. If
+ the secondary verification fails, then __vtv_verify_fail should not
+ return. */
+
+extern void
+__vtv_verify_fail (void **data_set_ptr, const void *vtbl_pointer)
+ __attribute__((visibility ("default")));
+
+#endif /* _VTV_FAIL_H */
diff --git a/libstdc++-v3/libsupc++/vtv_init.cc b/libstdc++-v3/libsupc++/vtv_init.cc
new file mode 100644
index 00000000000..2ab47adf552
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_init.cc
@@ -0,0 +1,179 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+
+/* This file contains all the definitions that go into the libvtv_init
+ library, which is part of the vtable verification feature. This
+ library should contain exactly two functionsa (__VLTunprotect and
+ __VLTprotect) and one global variable definition
+ (__vtv_defined_in_vtv_init_lib). Any program that was compiled
+ with the option "-fvtable-verify=std" MUST also be linked with
+ libvtv_init, because the two functions defined here are used by the
+ vtable verification code. The reason they are in a separate
+ library rather than in libstdc++ with all the rest of the vtable
+ verification runtime code is as follows. Each .o file that was
+ compiled with vtable verification will contain calls into the
+ runtime (made from constructor initialization functions) to build
+ the data structures needed for verification. At all times except
+ when they are being constructed, these data structures need to be
+ in protected memory, so that attackers cannot corrupt them.
+ __VLTunprotect sets the memory containing these data structures to
+ be writable, for updates. __VLTprotect makes the memory read-only,
+ for all other times. This memory protection and unprotection is
+ done via calls to mprotect, which are costly. So instead of
+ calling __VLTunprotect and __VLTprotect once per object file we
+ want to call them once per executable. Therefore instead of
+ putting calls to them directly into each object file, we put the
+ calls to them only in __VLTRegisterPair, in the libstdc++ library.
+ We give __VLTunprotect an initialization priority to make it run
+ before all of our data structure construction functions, and we
+ give __VLTprotect an initialization priority to make it run after
+ all of our data structure constructiion functions. We put them
+ into a separate library and link that library with the
+ "--whole-archive" linker option, to make sure that both functions get
+ linked in (since the actual calls to them are in the libstdc++
+ runtime). We can't put them into libstdc++ because linking
+ libstdc++ with "--whole-archive" is probably not a good idea.
+
+ The __vtv_defined_in_vtv_lib variable is referenced, but not
+ defined, in the constructor initialization functions where we have
+ the calls to build our data structures. The purpose of this
+ variable is to cause a linker error to occur if the programmer
+ compiled with -fvtable-verify=std and did not link with the vtv_int
+ library (better a link-time error than a run-time error). */
+
+
+/* Needs to build with C++ because the definition of
+ __VLTChangePermission is in C++. */
+#ifndef __cplusplus
+#error "This file must be compiled with a C++ compiler"
+#endif
+
+#include "vtv_rts.h"
+
+/* Define this dummy symbol to detect at link time the cases where
+ user is compiling with -fvtable-verify=std and not linking with the
+ vtv_init library. Note that the visibility needs to be hidden. Each
+ object module is supposed to link with the vtv_init library and we
+ don't want this definition to come from a different library */
+unsigned int
+__vtv_defined_in_vtv_init_lib __attribute__ ((visibility ("hidden"))) = 0;
+
+void __VLTunprotect (void) __attribute__ ((constructor(98)));
+void __VLTprotect (void) __attribute__ ((constructor(100)));
+
+void
+__VLTunprotect (void)
+{
+ __VLTChangePermission (__VLTP_READ_WRITE);
+}
+
+void
+__VLTprotect (void)
+{
+ __VLTChangePermission (__VLTP_READ_ONLY);
+}
+
+/* This VTV_STATIC_VERIFY macro is experimental for now. If we are
+ going to use it we need to put the code below in a common
+ place. Right now it is a copy of the code in vtv_rts.cc */
+#ifdef VTV_STATIC_VERIFY
+
+#ifdef VTV_DEBUG
+
+const void *
+__VLTVerifyVtablePointerDebug (void **set_handle_ptr,
+ const void *vtable_ptr,
+ const char *set_symbol_name,
+ const char *vtable_name)
+{
+#ifndef VTV_EMPTY_VERIFY
+ VTV_DEBUG_ASSERT(set_handle_ptr != NULL && *set_handle_ptr != NULL);
+ int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+ vtv_set_handle *handle_ptr;
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+ if (vtv_sets::contains (vtbl_ptr, handle_ptr))
+ {
+ if (debug_verify_vtable)
+ {
+ if (verify_vtable_log_fd == -1)
+ vtv_open_log ("vtv_verify_vtable.log");
+ vtv_add_to_log (verify_vtable_log_fd,
+ "Verified %s %s value = %p\n",
+ set_symbol_name, vtable_name, vtable_ptr);
+ }
+ }
+ else
+ {
+ snprintf (debug_log_message, sizeof (debug_log_message),
+ "Looking for %s in %s\n", vtable_name, set_symbol_name);
+ __vtv_verify_fail_debug (set_handle_ptr, vtable_ptr, debug_log_message);
+
+ /* Normally __vtv_verify_fail will call abort, so we won't
+ execute the return below. If we get this far, the assumption
+ is that the programmer has replace __vtv_verify_fail with
+ some kind of secondary verification AND this secondary
+ verification succeeded, so the vtable pointer is valid. */
+ }
+#endif /* VTV_EMPTY_VERIFY */
+
+ return vtable_ptr;
+}
+
+#else /* VTV_DEBUG */
+
+const void *
+__VLTVerifyVtablePointer (void **set_handle_ptr, const void *vtable_ptr)
+{
+#ifndef VTV_EMPTY_VERIFY
+ int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+ vtv_set_handle *handle_ptr;
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+ if (!vtv_sets::contains (vtbl_ptr, handle_ptr))
+ {
+ __vtv_verify_fail ((void **) handle_ptr, vtable_ptr);
+ /* Normally __vtv_verify_fail will call abort, so we won't
+ execute the return below. If we get this far, the assumption
+ is that the programmer has replaced __vtv_verify_fail with
+ some kind of secondary verification AND this secondary
+ verification succeeded, so the vtable pointer is valid. */
+ }
+#endif /* VTV_EMPTY_VERIFY*/
+
+ return vtable_ptr;
+}
+
+#endif /* else-clause VTV_DEBUG */
+
+#endif /* VTV_STATIC_VERIFY */
diff --git a/libstdc++-v3/libsupc++/vtv_malloc.cc b/libstdc++-v3/libsupc++/vtv_malloc.cc
new file mode 100644
index 00000000000..b080c7dd7d4
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_malloc.cc
@@ -0,0 +1,210 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is part of the vtable verification runtime library. It
+ contains our memory allocation and deallocation routines, which we
+ use in order to keep track of the pages in memory in which our sets
+ of valid vtable pointes are stored. (We need to know the pages so
+ we can set the protections on them appropriately). For more
+ information about the vtable verification feature, see the comments
+ in vtv_rts.cc. We use the existing obstack implementation in our
+ memory allocation scheme. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+#include "vtv_utils.h"
+#include "vtv_malloc.h"
+#include "obstack.h"
+
+/* Put the following variables in our ".vtable_map_vars" section so
+ that they are protected. They are explicitly unprotected and
+ protected again by calls to VTV_unprotect and VTV_protect */
+
+static struct obstack VTV_obstack VTV_PROTECTED_VAR;
+static unsigned long page_size VTV_PROTECTED_VAR = 0;
+static void *current_chunk VTV_PROTECTED_VAR = 0;
+static size_t current_chunk_size VTV_PROTECTED_VAR = 0;
+static int malloc_initialized VTV_PROTECTED_VAR = 0;
+
+/* This function goes through all of the pages we have allocated so
+ far and calls mprotect to make each page read-only. */
+
+void
+VTV_malloc_protect (void)
+{
+ struct _obstack_chunk *ci;
+ ci = (struct _obstack_chunk *) current_chunk;
+ while (ci)
+ {
+ VTV_DEBUG_ASSERT (((unsigned long) ci & (page_size - 1)) == 0);
+ if (mprotect (ci, (ci->limit - (char *) ci), PROT_READ) == -1)
+ VTV_error ();
+ ci = ci->prev;
+ }
+
+#if (VTV_DEBUG_MALLOC == 1)
+ VTV_malloc_dump_stats ();
+#endif
+}
+
+/* This function goes through all of the pages we have allocated so
+ far and calls mrpotect to make each page read-write. */
+
+void
+VTV_malloc_unprotect (void)
+{
+ struct _obstack_chunk * ci;
+ ci = (struct _obstack_chunk *) current_chunk;
+ while (ci)
+ {
+ VTV_DEBUG_ASSERT (((unsigned long) ci & (page_size - 1)) == 0);
+ if (mprotect (ci, (ci->limit - (char *) ci), PROT_READ | PROT_WRITE)
+ == -1)
+ VTV_error ();
+ ci = ci->prev;
+ }
+}
+
+/* Allocates a SIZE-sized chunk of memory that is aligned to a page
+ boundary. The amount of memory requested (SIZE) must be a multiple
+ of the page size. Note: We must use mmap to allocate the memory;
+ using malloc here will cause problems. */
+
+static void *
+obstack_chunk_alloc (size_t size)
+{
+ /* Increase size to the next multiple of page_size. */
+ size = (size + (page_size - 1)) & (~(page_size - 1));
+ VTV_DEBUG_ASSERT ((size & (page_size - 1)) == 0);
+ void *allocated;
+
+ if ((allocated = mmap (NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == 0)
+ VTV_error ();
+
+ VTV_DEBUG_ASSERT (((unsigned long) allocated & (page_size - 1)) == 0);
+
+ current_chunk = allocated;
+ current_chunk_size = size;
+ return allocated;
+}
+
+static void
+obstack_chunk_free (size_t size)
+{
+ /* Do nothing. For our purposes there should be very little
+ de-allocation. */
+}
+
+/* This function sets up and initializes the obstack pieces for our
+ memory allocation scheme. */
+
+void
+VTV_malloc_init (void)
+{
+ /* Make sure we only execute the main body of this function ONCE. */
+ if (malloc_initialized)
+ return;
+
+ page_size = sysconf (_SC_PAGE_SIZE);
+ if (page_size != 4096)
+ VTV_error ();
+
+ obstack_chunk_size (&VTV_obstack) = page_size;
+ obstack_alignment_mask (&VTV_obstack) = sizeof (long) - 1;
+ /* We guarantee that the obstack alloc failed handler will never be
+ called because in case the allocation of the chunk fails, it will
+ never return */
+ obstack_alloc_failed_handler = NULL;
+
+ obstack_init (&VTV_obstack);
+ malloc_initialized = 1;
+}
+
+/* This is our external interface for the memory allocation. SIZE is
+ the requested number of bytes to be allocated/ */
+
+void *
+VTV_malloc (size_t size)
+{
+ return obstack_alloc (&VTV_obstack, size);
+}
+
+
+/* This is our external interface for memory deallocation. */
+
+void
+VTV_free (void *)
+{
+ /* Do nothing. We dont care about recovering unneded memory at this
+ time. */
+}
+
+
+/* This is a debugging function tat collects statistics about our
+ memory allocation. */
+void
+VTV_malloc_stats (void)
+{
+ int count = 0;
+ struct _obstack_chunk * ci = (struct _obstack_chunk *) current_chunk;
+ while (ci)
+ {
+ count++;
+ ci = ci->prev;
+ }
+ fprintf (stderr,
+ "VTV_malloc_stats:\n Page Size = %lu bytes\n "
+ "Number of pages = %d\n", page_size, count);
+}
+
+/* This is a debugging function. It writes out our memory allocation
+ statistics to a log file. */
+
+void
+VTV_malloc_dump_stats (void)
+{
+ static int fd = -1;
+
+ if (fd == -1)
+ fd = vtv_open_log ("/tmp/vtv_mem_protection.log");
+ if (fd == -1)
+ return;
+
+ int count = 0;
+ struct _obstack_chunk * ci = (struct _obstack_chunk *) current_chunk;
+ while (ci)
+ {
+ count++;
+ ci = ci->prev;
+ }
+
+ vtv_add_to_log (fd, "VTV_malloc_protect protected=%d pages\n", count);
+}
diff --git a/libstdc++-v3/libsupc++/vtv_malloc.h b/libstdc++-v3/libsupc++/vtv_malloc.h
new file mode 100644
index 00000000000..26cab7e5de8
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_malloc.h
@@ -0,0 +1,49 @@
+/* Copyright (C) 2012, 2013
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VTV_MALLOC_H
+#define _VTV_MALLOC_H 1
+
+#include <stdlib.h>
+
+/* Alignment mask for any object returned by the VTV memory pool */
+#ifdef __LP64__
+#define VTV_ALIGNMENT_MASK (0x7)
+#else
+#define VTV_ALIGNMENT_MASK (0x3)
+#endif
+
+extern void VTV_malloc_init (void);
+
+extern void *VTV_malloc (size_t size);
+extern void VTV_free (void * ptr);
+
+
+extern void VTV_malloc_protect (void);
+extern void VTV_malloc_unprotect (void);
+
+extern void VTV_malloc_stats (void);
+extern void VTV_malloc_dump_stats (void);
+
+#endif /* vtv_malloc.h */
diff --git a/libstdc++-v3/libsupc++/vtv_map.h b/libstdc++-v3/libsupc++/vtv_map.h
new file mode 100644
index 00000000000..ed8769e02da
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_map.h
@@ -0,0 +1,311 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VTV_MAP_H
+#define _VTV_MAP_H 1
+
+#include <string.h>
+#include <vtv_utils.h>
+
+inline uint64_t
+load8bytes (const void *p)
+{
+ uint64_t result;
+ memcpy (&result, p, 8);
+ return result;
+}
+
+/* Insert_only_hash_map maps keys to values. The implementation is a
+ basic hash table with open addressing. The keys are not "owned" by
+ the table; it only stores pointers to keys. The key type is
+ specified below (see insert_only_hash_map::key_type) and is,
+ roughly speaking, a string of any length with the string length and
+ a hash code stored at the front. The code here does not compute
+ any hash codes, but rather uses what's given. */
+
+template<typename T, typename Alloc>
+class insert_only_hash_map
+ {
+ public:
+ typedef size_t size_type;
+ typedef T value_type;
+ typedef Alloc alloc_type;
+ enum { min_capacity = 4 };
+#if HASHMAP_STATS
+ enum { stats = true };
+#else
+ enum { stats = false };
+#endif
+
+ /* Keys are a byte string (up to 2^32 - 1 long) plus a uint32_t
+ that's used as a hash code. The latter can encode arbitrary
+ information at the client's discretion, so, e.g., multiple keys
+ that are the same string still "differ" if the hash codes differ.
+ Keys are equal if the first 8 bytes are equal and the next n
+ bytes are equal. */
+ struct key_type
+ {
+ uint32_t n;
+ uint32_t hash;
+ char bytes[0];
+
+ bool
+ equals (const key_type *k) const;
+ };
+
+ /* Create an empty map with a reasonable number of buckets for the
+ expected size. Returns NULL if the allocator fails. */
+
+ static insert_only_hash_map *
+ create (size_type expected_size);
+
+ /* The opposite of create(). Free the memory for the given map. */
+
+ static void
+ destroy (insert_only_hash_map *m)
+ { Alloc().dealloc (m, m->size_in_bytes_); }
+
+ /* Return a map identical to this except that *k is mapped to v.
+ Typcially it's done by modifying this in place, but if a resize
+ is necessary then this is deallocated and a new map is returned.
+ Requires k to be non-NULL. Does nothing and returns NULL if the
+ allocator fails. */
+
+ insert_only_hash_map*
+ put (const key_type *k, const value_type &v)
+ { return this->put_internal (k, v, false); }
+
+ /* If *k is a key in this then set *v to point to the corresponding
+ value. Otherwise, do the equivalent of insert(k, value_type())
+ and, if that succeeds, set *v to point to the inserted value.
+ Requires k to be non-NULL. Does nothing and returns NULL if the
+ allocator fails. Typically returns this, but will return a new
+ insert_only_hash_map if a resize occurs. If the return value is
+ non-NULL, *v is set and it's valid until a resize of the map that
+ is the return value. */
+
+ insert_only_hash_map *
+ find_or_add_key (const key_type *k, value_type **v);
+
+ /* Get the value corresponding to *k. Returns NULL if there is
+ none. Requires k to be non-NULL. The return value is valid
+ until any resize. */
+ const value_type *get (const key_type *k) const;
+
+ size_type
+ size () const
+ { return num_entries_; }
+
+ bool
+ empty () const
+ { return this->size () == 0; }
+
+ size_type
+ bucket_count () const
+ { return num_buckets_; }
+
+ private:
+ typedef std::pair <const key_type *, value_type> bucket_type;
+
+ insert_only_hash_map *put_internal (const key_type *, const value_type &,
+ bool);
+
+ /* This function determines when to resize the table. */
+ bool
+ is_too_full (size_type entries) const
+ { return entries > (this->bucket_count () * 0.7); }
+
+ /* Return a copy with double the number of buckets. Returns NULL if
+ the allocator fails. Otherwise, calls destroy (this). */
+ insert_only_hash_map *destructive_copy ();
+
+ /* Must be a power of 2 not less than min_capacity. */
+ size_type num_buckets_;
+ size_type num_entries_;
+ size_type size_in_bytes_;
+ bucket_type buckets[0]; /* Actual array size is num_buckets. */
+};
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc> *
+insert_only_hash_map <T, Alloc>::create (size_type expected_size)
+{
+ size_t cap = min_capacity;
+ while (expected_size >= cap)
+ {
+ cap *= 2;
+ }
+ size_t size_in_bytes = sizeof (insert_only_hash_map <T, Alloc>)
+ + cap * sizeof (bucket_type);
+ insert_only_hash_map <T, Alloc>* result =
+ static_cast <insert_only_hash_map <T, Alloc>*> (Alloc ()
+ .alloc (size_in_bytes));
+ if (result != NULL)
+ {
+ result->size_in_bytes_ = size_in_bytes;
+ result->num_buckets_ = cap;
+ result->num_entries_ = 0;
+ memset (result->buckets, 0, cap * sizeof (bucket_type));
+ }
+ return result;
+}
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc>*
+insert_only_hash_map <T, Alloc>::destructive_copy ()
+{
+ insert_only_hash_map* copy = create (this->bucket_count ());
+ if (copy == NULL)
+ return NULL;
+ VTV_DEBUG_ASSERT (copy->bucket_count () == 2 * this->bucket_count ());
+ for (size_type i = 0; i < this->bucket_count (); i++)
+ if (this->buckets[i].first != NULL)
+ copy->put_internal (this->buckets[i].first, this->buckets[i].second,
+ true);
+ VTV_DEBUG_ASSERT (copy->size () == this->size ());
+ destroy (this);
+ return copy;
+}
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc>*
+insert_only_hash_map <T, Alloc>::find_or_add_key (const key_type *k,
+ value_type **v)
+{
+ /* Table size is always a power of 2. */
+ const size_type mask = this->bucket_count () - 1;
+ size_type bucket_index = k->hash & mask;
+ size_type step = 1;
+ for (;;)
+ {
+ bucket_type &bucket = this->buckets[bucket_index];
+ if (bucket.first == NULL)
+ {
+ /* Key was not present. */
+ if (this->is_too_full (this->size () + 1))
+ {
+ insert_only_hash_map <T, Alloc>* result =
+ this->destructive_copy ();
+ return result == NULL
+ ? NULL
+ : result->find_or_add_key (k, v);
+ }
+ else
+ {
+ bucket.first = k;
+ bucket.second = T ();
+ this->num_entries_++;
+ *v = &bucket.second;
+ return this;
+ }
+ }
+ else if (bucket.first->equals (k))
+ {
+ /* Key was present. */
+ *v = &bucket.second;
+ return this;
+ }
+ else
+ bucket_index = (bucket_index + step++) & mask;
+ }
+}
+
+template <typename T, typename Alloc>
+insert_only_hash_map <T, Alloc>*
+insert_only_hash_map <T, Alloc>::put_internal (
+ const insert_only_hash_map::key_type *k,
+ const insert_only_hash_map::value_type &v,
+ bool unique_key_and_resize_not_needed)
+{
+ /* Table size is always a power of 2. */
+ const size_type mask = this->bucket_count () - 1;
+ size_type bucket_index = k->hash & mask;
+ size_type step = 1;
+ for (;;)
+ {
+ bucket_type &bucket = this->buckets[bucket_index];
+ if (bucket.first == NULL)
+ {
+ /* Key was not present. */
+ if (!unique_key_and_resize_not_needed
+ && this->is_too_full (this->size () + 1))
+ {
+ insert_only_hash_map <T, Alloc>* result =
+ this->destructive_copy ();
+ return result == NULL
+ ? NULL
+ : result->put_internal (k, v, true);
+ }
+ else
+ {
+ bucket.first = k;
+ bucket.second = v;
+ this->num_entries_++;
+ return this;
+ }
+ }
+ else if (!unique_key_and_resize_not_needed && bucket.first->equals (k))
+ {
+ /* Key was present. Just change the value. */
+ bucket.second = v;
+ return this;
+ }
+ else
+ bucket_index = (bucket_index + step++) & mask;
+ }
+}
+
+template <typename T, typename Alloc>
+const typename insert_only_hash_map <T, Alloc>::value_type*
+insert_only_hash_map <T, Alloc>::get (const insert_only_hash_map::key_type *k)
+ const
+{
+ /* Table size is always a power of 2. */
+ const size_type mask = this->bucket_count () - 1;
+ size_type bucket_index = k->hash & mask;
+ size_type step = 1;
+ for (;;)
+ {
+ const bucket_type &bucket = this->buckets[bucket_index];
+ if (bucket.first == NULL)
+ return NULL;
+ else if (bucket.first->equals (k))
+ return &bucket.second;
+ else
+ bucket_index = (bucket_index + step++) & mask;
+ }
+}
+
+template <typename T, typename Alloc>
+bool
+insert_only_hash_map <T, Alloc>::key_type::equals (
+ const typename insert_only_hash_map <T, Alloc>::key_type *k) const
+{
+ const char* x = reinterpret_cast <const char *> (k);
+ const char* y = reinterpret_cast <const char *> (this);
+ return (load8bytes (x) == load8bytes (y)
+ && memcmp (x + 8, y + 8, this->n) == 0);
+}
+
+#endif /* _VTV_MAP_H */
diff --git a/libstdc++-v3/libsupc++/vtv_rts.cc b/libstdc++-v3/libsupc++/vtv_rts.cc
new file mode 100644
index 00000000000..ad9aea4d5ef
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_rts.cc
@@ -0,0 +1,1314 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file 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. */
+
+/* This file contains the main externally visible runtime library
+ functions for vtable verification: __VLTChangePermission,
+ __VLTRegisterPair, and __VLTVerifyVtablePointer. It also contains
+ debug versions __VLTRegisterPairDebug and
+ __VLTVerifyVtablePointerDebug, which have extra parameters in order
+ to make it easier to debug verification failures.
+
+ This file also contains the failure functions that get called when
+ a vtable pointer is not found in the data set. Two particularly
+ important functions are __vtv_verify_fail and __vtv_really_fail.
+ They are both externally visible. __vtv_verify_fail is defined in
+ such a way that it can be replaced by a programmer, if desired. It
+ is the function that __VLTVerifyVtablePointer calls if it can't
+ find the pointer in the data set. Allowing the programmer to
+ overwrite this function means that he/she can do some alternate
+ verification, including NOT failing in certain specific cases, if
+ desired. This may be the case if the programmer has to deal wtih
+ unverified third party software, for example. __vtv_really_fail is
+ available for the programmer to call from his version of
+ __vtv_verify_fail, if he decides the failure is real.
+
+ The final piece of functionality implemented in this file is symbol
+ resolution for multiple instances of the same vtable map variable.
+ If the same virtual class is used in two different compilation
+ units, then each compilation unit will create a vtable map variable
+ for the class. We need all instances of the same vtable map
+ variable to point to the same (single) set of valid vtable
+ pointters for the class, so we wrote our own hashtable-based symbol
+ resolution for vtable map variables (with a tiny optimization in
+ the case where there is only one instance of the variable).
+
+ There are two other important pieces to the runtime for vtable
+ verification besides the main pieces that go into libstdc++.so: two
+ special tiny shared libraries, libvtv_init.so and libvtv_stubs.so.
+ libvtv_init.so is built from vtv_init.cc. It is designed to hel[p
+ minimize the calls made to mprotect (see the comments in
+ vtv_init.cc for more details). Anything compiled with
+ "-fvtable-verify=std" must be linked with libvtv_init.so (the gcc
+ driver has been modified to do this). vtv_stubs.so is built from
+ vtv_stubs.cc. It replaces the main runtime functions
+ (__VLTChangePermissino, __VLTRegisterPair and
+ __VLTVerifyVtablePoitner) with stub functions that do nothing. If
+ a programmer has a library that was built with verification, but
+ wishes to not have verification turned on, the programmer can link
+ in the vtv_stubs.so library. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <execinfo.h>
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <link.h>
+#include <fcntl.h>
+#include <limits.h>
+
+/* For gthreads suppport */
+#include <bits/c++config.h>
+#include <ext/concurrence.h>
+
+#include "vtv_utils.h"
+#include "vtv_malloc.h"
+#include "vtv_set.h"
+#include "vtv_map.h"
+#include "vtv_rts.h"
+#include "vtv_fail.h"
+
+extern "C" {
+
+ /* __fortify_fail is a function in glibc that calls __libc_message,
+ causing it to print out a program termination error message
+ (including the name of the binary being terminated), a stack
+ trace where the error occurred, and a memory map dump. Ideally
+ we would have called __libc_message directly, but that function
+ does not appear to be accessible to functions outside glibc,
+ whereas __fortify_fail is. We call __fortify_fail from
+ __vtv_really_fail. We looked at calling __libc_fatal, which is
+ externally accessible, but it does not do the back trace and
+ memory dump. */
+
+ extern void __fortify_fail (const char *) __attribute__((noreturn));
+
+} /* extern "C" */
+
+
+/* Be careful about initialization of statics in this file. Some of
+ the routines below are called before any runtime initialization for
+ statics in this file will be done. For example, dont try to
+ initialize any of these statics with a runtime call (for ex:
+ sysconf. The initialization will happen after calls to the routines
+ to protect/unprotec the vtabla_map variables */
+
+/* No need to mark the following variables with VTV_PROTECTED_VAR.
+ These are either const or are only used for debugging/tracing.
+ debugging/tracing will not be ON on production environments */
+
+static const bool debug_hash = HASHTABLE_STATS;
+
+/* TODO: Make sure debugging messages under this guard dont use malloc! */
+static const int debug_functions = 0;
+static const int debug_init = 0;
+static const int debug_verify_vtable = 0;
+
+
+#ifdef VTV_DEBUG
+/* Global file descriptor variables for logging, tracing and debugging. */
+static int init_log_fd = -1;
+static int verify_vtable_log_fd = -1;
+
+/* This holds a formatted error logging message, to be written to the
+ vtable verify failures log. */
+static char debug_log_message[1024];
+#endif
+
+/* TODO: should this be under VTV_DEBUG? */
+static int vtv_failures_log_fd = -1;
+
+#if HASHTABLE_STATS
+static int set_log_fd = -1;
+#endif
+
+
+#ifdef __GTHREAD_MUTEX_INIT
+/* TODO: NEED TO PROTECT THIS VAR !!!!!!!!!!!!!!!!!!! */
+static __gthread_mutex_t change_permissions_lock = __GTHREAD_MUTEX_INIT;
+#else
+/* TODO: NEED TO PROTECT THIS VAR !!!!!!!!!!!!!!!!!!! */
+static __gthread_mutex_t change_permissions_lock;
+#endif
+
+/* Types needed by insert_only_hash_sets. */
+typedef uintptr_t int_vptr;
+
+/* The set of valid vtable pointers for each virtual class is stored
+ in a hash table. This is the hashing function used for the hash
+ table. For more information on the implementation of the hash
+ table, see the class insert_only_hash_sets in vtv_set.h. */
+
+struct vptr_hash
+ {
+ /* Hash function, used to convert vtable pointer, V, (a memory
+ address) into an index into the hash table. */
+ size_t
+ operator() (int_vptr v) const
+ {
+ const uint32_t x = 0x7a35e4d9;
+ const int shift = (sizeof (v) == 8) ? 23 : 21;
+ v = x * v;
+ return v ^ (v >> shift);
+ }
+ };
+
+/* This is the memory allocator used to create the hash table data
+ sets of valid vtable pointers. We use VTV_malloc in order to keep
+ track of which pages have been allocated, so we can update the
+ protections on those pages appropriately. See the class
+ insert_only_hash_sets in vtv_set.h for more information. */
+
+struct vptr_set_alloc
+ {
+ /* Memory allocator operator. N is the number of bytes to be
+ allocated. */
+ void *
+ operator() (size_t n) const
+ {
+ return VTV_malloc (n);
+ }
+ };
+
+/* Instantiate the template classes (in vtv_set.h) for our particular
+ hash table needs. */
+typedef insert_only_hash_sets<int_vptr, vptr_hash, vptr_set_alloc> vtv_sets;
+typedef vtv_sets::insert_only_hash_set vtv_set;
+typedef vtv_set * vtv_set_handle;
+typedef vtv_set_handle * vtv_set_handle_handle;
+
+/* Data structure passed to our dl_iterate_phdr callback function,
+ indicating whether mprotect should make the pages readonly or
+ read/write, and what page size to use. */
+
+struct mprotect_data
+ {
+ int prot_mode;
+ unsigned long page_size;
+ };
+
+/* Records for caching teh section header information that we have
+ read out of the file(s) on disk (in dl_iterate_phdr_callback), to
+ avoid having to re-open and re-read the same file multiple
+ times. */
+
+struct sect_hdr_data
+{
+ ElfW (Addr) dlpi_addr; /* The header address in the INFO record,
+ passed in from dl_iterate_phdr. */
+ ElfW (Addr) mp_low; /* Start address of the .vtable_map_vars
+ section in memory. */
+ size_t mp_size; /* Size of the .vtable_map_vars section in
+ memory. */
+};
+
+/* Array for caching the section header information, read from file,
+ to avoid re-opening and re-reading the same file over-and-over
+ again. */
+
+#define MAX_ENTRIES 250
+struct sect_hdr_data sect_info_cache[MAX_ENTRIES];
+
+unsigned int num_cache_entries = 0;
+
+/* This function takes the LOAD_ADDR for an object opened by the
+ dynamic loader, and checks the array of cached file data to see if
+ there is an entry with the same addres. If it finds such an entry,
+ it returns the record for that entry; otherwise it returns
+ NULL. */
+
+struct sect_hdr_data *
+search_cached_file_data (ElfW (Addr) load_addr)
+{
+ unsigned int i;
+ for (i = 0; i < num_cache_entries; ++i)
+ {
+ if (sect_info_cache[i].dlpi_addr == load_addr)
+ return &(sect_info_cache[i]);
+ }
+
+ return NULL;
+}
+
+/* This function tries to read COUNT bytes out of the file referred to
+ by FD into the buffer BUF. It returns the actual number of bytes
+ it succeeded in reading. */
+
+static ssize_t
+ReadPersistent (int fd, void *buf, size_t count)
+{
+ char *buf0 = (char *) buf;
+ size_t num_bytes = 0;
+ while (num_bytes < count)
+ {
+ int len;
+ len = read (fd, buf0 + num_bytes, count - num_bytes);
+ if (len < 0)
+ return -1;
+ if (len == 0)
+ break;
+ num_bytes += len;
+ }
+
+ return num_bytes;
+}
+
+/* This function tries to read COUNT bytes, starting at OFFSET from
+ the file referred to by FD, and put them into BUF. It calls
+ ReadPersistent to help it do so. It returns the actual number of
+ bytes read, or -1 if it fails altogether. */
+
+static ssize_t
+ReadFromOffset (int fd, void *buf, const size_t count, const off_t offset)
+{
+ off_t off = lseek (fd, offset, SEEK_SET);
+ if (off != (off_t) -1)
+ return ReadPersistent (fd, buf, count);
+ return -1;
+}
+
+/* The function takes a MESSAGE and attempts to write it to the vtable
+ memory protection log (for debugging purposes). If the file is not
+ open, it attempts to open the file first. Sometimes multiple
+ processes may be attempting to write to the log file at the same
+ time, so we may attempt to open multiple log files (with versioned
+ names) if the first open fails. */
+
+static void
+log_memory_protection_data (char *message)
+{
+ static int log_fd = -1;
+
+ if (log_fd == -1)
+ log_fd = vtv_open_log ("vtv_memory_protection_data.log");
+
+ vtv_add_to_log (log_fd, "%s", message);
+}
+
+/* This is the callback function used by dl_iterate_phdr (which is
+ called from VTV_unprotect_vtable_vars and VTV_protect_vtable_vars).
+ It attempts to find the binary file on disk for the INFO record
+ that dl_iterate_phdr passes in; open the binary file, and read its
+ section header information. If the file contains a
+ ".vtable_map_vars" section, read the section offset and size. Use
+ the secttion offset and size, in conjunction with the data in INFO
+ to locate the pages in memory where the section is. Call
+ 'mprotect' on those pages, setting the protection either to
+ read-only or read-write, depending on what's in DATA. */
+
+static int
+dl_iterate_phdr_callback (struct dl_phdr_info *info,
+ size_t unused __attribute__((__unused__)),
+ void *data)
+{
+ mprotect_data * mdata = (mprotect_data *) data;
+ off_t map_sect_offset = 0;
+ ElfW (Word) map_sect_len = 0;
+ ElfW (Addr) start_addr = 0;
+ struct sect_hdr_data *cached_data = NULL;
+ bool found = false;
+ char buffer[PATH_MAX];
+ char program_name[PATH_MAX];
+ char *cptr;
+ static bool first_time = true;
+ const ElfW (Phdr) *phdr_info = info->dlpi_phdr;
+ const ElfW (Ehdr) *ehdr_info =
+ (const ElfW (Ehdr) *) (info->dlpi_addr + info->dlpi_phdr[0].p_vaddr
+ - info->dlpi_phdr[0].p_offset);
+
+ /* Check to see if this is the record for the Linux Virtual Dynamic
+ Shared Object (linux-vdso.so.1), which exists only in memory (and
+ therefore cannot be read from disk). */
+
+ if (strcmp (info->dlpi_name, "linux-vdso.so.1") == 0)
+ return 0;
+
+ if (strlen (info->dlpi_name) == 0
+ && info->dlpi_addr != 0)
+ return 0;
+
+ if (first_time)
+ {
+ int i;
+ for (i = 0; i < MAX_ENTRIES; ++i)
+ {
+ sect_info_cache[i].dlpi_addr = (ElfW (Addr)) 0;
+ sect_info_cache[i].dlpi_addr = (ElfW (Addr)) 0;
+ sect_info_cache[i].dlpi_addr = 0;
+ }
+ first_time = false;
+ }
+
+ /* Get the name of the main executable. This may or may not include
+ arguments passed to the program. Find the first space, assume it
+ is the start of the argument list, and change it to a '\0'. */
+ snprintf (program_name, sizeof (program_name), program_invocation_name);
+
+ /* Check to see if we already have the data for this file. */
+ cached_data = search_cached_file_data (info->dlpi_addr);
+
+ if (cached_data)
+ {
+ /* We already read the section header data and calculated the
+ appropriate addresses; use the cached data to set the
+ appropriate protections and return. */
+ if (mprotect ((void *) cached_data->mp_low, cached_data->mp_size,
+ mdata->prot_mode) == -1)
+ {
+ if (debug_functions)
+ {
+ snprintf (buffer, sizeof (buffer),
+ "Failed called to mprotect for %s error: ",
+ (mdata->prot_mode & PROT_WRITE) ?
+ "READ/WRITE" : "READ-ONLY");
+ log_memory_protection_data (buffer);
+ perror(NULL);
+ }
+ VTV_error();
+ }
+ else if (debug_functions)
+ {
+ snprintf (buffer, sizeof (buffer),
+ "mprotect'ed range [%p, %p]\n",
+ (void *) cached_data->mp_low,
+ (char *) cached_data->mp_low + cached_data->mp_size);
+ log_memory_protection_data (buffer);
+ }
+ return 0;
+ }
+
+ /* Find the first non-escaped space in the program name and make it
+ the end of the string. */
+ cptr = strchr (program_name, ' ');
+ if (cptr != NULL && cptr[-1] != '\\')
+ cptr[0] = '\0';
+
+ if ((phdr_info->p_type == PT_PHDR || phdr_info->p_type == PT_LOAD)
+ && (ehdr_info->e_shoff && ehdr_info->e_shnum))
+ {
+ const char *map_sect_name = ".vtable_map_vars";
+ int name_len = strlen (map_sect_name);
+ int fd = -1;
+
+ /* Attempt to open the binary file on disk. */
+ if (strlen (info->dlpi_name) == 0)
+ {
+ /* If the constructor initialization function was put into
+ the preinit array, then this function will get called
+ while handling preinit array stuff, in which case
+ program_invocation_name has not been initialized. In
+ that case we can get the filename of the executable from
+ "/proc/self/exe". */
+ if (strlen (program_name) > 0)
+ {
+ if (phdr_info->p_type == PT_PHDR)
+ fd = open (program_name, O_RDONLY);
+ }
+ else
+ fd = open ("/proc/self/exe", O_RDONLY);
+ }
+ else
+ fd = open (info->dlpi_name, O_RDONLY);
+
+ /* VTV_ASSERT (fd != -1); */
+ if (fd != -1)
+ {
+
+ /* Find the section header information in the file. */
+ ElfW (Half) strtab_idx = ehdr_info->e_shstrndx;
+ ElfW (Shdr) shstrtab;
+ off_t shstrtab_offset = ehdr_info->e_shoff +
+ (ehdr_info->e_shentsize * strtab_idx);
+ size_t bytes_read = ReadFromOffset (fd, &shstrtab, sizeof (shstrtab),
+ shstrtab_offset);
+ VTV_ASSERT (bytes_read == sizeof (shstrtab));
+
+ ElfW (Shdr) sect_hdr;
+
+ /* Loop through all the section headers, looking for one whose
+ name is ".vtable_map_vars". */
+
+ for (int i = 0; i < ehdr_info->e_shnum && !found; ++i)
+ {
+ off_t offset = ehdr_info->e_shoff + (ehdr_info->e_shentsize * i);
+
+ bytes_read = ReadFromOffset (fd, &sect_hdr, sizeof (sect_hdr),
+ offset);
+
+ VTV_ASSERT (bytes_read == sizeof (sect_hdr));
+
+ char header_name[64];
+ off_t name_offset = shstrtab.sh_offset + sect_hdr.sh_name;
+
+ bytes_read = ReadFromOffset (fd, &header_name, 64, name_offset);
+
+ VTV_ASSERT (bytes_read > 0);
+
+ if (memcmp (header_name, map_sect_name, name_len) == 0)
+ {
+ /* We found the section; get its load offset and
+ size. */
+ map_sect_offset = sect_hdr.sh_addr;
+ map_sect_len = sect_hdr.sh_size - mdata->page_size;
+ found = true;
+ }
+ }
+ close (fd);
+
+ }
+ /* Calculate the start address of the section in memory. */
+ start_addr = (const ElfW (Addr)) info->dlpi_addr + map_sect_offset;
+ }
+
+ if (debug_functions)
+ {
+ snprintf (buffer, sizeof(buffer),
+ " Looking at load module %s to change permissions to %s\n",
+ ((strlen (info->dlpi_name) == 0) ? program_name
+ : info->dlpi_name),
+ (mdata->prot_mode & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY");
+ log_memory_protection_data (buffer);
+ }
+
+ /* See if we actually found the section. */
+ if (start_addr && map_sect_len)
+ {
+ ElfW (Addr) relocated_start_addr = start_addr;
+ ElfW (Word) size_in_memory = map_sect_len;
+
+ if ((relocated_start_addr != 0)
+ && (size_in_memory != 0))
+ {
+ /* Calculate the address & size to pass to mprotect. */
+ ElfW (Addr) mp_low = relocated_start_addr & ~(mdata->page_size - 1);
+ size_t mp_size = size_in_memory - 1;
+
+ if (debug_functions)
+ {
+ snprintf (buffer, sizeof (buffer),
+ " (%s): Protecting %p to %p\n",
+ ((strlen (info->dlpi_name) == 0) ? program_name
+ : info->dlpi_name),
+ (void *) mp_low,
+ ((void *) mp_low + mp_size));
+ log_memory_protection_data (buffer);
+ }
+
+ /* Change the protections on the pages for the section. */
+ if (mprotect ((void *) mp_low, mp_size, mdata->prot_mode) == -1)
+ {
+ if (debug_functions)
+ {
+ snprintf (buffer, sizeof (buffer),
+ "Failed called to mprotect for %s error: ",
+ (mdata->prot_mode & PROT_WRITE) ?
+ "READ/WRITE" : "READ-ONLY");
+ log_memory_protection_data (buffer);
+ perror(NULL);
+ }
+ VTV_error();
+ }
+ else if (debug_functions)
+ {
+ if (num_cache_entries < MAX_ENTRIES)
+ {
+ sect_info_cache[num_cache_entries].dlpi_addr =
+ info->dlpi_addr;
+ sect_info_cache[num_cache_entries].mp_low = mp_low;
+ sect_info_cache[num_cache_entries].mp_size = mp_size;
+ num_cache_entries++;
+ }
+ snprintf (buffer, sizeof (buffer),
+ "mprotect'ed range [%p, %p]\n",
+ (void *) mp_low, (char *) mp_low + mp_size);
+ log_memory_protection_data (buffer);
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* Unprotect all the vtable map vars and other side data that is used
+ to keep the core hash_map data. All of these data have been put
+ into relro sections */
+
+static void
+VTV_unprotect_vtable_vars (void)
+{
+ mprotect_data mdata;
+
+ mdata.prot_mode = PROT_READ | PROT_WRITE;
+ mdata.page_size = sysconf (_SC_PAGE_SIZE);
+ dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mdata);
+}
+
+/* Protect all the vtable map vars and other side data that is used
+ to keep the core hash_map data. All of these data have been put
+ into relro sections */
+
+static void
+VTV_protect_vtable_vars (void)
+{
+ mprotect_data mdata;
+
+ mdata.prot_mode = PROT_READ;
+ mdata.page_size = sysconf (_SC_PAGE_SIZE);
+ dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mdata);
+}
+
+#ifndef __GTHREAD_MUTEX_INIT
+static void
+initialize_change_permissions_mutexes ()
+{
+ __GTHREAD_MUTEX_INIT_FUNCTION (&change_permissions_lock);
+}
+#endif
+
+/* Variables needed for getting the statistics about the hashtable set. */
+#if HASHTABLE_STATS
+_AtomicStatCounter stat_contains = 0;
+_AtomicStatCounter stat_insert = 0;
+_AtomicStatCounter stat_resize = 0;
+_AtomicStatCounter stat_create = 0;
+_AtomicStatCounter stat_probes_in_non_trivial_set = 0;
+_AtomicStatCounter stat_contains_size0 = 0;
+_AtomicStatCounter stat_contains_size1 = 0;
+_AtomicStatCounter stat_contains_size2 = 0;
+_AtomicStatCounter stat_contains_size3 = 0;
+_AtomicStatCounter stat_contains_size4 = 0;
+_AtomicStatCounter stat_contains_size5 = 0;
+_AtomicStatCounter stat_contains_size6 = 0;
+_AtomicStatCounter stat_contains_size7 = 0;
+_AtomicStatCounter stat_contains_size8 = 0;
+_AtomicStatCounter stat_contains_size9 = 0;
+_AtomicStatCounter stat_contains_size10 = 0;
+_AtomicStatCounter stat_contains_size11 = 0;
+_AtomicStatCounter stat_contains_size12 = 0;
+_AtomicStatCounter stat_contains_size13_or_more = 0;
+_AtomicStatCounter stat_contains_sizes = 0;
+_AtomicStatCounter stat_grow_from_size0_to_1 = 0;
+_AtomicStatCounter stat_grow_from_size1_to_2 = 0;
+_AtomicStatCounter stat_double_the_number_of_buckets = 0;
+_AtomicStatCounter stat_insert_found_hash_collision = 0;
+_AtomicStatCounter stat_contains_in_non_trivial_set = 0;
+_AtomicStatCounter stat_insert_key_that_was_already_present = 0;
+#endif
+
+/* Record statistics about the hash table sets, for debugging. */
+
+static void
+log_set_stats (void)
+{
+#if HASHTABLE_STATS
+ if (set_log_fd == -1)
+ set_log_fd = vtv_open_log ("vtv_set_stats.log");
+
+ vtv_add_to_log (set_log_fd, "---\n%s\n",
+ insert_only_hash_tables_stats().c_str());
+#endif
+}
+
+/* Change the permissions on all the pages we have allocated for the
+ data sets and all the ".vtable_map_var" sections in memory (which
+ contain our vtable map variables). PERM indicates whether to make
+ the permissions read-only or read-write. */
+
+void
+__VLTChangePermission (int perm)
+{
+ if (debug_functions)
+ {
+ if (perm == __VLTP_READ_WRITE)
+ fprintf (stdout, "Changing VLT permisisons to Read-Write.\n");
+ else if (perm == __VLTP_READ_ONLY)
+ fprintf (stdout, "Changing VLT permissions to Read-only.\n");
+ else
+ fprintf (stdout, "Unrecognized permissions value: %d\n", perm);
+ }
+
+#ifndef __GTHREAD_MUTEX_INIT
+ static __gthread_once_t mutex_once VTV_PROTECTED_VAR = __GTHREAD_ONCE_INIT;
+
+ __gthread_once (&mutex_once, initialize_change_permissions_mutexes);
+#endif
+
+ /* Ordering of these unprotect/protect calls is very important.
+ You first need to unprotect all the map vars and side
+ structures before you do anything with the core data
+ structures (hash_maps) */
+
+ if (perm == __VLTP_READ_WRITE)
+ {
+ /* TODO: Meed to revisit this code for dlopen. It most probably
+ is not unlocking the protected vtable vars after for a load
+ module that is not the first load module. */
+ __gthread_mutex_lock (&change_permissions_lock);
+
+ VTV_unprotect_vtable_vars ();
+ VTV_malloc_init ();
+ VTV_malloc_unprotect ();
+
+ }
+ else if (perm == __VLTP_READ_ONLY)
+ {
+ if (debug_hash)
+ log_set_stats();
+
+ VTV_malloc_protect ();
+ VTV_protect_vtable_vars ();
+
+ __gthread_mutex_unlock (&change_permissions_lock);
+ }
+}
+
+/* This is the memory allocator used to create the hash table that
+ maps from vtable map variable name to the data set that vtable map
+ variable should point to. This is part of our vtable map variable
+ symbol resolution, which is necessary because the same vtable map
+ variable may be created by multiple compilation units and we need a
+ method to make sure that all vtable map variables for a particular
+ class point to the same data set at runtime. */
+
+struct insert_only_hash_map_allocator
+ {
+ /* N is the number of bytes to allocate. */
+ void *
+ alloc (size_t n) const
+ {
+ return VTV_malloc (n);
+ }
+
+ /* P points to the memory to be deallocated; N is the number of
+ bytes to deallocate. */
+ void
+ dealloc (void *p, size_t n __attribute__((__unused__))) const
+ {
+ VTV_free (p);
+ }
+ };
+
+/* Explicitly instantiate this class since this file is compiled with
+ -fno-implicit-templates. These are for the hash table that is used
+ to do vtable map variable symbol resolution. */
+template class insert_only_hash_map <vtv_set_handle *,
+ insert_only_hash_map_allocator >;
+typedef insert_only_hash_map <vtv_set_handle *,
+ insert_only_hash_map_allocator > s2s;
+typedef const s2s::key_type vtv_symbol_key;
+
+static s2s * vtv_symbol_unification_map VTV_PROTECTED_VAR = NULL;
+
+const unsigned long SET_HANDLE_HANDLE_BIT = 0x2;
+
+/* In the case where a vtable map variable is the only instance of the
+ variable we have seen, it points directly to the set of valid
+ vtable pointers. All subsequent instances of the 'same' vtable map
+ variable point to the first vtable map variable. This function,
+ given a vtable map variable PTR, checks a bit to see whether it's
+ pointing directly to the data set or to the first vtable map
+ variable. */
+
+static inline bool
+is_set_handle_handle (void * ptr)
+{
+ return ((unsigned long) ptr & SET_HANDLE_HANDLE_BIT)
+ == SET_HANDLE_HANDLE_BIT;
+}
+
+/* Returns the actual pointer value of a vtable map variable, PTR (see
+ comments for is_set_handle_handle for more details). */
+
+static inline vtv_set_handle *
+ptr_from_set_handle_handle (void * ptr)
+{
+ return (vtv_set_handle *) ((unsigned long) ptr & ~SET_HANDLE_HANDLE_BIT);
+}
+
+/* Given a vtable map variable, PTR, this function sets the bit that
+ says this is the second (or later) instance of a vtable map
+ variable. */
+
+static inline vtv_set_handle_handle
+set_handle_handle (vtv_set_handle * ptr)
+{
+ return (vtv_set_handle_handle) ((unsigned long) ptr | SET_HANDLE_HANDLE_BIT);
+}
+
+/* Open error logging file, if not already open, and write vtable
+ verification failure messages (LOG_MSG) to the log file. Also
+ generate a backtrace in the log file, if GENERATE_BACKTRACE is
+ set. */
+
+static void
+log_error_message (const char *log_msg, bool generate_backtrace)
+{
+ if (vtv_failures_log_fd == -1)
+ vtv_failures_log_fd = vtv_open_log ("vtable_verification_failures.log");
+
+ if (vtv_failures_log_fd == -1)
+ return;
+
+ vtv_add_to_log (vtv_failures_log_fd, "%s", log_msg);
+
+ if (generate_backtrace)
+ {
+#define STACK_DEPTH 20
+ void *callers[STACK_DEPTH];
+ int actual_depth = backtrace (callers, STACK_DEPTH);
+ backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd);
+ }
+}
+
+/* Ideally it would be nice if the library always provided the 2
+ versions of the runtime libraries. However, when we use VTV_DEBUG
+ we want to make sure that only the debug versions are being
+ used. We could change this once the code is more stable. */
+
+#ifdef VTV_DEBUG
+
+/* This routine initializes a set handle to a vtable set. It makes
+ sure that there is only one set handle for a particular set by
+ using a map from set name to pointer to set handle. Since there
+ will be multiple copies of the pointer to the set handle (one per
+ compilation unit that uses it), it makes sure to initialize all the
+ pointers to the set handle so that the set handle is unique. To
+ make this a little more efficient and avoid a level of indirection
+ in some cases, the first pointer to handle for a particular handle
+ becomes the handle itself and the other pointers will point to the
+ set handle. This is the debug version of this function, so it
+ outputs extra debugging messages and logging. SET_HANDLE_PTR is
+ the address of the vtable map variable, SET_SYMBOL_KEY is the hash
+ table key (containing the name of the map variable and the hash
+ value) and SIZE_HINT is a guess for the best initial size for the
+ set of vtable pointers that SET_HANDLE_POINTER will point to. */
+
+void __VLTInitSetSymbolDebug (void **set_handle_ptr,
+ const void *set_symbol_key,
+ size_t size_hint)
+{
+ VTV_DEBUG_ASSERT (set_handle_ptr);
+
+ if (vtv_symbol_unification_map == NULL)
+ {
+ /* TODO: For now we have chosen 1024, but we need to come up with a
+ better initial size for this. */
+ vtv_symbol_unification_map = s2s::create (1024);
+ VTV_DEBUG_ASSERT(vtv_symbol_unification_map);
+ }
+
+ vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
+
+ const s2s::value_type * map_value_ptr =
+ vtv_symbol_unification_map->get (symbol_key_ptr);
+ char buffer[200];
+ if (map_value_ptr == NULL)
+ {
+ if (*handle_ptr != NULL)
+ {
+ snprintf (buffer, sizeof(buffer),
+ "*** Found non-NULL local set ptr %p missing for symbol"
+ " %.*s",
+ *handle_ptr, symbol_key_ptr->n, symbol_key_ptr->bytes);
+ log_error_message (buffer, true);
+ VTV_DEBUG_ASSERT (0);
+ }
+ }
+ else if (*handle_ptr != NULL &&
+ (handle_ptr != *map_value_ptr &&
+ ptr_from_set_handle_handle (*handle_ptr) != *map_value_ptr))
+ {
+ VTV_DEBUG_ASSERT (*map_value_ptr != NULL);
+ snprintf (buffer, sizeof(buffer),
+ "*** Found diffence between local set ptr %p and set ptr %p"
+ "for symbol %.*s",
+ *handle_ptr, *map_value_ptr,
+ symbol_key_ptr->n, symbol_key_ptr->bytes);
+ log_error_message (buffer, true);
+ VTV_DEBUG_ASSERT (0);
+ }
+ else if (*handle_ptr == NULL)
+ {
+ /* Execution should not reach this point. */
+ }
+
+ if (*handle_ptr != NULL)
+ {
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+ vtv_sets::resize (size_hint, handle_ptr);
+ return;
+ }
+
+ VTV_DEBUG_ASSERT (*handle_ptr == NULL);
+ if (map_value_ptr != NULL)
+ {
+ if (*map_value_ptr == handle_ptr)
+ vtv_sets::resize (size_hint, *map_value_ptr);
+ else
+ {
+ /* The one level handle to the set already exists. So, we
+ are adding one level of indirection here and we will
+ store a pointer to the one level handle here. */
+
+ vtv_set_handle_handle * handle_handle_ptr =
+ (vtv_set_handle_handle *)handle_ptr;
+ *handle_handle_ptr = set_handle_handle(*map_value_ptr);
+ VTV_DEBUG_ASSERT(*handle_handle_ptr != NULL);
+
+ /* The handle can itself be NULL if the set has only
+ been initiazlied with size hint == 1. */
+ vtv_sets::resize (size_hint, *map_value_ptr);
+ }
+ }
+ else
+ {
+ /* We will create a new set. So, in this case handle_ptr is the
+ one level pointer to the set handle. Create copy of map name
+ in case the memory where this comes from gets unmapped by
+ dlclose. */
+ size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
+ void *map_key = VTV_malloc (map_key_len);
+
+ memcpy (map_key, symbol_key_ptr, map_key_len);
+
+ s2s::value_type *value_ptr;
+ vtv_symbol_unification_map =
+ vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
+ &value_ptr);
+ *value_ptr = handle_ptr;
+
+ /* TODO: We should verify the return value. */
+ vtv_sets::create (size_hint, handle_ptr);
+ VTV_DEBUG_ASSERT (size_hint <= 1 || *handle_ptr != NULL);
+ }
+
+ if (debug_init)
+ {
+ if (init_log_fd == -1)
+ init_log_fd = vtv_open_log ("vtv_init.log");
+
+ vtv_add_to_log (init_log_fd,
+ "Init handle:%p for symbol:%.*s hash:%u size_hint:%lu"
+ "number of symbols:%lu \n",
+ set_handle_ptr, symbol_key_ptr->n,
+ symbol_key_ptr->bytes, symbol_key_ptr->hash, size_hint,
+ vtv_symbol_unification_map->size ());
+ }
+}
+
+/* This function takes a the address of a vtable map variable
+ (SET_HANDLE_PTR), a VTABLE_PTR to add to the data set, the name of
+ the vtable map variable (SET_SYMBOL_NAME) and the name of the
+ vtable (VTABLE_NAME) being pointed to. If the vtable map variable
+ is NULL it creates a new data set and initializes the variable,
+ otherwise it uses our symbol unification to find the right data
+ set; in either case it then adds the vtable pointer to the set.
+ The other two parameters are used for debugging information. */
+
+void
+__VLTRegisterPairDebug (void **set_handle_ptr, const void *vtable_ptr,
+ const char *set_symbol_name, const char *vtable_name)
+
+{
+ VTV_DEBUG_ASSERT(set_handle_ptr != NULL);
+ /* set_handle_ptr can be NULL if the call to InitSetSymbol had a
+ size hint of 1. */
+
+ int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+ VTV_DEBUG_ASSERT (vtv_symbol_unification_map != NULL);
+ vtv_set_handle *handle_ptr;
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+ /* TODO: We should verify the return value. */
+ vtv_sets::insert (vtbl_ptr, handle_ptr);
+
+ if (debug_init)
+ {
+ if (init_log_fd == -1)
+ init_log_fd = vtv_open_log("vtv_init.log");
+
+ vtv_add_to_log(init_log_fd,
+ "Registered %s : %s (%p) 2 level deref = %s\n",
+ set_symbol_name, vtable_name, vtbl_ptr,
+ is_set_handle_handle(*set_handle_ptr) ? "yes" : "no" );
+ }
+}
+
+/* This function is called from __VLTVerifyVtablePointerDebug; it
+ sends as much debugging information as it can to the error log
+ file, then calls __vtv_verify_fail. SET_HANDLE_PTR is the pointer
+ to the set of valid vtable pointers, VTBL_PTR is the pointer that
+ was not found in the set, and DEBUG_MSG is the message to be
+ written to the log file before failing. n */
+
+static void
+__vtv_verify_fail_debug (void **set_handle_ptr, const void *vtbl_ptr,
+ const char *debug_msg)
+{
+ log_error_message (debug_msg, false);
+
+ /* Call the public interface in case it has been overwritten by
+ user. */
+ __vtv_verify_fail (set_handle_ptr, vtbl_ptr);
+
+ log_error_message ("Returned from __vtv_verify_fail."
+ " Secondary verification succeeded.\n", false);
+}
+
+#ifndef VTV_STATIC_VERIFY
+
+/* This is the debug version of the verification function. It takes
+ the address of a vtable map variable (SET_HANDLE_PTR) and a
+ VTABLE_PTR to validate, as well as the name of the vtable map
+ variable (SET_SYMBOL_NAME) and VTABLE_NAME, which are used for
+ debugging messages. It checks to see if VTABLE_PTR is in the set
+ pointed to by SET_HANDLE_PTR. If so, it returns VTABLE_PTR,
+ otherwise it calls __vtv_verify_fail, which usually logs error
+ messages and calls abort. */
+
+const void *
+__VLTVerifyVtablePointerDebug (void **set_handle_ptr, const void *vtable_ptr,
+ const char *set_symbol_name,
+ const char *vtable_name)
+{
+#ifndef VTV_EMPTY_VERIFY
+ VTV_DEBUG_ASSERT (set_handle_ptr != NULL && *set_handle_ptr != NULL);
+ int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+ vtv_set_handle *handle_ptr;
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+ if (vtv_sets::contains (vtbl_ptr, handle_ptr))
+ {
+ if (debug_verify_vtable)
+ {
+ if (verify_vtable_log_fd == -1)
+ vtv_open_log ("vtv_verify_vtable.log");
+ vtv_add_to_log (verify_vtable_log_fd,
+ "Verified %s %s value = %p\n",
+ set_symbol_name, vtable_name, vtable_ptr);
+ }
+ }
+ else
+ {
+ /* We failed to find the vtable pointer in the set of valid
+ pointers. Log the error data and call the failure
+ function. */
+ snprintf (debug_log_message, sizeof (debug_log_message),
+ "Looking for %s in %s\n", vtable_name, set_symbol_name);
+ __vtv_verify_fail_debug (set_handle_ptr, vtable_ptr, debug_log_message);
+
+ /* Normally __vtv_verify_fail_debug will call abort, so we won't
+ execute the return below. If we get this far, the assumption
+ is that the programmer has replaced __vtv_verify_fail_debug
+ with some kind of secondary verification AND this secondary
+ verification succeeded, so the vtable pointer is valid. */
+ }
+#endif /* ifndef VTV_EMPTY_VERIFY*/
+
+ return vtable_ptr;
+}
+
+#endif /* ifndef VTV_STATIC_VERIFY */
+
+#else /* ifdef VTV_DEBUG */
+
+/* This routine initializes a set handle to a vtable set. It makes
+ sure that there is only one set handle for a particular set by
+ using a map from set name to pointer to set handle. Since there
+ will be multiple copies of the pointer to the set handle (one per
+ compilation unit that uses it), it makes sure to initialize all the
+ pointers to the set handle so that the set handle is unique. To
+ make this a little more efficient and avoid a level of indirection
+ in some cases, the first pointer to handle for a particular handle
+ becomes the handle itself and the other pointers will point to the
+ set handle. SET_HANDLE_PTR is the address of the vtable map
+ variable, SET_SYMBOL_KEY is the hash table key (containing the name
+ of the map variable and the hash value) and SIZE_HINT is a guess
+ for the best initial size for the set of vtable pointers that
+ SET_HANDLE_POINTER will point to.*/
+
+void __VLTInitSetSymbol (void **set_handle_ptr, const void *set_symbol_key,
+ size_t size_hint)
+{
+ vtv_set_handle *handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ if (*handle_ptr != NULL)
+ {
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+ vtv_sets::resize (size_hint, handle_ptr);
+ return;
+ }
+
+ if (vtv_symbol_unification_map == NULL)
+ vtv_symbol_unification_map = s2s::create (1024);
+
+ vtv_symbol_key *symbol_key_ptr = (vtv_symbol_key *) set_symbol_key;
+ const s2s::value_type *map_value_ptr =
+ vtv_symbol_unification_map->get (symbol_key_ptr);
+
+ if (map_value_ptr != NULL)
+ {
+ if (*map_value_ptr == handle_ptr)
+ vtv_sets::resize (size_hint, *map_value_ptr);
+ else
+ {
+ /* The one level handle to the set already exists. So, we
+ are adding one level of indirection here and we will
+ store a pointer to the one level pointer here. */
+ vtv_set_handle_handle *handle_handle_ptr =
+ (vtv_set_handle_handle *) handle_ptr;
+ *handle_handle_ptr = set_handle_handle (*map_value_ptr);
+ vtv_sets::resize (size_hint, *map_value_ptr);
+ }
+ }
+ else
+ {
+ /* We will create a new set. So, in this case handle_ptr is the
+ one level pointer to the set handle. Create copy of map name
+ in case the memory where this comes from gets unmapped by
+ dlclose. */
+ size_t map_key_len = symbol_key_ptr->n + sizeof (vtv_symbol_key);
+ void * map_key = VTV_malloc (map_key_len);
+ memcpy (map_key, symbol_key_ptr, map_key_len);
+
+ s2s::value_type * value_ptr;
+ vtv_symbol_unification_map =
+ vtv_symbol_unification_map->find_or_add_key ((vtv_symbol_key *)map_key,
+ &value_ptr);
+
+ *value_ptr = handle_ptr;
+
+ /* TODO: We should verify the return value. */
+ vtv_sets::create (size_hint, handle_ptr);
+ }
+}
+
+/* This function takes a the address of a vtable map variable
+ (SET_HANDLE_PTR) and a VTABLE_PTR. If the vtable map variable is
+ NULL it creates a new data set and initializes the variable,
+ otherwise it uses our symbol unification to find the right data
+ set; in either case it then adds the vtable pointer to the set. */
+
+void
+__VLTRegisterPair (void **set_handle_ptr, const void *vtable_ptr)
+{
+ int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+ vtv_set_handle *handle_ptr;
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+ /* TODO: We should verify the return value. */
+ vtv_sets::insert (vtbl_ptr, handle_ptr);
+}
+
+#ifndef VTV_STATIC_VERIFY
+
+/* This is the main verification function. It takes the address of a
+ vtable map variable (SET_HANDLE_PTR) and a VTABLE_PTR to validate.
+ It checks to see if VTABLE_PTR is in the set pointed to by
+ SET_HANDLE_PTR. If so, it returns VTABLE_PTR, otherwise it calls
+ __vtv_verify_fail, which usually logs error messages and calls
+ abort. Since this function gets called VERY frequently, it is
+ important for it to be as efficient as possible. */
+
+const void *
+__VLTVerifyVtablePointer (void ** set_handle_ptr, const void * vtable_ptr)
+{
+#ifndef VTV_EMPTY_VERIFY
+ int_vptr vtbl_ptr = (int_vptr) vtable_ptr;
+
+ vtv_set_handle *handle_ptr;
+ if (!is_set_handle_handle (*set_handle_ptr))
+ handle_ptr = (vtv_set_handle *) set_handle_ptr;
+ else
+ handle_ptr = ptr_from_set_handle_handle (*set_handle_ptr);
+
+ if (!vtv_sets::contains (vtbl_ptr, handle_ptr))
+ {
+ __vtv_verify_fail ((void **) handle_ptr, vtable_ptr);
+ /* Normally __vtv_verify_fail will call abort, so we won't
+ execute the return below. If we get this far, the assumption
+ is that the programmer has replaced __vtv_verify_fail with
+ some kind of secondary verification AND this secondary
+ verification succeeded, so the vtable pointer is valid. */
+ }
+#endif /* ifndef VTV_EMPTY_VERIFY */
+
+ return vtable_ptr;
+}
+
+#endif /* ifndef VTV_STATIC_VERIFY */
+
+#endif /* else-clause of ifdef VTV_DEBUG */
+
+/* This function calls __fortify_fail with a FAILURE_MSG and then
+ calls abort. */
+
+void
+__vtv_really_fail (const char *failure_msg)
+{
+ __fortify_fail (failure_msg);
+
+ /* We should never get this far; __fortify_fail calls __libc_message
+ which prints out a back trace and a memory dump and then is
+ supposed to call abort, but let's play it safe anyway and call abort
+ ourselves. */
+ abort ();
+}
+
+/* This function takes an error MSG, a vtable map variable
+ (DATA_SET_PTR) and a vtable pointer (VTBL_PTR). It is called when
+ an attempt to verify VTBL_PTR with the set pointed to by
+ DATA_SET_PTR failed. It outputs a failure message with the
+ addresses involved, and calls __vtv_really_fail. */
+
+static void
+vtv_fail (const char *msg, void **data_set_ptr, const void *vtbl_ptr)
+{
+ char buffer[128];
+ int buf_len;
+ const char *format_str =
+ "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
+
+ snprintf (buffer, sizeof (buffer), format_str, vtbl_ptr,
+ is_set_handle_handle(*data_set_ptr) ?
+ ptr_from_set_handle_handle (*data_set_ptr) :
+ *data_set_ptr);
+ buf_len = strlen (buffer);
+ /* Send this to to stderr. */
+ write (2, buffer, buf_len);
+
+#ifndef VTV_NO_ABORT
+ __vtv_really_fail (msg);
+#endif
+}
+
+/* Send information about what we were trying to do when verification
+ failed to the error log, then call vtv_fail. This function can be
+ overwritten/replaced by the user, to implement a secondary
+ verification function instead. DATA_SET_PTR is the vtable map
+ variable used for the failed verification, and VTBL_PTR is the
+ vtable pointer that was not found in the set. */
+
+void
+__vtv_verify_fail (void **data_set_ptr, const void *vtbl_ptr)
+{
+ char log_msg[256];
+ snprintf (log_msg, sizeof (log_msg), "Looking for vtable %p in set %p.\n",
+ vtbl_ptr,
+ is_set_handle_handle (*data_set_ptr) ?
+ ptr_from_set_handle_handle (*data_set_ptr) :
+ *data_set_ptr);
+ log_error_message (log_msg, false);
+
+ const char *format_str =
+ "*** Unable to verify vtable pointer (%p) in set (%p) *** \n";
+ snprintf (log_msg, sizeof (log_msg), format_str, vtbl_ptr, *data_set_ptr);
+ log_error_message (log_msg, false);
+ log_error_message (" Backtrace: \n", true);
+
+ const char *fail_msg = "Potential vtable pointer corruption detected!!\n";
+ vtv_fail (fail_msg, data_set_ptr, vtbl_ptr);
+}
diff --git a/libstdc++-v3/libsupc++/vtv_rts.h b/libstdc++-v3/libsupc++/vtv_rts.h
new file mode 100644
index 00000000000..4409d7a52c0
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_rts.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VTV_RTS_H
+#define _VTV_RTS_H 1
+
+#include <cstdlib>
+
+/* This prototype needs to be kept in sync with the compiler-
+ generated declaration in vtable-class-hierarchy.c. */
+
+/* We could have used an enumeration here but it just makes it more
+ difficult for the compiler to generate a call to this. */
+#define __VLTP_READ_ONLY 0
+#define __VLTP_READ_WRITE 1
+
+extern void __VLTChangePermission (int);
+
+#ifdef VTV_DEBUG
+
+extern void __VLTInitSetSymbolDebug (void **, const void *, std::size_t);
+extern void __VLTRegisterPairDebug (void **, const void *, const char *,
+ const char *);
+extern const void *__VLTVerifyVtablePointerDebug (void **, const void *,
+ const char *, const char *);
+
+#else
+
+extern void __VLTRegisterPair (void **, const void *);
+extern const void *__VLTVerifyVtablePointer (void **, const void *);
+extern void __VLTInitSetSymbol (void **, const void *, std::size_t );
+
+#endif
+
+#endif /* _VTV_RTS_H */
diff --git a/libstdc++-v3/libsupc++/vtv_set.h b/libstdc++-v3/libsupc++/vtv_set.h
new file mode 100644
index 00000000000..81bbba3fbe4
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_set.h
@@ -0,0 +1,652 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License
+ and a copy of the GCC Runtime Library Exception along with this
+ program; see the files COPYING3 and COPYING.RUNTIME respectively.
+ If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _VTV_SET_H
+#define _VTV_SET_H 1
+
+/* Code in this file manages a collection of insert-only sets. We
+ have only tested the case where Key is uintptr_t, though it
+ theoretically should work for some other cases. All odd keys are
+ reserved, and must not be inserted into any of the sets. This code
+ is intended primarily for sets of pointers, and the code is
+ optimized for small sets (including size 0 and 1), but regardless
+ of the set size, insert() and contains() have close to O(1) speed
+ in practice.
+
+ TODO(gpike): fix this comment.
+
+ Recommended multithreaded use of a set:
+
+ For speed, we want to use a lock-free test for set membership. The
+ code handles simultaneous reads and inserts, as long as at most one
+ insertion is in progress at a time. After an insert, other threads
+ may not immediately "see" the inserted key if they perform a
+ lock-free read, so we recommend retrying, as explained below.
+
+ Also, to make data corruption less likely, we recommend using a
+ "normal" RW page as well as one or pages that are typically RO
+ but that can be switched to RW and back as needed. The latter
+ pages should contain sets. The former should contain a lock, L,
+ and an int or similar, num_writers. Then, to insert, something
+ like this would be safe:
+ o Acquire L.
+ o Increment num_writers; if that made it 1, change pages to RW.
+ o Release L.
+ o while (there are insertions to do in some set, S) {
+ acquire L;
+ do some insertions in S;
+ release L;
+ }
+ o Acquire L.
+ o Decrement num_writers; if that made it 0, change pages to RO.
+ o Release L.
+
+ And to check if the set contains some key, one could use
+ set.contains(key) ||
+ ({ Acquire L; bool b = set.contains(key); Release L; b; })
+
+ In this scheme, the number of threads with reads in progress isn't
+ tracked, so old sets can never be deleted. In addition, on some
+ architectures the intentionally racy reads might cause contains()
+ to return true when it should have returned false. This should be
+ no problem on x86, and most other machines, where reading or
+ writing an aligned uintptr_t is atomic. E.g., on those machines,
+ if *p is 0 and one thread does *p = x while another reads *p, the
+ read will see either 0 or x.
+
+ To make the above easier, the insert_only_hash_sets class provides
+ an interface to manipulate any number of hash sets. One shouldn't
+ create objects of that class, as it has no member data and its
+ methods are static.
+
+ So the recommended model is to have a single lock, a single
+ num_writers variable, and some number of sets. If lock contention
+ becomes a problem then the sets can be divided into k groups, each
+ of which has a lock and a num_writers variable; or each set can be
+ represented as a set of values that equal 0 mod m, a set of values
+ that equal 1 mod m, ..., plus a set of values that equal m-1 mod m.
+
+ However, we expect most or all uses of this code to call contains()
+ much more frequently than anything else, so lock contention is
+ likely to be low. */
+
+#include <algorithm>
+
+#ifndef HASHTABLE_STATS
+#define HASHTABLE_STATS 0
+#endif
+
+#ifndef HASHTABLE_STATS_ATOMIC
+#define HASHTABLE_STATS_ATOMIC 0
+#endif
+
+#if HASHTABLE_STATS
+#if HASHTABLE_STATS_ATOMIC
+/* Stat counters, with atomics. */
+#include <bits/atomic_word.h>
+
+typedef _Atomic_word _AtomicStatCounter;
+
+void
+inc_by (_AtomicStatCounter &stat, int amount)
+{
+ __atomic_add_fetch (&stat, amount, __ATOMIC_ACQ_REL);
+}
+
+#else
+
+/* Stat counters, but without atomics. */
+typedef int _AtomicStatCounter;
+
+void
+inc_by (_AtomicStatCounter& stat, int amount)
+{
+ stat += amount;
+}
+
+#endif
+
+
+/* Number of calls to contains(), insert(), etc. */
+extern _AtomicStatCounter stat_insert;
+extern _AtomicStatCounter stat_contains;
+extern _AtomicStatCounter stat_resize;
+extern _AtomicStatCounter stat_create;
+
+/* Sum of set size over all calls to contains(). */
+extern _AtomicStatCounter stat_contains_sizes;
+
+/* contains() calls in a set whose capacity is more than 1. */
+extern _AtomicStatCounter stat_contains_in_non_trivial_set;
+
+/* Probes in a set whose capacity is more than 1. Ideally, this will
+ be pretty close to stat_contains_in_non_trivial_set. That will
+ happen if our hash function is good and/or important keys were
+ inserted before unimportant keys. */
+extern _AtomicStatCounter stat_probes_in_non_trivial_set;
+
+/* number of calls to contains() with size=0, 1, etc. */
+extern _AtomicStatCounter stat_contains_size0;
+extern _AtomicStatCounter stat_contains_size1;
+extern _AtomicStatCounter stat_contains_size2;
+extern _AtomicStatCounter stat_contains_size3;
+extern _AtomicStatCounter stat_contains_size4;
+extern _AtomicStatCounter stat_contains_size5;
+extern _AtomicStatCounter stat_contains_size6;
+extern _AtomicStatCounter stat_contains_size7;
+extern _AtomicStatCounter stat_contains_size8;
+extern _AtomicStatCounter stat_contains_size9;
+extern _AtomicStatCounter stat_contains_size10;
+extern _AtomicStatCounter stat_contains_size11;
+extern _AtomicStatCounter stat_contains_size12;
+extern _AtomicStatCounter stat_contains_size13_or_more;
+extern _AtomicStatCounter stat_grow_from_size0_to_1;
+extern _AtomicStatCounter stat_grow_from_size1_to_2;
+extern _AtomicStatCounter stat_double_the_number_of_buckets;
+extern _AtomicStatCounter stat_insert_key_that_was_already_present;
+
+/* Hash collisions detected during insert_no_resize(). Only counts
+ hasher(k) == hasher(k'); hasher(k) % tablesize == hasher(k') %
+ tablesize is not sufficient. Will count collisions that are
+ detected during table resizes etc., so the same two keys may add to
+ this stat multiple times. */
+extern _AtomicStatCounter stat_insert_found_hash_collision;
+
+#include <string>
+
+struct insert_only_hash_sets_logger
+{
+ static char *
+ log (char c, char *buf)
+ {
+ *buf++ = c;
+ return buf;
+ }
+
+ static char *
+ log (const char *s, char *buf)
+ { return strcpy (buf, s) + strlen (s); }
+
+ static char *
+ log (_AtomicStatCounter i, char *buf)
+ {
+ if (i < 10)
+ return log ((char) ('0' + i), buf);
+ else
+ return log ((char) ('0' + i % 10), log (i / 10, buf));
+ }
+
+ static char *
+ log (const char *label, _AtomicStatCounter i, char *buf)
+ {
+ buf = log (label, buf);
+ buf = log (": ", buf);
+ buf = log (i, buf);
+ return log ('\n', buf);
+ }
+};
+
+// Write stats to the given buffer, which should be at least 4000 bytes.
+static inline void
+insert_only_hash_tables_stats (char *buf)
+{
+ buf = insert_only_hash_sets_logger::log ("insert", stat_insert, buf);
+ buf = insert_only_hash_sets_logger::log ("contains", stat_contains, buf);
+ buf = insert_only_hash_sets_logger::log ("resize", stat_resize, buf);
+ buf = insert_only_hash_sets_logger::log ("create", stat_create, buf);
+ buf = insert_only_hash_sets_logger::log ("insert_key_that_was_already_"
+ "present",
+ stat_insert_key_that_was_already_present,
+ buf);
+ buf = insert_only_hash_sets_logger::log ("contains_sizes",
+ stat_contains_sizes, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_in_non_trivial_set",
+ stat_contains_in_non_trivial_set,
+ buf);
+ buf = insert_only_hash_sets_logger::log ("probes_in_non_trivial_set",
+ stat_probes_in_non_trivial_set,
+ buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size0",
+ stat_contains_size0, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size1",
+ stat_contains_size1, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size2",
+ stat_contains_size2, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size3",
+ stat_contains_size3, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size4",
+ stat_contains_size4, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size5",
+ stat_contains_size5, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size6",
+ stat_contains_size6, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size7",
+ stat_contains_size7, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size8",
+ stat_contains_size8, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size9",
+ stat_contains_size9, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size10",
+ stat_contains_size10, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size11",
+ stat_contains_size11, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size12",
+ stat_contains_size12, buf);
+ buf = insert_only_hash_sets_logger::log ("contains_size13_or_more",
+ stat_contains_size13_or_more, buf);
+ buf = insert_only_hash_sets_logger::log ("grow_from_size0_to_1",
+ stat_grow_from_size0_to_1, buf);
+ buf = insert_only_hash_sets_logger::log ("grow_from_size1_to_2",
+ stat_grow_from_size1_to_2, buf);
+ buf = insert_only_hash_sets_logger::log ("insert_found_hash_collision",
+ stat_insert_found_hash_collision,
+ buf);
+ buf = insert_only_hash_sets_logger::log ("double_the_number_of_buckets",
+ stat_double_the_number_of_buckets,
+ buf);
+ *buf = '\0';
+}
+
+#else
+
+/* No stats. */
+#define inc_by(statname, amount) do { } while (false && (amount))
+
+#endif
+
+#define inc(statname) inc_by (statname, 1)
+
+template <typename Key, class HashFcn, class Alloc>
+class insert_only_hash_sets
+{
+ public:
+ typedef Key key_type;
+ typedef size_t size_type;
+ typedef Alloc alloc_type;
+ enum { illegal_key = 1 };
+ enum { min_capacity = 4 };
+#if HASHTABLE_STATS
+ enum { stats = true };
+#else
+ enum { stats = false };
+#endif
+
+ /* Do not directly use insert_only_hash_set. Instead, use the
+ static methods below to create and manipulate objects of the
+ following class.
+
+ Implementation details: each set is represented by a pointer
+ plus, perhaps, out-of-line data, which would be an object of type
+ insert_only_hash_set. For a pointer, s, the interpretation is: s
+ == NULL means empty set, lsb(s) == 1 means a set with one
+ element, which is (uintptr_t)s - 1, and otherwise s is a pointer
+ of type insert_only_hash_set*. So, to increase the size of a set
+ we have to change s and/or *s. To check if a set contains some
+ key we have to examine s and possibly *s. */
+ class insert_only_hash_set
+ {
+ public:
+ /* Insert a key. The key must not be a reserved key. */
+ static inline insert_only_hash_set *insert (key_type key,
+ insert_only_hash_set *s);
+
+
+ /* Create an empty set. */
+ static inline insert_only_hash_set *create (size_type capacity);
+
+ /* Return whether the given key is present. If key is illegal_key
+ then either true or false may be returned, but for all other
+ reserved keys false will be returned. */
+ static bool
+ contains (key_type key, const insert_only_hash_set *s)
+ {
+ if (stats)
+ {
+ inc (stat_contains);
+ switch (size (s))
+ {
+ case 0: inc (stat_contains_size0); break;
+ case 1: inc (stat_contains_size1); break;
+ case 2: inc (stat_contains_size2); break;
+ case 3: inc (stat_contains_size3); break;
+ case 4: inc (stat_contains_size4); break;
+ case 5: inc (stat_contains_size5); break;
+ case 6: inc (stat_contains_size6); break;
+ case 7: inc (stat_contains_size7); break;
+ case 8: inc (stat_contains_size8); break;
+ case 9: inc (stat_contains_size9); break;
+ case 10: inc (stat_contains_size10); break;
+ case 11: inc (stat_contains_size11); break;
+ case 12: inc (stat_contains_size12); break;
+ default: inc (stat_contains_size13_or_more); break;
+ }
+ inc_by (stat_contains_sizes, size (s));
+ }
+
+ return (singleton (s) ?
+ singleton_key (key) == s :
+ ((s != NULL) && s->contains (key)));
+ }
+
+ /* Return a set's size. */
+ static size_type
+ size (const insert_only_hash_set *s)
+ { return (s == NULL) ? 0 : (singleton (s) ? 1 : s->num_entries); }
+
+ static inline insert_only_hash_set *resize (size_type target_num_buckets,
+ insert_only_hash_set *s);
+
+
+ private:
+ /* Return whether a set has size 1. */
+ static bool
+ singleton (const insert_only_hash_set *s)
+ { return (uintptr_t) s & 1; }
+
+ /* Return the representation of a singleton set containing the
+ given key. */
+ static insert_only_hash_set *
+ singleton_key (key_type key)
+ { return (insert_only_hash_set *) ((uintptr_t) key + 1); }
+
+ /* Given a singleton set, what key does it contain? */
+ static key_type
+ extract_singleton_key (const insert_only_hash_set *s)
+ {
+ VTV_DEBUG_ASSERT (singleton (s));
+ return (key_type) ((uintptr_t) s - 1);
+ }
+
+ volatile key_type &
+ key_at_index (size_type index)
+ { return buckets[index]; }
+
+ key_type
+ key_at_index (size_type index) const
+ { return buckets[index]; }
+
+ size_type
+ next_index (size_type index, size_type indices_examined) const
+ { return (index + indices_examined) & (num_buckets - 1); }
+
+ inline void insert_no_resize (key_type key);
+
+ inline bool contains (key_type key) const;
+
+ inline insert_only_hash_set *resize_if_necessary (void);
+
+ size_type num_buckets; /* Must be a power of 2 not less than
+ min_capacity. */
+ volatile size_type num_entries;
+ volatile key_type buckets[0]; /* Actual array size is num_buckets. */
+ };
+
+ /* Create an empty set with the given capacity. Requires that n be
+ 0 or a power of 2. If 1 < n < min_capacity then treat n as
+ min_capacity. Sets *handle. Returns true unless the allocator
+ fails. Subsequent operations on this set should use the same
+ handle. */
+
+ static inline bool create (size_type n, insert_only_hash_set **handle);
+
+ /* Force the capacity of a set to be n, unless it was more than n
+ already. Requires that n be 0 or a power of 2. Sets *handle
+ unless the current capacity is n or more. Returns true unless
+ the allocator fails. */
+
+ static inline bool resize (size_type n, insert_only_hash_set **handle);
+
+ /* Insert a key. *handle is unmodified unless (1) a resize occurs,
+ or (2) the set was initially empty. Returns true unless the
+ allocator fails during a resize. If the allocator fails during a
+ resize then the set is reset to be the empty set. The key must
+ not be a reserved key. */
+
+ static inline bool insert (key_type key, insert_only_hash_set **handle);
+
+ /* Check for the presence of a key. If key is illegal_key then
+ either true or false may be returned, but for all other reserved
+ keys false will be returned. */
+
+ static inline bool
+ contains (key_type key, /* const */ insert_only_hash_set **handle)
+ { return insert_only_hash_set::contains (key, *handle); }
+
+ /* Return the size of the given set. */
+ static size_type
+ size (const insert_only_hash_set **handle)
+ { return insert_only_hash_set::size (*handle); }
+
+ static bool
+ is_reserved_key (key_type key)
+ { return ((uintptr_t) key % 2) == 1; }
+};
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::resize
+ (size_type n, insert_only_hash_set *s)
+{
+ if (s == NULL)
+ return create (n);
+
+ size_type capacity = singleton (s) ? 1 : s->num_buckets;
+
+ if (n <= capacity)
+ return s;
+
+ insert_only_hash_set *result =
+ create (std::max<size_type> (n, min_capacity));
+ if (result != NULL)
+ {
+ if (singleton (s))
+ {
+ result->insert_no_resize (extract_singleton_key (s));
+ }
+ else
+ {
+ for (size_type i = 0; i < s->num_buckets; i++)
+ if (s->buckets[i] != (key_type) illegal_key)
+ result->insert_no_resize (s->buckets[i]);
+ }
+ VTV_DEBUG_ASSERT (size (result) == size (s));
+ }
+ return result;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::insert
+ (key_type key, insert_only_hash_set *s)
+{
+ VTV_DEBUG_ASSERT (!is_reserved_key (key));
+ inc_by (stat_grow_from_size0_to_1, s == NULL);
+
+ if (s == NULL)
+ return singleton_key (key);
+
+ if (singleton (s))
+ {
+ const key_type old_key = extract_singleton_key (s);
+ if (old_key == key)
+ return s;
+
+ /* Grow from size 1 to size 2. */
+ inc (stat_grow_from_size1_to_2);
+ s = create (2);
+ if (s == NULL)
+ return NULL;
+
+ s->insert_no_resize (old_key);
+ s->insert_no_resize (key);
+ VTV_DEBUG_ASSERT (size (s) == 2);
+ return s;
+ }
+ s = s->resize_if_necessary();
+ if (s != NULL)
+ s->insert_no_resize (key);
+ return s;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::create
+ (size_type capacity)
+{
+ if (capacity <= 1)
+ return NULL;
+
+ VTV_DEBUG_ASSERT (capacity > 1 && (capacity & (capacity - 1)) == 0);
+ VTV_DEBUG_ASSERT (sizeof (insert_only_hash_set) == 2 * sizeof (size_type));
+ capacity = std::max <size_type> (capacity, min_capacity);
+ const size_t num_bytes = sizeof (insert_only_hash_set) +
+ sizeof (key_type) * capacity;
+ alloc_type alloc;
+ insert_only_hash_set *result = (insert_only_hash_set *) alloc (num_bytes);
+ result->num_buckets = capacity;
+ result->num_entries = 0;
+ for (size_type i = 0; i < capacity; i++)
+ result->buckets[i] = (key_type) illegal_key;
+ return result;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+void
+insert_only_hash_sets<Key, HashFcn,
+ Alloc>::insert_only_hash_set::insert_no_resize
+ (key_type key)
+{
+ HashFcn hasher;
+ const size_type capacity = num_buckets;
+ VTV_DEBUG_ASSERT (capacity >= min_capacity);
+ VTV_DEBUG_ASSERT (!is_reserved_key (key));
+ size_type index = hasher (key) & (capacity - 1);
+ key_type k = key_at_index (index);
+ size_type indices_examined = 0;
+ while (k != key)
+ {
+ ++indices_examined;
+ if (k == (key_type) illegal_key)
+ {
+ key_at_index (index) = key;
+ ++num_entries;
+ return;
+ }
+ else
+ {
+ inc_by (stat_insert_found_hash_collision,
+ hasher (k) == hasher (key));
+ }
+ VTV_DEBUG_ASSERT (indices_examined < capacity);
+ index = next_index (index, indices_examined);
+ k = key_at_index (index);
+ }
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::insert_only_hash_set::contains
+ (key_type key) const
+{
+ inc (stat_contains_in_non_trivial_set);
+ HashFcn hasher;
+ const size_type capacity = num_buckets;
+ size_type index = hasher (key) & (capacity - 1);
+ key_type k = key_at_index (index);
+ size_type indices_examined = 0;
+ inc (stat_probes_in_non_trivial_set);
+ while (k != key)
+ {
+ ++indices_examined;
+ if (/*UNLIKELY*/(k == (key_type) illegal_key
+ || indices_examined == capacity))
+ return false;
+
+ index = next_index (index, indices_examined);
+ k = key_at_index (index);
+ inc (stat_probes_in_non_trivial_set);
+ }
+ return true;
+}
+
+template <typename Key, class HashFcn, class Alloc>
+typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
+ insert_only_hash_sets<Key, HashFcn,
+ Alloc>::insert_only_hash_set::resize_if_necessary (void)
+{
+ VTV_DEBUG_ASSERT (num_buckets >= min_capacity);
+ size_type unused = num_buckets - num_entries;
+ if (unused < (num_buckets >> 2))
+ {
+ inc (stat_double_the_number_of_buckets);
+ size_type new_num_buckets = num_buckets * 2;
+ insert_only_hash_set *s = create (new_num_buckets);
+ for (size_type i = 0; i < num_buckets; i++)
+ if (buckets[i] != (key_type) illegal_key)
+ s->insert_no_resize (buckets[i]);
+ VTV_DEBUG_ASSERT (size (this) == size (s));
+ return s;
+ }
+ else
+ return this;
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::create (size_type n,
+ insert_only_hash_set **handle)
+
+{
+ inc (stat_create);
+ *handle = insert_only_hash_set::create (n);
+ return (n <= 1) || (*handle != NULL);
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::resize (size_type n,
+ insert_only_hash_set **handle)
+{
+ inc (stat_resize);
+ *handle = insert_only_hash_set::resize (n, *handle);
+ return (n <= 1) || (*handle != NULL);
+}
+
+template<typename Key, class HashFcn, class Alloc>
+bool
+insert_only_hash_sets<Key, HashFcn, Alloc>::insert (key_type key,
+ insert_only_hash_set **handle)
+{
+ inc (stat_insert);
+ const size_type old_size = insert_only_hash_set::size (*handle);
+ *handle = insert_only_hash_set::insert (key, *handle);
+ if (*handle != NULL)
+ {
+ const size_type delta = insert_only_hash_set::size (*handle) - old_size;
+ inc_by (stat_insert_key_that_was_already_present, delta == 0);
+ }
+ return *handle != NULL;
+}
+
+#endif /* VTV_SET_H */
diff --git a/libstdc++-v3/libsupc++/vtv_stubs.cc b/libstdc++-v3/libsupc++/vtv_stubs.cc
new file mode 100644
index 00000000000..7b50db39a81
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_stubs.cc
@@ -0,0 +1,97 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "vtv_rts.h"
+
+/* The is part of the vtable verification runtime library. For more
+ information about this feature, see the comments in vtv_rts.cc. */
+
+/* The functions in this file are used to create the libvtv_stubs
+ library, as part of the vtable verification feature. When building
+ a binary without vtable verification, and linking it with a
+ (possibly pre-built third-party) library that was built with
+ verification, it is possible that vtable verification will fail due
+ to incomplete data (rather than due to corrupt vtable pointers). In
+ this case we need to give programmers a way of turning off the
+ vtable verification in their libraries. They can do so by linking
+ with the libvtv_stubs library, which (as you can see) will replace
+ the real verification functions with a set of functions that do
+ nothing (so no more verification failures/aborts). */
+
+void
+__VLTChangePermission (int perm __attribute__((__unused__)))
+{
+}
+
+#ifdef VTV_DEBUG
+
+void __VLTInitSetSymbolDebug
+ (void **set_handle_ptr __attribute__((__unused__)),
+ const void *set_symbol_key __attribute__((__unused__)),
+ std::size_t size_hint __attribute__((__unused__)))
+{
+}
+
+void
+__VLTRegisterPairDebug (void **set_handle_ptrr __attribute__((__unused__)),
+ const void *vtable_ptr __attribute__((__unused__)),
+ const char *set_symbol_name __attribute__((__unused__)),
+ const char *vtable_name __attribute__((__unused__)))
+{
+}
+
+const void *
+__VLTVerifyVtablePointerDebug
+ (void **set_handle_ptr __attribute__((__unused__)),
+ const void *vtable_ptr,
+ const char *set_symbol_name __attribute__((__unused__)),
+ const char *vtable_name __attribute__((__unused__)))
+
+{
+ return vtable_ptr;
+}
+
+#else
+
+void __VLTInitSetSymbol
+ (void **set_handle_ptr __attribute__((__unused__)),
+ const void *set_symbol_key __attribute__((__unused__)),
+ std::size_t size_hint __attribute__((__unused__)))
+{
+}
+
+void
+__VLTRegisterPair (void **set_handle_ptr __attribute__((__unused__)),
+ const void *vtable_ptr __attribute__((__unused__)))
+{
+}
+
+const void *
+__VLTVerifyVtablePointer (void **set_handle_ptr __attribute__((__unused__)),
+ const void *vtable_ptr)
+{
+ return vtable_ptr;
+}
+
+#endif
diff --git a/libstdc++-v3/libsupc++/vtv_utils.cc b/libstdc++-v3/libsupc++/vtv_utils.cc
new file mode 100644
index 00000000000..2dddb401fa2
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_utils.cc
@@ -0,0 +1,122 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is part of the vtable verication runtime library (see
+ comments in vtv_rts.cc for more information about vtable
+ verification). This file contains log file utilities. */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "vtv_utils.h"
+
+/* This is the directory into which all vtable verication log files
+ get written, if possible. */
+static const char * const logs_dir = "/var/log/chrome/vtv_logs";
+
+
+/* This is the directory into which the vtable verification log files
+ will get written if they can't be written to the directory
+ above. */
+static const char * const alt_logs_dir = "/tmp/vtv_logs";
+
+
+/* This function takes the NAME of a log file to open, attempts to
+ open it in the logs_dir directory, and returns the resulting file
+ decriptor. */
+
+int
+vtv_open_log (const char *name)
+{
+ /* Try to create the logs under /var/log/chrome first, which is
+ persistent across reboots. This location only exists on
+ ChromeOS. This code should not be commited upstream GCC. */
+ char log_name[256];
+ snprintf (log_name, sizeof (log_name), "%s/%s", logs_dir, name);
+ mkdir (logs_dir, S_IRWXU);
+ int fd = open (log_name, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
+ if (fd != -1)
+ return fd;
+
+ /* Otherwise, try to open in /tmp. */
+ snprintf(log_name, sizeof(log_name), "%s/%s", alt_logs_dir, name);
+ mkdir(alt_logs_dir, S_IRWXU);
+ fd = open(log_name, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU);
+ if (fd == -1)
+ vtv_add_to_log (2, "Cannot open log file %s %s\n", name,
+ strerror (errno));
+ return fd;
+}
+
+/* This function takes a file descriptor (FD) and a string (STR) and
+ tries to write the string to the file. */
+
+static int
+vtv_log_write (int fd, const char *str)
+{
+ if (write (fd, str, strlen (str)) != -1)
+ return 0;
+
+ if (fd != 2) /* Make sure we dont get in a loop. */
+ vtv_add_to_log (2, "Error writing to log: %s\n", strerror (errno));
+ return -1;
+}
+
+
+/* This function takes a file decriptor (LOG_FILE) and an output
+ format string (FORMAT), followed by zero or more print format
+ arguments (the same as fprintf, for example). It gets the current
+ process ID and PPID, pre-pends them to the formatted message, and
+ writes write it out to the log file referenced by LOG_FILE via calles
+ to vtv_log_write. */
+
+int
+vtv_add_to_log (int log_file, const char * format, ...)
+{
+ /* We dont want to dynamically allocate this buffer. This should be
+ more than enough in most cases. It if isn't we are careful not to
+ do a buffer overflow. */
+ char output[1024];
+
+ va_list ap;
+ va_start (ap, format);
+
+ snprintf (output, sizeof (output), "VTV: PID=%d PPID=%d ", getpid (),
+ getppid ());
+ vtv_log_write (log_file, output);
+ vsnprintf (output, sizeof (output), format, ap);
+ vtv_log_write (log_file, output);
+
+ /* fdatasync is quite expensive. Only enable if you suspect you are
+ loosing log data in in a program crash? */
+ /* fdatasync(log_file); */
+
+ return 0;
+}
diff --git a/libstdc++-v3/libsupc++/vtv_utils.h b/libstdc++-v3/libsupc++/vtv_utils.h
new file mode 100644
index 00000000000..962274c331c
--- /dev/null
+++ b/libstdc++-v3/libsupc++/vtv_utils.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2012
+ Free Software Foundation
+
+ This file is part of GCC.
+
+ GCC is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GCC is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _VTV_UTILS_H
+#define _VTV_UTILS_H 1
+
+#include <stdlib.h>
+
+/* Handler for verification runtime errors. */
+#define VTV_error abort
+
+/* Assertion macros used in vtable verification runtime. */
+#define VTV_ASSERT(EXPR) \
+ if (!(EXPR)) VTV_error();
+
+#ifdef VTV_DEBUG
+#define VTV_DEBUG_ASSERT(EXPR) ((bool) (!(EXPR)) ? VTV_error() : (void) 0)
+#else
+#define VTV_DEBUG_ASSERT(EXPR) ((void) 0)
+#endif
+
+/* Name of the section where we put general VTV variables for protection */
+#define VTV_PROTECTED_VARS_SECTION ".vtable_map_vars"
+#define VTV_PROTECTED_VAR \
+ __attribute__ ((section (VTV_PROTECTED_VARS_SECTION)))
+
+/* The following logging routines try to use low level file access
+ routines and avoid calling malloc. We need this so that we dont
+ disturb the order of calls to dlopen. Changing the order of dlopen
+ calls may lead to deadlocks */
+int vtv_open_log (const char * name);
+int vtv_add_to_log (int log, const char * format, ...);
+
+#endif /* VTV_UTILS_H */
diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am
index cc17c962eae..6c005f2c4c3 100644
--- a/libstdc++-v3/src/Makefile.am
+++ b/libstdc++-v3/src/Makefile.am
@@ -73,10 +73,23 @@ libstdc___la_DEPENDENCIES = \
$(top_builddir)/src/c++98/libc++98convenience.la \
$(top_builddir)/src/c++11/libc++11convenience.la
+if ENABLE_VTABLE_VERIFY
libstdc___la_LDFLAGS = \
- -version-info $(libtool_VERSION) ${version_arg} -lm
+ -version-info $(libtool_VERSION) ${version_arg} -lm -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
+libvtv___la_LIBADD = \
+ $(top_builddir)/libsupc++/.libs
+LIBVTV_FLAGS = \
+ -L$(libvtv___la_LIBADD) --whole-archive -lvtv_init --no-whole-archive
+else
+libstdc___la_LDFLAGS = \
+ -version-info $(libtool_VERSION) ${version_arg} -lm
+libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
+
+libvtv___la_LIBADD =
+LIBVTV_FLAGS =
+endif
# Use special rules for parallel mode compilation.
@@ -193,6 +206,7 @@ CXXLINK = \
$(LIBTOOL) --tag CXX \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXX) \
+ $(LIBVTV_FLAGS) \
$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
diff --git a/libstdc++-v3/src/Makefile.in b/libstdc++-v3/src/Makefile.in
index ab989e8d800..d8bb653f546 100644
--- a/libstdc++-v3/src/Makefile.in
+++ b/libstdc++-v3/src/Makefile.in
@@ -368,10 +368,22 @@ libstdc___la_DEPENDENCIES = \
$(top_builddir)/src/c++98/libc++98convenience.la \
$(top_builddir)/src/c++11/libc++11convenience.la
-libstdc___la_LDFLAGS = \
- -version-info $(libtool_VERSION) ${version_arg} -lm
+@ENABLE_VTABLE_VERIFY_FALSE@libstdc___la_LDFLAGS = \
+@ENABLE_VTABLE_VERIFY_FALSE@ -version-info $(libtool_VERSION) ${version_arg} -lm
+
+@ENABLE_VTABLE_VERIFY_TRUE@libstdc___la_LDFLAGS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ -version-info $(libtool_VERSION) ${version_arg} -lm -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
+
+@ENABLE_VTABLE_VERIFY_FALSE@libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
+@ENABLE_VTABLE_VERIFY_TRUE@libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
+@ENABLE_VTABLE_VERIFY_FALSE@libvtv___la_LIBADD =
+@ENABLE_VTABLE_VERIFY_TRUE@libvtv___la_LIBADD = \
+@ENABLE_VTABLE_VERIFY_TRUE@ $(top_builddir)/libsupc++/.libs
+
+@ENABLE_VTABLE_VERIFY_FALSE@LIBVTV_FLAGS =
+@ENABLE_VTABLE_VERIFY_TRUE@LIBVTV_FLAGS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ -L$(libvtv___la_LIBADD) --whole-archive -lvtv_init --no-whole-archive
-libstdc___la_LINK = $(CXXLINK) $(libstdc___la_LDFLAGS)
# Use special rules for parallel mode compilation.
PARALLEL_FLAGS = -fopenmp -D_GLIBCXX_PARALLEL -I$(glibcxx_builddir)/../libgomp
@@ -454,6 +466,7 @@ CXXLINK = \
$(LIBTOOL) --tag CXX \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXX) \
+ $(LIBVTV_FLAGS) \
$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
@ENABLE_SYMVERS_TRUE@CLEANFILES = libstdc++-symbols.ver $(version_dep)
diff --git a/libstdc++-v3/src/c++11/Makefile.am b/libstdc++-v3/src/c++11/Makefile.am
index 14a412711c6..e5eb30f5a61 100644
--- a/libstdc++-v3/src/c++11/Makefile.am
+++ b/libstdc++-v3/src/c++11/Makefile.am
@@ -61,6 +61,18 @@ vpath % $(top_srcdir)/src/c++11
libc__11convenience_la_SOURCES = $(sources) $(inst_sources)
+if ENABLE_VTABLE_VERIFY
+EXTRA_VTV_LDFLAGS = \
+ -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
+LIBVTV_FLAGS = \
+ -L$(top_builddir)/libsupc++/.libs --whole-archive -lvtv_init --no-whole-archive
+VTV_CXXFLAGS = -fvtable-verify=std $(EXTRA_VTV_LDFLAGS)
+else
+EXTRA_VTV_LDFLAGS =
+LIBVTV_FLAGS =
+VTV_CXXFLAGS =
+endif
+
# AM_CXXFLAGS needs to be in each subdirectory so that it can be
# modified in a per-library or per-sub-library way. Need to manually
# set this option because CONFIG_CXXFLAGS has to be after
@@ -69,7 +81,7 @@ libc__11convenience_la_SOURCES = $(sources) $(inst_sources)
AM_CXXFLAGS = \
-std=gnu++11 \
$(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
- $(XTEMPLATE_FLAGS) \
+ $(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
$(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) \
$($(@)_no_omit_frame_pointer)
@@ -120,6 +132,7 @@ CXXLINK = \
$(LIBTOOL) --tag CXX --tag disable-shared \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXX) \
+ $(LIBVTV_FLAGS) \
$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
# Google-specific pessimization
diff --git a/libstdc++-v3/src/c++11/Makefile.in b/libstdc++-v3/src/c++11/Makefile.in
index be91b30acf3..bf59ed88b17 100644
--- a/libstdc++-v3/src/c++11/Makefile.in
+++ b/libstdc++-v3/src/c++11/Makefile.in
@@ -325,6 +325,16 @@ sources = \
@ENABLE_EXTERN_TEMPLATE_TRUE@ wstring-inst.cc
libc__11convenience_la_SOURCES = $(sources) $(inst_sources)
+@ENABLE_VTABLE_VERIFY_FALSE@EXTRA_VTV_LDFLAGS =
+@ENABLE_VTABLE_VERIFY_TRUE@EXTRA_VTV_LDFLAGS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
+
+@ENABLE_VTABLE_VERIFY_FALSE@LIBVTV_FLAGS =
+@ENABLE_VTABLE_VERIFY_TRUE@LIBVTV_FLAGS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ -L$(top_builddir)/libsupc++/.libs --whole-archive -lvtv_init --no-whole-archive
+
+@ENABLE_VTABLE_VERIFY_FALSE@VTV_CXXFLAGS =
+@ENABLE_VTABLE_VERIFY_TRUE@VTV_CXXFLAGS = -fvtable-verify=std $(EXTRA_VTV_LDFLAGS)
# AM_CXXFLAGS needs to be in each subdirectory so that it can be
# modified in a per-library or per-sub-library way. Need to manually
@@ -334,7 +344,7 @@ libc__11convenience_la_SOURCES = $(sources) $(inst_sources)
AM_CXXFLAGS = \
-std=gnu++11 \
$(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
- $(XTEMPLATE_FLAGS) \
+ $(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
$(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) \
$($(@)_no_omit_frame_pointer)
@@ -386,6 +396,7 @@ CXXLINK = \
$(LIBTOOL) --tag CXX --tag disable-shared \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXX) \
+ $(LIBVTV_FLAGS) \
$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
diff --git a/libstdc++-v3/src/c++98/Makefile.am b/libstdc++-v3/src/c++98/Makefile.am
index c153a59336d..89606bc82b6 100644
--- a/libstdc++-v3/src/c++98/Makefile.am
+++ b/libstdc++-v3/src/c++98/Makefile.am
@@ -143,6 +143,18 @@ vpath % $(top_srcdir)/src/c++98
libc__98convenience_la_SOURCES = $(sources)
+if ENABLE_VTABLE_VERIFY
+EXTRA_VTV_LDFLAGS = \
+ -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
+LIBVTV_FLAGS = \
+ -L$(top_builddir)/libsupc++/.libs --whole-archive -lvtv_init --no-whole-archive
+VTV_CXXFLAGS = -fvtable-verify=std $(EXTRA_VTV_LDFLAGS)
+else
+EXTRA_VTV_LDFLAGS =
+LIBVTV_FLAGS =
+VTV_CXXFLAGS =
+endif
+
# Use special rules for the deprecated source files so that they find
# deprecated include files.
GLIBCXX_INCLUDE_DIR=$(glibcxx_builddir)/include
@@ -173,7 +185,7 @@ parallel_settings.o: parallel_settings.cc
# as the occasion calls for it.
AM_CXXFLAGS = \
$(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
- $(XTEMPLATE_FLAGS) \
+ $(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
$(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS)
AM_MAKEFLAGS = \
@@ -223,4 +235,5 @@ CXXLINK = \
$(LIBTOOL) --tag CXX --tag disable-shared \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXX) \
+ $(LIBVTV_FLAGS) \
$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
diff --git a/libstdc++-v3/src/c++98/Makefile.in b/libstdc++-v3/src/c++98/Makefile.in
index c3173bc91f2..fb86e6655cb 100644
--- a/libstdc++-v3/src/c++98/Makefile.in
+++ b/libstdc++-v3/src/c++98/Makefile.in
@@ -388,6 +388,16 @@ sources = \
${host_sources_extra}
libc__98convenience_la_SOURCES = $(sources)
+@ENABLE_VTABLE_VERIFY_FALSE@EXTRA_VTV_LDFLAGS =
+@ENABLE_VTABLE_VERIFY_TRUE@EXTRA_VTV_LDFLAGS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end
+
+@ENABLE_VTABLE_VERIFY_FALSE@LIBVTV_FLAGS =
+@ENABLE_VTABLE_VERIFY_TRUE@LIBVTV_FLAGS = \
+@ENABLE_VTABLE_VERIFY_TRUE@ -L$(top_builddir)/libsupc++/.libs --whole-archive -lvtv_init --no-whole-archive
+
+@ENABLE_VTABLE_VERIFY_FALSE@VTV_CXXFLAGS =
+@ENABLE_VTABLE_VERIFY_TRUE@VTV_CXXFLAGS = -fvtable-verify=std $(EXTRA_VTV_LDFLAGS)
# Use special rules for the deprecated source files so that they find
# deprecated include files.
@@ -403,7 +413,7 @@ PARALLEL_FLAGS = -fopenmp -D_GLIBCXX_PARALLEL -I$(glibcxx_builddir)/../libgomp
# as the occasion calls for it.
AM_CXXFLAGS = \
$(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
- $(XTEMPLATE_FLAGS) \
+ $(XTEMPLATE_FLAGS) $(VTV_CXXFLAGS) \
$(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS)
AM_MAKEFLAGS = \
@@ -454,6 +464,7 @@ CXXLINK = \
$(LIBTOOL) --tag CXX --tag disable-shared \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CXX) \
+ $(LIBVTV_FLAGS) \
$(OPT_LDFLAGS) $(SECTION_LDFLAGS) $(AM_CXXFLAGS) $(LTLDFLAGS) -o $@
all: all-am