mirror of
https://github.com/openharmony/third_party_elfutils.git
synced 2026-07-01 06:41:51 -04:00
libdw: Handle GNU DebugFission split ranges.
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 <mark@klomp.org>
This commit is contained in:
@@ -1,3 +1,15 @@
|
||||
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.
|
||||
|
||||
+46
-4
@@ -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 += __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;
|
||||
|
||||
+10
-8
@@ -1,7 +1,6 @@
|
||||
/* 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
|
||||
@@ -39,8 +38,14 @@ int
|
||||
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;
|
||||
|
||||
@@ -48,10 +53,7 @@ dwarf_highpc (Dwarf_Die *die, Dwarf_Addr *return_addr)
|
||||
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)
|
||||
|
||||
+8
-7
@@ -1,7 +1,6 @@
|
||||
/* 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
|
||||
@@ -38,10 +37,12 @@
|
||||
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)
|
||||
|
||||
+18
-4
@@ -122,7 +122,17 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
|
||||
|
||||
/* 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;
|
||||
@@ -131,6 +141,10 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
|
||||
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;
|
||||
@@ -144,7 +158,7 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (__libdw_offset_in_section (die->cu->dbg,
|
||||
if (__libdw_offset_in_section (cu->dbg,
|
||||
secidx, offset, 1))
|
||||
return -1;
|
||||
}
|
||||
@@ -156,9 +170,9 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
|
||||
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:
|
||||
|
||||
@@ -352,6 +352,11 @@ struct Dwarf_CU
|
||||
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;
|
||||
@@ -1055,6 +1060,27 @@ static inline Dwarf_Off __libdw_cu_str_off_base (Dwarf_CU *cu)
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
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,
|
||||
|
||||
+8
-3
@@ -56,7 +56,8 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
|
||||
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
|
||||
@@ -141,7 +142,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
|
||||
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
|
||||
@@ -366,7 +368,9 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
|
||||
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'
|
||||
@@ -528,6 +532,7 @@ dwarf_die_addr_die_LDADD = $(libdw)
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/* 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;
|
||||
}
|
||||
Executable
+49
@@ -0,0 +1,49 @@
|
||||
#! /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
|
||||
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user