splitdebug causes Portage to move symbols to debug files under /usr/lib/debug/path/to/program. It then adds a .gnu_debuglink section to any affected binaries. This section contains the basename of the file installed under /usr/lib/debug. When a package installs multiple hard links to the same binary that span multiple directories, splitdebug behaves strangely. Since there is only one actual ELF file on disk, .gnu_debugpath ends up being incorrect for all but one of the installed hard links. A great example of this is dev-vcs/git, which installs /usr/bin/git along with over a hundred hard links under /usr/libexec/git-core. Sometimes you get lucky and .gnu_debuglink gets set to "git.debug". Other times, you get unlucky and it gets set to something like "git-diff-tree.debug". The only solution I can think of is to have Portage break the hard links when splitdebug is enabled, and instead install separate copies of the file with appropriate .gnu_debuglink sections.
Some alternate solutions from #gentoo-toolchain: - Break hard links only if they reside in separate directories. - Install a copy of the same .debug file under /usr/lib/debug/${path} for each path in which a hard link will be installed.
(In reply to Mike Gilbert from comment #1) > - Install a copy of the same .debug file under /usr/lib/debug/${path} for > each path in which a hard link will be installed. Or this could be optimized by installing hard links to the same .debug file for each path.
(In reply to Mike Gilbert from comment #2) > (In reply to Mike Gilbert from comment #1) > > - Install a copy of the same .debug file under /usr/lib/debug/${path} for > > each path in which a hard link will be installed. > > Or this could be optimized by installing hard links to the same .debug file > for each path. I think it's supposed to do that in the bin/estrip save_elf_debug function, around here, but maybe it's buggy somehow: > if [ -f "${inode_debug}" ] ; then > ln "${inode_debug}" "${y}" || die "ln failed unexpectedly"
Note that the process_elf function has a lockfile for each inode to guard against the function running multiple times on the same inode at once, which is *supposed* to ensure correct behavior despite process_elf being launched via a multiprocessing loop.
Ah, you're right. I think estrip is smarter than I assumed. It does create hard links, but not the ones that matter. To better illustrate the problem in dev-vcs/git, here's what happened on my most recent install: > % objdump -s -j .gnu_debuglink /usr/bin/git > > /usr/bin/git: file format elf64-x86-64 > > Contents of section .gnu_debuglink: > 0000 6769742d 6164642e 64656275 67000000 git-add.debug... > 0010 ae8f7879 ..xy Given this, gdb will attempt to load /usr/lib/debug/usr/bin/git-add.debug, which does not exist. > % ls -l /usr/lib/debug/usr/bin/git-add.debug > ls: cannot access '/usr/lib/debug/usr/bin/git-add.debug': No such file or directory > > % gdb /usr/bin/git > GNU gdb (Gentoo 11.1 vanilla) 11.1 > ... > Reading symbols from /usr/bin/git... > (No debugging symbols found in /usr/bin/git)
I have a working local patch for estrip, just need to clean it up a bit.
The bug has been referenced in the following commit(s): https://gitweb.gentoo.org/proj/portage.git/commit/?id=84206c6200eb003314cf4f2d640bf73f04654012 commit 84206c6200eb003314cf4f2d640bf73f04654012 Author: Mike Gilbert <floppym@gentoo.org> AuthorDate: 2021-10-25 15:30:08 +0000 Commit: Mike Gilbert <floppym@gentoo.org> CommitDate: 2021-10-31 18:15:27 +0000 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@gentoo.org> bin/estrip | 60 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 21 deletions(-)
Released in portage-3.0.29.