PR 6844
[binutils-gdb.git] / bfd / peXXigen.c
index 3848f53dea85b84202180ceb5b589b789edf8bec..0c56067c238f0ce785ae3110de7dc8c1f9641fd3 100644 (file)
@@ -1,13 +1,13 @@
 /* Support for the generic parts of PE/PEI; the common executable parts.
    Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006 Free Software Foundation, Inc.
+   2005, 2006, 2007, 2008  Free Software Foundation, Inc.
    Written by Cygnus Solutions.
 
    This file is part of BFD, the Binary File Descriptor library.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -17,7 +17,9 @@
 
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
+   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+   MA 02110-1301, USA.  */
+
 
 /* Most of this hacked by Steve Chamberlain <sac@cygnus.com>.
 
@@ -56,8 +58,8 @@
    depending on whether we're compiling for straight PE or PE+.  */
 #define COFF_WITH_XX
 
-#include "bfd.h"
 #include "sysdep.h"
+#include "bfd.h"
 #include "libbfd.h"
 #include "coff/internal.h"
 
@@ -388,10 +390,11 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
                          void * aouthdr_ext1,
                          void * aouthdr_int1)
 {
-  struct internal_extra_pe_aouthdr *a;
-  PEAOUTHDR * src = (PEAOUTHDR *) (aouthdr_ext1);
+  PEAOUTHDR * src = (PEAOUTHDR *) aouthdr_ext1;
   AOUTHDR * aouthdr_ext = (AOUTHDR *) aouthdr_ext1;
-  struct internal_aouthdr *aouthdr_int = (struct internal_aouthdr *)aouthdr_int1;
+  struct internal_aouthdr *aouthdr_int
+    = (struct internal_aouthdr *) aouthdr_int1;
+  struct internal_extra_pe_aouthdr *a = &aouthdr_int->pe;
 
   aouthdr_int->magic = H_GET_16 (abfd, aouthdr_ext->magic);
   aouthdr_int->vstamp = H_GET_16 (abfd, aouthdr_ext->vstamp);
@@ -405,9 +408,17 @@ _bfd_XXi_swap_aouthdr_in (bfd * abfd,
   /* PE32+ does not have data_start member!  */
   aouthdr_int->data_start =
     GET_AOUTHDR_DATA_START (abfd, aouthdr_ext->data_start);
+  a->BaseOfData = aouthdr_int->data_start;
 #endif
 
-  a = &aouthdr_int->pe;
+  a->Magic = aouthdr_int->magic;
+  a->MajorLinkerVersion = H_GET_8 (abfd, aouthdr_ext->vstamp);
+  a->MinorLinkerVersion = H_GET_8 (abfd, aouthdr_ext->vstamp + 1);
+  a->SizeOfCode = aouthdr_int->tsize ;
+  a->SizeOfInitializedData = aouthdr_int->dsize ;
+  a->SizeOfUninitializedData = aouthdr_int->bsize ;
+  a->AddressOfEntryPoint = aouthdr_int->entry;
+  a->BaseOfCode = aouthdr_int->text_start;
   a->ImageBase = GET_OPTHDR_IMAGE_BASE (abfd, src->ImageBase);
   a->SectionAlignment = H_GET_32 (abfd, src->SectionAlignment);
   a->FileAlignment = H_GET_32 (abfd, src->FileAlignment);
@@ -636,16 +647,22 @@ _bfd_XXi_swap_aouthdr_out (bfd * abfd, void * in, void * out)
           in the virt_size field).  Files have been seen (from MSVC
           5.0 link.exe) where the file size of the .data segment is
           quite small compared to the virtual size.  Without this
-          fix, strip munges the file.  */
+          fix, strip munges the file.
+
+          FIXME: We need to handle holes between sections, which may
+          happpen when we covert from another format.  We just use
+          the virtual address and virtual size of the last section
+          for the image size.  */
        if (coff_section_data (abfd, sec) != NULL
            && pei_section_data (abfd, sec) != NULL)
-         isize += SA (FA (pei_section_data (abfd, sec)->virt_size));
+         isize = (sec->vma - extra->ImageBase
+                  + SA (FA (pei_section_data (abfd, sec)->virt_size)));
       }
 
     aouthdr_in->dsize = dsize;
     aouthdr_in->tsize = tsize;
     extra->SizeOfHeaders = hsize;
