2014-10-01  Pierre Muller  <muller@sourceware.org>

	Add support for pdata output for pe coff objects.
	* pe-x86_64.c (pex64_bfd_print_pdata): Add external
	declaration.
	(bfd_pe_print_data): Set macro to pex64_bfd_print_data.
	* pei-x86_64.c (pex64_bfd_print_pdata): Changed to
	global function. Now handles multiple .pdata sections.
	(pex_bfd_print_pdata_section): New static helper function,
	using most of old pex_bfd_print_pdata function code, but adding
	support for coff pe objects, which might have some fields
	starting at zero offset.
	(pex64_print_all_pdata_sections) : New static helper function,
	used in call to bfd_map_over_sections inside new
	pex66_bfd_print_pdata function.
	(bfd_boolean pdata_count): New static variable, used to return
	bfd_boolean value for pex64_bfd_print_pdata function.


diff --git a/bfd/pe-x86_64.c b/bfd/pe-x86_64.c
index 673a544..6fe519f 100644
--- a/bfd/pe-x86_64.c
+++ b/bfd/pe-x86_64.c
@@ -58,6 +58,12 @@
 { COFF_SECTION_NAME_PARTIAL_MATCH (".gnu.linkonce.wi."), \
   COFF_ALIGNMENT_FIELD_EMPTY, COFF_ALIGNMENT_FIELD_EMPTY, 0 }
 
+/* The function pex64_bfd_print_pdata is implemented in pei-x86_64.c
+   source, but has be extended to also handle pe objects.  */
+extern bfd_boolean pex64_bfd_print_pdata (bfd * abfd, void * vfile);
+
+#define bfd_pe_print_pdata   pex64_bfd_print_pdata
+
 #include "coff-x86_64.c"
 
 /* Entry for big object files.  */
diff --git a/bfd/pei-x86_64.c b/bfd/pei-x86_64.c
index 48554d3..37268e3 100644
--- a/bfd/pei-x86_64.c
+++ b/bfd/pei-x86_64.c
@@ -439,23 +439,24 @@ sort_xdata_arr (const void *l, const void *r)
 /* Display unwind tables for x86-64.  */
 
 static bfd_boolean
-pex64_bfd_print_pdata (bfd *abfd, void *vfile)
+pex64_bfd_print_pdata_section (bfd *abfd, void *vfile, asection *pdata_section)
 {
   FILE *file = (FILE *) vfile;
   bfd_byte *pdata = NULL;
   bfd_byte *xdata = NULL;
-  asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata");
-  asection *xdata_section;
+  asection *xdata_section = NULL;
   bfd_vma xdata_base;
   bfd_size_type i;
+  bfd_size_type datasize;
   bfd_size_type stop;
-  bfd_vma prev_beginaddress = 0;
-  bfd_vma prev_unwinddata_rva = 0;
+  bfd_vma prev_beginaddress = (bfd_vma) -1;
+  bfd_vma prev_unwinddata_rva = (bfd_vma) -1;
   bfd_vma imagebase;
   int onaline = PDATA_ROW_SIZE;
   int seen_error = 0;
   bfd_vma *xdata_arr = NULL;
   int xdata_arr_cnt;
+  int virt_size_is_zero = 0;
 
   /* Sanity checks.  */
   if (pdata_section == NULL
@@ -466,12 +467,37 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
   stop = pei_section_data (abfd, pdata_section)->virt_size;
   if ((stop % onaline) != 0)
     fprintf (file,
-	     _("warning: .pdata section size (%ld) is not a multiple of %d\n"),
-	     (long) stop, onaline);
+	     _("warning: %s section size (%ld) is not a multiple of %d\n"),
+	     pdata_section->name, (long) stop, onaline);
+
+  datasize = pdata_section->size;
+  if (datasize == 0)
+    {
+      if (stop)
+	fprintf (file, _("Warning, %s section size is zero sized\n"),
+		 pdata_section->name);
+      return TRUE;
+    }
+
+  /* virt_size might be zero for objects.  */
+  if (stop == 0 && strcmp (abfd->xvec->name, "pe-x86-64") == 0)
+    {
+      stop = (datasize / onaline) * onaline;
+      virt_size_is_zero = 1;
+    }
+  else if (datasize < stop)
+      {
+	fprintf (file,
+		 _("Warning, %s section size is smaller than virtual size\n"),
+		 pdata_section->name);
+	/* Be sure not to read passed datasize.  */
+	stop = datasize / onaline;
+      }
 
   /* Display functions table.  */
   fprintf (file,
-	   _("\nThe Function Table (interpreted .pdata section contents)\n"));
+	   _("\nThe Function Table (interpreted %s section contents)\n"),
+	   pdata_section->name);
 
   fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t  UnwindData\n"));
 
