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