diff options
Diffstat (limited to 'libdw/dwarf_formudata.c')
-rw-r--r-- | libdw/dwarf_formudata.c | 160 |
1 files changed, 143 insertions, 17 deletions
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c index e41981a4..26f86f12 100644 --- a/libdw/dwarf_formudata.c +++ b/libdw/dwarf_formudata.c @@ -1,5 +1,5 @@ /* Return unsigned constant represented by attribute. - Copyright (C) 2003-2012, 2014 Red Hat, Inc. + Copyright (C) 2003-2012, 2014, 2017 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <[email protected]>, 2003. @@ -34,15 +34,26 @@ #include <dwarf.h> #include "libdwP.h" -internal_function unsigned char * +internal_function const unsigned char * __libdw_formptr (Dwarf_Attribute *attr, int sec_index, - int err_nodata, unsigned char **endpp, + int err_nodata, const unsigned char **endpp, Dwarf_Off *offsetp) { if (attr == NULL) 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; @@ -141,11 +183,24 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) case DW_AT_string_length: case DW_AT_use_location: case DW_AT_vtable_elem_location: - /* loclistptr */ - if (__libdw_formptr (attr, IDX_debug_loc, - DWARF_E_NO_LOCLIST, NULL, - return_uval) == NULL) - return -1; + case DW_AT_GNU_locviews: + case DW_AT_loclists_base: + if (attr->cu->version < 5) + { + /* loclistptr */ + if (__libdw_formptr (attr, IDX_debug_loc, + DWARF_E_NO_DEBUG_LOC, NULL, + return_uval) == NULL) + return -1; + } + else + { + /* loclist, loclistsptr */ + if (__libdw_formptr (attr, IDX_debug_loclists, + DWARF_E_NO_DEBUG_LOCLISTS, NULL, + return_uval) == NULL) + return -1; + } break; case DW_AT_macro_info: @@ -157,6 +212,7 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) break; case DW_AT_GNU_macros: + case DW_AT_macros: /* macptr into .debug_macro */ if (__libdw_formptr (attr, IDX_debug_macro, DWARF_E_NO_ENTRY, NULL, @@ -166,11 +222,24 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) case DW_AT_ranges: case DW_AT_start_scope: - /* rangelistptr */ - if (__libdw_formptr (attr, IDX_debug_ranges, - DWARF_E_NO_DEBUG_RANGES, NULL, - return_uval) == NULL) - return -1; + case DW_AT_GNU_ranges_base: + case DW_AT_rnglists_base: + if (attr->cu->version < 5) + { + /* rangelistptr */ + if (__libdw_formptr (attr, IDX_debug_ranges, + DWARF_E_NO_DEBUG_RANGES, NULL, + return_uval) == NULL) + return -1; + } + else + { + /* rnglistsptr */ + if (__libdw_formptr (attr, IDX_debug_rnglists, + DWARF_E_NO_DEBUG_RNGLISTS, NULL, + return_uval) == NULL) + return -1; + } break; case DW_AT_stmt_list: @@ -181,6 +250,23 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) return -1; break; + case DW_AT_addr_base: + case DW_AT_GNU_addr_base: + /* addrptr */ + if (__libdw_formptr (attr, IDX_debug_addr, + DWARF_E_NO_DEBUG_ADDR, NULL, + return_uval) == NULL) + return -1; + break; + + case DW_AT_str_offsets_base: + /* stroffsetsptr */ + if (__libdw_formptr (attr, IDX_debug_str_offsets, + DWARF_E_NO_STR_OFFSETS, NULL, + return_uval) == NULL) + return -1; + break; + default: /* sec_offset can only be used by one of the above attrs. */ if (attr->form == DW_FORM_sec_offset) @@ -216,11 +302,51 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) break; case DW_FORM_udata: + case DW_FORM_rnglistx: + case DW_FORM_loclistx: if (datap + 1 > endp) goto invalid; get_uleb128 (*return_uval, datap, endp); break; + case DW_FORM_implicit_const: + // The data comes from the abbrev, which has been bounds checked. + get_sleb128_unchecked (*return_uval, datap); + break; + + /* These are indexes into the .debug_addr section, normally resolved + with dwarf_formaddr. Here treat as constants. */ + case DW_FORM_GNU_addr_index: + case DW_FORM_addrx: + if (datap >= endp) + goto invalid; + get_uleb128 (*return_uval, datap, endp); + break; + + case DW_FORM_addrx1: + if (datap >= endp - 1) + goto invalid; + *return_uval = *datap; + break; + + case DW_FORM_addrx2: + if (datap >= endp - 2) + goto invalid; + *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap); + break; + + case DW_FORM_addrx3: + if (datap >= endp - 3) + goto invalid; + *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap); + break; + + case DW_FORM_addrx4: + if (datap >= endp - 4) + goto invalid; + *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap); + break; + default: __libdw_seterrno (DWARF_E_NO_CONSTANT); return -1; |