This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: .eh_frame_hdr refers to overlapping FDEs
- From: Alan Modra <amodra at gmail dot com>
- To: Elmar Pruesse <epruesse at mpi-bremen dot de>
- Cc: binutils at sourceware dot org
- Date: Mon, 22 Sep 2014 18:49:13 +0930
- Subject: Re: .eh_frame_hdr refers to overlapping FDEs
- Authentication-results: sourceware.org; auth=none
- References: <zarafa dot 541ed295 dot 52da dot 03d11a7527767c8f at zarafa dot mpi-bremen dot de>
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