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