This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB 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 v12 17/32] Add file_location utility functions


Hi,

build id verification faces a problem current codebase calls openp() and
similar functions which search many directories and after they find the file
they return its filename.  Caller then typically opens that file as BFD.

But to search the directories openp() needs to open each file it iterates to
verify their build-id.  Then it would close the file and caller would reopen it
again.  This is inefficient (+racy), so a new intermediate representation of
the found files is created (file_location).

Another possibility would be to depends on bfd cache as being done in
exec_file_attach.  But then a similar problem is needed for callers which want
only fd (and not bfd).  Besides that I find depending on pending
make_cleanup_bfd_unref() from openp() calls would be tricky.


Jan


gdb/ChangeLog
2015-08-18  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* defs.h (enum openp_flags): Add OPF_IS_BFD.
	* gdb_bfd.c (fileio_errno_to_host): Make it public.
	* gdb_bfd.h (fileio_errno_to_host): Add prototype.
	* source.c: Include inferior.h and gdb/fileio.h.
	(file_location_enoent, file_location_free, file_location_cleanup)
	(file_location_is_valid, file_location_from_filename)
	(file_location_to_bfd, filename_to_bfd): New functions.
	* source.h (struct file_location): New definition.
	(file_location_enoent, file_location_free, file_location_is_valid)
	(file_location file_location_from_filename, file_location_to_bfd)
	(filename_to_bfd): New prototypes.
---
 0 files changed

diff --git a/gdb/defs.h b/gdb/defs.h
index 7795b4a..8ee8b33 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -338,6 +338,9 @@ enum openp_flags
      for source files but not for executables).  */
   OPF_SEARCH_IN_PATH  = (1 << 1),
 
+  /* Ask for bfd * to be returned in file_location.  */
+  OPF_IS_BFD          = (1 << 2),
+
   /* Open the file in read/write mode if WRITE_FILES says so.  */
   OPF_OPEN_RW_TMP     = (1 << 3),
 };
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 1224695..dc2d6c0 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -197,7 +197,7 @@ gdb_bfd_has_target_filename (struct bfd *abfd)
 
 /* Return the system error number corresponding to ERRNUM.  */
 
-static int
+int
 fileio_errno_to_host (int errnum)
 {
   switch (errnum)
diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h
index dcc6755..99fabfd 100644
--- a/gdb/gdb_bfd.h
+++ b/gdb/gdb_bfd.h
@@ -172,4 +172,6 @@ int gdb_bfd_count_sections (bfd *abfd);
 
 int gdb_bfd_requires_relocations (bfd *abfd);
 
+int fileio_errno_to_host (int errnum);
+
 #endif /* GDB_BFD_H */
diff --git a/gdb/source.c b/gdb/source.c
index 4096d0d..d06cc84 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -27,6 +27,8 @@
 #include "frame.h"
 #include "value.h"
 #include "filestuff.h"
+#include "inferior.h"
+#include "gdb/fileio.h"
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -737,6 +739,211 @@ dirnames_to_char_ptr_vec_target_exc (const char *string)
   return vec;
 }
 
