This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
[PATCH] readelf: Add .debug_rnglists support.
- From: Mark Wielaard <mark at klomp dot org>
- To: elfutils-devel at sourceware dot org
- Cc: Mark Wielaard <mark at klomp dot org>
- Date: Wed, 23 May 2018 16:29:56 +0200
- Subject: [PATCH] readelf: Add .debug_rnglists support.
Parse the .debug_rnglists section for DWARF5 --debug-dump=ranges.
Add testcase to show both "normal" and "split" DWARF variants are
handled for DWARF4 and DWARF5.
Signed-off-by: Mark Wielaard <mark@klomp.org>
---
libdw/ChangeLog | 11 +
libdw/dwarf.h | 13 ++
libdw/dwarf_begin_elf.c | 1 +
libdw/dwarf_error.c | 1 +
libdw/dwarf_formudata.c | 23 +-
libdw/dwarf_getscopes.c | 4 +-
libdw/libdwP.h | 2 +
src/ChangeLog | 13 ++
src/readelf.c | 529 ++++++++++++++++++++++++++++++++++++++++++--
tests/ChangeLog | 6 +
tests/Makefile.am | 3 +-
tests/run-readelf-ranges.sh | 236 ++++++++++++++++++++
12 files changed, 820 insertions(+), 22 deletions(-)
create mode 100755 tests/run-readelf-ranges.sh
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 3045359..b47fac7 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,14 @@
+2018-04-11 Mark Wielaard <mark@klomp.org>
+
+ * dwarf.h: Add DWARF5 range list entry DW_RLE encodings.
+ * begin_elf.c (dwarf_scnnames): Add IDX_debug_rnglists.
+ * dwarf_error.c (errmsgs): Add DWARF_E_NO_DEBUG_RNGLISTS.
+ * dwarf_formudata.c (dwarf_formudata): Handle DW_AT_rnglists_base
+ and DW_FORM_rnglistx.
+ * dwarf_getscopes.c (pc_match): Also check for
+ DWARF_E_NO_DEBUG_RNGLISTS.
+ * libdwP.h: Add IDX_debug_rnglists.
+
2018-05-22 Mark Wielaard <mark@klomp.org>
* dwarf_getlocation.c (__libdw_cu_base_address): Treat errors of
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index c438399..9c2495e 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -886,6 +886,19 @@ enum
#define DW_MACRO_GNU_hi_user DW_MACRO_hi_user
+/* Range list entry encoding. */
+enum
+ {
+ DW_RLE_end_of_list = 0x0,
+ DW_RLE_base_addressx = 0x1,
+ DW_RLE_startx_endx = 0x2,
+ DW_RLE_startx_length = 0x3,
+ DW_RLE_offset_pair = 0x4,
+ DW_RLE_base_address = 0x5,
+ DW_RLE_start_end = 0x6,
+ DW_RLE_start_length = 0x7
+ };
+
/* DWARF call frame instruction encodings. */
enum
{
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 5d8e79e..2e8c5f3 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -64,6 +64,7 @@ static const char dwarf_scnnames[IDX_last][19] =
[IDX_debug_macinfo] = ".debug_macinfo",
[IDX_debug_macro] = ".debug_macro",
[IDX_debug_ranges] = ".debug_ranges",
+ [IDX_debug_rnglists] = ".debug_rnglists",
[IDX_gnu_debugaltlink] = ".gnu_debugaltlink"
};
#define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0]))
diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c
index 63c8bbe..2e8cd77 100644
--- a/libdw/dwarf_error.c
+++ b/libdw/dwarf_error.c
@@ -93,6 +93,7 @@ static const char *errmsgs[] =
[DWARF_E_NO_FLAG] = N_("no flag value"),
[DWARF_E_INVALID_OFFSET] = N_("invalid offset"),
[DWARF_E_NO_DEBUG_RANGES] = N_(".debug_ranges section missing"),
+ [DWARF_E_NO_DEBUG_RNGLISTS] = N_(".debug_rnglists section missing"),
[DWARF_E_INVALID_CFI] = N_("invalid CFI section"),
[DWARF_E_NO_ALT_DEBUGLINK] = N_("no alternative debug link found"),
[DWARF_E_INVALID_OPCODE] = N_("invalid opcode"),
diff --git a/libdw/dwarf_formudata.c b/libdw/dwarf_formudata.c
index d56e7dc..280fef2 100644
--- a/libdw/dwarf_formudata.c
+++ b/libdw/dwarf_formudata.c
@@ -211,11 +211,23 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
case DW_AT_ranges:
case DW_AT_start_scope:
case DW_AT_GNU_ranges_base:
- /* rangelistptr */
- if (__libdw_formptr (attr, IDX_debug_ranges,
- DWARF_E_NO_DEBUG_RANGES, NULL,
- return_uval) == NULL)
- return -1;
+ 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:
@@ -278,6 +290,7 @@ dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
break;
case DW_FORM_udata:
+ case DW_FORM_rnglistx:
if (datap + 1 > endp)
goto invalid;
get_uleb128 (*return_uval, datap, endp);
diff --git a/libdw/dwarf_getscopes.c b/libdw/dwarf_getscopes.c
index df480d3..5662eec 100644
--- a/libdw/dwarf_getscopes.c
+++ b/libdw/dwarf_getscopes.c
@@ -62,7 +62,9 @@ pc_match (unsigned int depth, struct Dwarf_Die_Chain *die, void *arg)
if (result < 0)
{
int error = INTUSE(dwarf_errno) ();
- if (error != DWARF_E_NOERROR && error != DWARF_E_NO_DEBUG_RANGES)
+ if (error != DWARF_E_NOERROR
+ && error != DWARF_E_NO_DEBUG_RANGES
+ && error != DWARF_E_NO_DEBUG_RNGLISTS)
{
__libdw_seterrno (error);
return -1;
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 82ee5d0..3cfcc55 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -84,6 +84,7 @@ enum
IDX_debug_macinfo,
IDX_debug_macro,
IDX_debug_ranges,
+ IDX_debug_rnglists,
IDX_gnu_debugaltlink,
IDX_last
};
@@ -131,6 +132,7 @@ enum
DWARF_E_NO_FLAG,
DWARF_E_INVALID_OFFSET,
DWARF_E_NO_DEBUG_RANGES,
+ DWARF_E_NO_DEBUG_RNGLISTS,
DWARF_E_INVALID_CFI,
DWARF_E_NO_ALT_DEBUGLINK,
DWARF_E_INVALID_OPCODE,
diff --git a/src/ChangeLog b/src/ChangeLog
index 1a9f4a3..d28d89a 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,16 @@
+2018-04-11 Mark Wielaard <mark@klomp.org>
+
+ * readelf.c (dwarf_range_list_encoding_string): New function.
+ (dwarf_range_list_encoding_name): Likewise.
+ (known_rnglistptr): New static variable.
+ (listptr_cu): New function.
+ (print_debug_rnglists_section): Likewise.
+ (attr_callback): Call notice_listptr for DW_AT_ranges. Handle
+ DW_AT_rnglists_base.
+ (print_debug_units): Do (silently) scan split DWARF also for
+ debug_ranges before DWARF5 to catch all rangelistptrs.
+ (print_debug): Recognize .debug_rnglists. Reset known_rnglistptr.
+
2018-01-21 Mark Wielaard <mark@klomp.org>
* readelf.c (get_indexed_addr): New function.
diff --git a/src/readelf.c b/src/readelf.c
index 1858802..071906f 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -3984,6 +3984,20 @@ dwarf_unit_string (unsigned int type)
static const char *
+dwarf_range_list_encoding_string (unsigned int kind)
+{
+ switch (kind)
+ {
+#define DWARF_ONE_KNOWN_DW_RLE(NAME, CODE) case CODE: return #NAME;
+ DWARF_ALL_KNOWN_DW_RLE
+#undef DWARF_ONE_KNOWN_DW_RLE
+ default:
+ return NULL;
+ }
+}
+
+
+static const char *
dwarf_line_content_description_string (unsigned int kind)
{
switch (kind)
@@ -4145,6 +4159,14 @@ dwarf_unit_name (unsigned int type)
static const char *
+dwarf_range_list_encoding_name (unsigned int kind)
+{
+ const char *ret = dwarf_range_list_encoding_string (kind);
+ return string_or_unknown (ret, kind, 0, 0, false);
+}
+
+
+static const char *
dwarf_line_content_description_name (unsigned int kind)
{
const char *ret = dwarf_line_content_description_string (kind);
@@ -4183,6 +4205,9 @@ print_bytes (size_t n, const unsigned char *bytes)
static int
get_indexed_addr (Dwarf_CU *cu, Dwarf_Word idx, Dwarf_Addr *addr)
{
+ if (cu == NULL)
+ return -1;
+
Elf_Data *debug_addr = cu->dbg->sectiondata[IDX_debug_addr];
if (debug_addr == NULL)
return -1;
@@ -4734,6 +4759,7 @@ struct listptr_table
static struct listptr_table known_loclistptr;
static struct listptr_table known_rangelistptr;
+static struct listptr_table known_rnglistptr;
static void
reset_listptr (struct listptr_table *table)
@@ -4851,6 +4877,32 @@ next_listptr_offset (struct listptr_table *table, size_t idx)
return 0;
}
+/* Returns the next index, base address and CU associated with the
+ list unit offsets. If there is none false is returned, otherwise
+ true. Assumes the table has been sorted. */
+static bool
+listptr_cu (struct listptr_table *table, size_t *idxp,
+ Dwarf_Off start, Dwarf_Off end,
+ Dwarf_Addr *base, struct Dwarf_CU **cu)
+{
+ while (*idxp < table->n
+ && table->table[*idxp].offset < start)
+ ++*idxp;
+
+ if (*idxp < table->n
+ && table->table[*idxp].offset >= start
+ && table->table[*idxp].offset < end)
+ {
+ struct listptr *p = &table->table[*idxp];
+ *base = listptr_base (p);
+ *cu = p->cu;
+ ++*idxp;
+ return true;
+ }
+
+ return false;
+}
+
static void
print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
Ebl *ebl, GElf_Ehdr *ehdr,
@@ -5151,6 +5203,396 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
}
}
+/* Print content of DWARF .debug_rnglists section. */
+static void
+print_debug_rnglists_section (Dwfl_Module *dwflmod,
+ Ebl *ebl, GElf_Ehdr *ehdr,
+ Elf_Scn *scn, GElf_Shdr *shdr,
+ Dwarf *dbg __attribute__((unused)))
+{
+ printf (gettext ("\
+\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset);
+
+ Elf_Data *data =(dbg->sectiondata[IDX_debug_rnglists]
+ ?: elf_rawdata (scn, NULL));
+ if (unlikely (data == NULL))
+ {
+ error (0, 0, gettext ("cannot get .debug_rnglists content: %s"),
+ elf_errmsg (-1));
+ return;
+ }
+
+ /* For the listptr to get the base address/CU. */
+ sort_listptr (&known_rnglistptr, "rnglistptr");
+ size_t listptr_idx = 0;
+
+ const unsigned char *readp = data->d_buf;
+ const unsigned char *const dataend = ((unsigned char *) data->d_buf
+ + data->d_size);
+ while (readp < dataend)
+ {
+ if (unlikely (readp > dataend - 4))
+ {
+ invalid_data:
+ error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
+ return;
+ }
+
+ ptrdiff_t offset = readp - (unsigned char *) data->d_buf;
+ printf (gettext ("Table at Offset 0x%" PRIx64 ":\n\n"),
+ (uint64_t) offset);
+
+ 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 invalid_data;
+
+ unit_length = read_8ubyte_unaligned_inc (dbg, readp);
+ offset_size = 8;
+ }
+ printf (gettext (" Length: %8" PRIu64 "\n"), unit_length);
+
+ /* We need at least 2-bytes + 1-byte + 1-byte + 4-bytes = 8
+ bytes to complete the header. And this unit cannot go beyond
+ the section data. */
+ if (readp > dataend - 8
+ || unit_length < 8
+ || unit_length > (uint64_t) (dataend - readp))
+ goto invalid_data;
+
+ const unsigned char *nexthdr = readp + unit_length;
+
+ uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+ printf (gettext (" DWARF version: %8" PRIu16 "\n"), version);
+
+ if (version != 5)
+ {
+ error (0, 0, gettext ("Unknown version"));
+ goto next_table;
+ }
+
+ uint8_t address_size = *readp++;
+ printf (gettext (" Address size: %8" PRIu64 "\n"),
+ (uint64_t) address_size);
+
+ if (address_size != 4 && address_size != 8)
+ {
+ error (0, 0, gettext ("unsupported address size"));
+ goto next_table;
+ }
+
+ uint8_t segment_size = *readp++;
+ printf (gettext (" Segment size: %8" PRIu64 "\n"),
+ (uint64_t) segment_size);
+
+ if (segment_size != 0 && segment_size != 4 && segment_size != 8)
+ {
+ error (0, 0, gettext ("unsupported segment size"));
+ goto next_table;
+ }
+
+ uint32_t offset_entry_count = read_4ubyte_unaligned_inc (dbg, readp);
+ printf (gettext (" Offset entries: %8" PRIu64 "\n"),
+ (uint64_t) offset_entry_count);
+
+ /* We need the CU that uses this unit to get the initial base address. */
+ Dwarf_Addr cu_base = 0;
+ struct Dwarf_CU *cu = NULL;
+ if (listptr_cu (&known_rnglistptr, &listptr_idx,
+ (Dwarf_Off) offset,
+ (Dwarf_Off) (nexthdr - (unsigned char *) data->d_buf),
+ &cu_base, &cu))
+ {
+ char *basestr = format_dwarf_addr (dwflmod, address_size,
+ cu_base, cu_base);
+ Dwarf_Die cudie;
+ if (dwarf_cu_die (cu, &cudie,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL) == NULL)
+ printf (gettext (" Unknown CU base: %s\n"), basestr);
+ else
+ printf (gettext (" CU [%6" PRIx64 "] base: %s\n"),
+ dwarf_dieoffset (&cudie), basestr);
+ free (basestr);
+ }
+ else
+ printf (gettext (" Not associated with a CU.\n"));
+
+ printf ("\n");
+
+ const unsigned char *offset_array_start = readp;
+ if (offset_entry_count > 0)
+ {
+ uint64_t needed = offset_entry_count * offset_size;
+ if (unit_length - 8 < needed)
+ {
+ error (0, 0,
+ gettext ("too many offset entries for unit length"));
+ goto next_table;
+ }
+
+ printf (gettext (" Offsets starting at 0x%" PRIx64 ":\n"),
+ (uint64_t) (offset_array_start
+ - (unsigned char *) data->d_buf));
+ for (uint32_t idx = 0; idx < offset_entry_count; idx++)
+ {
+ printf (" [%6" PRIu32 "] ", idx);
+ if (offset_size == 4)
+ {
+ uint32_t off = read_4ubyte_unaligned_inc (dbg, readp);
+ printf ("0x%" PRIx32 "\n", off);
+ }
+ else
+ {
+ uint64_t off = read_8ubyte_unaligned_inc (dbg, readp);
+ printf ("0x%" PRIx64 "\n", off);
+ }
+ }
+ printf ("\n");
+ }
+
+ Dwarf_Addr base = cu_base;
+ bool start_of_list = true;
+ while (readp < nexthdr)
+ {
+ uint8_t kind = *readp++;
+ uint64_t op1, op2;
+ char *a1, *a2;
+
+ /* Skip padding. */
+ if (start_of_list && kind == DW_RLE_end_of_list)
+ continue;
+
+ if (start_of_list)
+ {
+ base = cu_base;
+ printf (" Offset: %" PRIx64 ", Index: %" PRIx64 "\n",
+ (uint64_t) (readp - (unsigned char *) data->d_buf - 1),
+ (uint64_t) (readp - offset_array_start - 1));
+ start_of_list = false;
+ }
+
+ printf (" %s", dwarf_range_list_encoding_name (kind));
+ switch (kind)
+ {
+ case DW_RLE_end_of_list:
+ start_of_list = true;
+ printf ("\n\n");
+ break;
+
+ case DW_RLE_base_addressx:
+ if ((uint64_t) (nexthdr - readp) < 1)
+ {
+ invalid_range:
+ error (0, 0, gettext ("invalid range list data"));
+ goto next_table;
+ }
+ get_uleb128 (op1, readp, nexthdr);
+ printf (" %" PRIx64 "\n", op1);
+ if (! print_unresolved_addresses)
+ {
+ Dwarf_Addr addr;
+ if (get_indexed_addr (cu, op1, &addr) != 0)
+ printf (" ???\n");
+ else
+ {
+ a1 = format_dwarf_addr (dwflmod, address_size,
+ addr, addr);
+ printf (" %s\n", a1);
+ free (a1);
+ }
+ }
+ break;
+
+ case DW_RLE_startx_endx:
+ if ((uint64_t) (nexthdr - readp) < 1)
+ goto invalid_range;
+ get_uleb128 (op1, readp, nexthdr);
+ if ((uint64_t) (nexthdr - readp) < 1)
+ goto invalid_range;
+ get_uleb128 (op2, readp, nexthdr);
+ printf (" %" PRIx64 ", %" PRIx64 "\n", op1, op2);
+ if (! print_unresolved_addresses)
+ {
+ Dwarf_Addr addr1;
+ Dwarf_Addr addr2;
+ if (get_indexed_addr (cu, op1, &addr1) != 0
+ || get_indexed_addr (cu, op2, &addr2) != 0)
+ {
+ printf (" ???..\n");
+ printf (" ???\n");
+ }
+ else
+ {
+ a1 = format_dwarf_addr (dwflmod, address_size, op1, op1);
+ a2 = format_dwarf_addr (dwflmod, address_size,
+ op2 - 1, op2);
+ printf (" %s..\n", a1);
+ printf (" %s\n", a2);
+ free (a1);
+ free (a2);
+ }
+ }
+ break;
+
+ case DW_RLE_startx_length:
+ if ((uint64_t) (nexthdr - readp) < 1)
+ goto invalid_range;
+ get_uleb128 (op1, readp, nexthdr);
+ if ((uint64_t) (nexthdr - readp) < 1)
+ goto invalid_range;
+ get_uleb128 (op2, readp, nexthdr);
+ printf (" %" PRIx64 ", %" PRIx64 "\n", op1, op2);
+ if (! print_unresolved_addresses)
+ {
+ Dwarf_Addr addr1;
+ Dwarf_Addr addr2;
+ bool resolved = get_indexed_addr (cu, op1, &addr1) == 0;
+ if (resolved)
+ {
+ op2 = addr1 + op2;
+ resolved = get_indexed_addr (cu, op2, &addr2) == 0;
+ }
+ if (resolved)
+ {
+ printf (" ???..\n");
+ printf (" ???\n");
+ }
+ else
+ {
+ a1 = format_dwarf_addr (dwflmod, address_size, op1, op1);
+ a2 = format_dwarf_addr (dwflmod, address_size,
+ op2 - 1, op2);
+ printf (" %s..\n", a1);
+ printf (" %s\n", a2);
+ free (a1);
+ free (a2);
+ }
+ }
+ break;
+
+ case DW_RLE_offset_pair:
+ if ((uint64_t) (nexthdr - readp) < 1)
+ goto invalid_range;
+ get_uleb128 (op1, readp, nexthdr);
+ if ((uint64_t) (nexthdr - readp) < 1)
+ goto invalid_range;
+ get_uleb128 (op2, readp, nexthdr);
+ printf (" %" PRIx64 ", %" PRIx64 "\n", op1, op2);
+ if (! print_unresolved_addresses)
+ {
+ op1 += base;
+ op2 += base;
+ a1 = format_dwarf_addr (dwflmod, address_size, op1, op1);
+ a2 = format_dwarf_addr (dwflmod, address_size,
+ op2 - 1, op2);
+ printf (" %s..\n", a1);
+ printf (" %s\n", a2);
+ free (a1);
+ free (a2);
+ }
+ break;
+
+ case DW_RLE_base_address:
+ if (address_size == 4)
+ {
+ if ((uint64_t) (nexthdr - readp) < 4)
+ goto invalid_range;
+ op1 = read_4ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ if ((uint64_t) (nexthdr - readp) < 8)
+ goto invalid_range;
+ op1 = read_8ubyte_unaligned_inc (dbg, readp);
+ }
+ base = op1;
+ printf (" 0x%" PRIx64 "\n", base);
+ if (! print_unresolved_addresses)
+ {
+ a1 = format_dwarf_addr (dwflmod, address_size, base, base);
+ printf (" %s\n", a1);
+ free (a1);
+ }
+ break;
+
+ case DW_RLE_start_end:
+ if (address_size == 4)
+ {
+ if ((uint64_t) (nexthdr - readp) < 8)
+ goto invalid_range;
+ op1 = read_4ubyte_unaligned_inc (dbg, readp);
+ op2 = read_4ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ if ((uint64_t) (nexthdr - readp) < 16)
+ goto invalid_range;
+ op1 = read_8ubyte_unaligned_inc (dbg, readp);
+ op2 = read_8ubyte_unaligned_inc (dbg, readp);
+ }
+ printf (" 0x%" PRIx64 "..0x%" PRIx64 "\n", op1, op2);
+ if (! print_unresolved_addresses)
+ {
+ a1 = format_dwarf_addr (dwflmod, address_size, op1, op1);
+ a2 = format_dwarf_addr (dwflmod, address_size,
+ op2 - 1, op2);
+ printf (" %s..\n", a1);
+ printf (" %s\n", a2);
+ free (a1);
+ free (a2);
+ }
+ break;
+
+ case DW_RLE_start_length:
+ if (address_size == 4)
+ {
+ if ((uint64_t) (nexthdr - readp) < 4)
+ goto invalid_range;
+ op1 = read_4ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ if ((uint64_t) (nexthdr - readp) < 8)
+ goto invalid_range;
+ op1 = read_8ubyte_unaligned_inc (dbg, readp);
+ }
+ if ((uint64_t) (nexthdr - readp) < 1)
+ goto invalid_range;
+ get_uleb128 (op2, readp, nexthdr);
+ printf (" 0x%" PRIx64 ", %" PRIx64 "\n", op1, op2);
+ if (! print_unresolved_addresses)
+ {
+ a1 = format_dwarf_addr (dwflmod, address_size, op1, op1);
+ op2 = op1 + op2;
+ a2 = format_dwarf_addr (dwflmod, address_size,
+ op2 - 1, op2);
+ printf (" %s..\n", a1);
+ printf (" %s\n", a2);
+ free (a1);
+ free (a2);
+ }
+ break;
+
+ default:
+ goto invalid_range;
+ }
+ }
+
+ next_table:
+ if (readp != nexthdr)
+ {
+ size_t padding = nexthdr - readp;
+ printf (gettext (" %zu padding bytes\n\n"), padding);
+ readp = nexthdr;
+ }
+ }
+}
/* Print content of DWARF .debug_ranges section. */
static void
@@ -6317,11 +6759,51 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
case DW_AT_ranges:
{
- bool nlpt = notice_listptr (section_ranges, &known_rangelistptr,
+ bool nlpt;
+ if (cbargs->cu->version < 5)
+ nlpt = notice_listptr (section_ranges, &known_rangelistptr,
+ cbargs->addrsize, cbargs->offset_size,
+ cbargs->cu, num, attr);
+ else
+ {
+ /* Only register for a real section offset. Otherwise
+ it is a DW_FORM_rangelistx which is just an index
+ number and we should already have registered the
+ section offset for the index when we saw the
+ DW_AT_rnglists_base CU attribute. */
+ if (form == DW_FORM_sec_offset)
+ nlpt = notice_listptr (section_ranges, &known_rnglistptr,
+ cbargs->addrsize, cbargs->offset_size,
+ cbargs->cu, num, attr);
+ else
+ nlpt = true;
+ }
+
+ if (!cbargs->silent)
+ {
+ if (cbargs->cu->version < 5 || form == DW_FORM_sec_offset)
+ printf (" %*s%-20s (%s) range list [%6"
+ PRIxMAX "]%s\n",
+ (int) (level * 2), "", dwarf_attr_name (attr),
+ dwarf_form_name (form), (uintmax_t) num,
+ nlpt ? "" : " <WARNING offset too big>");
+ else
+ printf (" %*s%-20s (%s) range index [%6"
+ PRIxMAX "]\n",
+ (int) (level * 2), "", dwarf_attr_name (attr),
+ dwarf_form_name (form), (uintmax_t) num);
+ }
+ }
+ return DWARF_CB_OK;
+
+ case DW_AT_rnglists_base:
+ {
+ bool nlpt = notice_listptr (section_ranges, &known_rnglistptr,
cbargs->addrsize, cbargs->offset_size,
cbargs->cu, num, attr);
if (!cbargs->silent)
- printf (" %*s%-20s (%s) range list [%6" PRIxMAX "]%s\n",
+ printf (" %*s%-20s (%s) range list [%6"
+ PRIxMAX "]%s\n",
(int) (level * 2), "", dwarf_attr_name (attr),
dwarf_form_name (form), (uintmax_t) num,
nlpt ? "" : " <WARNING offset too big>");
@@ -6771,13 +7253,21 @@ print_debug_units (Dwfl_Module *dwflmod,
}
while (level >= 0);
- /* We might want to show the split compile unit if this was a skeleton. */
- if (!silent && show_split_units && unit_type == DW_UT_skeleton)
+ /* We might want to show the split compile unit if this was a skeleton.
+ We need to scan it if we are requesting printing .debug_ranges for
+ DWARF4 since GNU DebugFission uses "offsets" into the main ranges
+ section. */
+ if (unit_type == DW_UT_skeleton
+ && ((!silent && show_split_units)
+ || (version < 5 && (print_debug_sections & section_ranges) != 0)))
{
Dwarf_Die subdie;
if (dwarf_cu_info (cu, NULL, NULL, NULL, &subdie, NULL, NULL, NULL) != 0
|| dwarf_tag (&subdie) == DW_TAG_invalid)
- error (0, 0, gettext ("Could not find split compile unit"));
+ {
+ if (!silent)
+ error (0, 0, gettext ("Could not find split compile unit"));
+ }
else
{
Dwarf_CU *split_cu = subdie.cu;
@@ -6785,16 +7275,21 @@ print_debug_units (Dwfl_Module *dwflmod,
&addrsize, &offsize, &unit_id, &subdie_off);
Dwarf_Off offset = cu->start;
- printf (gettext (" Split compilation unit at offset %" PRIu64 ":\n"
- " Version: %" PRIu16
- ", Abbreviation section offset: %" PRIu64
- ", Address size: %" PRIu8
- ", Offset size: %" PRIu8 "\n"),
- (uint64_t) offset, version, abbroffset, addrsize, offsize);
- printf (gettext (" Unit type: %s (%" PRIu8 ")"),
- dwarf_unit_name (unit_type), unit_type);
- printf (", Unit id: 0x%.16" PRIx64 "", unit_id);
- printf ("\n");
+ if (!silent)
+ {
+ printf (gettext (" Split compilation unit at offset %"
+ PRIu64 ":\n"
+ " Version: %" PRIu16
+ ", Abbreviation section offset: %" PRIu64
+ ", Address size: %" PRIu8
+ ", Offset size: %" PRIu8 "\n"),
+ (uint64_t) offset, version, abbroffset,
+ addrsize, offsize);
+ printf (gettext (" Unit type: %s (%" PRIu8 ")"),
+ dwarf_unit_name (unit_type), unit_type);
+ printf (", Unit id: 0x%.16" PRIx64 "", unit_id);
+ printf ("\n");
+ }
unit_type = DW_UT_split_compile;
is_split = true;
@@ -9248,6 +9743,9 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
NEW_SECTION (macinfo),
NEW_SECTION (macro),
NEW_SECTION (ranges),
+ /* rnglists is ranges for DWARF5. */
+ { ".debug_rnglists", section_ranges,
+ print_debug_rnglists_section },
{ ".eh_frame", section_frame | section_exception,
print_debug_frame_section },
{ ".eh_frame_hdr", section_frame | section_exception,
@@ -9291,6 +9789,7 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
reset_listptr (&known_loclistptr);
reset_listptr (&known_rangelistptr);
+ reset_listptr (&known_rnglistptr);
}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index e6f9959..7a4ccf0 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,9 @@
+2018-04-11 Mark Wielaard <mark@klomp.org>
+
+ * run-readelf-ranges.sh: New test.
+ * Makefile.am (TESTS): Add run-readelf-ranges.sh.
+ (EXTRA_DIST): Likewise.
+
2018-05-21 Mark Wielaard <mark@klomp.org>
* addrx_constx-4.dwo.bz2: New testfile.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4b13be2..54a3d1d 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -97,7 +97,7 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \
run-varlocs-self.sh run-exprlocs-self.sh \
run-readelf-test1.sh run-readelf-test2.sh run-readelf-test3.sh \
run-readelf-test4.sh run-readelf-twofiles.sh \
- run-readelf-macro.sh run-readelf-loc.sh \
+ run-readelf-macro.sh run-readelf-loc.sh run-readelf-ranges.sh \
run-readelf-aranges.sh run-readelf-line.sh run-readelf-z.sh \
run-native-test.sh run-bug1-test.sh \
run-debuglink.sh run-debugaltlink.sh run-buildid.sh \
@@ -234,6 +234,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh run-ar.sh \
testfile-macros-0xff.bz2 \
run-readelf-macro.sh testfilemacro.bz2 \
run-readelf-loc.sh testfileloc.bz2 \
+ run-readelf-ranges.sh \
run-readelf-aranges.sh run-readelf-line.sh testfilefoobarbaz.bz2 \
testfile-ppc64-min-instr.bz2 \
testfile-dwarf-45.source \
diff --git a/tests/run-readelf-ranges.sh b/tests/run-readelf-ranges.sh
new file mode 100755
index 0000000..160ef58
--- /dev/null
+++ b/tests/run-readelf-ranges.sh
@@ -0,0 +1,236 @@
+#! /bin/sh
+# Copyright (C) 2018 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# See run-readelf-loc.sh
+
+testfiles testfileloc
+
+# Process values as offsets from base addresses and resolve to symbols.
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=ranges testfileloc<<\EOF
+
+DWARF section [34] '.debug_ranges' at offset 0xd94:
+
+ CU [ b] base: 0x0000000000400480 <main>
+ [ 0] range 0, 2
+ 0x0000000000400480 <main>..
+ 0x0000000000400481 <main+0x1>
+ range 5, d
+ 0x0000000000400485 <main+0x5>..
+ 0x000000000040048c <main+0xc>
+
+ CU [ e0] base: 0x00000000004004a0 <say>
+ [ 30] range d, f
+ 0x00000000004004ad <say+0xd>..
+ 0x00000000004004ae <say+0xe>
+ range 12, 1a
+ 0x00000000004004b2 <say+0x12>..
+ 0x00000000004004b9 <say+0x19>
+EOF
+
+# Don't resolve addresses to symbols.
+testrun_compare ${abs_top_builddir}/src/readelf -N --debug-dump=ranges testfileloc<<\EOF
+
+DWARF section [34] '.debug_ranges' at offset 0xd94:
+
+ CU [ b] base: 0x0000000000400480
+ [ 0] range 0, 2
+ 0x0000000000400480..
+ 0x0000000000400481
+ range 5, d
+ 0x0000000000400485..
+ 0x000000000040048c
+
+ CU [ e0] base: 0x00000000004004a0
+ [ 30] range d, f
+ 0x00000000004004ad..
+ 0x00000000004004ae
+ range 12, 1a
+ 0x00000000004004b2..
+ 0x00000000004004b9
+EOF
+
+# Produce "raw" unprocessed content.
+testrun_compare ${abs_top_builddir}/src/readelf -U --debug-dump=ranges testfileloc<<\EOF
+
+DWARF section [34] '.debug_ranges' at offset 0xd94:
+
+ CU [ b] base: 0x0000000000400480
+ [ 0] range 0, 2
+ range 5, d
+
+ CU [ e0] base: 0x00000000004004a0
+ [ 30] range d, f
+ range 12, 1a
+EOF
+
+# .debug_rnglists (DWARF5), see tests/testfile-dwarf-45.source
+testfiles testfile-dwarf-5
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=ranges testfile-dwarf-5<<\EOF
+
+DWARF section [33] '.debug_rnglists' at offset 0x1d9a:
+Table at Offset 0x0:
+
+ Length: 45
+ DWARF version: 5
+ Address size: 8
+ Segment size: 0
+ Offset entries: 0
+ CU [ 218] base: 000000000000000000
+
+ Offset: c, Index: 0
+ base_address 0x400583
+ 0x0000000000400583 <calc+0x13>
+ offset_pair 0, 2
+ 0x0000000000400583 <calc+0x13>..
+ 0x0000000000400584 <calc+0x14>
+ offset_pair 5, 15
+ 0x0000000000400588 <calc+0x18>..
+ 0x0000000000400597 <calc+0x27>
+ end_of_list
+
+ Offset: 1c, Index: 10
+ start_length 0x400570, 2b
+ 0x0000000000400570 <calc>..
+ 0x000000000040059a <calc+0x2a>
+ start_length 0x400410, 20
+ 0x0000000000400410 <main>..
+ 0x000000000040042f <main+0x1f>
+ end_of_list
+
+EOF
+
+# Same as above, but for DWARF4, note no header, and base address is not
+# given, but ranges are the same.
+testfiles testfile-dwarf-4
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=ranges testfile-dwarf-4<<\EOF
+
+DWARF section [32] '.debug_ranges' at offset 0x1f96:
+
+ CU [ 21c] base: 000000000000000000
+ [ 0] range 400583, 400585
+ 0x0000000000400583 <calc+0x13>..
+ 0x0000000000400584 <calc+0x14>
+ range 400588, 400598
+ 0x0000000000400588 <calc+0x18>..
+ 0x0000000000400597 <calc+0x27>
+ [ 30] range 400570, 40059b
+ 0x0000000000400570 <calc>..
+ 0x000000000040059a <calc+0x2a>
+ range 400410, 400430
+ 0x0000000000400410 <main>..
+ 0x000000000040042f <main+0x1f>
+EOF
+
+# Now with split dwarf. See tests/testfile-dwarf-45.source.
+# Note that this will have an offsets table that the .dwo can refer to.
+testfiles testfile-splitdwarf-5 testfile-hello5.dwo testfile-world5.dwo
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=ranges testfile-splitdwarf-5<<\EOF
+
+DWARF section [35] '.debug_rnglists' at offset 0x393a:
+Table at Offset 0x0:
+
+ Length: 53
+ DWARF version: 5
+ Address size: 8
+ Segment size: 0
+ Offset entries: 2
+ CU [ 49] base: 000000000000000000
+
+ Offsets starting at 0xc:
+ [ 0] 0x8
+ [ 1] 0x18
+
+ Offset: 14, Index: 8
+ base_address 0x4011d3
+ 0x00000000004011d3 <calc+0x13>
+ offset_pair 0, 2
+ 0x00000000004011d3 <calc+0x13>..
+ 0x00000000004011d4 <calc+0x14>
+ offset_pair 5, 15
+ 0x00000000004011d8 <calc+0x18>..
+ 0x00000000004011e7 <calc+0x27>
+ end_of_list
+
+ Offset: 24, Index: 18
+ start_length 0x4011c0, 2b
+ 0x00000000004011c0 <calc>..
+ 0x00000000004011ea <calc+0x2a>
+ start_length 0x401060, 20
+ 0x0000000000401060 <main>..
+ 0x000000000040107f <main+0x1f>
+ end_of_list
+
+EOF
+
+# Note that the rnglist_base attribute of the second CU points to the offsets
+# above 0xc [c].
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=info testfile-splitdwarf-5<<\EOF
+
+DWARF section [28] '.debug_info' at offset 0x3102:
+ [Offset]
+ Compilation unit at offset 0:
+ Version: 5, Abbreviation section offset: 0, Address size: 8, Offset size: 4
+ Unit type: skeleton (4), Unit id: 0xc422aa5c31fec205
+ [ 14] skeleton_unit abbrev: 1
+ low_pc (addr) 0x0000000000401160 <foo>
+ high_pc (data8) 81 (0x00000000004011b1)
+ stmt_list (sec_offset) 0
+ dwo_name (strp) "testfile-hello5.dwo"
+ comp_dir (strp) "/home/mark/src/elfutils/tests"
+ GNU_pubnames (flag_present) yes
+ addr_base (sec_offset) 8
+ Compilation unit at offset 53:
+ Version: 5, Abbreviation section offset: 21, Address size: 8, Offset size: 4
+ Unit type: skeleton (4), Unit id: 0xb6c8b9d97e6dfdfe
+ [ 49] skeleton_unit abbrev: 1
+ ranges (sec_offset) range list [ 24]
+ low_pc (addr) 000000000000000000
+ stmt_list (sec_offset) 655
+ dwo_name (strp) "testfile-world5.dwo"
+ comp_dir (strp) "/home/mark/src/elfutils/tests"
+ GNU_pubnames (flag_present) yes
+ addr_base (sec_offset) 168
+ rnglists_base (sec_offset) range list [ c]
+EOF
+
+# Same for DWARF4 GNU DebugFission. But now we need to scan the .dwo
+# explicitly to know it will use the first ranges.
+testfiles testfile-splitdwarf-4 testfile-hello4.dwo testfile-world4.dwo
+testrun_compare ${abs_top_builddir}/src/readelf --debug-dump=ranges testfile-splitdwarf-4<<\EOF
+
+DWARF section [32] '.debug_ranges' at offset 0x3611:
+
+ CU [ b] base: 000000000000000000
+ [ 0] range 4011d3, 4011d5
+ 0x00000000004011d3 <calc+0x13>..
+ 0x00000000004011d4 <calc+0x14>
+ range 4011d8, 4011e8
+ 0x00000000004011d8 <calc+0x18>..
+ 0x00000000004011e7 <calc+0x27>
+
+ CU [ 3f] base: 000000000000000000
+ [ 30] range 4011c0, 4011eb
+ 0x00000000004011c0 <calc>..
+ 0x00000000004011ea <calc+0x2a>
+ range 401060, 401080
+ 0x0000000000401060 <main>..
+ 0x000000000040107f <main+0x1f>
+EOF
+
+exit 0
--
1.8.3.1