| #!/bin/bash |
| # Copyright 1999-2011 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| |
| source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh |
| |
| # avoid multiple calls to `has`. this creates things like: |
| # FEATURES_foo=false |
| # if "foo" is not in $FEATURES |
| tf() { "$@" && echo true || echo false ; } |
| exp_tf() { |
| local flag var=$1 |
| shift |
| for flag in "$@" ; do |
| eval ${var}_${flag}=$(tf has ${flag} ${!var}) |
| done |
| } |
| exp_tf FEATURES compressdebug installsources nostrip splitdebug |
| exp_tf RESTRICT binchecks installsources strip |
| |
| [[ " ${FEATURES} " == *" force-prefix "* ]] || \ |
| case "$EAPI" in 0|1|2) EPREFIX= ED=${D} ;; esac |
| |
| banner=false |
| SKIP_STRIP=false |
| if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then |
| SKIP_STRIP=true |
| banner=true |
| ${FEATURES_installsources} || exit 0 |
| fi |
| |
| # look up the tools we might be using |
| for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do |
| v=${t%:*} # STRIP |
| t=${t#*:} # strip |
| eval ${v}=\"${!v:-${CHOST}-${t}}\" |
| type -P -- ${!v} >/dev/null || eval ${v}=${t} |
| done |
| |
| # Figure out what tool set we're using to strip stuff |
| unset SAFE_STRIP_FLAGS DEF_STRIP_FLAGS SPLIT_STRIP_FLAGS |
| case $(${STRIP} --version 2>/dev/null) in |
| *elfutils*) # dev-libs/elfutils |
| # elfutils default behavior is always safe, so don't need to specify |
| # any flags at all |
| SAFE_STRIP_FLAGS="" |
| DEF_STRIP_FLAGS="--remove-comment" |
| SPLIT_STRIP_FLAGS="-f" |
| ;; |
| *GNU*) # sys-devel/binutils |
| # We'll leave out -R .note for now until we can check out the relevance |
| # of the section when it has the ALLOC flag set on it ... |
| SAFE_STRIP_FLAGS="--strip-unneeded" |
| DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line" |
| SPLIT_STRIP_FLAGS= |
| ;; |
| esac |
| : ${PORTAGE_STRIP_FLAGS=${SAFE_STRIP_FLAGS} ${DEF_STRIP_FLAGS}} |
| |
| prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF} |
| |
| type -P debugedit >/dev/null && debugedit_found=true || debugedit_found=false |
| debugedit_warned=false |
| |
| unset ${!INODE_*} |
| |
| inode_var_name() { |
| if [[ $USERLAND = BSD ]] ; then |
| stat -f 'INODE_%d_%i' "$1" |
| else |
| stat -c 'INODE_%d_%i' "$1" |
| fi |
| } |
| |
| save_elf_sources() { |
| ${FEATURES_installsources} || return 0 |
| ${RESTRICT_installsources} && return 0 |
| if ! ${debugedit_found} ; then |
| if ! ${debugedit_warned} ; then |
| debugedit_warned=true |
| ewarn "FEATURES=installsources is enabled but the debugedit binary could not" |
| ewarn "be found. This feature will not work unless debugedit is installed!" |
| fi |
| return 0 |
| fi |
| |
| local x=$1 |
| local inode=$(inode_var_name "$x") |
| [[ -n ${!inode} ]] && return 0 |
| |
| # since we're editing the ELF here, we should recompute the build-id |
| # (the -i flag below). save that output so we don't need to recompute |
| # it later on in the save_elf_debug step. |
| buildid=$(debugedit -i \ |
| -b "${WORKDIR}" \ |
| -d "${prepstrip_sources_dir}" \ |
| -l "${T}"/debug.sources \ |
| "${x}") |
| } |
| |
| save_elf_debug() { |
| ${FEATURES_splitdebug} || return 0 |
| |
| # NOTE: Debug files must be installed in |
| # ${EPREFIX}/usr/lib/debug/${EPREFIX} (note that ${EPREFIX} occurs |
| # twice in this path) in order for gdb's debug-file-directory |
| # lookup to work correctly. |
| local x=$1 |
| local y=${ED}usr/lib/debug/${x:${#D}}.debug |
| |
| # dont save debug info twice |
| [[ ${x} == *".debug" ]] && return 0 |
| |
| mkdir -p "${y%/*}" |
| |
| local inode=$(inode_var_name "$x") |
| if [[ -n ${!inode} ]] ; then |
| ln "${ED}usr/lib/debug/${!inode:${#D}}.debug" "$y" |
| else |
| eval $inode=\$x |
| if [[ -e ${T}/prepstrip.split.debug ]] ; then |
| mv "${T}"/prepstrip.split.debug "${y}" |
| else |
| local objcopy_flags="--only-keep-debug" |
| ${FEATURES_compressdebug} && objcopy_flags+=" --compress-debug-sections" |
| ${OBJCOPY} ${objcopy_flags} "${x}" "${y}" |
| ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}" |
| fi |
| local args="a-x,o-w" |
| [[ -g ${x} || -u ${x} ]] && args+=",go-r" |
| chmod ${args} "${y}" |
| fi |
| |
| # if we don't already have build-id from debugedit, look it up |
| if [[ -z ${buildid} ]] ; then |
| # convert the readelf output to something useful |
| buildid=$(${READELF} -x .note.gnu.build-id "${x}" 2>/dev/null \ |
| | awk '$NF ~ /GNU/ { getline; printf $2$3$4$5; getline; print $2 }') |
| fi |
| if [[ -n ${buildid} ]] ; then |
| local buildid_dir="${ED}usr/lib/debug/.build-id/${buildid:0:2}" |
| local buildid_file="${buildid_dir}/${buildid:2}" |
| mkdir -p "${buildid_dir}" |
| ln -s "../../${x:${#D}}.debug" "${buildid_file}.debug" |
| ln -s "/${x:${#D}}" "${buildid_file}" |
| fi |
| } |
| |
| process_elf() { |
| local x=$1 strip_flags=${*:2} |
| |
| vecho " ${x:${#ED}}" |
| save_elf_sources "${x}" |
| |
| if ${strip_this} ; then |
| # see if we can split & strip at the same time |
| if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then |
| ${STRIP} ${strip_flags} \ |
| -f "${T}"/prepstrip.split.debug \ |
| -F "${x##*/}.debug" \ |
| "${x}" |
| save_elf_debug "${x}" |
| else |
| save_elf_debug "${x}" |
| ${STRIP} ${strip_flags} "${x}" |
| fi |
| fi |
| } |
| |
| # The existance of the section .symtab tells us that a binary is stripped. |
| # We want to log already stripped binaries, as this may be a QA violation. |
| # They prevent us from getting the splitdebug data. |
| if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then |
| log=$T/scanelf-already-stripped.log |
| qa_var="QA_PRESTRIPPED_${ARCH/-/_}" |
| [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}" |
| scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED}##" > "$log" |
| if [[ -n $QA_PRESTRIPPED && -s $log && \ |
| ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then |
| shopts=$- |
| set -o noglob |
| for x in $QA_PRESTRIPPED ; do |
| sed -e "s#^${x#/}\$##" -i "$log" |
| done |
| set +o noglob |
| set -$shopts |
| fi |
| sed -e "/^\$/d" -e "s#^#/#" -i "$log" |
| if [[ -s $log ]] ; then |
| vecho -e "\n" |
| eqawarn "QA Notice: Pre-stripped files found:" |
| eqawarn "$(<"$log")" |
| else |
| rm -f "$log" |
| fi |
| fi |
| |
| # Now we look for unstripped binaries. |
| for x in \ |
| $(scanelf -yqRBF '#k%F' -k '.symtab' "$@") \ |
| $(find "$@" -type f -name '*.a') |
| do |
| if ! ${banner} ; then |
| vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}" |
| banner=true |
| fi |
| |
| f=$(file "${x}") || continue |
| [[ -z ${f} ]] && continue |
| |
| if ! ${SKIP_STRIP} ; then |
| # The noglob funk is to support STRIP_MASK="/*/booga" and to keep |
| # the for loop from expanding the globs. |
| # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex. |
| set -o noglob |
| strip_this=true |
| for m in $(eval echo ${STRIP_MASK}) ; do |
| [[ /${x#${ED}} == ${m} ]] && strip_this=false && break |
| done |
| set +o noglob |
| else |
| strip_this=false |
| fi |
| |
| # In Prefix we are usually an unprivileged user, so we can't strip |
| # unwritable objects. Make them temporarily writable for the |
| # stripping. |
| was_not_writable=false |
| if [[ ! -w ${x} ]] ; then |
| was_not_writable=true |
| chmod u+w "${x}" |
| fi |
| |
| # only split debug info for final linked objects |
| # or kernel modules as debuginfo for intermediatary |
| # files (think crt*.o from gcc/glibc) is useless and |
| # actually causes problems. install sources for all |
| # elf types though cause that stuff is good. |
| |
| buildid= |
| if [[ ${f} == *"current ar archive"* ]] ; then |
| vecho " ${x:${#ED}}" |
| if ${strip_this} ; then |
| # hmm, can we split debug/sources for .a ? |
| ${STRIP} -g "${x}" |
| fi |
| elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then |
| process_elf "${x}" ${PORTAGE_STRIP_FLAGS} |
| elif [[ ${f} == *"SB relocatable"* ]] ; then |
| process_elf "${x}" ${SAFE_STRIP_FLAGS} |
| fi |
| |
| if ${was_not_writable} ; then |
| chmod u-w "${x}" |
| fi |
| done |
| |
| if [[ -s ${T}/debug.sources ]] && \ |
| ${FEATURES_installsources} && \ |
| ! ${RESTRICT_installsources} && \ |
| ${debugedit_found} |
| then |
| vecho "installsources: rsyncing source files" |
| [[ -d ${D}${prepstrip_sources_dir} ]] || mkdir -p "${D}${prepstrip_sources_dir}" |
| grep -zv '/<[^/>]*>$' "${T}"/debug.sources | \ |
| (cd "${WORKDIR}"; LANG=C sort -z -u | \ |
| rsync -tL0 --files-from=- "${WORKDIR}/" "${D}${prepstrip_sources_dir}/" ) |
| |
| # Preserve directory structure. |
| # Needed after running save_elf_sources. |
| # https://bugzilla.redhat.com/show_bug.cgi?id=444310 |
| while read -r -d $'\0' emptydir |
| do |
| >> "$emptydir"/.keepdir |
| done < <(find "${D}${prepstrip_sources_dir}/" -type d -empty -print0) |
| fi |