From: Dodji Seketeli <dodji(a)seketeli.org>
[This bug has been found by using elfutils in the context of
libabigail. The initial bug report is
https://sourceware.org/bugzilla/show_bug.cgi?id=18792. The
interesting comments start at is
https://sourceware.org/bugzilla/show_bug.cgi?id=18792#c4]
suppose we have a debug info file that is located at a
/prefix1/usr/lib/debug/prefix2/libfoo.so. Suppose also that the debug
info describes a binary that is located at /prefix1/prefix2/libfoo.so
Suppose the debug_link property inside the binary
/prefix1/prefix2/libfoo.so correctly contains the string "libfoo.so"
that designates the name of the debug info file.
The problem is, when find_debuginfo_in_path() is called with its
file_name parameter set to "/prefix1/prefix2/libfoo.so" and
mod->dwfl->callbacks->debuginfo_path set to
"/prefix1/lib/debug/", it fails to locate the debug
info file libfoo.so under "/prefix1/usr/lib/debug/prefix2/".
This patch fixes the issue by making find_debuginfo_in_path() try all
the sub-strings of "/prefix1/prefix2/libfoo.so "under"
"/prefix1/usr/lib/debug/", to find libfoo.so. That is, it tries, in
order:
- /prefix1/usr/lib/debug/prefix1/prefix2/libfoo.so
- /prefix1/usr/lib/debug/prefix2/libfoo.so <-- and boom, it finds it!
Note that the patch tries the variations between the two candidates
above too.
The patch uses a goto. I dislike gotos like anyone else, but then
here, not using this would imply a bigger change of the logic of that
function. So I am proposing the scheme based on the goto instead.
The patch lacks a test case, but then it's a bit cumbersome to write
one right now. I'll defer that to later when people agree with the
general approach of the patch.
* libdwfl/find-debuginfo.c (find_debuginfo_in_path): Try to locate
the debug info file named debuglink_file under
mod->dwfl->callbacks->debuginfo_path, by looking at the set of
sub-trees under mod->dwfl->callbacks->debuginfo_path which is
common to the set of non-absolute parent trees of file_name.
Signed-off-by: Dodji Seketeli <dodji(a)seketeli.org>
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwfl/ChangeLog | 9 +++++++++
libdwfl/find-debuginfo.c | 13 ++++++++++++-
libdwfl/libdwfl.h | 14 ++++++++------
3 files changed, 29 insertions(+), 7 deletions(-)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 5059be6..3e36aa7 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,12 @@
+2015-08-14 Dodji Seketeli <dodji(a)seketeli.org>
+
+ * find-debuginfo.c (find_debuginfo_in_path): Try to locate the
+ debug info file named debuglink_file under
+ mod->dwfl->callbacks->debuginfo_path, by looking at
+ the set of sub-trees under mod->dwfl->callbacks->debuginfo_path
+ which is common to the set of non-absolute parent trees of
+ file_name.
+
2015-06-18 Mark Wielaard <mjw(a)redhat.com>
* find-debuginfo.c (try_open): Free fname on all failure paths.
diff --git a/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c
index 1faa494..6b8d1ac 100644
--- a/libdwfl/find-debuginfo.c
+++ b/libdwfl/find-debuginfo.c
@@ -252,7 +252,15 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
dir = p;
if (mod->dw == NULL)
{
- subdir = file_dirname + 1;
+ subdir = file_dirname;
+ /* We want to explore all sub-subdirs. Chop off one slash
+ at a time. */
+ explore_dir:
+ subdir = strchr (subdir, '/');
+ if (subdir != NULL)
+ subdir = subdir + 1;
+ if (subdir && *subdir == 0)
+ continue;
file = debuglink_file;
}
else
@@ -292,6 +300,9 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
}
break;
}
+ /* If possible try again with a sub-subdir. */
+ if (mod->dw == NULL && subdir)
+ goto explore_dir;
continue;
default:
goto fail_free;
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 2bb4f45..1098c83 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -275,12 +275,14 @@ extern int dwfl_module_build_id (Dwfl_Module *mod,
In searches for debuginfo by name, if the remainder of the
element is empty, the directory containing the main file is
tried; if it's an absolute path name, the absolute directory path
- containing the main file is taken as a subdirectory of this path;
- a relative path name is taken as a subdirectory of the directory
- containing the main file. Hence for /bin/ls, the default string
- ":.debug:/usr/lib/debug" says to look in /bin, then /bin/.debug,
- then /usr/lib/debug/bin, for the file name in the .gnu_debuglink
- section (or "ls.debug" if none was found). */
+ (and any subdirectory of that path) containing the main file is
+ taken as a subdirectory of this path; a relative path name is taken
+ as a subdirectory of the directory containing the main file.
+ Hence for /usr/bin/ls, the default string ":.debug:/usr/lib/debug"
+ says to look in /usr/bin, then /usr/bin/.debug, then the path subdirs
+ under /usr/lib/debug, in the order /usr/lib/debug/usr/bin, then
+ /usr/lib/debug/bin, and finally /usr/lib/debug, for the file name in
+ the .gnu_debuglink section (or "ls.debug" if none was found). */
/* Standard find_elf callback function working solely on build ID.
This can be tried first by any find_elf callback, to use the
--
1.8.3.1