This is the mail archive of the binutils@sources.redhat.com 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: BZ 635: Fix dumping .debug_ranges


This patch tries to dump .debug_ranges section correctly.


H.J.
----
2005-01-05  H.J. Lu  <hongjiu.lu@intel.com>

	BZ 635
	readelf.c (saved_base_address): Removed.
	(decode_64bit_range): Likewise.
	(decode_range): Likewise.
	(display_64bit_debug_ranges): Likewise.
	(debug_info): Add range_lists, num_range_lists and
	max_range_lists.
	(read_and_display_attr_value): Handle do_debug_ranges.
	(process_debug_info): Likewise.
	(display_debug_ranges): Rewrite.
	(process_object): Free range_lists.

--- binutils/readelf.c.range	2005-01-05 09:13:17.000000000 -0800
+++ binutils/readelf.c	2005-01-05 09:34:09.000000000 -0800
@@ -170,7 +170,6 @@ int do_notes;
 int is_32bit_elf;
 int have_frame_base;
 int need_base_address;
-unsigned long saved_base_address;
 
 struct group_list
 {
@@ -7895,120 +7894,6 @@ decode_location_expression (unsigned cha
   return need_frame_base;
 }
 
-/* Decode a DW_AT_ranges attribute for 64bit DWARF3 .  */
-
-static void
-decode_64bit_range (unsigned long offset, bfd_vma base_address)
-{
-  const char * start = debug_range_contents + offset;
-  const char * end   = debug_range_contents + debug_range_size;
-
-  do
-    {
-      bfd_vma a;
-      bfd_vma b;
-
-      a = byte_get ((unsigned char *) start, 8);
-      b = byte_get ((unsigned char *) start + 8, 8);
-
-      if (a == 0xffffffff)
-	{
-	  base_address = b;
-	}
-      else if (a == 0 && b == 0)
-	break;
-      else if (a > b)
-	printf (_(" [corrupt: start > end]"));
-      else
-	{
-	  printf (" ");
-	  print_vma (base_address + a, PREFIX_HEX);
-	  printf (" - ");
-	  print_vma (base_address + b, PREFIX_HEX);
-	  printf (", ");
-	}
-
-      start += 16;
-    }
-  while (start < end);
-}
-
-/* Decode a DW_AT_ranges attribute.  */
-
-static void
-decode_range (unsigned long offset, bfd_vma base_address)
-{
-  const char * start;
-  const char * end;
-
-  if (offset >= (debug_range_size - 8))
-    {
-      printf (_("[corrupt: offset is outside the .debug_ranges section]"));
-      return;
-    }
-
-  /* Since all entries in the .debug_ranges section are pairs of either
-     4-byte integers (32-bit DWARF3) or 8-byte integers (64-bit DWARF3)
-     the offset should always be a multiple of 8 bytes.  */
-  if (offset % 8)
-    {
-      printf (_("[corrupt: offset is not a multiple of 8]"));
-      return;
-    }  
-
-  start = debug_range_contents + offset;
-
-  if (offset > 0
-      /* Be paranoid - check to see if the previous
-	 two words were and end-of-range marker.  */
-      && (byte_get ((unsigned char *) start - 4, 4) != 0
-	  || byte_get ((unsigned char *) start - 8, 4) != 0))
-    {
-      printf (_("[corrupt: offset is not at the start of a range]"));
-      return;
-    }  
-
-  end = debug_range_contents + debug_range_size;
-
-  printf ("(");
-  do
-    {
-      unsigned long a;
-      unsigned long b;
-
-      a = byte_get ((unsigned char *) start, 4);
-      b = byte_get ((unsigned char *) start + 4, 4);
-
-      if (a == 0xffffffff)
-	{
-	  if (b == 0xffffffff)
-	    {
-	      decode_64bit_range (offset, base_address);
-	      return;
-	    }
-
-	  base_address = b;
-	}
-      else if (a == 0 && b == 0)
-	break;
-      else if (a > b)
-	printf (_("[corrupt: start > end]"));
-      else
-	{
-	  if (start > debug_range_contents + offset)
-	    printf (", ");
-
-	  printf (_("0x%lx - 0x%lx"),
-		  (unsigned long) base_address + a,
-		  (unsigned long) base_address + b);
-	}
-
-      start += 8;
-    }
-  while (start < end);
-  printf (")");
-}
-
 /* This structure records the information that
    we extract from the.debug_info section.  */
 typedef struct
@@ -8021,6 +7906,9 @@ typedef struct
   int		*have_frame_base;
   unsigned int   num_loc_offsets;
   unsigned int   max_loc_offsets;
+  unsigned long *range_lists;
+  unsigned int   num_range_lists;
+  unsigned int   max_range_lists;
 }
 debug_info;
 
