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