Upload Tizen:Base source
[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   struct ld_plugin_input_file file;
236   bfd *iobfd;
237   static int have_loaded = 0;
238   static int have_plugin = 0;
239
240   if (!have_loaded)
241     {
242       have_loaded = 1;
243       have_plugin = load_plugin ();
244     }
245   if (!have_plugin)
246     return NULL;
247
248   file.name = abfd->filename;
249
250   if (abfd->my_archive)
251     {
252       iobfd = abfd->my_archive;
253       file.offset = abfd->origin;
254       file.filesize = arelt_size (abfd);
255     }
256   else
257     {
258       iobfd = abfd;
259       file.offset = 0;
260       file.filesize = 0;
261     }
262
263   if (!iobfd->iostream && !bfd_open_file (iobfd))
264     return NULL;
265
266   file.fd = fileno ((FILE *) iobfd->iostream);
267
268   if (!abfd->my_archive)
269     {
270       struct stat stat_buf;
271       if (fstat (file.fd, &stat_buf))
272         return NULL;
273       file.filesize = stat_buf.st_size;
274     }
275
276   file.handle = abfd;
277   off_t cur_offset = lseek(file.fd, 0, SEEK_CUR);
278   claim_file (&file, &claimed);
279   lseek(file.fd, cur_offset, SEEK_SET);
280   if (!claimed)
281     return NULL;
282
283   return abfd->xvec;
284 }
285
286 /* Copy any private info we understand from the input bfd
287    to the output bfd.  */
288
289 static bfd_boolean
290 bfd_plugin_bfd_copy_private_bfd_data (bfd *ibfd ATTRIBUTE_UNUSED,
291                                       bfd *obfd ATTRIBUTE_UNUSED)
292 {
293   BFD_ASSERT (0);
294   return TRUE;
295 }
296
297 /* Copy any private info we understand from the input section
298    to the output section.  */
299
300 static bfd_boolean
301 bfd_plugin_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
302                                           asection *isection ATTRIBUTE_UNUSED,
303                                           bfd *obfd ATTRIBUTE_UNUSED,
304                                           asection *osection ATTRIBUTE_UNUSED)
305 {
306   BFD_ASSERT (0);
307   return TRUE;
308 }
309
310 /* Copy any private info we understand from the input symbol
311    to the output symbol.  */
312
313 static bfd_boolean
314 bfd_plugin_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
315                                          asymbol *isymbol ATTRIBUTE_UNUSED,
316                                          bfd *obfd ATTRIBUTE_UNUSED,
317                                          asymbol *osymbol ATTRIBUTE_UNUSED)
318 {
319   BFD_ASSERT (0);
320   return TRUE;
321 }
322
323 static bfd_boolean
324 bfd_plugin_bfd_print_private_bfd_data (bfd *abfd ATTRIBUTE_UNUSED, PTR ptr ATTRIBUTE_UNUSED)
325 {
326   BFD_ASSERT (0);
327   return TRUE;
328 }
329
330 static char *
331 bfd_plugin_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
332 {
333   BFD_ASSERT (0);
334   return NULL;
335 }
336
337 static int
338 bfd_plugin_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
339 {
340   BFD_ASSERT (0);
341   return 0;
342 }
343
344 static int
345 bfd_plugin_core_file_pid (bfd *abfd ATTRIBUTE_UNUSED)
346 {
347   BFD_ASSERT (0);
348   return 0;
349 }
350
351 static long
352 bfd_plugin_get_symtab_upper_bound (bfd *abfd)
353 {
354   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
355   long nsyms = plugin_data->nsyms;
356
357   BFD_ASSERT (nsyms >= 0);
358
359   return ((nsyms + 1) * sizeof (asymbol *));
360 }
361
362 static flagword
363 convert_flags (const struct ld_plugin_symbol *sym)
364 {
365  switch (sym->def)
366    { 
367    case LDPK_DEF:
368    case LDPK_COMMON:
369    case LDPK_UNDEF:
370      return BSF_GLOBAL;
371
372    case LDPK_WEAKUNDEF:
373    case LDPK_WEAKDEF:
374      return BSF_GLOBAL | BSF_WEAK;
375
376    default:
377      BFD_ASSERT (0);
378      return 0;
379    }
380 }
381
382 static long
383 bfd_plugin_canonicalize_symtab (bfd *abfd,
384                                 asymbol **alocation)
385 {
386   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
387   long nsyms = plugin_data->nsyms;
388   const struct ld_plugin_symbol *syms = plugin_data->syms;
389   static asection fake_section;
390   static asection fake_common_section;
391   int i;
392
393   fake_section.name = ".text";
394   fake_common_section.flags = SEC_IS_COMMON;
395
396   for (i = 0; i < nsyms; i++)
397     {
398       asymbol *s = bfd_alloc (abfd, sizeof (asymbol)); 
399
400       BFD_ASSERT (s);
401       alocation[i] = s;
402
403       s->the_bfd = abfd;
404       s->name = syms[i].name;
405       s->value = 0;
406       s->flags = convert_flags (&syms[i]);
407       switch (syms[i].def)
408         {
409         case LDPK_COMMON:
410           s->section = &fake_common_section;
411           break;
412         case LDPK_UNDEF:
413         case LDPK_WEAKUNDEF:
414           s->section = bfd_und_section_ptr;
415           break;
416         case LDPK_DEF:
417         case LDPK_WEAKDEF:
418           s->section = &fake_section;
419           break;
420         default:
421           BFD_ASSERT (0);
422         }
423
424       s->udata.p = (void *) &syms[i];
425     }
426
427   return nsyms;
428 }
429
430 static void
431 bfd_plugin_print_symbol (bfd *abfd ATTRIBUTE_UNUSED,
432                          PTR afile ATTRIBUTE_UNUSED,
433                          asymbol *symbol ATTRIBUTE_UNUSED,
434                          bfd_print_symbol_type how ATTRIBUTE_UNUSED)
435 {
436   BFD_ASSERT (0);
437 }
438
439 static void
440 bfd_plugin_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
441                             asymbol *symbol,
442                             symbol_info *ret)
443 {
444   bfd_symbol_info (symbol, ret);
445 }
446
447 /* Make an empty symbol. */
448
449 static asymbol *
450 bfd_plugin_make_empty_symbol (bfd *abfd)
451 {
452   asymbol *new_symbol = bfd_zalloc (abfd, sizeof (asymbol));
453   if (new_symbol == NULL)
454     return new_symbol;
455   new_symbol->the_bfd = abfd;
456   return new_symbol;
457 }
458
459 static int
460 bfd_plugin_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
461                            struct bfd_link_info *info ATTRIBUTE_UNUSED)
462 {
463   BFD_ASSERT (0);
464   return 0;
465 }
466
467 const bfd_target plugin_vec =
468 {
469   "plugin",                     /* Name.  */
470   bfd_target_unknown_flavour,
471   BFD_ENDIAN_LITTLE,            /* Target byte order.  */
472   BFD_ENDIAN_LITTLE,            /* Target headers byte order.  */
473   (HAS_RELOC | EXEC_P |         /* Object flags.  */
474    HAS_LINENO | HAS_DEBUG |
475    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
476   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
477    | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags.  */
478   0,                            /* symbol_leading_char.  */
479   '/',                          /* ar_pad_char.  */
480   15,                           /* ar_max_namelen.  */
481
482   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
483   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
484   bfd_getl16, bfd_getl_signed_16, bfd_putl16,   /* data */
485   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
486   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
487   bfd_getl16, bfd_getl_signed_16, bfd_putl16,   /* hdrs */
488
489   {                             /* bfd_check_format.  */
490     _bfd_dummy_target,
491     bfd_plugin_object_p,
492     bfd_generic_archive_p,
493     _bfd_dummy_target
494   },
495   {                             /* bfd_set_format.  */
496     bfd_false,
497     bfd_false,
498     _bfd_generic_mkarchive,
499     bfd_false,
500   },
501   {                             /* bfd_write_contents.  */
502     bfd_false,
503     bfd_false,
504     _bfd_write_archive_contents,
505     bfd_false,
506   },
507
508   BFD_JUMP_TABLE_GENERIC (bfd_plugin),
509   BFD_JUMP_TABLE_COPY (bfd_plugin),
510   BFD_JUMP_TABLE_CORE (bfd_plugin),
511   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
512   BFD_JUMP_TABLE_SYMBOLS (bfd_plugin),
513   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
514   BFD_JUMP_TABLE_WRITE (bfd_plugin),
515   BFD_JUMP_TABLE_LINK (bfd_plugin),
516   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
517
518   NULL,
519
520   NULL                          /* backend_data.  */
521 };
522 #endif /* BFD_SUPPORTS_PLUGIN */