2018-05-18 Mark Wielaard <mark@klomp.org>
+ * 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 <mark@klomp.org>
+
* libdw_findcu.c (__libdw_intern_next_unit): Init files to NULL.
* dwarf_getsrclines.c (dwarf_getsrclines): Handle split units by
taking the line table from the skeleton.
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);
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 += __libdw_cu_ranges_base (skel);
+ }
+ else
+ {
+ 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;
+ }
}
else if (attr->cu->version > 3)
goto invalid;
/* Return high PC attribute of DIE.
- Copyright (C) 2003, 2005, 2012 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2012, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <drepper@redhat.com>, 2003.
This file is free software; you can redistribute it and/or modify
it under the terms of either
dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
{
Dwarf_Attribute attr_high_mem;
- Dwarf_Attribute *attr_high = INTUSE(dwarf_attr) (die, DW_AT_high_pc,
- &attr_high_mem);
+ Dwarf_Attribute *attr_high;
+ /* Split compile DIEs inherit high_pc from their skeleton DIE. */
+ if (is_cudie (die) && die->cu->unit_type == DW_UT_split_compile)
+ attr_high = INTUSE(dwarf_attr_integrate) (die, DW_AT_high_pc,
+ &attr_high_mem);
+ else
+ attr_high = INTUSE(dwarf_attr) (die, DW_AT_high_pc, &attr_high_mem);
+
if (attr_high == NULL)
return -1;
return INTUSE(dwarf_formaddr) (attr_high, return_addr);
/* DWARF 4 allows high_pc to be a constant offset from low_pc. */
- Dwarf_Attribute attr_low_mem;
- if (INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
- &attr_low_mem),
- return_addr) == 0)
+ if (INTUSE(dwarf_lowpc) (die, return_addr) == 0)
{
Dwarf_Word uval;
if (INTUSE(dwarf_formudata) (attr_high, &uval) == 0)
/* Return low PC attribute of DIE.
- Copyright (C) 2003, 2005 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2018 Red Hat, Inc.
This file is part of elfutils.
- Written by Ulrich Drepper <drepper@redhat.com>, 2003.
This file is free software; you can redistribute it and/or modify
it under the terms of either
int
dwarf_lowpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
{
- Dwarf_Attribute attr_mem;
-
- return INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (die, DW_AT_low_pc,
- &attr_mem),
- return_addr);
+ Dwarf_Attribute attr_mem, *attr;
+ /* Split compile DIEs inherit low_pc from their skeleton DIE. */
+ if (is_cudie (die) && die->cu->unit_type == DW_UT_split_compile)
+ attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_low_pc, &attr_mem);
+ else
+ attr = INTUSE(dwarf_attr) (die, DW_AT_low_pc, &attr_mem);
+ return INTUSE(dwarf_formaddr) (attr, return_addr);
}
INTDEF(dwarf_lowpc)
/* We have to look for a noncontiguous range. */
size_t secidx = IDX_debug_ranges;
- const Elf_Data *d = die->cu->dbg->sectiondata[secidx];
+ Dwarf_CU *cu = die->cu;
+ const Elf_Data *d = cu->dbg->sectiondata[secidx];
+ if (d == NULL && cu->unit_type == DW_UT_split_compile)
+ {
+ Dwarf_CU *skel = __libdw_find_split_unit (cu);
+ if (skel != NULL)
+ {
+ cu = skel;
+ d = cu->dbg->sectiondata[secidx];
+ }
+ }
const unsigned char *readp;
const unsigned char *readendp;
Dwarf_Attribute attr_mem;
Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges,
&attr_mem);
+ if (attr == NULL
+ && is_cudie (die)
+ && die->cu->unit_type == DW_UT_split_compile)
+ attr = INTUSE(dwarf_attr_integrate) (die, DW_AT_ranges, &attr_mem);
if (attr == NULL)
/* No PC attributes in this DIE at all, so an empty range list. */
return 0;
}
else
{
- if (__libdw_offset_in_section (die->cu->dbg,
+ if (__libdw_offset_in_section (cu->dbg,
secidx, offset, 1))
return -1;
}
Dwarf_Addr end;
next:
- switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, secidx,
+ switch (__libdw_read_begin_end_pair_inc (cu->dbg, secidx,
&readp, readendp,
- die->cu->address_size,
+ cu->address_size,
&begin, &end, basep))
{
case 0:
Don't access directly, call __libdw_cu_str_off_base. */
Dwarf_Off str_off_base;
+ /* The offset into the .debug_ranges section to use for GNU
+ DebugFission split units. Don't access directly, call
+ __libdw_cu_ranges_base. */
+ Dwarf_Off ranges_base;
+
/* Memory boundaries of this CU. */
void *startp;
void *endp;
}
+static inline Dwarf_Off
+__libdw_cu_ranges_base (Dwarf_CU *cu)
+{
+ if (cu->ranges_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Off offset = 0;
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ if (dwarf_attr (&cu_die, DW_AT_GNU_ranges_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ offset = off;
+ }
+ cu->ranges_base = offset;
+ }
+
+ return cu->ranges_base;
+}
+
+
/* Helper function to set debugdir field in Dwarf, used from dwarf_begin_elf
and libdwfl process_file. */
char * __libdw_debugdir (int fd);
2018-05-18 Mark Wielaard <mark@klomp.org>
+ * tests/Makefiles.am (check_PROGRAMS): Add all-dwarf-ranges.
+ (TESTS): Add run-all-dwarf-ranges.sh.
+ (EXTRA_DIST): Add run-all-dwarf-ranges.sh,
+ testfilesplitranges4.debug.bz2, testfile-ranges-hello.dwo.bz2
+ and testfile-ranges-world.dwo.bz2.
+ (all_dwarf_ranges_LDADD): New variable.
+ * all-dwarf-ranges.c: New test program.
+ * run-all-dwarf-ranges: New test runner.
+ * testfile-ranges-hello.dwo.bz2: New test file.
+ * testfile-ranges-world.dwo.bz2: Likewise.
+ * testfilesplitranges4.debug.bz2: Likewise.
+
+2018-05-18 Mark Wielaard <mark@klomp.org>
+
* run-get-files.sh: Add testcases for testfile-splitdwarf-4,
testfile-hello4.dwo, testfile-world4.dwo and testfile-splitdwarf-5,
testfile-hello5.dwo, testfile-world5.dwo.
elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \
elfgetzdata elfputzdata zstrptr emptyfile vendorelf \
fillfile dwarf_default_lower_bound dwarf-die-addr-die \
- get-units-invalid get-units-split attr-integrate-skel
+ get-units-invalid get-units-split attr-integrate-skel \
+ all-dwarf-ranges
asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
asm-tst6 asm-tst7 asm-tst8 asm-tst9
emptyfile vendorelf fillfile dwarf_default_lower_bound \
run-dwarf-die-addr-die.sh \
run-get-units-invalid.sh run-get-units-split.sh \
- run-attr-integrate-skel.sh
+ run-attr-integrate-skel.sh \
+ run-all-dwarf-ranges.sh
if !BIARCH
export ELFUTILS_DISABLE_BIARCH = 1
testfile-hello4.dwo.bz2 testfile-hello5.dwo.bz2 \
testfile-splitdwarf-4.bz2 testfile-splitdwarf-5.bz2 \
testfile-world5.dwo.bz2 testfile-world4.dwo.bz2 \
- run-attr-integrate-skel.sh
+ run-attr-integrate-skel.sh \
+ run-all-dwarf-ranges.sh testfilesplitranges4.debug.bz2 \
+ testfile-ranges-hello.dwo.bz2 testfile-ranges-world.dwo.bz2
if USE_VALGRIND
valgrind_cmd='valgrind -q --leak-check=full --error-exitcode=1'
get_units_invalid_LDADD = $(libdw)
get_units_split_LDADD = $(libdw)
attr_integrate_skel_LDADD = $(libdw)
+all_dwarf_ranges_LDADD = $(libdw)
# We want to test the libelf header against the system elf.h header.
# Don't include any -I CPPFLAGS.
--- /dev/null
+/* Test program for dwarf_ranges
+ Copyright (C) 2015, 2018 Red Hat, Inc.
+ This file is part of elfutils.
+
+ This file is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ elfutils is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include ELFUTILS_HEADER(dw)
+#include <dwarf.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <inttypes.h>
+
+static void
+ranges_die (Dwarf_Die *die)
+{
+ Dwarf_Addr base, start, end;
+ int ranges = dwarf_ranges (die, 0, &base, &start, &end);
+ if (ranges < 0)
+ puts (dwarf_errmsg (-1));
+ else if (ranges > 0)
+ {
+ printf ("die: %s (%x)\n", dwarf_diename (die) ?: "<unknown>",
+ dwarf_tag (die));
+ for (ptrdiff_t off = 0;
+ (off = dwarf_ranges (die, off, &base, &start, &end)); )
+ if (off == -1)
+ {
+ puts (dwarf_errmsg (-1));
+ break;
+ }
+ else
+ printf (" %"PRIx64"..%"PRIx64"\n", start, end);
+ printf ("\n");
+ }
+}
+
+static void
+walk_tree (Dwarf_Die *dwarf_die)
+{
+ Dwarf_Die die = *dwarf_die;
+ do
+ {
+ Dwarf_Die child;
+ ranges_die (&die);
+ if (dwarf_child (&die, &child) == 0)
+ walk_tree (&child);
+ }
+ while (dwarf_siblingof (&die, &die) == 0);
+}
+
+int
+main (int argc, char *argv[])
+{
+ assert (argc >= 2);
+ const char *name = argv[1];
+
+ int fd = open (name, O_RDONLY);
+ Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
+
+ Dwarf_CU *cu = NULL;
+ Dwarf_Die cudie, subdie;
+ uint8_t unit_type;
+ while (dwarf_get_units (dbg, cu, &cu, NULL,
+ &unit_type, &cudie, &subdie) == 0)
+ {
+ Dwarf_Die die = (unit_type == DW_UT_skeleton
+ ? subdie : cudie);
+ walk_tree (&die);
+ }
+ dwarf_end (dbg);
+
+ return 0;
+}
--- /dev/null
+#! /bin/sh
+# Copyright (C) 2018 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# See run-dwarf-ranges.sh
+# Compiled with:
+# gcc -c -O2 -o testfile-ranges-hello.o -gsplit-dwarf -gdwarf-4 hello.c
+# gcc -c -O2 -o testfile-ranges-world.o -gsplit-dwarf -gdwarf-4 world.c
+# gcc -o testfilesplitranges4 -O2 \
+# testfile-ranges-hello.o testfile-ranges-world.o
+# eu-strip -f testfilesplitranges4.debug testfilesplitranges4
+
+testfiles testfilesplitranges4.debug
+testfiles testfile-ranges-hello.dwo testfile-ranges-world.dwo
+
+testrun_compare ${abs_builddir}/all-dwarf-ranges testfilesplitranges4.debug <<\EOF
+die: hello.c (11)
+ 4004e0..4004ff
+ 4003e0..4003f7
+
+die: world.c (11)
+ 400500..400567
+
+die: happy (1d)
+ 8009e0..8009ff
+ 8008e0..8008f7
+
+die: sad (1d)
+ 400530..400534
+ 400535..40053f
+
+EOF
+
+exit 0