1 /* PEF support for BFD. 2 Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 "sysdep.h" 23 #include "safe-ctype.h" 24 #include "pef.h" 25 #include "pef-traceback.h" 26 #include "bfd.h" 27 #include "libbfd.h" 28 #include "libiberty.h" 29 30 #ifndef BFD_IO_FUNCS 31 #define BFD_IO_FUNCS 0 32 #endif 33 34 #define bfd_pef_close_and_cleanup _bfd_generic_close_and_cleanup 35 #define bfd_pef_bfd_free_cached_info _bfd_generic_bfd_free_cached_info 36 #define bfd_pef_new_section_hook _bfd_generic_new_section_hook 37 #define bfd_pef_bfd_is_local_label_name bfd_generic_is_local_label_name 38 #define bfd_pef_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) 39 #define bfd_pef_get_lineno _bfd_nosymbols_get_lineno 40 #define bfd_pef_find_nearest_line _bfd_nosymbols_find_nearest_line 41 #define bfd_pef_find_inliner_info _bfd_nosymbols_find_inliner_info 42 #define bfd_pef_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol 43 #define bfd_pef_read_minisymbols _bfd_generic_read_minisymbols 44 #define bfd_pef_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol 45 #define bfd_pef_set_arch_mach _bfd_generic_set_arch_mach 46 #define bfd_pef_get_section_contents _bfd_generic_get_section_contents 47 #define bfd_pef_set_section_contents _bfd_generic_set_section_contents 48 #define bfd_pef_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents 49 #define bfd_pef_bfd_relax_section bfd_generic_relax_section 50 #define bfd_pef_bfd_gc_sections bfd_generic_gc_sections 51 #define bfd_pef_bfd_merge_sections bfd_generic_merge_sections 52 #define bfd_pef_bfd_is_group_section bfd_generic_is_group_section 53 #define bfd_pef_bfd_discard_group bfd_generic_discard_group 54 #define bfd_pef_section_already_linked _bfd_generic_section_already_linked 55 #define bfd_pef_bfd_link_hash_table_create _bfd_generic_link_hash_table_create 56 #define bfd_pef_bfd_link_hash_table_free _bfd_generic_link_hash_table_free 57 #define bfd_pef_bfd_link_add_symbols _bfd_generic_link_add_symbols 58 #define bfd_pef_bfd_link_just_syms _bfd_generic_link_just_syms 59 #define bfd_pef_bfd_final_link _bfd_generic_final_link 60 #define bfd_pef_bfd_link_split_section _bfd_generic_link_split_section 61 #define bfd_pef_get_section_contents_in_window _bfd_generic_get_section_contents_in_window 62 63 static int 64 bfd_pef_parse_traceback_table (bfd *abfd, 65 asection *section, 66 unsigned char *buf, 67 size_t len, 68 size_t pos, 69 asymbol *sym, 70 FILE *file) 71 { 72 struct traceback_table table; 73 size_t offset; 74 const char *s; 75 asymbol tmpsymbol; 76 77 if (sym == NULL) 78 sym = & tmpsymbol; 79 80 sym->name = NULL; 81 sym->value = 0; 82 sym->the_bfd = abfd; 83 sym->section = section; 84 sym->flags = 0; 85 sym->udata.i = 0; 86 87 /* memcpy is fine since all fields are unsigned char. */ 88 if ((pos + 8) > len) 89 return -1; 90 memcpy (&table, buf + pos, 8); 91 92 /* Calling code relies on returned symbols having a name and 93 correct offset. */ 94 if ((table.lang != TB_C) && (table.lang != TB_CPLUSPLUS)) 95 return -1; 96 97 if (! (table.flags2 & TB_NAME_PRESENT)) 98 return -1; 99 100 if (! table.flags1 & TB_HAS_TBOFF) 101 return -1; 102 103 offset = 8; 104 105 if ((table.flags5 & TB_FLOATPARAMS) || (table.fixedparams)) 106 offset += 4; 107 108 if (table.flags1 & TB_HAS_TBOFF) 109 { 110 struct traceback_table_tboff off; 111 112 if ((pos + offset + 4) > len) 113 return -1; 114 off.tb_offset = bfd_getb32 (buf + pos + offset); 115 offset += 4; 116 117 /* Need to subtract 4 because the offset includes the 0x0L 118 preceding the table. */ 119 if (file != NULL) 120 fprintf (file, " [offset = 0x%lx]", off.tb_offset); 121 122 if ((file == NULL) && ((off.tb_offset + 4) > (pos + offset))) 123 return -1; 124 125 sym->value = pos - off.tb_offset - 4; 126 } 127 128 if (table.flags2 & TB_INT_HNDL) 129 offset += 4; 130 131 if (table.flags1 & TB_HAS_CTL) 132 { 133 struct traceback_table_anchors anchors; 134 135 if ((pos + offset + 4) > len) 136 return -1; 137 anchors.ctl_info = bfd_getb32 (buf + pos + offset); 138 offset += 4; 139 140 if (anchors.ctl_info > 1024) 141 return -1; 142 143 offset += anchors.ctl_info * 4; 144 } 145 146 if (table.flags2 & TB_NAME_PRESENT) 147 { 148 struct traceback_table_routine name; 149 char *namebuf; 150 151 if ((pos + offset + 2) > len) 152 return -1; 153 name.name_len = bfd_getb16 (buf + pos + offset); 154 offset += 2; 155 156 if (name.name_len > 4096) 157 return -1; 158 159 if ((pos + offset + name.name_len) > len) 160 return -1; 161 162 namebuf = bfd_alloc (abfd, name.name_len + 1); 163 if (namebuf == NULL) 164 return -1; 165 166 memcpy (namebuf, buf + pos + offset, name.name_len); 167 namebuf[name.name_len] = '\0'; 168 169 /* Strip leading period inserted by compiler. */ 170 if (namebuf[0] == '.') 171 memmove (namebuf, namebuf + 1, name.name_len + 1); 172 173 sym->name = namebuf; 174 175 for (s = sym->name; (*s != '\0'); s++) 176 if (! ISPRINT (*s)) 177 return -1; 178 179 offset += name.name_len; 180 } 181 182 if (table.flags2 & TB_USES_ALLOCA) 183 offset += 4; 184 185 if (table.flags4 & TB_HAS_VEC_INFO) 186 offset += 4; 187 188 if (file != NULL) 189 fprintf (file, " [length = 0x%lx]", (unsigned long) offset); 190 191 return offset; 192 } 193 194 static void 195 bfd_pef_print_symbol (bfd *abfd, 196 void * afile, 197 asymbol *symbol, 198 bfd_print_symbol_type how) 199 { 200 FILE *file = (FILE *) afile; 201 202 switch (how) 203 { 204 case bfd_print_symbol_name: 205 fprintf (file, "%s", symbol->name); 206 break; 207 default: 208 bfd_print_symbol_vandf (abfd, (void *) file, symbol); 209 fprintf (file, " %-5s %s", symbol->section->name, symbol->name); 210 if (CONST_STRNEQ (symbol->name, "__traceback_")) 211 { 212 unsigned char *buf = alloca (symbol->udata.i); 213 size_t offset = symbol->value + 4; 214 size_t len = symbol->udata.i; 215 int ret; 216 217 bfd_get_section_contents (abfd, symbol->section, buf, offset, len); 218 ret = bfd_pef_parse_traceback_table (abfd, symbol->section, buf, 219 len, 0, NULL, file); 220 if (ret < 0) 221 fprintf (file, " [ERROR]"); 222 } 223 } 224 } 225 226 static void 227 bfd_pef_convert_architecture (unsigned long architecture, 228 enum bfd_architecture *type, 229 unsigned long *subtype) 230 { 231 const unsigned long ARCH_POWERPC = 0x70777063; /* 'pwpc'. */ 232 const unsigned long ARCH_M68K = 0x6d36386b; /* 'm68k'. */ 233 234 *subtype = bfd_arch_unknown; 235 *type = bfd_arch_unknown; 236 237 if (architecture == ARCH_POWERPC) 238 *type = bfd_arch_powerpc; 239 else if (architecture == ARCH_M68K) 240 *type = bfd_arch_m68k; 241 } 242 243 static bfd_boolean 244 bfd_pef_mkobject (bfd *abfd ATTRIBUTE_UNUSED) 245 { 246 return TRUE; 247 } 248 249 static const char *bfd_pef_section_name (bfd_pef_section *section) 250 { 251 switch (section->section_kind) 252 { 253 case BFD_PEF_SECTION_CODE: return "code"; 254 case BFD_PEF_SECTION_UNPACKED_DATA: return "unpacked-data"; 255 case BFD_PEF_SECTION_PACKED_DATA: return "packed-data"; 256 case BFD_PEF_SECTION_CONSTANT: return "constant"; 257 case BFD_PEF_SECTION_LOADER: return "loader"; 258 case BFD_PEF_SECTION_DEBUG: return "debug"; 259 case BFD_PEF_SECTION_EXEC_DATA: return "exec-data"; 260 case BFD_PEF_SECTION_EXCEPTION: return "exception"; 261 case BFD_PEF_SECTION_TRACEBACK: return "traceback"; 262 default: return "unknown"; 263 } 264 } 265 266 static unsigned long bfd_pef_section_flags (bfd_pef_section *section) 267 { 268 switch (section->section_kind) 269 { 270 case BFD_PEF_SECTION_CODE: 271 return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE; 272 case BFD_PEF_SECTION_UNPACKED_DATA: 273 case BFD_PEF_SECTION_PACKED_DATA: 274 case BFD_PEF_SECTION_CONSTANT: 275 case BFD_PEF_SECTION_LOADER: 276 case BFD_PEF_SECTION_DEBUG: 277 case BFD_PEF_SECTION_EXEC_DATA: 278 case BFD_PEF_SECTION_EXCEPTION: 279 case BFD_PEF_SECTION_TRACEBACK: 280 default: 281 return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; 282 } 283 } 284 285 static asection * 286 bfd_pef_make_bfd_section (bfd *abfd, bfd_pef_section *section) 287 { 288 asection *bfdsec; 289 const char *name = bfd_pef_section_name (section); 290 291 bfdsec = bfd_make_section_anyway (abfd, name); 292 if (bfdsec == NULL) 293 return NULL; 294 295 bfdsec->vma = section->default_address + section->container_offset; 296 bfdsec->lma = section->default_address + section->container_offset; 297 bfdsec->size = section->container_length; 298 bfdsec->filepos = section->container_offset; 299 bfdsec->alignment_power = section->alignment; 300 301 bfdsec->flags = bfd_pef_section_flags (section); 302 303 return bfdsec; 304 } 305 306 int 307 bfd_pef_parse_loader_header (bfd *abfd ATTRIBUTE_UNUSED, 308 unsigned char *buf, 309 size_t len, 310 bfd_pef_loader_header *header) 311 { 312 BFD_ASSERT (len == 56); 313 314 header->main_section = bfd_getb32 (buf); 315 header->main_offset = bfd_getb32 (buf + 4); 316 header->init_section = bfd_getb32 (buf + 8); 317 header->init_offset = bfd_getb32 (buf + 12); 318 header->term_section = bfd_getb32 (buf + 16); 319 header->term_offset = bfd_getb32 (buf + 20); 320 header->imported_library_count = bfd_getb32 (buf + 24); 321 header->total_imported_symbol_count = bfd_getb32 (buf + 28); 322 header->reloc_section_count = bfd_getb32 (buf + 32); 323 header->reloc_instr_offset = bfd_getb32 (buf + 36); 324 header->loader_strings_offset = bfd_getb32 (buf + 40); 325 header->export_hash_offset = bfd_getb32 (buf + 44); 326 header->export_hash_table_power = bfd_getb32 (buf + 48); 327 header->exported_symbol_count = bfd_getb32 (buf + 52); 328 329 return 0; 330 } 331 332 int 333 bfd_pef_parse_imported_library (bfd *abfd ATTRIBUTE_UNUSED, 334 unsigned char *buf, 335 size_t len, 336 bfd_pef_imported_library *header) 337 { 338 BFD_ASSERT (len == 24); 339 340 header->name_offset = bfd_getb32 (buf); 341 header->old_implementation_version = bfd_getb32 (buf + 4); 342 header->current_version = bfd_getb32 (buf + 8); 343 header->imported_symbol_count = bfd_getb32 (buf + 12); 344 header->first_imported_symbol = bfd_getb32 (buf + 16); 345 header->options = buf[20]; 346 header->reserved_a = buf[21]; 347 header->reserved_b = bfd_getb16 (buf + 22); 348 349 return 0; 350 } 351 352 int 353 bfd_pef_parse_imported_symbol (bfd *abfd ATTRIBUTE_UNUSED, 354 unsigned char *buf, 355 size_t len, 356 bfd_pef_imported_symbol *symbol) 357 { 358 unsigned long value; 359 360 BFD_ASSERT (len == 4); 361 362 value = bfd_getb32 (buf); 363 symbol->class = value >> 24; 364 symbol->name = value & 0x00ffffff; 365 366 return 0; 367 } 368 369 int 370 bfd_pef_scan_section (bfd *abfd, bfd_pef_section *section) 371 { 372 unsigned char buf[28]; 373 374 bfd_seek (abfd, section->header_offset, SEEK_SET); 375 if (bfd_bread ((void *) buf, 28, abfd) != 28) 376 return -1; 377 378 section->name_offset = bfd_h_get_32 (abfd, buf); 379 section->default_address = bfd_h_get_32 (abfd, buf + 4); 380 section->total_length = bfd_h_get_32 (abfd, buf + 8); 381 section->unpacked_length = bfd_h_get_32 (abfd, buf + 12); 382 section->container_length = bfd_h_get_32 (abfd, buf + 16); 383 section->container_offset = bfd_h_get_32 (abfd, buf + 20); 384 section->section_kind = buf[24]; 385 section->share_kind = buf[25]; 386 section->alignment = buf[26]; 387 section->reserved = buf[27]; 388 389 section->bfd_section = bfd_pef_make_bfd_section (abfd, section); 390 if (section->bfd_section == NULL) 391 return -1; 392 393 return 0; 394 } 395 396 void 397 bfd_pef_print_loader_header (bfd *abfd ATTRIBUTE_UNUSED, 398 bfd_pef_loader_header *header, 399 FILE *file) 400 { 401 fprintf (file, "main_section: %ld\n", header->main_section); 402 fprintf (file, "main_offset: %lu\n", header->main_offset); 403 fprintf (file, "init_section: %ld\n", header->init_section); 404 fprintf (file, "init_offset: %lu\n", header->init_offset); 405 fprintf (file, "term_section: %ld\n", header->term_section); 406 fprintf (file, "term_offset: %lu\n", header->term_offset); 407 fprintf (file, "imported_library_count: %lu\n", 408 header->imported_library_count); 409 fprintf (file, "total_imported_symbol_count: %lu\n", 410 header->total_imported_symbol_count); 411 fprintf (file, "reloc_section_count: %lu\n", header->reloc_section_count); 412 fprintf (file, "reloc_instr_offset: %lu\n", header->reloc_instr_offset); 413 fprintf (file, "loader_strings_offset: %lu\n", 414 header->loader_strings_offset); 415 fprintf (file, "export_hash_offset: %lu\n", header->export_hash_offset); 416 fprintf (file, "export_hash_table_power: %lu\n", 417 header->export_hash_table_power); 418 fprintf (file, "exported_symbol_count: %lu\n", 419 header->exported_symbol_count); 420 } 421 422 int 423 bfd_pef_print_loader_section (bfd *abfd, FILE *file) 424 { 425 bfd_pef_loader_header header; 426 asection *loadersec = NULL; 427 unsigned char *loaderbuf = NULL; 428 size_t loaderlen = 0; 429 430 loadersec = bfd_get_section_by_name (abfd, "loader"); 431 if (loadersec == NULL) 432 return -1; 433 434 loaderlen = loadersec->size; 435 loaderbuf = bfd_malloc (loaderlen); 436 437 if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0 438 || bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen 439 || loaderlen < 56 440 || bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header) < 0) 441 { 442 free (loaderbuf); 443 return -1; 444 } 445 446 bfd_pef_print_loader_header (abfd, &header, file); 447 return 0; 448 } 449 450 int 451 bfd_pef_scan_start_address (bfd *abfd) 452 { 453 bfd_pef_loader_header header; 454 asection *section; 455 456 asection *loadersec = NULL; 457 unsigned char *loaderbuf = NULL; 458 size_t loaderlen = 0; 459 int ret; 460 461 loadersec = bfd_get_section_by_name (abfd, "loader"); 462 if (loadersec == NULL) 463 goto end; 464 465 loaderlen = loadersec->size; 466 loaderbuf = bfd_malloc (loaderlen); 467 if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0) 468 goto error; 469 if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen) 470 goto error; 471 472 if (loaderlen < 56) 473 goto error; 474 ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header); 475 if (ret < 0) 476 goto error; 477 478 if (header.main_section < 0) 479 goto end; 480 481 for (section = abfd->sections; section != NULL; section = section->next) 482 if ((section->index + 1) == header.main_section) 483 break; 484 485 if (section == NULL) 486 goto error; 487 488 abfd->start_address = section->vma + header.main_offset; 489 490 end: 491 if (loaderbuf != NULL) 492 free (loaderbuf); 493 return 0; 494 495 error: 496 if (loaderbuf != NULL) 497 free (loaderbuf); 498 return -1; 499 } 500 501 int 502 bfd_pef_scan (abfd, header, mdata) 503 bfd *abfd; 504 bfd_pef_header *header; 505 bfd_pef_data_struct *mdata; 506 { 507 unsigned int i; 508 enum bfd_architecture cputype; 509 unsigned long cpusubtype; 510 511 mdata->header = *header; 512 513 bfd_pef_convert_architecture (header->architecture, &cputype, &cpusubtype); 514 if (cputype == bfd_arch_unknown) 515 { 516 fprintf (stderr, "bfd_pef_scan: unknown architecture 0x%lx\n", 517 header->architecture); 518 return -1; 519 } 520 bfd_set_arch_mach (abfd, cputype, cpusubtype); 521 522 mdata->header = *header; 523 524 abfd->flags = (abfd->xvec->object_flags 525 | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS))); 526 527 if (header->section_count != 0) 528 { 529 mdata->sections = bfd_alloc (abfd, header->section_count * sizeof (bfd_pef_section)); 530 531 if (mdata->sections == NULL) 532 return -1; 533 534 for (i = 0; i < header->section_count; i++) 535 { 536 bfd_pef_section *cur = &mdata->sections[i]; 537 cur->header_offset = 40 + (i * 28); 538 if (bfd_pef_scan_section (abfd, cur) < 0) 539 return -1; 540 } 541 } 542 543 if (bfd_pef_scan_start_address (abfd) < 0) 544 return -1; 545 546 abfd->tdata.pef_data = mdata; 547 548 return 0; 549 } 550 551 static int 552 bfd_pef_read_header (bfd *abfd, bfd_pef_header *header) 553 { 554 unsigned char buf[40]; 555 556 bfd_seek (abfd, 0, SEEK_SET); 557 558 if (bfd_bread ((void *) buf, 40, abfd) != 40) 559 return -1; 560 561 header->tag1 = bfd_getb32 (buf); 562 header->tag2 = bfd_getb32 (buf + 4); 563 header->architecture = bfd_getb32 (buf + 8); 564 header->format_version = bfd_getb32 (buf + 12); 565 header->timestamp = bfd_getb32 (buf + 16); 566 header->old_definition_version = bfd_getb32 (buf + 20); 567 header->old_implementation_version = bfd_getb32 (buf + 24); 568 header->current_version = bfd_getb32 (buf + 28); 569 header->section_count = bfd_getb32 (buf + 32) + 1; 570 header->instantiated_section_count = bfd_getb32 (buf + 34); 571 header->reserved = bfd_getb32 (buf + 36); 572 573 return 0; 574 } 575 576 static const bfd_target * 577 bfd_pef_object_p (bfd *abfd) 578 { 579 struct bfd_preserve preserve; 580 bfd_pef_header header; 581 582 preserve.marker = NULL; 583 if (bfd_pef_read_header (abfd, &header) != 0) 584 goto wrong; 585 586 if (header.tag1 != BFD_PEF_TAG1 || header.tag2 != BFD_PEF_TAG2) 587 goto wrong; 588 589 preserve.marker = bfd_zalloc (abfd, sizeof (bfd_pef_data_struct)); 590 if (preserve.marker == NULL 591 || !bfd_preserve_save (abfd, &preserve)) 592 goto fail; 593 594 if (bfd_pef_scan (abfd, &header, 595 (bfd_pef_data_struct *) preserve.marker) != 0) 596 goto wrong; 597 598 bfd_preserve_finish (abfd, &preserve); 599 return abfd->xvec; 600 601 wrong: 602 bfd_set_error (bfd_error_wrong_format); 603 604 fail: 605 if (preserve.marker != NULL) 606 bfd_preserve_restore (abfd, &preserve); 607 return NULL; 608 } 609 610 static int 611 bfd_pef_parse_traceback_tables (bfd *abfd, 612 asection *sec, 613 unsigned char *buf, 614 size_t len, 615 long *nsym, 616 asymbol **csym) 617 { 618 char *name; 619 620 asymbol function; 621 asymbol traceback; 622 623 const char *const tbprefix = "__traceback_"; 624 size_t tbnamelen; 625 626 size_t pos = 0; 627 unsigned long count = 0; 628 int ret; 629 630 for (;;) 631 { 632 /* We're reading symbols two at a time. */ 633 if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL))) 634 break; 635 636 pos += 3; 637 pos -= (pos % 4); 638 639 while ((pos + 4) <= len) 640 { 641 if (bfd_getb32 (buf + pos) == 0) 642 break; 643 pos += 4; 644 } 645 646 if ((pos + 4) > len) 647 break; 648 649 ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4, 650 &function, 0); 651 if (ret < 0) 652 { 653 /* Skip over 0x0L to advance to next possible traceback table. */ 654 pos += 4; 655 continue; 656 } 657 658 BFD_ASSERT (function.name != NULL); 659 660 /* Don't bother to compute the name if we are just 661 counting symbols. */ 662 if (csym) 663 { 664 tbnamelen = strlen (tbprefix) + strlen (function.name); 665 name = bfd_alloc (abfd, tbnamelen + 1); 666 if (name == NULL) 667 { 668 bfd_release (abfd, (void *) function.name); 669 function.name = NULL; 670 break; 671 } 672 snprintf (name, tbnamelen + 1, "%s%s", tbprefix, function.name); 673 traceback.name = name; 674 traceback.value = pos; 675 traceback.the_bfd = abfd; 676 traceback.section = sec; 677 traceback.flags = 0; 678 traceback.udata.i = ret; 679 680 *(csym[count]) = function; 681 *(csym[count + 1]) = traceback; 682 } 683 684 pos += ret; 685 count += 2; 686 } 687 688 *nsym = count; 689 return 0; 690 } 691 692 static int 693 bfd_pef_parse_function_stub (bfd *abfd ATTRIBUTE_UNUSED, 694 unsigned char *buf, 695 size_t len, 696 unsigned long *offset) 697 { 698 BFD_ASSERT (len == 24); 699 700 if ((bfd_getb32 (buf) & 0xffff0000) != 0x81820000) 701 return -1; 702 if (bfd_getb32 (buf + 4) != 0x90410014) 703 return -1; 704 if (bfd_getb32 (buf + 8) != 0x800c0000) 705 return -1; 706 if (bfd_getb32 (buf + 12) != 0x804c0004) 707 return -1; 708 if (bfd_getb32 (buf + 16) != 0x7c0903a6) 709 return -1; 710 if (bfd_getb32 (buf + 20) != 0x4e800420) 711 return -1; 712 713 if (offset != NULL) 714 *offset = (bfd_getb32 (buf) & 0x0000ffff) / 4; 715 716 return 0; 717 } 718 719 static int 720 bfd_pef_parse_function_stubs (bfd *abfd, 721 asection *codesec, 722 unsigned char *codebuf, 723 size_t codelen, 724 unsigned char *loaderbuf, 725 size_t loaderlen, 726 unsigned long *nsym, 727 asymbol **csym) 728 { 729 const char *const sprefix = "__stub_"; 730 731 size_t codepos = 0; 732 unsigned long count = 0; 733 734 bfd_pef_loader_header header; 735 bfd_pef_imported_library *libraries = NULL; 736 bfd_pef_imported_symbol *imports = NULL; 737 738 unsigned long i; 739 int ret; 740 741 if (loaderlen < 56) 742 goto error; 743 744 ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header); 745 if (ret < 0) 746 goto error; 747 748 libraries = bfd_malloc 749 (header.imported_library_count * sizeof (bfd_pef_imported_library)); 750 imports = bfd_malloc 751 (header.total_imported_symbol_count * sizeof (bfd_pef_imported_symbol)); 752 753 if (loaderlen < (56 + (header.imported_library_count * 24))) 754 goto error; 755 for (i = 0; i < header.imported_library_count; i++) 756 { 757 ret = bfd_pef_parse_imported_library 758 (abfd, loaderbuf + 56 + (i * 24), 24, &libraries[i]); 759 if (ret < 0) 760 goto error; 761 } 762 763 if (loaderlen < (56 + (header.imported_library_count * 24) 764 + (header.total_imported_symbol_count * 4))) 765 goto error; 766 for (i = 0; i < header.total_imported_symbol_count; i++) 767 { 768 ret = (bfd_pef_parse_imported_symbol 769 (abfd, 770 loaderbuf + 56 + (header.imported_library_count * 24) + (i * 4), 771 4, &imports[i])); 772 if (ret < 0) 773 goto error; 774 } 775 776 codepos = 0; 777 778 for (;;) 779 { 780 asymbol sym; 781 const char *symname; 782 char *name; 783 unsigned long index; 784 int ret; 785 786 if (csym && (csym[count] == NULL)) 787 break; 788 789 codepos += 3; 790 codepos -= (codepos % 4); 791 792 while ((codepos + 4) <= codelen) 793 { 794 if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000) 795 break; 796 codepos += 4; 797 } 798 799 if ((codepos + 4) > codelen) 800 break; 801 802 ret = bfd_pef_parse_function_stub (abfd, codebuf + codepos, 24, &index); 803 if (ret < 0) 804 { 805 codepos += 24; 806 continue; 807 } 808 809 if (index >= header.total_imported_symbol_count) 810 { 811 codepos += 24; 812 continue; 813 } 814 815 { 816 size_t max, namelen; 817 const char *s; 818 819 if (loaderlen < (header.loader_strings_offset + imports[index].name)) 820 goto error; 821 822 max = loaderlen - (header.loader_strings_offset + imports[index].name); 823 symname = (char *) loaderbuf; 824 symname += header.loader_strings_offset + imports[index].name; 825 namelen = 0; 826 for (s = symname; s < (symname + max); s++) 827 { 828 if (*s == '\0') 829 break; 830 if (! ISPRINT (*s)) 831 goto error; 832 namelen++; 833 } 834 if (*s != '\0') 835 goto error; 836 837 name = bfd_alloc (abfd, strlen (sprefix) + namelen + 1); 838 if (name == NULL) 839 break; 840 841 snprintf (name, strlen (sprefix) + namelen + 1, "%s%s", 842 sprefix, symname); 843 sym.name = name; 844 } 845 846 sym.value = codepos; 847 sym.the_bfd = abfd; 848 sym.section = codesec; 849 sym.flags = 0; 850 sym.udata.i = 0; 851 852 codepos += 24; 853 854 if (csym != NULL) 855 *(csym[count]) = sym; 856 857 count++; 858 } 859 860 goto end; 861 862 end: 863 if (libraries != NULL) 864 free (libraries); 865 if (imports != NULL) 866 free (imports); 867 *nsym = count; 868 return 0; 869 870 error: 871 if (libraries != NULL) 872 free (libraries); 873 if (imports != NULL) 874 free (imports); 875 *nsym = count; 876 return -1; 877 } 878 879 static long 880 bfd_pef_parse_symbols (bfd *abfd, asymbol **csym) 881 { 882 unsigned long count = 0; 883 884 asection *codesec = NULL; 885 unsigned char *codebuf = NULL; 886 size_t codelen = 0; 887 888 asection *loadersec = NULL; 889 unsigned char *loaderbuf = NULL; 890 size_t loaderlen = 0; 891 892 codesec = bfd_get_section_by_name (abfd, "code"); 893 if (codesec != NULL) 894 { 895 codelen = codesec->size; 896 codebuf = bfd_malloc (codelen); 897 if (bfd_seek (abfd, codesec->filepos, SEEK_SET) < 0) 898 goto end; 899 if (bfd_bread ((void *) codebuf, codelen, abfd) != codelen) 900 goto end; 901 } 902 903 loadersec = bfd_get_section_by_name (abfd, "loader"); 904 if (loadersec != NULL) 905 { 906 loaderlen = loadersec->size; 907 loaderbuf = bfd_malloc (loaderlen); 908 if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0) 909 goto end; 910 if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen) 911 goto end; 912 } 913 914 count = 0; 915 if (codesec != NULL) 916 { 917 long ncount = 0; 918 bfd_pef_parse_traceback_tables (abfd, codesec, codebuf, codelen, 919 &ncount, csym); 920 count += ncount; 921 } 922 923 if ((codesec != NULL) && (loadersec != NULL)) 924 { 925 unsigned long ncount = 0; 926 bfd_pef_parse_function_stubs 927 (abfd, codesec, codebuf, codelen, loaderbuf, loaderlen, &ncount, 928 (csym != NULL) ? (csym + count) : NULL); 929 count += ncount; 930 } 931 932 if (csym != NULL) 933 csym[count] = NULL; 934 935 end: 936 if (codebuf != NULL) 937 free (codebuf); 938 939 if (loaderbuf != NULL) 940 free (loaderbuf); 941 942 return count; 943 } 944 945 static long 946 bfd_pef_count_symbols (bfd *abfd) 947 { 948 return bfd_pef_parse_symbols (abfd, NULL); 949 } 950 951 static long 952 bfd_pef_get_symtab_upper_bound (bfd *abfd) 953 { 954 long nsyms = bfd_pef_count_symbols (abfd); 955 956 if (nsyms < 0) 957 return nsyms; 958 return ((nsyms + 1) * sizeof (asymbol *)); 959 } 960 961 static long 962 bfd_pef_canonicalize_symtab (bfd *abfd, asymbol **alocation) 963 { 964 long i; 965 asymbol *syms; 966 long ret; 967 long nsyms = bfd_pef_count_symbols (abfd); 968 969 if (nsyms < 0) 970 return nsyms; 971 972 syms = bfd_alloc (abfd, nsyms * sizeof (asymbol)); 973 if (syms == NULL) 974 return -1; 975 976 for (i = 0; i < nsyms; i++) 977 alocation[i] = &syms[i]; 978 979 alocation[nsyms] = NULL; 980 981 ret = bfd_pef_parse_symbols (abfd, alocation); 982 if (ret != nsyms) 983 return 0; 984 985 return ret; 986 } 987 988 #define bfd_pef_make_empty_symbol _bfd_generic_make_empty_symbol 989 990 static void 991 bfd_pef_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, 992 asymbol *symbol, 993 symbol_info *ret) 994 { 995 bfd_symbol_info (symbol, ret); 996 } 997 998 static int 999 bfd_pef_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, 1000 struct bfd_link_info *info ATTRIBUTE_UNUSED) 1001 { 1002 return 0; 1003 } 1004 1005 const bfd_target pef_vec = 1006 { 1007 "pef", /* Name. */ 1008 bfd_target_pef_flavour, /* Flavour. */ 1009 BFD_ENDIAN_BIG, /* Byteorder. */ 1010 BFD_ENDIAN_BIG, /* Header_byteorder. */ 1011 (HAS_RELOC | EXEC_P | /* Object flags. */ 1012 HAS_LINENO | HAS_DEBUG | 1013 HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), 1014 (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA 1015 | SEC_ROM | SEC_HAS_CONTENTS), /* Section_flags. */ 1016 0, /* Symbol_leading_char. */ 1017 ' ', /* AR_pad_char. */ 1018 16, /* AR_max_namelen. */ 1019 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 1020 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 1021 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ 1022 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 1023 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 1024 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ 1025 { /* bfd_check_format. */ 1026 _bfd_dummy_target, 1027 bfd_pef_object_p, /* bfd_check_format. */ 1028 _bfd_dummy_target, 1029 _bfd_dummy_target, 1030 }, 1031 { /* bfd_set_format. */ 1032 bfd_false, 1033 bfd_pef_mkobject, 1034 bfd_false, 1035 bfd_false, 1036 }, 1037 { /* bfd_write_contents. */ 1038 bfd_false, 1039 bfd_true, 1040 bfd_false, 1041 bfd_false, 1042 }, 1043 1044 BFD_JUMP_TABLE_GENERIC (bfd_pef), 1045 BFD_JUMP_TABLE_COPY (_bfd_generic), 1046 BFD_JUMP_TABLE_CORE (_bfd_nocore), 1047 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 1048 BFD_JUMP_TABLE_SYMBOLS (bfd_pef), 1049 BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 1050 BFD_JUMP_TABLE_WRITE (bfd_pef), 1051 BFD_JUMP_TABLE_LINK (bfd_pef), 1052 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 1053 1054 NULL, 1055 1056 NULL 1057 }; 1058 1059 #define bfd_pef_xlib_close_and_cleanup _bfd_generic_close_and_cleanup 1060 #define bfd_pef_xlib_bfd_free_cached_info _bfd_generic_bfd_free_cached_info 1061 #define bfd_pef_xlib_new_section_hook _bfd_generic_new_section_hook 1062 #define bfd_pef_xlib_get_section_contents _bfd_generic_get_section_contents 1063 #define bfd_pef_xlib_set_section_contents _bfd_generic_set_section_contents 1064 #define bfd_pef_xlib_get_section_contents_in_window _bfd_generic_get_section_contents_in_window 1065 #define bfd_pef_xlib_set_section_contents_in_window _bfd_generic_set_section_contents_in_window 1066 1067 static int 1068 bfd_pef_xlib_read_header (bfd *abfd, bfd_pef_xlib_header *header) 1069 { 1070 unsigned char buf[76]; 1071 1072 bfd_seek (abfd, 0, SEEK_SET); 1073 1074 if (bfd_bread ((void *) buf, 76, abfd) != 76) 1075 return -1; 1076 1077 header->tag1 = bfd_getb32 (buf); 1078 header->tag2 = bfd_getb32 (buf + 4); 1079 header->current_format = bfd_getb32 (buf + 8); 1080 header->container_strings_offset = bfd_getb32 (buf + 12); 1081 header->export_hash_offset = bfd_getb32 (buf + 16); 1082 header->export_key_offset = bfd_getb32 (buf + 20); 1083 header->export_symbol_offset = bfd_getb32 (buf + 24); 1084 header->export_names_offset = bfd_getb32 (buf + 28); 1085 header->export_hash_table_power = bfd_getb32 (buf + 32); 1086 header->exported_symbol_count = bfd_getb32 (buf + 36); 1087 header->frag_name_offset = bfd_getb32 (buf + 40); 1088 header->frag_name_length = bfd_getb32 (buf + 44); 1089 header->dylib_path_offset = bfd_getb32 (buf + 48); 1090 header->dylib_path_length = bfd_getb32 (buf + 52); 1091 header->cpu_family = bfd_getb32 (buf + 56); 1092 header->cpu_model = bfd_getb32 (buf + 60); 1093 header->date_time_stamp = bfd_getb32 (buf + 64); 1094 header->current_version = bfd_getb32 (buf + 68); 1095 header->old_definition_version = bfd_getb32 (buf + 72); 1096 header->old_implementation_version = bfd_getb32 (buf + 76); 1097 1098 return 0; 1099 } 1100 1101 static int 1102 bfd_pef_xlib_scan (bfd *abfd, bfd_pef_xlib_header *header) 1103 { 1104 bfd_pef_xlib_data_struct *mdata = NULL; 1105 1106 mdata = bfd_alloc (abfd, sizeof (* mdata)); 1107 if (mdata == NULL) 1108 return -1; 1109 1110 mdata->header = *header; 1111 1112 abfd->flags = (abfd->xvec->object_flags 1113 | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS))); 1114 1115 abfd->tdata.pef_xlib_data = mdata; 1116 1117 return 0; 1118 } 1119 1120 static const bfd_target * 1121 bfd_pef_xlib_object_p (bfd *abfd) 1122 { 1123 struct bfd_preserve preserve; 1124 bfd_pef_xlib_header header; 1125 1126 if (bfd_pef_xlib_read_header (abfd, &header) != 0) 1127 { 1128 bfd_set_error (bfd_error_wrong_format); 1129 return NULL; 1130 } 1131 1132 if ((header.tag1 != BFD_PEF_XLIB_TAG1) 1133 || ((header.tag2 != BFD_PEF_VLIB_TAG2) 1134 && (header.tag2 != BFD_PEF_BLIB_TAG2))) 1135 { 1136 bfd_set_error (bfd_error_wrong_format); 1137 return NULL; 1138 } 1139 1140 if (! bfd_preserve_save (abfd, &preserve)) 1141 { 1142 bfd_set_error (bfd_error_wrong_format); 1143 return NULL; 1144 } 1145 1146 if (bfd_pef_xlib_scan (abfd, &header) != 0) 1147 { 1148 bfd_preserve_restore (abfd, &preserve); 1149 bfd_set_error (bfd_error_wrong_format); 1150 return NULL; 1151 } 1152 1153 bfd_preserve_finish (abfd, &preserve); 1154 return abfd->xvec; 1155 } 1156 1157 const bfd_target pef_xlib_vec = 1158 { 1159 "pef-xlib", /* Name. */ 1160 bfd_target_pef_xlib_flavour, /* Flavour. */ 1161 BFD_ENDIAN_BIG, /* Byteorder */ 1162 BFD_ENDIAN_BIG, /* Header_byteorder. */ 1163 (HAS_RELOC | EXEC_P | /* Object flags. */ 1164 HAS_LINENO | HAS_DEBUG | 1165 HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), 1166 (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA 1167 | SEC_ROM | SEC_HAS_CONTENTS),/* Section_flags. */ 1168 0, /* Symbol_leading_char. */ 1169 ' ', /* AR_pad_char. */ 1170 16, /* AR_max_namelen. */ 1171 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 1172 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 1173 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ 1174 bfd_getb64, bfd_getb_signed_64, bfd_putb64, 1175 bfd_getb32, bfd_getb_signed_32, bfd_putb32, 1176 bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ 1177 { /* bfd_check_format. */ 1178 _bfd_dummy_target, 1179 bfd_pef_xlib_object_p, /* bfd_check_format. */ 1180 _bfd_dummy_target, 1181 _bfd_dummy_target, 1182 }, 1183 { /* bfd_set_format. */ 1184 bfd_false, 1185 bfd_pef_mkobject, 1186 bfd_false, 1187 bfd_false, 1188 }, 1189 { /* bfd_write_contents. */ 1190 bfd_false, 1191 bfd_true, 1192 bfd_false, 1193 bfd_false, 1194 }, 1195 1196 BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib), 1197 BFD_JUMP_TABLE_COPY (_bfd_generic), 1198 BFD_JUMP_TABLE_CORE (_bfd_nocore), 1199 BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 1200 BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols), 1201 BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 1202 BFD_JUMP_TABLE_WRITE (_bfd_nowrite), 1203 BFD_JUMP_TABLE_LINK (_bfd_nolink), 1204 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 1205 1206 NULL, 1207 1208 NULL 1209 }; 1210