aboutsummaryrefslogtreecommitdiff
path: root/libstdc++-v3/libsupc++
diff options
context:
space:
mode:
Diffstat (limited to 'libstdc++-v3/libsupc++')
-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
13 files changed, 3378 insertions, 74 deletions
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 */