085c93d56b9a72e6153a72d78b4dead1ef4ec100
[portage.git] / bin / ebuild-helpers / prepstrip
1 #!/bin/bash
2 # Copyright 1999-2011 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
6
7 # avoid multiple calls to `has`.  this creates things like:
8 #   FEATURES_foo=false
9 # if "foo" is not in $FEATURES
10 tf() { "$@" && echo true || echo false ; }
11 exp_tf() {
12         local flag var=$1
13         shift
14         for flag in "$@" ; do
15                 eval ${var}_${flag}=$(tf has ${flag} ${!var})
16         done
17 }
18 exp_tf FEATURES installsources nostrip splitdebug
19 exp_tf RESTRICT binchecks installsources strip
20
21 [[ " ${USE} " == *" prefix "* ]] || \
22         case "$EAPI" in 0|1|2) ED=${D} ;; esac
23
24 banner=false
25 SKIP_STRIP=false
26 if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then
27         SKIP_STRIP=true
28         banner=true
29         ${FEATURES_installsources} || exit 0
30 fi
31
32 # look up the tools we might be using
33 for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do
34         v=${t%:*} # STRIP
35         t=${t#*:} # strip
36         eval ${v}=\"${!v:-${CHOST}-${t}}\"
37         type -P -- ${!v} >/dev/null || eval ${v}=${t}
38 done
39
40 # Figure out what tool set we're using to strip stuff
41 unset SAFE_STRIP_FLAGS DEF_STRIP_FLAGS SPLIT_STRIP_FLAGS
42 case $(${STRIP} --version 2>/dev/null) in
43 *elfutils*) # dev-libs/elfutils
44         # elfutils default behavior is always safe, so don't need to specify
45         # any flags at all
46         SAFE_STRIP_FLAGS=""
47         DEF_STRIP_FLAGS="--remove-comment"
48         SPLIT_STRIP_FLAGS="-f"
49         ;;
50 *GNU*) # sys-devel/binutils
51         # We'll leave out -R .note for now until we can check out the relevance
52         # of the section when it has the ALLOC flag set on it ...
53         SAFE_STRIP_FLAGS="--strip-unneeded"
54         DEF_STRIP_FLAGS="-R .comment"
55         SPLIT_STRIP_FLAGS=
56         ;;
57 esac
58 : ${PORTAGE_STRIP_FLAGS=${SAFE_STRIP_FLAGS} ${DEF_STRIP_FLAGS}}
59
60 prepstrip_sources_dir=/usr/src/debug/${CATEGORY}/${PF}
61
62 type -P debugedit >/dev/null && debugedit_found=true || debugedit_found=false
63 debugedit_warned=false
64
65 unset ${!INODE_*}
66
67 inode_var_name() {
68         if  [[ $USERLAND = BSD ]] ; then
69                 stat -f 'INODE_%d_%i' "$1"
70         else
71                 stat -c 'INODE_%d_%i' "$1"
72         fi
73 }
74
75 save_elf_sources() {
76         ${FEATURES_installsources} || return 0
77         ${RESTRICT_installsources} && return 0
78         if ! ${debugedit_found} ; then
79                 if ! ${debugedit_warned} ; then
80                         debugedit_warned=true
81                         ewarn "FEATURES=installsources is enabled but the debugedit binary could not"
82                         ewarn "be found. This feature will not work unless debugedit is installed!"
83                 fi
84                 return 0
85         fi
86
87         local x=$1
88         local inode=$(inode_var_name "$x")
89         [[ -n ${!inode} ]] && return 0
90
91         # since we're editing the ELF here, we should recompute the build-id
92         # (the -i flag below).  save that output so we don't need to recompute
93         # it later on in the save_elf_debug step.
94         buildid=$(debugedit -i \
95                 -b "${WORKDIR}" \
96                 -d "${prepstrip_sources_dir}" \
97                 -l "${T}"/debug.sources \
98                 "${x}")
99 }
100
101 save_elf_debug() {
102         ${FEATURES_splitdebug} || return 0
103
104         local x=$1
105         local y="${ED}usr/lib/debug/${x:${#ED}}.debug"
106
107         # dont save debug info twice
108         [[ ${x} == *".debug" ]] && return 0
109
110         mkdir -p "${y%/*}"
111
112         local inode=$(inode_var_name "$x")
113         if [[ -n ${!inode} ]] ; then
114                 ln "${ED}usr/lib/debug/${!inode:${#ED}}.debug" "$y"
115         else
116                 eval $inode=\$x
117                 if [[ -e ${T}/prepstrip.split.debug ]] ; then
118                         mv "${T}"/prepstrip.split.debug "${y}"
119                 else
120                         ${OBJCOPY} --only-keep-debug "${x}" "${y}"
121                         ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
122                 fi
123                 local args="a-x,o-w"
124                 [[ -g ${x} || -u ${x} ]] && args+=",go-r"
125                 chmod ${args} "${y}"
126         fi
127
128         # if we don't already have build-id from debugedit, look it up
129         if [[ -z ${buildid} ]] ; then
130                 # convert the readelf output to something useful
131                 buildid=$(${READELF} -x .note.gnu.build-id "${x}" 2>/dev/null \
132                         | awk '$NF ~ /GNU/ { getline; printf $2$3$4$5; getline; print $2 }')
133         fi
134         if [[ -n ${buildid} ]] ; then
135                 local buildid_dir="${ED}usr/lib/debug/.build-id/${buildid:0:2}"
136                 local buildid_file="${buildid_dir}/${buildid:2}"
137                 mkdir -p "${buildid_dir}"
138                 ln -s "../../${x:${#ED}}.debug" "${buildid_file}.debug"
139                 ln -s "/${x:${#ED}}" "${buildid_file}"
140         fi
141 }
142
143 process_elf() {
144         local x=$1 strip_flags=${*:2}
145
146         vecho "   ${x:${#ED}}"
147         save_elf_sources "${x}"
148
149         if ${strip_this} ; then
150                 # see if we can split & strip at the same time
151                 if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then
152                         ${STRIP} ${strip_flags} \
153                                 -f "${T}"/prepstrip.split.debug \
154                                 -F "${x##*/}.debug" \
155                                 "${x}"
156                         save_elf_debug "${x}"
157                 else
158                         save_elf_debug "${x}"
159                         ${STRIP} ${strip_flags} "${x}"
160                 fi
161         fi
162 }
163
164 # The existance of the section .symtab tells us that a binary is stripped.
165 # We want to log already stripped binaries, as this may be a QA violation.
166 # They prevent us from getting the splitdebug data.
167 if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then
168         log=$T/scanelf-already-stripped.log
169         qa_var="QA_PRESTRIPPED_${ARCH/-/_}"
170         [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}"
171         scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED}##" > "$log"
172         if [[ -n $QA_PRESTRIPPED && -s $log && \
173                 ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then
174                 shopts=$-
175                 set -o noglob
176                 for x in $QA_PRESTRIPPED ; do
177                         sed -e "s#^${x#/}\$##" -i "$log"
178                 done
179                 set +o noglob
180                 set -$shopts
181         fi
182         sed -e "/^\$/d" -e "s#^#/#" -i "$log"
183         if [[ -s $log ]] ; then
184                 vecho -e "\n"
185                 eqawarn "QA Notice: Pre-stripped files found:"
186                 eqawarn "$(<"$log")"
187         else
188                 rm -f "$log"
189         fi
190 fi
191
192 # Now we look for unstripped binaries.
193 for x in \
194         $(scanelf -yqRBF '#k%F' -k '.symtab' "$@") \
195         $(find "$@" -type f -name '*.a')
196 do
197         if ! ${banner} ; then
198                 vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
199                 banner=true
200         fi
201
202         f=$(file "${x}") || continue
203         [[ -z ${f} ]] && continue
204
205         if ! ${SKIP_STRIP} ; then
206                 # The noglob funk is to support STRIP_MASK="/*/booga" and to keep
207                 #  the for loop from expanding the globs.
208                 # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
209                 set -o noglob
210                 strip_this=true
211                 for m in $(eval echo ${STRIP_MASK}) ; do
212                         [[ /${x#${ED}} == ${m} ]] && strip_this=false && break
213                 done
214                 set +o noglob
215         else
216                 strip_this=false
217         fi
218
219         # only split debug info for final linked objects
220         # or kernel modules as debuginfo for intermediatary
221         # files (think crt*.o from gcc/glibc) is useless and
222         # actually causes problems.  install sources for all
223         # elf types though cause that stuff is good.
224
225         buildid=
226         if [[ ${f} == *"current ar archive"* ]] ; then
227                 vecho "   ${x:${#ED}}"
228                 if ${strip_this} ; then
229                         # hmm, can we split debug/sources for .a ?
230                         ${STRIP} -g "${x}"
231                 fi
232         elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
233                 process_elf "${x}" ${PORTAGE_STRIP_FLAGS}
234         elif [[ ${f} == *"SB relocatable"* ]] ; then
235                 process_elf "${x}" ${SAFE_STRIP_FLAGS}
236         fi
237 done
238
239 if [[ -s ${T}/debug.sources ]] && \
240    ${FEATURES_installsources} && \
241    ! ${RESTRICT_installsources} && \
242    ${debugedit_found}
243 then
244         vecho "installsources: rsyncing source files"
245         [[ -d ${ED}${prepstrip_sources_dir} ]] || mkdir -p "${ED}${prepstrip_sources_dir}"
246         grep -zv '/<[^/>]*>$' "${T}"/debug.sources | \
247                 (cd "${WORKDIR}"; LANG=C sort -z -u | \
248                 rsync -tL0 --files-from=- "${WORKDIR}/" "${ED}${prepstrip_sources_dir}/" )
249
250         # Preserve directory structure.
251         # Needed after running save_elf_sources.
252         # https://bugzilla.redhat.com/show_bug.cgi?id=444310
253         while read -r -d $'\0' emptydir
254         do
255                 >> "$emptydir"/.keepdir
256         done < <(find "${ED}${prepstrip_sources_dir}/" -type d -empty -print0)
257 fi