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