1 /* libdeps plugin for the GNU linker.
2 Copyright (C) 2020-2023 Free Software Foundation, Inc.
4 This file is part of the GNU Binutils.
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.
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.
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. */
23 #if BFD_SUPPORTS_PLUGINS
24 #include "plugin-api.h"
26 #include <ctype.h> /* For isspace. */
28 extern enum ld_plugin_status
onload (struct ld_plugin_tv
*tv
);
30 /* Helper for calling plugin api message function. */
31 #define TV_MESSAGE if (tv_message) (*tv_message)
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;
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
)
45 #define SETVAR(x) x = tv->tv_u.x
48 case LDPT_REGISTER_CLAIM_FILE_HOOK
:
49 SETVAR(tv_register_claim_file
);
51 case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK
:
52 SETVAR(tv_register_all_symbols_read
);
54 case LDPT_REGISTER_CLEANUP_HOOK
:
55 SETVAR(tv_register_cleanup
);
60 case LDPT_ADD_INPUT_LIBRARY
:
61 SETVAR(tv_add_input_library
);
63 case LDPT_SET_EXTRA_LIBRARY_PATH
:
64 SETVAR(tv_set_extra_library_path
);
73 /* Defs for archive parsing. */
86 typedef struct linerec
92 #define LIBDEPS "__.LIBDEP/ "
94 static linerec
*line_head
, **line_tail
= &line_head
;
96 static enum ld_plugin_status
104 enum ld_plugin_status rc
= LDPS_NO_SYMS
;
106 lseek (fd
, ARMAGSIZE
, SEEK_SET
);
109 len
= read (fd
, (void *) &ah
, sizeof (ah
));
110 if (len
!= sizeof (ah
))
112 mlen
= strtoul (ah
.ar_size
, NULL
, 10);
113 if (!mlen
|| strncmp (ah
.ar_name
, LIBDEPS
, sizeof (LIBDEPS
)-1))
115 lseek (fd
, mlen
, SEEK_CUR
);
118 amt
= mlen
+ sizeof (linerec
);
125 len
= read (fd
, lr
->line
, mlen
);
126 lr
->line
[mlen
-1] = '\0';
128 line_tail
= &lr
->next
;
135 /* Turn a string into an argvec. */
140 char *s
, *first
, *end
;
144 end
= in
+ strlen (in
);
146 while (isspace ((unsigned char) *s
)) s
++;
150 while ((s
= strchr (s
, ' ')))
155 res
= (char **)malloc ((i
+1) * sizeof (char *));
163 for (s
= first
; *s
; s
++)
167 memmove (s
, s
+1, end
-s
-1);
170 if (isspace ((unsigned char) *s
))
175 while (isspace ((unsigned char) *s
)) s
++;
179 if (*s
== '\'' && !dq
)
183 memmove (sq
, sq
+1, s
-sq
-1);
184 memmove (s
-2, s
+1, end
-s
-1);
194 if (*s
== '"' && !sq
)
198 memmove (dq
, dq
+1, s
-dq
-1);
199 memmove (s
-2, s
+1, end
-s
-1);
214 static char *prevfile
;
216 /* Standard plugin API registerable hook. */
217 static enum ld_plugin_status
218 onclaim_file (const struct ld_plugin_input_file
*file
, int *claimed
)
220 enum ld_plugin_status rv
;
224 /* If we've already seen this file, ignore it. */
225 if (prevfile
&& !strcmp (file
->name
, prevfile
))
228 /* If it's not an archive member, ignore it. */
235 prevfile
= strdup (file
->name
);
239 /* This hook only gets called on actual object files.
240 * We have to examine the archive ourselves, to find
241 * our LIBDEPS member. */
242 rv
= get_libdeps (file
->fd
);
248 linerec
*lr
= (linerec
*)line_tail
;
249 /* Inform the user/testsuite. */
250 TV_MESSAGE (LDPL_INFO
, "got deps for library %s: %s",
251 file
->name
, lr
->line
);
258 /* Standard plugin API registerable hook. */
259 static enum ld_plugin_status
260 onall_symbols_read (void)
264 enum ld_plugin_status rv
= LDPS_OK
;
266 while ((lr
= line_head
))
268 line_head
= lr
->next
;
269 vec
= str2vec (lr
->line
);
273 for (i
= 0; vec
[i
]; i
++)
275 if (vec
[i
][0] != '-')
277 TV_MESSAGE (LDPL_WARNING
, "ignoring libdep argument %s",
282 if (vec
[i
][1] == 'l')
283 rv
= tv_add_input_library (vec
[i
]+2);
284 else if (vec
[i
][1] == 'L')
285 rv
= tv_set_extra_library_path (vec
[i
]+2);
288 TV_MESSAGE (LDPL_WARNING
, "ignoring libdep argument %s",
303 /* Standard plugin API registerable hook. */
304 static enum ld_plugin_status
315 while ((lr
= line_head
))
317 line_head
= lr
->next
;
325 /* Standard plugin API entry point. */
326 enum ld_plugin_status
327 onload (struct ld_plugin_tv
*tv
)
329 enum ld_plugin_status rv
;
331 /* This plugin requires a valid tv array. */
335 /* First entry should always be LDPT_MESSAGE, letting us get
336 hold of it easily so we can send output straight away. */
337 if (tv
[0].tv_tag
== LDPT_MESSAGE
)
338 tv_message
= tv
[0].tv_u
.tv_message
;
341 if ((rv
= parse_tv_tag (tv
)) != LDPS_OK
)
343 while ((tv
++)->tv_tag
!= LDPT_NULL
);
345 /* Register hooks. */
346 if (tv_register_claim_file
347 && tv_register_all_symbols_read
348 && tv_register_cleanup
)
350 (*tv_register_claim_file
) (onclaim_file
);
351 (*tv_register_all_symbols_read
) (onall_symbols_read
);
352 (*tv_register_cleanup
) (oncleanup
);
357 #endif /* BFD_SUPPORTS_PLUGINS */