Exemplo n.º 1
0
Arquivo: rddbg.c Projeto: CromFr/gdb
static void
stab_context (void)
{
  int i;

  fprintf (stderr, _("Last stabs entries before error:\n"));
  fprintf (stderr, "n_type n_desc n_value  string\n");

  i = saved_stabs_index;
  do
    {
      struct saved_stab *stabp;

      stabp = saved_stabs + i;
      if (stabp->string != NULL)
	{
	  const char *s;

	  s = bfd_get_stab_name (stabp->type);
	  if (s != NULL)
	    fprintf (stderr, "%-6s", s);
	  else if (stabp->type == 0)
	    fprintf (stderr, "HdrSym");
	  else
	    fprintf (stderr, "%-6d", stabp->type);
	  fprintf (stderr, " %-6d ", stabp->desc);
	  fprintf_vma (stderr, stabp->value);
	  if (stabp->type != 0)
	    fprintf (stderr, " %s", stabp->string);
	  fprintf (stderr, "\n");
	}
      i = (i + 1) % SAVE_STABS_COUNT;
    }
  while (i != saved_stabs_index);
}
Exemplo n.º 2
0
void
fprint_value (FILE *file, valueT val)
{
  if (sizeof (val) <= sizeof (long))
    {
      fprintf (file, "%ld", (long) val);
      return;
    }
#ifdef BFD_ASSEMBLER
  if (sizeof (val) <= sizeof (bfd_vma))
    {
      fprintf_vma (file, val);
      return;
    }
#endif
  abort ();
}
Exemplo n.º 3
0
static bfd_boolean
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 *xdata_section = NULL;
  bfd_vma xdata_base;
  bfd_size_type i;
  bfd_size_type datasize;
  bfd_size_type stop;
  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;
  bfd_boolean virt_size_is_zero = FALSE;

  /* 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, pdata_section)->virt_size;
  if ((stop % onaline) != 0)
    fprintf (file,
	     _("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\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 = TRUE;
    }
  else if (datasize < stop)
      {
	fprintf (file,
		 _("Warning: %s section size (%ld) is smaller than virtual size (%ld)\n"),
		 pdata_section->name, (unsigned long) datasize,
		 (unsigned long) stop);
	/* Be sure not to read passed datasize.  */
	stop = datasize / onaline;
      }

  /* Display functions table.  */
  fprintf (file,
	   _("\nThe Function Table (interpreted %s section contents)\n"),
	   pdata_section->name);

  fprintf (file, _("vma:\t\t\tBeginAddress\t EndAddress\t  UnwindData\n"));

  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;

  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)
    {
      struct pex64_runtime_function rf;

      if (i + PDATA_ROW_SIZE > stop)
	break;

      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 + pdata_section->vma);
      fprintf (file, ":\t");
      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)
	{
	  seen_error = 1;
	  fprintf (file, "  has %s begin address as predecessor\n",
	    (rf.rva_BeginAddress < prev_beginaddress ? "smaller" : "same"));
        }
      prev_beginaddress = rf.rva_BeginAddress;
      /* Now we check for negative addresses.  */
      if ((prev_beginaddress & 0x80000000) != 0)
	{
	  seen_error = 1;
	  fprintf (file, "  has negative begin address\n");
	}
      if ((rf.rva_EndAddress & 0x80000000) != 0)
	{
	  seen_error = 1;
	  fprintf (file, "  has negative end address\n");
	}
      if ((rf.rva_UnwindData & 0x80000000) != 0)
	{
	  seen_error = 1;
	  fprintf (file, "  has negative unwind address\n");
	}
      else if ((rf.rva_UnwindData && !PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
		|| virt_size_is_zero)
	xdata_arr[xdata_arr_cnt++] = rf.rva_UnwindData;
    }

  if (seen_error)
    goto done;

  /* Add end of list marker.  */
  xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0);

  /* Sort start RVAs of xdata.  */
  if (xdata_arr_cnt > 1)
    qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma),
	   sort_xdata_arr);

  /* Find the section containing the unwind data (.xdata).  */
  xdata_base = xdata_arr[0];
  /* For sections with long names, first look for the same
     section name, replacing .pdata by .xdata prefix.  */
  if (strcmp (pdata_section->name, ".pdata") != 0)
    {
      size_t len = strlen (pdata_section->name);
      char *xdata_name = alloca (len + 1);

      xdata_name = memcpy (xdata_name, pdata_section->name, len + 1);
      /* Transform .pdata prefix into .xdata prefix.  */
      if (len > 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");
  /* 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 && 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)
    {
      struct pex64_runtime_function rf;

      if (i + PDATA_ROW_SIZE > stop)
	break;

      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;
      if (i == 0)
        fprintf (file, _("\nDump of %s\n"), xdata_section->name);

      fputc (' ', file);
      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;

      fprintf (file, " (rva: %08x): ",
	       (unsigned int) rf.rva_UnwindData);
      fprintf_vma (file, rf.rva_BeginAddress + imagebase);
      fprintf (file, " - ");
      fprintf_vma (file, rf.rva_EndAddress + imagebase);
      fputc ('\n', file);

      if (rf.rva_UnwindData != 0 || virt_size_is_zero)
	{
	  if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
	    {
	      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
	    {
	      bfd_vma *p;

	      /* Search for the current entry in the sorted array.  */
	      p = (bfd_vma *)
	          bsearch (&rf.rva_UnwindData, xdata_arr,
			   (size_t) xdata_arr_cnt, sizeof (bfd_vma),
			   sort_xdata_arr);

	      /* Advance to the next pointer into the xdata section.  We may
		 have shared xdata entries, which will result in a string of
		 identical pointers in the array; advance past all of them.  */
	      while (p[0] <= rf.rva_UnwindData)
		++p;

	      if (p[0] == ~((bfd_vma) 0))
		p = NULL;

	      pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf);
	    }
	}
    }

 done:
  free (pdata);
  free (xdata_arr);
  free (xdata);

  return TRUE;
}
Exemplo n.º 4
0
static void
pex64_dump_xdata (FILE *file, bfd *abfd,
		  asection *xdata_section, bfd_byte *xdata, bfd_vma *endx,
		  struct pex64_runtime_function *rf)
{
  bfd_vma vaddr;
  bfd_vma end_addr;
  bfd_vma addr = rf->rva_UnwindData;
  bfd_size_type sec_size = xdata_section->rawsize > 0 ? xdata_section->rawsize : xdata_section->size;
  struct pex64_unwind_info ui;

