The existing code was first trying .gnu_debugaltlink paths directly, so relative paths would start from the current program's working directory. That's unlikely to be useful, so it was almost always falling back to a build-id based path.
In Fedora, these paths are relative to the debug file itself, so that's a better thing to try first. We don't actually have the debug path in libdw, but we can usually find it from elf->fildes and /proc/self/fd/. Signed-off-by: Josh Stone <[email protected]> --- PS - Mark tipped me to use git-merge-changelog, but that doesn't seem to worry about keeping dates in order. It's not the first such case in the ChangeLogs, but I can reorder or re-date mine if desired. --- libdw/ChangeLog | 5 +++++ libdw/dwarf_begin_elf.c | 42 +++++++++++++++++++++++++++++++++++++++--- tests/ChangeLog | 4 ++++ tests/run-allfcts-multi.sh | 14 ++++++++++---- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 8b1e2c0839be..a61efb8bf763 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,8 @@ +2013-12-14 Josh Stone <[email protected]> + + * dwarf_begin_elf.c (build_rel_debugaltlink): New function. + (open_debugaltlink): Use it. + 2013-12-16 Mark Wielaard <[email protected]> * libdw.map (ELFUTILS_0.158): Add dwfl_module_getsymtab_first_global. diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c index 6cf3aa17855d..3161ef46212d 100644 --- a/libdw/dwarf_begin_elf.c +++ b/libdw/dwarf_begin_elf.c @@ -42,8 +42,10 @@ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <libgen.h> #include "libdwP.h" +#include "libelfP.h" #if USE_ZLIB # include <endian.h> @@ -136,14 +138,48 @@ try_debugaltlink (Dwarf *result, const char *try_name, return NULL; } +/* Make relative links into an absolute path. */ +static char * +build_rel_debugaltlink (Dwarf *result, const char *alt_name) +{ + if (alt_name[0] == '/' || result->elf->fildes < 0) + return NULL; + + char *fd_link; + if (asprintf (&fd_link, "/proc/self/fd/%d", result->elf->fildes) == -1) + return NULL; + + char *fd_name = canonicalize_file_name (fd_link); + free (fd_link); + if (fd_name == NULL) + return NULL; + + char *rel_name; + if (asprintf (&rel_name, "%s/%s", dirname (fd_name), alt_name) == -1) + rel_name = NULL; + free (fd_name); + + return rel_name; +} + /* For dwz multifile support, ignore if it looks wrong. */ static Dwarf * open_debugaltlink (Dwarf *result, const char *alt_name, const uint8_t *build_id, const size_t id_len) { - /* First try the name itself, it is either an absolute path or - a relative one. Sadly we don't know relative from where at - this point. */ + /* First try it relative to the debug file. */ + char *rel_name = build_rel_debugaltlink (result, alt_name); + if (rel_name != NULL) + { + Dwarf *alt = try_debugaltlink (result, rel_name, build_id, id_len); + free (rel_name); + if (alt != NULL) + return result; + } + + /* Then try the name itself, it is either an absolute path or + a relative one. (Using a path relative to the tool's cwd + doesn't make much sense in general, but it's also harmless.) */ if (try_debugaltlink (result, alt_name, build_id, id_len) != NULL) return result; diff --git a/tests/ChangeLog b/tests/ChangeLog index f7007e5a0a4d..297a588c1dbd 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2013-12-14 Josh Stone <[email protected]> + + * run-allfcts-multi.sh: Test relative altlinks. + 2013-12-15 Jan Kratochvil <[email protected]> unwinder: ppc diff --git a/tests/run-allfcts-multi.sh b/tests/run-allfcts-multi.sh index 727b76ee5c72..35e3177a57ae 100755 --- a/tests/run-allfcts-multi.sh +++ b/tests/run-allfcts-multi.sh @@ -42,15 +42,21 @@ EOF # dwz test-offset-loop test-offset-loop2 -m test-offset-loop.alt testfiles test-offset-loop test-offset-loop.alt -tempfiles allfcts.out +tempfiles allfcts.in allfcts.out -# Use head to capture output because the output could be infinite... -testrun ${abs_builddir}/allfcts test-offset-loop | head -n 20 > allfcts.out -testrun_compare cat allfcts.out <<\EOF +cat >allfcts.in <<\EOF /tmp/test-offset-loop.c:6:get_errno /tmp/test-offset-loop.c:5:is_error /tmp/test-offset-loop.c:4:padding /tmp/test-offset-loop.c:7:main EOF +# Use head to capture output because the output could be infinite... +testrun ${abs_builddir}/allfcts test-offset-loop | head -n 20 > allfcts.out +testrun_compare cat allfcts.out <allfcts.in + +# Repeat from a different directory for relative .gnu_debugaltlink +(cd / && testrun ${abs_builddir}/allfcts $OLDPWD/test-offset-loop) | head -n 20 > allfcts.out +testrun_compare cat allfcts.out <allfcts.in + exit 0 -- 1.8.4.2
