This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
Re: readelf: Displaying "raw" .debug_aranges
- From: Mark Wielaard <mjw at redhat dot com>
- To: elfutils-devel at lists dot fedorahosted dot org
- Date: Thu, 21 Mar 2013 23:12:52 +0100
- Subject: Re: readelf: Displaying "raw" .debug_aranges
Hi,
On Thu, 2013-03-21 at 17:09 +0100, Mark Wielaard wrote:
> The above seems to be "correct" according to the DWARF spec. You have to
> skip till the next table based on table header length field. But on the
> buggy (?) .debug_aranges I am looking at not skipping the padding is the
> right thing. This is also what dwarf_getaranges does. So maybe that is
> correct? But it also isn't what binutils readelf and dwz seem to do...
>
> I'll try to figure out what is going on.
Found it. It was a bug in GCC:
http://gcc.gnu.org/ml/gcc-patches/2013-03/msg00827.html
Based on that I kept the code as it is and removed the comment.
I am undecided whether to "fix" the dwarf_getaranges code to do the same
(in normal cases the length and terminator for the table match up, so it
shouldn't matter).
I still like to add this "raw" .debug_aranges reader in readelf because
I think it is useful to have. Using dwarf_getaranges does too much
(especially the sorting of addresses).
Cheers,
Mark
commit ab51506feab195ac9e668356332d7fbf859bfa7d
Author: Mark Wielaard <mjw@redhat.com>
Date: Thu Mar 21 11:04:53 2013 +0100
readelf: Display raw .debug_aranges. Don't use libdw dwarf_getaranges.
Signed-off-by: Mark Wielaard <mjw@redhat.com>
diff --git a/src/ChangeLog b/src/ChangeLog
index a641d33..2588c9e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,7 @@
+2013-03-21 Mark Wielaard <mjw@redhat.com>
+
+ * readelf.c (print_debug_aranges_section): Reimplement.
+
2013-03-19 Mark Wielaard <mjw@redhat.com>
* readelf.c (print_gdb_index_section): Free format_dwarf_addr results.
diff --git a/src/readelf.c b/src/readelf.c
index 1412bed..dfe2a6e 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -4326,61 +4326,155 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
}
-/* Print content of DWARF .debug_aranges section. We fortunately do
- not have to know a bit about the structure of the section, libdwarf
- takes care of it. */
+/* Print content of DWARF .debug_aranges section. */
static void
print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
GElf_Shdr *shdr, Dwarf *dbg)
{
- Dwarf_Aranges *aranges;
- size_t cnt;
- if (unlikely (dwarf_getaranges (dbg, &aranges, &cnt) != 0))
+ Elf_Data *data = elf_rawdata (scn, NULL);
+
+ if (unlikely (data == NULL))
{
error (0, 0, gettext ("cannot get .debug_aranges content: %s"),
- dwarf_errmsg (-1));
+ elf_errmsg (-1));
return;
}
- printf (ngettext ("\
-\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entry:\n",
- "\
-\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n",
- cnt),
+ printf (gettext ("\
+\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
- (uint64_t) shdr->sh_offset, cnt);
+ (uint64_t) shdr->sh_offset);
- /* Compute floor(log16(cnt)). */
- size_t tmp = cnt;
- int digits = 1;
- while (tmp >= 16)
- {
- ++digits;
- tmp >>= 4;
- }
+ const unsigned char *readp = data->d_buf;
+ const unsigned char *readendp = readp + data->d_size;
- for (size_t n = 0; n < cnt; ++n)
+ while (readp < readendp)
{
- Dwarf_Arange *runp = dwarf_onearange (aranges, n);
- if (unlikely (runp == NULL))
+ const unsigned char *hdrstart = readp;
+ size_t start_offset = hdrstart - (const unsigned char *) data->d_buf;
+
+ printf (gettext ("\nTable at offset %Zu:\n"), start_offset);
+ if (readp + 4 > readendp)
{
- printf ("cannot get arange %zu: %s\n", n, dwarf_errmsg (-1));
+ invalid_data:
+ error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
return;
}
- Dwarf_Addr start;
- Dwarf_Word length;
- Dwarf_Off offset;
+ Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
+ unsigned int length_bytes = 4;
+ if (length == DWARF3_LENGTH_64_BIT)
+ {
+ if (readp + 8 > readendp)
+ goto invalid_data;
+ length = read_8ubyte_unaligned_inc (dbg, readp);
+ length_bytes = 8;
+ }
+
+ const unsigned char *nexthdr = readp + length;
+ printf (gettext ("\n Length: %6" PRIu64 "\n"),
+ (uint64_t) length);
+
+ if (nexthdr > readendp)
+ goto invalid_data;
+
+ if (length == 0)
+ continue;
+
+ if (readp + 2 > readendp)
+ goto invalid_data;
+ uint_fast16_t version = read_2ubyte_unaligned_inc (dbg, readp);
+ printf (gettext (" DWARF version: %6" PRIuFAST16 "\n"),
+ version);
+ if (version != 2)
+ {
+ error (0, 0, gettext ("unsupported aranges version"));
+ goto next_table;
+ }
- if (unlikely (dwarf_getarangeinfo (runp, &start, &length, &offset) != 0))
- printf (gettext (" [%*zu] ???\n"), digits, n);
+ Dwarf_Word offset;
+ if (readp + length_bytes > readendp)
+ goto invalid_data;
+ if (length_bytes == 8)
+ offset = read_8ubyte_unaligned_inc (dbg, readp);
else
- printf (gettext (" [%*zu] start: %0#*" PRIx64
- ", length: %5" PRIu64 ", CU DIE offset: %6"
- PRId64 "\n"),
- digits, n, ehdr->e_ident[EI_CLASS] == ELFCLASS32 ? 10 : 18,
- (uint64_t) start, (uint64_t) length, (int64_t) offset);
+ offset = read_4ubyte_unaligned_inc (dbg, readp);
+ printf (gettext (" CU offset: %6" PRIx64 "\n"),
+ (uint64_t) offset);
+
+ if (readp + 1 > readendp)
+ goto invalid_data;
+ unsigned int address_size = *readp++;
+ printf (gettext (" Address size: %6" PRIu64 "\n"),
+ (uint64_t) address_size);
+ if (address_size != 4 && address_size != 8)
+ {
+ error (0, 0, gettext ("unsupported address size"));
+ goto next_table;
+ }
+
+ unsigned int segment_size = *readp++;
+ printf (gettext (" Segment size: %6" PRIu64 "\n\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;
+ }
+
+ /* Round the address to the next multiple of 2*address_size. */
+ readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
+ % (2 * address_size));
+
+ while (readp < nexthdr)
+ {
+ Dwarf_Word range_address;
+ Dwarf_Word range_length;
+ Dwarf_Word segment = 0;
+ if (readp + 2 * address_size + segment_size > readendp)
+ goto invalid_data;
+ if (address_size == 4)
+ {
+ range_address = read_4ubyte_unaligned_inc (dbg, readp);
+ range_length = read_4ubyte_unaligned_inc (dbg, readp);
+ }
+ else
+ {
+ range_address = read_8ubyte_unaligned_inc (dbg, readp);
+ range_length = read_8ubyte_unaligned_inc (dbg, readp);
+ }
+
+ if (segment_size == 4)
+ segment = read_4ubyte_unaligned_inc (dbg, readp);
+ else if (segment_size == 8)
+ segment = read_8ubyte_unaligned_inc (dbg, readp);
+
+ if (range_address == 0 && range_length == 0 && segment == 0)
+ break;
+
+ char *b = format_dwarf_addr (dwflmod, address_size, range_address,
+ range_address);
+ char *e = format_dwarf_addr (dwflmod, address_size,
+ range_address + range_length - 1,
+ range_length);
+ if (segment_size != 0)
+ printf (gettext (" %s..%s (%" PRIx64 ")\n"), b, e,
+ (uint64_t) segment);
+ else
+ printf (gettext (" %s..%s\n"), b, e);
+ free (b);
+ free (e);
+ }
+
+ next_table:
+ if (readp != nexthdr)
+ {
+ size_t padding = nexthdr - readp;
+ printf (gettext (" %Zu padding bytes\n"), padding);
+ readp = nexthdr;
+ }
}
}