-    extra->SizeOfImage = SA (hsize) + isize;
+    extra->SizeOfImage = isize;
   }
 
   H_PUT_16 (abfd, aouthdr_in->magic, aouthdr_out->standard.magic);
@@ -1293,7 +1310,7 @@ pe_print_idata (bfd * abfd, void * vfile)
                  && first_thunk != 0
                  && first_thunk != hint_addr)
                fprintf (file, "\t%04lx",
-                        (long) bfd_get_32 (abfd, ft_data + ft_idx + j));
+                        (unsigned long) bfd_get_32 (abfd, ft_data + ft_idx + j));
              fprintf (file, "\n");
            }
 #else
@@ -1325,7 +1342,7 @@ pe_print_idata (bfd * abfd, void * vfile)
                  && first_thunk != 0
                  && first_thunk != hint_addr)
                fprintf (file, "\t%04lx",
-                        (long) bfd_get_32 (abfd, ft_data + ft_idx + j));
+                        (unsigned long) bfd_get_32 (abfd, ft_data + ft_idx + j));
 
              fprintf (file, "\n");
            }
@@ -1564,7 +1581,14 @@ pe_print_edata (bfd * abfd, void * vfile)
 /* This really is architecture dependent.  On IA-64, a .pdata entry
    consists of three dwords containing relative virtual addresses that
    specify the start and end address of the code range the entry
-   covers and the address of the corresponding unwind info data.  */
+   covers and the address of the corresponding unwind info data. 
+
+   On ARM and SH-4, a compressed PDATA structure is used :
+   _IMAGE_CE_RUNTIME_FUNCTION_ENTRY, whereas MIPS is documented to use
+   _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY.
+   See http://msdn2.microsoft.com/en-us/library/ms253988(VS.80).aspx .
+
+   This is the version for uncompressed data.  */
 
 static bfd_boolean
 pe_print_pdata (bfd * abfd, void * vfile)
@@ -1688,8 +1712,189 @@ pe_print_pdata (bfd * abfd, void * vfile)
   free (data);
 
   return TRUE;
+#undef PDATA_ROW_SIZE
+}
+
+typedef struct sym_cache
+{
+  int        symcount;
+  asymbol ** syms;
+} sym_cache;
+
+static asymbol **
+slurp_symtab (bfd *abfd, sym_cache *psc)
+{
+  asymbol ** sy = NULL;
+  long storage;
+
+  if (!(bfd_get_file_flags (abfd) & HAS_SYMS))
+    {
+      psc->symcount = 0;
+      return NULL;
+    }
+
+  storage = bfd_get_symtab_upper_bound (abfd);
+  if (storage < 0)
+    return NULL;
+  if (storage)
+    sy = bfd_malloc (storage);
+
+  psc->symcount = bfd_canonicalize_symtab (abfd, sy);
+  if (psc->symcount < 0)
+    return NULL;
+  return sy;
 }
 
