commit:     84206c6200eb003314cf4f2d640bf73f04654012
Author:     Mike Gilbert <floppym <AT> gentoo <DOT> org>
AuthorDate: Mon Oct 25 15:30:08 2021 +0000
Commit:     Mike Gilbert <floppym <AT> gentoo <DOT> org>
CommitDate: Sun Oct 31 18:15:27 2021 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=84206c62

estrip: rework hard link logic in save_elf_debug

GDB loads debug files based on the file name given in the .gnu_debuglink
section, prepended with /usr/lib/debug/${dirname}, where dirname is the
absolute path to the parent directory of the binary being executed.

For each unique inode as input, we need a link to the debug file with
the GNU debuglink as its basename. A link to the debug file should exist
for each directory in which the input inode exists.

The debug link names should be based on the .gnu_debuglink value instead
of the name of the file we are processing as input.

The .gnu_debuglink value is based on the name of the first link
processed for each inode. We save this value as a symlink, and then read
it back as we process subsequent links.

For example, given the following input:

INODE PATH
    1 /usr/bin/git
    1 /usr/libexec/git-core/git-add
    2 /usr/bin/git-shell
    2 /usr/libexec/git-core/git-shell

We generate the following inodes for the debug files:

INODE DEBUGLINK
    3 git.debug
    4 git-shell.debug

We should generate the following links:

INODE PATH
    3 /usr/lib/debug/usr/bin/git.debug
    3 /usr/lib/debug/usr/libexec/git-core/git.debug
    4 /usr/bin/debug/usr/bin/git-shell.debug
    4 /usr/bin/debug/usr/libexec/git-core/git-shell.debug

The previous code would have generated this broken output:

INODE PATH
    3 /usr/lib/debug/usr/bin/git.debug
    3 /usr/lib/debug/usr/libexec/git-core/git-add.debug (*)
    4 /usr/bin/debug/usr/bin/git-shell.debug
    4 /usr/bin/debug/usr/libexec/git-core/git-shell.debug

(*) This link has the wrong name.

Bug: https://bugs.gentoo.org/820107
Signed-off-by: Mike Gilbert <floppym <AT> gentoo.org>

 bin/estrip | 60 +++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 39 insertions(+), 21 deletions(-)

diff --git a/bin/estrip b/bin/estrip
index abe523fff..e33977091 100755
--- a/bin/estrip
+++ b/bin/estrip
@@ -189,7 +189,7 @@ save_elf_sources() {
                "${x}")
 }
 
-# Usage: save_elf_debug <elf> [splitdebug file]
+# Usage: save_elf_debug <src> <inode_debug> [splitdebug]
 save_elf_debug() {
        ${FEATURES_splitdebug} || return 0
        ${PORTAGE_RESTRICT_splitdebug} && return 0
@@ -198,49 +198,67 @@ save_elf_debug() {
        # ${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 inode_debug=$2
-       local splitdebug=$3
-       local d_noslash=${D%/}
-       local y=${ED%/}/usr/lib/debug/${x:${#d_noslash}}.debug
+       local src=$1         # File from which we extract symbols.
+       local inode_debug=$2 # Temp path for hard link tracking
+       local splitdebug=$3  # Existing debug file optionally created by 
eu-strip in parent function
 
-       # dont save debug info twice
-       [[ ${x} == *".debug" ]] && return 0
+       # Source paths
+       local src_basename=${src##*/}
+       local src_dirname=${src%/*}
 
-       mkdir -p "${y%/*}"
+       # Destination paths
+       local dst_dirname=${ED%/}/usr/lib/debug/${src_dirname#${D%/}/}
+       local dst_basename dst
 
-       if [ -f "${inode_debug}" ] ; then
-               ln "${inode_debug}" "${y}" || die "ln failed unexpectedly"
+       # dont save debug info twice
+       [[ ${src} == *".debug" ]] && return 0
+
+       mkdir -p "${dst_dirname}" || die
+
+       if [[ -L ${inode_debug} ]] ; then
+               # We already created a debug file for this inode.
+               # Read back the file name, and create another hard link if 
necessary.
+               dst_basename=$(readlink "${inode_debug}") || die
+               dst_basename=${dst_basename##*/}
+               dst=${dst_dirname}/${dst_basename}
+               if [[ ! -e ${dst} ]]; then
+                       ln -L "${inode_debug}" "${dst}" || die
+               fi
        else
+               dst_basename=${src_basename}.debug
+               dst=${dst_dirname}/${dst_basename}
                if [[ -n ${splitdebug} ]] ; then
-                       mv "${splitdebug}" "${y}"
+                       mv "${splitdebug}" "${dst}"
                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}"
+                       ${OBJCOPY} ${objcopy_flags} "${src}" "${dst}" &&
+                       ${OBJCOPY} --add-gnu-debuglink="${dst}" "${src}"
                fi
                # Only do the following if the debug file was
                # successfully created (see bug #446774).
-               if [ $? -eq 0 ] ; then
+               if [[ $? -eq 0 ]] ; then
                        local args="a-x,o-w"
-                       [[ -g ${x} || -u ${x} ]] && args+=",go-r"
-                       chmod ${args} "${y}"
-                       ln "${y}" "${inode_debug}" || die "ln failed 
unexpectedly"
+                       [[ -g ${src} || -u ${src} ]] && args+=",go-r"
+                       chmod ${args} "${dst}"
+                       # symlink so we can read the name back.
+                       ln -s "${dst}" "${inode_debug}" || die
                fi
        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} -n "${x}" 2>/dev/null | awk '/Build ID:/{ 
print $NF; exit }')
+               buildid=$(${READELF} -n "${src}" 2>/dev/null | awk '/Build 
ID:/{ print $NF; exit }')
        fi
        if [[ -n ${buildid} ]] ; then
                local 
buildid_dir="${ED%/}/usr/lib/debug/.build-id/${buildid:0:2}"
                local buildid_file="${buildid_dir}/${buildid:2}"
+               local src_buildid_rel="../../../../../${src#${ED%/}/}"
+               local dst_buildid_rel="../../${dst#${ED%/}/usr/lib/debug/}"
                mkdir -p "${buildid_dir}"
-               [ -L "${buildid_file}".debug ] || ln -s 
"../../${x:$((${#d_noslash} + 1))}.debug" "${buildid_file}.debug"
-               [ -L "${buildid_file}" ] || ln -s "/${x:$((${#d_noslash} + 
1))}" "${buildid_file}"
+               [[ -L "${buildid_file}".debug ]] || ln -s "${dst_buildid_rel}" 
"${buildid_file}.debug"
+               [[ -L "${buildid_file}" ]] || ln -s "${src_buildid_rel}" 
"${buildid_file}"
        fi
 }
 

Reply via email to