This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] libdw: Cache ELF directory early. Explicitly set it in dwfl.


The logic that finds alt files and dwo files relies on having an open
file descriptor. But after all needed ELF data has been read the
underlying Elf file descriptor can be closed. libdwfl in particular
closes file descriptor fairly aggressively. So capture the directory
early on. And make dwfl set it if it has recorded it. Which it will
do now before closing a file descriptor for the main Dwfl_Module file.

Signed-off-by: Mark Wielaard <mark@klomp.org>
---
 libdw/ChangeLog                | 15 ++++++++++++++
 libdw/dwarf_begin_elf.c        | 24 +++++++++++++++++++++++
 libdw/dwarf_end.c              |  3 +++
 libdw/dwarf_getalt.c           | 44 +++++++++++++++---------------------------
 libdw/libdwP.h                 | 26 +++++++++++++++++--------
 libdw/libdw_find_split_unit.c  |  6 +++---
 libdwfl/ChangeLog              | 10 ++++++++++
 libdwfl/dwfl_module.c          |  1 +
 libdwfl/dwfl_module_getdwarf.c | 23 ++++++++++++++++------
 libdwfl/libdwflP.h             |  2 ++
 libdwfl/offline.c              |  3 +++
 11 files changed, 112 insertions(+), 45 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index c22811e..0a0728b 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,20 @@
 2018-05-17  Mark Wielaard  <mark@klomp.org>
 
+	* dwarf_begin_elf.c (__libdw_debugdir): New function.
+	(valid_p): Call __libdw_debugdir.
+	* dwarf_end.c (dwarf_end.c): Free debugdir.
+	* dwarf_getalt.c (__libdw_filepath): Extract __libdw_debugdir logic.
+	take debugdir as argument instead of fd.
+	(find_debug_altlink): Call __libdw_filepath with debugdir.
+	* libdwP.h (struct Dwarf): Add debugdir field.
+	(__libdw_debugdir): New function prototype.
+	(__libdw_filepath): Adjust prototype to take a const char * instead of
+	an int.
+	* libdw_find_split_unit.c (__libdw_find_split_unit): Call
+	__libdw_filepath with debugdir.
+
+2018-05-17  Mark Wielaard  <mark@klomp.org>
+
 	* dwarf_attr_integrate.c (dwarf_attr_integrate): Handle split_compile
 	unit DIE, search skeleton_compile unit DIE.
 	* dwarf_hasattr_integrate.c (dwarf_hasattr_integrate): Likewise.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 61de752..0e435c5 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -42,6 +42,7 @@
 #include <fcntl.h>
 #include <endian.h>
 
+#include "libelfP.h"
 #include "libdwP.h"
 
 
@@ -184,6 +185,26 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
 }
 
 
+/* Helper function to set debugdir field.  We want to cache the dir
+   where we found this Dwarf ELF file to locate alt and dwo files.  */
+char *
+__libdw_debugdir (int fd)
+{
+  /* strlen ("/proc/self/fd/") = 14 + strlen (<MAXINT>) = 10 + 1 = 25.  */
+  char devfdpath[25];
+  sprintf (devfdpath, "/proc/self/fd/%u", fd);
+  char *fdpath = realpath (devfdpath, NULL);
+  char *fddir;
+  if (fdpath != NULL && fdpath[0] == '/'
+      && (fddir = strrchr (fdpath, '/')) != NULL)
+    {
+      *++fddir = '\0';
+      return fdpath;
+    }
+  return NULL;
+}
+
+
 /* Check whether all the necessary DWARF information is available.  */
 static Dwarf *
 valid_p (Dwarf *result)
@@ -225,6 +246,9 @@ valid_p (Dwarf *result)
 	}
     }
 
+  if (result != NULL)
+    result->debugdir = __libdw_debugdir (result->elf->fildes);
+
   return result;
 }
 
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 43223de..4702f1b 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -116,6 +116,9 @@ dwarf_end (Dwarf *dwarf)
 	  close (dwarf->alt_fd);
 	}
 
+      /* The cached dir we found the Dwarf ELF file in.  */
+      free (dwarf->debugdir);
+
       /* Free the context descriptor.  */
       free (dwarf);
     }
diff --git a/libdw/dwarf_getalt.c b/libdw/dwarf_getalt.c
index 3e5af15..3339b3e 100644
--- a/libdw/dwarf_getalt.c
+++ b/libdw/dwarf_getalt.c
@@ -47,7 +47,7 @@
 
 char *
 internal_function