+static const char *
+my_symbol_for_address (bfd *abfd, bfd_vma func, sym_cache *psc)
+{
+  int i;
+
+  if (psc->syms == 0)
+    psc->syms = slurp_symtab (abfd, psc);
+
+  for (i = 0; i < psc->symcount; i++)
+    {
+      if (psc->syms[i]->section->vma + psc->syms[i]->value == func)
+       return psc->syms[i]->name;
+    }
+
+  return NULL;
+}
+
+static void
+cleanup_syms (sym_cache *psc)
+{
+  psc->symcount = 0;
+  free (psc->syms);
+  psc->syms = NULL;
+}
+
+/* This is the version for "compressed" pdata.  */
+
+bfd_boolean
+_bfd_XX_print_ce_compressed_pdata (bfd * abfd, void * vfile)
+{
+# define PDATA_ROW_SIZE        (2 * 4)
+  FILE *file = (FILE *) vfile;
+  bfd_byte *data = NULL;
+  asection *section = bfd_get_section_by_name (abfd, ".pdata");
+  bfd_size_type datasize = 0;
+  bfd_size_type i;
+  bfd_size_type start, stop;
+  int onaline = PDATA_ROW_SIZE;
+  struct sym_cache sym_cache = {0, 0} ;
+
+  if (section == NULL
+      || coff_section_data (abfd, section) == NULL
+      || pei_section_data (abfd, section) == NULL)
+    return TRUE;
+
+  stop = pei_section_data (abfd, section)->virt_size;
+  if ((stop % onaline) != 0)
+    fprintf (file,
+            _("Warning, .pdata section size (%ld) is not a multiple of %d\n"),
+            (long) stop, onaline);
+
+  fprintf (file,
+          _("\nThe Function Table (interpreted .pdata section contents)\n"));
+
+  fprintf (file, _("\
+ vma:\t\tBegin    Prolog   Function Flags    Exception EH\n\
+     \t\tAddress  Length   Length   32b exc  Handler   Data\n"));
+
+  datasize = section->size;
+  if (datasize == 0)
+    return TRUE;
+
+  if (! bfd_malloc_and_get_section (abfd, section, &data))
+    {
+      if (data != NULL)
+       free (data);
+      return FALSE;
+    }
+
+  start = 0;
+
+  for (i = start; i < stop; i += onaline)
+    {
+      bfd_vma begin_addr;
+      bfd_vma other_data;
+      bfd_vma prolog_length, function_length;
+      int flag32bit, exception_flag;
+      bfd_byte *tdata = 0;
+      asection *tsection;
+
+      if (i + PDATA_ROW_SIZE > stop)
+       break;
+
+      begin_addr = GET_PDATA_ENTRY (abfd, data + i     );
+      other_data = GET_PDATA_ENTRY (abfd, data + i +  4);
+
+      if (begin_addr == 0 && other_data == 0)
+       /* We are probably into the padding of the section now.  */
+       break;
+
+      prolog_length = (other_data & 0x000000FF);
+      function_length = (other_data & 0x3FFFFF00) >> 8;
+      flag32bit = (int)((other_data & 0x40000000) >> 30);
+      exception_flag = (int)((other_data & 0x80000000) >> 31);
+
+      fputc (' ', file);
+      fprintf_vma (file, i + section->vma); fputc ('\t', file);
+      fprintf_vma (file, begin_addr); fputc (' ', file);
+      fprintf_vma (file, prolog_length); fputc (' ', file);
+      fprintf_vma (file, function_length); fputc (' ', file);
+      fprintf (file, "%2d  %2d   ", flag32bit, exception_flag);
+
+      /* Get the exception handler's address and the data passed from the
+         .text section. This is really the data that belongs with the .pdata
+         but got "compressed" out for the ARM and SH4 architectures.  */
+      tsection = bfd_get_section_by_name (abfd, ".text");
+      if (tsection && coff_section_data (abfd, tsection)
+         && pei_section_data (abfd, tsection))
+       {
+         if (bfd_malloc_and_get_section (abfd, tsection, & tdata))
+           {
+             int xx = (begin_addr - 8) - tsection->vma;
+
+             tdata = bfd_malloc (8);
+             if (bfd_get_section_contents (abfd, tsection, tdata, (bfd_vma) xx, 8))
+               {
+                 bfd_vma eh, eh_data;
+
+                 eh = bfd_get_32 (abfd, tdata);
+                 eh_data = bfd_get_32 (abfd, tdata + 4);
+                 fprintf (file, "%08x  ", (unsigned int) eh);
+                 fprintf (file, "%08x", (unsigned int) eh_data);
+                 if (eh != 0)
+                   {
+                     const char *s = my_symbol_for_address (abfd, eh, &sym_cache);
+
+                     if (s)
+                       fprintf (file, " (%s) ", s);
+                   }
+               }
+             free (tdata);
+           }
+         else
+           {
+             if (tdata)
+               free (tdata);
+           }
+       }
+
+      fprintf (file, "\n");
+    }
+
+  free (data);
+
+  cleanup_syms (& sym_cache);
+
+  return TRUE;
+#undef PDATA_ROW_SIZE
+}
+\f
 #define IMAGE_REL_BASED_HIGHADJ 4
 static const char * const tbl[] =
 {
@@ -1756,7 +1961,7 @@ pe_print_reloc (bfd * abfd, void * vfile)
 
       fprintf (file,
               _("\nVirtual Address: %08lx Chunk size %ld (0x%lx) Number of fixups %ld\n"),
-              (unsigned long) virtual_address, size, size, number);
+              (unsigned long) virtual_address, size, (unsigned long) size, number);
 
       for (j = 0; j < number; ++j)
        {
@@ -1769,7 +1974,7 @@ pe_print_reloc (bfd * abfd, void * vfile)
 
          fprintf (file,
                   _("\treloc %4d offset %4x [%4lx] %s"),
-                  j, off, (long) (off + virtual_address), tbl[t]);
+                  j, off, (unsigned long) (off + virtual_address), tbl[t]);
 
          /* HIGHADJ takes an argument, - the next record *is* the
             low 16 bits of addend.  */
