diff options
author | Tom Tromey <tom@tromey.com> | 2018-06-28 08:02:42 -0600 |
---|---|---|
committer | Tom Tromey <tom@tromey.com> | 2018-07-02 08:24:32 -0600 |
commit | eac61af65bcd24a48633da375527eb3f36ab47ed (patch) | |
tree | cb3dd22ee041e9f253a12838b1802c73df14cd0a /bfd/archive.c | |
parent | 41823f29a811bb250ae274652281a6294fdc2530 (diff) | |
download | gdb-eac61af65bcd24a48633da375527eb3f36ab47ed.zip gdb-eac61af65bcd24a48633da375527eb3f36ab47ed.tar.gz gdb-eac61af65bcd24a48633da375527eb3f36ab47ed.tar.bz2 |
Allow BFD to recognize macOS universal libraries
Bug #13157 is about a gdb regression, where previously it could handle
universal libraries, but now cannot.
gdb isn't working for me on macOS for other reasons, so I wrote this
small test program to show the problem:
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <bfd.h>
void
die (const char *what)
{
fprintf (stderr, "die: %s\n", what);
exit (1);
}
int
main (int argc, char **argv)
{
bfd *file = bfd_openr (argv[1], NULL);
if (file == NULL)
die ("couldn't open");
if (!bfd_check_format (file, bfd_archive))
die ("not an archive");
printf ("yay\n");
bfd_close (file);
return 0;
}
Then I built a simple universal binary. With git master BFD, I get:
$ ./doit ./universal-exe
die: not an archive
Jeff Muizelaar tracked this down to the BFD change for PR binutils/21787.
This patch changed bfd_generic_archive_p to sometimes reset the BFD's
"format" field.
However, simply changing bfd_generic_archive_p regressed the test case
in that bug.
Debugging PR binutils/21787 again, what I saw is that the mach-o
universal binary support acts like a bfd_archive but does not provide
a _close_and_cleanup function. However, if a BFD appears as an
archive member, it must always remove its own entry from its parent's
map. Otherwise, when the parent is destroyed, the already-destroyed
child BFD will be referenced. mach-o does not use the usual archive
member support, so simply using _bfd_archive_close_and_cleanup (as
other targets do) will not work.
This patch fixes the problem by introducing a new
_bfd_unlink_from_archive_parent function, then arranging for it to be
called in the mach-o case.
Ok?
bfd/ChangeLog
2018-07-02 Jeff Muizelaar <jrmuizel@gmail.com>
Tom Tromey <tom@tromey.com>
PR 13157
PR 21787
* mach-o.c (bfd_mach_o_fat_close_and_cleanup): New function.
(bfd_mach_o_close_and_cleanup): Redefine.
* archive.c (_bfd_unlink_from_archive_parent): New function,
extracted from..
(_bfd_archive_close_and_cleanup): ..here.
(bfd_generic_archive_p): Do not clear archive's format.
* libbfd-in.h (_bfd_unlink_from_archive_parent): Declare.
* libbfd.h: Regenerate.
Diffstat (limited to 'bfd/archive.c')
-rw-r--r-- | bfd/archive.c | 44 |
1 files changed, 25 insertions, 19 deletions
diff --git a/bfd/archive.c b/bfd/archive.c index d56bb06..a51c135 100644 --- a/bfd/archive.c +++ b/bfd/archive.c @@ -850,8 +850,6 @@ bfd_generic_archive_p (bfd *abfd) && ! bfd_is_thin_archive (abfd)) { bfd_set_error (bfd_error_wrong_format); - if (abfd->format == bfd_archive) - abfd->format = bfd_unknown; return NULL; } @@ -2765,6 +2763,30 @@ archive_close_worker (void **slot, void *inf ATTRIBUTE_UNUSED) return 1; } +void +_bfd_unlink_from_archive_parent (bfd *abfd) +{ + 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); + } + } + } +} + bfd_boolean _bfd_archive_close_and_cleanup (bfd *abfd) { @@ -2789,25 +2811,9 @@ _bfd_archive_close_and_cleanup (bfd *abfd) bfd_ardata (abfd)->cache = NULL; } } - 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; + _bfd_unlink_from_archive_parent (abfd); - 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); - } - } - } if (abfd->is_linker_output) (*abfd->link.hash->hash_table_free) (abfd); |