This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
[patch] Fix error code from __libdw_find_fde
- From: Jan Kratochvil <jan dot kratochvil at redhat dot com>
- To: elfutils-devel at lists dot fedorahosted dot org
- Date: Mon, 08 Oct 2012 19:48:23 +0200
- Subject: [patch] Fix error code from __libdw_find_fde
Hi,
__libdw_find_fde may errorneously return DWARF_E_INVALID_DWARF instead of
correct DWARF_E_NO_MATCH.
This is because .eh_frame_hdr contains only starts of ranges covered by FDEs,
not their ends (lengths). Therefore if .eh_frame_hdr returned us some FDE but
that FDE ends before the searched PC that .eh_frame_hdr is not broken.
.eh_frame_hdr is just acceleration, not authoritative information, only
.eh_frame is authoritative what it does and what it does not cover.
Testcase for this patch is the whole testsuite of:
[API RFC] unwinder
https://lists.fedorahosted.org/pipermail/elfutils-devel/2012-October/002618.html
where without -> with this fix on x86_64:
$ cd tests; ./backtrace; echo $?
# 3 0x7f8ce6f56959 - 1 _start
No DWARF information found
1
->
[...]
# 3 0x7f18eae6c959 - 1 _start
0
("No DWARF information found" is not the real error code from .eh_frame_hdr,
it got translated into a different code from the DWARF unwinder.)
Thanks,
Jan
libdw/
2012-10-08 Jan Kratochvil <jan.kratochvil@redhat.com>
* fde.c (__libdw_find_fde): Return DWARF_E_NO_MATCH if .eh_frame_hdr
points to FDE which is too short for searched PC.
diff --git a/libdw/fde.c b/libdw/fde.c
index bde0c99..f619912 100644
--- a/libdw/fde.c
+++ b/libdw/fde.c
@@ -231,11 +231,15 @@ __libdw_find_fde (Dwarf_CFI *cache, Dwarf_Addr address)
struct dwarf_fde *fde = __libdw_fde_by_offset (cache, offset);
if (unlikely (fde != NULL)
/* Sanity check the address range. */
- && unlikely (address < fde->start || address >= fde->end))
+ && unlikely (address < fde->start))
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
}
+ if (unlikely (fde != NULL)
+ /* .eh_frame_hdr does not indicate length covered by FDE. */
+ && unlikely (address >= fde->end))
+ goto no_match;
return fde;
}