forked from Imagelibrary/binutils-gdb
Automatically choosing "plugin" for the archive target when plugins are enabled can result in making archives as specified by the plugin target vec, ie. COFF style archives (also used by most ELF binutils targets). This is wrong for aix, hpux, vms, aout, macho and possibly other targets, if compatibility with target system archives matters. This patch removes archive support entirely from the plugin target. That means an archive will never get past bfd_check_format with a target of plugin_vec, even if it is opened using "plugin". Instead, archives will have their elements opened using the plugin target selected is such a way that the plugin target will be tried first in bfd_check_format and then continue to try other targets if that fails. The patch tries to avoid opening archives using "plugin" because that is guaranteed to fail the first target check in bfd_check_format, but mm.c still does so, and nested archives will also be opened using "plugin". The patch also fixes poor arsup.c plugin support. bfd/ * plugin.c (plugin_vec): Remove archive support. * configure.ac: Remove plugin archive warning, and don't disable plugins by default on anything but aout targets. * configure: Regenerate. binutils/ * bucomm.h (set_plugin_target): New inline function. * ar.c: Remove unneeded forward declarations. (open_inarch): Don't use "plugin" if defaulting target when opening an archive, use "plugin" when opening elements. (replace_members): Use "plugin" when opening replacement or additional elements. * arsup.c: Remove unneeded forward declarations. (plugin_target): New. (ar_open): Don't open archives using "plugin", use it when opening elements. (ar_addmod): Use plugin_target. (ar_replace): Use plugin_target when opening replacement or additional elements. (ar_extract): Don't bfd_openr. * nm.c (display_archive): Open archive elements using the "plugin" target.
515 lines
10 KiB
C
515 lines
10 KiB
C
/* arsup.c - Archive support for MRI compatibility
|
|
Copyright (C) 1992-2025 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
|
|
/* Contributed by Steve Chamberlain
|
|
sac@cygnus.com
|
|
|
|
This file looks after requests from arparse.y, to provide the MRI
|
|
style librarian command syntax + 1 word LIST. */
|
|
|
|
#include "sysdep.h"
|
|
#include "bfd.h"
|
|
#include "libiberty.h"
|
|
#include "filenames.h"
|
|
#include "bucomm.h"
|
|
#include "arsup.h"
|
|
|
|
extern int verbose;
|
|
extern int deterministic;
|
|
|
|
static bfd *obfd;
|
|
static char *real_name;
|
|
static char *temp_name;
|
|
static int temp_fd;
|
|
static FILE *outfile;
|
|
|
|
#if BFD_SUPPORTS_PLUGINS
|
|
static const char *plugin_target = "plugin";
|
|
#else
|
|
static const char *plugin_target = NULL;
|
|
#endif
|
|
|
|
static void
|
|
map_over_list (bfd *arch, void (*function) (bfd *, bfd *), struct list *list)
|
|
{
|
|
bfd *head;
|
|
|
|
if (list == NULL)
|
|
{
|
|
bfd *next;
|
|
|
|
head = arch->archive_next;
|
|
while (head != NULL)
|
|
{
|
|
next = head->archive_next;
|
|
function (head, (bfd *) NULL);
|
|
head = next;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
struct list *ptr;
|
|
|
|
/* This may appear to be a baroque way of accomplishing what we
|
|
want. however we have to iterate over the filenames in order
|
|
to notice where a filename is requested but does not exist in
|
|
the archive. Ditto mapping over each file each time -- we
|
|
want to hack multiple references. */
|
|
for (ptr = list; ptr; ptr = ptr->next)
|
|
{
|
|
bool found = false;
|
|
bfd *prev = arch;
|
|
|
|
for (head = arch->archive_next; head; head = head->archive_next)
|
|
{
|
|
if (bfd_get_filename (head) != NULL
|
|
&& FILENAME_CMP (ptr->name, bfd_get_filename (head)) == 0)
|
|
{
|
|
found = true;
|
|
function (head, prev);
|
|
}
|
|
prev = head;
|
|
}
|
|
if (! found)
|
|
fprintf (stderr, _("No entry %s in archive.\n"), ptr->name);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
ar_directory_doer (bfd *abfd, bfd *ignore ATTRIBUTE_UNUSED)
|
|
{
|
|
print_arelt_descr(outfile, abfd, verbose, false);
|
|
}
|
|
|
|
void
|
|
ar_directory (char *ar_name, struct list *list, char *output)
|
|
{
|
|
bfd *arch;
|
|
|
|
arch = open_inarch (ar_name, (char *) NULL);
|
|
if (output)
|
|
{
|
|
outfile = fopen(output,"w");
|
|
if (outfile == 0)
|
|
{
|
|
outfile = stdout;
|
|
fprintf (stderr,_("Can't open file %s\n"), output);
|
|
output = 0;
|
|
}
|
|
}
|
|
else
|
|
outfile = stdout;
|
|
|
|
map_over_list (arch, ar_directory_doer, list);
|
|
|
|
bfd_close (arch);
|
|
|
|
if (output)
|
|
fclose (outfile);
|
|
}
|
|
|
|
void
|
|
prompt (void)
|
|
{
|
|
extern int interactive;
|
|
|
|
if (interactive)
|
|
{
|
|
printf ("AR >");
|
|
fflush (stdout);
|
|
}
|
|
}
|
|
|
|
void
|
|
maybequit (void)
|
|
{
|
|
if (! interactive)
|
|
xexit (9);
|
|
}
|
|
|
|
|
|
void
|
|
ar_open (char *name, int t)
|
|
{
|
|
real_name = xstrdup (name);
|
|
temp_name = make_tempname (real_name, &temp_fd);
|
|
|
|
if (temp_name == NULL)
|
|
{
|
|
fprintf (stderr, _("%s: Can't open temporary file (%s)\n"),
|
|
program_name, strerror(errno));
|
|
maybequit ();
|
|
return;
|
|
}
|
|
|
|
obfd = bfd_fdopenw (temp_name, NULL, temp_fd);
|
|
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr,
|
|
_("%s: Can't open output archive %s\n"),
|
|
program_name, temp_name);
|
|
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
if (!t)
|
|
{
|
|
bfd **ptr;
|
|
bfd *element;
|
|
bfd *ibfd;
|
|
|
|
ibfd = bfd_openr (name, NULL);
|
|
|
|
if (!ibfd)
|
|
{
|
|
fprintf (stderr,_("%s: Can't open input archive %s\n"),
|
|
program_name, name);
|
|
maybequit ();
|
|
return;
|
|
}
|
|
|
|
if (!bfd_check_format(ibfd, bfd_archive))
|
|
{
|
|
fprintf (stderr,
|
|
_("%s: file %s is not an archive\n"),
|
|
program_name, name);
|
|
maybequit ();
|
|
return;
|
|
}
|
|
|
|
ptr = &(obfd->archive_head);
|
|
element = bfd_openr_next_archived_file (ibfd, NULL);
|
|
|
|
#if BFD_SUPPORTS_PLUGINS
|
|
const struct bfd_target *plugin_vec
|
|
= bfd_find_target (plugin_target, NULL);
|
|
#endif
|
|
while (element)
|
|
{
|
|
#if BFD_SUPPORTS_PLUGINS
|
|
set_plugin_target (element, plugin_vec);
|
|
#endif
|
|
*ptr = element;
|
|
ptr = &element->archive_next;
|
|
element = bfd_openr_next_archived_file (ibfd, element);
|
|
}
|
|
}
|
|
|
|
bfd_set_format (obfd, bfd_archive);
|
|
|
|
obfd->has_armap = 1;
|
|
obfd->is_thin_archive = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
ar_addlib_doer (bfd *abfd, bfd *prev)
|
|
{
|
|
/* Add this module to the output bfd. */
|
|
if (prev != NULL)
|
|
prev->archive_next = abfd->archive_next;
|
|
|
|
abfd->archive_next = obfd->archive_head;
|
|
obfd->archive_head = abfd;
|
|
}
|
|
|
|
void
|
|
ar_addlib (char *name, struct list *list)
|
|
{
|
|
if (obfd == NULL)
|
|
{
|
|
fprintf (stderr, _("%s: no output archive specified yet\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
bfd *arch;
|
|
|
|
arch = open_inarch (name, (char *) NULL);
|
|
if (arch != NULL)
|
|
map_over_list (arch, ar_addlib_doer, list);
|
|
|
|
/* Don't close the bfd, since it will make the elements disappear. */
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_addmod (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
while (list)
|
|
{
|
|
bfd *abfd;
|
|
|
|
abfd = bfd_openr (list->name, plugin_target);
|
|
if (!abfd)
|
|
{
|
|
fprintf (stderr, _("%s: can't open file %s\n"),
|
|
program_name, list->name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
abfd->archive_next = obfd->archive_head;
|
|
obfd->archive_head = abfd;
|
|
}
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ar_clear (void)
|
|
{
|
|
if (obfd)
|
|
obfd->archive_head = 0;
|
|
}
|
|
|
|
void
|
|
ar_delete (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
while (list)
|
|
{
|
|
/* Find this name in the archive. */
|
|
bfd *member = obfd->archive_head;
|
|
bfd **prev = &(obfd->archive_head);
|
|
int found = 0;
|
|
|
|
while (member)
|
|
{
|
|
if (FILENAME_CMP (bfd_get_filename (member), list->name) == 0)
|
|
{
|
|
*prev = member->archive_next;
|
|
found = 1;
|
|
}
|
|
else
|
|
prev = &(member->archive_next);
|
|
|
|
member = member->archive_next;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
fprintf (stderr, _("%s: can't find module file %s\n"),
|
|
program_name, list->name);
|
|
maybequit ();
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_save (void)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
struct stat target_stat;
|
|
|
|
if (deterministic > 0)
|
|
obfd->flags |= BFD_DETERMINISTIC_OUTPUT;
|
|
|
|
temp_fd = dup (temp_fd);
|
|
bfd_close (obfd);
|
|
|
|
if (stat (real_name, &target_stat) != 0)
|
|
{
|
|
/* The temp file created in ar_open has mode 0600 as per mkstemp.
|
|
Create the real empty output file here so smart_rename will
|
|
update the mode according to the process umask. */
|
|
obfd = bfd_openw (real_name, NULL);
|
|
if (obfd != NULL)
|
|
{
|
|
bfd_set_format (obfd, bfd_archive);
|
|
bfd_close (obfd);
|
|
}
|
|
}
|
|
|
|
smart_rename (temp_name, real_name, temp_fd, NULL, false);
|
|
obfd = 0;
|
|
free (temp_name);
|
|
free (real_name);
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_replace (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
while (list)
|
|
{
|
|
/* Find this name in the archive. */
|
|
bfd *member = obfd->archive_head;
|
|
bfd **prev = &(obfd->archive_head);
|
|
int found = 0;
|
|
|
|
while (member)
|
|
{
|
|
if (FILENAME_CMP (bfd_get_filename (member), list->name) == 0)
|
|
{
|
|
/* Found the one to replace. */
|
|
bfd *abfd = bfd_openr (list->name, plugin_target);
|
|
|
|
if (!abfd)
|
|
{
|
|
fprintf (stderr, _("%s: can't open file %s\n"),
|
|
program_name, list->name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
*prev = abfd;
|
|
abfd->archive_next = member->archive_next;
|
|
found = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prev = &(member->archive_next);
|
|
}
|
|
member = member->archive_next;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
bfd *abfd = bfd_openr (list->name, plugin_target);
|
|
|
|
fprintf (stderr,_("%s: can't find module file %s\n"),
|
|
program_name, list->name);
|
|
if (!abfd)
|
|
{
|
|
fprintf (stderr, _("%s: can't open file %s\n"),
|
|
program_name, list->name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
*prev = abfd;
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* And I added this one. */
|
|
void
|
|
ar_list (void)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open output archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
bfd *abfd;
|
|
|
|
outfile = stdout;
|
|
verbose =1 ;
|
|
printf (_("Current open archive is %s\n"), bfd_get_filename (obfd));
|
|
|
|
for (abfd = obfd->archive_head;
|
|
abfd != (bfd *)NULL;
|
|
abfd = abfd->archive_next)
|
|
ar_directory_doer (abfd, (bfd *) NULL);
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_end (void)
|
|
{
|
|
if (obfd)
|
|
{
|
|
const char *filename = bfd_get_filename (obfd);
|
|
bfd_close_all_done (obfd);
|
|
unlink (filename);
|
|
}
|
|
}
|
|
|
|
void
|
|
ar_extract (struct list *list)
|
|
{
|
|
if (!obfd)
|
|
{
|
|
fprintf (stderr, _("%s: no open archive\n"), program_name);
|
|
maybequit ();
|
|
}
|
|
else
|
|
{
|
|
while (list)
|
|
{
|
|
/* Find this name in the archive. */
|
|
bfd *member = obfd->archive_head;
|
|
int found = 0;
|
|
|
|
while (member && !found)
|
|
{
|
|
if (FILENAME_CMP (bfd_get_filename (member), list->name) == 0)
|
|
{
|
|
extract_file (member);
|
|
found = 1;
|
|
}
|
|
|
|
member = member->archive_next;
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
fprintf (stderr, _("%s: can't find module file %s\n"),
|
|
program_name, list->name);
|
|
}
|
|
|
|
list = list->next;
|
|
}
|
|
}
|
|
}
|