Improve dump of xdata/pdata on x86_64.
authorTristan Gingold <gingold@adacore.com>
Thu, 21 Nov 2013 11:00:48 +0000 (12:00 +0100)
committerTristan Gingold <gingold@adacore.com>
Wed, 27 Nov 2013 10:21:03 +0000 (11:21 +0100)
bfd/
2013-11-27  Tristan Gingold  <gingold@adacore.com>

* pei-x86_64.c (pex_regs): Make it const.  Add comments.
(pex64_get_runtime_function): Do not split UnwindData.
(pex64_get_unwind_info): Extract the chain and the handler.
(pex64_xdata_print_uwd_codes): Rewritten: do not reverse print
the opcode, handle version 2, add consistency check, make the
code host neutral.
(pex64_dump_xdata): Change arguments to pass the section and its
content.  Handle version 2, change output.
(pex64_bfd_print_pdata): Add comments, load section for xdata.
Avoid duplicate outputs.

include/coff
2013-11-27  Tristan Gingold  <gingold@adacore.com>

* pe.h (struct pex64_runtime_function): Remove isChained.
(UWOP_SAVE_XMM): Add comment.
(struct pex64_unwind_info): Remove extra fields.

bfd/pei-x86_64.c
include/coff/pe.h

index 6139ca24c7cf51a7850a8fd4d3edc7abac9c4578..ecbef47c50328de48e54794f40d96f9c5b935939 100644 (file)
 #define AOUTSZ         PEPAOUTSZ
 #define PEAOUTHDR      PEPAOUTHDR
 
-static const char *pex_regs[16] = {
+/* Name of registers according to SEH conventions.  */
+
+static const char * const pex_regs[16] = {
   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
 };
 
+/* Swap in a runtime function.  */
+
 static void
 pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf,
                            const void *data)
@@ -90,10 +94,10 @@ pex64_get_runtime_function (bfd *abfd, struct pex64_runtime_function *rf,
   rf->rva_BeginAddress = bfd_get_32 (abfd, ex_rf->rva_BeginAddress);
   rf->rva_EndAddress = bfd_get_32 (abfd, ex_rf->rva_EndAddress);
   rf->rva_UnwindData = bfd_get_32 (abfd, ex_rf->rva_UnwindData);
-  rf->isChained = PEX64_IS_RUNTIME_FUNCTION_CHAINED (rf);
-  rf->rva_UnwindData = PEX64_GET_UNWINDDATA_UNIFIED_RVA (rf);
 }
 
+/* Swap in unwind info header.  */
+
 static void
 pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
 {
@@ -115,7 +119,15 @@ pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
   switch (ui->Flags)
     {
     case UNW_FLAG_CHAININFO:
-      ui->rva_FunctionEntry = bfd_get_32 (abfd, ex_dta);
+      ui->rva_BeginAddress = bfd_get_32 (abfd, ex_dta + 0);
+      ui->rva_EndAddress = bfd_get_32 (abfd, ex_dta + 4);
+      ui->rva_UnwindData = bfd_get_32 (abfd, ex_dta + 8);
+      ui->SizeOfBlock += 12;
+      return;
+    case UNW_FLAG_EHANDLER:
+    case UNW_FLAG_UHANDLER:
+    case UNW_FLAG_FHANDLER:
+      ui->rva_ExceptionHandler = bfd_get_32 (abfd, ex_dta);
       ui->SizeOfBlock += 4;
       return;
     default:
@@ -123,168 +135,143 @@ pex64_get_unwind_info (bfd *abfd, struct pex64_unwind_info *ui, void *data)
     }
 }
 
+/* Display unwind codes.  */
+
 static void
