Home | History | Annotate | Download | only in bfd
      1 /* Plugin support for BFD.
      2    Copyright (C) 2009-2014 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 *
     46 dlopen (const char *file, int mode ATTRIBUTE_UNUSED)
     47 {
     48   return LoadLibrary (file);
     49 }
     50 
     51 static void *
     52 dlsym (void *handle, const char *name)
     53 {
     54   return GetProcAddress (handle, name);
     55 }
     56 
     57 static int ATTRIBUTE_UNUSED
     58 dlclose (void *handle)
     59 {
     60   FreeLibrary (handle);
     61   return 0;
     62 }
     63 
     64 static const char *
     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_boolean (*) (bfd *, asymbol *)) bfd_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_line                          _bfd_nosymbols_find_line
     87 #define bfd_plugin_find_inliner_info                  _bfd_nosymbols_find_inliner_info
     88 #define bfd_plugin_bfd_make_debug_symbol              _bfd_nosymbols_bfd_make_debug_symbol
     89 #define bfd_plugin_read_minisymbols                   _bfd_generic_read_minisymbols
     90 #define bfd_plugin_minisymbol_to_symbol               _bfd_generic_minisymbol_to_symbol
     91 #define bfd_plugin_set_arch_mach                      bfd_default_set_arch_mach
     92 #define bfd_plugin_set_section_contents               _bfd_generic_set_section_contents
     93 #define bfd_plugin_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
     94 #define bfd_plugin_bfd_relax_section                  bfd_generic_relax_section
     95 #define bfd_plugin_bfd_link_hash_table_create         _bfd_generic_link_hash_table_create
     96 #define bfd_plugin_bfd_link_add_symbols               _bfd_generic_link_add_symbols
     97 #define bfd_plugin_bfd_link_just_syms                 _bfd_generic_link_just_syms
     98 #define bfd_plugin_bfd_final_link                     _bfd_generic_final_link
     99 #define bfd_plugin_bfd_link_split_section             _bfd_generic_link_split_section
    100 #define bfd_plugin_bfd_gc_sections                    bfd_generic_gc_sections
    101 #define bfd_plugin_bfd_lookup_section_flags           bfd_generic_lookup_section_flags
    102 #define bfd_plugin_bfd_merge_sections                 bfd_generic_merge_sections
    103 #define bfd_plugin_bfd_is_group_section               bfd_generic_is_group_section
    104 #define bfd_plugin_bfd_discard_group                  bfd_generic_discard_group
    105 #define bfd_plugin_section_already_linked             _bfd_generic_section_already_linked
    106 #define bfd_plugin_bfd_define_common_symbol           bfd_generic_define_common_symbol
    107 #define bfd_plugin_bfd_copy_link_hash_symbol_type     _bfd_generic_copy_link_hash_symbol_type
    108 
    109 static enum ld_plugin_status
    110 message (int level ATTRIBUTE_UNUSED,
    111 	 const char * format, ...)
    112 {
    113   va_list args;
    114   va_start (args, format);
    115   printf ("bfd plugin: ");
    116   vprintf (format, args);
    117   putchar ('\n');
    118   va_end (args);
    119   return LDPS_OK;
    120 }
    121 
    122 /* Register a claim-file handler. */
    123 static ld_plugin_claim_file_handler claim_file;
    124 
    125 static enum ld_plugin_status
    126 register_claim_file (ld_plugin_claim_file_handler handler)
    127 {
    128   claim_file = handler;
    129   return LDPS_OK;
    130 }
    131 
    132 static enum ld_plugin_status
    133 add_symbols (void * handle,
    134 	     int nsyms,
    135 	     const struct ld_plugin_symbol * syms)
    136 {
    137   bfd *abfd = handle;
    138   struct plugin_data_struct *plugin_data =
    139     bfd_alloc (abfd, sizeof (plugin_data_struct));
    140 
    141   plugin_data->nsyms = nsyms;
    142   plugin_data->syms = syms;
    143 
    144   if (nsyms != 0)
    145     abfd->flags |= HAS_SYMS;
    146 
    147   abfd->tdata.plugin_data = plugin_data;
    148   return LDPS_OK;
    149 }
    150 
    151 static const char *plugin_program_name;
    152 
    153 void
    154 bfd_plugin_set_program_name (const char *program_name)
    155 {
    156   plugin_program_name = program_name;
    157 }
    158 
    159 static int
    160 try_claim (bfd *abfd)
    161 {
    162   int claimed = 0;
    163   struct ld_plugin_input_file file;
    164   bfd *iobfd;
    165 
    166   file.name = abfd->filename;
    167 
    168   if (abfd->my_archive)
    169     {
    170       iobfd = abfd->my_archive;
    171       file.offset = abfd->origin;
    172       file.filesize = arelt_size (abfd);
    173     }
    174   else
    175     {
    176       iobfd = abfd;
    177       file.offset = 0;
    178       file.filesize = 0;
    179     }
    180 
    181   if (!iobfd->iostream && !bfd_open_file (iobfd))
    182     return 0;
    183 
    184   file.fd = fileno ((FILE *) iobfd->iostream);
    185 
    186   if (!abfd->my_archive)
    187     {
    188       struct stat stat_buf;
    189       if (fstat (file.fd, &stat_buf))
    190         return 0;
    191       file.filesize = stat_buf.st_size;
    192     }
    193 
    194   file.handle = abfd;
    195   off_t cur_offset = lseek(file.fd, 0, SEEK_CUR);
    196   claim_file (&file, &claimed);
    197   lseek(file.fd, cur_offset, SEEK_SET);
    198   if (!claimed)
    199     return 0;
    200 
    201   return 1;
    202 }
    203 
    204 static int
    205 try_load_plugin (const char *pname, bfd *abfd)
    206 {
    207   void *plugin_handle;
    208   int tv_size = 4;
    209   struct ld_plugin_tv tv[tv_size];
    210   int i;
    211   ld_plugin_onload onload;
    212   enum ld_plugin_status status;
    213 
    214   plugin_handle = dlopen (pname, RTLD_NOW);
    215   if (!plugin_handle)
    216     {
    217       (*_bfd_error_handler)("%s\n", dlerror ());
    218       return 0;
    219     }
    220 
    221   onload = dlsym (plugin_handle, "onload");
    222   if (!onload)
    223     goto err;
    224 
    225   i = 0;
    226   tv[i].tv_tag = LDPT_MESSAGE;
    227   tv[i].tv_u.tv_message = message;
    228 
    229   ++i;
    230   tv[i].tv_tag = LDPT_REGISTER_CLAIM_FILE_HOOK;
    231   tv[i].tv_u.tv_register_claim_file = register_claim_file;
    232 
    233   ++i;
    234   tv[i].tv_tag = LDPT_ADD_SYMBOLS;
    235   tv[i].tv_u.tv_add_symbols = add_symbols;
    236 
    237   ++i;
    238   tv[i].tv_tag = LDPT_NULL;
    239   tv[i].tv_u.tv_val = 0;
    240 
    241   status = (*onload)(tv);
    242 
    243   if (status != LDPS_OK)
    244     goto err;
    245 
    246   if (!claim_file)
    247     goto err;
    248 
    249   if (!try_claim (abfd))
    250     goto err;
    251 
    252   return 1;
    253 
    254  err:
    255   plugin_handle = NULL;
    256   return 0;
    257 }
    258 
    259 static const char *plugin_name;
    260 
    261 void
    262 bfd_plugin_set_plugin (const char *p)
    263 {
    264   plugin_name = p;
    265 }
    266 
    267 static int
    268 load_plugin (bfd *abfd)
    269 {
    270   char *plugin_dir;
    271   char *p;
    272   DIR *d;
    273   struct dirent *ent;
    274   int found = 0;
    275 
    276   if (plugin_name)
    277     return try_load_plugin (plugin_name, abfd);
    278 
    279   if (plugin_program_name == NULL)
    280     return 0;
    281 
    282   plugin_dir = concat (BINDIR, "/../lib/bfd-plugins", NULL);
    283   p = make_relative_prefix (plugin_program_name,
    284 			    BINDIR,
    285 			    plugin_dir);
    286   free (plugin_dir);
    287   plugin_dir = NULL;
    288 
    289   d = opendir (p);
    290   if (!d)
    291     goto out;
    292 
    293   while ((ent = readdir (d)))
    294     {
    295       char *full_name;
    296       struct stat s;
    297 
    298       full_name = concat (p, "/", ent->d_name, NULL);
    299       if (stat(full_name, &s) == 0 && S_ISREG (s.st_mode))
    300 	found = try_load_plugin (full_name, abfd);
    301       free (full_name);
    302       if (found)
    303 	break;
    304     }
    305 
    306  out:
    307   free (p);
    308   if (d)
    309     closedir (d);
    310 
    311   return found;
    312 }
    313 
    314 
    315 static const bfd_target *
    316 bfd_plugin_object_p (bfd *abfd)
    317 {
    318   if (!load_plugin (abfd))
    319     return NULL;
    320 
    321   return abfd->xvec;
    322 }
    323 
    324 /* Copy any private info we understand from the input bfd
    325    to the output bfd.  */
    326 
    327 static bfd_boolean
    328 bfd_plugin_bfd_copy_private_bfd_data (bfd *ibfd ATTRIBUTE_UNUSED,
    329 				      bfd *obfd ATTRIBUTE_UNUSED)
    330 {
    331   BFD_ASSERT (0);
    332   return TRUE;
    333 }
    334 
    335 /* Copy any private info we understand from the input section
    336    to the output section.  */
    337 
    338 static bfd_boolean
    339 bfd_plugin_bfd_copy_private_section_data (bfd *ibfd ATTRIBUTE_UNUSED,
    340 					  asection *isection ATTRIBUTE_UNUSED,
    341 					  bfd *obfd ATTRIBUTE_UNUSED,
    342 					  asection *osection ATTRIBUTE_UNUSED)
    343 {
    344   BFD_ASSERT (0);
    345   return TRUE;
    346 }
    347 
    348 /* Copy any private info we understand from the input symbol
    349    to the output symbol.  */
    350 
    351 static bfd_boolean
    352 bfd_plugin_bfd_copy_private_symbol_data (bfd *ibfd ATTRIBUTE_UNUSED,
    353 					 asymbol *isymbol ATTRIBUTE_UNUSED,
    354 					 bfd *obfd ATTRIBUTE_UNUSED,
    355 					 asymbol *osymbol ATTRIBUTE_UNUSED)
    356 {
    357   BFD_ASSERT (0);
    358   return TRUE;
    359 }
    360 
    361 static bfd_boolean
    362 bfd_plugin_bfd_print_private_bfd_data (bfd *abfd ATTRIBUTE_UNUSED, PTR ptr ATTRIBUTE_UNUSED)
    363 {
    364   BFD_ASSERT (0);
    365   return TRUE;
    366 }
    367 
    368 static char *
    369 bfd_plugin_core_file_failing_command (bfd *abfd ATTRIBUTE_UNUSED)
    370 {
    371   BFD_ASSERT (0);
    372   return NULL;
    373 }
    374 
    375 static int
    376 bfd_plugin_core_file_failing_signal (bfd *abfd ATTRIBUTE_UNUSED)
    377 {
    378   BFD_ASSERT (0);
    379   return 0;
    380 }
    381 
    382 static int
    383 bfd_plugin_core_file_pid (bfd *abfd ATTRIBUTE_UNUSED)
    384 {
    385   BFD_ASSERT (0);
    386   return 0;
    387 }
    388 
    389 static long
    390 bfd_plugin_get_symtab_upper_bound (bfd *abfd)
    391 {
    392   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
    393   long nsyms = plugin_data->nsyms;
    394 
    395   BFD_ASSERT (nsyms >= 0);
    396 
    397   return ((nsyms + 1) * sizeof (asymbol *));
    398 }
    399 
    400 static flagword
    401 convert_flags (const struct ld_plugin_symbol *sym)
    402 {
    403  switch (sym->def)
    404    {
    405    case LDPK_DEF:
    406    case LDPK_COMMON:
    407    case LDPK_UNDEF:
    408      return BSF_GLOBAL;
    409 
    410    case LDPK_WEAKUNDEF:
    411    case LDPK_WEAKDEF:
    412      return BSF_GLOBAL | BSF_WEAK;
    413 
    414    default:
    415      BFD_ASSERT (0);
    416      return 0;
    417    }
    418 }
    419 
    420 static long
    421 bfd_plugin_canonicalize_symtab (bfd *abfd,
    422 				asymbol **alocation)
    423 {
    424   struct plugin_data_struct *plugin_data = abfd->tdata.plugin_data;
    425   long nsyms = plugin_data->nsyms;
    426   const struct ld_plugin_symbol *syms = plugin_data->syms;
    427   static asection fake_section;
    428   static asection fake_common_section;
    429   int i;
    430 
    431   fake_section.name = ".text";
    432   fake_common_section.flags = SEC_IS_COMMON;
    433 
    434   for (i = 0; i < nsyms; i++)
    435     {
    436       asymbol *s = bfd_alloc (abfd, sizeof (asymbol));
    437 
    438       BFD_ASSERT (s);
    439       alocation[i] = s;
    440 
    441       s->the_bfd = abfd;
    442       s->name = syms[i].name;
    443       s->value = 0;
    444       s->flags = convert_flags (&syms[i]);
    445       switch (syms[i].def)
    446 	{
    447 	case LDPK_COMMON:
    448 	  s->section = &fake_common_section;
    449 	  break;
    450 	case LDPK_UNDEF:
    451 	case LDPK_WEAKUNDEF:
    452 	  s->section = bfd_und_section_ptr;
    453 	  break;
    454 	case LDPK_DEF:
    455 	case LDPK_WEAKDEF:
    456 	  s->section = &fake_section;
    457 	  break;
    458 	default:
    459 	  BFD_ASSERT (0);
    460 	}
    461 
    462       s->udata.p = (void *) &syms[i];
    463     }
    464 
    465   return nsyms;
    466 }
    467 
    468 static void
    469 bfd_plugin_print_symbol (bfd *abfd ATTRIBUTE_UNUSED,
    470 			 PTR afile ATTRIBUTE_UNUSED,
    471 			 asymbol *symbol ATTRIBUTE_UNUSED,
    472 			 bfd_print_symbol_type how ATTRIBUTE_UNUSED)
    473 {
    474   BFD_ASSERT (0);
    475 }
    476 
    477 static void
    478 bfd_plugin_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
    479 			    asymbol *symbol,
    480 			    symbol_info *ret)
    481 {
    482   bfd_symbol_info (symbol, ret);
    483 }
    484 
    485 /* Make an empty symbol. */
    486 
    487 static asymbol *
    488 bfd_plugin_make_empty_symbol (bfd *abfd)
    489 {
    490   asymbol *new_symbol = bfd_zalloc (abfd, sizeof (asymbol));
    491   if (new_symbol == NULL)
    492     return new_symbol;
    493   new_symbol->the_bfd = abfd;
    494   return new_symbol;
    495 }
    496 
    497 static int
    498 bfd_plugin_sizeof_headers (bfd *a ATTRIBUTE_UNUSED,
    499 			   struct bfd_link_info *info ATTRIBUTE_UNUSED)
    500 {
    501   BFD_ASSERT (0);
    502   return 0;
    503 }
    504 
    505 const bfd_target plugin_vec =
    506 {
    507   "plugin",			/* Name.  */
    508   bfd_target_unknown_flavour,
    509   BFD_ENDIAN_LITTLE,		/* Target byte order.  */
    510   BFD_ENDIAN_LITTLE,		/* Target headers byte order.  */
    511   (HAS_RELOC | EXEC_P |		/* Object flags.  */
    512    HAS_LINENO | HAS_DEBUG |
    513    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
    514   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
    515    | SEC_ALLOC | SEC_LOAD | SEC_RELOC),	/* Section flags.  */
    516   0,				/* symbol_leading_char.  */
    517   '/',				/* ar_pad_char.  */
    518   15,				/* ar_max_namelen.  */
    519   0,				/* match priority.  */
    520 
    521   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    522   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    523   bfd_getl16, bfd_getl_signed_16, bfd_putl16,	/* data */
    524   bfd_getl64, bfd_getl_signed_64, bfd_putl64,
    525   bfd_getl32, bfd_getl_signed_32, bfd_putl32,
    526   bfd_getl16, bfd_getl_signed_16, bfd_putl16,	/* hdrs */
    527 
    528   {				/* bfd_check_format.  */
    529     _bfd_dummy_target,
    530     bfd_plugin_object_p,
    531     bfd_generic_archive_p,
    532     _bfd_dummy_target
    533   },
    534   {				/* bfd_set_format.  */
    535     bfd_false,
    536     bfd_false,
    537     _bfd_generic_mkarchive,
    538     bfd_false,
    539   },
    540   {				/* bfd_write_contents.  */
    541     bfd_false,
    542     bfd_false,
    543     _bfd_write_archive_contents,
    544     bfd_false,
    545   },
    546 
    547   BFD_JUMP_TABLE_GENERIC (bfd_plugin),
    548   BFD_JUMP_TABLE_COPY (bfd_plugin),
    549   BFD_JUMP_TABLE_CORE (bfd_plugin),
    550   BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
    551   BFD_JUMP_TABLE_SYMBOLS (bfd_plugin),
    552   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
    553   BFD_JUMP_TABLE_WRITE (bfd_plugin),
    554   BFD_JUMP_TABLE_LINK (bfd_plugin),
    555   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
    556 
    557   NULL,
    558 
    559   NULL  			/* backend_data.  */
    560 };
    561 #endif /* BFD_SUPPORTS_PLUGIN */
    562