GNU DebugFission split dwarf handles DW_FORM_sec_offset specially for
attributes that point to ranges. The .debug_ranges section is not in
the .dwo file, but in the main/skeleton object file. The sec_offset is
not relocated (in the ELF file), but is an offset against the skeleton
DIE DW_AT_GNU_ranges_base attribute. dwarf_formudata is changed so it
still looks like a normal offset ptr into the .debug_ranges section.
dwarf_ranges is adapted to look for the .debug_ranges in the main object
file. dwarf_highpc and dwarf_lowpc now handle the highpc and lowpc
attributes being inherited for the split unit DIE from the skeleton.
A new testcase is added to iterate over all ranges in a split GNU
DebugFission file.
Signed-off-by: Mark Wielaard
---
libdw/ChangeLog | 12
libdw/dwarf_formudata.c | 50 +--
libdw/dwarf_highpc.c | 18 +++---
libdw/dwarf_lowpc.c | 15 ++---
libdw/dwarf_ranges.c | 22 +--
libdw/libdwP.h | 26
tests/ChangeLog | 14 +
tests/Makefile.am| 11 +++-
tests/all-dwarf-ranges.c | 90 +++
tests/run-all-dwarf-ranges.sh| 49 +++
tests/testfile-ranges-hello.dwo.bz2 | Bin 0 -> 948 bytes
tests/testfile-ranges-world.dwo.bz2 | Bin 0 -> 1176 bytes
tests/testfilesplitranges4.debug.bz2 | Bin 0 -> 2154 bytes
13 files changed, 281 insertions(+), 26 deletions(-)
create mode 100644 tests/all-dwarf-ranges.c
create mode 100755 tests/run-all-dwarf-ranges.sh
create mode 100644 tests/testfile-ranges-hello.dwo.bz2
create mode 100644 tests/testfile-ranges-world.dwo.bz2
create mode 100755 tests/testfilesplitranges4.debug.bz2
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index e067827b..caa2d124 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,15 @@
+2018-05-18 Mark Wielaard
+
+ * dwarf_formudata.c (__libdw_formptr): Handle the special case
+ of IDX_debug_ranges for DW_UT_split_compile with version < 5.
+ * dwarf_highpc.c (dwarf_highpc): Use dwarf_lowpc, check for
+ split compile cudie.
+ * dwarf_lowpc.c (dwarf_lowpc): Check for split compile cudie.
+ * dwarf_ranges.c (dwarf_ranges): Switch cu and sectiondata for
+ split compile units.
+ * libdwP.h (struct Dwarf_CU): Add ranges_base field.
+ (__libdw_cu_ranges_base): New static inline function.
+
2018-05-18 Mark Wielaard
* libdw_findcu.c (__libdw_intern_next_unit): Init files to NULL.
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index 19d34f8e..316ad865 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -43,6 +43,17 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
return NULL;
const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index];
+ Dwarf_CU *skel = NULL; /* See below, needed for GNU DebugFission. */
+ if (unlikely (d == NULL
+ && sec_index == IDX_debug_ranges
+ && attr->cu->version < 5
+ && attr->cu->unit_type == DW_UT_split_compile))
+{
+ skel = __libdw_find_split_unit (attr->cu);
+ if (skel != NULL)
+ d = skel->dbg->sectiondata[IDX_debug_ranges];
+}
+
if (unlikely (d == NULL))
{
__libdw_seterrno (err_nodata);
@@ -52,10 +63,41 @@ __libdw_formptr (Dwarf_Attribute *attr, int sec_index,
Dwarf_Word offset;
if (attr->form == DW_FORM_sec_offset)
{
- if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
- cu_sec_idx (attr->cu), attr->valp,
- attr->cu->offset_size, &offset, sec_index, 0))
- return NULL;
+ /* GNU DebugFission is slightly odd. It uses DW_FORM_sec_offset
+in split units, but they are really (unrelocated) offsets
+from the skeleton DW_AT_GNU_ranges_base (which is only used
+for the split unit, not the skeleton ranges itself, see also
+DW_AT_rnglists_base, which is used in DWARF5 for both, but
+points to the offsets index). So it isn't really a formptr,
+but an offset + base calculation. */
+ if (unlikely (skel != NULL))
+ {
+ Elf_Data *data = attr->cu->dbg->sectiondata[cu_sec_idx (attr->cu)];
+ const unsigned char *datap = attr->valp;
+ size_t size = attr->cu->offset_size;
+ if (unlikely (data == NULL
+ || datap < (const unsigned char *) data->d_buf
+ || data->d_size < size
+ || ((size_t) (datap
+ - (const unsigned char *) data->d_buf)
+ > data->d_size - size)))
+ goto invalid;
+
+ if (size == 4)
+ offset = read_4ubyte_unaligned (attr->cu->dbg, datap);
+ else
+ offset = read_8ubyte_unaligned (attr->cu->dbg, datap);
+
+ offset += __l