xref: /netbsd-src/external/gpl3/binutils/dist/bfd/plugin.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1 /* Plugin support for BFD.
2    Copyright (C) 2009-2024 Free Software Foundation, Inc.
3 
4    This file is part of BFD, the Binary File Descriptor library.
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 
24 #if BFD_SUPPORTS_PLUGINS
25 
26 #include <assert.h>
27 #ifdef HAVE_DLFCN_H
28 #include <dlfcn.h>
29 #elif defined (HAVE_WINDOWS_H)
30 #include <windows.h>
31 #else
32 #error Unknown how to handle dynamic-load-libraries.
33 #endif
34 #include <stdarg.h>
35 #include "plugin-api.h"
36 #include "plugin.h"
37 #include "libbfd.h"
38 #include "libiberty.h"
39 #include <dirent.h>
40 
41 #if !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)
42 
43 #define RTLD_NOW 0      /* Dummy value.  */
44 
45 static void *
dlopen(const char * file,int mode ATTRIBUTE_UNUSED)46 dlopen (const char *file, int mode ATTRIBUTE_UNUSED)
47 {
48   return LoadLibrary (file);
49 }
50 
51 static void *
dlsym(void * handle,const char * name)52 dlsym (void *handle, const char *name)
53 {
54   return GetProcAddress (handle, name);
55 }
56 
57 static int ATTRIBUTE_UNUSED
dlclose(void * handle)58 dlclose (void *handle)
59 {
60   FreeLibrary (handle);
61   return 0;
62 }
63 
64 static const char *
dlerror(void)65 dlerror (void)
66 {
67   return "Unable to load DLL.";
68 }
69 
70 #endif /* !defined (HAVE_DLFCN_H) && defined (HAVE_WINDOWS_H)  */
71 
72 #define bfd_plugin_close_and_cleanup		      _bfd_generic_close_and_cleanup
73 #define bfd_plugin_bfd_free_cached_info		      _bfd_generic_bfd_free_cached_info
74 #define bfd_plugin_new_section_hook		      _bfd_generic_new_section_hook
75 #define bfd_plugin_get_section_contents		      _bfd_generic_get_section_contents
76 #define bfd_plugin_get_section_contents_in_window     _bfd_generic_get_section_contents_in_window
77 #define bfd_plugin_bfd_copy_private_header_data	      _bfd_generic_bfd_copy_private_header_data
78 #define bfd_plugin_bfd_merge_private_bfd_data	      _bfd_generic_bfd_merge_private_bfd_data
79 #define bfd_plugin_bfd_copy_private_header_data	      _bfd_generic_bfd_copy_private_header_data
80 #define bfd_plugin_bfd_set_private_flags	      _bfd_generic_bfd_set_private_flags
81 #define bfd_plugin_core_file_matches_executable_p     generic_core_file_matches_executable_p
82 #define bfd_plugin_bfd_is_local_label_name	      _bfd_nosymbols_bfd_is_local_label_name
83 #define bfd_plugin_bfd_is_target_special_symbol	      _bfd_bool_bfd_asymbol_false
84 #define bfd_plugin_get_lineno			      _bfd_nosymbols_get_lineno
85 #define bfd_plugin_find_nearest_line		      _bfd_nosymbols_find_nearest_line
86 #define bfd_plugin_find_nearest_line_with_alt	      _bfd_nosymbols_find_nearest_line_with_alt
87 #define bfd_plugin_find_line			      _bfd_nosymbols_find_line
88 #define bfd_plugin_find_inliner_info		      _bfd_nosymbols_find_inliner_info
89 #define bfd_plugin_get_symbol_version_string	      _bfd_nosymbols_get_symbol_version_string
90 #define bfd_plugin_bfd_make_debug_symbol	      _bfd_nosymbols_bfd_make_debug_symbol
91 #define bfd_plugin_read_minisymbols		      _bfd_generic_read_minisymbols
92 #define bfd_plugin_minisymbol_to_symbol		      _bfd_generic_minisymbol_to_symbol
93 #define bfd_plugin_set_arch_mach		      bfd_default_set_arch_mach
94 #define bfd_plugin_set_section_contents		      _bfd_generic_set_section_contents
95 #define bfd_plugin_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
96 #define bfd_plugin_bfd_relax_section		      bfd_generic_relax_section
97 #define bfd_plugin_bfd_link_hash_table_create	      _bfd_generic_link_hash_table_create
98 #define bfd_plugin_bfd_link_add_symbols		      _bfd_generic_link_add_symbols
99 #define bfd_plugin_bfd_link_just_syms		      _bfd_generic_link_just_syms
100 #define bfd_plugin_bfd_final_link		      _bfd_generic_final_link
101 #define bfd_plugin_bfd_link_split_section	      _bfd_generic_link_split_section
102 #define bfd_plugin_bfd_gc_sections		      bfd_generic_gc_sections
103 #define bfd_plugin_bfd_lookup_section_flags	      bfd_generic_lookup_section_flags
104 #define bfd_plugin_bfd_merge_sections		      bfd_generic_merge_sections
105 #define bfd_plugin_bfd_is_group_section		      bfd_generic_is_group_section
106 #define bfd_plugin_bfd_group_name		      bfd_generic_group_name
107 #define bfd_plugin_bfd_discard_group		      bfd_generic_discard_group
108 #define bfd_plugin_section_already_linked	      _bfd_generic_section_already_linked
109 #define bfd_plugin_bfd_define_common_symbol	      bfd_generic_define_common_symbol
110 #define bfd_plugin_bfd_link_hide_symbol		      _bfd_generic_link_hide_symbol
111 #define bfd_plugin_bfd_define_start_stop	      bfd_generic_define_start_stop
112 #define bfd_plugin_bfd_copy_link_hash_symbol_type     _bfd_generic_copy_link_hash_symbol_type
113 #define bfd_plugin_bfd_link_check_relocs	      _bfd_generic_link_check_relocs
114 
115 static enum ld_plugin_status
message(int level ATTRIBUTE_UNUSED,const char * format,...)116 message (int level ATTRIBUTE_UNUSED,
117 	 const char * format, ...)
118 {
119   va_list args;
120   va_start (args, format);
121   printf ("bfd plugin: ");
122   vprintf (format, args);
123   putchar ('\n');
124   va_end (args);
125   return LDPS_OK;
126 }
127 
128 struct plugin_list_entry
129 {
130   /* These must be initialized for each IR object with LTO wrapper.  */
131   ld_plugin_claim_file_handler claim_file;
132   ld_plugin_claim_file_handler_v2 claim_file_v2;
133   ld_plugin_all_symbols_read_handler all_symbols_read;
134   ld_plugin_all_symbols_read_handler cleanup_handler;
135   bool has_symbol_type;
136 
137   struct plugin_list_entry *next;
138 
139   /* These can be reused for all IR objects.  */
140   const char *plugin_name;
141 };
142 
143 static const char *plugin_program_name;
144 
145 void
bfd_plugin_set_program_name(const char * program_name)146 bfd_plugin_set_program_name (const char *program_name)
147 {
148   plugin_program_name = program_name;
149 }
150 
151 static struct plugin_list_entry *plugin_list = NULL;
152 static struct plugin_list_entry *current_plugin = NULL;
153 
154 /* Register a claim-file handler. */
155 
156 static enum ld_plugin_status
register_claim_file(ld_plugin_claim_file_handler handler)157 register_claim_file (ld_plugin_claim_file_handler handler)
158 {
159   current_plugin->claim_file = handler;
160   return LDPS_OK;
161 }
162 
163 
164 /* Register a claim-file handler, version 2. */
165 
166 static enum ld_plugin_status
register_claim_file_v2(ld_plugin_claim_file_handler_v2 handler)167 register_claim_file_v2 (ld_plugin_claim_file_handler_v2 handler)
168 {
169   current_plugin->claim_file_v2 = handler;
170   return LDPS_OK;
171 }
172 
173 static enum ld_plugin_status
add_symbols(void * handle,int nsyms,const struct ld_plugin_symbol * syms)174 add_symbols (void * handle,
175 	     int nsyms,
176 	     const struct ld_plugin_symbol * syms)
177 {
178   bfd *abfd = handle;
179   struct plugin_data_struct *plugin_data =
180     bfd_alloc (abfd, sizeof (plugin_data_struct));
181 
182   if (!plugin_data)
183     return LDPS_ERR;
184 
185   plugin_data->nsyms = nsyms;
186   plugin_data->syms = syms;
187 
188   if (nsyms != 0)
189     abfd->flags |= HAS_SYMS;
190 
191   abfd->tdata.plugin_data = plugin_data;
192   return LDPS_OK;
193 }
194 
195 static enum ld_plugin_status
add_symbols_v2(void * handle,int nsyms,const struct ld_plugin_symbol * syms)196 add_symbols_v2 (void *handle, int nsyms,
197 		const struct ld_plugin_symbol *syms)
198 {
199   current_plugin->has_symbol_type = true;
200   return add_symbols (handle, nsyms, syms);
201 }
202 
203 int
bfd_plugin_open_input(bfd * ibfd,struct ld_plugin_input_file * file)204 bfd_plugin_open_input (bfd *ibfd, struct ld_plugin_input_file *file)
205 {
206   bfd *iobfd;
207   int fd;
208 
209   iobfd = ibfd;
210   while (iobfd->my_archive
211 	 && !bfd_is_thin_archive (iobfd->my_archive))
212     iobfd = iobfd->my_archive;
213   file->name = bfd_get_filename (iobfd);
214 
215   if (!iobfd->iostream && !bfd_open_file (iobfd))
216     return 0;
217 
218   /* Reuse the archive plugin file descriptor.  */
219   if (iobfd != ibfd)
220     fd = iobfd->archive_plugin_fd;
221   else
222     fd = -1;
223 
224   if (fd < 0)
225     {
226       /* The plugin API expects that the file descriptor won't be closed
227 	 and reused as done by the bfd file cache.  So open it again.
228 	 dup isn't good enough.  plugin IO uses lseek/read while BFD uses
229 	 fseek/fread.  It isn't wise to mix the unistd and stdio calls on
230 	 the same underlying file descriptor.  */
231       fd = open (file->name, O_RDONLY | O_BINARY);
232       if (fd < 0)
233 	{
234 #ifndef EMFILE
235 	  return 0;
236 #else
237 	  if (errno != EMFILE)
238 	    return 0;
239 
240 #ifdef HAVE_GETRLIMIT
241 	  struct rlimit lim;
242 
243 	  /* Complicated links involving lots of files and/or large
244 	     archives can exhaust the number of file descriptors
245 	     available to us.  If possible, try to allocate more
246 	     descriptors.  */
247 	  if (getrlimit (RLIMIT_NOFILE, & lim) == 0
248 	      && lim.rlim_cur < lim.rlim_max)
249 	    {
250 	      lim.rlim_cur = lim.rlim_max;
251 	      if (setrlimit (RLIMIT_NOFILE, &lim) == 0)
252 		fd = open (file->name, O_RDONLY | O_BINARY);
253 	    }
254 
255 	  if (fd < 0)
256 #endif
257 	    {
258 	      _bfd_error_handler (_("plugin framework: out of file descriptors. Try using fewer objects/archives\n"));
259 	      return 0;
260 	    }
261 #endif
262 	}
263     }
264 
265   if (iobfd == ibfd)
266     {
267       struct stat stat_buf;
268 
269       if (fstat (fd, &stat_buf))
270 	{
271 	  close (fd);
272 	  return 0;
273 	}
274 
275       file->offset = 0;
276       file->filesize = stat_buf.st_size;
277     }
278   else
279     {
280       /* Cache the archive plugin file descriptor.  */
281       iobfd->archive_plugin_fd = fd;
282       iobfd->archive_plugin_fd_open_count++;
283 
284       file->offset = ibfd->origin;
285       file->filesize = arelt_size (ibfd);
286     }
287 
288   file->fd = fd;
289   return 1;
290 }
291 
292 /* Close the plugin file descriptor FD.  If ABFD isn't NULL, it is an
293    archive member.   */
294 
295 void
bfd_plugin_close_file_descriptor(bfd * abfd,int fd)296 bfd_plugin_close_file_descriptor (bfd *abfd, int fd)
297 {
298   if (abfd == NULL)
299     close (fd);
300   else
301     {
302       while (abfd->my_archive
303 	     && !bfd_is_thin_archive (abfd->my_archive))
304 	abfd = abfd->my_archive;
305 
306       /* Close the file descriptor if there is no archive plugin file
307 	 descriptor.  */
308       if (abfd->archive_plugin_fd == -1)
309 	{
310 	  close (fd);
311 	  return;
312 	}
313 
314       abfd->archive_plugin_fd_open_count--;
315       /* Dup the archive plugin file descriptor for later use, which
316 	 will be closed by _bfd_archive_close_and_cleanup.  */
317       if (abfd->archive_plugin_fd_open_count == 0)
318 	{
319 	  abfd->archive_plugin_fd = dup (fd);
320 	  close (fd);
321 	}
322     }
323 }
324 
325 static int
try_claim(bfd * abfd)326 try_claim (bfd *abfd)
327 {
328   int claimed = 0;
329   struct ld_plugin_input_file file;
330 
331   file.handle = abfd;
332   if (bfd_plugin_open_input (abfd, &file)
333       && current_plugin->claim_file)
334     {
335       current_plugin->claim_file (&file, &claimed);
336       bfd_plugin_close_file_descriptor ((abfd->my_archive != NULL
337 					 ? abfd : NULL),
338 					file.fd);
339     }
340 
341   return claimed;
342 }
343 
344 static bool
try_load_plugin(const char * pname,struct plugin_list_entry * plugin_list_iter,bfd * abfd,bool build_list_p)345 try_load_plugin (const char *pname,
346 		 struct plugin_list_entry *plugin_list_iter,
347 		 bfd *abfd,
348 		 bool build_list_p)
349 {
350   void *plugin_handle;
351   struct ld_plugin_tv tv[6];
352   int i;
353   ld_plugin_onload onload;
354   enum ld_plugin_status status;
355   bool result = false;
356 
357   /* NB: Each object is independent.  Reuse the previous plugin from
358      the last run will lead to wrong result.  */
359   if (current_plugin)
360     memset (current_plugin, 0,
361 	    offsetof (struct plugin_list_entry, next));
362 
363   if (plugin_list_iter)
364     pname = plugin_list_iter->plugin_name;
365 
366   plugin_handle = dlopen (pname, RTLD_NOW);
367   if (!plugin_handle)
368     {
369       /* If we are building a list of viable plugins, then
370 	 we do not bother the user with the details of any
371 	 plugins that cannot be loaded.  */
372       if (! build_list_p)
373 	_bfd_error_handler ("Failed to load plugin '%s', reason: %s\n",
374 			    pname, dlerror ());
375       return false;
376     }
377 
378   if (plugin_list_iter == NULL)
379     {
380       size_t length_plugin_name = strlen (pname) + 1;
381       char *plugin_name = bfd_malloc (length_plugin_name);
382 
383       if (plugin_name == NULL)
384 	goto short_circuit;
385       plugin_list_iter = bfd_malloc (sizeof *plugin_list_iter);
386       if (plugin_list_iter == NULL)
387 	{
388 	  free (plugin_name);
389 	  goto short_circuit;
390 	}
391       /* Make a copy of PNAME since PNAME from load_plugin () will be
392 	 freed.  */
393       memcpy (plugin_name, pname, length_plugin_name);
394       memset (plugin_list_iter, 0, sizeof (*plugin_list_iter));
395       plugin_list_iter->plugin_name = plugin_name;
396       plugin_list_iter->next = plugin_list;
397       plugin_list = plugin_list_iter;
398     }
399 
400   current_plugin = plugin_list_iter;
401   if (build_list_p)
402     goto short_circuit;
403 
404   onload = dlsym (plugin_handle, "onload");
405   if (!onload)
406     goto short_circuit;
407 
408   i = 0;
409   tv[i].tv_tag = LDPT_MESSAGE;
410   tv[i].tv_u.tv_message = message;
411 
412   ++i;
413   tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
414   tv[i].tv_u.tv_register_claim_file = register_claim_file;
415 
416   ++i;
417   tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK_V2;
418   tv[i].tv_u.tv_register_claim_file_v2 = register_claim_file_v2;
419 
420   ++i;
421   tv[i].tv_tag = LDPT_ADD_SYMBOLS;
422   tv[i].tv_u.tv_add_symbols = add_symbols;
423 
424   ++i;
425   tv[i].tv_tag = LDPT_ADD_SYMBOLS_V2;
426   tv[i].tv_u.tv_add_symbols = add_symbols_v2;
427 
428   ++i;
429   tv[i].tv_tag = LDPT_NULL;
430   tv[i].tv_u.tv_val = 0;
431 
432   /* LTO plugin will call handler hooks to set up plugin handlers.  */
433   status = (*onload)(tv);
434 
435   if (status != LDPS_OK)
436     goto short_circuit;
437 
438   abfd->plugin_format = bfd_plugin_no;
439 
440   if (!current_plugin->claim_file)
441     goto short_circuit;
442 
443   if (!try_claim (abfd))
444     goto short_circuit;
445 
446   abfd->plugin_format = bfd_plugin_yes;
447   result = true;
448 
449  short_circuit:
450   dlclose (plugin_handle);
451   return result;
452 }
453 
454 /* There may be plugin libraries in lib/bfd-plugins.  */
455 static int has_plugin_list = -1;
456 
457 static bfd_cleanup (*ld_plugin_object_p) (bfd *, bool);
458 
459 static const char *plugin_name;
460 
461 void
bfd_plugin_set_plugin(const char * p)462 bfd_plugin_set_plugin (const char *p)
463 {
464   plugin_name = p;
465 }
466 
467 /* Return TRUE if a plugin library is used.  */
468 
469 bool
bfd_plugin_specified_p(void)470 bfd_plugin_specified_p (void)
471 {
472   return plugin_list != NULL;
473 }
474 
475 /* Return TRUE if ABFD can be claimed by linker LTO plugin.  */
476 
477 bool
bfd_link_plugin_object_p(bfd * abfd)478 bfd_link_plugin_object_p (bfd *abfd)
479 {
480   if (ld_plugin_object_p)
481     return ld_plugin_object_p (abfd, false) != NULL;
482   return false;
483 }
484 
485 extern const bfd_target plugin_vec;
486 
487 /* Return TRUE if TARGET is a pointer to plugin_vec.  */
488 
489 bool
bfd_plugin_target_p(const bfd_target * target)490 bfd_plugin_target_p (const bfd_target *target)
491 {
492   return target == &plugin_vec;
493 }
494 
495 /* Register OBJECT_P to be used by bfd_plugin_object_p.  */
496 
497 void
register_ld_plugin_object_p(bfd_cleanup (* object_p)(bfd *,bool))498 register_ld_plugin_object_p (bfd_cleanup (*object_p) (bfd *, bool))
499 {
500   ld_plugin_object_p = object_p;
501 }
502 
503 static void
build_plugin_list(bfd * abfd)504 build_plugin_list (bfd *abfd)
505 {
506   /* The intent was to search ${libdir}/bfd-plugins for plugins, but
507      unfortunately the original implementation wasn't precisely that
508      when configuring binutils using --libdir.  Search in the proper
509      path first, then the old one for backwards compatibility.  */
510   static const char *path[]
511     = { LIBDIR "/bfd-plugins", BINDIR "/../lib/bfd-plugins" };
512   struct stat last_st;
513   unsigned int i;
514 
515   if (has_plugin_list >= 0)
516     return;
517 
518   /* Try not to search the same dir twice, by looking at st_dev and
519      st_ino for the dir.  If we are on a file system that always sets
520      st_ino to zero or the actual st_ino is zero we might waste some
521      time, but that doesn't matter too much.  */
522   last_st.st_dev = 0;
523   last_st.st_ino = 0;
524   for (i = 0; i < sizeof (path) / sizeof (path[0]); i++)
525     {
526       char *plugin_dir = make_relative_prefix (plugin_program_name,
527 					       BINDIR,
528 					       path[i]);
529       if (plugin_dir)
530 	{
531 	  struct stat st;
532 	  DIR *d;
533 
534 	  if (stat (plugin_dir, &st) == 0
535 	      && S_ISDIR (st.st_mode)
536 	      && !(last_st.st_dev == st.st_dev
537 		   && last_st.st_ino == st.st_ino
538 		   && st.st_ino != 0)
539 	      && (d = opendir (plugin_dir)) != NULL)
540 	    {
541 	      struct dirent *ent;
542 
543 	      last_st.st_dev = st.st_dev;
544 	      last_st.st_ino = st.st_ino;
545 	      while ((ent = readdir (d)) != NULL)
546 		{
547 		  char *full_name;
548 
549 		  full_name = concat (plugin_dir, "/", ent->d_name, NULL);
550 		  if (stat (full_name, &st) == 0 && S_ISREG (st.st_mode))
551 		    (void) try_load_plugin (full_name, NULL, abfd, true);
552 		  free (full_name);
553 		}
554 	      closedir (d);
555 	    }
556 	  free (plugin_dir);
557 	}
558     }
559 
560   has_plugin_list = plugin_list != NULL;
561 }
562 
563 static bool
load_plugin(bfd * abfd)564 load_plugin (bfd *abfd)
565 {
566   struct plugin_list_entry *plugin_list_iter;
567 
568   if (plugin_name)
569     return try_load_plugin (plugin_name, plugin_list, abfd, false);
570 
571   if (plugin_program_name == NULL)
572     return false;
573 
574   build_plugin_list (abfd);
575 
576   for (plugin_list_iter = plugin_list;
577        plugin_list_iter;
578        plugin_list_iter = plugin_list_iter->next)
579     if (try_load_plugin (NULL, plugin_list_iter, abfd, false))
580       return true;
581 
582   return false;
583 }
584 
585 
586 static bfd_cleanup
bfd_plugin_object_p(bfd * abfd)587 bfd_plugin_object_p (bfd *abfd)
588 {
589   if (ld_plugin_object_p)
590     return ld_plugin_object_p (abfd, false);
591 
592   if (abfd->plugin_format == bfd_plugin_unknown && !load_plugin (abfd))
593     return NULL;
594 
595   return abfd->plugin_format == bfd_plugin_yes ? _bfd_no_cleanup : NULL;
596 }
597 
598 /* Copy any private info we understand from the input bfd
599    to the output bfd.  */
600 
601 static bool
bfd_plugin_bfd_copy_private_bfd_data(bfd * ibfd ATTRIBUTE_UNUSED,bfd * obfd ATTRIBUTE_UNUSED)602 bfd_plugin_bfd_copy_private_bfd_data (bfd *ibfd ATTRIBUTE_UNUSED,
603 				      bfd *obfd ATTRIBUTE_UNUSED)
604 {
605   BFD_ASSERT (0);
606   return true;
607 }
608 
609 /* Copy any private info we understand from the input section
610    to the output section.  */
611 
612 static bool
bfd_plugin_bfd_copy_private_section_data(bfd * ibfd ATTRIBUTE_UNUSED,asection * isection ATTRIBUTE_UNUSED,bfd * obfd ATTRIBUTE_UNUSED,asection * osection ATTRIBUTE_UNUSED)613 bfd_plugin_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
614 					  asection *isection ATTRIBUTE_UNUSED,
615 					  bfd *obfd ATTRIBUTE_UNUSED,
616 					  asection *osection ATTRIBUTE_UNUSED)
617 {
618   BFD_ASSERT (0);
619   return true;
620 }
621 
622 /* Copy any private info we understand from the input symbol
623    to the output symbol.  */
624 
625 static bool
bfd_plugin_bfd_copy_private_symbol_data(bfd * ibfd ATTRIBUTE_UNUSED,asymbol * isymbol ATTRIBUTE_UNUSED,bfd * obfd ATTRIBUTE_UNUSED,asymbol * osymbol ATTRIBUTE_UNUSED)626 bfd_plugin_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
627 					 asymbol *isymbol ATTRIBUTE_UNUSED,
628 					 bfd *obfd ATTRIBUTE_UNUSED,
629 					 asymbol *osymbol ATTRIBUTE_UNUSED)
630 {
631   BFD_ASSERT (0);
632   return true;
633 }
634 
635 static bool
bfd_plugin_bfd_print_private_bfd_data(bfd * abfd ATTRIBUTE_UNUSED,void * ptr ATTRIBUTE_UNUSED)636 bfd_plugin_bfd_print_private_bfd_data (bfd *abfd ATTRIBUTE_UNUSED, void *ptr ATTRIBUTE_UNUSED)
637 {
638   BFD_ASSERT (0);
639   return true;
640 }
641 
642 static char *
bfd_plugin_core_file_failing_command(bfd * abfd ATTRIBUTE_UNUSED)643 bfd_plugin_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
644 {
645   BFD_ASSERT (0);
646   return NULL;
647 }
648 
649 static int
bfd_plugin_core_file_failing_signal(bfd * abfd ATTRIBUTE_UNUSED)650 bfd_plugin_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
651 {
652   BFD_ASSERT (0);
653   return 0;
654 }
655 
656 static int
bfd_plugin_core_file_pid(bfd * abfd ATTRIBUTE_UNUSED)657 bfd_plugin_core_file_pid (bfd *abfd ATTRIBUTE_UNUSED)
658 {
659   BFD_ASSERT (0);
660   return 0;
661 }
662 
663 static long
bfd_plugin_get_symtab_upper_bound(bfd * abfd)664 bfd_plugin_get_symtab_upper_bound (bfd *abfd)
665 {
666   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
667   long nsyms = plugin_data->nsyms;
668 
669   BFD_ASSERT (nsyms >= 0);
670 
671   return ((nsyms + 1) * sizeof (asymbol *));
672 }
673 
674 static flagword
convert_flags(const struct ld_plugin_symbol * sym)675 convert_flags (const struct ld_plugin_symbol *sym)
676 {
677  switch (sym->def)
678    {
679    case LDPK_DEF:
680    case LDPK_COMMON:
681    case LDPK_UNDEF:
682      return BSF_GLOBAL;
683 
684    case LDPK_WEAKUNDEF:
685    case LDPK_WEAKDEF:
686      return BSF_GLOBAL | BSF_WEAK;
687 
688    default:
689      BFD_ASSERT (0);
690      return 0;
691    }
692 }
693 
694 static long
bfd_plugin_canonicalize_symtab(bfd * abfd,asymbol ** alocation)695 bfd_plugin_canonicalize_symtab (bfd *abfd,
696 				asymbol **alocation)
697 {
698   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
699   long nsyms = plugin_data->nsyms;
700   const struct ld_plugin_symbol *syms = plugin_data->syms;
701   static asection fake_text_section
702     = BFD_FAKE_SECTION (fake_text_section, NULL, "plug", 0,
703 			SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS);
704   static asection fake_data_section
705     = BFD_FAKE_SECTION (fake_data_section, NULL, "plug", 0,
706 			SEC_ALLOC | SEC_LOAD | SEC_DATA | SEC_HAS_CONTENTS);
707   static asection fake_bss_section
708     = BFD_FAKE_SECTION (fake_bss_section, NULL, "plug", 0,
709 			SEC_ALLOC);
710   static asection fake_common_section
711     = BFD_FAKE_SECTION (fake_common_section, NULL, "plug", 0, SEC_IS_COMMON);
712   int i;
713 
714   for (i = 0; i < nsyms; i++)
715     {
716       asymbol *s = bfd_alloc (abfd, sizeof (asymbol));
717 
718       BFD_ASSERT (s);
719       alocation[i] = s;
720 
721       s->the_bfd = abfd;
722       s->name = syms[i].name;
723       s->value = 0;
724       s->flags = convert_flags (&syms[i]);
725       switch (syms[i].def)
726 	{
727 	case LDPK_COMMON:
728 	  s->section = &fake_common_section;
729 	  break;
730 	case LDPK_UNDEF:
731 	case LDPK_WEAKUNDEF:
732 	  s->section = bfd_und_section_ptr;
733 	  break;
734 	case LDPK_DEF:
735 	case LDPK_WEAKDEF:
736 	  if (current_plugin->has_symbol_type)
737 	    switch (syms[i].symbol_type)
738 	      {
739 	      default:
740 		/* FIXME: Should we issue an error here ?  */
741 	      case LDST_UNKNOWN:
742 		/* What is the best fake section for LDST_UNKNOWN?  */
743 	      case LDST_FUNCTION:
744 		s->section = &fake_text_section;
745 		break;
746 	      case LDST_VARIABLE:
747 		if (syms[i].section_kind == LDSSK_BSS)
748 		  s->section = &fake_bss_section;
749 		else
750 		  s->section = &fake_data_section;
751 		break;
752 	      }
753 	  else
754 	    s->section = &fake_text_section;
755 	  break;
756 	default:
757 	  BFD_ASSERT (0);
758 	}
759 
760       s->udata.p = (void *) &syms[i];
761     }
762 
763   return nsyms;
764 }
765 
766 static void
bfd_plugin_print_symbol(bfd * abfd ATTRIBUTE_UNUSED,void * afile ATTRIBUTE_UNUSED,asymbol * symbol ATTRIBUTE_UNUSED,bfd_print_symbol_type how ATTRIBUTE_UNUSED)767 bfd_plugin_print_symbol (bfd *abfd ATTRIBUTE_UNUSED,
768 			 void *afile ATTRIBUTE_UNUSED,
769 			 asymbol *symbol ATTRIBUTE_UNUSED,
770 			 bfd_print_symbol_type how ATTRIBUTE_UNUSED)
771 {
772   BFD_ASSERT (0);
773 }
774 
775 static void
bfd_plugin_get_symbol_info(bfd * abfd ATTRIBUTE_UNUSED,asymbol * symbol,symbol_info * ret)776 bfd_plugin_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
777 			    asymbol *symbol,
778 			    symbol_info *ret)
779 {
780   bfd_symbol_info (symbol, ret);
781 }
782 
783 /* Make an empty symbol. */
784 
785 static asymbol *
bfd_plugin_make_empty_symbol(bfd * abfd)786 bfd_plugin_make_empty_symbol (bfd *abfd)
787 {
788   asymbol *new_symbol = bfd_zalloc (abfd, sizeof (asymbol));
789   if (new_symbol == NULL)
790     return new_symbol;
791   new_symbol->the_bfd = abfd;
792   return new_symbol;
793 }
794 
795 static int
bfd_plugin_sizeof_headers(bfd * a ATTRIBUTE_UNUSED,struct bfd_link_info * info ATTRIBUTE_UNUSED)796 bfd_plugin_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
797 			   struct bfd_link_info *info ATTRIBUTE_UNUSED)
798 {
799   BFD_ASSERT (0);
800   return 0;
801 }
802 
803 const bfd_target plugin_vec =
804 {
805   "plugin",			/* Name.  */
806   bfd_target_unknown_flavour,
807   BFD_ENDIAN_LITTLE,		/* Target byte order.  */
808   BFD_ENDIAN_LITTLE,		/* Target headers byte order.  */
809   (HAS_RELOC | EXEC_P |		/* Object flags.  */
810    HAS_LINENO | HAS_DEBUG |
811    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
812   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
813    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* Section flags.  */
814   0,				/* symbol_leading_char.  */
815   '/',				/* ar_pad_char.  */
816   15,				/* ar_max_namelen.  */
817   255,				/* match priority.  */
818   TARGET_KEEP_UNUSED_SECTION_SYMBOLS, /* keep unused section symbols.  */
819 
820   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
821   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
822   bfd_getl16, bfd_getl_signed_16, bfd_putl16,	/* data */
823   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
824   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
825   bfd_getl16, bfd_getl_signed_16, bfd_putl16,	/* hdrs */
826 
827   {				/* bfd_check_format.  */
828     _bfd_dummy_target,
829     bfd_plugin_object_p,
830     bfd_generic_archive_p,
831     _bfd_dummy_target
832   },
833   {				/* bfd_set_format.  */
834     _bfd_bool_bfd_false_error,
835     _bfd_bool_bfd_false_error,
836     _bfd_generic_mkarchive,
837     _bfd_bool_bfd_false_error,
838   },
839   {				/* bfd_write_contents.  */
840     _bfd_bool_bfd_false_error,
841     _bfd_bool_bfd_false_error,
842     _bfd_write_archive_contents,
843     _bfd_bool_bfd_false_error,
844   },
845 
846   BFD_JUMP_TABLE_GENERIC (bfd_plugin),
847   BFD_JUMP_TABLE_COPY (bfd_plugin),
848   BFD_JUMP_TABLE_CORE (bfd_plugin),
849 #ifdef USE_64_BIT_ARCHIVE
850   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_64_bit),
851 #else
852   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
853 #endif
854   BFD_JUMP_TABLE_SYMBOLS (bfd_plugin),
855   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
856   BFD_JUMP_TABLE_WRITE (bfd_plugin),
857   BFD_JUMP_TABLE_LINK (bfd_plugin),
858   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
859 
860   NULL,
861 
862   NULL				/* backend_data.  */
863 };
864 #endif /* BFD_SUPPORTS_PLUGINS */
865