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