[PATCH] libdw: Try .gnu_debugaltlink paths relative to the debug file
Josh Stone
jistone at redhat.com
Sat Dec 14 21:51:01 UTC 2013
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 <jistone at redhat.com>
---
libdw/ChangeLog | 5 +++++
libdw/dwarf_begin_elf.c | 44 +++++++++++++++++++++++++++++++++++++++++---
tests/ChangeLog | 4 ++++
tests/run-allfcts-multi.sh | 14 ++++++++++----
4 files changed, 60 insertions(+), 7 deletions(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index aa7b9ca486c2..a540a5219856 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,8 @@
+2013-12-14 Josh Stone <jistone at redhat.com>
+
+ * dwarf_begin_elf.c (build_rel_debugaltlink): New function.
+ (open_debugaltlink): Use it.
+
2013-12-10 Josh Stone <jistone at redhat.com>
* memory-access.h (get_uleb128_rest_return): Removed.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 6cf3aa17855d..eeb84c051770 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,50 @@ 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;
+
+#define SELFFD_PREFIX "/proc/self/fd/"
+ char fd_name[sizeof SELFFD_PREFIX + 12];
+ sprintf (fd_name, "%s%d", SELFFD_PREFIX, result->elf->fildes);
+
+ /* Note, readlink(2) recommends sizing the buffer based on lstat(2), but
+ procfs always reports st_size=64, even if it's really longer. */
+ char fd_link[PATH_MAX + 1];
+ ssize_t len_link = readlink (fd_name, fd_link, sizeof fd_link);
+ if (len_link == -1 || (size_t) len_link > sizeof fd_link - 1)
+ return NULL;
+ fd_link[len_link] = '\0';
+
+ char *rel_name;
+ if (asprintf (&rel_name, "%s/%s", dirname (fd_link), alt_name) == -1)
+ return NULL;
+
+ 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 008198166da6..6325a74d5915 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,7 @@
+2013-12-14 Josh Stone <jistone at redhat.com>
+
+ * run-allfcts-multi.sh: Test relative altlinks.
+
2013-12-10 Mark Wielaard <mjw at redhat.com>
* Makefile.am (backtrace_child_biarch_SOURCES): New backtrace-child.c.
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
More information about the elfutils-devel
mailing list