Files
binutils-gdb/binutils/arsup.c
Alan Modra 46cd7e0dc8 archives and plugin target
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.
2025-08-16 07:37:08 +09:30

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;
}
}
}