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