@@ -1802,6 +2007,7 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
   pe_data_type *pe = pe_data (abfd);
   struct internal_extra_pe_aouthdr *i = &pe->pe_opthdr;
   const char *subsystem_name = NULL;
+  const char *name;
 
   /* The MS dumpbin program reportedly ands with 0xff0f before
      printing the characteristics field.  Not sure why.  No reason to
@@ -1827,6 +2033,52 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
     time_t t = pe->coff.timestamp;
     fprintf (file, "\nTime/Date\t\t%s", ctime (&t));
   }
+
+#ifndef IMAGE_NT_OPTIONAL_HDR_MAGIC
+# define IMAGE_NT_OPTIONAL_HDR_MAGIC 0x10b
+#endif
+#ifndef IMAGE_NT_OPTIONAL_HDR64_MAGIC
+# define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+#endif
+#ifndef IMAGE_NT_OPTIONAL_HDRROM_MAGIC
+# define IMAGE_NT_OPTIONAL_HDRROM_MAGIC 0x107
+#endif
+
+  switch (i->Magic)
+    {
+    case IMAGE_NT_OPTIONAL_HDR_MAGIC:
+      name = "PE32";
+      break;
+    case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
+      name = "PE32+";
+      break;
+    case IMAGE_NT_OPTIONAL_HDRROM_MAGIC:
+      name = "ROM";
+      break;
+    default:
+      name = NULL;
+      break;
+    }
+  fprintf (file, "Magic\t\t\t%04x", i->Magic);
+  if (name)
+    fprintf (file, "\t(%s)",name);
+  fprintf (file, "\nMajorLinkerVersion\t%d\n", i->MajorLinkerVersion);
+  fprintf (file, "MinorLinkerVersion\t%d\n", i->MinorLinkerVersion);
+  fprintf (file, "SizeOfCode\t\t%08lx\n", (unsigned long) i->SizeOfCode);
+  fprintf (file, "SizeOfInitializedData\t%08lx\n",
+          (unsigned long) i->SizeOfInitializedData);
+  fprintf (file, "SizeOfUninitializedData\t%08lx\n",
+          (unsigned long) i->SizeOfUninitializedData);
+  fprintf (file, "AddressOfEntryPoint\t");
+  fprintf_vma (file, i->AddressOfEntryPoint);
+  fprintf (file, "\nBaseOfCode\t\t");
+  fprintf_vma (file, i->BaseOfCode);
+#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
+  /* PE32+ does not have BaseOfData member!  */
+  fprintf (file, "\nBaseOfData\t\t");
+  fprintf_vma (file, i->BaseOfData);
+#endif
+
   fprintf (file, "\nImageBase\t\t");
   fprintf_vma (file, i->ImageBase);
   fprintf (file, "\nSectionAlignment\t");
