Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 400767 - sys-devel/binutils: --add-gnu-debuglink doesn't play well with hardlinks
Summary: sys-devel/binutils: --add-gnu-debuglink doesn't play well with hardlinks
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: New packages (show other bugs)
Hardware: All Linux
: Normal normal (vote)
Assignee: Gentoo Toolchain Maintainers
: 406159 (view as bug list)
Depends on:
Reported: 2012-01-25 16:22 UTC by Brian Harring (RETIRED)
Modified: 2018-06-20 21:38 UTC (History)
2 users (show)

See Also:
Package list:
Runtime testing required: ---


Note You need to log in before you can comment on or make changes to this bug.
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


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.]