From patchwork Wed Jan 14 20:28:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Wollgast X-Patchwork-Id: 429078 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 8A7AD140077 for ; Thu, 15 Jan 2015 07:28:42 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=wZvLUHlwMJzrgoHhQ mVu4EOAc6KK4JzSRNLNwCEasNbEkPCZxaymUt7R4WPOyoByOsOCKbI/3HmuucQnk wMW0wA0TqsoYTQlWkQg4tnGtwL8A9vQkKRrMM7WkbmOdKzKorOOml2WY6RDX1ywd I6T671T9PGm4xw25BTF6Kiegb0= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=Le94153y5bxwQsTiQbBCQ+P KPak=; b=VLnXLcQTrU11LBwnudw8Pka+5CR7blg7qfB6zCX08UaHxXpwiGG5r5d wY6h9BemyTn7WptitR3SCJBGGfxqhP1on4wbLZ499gHXTqOnk/Jrt6GaKgeeG1FG GcJiHL9E6W2D6PkobW18NQsdDRqg8o48scUK31ciuJFliWIC/Otc= Received: (qmail 601 invoked by alias); 14 Jan 2015 20:28:34 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 561 invoked by uid 89); 14 Jan 2015 20:28:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.4 required=5.0 tests=AWL, BAYES_00, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mx6.rz.ruhr-uni-bochum.de Received: from mi.ruhr-uni-bochum.de (HELO mx6.rz.ruhr-uni-bochum.de) (134.147.64.30) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with SMTP; Wed, 14 Jan 2015 20:28:19 +0000 X-Queued: (qmail 21664 invoked by alias); 14 Jan 2015 20:28:15 -0000 X-RUB-Notes: Internal X-Queued: (qmail 20945 invoked by uid 108); 14 Jan 2015 20:28:10 -0000 X-Qmailscanner: from 134.147.42.227 by mx6.rz.ruhr-uni-bochum.de (envelope-from , uid 102) with qmail-scanner-2.01 (clamdscan: 0.98.1/18526. Clear:RC:1(134.147.42.227):. Processed in 0.207528 secs); 14 Jan 2015 20:28:10 -0000 Received: from mail1.mail.ruhr-uni-bochum.de (134.147.42.227) by mx6.rz.ruhr-uni-bochum.de with SMTP; 14 Jan 2015 20:28:10 -0000 Received: from [192.168.178.57] (p5B34DE5E.dip0.t-ipconnect.de [91.52.222.94]) (Authenticated sender: wollgpsz) by mail1.mail.ruhr-uni-bochum.de (Postfix) with ESMTPSA id 5A2BB200D9; Wed, 14 Jan 2015 21:28:09 +0100 (CET) Message-ID: <54B6D159.4000002@rub.de> Date: Wed, 14 Jan 2015 21:28:09 +0100 From: Patrick Wollgast User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.3.0 MIME-Version: 1.0 To: Ian Lance Taylor CC: Kai Tietz , "cmtice@google.com >> Caroline Tice" , bkoz@gnu.org, "jwakely@redhat.com >> Jonathan Wakely" , gcc-patches , "libstdc++@gcc.gnu.org" Subject: Re: [Ping] Port of VTV for Cygwin and MinGW References: <53FF0C8C.8090507@rub.de> <5411213F.1070104@rub.de> <541B5B7E.2090300@rub.de> <20140923102235.GJ2669@redhat.com> <542344CB.6050600@rub.de> <54369316.7070001@rub.de> <543F9BB8.1040503@rub.de> <54524B43.7000105@rub.de> <5463893D.50807@rub.de> <54639CC5.4050508@rub.de> <5476F20C.5010801@rub.de> <548876B5.70306@rub.de> <54A99E34.2010202@rub.de> <54AEE9B0.3010407@rub.de> In-Reply-To: On 14.01.2015 20:00, Ian Lance Taylor wrote: > On Thu, Jan 8, 2015 at 12:33 PM, Patrick Wollgast > wrote: >> A short recap again: >> >> Latest patch, changelog and a test program (further information about >> the program in the mail): >> https://gcc.gnu.org/ml/gcc-patches/2014-11/msg03368.html > > In that patch, the change to varasm.c looks wrong if neither > OBJECT_FORMAT_ELF nor TARGET_PECOFF are defined. It looks like you've > dropped the switch_to_section call in that case. > > Ian > You're right. It should have been '#else' again, instead of 'else' before the switch_to_section call. Regards, Patrick Index: gcc/config/i386/cygwin.h =================================================================== --- gcc/config/i386/cygwin.h (Revision 214408) +++ gcc/config/i386/cygwin.h (Arbeitskopie) @@ -41,12 +41,18 @@ along with GCC; see the file COPYING3. #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. %{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 Index: gcc/config/i386/mingw-w64.h =================================================================== --- gcc/config/i386/mingw-w64.h (Revision 214408) +++ gcc/config/i386/mingw-w64.h (Arbeitskopie) @@ -32,7 +32,10 @@ along with GCC; see the file COPYING3. %{!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. #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 Index: gcc/config/i386/mingw32.h =================================================================== --- gcc/config/i386/mingw32.h (Revision 214408) +++ gcc/config/i386/mingw32.h (Arbeitskopie) @@ -91,6 +91,8 @@ along with GCC; see the file COPYING3. #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. #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. */ Index: gcc/cp/vtable-class-hierarchy.c =================================================================== --- gcc/cp/vtable-class-hierarchy.c (Revision 214408) +++ gcc/cp/vtable-class-hierarchy.c (Arbeitskopie) @@ -1182,7 +1182,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); @@ -1190,7 +1194,11 @@ vtv_generate_init_routine (void) cgraph_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); } Index: gcc/varasm.c =================================================================== --- gcc/varasm.c (Revision 214408) +++ gcc/varasm.c (Arbeitskopie) @@ -2164,6 +2164,33 @@ assemble_variable (tree decl, int top_le | 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 Index: libgcc/Makefile.in =================================================================== --- libgcc/Makefile.in (Revision 214408) +++ libgcc/Makefile.in (Arbeitskopie) @@ -986,6 +986,7 @@ crtendS$(objext): $(srcdir)/crtstuff.c # This is a version of crtbegin for -static links. crtbeginT$(objext): $(srcdir)/crtstuff.c $(crt_compile) $(CRTSTUFF_T_CFLAGS) -c $< -DCRT_BEGIN -DCRTSTUFFT_O +endif ifeq ($(enable_vtable_verify),yes) # These are used in vtable verification; see comments in source files for @@ -1002,7 +1003,6 @@ vtv_start_preinit$(objext): $(srcdir)/vt 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. Index: libgcc/config.host =================================================================== --- libgcc/config.host (Revision 214408) +++ libgcc/config.host (Arbeitskopie) @@ -615,6 +615,9 @@ i[4567]86-wrs-vxworks|i[4567]86-wrs-vxwo ;; 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" @@ -631,6 +634,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" @@ -648,6 +654,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" @@ -694,6 +703,9 @@ x86_64-*-mingw*) fi tmake_file="${tmake_file} ${tmake_eh_file} ${tmake_dlldir_file} i386/t-slibgcc-cygming i386/t-mingw32 t-dfprules i386/t-crtfm i386/t-chkstk" extra_parts="$extra_parts 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" Index: libstdc++-v3/acinclude.m4 =================================================================== --- libstdc++-v3/acinclude.m4 (Revision 214408) +++ libstdc++-v3/acinclude.m4 (Arbeitskopie) @@ -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 Index: libstdc++-v3/libsupc++/Makefile.am =================================================================== --- libstdc++-v3/libsupc++/Makefile.am (Revision 214408) +++ libstdc++-v3/libsupc++/Makefile.am (Arbeitskopie) @@ -98,9 +98,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) Index: libstdc++-v3/libsupc++/vtv_stubs.cc =================================================================== --- libstdc++-v3/libsupc++/vtv_stubs.cc (Revision 214408) +++ libstdc++-v3/libsupc++/vtv_stubs.cc (Arbeitskopie) @@ -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" Index: libstdc++-v3/src/Makefile.am =================================================================== --- libstdc++-v3/src/Makefile.am (Revision 214408) +++ libstdc++-v3/src/Makefile.am (Arbeitskopie) @@ -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 Index: libvtv/Makefile.am =================================================================== --- libvtv/Makefile.am (Revision 214408) +++ libvtv/Makefile.am (Arbeitskopie) @@ -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) Index: libvtv/configure.ac =================================================================== --- libvtv/configure.ac (Revision 214408) +++ libvtv/configure.ac (Arbeitskopie) @@ -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 Index: libvtv/configure.tgt =================================================================== --- libvtv/configure.tgt (Revision 214408) +++ libvtv/configure.tgt (Arbeitskopie) @@ -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*) Index: libvtv/vtv_fail.cc =================================================================== --- libvtv/vtv_fail.cc (Revision 214408) +++ libvtv/vtv_fail.cc (Arbeitskopie) @@ -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, { #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 } } Index: libvtv/vtv_malloc.cc =================================================================== --- libvtv/vtv_malloc.cc (Revision 214408) +++ libvtv/vtv_malloc.cc (Arbeitskopie) @@ -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 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; Index: libvtv/vtv_malloc.h =================================================================== --- libvtv/vtv_malloc.h (Revision 214408) +++ libvtv/vtv_malloc.h (Arbeitskopie) @@ -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 */ Index: libvtv/vtv_map.h =================================================================== --- libvtv/vtv_map.h (Revision 214408) +++ libvtv/vtv_map.h (Arbeitskopie) @@ -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) Index: libvtv/vtv_rts.cc =================================================================== --- libvtv/vtv_rts.cc (Revision 214408) +++ libvtv/vtv_rts.cc (Arbeitskopie) @@ -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_ 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_PROTE 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 *messag __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 d } } } +#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 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 pr 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_BI 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_ha 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_p 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 (); } Index: libvtv/vtv_utils.cc =================================================================== --- libvtv/vtv_utils.cc (Revision 214408) +++ libvtv/vtv_utils.cc (Arbeitskopie) @@ -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); +#endif + snprintf (log_dir, sizeof (log_dir), "%s/vtv_logs", logs_prefix); - mkdir (log_dir, S_IRWXU); +#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 ch 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 ch __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 ch int actual_depth = backtrace (callers, STACK_DEPTH); backtrace_symbols_fd (callers, actual_depth, vtv_failures_log_fd); } +#endif }