]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Cache ELF directory early. Explicitly set it in dwfl.
authorMark Wielaard <mark@klomp.org>
Thu, 17 May 2018 17:23:46 +0000 (19:23 +0200)
committerMark Wielaard <mark@klomp.org>
Sun, 20 May 2018 21:35:15 +0000 (23:35 +0200)
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
libdw/dwarf_begin_elf.c
libdw/dwarf_end.c
libdw/dwarf_getalt.c
libdw/libdwP.h
libdw/libdw_find_split_unit.c
libdwfl/ChangeLog
libdwfl/dwfl_module.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/libdwflP.h
libdwfl/offline.c

index c91d9ff22bf5306af706dbdcba9554b3d8380032..72ff8a7395ab5bbd26e1e2cbef049f8a639527f9 100644 (file)
@@ -1,3 +1,18 @@
+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
index 61de75262aeba385404f33546efc11c2e8af2477..0e435c57848d5e039e19757bb029c4b8ab3056d2 100644 (file)
@@ -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;
 }
 
index 43223de0fea39912880870762c7c194f7c07ec94..4702f1b1f92df7f067ddcb7d0800e294740d8c6c 100644 (file)
@@ -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);
     }
index 3e5af151260a3833443f07b6fc71ed831b50af35..3339b3e1be8c29028d48012ffe94495f2340d529 100644 (file)
@@ -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));
index cffe6ce7dd640405058970c7f11560aee13497e8..f739005755ca1bc0265b531f52d75be45624ee2e 100644 (file)
@@ -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;
 
@@ -1051,20 +1055,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;
 
 
index 0f74b39a97c36fbbe582c86d4e2027a419a94559..bd48b9e51a410ad888cef66f98d1b8019c7c3a07 100644 (file)
@@ -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);
index b6262c2086d83bd88c5442aa67477387ed86cb04..d69fe0cd145a3340753d2d2b858b24a3cd43a104 100644 (file)
@@ -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
index 510bd6910d26ee0d1fb82489caa4418b8b3dcbce..e7dfdace70502344f1f83bbc70f6c817c8c9d962 100644 (file)
@@ -120,6 +120,7 @@ __libdwfl_module_free (Dwfl_Module *mod)
     free (mod->reloc_info);
 
   free (mod->name);
+  free (mod->elfdir);
   free (mod);
 }
 
index 9775aced3d2d6af7eb12f085bdb8bfdd3e403ba3..af6838a6f87fdc0f9f279e93174ae405ffad0d7e 100644 (file)
@@ -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;
index 15ca0a114ab2369b5ff874ffc9906c4e9d6eef2b..362987110d5439b766632a640d620a9aea6a66e2 100644 (file)
@@ -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.  */
index 80c80a168e3625e7d2e481d8822546b95fa8e530..d8697cf28480269eddd53945d08a6ef76f6ae9ee 100644 (file)
@@ -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;
        }