aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfd/ChangeLog16
-rw-r--r--bfd/archive.c86
-rw-r--r--bfd/libbfd-in.h8
-rw-r--r--bfd/libbfd.h8
-rw-r--r--bfd/opncls.c12
5 files changed, 95 insertions, 35 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index da2a229..3f40b9e 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,19 @@
+2012-08-09 Alan Modra <amodra@gmail.com>
+ Tom Tromey <tromey@redhat.com>
+
+ * archive.c (SECTION Archives): Update documentation.
+ (_bfd_delete_archive_data): Remove.
+ (_bfd_add_bfd_to_archive_cache): Set 'parent_cache' and 'key'.
+ (archive_close_worker, _bfd_archive_close_and_cleanup): New
+ functions.
+ * libbfd-in.h (struct areltdata <parent_cache, key>): New fields.
+ (_bfd_delete_archive_data): Don't declare.
+ (_bfd_archive_close_and_cleanup): Declare.
+ (_bfd_generic_close_and_cleanup): Redefine.
+ * libbfd.h: Rebuild.
+ * opncls.c (_bfd_delete_bfd): Don't call _bfd_delete_archive_data.
+ (bfd_close): Don't close nested thin archives here.
+
2012-08-07 Tom Tromey <tromey@redhat.com>
* archive.c (_bfd_delete_archive_data): New function.
diff --git a/bfd/archive.c b/bfd/archive.c
index 1148c11..dc67da7 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -42,11 +42,17 @@ DESCRIPTION
have to read the entire archive if you don't want
to! Read it until you find what you want.
+ A BFD returned by <<bfd_openr_next_archived_file>> can be
+ closed manually with <<bfd_close>>. If you do not close it,
+ then a second iteration through the members of an archive may
+ return the same BFD. If you close the archive BFD, then all
+ the member BFDs will automatically be closed as well.
+
Archive contents of output BFDs are chained through the
- <<next>> pointer in a BFD. The first one is findable through
- the <<archive_head>> slot of the archive. Set it with
- <<bfd_set_archive_head>> (q.v.). A given BFD may be in only one
- open output archive at a time.
+ <<archive_next>> pointer in a BFD. The first one is findable
+ through the <<archive_head>> slot of the archive. Set it with
+ <<bfd_set_archive_head>> (q.v.). A given BFD may be in only
+ one open output archive at a time.
As expected, the BFD archive code is more general than the
archive code of any given environment. BFD archives may
@@ -293,19 +299,6 @@ bfd_set_archive_head (bfd *output_archive, bfd *new_head)
return TRUE;
}
-/* Free the archive hash table, if it exists. */
-
-void
-_bfd_delete_archive_data (bfd *abfd)
-{
- struct artdata *ardata = bfd_ardata (abfd);
-
- BFD_ASSERT (abfd->format == bfd_archive);
-
- if (ardata && ardata->cache)
- htab_delete (ardata->cache);
-}
-
bfd *
_bfd_look_for_bfd_in_cache (bfd *arch_bfd, file_ptr filepos)
{
@@ -375,6 +368,10 @@ _bfd_add_bfd_to_archive_cache (bfd *arch_bfd, file_ptr filepos, bfd *new_elt)
cache->arbfd = new_elt;
*htab_find_slot (hash_table, (const void *) cache, INSERT) = cache;
+ /* Provide a means of accessing this from child. */
+ arch_eltdata (new_elt)->parent_cache = hash_table;
+ arch_eltdata (new_elt)->key = filepos;
+
return TRUE;
}
@@ -2695,3 +2692,58 @@ coff_write_armap (bfd *arch,
return TRUE;
}
+
+static int
+archive_close_worker (void **slot, void *inf ATTRIBUTE_UNUSED)
+{
+ struct ar_cache *ent = (struct ar_cache *) *slot;
+
+ bfd_close_all_done (ent->arbfd);
+ return 1;
+}
+
+bfd_boolean
+_bfd_archive_close_and_cleanup (bfd *abfd)
+{
+ if (bfd_read_p (abfd) && abfd->format == bfd_archive)
+ {
+ bfd *nbfd;
+ bfd *next;
+ htab_t htab;
+
+ /* Close nested archives (if this bfd is a thin archive). */
+ for (nbfd = abfd->nested_archives; nbfd; nbfd = next)
+ {
+ next = nbfd->archive_next;
+ bfd_close (nbfd);
+ }
+
+ htab = bfd_ardata (abfd)->cache;
+ if (htab)
+ {
+ htab_traverse_noresize (htab, archive_close_worker, NULL);
+ htab_delete (htab);
+ bfd_ardata (abfd)->cache = NULL;
+ }
+ }
+ else if (arch_eltdata (abfd) != NULL)
+ {
+ struct areltdata *ared = arch_eltdata (abfd);
+ htab_t htab = (htab_t) ared->parent_cache;
+
+ if (htab)
+ {
+ struct ar_cache ent;
+ void **slot;
+
+ ent.ptr = ared->key;
+ slot = htab_find_slot (htab, &ent, NO_INSERT);
+ if (slot != NULL)
+ {
+ BFD_ASSERT (((struct ar_cache *) *slot)->arbfd == abfd);
+ htab_clear_slot (htab, slot);
+ }
+ }
+ }
+ return TRUE;
+}
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index 8cdb1c6..80cb051 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -96,6 +96,8 @@ struct areltdata
bfd_size_type extra_size; /* BSD4.4: extra bytes after the header. */
char *filename; /* Null-terminated. */
file_ptr origin; /* For element of a thin archive. */
+ void *parent_cache; /* Where and how to find this member. */
+ file_ptr key;
};
#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
@@ -130,8 +132,6 @@ extern void bfd_release
bfd * _bfd_create_empty_archive_element_shell
(bfd *obfd);
-void _bfd_delete_archive_data
- (bfd *abfd);
bfd * _bfd_look_for_bfd_in_cache
(bfd *, file_ptr);
bfd_boolean _bfd_add_bfd_to_archive_cache
@@ -232,7 +232,9 @@ int bfd_generic_stat_arch_elt
/* Generic routines to use for BFD_JUMP_TABLE_GENERIC. Use
BFD_JUMP_TABLE_GENERIC (_bfd_generic). */
-#define _bfd_generic_close_and_cleanup bfd_true
+#define _bfd_generic_close_and_cleanup _bfd_archive_close_and_cleanup
+extern bfd_boolean _bfd_archive_close_and_cleanup
+ (bfd *);
#define _bfd_generic_bfd_free_cached_info bfd_true
extern bfd_boolean _bfd_generic_new_section_hook
(bfd *, asection *);
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index a1e544f..03b065f 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -101,6 +101,8 @@ struct areltdata
bfd_size_type extra_size; /* BSD4.4: extra bytes after the header. */
char *filename; /* Null-terminated. */
file_ptr origin; /* For element of a thin archive. */
+ void *parent_cache; /* Where and how to find this member. */
+ file_ptr key;
};
#define arelt_size(bfd) (((struct areltdata *)((bfd)->arelt_data))->parsed_size)
@@ -135,8 +137,6 @@ extern void bfd_release
bfd * _bfd_create_empty_archive_element_shell
(bfd *obfd);
-void _bfd_delete_archive_data
- (bfd *abfd);
bfd * _bfd_look_for_bfd_in_cache
(bfd *, file_ptr);
bfd_boolean _bfd_add_bfd_to_archive_cache
@@ -237,7 +237,9 @@ int bfd_generic_stat_arch_elt
/* Generic routines to use for BFD_JUMP_TABLE_GENERIC. Use
BFD_JUMP_TABLE_GENERIC (_bfd_generic). */
-#define _bfd_generic_close_and_cleanup bfd_true
+#define _bfd_generic_close_and_cleanup _bfd_archive_close_and_cleanup
+extern bfd_boolean _bfd_archive_close_and_cleanup
+ (bfd *);
#define _bfd_generic_bfd_free_cached_info bfd_true
extern bfd_boolean _bfd_generic_new_section_hook
(bfd *, asection *);
diff --git a/bfd/opncls.c b/bfd/opncls.c
index e538981..b2ed9be 100644
--- a/bfd/opncls.c
+++ b/bfd/opncls.c
@@ -130,9 +130,6 @@ _bfd_new_bfd_contained_in (bfd *obfd)
static void
_bfd_delete_bfd (bfd *abfd)
{
- if (abfd->format == bfd_archive)
- _bfd_delete_archive_data (abfd);
-
if (abfd->memory)
{
bfd_hash_table_free (&abfd->section_htab);
@@ -711,8 +708,6 @@ bfd_boolean
bfd_close (bfd *abfd)
{
bfd_boolean ret;
- bfd *nbfd;
- bfd *next;
if (bfd_write_p (abfd))
{
@@ -720,13 +715,6 @@ bfd_close (bfd *abfd)
return FALSE;
}
- /* Close nested archives (if this bfd is a thin archive). */
- for (nbfd = abfd->nested_archives; nbfd; nbfd = next)
- {
- next = nbfd->archive_next;
- bfd_close (nbfd);
- }
-
if (! BFD_SEND (abfd, _close_and_cleanup, (abfd)))
return FALSE;