summaryrefslogtreecommitdiffstats
path: root/libdw/dwarf_getlocation.c
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2018-04-07 23:48:27 +0200
committerMark Wielaard <mark@klomp.org>2018-05-30 00:16:15 +0200
commit4dc31fde711c69fed6acfe18e7e57dfd5665cebb (patch)
tree1f8cac4d4e3a2da4314cf37410dd94cd418d47d8 /libdw/dwarf_getlocation.c
parent7cfe2c16f9ddaa7478a2d97dd893c6b89080020a (diff)
libdw: Handle .debug_loclists in dwarf_getlocation.
Handle all new DW_LLE opcodes in .debug_loclists in dwarf_getlocation. __libdw_read_begin_end_pair_inc now also handles a default location (which is simply the range [0,-1]). Since expression blocks can now also come from the .debug_loclists section add a new fake_loclists_cu necessary for checking bounds while parsing expression blocks. Adapt varlocs test to handle debug-only files. Test testfileranges5.debug and testfilesplitranges5.debug with it. Signed-off-by: Mark Wielaard <mark@klomp.org>
Diffstat (limited to 'libdw/dwarf_getlocation.c')
-rw-r--r--libdw/dwarf_getlocation.c99
1 files changed, 86 insertions, 13 deletions
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c
index d4b8effe..d293e75d 100644
--- a/libdw/dwarf_getlocation.c
+++ b/libdw/dwarf_getlocation.c
@@ -696,13 +696,77 @@ __libdw_cu_base_address (Dwarf_CU *cu)
static int
initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
{
- size_t secidx = IDX_debug_loc;
+ size_t secidx = (attr->cu->version < 5
+ ? IDX_debug_loc : IDX_debug_loclists);
Dwarf_Word start_offset;
- if (__libdw_formptr (attr, secidx,
- DWARF_E_NO_DEBUG_LOC,
- NULL, &start_offset) == NULL)
- return -1;
+ if (attr->form == DW_FORM_loclistx)
+ {
+ Dwarf_Word idx;
+ Dwarf_CU *cu = attr->cu;
+ const unsigned char *datap = attr->valp;
+ const unsigned char *endp = cu->endp;
+ if (datap >= endp)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ get_uleb128 (idx, datap, endp);
+
+ Elf_Data *data = cu->dbg->sectiondata[secidx];
+ if (data == NULL && cu->unit_type == DW_UT_split_compile)
+ {
+ cu = __libdw_find_split_unit (cu);
+ if (cu != NULL)
+ data = cu->dbg->sectiondata[secidx];
+ }
+
+ if (data == NULL)
+ {
+ __libdw_seterrno (secidx == IDX_debug_loc
+ ? DWARF_E_NO_DEBUG_LOC
+ : DWARF_E_NO_DEBUG_LOCLISTS);
+ return -1;
+ }
+
+ Dwarf_Off loc_base_off = __libdw_cu_locs_base (cu);
+
+ /* The section should at least contain room for one offset. */
+ size_t sec_size = cu->dbg->sectiondata[secidx]->d_size;
+ size_t offset_size = cu->offset_size;
+ if (offset_size > sec_size)
+ {
+ invalid_offset:
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ /* And the base offset should be at least inside the section. */
+ if (loc_base_off > (sec_size - offset_size))
+ goto invalid_offset;
+
+ size_t max_idx = (sec_size - offset_size - loc_base_off) / offset_size;
+ if (idx > max_idx)
+ goto invalid_offset;
+
+ datap = (cu->dbg->sectiondata[secidx]->d_buf
+ + loc_base_off + (idx * offset_size));
+ if (offset_size == 4)
+ start_offset = read_4ubyte_unaligned (cu->dbg, datap);
+ else
+ start_offset = read_8ubyte_unaligned (cu->dbg, datap);
+
+ start_offset += loc_base_off;
+ }
+ else
+ {
+ if (__libdw_formptr (attr, secidx,
+ (secidx == IDX_debug_loc
+ ? DWARF_E_NO_DEBUG_LOC
+ : DWARF_E_NO_DEBUG_LOCLISTS),
+ NULL, &start_offset) == NULL)
+ return -1;
+ }
*offset = start_offset;
return 0;
@@ -716,7 +780,7 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
{
Dwarf_CU *cu = attr->cu;
Dwarf *dbg = cu->dbg;
- size_t secidx = IDX_debug_loc;
+ size_t secidx = cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
const unsigned char *readp = locs->d_buf + offset;
const unsigned char *readendp = locs->d_buf + locs->d_size;
@@ -741,13 +805,22 @@ getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
/* We have a location expression. */
Dwarf_Block block;
- if (readendp - readp < 2)
+ if (secidx == IDX_debug_loc)
{
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
+ if (readendp - readp < 2)
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ block.length = read_2ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ if (readendp - readp < 1)
+ goto invalid;
+ get_uleb128 (block.length, readp, readendp);
}
- block.length = read_2ubyte_unaligned_inc (dbg, readp);
block.data = (unsigned char *) readp;
if (readendp - readp < (ptrdiff_t) block.length)
goto invalid;
@@ -815,7 +888,7 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
if (initial_offset (attr, &off) != 0)
return -1;
- size_t secidx = IDX_debug_loc;
+ size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
while (got < maxlocs
@@ -896,7 +969,7 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
return -1;
}
- size_t secidx = IDX_debug_loc;
+ size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists;
const Elf_Data *d = attr->cu->dbg->sectiondata[secidx];
return getlocations_addr (attr, offset, basep, startp, endp,