Wolfgang Thallergcc16 merge934c3885 months agoHistory
341 lines · 7.3 KB · C
RawDownload
/* libdeps plugin for the GNU linker.   Copyright (C) 2020-2026 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"#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_statusparse_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	8typedef 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_statusget_libdeps (int fd){  arhdr ah;  int len;  unsigned long mlen;  size_t amt;  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;	}      amt = mlen + sizeof (linerec);      if (amt <= mlen)	return LDPS_ERR;      lr = malloc (amt);      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;} /* Parse arguments in-place as contiguous C-strings   and return the number of arguments.  */ static intparse_libdep (char *str){  char *src, *dst;  char quote;  int narg;   src = dst = str;   for (; isspace ((unsigned char) *src); ++src)    ;   if (*src == '\0')    return 0;   narg = 1;  quote = 0;   while (*src)    {      if (*src == '\'' || *src == '\"')	{	  if (!quote)	    quote = *src++;	  else if (*src == quote)	    {	      ++src;	      quote = 0;	    }	  else	    *dst++ = *src++;	}      else if (!quote && isspace ((unsigned char) *src))	{	  ++narg;	  ++src;	  *dst++ = '\0';	  for (; isspace ((unsigned char) *src); ++src);	}      else	*dst++ = *src++;    }   *dst = '\0';   if (quote)    {      TV_MESSAGE (LDPL_WARNING,		  "libdep syntax error: unterminated quoted string");      return 0;    }   return narg;} static char *prevfile; /* Standard plugin API registerable hook.  */ static enum ld_plugin_statusonclaim_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_statusonall_symbols_read (void){  linerec *lr;  int nargs;  char const *arg;  enum ld_plugin_status rv = LDPS_OK;   while ((lr = line_head))    {      line_head = lr->next;      nargs = parse_libdep (lr->line);      arg = lr->line;       int i;      for (i = 0; i < nargs; i++, arg = strchr (arg, '\0') + 1)	{	  if (arg[0] != '-')	    {	      TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s", arg);	      fflush (NULL);	      continue;	    }	  if (arg[1] == 'l')	    rv = tv_add_input_library (arg + 2);	  else if (arg[1] == 'L')	    rv = tv_set_extra_library_path (arg + 2);	  else	    {	      TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s", arg);	      fflush (NULL);	    }	  if (rv != LDPS_OK)	    break;	}      free (lr);    }   line_tail = NULL;  return rv;} /* Standard plugin API registerable hook.  */ static enum ld_plugin_statusoncleanup (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_statusonload (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;}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t