+/* Initialize *FILE as failed one with error code ENOENT.  Such
+   file_location still should be processed by file_location_free.  */
+
+void
+file_location_enoent (struct file_location *file)
+{
+  memset (file, 0, sizeof (*file));
+  file->fd = -1;
+  file->file_errno = ENOENT;
+}
+
+/* Free resources of *FILE.  *FILE must be properly initialized, either
+   by a successful or unsuccessful locator.  *FILE remains unspecified
+   after this call.  */
+
+void
+file_location_free (struct file_location *file)
+{
+  if (file->fd != -1)
+    {
+      if (file->load_via_target)
+	{
+	  int target_errno;
+
+	  target_fileio_close (file->fd, &target_errno);
+	}
+      else
+	close (file->fd);
+    }
+  gdb_bfd_unref (file->abfd);
+  xfree (file->filename);
+}
+
+/* Call file_location_free suitable for make_cleanup.  */
+
+static void
+file_location_cleanup (void *file_voidp)
+{
+  file_location_free (file_voidp);
+}
+
+/* Return boolean 1 if *FILE contains a successful file representation.
+   Return 0 otherwise.  */
+
+int
+file_location_is_valid (const struct file_location *file)
+{
+  if (!file->file_errno && !file->bfderr)
+    return 1;
+  gdb_assert (file->abfd == NULL);
+  return 0;
+}
+
+/* Return new file_location from FILENAME and OPTS.  */
+
+struct file_location
+file_location_from_filename (const char *filename, enum openp_flags opts)
+{
+  struct file_location file;
+  struct cleanup *back_to;
+
+  memset (&file, 0, sizeof (file));
+  file.fd = -1;
+  back_to = make_cleanup (file_location_cleanup, &file);
+  file.filename = xstrdup (filename);
+
+  if (is_target_filename (filename))
+    {
+      filename += strlen (TARGET_SYSROOT_PREFIX);
+      if (!target_filesystem_is_local ())
+	{
+	  file.load_via_target = 1;
+
+	  /* gdb_bfd_fopen does not support "target:" filenames.  */
+	  if (write_files)
+	    warning (_("writing into executable files is "
+		       "not supported for %s sysroots"),
+		     TARGET_SYSROOT_PREFIX);
+	}
+    }
+
+  if (file.load_via_target)
+    {
+      int target_errno;
+
+      file.fd = target_fileio_open (current_inferior (),
+				    filename, FILEIO_O_RDONLY, 0,
+				    &target_errno);
+      if (file.fd == -1)
+	{
+	  file.file_errno = fileio_errno_to_host (target_errno);
+	  discard_cleanups (back_to);
+	  return file;
+	}
+    }
+  else
+    {
+      /* WRITE_FILES is ignored if !OPF_IS_BFD.  */
+
+      file.fd = gdb_open_cloexec (filename, O_RDONLY | O_BINARY, 0);
+      if (file.fd == -1)
+	{
+	  file.file_errno = errno;
+	  discard_cleanups (back_to);
+	  return file;
+	}
+    }
+
+  if ((opts & OPF_IS_BFD) == 0)
+    {
+      discard_cleanups (back_to);
+      return file;
+    }
+
+  if (file.load_via_target)
+    {
+      const int do_close = (opts & OPF_IS_BFD) != 0;
+
+      gdb_assert (strcmp (filename,
+			  file.filename + strlen (TARGET_SYSROOT_PREFIX)) == 0);
+      file.abfd = gdb_bfd_open_from_target (file.filename, gnutarget, file.fd,
+					    do_close);
+      if (do_close && file.abfd != NULL)
+	file.fd = -1;
+    }
+  else
+    {
+      if (write_files)
+	file.abfd = gdb_bfd_fopen (filename, gnutarget, FOPEN_RUB, file.fd);
+      else
+	file.abfd = gdb_bfd_open (filename, gnutarget, file.fd);
+      if ((opts & OPF_IS_BFD) != 0)
+	file.fd = -1;
+      else
+	{
+	  file.fd = dup (file.fd);
+	  if (file.fd == -1)
+	    {
+	      int save_errno = errno;
+
+	      do_cleanups (back_to);
+	      file_location_enoent (&file);
+	      file.file_errno = save_errno;
+	      return file;
+	    }
+	}
+    }
+
+  if (file.abfd == NULL)
+    {
+      file.bfderr = bfd_get_error ();
+      discard_cleanups (back_to);
+      return file;
+    }
+
+  discard_cleanups (back_to);
+  return file;
+}
+
+/* Return new BFD * from FILE.  If FILE represents a failed locator
+   result then bfd_set_error is called and NULL is returned.  FILE
+   content is always freed by this function.  The locator for FILE must
+   have been called with OPF_IS_BFD.  */
+
+bfd *
+file_location_to_bfd (struct file_location file)
+{
+  bfd *retval;
+
+  if (file.abfd == NULL)
+    {
+      const int file_errno = file.file_errno;
+      const bfd_error_type file_bfderr = file.bfderr;
+
+      gdb_assert (file_errno || file_bfderr);
+
+      file_location_free (&file);
+
+      if (file_bfderr == bfd_error_on_input)
+	bfd_set_error (bfd_error_malformed_archive);
+      else if (file_bfderr)
+	bfd_set_error (file_bfderr);
+      else
+	{
+	  bfd_set_error (bfd_error_system_call);
+	  errno = file_errno;
+	}
+      return NULL;
+    }
+  gdb_bfd_ref (file.abfd);
+  retval = file.abfd;
+  file_location_free (&file);
+  return retval;
+}
+
+/* Return new BFD * from FILENAME.  See file_location_from_filename and
+   file_location_to_bfd.  */
+
+bfd *
+filename_to_bfd (const char *filename)
+{
+  return file_location_to_bfd (file_location_from_filename (filename,
+							    OPF_IS_BFD));
+}
+
 /* Open a file named STRING, searching path PATH (dir names sep by some char).
    You cannot use this function to create files.
 
diff --git a/gdb/source.h b/gdb/source.h
index fd58d8e..f511959 100644
--- a/gdb/source.h
+++ b/gdb/source.h
@@ -101,4 +101,50 @@ extern void add_substitute_path_rule (char *, char *);
 
 extern VEC (char_ptr) *dirnames_to_char_ptr_vec_target_exc (const char *string);
 
+/* Unified file representation which can contain BFD *, filename and FD
+   in all or some of the forms.  */
+struct file_location
+{
+  /* This pointer can be NULL.  Use OPF_IS_BFD to get it filled in.  */
+  bfd *abfd;
+
+  /* This pointer is never NULL.  It names the actual file opened (this
+     string will always start with a "/").  We have to take special
+     pains to avoid doubling the "/" between the directory and the file,
+     sigh!  Emacs gets confuzzed by this when we print the source file
+     name!!!  */
+  char *filename;
+
+  /* A flag whether FD represents remote target fileio descriptor or
+     local operating system file descriptor.  */
+  unsigned char load_via_target;
+
+  /* File descriptor (see LOAD_VIA_TARGET) or -1.  Do not use OPF_IS_BFD
+     to get it filled in.  */
+  int fd;
+
+  /* ERRNO value if a call to fill-in this structure failed.  See also
+     BFDERR.  */
+  int file_errno;
+
+  /* BFD error value if a call to fill-in this structure failed or
+     bfd_error_no_error.  If either FILE_ERRNO or BFDERR are non-zero
+     then this file_location failed and ABFD must be NULL.  There is no
+     guarantee for failed file_location about FD value.  */
+  bfd_error_type bfderr;
+};
+
+extern void file_location_enoent (struct file_location *file);
+
+extern void file_location_free (struct file_location *file);
+
+extern int file_location_is_valid (const struct file_location *file);
+
+extern struct file_location file_location_from_filename (const char *filename,
+							 enum openp_flags opts);
+
+extern bfd *file_location_to_bfd (struct file_location file);
+
+extern bfd *filename_to_bfd (const char *filename);
+
 #endif


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