No longer use .debug_aranges to build the aranges list since it could be
absent or incomplete.
Instead build the aranges list by iterating over each CU and recording
each address range.
https://sourceware.org/bugzilla/show_bug.cgi?id=22288
https://sourceware.org/bugzilla/show_bug.cgi?id=30948
Signed-off-by: Aaron Merey
---
v2 adds a test for generating aranges from a binary with no
.debug_aranges.
This patch's method of building the aranges list is slower than simply
reading .debug_aranges. On my machine, running eu-stack on a 2.9G
firefox core file takes about 8.7 seconds with this patch applied,
compared to about 3.3 seconds without this patch.
Ideally we could assume that .debug_aranges is complete if it is present
and build the aranges list via CU iteration only when .debug_aranges
is absent. This would let us save time on gcc-compiled binaries, which
include complete .debug_aranges by default.
However the DWARF spec appears to permit partially complete
.debug_aranges [1]. We could improve performance by starting with a
potentially incomplete list built from .debug_aranges. If a lookup
fails then search the CUs for missing aranges and add to the list
when found.
This approach would complicate the dwarf_get_aranges interface. The
list it initially provides could no longer be assumed to be complete.
The number of elements in the list could change during calls to
dwarf_getarange{info, _addr}. This would invalidate the naranges value
set by dwarf_getaranges. The current API doesn't include a way to
communicate to the caller when narages changes and by how much.
Due to these complications I think it's better to simply ignore
.debug_aranges altogether and build the aranges table via CU iteration,
as is done in this patch.
[1] https://sourceware.org/bugzilla/show_bug.cgi?id=22288#c5
libdw/dwarf_getaranges.c | 215 ++-
tests/run-get-aranges.sh | 48 +
2 files changed, 100 insertions(+), 163 deletions(-)
diff --git a/libdw/dwarf_getaranges.c b/libdw/dwarf_getaranges.c
index 27439d37..8676f93b 100644
--- a/libdw/dwarf_getaranges.c
+++ b/libdw/dwarf_getaranges.c
@@ -33,7 +33,6 @@
#endif
#include
-#include
#include "libdwP.h"
#include
@@ -68,174 +67,51 @@ dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges,
size_t *naranges)
return 0;
}
- if (dbg->sectiondata[IDX_debug_aranges] == NULL)
-{
- /* No such section. */
- *aranges = NULL;
- if (naranges != NULL)
- *naranges = 0;
- return 0;
-}
-
- if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
-return -1;
-
struct arangelist *arangelist = NULL;
unsigned int narangelist = 0;
- const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
- const unsigned char *readendp
-= readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
-
- while (readp < readendp)
+ Dwarf_CU *cu = NULL;
+ while (INTUSE(dwarf_get_units) (dbg, cu, &cu, NULL, NULL, NULL, NULL) == 0)
{
- const unsigned char *hdrstart = readp;
-
- /* Each entry starts with a header:
-
-1. A 4-byte or 12-byte length containing the length of the
-set of entries for this compilation unit, not including the
-length field itself. [...]
-
-2. A 2-byte version identifier containing the value 2 for
-DWARF Version 2.1.
-
-3. A 4-byte or 8-byte offset into the .debug_info section. [...]
-
-4. A 1-byte unsigned integer containing the size in bytes of
-an address (or the offset portion of an address for segmented
-addressing) on the target system.
-
-5. A 1-byte unsigned integer containing the size in bytes of
-a segment descriptor on the target system. */
- if (unlikely (readp + 4 > readendp))
- goto invalid;
-
- Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
- unsigned int length_bytes = 4;
- if (length == DWARF3_LENGTH_64_BIT)
- {
- if (unlikely (readp + 8 > readendp))
- goto invalid;
-
- length = read_8ubyte_unaligned_inc (dbg, readp);
- length_bytes = 8;
- }
- else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
-&& length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
- goto invalid;
-
- const unsigned char *endp = readp + length;
- if (unlikely (endp > readendp))
- goto invalid;
-
- if (unlikely (readp + 2 > readendp))
- goto invalid;
-
- unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
- if (version != 2)
- {
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- fail:
- while (arangelist != NULL)
- {
- struct arangelist *next = arangelist->next;
- free (arangelist);
- arangelist = next;
- }
- return -1;
- }
-
- Dwarf_Word offset = 0;
- if (__libdw_read_offset_inc (dbg,
-