xref: /netbsd-src/external/gpl3/binutils.old/dist/ld/libdep_plugin.c (revision c42dbd0ed2e61fe6eda8590caa852ccf34719964)
1*c42dbd0eSchristos /* libdeps plugin for the GNU linker.
2*c42dbd0eSchristos    Copyright (C) 2020-2022 Free Software Foundation, Inc.
3*c42dbd0eSchristos 
4*c42dbd0eSchristos    This file is part of the GNU Binutils.
5*c42dbd0eSchristos 
6*c42dbd0eSchristos    This program is free software; you can redistribute it and/or modify
7*c42dbd0eSchristos    it under the terms of the GNU General Public License as published by
8*c42dbd0eSchristos    the Free Software Foundation; either version 3 of the License, or
9*c42dbd0eSchristos    (at your option) any later version.
10*c42dbd0eSchristos 
11*c42dbd0eSchristos    This program is distributed in the hope that it will be useful,
12*c42dbd0eSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*c42dbd0eSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*c42dbd0eSchristos    GNU General Public License for more details.
15*c42dbd0eSchristos 
16*c42dbd0eSchristos    You should have received a copy of the GNU General Public License
17*c42dbd0eSchristos    along with this program; if not, write to the Free Software
18*c42dbd0eSchristos    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19*c42dbd0eSchristos    MA 02110-1301, USA.  */
20*c42dbd0eSchristos 
21*c42dbd0eSchristos #include "sysdep.h"
22*c42dbd0eSchristos #include "bfd.h"
23*c42dbd0eSchristos #if BFD_SUPPORTS_PLUGINS
24*c42dbd0eSchristos #include "plugin-api.h"
25*c42dbd0eSchristos 
26*c42dbd0eSchristos #include <ctype.h> /* For isspace.  */
27*c42dbd0eSchristos 
28*c42dbd0eSchristos extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
29*c42dbd0eSchristos 
30*c42dbd0eSchristos /* Helper for calling plugin api message function.  */
31*c42dbd0eSchristos #define TV_MESSAGE if (tv_message) (*tv_message)
32*c42dbd0eSchristos 
33*c42dbd0eSchristos /* Function pointers to cache hooks passed at onload time.  */
34*c42dbd0eSchristos static ld_plugin_register_claim_file tv_register_claim_file = 0;
35*c42dbd0eSchristos static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
36*c42dbd0eSchristos static ld_plugin_register_cleanup tv_register_cleanup = 0;
37*c42dbd0eSchristos static ld_plugin_message tv_message = 0;
38*c42dbd0eSchristos static ld_plugin_add_input_library tv_add_input_library = 0;
39*c42dbd0eSchristos static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
40*c42dbd0eSchristos 
41*c42dbd0eSchristos /* Handle/record information received in a transfer vector entry.  */
42*c42dbd0eSchristos static enum ld_plugin_status
parse_tv_tag(struct ld_plugin_tv * tv)43*c42dbd0eSchristos parse_tv_tag (struct ld_plugin_tv *tv)
44*c42dbd0eSchristos {
45*c42dbd0eSchristos #define SETVAR(x) x = tv->tv_u.x
46*c42dbd0eSchristos   switch (tv->tv_tag)
47*c42dbd0eSchristos     {
48*c42dbd0eSchristos       case LDPT_REGISTER_CLAIM_FILE_HOOK:
49*c42dbd0eSchristos 	SETVAR(tv_register_claim_file);
50*c42dbd0eSchristos 	break;
51*c42dbd0eSchristos       case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
52*c42dbd0eSchristos 	SETVAR(tv_register_all_symbols_read);
53*c42dbd0eSchristos 	break;
54*c42dbd0eSchristos       case LDPT_REGISTER_CLEANUP_HOOK:
55*c42dbd0eSchristos 	SETVAR(tv_register_cleanup);
56*c42dbd0eSchristos 	break;
57*c42dbd0eSchristos       case LDPT_MESSAGE:
58*c42dbd0eSchristos 	SETVAR(tv_message);
59*c42dbd0eSchristos 	break;
60*c42dbd0eSchristos       case LDPT_ADD_INPUT_LIBRARY:
61*c42dbd0eSchristos 	SETVAR(tv_add_input_library);
62*c42dbd0eSchristos 	break;
63*c42dbd0eSchristos       case LDPT_SET_EXTRA_LIBRARY_PATH:
64*c42dbd0eSchristos 	SETVAR(tv_set_extra_library_path);
65*c42dbd0eSchristos 	break;
66*c42dbd0eSchristos       default:
67*c42dbd0eSchristos 	break;
68*c42dbd0eSchristos     }
69*c42dbd0eSchristos #undef SETVAR
70*c42dbd0eSchristos   return LDPS_OK;
71*c42dbd0eSchristos }
72*c42dbd0eSchristos 
73*c42dbd0eSchristos /* Defs for archive parsing.  */
74*c42dbd0eSchristos #define ARMAGSIZE	8
75*c42dbd0eSchristos typedef struct arhdr
76*c42dbd0eSchristos {
77*c42dbd0eSchristos   char ar_name[16];
78*c42dbd0eSchristos   char ar_date[12];
79*c42dbd0eSchristos   char ar_uid[6];
80*c42dbd0eSchristos   char ar_gid[6];
81*c42dbd0eSchristos   char ar_mode[8];
82*c42dbd0eSchristos   char ar_size[10];
83*c42dbd0eSchristos   char ar_fmag[2];
84*c42dbd0eSchristos } arhdr;
85*c42dbd0eSchristos 
86*c42dbd0eSchristos typedef struct linerec
87*c42dbd0eSchristos {
88*c42dbd0eSchristos   struct linerec *next;
89*c42dbd0eSchristos   char line[];
90*c42dbd0eSchristos } linerec;
91*c42dbd0eSchristos 
92*c42dbd0eSchristos #define LIBDEPS "__.LIBDEP/ "
93*c42dbd0eSchristos 
94*c42dbd0eSchristos static linerec *line_head, **line_tail = &line_head;
95*c42dbd0eSchristos 
96*c42dbd0eSchristos static enum ld_plugin_status
get_libdeps(int fd)97*c42dbd0eSchristos get_libdeps (int fd)
98*c42dbd0eSchristos {
99*c42dbd0eSchristos   arhdr ah;
100*c42dbd0eSchristos   int len;
101*c42dbd0eSchristos   unsigned long mlen;
102*c42dbd0eSchristos   size_t amt;
103*c42dbd0eSchristos   linerec *lr;
104*c42dbd0eSchristos   enum ld_plugin_status rc = LDPS_NO_SYMS;
105*c42dbd0eSchristos 
106*c42dbd0eSchristos   lseek (fd, ARMAGSIZE, SEEK_SET);
107*c42dbd0eSchristos   for (;;)
108*c42dbd0eSchristos     {
109*c42dbd0eSchristos       len = read (fd, (void *) &ah, sizeof (ah));
110*c42dbd0eSchristos       if (len != sizeof (ah))
111*c42dbd0eSchristos 	break;
112*c42dbd0eSchristos       mlen = strtoul (ah.ar_size, NULL, 10);
113*c42dbd0eSchristos       if (!mlen || strncmp (ah.ar_name, LIBDEPS, sizeof (LIBDEPS)-1))
114*c42dbd0eSchristos 	{
115*c42dbd0eSchristos 	  lseek (fd, mlen, SEEK_CUR);
116*c42dbd0eSchristos 	  continue;
117*c42dbd0eSchristos 	}
118*c42dbd0eSchristos       amt = mlen + sizeof (linerec);
119*c42dbd0eSchristos       if (amt <= mlen)
120*c42dbd0eSchristos 	return LDPS_ERR;
121*c42dbd0eSchristos       lr = malloc (amt);
122*c42dbd0eSchristos       if (!lr)
123*c42dbd0eSchristos 	return LDPS_ERR;
124*c42dbd0eSchristos       lr->next = NULL;
125*c42dbd0eSchristos       len = read (fd, lr->line, mlen);
126*c42dbd0eSchristos       lr->line[mlen-1] = '\0';
127*c42dbd0eSchristos       *line_tail = lr;
128*c42dbd0eSchristos       line_tail = &lr->next;
129*c42dbd0eSchristos       rc = LDPS_OK;
130*c42dbd0eSchristos       break;
131*c42dbd0eSchristos     }
132*c42dbd0eSchristos   return rc;
133*c42dbd0eSchristos }
134*c42dbd0eSchristos 
135*c42dbd0eSchristos /* Turn a string into an argvec.  */
136*c42dbd0eSchristos static char **
str2vec(char * in)137*c42dbd0eSchristos str2vec (char *in)
138*c42dbd0eSchristos {
139*c42dbd0eSchristos   char **res;
140*c42dbd0eSchristos   char *s, *first, *end;
141*c42dbd0eSchristos   char *sq, *dq;
142*c42dbd0eSchristos   int i;
143*c42dbd0eSchristos 
144*c42dbd0eSchristos   end = in + strlen (in);
145*c42dbd0eSchristos   s = in;
146*c42dbd0eSchristos   while (isspace ((unsigned char) *s)) s++;
147*c42dbd0eSchristos   first = s;
148*c42dbd0eSchristos 
149*c42dbd0eSchristos   i = 1;
150*c42dbd0eSchristos   while ((s = strchr (s, ' ')))
151*c42dbd0eSchristos     {
152*c42dbd0eSchristos       s++;
153*c42dbd0eSchristos       i++;
154*c42dbd0eSchristos     }
155*c42dbd0eSchristos   res = (char **)malloc ((i+1) * sizeof (char *));
156*c42dbd0eSchristos   if (!res)
157*c42dbd0eSchristos     return res;
158*c42dbd0eSchristos 
159*c42dbd0eSchristos   i = 0;
160*c42dbd0eSchristos   sq = NULL;
161*c42dbd0eSchristos   dq = NULL;
162*c42dbd0eSchristos   res[0] = first;
163*c42dbd0eSchristos   for (s = first; *s; s++)
164*c42dbd0eSchristos     {
165*c42dbd0eSchristos       if (*s == '\\')
166*c42dbd0eSchristos 	{
167*c42dbd0eSchristos 	  memmove (s, s+1, end-s-1);
168*c42dbd0eSchristos 	  end--;
169*c42dbd0eSchristos 	}
170*c42dbd0eSchristos       if (isspace ((unsigned char) *s))
171*c42dbd0eSchristos 	{
172*c42dbd0eSchristos 	  if (sq || dq)
173*c42dbd0eSchristos 	    continue;
174*c42dbd0eSchristos 	  *s++ = '\0';
175*c42dbd0eSchristos 	  while (isspace ((unsigned char) *s)) s++;
176*c42dbd0eSchristos 	  if (*s)
177*c42dbd0eSchristos 	    res[++i] = s;
178*c42dbd0eSchristos 	}
179*c42dbd0eSchristos       if (*s == '\'' && !dq)
180*c42dbd0eSchristos 	{
181*c42dbd0eSchristos 	  if (sq)
182*c42dbd0eSchristos 	    {
183*c42dbd0eSchristos 	      memmove (sq, sq+1, s-sq-1);
184*c42dbd0eSchristos 	      memmove (s-2, s+1, end-s-1);
185*c42dbd0eSchristos 	      end -= 2;
186*c42dbd0eSchristos 	      s--;
187*c42dbd0eSchristos 	      sq = NULL;
188*c42dbd0eSchristos 	    }
189*c42dbd0eSchristos 	  else
190*c42dbd0eSchristos 	    {
191*c42dbd0eSchristos 	      sq = s;
192*c42dbd0eSchristos 	    }
193*c42dbd0eSchristos 	}
194*c42dbd0eSchristos       if (*s == '"' && !sq)
195*c42dbd0eSchristos 	{
196*c42dbd0eSchristos 	  if (dq)
197*c42dbd0eSchristos 	    {
198*c42dbd0eSchristos 	      memmove (dq, dq+1, s-dq-1);
199*c42dbd0eSchristos 	      memmove (s-2, s+1, end-s-1);
200*c42dbd0eSchristos 	      end -= 2;
201*c42dbd0eSchristos 	      s--;
202*c42dbd0eSchristos 	      dq = NULL;
203*c42dbd0eSchristos 	    }
204*c42dbd0eSchristos 	  else
205*c42dbd0eSchristos 	    {
206*c42dbd0eSchristos 	      dq = s;
207*c42dbd0eSchristos 	    }
208*c42dbd0eSchristos 	}
209*c42dbd0eSchristos     }
210*c42dbd0eSchristos   res[++i] = NULL;
211*c42dbd0eSchristos   return res;
212*c42dbd0eSchristos }
213*c42dbd0eSchristos 
214*c42dbd0eSchristos static char *prevfile;
215*c42dbd0eSchristos 
216*c42dbd0eSchristos /* Standard plugin API registerable hook.  */
217*c42dbd0eSchristos static enum ld_plugin_status
onclaim_file(const struct ld_plugin_input_file * file,int * claimed)218*c42dbd0eSchristos onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
219*c42dbd0eSchristos {
220*c42dbd0eSchristos   enum ld_plugin_status rv;
221*c42dbd0eSchristos 
222*c42dbd0eSchristos   *claimed = 0;
223*c42dbd0eSchristos 
224*c42dbd0eSchristos   /* If we've already seen this file, ignore it.  */
225*c42dbd0eSchristos   if (prevfile && !strcmp (file->name, prevfile))
226*c42dbd0eSchristos     return LDPS_OK;
227*c42dbd0eSchristos 
228*c42dbd0eSchristos   /* If it's not an archive member, ignore it.  */
229*c42dbd0eSchristos   if (!file->offset)
230*c42dbd0eSchristos     return LDPS_OK;
231*c42dbd0eSchristos 
232*c42dbd0eSchristos   if (prevfile)
233*c42dbd0eSchristos     free (prevfile);
234*c42dbd0eSchristos 
235*c42dbd0eSchristos   prevfile = strdup (file->name);
236*c42dbd0eSchristos   if (!prevfile)
237*c42dbd0eSchristos     return LDPS_ERR;
238*c42dbd0eSchristos 
239*c42dbd0eSchristos   /* This hook only gets called on actual object files.
240*c42dbd0eSchristos    * We have to examine the archive ourselves, to find
241*c42dbd0eSchristos    * our LIBDEPS member.  */
242*c42dbd0eSchristos   rv = get_libdeps (file->fd);
243*c42dbd0eSchristos   if (rv == LDPS_ERR)
244*c42dbd0eSchristos     return rv;
245*c42dbd0eSchristos 
246*c42dbd0eSchristos   if (rv == LDPS_OK)
247*c42dbd0eSchristos     {
248*c42dbd0eSchristos       linerec *lr = (linerec *)line_tail;
249*c42dbd0eSchristos       /* Inform the user/testsuite.  */
250*c42dbd0eSchristos       TV_MESSAGE (LDPL_INFO, "got deps for library %s: %s",
251*c42dbd0eSchristos 		  file->name, lr->line);
252*c42dbd0eSchristos       fflush (NULL);
253*c42dbd0eSchristos     }
254*c42dbd0eSchristos 
255*c42dbd0eSchristos   return LDPS_OK;
256*c42dbd0eSchristos }
257*c42dbd0eSchristos 
258*c42dbd0eSchristos /* Standard plugin API registerable hook.  */
259*c42dbd0eSchristos static enum ld_plugin_status
onall_symbols_read(void)260*c42dbd0eSchristos onall_symbols_read (void)
261*c42dbd0eSchristos {
262*c42dbd0eSchristos   linerec *lr;
263*c42dbd0eSchristos   char **vec;
264*c42dbd0eSchristos   enum ld_plugin_status rv = LDPS_OK;
265*c42dbd0eSchristos 
266*c42dbd0eSchristos   while ((lr = line_head))
267*c42dbd0eSchristos     {
268*c42dbd0eSchristos       line_head = lr->next;
269*c42dbd0eSchristos       vec = str2vec (lr->line);
270*c42dbd0eSchristos       if (vec)
271*c42dbd0eSchristos 	{
272*c42dbd0eSchristos 	  int i;
273*c42dbd0eSchristos 	  for (i = 0; vec[i]; i++)
274*c42dbd0eSchristos 	    {
275*c42dbd0eSchristos 	      if (vec[i][0] != '-')
276*c42dbd0eSchristos 		{
277*c42dbd0eSchristos 		  TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
278*c42dbd0eSchristos 			      vec[i]);
279*c42dbd0eSchristos 		  fflush (NULL);
280*c42dbd0eSchristos 		  continue;
281*c42dbd0eSchristos 		}
282*c42dbd0eSchristos 	      if (vec[i][1] == 'l')
283*c42dbd0eSchristos 		rv = tv_add_input_library (vec[i]+2);
284*c42dbd0eSchristos 	      else if (vec[i][1] == 'L')
285*c42dbd0eSchristos 		rv = tv_set_extra_library_path (vec[i]+2);
286*c42dbd0eSchristos 	      else
287*c42dbd0eSchristos 		{
288*c42dbd0eSchristos 		  TV_MESSAGE (LDPL_WARNING, "ignoring libdep argument %s",
289*c42dbd0eSchristos 			      vec[i]);
290*c42dbd0eSchristos 		  fflush (NULL);
291*c42dbd0eSchristos 		}
292*c42dbd0eSchristos 	      if (rv != LDPS_OK)
293*c42dbd0eSchristos 		break;
294*c42dbd0eSchristos 	    }
295*c42dbd0eSchristos 	  free (vec);
296*c42dbd0eSchristos 	}
297*c42dbd0eSchristos       free (lr);
298*c42dbd0eSchristos     }
299*c42dbd0eSchristos   line_tail = NULL;
300*c42dbd0eSchristos   return rv;
301*c42dbd0eSchristos }
302*c42dbd0eSchristos 
303*c42dbd0eSchristos /* Standard plugin API registerable hook.  */
304*c42dbd0eSchristos static enum ld_plugin_status
oncleanup(void)305*c42dbd0eSchristos oncleanup (void)
306*c42dbd0eSchristos {
307*c42dbd0eSchristos   if (prevfile)
308*c42dbd0eSchristos     {
309*c42dbd0eSchristos       free (prevfile);
310*c42dbd0eSchristos       prevfile = NULL;
311*c42dbd0eSchristos     }
312*c42dbd0eSchristos   if (line_head)
313*c42dbd0eSchristos     {
314*c42dbd0eSchristos       linerec *lr;
315*c42dbd0eSchristos       while ((lr = line_head))
316*c42dbd0eSchristos 	{
317*c42dbd0eSchristos 	  line_head = lr->next;
318*c42dbd0eSchristos 	  free (lr);
319*c42dbd0eSchristos 	}
320*c42dbd0eSchristos       line_tail = NULL;
321*c42dbd0eSchristos     }
322*c42dbd0eSchristos   return LDPS_OK;
323*c42dbd0eSchristos }
324*c42dbd0eSchristos 
325*c42dbd0eSchristos /* Standard plugin API entry point.  */
326*c42dbd0eSchristos enum ld_plugin_status
onload(struct ld_plugin_tv * tv)327*c42dbd0eSchristos onload (struct ld_plugin_tv *tv)
328*c42dbd0eSchristos {
329*c42dbd0eSchristos   enum ld_plugin_status rv;
330*c42dbd0eSchristos 
331*c42dbd0eSchristos   /* This plugin requires a valid tv array.  */
332*c42dbd0eSchristos   if (!tv)
333*c42dbd0eSchristos     return LDPS_ERR;
334*c42dbd0eSchristos 
335*c42dbd0eSchristos   /* First entry should always be LDPT_MESSAGE, letting us get
336*c42dbd0eSchristos      hold of it easily so we can send output straight away.  */
337*c42dbd0eSchristos   if (tv[0].tv_tag == LDPT_MESSAGE)
338*c42dbd0eSchristos     tv_message = tv[0].tv_u.tv_message;
339*c42dbd0eSchristos 
340*c42dbd0eSchristos   do
341*c42dbd0eSchristos     if ((rv = parse_tv_tag (tv)) != LDPS_OK)
342*c42dbd0eSchristos       return rv;
343*c42dbd0eSchristos   while ((tv++)->tv_tag != LDPT_NULL);
344*c42dbd0eSchristos 
345*c42dbd0eSchristos   /* Register hooks.  */
346*c42dbd0eSchristos   if (tv_register_claim_file
347*c42dbd0eSchristos       && tv_register_all_symbols_read
348*c42dbd0eSchristos       && tv_register_cleanup)
349*c42dbd0eSchristos     {
350*c42dbd0eSchristos       (*tv_register_claim_file) (onclaim_file);
351*c42dbd0eSchristos       (*tv_register_all_symbols_read) (onall_symbols_read);
352*c42dbd0eSchristos       (*tv_register_cleanup) (oncleanup);
353*c42dbd0eSchristos     }
354*c42dbd0eSchristos   fflush (NULL);
355*c42dbd0eSchristos   return LDPS_OK;
356*c42dbd0eSchristos }
357*c42dbd0eSchristos #endif /* BFD_SUPPORTS_PLUGINS */
358