-__libdw_filepath (int fd, const char *dir, const char *file)
+__libdw_filepath (const char *debugdir, const char *dir, const char *file)
 {
   if (file == NULL)
     return NULL;
@@ -71,37 +71,25 @@ __libdw_filepath (int fd, const char *dir, const char *file)
       return path;
     }
 
-  if (fd >= 0)
+  if (debugdir != NULL)
     {
-      /* strlen ("/proc/self/fd/") = 14 + strlen (<MAXINT>) = 10 + 1 = 25.  */
-      char devfdpath[25];
-      sprintf (devfdpath, "/proc/self/fd/%u", fd);
-      char *fdpath = realpath (devfdpath, NULL);
-      char *path = NULL;
-      char *fddir;
-      if (fdpath != NULL && fdpath[0] == '/'
-	  && (fddir = strrchr (fdpath, '/')) != NULL)
+      size_t debugdirlen = strlen (debugdir);
+      size_t dirlen = dir != NULL ? strlen (dir) : 0;
+      size_t filelen = strlen (file);
+      size_t len = debugdirlen + 1 + dirlen + 1 + filelen + 1;
+      char *path = malloc (len);
+      if (path != NULL)
 	{
-	  *++fddir = '\0';
-	  size_t fdpathlen = strlen (fdpath);
-	  size_t dirlen = dir != NULL ? strlen (dir) : 0;
-	  size_t filelen = strlen (file);
-	  size_t len = fdpathlen + 1 + dirlen + 1 + filelen + 1;
-	  path = malloc (len);
-	  if (path != NULL)
+	  char *c = mempcpy (path, debugdir, debugdirlen);
+	  if (dirlen > 0)
 	    {
-	      char *c = mempcpy (path, fdpath, fdpathlen);
-	      if (dirlen > 0)
-		{
-		  c = mempcpy (c, dir, dirlen);
-		  if (dir[dirlen - 1] != '/')
-		    *c++ = '/';
-		}
-	      mempcpy (c, file, filelen + 1);
+	      c = mempcpy (c, dir, dirlen);
+	      if (dir[dirlen - 1] != '/')
+		*c++ = '/';
 	    }
+	  mempcpy (c, file, filelen + 1);
+	  return path;
 	}
-      free (fdpath);
-      return path;
     }
 
   return NULL;
