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]

Re: .eh_frame_hdr refers to overlapping FDEs


Hi Elmar,
On Sun, Sep 21, 2014 at 03:28:53PM +0200, Elmar Pruesse wrote:
> I just got a fail report for our daily build on launchpad(1), which
> seems to track back to your change to binutils(2). A similar issue
> was reported for Mesa (3). But that's all Google would tell me...
[snip]
> 1: https://launchpad.net/~epr/+archive/ubuntu/arb-daily
> 2: ae6c7e33e1510665e8e043eb11a71e59414efbf3
> 3: http://www.mail-archive.com/ubuntu-bugs@lists.ubuntu.com/msg4495498.html

Thanks for reporting this to me.  I think this points to a real bug
somewhere in the toolchain, most likely in g++.

Overlapping FDEs can cause unwinder trouble, for example if you have a
proper FDE for function foo covering addresses from foo to
foo+foo_size, and a bogus FDE for foo to foo+8 then either FDE can be
selected by the unwinder for any address between foo and the following
function.  Which one is selected depends on the vagaries of qsort.  If
you're trying to unwind through address foo+12, and happen to select
the bogus FDE, the unwinder will decide address foo+12 isn't covered
and will end up calling terminate.  It was seeing exactly this
situation with a developmental version of powerpc64le xlc that led me
to add the linker sanity check.

I didn't expect to see the problem elsewhere, and so didn't make the
error message as useful as it could have been.  Also, it would have
been better to allow ld to produce an output if given -noinhibit-exec.

So, if you apply the following patch, rebuild your binutils, then run
the failing g++ link with the addition of -Wl,-noinhibit-exec you
should get an executable that you can dump with readelf -wf to find
the overlapping FDEs.

	* elf-eh-frame (_bfd_elf_write_section_eh_frame_hdr): Don't return
	false for overflow or overlapping FDEs.  Give more detail in
	error messages.

diff --git a/bfd/elf-eh-frame.c b/bfd/elf-eh-frame.c
index 02f2d23..b32add3 100644
--- a/bfd/elf-eh-frame.c
+++ b/bfd/elf-eh-frame.c
@@ -1807,13 +1807,10 @@ _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
       if (contents[2] != DW_EH_PE_omit)
 	{
 	  unsigned int i;
-	  bfd_boolean overlap, overflow;
 
 	  bfd_put_32 (abfd, hdr_info->fde_count, contents + EH_FRAME_HDR_SIZE);
 	  qsort (hdr_info->array, hdr_info->fde_count,
 		 sizeof (*hdr_info->array), vma_compare);
-	  overlap = FALSE;
-	  overflow = FALSE;
 	  for (i = 0; i < hdr_info->fde_count; i++)
 	    {
 	      bfd_vma val;
@@ -1823,31 +1820,28 @@ _bfd_elf_write_section_eh_frame_hdr (bfd *abfd, struct bfd_link_info *info)
 	      if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64
 		  && (hdr_info->array[i].initial_loc
 		      != sec->output_section->vma + val))
-		overflow = TRUE;
+		(*info->callbacks->einfo)
+		  (_("%X%P: .eh_frame_hdr table[%u] pc overflow.\n"), i);
 	      bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 4);
+
 	      val = hdr_info->array[i].fde - sec->output_section->vma;
 	      val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
 	      if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64
 		  && (hdr_info->array[i].fde
 		      != sec->output_section->vma + val))
-		overflow = TRUE;
+		(*info->callbacks->einfo)
+		  (_("%X%P: .eh_frame_hdr table[%u] fde overflow.\n"), i);
 	      bfd_put_32 (abfd, val, contents + EH_FRAME_HDR_SIZE + i * 8 + 8);
+
 	      if (i != 0
 		  && (hdr_info->array[i].initial_loc
 		      < (hdr_info->array[i - 1].initial_loc
 			 + hdr_info->array[i - 1].range)))
-		overlap = TRUE;
-	    }
-	  if (overflow)
-	    (*info->callbacks->einfo)
-	      (_("%P: .eh_frame_hdr entry overflow.\n"));
-	  if (overlap)
-	    (*info->callbacks->einfo)
-	      (_("%P: .eh_frame_hdr refers to overlapping FDEs.\n"));
-	  if (overflow || overlap)
-	    {
-	      bfd_set_error (bfd_error_bad_value);
-	      retval = FALSE;
+		(*info->callbacks->einfo)
+		  (_("%X%P: .eh_frame_hdr table[%u] FDE at %V overlaps "
+		     "table[%u] FDE at %V.\n"),
+		   i - 1, hdr_info->array[i - 1].fde,
+		   i, hdr_info->array[i].fde);
 	    }
 	}
 
-- 
Alan Modra
Australia Development Lab, IBM


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