[5/17] introduce the BFD cache
Tom Tromey
tromey@redhat.com
Wed Dec 14 21:15:00 GMT 2011
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
More information about the Gdb-patches
mailing list