This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch]: Improve x86_64-mingw32 dump of xdata/pdata


Hello,

I have intensively used objdump on x64 windows binaries to implement the gdb SEH unwinder.
For that, I have modified it to make it endian neutral and more efficient. I added support
of version 2 opcodes, made the output more useful to check with assembly code, fixed at least
one issue with chaining.

So this patch changes the output, but I think it is better (but might be a matter of taste).

This code was longly tested with both MS and gcc generated binaries.

Ok for trunk ?

Tristan.

bfd/
2013-11-21  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-21  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.

--- a/bfd/pei-x86_64.c
+++ b/bfd/pei-x86_64.c
@@ -76,11 +76,15 @@
 #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;
 }
diff --git a/include/coff/pe.h b/include/coff/pe.h
index 601a68e..3b37276 100644
--- a/include/coff/pe.h
+++ b/include/coff/pe.h
@@ -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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]