[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