This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Support unordered .debug_info references to .debug_ranges


Hi,

readelf sometimes complains on valid DWARF already produced by g++-4.3+:

readelf: Error: Range lists in .debug_info section aren't in ascending order!
readelf: Warning: Range lists in .debug_ranges section start at 0x60
[...]

A Googled bugreport:
	http://gcc.gnu.org/ml/gcc/2009-01/msg00540.html

C++ source reproducer:
class A {
public:
  A();
  void f(){}
};
class C {
  C();
};
C::C() {
  A* p = new A;
  p->f();
}

Contents of the .debug_info section:
 <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
    <29>   DW_AT_ranges      : 0x60
 <1><dc>: Abbrev Number: 15 (DW_TAG_subprogram)
 <2><102>: Abbrev Number: 17 (DW_TAG_lexical_block)
    <103>   DW_AT_ranges      : 0x0
 <1><111>: Abbrev Number: 19 (DW_TAG_subprogram)
 <2><133>: Abbrev Number: 17 (DW_TAG_lexical_block)
    <134>   DW_AT_ranges      : 0x30

Checked GCC dwarf2out_finish() it is natural there to produce it that way.

It is due to this readelf code:
  if (!use_debug_info)
    /* FIXME: Should we handle this case?  */
    error (_("Range lists in .debug_info section aren't in ascending
order!\n"));

Not sure if it would be worth the performance to have a no-copy optimization
for already sorted references.

Regression tested on {x86_64,i686}-fedora-linux-gnu.


Thanks,
Jan


binutils/
2009-07-13  Jan Kratochvil  <jan.kratochvil@redhat.com>

	Support unordered .debug_info references to .debug_ranges.
	* dwarf.c (struct range_entry, range_entry_compar): New.
	(display_debug_ranges): Remove variables last_offset, first, j,
	seen_first_offset, use_debug_info and next.  New variables
	range_entries and range_entry_fill.  Create the sorted copy
	range_entries.  Remove the FIXME error on detected unordered references.
	* dwarf.h (debug_info <range_lists>): New comment.

binutils/testsuite/
2009-07-13  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* binutils-all/objcopy.exp (testranges): New test.
	* binutils-all/testranges.d, binutils-all/testranges.s: New files.

--- binutils/dwarf.c	10 Jul 2009 15:26:57 -0000	1.50
+++ binutils/dwarf.c	13 Jul 2009 08:49:22 -0000
@@ -3457,6 +3457,31 @@ display_debug_aranges (struct dwarf_sect
   return 1;
 }
 
+/* Each debug_information[x].range_lists[y] gets this representation for
+   sorting purposes.  */
+
+struct range_entry
+  {
+    /* The debug_information[x].range_lists[y] value.  */
+    unsigned long ranges_offset;
+
+    /* Original debug_information to find parameters of the data.  */
+    debug_info *debug_info_p;
+  };
+
+/* Sort struct range_entry in ascending order of its RANGES_OFFSET.  */
+
+static int
+range_entry_compar (const void *ap, const void *bp)
+{
+  const struct range_entry *a_re = ap;
+  const struct range_entry *b_re = bp;
+  const unsigned long a = a_re->ranges_offset;
+  const unsigned long b = b_re->ranges_offset;
+
+  return (a > b) - (b > a);
+}
+
 static int
 display_debug_ranges (struct dwarf_section *section,
 		      void *file ATTRIBUTE_UNUSED)
@@ -3465,14 +3490,8 @@ display_debug_ranges (struct dwarf_secti
   unsigned char *section_end;
   unsigned long bytes;
   unsigned char *section_begin = start;
-  unsigned int num_range_list = 0;
-  unsigned long last_offset = 0;
-  unsigned int first = 0;
-  unsigned int i;
-  unsigned int j;
-  int seen_first_offset = 0;
-  int use_debug_info = 1;
-  unsigned char *next;
+  unsigned int num_range_list, i;
+  struct range_entry *range_entries, *range_entry_fill;
 
   bytes = section->size;
   section_end = start + bytes;
@@ -3490,135 +3509,117 @@ display_debug_ranges (struct dwarf_secti
       return 0;
     }
 
-  /* Check the order of range list in .debug_info section. If
-     offsets of range lists are in the ascending order, we can
-     use `debug_information' directly.  */
+  num_range_list = 0;
   for (i = 0; i < num_debug_info_entries; i++)
-    {
-      unsigned int num;
+    num_range_list += debug_information [i].num_range_lists;
 
-      num = debug_information [i].num_range_lists;
-      num_range_list += num;
+  if (num_range_list == 0)
+    error (_("No range lists in .debug_info section!\n"));
 
-      /* Check if we can use `debug_information' directly.  */
-      if (use_debug_info && num != 0)
-	{
-	  if (!seen_first_offset)
-	    {
-	      /* This is the first range list.  */
-	      last_offset = debug_information [i].range_lists [0];
-	      first = i;
-	      seen_first_offset = 1;
-	      j = 1;
-	    }
-	  else
-	    j = 0;
+  range_entries = xmalloc (sizeof (*range_entries) * num_range_list);
+  range_entry_fill = range_entries;
 
-	  for (; j < num; j++)
-	    {
-	      if (last_offset >
-		  debug_information [i].range_lists [j])
-		{
-		  use_debug_info = 0;
-		  break;
-		}
-	      last_offset = debug_information [i].range_lists [j];
-	    }
+  for (i = 0; i < num_debug_info_entries; i++)
+    {
+      debug_info *debug_info_p = &debug_information[i];
+      unsigned int j;
+
+      for (j = 0; j < debug_info_p->num_range_lists; j++)
+	{
+	  range_entry_fill->ranges_offset = debug_info_p->range_lists[j];
+	  range_entry_fill->debug_info_p = debug_info_p;
+	  range_entry_fill++;
 	}
     }
 
-  if (!use_debug_info)
-    /* FIXME: Should we handle this case?  */
-    error (_("Range lists in .debug_info section aren't in ascending order!\n"));
-
-  if (!seen_first_offset)
-    error (_("No range lists in .debug_info section!\n"));
+  qsort (range_entries, num_range_list, sizeof (*range_entries),
+	 range_entry_compar);
 
   /* DWARF sections under Mach-O have non-zero addresses.  */
-  if (debug_information [first].num_range_lists > 0
-      && debug_information [first].range_lists [0] != section->address)
+  if (range_entries[0].ranges_offset != section->address)
     warn (_("Range lists in %s section start at 0x%lx\n"),
-	  section->name, debug_information [first].range_lists [0]);
+	  section->name, range_entries[0].ranges_offset);
 
   printf (_("Contents of the %s section:\n\n"), section->name);
   printf (_("    Offset   Begin    End\n"));
 
-  seen_first_offset = 0;
-  for (i = first; i < num_debug_info_entries; i++)
+  for (i = 0; i < num_range_list; i++)
     {
-      dwarf_vma begin;
-      dwarf_vma end;
-      unsigned long offset;
+      struct range_entry *range_entry = &range_entries[i];
+      debug_info *debug_info_p = range_entry->debug_info_p;
       unsigned int pointer_size;
+      unsigned long offset;
+      unsigned char *next;
       unsigned long base_address;
 
-      pointer_size = debug_information [i].pointer_size;
+      pointer_size = debug_info_p->pointer_size;
 
-      for (j = 0; j < debug_information [i].num_range_lists; j++)
+      /* DWARF sections under Mach-O have non-zero addresses.  */
+      offset = range_entry->ranges_offset - section->address;
+      next = section_begin + offset;
+      base_address = debug_info_p->base_address;
+
+      if (i > 0)
 	{
-	  /* DWARF sections under Mach-O have non-zero addresses.  */
-	  offset = debug_information [i].range_lists [j] - section->address;
-	  next = section_begin + offset;
-	  base_address = debug_information [i].base_address;
+	  if (start < next)
+	    warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
+		  (unsigned long) (start - section_begin),
+		  (unsigned long) (next - section_begin), section->name);
+	  else if (start > next)
+	    warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
+		  (unsigned long) (start - section_begin),
+		  (unsigned long) (next - section_begin), section->name);
+	}
+      start = next;
 
-	  if (!seen_first_offset)
-	    seen_first_offset = 1;
-	  else
-	    {
-	      if (start < next)
-		warn (_("There is a hole [0x%lx - 0x%lx] in %s section.\n"),
-		      (unsigned long) (start - section_begin),
-		      (unsigned long) (next - section_begin), section->name);
-	      else if (start > next)
-		warn (_("There is an overlap [0x%lx - 0x%lx] in %s section.\n"),
-		      (unsigned long) (start - section_begin),
-		      (unsigned long) (next - section_begin), section->name);
-	    }
-	  start = next;
+      while (1)
+	{
+	  dwarf_vma begin;
+	  dwarf_vma end;
 
-	  while (1)
-	    {
-	      /* Note: we use sign extension here in order to be sure that
-		 we can detect the -1 escape value.  Sign extension into the
-		 top 32 bits of a 32-bit address will not affect the values
-		 that we display since we always show hex values, and always
-		 the bottom 32-bits.  */
-	      begin = byte_get_signed (start, pointer_size);
-	      start += pointer_size;
-	      end = byte_get_signed (start, pointer_size);
-	      start += pointer_size;
+	  /* Note: we use sign extension here in order to be sure that
+	     we can detect the -1 escape value.  Sign extension into the
+	     top 32 bits of a 32-bit address will not affect the values
+	     that we display since we always show hex values, and always
+	     the bottom 32-bits.  */
+	  begin = byte_get_signed (start, pointer_size);
+	  start += pointer_size;
+	  end = byte_get_signed (start, pointer_size);
+	  start += pointer_size;
 
-	      printf ("    %8.8lx ", offset);
+	  printf ("    %8.8lx ", offset);
 
-	      if (begin == 0 && end == 0)
-		{
-		  printf (_("<End of list>\n"));
-		  break;
-		}
+	  if (begin == 0 && end == 0)
+	    {
+	      printf (_("<End of list>\n"));
+	      break;
+	    }
 
-	      /* Check base address specifiers.  */
-	      if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
-		{
-		  base_address = end;
-		  print_dwarf_vma (begin, pointer_size);
-		  print_dwarf_vma (end, pointer_size);
-		  printf ("(base address)\n");
-		  continue;
-		}
+	  /* Check base address specifiers.  */
+	  if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
+	    {
+	      base_address = end;
+	      print_dwarf_vma (begin, pointer_size);
+	      print_dwarf_vma (end, pointer_size);
+	      printf ("(base address)\n");
+	      continue;
+	    }
 
-	      print_dwarf_vma (begin + base_address, pointer_size);
-	      print_dwarf_vma (end + base_address, pointer_size);
+	  print_dwarf_vma (begin + base_address, pointer_size);
+	  print_dwarf_vma (end + base_address, pointer_size);
 
-	      if (begin == end)
-		fputs (_("(start == end)"), stdout);
-	      else if (begin > end)
-		fputs (_("(start > end)"), stdout);
+	  if (begin == end)
+	    fputs (_("(start == end)"), stdout);
+	  else if (begin > end)
+	    fputs (_("(start > end)"), stdout);
 
-	      putchar ('\n');
-	    }
+	  putchar ('\n');
 	}
     }
   putchar ('\n');
+
+  free (range_entries);
+
   return 1;
 }
 
--- binutils/dwarf.h	6 Jul 2009 14:45:56 -0000	1.9
+++ binutils/dwarf.h	13 Jul 2009 08:49:22 -0000
@@ -87,6 +87,7 @@ typedef struct
   int		*have_frame_base;
   unsigned int   num_loc_offsets;
   unsigned int   max_loc_offsets;
+  /* List of .debug_ranges offsets seen in this .debug_info.  */
   unsigned long *range_lists;
   unsigned int   num_range_lists;
   unsigned int   max_range_lists;
--- binutils/testsuite/binutils-all/objcopy.exp	26 Jun 2009 01:26:28 -0000	1.57
+++ binutils/testsuite/binutils-all/objcopy.exp	13 Jul 2009 08:49:22 -0000
@@ -874,3 +874,4 @@ if [is_elf_format] {
     run_dump_test "localize-hidden-1"
 }
 run_dump_test "localize-hidden-2"
+run_dump_test "testranges"
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ binutils/testsuite/binutils-all/testranges.d	13 Jul 2009 08:49:22 -0000
@@ -0,0 +1,14 @@
+#PROG: objcopy
+#source: testranges.s
+#readelf: -wR --wide
+#name: unordered .debug_info references to .debug_ranges
+
+Contents of the .debug_ranges section:
+
+    Offset   Begin    End
+    00000000 00000001 00000002 
+    00000000 <End of list>
+    00000010 00000000 00000002 
+    00000010 <End of list>
+
+#pass
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ binutils/testsuite/binutils-all/testranges.s	13 Jul 2009 08:49:22 -0000
@@ -0,0 +1,57 @@
+# Test .debug_info can reference .debug_ranges entries without ordering the
+# offsets strictly as increasing.
+
+	.text
+start:
+	.byte	1
+sub:
+	.byte	2
+end:
+
+	.section	.debug_ranges,"",@progbits
+range:
+
+range_sub:
+	.long	sub, end
+	.long	0, 0	# range terminator
+
+range_cu:
+	.long	start, end
+	.long	0, 0	# range terminator
+
+	.section	.debug_info,"",@progbits
+	.long	debugE - debugS	# Length of Compilation Unit Info
+debugS:
+	.value	0x2	# DWARF version number
+	.long	abbrev0	# Offset Into Abbrev. Section
+	.byte	0x4	# Pointer Size (in bytes)
+
+	.uleb128 0x1	# (DIE (0xb) DW_TAG_compile_unit)
+	.long	range_cu - range	# DW_AT_ranges
+
+	.uleb128 0x2	# (DIE (0x6d) DW_TAG_subprogram)
+	.ascii "A\0"	# DW_AT_name
+	.long	range_sub - range	# DW_AT_ranges
+debugE:
+
+	.section	.debug_abbrev,"",@progbits
+abbrev0:
+	.uleb128 0x1	# (abbrev code)
+	.uleb128 0x11	# (TAG: DW_TAG_compile_unit)
+	.byte	0x0	# DW_children_no
+	.uleb128 0x55	# (DW_AT_ranges)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.byte	0x0
+	.byte	0x0
+
+	.uleb128 0x2	# (abbrev code)
+	.uleb128 0x2e	# (TAG: DW_TAG_subprogram)
+	.byte	0x0	# DW_children_no
+	.uleb128 0x3	# (DW_AT_name)
+	.uleb128 0x8	# (DW_FORM_string)
+	.uleb128 0x55	# (DW_AT_ranges)
+	.uleb128 0x6	# (DW_FORM_data4)
+	.byte	0x0
+	.byte	0x0
+
+	.byte	0x0	# abbrevs terminator


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]