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