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]

[5/17] introduce the BFD cache


Now that BFDs are reference counted, we can start to share them.

This adds a wrapper function, gdb_bfd_open, which tries to share
ordinary file-based BFDs when possible.  It uses the file name and mtime
to decide shareability.

Note that this wrapper doesn't call bfd_cache_init.  See the discussion
in the first message for more on this.  This is arguably a bug, but some
comprehensive approach to this problem is needed, so I didn't bother
with it here.

Tom

>From 00e5c9540e88cef5dcfffc237efa08ea6eee7b94 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Mon, 5 Dec 2011 08:49:24 -0700
Subject: [PATCH 05/18] introduce bfd cache

	* windows-nat.c (windows_make_so): Use gdb_bfd_open.
	* symfile.c (bfd_open_maybe_remote): Use gdb_bfd_open.
	(symfile_bfd_open): Likewise.
	(generic_load): Likewise.
	* solib.c (solib_bfd_fopen): Use gdb_bfd_open.
	* solib-pa64.c (pa64_solib_create_inferior_hook): Use
	gdb_bfd_open.
	* solib-darwin.c (darwin_solib_get_all_image_info_addr_at_init):
	Use gdb_bfd_open.
	* rs6000-nat.c (add_vmap): Use gdb_bfd_open.
	* remote-mips.c (mips_load_srec): Use gdb_bfd_open.
	(pmon_load_fast): Likewise.
	* remote-m32r-sdi.c (m32r_load): Use gdb_bfd_open.
	* procfs.c (insert_dbx_link_bpt_in_file): Use gdb_bfd_open.
	* machoread.c (macho_symfile_read_all_oso): Use gdb_bfd_open.
	(macho_check_dsym): Likewise.
	* m32r-rom.c (m32r_load): Use gdb_bfd_open.
	(m32r_upload_command): Likewise.
	* gdb_bfd.h (gdb_bfd_cache): Declare.
	* gdb_bfd.c (struct gdb_bfd_data): New.
	(gdb_bfd_cache): New global.
	(struct gdb_bfd_cache_search): New.
	(hash_bfd): New function.
	(eq_bfd): Likewise.
	(gdb_bfd_open): Likewise.
	(gdb_bfd_ref): Allocate a gdb_bfd_data and attach to the BFD.
	(gdb_bfd_unref): Remove closed BFD from cache.  Update for
	gdb_bfd_data.
	* exec.c (exec_file_attach): Use gdb_bfd_open.
	* dsrec.c (load_srec): Use gdb_bfd_open.
---
 gdb/dsrec.c           |    2 +-
 gdb/exec.c            |    8 ++-
 gdb/gdb_bfd.c         |  153 ++++++++++++++++++++++++++++++++++++++++++++-----
 gdb/gdb_bfd.h         |    8 +++
 gdb/m32r-rom.c        |    4 +-
 gdb/machoread.c       |    5 +-
 gdb/procfs.c          |    2 +-
 gdb/remote-m32r-sdi.c |    2 +-
 gdb/remote-mips.c     |    4 +-
 gdb/rs6000-nat.c      |    5 +-
 gdb/solib-darwin.c    |    2 +-
 gdb/solib-pa64.c      |    2 +-
 gdb/solib.c           |    6 +-
 gdb/symfile.c         |    6 +-
 gdb/windows-nat.c     |    2 +-
 15 files changed, 171 insertions(+), 40 deletions(-)