-pex64_xdata_print_uwd_codes (FILE *file, struct pex64_unwind_info *ui,
-                            bfd_vma pc_addr)
+pex64_xdata_print_uwd_codes (FILE *file, bfd *abfd,
+                            struct pex64_unwind_info *ui)
 {
-  bfd_vma i;
-  bfd_vma tmp = 0;
-  const bfd_byte *insns[256];
-  bfd_vma insns_count = 0;
-  const bfd_byte *dta = ui->rawUnwindCodes;
+  unsigned int i;
+  unsigned int tmp; /* At least 32 bits.  */
+  int save_allowed;
 
-  if (ui->CountOfCodes == 0 || !dta)
+  if (ui->CountOfCodes == 0 || ui->rawUnwindCodes == NULL)
     return;
 
-  /* Sort array ascending. Note: it is stored in reversed order.  */
-  for (i = 0; i < ui->CountOfCodes; i++)
-    {
-      const bfd_byte *t;
+  /* According to UNWIND_CODE documentation:
+      If an FP reg is used, the any unwind code taking an offset must only be
+      used after the FP reg is established in the prolog.
+     But there are counter examples of that in system dlls...  */
+  save_allowed = TRUE;
 
-      t = insns[insns_count++] = &dta[i * 2];
-      switch (PEX64_UNWCODE_CODE (t[1]))
+  i = 0;
+
+  if (ui->Version == 2 && PEX64_UNWCODE_CODE (ui->rawUnwindCodes[1]) == 6)
+    {
+      /* Display opcodes 6 (whose meaning is not documented).  */
+      fprintf (file, "\tv2 opcode6:");
+      for (; i < ui->CountOfCodes; i++)
        {
-       case UWOP_PUSH_NONVOL:
-       case UWOP_ALLOC_SMALL:
-       case UWOP_SET_FPREG:
-       case UWOP_PUSH_MACHFRAME:
-         break;
-       case UWOP_ALLOC_LARGE:
-         if (PEX64_UNWCODE_INFO (t[1]) == 0)
-           {
-             i += 1;
-             break;
-           }
-         else if (PEX64_UNWCODE_INFO (t[1]) == 1)
-           {
-             i += 2;
-             break;
-           }
-         /* fall through.  */
-       default:
-         fprintf (file, "\t contains unknown code (%u).\n",
-                  (unsigned int) PEX64_UNWCODE_CODE (t[1]));
-         return;
-       case UWOP_SAVE_NONVOL:
-       case UWOP_SAVE_XMM:
-       case UWOP_SAVE_XMM128:
-         i++;
-         break;
-       case UWOP_SAVE_NONVOL_FAR:
-       case UWOP_SAVE_XMM_FAR:
-       case UWOP_SAVE_XMM128_FAR:
-         i += 2;
-         break;
+         const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
+
+         if (PEX64_UNWCODE_CODE (dta[1]) != 6)
+           break;
+         fprintf (file, " %02x %01x", dta[0], PEX64_UNWCODE_INFO (dta[1]));
        }
+      fputc ('\n', file);
     }
-  fprintf (file, "\t At pc 0x");
-  fprintf_vma (file, pc_addr);
-  fprintf (file, " there are the following saves (in logical order).\n");
-  for (i = insns_count; i > 0;)
+
+  for (; i < ui->CountOfCodes; i++)
     {
-      --i;
-      dta = insns[i];
-      fprintf (file, "\t  insn ends at pc+0x%02x: ", (unsigned int) dta[0]);
+      const bfd_byte *dta = ui->rawUnwindCodes + 2 * i;
+      unsigned int info = PEX64_UNWCODE_INFO (dta[1]);
+      int unexpected = FALSE;
+
+      fprintf (file, "\t  pc+0x%02x: ", (unsigned int) dta[0]);
       switch (PEX64_UNWCODE_CODE (dta[1]))
        {
        case UWOP_PUSH_NONVOL:
-         fprintf (file, "push %s.\n", pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
+         fprintf (file, "push %s", pex_regs[info]);
          break;
        case UWOP_ALLOC_LARGE:
-         if (PEX64_UNWCODE_INFO (dta[1]) == 0)
+         if (info == 0)
            {
-             tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
-             tmp *= 8;
+             tmp = bfd_get_16 (abfd, &dta[2]) * 8;
+             i++;
            }
          else
-           tmp = (bfd_vma) (*((unsigned int *)&dta[2]));
-         fprintf (file, "save stack region of size 0x");
-         fprintf_vma (file, tmp);
-         fprintf (file,".\n");
+           {
+             tmp = bfd_get_32 (abfd, &dta[2]);
+             i += 2;
+           }
+         fprintf (file, "alloc large area: rsp = rsp - 0x%x", tmp);
          break;
        case UWOP_ALLOC_SMALL:
-         tmp = (bfd_vma) PEX64_UNWCODE_INFO (dta[1]);
-         tmp += 1;
-         tmp *= 8;
-         fprintf (file, "save stack region of size 0x");
-         fprintf_vma (file, tmp);
-         fprintf (file,".\n");
+         fprintf (file, "alloc small area: rsp = rsp - 0x%x", (info + 1) * 8);
          break;
        case UWOP_SET_FPREG:
-         tmp = (bfd_vma) PEX64_UNWCODE_INFO (dta[1]);
-         tmp *= 16;
-         fprintf (file, "FPReg = (FrameReg) + 0x");
-         fprintf_vma (file, tmp);
-         fprintf (file, ".\n");
+         /* According to the documentation, info field is unused.  */
+         fprintf (file, "FPReg: %s = rsp + 0x%x (info = 0x%x)",
+                  pex_regs[ui->FrameRegister],
+                  (unsigned int) ui->FrameOffset * 16, info);
+         unexpected = ui->FrameRegister == 0;
+         save_allowed = FALSE;
          break;
        case UWOP_SAVE_NONVOL:
-         fprintf (file, "mov %s at 0x",
-                  pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
-         tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
-         tmp *= 8;
-         fprintf_vma (file, tmp);
-         fprintf (file, ".\n");
+         tmp = bfd_get_16 (abfd, &dta[2]) * 8;
+         i++;
+         fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
+         unexpected = !save_allowed;
          break;
        case UWOP_SAVE_NONVOL_FAR:
-         fprintf (file, "mov %s at 0x",
-                  pex_regs[PEX64_UNWCODE_INFO (dta[1])]);
-         tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
-         fprintf_vma (file, tmp);
-         fprintf (file, ".\n");
+         tmp = bfd_get_32 (abfd, &dta[2]);
+         i += 2;
+         fprintf (file, "save %s at rsp + 0x%x", pex_regs[info], tmp);
+         unexpected = !save_allowed;
          break;
        case UWOP_SAVE_XMM:
-         tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
-         tmp *= 8;
-         fprintf (file, "mov mm%u at 0x",
-                  (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
-         fprintf_vma (file, tmp);
-         fprintf (file, ".\n");
+         if (ui->Version == 1)
+           {
+             tmp = bfd_get_16 (abfd, &dta[2]) * 8;
+             i++;
+             fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
+             unexpected = !save_allowed;
+           }
+         else if (ui->Version == 2)
+           {
+             fprintf (file, "v2-opc6 %02x %01x", dta[0], info);
+             unexpected = TRUE;
+           }
          break;
        case UWOP_SAVE_XMM_FAR:
-         tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
-         fprintf (file, "mov mm%u at 0x",
-                  (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
-         fprintf_vma (file, tmp);
-         fprintf (file, ".\n");
+         tmp = bfd_get_32 (abfd, &dta[2]) * 8;
+         i += 2;
+         fprintf (file, "save mm%u at rsp + 0x%x", info, tmp);
+         unexpected = !save_allowed;
          break;
        case UWOP_SAVE_XMM128:
-         tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
-         tmp *= 16;
-         fprintf (file, "mov xmm%u at 0x",
-                  (unsigned int) PEX64_UNWCODE_INFO ( dta[1]));
-         fprintf_vma (file, tmp);
-         fprintf (file, ".\n");
+         tmp = bfd_get_16 (abfd, &dta[2]) * 16;
+         i++;
+         fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
+         unexpected = !save_allowed;
          break;
        case UWOP_SAVE_XMM128_FAR:
-         tmp = (bfd_vma) (*((unsigned int *) &dta[2]));
-         fprintf (file, "mov xmm%u at 0x",
-                  (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
-         fprintf_vma (file, tmp);
-         fprintf (file, ".\n");
+         tmp = bfd_get_32 (abfd, &dta[2]) * 16;
+         i += 2;
+         fprintf (file, "save xmm%u at rsp + 0x%x", info, tmp);
+         unexpected = !save_allowed;
          break;
        case UWOP_PUSH_MACHFRAME:
          fprintf (file, "interrupt entry (SS, old RSP, EFLAGS, CS, RIP");
-         if (PEX64_UNWCODE_INFO (dta[1]) == 0)
-           {
-             fprintf (file, ")");
-           }
-         else if (PEX64_UNWCODE_INFO (dta[1]) == 1)
-           {
-             fprintf (file, ",ErrorCode)");
-           }
+         if (info == 0)
+           fprintf (file, ")");
+         else if (info == 1)
+           fprintf (file, ",ErrorCode)");
          else
-           fprintf (file, ", unknown(%u))",
-                    (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
-         fprintf (file,".\n");
+           fprintf (file, ", unknown(%u))", info);
          break;
        default:
-         fprintf (file, "unknown code %u.\n",
-                  (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
-         break;
+         /* Already caught by the previous scan.  */
+         abort ();
       }
+      if (unexpected)
+       fprintf (file, " [Unexpected!]");
+      fputc ('\n', file);
     }
 }
 
+/* Check wether section SEC_NAME contains the xdata at address ADDR.  */
+
 static asection *
 pex64_get_section_by_rva (bfd *abfd, bfd_vma addr, const char *sec_name)
 {
@@ -303,110 +290,123 @@ pex64_get_section_by_rva (bfd *abfd, bfd_vma addr, const char *sec_name)
   return section;
 }
 
+/* Dump xdata at rva ADDR to FILE for ABFD.  */
+
 static void
-pex64_dump_xdata (FILE *file, bfd *abfd, bfd_vma addr, bfd_vma pc_addr,
-                 bfd_vma *endx)
+pex64_dump_xdata (FILE *file, bfd *abfd,
+                 asection *xdata_section, bfd_byte *xdata,
+                 bfd_vma addr, bfd_vma *endx)
 {
-  asection *section = pex64_get_section_by_rva (abfd, addr, ".rdata");
-  bfd_vma vsize;
-  bfd_byte *data = NULL;
+  bfd_vma vaddr;
   bfd_vma end_addr;
+  struct pex64_unwind_info ui;
 
-  if (!section)
-    section = pex64_get_section_by_rva (abfd, addr, ".data");
-  if (!section)
-    section = pex64_get_section_by_rva (abfd, addr, ".xdata");
-  if (!section)
-    {
-      section = pex64_get_section_by_rva (abfd, addr, ".pdata");
-      if (section)
-       {
-         fprintf (file, "\t Shares information with pdata element at 0x");
-         fprintf_vma (file, addr + pe_data (abfd)->pe_opthdr.ImageBase);
-         fprintf (file, ".\n");
-       }
-    }
-  if (!section)
-    return;
-
-  vsize = section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
-  addr -= vsize;
+  vaddr = xdata_section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
+  addr -= vaddr;
 
   if (endx)
-    end_addr = endx[0] - vsize;
+    end_addr = endx[0] - vaddr;
   else
-    end_addr = (section->rawsize != 0 ? section->rawsize : section->size);
-
-  if (bfd_malloc_and_get_section (abfd, section, &data))
-    {
-      struct pex64_unwind_info ui;
+    end_addr = (xdata_section->rawsize != 0 ?
+               xdata_section->rawsize : xdata_section->size);
 
-      if (!data)
-       return;
 
-      pex64_get_unwind_info (abfd, &ui, &data[addr]);
+  pex64_get_unwind_info (abfd, &ui, &xdata[addr]);
 
-      if (ui.Version != 1)
+  if (ui.Version != 1 && ui.Version != 2)
+    {
+      unsigned int i;
+      fprintf (file, "\tVersion %u (unknown).\n",
+              (unsigned int) ui.Version);
+      for (i = 0; addr < end_addr; addr += 1, i++)
        {
-         fprintf (file, "\tVersion %u (unknown).\n", (unsigned int) ui.Version);
-         return;
+         if ((i & 15) == 0)
+           fprintf (file, "\t  %03x:", i);
+         fprintf (file, " %02x", xdata[addr]);
+         if ((i & 15) == 15)
+           fprintf (file, "\n");
        }
+      if ((i & 15) != 0)
+       fprintf (file, "\n");
+      return;
+    }
 
-      fprintf (file, "\tFlags: ");
-      switch (ui.Flags)
-       {
-       case UNW_FLAG_NHANDLER:
-         fprintf (file, "UNW_FLAG_NHANDLER");
-         break;
-       case UNW_FLAG_EHANDLER:
-         fprintf (file, "UNW_FLAG_EHANDLER");
-         break;
-       case UNW_FLAG_UHANDLER:
-         fprintf (file, "UNW_FLAG_UHANDLER");
-         break;
-       case UNW_FLAG_FHANDLER:
-         fprintf (file, "UNW_FLAG_FHANDLER = (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER)");
-         break;
-       case UNW_FLAG_CHAININFO:
-         fprintf (file, "UNW_FLAG_CHAININFO");
-         break;
-       default:
-         fprintf (file, "unknown flags value 0x%x", (unsigned int) ui.Flags);
-         break;
-       }
+  fprintf (file, "\tVersion: %d, Flags: ", ui.Version);
+  switch (ui.Flags)
+    {
+    case UNW_FLAG_NHANDLER:
+      fprintf (file, "none");
+      break;
+    case UNW_FLAG_EHANDLER:
+      fprintf (file, "UNW_FLAG_EHANDLER");
+      break;
+    case UNW_FLAG_UHANDLER:
+      fprintf (file, "UNW_FLAG_UHANDLER");
+      break;
+    case UNW_FLAG_FHANDLER:
+      fprintf
+       (file, "UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER");
+      break;
+    case UNW_FLAG_CHAININFO:
+      fprintf (file, "UNW_FLAG_CHAININFO");
+      break;
+    default:
+      fprintf (file, "unknown flags value 0x%x", (unsigned int) ui.Flags);
+      break;
+    }
+  fputc ('\n', file);
+  fprintf (file, "\tNbr codes: %u, ", (unsigned int) ui.CountOfCodes);
+  fprintf (file, "Prologue size: 0x%02x, Frame offset: 0x%x, ",
+          (unsigned int) ui.SizeOfPrologue, (unsigned int) ui.FrameOffset);
+  fprintf (file, "Frame reg: %s\n",
+          ui.FrameRegister == 0 ? "none"
+          : pex_regs[(unsigned int) ui.FrameRegister]);
+
+  pex64_xdata_print_uwd_codes (file, abfd, &ui);
+
+  switch (ui.Flags)
+    {
+    case UNW_FLAG_EHANDLER:
+    case UNW_FLAG_UHANDLER:
+    case UNW_FLAG_FHANDLER:
+      fprintf (file, "\tHandler: ");
+      fprintf_vma (file, (ui.rva_ExceptionHandler
+                         + pe_data (abfd)->pe_opthdr.ImageBase));
       fprintf (file, ".\n");
-      if (ui.CountOfCodes != 0)
-       fprintf (file, "\tEntry has %u codes.", (unsigned int) ui.CountOfCodes);
-      fprintf (file, "\tPrologue size: %u, Frame offset = 0x%x.\n",
-              (unsigned int) ui.SizeOfPrologue, (unsigned int) ui.FrameOffset);
-      fprintf (file, "\tFrame register is %s.\n",
-       ui.FrameRegister == 0 ? "none"
-                             : pex_regs[(unsigned int) ui.FrameRegister]);
-
-      pex64_xdata_print_uwd_codes (file, &ui, pc_addr);
-
-      /* Now we need end of this xdata block.  */
-      addr += ui.SizeOfBlock;
-      if (addr < end_addr)
-        {
-         unsigned int i;
-         fprintf (file,"\tUser data:\n");
-         for (i = 0; addr < end_addr; addr += 1, i++)
-           {
-             if ((i & 15) == 0)
-               fprintf (file, "\t  %03x:", i);
-             fprintf (file, " %02x", data[addr]);
-             if ((i & 15) == 15)
-               fprintf (file, "\n");
-           }
-         if ((i & 15) != 0)
+      break;
+    case UNW_FLAG_CHAININFO:
+      fprintf (file, "\tChain: start: ");
+      fprintf_vma (file, ui.rva_BeginAddress);
+      fprintf (file, ", end: ");
+      fprintf_vma (file, ui.rva_EndAddress);
+      fprintf (file, "\n\t unwind data: ");
+      fprintf_vma (file, ui.rva_UnwindData);
+      fprintf (file, ".\n");
+      break;
+    }
+
+  /* Now we need end of this xdata block.  */
+  addr += ui.SizeOfBlock;
+  if (addr < end_addr)
+    {
+      unsigned int i;
+      fprintf (file,"\tUser data:\n");
+      for (i = 0; addr < end_addr; addr += 1, i++)
+       {
+         if ((i & 15) == 0)
+           fprintf (file, "\t  %03x:", i);
+         fprintf (file, " %02x", xdata[addr]);
+         if ((i & 15) == 15)
            fprintf (file, "\n");
-        }
+       }
+      if ((i & 15) != 0)
+       fprintf (file, "\n");
     }
-  if (data != NULL)
-    free (data);
 }
 
+/* Helper function to sort xdata.  The entries of xdata are sorted to know
+   the size of each entry.  */
+
 static int
 sort_xdata_arr (const void *l, const void *r)
 {
@@ -418,71 +418,74 @@ sort_xdata_arr (const void *l, const void *r)
   return (*lp < *rp ? -1 : 1);
 }
 
+/* Display unwind tables for x86-64.  */
+
 static bfd_boolean
 pex64_bfd_print_pdata (bfd *abfd, void *vfile)
 {
   FILE *file = (FILE *) vfile;
-  bfd_byte *data = NULL;
-  asection *section = bfd_get_section_by_name (abfd, ".pdata");
-  bfd_size_type datasize = 0;
+  bfd_byte *pdata = NULL;
+  bfd_byte *xdata = NULL;
+  asection *pdata_section = bfd_get_section_by_name (abfd, ".pdata");
+  asection *xdata_section;
+  bfd_vma xdata_base;
   bfd_size_type i;
   bfd_size_type stop;
   bfd_vma prev_beginaddress = 0;
+  bfd_vma prev_unwinddata_rva = 0;
+  bfd_vma imagebase;
   int onaline = PDATA_ROW_SIZE;
   int seen_error = 0;
-  bfd_vma *xdata_arr;
+  bfd_vma *xdata_arr = NULL;
   int xdata_arr_cnt;
 
-  if (section == NULL
-      || coff_section_data (abfd, section) == NULL
-      || pei_section_data (abfd, section) == NULL)
+  /* Sanity checks.  */
+  if (pdata_section == NULL
+      || coff_section_data (abfd, pdata_section) == NULL
+      || pei_section_data (abfd, pdata_section) == NULL)
     return TRUE;
 
-  stop = pei_section_data (abfd, section)->virt_size;
+  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);
 
+  /* Display functions table.  */
   fprintf (file,
           _("\nThe Function Table (interpreted .pdata section contents)\n"));
 
   fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t  UnwindData\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;
-    }
+  if (!bfd_malloc_and_get_section (abfd, pdata_section, &pdata))
+    goto done;
 
+  /* Table of xdata entries.  */
   xdata_arr = (bfd_vma *) xmalloc (sizeof (bfd_vma) * ((stop / onaline) + 1));
   xdata_arr_cnt = 0;
-  /* Do sanity check of pdata.  */
+
+  imagebase = pe_data (abfd)->pe_opthdr.ImageBase;
+
   for (i = 0; i < stop; i += onaline)
     {
       struct pex64_runtime_function rf;
 
       if (i + PDATA_ROW_SIZE > stop)
        break;
-      pex64_get_runtime_function (abfd, &rf, &data[i]);
+      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
 
       if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
          && rf.rva_UnwindData == 0)
        /* We are probably into the padding of the section now.  */
        break;
       fputc (' ', file);
-      fprintf_vma (file, i + section->vma);
+      fprintf_vma (file, i + pdata_section->vma);
       fprintf (file, ":\t");
-      fprintf_vma (file, rf.rva_BeginAddress);
-      fputc (' ', file);
-      fprintf_vma (file, rf.rva_EndAddress);
-      fputc (' ', file);
-      fprintf_vma (file, rf.rva_UnwindData);
+      fprintf_vma (file, imagebase + rf.rva_BeginAddress);
+      fprintf (file, " ");
+      fprintf_vma (file, imagebase + rf.rva_EndAddress);
+      fprintf (file, " ");
+      fprintf_vma (file, imagebase + rf.rva_UnwindData);
       fprintf (file, "\n");
       if (i != 0 && rf.rva_BeginAddress <= prev_beginaddress)
        {
@@ -507,17 +510,12 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
          seen_error = 1;
          fprintf (file, "  has negative unwind address\n");
        }
-      if (rf.rva_UnwindData && !rf.isChained)
+      if (rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
         xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
     }
 
   if (seen_error)
-    {
-      free (data);
-      free (xdata_arr);
-
-      return TRUE;
-    }
+    goto done;
 
   /* Add end of list marker.  */
   xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0);
@@ -527,15 +525,30 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
     qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma),
           sort_xdata_arr);
 
-  /* Do dump of pdata related xdata.  */
+  /* 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");
+  if (!xdata_section)
+    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".xdata");
+  if (!xdata_section)
+    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".pdata");
+  if (!xdata_section)
+    xdata_section = pex64_get_section_by_rva (abfd, xdata_base, ".text");
+  if (!xdata_section
+      || !bfd_malloc_and_get_section (abfd, xdata_section, &xdata))
+    goto done;
 
+  /* Do dump of pdata related xdata.  */
   for (i = 0; i < stop; i += onaline)
     {
       struct pex64_runtime_function rf;
 
       if (i + PDATA_ROW_SIZE > stop)
        break;
-      pex64_get_runtime_function (abfd, &rf, &data[i]);
+      pex64_get_runtime_function (abfd, &rf, &pdata[i]);
 
       if (rf.rva_BeginAddress == 0 && rf.rva_EndAddress == 0
          && rf.rva_UnwindData == 0)
@@ -543,19 +556,48 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
        break;
       if (i == 0)
         fprintf (file, "\nDump of .xdata\n");
+
       fputc (' ', file);
-      fprintf_vma (file, rf.rva_UnwindData);
-      fprintf (file, ":\n");
+      fprintf_vma (file, rf.rva_UnwindData + imagebase);
+
+      if (prev_unwinddata_rva == rf.rva_UnwindData)
+       {
+         /* Do not dump again the xdata for the same entry.  */
+         fprintf (file, " also used for function at ");
+         fprintf_vma (file, rf.rva_BeginAddress + imagebase);
+         fputc ('\n', file);
+         continue;
+       }
+      else
+       prev_unwinddata_rva = rf.rva_UnwindData;
 
-      rf.rva_BeginAddress += pe_data (abfd)->pe_opthdr.ImageBase;
-      rf.rva_EndAddress += pe_data (abfd)->pe_opthdr.ImageBase;
+      fprintf (file, " (rva: %08x): for function at ",
+              (unsigned int) rf.rva_UnwindData);
+      fprintf_vma (file, rf.rva_BeginAddress + imagebase);
+      fputc ('\n', file);
 
       if (rf.rva_UnwindData != 0)
        {
-         if (rf.isChained)
+         if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
            {
-             fprintf (file, "\t shares information with pdata element at 0x");
-             fprintf_vma (file, rf.rva_UnwindData);
+             bfd_vma altent = PEX64_GET_UNWINDDATA_UNIFIED_RVA (&rf);
+             bfd_vma pdata_vma = bfd_get_section_vma (abfd, pdata_section);
+             struct pex64_runtime_function arf;
+
+             fprintf (file, "\t shares information with ");
+             altent += imagebase;
+
+             if (altent >= pdata_vma
+                 && (altent + PDATA_ROW_SIZE <= pdata_vma
+                     + pei_section_data (abfd, pdata_section)->virt_size))
+               {
+                 pex64_get_runtime_function
+                   (abfd, &arf, &pdata[altent - pdata_vma]);
+                 fprintf (file, "pdata element at 0x");
+                 fprintf_vma (file, arf.rva_UnwindData);
+               }
+             else
+               fprintf (file, "unknown pdata element");
              fprintf (file, ".\n");
            }
          else
@@ -576,14 +618,16 @@ pex64_bfd_print_pdata (bfd *abfd, void *vfile)
              if (p[0] == ~((bfd_vma) 0))
                p = NULL;
 
-             pex64_dump_xdata (file, abfd, rf.rva_UnwindData,
-                               rf.rva_BeginAddress, p);
+             pex64_dump_xdata (file, abfd, xdata_section, xdata,
+                               rf.rva_UnwindData, p);
            }
        }
     }
 
-  free (data);
+ done:
+  free (pdata);
   free (xdata_arr);
+  free (xdata);
 
   return TRUE;
 }
index 601a68e8f11381b0c30a7a6026568b05b85a41f8..3b372769a0e64ead660c823dab039cc91746e297 100644 (file)
@@ -368,7 +368,6 @@ struct pex64_runtime_function
   bfd_vma rva_BeginAddress;
   bfd_vma rva_EndAddress;
   bfd_vma rva_UnwindData;
-  unsigned int isChained : 1;
 };
 
 struct external_pex64_runtime_function
@@ -393,8 +392,8 @@ struct external_pex64_runtime_function
 #define UWOP_SET_FPREG       3
 #define UWOP_SAVE_NONVOL      4
 #define UWOP_SAVE_NONVOL_FAR  5
-#define UWOP_SAVE_XMM        6
-#define UWOP_SAVE_XMM_FAR     7
+#define UWOP_SAVE_XMM        6 /* Deprecated, redefined in version 2.  */
+#define UWOP_SAVE_XMM_FAR     7        /* Deprecated.  */
 #define UWOP_SAVE_XMM128      8
 #define UWOP_SAVE_XMM128_FAR  9
 #define UWOP_PUSH_MACHFRAME   10
@@ -441,14 +440,10 @@ struct pex64_unwind_info
   bfd_vma FrameOffset;
   bfd_vma sizeofUnwindCodes;
   bfd_byte *rawUnwindCodes;
-  /* Valid for UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER.  */
-  bfd_vma CountOfScopes;
-  bfd_byte *rawScopeEntries;
-  bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER.  */
-  bfd_vma rva_TerminationHandler; /* UNW_FLAG_UHANDLER.  */
-  bfd_vma rva_FrameHandler; /* UNW_FLAG_FHANDLER.  */
-  bfd_vma FrameHandlerArgument; /* UNW_FLAG_FHANDLER.  */
-  bfd_vma rva_FunctionEntry; /* UNW_FLAG_CHAININFO.  */
+  bfd_vma rva_ExceptionHandler; /* UNW_EHANDLER or UNW_FLAG_UHANDLER.  */
+  bfd_vma rva_BeginAddress;    /* UNW_FLAG_CHAININFO.  */
+  bfd_vma rva_EndAddress;      /* UNW_FLAG_CHAININFO.  */
+  bfd_vma rva_UnwindData;      /* UNW_FLAG_CHAININFO.  */
 };
 
 struct external_pex64_unwind_info