Add a plugin for processing static library dependencies.

* libdep_plugin.c: New file: Processes archives that contain a
	special library dependencies element.
	* Makefile.am: Add build rules for libdep_plugin.
	* Makefile.in: Regenerate.
	* NEWS: Mention the new plugin.
	* ld.texi: Document the new plugin.
This commit is contained in:
Howard Chu 2020-12-14 14:26:11 +00:00 committed by Nick Clifton
parent a86c6c1964
commit bf6d803782
7 changed files with 2207 additions and 1551 deletions

View File

@ -1,3 +1,12 @@
2020-12-14 Howard Chu <hyc@symas.com>
* libdep_plugin.c: New file: Processes archives that contain a
special library dependencies element.
* Makefile.am: Add build rules for libdep_plugin.
* Makefile.in: Regenerate.
* NEWS: Mention the new plugin.
* ld.texi: Document the new plugin.
2020-12-14 Alan Modra <amodra@gmail.com>
PR 26836

View File

@ -998,6 +998,11 @@ libldtestplug4_la_SOURCES = testplug4.c
libldtestplug4_la_CFLAGS= -g -O2
libldtestplug4_la_LDFLAGS = -no-undefined -rpath /nowhere
bfdplugindir = $(libdir)/bfd-plugins
bfdplugin_LTLIBRARIES = libdep.la
libdep_la_SOURCES = libdep_plugin.c
libdep_la_LDFLAGS = -no-undefined -rpath /nowhere
# DOCUMENTATION TARGETS
# Manual configuration file; not usually attached to normal configuration,
# because almost all configs use "gen" version of manual.

View File