  vaddr = xdata_section->vma - pe_data (abfd)->pe_opthdr.ImageBase;
  addr -= vaddr;

  /* PR 17512: file: 2245-7442-0.004.  */
  if (addr >= sec_size)
    {
      fprintf (file, _("warning: xdata section corrupt\n"));
      return;
    }

  if (endx)
    {
      end_addr = endx[0] - vaddr;
      /* PR 17512: file: 2245-7442-0.004.  */
      if (end_addr > sec_size)
	{
	  fprintf (file, _("warning: xdata section corrupt"));
	  end_addr = sec_size;
	}
    }
  else
    end_addr = sec_size;

  pex64_get_unwind_info (abfd, &ui, &xdata[addr]);

  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++)
	{
	  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, "\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]);

  /* PR 17512: file: 2245-7442-0.004.  */
  if (ui.CountOfCodes * 2 + ui.rawUnwindCodes > xdata + xdata_section->size)
    fprintf (file, _("Too many unwind codes (%ld)\n"), (long) ui.CountOfCodes);
  else
    pex64_xdata_print_uwd_codes (file, abfd, &ui, rf);

  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");
      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");
    }
}
Exemplo n.º 5
0
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_size_type i;
  bfd_size_type start, stop;
  int onaline = PDATA_ROW_SIZE;

  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\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;
    }

  start = 0;

  for (i = start; i < stop; i += onaline)
    {
      struct pex64_runtime_function rf;

      if (i + PDATA_ROW_SIZE > stop)
	break;
      pex64_get_runtime_function (abfd, &rf, &data[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 (file, ":\t");
      rf.rva_BeginAddress += pe_data (abfd)->pe_opthdr.ImageBase;
      fprintf_vma (file, rf.rva_BeginAddress);
      fputc (' ', file);
      rf.rva_EndAddress += pe_data (abfd)->pe_opthdr.ImageBase;
      fprintf_vma (file, rf.rva_EndAddress);
      fputc (' ', file);
      fprintf_vma (file, rf.rva_UnwindData);
      fprintf (file, "\n");

      if (rf.rva_UnwindData != 0)
	{
	  if (rf.isChained)
	    {
	      fprintf (file, "\t shares information with pdata element at 0x");
	      fprintf_vma (file, rf.rva_UnwindData + pe_data (abfd)->pe_opthdr.ImageBase);
	      fprintf (file, ".\n");
	    }
	  else
	    pex64_dump_xdata (file, abfd, rf.rva_UnwindData, rf.rva_BeginAddress);
	}
    }

  free (data);

  return TRUE;
}
Exemplo n.º 6
0
static void
pex64_dump_xdata (FILE *file, bfd *abfd, bfd_vma addr, bfd_vma pc_addr)
{
  asection *section = pex64_get_section_by_rva (abfd, addr, ".rdata");
  bfd_vma vsize;
  bfd_byte *data = NULL;
  bfd_vma i;

  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;
  if (bfd_malloc_and_get_section (abfd, section, &data))
    {
      struct pex64_unwind_info ui;

      if (!data)
	return;

      pex64_get_unwind_info (abfd, &ui, &data[addr]);

      if (ui.Version != 1)
	{
	  fprintf (file, "\tVersion %u (unknown).\n", (unsigned int) ui.Version);
	  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, ".\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 ? "CFA"
			      : pex_regs[(unsigned int) ui.FrameRegister]);

      pex64_xdata_print_uwd_codes (file, &ui, pc_addr);
      
      switch (ui.Flags)
	{
	case UNW_FLAG_NHANDLER:
	  return;
	case UNW_FLAG_EHANDLER:
	  fprintf (file, "\texception_handler at 0x%x.\n", (unsigned int) ui.rva_ExceptionHandler);
	  break;
	case UNW_FLAG_UHANDLER:
	  fprintf (file, "\ttermination_handler at 0x%x.\n", (unsigned int) ui.rva_TerminationHandler);
	case UNW_FLAG_FHANDLER:
	  fprintf (file, "\tframe_handler at 0x%x.\n", (unsigned int) ui.rva_FrameHandler);
	  fprintf (file, "\t Argument for FrameHandler: 0x%x.\n",
		   (unsigned int) ui.FrameHandlerArgument);
	  return;
	case UNW_FLAG_CHAININFO:
	  fprintf (file, "\t Function Entry: 0x%x\n", (unsigned int) ui.rva_FunctionEntry);
	  return;
	default:
	  fprintf (file, "\t Unknown flag value of 0x%x\n", (unsigned int) ui.Flags);
	  return;
	}
      fprintf (file, "\t 0x%x # of scope(s)\n", (unsigned int) ui.CountOfScopes);
      for (i = 0; i < ui.CountOfScopes; i++)
	{
	  struct pex64_scope_entry se;
	  pex64_get_scope_entry (abfd, &se, i, ui.rawScopeEntries);
	  fprintf (file, "\t scope #%u: BeginAddress: 0x%x, EndAddress: 0x%x,"
		   "\n\t\tHandlerAddress:0x%x, JumpTarget:0x%x\n",
		   (unsigned int) (i + 1),
		   (unsigned int) se.rva_BeginAddress,
		   (unsigned int) se.rva_EndAddress,
		   (unsigned int) se.rva_HandlerAddress,
		   (unsigned int) se.rva_JumpAddress);
	}
    }
  if (data != NULL)
    free (data);
}
Exemplo n.º 7
0
static void
pex64_xdata_print_uwd_codes (FILE *file, struct pex64_unwind_info *ui,
			     bfd_vma pc_addr)
{
  bfd_vma i;
  bfd_vma tmp = 0;
  const bfd_byte *insns[256];
  bfd_vma insns_count = 0;
  const bfd_byte *dta = ui->rawUnwindCodes;

  if (ui->CountOfCodes == 0 || !dta)
    return;

  /* Sort array ascending. Note: it is stored in reversed order.  */
  for (i = 0; i < ui->CountOfCodes; i++)
    {
      const bfd_byte *t;

      t = insns[insns_count++] = &dta[i * 2];
      switch (PEX64_UNWCODE_CODE (t[1]))
	{
	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;
	}
    }
  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;)
    {
      --i;
      dta = insns[i];
      fprintf (file, "\t  insn ends at 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])]);
	  break;
	case UWOP_ALLOC_LARGE:
	  if (PEX64_UNWCODE_INFO (dta[1]) == 0)
	    {
	      tmp = (bfd_vma) (*((unsigned short *) &dta[2]));
	      tmp *= 8;
	    }
	  else
	    tmp = (bfd_vma) (*((unsigned int *)&dta[2]));
	  fprintf (file, "save stack region of size 0x");
	  fprintf_vma (file, tmp);
	  fprintf (file,".\n");
	  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");
	  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");
	  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");
	  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");
	  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");
	  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");
	  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");
	  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");
	  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)");
	    }
	  else
	    fprintf (file, ", unknown(%u))",
		     (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
	  fprintf (file,".\n");
	  break;
	default:
	  fprintf (file, "unknown code %u.\n",
		   (unsigned int) PEX64_UNWCODE_INFO (dta[1]));
	  break;
      }
    }
}
Exemplo n.º 8
0
void
vfinfo (FILE *fp, const char *fmt, va_list ap, bfd_boolean is_warning)
{
  bfd_boolean fatal = FALSE;
  const char *scan;
  int arg_type;
  unsigned int arg_count = 0;
  unsigned int arg_no;
  union vfinfo_args
  {
    int i;
    long l;
    void *p;
    bfd_vma v;
    struct {
      bfd *abfd;
      asection *sec;
      bfd_vma off;
    } reladdr;
    enum
      {
	Bad,
	Int,
	Long,
	Ptr,
	Vma,
	RelAddr
      } type;
  } args[9];

  for (arg_no = 0; arg_no < sizeof (args) / sizeof (args[0]); arg_no++)
    args[arg_no].type = Bad;

  arg_count = 0;
  scan = fmt;
  while (*scan != '\0')
    {
      while (*scan != '%' && *scan != '\0')
	scan++;

      if (*scan == '%')
	{
	  scan++;

	  arg_no = arg_count;
	  if (*scan != '0' && ISDIGIT (*scan) && scan[1] == '$')
	    {
	      arg_no = *scan - '1';
	      scan += 2;
	    }

	  arg_type = Bad;
	  switch (*scan++)
	    {
	    case '\0':
	      --scan;
	      break;

	    case 'V':
	    case 'v':
	    case 'W':
	      arg_type = Vma;
	      break;

	    case 's':
	      arg_type = Ptr;
	      break;

	    case 'p':
	      if (*scan == 'A' || *scan == 'B' || *scan == 'I'
		  || *scan == 'R' || *scan == 'S' || *scan ==  'T')
		scan++;
	      arg_type = Ptr;
	      break;

	    case 'C':
	    case 'D':
	    case 'G':
	    case 'H':
	      arg_type = RelAddr;
	      break;

	    case 'd':
	    case 'u':
	      arg_type = Int;
	      break;

	    case 'l':
	      if (*scan == 'd' || *scan == 'u')
		{
		  ++scan;
		  arg_type = Long;
		}
	      break;

	    default:
	      break;
	    }
	  if (arg_type != Bad)
	    {
	      if (arg_no >= sizeof (args) / sizeof (args[0]))
		abort ();
	      args[arg_no].type = arg_type;
	      ++arg_count;
	    }
	}
    }

  for (arg_no = 0; arg_no < arg_count; arg_no++)
    {
      switch (args[arg_no].type)
	{
	case Int:
	  args[arg_no].i = va_arg (ap, int);
	  break;
	case Long:
	  args[arg_no].l = va_arg (ap, long);
	  break;
	case Ptr:
	  args[arg_no].p = va_arg (ap, void *);
	  break;
	case Vma:
	  args[arg_no].v = va_arg (ap, bfd_vma);
	  break;
	case RelAddr:
	  args[arg_no].reladdr.abfd = va_arg (ap, bfd *);
	  args[arg_no].reladdr.sec = va_arg (ap, asection *);
	  args[arg_no].reladdr.off = va_arg (ap, bfd_vma);
	  break;
	default:
	  abort ();
	}
    }

  arg_count = 0;
  while (*fmt != '\0')
    {
      const char *str = fmt;
      while (*fmt != '%' && *fmt != '\0')
	fmt++;
      if (fmt != str)
	if (fwrite (str, 1, fmt - str, fp))
	  {
	    /* Ignore.  */
	  }

      if (*fmt == '%')
	{
	  fmt++;

	  arg_no = arg_count;
	  if (*fmt != '0' && ISDIGIT (*fmt) && fmt[1] == '$')
	    {
	      arg_no = *fmt - '1';
	      fmt += 2;
	    }

	  switch (*fmt++)
	    {
	    case '\0':
	      --fmt;
	      /* Fall through.  */

	    case '%':
	      /* literal % */
	      putc ('%', fp);
	      break;

	    case 'X':
	      /* no object output, fail return */
	      config.make_executable = FALSE;
	      break;

	    case 'V':
	      /* hex bfd_vma */
	      {
		bfd_vma value = args[arg_no].v;
		++arg_count;
		fprintf_vma (fp, value);
	      }
	      break;

	    case 'v':
	      /* hex bfd_vma, no leading zeros */
	      {
		char buf[100];
		char *p = buf;
		bfd_vma value = args[arg_no].v;
		++arg_count;
		sprintf_vma (p, value);
		while (*p == '0')
		  p++;
		if (!*p)
		  p--;
		fputs (p, fp);
	      }
	      break;

	    case 'W':
	      /* hex bfd_vma with 0x with no leading zeroes taking up
		 8 spaces.  */
	      {
		char buf[100];
		bfd_vma value;
		char *p;
		int len;

		value = args[arg_no].v;
		++arg_count;
		sprintf_vma (buf, value);
		for (p = buf; *p == '0'; ++p)
		  ;
		if (*p == '\0')
		  --p;
		len = strlen (p);
		while (len < 8)
		  {
		    putc (' ', fp);
		    ++len;
		  }
		fprintf (fp, "0x%s", p);
	      }
	      break;

	    case 'F':
	      /* Error is fatal.  */
	      fatal = TRUE;
	      break;

	    case 'P':
	      /* Print program name.  */
	      fprintf (fp, "%s", program_name);
	      break;

	    case 'E':
	      /* current bfd error or errno */
	      fprintf (fp, "%s", bfd_errmsg (bfd_get_error ()));
	      break;

	    case 'C':
	    case 'D':
	    case 'G':
	    case 'H':
	      /* Clever filename:linenumber with function name if possible.
		 The arguments are a BFD, a section, and an offset.  */
	      {
		static bfd *last_bfd;
		static char *last_file;
		static char *last_function;
		bfd *abfd;
		asection *section;
		bfd_vma offset;
		asymbol **asymbols = NULL;
		const char *filename;
		const char *functionname;
		unsigned int linenumber;
		bfd_boolean discard_last;
		bfd_boolean done;

		abfd = args[arg_no].reladdr.abfd;
		section = args[arg_no].reladdr.sec;
		offset = args[arg_no].reladdr.off;
		++arg_count;

		if (abfd != NULL)
		  {
		    if (!bfd_generic_link_read_symbols (abfd))
		      einfo (_("%F%P: %pB: could not read symbols: %E\n"), abfd);

		    asymbols = bfd_get_outsymbols (abfd);
		  }

		/* The GNU Coding Standard requires that error messages
		   be of the form:

		     source-file-name:lineno: message

		   We do not always have a line number available so if
		   we cannot find them we print out the section name and
		   offset instead.  */
		discard_last = TRUE;
		if (abfd != NULL
		    && bfd_find_nearest_line (abfd, section, asymbols, offset,
					      &filename, &functionname,
					      &linenumber))
		  {
		    if (functionname != NULL
			&& (fmt[-1] == 'C' || fmt[-1] == 'H'))
		      {
			/* Detect the case where we are printing out a
			   message for the same function as the last
			   call to vinfo ("%C").  In this situation do
			   not print out the ABFD filename or the
			   function name again.  Note - we do still
			   print out the source filename, as this will
			   allow programs that parse the linker's output
			   (eg emacs) to correctly locate multiple
			   errors in the same source file.  */
			if (last_bfd == NULL
			    || last_function == NULL
			    || last_bfd != abfd
			    || (last_file == NULL) != (filename == NULL)
			    || (filename != NULL
				&& filename_cmp (last_file, filename) != 0)
			    || strcmp (last_function, functionname) != 0)
			  {
			    lfinfo (fp, _("%pB: in function `%pT':\n"),
				    abfd, functionname);

			    last_bfd = abfd;
			    if (last_file != NULL)
			      free (last_file);
			    last_file = NULL;
			    if (filename)
			      last_file = xstrdup (filename);
			    if (last_function != NULL)
			      free (last_function);
			    last_function = xstrdup (functionname);
			  }
			discard_last = FALSE;
		      }
		    else
		      lfinfo (fp, "%pB:", abfd);

		    if (filename != NULL)
		      fprintf (fp, "%s:", filename);

		    done = fmt[-1] != 'H';
		    if (functionname != NULL && fmt[-1] == 'G')
		      lfinfo (fp, "%pT", functionname);
		    else if (filename != NULL && linenumber != 0)
		      fprintf (fp, "%u%s", linenumber, done ? "" : ":");
		    else
		      done = FALSE;
		  }
		else
		  {
		    lfinfo (fp, "%pB:", abfd);
		    done = FALSE;
		  }
		if (!done)
		  lfinfo (fp, "(%pA+0x%v)", section, offset);

		if (discard_last)
		  {
		    last_bfd = NULL;
		    if (last_file != NULL)
		      {
			free (last_file);
			last_file = NULL;
		      }
		    if (last_function != NULL)
		      {
			free (last_function);
			last_function = NULL;
		      }
		  }
	      }
	      break;

	    case 'p':
	      if (*fmt == 'A')
		{
		  /* section name from a section */
		  asection *sec;
		  bfd *abfd;
		  const char *group = NULL;
		  struct coff_comdat_info *ci;

		  fmt++;
		  sec = (asection *) args[arg_no].p;
		  ++arg_count;
		  abfd = sec->owner;
		  fprintf (fp, "%s", sec->name);
		  if (abfd != NULL
		      && bfd_get_flavour (abfd) == bfd_target_elf_flavour
		      && elf_next_in_group (sec) != NULL
		      && (sec->flags & SEC_GROUP) == 0)
		    group = elf_group_name (sec);
		  else if (abfd != NULL
			   && bfd_get_flavour (abfd) == bfd_target_coff_flavour
			   && (ci = bfd_coff_get_comdat_section (sec->owner,
								 sec)) != NULL)
		    group = ci->name;
		  if (group != NULL)
		    fprintf (fp, "[%s]", group);
		}
	      else if (*fmt == 'B')
		{
		  /* filename from a bfd */
		  bfd *abfd = (bfd *) args[arg_no].p;

		  fmt++;
		  ++arg_count;
		  if (abfd == NULL)
		    fprintf (fp, "%s generated", program_name);
		  else if (abfd->my_archive != NULL
			   && !bfd_is_thin_archive (abfd->my_archive))
		    fprintf (fp, "%s(%s)", abfd->my_archive->filename,
			     abfd->filename);
		  else
		    fprintf (fp, "%s", abfd->filename);
		}
	      else if (*fmt == 'I')
		{
		  /* filename from a lang_input_statement_type */
		  lang_input_statement_type *i;

		  fmt++;
		  i = (lang_input_statement_type *) args[arg_no].p;
		  ++arg_count;
		  if (i->the_bfd != NULL
		      && i->the_bfd->my_archive != NULL
		      && !bfd_is_thin_archive (i->the_bfd->my_archive))
		    fprintf (fp, "(%s)%s", i->the_bfd->my_archive->filename,
			     i->local_sym_name);
		  else
		    fprintf (fp, "%s", i->filename);
		}
	      else if (*fmt == 'R')
		{
		  /* Print all that's interesting about a relent.  */
		  arelent *relent = (arelent *) args[arg_no].p;

		  fmt++;
		  ++arg_count;
		  lfinfo (fp, "%s+0x%v (type %s)",
			  (*(relent->sym_ptr_ptr))->name,
			  relent->addend,
			  relent->howto->name);
		}
	      else if (*fmt == 'S')
		{
		  /* Print script file and linenumber.  */
		  etree_type node;
		  etree_type *tp = (etree_type *) args[arg_no].p;

		  fmt++;
		  ++arg_count;
		  if (tp == NULL)
		    {
		      tp = &node;
		      tp->type.filename = ldlex_filename ();
		      tp->type.lineno = lineno;
		    }
		  if (tp->type.filename != NULL)
		    fprintf (fp, "%s:%u", tp->type.filename, tp->type.lineno);
		}
	      else if (*fmt == 'T')
		{
		  /* Symbol name.  */
		  const char *name = (const char *) args[arg_no].p;

		  fmt++;
		  ++arg_count;
		  if (name == NULL || *name == 0)
		    {
		      fprintf (fp, _("no symbol"));
		      break;
		    }
		  else if (demangling)
		    {
		      char *demangled;

		      demangled = bfd_demangle (link_info.output_bfd, name,
						DMGL_ANSI | DMGL_PARAMS);
		      if (demangled != NULL)
			{
			  fprintf (fp, "%s", demangled);
			  free (demangled);
			  break;
			}
		    }
		  fprintf (fp, "%s", name);
		}
	      else
		{
		  /* native (host) void* pointer, like printf */
		  fprintf (fp, "%p", args[arg_no].p);
		  ++arg_count;
		}
	      break;

	    case 's':
	      /* arbitrary string, like printf */
	      fprintf (fp, "%s", (char *) args[arg_no].p);
	      ++arg_count;
	      break;

	    case 'd':
	      /* integer, like printf */
	      fprintf (fp, "%d", args[arg_no].i);
	      ++arg_count;
	      break;

	    case 'u':
	      /* unsigned integer, like printf */
	      fprintf (fp, "%u", args[arg_no].i);
	      ++arg_count;
	      break;

	    case 'l':
	      if (*fmt == 'd')
		{
		  fprintf (fp, "%ld", args[arg_no].l);
		  ++arg_count;
		  ++fmt;
		  break;
		}
	      else if (*fmt == 'u')
		{
		  fprintf (fp, "%lu", args[arg_no].l);
		  ++arg_count;
		  ++fmt;
		  break;
		}
	      /* Fallthru */

	    default:
	      fprintf (fp, "%%%c", fmt[-1]);
	      break;
	    }
	}
    }

  if (is_warning && config.fatal_warnings)
    config.make_executable = FALSE;

  if (fatal)
    xexit (1);
}
Exemplo n.º 9
0
static bfd_boolean
pex64_bfd_print_pdata (bfd *abfd, void *vfile)
{
  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;
  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 = NULL;
  int xdata_arr_cnt;

  /* 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, pdata_section)->virt_size;
  /* PR 17512: file: 005-181405-0.004.  */
  if (stop == 0 || pdata_section->size == 0)
    {
      fprintf (file, _("No unwind data in .pdata section\n"));
      return TRUE;
    }
  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"));

  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;

  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, &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 + pdata_section->vma);
      fprintf (file, ":\t");
      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)
	{
	  seen_error = 1;
	  fprintf (file, "  has %s begin address as predecessor\n",
	    (rf.rva_BeginAddress < prev_beginaddress ? "smaller" : "same"));
        }
      prev_beginaddress = rf.rva_BeginAddress;
      /* Now we check for negative addresses.  */
      if ((prev_beginaddress & 0x80000000) != 0)
	{
	  seen_error = 1;
	  fprintf (file, "  has negative begin address\n");
	}
      if ((rf.rva_EndAddress & 0x80000000) != 0)
	{
	  seen_error = 1;
	  fprintf (file, "  has negative end address\n");
	}
      if ((rf.rva_UnwindData & 0x80000000) != 0)
	{
	  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;
    }

  if (seen_error)
    goto done;

  /* Add end of list marker.  */
  xdata_arr[xdata_arr_cnt++] = ~((bfd_vma) 0);

  /* Sort start RVAs of xdata.  */
  if (xdata_arr_cnt > 1)
    qsort (xdata_arr, (size_t) xdata_arr_cnt, sizeof (bfd_vma),
	   sort_xdata_arr);

  /* 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, &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;
      if (i == 0)
        fprintf (file, "\nDump of .xdata\n");

      fputc (' ', file);
      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;

      fprintf (file, " (rva: %08x): ",
	       (unsigned int) rf.rva_UnwindData);
      fprintf_vma (file, rf.rva_BeginAddress + imagebase);
      fprintf (file, " - ");
      fprintf_vma (file, rf.rva_EndAddress + imagebase);
      fputc ('\n', file);

      if (rf.rva_UnwindData != 0)
	{
	  if (PEX64_IS_RUNTIME_FUNCTION_CHAINED (&rf))
	    {
	      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
	    {
	      bfd_vma *p;

	      /* Search for the current entry in the sorted array.  */
	      p = (bfd_vma *)
	          bsearch (&rf.rva_UnwindData, xdata_arr,
			   (size_t) xdata_arr_cnt, sizeof (bfd_vma),
			   sort_xdata_arr);

	      /* Advance to the next pointer into the xdata section.  We may
		 have shared xdata entries, which will result in a string of
		 identical pointers in the array; advance past all of them.  */
	      while (p[0] <= rf.rva_UnwindData)
		++p;

	      if (p[0] == ~((bfd_vma) 0))
		p = NULL;

	      pex64_dump_xdata (file, abfd, xdata_section, xdata, p, &rf);
	    }
	}
    }

 done:
  free (pdata);
  free (xdata_arr);
  free (xdata);

  return TRUE;
}