@@ -1839,10 +2091,10 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
   fprintf (file, "MinorImageVersion\t%d\n", i->MinorImageVersion);
   fprintf (file, "MajorSubsystemVersion\t%d\n", i->MajorSubsystemVersion);
   fprintf (file, "MinorSubsystemVersion\t%d\n", i->MinorSubsystemVersion);
-  fprintf (file, "Win32Version\t\t%08lx\n", i->Reserved1);
-  fprintf (file, "SizeOfImage\t\t%08lx\n", i->SizeOfImage);
-  fprintf (file, "SizeOfHeaders\t\t%08lx\n", i->SizeOfHeaders);
-  fprintf (file, "CheckSum\t\t%08lx\n", i->CheckSum);
+  fprintf (file, "Win32Version\t\t%08lx\n", (unsigned long) i->Reserved1);
+  fprintf (file, "SizeOfImage\t\t%08lx\n", (unsigned long) i->SizeOfImage);
+  fprintf (file, "SizeOfHeaders\t\t%08lx\n", (unsigned long) i->SizeOfHeaders);
+  fprintf (file, "CheckSum\t\t%08lx\n", (unsigned long) i->CheckSum);
 
   switch (i->Subsystem)
     {
@@ -1897,21 +2149,25 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
   fprintf_vma (file, i->SizeOfHeapReserve);
   fprintf (file, "\nSizeOfHeapCommit\t");
   fprintf_vma (file, i->SizeOfHeapCommit);
-  fprintf (file, "\nLoaderFlags\t\t%08lx\n", i->LoaderFlags);
-  fprintf (file, "NumberOfRvaAndSizes\t%08lx\n", i->NumberOfRvaAndSizes);
+  fprintf (file, "\nLoaderFlags\t\t%08lx\n", (unsigned long) i->LoaderFlags);
+  fprintf (file, "NumberOfRvaAndSizes\t%08lx\n",
+          (unsigned long) i->NumberOfRvaAndSizes);
 
   fprintf (file, "\nThe Data Directory\n");
   for (j = 0; j < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; j++)
     {
       fprintf (file, "Entry %1x ", j);
       fprintf_vma (file, i->DataDirectory[j].VirtualAddress);
-      fprintf (file, " %08lx ", i->DataDirectory[j].Size);
+      fprintf (file, " %08lx ", (unsigned long) i->DataDirectory[j].Size);
       fprintf (file, "%s\n", dir_names[j]);
     }
 
   pe_print_idata (abfd, vfile);
   pe_print_edata (abfd, vfile);
-  pe_print_pdata (abfd, vfile);
+  if (bfd_coff_have_print_pdata (abfd))
+    bfd_coff_print_pdata (abfd, vfile);
+  else
+    pe_print_pdata (abfd, vfile);
   pe_print_reloc (abfd, vfile);
 
   return TRUE;
@@ -1923,13 +2179,22 @@ _bfd_XX_print_private_bfd_data_common (bfd * abfd, void * vfile)
 bfd_boolean
 _bfd_XX_bfd_copy_private_bfd_data_common (bfd * ibfd, bfd * obfd)
 {
+  pe_data_type *ipe, *ope;
+
   /* One day we may try to grok other private data.  */
   if (ibfd->xvec->flavour != bfd_target_coff_flavour
       || obfd->xvec->flavour != bfd_target_coff_flavour)
     return TRUE;
 
-  pe_data (obfd)->pe_opthdr = pe_data (ibfd)->pe_opthdr;
-  pe_data (obfd)->dll = pe_data (ibfd)->dll;
+  ipe = pe_data (ibfd);
+  ope = pe_data (obfd);
+  ope->pe_opthdr = ipe->pe_opthdr;
+  ope->dll = ipe->dll;
+
+  /* Don't copy input subsystem if output is different from input.  */
+  if (obfd->xvec != ibfd->xvec)
+    ope->pe_opthdr.Subsystem = IMAGE_SUBSYSTEM_UNKNOWN;
 
   /* For strip: if we removed .reloc, we'll make a real mess of things
      if we don't remove this entry as well.  */