summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2018-05-17 19:23:46 +0200
committerMark Wielaard <mark@klomp.org>2018-05-20 23:35:15 +0200
commit46d5523c94b5e9c830aeba9de863e1b65b08b1df (patch)
tree98344940b8f62388620aec92054ea59bd5e4841a
parent3d4998a9edd9f88b46662b3584de89ecd8f2f4c8 (diff)
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>
-rw-r--r--libdw/ChangeLog15
-rw-r--r--libdw/dwarf_begin_elf.c24
-rw-r--r--libdw/dwarf_end.c3
-rw-r--r--libdw/dwarf_getalt.c44
-rw-r--r--libdw/libdwP.h26
-rw-r--r--libdw/libdw_find_split_unit.c6
-rw-r--r--libdwfl/ChangeLog10
-rw-r--r--libdwfl/dwfl_module.c1
-rw-r--r--libdwfl/dwfl_module_getdwarf.c23
-rw-r--r--libdwfl/libdwflP.h2
-rw-r--r--libdwfl/offline.c3
11 files changed, 112 insertions, 45 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index c91d9ff2..72ff8a73 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 61de7526..0e435c57 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 43223de0..4702f1b1 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 3e5af151..3339b3e1 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 cffe6ce7..f7390057 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;
@@ -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;
diff --git a/libdw/libdw_find_split_unit.c b/libdw/libdw_find_split_unit.c
index 0f74b39a..bd48b9e5 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 b6262c20..d69fe0cd 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 510bd691..e7dfdace 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 9775aced..af6838a6 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 15ca0a11..36298711 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 80c80a16..d8697cf2 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;
}