123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- /* libdeps plugin for the GNU linker.
- Copyright (C) 2020-2022 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 ((unsigned char) *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 ((unsigned char) *s))
- {
- if (sq || dq)
- continue;
- *s++ = '\0';
- while (isspace ((unsigned char) *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_register_all_symbols_read
- && tv_register_cleanup)
- {
- (*tv_register_claim_file) (onclaim_file);
- (*tv_register_all_symbols_read) (onall_symbols_read);
- (*tv_register_cleanup) (oncleanup);
- }
- fflush (NULL);
- return LDPS_OK;
- }
- #endif /* BFD_SUPPORTS_PLUGINS */
|