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)
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);
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;
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)
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,
}
}
+/* 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,
+ addr1, addr1);
+ a2 = format_dwarf_addr (dwflmod, address_size,
+ addr2 - 1, addr2);
+ 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;
+ if (get_indexed_addr (cu, op1, &addr1) != 0)
+ {
+ printf (" ???..\n");
+ printf (" ???\n");
+ }
+ else
+ {
+ addr2 = addr1 + op2;
+ a1 = format_dwarf_addr (dwflmod, address_size,
+ addr1, addr1);
+ a2 = format_dwarf_addr (dwflmod, address_size,
+ addr2 - 1, addr2);
+ 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
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>");
}
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;
&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;
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,
reset_listptr (&known_loclistptr);
reset_listptr (&known_rangelistptr);
+ reset_listptr (&known_rnglistptr);
}
--- /dev/null
+#! /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