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 */ 523