@ -137,14 +137,49 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = po/Makefile.in
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libldtestplug_la_LIBADD =
am_libldtestplug_la_OBJECTS = libldtestplug_la-testplug.lo
libldtestplug_la_OBJECTS = $(am_libldtestplug_la_OBJECTS)
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
am__installdirs = "$(DESTDIR)$(bfdplugindir)" "$(DESTDIR)$(bindir)" \
"$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)"
LTLIBRARIES = $(bfdplugin_LTLIBRARIES) $(noinst_LTLIBRARIES)
libdep_la_LIBADD =
am_libdep_la_OBJECTS = libdep_plugin.lo
libdep_la_OBJECTS = $(am_libdep_la_OBJECTS)
AM_V_lt = $(am__v_lt_@AM_V@)
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
am__v_lt_0 = --silent
am__v_lt_1 =
libdep_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libdep_la_LDFLAGS) $(LDFLAGS) -o $@
libldtestplug_la_LIBADD =
am_libldtestplug_la_OBJECTS = libldtestplug_la-testplug.lo
libldtestplug_la_OBJECTS = $(am_libldtestplug_la_OBJECTS)
libldtestplug_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(libldtestplug_la_CFLAGS) $(CFLAGS) \
@ -170,8 +205,6 @@ libldtestplug4_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
$(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
$(libldtestplug4_la_CFLAGS) $(CFLAGS) \
$(libldtestplug4_la_LDFLAGS) $(LDFLAGS) -o $@
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(infodir)" \
"$(DESTDIR)$(man1dir)"
PROGRAMS = $(bin_PROGRAMS)
am_ld_new_OBJECTS = ldgram.$(OBJEXT) ldlex-wrapper.$(OBJEXT) \
lexsup.$(OBJEXT) ldlang.$(OBJEXT) mri.$(OBJEXT) \
@ -235,9 +268,10 @@ AM_V_YACC = $(am__v_YACC_@AM_V@)
am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
am__v_YACC_0 = @echo " YACC " $@;
am__v_YACC_1 =
SOURCES = $(libldtestplug_la_SOURCES) $(libldtestplug2_la_SOURCES) \
$(libldtestplug3_la_SOURCES) $(libldtestplug4_la_SOURCES) \
$(ld_new_SOURCES) $(EXTRA_ld_new_SOURCES)
SOURCES = $(libdep_la_SOURCES) $(libldtestplug_la_SOURCES) \
$(libldtestplug2_la_SOURCES) $(libldtestplug3_la_SOURCES) \
$(libldtestplug4_la_SOURCES) $(ld_new_SOURCES) \
$(EXTRA_ld_new_SOURCES)
AM_V_DVIPS = $(am__v_DVIPS_@AM_V@)
am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@)
am__v_DVIPS_0 = @echo " DVIPS " $@;
@ -290,33 +324,6 @@ am__can_run_installinfo = \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
am__install_max = 40
am__nobase_strip_setup = \
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
am__nobase_strip = \
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
am__nobase_list = $(am__nobase_strip_setup); \
for p in $$list; do echo "$$p $$p"; done | \
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
if (++n[$$2] == $(am__install_max)) \
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
END { for (dir in files) print dir, files[dir] }'
am__base_list = \
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
am__uninstall_files_from_dir = { \
test -z "$$files" \
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
man1dir = $(mandir)/man1
NROFF = nroff
MANS = $(man_MANS)
@ -1013,6 +1020,10 @@ libldtestplug3_la_LDFLAGS = -no-undefined -rpath /nowhere
libldtestplug4_la_SOURCES = testplug4.c
libldtestplug4_la_CFLAGS = -g -O2
libldtestplug4_la_LDFLAGS = -no-undefined -rpath /nowhere
bfdplugindir = $(libdir)/bfd-plugins
bfdplugin_LTLIBRARIES = libdep.la
libdep_la_SOURCES = libdep_plugin.c
libdep_la_LDFLAGS = -no-undefined -rpath /nowhere
MAINTAINERCLEANFILES = configdoc.texi ld.1 ld.info
# We want to reconfigure if configure.host or configure.tgt changes.
@ -1088,6 +1099,41 @@ distclean-hdr:
po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in
cd $(top_builddir) && $(SHELL) ./config.status $@
install-bfdpluginLTLIBRARIES: $(bfdplugin_LTLIBRARIES)
@$(NORMAL_INSTALL)
@list='$(bfdplugin_LTLIBRARIES)'; test -n "$(bfdplugindir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
list2="$$list2 $$p"; \
else :; fi; \
done; \
test -z "$$list2" || { \
echo " $(MKDIR_P) '$(DESTDIR)$(bfdplugindir)'"; \
$(MKDIR_P) "$(DESTDIR)$(bfdplugindir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(bfdplugindir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(bfdplugindir)"; \
}
uninstall-bfdpluginLTLIBRARIES:
@$(NORMAL_UNINSTALL)
@list='$(bfdplugin_LTLIBRARIES)'; test -n "$(bfdplugindir)" || list=; \
for p in $$list; do \
$(am__strip_dir) \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(bfdplugindir)/$$f'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(bfdplugindir)/$$f"; \
done
clean-bfdpluginLTLIBRARIES:
-test -z "$(bfdplugin_LTLIBRARIES)" || rm -f $(bfdplugin_LTLIBRARIES)
@list='$(bfdplugin_LTLIBRARIES)'; \
locs=`for p in $$list; do echo $$p; done | \
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
sort -u`; \
test -z "$$locs" || { \
echo rm -f $${locs}; \
rm -f $${locs}; \
}
clean-noinstLTLIBRARIES:
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
@list='$(noinst_LTLIBRARIES)'; \
@ -1099,6 +1145,9 @@ clean-noinstLTLIBRARIES:
rm -f $${locs}; \
}
libdep.la: $(libdep_la_OBJECTS) $(libdep_la_DEPENDENCIES) $(EXTRA_libdep_la_DEPENDENCIES)
$(AM_V_CCLD)$(libdep_la_LINK) -rpath $(bfdplugindir) $(libdep_la_OBJECTS) $(libdep_la_LIBADD) $(LIBS)
libldtestplug.la: $(libldtestplug_la_OBJECTS) $(libldtestplug_la_DEPENDENCIES) $(EXTRA_libldtestplug_la_DEPENDENCIES)
$(AM_V_CCLD)$(libldtestplug_la_LINK) $(libldtestplug_la_OBJECTS) $(libldtestplug_la_LIBADD) $(LIBS)
@ -1492,6 +1541,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldver.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldwrite.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lexsup.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdep_plugin.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libldtestplug2_la-testplug2.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libldtestplug3_la-testplug3.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libldtestplug4_la-testplug4.Plo@am__quote@
@ -1886,7 +1936,7 @@ all-am: Makefile $(INFO_DEPS) $(LTLIBRARIES) $(PROGRAMS) $(MANS) \
config.h
installdirs: installdirs-recursive
installdirs-am:
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)"; do \
for dir in "$(DESTDIR)$(bfdplugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man1dir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: $(BUILT_SOURCES)
@ -1932,8 +1982,9 @@ maintainer-clean-generic:
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
clean: clean-recursive
clean-am: clean-aminfo clean-binPROGRAMS clean-generic clean-libtool \
clean-noinstLTLIBRARIES mostlyclean-am
clean-am: clean-aminfo clean-bfdpluginLTLIBRARIES clean-binPROGRAMS \
clean-generic clean-libtool clean-noinstLTLIBRARIES \
mostlyclean-am
distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
@ -1955,7 +2006,8 @@ info: info-recursive
info-am: $(INFO_DEPS)
install-data-am: install-data-local install-info-am install-man
install-data-am: install-bfdpluginLTLIBRARIES install-data-local \
install-info-am install-man
install-dvi: install-dvi-recursive
@ -2095,9 +2147,9 @@ ps: ps-recursive
ps-am: $(PSS)
uninstall-am: uninstall-binPROGRAMS uninstall-dvi-am uninstall-html-am \
uninstall-info-am uninstall-man uninstall-pdf-am \
uninstall-ps-am
uninstall-am: uninstall-bfdpluginLTLIBRARIES uninstall-binPROGRAMS \
uninstall-dvi-am uninstall-html-am uninstall-info-am \
uninstall-man uninstall-pdf-am uninstall-ps-am
uninstall-man: uninstall-man1
@ -2106,12 +2158,13 @@ uninstall-man: uninstall-man1
.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
am--refresh check check-DEJAGNU check-am clean clean-aminfo \
clean-binPROGRAMS clean-cscope clean-generic clean-libtool \
clean-noinstLTLIBRARIES cscope cscopelist-am ctags ctags-am \
dist-info distclean distclean-DEJAGNU distclean-compile \
distclean-generic distclean-hdr distclean-libtool \
distclean-local distclean-tags dvi dvi-am html html-am info \
info-am install install-am install-binPROGRAMS install-data \
clean-bfdpluginLTLIBRARIES clean-binPROGRAMS clean-cscope \
clean-generic clean-libtool clean-noinstLTLIBRARIES cscope \
cscopelist-am ctags ctags-am dist-info distclean \
distclean-DEJAGNU distclean-compile distclean-generic \
distclean-hdr distclean-libtool distclean-local distclean-tags \
dvi dvi-am html html-am info info-am install install-am \
install-bfdpluginLTLIBRARIES install-binPROGRAMS install-data \
install-data-am install-data-local install-dvi install-dvi-am \
install-exec install-exec-am install-exec-local install-html \
install-html-am install-info install-info-am install-man \
@ -2121,9 +2174,10 @@ uninstall-man: uninstall-man1
maintainer-clean-aminfo maintainer-clean-generic mostlyclean \
mostlyclean-aminfo mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool mostlyclean-local pdf pdf-am ps ps-am tags \
tags-am uninstall uninstall-am uninstall-binPROGRAMS \
uninstall-dvi-am uninstall-html-am uninstall-info-am \
uninstall-man uninstall-man1 uninstall-pdf-am uninstall-ps-am
tags-am uninstall uninstall-am uninstall-bfdpluginLTLIBRARIES \
uninstall-binPROGRAMS uninstall-dvi-am uninstall-html-am \
uninstall-info-am uninstall-man uninstall-man1 \
uninstall-pdf-am uninstall-ps-am
.PRECIOUS: Makefile

View File

@ -1,5 +1,8 @@
-*- text -*-
* Add libdep plugin, for linking dependencies of static libraries that
were recorded by ar in the __.LIBDEP archive member.
* Add --error-handling-script=<NAME> command line option to allow a helper
script to be invoked when an undefined symbol or a missing library is
encountered. This option can be suppressed via the configure time

View File

@ -126,6 +126,7 @@ in the section entitled ``GNU Free Documentation License''.
* Overview:: Overview
* Invocation:: Invocation
* Scripts:: Linker Scripts
* Plugins:: Linker Plugins
@ifset GENERIC
* Machine Dependent:: Machine Dependent Features
@end ifset
@ -6954,6 +6955,58 @@ Any input files read because of an implicit linker script will be read
at the position in the command line where the implicit linker script was
read. This can affect archive searching.
@node Plugins
@chapter Linker Plugins
@cindex plugins
@cindex linker plugins
The linker can use dynamically loaded plugins to modify its behavior.
For example, the link-time optimization feature that some compilers
support is implemented with a linker plugin.
Currently there is only one plugin shipped by default, but more may
be added here later.
@menu
* libdep Plugin:: Static Library Dependencies Plugin
@end menu
@node libdep Plugin
@section Static Library Dependencies Plugin
@cindex static library dependencies
Originally, static libraries were contained in an archive file consisting
just of a collection of relocatable object files. Later they evolved to
optionally include a symbol table, to assist in finding the needed objects
within a library. There their evolution ended, and dynamic libraries
rose to ascendance.
One useful feature of dynamic libraries was that, more than just collecting
multiple objects into a single file, they also included a list of their
dependencies, such that one could specify just the name of a single dynamic
library at link time, and all of its dependencies would be implicitly
referenced as well. But static libraries lacked this feature, so if a
link invocation was switched from using dynamic libraries to static
libraries, the link command would usually fail unless it was rewritten to
explicitly list the dependencies of the static library.
The GNU @command{ar} utility now supports a @option{--record-libdeps} option
to embed dependency lists into static libraries as well, and the @file{libdep}
plugin may be used to read this dependency information at link time. The
dependency information is stored as a single string, carrying @option{-l}
and @option{-L} arguments as they would normally appear in a linker
command line. As such, the information can be written with any text
utility and stored into any archive, even if GNU @command{ar} is not
being used to create the archive. The information is stored in an
archive member named @samp{__.LIBDEP}.
For example, given a library @file{libssl.a} that depends on another
library @file{libcrypto.a} which may be found in @file{/usr/local/lib},
the @samp{__.LIBDEP} member of @file{libssl.a} would contain
@smallexample
-L/usr/local/lib -lcrypto
@end smallexample
@ifset GENERIC
@node Machine Dependent
@chapter Machine Dependent Features

366
ld/libdep_plugin.c Normal file
View File

@ -0,0 +1,366 @@
/* libdeps plugin for the GNU linker.
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of the 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. */
#include "sysdep.h"
#include "bfd.h"
#if BFD_SUPPORTS_PLUGINS
#include "plugin-api.h"
#include <ctype.h> /* For isspace. */
extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
/* Helper for calling plugin api message function. */
#define TV_MESSAGE if (tv_message) (*tv_message)
/* Function pointers to cache hooks passed at onload time. */
static ld_plugin_register_claim_file tv_register_claim_file = 0;
static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
static ld_plugin_register_cleanup tv_register_cleanup = 0;
static ld_plugin_message tv_message = 0;
static ld_plugin_add_input_library tv_add_input_library = 0;
static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
/* Handle/record information received in a transfer vector entry. */
static enum ld_plugin_status
parse_tv_tag (struct ld_plugin_tv *tv)
{
#define SETVAR(x) x = tv->tv_u.x
switch (tv->tv_tag)
{
case LDPT_REGISTER_CLAIM_FILE_HOOK:
SETVAR(tv_register_claim_file);
break;
case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
SETVAR(tv_register_all_symbols_read);
break;
case LDPT_REGISTER_CLEANUP_HOOK:
SETVAR(tv_register_cleanup);
break;
case LDPT_MESSAGE:
SETVAR(tv_message);
break;
case LDPT_ADD_INPUT_LIBRARY:
SETVAR(tv_add_input_library);
break;
case LDPT_SET_EXTRA_LIBRARY_PATH:
SETVAR(tv_set_extra_library_path);
break;
default:
break;
}
#undef SETVAR
return LDPS_OK;
}
/* Defs for archive parsing. */
#define ARMAGSIZE 8
typedef struct arhdr
{
char ar_name[16];
char ar_date[12];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];
} arhdr;
typedef struct linerec
{
struct linerec *next;
char line[];
} linerec;
#define LIBDEPS "__.LIBDEP/ "
static linerec *line_head, **line_tail = &line_head;
static enum ld_plugin_status
get_libdeps (int fd)
{
arhdr ah;
int len;
unsigned long mlen;
linerec *lr;
enum ld_plugin_status rc = LDPS_NO_SYMS;
lseek (fd, ARMAGSIZE, SEEK_SET);
for (;;)
{
len = read (fd, (void *) &ah, sizeof (ah));
if (len != sizeof (ah))
break;
mlen = strtoul (ah.ar_size, NULL, 10);
if (!mlen || strncmp (ah.ar_name, LIBDEPS, sizeof (LIBDEPS)-1))
{
lseek (fd, mlen, SEEK_CUR);
continue;
}
lr = malloc (sizeof (linerec) + mlen);
if (!lr)
return LDPS_ERR;
lr->next = NULL;
len = read (fd, lr->line, mlen);
lr->line[mlen-1] = '\0';
*line_tail = lr;
line_tail = &lr->next;
rc = LDPS_OK;
break;
}
return rc;
}
/* Turn a string into an argvec. */
static char **
str2vec (char *in)
{
char **res;
char *s, *first, *end;
char *sq, *dq;
int i;
end = in + strlen (in);
s = in;
while (isspace (*s)) s++;
first = s;
i = 1;
while ((s = strchr (s, ' ')))
{
s++;
i++;
}
res = (char **)malloc ((i+1) * sizeof (char *));
if (!res)
return res;
i = 0;
sq = NULL;
dq = NULL;
res[0] = first;
for (s = first; *s; s++)
{
if (*s == '\\')
{
memmove (s, s+1, end-s-1);
end--;
}
if (isspace (*s))
{
if (sq || dq)
continue;
*s++ = '\0';
while (isspace (*s)) s++;
if (*s)
res[++i] = s;
}
if (*s == '\'' && !dq)
{
if (sq)
{
memmove (sq, sq+1, s-sq-1);
memmove (s-2, s+1, end-s-1);
end -= 2;
s--;
sq = NULL;
}
else
{
sq = s;
}
}
if (*s == '"' && !sq)
{
if (dq)
{
memmove (dq, dq+1, s-dq-1);
memmove (s-2, s+1, end-s-1);
end -= 2;
s--;
dq = NULL;
}
else
{
dq = s;
}
}
}
res[++i] = NULL;
return res;
}
static char *prevfile;
/* Standard plugin API registerable hook. */
static enum ld_plugin_status
onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
{
enum ld_plugin_status rv;
*claimed = 0;
/* If we've already seen this file, ignore it. */
if (prevfile && !strcmp (file->name, prevfile))
return LDPS_OK;
/* If it's not an archive member, ignore it. */
if (!file->offset)
return LDPS_OK;
if (prevfile)
free (prevfile);
prevfile = strdup (file->name);
if (!prevfile)
return LDPS_ERR;
/* This hook only gets called on actual object files.
* We have to examine the archive ourselves, to find
* our LIBDEPS member. */
rv = get_libdeps (file->fd);
if (rv == LDPS_ERR)
return rv;
if (rv == LDPS_OK)
{
linerec *lr = (linerec *)line_tail;
/* Inform the user/testsuite. */
TV_MESSAGE (LDPL_INFO, "got deps for library %s: %s",
file->name, lr->line);
fflush (NULL);
}
return LDPS_OK;
}
/* Standard plugin API registerable hook. */
static enum ld_plugin_status
onall_symbols_read (void)
{
linerec *lr;
char **vec;
enum ld_plugin_status rv = LDPS_OK;
while ((lr = line_head))
{
line_head = lr->next;
vec = str2vec (lr->line);
if (vec)
{
int i;
for (i = 0; vec[i]; i++)
{
if (vec[i][0] != '-')
{
TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
vec[i]);
fflush (NULL);
continue;
}
if (vec[i][1] == 'l')
rv = tv_add_input_library (vec[i]+2);
else if (vec[i][1] == 'L')
rv = tv_set_extra_library_path (vec[i]+2);
else
{
TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
vec[i]);
fflush (NULL);
}
if (rv != LDPS_OK)
break;
}
free (vec);
}
free (lr);
}
line_tail = NULL;
return rv;
}
/* Standard plugin API registerable hook. */
static enum ld_plugin_status
oncleanup (void)
{
if (prevfile)
{
free (prevfile);
prevfile = NULL;
}
if (line_head)
{
linerec *lr;
while ((lr = line_head))
{
line_head = lr->next;
free (lr);
}
line_tail = NULL;
}
return LDPS_OK;
}
/* Standard plugin API entry point. */
enum ld_plugin_status
onload (struct ld_plugin_tv *tv)
{
enum ld_plugin_status rv;
/* This plugin requires a valid tv array. */
if (!tv)
return LDPS_ERR;
/* First entry should always be LDPT_MESSAGE, letting us get
hold of it easily so we can send output straight away. */
if (tv[0].tv_tag == LDPT_MESSAGE)
tv_message = tv[0].tv_u.tv_message;
do
if ((rv = parse_tv_tag (tv)) != LDPS_OK)
return rv;
while ((tv++)->tv_tag != LDPT_NULL);
/* Register hooks. */
if (!tv_register_claim_file)
{
TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook");
fflush (NULL);
return LDPS_ERR;
}
(*tv_register_claim_file) (onclaim_file);
if (!tv_register_all_symbols_read)
{
TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook");
fflush (NULL);
return LDPS_ERR;
}
(*tv_register_all_symbols_read) (onall_symbols_read);
if (!tv_register_cleanup)
{
TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook");
fflush (NULL);
return LDPS_ERR;
}
(*tv_register_cleanup) (oncleanup);
fflush (NULL);
return LDPS_OK;
}
#endif /* BFD_SUPPORTS_PLUGINS */

File diff suppressed because it is too large Load Diff