Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!

Bug 400767

Summary: sys-devel/binutils: --add-gnu-debuglink doesn't play well with hardlinks
Product: Gentoo Linux Reporter: Brian Harring (RETIRED) <ferringb>
Component: New packagesAssignee: Gentoo Toolchain Maintainers <toolchain>
Status: RESOLVED NEEDINFO    
Severity: normal CC: dev-portage, lu_zero
Priority: Normal    
Version: unspecified   
Hardware: All   
OS: Linux   
Whiteboard:
Package list:
Runtime testing required: ---

Description Brian Harring (RETIRED) gentoo-dev 2012-01-25 16:22:45 UTC
Please note when trying to replicate this, you need to dig in a bit closely- there's a bit of luck that can occur here resulting in it working; this is part of the reason.

The git pkg uses hardlinks for most of it's commands; git, git-mailinfo, etc, all being a hardlink to the same file.  Portage is smart enough to recognize that hardlinks are in play here, and to only mangle the actual inode once, doing the following for each unique inode:

objcopy --only-keep-debug ${D}/usr/bin/git ${D}/usr/lib/debug/usr/bin/git.debug
strip --strip-debug ${D}/usr/bin/git
objcopy --add-gnu-debuglink=${D}/usr/lib/debug/usr/bin/git.debug ${D}/usr/bin/git

The problem here is that binutils implementation of --add-gnu-debuglink records a record of the basename of the given debug file (look in bfd_create_gnu_debuglink-section)- not the absolute path at the time of invocation.  Literally, /usr/bin/git gets 'git.debug' recorded.

This is where hardlinks screw the pooch.  If we're lucky for that case, 'git.debug' is the recorded debuglink.  If we're not, one of the libexec/git-core binaries is what's recorded, something like 'git-whatchanged'.

Because the record is just the basename, gdb has to look relative- so for example, it would check

/usr/bin/git-mailinfo.debug
/usr/bin/.debug/git-mailinfo.debug
/usr/lib/debug/usr/bin/git-mailinfo.debug

Etc.  Which if the first node processed results in a common name like 'git.debug', mostly works by luck.  If it's something like 'git-whatchanged.debug', that however doesn't work.

A way to verify this behaviour is a mixture of the following commands:

readelf -p .gnu_debuglink /usr/bin/git # pull the recorded string
gdb --args /usr/bin/git # note the failure to find debug symbols
gdb --args /usr/libexec/git-core/git # note that it succeeded, because it could find 'git-whatchanged.debug' (or whatever it was named) relative to that offset pathway).

When testing this, you may have to do an objcopy --add-gnu-debuglink invocation to switch the inode's recorded .gnu_debuglink to something like git-whatchanged.debug.

Unfortunately this is a bit nasty- our options are-
1) hardlink breaking as needed if the reference would point outside the relative directory, and add a new gnu-debuglink.  The code to do this is ugly from the PM standpoint.
2) modify binutils to record absolute pathways for .gnu_debuglink; this is slightly more complex then it sounds, would require adding another option to record the final installed location of the debugfile; keep in mind binutils needs access to the debugfile during adding the record for accessing crcs.  Thus we'd have to give it the current path to the debugfile, /and/ tell it "the debugfile will live over there- thus record that pathway".
3) find some other tool that we can invoke after the --add-gnu-debuglink to inject in the final on disk abspath.  Not sure how feasible that is, including making sure the crc's don't get screwed up.

Thoughts?  This isn't binutils version specific, but 2.22* still holds the offending code, and any 2.1/2.2 portage version will do this (this pathway hasn't changed in a long while, aside from the recent compressdebug addition).
Comment 1 SpanKY gentoo-dev 2014-04-19 14:49:30 UTC
*** Bug 406159 has been marked as a duplicate of this bug. ***
Comment 2 Andreas K. Hüttel archtester gentoo-dev 2018-06-20 21:38:51 UTC
@Brian: (in case you still remember :), 

What actually triggers this problem? I.e., what determines *which* name is recorded in the inode?

[I checked and the objcopy behaviour hasn't changed in the meantime.]
Comment 3 Andreas K. Hüttel archtester gentoo-dev 2023-08-22 21:37:03 UTC
(In reply to Andreas K. Hüttel from comment #2)
> @Brian: (in case you still remember :), 
> 
> What actually triggers this problem? I.e., what determines *which* name is
> recorded in the inode?
> 
> [I checked and the objcopy behaviour hasn't changed in the meantime.]