diff options
author | Mark Wielaard <[email protected]> | 2018-05-19 00:46:02 +0200 |
---|---|---|
committer | Mark Wielaard <[email protected]> | 2018-05-23 00:31:22 +0200 |
commit | 144b73c49acf3ed894e4635aedb9b0d1208ade2e (patch) | |
tree | 53ce2f235c75324b4010c419b5d5fe1a524c09ba /libdw/dwarf_formudata.c | |
parent | a4c74cc67de22cb3208fc768989c509d6837cd77 (diff) |
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 <[email protected]>
Diffstat (limited to 'libdw/dwarf_formudata.c')
-rw-r--r-- | libdw/dwarf_formudata.c | 50 |
1 files changed, 46 insertions, 4 deletions
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 += __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; |