summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Haubenwallner <haubi@gentoo.org>2019-05-06 11:43:11 +0200
committerMichael Haubenwallner <haubi@gentoo.org>2019-05-07 10:05:53 +0200
commit949b7a9801e59a2317cd68da53bdae344cd3e417 (patch)
tree0fd4d4c9debf7fe8f9283d827cc9189063ba1801 /profiles/prefix
parentprefix/cygwin/profile.bashrc: add pre/post pkg_* hook stubs (diff)
downloadgentoo-949b7a9801e59a2317cd68da53bdae344cd3e417.tar.gz
gentoo-949b7a9801e59a2317cd68da53bdae344cd3e417.tar.bz2
gentoo-949b7a9801e59a2317cd68da53bdae344cd3e417.zip
prefix/cygwin/profile.bashrc: add the Cygwin rebase hook
The Cygwin fork can work more reliable when each DLL is loaded at it's preferred base address. The Cygwin rebase hook does maintain these preferred base addresses to be unique across all installed DLLs, using the app-admin/cygwin-rebase utility. Signed-off-by: Michael Haubenwallner <haubi@gentoo.org>
Diffstat (limited to 'profiles/prefix')
-rw-r--r--profiles/prefix/windows/cygwin/profile.bashrc187
1 files changed, 184 insertions, 3 deletions
diff --git a/profiles/prefix/windows/cygwin/profile.bashrc b/profiles/prefix/windows/cygwin/profile.bashrc
index dd7e59f331a2..aecfd9adb7c0 100644
--- a/profiles/prefix/windows/cygwin/profile.bashrc
+++ b/profiles/prefix/windows/cygwin/profile.bashrc
@@ -25,13 +25,194 @@ post_pkg_prerm() {
}
cygwin-post_pkg_preinst() {
- :
+ cygwin-rebase-post_pkg_preinst
}
cygwin-pre_pkg_postinst() {
- :
+ cygwin-rebase-pre_pkg_postinst
}
cygwin-post_pkg_prerm() {
- :
+ cygwin-rebase-post_pkg_prerm
+}
+
+###############################################################################
+# To allow a Windows DLL to reside in memory just once for multiple processes,
+# each process needs to be able to map that DLL at the same base address,
+# without the need for a dynamic rebase. However, this requires the DLL's
+# base address to be unique across all DLLs potentially loaded into a single
+# process. Hence the PE/COFF binary format allows to define a preferred base
+# address for DLLs, but leaves it up to the package manager to maintain that
+# base address to be unique across all DLLs related together.
+# (Not sure how exactly ASLR plays in here, though.)
+#
+# Furthermore, for the Cygwin fork, it is crucial that the child process is
+# able to reload a DLL at the very same address as in the parent process.
+# Having unique preferred base addresses across all related DLLs does help
+# here as well.
+#
+# The Cygwin rebase utility does maintain some database holding the size and
+# preferred base address for each DLL, and allows to update a DLL's preferred
+# base address to not conflict with already installed DLLs.
+#
+# As updating the preferred base address for a DLL in use is a bad idea, we
+# need to update the base address while the DLL is in staging directory, and
+# update the rebase database after merging the DLL to the live file system.
+#
+# This allows to define a new preferred base address for a DLL that would
+# replace an existing one, because during fork we really want to use the
+# old version in the child process, which is verified using the preferred
+# base address value to be identical in parent and child process.
+#
+# Otherwise, the new DLL may have identical size and preferred base address
+# as the old DLL, and we may not detect a different DLL in the fork child.
+#
+# For unmerging a DLL: The Cygwin rebase utility does check if a DLL found
+# in the database does still exist, removing that database entry otherwise.
+###############################################################################
+
+cygwin-rebase-get_pendingdir() {
+ echo "var/db/rebase/pending"
+}
+
+cygwin-rebase-get_mergeddir() {
+ echo "var/db/rebase/merged"
+}
+
+cygwin-rebase-get_listname() {
+ echo "dlls_${CATEGORY}_${P}${PR:+-}${PR}"
+}
+
+cygwin-rebase-get_rebase_program() {
+ [[ ${CHOST} == "${CBUILD}" ]] || return 1
+ local pfx
+ for pfx in "${EPREFIX}" "${BROOT:-${PORTAGE_OVERRIDE_EPREFIX}}"
+ do
+ [[ -x ${pfx}/usr/bin/rebase ]] || continue
+ echo "${pfx}/usr/bin/rebase"
+ return 0
+ done
+ return 1
+}
+
+cygwin-rebase-post_pkg_preinst() {
+ # Ensure database is up to date for when dlls were merged but
+ # subsequent cygwin-rebase-merge-pending was not executed.
+ einfo "Cygwin: Merging pending files into rebase database..."
+ cygwin-rebase-merge pending
+ eend $?
+
+ local listname=$(cygwin-rebase-get_listname)
+ local pendingdir=$(cygwin-rebase-get_pendingdir)
+ local rebase_program=$(cygwin-rebase-get_rebase_program)
+
+ if [[ ${CATEGORY}/${PN} == 'app-admin/cygwin-rebase' ]]
+ then
+ local mergeddir=$(cygwin-rebase-get_mergeddir)
+ keepdir "/${pendingdir}"
+ keepdir "/${mergeddir}"
+ fi
+
+ einfo "Cygwin: Rebasing new files..."
+ (
+ set -e
+ cd "${ED}"
+
+ # The list of suffixes is found in the rebaseall script.
+ find . -type f \
+ '(' -name '*.dll' \
+ -o -name '*.so' \
+ -o -name '*.oct' \
+ ')' \
+ | sed -e "s|^\.|${EPREFIX}|" > "${T}/rebase-filelist"
+ [[ "${PIPESTATUS[*]}" == '0 0' ]]
+
+ # Nothing found to rebase in this package.
+ [[ -s ${T}/rebase-filelist ]] || exit 0
+
+ mkdir -p "./${pendingdir}"
+ cp -f "${T}/rebase-filelist" "./${pendingdir}/${listname}"
+
+ # Without the rebase program, do not perform a rebase.
+ [[ ${rebase_program} ]] || exit 0
+
+ sed -ne "/^${EPREFIX//\//\\/}\\//{s|^${EPREFIX}/||;p}" "./${pendingdir}/${listname}" \
+ | "${rebase_program}" --verbose --oblivious --database --filelist=-
+ [[ "${PIPESTATUS[*]}" == '0 0' ]]
+ )
+ eend $?
+}
+
+cygwin-rebase-pre_pkg_postinst() {
+ if [[ ${CATEGORY}/${PN} == 'app-admin/cygwin-rebase' ]]
+ then
+ einfo "Cygwin: Updating rebase database with installed files..."
+ cygwin-rebase-merge merged
+ eend $?
+ fi
+ einfo "Cygwin: Merging updated files into rebase database..."
+ cygwin-rebase-merge pending
+ eend $?
+}
+
+cygwin-rebase-merge() {
+ local mode=${1}
+
+ local rebase_program=$(cygwin-rebase-get_rebase_program)
+ [[ ${rebase_program} ]] || return 0
+
+ local pendingdir=''
+ local mergeddir=''
+ case ${mode} in
+ pending)
+ pendingdir=$(cygwin-rebase-get_pendingdir)
+ mergeddir=$(cygwin-rebase-get_mergeddir)
+ ;;
+ merged)
+ pendingdir=$(cygwin-rebase-get_mergeddir)
+ mergeddir=''
+ ;;
+ *)
+ die "Invalid mode '${mode}'."
+ ;;
+ esac
+
+ (
+ set -e
+ cd "${EROOT}"
+
+ [[ -r ./${pendingdir}/. ]]
+ [[ -r ./${mergeddir}/. ]]
+
+ find ./"${pendingdir}" -mindepth 1 -maxdepth 1 -type f -name 'dlls_*' \
+ -exec sed -ne "/^${EPREFIX//\//\\/}\\//{s|^${EPREFIX}/||;p}" {} + \
+ | "${rebase_program}" --verbose --merge-files --database --filelist=-
+ [[ "${PIPESTATUS[*]}" == '0 0' ]]
+
+ [[ ${mode} == 'pending' ]] || exit 0
+
+ find "./${pendingdir}" -maxdepth 1 -type f \
+ -exec mv -f -t "./${mergeddir}/" {} +
+ )
+ [[ $? == 0 ]] || die "Merging ${mode} files into rebase database failed."
+}
+
+cygwin-rebase-post_pkg_prerm() {
+ # The pending list is installed as part of the package, but
+ # the merged list is not. Move from merged back to pending,
+ # in case the unmerge fails...
+ local pendingdir=$(cygwin-rebase-get_pendingdir)
+ local mergeddir=$(cygwin-rebase-get_mergeddir)
+ local listname=$(cygwin-rebase-get_listname)
+ (
+ set -e
+ cd "${EROOT}"
+ [[ -w ./${mergeddir}/. ]]
+ [[ -w ./${pendingdir}/. ]]
+ if [[ -s ./${mergeddir}/${listname} ]]
+ then
+ mv -f "./${mergeddir}/${listname}" "./${pendingdir}/${listname}" || :
+ fi
+ rm -f "./${mergeddir}/${listname}"
+ )
}