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;
+	}
     }
 }
 