@@ -482,7 +508,10 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
   xdata_arr = (bfd_vma *) xmalloc (sizeof (bfd_vma) * ((stop / onaline) + 1));
   xdata_arr_cnt = 0;
 
-  imagebase = pe_data (abfd)->pe_opthdr.ImageBase;
+  if (strcmp (abfd->xvec->name, "pei-x86-64") == 0)
+    imagebase = pe_data (abfd)->pe_opthdr.ImageBase;
+  else
+    imagebase = 0;
 
   for (i = 0; i < stop; i += onaline)
     {
@@ -528,8 +557,8 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
 	  seen_error = 1;
 	  fprintf (file, "  has negative unwind address\n");
 	}
-      if (rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
-        xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
+      else if (rf.rva_UnwindData != 0 || virt_size_is_zero)
+	xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
     }
 
   if (seen_error)
@@ -545,20 +574,42 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
 
   /* Find the section containing the unwind data (.xdata).  */
   xdata_base = xdata_arr[0];
-  xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata");
 
-  if (!xdata_section)
-    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data");
+  /* For sections with long names, first look for the same section name,
+     replacing .pdata by .xdata prefix.  */
+  if (strcmp (pdata_section->name, ".pdata") != 0)
+    {
+      char *xdata_name = alloca (strlen (pdata_section->name + 1));
+
+      xdata_name = strcpy (xdata_name, pdata_section->name);
+      // transform .pdata prefix into .xdata prefix
+      if (strlen (xdata_name) > 1)
+	xdata_name [1] = 'x';
+      xdata_section = pex64_get_section_by_rva (abfd, xdata_base,
+						xdata_name);
+    }
+  /* Second, try the .xdata section itself.  */
   if (!xdata_section)
     xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".xdata");
-  if (!xdata_section)
+  /* Otherwise, if xdata_base is non zero, search also inside
+     other standard sections.  */
+  if (!xdata_section && xdata_base)
+    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".rdata");
+  if (!xdata_section && xdata_base)
+    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".data");
+  if (!xdata_section && xdata_base)
     xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".pdata");
-  if (!xdata_section)
+  if (!xdata_section && xdata_base)
     xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text");
+  /* Transfer xdata section into xdata array.  */
   if (!xdata_section
       || !bfd_malloc_and_get_section (abfd, xdata_section, &xdata))
     goto done;
 
+  /* Avoid "also used "... ouput for single unwind info
+     in object file.  */
+  prev_unwinddata_rva = (bfd_vma) -1;
+
   /* Do dump of pdata related xdata.  */
   for (i = 0; i < stop; i += onaline)
     {
@@ -573,7 +624,7 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
 	/* We are probably into the padding of the section now.  */
 	break;
       if (i == 0)
-        fprintf (file, "\nDump of .xdata\n");
+        fprintf (file, "\nDump of %s\n", xdata_section->name);
 
       fputc (' ', file);
       fprintf_vma (file, rf.rva_UnwindData + imagebase);
@@ -596,7 +647,7 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
       fprintf_vma (file, rf.rva_EndAddress + imagebase);
       fputc ('\n', file);
 
-      if (rf.rva_UnwindData != 0)
+      if (rf.rva_UnwindData != 0 || virt_size_is_zero)
 	{
 	  if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
 	    {
@@ -651,6 +702,41 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
   return TRUE;
 }
 
+
+/* Static counter of number of found pdata sections.  */
+static bfd_boolean pdata_count;
+
+/* Functionn prototype.  */
+bfd_boolean pex64_bfd_print_pdata (bfd *abfd, void *vfile);
+
+/* Helper function for bfd_map_over_section.  */
+static void
+pex64_print_all_pdata_sections (bfd *abfd, asection *pdata, void *obj)
+{
+  if (strncmp (pdata->name, ".pdata",
+	       strlen (".pdata")) == 0)
+    {
+      if (pex64_bfd_print_pdata_section (abfd, obj, pdata))
+	pdata_count++;
+    }
+}
+
+bfd_boolean
+pex64_bfd_print_pdata (bfd *abfd, void *vfile)
+{
+  asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata");
+
+  if (pdata_section)
+    return pex64_bfd_print_pdata_section (abfd, vfile, pdata_section);
+  else
+    {
+      pdata_count = 0;
+      bfd_map_over_sections (abfd, pex64_print_all_pdata_sections, vfile);
+      return (pdata_count > 0);
+    }
+}
+
 #define bfd_pe_print_pdata   pex64_bfd_print_pdata
+#define bfd_coff_std_swap_table bfd_coff_pei_swap_table
 
 #include "coff-x86_64.c"

