diff options
author | Tom Tromey <tromey@redhat.com> | 2012-07-18 19:49:33 +0000 |
---|---|---|
committer | Tom Tromey <tromey@redhat.com> | 2012-07-18 19:49:33 +0000 |
commit | 6ec53d052b63163944019f5e17d73fafb9c57c2d (patch) | |
tree | 8bd0dd4e16b2b192102396f08878837761fd5ae6 /gdb/gdb_bfd.c | |
parent | f9a062ffb59ebed937221b852eab2abbd43111ed (diff) | |
download | gdb-6ec53d052b63163944019f5e17d73fafb9c57c2d.zip gdb-6ec53d052b63163944019f5e17d73fafb9c57c2d.tar.gz gdb-6ec53d052b63163944019f5e17d73fafb9c57c2d.tar.bz2 |
* gdb_bfd.c (struct gdb_bfd_data): New.
(gdb_bfd_cache): New global.
(struct gdb_bfd_cache_search): New.
(hash_bfd, eq_bfd, gdb_bfd_open): New functions.
(gdb_bfd_ref, gdb_bfd_unref): Use gdb_bfd_data.
* gdb_bfd.h (gdb_bfd_open): Declare.
Diffstat (limited to 'gdb/gdb_bfd.c')
-rw-r--r-- | gdb/gdb_bfd.c | 157 |
1 files changed, 141 insertions, 16 deletions
diff --git a/gdb/gdb_bfd.c b/gdb/gdb_bfd.c index 8f40d74..5ad9878 100644 --- a/gdb/gdb_bfd.c +++ b/gdb/gdb_bfd.c @@ -1,6 +1,6 @@ /* Definitions for BFD wrappers used by GDB. - Copyright (C) 2011 + Copyright (C) 2011, 2012 Free Software Foundation, Inc. This file is part of GDB. @@ -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,116 @@ 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); +} + +/* See gdb_bfd.h. */ + +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 | O_BINARY); + 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 +171,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 +197,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); } |