[PATCH 4/4] dwfl_module_getdwarf: report paths tried
Jonathan Lebon
jlebon at redhat.com
Mon May 11 19:38:16 UTC 2015
We add a new member to Dwfl_Module which remembers all the paths that
were attempted when looking for DWARF information. This member is then
used with the new __libdw_seterrno_details() if no DWARF information is
found with details about every files tried and the reason why they
failed.
Possible reasons include the open() call failed (errno is printed), and
build ID/CRC validation failed.
Signed-off-by: Jonathan Lebon <jlebon at redhat.com>
---
libdwfl/dwfl_build_id_find_elf.c | 21 +++++++
libdwfl/dwfl_module.c | 3 +
libdwfl/dwfl_module_getdwarf.c | 10 ++++
libdwfl/find-debuginfo.c | 120 +++++++++++++++++++++++++++++----------
libdwfl/libdwflP.h | 1 +
5 files changed, 124 insertions(+), 31 deletions(-)
diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c
index 062aad1..338343e 100644
--- a/libdwfl/dwfl_build_id_find_elf.c
+++ b/libdwfl/dwfl_build_id_find_elf.c
@@ -32,6 +32,23 @@
#include <unistd.h>
+static void
+append_open_attempt (char **path_list, char *path, int error)
+{
+ char *new_path_list;
+ if (*path_list != NULL)
+ {
+ if (asprintf (&new_path_list, "%s, %s (errno %d)",
+ *path_list, path, error) < 0)
+ return;
+ free (*path_list);
+ }
+ else if (asprintf (&new_path_list, "%s (errno %d)", path, error) < 0)
+ return;
+
+ *path_list = new_path_list;
+}
+
int
internal_function
__libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name,
@@ -87,6 +104,10 @@ __libdwfl_open_by_build_id (Dwfl_Module *mod, bool debug, char **file_name,
name = NULL;
}
}
+ else if (debug)
+ /* We found nothing, append to the list of failed files. */
+ append_open_attempt (&mod->dw_tried_paths, name, errno);
+
free (name);
}
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index 8efcfaa..cb3774f 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -100,6 +100,9 @@ __libdwfl_module_free (Dwfl_Module *mod)
if (mod->eh_cfi != NULL)
dwarf_cfi_end (mod->eh_cfi);
+ if (mod->dw_tried_paths != NULL)
+ free (mod->dw_tried_paths);
+
free (mod->name);
free (mod);
}
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index a31898a..c7bc29c 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -1316,6 +1316,16 @@ dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
}
__libdwfl_seterrno (mod->dwerr);
+
+ if (mod->dwerr == DWFL_E_NO_DWARF && mod->dw_tried_paths != NULL)
+ {
+ /* Provide more details to NO_DWARF error by giving the list of files we
+ * tried to open. */
+ char *details = NULL;
+ if (asprintf (&details, "tried to open %s", mod->dw_tried_paths) > 0)
+ __libdwfl_seterrno_details (mod->dwerr, details);
+ }
+
return NULL;
}
INTDEF (dwfl_module_getdwarf)
diff --git a/libdwfl/find-debuginfo.c b/libdwfl/find-debuginfo.c
index 3f5314a..80624ff 100644
--- a/libdwfl/find-debuginfo.c
+++ b/libdwfl/find-debuginfo.c
@@ -33,9 +33,36 @@
#include <sys/stat.h>
#include "system.h"
+/* Add to the list of attempts a new attempt along with the reason it failed. If
+ error < 0, then it's a mismatch. Otherwise, it's the errno. */
+static void
+append_open_attempt (char **path_list, char *path, int error)
+{
+ char *reason;
+ if (error < 0 && asprintf (&reason, "mismatched") < 0)
+ return;
+ if (error >= 0 && asprintf (&reason, "errno %d", error) < 0)
+ return;
+
+ int rc;
+ char *new_path_list;
+ if (*path_list != NULL)
+ rc = asprintf (&new_path_list, "%s, %s (%s)", *path_list, path, reason);
+ else
+ rc = asprintf (&new_path_list, "%s (%s)", path, reason);
+ free (reason);
+
+ if (rc < 0)
+ return;
+
+ if (*path_list != NULL)
+ free (*path_list);
+ *path_list = new_path_list;
+}
/* Try to open64 [DIR/][SUBDIR/]DEBUGLINK, return file descriptor or -1.
- On success, *DEBUGINFO_FILE_NAME has the malloc'd name of the open file. */
+ *DEBUGINFO_FILE_NAME has the final malloc'd name of the file we are
+ attempting to open. */
static int
try_open (const struct stat64 *main_stat,
const char *dir, const char *subdir, const char *debuglink,
@@ -55,20 +82,18 @@ try_open (const struct stat64 *main_stat,
struct stat64 st;
int fd = TEMP_FAILURE_RETRY (open64 (fname, O_RDONLY));
- if (fd < 0)
- free (fname);
- else if (fstat64 (fd, &st) == 0
- && st.st_ino == main_stat->st_ino
- && st.st_dev == main_stat->st_dev)
+ if (fd >= 0
+ && fstat64 (fd, &st) == 0
+ && st.st_ino == main_stat->st_ino
+ && st.st_dev == main_stat->st_dev)
{
/* This is the main file by another name. Don't look at it again. */
close (fd);
errno = ENOENT;
fd = -1;
}
- else
- *debuginfo_file_name = fname;
+ *debuginfo_file_name = fname;
return fd;
}
@@ -257,34 +282,61 @@ find_debuginfo_in_path (Dwfl_Module *mod, const char *file_name,
char *fname = NULL;
int fd = try_open (&main_stat, dir, subdir, file, &fname);
if (fd < 0)
- switch (errno)
- {
- case ENOENT:
- case ENOTDIR:
- /* If we are looking for the alt file also try the .dwz subdir.
- But only if this is the empty or absolute path. */
- if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
- {
- fd = try_open (&main_stat, dir, ".dwz",
- basename (file), &fname);
- if (fd < 0)
- {
- if (errno != ENOENT && errno != ENOTDIR)
- return -1;
- else
- continue;
- }
- break;
- }
- continue;
- default:
- return -1;
- }
+ {
+ int error = errno;
+
+ /* Append to the list of failed files. */
+ if (fname != NULL)
+ {
+ append_open_attempt (&mod->dw_tried_paths, fname, error);
+ free (fname);
+ fname = NULL;
+ }
+
+ switch (error)
+ {
+ case ENOENT:
+ case ENOTDIR:
+
+ /* If we are looking for the alt file also try the .dwz subdir.
+ But only if this is the empty or absolute path. */
+ if (mod->dw != NULL && (p[0] == '\0' || p[0] == '/'))
+ {
+ fd = try_open (&main_stat, dir, ".dwz",
+ basename (file), &fname);
+ if (fd < 0)
+ {
+ error = errno;
+
+ /* Append to the list of failed files. */
+ if (fname != NULL)
+ {
+ append_open_attempt (&mod->dw_tried_paths, fname, error);
+ free (fname);
+ fname = NULL;
+ }
+
+ if (error != ENOENT && error != ENOTDIR)
+ return -1;
+ else
+ continue;
+ }
+ break;
+ }
+ continue;
+ default:
+ return -1;
+ }
+ }
if (validate (mod, fd, check, debuglink_crc))
{
*debuginfo_file_name = fname;
return fd;
}
+ else
+ // validation failed, they're mismatched files
+ append_open_attempt (&mod->dw_tried_paths, fname, -1);
+
free (fname);
close (fd);
}
@@ -304,6 +356,12 @@ dwfl_standard_find_debuginfo (Dwfl_Module *mod,
GElf_Word debuglink_crc,
char **debuginfo_file_name)
{
+ if (mod->dw_tried_paths != NULL)
+ {
+ free (mod->dw_tried_paths);
+ mod->dw_tried_paths = NULL;
+ }
+
/* First try by build ID if we have one. If that succeeds or fails
other than just by finding nothing, that's all we do. */
const unsigned char *bits;
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 17db534..640f5bb 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -191,6 +191,7 @@ struct Dwfl_Module
Dwfl_Error symerr; /* Previous failure to load symbols. */
Dwfl_Error dwerr; /* Previous failure to load DWARF. */
+ char *dw_tried_paths; /* Paths that were tried when loading DWARF. */
/* Known CU's in this module. */
struct dwfl_cu *first_cu, **cu;
--
2.1.0
More information about the elfutils-devel
mailing list