diff --git a/gdb/dsrec.c b/gdb/dsrec.c
index 60591ba..1b84c01 100644
--- a/gdb/dsrec.c
+++ b/gdb/dsrec.c
@@ -61,7 +61,7 @@ load_srec (struct serial *desc, const char *file, bfd_vma load_offset,
 
   srec = (char *) alloca (maxrecsize + 1);
 
-  abfd = gdb_bfd_ref (bfd_openr (file, 0));
+  abfd = gdb_bfd_open (file, NULL, -1);
   if (!abfd)
     {
       printf_filtered (_("Unable to open file %s\n"), file);
diff --git a/gdb/exec.c b/gdb/exec.c
index 19a79ed..891aaa4 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -235,9 +235,11 @@ exec_file_attach (char *filename, int from_tty)
 
       if (scratch_chan < 0)
 	perror_with_name (filename);
-      exec_bfd = gdb_bfd_ref (bfd_fopen (scratch_pathname, gnutarget,
-					 write_files ? FOPEN_RUB : FOPEN_RB,
-					 scratch_chan));
+      if (write_files)
+	exec_bfd = gdb_bfd_ref (bfd_fopen (scratch_pathname, gnutarget,
+					   FOPEN_RUB, scratch_chan));
+      else
+	exec_bfd = gdb_bfd_open (scratch_pathname, gnutarget, scratch_chan);
 
       if (!exec_bfd)
 	{
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c
index 8f40d74..84b612d 100644
--- a/gdb/gdb_bfd.c
+++ b/gdb/gdb_bfd.c
@@ -22,6 +22,7 @@
 #include "gdb_bfd.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
+#include "hashtab.h"
 
 /* See gdb_bfd.h.  */
 
@@ -38,6 +39,114 @@ gdb_bfd_stash_filename (struct bfd *abfd)
   abfd->filename = data;
 }
 
+/* An object of this type is stored in each BFD's user data.  */
+
+struct gdb_bfd_data
+{
+  /* The reference count.  */
+  int refc;
+
+  /* The mtime of the BFD at the point the cache entry was made.  */
+  time_t mtime;
+};
+
+/* A hash table storing all the BFDs maintained in the cache.  */
+
+static htab_t gdb_bfd_cache;
+
+/* The type of an object being looked up in gdb_bfd_cache.  We use
+   htab's capability of storing one kind of object (BFD in this case)
+   and using a different sort of object for searching.  */
+
+struct gdb_bfd_cache_search
+{
+  /* The filename.  */
+  const char *filename;
+  /* The mtime.  */
+  time_t mtime;
+};
+
+/* A hash function for BFDs.  */
+
+static hashval_t
+hash_bfd (const void *b)
+{
+  const bfd *abfd = b;
+
+  /* It is simplest to just hash the filename.  */
+  return htab_hash_string (bfd_get_filename (abfd));
+}
+
+/* An equality function for BFDs.  Note that this expects the caller
+   to search using struct gdb_bfd_cache_search only, not BFDs.  */
+
+static int
+eq_bfd (const void *a, const void *b)
+{
+  const bfd *abfd = a;
+  const struct gdb_bfd_cache_search *s = b;
+  struct gdb_bfd_data *gdata = bfd_usrdata (abfd);
+
+  return (gdata->mtime == s->mtime
+	  && strcmp (bfd_get_filename (abfd), s->filename) == 0);
+}
+
+struct bfd *
+gdb_bfd_open (const char *name, const char *target, int fd)
+{
+  hashval_t hash;
+  void **slot;
+  bfd *abfd;
+  struct gdb_bfd_cache_search search;
+  struct stat st;
+
+  if (gdb_bfd_cache == NULL)
+    gdb_bfd_cache = htab_create_alloc (1, hash_bfd, eq_bfd, NULL,
+				       xcalloc, xfree);
+
+  if (fd == -1)
+    {
+      fd = open (name, O_RDONLY);
+      if (fd == -1)
+	{
+	  bfd_set_error (bfd_error_system_call);
+	  return NULL;
+	}
+    }
+
+  search.filename = name;
+  if (fstat (fd, &st) < 0)
+    {
+      /* Weird situation here.  */
+      search.mtime = 0;
+    }
+  else
+    search.mtime = st.st_mtime;
+
+  /* Note that this must compute the same result as hash_bfd.  */
+  hash = htab_hash_string (name);
+  /* Note that we cannot use htab_find_slot_with_hash here, because
+     opening the BFD may fail; and this would violate hashtab
+     invariants.  */
+  abfd = htab_find_with_hash (gdb_bfd_cache, &search, hash);
+  if (abfd != NULL)
+    {
+      close (fd);
+      return gdb_bfd_ref (abfd);
+    }
+
+  abfd = bfd_fopen (name, target, FOPEN_RB, fd);
+  if (abfd == NULL)
+    return NULL;
+
+  slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash, INSERT);
+  gdb_assert (!*slot);
+  *slot = abfd;
+
+  gdb_bfd_stash_filename (abfd);
+  return gdb_bfd_ref (abfd);
+}
+
 /* Close ABFD, and warn if that fails.  */
 
 static int
@@ -60,22 +169,23 @@ gdb_bfd_close_or_warn (struct bfd *abfd)
 struct bfd *
 gdb_bfd_ref (struct bfd *abfd)
 {
-  int *p_refcount;
+  struct gdb_bfd_data *gdata;
 
   if (abfd == NULL)
     return NULL;
 
-  p_refcount = bfd_usrdata (abfd);
+  gdata = bfd_usrdata (abfd);
 
-  if (p_refcount != NULL)
+  if (gdata != NULL)
     {
-      *p_refcount += 1;
+      gdata->refc += 1;
       return abfd;
     }
 
-  p_refcount = xmalloc (sizeof (*p_refcount));
-  *p_refcount = 1;
-  bfd_usrdata (abfd) = p_refcount;
+  gdata = bfd_zalloc (abfd, sizeof (struct gdb_bfd_data));
+  gdata->refc = 1;
+  gdata->mtime = bfd_get_mtime (abfd);
+  bfd_usrdata (abfd) = gdata;
 
   return abfd;
 }
@@ -85,22 +195,35 @@ gdb_bfd_ref (struct bfd *abfd)
 void
 gdb_bfd_unref (struct bfd *abfd)
 {
-  int *p_refcount;
-  char *name;
+  struct gdb_bfd_data *gdata;
+  struct gdb_bfd_cache_search search;
 
   if (abfd == NULL)
     return;
 
-  p_refcount = bfd_usrdata (abfd);
-  gdb_assert (*p_refcount >= 1);
+  gdata = bfd_usrdata (abfd);
+  gdb_assert (gdata->refc >= 1);
 
-  *p_refcount -= 1;
-  if (*p_refcount > 0)
+  gdata->refc -= 1;
+  if (gdata->refc > 0)
     return;
 
-  xfree (p_refcount);
+  search.filename = bfd_get_filename (abfd);
+
+  if (gdb_bfd_cache && search.filename)
+    {
+      hashval_t hash = htab_hash_string (search.filename);
+      void **slot;
+
+      search.mtime = gdata->mtime;
+      slot = htab_find_slot_with_hash (gdb_bfd_cache, &search, hash,
+				       NO_INSERT);
+
+      if (slot && *slot)
+	htab_clear_slot (gdb_bfd_cache, slot);
+    }
+
   bfd_usrdata (abfd) = NULL;  /* Paranoia.  */
 
-  name = bfd_get_filename (abfd);
   gdb_bfd_close_or_warn (abfd);
 }
diff --git a/gdb/gdb_bfd.h b/gdb/gdb_bfd.h
index d2d7e5d..0f42c8f 100644
--- a/gdb/gdb_bfd.h
+++ b/gdb/gdb_bfd.h
@@ -27,6 +27,14 @@
 
 void gdb_bfd_stash_filename (struct bfd *abfd);
 
+/* Open a read-only (FOPEN_RB) BFD given arguments like bfd_fopen.
+   Returns NULL on error.  On success, returns a new reference to the
+   BFD, which must be freed with gdb_bfd_unref.  BFDs returned by this
+   call are shared among all callers opening the same file.  If FD is
+   not -1, then after this call it is owned by BFD.  */
+
+struct bfd *gdb_bfd_open (const char *name, const char *target, int fd);
+
 /* Acquire a new reference to ABFD.  Returns ABFD for convenience.  */
 
 struct bfd *gdb_bfd_ref (struct bfd *abfd);
diff --git a/gdb/m32r-rom.c b/gdb/m32r-rom.c
index ea140a9..1225c78 100644
--- a/gdb/m32r-rom.c
+++ b/gdb/m32r-rom.c
@@ -131,7 +131,7 @@ m32r_load (char *filename, int from_tty)
   if (filename == NULL || filename[0] == 0)
     filename = get_exec_file (1);
 
-  abfd = gdb_bfd_ref (bfd_openr (filename, 0));
+  abfd = gdb_bfd_open (filename, NULL, -1);
   if (!abfd)
     error (_("Unable to open file %s."), filename);
   cleanup = make_cleanup_bfd_close (abfd);
@@ -526,7 +526,7 @@ m32r_upload_command (char *args, int from_tty)
     printf_filtered (" -- Ethernet load complete.\n");
 
   gettimeofday (&end_time, NULL);
-  abfd = gdb_bfd_ref (bfd_openr (args, 0));
+  abfd = gdb_bfd_open (args, NULL, -1);
   cleanup = make_cleanup_bfd_close (abfd);
   if (abfd != NULL)
     {		/* Download is done -- print section statistics.  */
diff --git a/gdb/machoread.c b/gdb/machoread.c
index a384940..f907355 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -689,7 +689,7 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags)
             }
 
 	  /* Open the archive and check the format.  */
