2 # Copyright 1999-2012 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
5 source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/helper-functions.sh
7 # avoid multiple calls to `has`. this creates things like:
9 # if "foo" is not in $FEATURES
10 tf() { "$@" && echo true || echo false ; }
15 eval ${var}_${flag}=$(tf has ${flag} ${!var})
18 exp_tf FEATURES compressdebug installsources nostrip splitdebug
19 exp_tf RESTRICT binchecks installsources strip
21 if ! ___eapi_has_prefix_variables; then
27 if ${RESTRICT_strip} || ${FEATURES_nostrip} ; then
30 ${FEATURES_installsources} || exit 0
33 # look up the tools we might be using
34 for t in STRIP:strip OBJCOPY:objcopy READELF:readelf ; do
37 eval ${v}=\"${!v:-${CHOST}-${t}}\"
38 type -P -- ${!v} >/dev/null || eval ${v}=${t}
41 # Figure out what tool set we're using to strip stuff
42 unset SAFE_STRIP_FLAGS DEF_STRIP_FLAGS SPLIT_STRIP_FLAGS
43 case $(${STRIP} --version 2>/dev/null) in
44 *elfutils*) # dev-libs/elfutils
45 # elfutils default behavior is always safe, so don't need to specify
48 DEF_STRIP_FLAGS="--remove-comment"
49 SPLIT_STRIP_FLAGS="-f"
51 *GNU*) # sys-devel/binutils
52 # We'll leave out -R .note for now until we can check out the relevance
53 # of the section when it has the ALLOC flag set on it ...
54 SAFE_STRIP_FLAGS="--strip-unneeded"
55 DEF_STRIP_FLAGS="-R .comment -R .GCC.command.line"
59 : ${PORTAGE_STRIP_FLAGS=${SAFE_STRIP_FLAGS} ${DEF_STRIP_FLAGS}}
61 prepstrip_sources_dir=${EPREFIX}/usr/src/debug/${CATEGORY}/${PF}
63 type -P debugedit >/dev/null && debugedit_found=true || debugedit_found=false
64 debugedit_warned=false
68 # Setup $T filesystem layout that we care about.
69 tmpdir="${T}/prepstrip"
71 mkdir -p "${tmpdir}"/{inodes,splitdebug,sources}
73 # Usage: save_elf_sources <elf>
75 ${FEATURES_installsources} || return 0
76 ${RESTRICT_installsources} && return 0
77 if ! ${debugedit_found} ; then
78 if ! ${debugedit_warned} ; then
80 ewarn "FEATURES=installsources is enabled but the debugedit binary could not"
81 ewarn "be found. This feature will not work unless debugedit is installed!"
88 # since we're editing the ELF here, we should recompute the build-id
89 # (the -i flag below). save that output so we don't need to recompute
90 # it later on in the save_elf_debug step.
91 buildid=$(debugedit -i \
93 -d "${prepstrip_sources_dir}" \
94 -l "${tmpdir}/sources/${x##*/}.${BASHPID}" \
98 # Usage: save_elf_debug <elf> [splitdebug file]
100 ${FEATURES_splitdebug} || return 0
102 # NOTE: Debug files must be installed in
103 # ${EPREFIX}/usr/lib/debug/${EPREFIX} (note that ${EPREFIX} occurs
104 # twice in this path) in order for gdb's debug-file-directory
105 # lookup to work correctly.
109 local y=${ED}usr/lib/debug/${x:${#D}}.debug
111 # dont save debug info twice
112 [[ ${x} == *".debug" ]] && return 0
116 if [ -f "${inode_debug}" ] ; then
117 ln "${inode_debug}" "${y}" || die "ln failed unexpectedly"
119 if [[ -n ${splitdebug} ]] ; then
120 mv "${splitdebug}" "${y}"
122 local objcopy_flags="--only-keep-debug"
123 ${FEATURES_compressdebug} && objcopy_flags+=" --compress-debug-sections"
124 ${OBJCOPY} ${objcopy_flags} "${x}" "${y}"
125 ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
128 [[ -g ${x} || -u ${x} ]] && args+=",go-r"
130 ln "${y}" "${inode_debug}" || die "ln failed unexpectedly"
133 # if we don't already have build-id from debugedit, look it up
134 if [[ -z ${buildid} ]] ; then
135 # convert the readelf output to something useful
136 buildid=$(${READELF} -x .note.gnu.build-id "${x}" 2>/dev/null \
137 | awk '$NF ~ /GNU/ { getline; printf $2$3$4$5; getline; print $2 }')
139 if [[ -n ${buildid} ]] ; then
140 local buildid_dir="${ED}usr/lib/debug/.build-id/${buildid:0:2}"
141 local buildid_file="${buildid_dir}/${buildid:2}"
142 mkdir -p "${buildid_dir}"
143 ln -s "../../${x:${#D}}.debug" "${buildid_file}.debug"
144 ln -s "/${x:${#D}}" "${buildid_file}"
148 # Usage: process_elf <elf>
150 local x=$1 inode_link=$2 strip_flags=${*:3}
151 local already_stripped lockfile
153 __vecho " ${x:${#ED}}"
155 # If two processes try to debugedit or strip the same hardlink at the
156 # same time, it may corrupt files or cause loss of splitdebug info.
157 # So, use a lockfile to prevent interference (easily observed with
158 # dev-vcs/git which creates ~111 hardlinks to one file in
159 # /usr/libexec/git-core).
160 lockfile=${inode_link}_lockfile
161 if ! ln "${inode_link}" "${lockfile}" 2>/dev/null ; then
162 while [[ -f ${lockfile} ]] ; do
168 [ -f "${inode_link}_stripped" ] && already_stripped=true || already_stripped=false
170 ${already_stripped} || save_elf_sources "${x}"
172 if ${strip_this} ; then
174 # see if we can split & strip at the same time
175 if [[ -n ${SPLIT_STRIP_FLAGS} ]] ; then
176 local shortname="${x##*/}.debug"
177 local splitdebug="${tmpdir}/splitdebug/${shortname}.${BASHPID}"
178 ${already_stripped} || \
179 ${STRIP} ${strip_flags} \
183 save_elf_debug "${x}" "${inode_link}_debug" "${splitdebug}"
185 save_elf_debug "${x}" "${inode_link}_debug"
186 ${already_stripped} || \
187 ${STRIP} ${strip_flags} "${x}"
191 if ${already_stripped} ; then
192 rm -f "${x}" || die "rm failed unexpectedly"
193 ln "${inode_link}_stripped" "${x}" || die "ln failed unexpectedly"
195 ln "${x}" "${inode_link}_stripped" || die "ln failed unexpectedly"
198 [[ -n ${lockfile} ]] && rm -f "${lockfile}"
201 # The existance of the section .symtab tells us that a binary is stripped.
202 # We want to log already stripped binaries, as this may be a QA violation.
203 # They prevent us from getting the splitdebug data.
204 if ! ${RESTRICT_binchecks} && ! ${RESTRICT_strip} ; then
205 # We need to do the non-stripped scan serially first before we turn around
206 # and start stripping the files ourselves. The log parsing can be done in
208 log=${tmpdir}/scanelf-already-stripped.log
209 scanelf -yqRBF '#k%F' -k '!.symtab' "$@" | sed -e "s#^${ED}##" > "${log}"
211 __multijob_child_init
212 qa_var="QA_PRESTRIPPED_${ARCH/-/_}"
213 [[ -n ${!qa_var} ]] && QA_PRESTRIPPED="${!qa_var}"
214 if [[ -n ${QA_PRESTRIPPED} && -s ${log} && \
215 ${QA_STRICT_PRESTRIPPED-unset} = unset ]] ; then
218 for x in ${QA_PRESTRIPPED} ; do
219 sed -e "s#^${x#/}\$##" -i "${log}"
224 sed -e "/^\$/d" -e "s#^#/#" -i "${log}"
225 if [[ -s ${log} ]] ; then
227 eqawarn "QA Notice: Pre-stripped files found:"
228 eqawarn "$(<"${log}")"
236 # Since strip creates a new inode, we need to know the initial set of
237 # inodes in advance, so that we can avoid interference due to trying
238 # to strip the same (hardlinked) file multiple times in parallel.
240 if [[ ${USERLAND} == BSD ]] ; then
241 get_inode_number() { stat -f '%i' "$1"; }
243 get_inode_number() { stat -c '%i' "$1"; }
245 cd "${tmpdir}/inodes" || die "cd failed unexpectedly"
247 inode_link=$(get_inode_number "${x}") || die "stat failed unexpectedly"
248 echo "${x}" >> "${inode_link}" || die "echo failed unexpectedly"
250 # Use sort -u to eliminate duplicates for bug #445336.
252 scanelf -yqRBF '#k%F' -k '.symtab' "$@"
253 find "$@" -type f ! -type l -name '*.a'
257 # Now we look for unstripped binaries.
258 for inode_link in $(shopt -s nullglob; echo *) ; do
262 if ! ${banner} ; then
263 __vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
268 __multijob_child_init
269 f=$(file "${x}") || exit 0
270 [[ -z ${f} ]] && exit 0
272 if ! ${SKIP_STRIP} ; then
273 # The noglob funk is to support STRIP_MASK="/*/booga" and to keep
274 # the for loop from expanding the globs.
275 # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
278 for m in $(eval echo ${STRIP_MASK}) ; do
279 [[ /${x#${ED}} == ${m} ]] && strip_this=false && break
286 # In Prefix we are usually an unprivileged user, so we can't strip
287 # unwritable objects. Make them temporarily writable for the
289 was_not_writable=false
290 if [[ ! -w ${x} ]] ; then
291 was_not_writable=true
295 # only split debug info for final linked objects
296 # or kernel modules as debuginfo for intermediatary
297 # files (think crt*.o from gcc/glibc) is useless and
298 # actually causes problems. install sources for all
299 # elf types though cause that stuff is good.
302 if [[ ${f} == *"current ar archive"* ]] ; then
303 __vecho " ${x:${#ED}}"
304 if ${strip_this} ; then
305 # hmm, can we split debug/sources for .a ?
308 elif [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
309 process_elf "${x}" "${inode_link}" ${PORTAGE_STRIP_FLAGS}
310 elif [[ ${f} == *"SB relocatable"* ]] ; then
311 process_elf "${x}" "${inode_link}" ${SAFE_STRIP_FLAGS}
314 if ${was_not_writable} ; then
320 done < "${inode_link}"
323 # With a bit more work, we could run the rsync processes below in
324 # parallel, but not sure that'd be an overall improvement.
327 cd "${tmpdir}"/sources/ && cat * > "${tmpdir}/debug.sources" 2>/dev/null
328 if [[ -s ${tmpdir}/debug.sources ]] && \
329 ${FEATURES_installsources} && \
330 ! ${RESTRICT_installsources} && \
333 __vecho "installsources: rsyncing source files"
334 [[ -d ${D}${prepstrip_sources_dir} ]] || mkdir -p "${D}${prepstrip_sources_dir}"
335 grep -zv '/<[^/>]*>$' "${tmpdir}"/debug.sources | \
336 (cd "${WORKDIR}"; LANG=C sort -z -u | \
337 rsync -tL0 --chmod=ugo-st,a+r,go-w,Da+x,Fa-x --files-from=- "${WORKDIR}/" "${D}${prepstrip_sources_dir}/" )
339 # Preserve directory structure.
340 # Needed after running save_elf_sources.
341 # https://bugzilla.redhat.com/show_bug.cgi?id=444310
342 while read -r -d $'\0' emptydir
344 >> "${emptydir}"/.keepdir
345 done < <(find "${D}${prepstrip_sources_dir}/" -type d -empty -print0)