Use putchar for the trailing `\n' in plugin message.
[external/binutils.git] / bfd / plugin.c
1 /* Plugin support for BFD.
2    Copyright 2009
3    Free Software Foundation, Inc.
4
5    This file is part of BFD, the Binary File Descriptor library.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 #include "config.h"
23 #include "bfd.h"
24
25 #if BFD_SUPPORTS_PLUGINS
26
27 #include <assert.h>
28 #include <dlfcn.h>
29 #include <stdarg.h>
30 #include "plugin-api.h"
31 #include "sysdep.h"
32 #include "plugin.h"
33 #include "libbfd.h"
34 #include "libiberty.h"
35 #include <dirent.h>
36
37 #define bfd_plugin_close_and_cleanup                  _bfd_generic_close_and_cleanup
38 #define bfd_plugin_bfd_free_cached_info               _bfd_generic_bfd_free_cached_info
39 #define bfd_plugin_new_section_hook                   _bfd_generic_new_section_hook
40 #define bfd_plugin_get_section_contents               _bfd_generic_get_section_contents
41 #define bfd_plugin_get_section_contents_in_window     _bfd_generic_get_section_contents_in_window
42 #define bfd_plugin_bfd_copy_private_header_data       _bfd_generic_bfd_copy_private_header_data
43 #define bfd_plugin_bfd_merge_private_bfd_data         _bfd_generic_bfd_merge_private_bfd_data
44 #define bfd_plugin_bfd_copy_private_header_data       _bfd_generic_bfd_copy_private_header_data
45 #define bfd_plugin_bfd_set_private_flags              _bfd_generic_bfd_set_private_flags
46 #define bfd_plugin_core_file_matches_executable_p     generic_core_file_matches_executable_p
47 #define bfd_plugin_bfd_is_local_label_name            _bfd_nosymbols_bfd_is_local_label_name
48 #define bfd_plugin_bfd_is_target_special_symbol       ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
49 #define bfd_plugin_get_lineno                         _bfd_nosymbols_get_lineno
50 #define bfd_plugin_find_nearest_line                  _bfd_nosymbols_find_nearest_line
51 #define bfd_plugin_find_inliner_info                  _bfd_nosymbols_find_inliner_info
52 #define bfd_plugin_bfd_make_debug_symbol              _bfd_nosymbols_bfd_make_debug_symbol
53 #define bfd_plugin_read_minisymbols                   _bfd_generic_read_minisymbols
54 #define bfd_plugin_minisymbol_to_symbol               _bfd_generic_minisymbol_to_symbol
55 #define bfd_plugin_set_arch_mach                      bfd_default_set_arch_mach
56 #define bfd_plugin_set_section_contents               _bfd_generic_set_section_contents
57 #define bfd_plugin_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
58 #define bfd_plugin_bfd_relax_section                  bfd_generic_relax_section
59 #define bfd_plugin_bfd_link_hash_table_create         _bfd_generic_link_hash_table_create
60 #define bfd_plugin_bfd_link_hash_table_free           _bfd_generic_link_hash_table_free
61 #define bfd_plugin_bfd_link_add_symbols               _bfd_generic_link_add_symbols
62 #define bfd_plugin_bfd_link_just_syms                 _bfd_generic_link_just_syms
63 #define bfd_plugin_bfd_final_link                     _bfd_generic_final_link
64 #define bfd_plugin_bfd_link_split_section             _bfd_generic_link_split_section
65 #define bfd_plugin_bfd_gc_sections                    bfd_generic_gc_sections
66 #define bfd_plugin_bfd_merge_sections                 bfd_generic_merge_sections
67 #define bfd_plugin_bfd_is_group_section               bfd_generic_is_group_section
68 #define bfd_plugin_bfd_discard_group                  bfd_generic_discard_group
69 #define bfd_plugin_section_already_linked             _bfd_generic_section_already_linked
70 #define bfd_plugin_bfd_define_common_symbol           bfd_generic_define_common_symbol
71 #define bfd_plugin_bfd_copy_link_hash_symbol_type     _bfd_generic_copy_link_hash_symbol_type
72
73 static enum ld_plugin_status
74 message (int level ATTRIBUTE_UNUSED,
75          const char * format, ...)
76 {
77   va_list args;
78   va_start (args, format);
79   printf ("bfd plugin: ");
80   vprintf (format, args);
81   putchar ('\n');
82   va_end (args);
83   return LDPS_OK;
84 }
85
86 /* Register a claim-file handler. */
87 static ld_plugin_claim_file_handler claim_file;
88
89 static enum ld_plugin_status
90 register_claim_file (ld_plugin_claim_file_handler handler)
91 {
92   claim_file = handler;
93   return LDPS_OK;
94 }
95
96 static enum ld_plugin_status
97 add_symbols (void * handle,
98              int nsyms,
99              const struct ld_plugin_symbol * syms)
100 {
101   bfd *abfd = handle;
102   struct plugin_data_struct *plugin_data =
103     bfd_alloc (abfd, sizeof (plugin_data_struct));;
104
105   plugin_data->nsyms = nsyms;
106   plugin_data->syms = syms;
107
108   if (nsyms != 0)
109     abfd->flags |= HAS_SYMS;
110
111   abfd->tdata.plugin_data = plugin_data;
112   return LDPS_OK;
113 }
114
115 static const char *plugin_program_name;
116
117 void
118 bfd_plugin_set_program_name (const char *program_name)
119 {
120   plugin_program_name = program_name;
121 }
122
123 static int
124 try_load_plugin (const char *pname)
125 {
126   static void *plugin_handle;
127   int tv_size = 4;
128   struct ld_plugin_tv tv[tv_size];
129   int i;
130   ld_plugin_onload onload;
131   enum ld_plugin_status status;
132
133   plugin_handle = dlopen (pname, RTLD_NOW);
134   if (!plugin_handle)
135     {
136       (*_bfd_error_handler)("%s\n", dlerror ());
137       return 0;
138     }
139
140   onload = dlsym (plugin_handle, "onload");
141   if (!onload)
142     goto err;
143
144   i = 0;
145   tv[i].tv_tag = LDPT_MESSAGE;
146   tv[i].tv_u.tv_message = message;
147
148   ++i;
149   tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
150   tv[i].tv_u.tv_register_claim_file = register_claim_file;
151
152   ++i;
153   tv[i].tv_tag = LDPT_ADD_SYMBOLS;
154   tv[i].tv_u.tv_add_symbols = add_symbols;
155
156   ++i;
157   tv[i].tv_tag = LDPT_NULL;
158   tv[i].tv_u.tv_val = 0;
159
160   status = (*onload)(tv);
161
162   if (status != LDPS_OK)
163     goto err;
164
165   if (!claim_file)
166     goto err;
167
168   return 1;
169
170  err:
171   plugin_handle = NULL;
172   return 0;
173 }
174
175 static const char *plugin_name;
176
177 void
178 bfd_plugin_set_plugin (const char *p)
179 {
180   plugin_name = p;
181 }
182
183 static int
184 load_plugin (void)
185 {
186   char *plugin_dir;
187   char *p;
188   DIR *d;
189   struct dirent *ent;
190   int found = 0;
191
192   if (plugin_name)
193     return try_load_plugin (plugin_name);
194
195   if (plugin_program_name == NULL)
196     return 0;
197
198   plugin_dir = concat (BINDIR, "/../lib/bfd-plugins", NULL);
199   p = make_relative_prefix (plugin_program_name,
200                             BINDIR,
201                             plugin_dir);
202   free (plugin_dir);
203   plugin_dir = NULL;
204
205   d = opendir (p);
206   if (!d)
207     goto out;
208
209   while ((ent = readdir (d)))
210     {
211       char *full_name;
212       struct stat s;
213
214       full_name = concat (p, "/", ent->d_name, NULL);
215       if (stat(full_name, &s) == 0 && S_ISREG (s.st_mode))
216         found = try_load_plugin (full_name);
217       free (full_name);
218       if (found)
219         break;
220     }
221
222  out:
223   free (p);
224   if (d)
225     closedir (d);
226
227   return found;
228 }
229
230
231 static const bfd_target *
232 bfd_plugin_object_p (bfd *abfd)
233 {
234   int claimed = 0;
235   int t = load_plugin ();
236   struct ld_plugin_input_file file;
237   bfd *iobfd;
238
239   if (!t)
240     return NULL;
241
242   file.name = abfd->filename;
243
244   if (abfd->my_archive)
245     {
246       iobfd = abfd->my_archive;
247       file.offset = abfd->origin;
248       file.filesize = arelt_size (abfd);
249     }
250   else
251     {
252       iobfd = abfd;
253       file.offset = 0;
254       file.filesize = 0; /*FIXME*/
255     }
256
257   if (!iobfd->iostream && !bfd_open_file (iobfd))
258     return NULL;
259
260   file.fd = fileno ((FILE *) iobfd->iostream);
261
262   file.handle = abfd;
263   claim_file (&file, &claimed);
264   if (!claimed)
265     return NULL;
266
267   return abfd->xvec;
268 }
269
270 /* Copy any private info we understand from the input bfd
271    to the output bfd.  */
272
273 static bfd_boolean
274 bfd_plugin_bfd_copy_private_bfd_data (bfd *ibfd ATTRIBUTE_UNUSED,
275                                       bfd *obfd ATTRIBUTE_UNUSED)
276 {
277   BFD_ASSERT (0);
278   return TRUE;
279 }
280
281 /* Copy any private info we understand from the input section
282    to the output section.  */
283
284 static bfd_boolean
285 bfd_plugin_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
286                                           asection *isection ATTRIBUTE_UNUSED,
287                                           bfd *obfd ATTRIBUTE_UNUSED,
288                                           asection *osection ATTRIBUTE_UNUSED)
289 {
290   BFD_ASSERT (0);
291   return TRUE;
292 }
293
294 /* Copy any private info we understand from the input symbol
295    to the output symbol.  */
296
297 static bfd_boolean
298 bfd_plugin_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
299                                          asymbol *isymbol ATTRIBUTE_UNUSED,
300                                          bfd *obfd ATTRIBUTE_UNUSED,
301                                          asymbol *osymbol ATTRIBUTE_UNUSED)
302 {
303   BFD_ASSERT (0);
304   return TRUE;
305 }
306
307 static bfd_boolean
308 bfd_plugin_bfd_print_private_bfd_data (bfd *abfd ATTRIBUTE_UNUSED, PTR ptr ATTRIBUTE_UNUSED)
309 {
310   BFD_ASSERT (0);
311   return TRUE;
312 }
313
314 static char *
315 bfd_plugin_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
316 {
317   BFD_ASSERT (0);
318   return NULL;
319 }
320
321 static int
322 bfd_plugin_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
323 {
324   BFD_ASSERT (0);
325   return 0;
326 }
327
328 static int
329 bfd_plugin_core_file_pid (bfd *abfd ATTRIBUTE_UNUSED)
330 {
331   BFD_ASSERT (0);
332   return 0;
333 }
334
335 static long
336 bfd_plugin_get_symtab_upper_bound (bfd *abfd)
337 {
338   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
339   long nsyms = plugin_data->nsyms;
340
341   BFD_ASSERT (nsyms >= 0);
342
343   return ((nsyms + 1) * sizeof (asymbol *));
344 }
345
346 static flagword
347 convert_flags (const struct ld_plugin_symbol *sym)
348 {
349  switch (sym->def)
350    { 
351    case LDPK_DEF:
352    case LDPK_COMMON:
353    case LDPK_UNDEF:
354      return BSF_GLOBAL;
355
356    case LDPK_WEAKUNDEF:
357    case LDPK_WEAKDEF:
358      return BSF_GLOBAL | BSF_WEAK;
359
360    default:
361      BFD_ASSERT (0);
362      return 0;
363    }
364 }
365
366 static long
367 bfd_plugin_canonicalize_symtab (bfd *abfd,
368                                 asymbol **alocation)
369 {
370   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
371   long nsyms = plugin_data->nsyms;
372   const struct ld_plugin_symbol *syms = plugin_data->syms;
373   static asection fake_section;
374   static asection fake_common_section;
375   int i;
376
377   fake_section.name = ".text";
378   fake_common_section.flags = SEC_IS_COMMON;
379
380   for (i = 0; i < nsyms; i++)
381     {
382       asymbol *s = bfd_alloc (abfd, sizeof (asymbol)); 
383
384       BFD_ASSERT (s);
385       alocation[i] = s;
386
387       s->the_bfd = abfd;
388       s->name = syms[i].name;
389       s->value = 0;
390       s->flags = convert_flags (&syms[i]);
391       switch (syms[i].def)
392         {
393         case LDPK_COMMON:
394           s->section = &fake_common_section;
395           break;
396         case LDPK_UNDEF:
397         case LDPK_WEAKUNDEF:
398           s->section = bfd_und_section_ptr;
399           break;
400         case LDPK_DEF:
401         case LDPK_WEAKDEF:
402           s->section = &fake_section;
403           break;
404         default:
405           BFD_ASSERT (0);
406         }
407
408       s->udata.p = (void *) &syms[i];
409     }
410
411   return nsyms;
412 }
413
414 static void
415 bfd_plugin_print_symbol (bfd *abfd ATTRIBUTE_UNUSED,
416                          PTR afile ATTRIBUTE_UNUSED,
417                          asymbol *symbol ATTRIBUTE_UNUSED,
418                          bfd_print_symbol_type how ATTRIBUTE_UNUSED)
419 {
420   BFD_ASSERT (0);
421 }
422
423 static void
424 bfd_plugin_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
425                             asymbol *symbol,
426                             symbol_info *ret)
427 {
428   bfd_symbol_info (symbol, ret);
429 }
430
431 /* Make an empty symbol. */
432
433 static asymbol *
434 bfd_plugin_make_empty_symbol (bfd *abfd)
435 {
436   asymbol *new_symbol = bfd_zalloc (abfd, sizeof (asymbol));
437   if (new_symbol == NULL)
438     return new_symbol;
439   new_symbol->the_bfd = abfd;
440   return new_symbol;
441 }
442
443 static int
444 bfd_plugin_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
445                            struct bfd_link_info *info ATTRIBUTE_UNUSED)
446 {
447   BFD_ASSERT (0);
448   return 0;
449 }
450
451 static bfd_boolean
452 bfd_plugin_mkobject (bfd *abfd ATTRIBUTE_UNUSED)
453 {
454   BFD_ASSERT (0);
455   return 0;
456 }
457
458 const bfd_target plugin_vec =
459 {
460   "plugin",                     /* Name.  */
461   bfd_target_unknown_flavour,
462   BFD_ENDIAN_LITTLE,            /* Target byte order.  */
463   BFD_ENDIAN_LITTLE,            /* Target headers byte order.  */
464   (HAS_RELOC | EXEC_P |         /* Object flags.  */
465    HAS_LINENO | HAS_DEBUG |
466    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
467   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
468    | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags.  */
469   0,                            /* symbol_leading_char.  */
470   '/',                          /* ar_pad_char.  */
471   15,                           /* ar_max_namelen.  */
472
473   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
474   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
475   bfd_getl16, bfd_getl_signed_16, bfd_putl16,   /* data */
476   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
477   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
478   bfd_getl16, bfd_getl_signed_16, bfd_putl16,   /* hdrs */
479
480   {                             /* bfd_check_format.  */
481     _bfd_dummy_target,
482     bfd_plugin_object_p,
483     bfd_generic_archive_p,
484     _bfd_dummy_target
485   },
486   {                             /* bfd_set_format.  */
487     bfd_false,
488     bfd_plugin_mkobject,
489     _bfd_generic_mkarchive,
490     bfd_false,
491   },
492   {                             /* bfd_write_contents.  */
493     bfd_false,
494     bfd_false,
495     _bfd_write_archive_contents,
496     bfd_false,
497   },
498
499   BFD_JUMP_TABLE_GENERIC (bfd_plugin),
500   BFD_JUMP_TABLE_COPY (bfd_plugin),
501   BFD_JUMP_TABLE_CORE (bfd_plugin),
502   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
503   BFD_JUMP_TABLE_SYMBOLS (bfd_plugin),
504   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
505   BFD_JUMP_TABLE_WRITE (bfd_plugin),
506   BFD_JUMP_TABLE_LINK (bfd_plugin),
507   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
508
509   NULL,
510
511   NULL                          /* backend_data.  */
512 };
513 #endif /* BFD_SUPPORTS_PLUGIN */