summaryrefslogtreecommitdiffstats
path: root/libdw/dwarf_ranges.c
diff options
context:
space:
mode:
authorMark Wielaard <[email protected]>2018-04-02 23:08:40 +0200
committerMark Wielaard <[email protected]>2018-04-13 13:37:16 +0200
commita46d8d5f87e42b7d61cdff671ec7d3728cd1a637 (patch)
tree9fc38d4cc99bbe28bb665cc360411af5af737744 /libdw/dwarf_ranges.c
parent7f3934c919bc24e5b39499b24a28f8fed0f9a649 (diff)
libdw: Restructure address range reading for .debug_loc and .debug_ranges.
This caches the CU base address, makes error checking slight more relaxed and restructures the code so it will be easier to add different forms of ranges. Adds a new test for the new CU base address code. Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'libdw/dwarf_ranges.c')
-rw-r--r--libdw/dwarf_ranges.c113
1 files changed, 49 insertions, 64 deletions
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
index 4b6853d3..dbcfa2d4 100644
--- a/libdw/dwarf_ranges.c
+++ b/libdw/dwarf_ranges.c
@@ -1,5 +1,5 @@
/* Enumerate the PC ranges covered by a DIE.
- Copyright (C) 2005, 2007, 2009 Red Hat, Inc.
+ Copyright (C) 2005, 2007, 2009, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -41,7 +41,9 @@
- If an error occurs, don't set anything and return -1. */
internal_function int
__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
- unsigned char **addrp, int width,
+ const unsigned char **addrp,
+ const unsigned char *addrend,
+ int width,
Dwarf_Addr *beginp, Dwarf_Addr *endp,
Dwarf_Addr *basep)
{
@@ -50,7 +52,14 @@ __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
Dwarf_Addr begin;
Dwarf_Addr end;
- unsigned char *addr = *addrp;
+ const unsigned char *addr = *addrp;
+ if (addrend - addr < width * 2)
+ {
+ invalid:
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+
bool begin_relocated = READ_AND_RELOCATE (__libdw_relocate_address, begin);
bool end_relocated = READ_AND_RELOCATE (__libdw_relocate_address, end);
*addrp = addr;
@@ -59,13 +68,9 @@ __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
if (begin == escape && !begin_relocated)
{
if (unlikely (end == escape))
- {
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- return -1;
- }
+ goto invalid;
- if (basep != NULL)
- *basep = end;
+ *basep = end;
return 1;
}
@@ -75,12 +80,27 @@ __libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
/* Don't check for begin_relocated == end_relocated. Serve the data
to the client even though it may be buggy. */
- *beginp = begin;
- *endp = end;
+ *beginp = begin + *basep;
+ *endp = end + *basep;
return 0;
}
+static int
+initial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset)
+{
+ size_t secidx = IDX_debug_ranges;
+
+ Dwarf_Word start_offset;
+ if (__libdw_formptr (attr, secidx,
+ DWARF_E_NO_DEBUG_RANGES,
+ NULL, &start_offset) == NULL)
+ return -1;
+
+ *offset = start_offset;
+ return 0;
+}
+
ptrdiff_t
dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
Dwarf_Addr *startp, Dwarf_Addr *endp)
@@ -101,16 +121,11 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
return 0;
/* We have to look for a noncontiguous range. */
+ size_t secidx = IDX_debug_ranges;
+ const Elf_Data *d = die->cu->dbg->sectiondata[secidx];
- const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges];
- if (d == NULL && offset != 0)
- {
- __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES);
- return -1;
- }
-
- unsigned char *readp;
- unsigned char *readendp;
+ const unsigned char *readp;
+ const unsigned char *readendp;
if (offset == 0)
{
Dwarf_Attribute attr_mem;
@@ -120,49 +135,30 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
/* No PC attributes in this DIE at all, so an empty range list. */
return 0;
- Dwarf_Word start_offset;
- if ((readp = __libdw_formptr (attr, IDX_debug_ranges,
- DWARF_E_NO_DEBUG_RANGES,
- &readendp, &start_offset)) == NULL)
+ *basep = __libdw_cu_base_address (attr->cu);
+ if (*basep == (Dwarf_Addr) -1)
return -1;
- offset = start_offset;
- assert ((Dwarf_Word) offset == start_offset);
-
- /* Fetch the CU's base address. */
- Dwarf_Die cudie = CUDIE (attr->cu);
-
- /* Find the base address of the compilation unit. It will
- normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
- the base address could be overridden by DW_AT_entry_pc. It's
- been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
- for compilation units with discontinuous ranges. */
- if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
- && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
- DW_AT_entry_pc,
- &attr_mem),
- basep) != 0)
- *basep = (Dwarf_Addr) -1;
+ if (initial_offset (attr, &offset) != 0)
+ return -1;
}
else
{
if (__libdw_offset_in_section (die->cu->dbg,
- IDX_debug_ranges, offset, 1))
- return -1l;
-
- readp = d->d_buf + offset;
- readendp = d->d_buf + d->d_size;
+ secidx, offset, 1))
+ return -1;
}
- next:
- if (readendp - readp < die->cu->address_size * 2)
- goto invalid;
+ readp = d->d_buf + offset;
+ readendp = d->d_buf + d->d_size;
Dwarf_Addr begin;
Dwarf_Addr end;
- switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
- &readp, die->cu->address_size,
+ next:
+ switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, secidx,
+ &readp, readendp,
+ die->cu->address_size,
&begin, &end, basep))
{
case 0:
@@ -172,22 +168,11 @@ dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
case 2:
return 0;
default:
- return -1l;
- }
-
- /* We have an address range entry. Check that we have a base. */
- if (*basep == (Dwarf_Addr) -1)
- {
- if (INTUSE(dwarf_errno) () == 0)
- {
- invalid:
- __libdw_seterrno (DWARF_E_INVALID_DWARF);
- }
return -1;
}
- *startp = *basep + begin;
- *endp = *basep + end;
+ *startp = begin;
+ *endp = end;
return readp - (unsigned char *) d->d_buf;
}
INTDEF (dwarf_ranges)