@@ -8154,7 +8042,7 @@ read_and_display_attr_value (unsigned lo
 	  printf (" %lx", uvalue);
 	  printf (" %lx", (unsigned long) byte_get (data + 4, 4));
 	}
-      if ((do_loc || do_debug_loc)
+      if ((do_loc || do_debug_loc || do_debug_ranges)
 	  && num_debug_info_entries == 0)
 	{
 	  if (sizeof (uvalue) == 8)
@@ -8223,7 +8111,7 @@ read_and_display_attr_value (unsigned lo
     }
 
   /* For some attributes we can display further information.  */
-  if ((do_loc || do_debug_loc)
+  if ((do_loc || do_debug_loc || do_debug_ranges)
       && num_debug_info_entries == 0)
     {
       switch (attribute)
@@ -8267,6 +8155,26 @@ read_and_display_attr_value (unsigned lo
 	    debug_info_p->base_address = uvalue;
 	  break;
 
+	case DW_AT_ranges:
+	  if (form == DW_FORM_data4 || form == DW_FORM_data8)
+	    {
+	      /* Process range list.  */
+	      unsigned int max = debug_info_p->max_range_lists;
+	      unsigned int num = debug_info_p->num_range_lists;
+
+	      if (max == 0 || num >= max)
+		{
+		  max += 1024;
+		  debug_info_p->range_lists
+		    = xrealloc (debug_info_p->range_lists,
+				max * sizeof (*debug_info_p->range_lists));
+		  debug_info_p->max_range_lists = max;
+		}
+	      debug_info_p->range_lists [num] = uvalue;
+	      debug_info_p->num_range_lists++;
+	    }
+	  break;
+
 	default:
 	  break;
 	}
@@ -8447,15 +8355,6 @@ read_and_display_attr_value (unsigned lo
 
       break;
 
-    case DW_AT_low_pc:
-      if (need_base_address)
-	saved_base_address = uvalue;
-      break;
-
-    case DW_AT_ranges:
-      decode_range (uvalue, saved_base_address);
-      break;
-
     default:
       break;
     }
@@ -8612,7 +8511,7 @@ process_debug_info (Elf_Internal_Shdr *s
   unsigned int unit;
   unsigned int num_units = 0;
 
-  if ((do_loc || do_debug_loc)
+  if ((do_loc || do_debug_loc || do_debug_ranges)
       && num_debug_info_entries == 0)
     {
       unsigned long length;
@@ -8708,7 +8607,7 @@ process_debug_info (Elf_Internal_Shdr *s
 
       compunit.cu_pointer_size = byte_get (hdrptr, 1);
       hdrptr += 1;
-      if ((do_loc || do_debug_loc)
+      if ((do_loc || do_debug_loc || do_debug_ranges)
 	  && num_debug_info_entries == 0)
 	{
 	  debug_information [unit].cu_offset = cu_offset;
@@ -8719,6 +8618,9 @@ process_debug_info (Elf_Internal_Shdr *s
 	  debug_information [unit].have_frame_base = NULL;
 	  debug_information [unit].max_loc_offsets = 0;
 	  debug_information [unit].num_loc_offsets = 0;
+	  debug_information [unit].range_lists = NULL;
+	  debug_information [unit].max_range_lists= 0;
+	  debug_information [unit].num_range_lists = 0;
 	}
 
       tags = hdrptr;
@@ -8811,7 +8713,6 @@ process_debug_info (Elf_Internal_Shdr *s
 	      break;
 	    case DW_TAG_compile_unit:
 	      need_base_address = 1;
-	      saved_base_address = 0;
 	      break;
 	    case DW_TAG_entry_point:
 	    case DW_TAG_inlined_subroutine:
@@ -8837,9 +8738,9 @@ process_debug_info (Elf_Internal_Shdr *s
  	}
     }
  
-  /* Set num_debug_info_entries here so that it can be used
-     to check if we need to proecess .debug_loc section.  */
-  if ((do_loc || do_debug_loc)
+  /* Set num_debug_info_entries here so that it can be used to check if
+     we need to proecess .debug_loc and .debug_ranges sections.  */
+  if ((do_loc || do_debug_loc || do_debug_ranges)
       && num_debug_info_entries == 0)
     num_debug_info_entries = num_units;
       
@@ -9752,91 +9653,147 @@ display_debug_aranges (Elf_Internal_Shdr
 }
 
 static int
-display_64bit_debug_ranges (unsigned char * start, unsigned char * end)
+display_debug_ranges (Elf_Internal_Shdr *section,
+		      unsigned char *start,
+		      FILE *file ATTRIBUTE_UNUSED)
 {
-  bfd_vma base_address = 0;
+  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;
 
-  while (start < end)
+  bytes = section->sh_size;
+  section_end = start + bytes;
+
+  if (bytes == 0)
+    {
+      printf (_("\nThe .debug_ranges section is empty.\n"));
+      return 0;
+    }
+
+  get_debug_info (file);
+
+  /* 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.  */
+  for (i = 0; i < num_debug_info_entries; i++)
     {
-      bfd_vma a, b;
+      unsigned int num;
 
-      a = byte_get (start, 8);
-      b = byte_get (start + 8, 8);
+      num = debug_information [i].num_range_lists;
+      num_range_list += num;
 
-      if (a == 0xffffffffffffffffLL)
-	{
-	  printf (_(" set base address to "));
-	  print_vma (b, PREFIX_HEX);
-	  base_address = b;
-	}
-      else if (a == 0 && b == 0)
-	printf ( _("end of range"));
-      else if (a > b)
-	printf (_(" <corrupt range entry, start is greater than end>"));
-      else if (base_address == 0)
-	{
-	  printf ("range from base address + ");
-	  print_vma (a, PREFIX_HEX);
-	  printf (" to base address + ");
-	  print_vma (b, PREFIX_HEX);
-	}
-      else
+      /* Check if we can use `debug_information' directly.  */
+      if (use_debug_info && num != 0)
 	{
-	  printf ("range from ");
-	  print_vma (base_address + a, PREFIX_HEX);
-	  printf (" to ");
-	  print_vma (base_address + b, PREFIX_HEX);
-	}
+	  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;
 
-      start += 16;
-      printf ("\n");
+	  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];
+	    }
+	}
     }
 
-  return 1;
-}
+  if (!use_debug_info)
+    /* FIXME: Should we handle this case?  */
+    error (_("Range lists in .debug_info section aren't in ascending order!\n"));
 
-static int
-display_debug_ranges (Elf_Internal_Shdr *section,
-		      unsigned char *start,
-		      FILE *file ATTRIBUTE_UNUSED)
-{
-  unsigned long base_address = 0;
-  unsigned char *end = start + section->sh_size;
+  if (!seen_first_offset)
+    error (_("No range lists in .debug_info section!\n"));
 
-  printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
+  if (debug_information [first].range_lists [0] != 0)
+    warn (_("Range lists in .debug_ranges section start at 0x%lx\n"),
+	  debug_information [first].range_lists [0]);
 
-  while (start < end)
+  printf (_("Contents of the .debug_ranges section:\n\n"));
+  printf (_("    Offset   Begin    End\n"));
+
+  seen_first_offset = 0;
+  for (i = first; i < num_debug_info_entries; i++)
     {
-      unsigned long a;
-      unsigned long b;
+      unsigned long begin;
+      unsigned long end;
+      unsigned long offset;
+      unsigned int pointer_size;
+      unsigned long base_address;
 
-      a = byte_get (start, 4);
-      b = byte_get (start + 4, 4);
+      pointer_size = debug_information [i].pointer_size;
 
-      if (a == 0xffffffff)
+      for (j = 0; j < debug_information [i].num_range_lists; j++)
 	{
-	  /* Attempt to handle 64-bit DWARF3 format.  This assumes
-	     that in a 32-bit DWARF3 file the base address will
-	     never be 0xffffffff, and that the .debug_ranges section
-	     will never contain a mixture of 32-bit and 64-bit entries.  */
-	  if (b == 0xffffffff)
-	    return display_64bit_debug_ranges (start, end);
-      
-	  printf (_(" set base address to 0x%lx\n"), b);
-	  base_address = b;
-	}
-      else if (a == 0 && b == 0)
-	printf (_(" end of range\n"));
-      else if (a > b)
-	printf (_(" <corrupt range entry, start is greater than end>\n"));
-      else if (base_address == 0)
-	printf (_(" range from base address + 0x%lx to base address + 0x%lx\n"), a, b);
-      else
-	printf (_(" range from 0x%lx to 0x%lx\n"), base_address + a, base_address + b);
+	  offset = debug_information [i].range_lists [j];
+	  next = section_begin + offset;
+	  base_address = debug_information [i].base_address;
 
-      start += 8;
-    }
+	  if (!seen_first_offset)
+	    seen_first_offset = 1;
+	  else
+	    {
+	      if (start < next)
+		warn (_("There is a hole [0x%lx - 0x%lx] in .debug_ranges section.\n"),
+		      start - section_begin, next - section_begin);
+	      else if (start > next)
+		warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_ranges section.\n"),
+		      start - section_begin, next - section_begin);
+	    }
+	  start = next;
+
+	  while (1)
+	    {
+	      begin = byte_get (start, pointer_size);
+	      start += pointer_size;
+	      end = byte_get (start, pointer_size);
+	      start += pointer_size;
+
+	      if (begin == 0 && end == 0)
+		break;
+
+	      /* Check base address specifiers.  */
+	      if (begin == -1UL && end != -1UL)
+		{
+		  base_address = end;
+		  printf ("    %8.8lx %8.8lx %8.8lx (base address)\n",
+			  offset, begin, end);
+		  continue;
+		}
+
+	      printf ("    %8.8lx %8.8lx %8.8lx",
+		      offset, begin + base_address, end + base_address);
+
+	      if (begin == end)
+		fputs (_(" (start == end)"), stdout);
+	      else if (begin > end)
+		fputs (_(" (start > end)"), stdout);
 
+	      putchar ('\n');
+	    }
+	  fputs (_("  <End of list>\n"), stdout);
+	}
+    }
+  putchar ('\n');
   return 1;
 }
 
@@ -11804,11 +11761,15 @@ process_object (char *file_name, FILE *f
   if (debug_information)
     {
       for (i = 0; i < num_debug_info_entries; i++)
-	if (!debug_information [i].max_loc_offsets)
-	  {
-	    free (debug_information [i].loc_offsets);
-	    free (debug_information [i].have_frame_base);
-	  }
+	{
+	  if (!debug_information [i].max_loc_offsets)
+	    {
+	      free (debug_information [i].loc_offsets);
+	      free (debug_information [i].have_frame_base);
+	    }
+	  if (!debug_information [i].max_range_lists)
+	    free (debug_information [i].range_lists);
+	}
       free (debug_information);
       debug_information = NULL;
       num_debug_info_entries = 0;


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