@@ -151,7 +139,7 @@ find_debug_altlink (Dwarf *dbg)
   /* Fall back on (possible relative) alt file path.  */
   if (fd < 0)
     {
-      char *altpath = __libdw_filepath (dbg->elf->fildes, NULL, altname);
+      char *altpath = __libdw_filepath (dbg->debugdir, NULL, altname);
       if (altpath != NULL)
 	{
 	  fd = TEMP_FAILURE_RETRY (open (altpath, O_RDONLY));
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 08d144b..7cc68fc 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -148,6 +148,10 @@ struct Dwarf
   /* The underlying ELF file.  */
   Elf *elf;
 
+  /* The (absolute) path to the ELF dir, if known.  To help locating
+     alt and dwo files.  */
+  char *debugdir;
+
   /* dwz alternate DWARF file.  */
   Dwarf *alt_dwarf;
 
@@ -1050,20 +1054,26 @@ static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
 }
 
 
-/* Given a file descriptor, dir and file returns a full path.  If the
-   file is absolute (starts with a /) a copy of file is returned.  If
+/* Helper function to set debugdir field in Dwarf, used from dwarf_begin_elf
+   and libdwfl process_file.  */
+char * __libdw_debugdir (int fd);
+
+
+/* Given the directory of a debug file, an absolute or relative dir
+   to look in, and file returns a full path.
+
+   If the file is absolute (starts with a /) a copy of file is returned.
    the file isn't absolute, but dir is absolute, then a path that is
    the concatenation of dir and file is returned.  If neither file,
    nor dir is absolute, the path will be constructed using dir (if not
-   NULL) and file relative to the path of the given file descriptor
-   (if valid).
+   NULL) and file relative to the debugdir (if valid).
 
-   The file descriptor may be -1 and the dir may be NULL (in which
-   case they aren't used). If file is NULL, or no full path can be
-   constructed NULL is returned.
+   The debugdir and the dir may be NULL (in which case they aren't used).
+   If file is NULL, or no full path can be constructed NULL is returned.
 
    The caller is responsible for freeing the result if not NULL.  */
-char * __libdw_filepath (int fd, const char *dir, const char *file)
+char * __libdw_filepath (const char *debugdir, const char *dir,
+			 const char *file)
   internal_function;
 
 
diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c
index 0f74b39..bd48b9e 100644
--- a/libdw/libdw_find_split_unit.c
+++ b/libdw/libdw_find_split_unit.c
@@ -65,10 +65,10 @@ __libdw_find_split_unit (Dwarf_CU *cu)
 	{
 	  const char *comp_dir = dwarf_formstring (&compdir);
 	  const char *dwo_file = dwarf_formstring (&dwo_name);
-	  int fd = cu->dbg->elf->fildes;
-	  char *dwo_path = __libdw_filepath (fd, NULL, dwo_file);
+	  const char *debugdir = cu->dbg->debugdir;
+	  char *dwo_path = __libdw_filepath (debugdir, NULL, dwo_file);
 	  if (dwo_path == NULL && comp_dir != NULL)
-	    dwo_path = __libdw_filepath (fd, comp_dir, dwo_file);
+	    dwo_path = __libdw_filepath (debugdir, comp_dir, dwo_file);
 	  if (dwo_path != NULL)
 	    {
 	      int split_fd = open (dwo_path, O_RDONLY);
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index b6262c2..d69fe0c 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2018-05-17  Mark Wielaard  <mark@klomp.org>
+
+	* dwfl_module (__libdwfl_module_free): Free elfdir.
+	* dwfl_module_getdwarf.c (load_dw): Close file descriptors after
+	dwarf_begin_elf call. Set Dwarf debugdir if it is NULL, this is the
+	main module file and we recorded the elfdir.
+	* libdwflP.h (struct Dwfl_Module): Add elfdir field.
+	* offline.c (process_elf): Record the elfdir before we close the
+	main ELF file descriptor.
+
 2018-04-10  Mark Wielaard  <mark@klomp.org>
 
 	* frame_unwind.c (unwind): If __libdwfl_frame_reg_get fails for
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index 510bd69..e7dfdac 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -120,6 +120,7 @@ __libdwfl_module_free (Dwfl_Module *mod)
     free (mod->reloc_info);
 
   free (mod->name);
+  free (mod->elfdir);
   free (mod);
 }
 
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 9775ace..af6838a 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -1335,7 +1335,18 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
 	result = __libdwfl_relocate (mod, debugfile->elf, true);
       if (result != DWFL_E_NOERROR)
 	return result;
+    }
+
+  mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
+  if (mod->dw == NULL)
+    {
+      int err = INTUSE(dwarf_errno) ();
+      return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
+    }
 
+  /* Do this after dwarf_begin_elf has a chance to process the fd.  */
+  if (mod->e_type == ET_REL && !debugfile->relocated)
+    {
       /* Don't keep the file descriptors around.  */
       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
 	{
@@ -1349,12 +1360,12 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
 	}
     }
 
-  mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
-  if (mod->dw == NULL)
-    {
-      int err = INTUSE(dwarf_errno) ();
-      return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
-    }
+  /* We might have already closed the fd when we asked dwarf_begin_elf to
+     create an Dwarf.  Help out a little in case we need to find an alt or
+     dwo file later.  */
+  if (mod->dw->debugdir == NULL && mod->elfdir != NULL
+      && debugfile == &mod->main)
+    mod->dw->debugdir = strdup (mod->elfdir);
 
   /* Until we have iterated through all CU's, we might do lazy lookups.  */
   mod->lazycu = 1;
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 15ca0a1..3629871 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -190,6 +190,8 @@ struct Dwfl_Module
   Elf_Data *symxndxdata;	/* Data in the extended section index table. */
   Elf_Data *aux_symxndxdata;	/* Data in the extended auxiliary table. */
 
+  char *elfdir;			/* The dir where we found the main Elf.  */
+
   Dwarf *dw;			/* libdw handle for its debugging info.  */
   Dwarf *alt;			/* Dwarf used for dwarf_setalt, or NULL.  */
   int alt_fd; 			/* descriptor, only valid when alt != NULL.  */
diff --git a/libdwfl/offline.c b/libdwfl/offline.c
index 80c80a1..d8697cf 100644
--- a/libdwfl/offline.c
+++ b/libdwfl/offline.c
@@ -150,6 +150,9 @@ process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
       /* Don't keep the file descriptor around.  */
       if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
 	{
+	  /* Grab the dir path in case we want to report this file as
+	     Dwarf later.  */
+	  mod->elfdir = __libdw_debugdir (mod->main.fd);
 	  close (mod->main.fd);
 	  mod->main.fd = -1;
 	}
-- 
1.8.3.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]