diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1471b218cf0..67f5f7fb446 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,21 @@ +2015-01-27 Caroline Tice + + Committing VTV Cywin/Ming patch for Patrick Wollgast + * config/i386/cygwin.h (STARTFILE_SPEC): Add vtv_start.o, + if -fvtable-verify=preinit/std is used. + * config/i386/mingw-w64.h (STARTFILE_SPEC): Likewise. + * config/i386/mingw32.h (STARTFILE_SPEC): Likewise. + * config/i386/cygwin.h (ENDFILE_SPEC): Add vtv_end.o, + if -fvtable-verify=preinit/std is used. + * config/i386/mingw32.h (ENDFILE_SPEC): Likewise. + * config/i386/cygwin.h (LIB_SPEC): Pass -lvtv and -lpsapi, + if -fvtable-verify=preinit/std is used. + * config/i386/mingw-w64.h (LIB_SPEC): Likewise. + * config/i386/mingw32.h (LIB_SPEC): Likewise. + * varasm.c (assemble_variable): Add code to properly set the comdat + section and name for the .vtable_map_vars section in case the + target is PE or COFF. + 2015-01-29 Jan Hubicka PR ipa/64801 diff --git a/gcc/config/i386/cygwin.h b/gcc/config/i386/cygwin.h index a90f5133105..2186937849a 100644 --- a/gcc/config/i386/cygwin.h +++ b/gcc/config/i386/cygwin.h @@ -41,12 +41,18 @@ along with GCC; see the file COPYING3. If not see #define STARTFILE_SPEC "\ %{!shared: %{!mdll: crt0%O%s \ %{pg:gcrt0%O%s}}}\ - %{shared:crtbeginS.o%s;:crtbegin.o%s}" + %{shared:crtbeginS.o%s;:crtbegin.o%s} \ + %{fvtable-verify=none:%s; \ + fvtable-verify=preinit:vtv_start.o%s; \ + fvtable-verify=std:vtv_start.o%s}" #undef ENDFILE_SPEC #define ENDFILE_SPEC \ "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s}\ %{!shared:%:if-exists(default-manifest.o%s)}\ + %{fvtable-verify=none:%s; \ + fvtable-verify=preinit:vtv_end.o%s; \ + fvtable-verify=std:vtv_end.o%s} \ crtend.o%s" /* Normally, -lgcc is not needed since everything in it is in the DLL, but we @@ -81,6 +87,8 @@ along with GCC; see the file COPYING3. If not see %{pthread: } \ -lcygwin \ %{mwindows:-lgdi32 -lcomdlg32} \ + %{fvtable-verify=preinit:-lvtv -lpsapi; \ + fvtable-verify=std:-lvtv -lpsapi} \ -ladvapi32 -lshell32 -luser32 -lkernel32" /* To implement C++ function replacement we always wrap the cxx diff --git a/gcc/config/i386/mingw-w64.h b/gcc/config/i386/mingw-w64.h index dfb7f3c7601..578a7b7c699 100644 --- a/gcc/config/i386/mingw-w64.h +++ b/gcc/config/i386/mingw-w64.h @@ -32,7 +32,10 @@ along with GCC; see the file COPYING3. If not see %{!shared:%{!mdll:%{!municode:crt2%O%s}}} \ %{!shared:%{!mdll:%{municode:crt2u%O%s}}} \ %{pg:gcrt2%O%s} \ - crtbegin.o%s" + crtbegin.o%s \ + %{fvtable-verify=none:%s; \ + fvtable-verify=preinit:vtv_start.o%s; \ + fvtable-verify=std:vtv_start.o%s}" /* Enable multilib. */ @@ -43,6 +46,8 @@ along with GCC; see the file COPYING3. If not see #define LIB_SPEC "%{pg:-lgmon} %{" SPEC_PTHREAD1 ":-lpthread} " \ "%{" SPEC_PTHREAD2 ": } " \ "%{mwindows:-lgdi32 -lcomdlg32} " \ + "%{fvtable-verify=preinit:-lvtv -lpsapi; \ + fvtable-verify=std:-lvtv -lpsapi} " \ "-ladvapi32 -lshell32 -luser32 -lkernel32" #undef SPEC_32 diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h index ab46ff26d2d..f1397614ed8 100644 --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -91,6 +91,8 @@ along with GCC; see the file COPYING3. If not see #define LIB_SPEC "%{pg:-lgmon} %{" SPEC_PTHREAD1 ":-lpthread} " \ "%{" SPEC_PTHREAD2 ": } " \ "%{mwindows:-lgdi32 -lcomdlg32} " \ + "%{fvtable-verify=preinit:-lvtv -lpsapi; \ + fvtable-verify=std:-lvtv -lpsapi} " \ "-ladvapi32 -lshell32 -luser32 -lkernel32" /* Weak symbols do not get resolved if using a Windows dll import lib. @@ -143,12 +145,18 @@ along with GCC; see the file COPYING3. If not see #undef STARTFILE_SPEC #define STARTFILE_SPEC "%{shared|mdll:dllcrt2%O%s} \ %{!shared:%{!mdll:crt2%O%s}} %{pg:gcrt2%O%s} \ - crtbegin.o%s" + crtbegin.o%s \ + %{fvtable-verify=none:%s; \ + fvtable-verify=preinit:vtv_start.o%s; \ + fvtable-verify=std:vtv_start.o%s}" #undef ENDFILE_SPEC #define ENDFILE_SPEC \ "%{Ofast|ffast-math|funsafe-math-optimizations:crtfastmath.o%s} \ %{!shared:%:if-exists(default-manifest.o%s)}\ + %{fvtable-verify=none:%s; \ + fvtable-verify=preinit:vtv_end.o%s; \ + fvtable-verify=std:vtv_end.o%s} \ crtend.o%s" /* Override startfile prefix defaults. */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2ae15d027d8..743fda3704d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2015-01-27 Caroline Tice + + Committing VTV Cywin/Ming patch for Patrick Wollgast + * vtable-class-hierarchy.cc (vtv_generate_init_routine): Add + check for not TARGET_PECOFF at the VTV_PREINIT_PRIORITY checks. + 2015-01-27 Jason Merrill PR c++/58597 diff --git a/gcc/cp/vtable-class-hierarchy.c b/gcc/cp/vtable-class-hierarchy.c index aec2fcae51c..a138ee4e43b 100644 --- a/gcc/cp/vtable-class-hierarchy.c +++ b/gcc/cp/vtable-class-hierarchy.c @@ -1194,7 +1194,11 @@ vtv_generate_init_routine (void) TREE_STATIC (vtv_fndecl) = 1; TREE_USED (vtv_fndecl) = 1; DECL_PRESERVE_P (vtv_fndecl) = 1; +#if defined (TARGET_PECOFF) + if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF) +#else if (flag_vtable_verify == VTV_PREINIT_PRIORITY) +#endif DECL_STATIC_CONSTRUCTOR (vtv_fndecl) = 0; gimplify_function_tree (vtv_fndecl); @@ -1202,7 +1206,11 @@ vtv_generate_init_routine (void) symtab->process_new_functions (); +#if defined (TARGET_PECOFF) + if (flag_vtable_verify == VTV_PREINIT_PRIORITY && !TARGET_PECOFF) +#else if (flag_vtable_verify == VTV_PREINIT_PRIORITY) +#endif assemble_vtv_preinit_initializer (vtv_fndecl); } diff --git a/gcc/varasm.c b/gcc/varasm.c index 36c3633deb4..2069432ad9a 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -2252,6 +2252,33 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, | SECTION_LINKONCE, DECL_NAME (decl)); in_section = sect; +#elif defined (TARGET_PECOFF) + /* Neither OBJECT_FORMAT_PE, nor OBJECT_FORMAT_COFF is set here. + Therefore the following check is used. + In case a the target is PE or COFF a comdat group section + is created, e.g. .vtable_map_vars$foo. The linker places + everything in .vtable_map_vars at the end. + + A fix could be made in + gcc/config/i386/winnt.c: i386_pe_unique_section. */ + if (TARGET_PECOFF) + { + char *name; + + if (TREE_CODE (DECL_NAME (decl)) == IDENTIFIER_NODE) + name = ACONCAT ((sect->named.name, "$", + IDENTIFIER_POINTER (DECL_NAME (decl)), NULL)); + else + name = ACONCAT ((sect->named.name, "$", + IDENTIFIER_POINTER (DECL_COMDAT_GROUP (DECL_NAME (decl))), + NULL)); + + targetm.asm_out.named_section (name, + sect->named.common.flags + | SECTION_LINKONCE, + DECL_NAME (decl)); + in_section = sect; + } #else switch_to_section (sect); #endif diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index dbe2b82905a..5600d56bb86 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,13 @@ +2015-01-27 Caroline Tice + + Committing VTV Cywin/Ming patch for Patrick Wollgast + * Makefile.in: Move rules to build vtv_*.o out of the check + for CUSTOM_CRTSTUFF. + * config.host (i[34567]86-*-cygwin*, x86_64-*-cygwin*, + i[34567]86-*-mingw*) + (x86_64-*-mingw*): Only add vtv_*.o to extra_parts if + enable_vtable_verify. + 2015-01-27 Nick Clifton * config/rl78/cmpsi2.S: Use function start and end macros. diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in index f693883d718..88ddfea18eb 100644 --- a/libgcc/Makefile.in +++ b/libgcc/Makefile.in @@ -1003,6 +1003,7 @@ crtoffloadbegin$(objext): $(srcdir)/offloadstuff.c crtoffloadend$(objext): $(srcdir)/offloadstuff.c $(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_END +endif ifeq ($(enable_vtable_verify),yes) # These are used in vtable verification; see comments in source files for @@ -1019,7 +1020,6 @@ vtv_start_preinit$(objext): $(srcdir)/vtv_start_preinit.c vtv_end_preinit$(objext): $(srcdir)/vtv_end_preinit.c $(crt_compile) $(CRTSTUFF_T_CFLAGS_S) -c $(srcdir)/vtv_end_preinit.c endif -endif ifeq ($(CUSTOM_CRTIN),) # -x assembler-with-cpp is only needed on case-insensitive filesystem. diff --git a/libgcc/config.host b/libgcc/config.host index 3c19b1fcfc2..5baeae54e6c 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -626,6 +626,9 @@ i[4567]86-wrs-vxworks|i[4567]86-wrs-vxworksae) ;; i[34567]86-*-cygwin*) extra_parts="crtbegin.o crtbeginS.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi # This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h if test x$enable_sjlj_exceptions = xyes; then tmake_eh_file="i386/t-sjlj-eh" @@ -642,6 +645,9 @@ i[34567]86-*-cygwin*) ;; x86_64-*-cygwin*) extra_parts="crtbegin.o crtbeginS.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi # This has to match the logic for DWARF2_UNWIND_INFO in gcc/config/i386/cygming.h if test x$enable_sjlj_exceptions = xyes; then tmake_eh_file="i386/t-sjlj-eh" @@ -659,6 +665,9 @@ x86_64-*-cygwin*) ;; i[34567]86-*-mingw*) extra_parts="crtbegin.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi case ${target_thread_file} in win32) tmake_file="$tmake_file i386/t-gthr-win32" @@ -705,6 +714,9 @@ x86_64-*-mingw*) fi tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-cygming i386/t-mingw32 t-dfprules i386/t-crtfm i386/t-chkstk" extra_parts="$extra_parts crtbegin.o crtend.o crtfastmath.o" + if test x$enable_vtable_verify = xyes; then + extra_parts="$extra_parts vtv_start.o vtv_end.o vtv_start_preinit.o vtv_end_preinit.o" + fi ;; i[34567]86-*-interix[3-9]*) tmake_file="$tmake_file i386/t-interix i386/t-chkstk" diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 323c8d2feba..5e1aeaeeb52 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2015-01-27 Caroline Tice + + Committing VTV Cywin/Ming patch for Patrick Wollgast + * acinclude.m4: Define VTV_CYGMIN. + * configure: Regenerate. + * libsupc++/Makefile.am: Add vtv_sources only to libsupc___la_SOURCES + and libsupc__convenience_la_SOURCES if VTV_CYGMIN is not set. + * libsupc++/Makefile.in: Regenerated. + * libsupc++/vtv_stubs.cc: Add none weak declaration of every function + for Cygwin and MinGW. + * src/Makefile.am: Add libvtv.la to toolexeclib_LTLIBRARIES, if + VTV_CYGMIN is set. Define libvtv_la_SOURCES, libvtv_la_LDFLAGS, + libvtv_la_AM_CXXFLAGS and libvtv_la_LINK if VTV_CYGMIN is set. + * libstdc++-v3/src/Makefile.in: Regenerate. + 2015-01-28 Jonathan Wakely PR libstdc++/64828 diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 74e8eaffe0a..59df22d8703 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -2321,7 +2321,17 @@ AC_DEFUN([GLIBCXX_ENABLE_VTABLE_VERIFY], [ AC_MSG_RESULT([$enable_vtable_verify]) if test $enable_vtable_verify = yes; then - VTV_CXXFLAGS="-fvtable-verify=std -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end" + case ${target_os} in + cygwin*|mingw32*) + VTV_CXXFLAGS="-fvtable-verify=std -Wl,-lvtv,-u_vtable_map_vars_start,-u_vtable_map_vars_end" + vtv_cygmin="yes" + ;; + *) + VTV_CXXFLAGS="-fvtable-verify=std -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end" + vtv_cygmin="no" + ;; + esac + AM_CONDITIONAL(VTV_CYGMIN, test $vtv_cygmin = yes) VTV_PCH_CXXFLAGS="-fvtable-verify=std" VTV_CXXLINKFLAGS="-L${toplevel_builddir}/libvtv/.libs -Wl,--rpath -Wl,${toplevel_builddir}/libvtv/.libs" else diff --git a/libstdc++-v3/libsupc++/Makefile.am b/libstdc++-v3/libsupc++/Makefile.am index b87ffbf2490..651a66254be 100644 --- a/libstdc++-v3/libsupc++/Makefile.am +++ b/libstdc++-v3/libsupc++/Makefile.am @@ -100,9 +100,11 @@ sources = \ vterminate.cc if ENABLE_VTABLE_VERIFY +if !VTV_CYGMIN vtv_sources = \ vtv_stubs.cc endif +endif libsupc___la_SOURCES = $(sources) $(c_sources) $(vtv_sources) libsupc__convenience_la_SOURCES = $(sources) $(c_sources) $(vtv_sources) diff --git a/libstdc++-v3/libsupc++/vtv_stubs.cc b/libstdc++-v3/libsupc++/vtv_stubs.cc index c0b27d4f991..e573b336ee5 100644 --- a/libstdc++-v3/libsupc++/vtv_stubs.cc +++ b/libstdc++-v3/libsupc++/vtv_stubs.cc @@ -37,6 +37,39 @@ #include +/* weak symbols on Windows work differently than on Linux. To be able + to switch vtv on and off on Windows two dlls are built. One with + the sources from libvtv, the other from these stubs. Depending on + which dll is placed in the folder of the executable the functions + from libvtv or the stubs functions are used. */ +#if defined (__CYGWIN__) || defined (__MINGW32__) +extern "C" +void +__VLTChangePermission(int); + +void +__VLTRegisterSet(void**, const void*, std::size_t, std::size_t, + void**); + +void +__VLTRegisterPair(void**, const void*, std::size_t, + const void*); + +const void* +__VLTVerifyVtablePointer(void**, const void*); + +void +__VLTRegisterSetDebug(void**, const void*, std::size_t, std::size_t, + void**); + +void +__VLTRegisterPairDebug(void**, const void*, std::size_t, const void*, + const char*, const char*); + +const void* +__VLTVerifyVtablePointerDebug(void**, const void*, const char*, + const char*); +#else // Declare as weak for libsupc++, strong definitions are in libvtv. #if __GXX_WEAK__ extern "C" @@ -66,6 +99,7 @@ const void* __VLTVerifyVtablePointerDebug(void**, const void*, const char*, const char*) __attribute__((weak)); #endif +#endif // Stub definitions. extern "C" diff --git a/libstdc++-v3/src/Makefile.am b/libstdc++-v3/src/Makefile.am index cee9f2177d0..debf967801f 100644 --- a/libstdc++-v3/src/Makefile.am +++ b/libstdc++-v3/src/Makefile.am @@ -25,7 +25,30 @@ include $(top_srcdir)/fragment.am SUBDIRS = c++98 c++11 # Cross compiler support. +if VTV_CYGMIN +toolexeclib_LTLIBRARIES = libvtv.la libstdc++.la +else toolexeclib_LTLIBRARIES = libstdc++.la +endif + +if VTV_CYGMIN +vtv_stubs.cc: + rm -f $@ + $(LN_S) $(toplevel_srcdir)/libstdc++-v3/libsupc++/vtv_stubs.cc $@ + +libvtv_la_SOURCES = vtv_stubs.cc +libvtv_la_LDFLAGS = $(lt_host_flags) + +libvtv_la_AM_CXXFLAGS = \ + $(glibcxx_compiler_pic_flag) \ + $(XTEMPLATE_FLAGS) \ + -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end \ + $(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS) + +libvtv_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(libvtv_la_AM_CXXFLAGS) \ + $(CXXFLAGS) $(libvtv_la_LDFLAGS) $(LDFLAGS) -o $@ +endif vpath % $(top_srcdir)/src/c++98 vpath % $(top_srcdir)/src/c++11 diff --git a/libvtv/ChangeLog b/libvtv/ChangeLog index 671223f5891..7b80282a5f8 100644 --- a/libvtv/ChangeLog +++ b/libvtv/ChangeLog @@ -1,3 +1,50 @@ +2015-01-27 Caroline Tice + + Committing VTV Cywin/Ming patch for Patrick Wollgast + * libvtv/Makefile.am : Add libvtv.la to toolexeclib_LTLIBRARIES, if + VTV_CYGMIN is set. Define libvtv_la_LIBADD, libvtv_la_LDFLAGS, + libvtv_stubs_la_LDFLAGS and libvtv_stubs_la_SOURCES if VTV_CYGMIN is + set. Add obstac.c to libvtv_la_SOURCES if VTV_CYGMIN is set. + * libvtv/Makefile.in : Regenerate. + * libvtv/aclocal.m4 : Regenerate. + * libvtv/configure : Regenerate. + * libvtv/configure.ac : Add ACX_LT_HOST_FLAGS. Define VTV_CYGMIN. + * libvtv/configure.tgt : (x86_64-*-cygwin*, i?86-*-cygwin*, + x86_64-*-mingw*) + (i?86-*-mingw*): Add to supported targets. + * libvtv/vtv_fail.cc : Skip inclusion of execinfo.h on Cygwin and MinGW. + (log_error_message): Skip calls to backtrace and backtrace_symbols_fd + on Cygwin and MinGW. + * libvtv/vtv_malloc.cc : Include windows.h and skip sys/mman.h + inclusion on Cygwin and MinGW. Add sysconf port on Cygwin and MinGW. + (obstack_chunk_alloc): Exchange call to mmap with call to VirtualAlloc + on Cygwin and MinGW. + (__vtv_malloc_init): Exchange call to sysconf with call to port of + sysconf on Cygwin and MinGW. + * libvtv/vtv_malloc.h : Declare mprotect and define PROT_READ and + PROT_WRITE on Cygwin and MinGW. + * libvtv/map.h : Include stdint.h on MinGW. + * libvtv/rts.cc : Include windows.h, winternl.h and psapi.h, skip + include of execinfo.h, sys/mman.h and link.h on Cygwin and MinGW. Add + port of __fortify_fail on Cygwin and MinGW. Change ElfW (Addr) to + uintptr_t on Cygwin and MinGW. + (read_section_offset_and_length): Add port for Cygwin and MinGW + (iterate_modules): New function. + (vtv_unprotect_vtable_vars): Use iterate_modules instead of + dl_iterate_phdr on Cygwin and MinGW. + (vtv_protect_vtable_vars): Likewise. + (count_all_pages): Likewise. + (dl_iterate_phdr_count_pages): Don't build on Cygwin and MinGW. + * libvtv/utils.cc : Include windows.h and skip execinfo.h inclusion on + Cygwin and MinGW. + (__vtv_open_log): Exchange call to getuid and getpid with + GetCurrentProcessId and adjust call to snprintf accordingly on Cygwin + and MinGW. Adjust calls to mkdir on MinGW. Adjust call to open on + Cygwin and MinGW. + (__vtv_add_to_log): Adjust call to snprintf on Cygwin and MinGW. + (__vtv_log_verification_failure): Don't generate a backtrace on Cygwin + and MinGW. + 2014-12-12 Kyrylo Tkachov * testsuite/lib/libvtv.exp: Load target-utils.exp diff --git a/libvtv/Makefile.am b/libvtv/Makefile.am index 886d7e6be8d..2c9fb548d5f 100644 --- a/libvtv/Makefile.am +++ b/libvtv/Makefile.am @@ -38,7 +38,11 @@ AM_CXXFLAGS = $(XCFLAGS) AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS) AM_CXXFLAGS += -Wl,-u_vtable_map_vars_start,-u_vtable_map_vars_end -toolexeclib_LTLIBRARIES = libvtv.la +if VTV_CYGMIN + toolexeclib_LTLIBRARIES = libvtv.la libvtv_stubs.la +else + toolexeclib_LTLIBRARIES = libvtv.la +endif vtv_headers = \ vtv_map.h \ @@ -55,6 +59,11 @@ vtv_sources = \ vtv_utils.cc \ vtv_end.c +vtv_stubs_sources = \ + vtv_start.c \ + vtv_stubs.cc \ + vtv_end.c + libvtv_includedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)/include # Link in vtv_start and vtv_end. @@ -67,8 +76,29 @@ vtv_end.c: rm -f $@ $(LN_S) $(toplevel_srcdir)/libgcc/vtv_end.c $@ +if VTV_CYGMIN + obstack.c: + rm -f $@ + $(LN_S) $(toplevel_srcdir)/libiberty/obstack.c $@ + + vtv_stubs.cc: + rm -f $@ + $(LN_S) $(toplevel_srcdir)/libstdc++-v3/libsupc++/vtv_stubs.cc $@ +endif + +if VTV_CYGMIN + libvtv_la_LIBADD = -lpsapi + libvtv_la_LDFLAGS = $(lt_host_flags) + libvtv_stubs_la_LDFLAGS = $(lt_host_flags) +endif + if ENABLE_VTABLE_VERIFY +if VTV_CYGMIN + libvtv_la_SOURCES = $(vtv_sources) obstack.c + libvtv_stubs_la_SOURCES = $(vtv_stubs_sources) +else libvtv_la_SOURCES = $(vtv_sources) +endif libvtv_include_HEADERS = $(vtv_headers) else libvtv_la_SOURCES = @@ -78,6 +108,8 @@ endif # Least ordering for dependencies mean linking w/o libstdc++ for as # long as the development of libvtv does not absolutely require it. CXXVTV=$(CC_FOR_TARGET) +CXXLD=$(CC_FOR_TARGET) + LTCXXCOMPILE = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ --mode=compile $(CXXVTV) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) diff --git a/libvtv/configure.ac b/libvtv/configure.ac index 12b4664de2e..f0af8ede0c4 100644 --- a/libvtv/configure.ac +++ b/libvtv/configure.ac @@ -122,6 +122,7 @@ AC_CHECK_TOOL(RANLIB, ranlib, :) # Configure libtool AC_LIBTOOL_DLOPEN AM_PROG_LIBTOOL +ACX_LT_HOST_FLAGS AC_SUBST(enable_shared) AC_SUBST(enable_static) @@ -155,4 +156,15 @@ _EOF ]) fi +case "$target_os" in + cygwin*|mingw32*) + vtv_cygmin="yes" + ;; + *) + vtv_cygmin="no" + ;; +esac + +AM_CONDITIONAL(VTV_CYGMIN, test $vtv_cygmin = yes) + AC_OUTPUT diff --git a/libvtv/configure.tgt b/libvtv/configure.tgt index 046b4152429..00fb4d51ed4 100644 --- a/libvtv/configure.tgt +++ b/libvtv/configure.tgt @@ -26,6 +26,12 @@ case "${target}" in x86_64-*-linux* | i?86-*-linux*) VTV_SUPPORTED=yes ;; + x86_64-*-cygwin* | i?86-*-cygwin*) + VTV_SUPPORTED=yes + ;; + x86_64-*-mingw* | i?86-*-mingw*) + VTV_SUPPORTED=yes + ;; powerpc*-*-linux*) ;; sparc*-*-linux*) diff --git a/libvtv/vtv_fail.cc b/libvtv/vtv_fail.cc index 4f183d8cac2..7e7992267aa 100644 --- a/libvtv/vtv_fail.cc +++ b/libvtv/vtv_fail.cc @@ -46,7 +46,11 @@ #include #include #include + +#if !defined (__CYGWIN__) && !defined (__MINGW32__) #include +#endif + #include #include "vtv_utils.h" @@ -102,8 +106,10 @@ log_error_message (const char *log_msg, bool generate_backtrace) { #define STACK_DEPTH 20 void *callers[STACK_DEPTH]; +#if !defined (__CYGWIN__) && !defined (__MINGW32__) int actual_depth = backtrace (callers, STACK_DEPTH); backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd); +#endif } } diff --git a/libvtv/vtv_malloc.cc b/libvtv/vtv_malloc.cc index 8aaa636e0e3..4b675f40bdc 100644 --- a/libvtv/vtv_malloc.cc +++ b/libvtv/vtv_malloc.cc @@ -33,7 +33,11 @@ #include #include +#if defined (__CYGWIN__) || defined (__MINGW32__) +#include +#else #include +#endif #include #include #include @@ -62,6 +66,18 @@ 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; +#if defined (__CYGWIN__) || defined (__MINGW32__) +//sysconf(_SC_PAGE_SIZE) port +long sysconf_SC_PAGE_SIZE() +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + long pageSize = (long)si.dwPageSize; + return pageSize; + //return 4096; // standard usermode 32bit pagesize in bytes // FIXME +} +#endif + /* The function goes through and counts all the pages we have allocated so far. It returns the page count. */ @@ -162,8 +178,13 @@ obstack_chunk_alloc (size_t size) VTV_DEBUG_ASSERT ((size & (VTV_PAGE_SIZE - 1)) == 0); void *allocated; +#if defined (__CYGWIN__) || defined (__MINGW32__) + if ((allocated = VirtualAlloc(NULL, size, MEM_RESERVE|MEM_COMMIT, + PAGE_READWRITE)) == 0) +#else if ((allocated = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == 0) +#endif VTV_error (); VTV_DEBUG_ASSERT (((unsigned long) allocated & (VTV_PAGE_SIZE - 1)) == 0); @@ -190,7 +211,11 @@ __vtv_malloc_init (void) if (malloc_initialized) return; +#if defined (__CYGWIN__) || defined (__MINGW32__) + if (VTV_PAGE_SIZE != sysconf_SC_PAGE_SIZE()) +#else if (VTV_PAGE_SIZE != sysconf (_SC_PAGE_SIZE)) +#endif VTV_error (); obstack_chunk_size (&vtv_obstack) = VTV_PAGE_SIZE; diff --git a/libvtv/vtv_malloc.h b/libvtv/vtv_malloc.h index 55f5fe8022b..2af565f6e66 100644 --- a/libvtv/vtv_malloc.h +++ b/libvtv/vtv_malloc.h @@ -95,4 +95,11 @@ extern void __vtv_malloc_stats (void); extern void __vtv_malloc_dump_stats (void); extern int __vtv_count_mmapped_pages (void); +#if defined (__CYGWIN__) || defined (__MINGW32__) +extern "C" int mprotect (void *addr, int len, int prot); + + #define PROT_READ 0x1 + #define PROT_WRITE 0x2 +#endif + #endif /* vtv_malloc.h */ diff --git a/libvtv/vtv_map.h b/libvtv/vtv_map.h index ec058f845f7..91665bc773d 100644 --- a/libvtv/vtv_map.h +++ b/libvtv/vtv_map.h @@ -26,7 +26,13 @@ #define _VTV_MAP_H 1 #include + +#ifdef __MINGW32__ +#include +#include "vtv_utils.h" +#else #include +#endif inline uint64_t load8bytes (const void *p) diff --git a/libvtv/vtv_rts.cc b/libvtv/vtv_rts.cc index 1af000d8eb5..f5344a00687 100644 --- a/libvtv/vtv_rts.cc +++ b/libvtv/vtv_rts.cc @@ -121,12 +121,20 @@ #include #include #include +#if defined (__CYGWIN__) || defined (__MINGW32__) +#include +#include +#include +#else #include +#endif #include +#if !defined (__CYGWIN__) && !defined (__MINGW32__) #include -#include #include +#endif +#include #include #include @@ -143,6 +151,13 @@ #include "vtv-change-permission.h" +#if defined (__CYGWIN__) || defined (__MINGW32__) +// porting: fix link error to libc +void __fortify_fail (const char * msg){ + OutputDebugString(msg); + abort(); +} +#else extern "C" { /* __fortify_fail is a function in glibc that calls __libc_message, @@ -159,6 +174,7 @@ extern "C" { extern void __fortify_fail (const char *) __attribute__((noreturn)); } /* extern "C" */ +#endif /* The following variables are used only for debugging and performance tuning purposes. Therefore they do not need to be "protected". @@ -313,10 +329,17 @@ typedef vtv_set_handle * vtv_set_handle_handle; struct sect_hdr_data { +#if defined (__CYGWIN__) || defined (__MINGW32__) + uintptr_t dlpi_addr; /* The header address in the INFO record, + passed in from dl_iterate_phdr. */ + uintptr_t mp_low; /* Start address of the .vtable_map_vars + section in memory. */ +#else 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. */ +#endif size_t mp_size; /* Size of the .vtable_map_vars section in memory. */ }; @@ -336,8 +359,13 @@ unsigned int num_cache_entries VTV_PROTECTED_VAR = 0; it returns the record for that entry; otherwise it returns NULL. */ +#if defined (__CYGWIN__) || defined (__MINGW32__) +struct sect_hdr_data * +search_cached_file_data (uintptr_t load_addr) +#else struct sect_hdr_data * search_cached_file_data (ElfW (Addr) load_addr) +#endif { unsigned int i; for (i = 0; i < num_cache_entries; ++i) @@ -401,6 +429,130 @@ log_memory_protection_data (char *message) __vtv_add_to_log (log_fd, "%s", message); } +#if defined (__CYGWIN__) || defined (__MINGW32__) +static void +read_section_offset_and_length (char *name, + uintptr_t addr, + const char *sect_name, + int mprotect_flags, + off_t *sect_offset, + WORD *sect_len) +{ + bool found = false; + struct sect_hdr_data *cached_data = NULL; + + /* Check to see if we already have the data for this file. */ + cached_data = search_cached_file_data (addr); + + if (cached_data) + { + *sect_offset = cached_data->mp_low; + *sect_len = cached_data->mp_size; + return; + } + + // check for DOS Header magic bytes + if (*(WORD *)addr == 0x5A4D) + { + int name_len = strlen (sect_name); + int fd = -1; + + /* Attempt to open the binary file on disk. */ + if (strlen (name) == 0) + { + return; + } + else + fd = open (name, O_RDONLY | O_BINARY); + + if (fd != -1) + { + /* Find the section header information in memory. */ + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)addr; + PIMAGE_NT_HEADERS pNtHeaders = (PIMAGE_NT_HEADERS)((char *)addr + + pDosHeader->e_lfanew); + PIMAGE_FILE_HEADER pFileHeader = &pNtHeaders->FileHeader; + + DWORD PointerToStringTable = pFileHeader->PointerToSymbolTable + + (pFileHeader->NumberOfSymbols*0x12); + + PIMAGE_SECTION_HEADER sect_hdr = + (PIMAGE_SECTION_HEADER)((char *)&pNtHeaders->OptionalHeader + + pFileHeader->SizeOfOptionalHeader); + + /* Loop through all the section headers, looking for one whose + name is ".vtable_map_vars". */ + + for (int i = 0; i < pFileHeader->NumberOfSections && !found; ++i) + { + char header_name[64]; + + /* Check if we have to get the section name from the COFF string + table. */ + if (sect_hdr[i].Name[0] == '/') + { + if (atoi((const char*)sect_hdr[i].Name+1) == 0) + { + continue; + } + + off_t name_offset = PointerToStringTable + + atoi((const char*)sect_hdr[i].Name+1); + + size_t bytes_read = ReadFromOffset (fd, &header_name, 64, + name_offset); + + VTV_ASSERT (bytes_read > 0); + } + else + { + memcpy (&header_name, sect_hdr[i].Name, + sizeof (sect_hdr[i].Name)); + } + + if (memcmp (header_name, sect_name, name_len) == 0) + { + /* We found the section; get its load offset and + size. */ + *sect_offset = sect_hdr[i].VirtualAddress; + if (sect_hdr[i].Misc.VirtualSize % VTV_PAGE_SIZE != 0) + *sect_len = sect_hdr[i].Misc.VirtualSize + VTV_PAGE_SIZE + - (sect_hdr[i].Misc.VirtualSize % VTV_PAGE_SIZE); + else + *sect_len = sect_hdr[i].Misc.VirtualSize; + found = true; + } + } + close (fd); + } + } + + if (*sect_offset != 0 && *sect_len != 0) + { + /* Calculate the page location in memory, making sure the + address is page-aligned. */ + uintptr_t start_addr = addr + *sect_offset; + *sect_offset = start_addr & ~(VTV_PAGE_SIZE - 1); + *sect_len = *sect_len - 1; + + /* Since we got this far, we must not have found these pages in + the cache, so add them to it. NOTE: We could get here either + while making everything read-only or while making everything + read-write. We will only update the cache if we get here on + a read-write (to make absolutely sure the cache is writable + -- also the read-write pass should come before the read-only + pass). */ + if ((mprotect_flags & PROT_WRITE) + && num_cache_entries < MAX_ENTRIES) + { + vtv_sect_info_cache[num_cache_entries].dlpi_addr = addr; + vtv_sect_info_cache[num_cache_entries].mp_low = *sect_offset; + vtv_sect_info_cache[num_cache_entries].mp_size = *sect_len; + num_cache_entries++; + } + } +} +#else static void read_section_offset_and_length (struct dl_phdr_info *info, const char *sect_name, @@ -547,7 +699,125 @@ read_section_offset_and_length (struct dl_phdr_info *info, } } } +#endif +#if defined (__CYGWIN__) || defined (__MINGW32__) +/* This function is used to iterate over all loaded modules and searches + for a section called ".vtable_map_vars". The only interaction with + the binary file on disk of the module is to read section names in the + COFF string table. If the module contains a ".vtable_map_vars" section, + read section offset and size from the section header of the loaded module. + Call 'mprotect' on those pages, setting the protection either to + read-only or read-write, depending on what's in data. + The calls to change the protection occur in vtv_unprotect_vtable_vars + and vtv_protect_vtable_vars. */ + +static int +iterate_modules (void *data) +{ + int * mprotect_flags = (int *) data; + off_t map_sect_offset = 0; + WORD map_sect_len = 0; + char buffer[1024]; + const char *map_sect_name = VTV_PROTECTED_VARS_SECTION; + HMODULE hMods[1024]; + HANDLE hProcess; + DWORD cbNeeded; + + hProcess = GetCurrentProcess (); + + if (NULL == hProcess) + return 0; + + if (EnumProcessModules (hProcess, hMods, sizeof (hMods), &cbNeeded)) + { + /* Iterate over all loaded modules. */ + for (unsigned int i = 0; i < (cbNeeded / sizeof (HMODULE)); i++) + { + char szModName[MAX_PATH]; + + if (GetModuleFileNameExA (hProcess, hMods[i], szModName, + sizeof (szModName))) + { + map_sect_offset = 0; + map_sect_len = 0; + read_section_offset_and_length (szModName, + (uintptr_t) hMods[i], + map_sect_name, + *mprotect_flags, + &map_sect_offset, + &map_sect_len); + + if (debug_functions) + { + snprintf (buffer, sizeof(buffer), + " Looking at load module %s to change permissions to %s\n", + szModName, + (*mprotect_flags & PROT_WRITE) ? "READ/WRITE" : "READ-ONLY"); + log_memory_protection_data (buffer); + } + + /* See if we actually found the section. */ + if (map_sect_offset && map_sect_len) + { + unsigned long long start; + int result; + + if (debug_functions) + { + snprintf (buffer, sizeof (buffer), + " (%s): Protecting %p to %p\n", + szModName, + (void *) map_sect_offset, + (void *) (map_sect_offset + map_sect_len)); + log_memory_protection_data (buffer); + } + + /* Change the protections on the pages for the section. */ + + start = get_cycle_count (); + result = mprotect ((void *) map_sect_offset, map_sect_len, + *mprotect_flags); + accumulate_cycle_count (&mprotect_cycles, start); + if (result == -1) + { + if (debug_functions) + { + snprintf (buffer, sizeof (buffer), + "Failed called to mprotect for %s error: ", + (*mprotect_flags & 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 *) map_sect_offset, + (char *) map_sect_offset + map_sect_len); + log_memory_protection_data (buffer); + } + } + increment_num_calls (&num_calls_to_mprotect); + /* num_pages_protected += (map_sect_len + VTV_PAGE_SIZE - 1) + / VTV_PAGE_SIZE; */ + num_pages_protected += (map_sect_len + 4096 - 1) / 4096; + continue; + } + } + } + } + + CloseHandle(hProcess); + + return 0; +} +#else /* 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 @@ -652,6 +922,7 @@ dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t, void *data) return 0; } +#endif /* This function explicitly changes the protection (read-only or read-write) on the vtv_sect_info_cache, which is used for speeding up look ups in the @@ -678,7 +949,7 @@ change_protections_on_phdr_cache (int protection_flag) char * low_address = (char *) &(vtv_sect_info_cache); size_t cache_size = MAX_ENTRIES * sizeof (struct sect_hdr_data); - low_address = (char *) ((unsigned long) low_address & ~(VTV_PAGE_SIZE - 1)); + low_address = (char *) ((uintptr_t) low_address & ~(VTV_PAGE_SIZE - 1)); if (mprotect ((void *) low_address, cache_size, protection_flag) == -1) VTV_error (); @@ -695,7 +966,11 @@ vtv_unprotect_vtable_vars (void) mprotect_flags = PROT_READ | PROT_WRITE; change_protections_on_phdr_cache (mprotect_flags); +#if defined (__CYGWIN__) || defined (__MINGW32__) + iterate_modules ((void *) &mprotect_flags); +#else dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mprotect_flags); +#endif } /* Protect all the vtable map vars and other side data that is used @@ -708,7 +983,11 @@ vtv_protect_vtable_vars (void) int mprotect_flags; mprotect_flags = PROT_READ; +#if defined (__CYGWIN__) || defined (__MINGW32__) + iterate_modules ((void *) &mprotect_flags); +#else dl_iterate_phdr (dl_iterate_phdr_callback, (void *) &mprotect_flags); +#endif change_protections_on_phdr_cache (mprotect_flags); } @@ -868,7 +1147,7 @@ const unsigned long SET_HANDLE_HANDLE_BIT = 0x2; static inline bool is_set_handle_handle (void * ptr) { - return ((unsigned long) ptr & SET_HANDLE_HANDLE_BIT) + return ((uintptr_t) ptr & SET_HANDLE_HANDLE_BIT) == SET_HANDLE_HANDLE_BIT; } @@ -878,7 +1157,7 @@ is_set_handle_handle (void * ptr) static inline vtv_set_handle * ptr_from_set_handle_handle (void * ptr) { - return (vtv_set_handle *) ((unsigned long) ptr & ~SET_HANDLE_HANDLE_BIT); + return (vtv_set_handle *) ((uintptr_t) ptr & ~SET_HANDLE_HANDLE_BIT); } /* Given a vtable map variable, PTR, this function sets the bit that @@ -888,7 +1167,7 @@ ptr_from_set_handle_handle (void * ptr) 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); + return (vtv_set_handle_handle) ((uintptr_t) ptr | SET_HANDLE_HANDLE_BIT); } static inline void @@ -1362,6 +1641,7 @@ __VLTVerifyVtablePointer (void ** set_handle_ptr, const void * vtable_ptr) static int page_count_2 = 0; +#if !defined (__CYGWIN__) && !defined (__MINGW32__) static int dl_iterate_phdr_count_pages (struct dl_phdr_info *info, size_t unused __attribute__ ((__unused__)), @@ -1392,6 +1672,7 @@ dl_iterate_phdr_count_pages (struct dl_phdr_info *info, return 0; } +#endif static void count_all_pages (void) @@ -1401,7 +1682,11 @@ count_all_pages (void) mprotect_flags = PROT_READ; page_count_2 = 0; +#if defined (__CYGWIN__) || defined (__MINGW32__) + iterate_modules ((void *) &mprotect_flags); +#else dl_iterate_phdr (dl_iterate_phdr_count_pages, (void *) &mprotect_flags); +#endif page_count_2 += __vtv_count_mmapped_pages (); } diff --git a/libvtv/vtv_utils.cc b/libvtv/vtv_utils.cc index 9cf4b08dc24..ebbeaf51999 100644 --- a/libvtv/vtv_utils.cc +++ b/libvtv/vtv_utils.cc @@ -33,7 +33,12 @@ #include #include #include +#if defined (__CYGWIN__) || defined (__MINGW32__) +#include +#else #include +#endif + #include #include @@ -64,8 +69,12 @@ __vtv_open_log (const char *name) { char log_name[1024]; char log_dir[512]; +#if defined (__CYGWIN__) || defined (__MINGW32__) + pid_t process_id = GetCurrentProcessId (); +#else uid_t user_id = getuid (); pid_t process_id = getpid (); +#endif char *logs_prefix; bool logs_dir_specified = false; int fd = -1; @@ -74,14 +83,29 @@ __vtv_open_log (const char *name) if (logs_prefix && strlen (logs_prefix) > 0) { logs_dir_specified = true; +#ifdef __MINGW32__ + mkdir (logs_prefix); +#else mkdir (logs_prefix, S_IRWXU); - snprintf (log_dir, sizeof (log_dir), "%s/vtv_logs", logs_prefix); - mkdir (log_dir, S_IRWXU); +#endif + snprintf (log_dir, sizeof (log_dir), "%s/vtv_logs", logs_prefix); + +#ifdef __MINGW32__ + mkdir (log_dir); +#else + mkdir (log_dir, S_IRWXU); +#endif +#if defined (__CYGWIN__) || defined (__MINGW32__) + snprintf (log_name, sizeof (log_name), "%s_%d_%s", log_dir, + (unsigned) process_id, name); + fd = open (log_name, O_WRONLY | O_APPEND | O_CREAT, S_IRWXU); +#else snprintf (log_name, sizeof (log_name), "%s/%d_%d_%s", log_dir, (unsigned) user_id, (unsigned) process_id, name); fd = open (log_name, O_WRONLY | O_APPEND | O_CREAT | O_NOFOLLOW, S_IRWXU); +#endif } else fd = dup (2); @@ -125,8 +149,12 @@ __vtv_add_to_log (int log_file, const char * format, ...) va_list ap; va_start (ap, format); +#if defined (__CYGWIN__) || defined (__MINGW32__) + snprintf (output, sizeof (output), "VTV: PID=%ld ", GetCurrentProcessId ()); +#else snprintf (output, sizeof (output), "VTV: PID=%d PPID=%d ", getpid (), getppid ()); +#endif vtv_log_write (log_file, output); vsnprintf (output, sizeof (output), format, ap); vtv_log_write (log_file, output); @@ -151,6 +179,7 @@ __vtv_log_verification_failure (const char *log_msg, bool generate_backtrace) __vtv_add_to_log (vtv_failures_log_fd, "%s", log_msg); +#if !defined (__CYGWIN__) && !defined (__MINGW32__) if (generate_backtrace) { #define STACK_DEPTH 20 @@ -158,4 +187,5 @@ __vtv_log_verification_failure (const char *log_msg, bool generate_backtrace) int actual_depth = backtrace (callers, STACK_DEPTH); backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd); } +#endif }