summaryrefslogtreecommitdiff
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
parent7cfe2c16f9ddaa7478a2d97dd893c6b89080020a (diff)
downloadelfutils-4dc31fde711c69fed6acfe18e7e57dfd5665cebb.tar.gz
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>
-rw-r--r--libdw/ChangeLog17
-rw-r--r--libdw/dwarf_begin_elf.c27
-rw-r--r--libdw/dwarf_end.c5
-rw-r--r--libdw/dwarf_getlocation.c99
-rw-r--r--libdw/dwarf_getlocation_attr.c6
-rw-r--r--libdw/dwarf_ranges.c114
-rw-r--r--libdw/libdwP.h87
-rw-r--r--libdw/libdw_findcu.c1
-rw-r--r--src/ChangeLog5
-rw-r--r--src/readelf.c4
-rw-r--r--tests/ChangeLog8
-rwxr-xr-xtests/run-varlocs.sh152
-rw-r--r--tests/varlocs.c39
13 files changed, 539 insertions, 25 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 0db49bf8..22712f18 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,20 @@
+2018-04-07 Mark Wielaard <mark@klomp.org>
+
+ * libdwP.h (struct Dwarf_CU): Add locs_base.
+ (__libdw_cu_locs_base): New static inline function.
+ * libdw_findcu.c (__libdw_intern_next_unit): Initialize locs_base.
+ * dwarf_begin_elf.c (valid_p): Create fake_loclists_cu if necessary.
+ * dwarf_end.c (dwarf_end): Clean up fake_loclists_cu.
+ * dwarf_getlocation.c (initial_offset): Handle .debug_loclists.
+ (getlocations_addr): Likewise.
+ (dwarf_getlocation_addr): Likewise.
+ * dwarf_getlocation_attr.c (attr_form_cu): Use fake_loclists_cu for
+ DWARF5.
+ (initial_offset): Handle DW_FORM_loclistx.
+ * dwarf_ranges.c (__libdw_read_begin_end_pair_inc): Handle
+ .debug_loclists.
+ * libdwP.h (struct Dwarf): Add fake_loclists_cu.
+
2018-04-12 Mark Wielaard <mark@klomp.org>
* dwarf.h: Add DWARF5 location list entry DW_LLE encodings.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index af5096fb..513af2b1 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -226,6 +226,9 @@ valid_p (Dwarf *result)
result = NULL;
}
+ /* For dwarf_location_attr () we need a "fake" CU to indicate
+ where the "fake" attribute data comes from. This is a block
+ inside the .debug_loc or .debug_loclists section. */
if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL)
{
result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
@@ -248,6 +251,29 @@ valid_p (Dwarf *result)
}
}
+ if (result != NULL && result->sectiondata[IDX_debug_loclists] != NULL)
+ {
+ result->fake_loclists_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
+ if (unlikely (result->fake_loclists_cu == NULL))
+ {
+ Dwarf_Sig8_Hash_free (&result->sig8_hash);
+ __libdw_seterrno (DWARF_E_NOMEM);
+ free (result->fake_loc_cu);
+ free (result);
+ result = NULL;
+ }
+ else
+ {
+ result->fake_loclists_cu->sec_idx = IDX_debug_loclists;
+ result->fake_loclists_cu->dbg = result;
+ result->fake_loclists_cu->startp
+ = result->sectiondata[IDX_debug_loclists]->d_buf;
+ result->fake_loclists_cu->endp
+ = (result->sectiondata[IDX_debug_loclists]->d_buf
+ + result->sectiondata[IDX_debug_loclists]->d_size);
+ }
+ }
+
/* For DW_OP_constx/GNU_const_index and DW_OP_addrx/GNU_addr_index
the dwarf_location_attr () will need a "fake" address CU to
indicate where the attribute data comes from. This is a just
@@ -260,6 +286,7 @@ valid_p (Dwarf *result)
Dwarf_Sig8_Hash_free (&result->sig8_hash);
__libdw_seterrno (DWARF_E_NOMEM);
free (result->fake_loc_cu);
+ free (result->fake_loclists_cu);
free (result);
result = NULL;
}
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index 19546741..23a50a0b 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -113,6 +113,11 @@ dwarf_end (Dwarf *dwarf)
cu_free (dwarf->fake_loc_cu);
free (dwarf->fake_loc_cu);
}
+ if (dwarf->fake_loclists_cu != NULL)
+ {
+ cu_free (dwarf->fake_loclists_cu);
+ free (dwarf->fake_loclists_cu);
+ }
if (dwarf->fake_addr_cu != NULL)
{
cu_free (dwarf->fake_addr_cu);
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,
diff --git a/libdw/dwarf_getlocation_attr.c b/libdw/dwarf_getlocation_attr.c
index 9d7fd4b5..875fc5d7 100644
--- a/libdw/dwarf_getlocation_attr.c
+++ b/libdw/dwarf_getlocation_attr.c
@@ -38,7 +38,7 @@ attr_form_cu (Dwarf_Attribute *attr)
{
/* If the attribute has block/expr form the data comes from the
.debug_info from the same cu as the attr. Otherwise it comes from
- the .debug_loc data section. */
+ the .debug_loc or .debug_loclists data section. */
switch (attr->form)
{
case DW_FORM_block1:
@@ -48,7 +48,9 @@ attr_form_cu (Dwarf_Attribute *attr)
case DW_FORM_exprloc:
return attr->cu;
default:
- return attr->cu->dbg->fake_loc_cu;
+ return (attr->cu->version < 5
+ ? attr->cu->dbg->fake_loc_cu
+ : attr->cu->dbg->fake_loclists_cu);
}
}
diff --git a/libdw/dwarf_ranges.c b/libdw/dwarf_ranges.c
index fa65e5c6..0f3ee6b5 100644
--- a/libdw/dwarf_ranges.c
+++ b/libdw/dwarf_ranges.c
@@ -36,6 +36,7 @@
/* Read up begin/end pair and increment read pointer.
- If it's normal range record, set up `*beginp' and `*endp' and return 0.
+ - If it's a default location, set `*beginp' (0), `*endp' (-1) and return 0.
- If it's base address selection record, set up `*basep' and return 1.
- If it's end of rangelist, don't set anything and return 2
- If an error occurs, don't set anything and return -1. */
@@ -197,6 +198,119 @@ __libdw_read_begin_end_pair_inc (Dwarf_CU *cu, int sec_index,
goto invalid;
}
}
+ else if (sec_index == IDX_debug_loclists)
+ {
+ const unsigned char *addr = *addrp;
+ if (addrend - addr < 1)
+ goto invalid;
+
+ const char code = *addr++;
+ uint64_t begin = 0, end = 0, base = *basep, addr_idx;
+ switch (code)
+ {
+ case DW_LLE_end_of_list:
+ *addrp = addr;
+ return 2;
+
+ case DW_LLE_base_addressx:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &base) != 0)
+ return -1;
+
+ *basep = base;
+ *addrp = addr;
+ return 1;
+
+ case DW_LLE_startx_endx:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &end) != 0)
+ return -1;
+
+ *beginp = begin;
+ *endp = end;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_startx_length:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (addr_idx, addr, addrend);
+ if (__libdw_addrx (cu, addr_idx, &begin) != 0)
+ return -1;
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin;
+ *endp = begin + end;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_offset_pair:
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (begin, addr, addrend);
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin + base;
+ *endp = end + base;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_default_location:
+ *beginp = 0;
+ *endp = (Dwarf_Addr) -1;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_base_address:
+ if (addrend - addr < width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &base);
+
+ *basep = base;
+ *addrp = addr;
+ return 1;
+
+ case DW_LLE_start_end:
+ if (addrend - addr < 2 * width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &end);
+
+ *beginp = begin;
+ *endp = end;
+ *addrp = addr;
+ return 0;
+
+ case DW_LLE_start_length:
+ if (addrend - addr < width)
+ goto invalid;
+ __libdw_read_address_inc (dbg, sec_index, &addr, width, &begin);
+ if (addrend - addr < 1)
+ goto invalid;
+ get_uleb128 (end, addr, addrend);
+
+ *beginp = begin;
+ *endp = begin + end;
+ *addrp = addr;
+ return 0;
+
+ default:
+ goto invalid;
+ }
+ }
else
{
__libdw_seterrno (DWARF_E_INVALID_DWARF);
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index f99ea584..dd47009b 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -206,8 +206,11 @@ struct Dwarf
struct Dwarf_CFI_s *cfi;
/* Fake loc CU. Used when synthesizing attributes for Dwarf_Ops that
- came from a location list entry in dwarf_getlocation_attr. */
+ came from a location list entry in dwarf_getlocation_attr.
+ Depending on version this is the .debug_loc or .debug_loclists
+ section (could be both if mixing CUs with different DWARF versions). */
struct Dwarf_CU *fake_loc_cu;
+ struct Dwarf_CU *fake_loclists_cu;
/* Similar for addrx/constx, which will come from .debug_addr section. */
struct Dwarf_CU *fake_addr_cu;
@@ -365,6 +368,10 @@ struct Dwarf_CU
__libdw_cu_ranges_base. */
Dwarf_Off ranges_base;
+ /* The start of the offset table in .debug_loclists.
+ Don't access directly, call __libdw_cu_locs_base. */
+ Dwarf_Off locs_base;
+
/* Memory boundaries of this CU. */
void *startp;
void *endp;
@@ -1177,6 +1184,84 @@ __libdw_cu_ranges_base (Dwarf_CU *cu)
}
+/* The start of the offset table in .debug_loclists for DWARF5. */
+static inline Dwarf_Off
+__libdw_cu_locs_base (Dwarf_CU *cu)
+{
+ if (cu->locs_base == (Dwarf_Off) -1)
+ {
+ Dwarf_Off offset = 0;
+ Dwarf_Die cu_die = CUDIE(cu);
+ Dwarf_Attribute attr;
+ if (dwarf_attr (&cu_die, DW_AT_loclists_base, &attr) != NULL)
+ {
+ Dwarf_Word off;
+ if (dwarf_formudata (&attr, &off) == 0)
+ offset = off;
+ }
+
+ /* There wasn't an loclists_base, if the Dwarf does have a
+ .debug_loclists section, then it might be we need the
+ base after the first header. */
+ Elf_Data *data = cu->dbg->sectiondata[IDX_debug_loclists];
+ if (offset == 0 && data != NULL)
+ {
+ Dwarf *dbg = cu->dbg;
+ const unsigned char *readp = data->d_buf;
+ const unsigned char *const dataend
+ = (unsigned char *) data->d_buf + data->d_size;
+
+ uint64_t unit_length = read_4ubyte_unaligned_inc (dbg, readp);
+ unsigned int offset_size = 4;
+ if (unlikely (unit_length == 0xffffffff))
+ {
+ if (unlikely (readp > dataend - 8))
+ goto no_header;
+
+ unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+ offset_size = 8;
+ }
+
+ if (readp > dataend - 8
+ || unit_length < 8
+ || unit_length > (uint64_t) (dataend - readp))
+ goto no_header;
+
+ uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+ if (version != 5)
+ goto no_header;
+
+ uint8_t address_size = *readp++;
+ if (address_size != 4 && address_size != 8)
+ goto no_header;
+
+ uint8_t segment_size = *readp++;
+ if (segment_size != 0)
+ goto no_header;
+
+ uint32_t offset_entry_count;
+ offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp);
+
+ const unsigned char *offset_array_start = readp;
+ if (offset_entry_count <= 0)
+ goto no_header;
+
+ uint64_t needed = offset_entry_count * offset_size;
+ if (unit_length - 8 < needed)
+ goto no_header;
+
+ offset = (Dwarf_Off) (offset_array_start
+ - (unsigned char *) data->d_buf);
+ }
+
+ no_header:
+ cu->locs_base = offset;
+ }
+
+ return cu->locs_base;
+}
+
+
/* Link skeleton and split compile units. */
static inline void
__libdw_link_skel_split (Dwarf_CU *skel, Dwarf_CU *split)
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index 83c2eb14..9d231999 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -122,6 +122,7 @@ __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
newp->addr_base = (Dwarf_Off) -1;
newp->str_off_base = (Dwarf_Off) -1;
newp->ranges_base = (Dwarf_Off) -1;
+ newp->locs_base = (Dwarf_Off) -1;
newp->startp = data->d_buf + newp->start;
newp->endp = data->d_buf + newp->end;
diff --git a/src/ChangeLog b/src/ChangeLog
index 8e02d3c5..b6c27432 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2018-04-07 Mark Wielaard <mark@klomp.org>
+
+ * readelf.c (attr_callback): Handle DW_FORM_loclistx and
+ DW_AT_segment.
+
2018-04-12 Mark Wielaard <mark@klomp.org>
* readelf.c (dwarf_loc_list_encoding_string): New functions.
diff --git a/src/readelf.c b/src/readelf.c
index 153fbf5a..54bf22c5 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -6779,6 +6779,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
case DW_FORM_sec_offset:
case DW_FORM_rnglistx:
+ case DW_FORM_loclistx:
case DW_FORM_implicit_const:
case DW_FORM_udata:
case DW_FORM_sdata:
@@ -6808,7 +6809,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
}
FALLTHROUGH;
- /* These cases always take a loclistptr and no constant. */
+ /* These cases always take a loclist[ptr] and no constant. */
case DW_AT_location:
case DW_AT_data_location:
case DW_AT_vtable_elem_location:
@@ -6817,6 +6818,7 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
case DW_AT_frame_base:
case DW_AT_return_addr:
case DW_AT_static_link:
+ case DW_AT_segment:
case DW_AT_GNU_call_site_value:
case DW_AT_GNU_call_site_data_value:
case DW_AT_GNU_call_site_target:
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 6e366eb3..3ed88f6d 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,11 @@
+2018-04-07 Mark Wielaard <mark@klomp.org>
+
+ * run-varlocs.sh: Run on testfileranges5.debug and
+ testsplitfileranges5.debug.
+ * varlocs.c (is_debug): New bool.
+ (print_expr): Don't fail on missing CFI for is_debug.
+ (main): Parse --debug, set is_debug.
+
2018-04-12 Mark Wielaard <mark@klomp.org>
* run-readelf-loc.sh: Add new testcases.
diff --git a/tests/run-varlocs.sh b/tests/run-varlocs.sh
index 2781fef4..8426d20d 100755
--- a/tests/run-varlocs.sh
+++ b/tests/run-varlocs.sh
@@ -124,6 +124,158 @@ module 'testfile_implicit_pointer'
frame_base: {call_frame_cfa {bregx(7,8)}}
EOF
+# Multi CU DWARF5. See run-dwarf-ranges.sh.
+testfiles testfileranges5.debug
+testrun_compare ${abs_top_builddir}/tests/varlocs --debug -e testfileranges5.debug <<\EOF
+module 'testfileranges5.debug'
+[c] CU 'hello.c'@0
+ [2a] function 'no_say'@401160
+ frame_base: {call_frame_cfa {...}}
+ [4a] parameter 'prefix'
+ [401160,401169) {reg5}
+ [401169,40116a) {entry_value(1) {reg5}, stack_value}
+ [40116a,401175) {reg5}
+ [401175,40117a) {entry_value(1) {reg5}, stack_value}
+ [59] variable 'world'
+ [401160,40117a) {addr(0x402004), stack_value}
+ [bd] function 'main'@401050
+ frame_base: {call_frame_cfa {...}}
+ [dd] parameter 'argc'
+ [401050,401062) {reg5}
+ [401062,401067) {entry_value(1) {reg5}, stack_value}
+ [ec] parameter 'argv'
+ [401050,401066) {reg4}
+ [401066,401067) {entry_value(1) {reg4}, stack_value}
+ [fb] inlined function 'subject'@401053
+ [117] parameter 'count'
+ [401053,40105f) {reg5}
+ [120] parameter 'word'
+ [401053,40105f) {reg0}
+ [168] function 'subject'@401150
+ frame_base: {call_frame_cfa {...}}
+ [183] parameter 'word'
+ [401150,401160) {reg5}
+ [18a] parameter 'count'
+ [401150,401160) {reg4}
+module 'testfileranges5.debug'
+[1ab] CU 'world.c'@401180
+ [1cd] function 'no_main'@4011d0
+ frame_base: {call_frame_cfa {...}}
+ [1ef] parameter 'argc'
+ [4011d0,4011e2) {reg5}
+ [4011e2,4011e7) {entry_value(1) {reg5}, stack_value}
+ [1fe] parameter 'argv'
+ [4011d0,4011e6) {reg4}
+ [4011e6,4011e7) {entry_value(1) {reg4}, stack_value}
+ [20d] inlined function 'no_subject'@4011d3
+ [229] parameter 'count'
+ [4011d3,4011df) {reg5}
+ [232] parameter 'word'
+ [4011d3,4011df) {reg0}
+ [28d] function 'say'@401180
+ frame_base: {call_frame_cfa {...}}
+ [2af] parameter 'prefix'
+ [401180,40118e) {reg5}
+ [40118e,40119c) {reg3}
+ [40119c,4011a7) {entry_value(1) {reg5}, stack_value}
+ [4011a7,4011b5) {reg3}
+ [4011b5,4011c0) {entry_value(1) {reg5}, stack_value}
+ [2be] variable 'world'
+ [401193,40119b) {reg0}
+ [4011a7,4011b4) {reg0}
+ [2ce] inlined function 'happy'@40119b
+ [2e6] parameter 'w'
+ [4011a7,4011b4) {reg0}
+ [2ef] inlined function 'sad'@40119b
+ [303] parameter 'c'
+ [40119b,4011a6) {reg0}
+ [4011a6,4011a7) {entry_value(1) {reg5}}
+ [4011b4,4011bf) {reg0}
+ [36b] function 'no_subject'@4011c0
+ frame_base: {call_frame_cfa {...}}
+ [386] parameter 'word'
+ [4011c0,4011d0) {reg5}
+ [38d] parameter 'count'
+ [4011c0,4011d0) {reg4}
+EOF
+
+# Multi CU Split DWARF5. See run-dwarf-ranges.sh.
+# Note that the DIE numbers change, but the actual location addresses are
+# the same as above, even though the representation is totally different.
+testfiles testfilesplitranges5.debug
+testfiles testfile-ranges-hello5.dwo testfile-ranges-world5.dwo
+testrun_compare ${abs_top_builddir}/tests/varlocs --debug -e testfilesplitranges5.debug <<\EOF
+module 'testfilesplitranges5.debug'
+[14] CU 'hello.c'
+ [1d] function 'no_say'@401160
+ frame_base: {call_frame_cfa {...}}
+ [33] parameter 'prefix'
+ [401160,401169) {reg5}
+ [401169,40116a) {entry_value(1) {reg5}, stack_value}
+ [40116a,401175) {reg5}
+ [401175,40117a) {entry_value(1) {reg5}, stack_value}
+ [3c] variable 'world'
+ [401160,40117a) {addr: 0x402004, stack_value}
+ [7e] function 'main'@401050
+ frame_base: {call_frame_cfa {...}}
+ [94] parameter 'argc'
+ [401050,401062) {reg5}
+ [401062,401067) {entry_value(1) {reg5}, stack_value}
+ [9d] parameter 'argv'
+ [401050,401066) {reg4}
+ [401066,401067) {entry_value(1) {reg4}, stack_value}
+ [a6] inlined function 'subject'@401053
+ [bb] parameter 'count'
+ [401053,40105f) {reg5}
+ [c1] parameter 'word'
+ [401053,40105f) {reg0}
+ [f6] function 'subject'@401150
+ frame_base: {call_frame_cfa {...}}
+ [10a] parameter 'word'
+ [401150,401160) {reg5}
+ [111] parameter 'count'
+ [401150,401160) {reg4}
+module 'testfilesplitranges5.debug'
+[14] CU 'world.c'
+ [1d] function 'no_main'@4011d0
+ frame_base: {call_frame_cfa {...}}
+ [35] parameter 'argc'
+ [4011d0,4011e2) {reg5}
+ [4011e2,4011e7) {entry_value(1) {reg5}, stack_value}
+ [3e] parameter 'argv'
+ [4011d0,4011e6) {reg4}
+ [4011e6,4011e7) {entry_value(1) {reg4}, stack_value}
+ [47] inlined function 'no_subject'@4011d3
+ [5c] parameter 'count'
+ [4011d3,4011df) {reg5}
+ [62] parameter 'word'
+ [4011d3,4011df) {reg0}
+ [a7] function 'say'@401180
+ frame_base: {call_frame_cfa {...}}
+ [c2] parameter 'prefix'
+ [401180,40118e) {reg5}
+ [40118e,40119c) {reg3}
+ [40119c,4011a7) {entry_value(1) {reg5}, stack_value}
+ [4011a7,4011b5) {reg3}
+ [4011b5,4011c0) {entry_value(1) {reg5}, stack_value}
+ [cb] variable 'world'
+ [401193,40119b) {reg0}
+ [4011a7,4011b4) {reg0}
+ [d5] inlined function 'happy'@40119b
+ [e3] parameter 'w'
+ [4011a7,4011b4) {reg0}
+ [e9] inlined function 'sad'@40119b
+ [f3] parameter 'c'
+ [40119b,4011a6) {reg0}
+ [4011a6,4011a7) {entry_value(1) {reg5}}
+ [4011b4,4011bf) {reg0}
+ [147] function 'no_subject'@4011c0
+ frame_base: {call_frame_cfa {...}}
+ [15b] parameter 'word'
+ [4011c0,4011d0) {reg5}
+ [162] parameter 'count'
+ [4011c0,4011d0) {reg4}
+EOF
# DW_OP_addrx and DW_OP_constx testcases.
#
diff --git a/tests/varlocs.c b/tests/varlocs.c
index 859068d6..31a1069a 100644
--- a/tests/varlocs.c
+++ b/tests/varlocs.c
@@ -1,5 +1,5 @@
/* Test program for dwarf location functions.
- Copyright (C) 2013, 2015, 2017 Red Hat, Inc.
+ Copyright (C) 2013, 2015, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -44,6 +44,7 @@ Dwarf_CFI *cfi_eh;
Dwarf_Addr cfi_eh_bias;
bool is_ET_REL;
+bool is_debug;
// Whether the current function has a DW_AT_frame_base defined.
// Needed for DW_OP_fbreg.
@@ -257,7 +258,7 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
error (EXIT_FAILURE, 0, "%s used in CFI", opname);
printf ("%s ", opname);
- if (cfi_eh == NULL && cfi_debug == NULL)
+ if (cfi_eh == NULL && cfi_debug == NULL && !is_debug)
error (EXIT_FAILURE, 0, "DW_OP_call_frame_cfa used but no cfi found.");
Dwarf_Frame *frame;
@@ -275,11 +276,11 @@ print_expr (Dwarf_Attribute *attr, Dwarf_Op *expr, Dwarf_Addr addr)
print_expr_block (NULL, cfa_ops, cfa_nops, 0);
free (frame);
}
- else if (is_ET_REL)
+ else if (is_ET_REL || is_debug)
{
/* XXX In ET_REL files there might be an .eh_frame with relocations
we don't handle (e.g. X86_64_PC32). Maybe we should? */
- printf ("{...}\n");
+ printf ("{...}");
}
else
error (EXIT_FAILURE, 0, "dwarf_cfi_addrframe 0x%" PRIx64 ": %s",
@@ -1033,12 +1034,34 @@ main (int argc, char *argv[])
which contains an DWARF expression (but not location lists) and
print those. Otherwise we process all function DIEs and print
all DWARF expressions and location lists associated with
- parameters and variables). */
+ parameters and variables). It must be the first argument,
+ or the second, after --debug. */
bool exprlocs = false;
- if (argc > 1 && strcmp ("--exprlocs", argv[1]) == 0)
+
+ /* With --debug we ignore not being able to find .eh_frame.
+ It must come as first argument. */
+ is_debug = false;
+ if (argc > 1)
+ {
+ if (strcmp ("--exprlocs", argv[1]) == 0)
+ {
+ exprlocs = true;
+ argv[1] = "";
+ }
+ else if (strcmp ("--debug", argv[1]) == 0)
+ {
+ is_debug = true;
+ argv[1] = "";
+ }
+ }
+
+ if (argc > 2)
{
- exprlocs = true;
- argv[1] = "";
+ if (strcmp ("--exprlocs", argv[2]) == 0)
+ {
+ exprlocs = true;
+ argv[2] = "";
+ }
}
int remaining;