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