Back to index

cell-binutils  2.17cvs20070401
pef.c
Go to the documentation of this file.
00001 /* PEF support for BFD.
00002    Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
00003    Free Software Foundation, Inc.
00004 
00005    This file is part of BFD, the Binary File Descriptor library.
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
00020 
00021 #include "safe-ctype.h"
00022 #include "pef.h"
00023 #include "pef-traceback.h"
00024 #include "bfd.h"
00025 #include "sysdep.h"
00026 #include "libbfd.h"
00027 #include "libiberty.h"
00028 
00029 #ifndef BFD_IO_FUNCS
00030 #define BFD_IO_FUNCS 0
00031 #endif
00032 
00033 #define bfd_pef_close_and_cleanup                   _bfd_generic_close_and_cleanup
00034 #define bfd_pef_bfd_free_cached_info                _bfd_generic_bfd_free_cached_info
00035 #define bfd_pef_new_section_hook                    _bfd_generic_new_section_hook
00036 #define bfd_pef_bfd_is_local_label_name             bfd_generic_is_local_label_name
00037 #define bfd_pef_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
00038 #define bfd_pef_get_lineno                          _bfd_nosymbols_get_lineno
00039 #define bfd_pef_find_nearest_line                   _bfd_nosymbols_find_nearest_line
00040 #define bfd_pef_find_inliner_info                   _bfd_nosymbols_find_inliner_info
00041 #define bfd_pef_bfd_make_debug_symbol               _bfd_nosymbols_bfd_make_debug_symbol
00042 #define bfd_pef_read_minisymbols                    _bfd_generic_read_minisymbols
00043 #define bfd_pef_minisymbol_to_symbol                _bfd_generic_minisymbol_to_symbol
00044 #define bfd_pef_set_arch_mach                       _bfd_generic_set_arch_mach
00045 #define bfd_pef_get_section_contents                _bfd_generic_get_section_contents
00046 #define bfd_pef_set_section_contents                _bfd_generic_set_section_contents
00047 #define bfd_pef_bfd_get_relocated_section_contents  bfd_generic_get_relocated_section_contents
00048 #define bfd_pef_bfd_relax_section                   bfd_generic_relax_section
00049 #define bfd_pef_bfd_gc_sections                     bfd_generic_gc_sections
00050 #define bfd_pef_bfd_merge_sections                  bfd_generic_merge_sections
00051 #define bfd_pef_bfd_is_group_section                 bfd_generic_is_group_section
00052 #define bfd_pef_bfd_discard_group                   bfd_generic_discard_group
00053 #define bfd_pef_section_already_linked                _bfd_generic_section_already_linked
00054 #define bfd_pef_bfd_link_hash_table_create          _bfd_generic_link_hash_table_create
00055 #define bfd_pef_bfd_link_hash_table_free            _bfd_generic_link_hash_table_free
00056 #define bfd_pef_bfd_link_add_symbols                _bfd_generic_link_add_symbols
00057 #define bfd_pef_bfd_link_just_syms                  _bfd_generic_link_just_syms
00058 #define bfd_pef_bfd_final_link                      _bfd_generic_final_link
00059 #define bfd_pef_bfd_link_split_section              _bfd_generic_link_split_section
00060 #define bfd_pef_get_section_contents_in_window      _bfd_generic_get_section_contents_in_window
00061 
00062 static int
00063 bfd_pef_parse_traceback_table (bfd *abfd,
00064                             asection *section,
00065                             unsigned char *buf,
00066                             size_t len,
00067                             size_t pos,
00068                             asymbol *sym,
00069                             FILE *file)
00070 {
00071   struct traceback_table table;
00072   size_t offset;
00073   const char *s;
00074   asymbol tmpsymbol;
00075 
00076   if (sym == NULL)
00077     sym = & tmpsymbol;
00078 
00079   sym->name = NULL;
00080   sym->value = 0;
00081   sym->the_bfd = abfd;
00082   sym->section = section;
00083   sym->flags = 0;
00084   sym->udata.i = 0;
00085 
00086   /* memcpy is fine since all fields are unsigned char.  */
00087   if ((pos + 8) > len)
00088     return -1;
00089   memcpy (&table, buf + pos, 8);
00090 
00091   /* Calling code relies on returned symbols having a name and
00092      correct offset.  */
00093   if ((table.lang != TB_C) && (table.lang != TB_CPLUSPLUS))
00094     return -1;
00095 
00096   if (! (table.flags2 & TB_NAME_PRESENT))
00097     return -1;
00098 
00099   if (! table.flags1 & TB_HAS_TBOFF)
00100     return -1;
00101 
00102   offset = 8;
00103 
00104   if ((table.flags5 & TB_FLOATPARAMS) || (table.fixedparams))
00105     offset += 4;
00106 
00107   if (table.flags1 & TB_HAS_TBOFF)
00108     {
00109       struct traceback_table_tboff off;
00110 
00111       if ((pos + offset + 4) > len)
00112        return -1;
00113       off.tb_offset = bfd_getb32 (buf + pos + offset);
00114       offset += 4;
00115 
00116       /* Need to subtract 4 because the offset includes the 0x0L
00117         preceding the table.  */
00118       if (file != NULL)
00119        fprintf (file, " [offset = 0x%lx]", off.tb_offset);
00120 
00121       if ((file == NULL) && ((off.tb_offset + 4) > (pos + offset)))
00122        return -1;
00123 
00124       sym->value = pos - off.tb_offset - 4;
00125     }
00126 
00127   if (table.flags2 & TB_INT_HNDL)
00128     offset += 4;
00129 
00130   if (table.flags1 & TB_HAS_CTL)
00131     {
00132       struct traceback_table_anchors anchors;
00133 
00134       if ((pos + offset + 4) > len)
00135        return -1;
00136       anchors.ctl_info = bfd_getb32 (buf + pos + offset);
00137       offset += 4;
00138 
00139       if (anchors.ctl_info > 1024)
00140        return -1;
00141 
00142       offset += anchors.ctl_info * 4;
00143     }
00144 
00145   if (table.flags2 & TB_NAME_PRESENT)
00146     {
00147       struct traceback_table_routine name;
00148       char *namebuf;
00149 
00150       if ((pos + offset + 2) > len)
00151        return -1;
00152       name.name_len = bfd_getb16 (buf + pos + offset);
00153       offset += 2;
00154 
00155       if (name.name_len > 4096)
00156        return -1;
00157 
00158       if ((pos + offset + name.name_len) > len)
00159        return -1;
00160 
00161       namebuf = bfd_alloc (abfd, name.name_len + 1);
00162       if (namebuf == NULL)
00163        return -1;
00164 
00165       memcpy (namebuf, buf + pos + offset, name.name_len);
00166       namebuf[name.name_len] = '\0';
00167 
00168       /* Strip leading period inserted by compiler.  */
00169       if (namebuf[0] == '.')
00170        memmove (namebuf, namebuf + 1, name.name_len + 1);
00171 
00172       sym->name = namebuf;
00173 
00174       for (s = sym->name; (*s != '\0'); s++)
00175        if (! ISPRINT (*s))
00176          return -1;
00177 
00178       offset += name.name_len;
00179     }
00180 
00181   if (table.flags2 & TB_USES_ALLOCA)
00182     offset += 4;
00183 
00184   if (table.flags4 & TB_HAS_VEC_INFO)
00185     offset += 4;
00186 
00187   if (file != NULL)
00188     fprintf (file, " [length = 0x%lx]", (long) offset);
00189 
00190   return offset;
00191 }
00192 
00193 static void
00194 bfd_pef_print_symbol (bfd *abfd,
00195                     void * afile,
00196                     asymbol *symbol,
00197                     bfd_print_symbol_type how)
00198 {
00199   FILE *file = (FILE *) afile;
00200 
00201   switch (how)
00202     {
00203     case bfd_print_symbol_name:
00204       fprintf (file, "%s", symbol->name);
00205       break;
00206     default:
00207       bfd_print_symbol_vandf (abfd, (void *) file, symbol);
00208       fprintf (file, " %-5s %s", symbol->section->name, symbol->name);
00209       if (CONST_STRNEQ (symbol->name, "__traceback_"))
00210        {
00211          unsigned char *buf = alloca (symbol->udata.i);
00212          size_t offset = symbol->value + 4;
00213          size_t len = symbol->udata.i;
00214          int ret;
00215 
00216          bfd_get_section_contents (abfd, symbol->section, buf, offset, len);
00217          ret = bfd_pef_parse_traceback_table (abfd, symbol->section, buf,
00218                                           len, 0, NULL, file);
00219          if (ret < 0)
00220            fprintf (file, " [ERROR]");
00221        }
00222     }
00223 }
00224 
00225 static void
00226 bfd_pef_convert_architecture (unsigned long architecture,
00227                            enum bfd_architecture *type,
00228                            unsigned long *subtype)
00229 {
00230   const unsigned long ARCH_POWERPC = 0x70777063; /* 'pwpc'.  */
00231   const unsigned long ARCH_M68K = 0x6d36386b; /* 'm68k'.  */
00232 
00233   *subtype = bfd_arch_unknown;
00234   *type = bfd_arch_unknown;
00235 
00236   if (architecture == ARCH_POWERPC)
00237     *type = bfd_arch_powerpc;
00238   else if (architecture == ARCH_M68K)
00239     *type = bfd_arch_m68k;
00240 }
00241 
00242 static bfd_boolean
00243 bfd_pef_mkobject (bfd *abfd ATTRIBUTE_UNUSED)
00244 {
00245   return TRUE;
00246 }
00247 
00248 static const char *bfd_pef_section_name (bfd_pef_section *section)
00249 {
00250   switch (section->section_kind)
00251     {
00252     case BFD_PEF_SECTION_CODE: return "code";
00253     case BFD_PEF_SECTION_UNPACKED_DATA: return "unpacked-data";
00254     case BFD_PEF_SECTION_PACKED_DATA: return "packed-data";
00255     case BFD_PEF_SECTION_CONSTANT: return "constant";
00256     case BFD_PEF_SECTION_LOADER: return "loader";
00257     case BFD_PEF_SECTION_DEBUG: return "debug";
00258     case BFD_PEF_SECTION_EXEC_DATA: return "exec-data";
00259     case BFD_PEF_SECTION_EXCEPTION: return "exception";
00260     case BFD_PEF_SECTION_TRACEBACK: return "traceback";
00261     default: return "unknown";
00262     }
00263 }
00264 
00265 static unsigned long bfd_pef_section_flags (bfd_pef_section *section)
00266 {
00267   switch (section->section_kind)
00268     {
00269     case BFD_PEF_SECTION_CODE:
00270       return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_CODE;
00271     case BFD_PEF_SECTION_UNPACKED_DATA:
00272     case BFD_PEF_SECTION_PACKED_DATA:
00273     case BFD_PEF_SECTION_CONSTANT:
00274     case BFD_PEF_SECTION_LOADER:
00275     case BFD_PEF_SECTION_DEBUG:
00276     case BFD_PEF_SECTION_EXEC_DATA:
00277     case BFD_PEF_SECTION_EXCEPTION:
00278     case BFD_PEF_SECTION_TRACEBACK:
00279     default:
00280       return SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
00281     }
00282 }
00283 
00284 static asection *
00285 bfd_pef_make_bfd_section (bfd *abfd, bfd_pef_section *section)
00286 {
00287   asection *bfdsec;
00288   const char *name = bfd_pef_section_name (section);
00289 
00290   bfdsec = bfd_make_section_anyway (abfd, name);
00291   if (bfdsec == NULL)
00292     return NULL;
00293 
00294   bfdsec->vma = section->default_address + section->container_offset;
00295   bfdsec->lma = section->default_address + section->container_offset;
00296   bfdsec->size = section->container_length;
00297   bfdsec->filepos = section->container_offset;
00298   bfdsec->alignment_power = section->alignment;
00299 
00300   bfdsec->flags = bfd_pef_section_flags (section);
00301 
00302   return bfdsec;
00303 }
00304 
00305 int
00306 bfd_pef_parse_loader_header (bfd *abfd ATTRIBUTE_UNUSED,
00307                           unsigned char *buf,
00308                           size_t len,
00309                           bfd_pef_loader_header *header)
00310 {
00311   BFD_ASSERT (len == 56);
00312 
00313   header->main_section = bfd_getb32 (buf);
00314   header->main_offset = bfd_getb32 (buf + 4);
00315   header->init_section = bfd_getb32 (buf + 8);
00316   header->init_offset = bfd_getb32 (buf + 12);
00317   header->term_section = bfd_getb32 (buf + 16);
00318   header->term_offset = bfd_getb32 (buf + 20);
00319   header->imported_library_count = bfd_getb32 (buf + 24);
00320   header->total_imported_symbol_count = bfd_getb32 (buf + 28);
00321   header->reloc_section_count = bfd_getb32 (buf + 32);
00322   header->reloc_instr_offset = bfd_getb32 (buf + 36);
00323   header->loader_strings_offset = bfd_getb32 (buf + 40);
00324   header->export_hash_offset = bfd_getb32 (buf + 44);
00325   header->export_hash_table_power = bfd_getb32 (buf + 48);
00326   header->exported_symbol_count = bfd_getb32 (buf + 52);
00327 
00328   return 0;
00329 }
00330 
00331 int
00332 bfd_pef_parse_imported_library (bfd *abfd ATTRIBUTE_UNUSED,
00333                             unsigned char *buf,
00334                             size_t len,
00335                             bfd_pef_imported_library *header)
00336 {
00337   BFD_ASSERT (len == 24);
00338 
00339   header->name_offset = bfd_getb32 (buf);
00340   header->old_implementation_version = bfd_getb32 (buf + 4);
00341   header->current_version = bfd_getb32 (buf + 8);
00342   header->imported_symbol_count = bfd_getb32 (buf + 12);
00343   header->first_imported_symbol = bfd_getb32 (buf + 16);
00344   header->options = buf[20];
00345   header->reserved_a = buf[21];
00346   header->reserved_b = bfd_getb16 (buf + 22);
00347 
00348   return 0;
00349 }
00350 
00351 int
00352 bfd_pef_parse_imported_symbol (bfd *abfd ATTRIBUTE_UNUSED,
00353                             unsigned char *buf,
00354                             size_t len,
00355                             bfd_pef_imported_symbol *symbol)
00356 {
00357   unsigned long value;
00358 
00359   BFD_ASSERT (len == 4);
00360 
00361   value = bfd_getb32 (buf);
00362   symbol->class = value >> 24;
00363   symbol->name = value & 0x00ffffff;
00364 
00365   return 0;
00366 }
00367 
00368 int
00369 bfd_pef_scan_section (bfd *abfd, bfd_pef_section *section)
00370 {
00371   unsigned char buf[28];
00372 
00373   bfd_seek (abfd, section->header_offset, SEEK_SET);
00374   if (bfd_bread ((void *) buf, 28, abfd) != 28)
00375     return -1;
00376 
00377   section->name_offset = bfd_h_get_32 (abfd, buf);
00378   section->default_address = bfd_h_get_32 (abfd, buf + 4);
00379   section->total_length = bfd_h_get_32 (abfd, buf + 8);
00380   section->unpacked_length = bfd_h_get_32 (abfd, buf + 12);
00381   section->container_length = bfd_h_get_32 (abfd, buf + 16);
00382   section->container_offset = bfd_h_get_32 (abfd, buf + 20);
00383   section->section_kind = buf[24];
00384   section->share_kind = buf[25];
00385   section->alignment = buf[26];
00386   section->reserved = buf[27];
00387 
00388   section->bfd_section = bfd_pef_make_bfd_section (abfd, section);
00389   if (section->bfd_section == NULL)
00390     return -1;
00391 
00392   return 0;
00393 }
00394 
00395 void
00396 bfd_pef_print_loader_header (bfd *abfd ATTRIBUTE_UNUSED,
00397                           bfd_pef_loader_header *header,
00398                           FILE *file)
00399 {
00400   fprintf (file, "main_section: %ld\n", header->main_section);
00401   fprintf (file, "main_offset: %lu\n", header->main_offset);
00402   fprintf (file, "init_section: %ld\n", header->init_section);
00403   fprintf (file, "init_offset: %lu\n", header->init_offset);
00404   fprintf (file, "term_section: %ld\n", header->term_section);
00405   fprintf (file, "term_offset: %lu\n", header->term_offset);
00406   fprintf (file, "imported_library_count: %lu\n",
00407           header->imported_library_count);
00408   fprintf (file, "total_imported_symbol_count: %lu\n",
00409           header->total_imported_symbol_count);
00410   fprintf (file, "reloc_section_count: %lu\n", header->reloc_section_count);
00411   fprintf (file, "reloc_instr_offset: %lu\n", header->reloc_instr_offset);
00412   fprintf (file, "loader_strings_offset: %lu\n",
00413           header->loader_strings_offset);
00414   fprintf (file, "export_hash_offset: %lu\n", header->export_hash_offset);
00415   fprintf (file, "export_hash_table_power: %lu\n",
00416           header->export_hash_table_power);
00417   fprintf (file, "exported_symbol_count: %lu\n",
00418           header->exported_symbol_count);
00419 }
00420 
00421 int
00422 bfd_pef_print_loader_section (bfd *abfd, FILE *file)
00423 {
00424   bfd_pef_loader_header header;
00425   asection *loadersec = NULL;
00426   unsigned char *loaderbuf = NULL;
00427   size_t loaderlen = 0;
00428 
00429   loadersec = bfd_get_section_by_name (abfd, "loader");
00430   if (loadersec == NULL)
00431     return -1;
00432 
00433   loaderlen = loadersec->size;
00434   loaderbuf = bfd_malloc (loaderlen);
00435 
00436   if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0
00437       || bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen
00438       || loaderlen < 56
00439       || bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header) < 0)
00440     {
00441       free (loaderbuf);
00442       return -1;
00443     }
00444 
00445   bfd_pef_print_loader_header (abfd, &header, file);
00446   return 0;
00447 }
00448 
00449 int
00450 bfd_pef_scan_start_address (bfd *abfd)
00451 {
00452   bfd_pef_loader_header header;
00453   asection *section;
00454 
00455   asection *loadersec = NULL;
00456   unsigned char *loaderbuf = NULL;
00457   size_t loaderlen = 0;
00458   int ret;
00459 
00460   loadersec = bfd_get_section_by_name (abfd, "loader");
00461   if (loadersec == NULL)
00462     goto end;
00463 
00464   loaderlen = loadersec->size;
00465   loaderbuf = bfd_malloc (loaderlen);
00466   if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
00467     goto error;
00468   if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
00469     goto error;
00470 
00471   if (loaderlen < 56)
00472     goto error;
00473   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
00474   if (ret < 0)
00475     goto error;
00476 
00477   if (header.main_section < 0)
00478     goto end;
00479 
00480   for (section = abfd->sections; section != NULL; section = section->next)
00481     if ((section->index + 1) == header.main_section)
00482       break;
00483 
00484   if (section == NULL)
00485     goto error;
00486 
00487   abfd->start_address = section->vma + header.main_offset;
00488 
00489  end:
00490   if (loaderbuf != NULL)
00491     free (loaderbuf);
00492   return 0;
00493 
00494  error:
00495   if (loaderbuf != NULL)
00496     free (loaderbuf);
00497   return -1;
00498 }
00499 
00500 int
00501 bfd_pef_scan (abfd, header, mdata)
00502      bfd *abfd;
00503      bfd_pef_header *header;
00504      bfd_pef_data_struct *mdata;
00505 {
00506   unsigned int i;
00507   enum bfd_architecture cputype;
00508   unsigned long cpusubtype;
00509 
00510   mdata->header = *header;
00511 
00512   bfd_pef_convert_architecture (header->architecture, &cputype, &cpusubtype);
00513   if (cputype == bfd_arch_unknown)
00514     {
00515       fprintf (stderr, "bfd_pef_scan: unknown architecture 0x%lx\n",
00516               header->architecture);
00517       return -1;
00518     }
00519   bfd_set_arch_mach (abfd, cputype, cpusubtype);
00520 
00521   mdata->header = *header;
00522 
00523   abfd->flags = (abfd->xvec->object_flags
00524                | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
00525 
00526   if (header->section_count != 0)
00527     {
00528       mdata->sections = bfd_alloc (abfd, header->section_count * sizeof (bfd_pef_section));
00529 
00530       if (mdata->sections == NULL)
00531        return -1;
00532 
00533       for (i = 0; i < header->section_count; i++)
00534        {
00535          bfd_pef_section *cur = &mdata->sections[i];
00536          cur->header_offset = 40 + (i * 28);
00537          if (bfd_pef_scan_section (abfd, cur) < 0)
00538            return -1;
00539        }
00540     }
00541 
00542   if (bfd_pef_scan_start_address (abfd) < 0)
00543     return -1;
00544 
00545   abfd->tdata.pef_data = mdata;
00546 
00547   return 0;
00548 }
00549 
00550 static int
00551 bfd_pef_read_header (bfd *abfd, bfd_pef_header *header)
00552 {
00553   unsigned char buf[40];
00554 
00555   bfd_seek (abfd, 0, SEEK_SET);
00556 
00557   if (bfd_bread ((void *) buf, 40, abfd) != 40)
00558     return -1;
00559 
00560   header->tag1 = bfd_getb32 (buf);
00561   header->tag2 = bfd_getb32 (buf + 4);
00562   header->architecture = bfd_getb32 (buf + 8);
00563   header->format_version = bfd_getb32 (buf + 12);
00564   header->timestamp = bfd_getb32 (buf + 16);
00565   header->old_definition_version = bfd_getb32 (buf + 20);
00566   header->old_implementation_version = bfd_getb32 (buf + 24);
00567   header->current_version = bfd_getb32 (buf + 28);
00568   header->section_count = bfd_getb32 (buf + 32) + 1;
00569   header->instantiated_section_count = bfd_getb32 (buf + 34);
00570   header->reserved = bfd_getb32 (buf + 36);
00571 
00572   return 0;
00573 }
00574 
00575 static const bfd_target *
00576 bfd_pef_object_p (bfd *abfd)
00577 {
00578   struct bfd_preserve preserve;
00579   bfd_pef_header header;
00580 
00581   preserve.marker = NULL;
00582   if (bfd_pef_read_header (abfd, &header) != 0)
00583     goto wrong;
00584 
00585   if (header.tag1 != BFD_PEF_TAG1 || header.tag2 != BFD_PEF_TAG2)
00586     goto wrong;
00587 
00588   preserve.marker = bfd_zalloc (abfd, sizeof (bfd_pef_data_struct));
00589   if (preserve.marker == NULL
00590       || !bfd_preserve_save (abfd, &preserve))
00591     goto fail;
00592 
00593   if (bfd_pef_scan (abfd, &header,
00594                   (bfd_pef_data_struct *) preserve.marker) != 0)
00595     goto wrong;
00596 
00597   bfd_preserve_finish (abfd, &preserve);
00598   return abfd->xvec;
00599 
00600  wrong:
00601   bfd_set_error (bfd_error_wrong_format);
00602 
00603  fail:
00604   if (preserve.marker != NULL)
00605     bfd_preserve_restore (abfd, &preserve);
00606   return NULL;
00607 }
00608 
00609 static int
00610 bfd_pef_parse_traceback_tables (bfd *abfd,
00611                             asection *sec,
00612                             unsigned char *buf,
00613                             size_t len,
00614                             long *nsym,
00615                             asymbol **csym)
00616 {
00617   char *name;
00618 
00619   asymbol function;
00620   asymbol traceback;
00621 
00622   const char *const tbprefix = "__traceback_";
00623   size_t tbnamelen;
00624 
00625   size_t pos = 0;
00626   unsigned long count = 0;
00627   int ret;
00628 
00629   for (;;)
00630     {
00631       /* We're reading symbols two at a time.  */
00632       if (csym && ((csym[count] == NULL) || (csym[count + 1] == NULL)))
00633        break;
00634 
00635       pos += 3;
00636       pos -= (pos % 4);
00637 
00638       while ((pos + 4) <= len)
00639        {
00640          if (bfd_getb32 (buf + pos) == 0)
00641            break;
00642          pos += 4;
00643        }
00644 
00645       if ((pos + 4) > len)
00646        break;
00647 
00648       ret = bfd_pef_parse_traceback_table (abfd, sec, buf, len, pos + 4,
00649                                       &function, 0);
00650       if (ret < 0)
00651        {
00652          /* Skip over 0x0L to advance to next possible traceback table.  */
00653          pos += 4;
00654          continue;
00655        }
00656 
00657       BFD_ASSERT (function.name != NULL);
00658 
00659       /* Don't bother to compute the name if we are just
00660         counting symbols.  */
00661       if (csym)
00662        {
00663          tbnamelen = strlen (tbprefix) + strlen (function.name);
00664          name = bfd_alloc (abfd, tbnamelen + 1);
00665          if (name == NULL)
00666            {
00667              bfd_release (abfd, (void *) function.name);
00668              function.name = NULL;
00669              break;
00670            }
00671          snprintf (name, tbnamelen + 1, "%s%s", tbprefix, function.name);
00672          traceback.name = name;
00673          traceback.value = pos;
00674          traceback.the_bfd = abfd;
00675          traceback.section = sec;
00676          traceback.flags = 0;
00677          traceback.udata.i = ret;
00678 
00679          *(csym[count]) = function;
00680          *(csym[count + 1]) = traceback;
00681        }
00682 
00683       pos += ret;
00684       count += 2;
00685     }
00686 
00687   *nsym = count;
00688   return 0;
00689 }
00690 
00691 static int
00692 bfd_pef_parse_function_stub (bfd *abfd ATTRIBUTE_UNUSED,
00693                           unsigned char *buf,
00694                           size_t len,
00695                           unsigned long *offset)
00696 {
00697   BFD_ASSERT (len == 24);
00698 
00699   if ((bfd_getb32 (buf) & 0xffff0000) != 0x81820000)
00700     return -1;
00701   if (bfd_getb32 (buf + 4) != 0x90410014)
00702     return -1;
00703   if (bfd_getb32 (buf + 8) != 0x800c0000)
00704     return -1;
00705   if (bfd_getb32 (buf + 12) != 0x804c0004)
00706     return -1;
00707   if (bfd_getb32 (buf + 16) != 0x7c0903a6)
00708     return -1;
00709   if (bfd_getb32 (buf + 20) != 0x4e800420)
00710     return -1;
00711 
00712   if (offset != NULL)
00713     *offset = (bfd_getb32 (buf) & 0x0000ffff) / 4;
00714 
00715   return 0;
00716 }
00717 
00718 static int
00719 bfd_pef_parse_function_stubs (bfd *abfd,
00720                            asection *codesec,
00721                            unsigned char *codebuf,
00722                            size_t codelen,
00723                            unsigned char *loaderbuf,
00724                            size_t loaderlen,
00725                            unsigned long *nsym,
00726                            asymbol **csym)
00727 {
00728   const char *const sprefix = "__stub_";
00729 
00730   size_t codepos = 0;
00731   unsigned long count = 0;
00732 
00733   bfd_pef_loader_header header;
00734   bfd_pef_imported_library *libraries = NULL;
00735   bfd_pef_imported_symbol *imports = NULL;
00736 
00737   unsigned long i;
00738   int ret;
00739 
00740   if (loaderlen < 56)
00741     goto error;
00742 
00743   ret = bfd_pef_parse_loader_header (abfd, loaderbuf, 56, &header);
00744   if (ret < 0)
00745     goto error;
00746 
00747   libraries = bfd_malloc
00748     (header.imported_library_count * sizeof (bfd_pef_imported_library));
00749   imports = bfd_malloc
00750     (header.total_imported_symbol_count * sizeof (bfd_pef_imported_symbol));
00751 
00752   if (loaderlen < (56 + (header.imported_library_count * 24)))
00753     goto error;
00754   for (i = 0; i < header.imported_library_count; i++)
00755     {
00756       ret = bfd_pef_parse_imported_library
00757        (abfd, loaderbuf + 56 + (i * 24), 24, &libraries[i]);
00758       if (ret < 0)
00759        goto error;
00760     }
00761 
00762   if (loaderlen < (56 + (header.imported_library_count * 24)
00763                  + (header.total_imported_symbol_count * 4)))
00764     goto error;
00765   for (i = 0; i < header.total_imported_symbol_count; i++)
00766     {
00767       ret = (bfd_pef_parse_imported_symbol
00768             (abfd,
00769              loaderbuf + 56 + (header.imported_library_count * 24) + (i * 4),
00770              4, &imports[i]));
00771       if (ret < 0)
00772        goto error;
00773     }
00774 
00775   codepos = 0;
00776 
00777   for (;;)
00778     {
00779       asymbol sym;
00780       const char *symname;
00781       char *name;
00782       unsigned long index;
00783       int ret;
00784 
00785       if (csym && (csym[count] == NULL))
00786        break;
00787 
00788       codepos += 3;
00789       codepos -= (codepos % 4);
00790 
00791       while ((codepos + 4) <= codelen)
00792        {
00793          if ((bfd_getb32 (codebuf + codepos) & 0xffff0000) == 0x81820000)
00794            break;
00795          codepos += 4;
00796        }
00797 
00798       if ((codepos + 4) > codelen)
00799        break;
00800 
00801       ret = bfd_pef_parse_function_stub (abfd, codebuf + codepos, 24, &index);
00802       if (ret < 0)
00803        {
00804          codepos += 24;
00805          continue;
00806        }
00807 
00808       if (index >= header.total_imported_symbol_count)
00809        {
00810          codepos += 24;
00811          continue;
00812        }
00813 
00814       {
00815        size_t max, namelen;
00816        const char *s;
00817 
00818        if (loaderlen < (header.loader_strings_offset + imports[index].name))
00819          goto error;
00820 
00821        max = loaderlen - (header.loader_strings_offset + imports[index].name);
00822        symname = (char *) loaderbuf;
00823        symname += header.loader_strings_offset + imports[index].name;
00824        namelen = 0;
00825        for (s = symname; s < (symname + max); s++)
00826          {
00827            if (*s == '\0')
00828              break;
00829            if (! ISPRINT (*s))
00830              goto error;
00831            namelen++;
00832          }
00833        if (*s != '\0')
00834          goto error;
00835 
00836        name = bfd_alloc (abfd, strlen (sprefix) + namelen + 1);
00837        if (name == NULL)
00838          break;
00839 
00840        snprintf (name, strlen (sprefix) + namelen + 1, "%s%s",
00841                 sprefix, symname);
00842        sym.name = name;
00843       }
00844 
00845       sym.value = codepos;
00846       sym.the_bfd = abfd;
00847       sym.section = codesec;
00848       sym.flags = 0;
00849       sym.udata.i = 0;
00850 
00851       codepos += 24;
00852 
00853       if (csym != NULL)
00854        *(csym[count]) = sym;
00855 
00856       count++;
00857     }
00858 
00859   goto end;
00860 
00861  end:
00862   if (libraries != NULL)
00863     free (libraries);
00864   if (imports != NULL)
00865     free (imports);
00866   *nsym = count;
00867   return 0;
00868 
00869  error:
00870   if (libraries != NULL)
00871     free (libraries);
00872   if (imports != NULL)
00873     free (imports);
00874   *nsym = count;
00875   return -1;
00876 }
00877 
00878 static long
00879 bfd_pef_parse_symbols (bfd *abfd, asymbol **csym)
00880 {
00881   unsigned long count = 0;
00882 
00883   asection *codesec = NULL;
00884   unsigned char *codebuf = NULL;
00885   size_t codelen = 0;
00886 
00887   asection *loadersec = NULL;
00888   unsigned char *loaderbuf = NULL;
00889   size_t loaderlen = 0;
00890 
00891   codesec = bfd_get_section_by_name (abfd, "code");
00892   if (codesec != NULL)
00893     {
00894       codelen = codesec->size;
00895       codebuf = bfd_malloc (codelen);
00896       if (bfd_seek (abfd, codesec->filepos, SEEK_SET) < 0)
00897        goto end;
00898       if (bfd_bread ((void *) codebuf, codelen, abfd) != codelen)
00899        goto end;
00900     }
00901 
00902   loadersec = bfd_get_section_by_name (abfd, "loader");
00903   if (loadersec != NULL)
00904     {
00905       loaderlen = loadersec->size;
00906       loaderbuf = bfd_malloc (loaderlen);
00907       if (bfd_seek (abfd, loadersec->filepos, SEEK_SET) < 0)
00908        goto end;
00909       if (bfd_bread ((void *) loaderbuf, loaderlen, abfd) != loaderlen)
00910        goto end;
00911     }
00912 
00913   count = 0;
00914   if (codesec != NULL)
00915     {
00916       long ncount = 0;
00917       bfd_pef_parse_traceback_tables (abfd, codesec, codebuf, codelen,
00918                                   &ncount, csym);
00919       count += ncount;
00920     }
00921 
00922   if ((codesec != NULL) && (loadersec != NULL))
00923     {
00924       unsigned long ncount = 0;
00925       bfd_pef_parse_function_stubs
00926        (abfd, codesec, codebuf, codelen, loaderbuf, loaderlen, &ncount,
00927         (csym != NULL) ? (csym + count) : NULL);
00928       count += ncount;
00929     }
00930 
00931   if (csym != NULL)
00932     csym[count] = NULL;
00933 
00934  end:
00935   if (codebuf != NULL)
00936     free (codebuf);
00937 
00938   if (loaderbuf != NULL)
00939     free (loaderbuf);
00940 
00941   return count;
00942 }
00943 
00944 static long
00945 bfd_pef_count_symbols (bfd *abfd)
00946 {
00947   return bfd_pef_parse_symbols (abfd, NULL);
00948 }
00949 
00950 static long
00951 bfd_pef_get_symtab_upper_bound (bfd *abfd)
00952 {
00953   long nsyms = bfd_pef_count_symbols (abfd);
00954 
00955   if (nsyms < 0)
00956     return nsyms;
00957   return ((nsyms + 1) * sizeof (asymbol *));
00958 }
00959 
00960 static long
00961 bfd_pef_canonicalize_symtab (bfd *abfd, asymbol **alocation)
00962 {
00963   long i;
00964   asymbol *syms;
00965   long ret;
00966   long nsyms = bfd_pef_count_symbols (abfd);
00967 
00968   if (nsyms < 0)
00969     return nsyms;
00970 
00971   syms = bfd_alloc (abfd, nsyms * sizeof (asymbol));
00972   if (syms == NULL)
00973     return -1;
00974 
00975   for (i = 0; i < nsyms; i++)
00976     alocation[i] = &syms[i];
00977 
00978   alocation[nsyms] = NULL;
00979 
00980   ret = bfd_pef_parse_symbols (abfd, alocation);
00981   if (ret != nsyms)
00982     return 0;
00983 
00984   return ret;
00985 }
00986 
00987 #define bfd_pef_make_empty_symbol _bfd_generic_make_empty_symbol
00988 
00989 static void
00990 bfd_pef_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED,
00991                       asymbol *symbol,
00992                       symbol_info *ret)
00993 {
00994   bfd_symbol_info (symbol, ret);
00995 }
00996 
00997 static int
00998 bfd_pef_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
00999                      struct bfd_link_info *info ATTRIBUTE_UNUSED)
01000 {
01001   return 0;
01002 }
01003 
01004 const bfd_target pef_vec =
01005 {
01006   "pef",                    /* Name.  */
01007   bfd_target_pef_flavour,   /* Flavour.  */
01008   BFD_ENDIAN_BIG,           /* Byteorder.  */
01009   BFD_ENDIAN_BIG,           /* Header_byteorder.  */
01010   (HAS_RELOC | EXEC_P |            /* Object flags.  */
01011    HAS_LINENO | HAS_DEBUG |
01012    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
01013   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
01014    | SEC_ROM | SEC_HAS_CONTENTS), /* Section_flags.  */
01015   0,                        /* Symbol_leading_char.  */
01016   ' ',                      /* AR_pad_char.  */
01017   16,                       /* AR_max_namelen.  */
01018   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01019   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01020   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Data.  */
01021   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01022   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01023   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Headers.  */
01024   {                         /* bfd_check_format.  */
01025     _bfd_dummy_target,
01026     bfd_pef_object_p,              /* bfd_check_format.  */
01027     _bfd_dummy_target,
01028     _bfd_dummy_target,
01029   },
01030   {                         /* bfd_set_format.  */
01031     bfd_false,
01032     bfd_pef_mkobject,
01033     bfd_false,
01034     bfd_false,
01035   },
01036   {                         /* bfd_write_contents.  */
01037     bfd_false,
01038     bfd_true,
01039     bfd_false,
01040     bfd_false,
01041   },
01042 
01043   BFD_JUMP_TABLE_GENERIC (bfd_pef),
01044   BFD_JUMP_TABLE_COPY (_bfd_generic),
01045   BFD_JUMP_TABLE_CORE (_bfd_nocore),
01046   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
01047   BFD_JUMP_TABLE_SYMBOLS (bfd_pef),
01048   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
01049   BFD_JUMP_TABLE_WRITE (bfd_pef),
01050   BFD_JUMP_TABLE_LINK (bfd_pef),
01051   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
01052 
01053   NULL,
01054 
01055   NULL
01056 };
01057 
01058 #define bfd_pef_xlib_close_and_cleanup              _bfd_generic_close_and_cleanup
01059 #define bfd_pef_xlib_bfd_free_cached_info           _bfd_generic_bfd_free_cached_info
01060 #define bfd_pef_xlib_new_section_hook               _bfd_generic_new_section_hook
01061 #define bfd_pef_xlib_get_section_contents           _bfd_generic_get_section_contents
01062 #define bfd_pef_xlib_set_section_contents           _bfd_generic_set_section_contents
01063 #define bfd_pef_xlib_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
01064 #define bfd_pef_xlib_set_section_contents_in_window _bfd_generic_set_section_contents_in_window
01065 
01066 static int
01067 bfd_pef_xlib_read_header (bfd *abfd, bfd_pef_xlib_header *header)
01068 {
01069   unsigned char buf[76];
01070 
01071   bfd_seek (abfd, 0, SEEK_SET);
01072 
01073   if (bfd_bread ((void *) buf, 76, abfd) != 76)
01074     return -1;
01075 
01076   header->tag1 = bfd_getb32 (buf);
01077   header->tag2 = bfd_getb32 (buf + 4);
01078   header->current_format = bfd_getb32 (buf + 8);
01079   header->container_strings_offset = bfd_getb32 (buf + 12);
01080   header->export_hash_offset = bfd_getb32 (buf + 16);
01081   header->export_key_offset = bfd_getb32 (buf + 20);
01082   header->export_symbol_offset = bfd_getb32 (buf + 24);
01083   header->export_names_offset = bfd_getb32 (buf + 28);
01084   header->export_hash_table_power = bfd_getb32 (buf + 32);
01085   header->exported_symbol_count = bfd_getb32 (buf + 36);
01086   header->frag_name_offset = bfd_getb32 (buf + 40);
01087   header->frag_name_length = bfd_getb32 (buf + 44);
01088   header->dylib_path_offset = bfd_getb32 (buf + 48);
01089   header->dylib_path_length = bfd_getb32 (buf + 52);
01090   header->cpu_family = bfd_getb32 (buf + 56);
01091   header->cpu_model = bfd_getb32 (buf + 60);
01092   header->date_time_stamp = bfd_getb32 (buf + 64);
01093   header->current_version = bfd_getb32 (buf + 68);
01094   header->old_definition_version = bfd_getb32 (buf + 72);
01095   header->old_implementation_version = bfd_getb32 (buf + 76);
01096 
01097   return 0;
01098 }
01099 
01100 static int
01101 bfd_pef_xlib_scan (bfd *abfd, bfd_pef_xlib_header *header)
01102 {
01103   bfd_pef_xlib_data_struct *mdata = NULL;
01104 
01105   mdata = bfd_alloc (abfd, sizeof (* mdata));
01106   if (mdata == NULL)
01107     return -1;
01108 
01109   mdata->header = *header;
01110 
01111   abfd->flags = (abfd->xvec->object_flags
01112                | (abfd->flags & (BFD_IN_MEMORY | BFD_IO_FUNCS)));
01113 
01114   abfd->tdata.pef_xlib_data = mdata;
01115 
01116   return 0;
01117 }
01118 
01119 static const bfd_target *
01120 bfd_pef_xlib_object_p (bfd *abfd)
01121 {
01122   struct bfd_preserve preserve;
01123   bfd_pef_xlib_header header;
01124 
01125   if (bfd_pef_xlib_read_header (abfd, &header) != 0)
01126     {
01127       bfd_set_error (bfd_error_wrong_format);
01128       return NULL;
01129     }
01130 
01131   if ((header.tag1 != BFD_PEF_XLIB_TAG1)
01132       || ((header.tag2 != BFD_PEF_VLIB_TAG2)
01133          && (header.tag2 != BFD_PEF_BLIB_TAG2)))
01134     {
01135       bfd_set_error (bfd_error_wrong_format);
01136       return NULL;
01137     }
01138 
01139   if (! bfd_preserve_save (abfd, &preserve))
01140     {
01141       bfd_set_error (bfd_error_wrong_format);
01142       return NULL;
01143     }
01144 
01145   if (bfd_pef_xlib_scan (abfd, &header) != 0)
01146     {
01147       bfd_preserve_restore (abfd, &preserve);
01148       bfd_set_error (bfd_error_wrong_format);
01149       return NULL;
01150     }
01151 
01152   bfd_preserve_finish (abfd, &preserve);
01153   return abfd->xvec;
01154 }
01155 
01156 const bfd_target pef_xlib_vec =
01157 {
01158   "pef-xlib",               /* Name.  */
01159   bfd_target_pef_xlib_flavour,     /* Flavour.  */
01160   BFD_ENDIAN_BIG,           /* Byteorder */
01161   BFD_ENDIAN_BIG,           /* Header_byteorder.  */
01162   (HAS_RELOC | EXEC_P |            /* Object flags.  */
01163    HAS_LINENO | HAS_DEBUG |
01164    HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED),
01165   (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE | SEC_DATA
01166    | SEC_ROM | SEC_HAS_CONTENTS),/* Section_flags.  */
01167   0,                        /* Symbol_leading_char.  */
01168   ' ',                      /* AR_pad_char.  */
01169   16,                       /* AR_max_namelen.  */
01170   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01171   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01172   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Data.  */
01173   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
01174   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
01175   bfd_getb16, bfd_getb_signed_16, bfd_putb16,    /* Headers.  */
01176   {                         /* bfd_check_format.  */
01177     _bfd_dummy_target,
01178     bfd_pef_xlib_object_p,  /* bfd_check_format.  */
01179     _bfd_dummy_target,
01180     _bfd_dummy_target,
01181   },
01182   {                         /* bfd_set_format.  */
01183     bfd_false,
01184     bfd_pef_mkobject,
01185     bfd_false,
01186     bfd_false,
01187   },
01188   {                         /* bfd_write_contents.  */
01189     bfd_false,
01190     bfd_true,
01191     bfd_false,
01192     bfd_false,
01193   },
01194 
01195   BFD_JUMP_TABLE_GENERIC (bfd_pef_xlib),
01196   BFD_JUMP_TABLE_COPY (_bfd_generic),
01197   BFD_JUMP_TABLE_CORE (_bfd_nocore),
01198   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
01199   BFD_JUMP_TABLE_SYMBOLS (_bfd_nosymbols),
01200   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
01201   BFD_JUMP_TABLE_WRITE (_bfd_nowrite),
01202   BFD_JUMP_TABLE_LINK (_bfd_nolink),
01203   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
01204 
01205   NULL,
01206 
01207   NULL
01208 };