-	  archive_bfd = gdb_bfd_ref (bfd_openr (archive_name, gnutarget));
+	  archive_bfd = gdb_bfd_open (archive_name, gnutarget, -1);
 	  if (archive_bfd == NULL)
 	    {
 	      warning (_("Could not open OSO archive file \"%s\""),
@@ -764,7 +764,7 @@ macho_symfile_read_all_oso (struct objfile *main_objfile, int symfile_flags)
 	{
           bfd *abfd;
 
-	  abfd = gdb_bfd_ref (bfd_openr (oso->name, gnutarget));
+	  abfd = gdb_bfd_open (oso->name, gnutarget, -1);
 	  if (!abfd)
             warning (_("`%s': can't open to read symbols: %s."), oso->name,
                      bfd_errmsg (bfd_get_error ()));
@@ -820,7 +820,6 @@ macho_check_dsym (struct objfile *objfile)
       warning (_("can't open dsym file %s"), dsym_filename);
       return NULL;
     }
-  gdb_bfd_stash_filename (dsym_filename);
 
   if (!bfd_check_format (dsym_bfd, bfd_object))
     {
diff --git a/gdb/procfs.c b/gdb/procfs.c
index f90f20b..cd2f3e8 100644
--- a/gdb/procfs.c
+++ b/gdb/procfs.c
@@ -3688,7 +3688,7 @@ insert_dbx_link_bpt_in_file (int fd, CORE_ADDR ignored)
   long storage_needed;
   CORE_ADDR sym_addr;
 
-  abfd = gdb_bfd_ref (bfd_fdopenr ("unamed", 0, fd));
+  abfd = gdb_bfd_open (bfd_fdopenr ("unamed", 0, fd));
   if (abfd == NULL)
     {
       warning (_("Failed to create a bfd: %s."), bfd_errmsg (bfd_get_error ()));
diff --git a/gdb/remote-m32r-sdi.c b/gdb/remote-m32r-sdi.c
index 3fb54cc..56feb84 100644
--- a/gdb/remote-m32r-sdi.c
+++ b/gdb/remote-m32r-sdi.c
@@ -1263,7 +1263,7 @@ m32r_load (char *args, int from_tty)
   if (!filename)
     filename = get_exec_file (1);
 
-  pbfd = gdb_bfd_ref (bfd_openr (filename, gnutarget));
+  pbfd = gdb_bfd_open (filename, gnutarget, -1);
   if (pbfd == NULL)
     {
       perror_with_name (filename);
diff --git a/gdb/remote-mips.c b/gdb/remote-mips.c
index 87d4804..07773bf 100644
--- a/gdb/remote-mips.c
+++ b/gdb/remote-mips.c
@@ -2793,7 +2793,7 @@ mips_load_srec (char *args)
 
   buffer = alloca (srec_frame * 2 + 256);
 
-  abfd = gdb_bfd_ref (bfd_openr (args, 0));
+  abfd = gdb_bfd_open (args, NULL, -1);
   if (!abfd)
     {
       printf_filtered ("Unable to open file %s\n", args);
@@ -3380,7 +3380,7 @@ pmon_load_fast (char *file)
   buffer = (char *) xmalloc (MAXRECSIZE + 1);
   binbuf = (unsigned char *) xmalloc (BINCHUNK);
 
-  abfd = gdb_bfd_ref (bfd_openr (file, 0));
+  abfd = gdb_bfd_open (file, NULL, -1);
   if (!abfd)
     {
       printf_filtered ("Unable to open file %s\n", file);
diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c
index a92f8cb..991c3e0 100644
--- a/gdb/rs6000-nat.c
+++ b/gdb/rs6000-nat.c
@@ -748,10 +748,9 @@ add_vmap (LdInfo *ldi)
   if (fd < 0)
     /* Note that this opens it once for every member; a possible
        enhancement would be to only open it once for every object.  */
-    abfd = bfd_openr (objname, gnutarget);
+    abfd = gdb_bfd_open (objname, gnutarget, -1);
   else
-    abfd = bfd_fdopenr (objname, gnutarget, fd);
-  abfd = gdb_bfd_ref (abfd);
+    abfd = gdb_bfd_open (objname, gnutarget, fd);
   if (!abfd)
     {
       warning (_("Could not open `%s' as an executable file: %s"),
diff --git a/gdb/solib-darwin.c b/gdb/solib-darwin.c
index cf92deb..ea499e5 100644
--- a/gdb/solib-darwin.c
+++ b/gdb/solib-darwin.c
@@ -314,7 +314,7 @@ darwin_solib_get_all_image_info_addr_at_init (void)
     return;
 
   /* Create a bfd for the interpreter.  */
-  dyld_bfd = gdb_bfd_ref (bfd_openr (interp_name, gnutarget));
+  dyld_bfd = gdb_bfd_open (interp_name, gnutarget, -1);
   if (dyld_bfd)
     {
       bfd *sub;
diff --git a/gdb/solib-pa64.c b/gdb/solib-pa64.c
index 688e145..8f4d801 100644
--- a/gdb/solib-pa64.c
+++ b/gdb/solib-pa64.c
@@ -363,7 +363,7 @@ manpage for methods to privately map shared library text."));
 	 to find any magic formula to find it for Solaris (appears to
 	 be trivial on GNU/Linux).  Therefore, we have to try an alternate
 	 mechanism to find the dynamic linker's base address.  */
-      tmp_bfd = gdb_bfd_ref (bfd_openr (buf, gnutarget));
+      tmp_bfd = gdb_bfd_open (buf, gnutarget, -1);
       if (tmp_bfd == NULL)
 	return;
 
diff --git a/gdb/solib.c b/gdb/solib.c
index 9ef8932..79d1905 100644
--- a/gdb/solib.c
+++ b/gdb/solib.c
@@ -375,11 +375,11 @@ solib_bfd_fopen (char *pathname, int fd)
   if (remote_filename_p (pathname))
     {
       gdb_assert (fd == -1);
-      abfd = remote_bfd_open (pathname, gnutarget);
+      abfd = gdb_bfd_ref (remote_bfd_open (pathname, gnutarget));
     }
   else
     {
-      abfd = bfd_fopen (pathname, gnutarget, FOPEN_RB, fd);
+      abfd = gdb_bfd_open (pathname, gnutarget, fd);
 
       if (abfd)
 	bfd_set_cacheable (abfd, 1);
@@ -394,7 +394,7 @@ solib_bfd_fopen (char *pathname, int fd)
 	     pathname, bfd_errmsg (bfd_get_error ()));
     }
 
-  return gdb_bfd_ref (abfd);
+  return abfd;
 }
 
 /* Find shared library PATHNAME and open a BFD for it.  */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 74a0317..fd39824 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -1662,7 +1662,7 @@ bfd_open_maybe_remote (const char *name)
   if (remote_filename_p (name))
     return gdb_bfd_ref (remote_bfd_open (name, gnutarget));
   else
-    return gdb_bfd_ref (bfd_openr (name, gnutarget));
+    return gdb_bfd_open (name, gnutarget, -1);
 }
 
 
@@ -1720,7 +1720,7 @@ symfile_bfd_open (char *name)
   name = absolute_name;
   make_cleanup (xfree, name);
 
-  sym_bfd = gdb_bfd_ref (bfd_fopen (name, gnutarget, FOPEN_RB, desc));
+  sym_bfd = gdb_bfd_open (name, gnutarget, desc);
   if (!sym_bfd)
     {
       close (desc);
@@ -2060,7 +2060,7 @@ generic_load (char *args, int from_tty)
     }
 
   /* Open the file for loading.  */
-  loadfile_bfd = gdb_bfd_ref (bfd_openr (filename, gnutarget));
+  loadfile_bfd = gdb_bfd_open (filename, gnutarget, -1);
   if (loadfile_bfd == NULL)
     {
       perror_with_name (filename);
diff --git a/gdb/windows-nat.c b/gdb/windows-nat.c
index ff34778..25cae95 100644
--- a/gdb/windows-nat.c
+++ b/gdb/windows-nat.c
@@ -731,7 +731,7 @@ windows_make_so (const char *name, LPVOID load_addr)
       asection *text = NULL;
       CORE_ADDR text_vma;
 
-      abfd = gdb_bfd_ref (bfd_openr (so->so_name, "pei-i386"));
+      abfd = gdb_bfd_open (so->so_name, "pei-i386", -1);
 
       if (!abfd)
 	return so;
-- 
1.7.6.4


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