1ed0d50c3Schristos /* Plugin support for BFD.
2*b88e3e88Schristos Copyright (C) 2009-2020 Free Software Foundation, Inc.
3ed0d50c3Schristos
4ed0d50c3Schristos This file is part of BFD, the Binary File Descriptor library.
5ed0d50c3Schristos
6ed0d50c3Schristos This program is free software; you can redistribute it and/or modify
7ed0d50c3Schristos it under the terms of the GNU General Public License as published by
8ed0d50c3Schristos the Free Software Foundation; either version 3 of the License, or
9ed0d50c3Schristos (at your option) any later version.
10ed0d50c3Schristos
11ed0d50c3Schristos This program is distributed in the hope that it will be useful,
12ed0d50c3Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13ed0d50c3Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14ed0d50c3Schristos GNU General Public License for more details.
15ed0d50c3Schristos
16ed0d50c3Schristos You should have received a copy of the GNU General Public License
17ed0d50c3Schristos along with this program; if not, write to the Free Software
18ed0d50c3Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19ed0d50c3Schristos MA 02110-1301, USA. */
20ed0d50c3Schristos
21ed0d50c3Schristos #include "sysdep.h"
22ed0d50c3Schristos #include "bfd.h"
23ed0d50c3Schristos
24ed0d50c3Schristos #if BFD_SUPPORTS_PLUGINS
25ed0d50c3Schristos
26ed0d50c3Schristos #include <assert.h>
27ed0d50c3Schristos #ifdef HAVE_DLFCN_H
28ed0d50c3Schristos #include <dlfcn.h>
29ed0d50c3Schristos #elif defined (HAVE_WINDOWS_H)
30ed0d50c3Schristos #include <windows.h>
31ed0d50c3Schristos #else
32ed0d50c3Schristos #error Unknown how to handle dynamic-load-libraries.
33ed0d50c3Schristos #endif
34ed0d50c3Schristos #include <stdarg.h>
35ed0d50c3Schristos #include "plugin-api.h"
36ed0d50c3Schristos #include "plugin.h"
37ed0d50c3Schristos #include "libbfd.h"
38ed0d50c3Schristos #include "libiberty.h"
39ed0d50c3Schristos #include <dirent.h>
40ed0d50c3Schristos
41ed0d50c3Schristos #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
42ed0d50c3Schristos
43ed0d50c3Schristos #define RTLD_NOW 0 /* Dummy value. */
44ed0d50c3Schristos
45ed0d50c3Schristos static void *
dlopen(const char * file,int mode ATTRIBUTE_UNUSED)46ed0d50c3Schristos dlopen (const char *file, int mode ATTRIBUTE_UNUSED)
47ed0d50c3Schristos {
48ed0d50c3Schristos return LoadLibrary (file);
49ed0d50c3Schristos }
50ed0d50c3Schristos
51ed0d50c3Schristos static void *
dlsym(void * handle,const char * name)52ed0d50c3Schristos dlsym (void *handle, const char *name)
53ed0d50c3Schristos {
54ed0d50c3Schristos return GetProcAddress (handle, name);
55ed0d50c3Schristos }
56ed0d50c3Schristos
57ed0d50c3Schristos static int ATTRIBUTE_UNUSED
dlclose(void * handle)58ed0d50c3Schristos dlclose (void *handle)
59ed0d50c3Schristos {
60ed0d50c3Schristos FreeLibrary (handle);
61ed0d50c3Schristos return 0;
62ed0d50c3Schristos }
63ed0d50c3Schristos
64ed0d50c3Schristos static const char *
dlerror(void)65ed0d50c3Schristos dlerror (void)
66ed0d50c3Schristos {
67ed0d50c3Schristos return "Unable to load DLL.";
68ed0d50c3Schristos }
69ed0d50c3Schristos
70ed0d50c3Schristos #endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H) */
71ed0d50c3Schristos
72ed0d50c3Schristos #define bfd_plugin_close_and_cleanup _bfd_generic_close_and_cleanup
73ed0d50c3Schristos #define bfd_plugin_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
74ed0d50c3Schristos #define bfd_plugin_new_section_hook _bfd_generic_new_section_hook
75ed0d50c3Schristos #define bfd_plugin_get_section_contents _bfd_generic_get_section_contents
76ed0d50c3Schristos #define bfd_plugin_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
77ed0d50c3Schristos #define bfd_plugin_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
78ed0d50c3Schristos #define bfd_plugin_bfd_merge_private_bfd_data _bfd_generic_bfd_merge_private_bfd_data
79ed0d50c3Schristos #define bfd_plugin_bfd_copy_private_header_data _bfd_generic_bfd_copy_private_header_data
80ed0d50c3Schristos #define bfd_plugin_bfd_set_private_flags _bfd_generic_bfd_set_private_flags
81ed0d50c3Schristos #define bfd_plugin_core_file_matches_executable_p generic_core_file_matches_executable_p
82ed0d50c3Schristos #define bfd_plugin_bfd_is_local_label_name _bfd_nosymbols_bfd_is_local_label_name
8306324dcfSchristos #define bfd_plugin_bfd_is_target_special_symbol _bfd_bool_bfd_asymbol_false
84ed0d50c3Schristos #define bfd_plugin_get_lineno _bfd_nosymbols_get_lineno
85ed0d50c3Schristos #define bfd_plugin_find_nearest_line _bfd_nosymbols_find_nearest_line
86ed0d50c3Schristos #define bfd_plugin_find_line _bfd_nosymbols_find_line
87ed0d50c3Schristos #define bfd_plugin_find_inliner_info _bfd_nosymbols_find_inliner_info
88ed0d50c3Schristos #define bfd_plugin_get_symbol_version_string _bfd_nosymbols_get_symbol_version_string
89ed0d50c3Schristos #define bfd_plugin_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
90ed0d50c3Schristos #define bfd_plugin_read_minisymbols _bfd_generic_read_minisymbols
91ed0d50c3Schristos #define bfd_plugin_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
92ed0d50c3Schristos #define bfd_plugin_set_arch_mach bfd_default_set_arch_mach
93ed0d50c3Schristos #define bfd_plugin_set_section_contents _bfd_generic_set_section_contents
94ed0d50c3Schristos #define bfd_plugin_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
95ed0d50c3Schristos #define bfd_plugin_bfd_relax_section bfd_generic_relax_section
96ed0d50c3Schristos #define bfd_plugin_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
97ed0d50c3Schristos #define bfd_plugin_bfd_link_add_symbols _bfd_generic_link_add_symbols
98ed0d50c3Schristos #define bfd_plugin_bfd_link_just_syms _bfd_generic_link_just_syms
99ed0d50c3Schristos #define bfd_plugin_bfd_final_link _bfd_generic_final_link
100ed0d50c3Schristos #define bfd_plugin_bfd_link_split_section _bfd_generic_link_split_section
101ed0d50c3Schristos #define bfd_plugin_bfd_gc_sections bfd_generic_gc_sections
102ed0d50c3Schristos #define bfd_plugin_bfd_lookup_section_flags bfd_generic_lookup_section_flags
103ed0d50c3Schristos #define bfd_plugin_bfd_merge_sections bfd_generic_merge_sections
104ed0d50c3Schristos #define bfd_plugin_bfd_is_group_section bfd_generic_is_group_section
105*b88e3e88Schristos #define bfd_plugin_bfd_group_name bfd_generic_group_name
106ed0d50c3Schristos #define bfd_plugin_bfd_discard_group bfd_generic_discard_group
107ed0d50c3Schristos #define bfd_plugin_section_already_linked _bfd_generic_section_already_linked
108ed0d50c3Schristos #define bfd_plugin_bfd_define_common_symbol bfd_generic_define_common_symbol
10906324dcfSchristos #define bfd_plugin_bfd_link_hide_symbol _bfd_generic_link_hide_symbol
11006324dcfSchristos #define bfd_plugin_bfd_define_start_stop bfd_generic_define_start_stop
111ed0d50c3Schristos #define bfd_plugin_bfd_copy_link_hash_symbol_type _bfd_generic_copy_link_hash_symbol_type
112ed0d50c3Schristos #define bfd_plugin_bfd_link_check_relocs _bfd_generic_link_check_relocs
113ed0d50c3Schristos
114ed0d50c3Schristos static enum ld_plugin_status
message(int level ATTRIBUTE_UNUSED,const char * format,...)115ed0d50c3Schristos message (int level ATTRIBUTE_UNUSED,
116ed0d50c3Schristos const char * format, ...)
117ed0d50c3Schristos {
118ed0d50c3Schristos va_list args;
119ed0d50c3Schristos va_start (args, format);
120ed0d50c3Schristos printf ("bfd plugin: ");
121ed0d50c3Schristos vprintf (format, args);
122ed0d50c3Schristos putchar ('\n');
123ed0d50c3Schristos va_end (args);
124ed0d50c3Schristos return LDPS_OK;
125ed0d50c3Schristos }
126ed0d50c3Schristos
127ed0d50c3Schristos /* Register a claim-file handler. */
128*b88e3e88Schristos static ld_plugin_claim_file_handler claim_file = NULL;
129ed0d50c3Schristos
130ed0d50c3Schristos static enum ld_plugin_status
register_claim_file(ld_plugin_claim_file_handler handler)131ed0d50c3Schristos register_claim_file (ld_plugin_claim_file_handler handler)
132ed0d50c3Schristos {
133ed0d50c3Schristos claim_file = handler;
134ed0d50c3Schristos return LDPS_OK;
135ed0d50c3Schristos }
136ed0d50c3Schristos
137ed0d50c3Schristos static enum ld_plugin_status
add_symbols(void * handle,int nsyms,const struct ld_plugin_symbol * syms)138ed0d50c3Schristos add_symbols (void * handle,
139ed0d50c3Schristos int nsyms,
140ed0d50c3Schristos const struct ld_plugin_symbol * syms)
141ed0d50c3Schristos {
142ed0d50c3Schristos bfd *abfd = handle;
143ed0d50c3Schristos struct plugin_data_struct *plugin_data =
144ed0d50c3Schristos bfd_alloc (abfd, sizeof (plugin_data_struct));
145ed0d50c3Schristos
146ed0d50c3Schristos plugin_data->nsyms = nsyms;
147ed0d50c3Schristos plugin_data->syms = syms;
148ed0d50c3Schristos
149ed0d50c3Schristos if (nsyms != 0)
150ed0d50c3Schristos abfd->flags |= HAS_SYMS;
151ed0d50c3Schristos
152ed0d50c3Schristos abfd->tdata.plugin_data = plugin_data;
153ed0d50c3Schristos return LDPS_OK;
154ed0d50c3Schristos }
155ed0d50c3Schristos
156ed0d50c3Schristos static const char *plugin_program_name;
157ed0d50c3Schristos
158ed0d50c3Schristos void
bfd_plugin_set_program_name(const char * program_name)159ed0d50c3Schristos bfd_plugin_set_program_name (const char *program_name)
160ed0d50c3Schristos {
161ed0d50c3Schristos plugin_program_name = program_name;
162ed0d50c3Schristos }
163ed0d50c3Schristos
16406324dcfSchristos int
bfd_plugin_open_input(bfd * ibfd,struct ld_plugin_input_file * file)16506324dcfSchristos bfd_plugin_open_input (bfd *ibfd, struct ld_plugin_input_file *file)
16606324dcfSchristos {
16706324dcfSchristos bfd *iobfd;
16806324dcfSchristos
16906324dcfSchristos iobfd = ibfd;
17006324dcfSchristos while (iobfd->my_archive
17106324dcfSchristos && !bfd_is_thin_archive (iobfd->my_archive))
17206324dcfSchristos iobfd = iobfd->my_archive;
17306324dcfSchristos file->name = iobfd->filename;
17406324dcfSchristos
17506324dcfSchristos if (!iobfd->iostream && !bfd_open_file (iobfd))
17606324dcfSchristos return 0;
17706324dcfSchristos
17806324dcfSchristos /* The plugin API expects that the file descriptor won't be closed
17906324dcfSchristos and reused as done by the bfd file cache. So open it again.
18006324dcfSchristos dup isn't good enough. plugin IO uses lseek/read while BFD uses
18106324dcfSchristos fseek/fread. It isn't wise to mix the unistd and stdio calls on
18206324dcfSchristos the same underlying file descriptor. */
18306324dcfSchristos file->fd = open (file->name, O_RDONLY | O_BINARY);
18406324dcfSchristos if (file->fd < 0)
18506324dcfSchristos return 0;
18606324dcfSchristos
18706324dcfSchristos if (iobfd == ibfd)
18806324dcfSchristos {
18906324dcfSchristos struct stat stat_buf;
190*b88e3e88Schristos
19106324dcfSchristos if (fstat (file->fd, &stat_buf))
192*b88e3e88Schristos {
193*b88e3e88Schristos close(file->fd);
19406324dcfSchristos return 0;
195*b88e3e88Schristos }
196*b88e3e88Schristos
19706324dcfSchristos file->offset = 0;
19806324dcfSchristos file->filesize = stat_buf.st_size;
19906324dcfSchristos }
20006324dcfSchristos else
20106324dcfSchristos {
20206324dcfSchristos file->offset = ibfd->origin;
20306324dcfSchristos file->filesize = arelt_size (ibfd);
20406324dcfSchristos }
20506324dcfSchristos return 1;
20606324dcfSchristos }
20706324dcfSchristos
208ed0d50c3Schristos static int
try_claim(bfd * abfd)209ed0d50c3Schristos try_claim (bfd *abfd)
210ed0d50c3Schristos {
211ed0d50c3Schristos int claimed = 0;
212ed0d50c3Schristos struct ld_plugin_input_file file;
213ed0d50c3Schristos
214ed0d50c3Schristos file.handle = abfd;
21506324dcfSchristos if (!bfd_plugin_open_input (abfd, &file))
216ed0d50c3Schristos return 0;
217*b88e3e88Schristos if (claim_file)
21806324dcfSchristos claim_file (&file, &claimed);
21906324dcfSchristos close (file.fd);
22006324dcfSchristos return claimed;
221ed0d50c3Schristos }
222ed0d50c3Schristos
223*b88e3e88Schristos struct plugin_list_entry
224*b88e3e88Schristos {
225*b88e3e88Schristos void * handle;
226*b88e3e88Schristos ld_plugin_claim_file_handler claim_file;
227*b88e3e88Schristos struct plugin_list_entry * next;
228*b88e3e88Schristos };
229*b88e3e88Schristos
230*b88e3e88Schristos static struct plugin_list_entry * plugin_list = NULL;
231*b88e3e88Schristos
232ed0d50c3Schristos static int
try_load_plugin(const char * pname,bfd * abfd,int * has_plugin_p)233ed0d50c3Schristos try_load_plugin (const char *pname, bfd *abfd, int *has_plugin_p)
234ed0d50c3Schristos {
235*b88e3e88Schristos void *plugin_handle = NULL;
236ed0d50c3Schristos struct ld_plugin_tv tv[4];
237ed0d50c3Schristos int i;
238ed0d50c3Schristos ld_plugin_onload onload;
239ed0d50c3Schristos enum ld_plugin_status status;
240*b88e3e88Schristos struct plugin_list_entry *plugin_list_iter;
241ed0d50c3Schristos
242ed0d50c3Schristos *has_plugin_p = 0;
243ed0d50c3Schristos
244ed0d50c3Schristos plugin_handle = dlopen (pname, RTLD_NOW);
245ed0d50c3Schristos if (!plugin_handle)
246ed0d50c3Schristos {
24706324dcfSchristos _bfd_error_handler ("%s\n", dlerror ());
248ed0d50c3Schristos return 0;
249ed0d50c3Schristos }
250ed0d50c3Schristos
251*b88e3e88Schristos for (plugin_list_iter = plugin_list;
252*b88e3e88Schristos plugin_list_iter;
253*b88e3e88Schristos plugin_list_iter = plugin_list_iter->next)
254*b88e3e88Schristos {
255*b88e3e88Schristos if (plugin_handle == plugin_list_iter->handle)
256*b88e3e88Schristos {
257*b88e3e88Schristos dlclose (plugin_handle);
258*b88e3e88Schristos if (!plugin_list_iter->claim_file)
259*b88e3e88Schristos return 0;
260*b88e3e88Schristos
261*b88e3e88Schristos register_claim_file (plugin_list_iter->claim_file);
262*b88e3e88Schristos goto have_claim_file;
263*b88e3e88Schristos }
264*b88e3e88Schristos }
265*b88e3e88Schristos
266*b88e3e88Schristos plugin_list_iter = bfd_malloc (sizeof *plugin_list_iter);
267*b88e3e88Schristos if (plugin_list_iter == NULL)
268*b88e3e88Schristos return 0;
269*b88e3e88Schristos plugin_list_iter->handle = plugin_handle;
270*b88e3e88Schristos plugin_list_iter->claim_file = NULL;
271*b88e3e88Schristos plugin_list_iter->next = plugin_list;
272*b88e3e88Schristos plugin_list = plugin_list_iter;
273*b88e3e88Schristos
274ed0d50c3Schristos onload = dlsym (plugin_handle, "onload");
275ed0d50c3Schristos if (!onload)
276*b88e3e88Schristos return 0;
277ed0d50c3Schristos
278ed0d50c3Schristos i = 0;
279ed0d50c3Schristos tv[i].tv_tag = LDPT_MESSAGE;
280ed0d50c3Schristos tv[i].tv_u.tv_message = message;
281ed0d50c3Schristos
282ed0d50c3Schristos ++i;
283ed0d50c3Schristos tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
284ed0d50c3Schristos tv[i].tv_u.tv_register_claim_file = register_claim_file;
285ed0d50c3Schristos
286ed0d50c3Schristos ++i;
287ed0d50c3Schristos tv[i].tv_tag = LDPT_ADD_SYMBOLS;
288ed0d50c3Schristos tv[i].tv_u.tv_add_symbols = add_symbols;
289ed0d50c3Schristos
290ed0d50c3Schristos ++i;
291ed0d50c3Schristos tv[i].tv_tag = LDPT_NULL;
292ed0d50c3Schristos tv[i].tv_u.tv_val = 0;
293ed0d50c3Schristos
294ed0d50c3Schristos status = (*onload)(tv);
295ed0d50c3Schristos
296ed0d50c3Schristos if (status != LDPS_OK)
297*b88e3e88Schristos return 0;
298ed0d50c3Schristos
299*b88e3e88Schristos plugin_list_iter->claim_file = claim_file;
300*b88e3e88Schristos
301*b88e3e88Schristos have_claim_file:
302ed0d50c3Schristos *has_plugin_p = 1;
303ed0d50c3Schristos
304ed0d50c3Schristos abfd->plugin_format = bfd_plugin_no;
305ed0d50c3Schristos
306ed0d50c3Schristos if (!claim_file)
307*b88e3e88Schristos return 0;
308ed0d50c3Schristos
309ed0d50c3Schristos if (!try_claim (abfd))
310*b88e3e88Schristos return 0;
311ed0d50c3Schristos
312ed0d50c3Schristos abfd->plugin_format = bfd_plugin_yes;
313ed0d50c3Schristos return 1;
314ed0d50c3Schristos }
315ed0d50c3Schristos
316ed0d50c3Schristos /* There may be plugin libraries in lib/bfd-plugins. */
317ed0d50c3Schristos
318ed0d50c3Schristos static int has_plugin = -1;
319ed0d50c3Schristos
320ed0d50c3Schristos static const bfd_target *(*ld_plugin_object_p) (bfd *);
321ed0d50c3Schristos
322ed0d50c3Schristos static const char *plugin_name;
323ed0d50c3Schristos
324ed0d50c3Schristos void
bfd_plugin_set_plugin(const char * p)325ed0d50c3Schristos bfd_plugin_set_plugin (const char *p)
326ed0d50c3Schristos {
327ed0d50c3Schristos plugin_name = p;
328ed0d50c3Schristos has_plugin = p != NULL;
329ed0d50c3Schristos }
330ed0d50c3Schristos
331ed0d50c3Schristos /* Return TRUE if a plugin library is used. */
332ed0d50c3Schristos
333ed0d50c3Schristos bfd_boolean
bfd_plugin_specified_p(void)334ed0d50c3Schristos bfd_plugin_specified_p (void)
335ed0d50c3Schristos {
336ed0d50c3Schristos return has_plugin > 0;
337ed0d50c3Schristos }
338ed0d50c3Schristos
339ed0d50c3Schristos /* Return TRUE if ABFD can be claimed by linker LTO plugin. */
340ed0d50c3Schristos
341ed0d50c3Schristos bfd_boolean
bfd_link_plugin_object_p(bfd * abfd)342ed0d50c3Schristos bfd_link_plugin_object_p (bfd *abfd)
343ed0d50c3Schristos {
344ed0d50c3Schristos if (ld_plugin_object_p)
345ed0d50c3Schristos return ld_plugin_object_p (abfd) != NULL;
346ed0d50c3Schristos return FALSE;
347ed0d50c3Schristos }
348ed0d50c3Schristos
349ed0d50c3Schristos extern const bfd_target plugin_vec;
350ed0d50c3Schristos
351ed0d50c3Schristos /* Return TRUE if TARGET is a pointer to plugin_vec. */
352ed0d50c3Schristos
353ed0d50c3Schristos bfd_boolean
bfd_plugin_target_p(const bfd_target * target)354ed0d50c3Schristos bfd_plugin_target_p (const bfd_target *target)
355ed0d50c3Schristos {
356ed0d50c3Schristos return target == &plugin_vec;
357ed0d50c3Schristos }
358ed0d50c3Schristos
359ed0d50c3Schristos /* Register OBJECT_P to be used by bfd_plugin_object_p. */
360ed0d50c3Schristos
361ed0d50c3Schristos void
register_ld_plugin_object_p(const bfd_target * (* object_p)(bfd *))362ed0d50c3Schristos register_ld_plugin_object_p (const bfd_target *(*object_p) (bfd *))
363ed0d50c3Schristos {
364ed0d50c3Schristos ld_plugin_object_p = object_p;
365ed0d50c3Schristos }
366ed0d50c3Schristos
367ed0d50c3Schristos static int
load_plugin(bfd * abfd)368ed0d50c3Schristos load_plugin (bfd *abfd)
369ed0d50c3Schristos {
370*b88e3e88Schristos /* The intent was to search ${libdir}/bfd-plugins for plugins, but
371*b88e3e88Schristos unfortunately the original implementation wasn't precisely that
372*b88e3e88Schristos when configuring binutils using --libdir. Search in the proper
373*b88e3e88Schristos path first, then the old one for backwards compatibility. */
374*b88e3e88Schristos static const char *path[]
375*b88e3e88Schristos = { LIBDIR "/bfd-plugins", BINDIR "/../lib/bfd-plugins" };
376*b88e3e88Schristos struct stat last_st;
377ed0d50c3Schristos int found = 0;
378*b88e3e88Schristos unsigned int i;
379ed0d50c3Schristos
380ed0d50c3Schristos if (!has_plugin)
381ed0d50c3Schristos return found;
382ed0d50c3Schristos
383ed0d50c3Schristos if (plugin_name)
384ed0d50c3Schristos return try_load_plugin (plugin_name, abfd, &has_plugin);
385ed0d50c3Schristos
386ed0d50c3Schristos if (plugin_program_name == NULL)
387ed0d50c3Schristos return found;
388ed0d50c3Schristos
389*b88e3e88Schristos /* Try not to search the same dir twice, by looking at st_dev and
390*b88e3e88Schristos st_ino for the dir. If we are on a file system that always sets
391*b88e3e88Schristos st_ino to zero or the actual st_ino is zero we might waste some
392*b88e3e88Schristos time, but that doesn't matter too much. */
393*b88e3e88Schristos last_st.st_dev = 0;
394*b88e3e88Schristos last_st.st_ino = 0;
395*b88e3e88Schristos for (i = 0; i < sizeof (path) / sizeof (path[0]); i++)
396*b88e3e88Schristos {
397*b88e3e88Schristos char *plugin_dir = make_relative_prefix (plugin_program_name,
398ed0d50c3Schristos BINDIR,
399*b88e3e88Schristos path[i]);
400*b88e3e88Schristos if (plugin_dir)
401*b88e3e88Schristos {
402*b88e3e88Schristos struct stat st;
403*b88e3e88Schristos DIR *d;
404ed0d50c3Schristos
405*b88e3e88Schristos if (stat (plugin_dir, &st) == 0
406*b88e3e88Schristos && S_ISDIR (st.st_mode)
407*b88e3e88Schristos && !(last_st.st_dev == st.st_dev
408*b88e3e88Schristos && last_st.st_ino == st.st_ino
409*b88e3e88Schristos && st.st_ino != 0)
410*b88e3e88Schristos && (d = opendir (plugin_dir)) != NULL)
411*b88e3e88Schristos {
412*b88e3e88Schristos struct dirent *ent;
413ed0d50c3Schristos
414*b88e3e88Schristos last_st.st_dev = st.st_dev;
415*b88e3e88Schristos last_st.st_ino = st.st_ino;
416*b88e3e88Schristos while ((ent = readdir (d)) != NULL)
417ed0d50c3Schristos {
418ed0d50c3Schristos char *full_name;
419*b88e3e88Schristos
420*b88e3e88Schristos full_name = concat (plugin_dir, "/", ent->d_name, NULL);
421*b88e3e88Schristos if (stat (full_name, &st) == 0 && S_ISREG (st.st_mode))
422*b88e3e88Schristos {
423ed0d50c3Schristos int valid_plugin;
424ed0d50c3Schristos
425ed0d50c3Schristos found = try_load_plugin (full_name, abfd, &valid_plugin);
426ed0d50c3Schristos if (has_plugin <= 0)
427ed0d50c3Schristos has_plugin = valid_plugin;
428*b88e3e88Schristos }
429ed0d50c3Schristos free (full_name);
430ed0d50c3Schristos if (found)
431ed0d50c3Schristos break;
432ed0d50c3Schristos }
433ed0d50c3Schristos closedir (d);
434*b88e3e88Schristos }
435*b88e3e88Schristos free (plugin_dir);
436*b88e3e88Schristos }
437*b88e3e88Schristos if (found)
438*b88e3e88Schristos break;
439*b88e3e88Schristos }
440ed0d50c3Schristos
441ed0d50c3Schristos return found;
442ed0d50c3Schristos }
443ed0d50c3Schristos
444ed0d50c3Schristos
445ed0d50c3Schristos static const bfd_target *
bfd_plugin_object_p(bfd * abfd)446ed0d50c3Schristos bfd_plugin_object_p (bfd *abfd)
447ed0d50c3Schristos {
448ed0d50c3Schristos if (ld_plugin_object_p)
449ed0d50c3Schristos return ld_plugin_object_p (abfd);
450ed0d50c3Schristos
451ed0d50c3Schristos if (abfd->plugin_format == bfd_plugin_unknown && !load_plugin (abfd))
452ed0d50c3Schristos return NULL;
453ed0d50c3Schristos
454ed0d50c3Schristos return abfd->plugin_format == bfd_plugin_yes ? abfd->xvec : NULL;
455ed0d50c3Schristos }
456ed0d50c3Schristos
457ed0d50c3Schristos /* Copy any private info we understand from the input bfd
458ed0d50c3Schristos to the output bfd. */
459ed0d50c3Schristos
460ed0d50c3Schristos static bfd_boolean
bfd_plugin_bfd_copy_private_bfd_data(bfd * ibfd ATTRIBUTE_UNUSED,bfd * obfd ATTRIBUTE_UNUSED)461ed0d50c3Schristos bfd_plugin_bfd_copy_private_bfd_data (bfd *ibfd ATTRIBUTE_UNUSED,
462ed0d50c3Schristos bfd *obfd ATTRIBUTE_UNUSED)
463ed0d50c3Schristos {
464ed0d50c3Schristos BFD_ASSERT (0);
465ed0d50c3Schristos return TRUE;
466ed0d50c3Schristos }
467ed0d50c3Schristos
468ed0d50c3Schristos /* Copy any private info we understand from the input section
469ed0d50c3Schristos to the output section. */
470ed0d50c3Schristos
471ed0d50c3Schristos static bfd_boolean
bfd_plugin_bfd_copy_private_section_data(bfd * ibfd ATTRIBUTE_UNUSED,asection * isection ATTRIBUTE_UNUSED,bfd * obfd ATTRIBUTE_UNUSED,asection * osection ATTRIBUTE_UNUSED)472ed0d50c3Schristos bfd_plugin_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
473ed0d50c3Schristos asection *isection ATTRIBUTE_UNUSED,
474ed0d50c3Schristos bfd *obfd ATTRIBUTE_UNUSED,
475ed0d50c3Schristos asection *osection ATTRIBUTE_UNUSED)
476ed0d50c3Schristos {
477ed0d50c3Schristos BFD_ASSERT (0);
478ed0d50c3Schristos return TRUE;
479ed0d50c3Schristos }
480ed0d50c3Schristos
481ed0d50c3Schristos /* Copy any private info we understand from the input symbol
482ed0d50c3Schristos to the output symbol. */
483ed0d50c3Schristos
484ed0d50c3Schristos static bfd_boolean
bfd_plugin_bfd_copy_private_symbol_data(bfd * ibfd ATTRIBUTE_UNUSED,asymbol * isymbol ATTRIBUTE_UNUSED,bfd * obfd ATTRIBUTE_UNUSED,asymbol * osymbol ATTRIBUTE_UNUSED)485ed0d50c3Schristos bfd_plugin_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
486ed0d50c3Schristos asymbol *isymbol ATTRIBUTE_UNUSED,
487ed0d50c3Schristos bfd *obfd ATTRIBUTE_UNUSED,
488ed0d50c3Schristos asymbol *osymbol ATTRIBUTE_UNUSED)
489ed0d50c3Schristos {
490ed0d50c3Schristos BFD_ASSERT (0);
491ed0d50c3Schristos return TRUE;
492ed0d50c3Schristos }
493ed0d50c3Schristos
494ed0d50c3Schristos static bfd_boolean
bfd_plugin_bfd_print_private_bfd_data(bfd * abfd ATTRIBUTE_UNUSED,PTR ptr ATTRIBUTE_UNUSED)495ed0d50c3Schristos bfd_plugin_bfd_print_private_bfd_data (bfd *abfd ATTRIBUTE_UNUSED, PTR ptr ATTRIBUTE_UNUSED)
496ed0d50c3Schristos {
497ed0d50c3Schristos BFD_ASSERT (0);
498ed0d50c3Schristos return TRUE;
499ed0d50c3Schristos }
500ed0d50c3Schristos
501ed0d50c3Schristos static char *
bfd_plugin_core_file_failing_command(bfd * abfd ATTRIBUTE_UNUSED)502ed0d50c3Schristos bfd_plugin_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
503ed0d50c3Schristos {
504ed0d50c3Schristos BFD_ASSERT (0);
505ed0d50c3Schristos return NULL;
506ed0d50c3Schristos }
507ed0d50c3Schristos
508ed0d50c3Schristos static int
bfd_plugin_core_file_failing_signal(bfd * abfd ATTRIBUTE_UNUSED)509ed0d50c3Schristos bfd_plugin_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
510ed0d50c3Schristos {
511ed0d50c3Schristos BFD_ASSERT (0);
512ed0d50c3Schristos return 0;
513ed0d50c3Schristos }
514ed0d50c3Schristos
515ed0d50c3Schristos static int
bfd_plugin_core_file_pid(bfd * abfd ATTRIBUTE_UNUSED)516ed0d50c3Schristos bfd_plugin_core_file_pid (bfd *abfd ATTRIBUTE_UNUSED)
517ed0d50c3Schristos {
518ed0d50c3Schristos BFD_ASSERT (0);
519ed0d50c3Schristos return 0;
520ed0d50c3Schristos }
521ed0d50c3Schristos
522ed0d50c3Schristos static long
bfd_plugin_get_symtab_upper_bound(bfd * abfd)523ed0d50c3Schristos bfd_plugin_get_symtab_upper_bound (bfd *abfd)
524ed0d50c3Schristos {
525ed0d50c3Schristos struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
526ed0d50c3Schristos long nsyms = plugin_data->nsyms;
527ed0d50c3Schristos
528ed0d50c3Schristos BFD_ASSERT (nsyms >= 0);
529ed0d50c3Schristos
530ed0d50c3Schristos return ((nsyms + 1) * sizeof (asymbol *));
531ed0d50c3Schristos }
532ed0d50c3Schristos
533ed0d50c3Schristos static flagword
convert_flags(const struct ld_plugin_symbol * sym)534ed0d50c3Schristos convert_flags (const struct ld_plugin_symbol *sym)
535ed0d50c3Schristos {
536ed0d50c3Schristos switch (sym->def)
537ed0d50c3Schristos {
538ed0d50c3Schristos case LDPK_DEF:
539ed0d50c3Schristos case LDPK_COMMON:
540ed0d50c3Schristos case LDPK_UNDEF:
541ed0d50c3Schristos return BSF_GLOBAL;
542ed0d50c3Schristos
543ed0d50c3Schristos case LDPK_WEAKUNDEF:
544ed0d50c3Schristos case LDPK_WEAKDEF:
545ed0d50c3Schristos return BSF_GLOBAL | BSF_WEAK;
546ed0d50c3Schristos
547ed0d50c3Schristos default:
548ed0d50c3Schristos BFD_ASSERT (0);
549ed0d50c3Schristos return 0;
550ed0d50c3Schristos }
551ed0d50c3Schristos }
552ed0d50c3Schristos
553ed0d50c3Schristos static long
bfd_plugin_canonicalize_symtab(bfd * abfd,asymbol ** alocation)554ed0d50c3Schristos bfd_plugin_canonicalize_symtab (bfd *abfd,
555ed0d50c3Schristos asymbol **alocation)
556ed0d50c3Schristos {
557ed0d50c3Schristos struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
558ed0d50c3Schristos long nsyms = plugin_data->nsyms;
559ed0d50c3Schristos const struct ld_plugin_symbol *syms = plugin_data->syms;
560*b88e3e88Schristos static asection fake_section
561*b88e3e88Schristos = BFD_FAKE_SECTION (fake_section, NULL, "plug", 0,
562*b88e3e88Schristos SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS);
563*b88e3e88Schristos static asection fake_common_section
564*b88e3e88Schristos = BFD_FAKE_SECTION (fake_common_section, NULL, "plug", 0, SEC_IS_COMMON);
565ed0d50c3Schristos int i;
566ed0d50c3Schristos
567ed0d50c3Schristos for (i = 0; i < nsyms; i++)
568ed0d50c3Schristos {
569ed0d50c3Schristos asymbol *s = bfd_alloc (abfd, sizeof (asymbol));
570ed0d50c3Schristos
571ed0d50c3Schristos BFD_ASSERT (s);
572ed0d50c3Schristos alocation[i] = s;
573ed0d50c3Schristos
574ed0d50c3Schristos s->the_bfd = abfd;
575ed0d50c3Schristos s->name = syms[i].name;
576ed0d50c3Schristos s->value = 0;
577ed0d50c3Schristos s->flags = convert_flags (&syms[i]);
578ed0d50c3Schristos switch (syms[i].def)
579ed0d50c3Schristos {
580ed0d50c3Schristos case LDPK_COMMON:
581ed0d50c3Schristos s->section = &fake_common_section;
582ed0d50c3Schristos break;
583ed0d50c3Schristos case LDPK_UNDEF:
584ed0d50c3Schristos case LDPK_WEAKUNDEF:
585ed0d50c3Schristos s->section = bfd_und_section_ptr;
586ed0d50c3Schristos break;
587ed0d50c3Schristos case LDPK_DEF:
588ed0d50c3Schristos case LDPK_WEAKDEF:
589ed0d50c3Schristos s->section = &fake_section;
590ed0d50c3Schristos break;
591ed0d50c3Schristos default:
592ed0d50c3Schristos BFD_ASSERT (0);
593ed0d50c3Schristos }
594ed0d50c3Schristos
595ed0d50c3Schristos s->udata.p = (void *) &syms[i];
596ed0d50c3Schristos }
597ed0d50c3Schristos
598ed0d50c3Schristos return nsyms;
599ed0d50c3Schristos }
600ed0d50c3Schristos
601ed0d50c3Schristos static void
bfd_plugin_print_symbol(bfd * abfd ATTRIBUTE_UNUSED,PTR afile ATTRIBUTE_UNUSED,asymbol * symbol ATTRIBUTE_UNUSED,bfd_print_symbol_type how ATTRIBUTE_UNUSED)602ed0d50c3Schristos bfd_plugin_print_symbol (bfd *abfd ATTRIBUTE_UNUSED,
603ed0d50c3Schristos PTR afile ATTRIBUTE_UNUSED,
604ed0d50c3Schristos asymbol *symbol ATTRIBUTE_UNUSED,
605ed0d50c3Schristos bfd_print_symbol_type how ATTRIBUTE_UNUSED)
606ed0d50c3Schristos {
607ed0d50c3Schristos BFD_ASSERT (0);
608ed0d50c3Schristos }
609ed0d50c3Schristos
610ed0d50c3Schristos static void
bfd_plugin_get_symbol_info(bfd * abfd ATTRIBUTE_UNUSED,asymbol * symbol,symbol_info * ret)611ed0d50c3Schristos bfd_plugin_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
612ed0d50c3Schristos asymbol *symbol,
613ed0d50c3Schristos symbol_info *ret)
614ed0d50c3Schristos {
615ed0d50c3Schristos bfd_symbol_info (symbol, ret);
616ed0d50c3Schristos }
617ed0d50c3Schristos
618ed0d50c3Schristos /* Make an empty symbol. */
619ed0d50c3Schristos
620ed0d50c3Schristos static asymbol *
bfd_plugin_make_empty_symbol(bfd * abfd)621ed0d50c3Schristos bfd_plugin_make_empty_symbol (bfd *abfd)
622ed0d50c3Schristos {
623ed0d50c3Schristos asymbol *new_symbol = bfd_zalloc (abfd, sizeof (asymbol));
624ed0d50c3Schristos if (new_symbol == NULL)
625ed0d50c3Schristos return new_symbol;
626ed0d50c3Schristos new_symbol->the_bfd = abfd;
627ed0d50c3Schristos return new_symbol;
628ed0d50c3Schristos }
629ed0d50c3Schristos
630ed0d50c3Schristos static int
bfd_plugin_sizeof_headers(bfd * a ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED)631ed0d50c3Schristos bfd_plugin_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
632ed0d50c3Schristos struct bfd_link_info *info ATTRIBUTE_UNUSED)
633ed0d50c3Schristos {
634ed0d50c3Schristos BFD_ASSERT (0);
635ed0d50c3Schristos return 0;
636ed0d50c3Schristos }
637ed0d50c3Schristos
638ed0d50c3Schristos const bfd_target plugin_vec =
639ed0d50c3Schristos {
640ed0d50c3Schristos "plugin", /* Name. */
641ed0d50c3Schristos bfd_target_unknown_flavour,
642ed0d50c3Schristos BFD_ENDIAN_LITTLE, /* Target byte order. */
643ed0d50c3Schristos BFD_ENDIAN_LITTLE, /* Target headers byte order. */
644ed0d50c3Schristos (HAS_RELOC | EXEC_P | /* Object flags. */
645ed0d50c3Schristos HAS_LINENO | HAS_DEBUG |
646ed0d50c3Schristos HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
647ed0d50c3Schristos (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
648ed0d50c3Schristos | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */
649ed0d50c3Schristos 0, /* symbol_leading_char. */
650ed0d50c3Schristos '/', /* ar_pad_char. */
651ed0d50c3Schristos 15, /* ar_max_namelen. */
652ed0d50c3Schristos 255, /* match priority. */
653ed0d50c3Schristos
654ed0d50c3Schristos bfd_getl64, bfd_getl_signed_64, bfd_putl64,
655ed0d50c3Schristos bfd_getl32, bfd_getl_signed_32, bfd_putl32,
656ed0d50c3Schristos bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
657ed0d50c3Schristos bfd_getl64, bfd_getl_signed_64, bfd_putl64,
658ed0d50c3Schristos bfd_getl32, bfd_getl_signed_32, bfd_putl32,
659ed0d50c3Schristos bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
660ed0d50c3Schristos
661ed0d50c3Schristos { /* bfd_check_format. */
662ed0d50c3Schristos _bfd_dummy_target,
663ed0d50c3Schristos bfd_plugin_object_p,
664ed0d50c3Schristos bfd_generic_archive_p,
665ed0d50c3Schristos _bfd_dummy_target
666ed0d50c3Schristos },
667ed0d50c3Schristos { /* bfd_set_format. */
66806324dcfSchristos _bfd_bool_bfd_false_error,
66906324dcfSchristos _bfd_bool_bfd_false_error,
670ed0d50c3Schristos _bfd_generic_mkarchive,
67106324dcfSchristos _bfd_bool_bfd_false_error,
672ed0d50c3Schristos },
673ed0d50c3Schristos { /* bfd_write_contents. */
67406324dcfSchristos _bfd_bool_bfd_false_error,
67506324dcfSchristos _bfd_bool_bfd_false_error,
676ed0d50c3Schristos _bfd_write_archive_contents,
67706324dcfSchristos _bfd_bool_bfd_false_error,
678ed0d50c3Schristos },
679ed0d50c3Schristos
680ed0d50c3Schristos BFD_JUMP_TABLE_GENERIC (bfd_plugin),
681ed0d50c3Schristos BFD_JUMP_TABLE_COPY (bfd_plugin),
682ed0d50c3Schristos BFD_JUMP_TABLE_CORE (bfd_plugin),
683ed0d50c3Schristos #ifdef USE_64_BIT_ARCHIVE
684ed0d50c3Schristos BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_64_bit),
685ed0d50c3Schristos #else
686ed0d50c3Schristos BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
687ed0d50c3Schristos #endif
688ed0d50c3Schristos BFD_JUMP_TABLE_SYMBOLS (bfd_plugin),
689ed0d50c3Schristos BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
690ed0d50c3Schristos BFD_JUMP_TABLE_WRITE (bfd_plugin),
691ed0d50c3Schristos BFD_JUMP_TABLE_LINK (bfd_plugin),
692ed0d50c3Schristos BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
693ed0d50c3Schristos
694ed0d50c3Schristos NULL,
695ed0d50c3Schristos
696ed0d50c3Schristos NULL /* backend_data. */
697ed0d50c3Schristos };
698ed0d50c3Schristos #endif /* BFD_SUPPORTS_PLUGIN */
699