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]

Re: PATCH: BZ 615: Fix dumping .debug_loc section


On Tue, Dec 28, 2004 at 04:59:26PM -0800, H. J. Lu wrote:
> This patch tries to fix dumping .debug_loc section. This patch
> assumes location lists in .debug_info are in the same order as
> compilation units. It may be better to dump location lists by
> compilation units.
> 

I updated the patch to dump location lists by compilation units.


H.J.
-----
2004-12-29  H.J. Lu  <hongjiu.lu@intel.com>

	BZ 615
	* readelf.c (process_debug_info): New.
	(debug_info): Add num_loc_offsets, loc_offsets and
	last_loc_offset_p.
	(get_debug_info): Use process_debug_info.
	(display_debug_loc): Properly handle location list. Warn bad
	location lists.
	(read_and_process_attr_value): New.
	(read_and_display_attr_value): Use "%lx" for DW_FORM_data4.
	(display_debug_info): Use process_debug_info.
	(process_object): Also free loc_offsets in debug_information.

--- binutils/readelf.c.loc	2004-12-27 11:39:00.000000000 -0800
+++ binutils/readelf.c	2004-12-29 19:11:57.462696492 -0800
@@ -218,6 +218,8 @@ print_mode;
 
 static bfd_vma (*byte_get) (unsigned char *, int);
 static void (*byte_put) (unsigned char *, bfd_vma, int);
+static int process_debug_info (Elf_Internal_Shdr *, unsigned char *,
+			       FILE *, int);
 
 #define UNKNOWN -1
 
@@ -7074,6 +7076,10 @@ typedef struct
 {
   unsigned int   pointer_size;
   unsigned long  cu_offset;
+  /* This is an array of offsets to the location list table.  */
+  unsigned long  *loc_offsets;
+  unsigned int   num_loc_offsets;
+  unsigned int   max_loc_offsets;
 }
 debug_info;
 
@@ -7135,11 +7141,7 @@ get_debug_info (FILE * file)
 {
   Elf_Internal_Shdr * section;
   unsigned char *     start;
-  unsigned char *     end;
-  unsigned char *     begin;
-  unsigned long       length;
-  unsigned int        num_units;
-  unsigned int        unit;
+  int		      ret;
 
   /* Reset the last pointer size so that we can issue correct error
      messages if we are displaying the contents of more than one section.  */
@@ -7154,87 +7156,14 @@ get_debug_info (FILE * file)
   if (section == NULL)
     return 0;
 
-  length = section->sh_size;
   start = get_data (NULL, file, section->sh_offset, section->sh_size,
 		    _("extracting information from .debug_info section"));
   if (start == NULL)
     return 0;
 
-  end = start + section->sh_size;
-  /* First scan the section to get the number of comp units.  */
-  for (begin = start, num_units = 0; begin < end; num_units++)
-    {
-      /* Read the first 4 bytes.  For a 32-bit DWARF section, this will
-	 be the length.  For a 64-bit DWARF section, it'll be the escape
-	 code 0xffffffff followed by an 8 byte length.  */
-      length = byte_get (begin, 4);
-
-      if (length == 0xffffffff)
-	{
-	  length = byte_get (begin + 4, 8);
-	  begin += length + 12;
-	}
-      else
-	begin += length + 4;
-    }
-
-  if (num_units == 0)
-    {
-      error (_("No comp units in .debug_info section ?"));
-      free (start);
-      return 0;
-    }
-
-  /* Then allocate an array to hold the information.  */
-  debug_information = malloc (num_units * sizeof * debug_information);
-  if (debug_information == NULL)
-    {
-      error (_("Not enough memory for a debug info array of %u entries"),
-	     num_units);
-      free (start);
-      return 0;
-    }
-
-  /* Populate the array.  */
-  for (begin = start, unit = 0; begin < end; unit++)
-    {
-      debug_information [unit].cu_offset = begin - start;
-
-      length = byte_get (begin, 4);
-      if (length == 0xffffffff)
-	{
-	  /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes
-	     from the start of the section.  This is computed as follows:
-
-	     unit_length:         12 bytes
-	     version:              2 bytes
-	     debug_abbrev_offset:  8 bytes
-	     -----------------------------
-	     Total:               22 bytes  */
-
-	  debug_information [unit].pointer_size = byte_get (begin + 22, 1);
-	  length = byte_get (begin + 4, 8);
-	  begin += length + 12;
-	}
-      else
-	{
-	  /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from
-	     the start of the section:
-
-	     unit_length:          4 bytes
-	     version:              2 bytes
-	     debug_abbrev_offset:  4 bytes
-	     -----------------------------
-	     Total:               10 bytes  */
-
-	  debug_information [unit].pointer_size = byte_get (begin + 10, 1);
-	  begin += length + 4;
-	}
-    }
-
+  ret = process_debug_info (section, start, file, 1);
   free (start);
-
-  return num_debug_info_entries = num_units;
+  return ret ? num_debug_info_entries : 0;
 }
 
 static int
@@ -8500,7 +8429,13 @@ display_debug_loc (Elf_Internal_Shdr *se
   unsigned long bytes;
   unsigned char *section_begin = start;
   bfd_vma addr;
-  unsigned int comp_unit = 0;
+  unsigned int num_loc_list = 0;
+  unsigned long last_offset = 0;
+  unsigned int first = 0;
+  unsigned int i, j;
+  int seen_first_offset = 0;
+  int use_debug_info = 1;
+  unsigned char *next;
 
   addr = section->sh_addr;
   bytes = section->sh_size;
@@ -8514,10 +8449,65 @@ display_debug_loc (Elf_Internal_Shdr *se
 
   get_debug_info (file);
 
+  /* Check the order of location list in .debug_info section. If
+     offsets of location lists are in the ascending order, we can
+     use `debug_information' directly.  */
+  for (i = 0; i < num_debug_info_entries; i++)
+    {
+      unsigned int num;
+
+      num = debug_information [i].num_loc_offsets;
+      num_loc_list += num;
+
+      /* Check if we can use `debug_information' directly.  */
+      if (use_debug_info && num != 0)
+	{
+	  if (!seen_first_offset)
+	    {
+	      /* This is the first location list.  */
+	      last_offset = debug_information [i].loc_offsets [0];
+	      first = i;
+	      seen_first_offset = 1;
+	      j = 1;
+	    }
+	  else
+	    j = 0;
+
+	  for (; j < num; j++)
+	    {
+	      if (last_offset >
+		  debug_information [i].loc_offsets [j])
+		{
+		  use_debug_info = 0;
+		  break;
+		}
+	      last_offset = debug_information [i].loc_offsets [j];
+	    }
+	}
+    }
+
+  if (!use_debug_info)
+    {
+      /* FIXME: Should we handle this case?  */
+      error (_("Location lists in .debug_info section aren't in ascending order!\n"));
+    }
+
+  if (!seen_first_offset)
+    {
+      error (_("No location lists in .debug_info section!\n"));
+    }
+
+  if (debug_information [first].loc_offsets [0] != 0)
+    {
+      warn (_("Location lists in .debug_loc section start at 0x%lx\n"),
+	      debug_information [first].loc_offsets [0]);
+    }
+
   printf (_("Contents of the .debug_loc section:\n\n"));
   printf (_("\n    Offset   Begin    End      Expression\n"));
 
-  while (start < section_end)
+  seen_first_offset = 0;
+  for (i = first; i < num_debug_info_entries; i++)
     {
       unsigned long begin;
       unsigned long end;
@@ -8526,42 +8516,63 @@ display_debug_loc (Elf_Internal_Shdr *se
       unsigned int pointer_size;
       unsigned long cu_offset;
 
-      offset = start - section_begin;
+      pointer_size = debug_information [i].pointer_size;
+      cu_offset = debug_information [i].cu_offset;
 
-      /* Get the pointer size from the comp unit associated
-	 with this block of location information.  */
-      pointer_size = get_pointer_size_and_offset_of_comp_unit
-	(comp_unit, ".debug_loc", & cu_offset);
+      for (j = 0; j < debug_information [i].num_loc_offsets; j++)
+	{
+	  offset = debug_information [i].loc_offsets [j];
+	  next = section_begin + offset;
 
-      comp_unit ++;
+	  if (!seen_first_offset)
+	    seen_first_offset = 1;
+	  else
+	    {
+	      if (start < next)
+		warn (_("There is a hole [0x%lx - 0x%lx] in .debug_loc section.\n"),
+		      start, next);
+	      else if (start > next)
+		warn (_("There is an overlap [0x%lx - 0x%lx] in .debug_loc section.\n"),
+		      start, next);
+	    }
 
-      while (1)
-	{
-	  begin = byte_get (start, pointer_size);
-	  start += pointer_size;
-	  end = byte_get (start, pointer_size);
-	  start += pointer_size;
+	  start = next;
 
-	  if (begin == 0 && end == 0)
-	    break;
+	  while (1)
+	    {
+	      begin = byte_get (start, pointer_size);
+	      start += pointer_size;
+	      end = byte_get (start, pointer_size);
+	      start += pointer_size;
 
-	  /* For now, skip any base address specifiers.  */
-	  if (begin == 0xffffffff)
-	    continue;
+	      if (begin == 0 && end == 0)
+		break;
 
-	  begin += addr;
-	  end += addr;
+	      /* For now, skip any base address specifiers.  */
+	      if (begin == 0xffffffff)
+		continue;
 
-	  length = byte_get (start, 2);
-	  start += 2;
+	      begin += addr;
+	      end += addr;
 
-	  printf ("    %8.8lx %8.8lx %8.8lx (", offset, begin, end);
-	  decode_location_expression (start, pointer_size, length, cu_offset);
-	  printf (")\n");
+	      length = byte_get (start, 2);
+	      start += 2;
+
+	      printf ("    %8.8lx %8.8lx %8.8lx (",
+		      offset, begin, end);
+	      decode_location_expression (start, pointer_size, length,
+					  cu_offset);
+	      printf (")\n");
+
+	      if (begin >= end)
+		warn ("Bad location list at %8.8lx from %8.8lx to %8.8lx\n",
+		      offset, begin, end);
+
+	      start += length;
+	    }
 
-	  start += length;
+	  printf ("\n");
 	}
-      printf ("\n");
     }
   return 1;
 }
@@ -8828,7 +8839,9 @@ read_and_display_attr_value (unsigned lo
 			     unsigned long cu_offset,
 			     unsigned long pointer_size,
 			     unsigned long offset_size,
-			     int dwarf_version)
+			     int dwarf_version,
+			     debug_info *debug_info_p,
+			     int do_loc)
 {
   static unsigned long saved_DW_AT_low_pc = 0;
   unsigned long uvalue = 0;
@@ -8899,78 +8912,113 @@ read_and_display_attr_value (unsigned lo
     case DW_FORM_indirect:
       form = read_leb128 (data, & bytes_read, 0);
       data += bytes_read;
-      printf (" %s", get_FORM_name (form));
-      return read_and_display_attr_value (attribute, form, data, cu_offset,
-					  pointer_size, offset_size,
-					  dwarf_version);
+      if (!do_loc)
+	printf (" %s", get_FORM_name (form));
+      return read_and_display_attr_value (attribute, form, data,
+					  cu_offset, pointer_size,
+					  offset_size, dwarf_version,
+					  debug_info_p, do_loc);
     }
 
   switch (form)
     {
     case DW_FORM_ref_addr:
-      printf (" <#%lx>", uvalue);
+      if (!do_loc)
+	printf (" <#%lx>", uvalue);
       break;
 
     case DW_FORM_ref1:
     case DW_FORM_ref2:
     case DW_FORM_ref4:
     case DW_FORM_ref_udata:
-      printf (" <%lx>", uvalue + cu_offset);
+      if (!do_loc)
+	printf (" <%lx>", uvalue + cu_offset);
       break;
 
     case DW_FORM_addr:
-      printf (" %#lx", uvalue);
+      if (!do_loc)
+	printf (" %#lx", uvalue);
       break;
 
     case DW_FORM_flag:
     case DW_FORM_data1:
     case DW_FORM_data2:
-    case DW_FORM_data4:
     case DW_FORM_sdata:
     case DW_FORM_udata:
-      printf (" %ld", uvalue);
+      if (!do_loc)
+	printf (" %ld", uvalue);
+      break;
+
+    case DW_FORM_data4:
+      if (!do_loc)
+	printf (" %lx", uvalue);
       break;
 
     case DW_FORM_ref8:
     case DW_FORM_data8:
-      uvalue = byte_get (data, 4);
-      printf (" %lx", uvalue);
-      printf (" %lx", (unsigned long) byte_get (data + 4, 4));
+      if (!do_loc)
+	{
+	  uvalue = byte_get (data, 4);
+	  printf (" %lx", uvalue);
+	  printf (" %lx", (unsigned long) byte_get (data + 4, 4));
+	}
+      if ((do_loc || do_debug_loc)
+	  && num_debug_info_entries == 0)
+	{
+	  if (sizeof (uvalue) == 8)
+	    uvalue = byte_get (data, 8);
+	  else
+	    error (_("DW_FORM_data8 is unsupported when sizeof (unsigned long) != 8\n"));
+	}
       data += 8;
       break;
 
     case DW_FORM_string:
-      printf (" %s", data);
+      if (!do_loc)
+	printf (" %s", data);
       data += strlen ((char *) data) + 1;
       break;
 
     case DW_FORM_block:
       uvalue = read_leb128 (data, & bytes_read, 0);
       block_start = data + bytes_read;
-      data = display_block (block_start, uvalue);
+      if (do_loc)
+	data = block_start + uvalue;
+      else
+	data = display_block (block_start, uvalue);
       break;
 
     case DW_FORM_block1:
       uvalue = byte_get (data, 1);
       block_start = data + 1;
-      data = display_block (block_start, uvalue);
+      if (do_loc)
+	data = block_start + uvalue;
+      else
+	data = display_block (block_start, uvalue);
       break;
 
     case DW_FORM_block2:
       uvalue = byte_get (data, 2);
       block_start = data + 2;
-      data = display_block (block_start, uvalue);
+      if (do_loc)
+	data = block_start + uvalue;
+      else
+	data = display_block (block_start, uvalue);
       break;
 
     case DW_FORM_block4:
       uvalue = byte_get (data, 4);
       block_start = data + 4;
-      data = display_block (block_start, uvalue);
+      if (do_loc)
+	data = block_start + uvalue;
+      else
+	data = display_block (block_start, uvalue);
       break;
 
     case DW_FORM_strp:
-      printf (_(" (indirect string, offset: 0x%lx): %s"),
-	      uvalue, fetch_indirect_string (uvalue));
+      if (!do_loc)
+	printf (_(" (indirect string, offset: 0x%lx): %s"),
+		uvalue, fetch_indirect_string (uvalue));
       break;
 
     case DW_FORM_indirect:
@@ -8984,6 +9032,47 @@ read_and_display_attr_value (unsigned lo
 
   /* For some attributes we can display further information.  */
 
+  if ((do_loc || do_debug_loc)
+      && num_debug_info_entries == 0)
+    {
+      switch (attribute)
+	{
+	case DW_AT_frame_base:
+	case DW_AT_location:
+	case DW_AT_data_member_location:
+	case DW_AT_vtable_elem_location:
+	case DW_AT_allocated:
+	case DW_AT_associated:
+	case DW_AT_data_location:
+	case DW_AT_stride:
+	case DW_AT_upper_bound:
+	case DW_AT_lower_bound:
+	  if (form == DW_FORM_data4 || form == DW_FORM_data8)
+	    {
+	      /* Process location list.  */
+	      unsigned int max = debug_info_p->max_loc_offsets;
+	      unsigned int num = debug_info_p->num_loc_offsets;
+	      if (max == 0 || num >= max)
+		{
+		  max += 1024;
+		  debug_info_p->loc_offsets
+		    = xrealloc (debug_info_p->loc_offsets,
+				max * sizeof (*debug_info_p->loc_offsets));
+		  debug_info_p->max_loc_offsets = max;
+		}
+	      debug_info_p->loc_offsets [num] = uvalue;
+	      debug_info_p->num_loc_offsets++;
+	    }
+	  break;
+
+	default:
+	  break;
+	}
+    }
+
+  if (do_loc)
+    return data;
+
   printf ("\t");
 
   switch (attribute)
@@ -9174,12 +9263,18 @@ read_and_display_attr (unsigned long att
 		       unsigned long cu_offset,
 		       unsigned long pointer_size,
 		       unsigned long offset_size,
-		       int dwarf_version)
+		       int dwarf_version,
+		       debug_info *debug_info_p,
+		       int do_loc)
 {
-  printf ("     %-18s:", get_AT_name (attribute));
+  if (!do_loc)
+    printf ("     %-18s:", get_AT_name (attribute));
   data = read_and_display_attr_value (attribute, form, data, cu_offset,
-				      pointer_size, offset_size, dwarf_version);
-  printf ("\n");
+				      pointer_size, offset_size,
+				      dwarf_version, debug_info_p,
+				      do_loc);
+  if (!do_loc)
+    printf ("\n");
   return data;
 }
 
@@ -9273,20 +9368,66 @@ debug_apply_rela_addends (FILE *file,
 }
 
 static int
-display_debug_info (Elf_Internal_Shdr *section,
-		    unsigned char *start,
-		    FILE *file)
+process_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
+		    FILE *file, int do_loc)
 {
   unsigned char *end = start + section->sh_size;
-  unsigned char *section_begin = start;
+  unsigned char *section_begin;
+  unsigned int unit;
+  unsigned int num_units = 0;
 
-  printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
+  if ((do_loc || do_debug_loc)
+      && num_debug_info_entries == 0)
+    {
+      unsigned long length;
+
+      /* First scan the section to get the number of comp units.  */
+      for (section_begin = start, num_units = 0; section_begin < end;
+	   num_units++)
+	{
+	  /* Read the first 4 bytes.  For a 32-bit DWARF section, this
+	     will be the length.  For a 64-bit DWARF section, it'll be
+	     the escape code 0xffffffff followed by an 8 byte length.
+	   */
+	  length = byte_get (section_begin, 4);
+
+	  if (length == 0xffffffff)
+	    {
+	      length = byte_get (section_begin + 4, 8);
+	      section_begin += length + 12;
+	    }
+	  else
+	    section_begin += length + 4;
+	}
 
-  load_debug_str (file);
-  load_debug_loc (file);
-  load_debug_range (file);
+      if (num_units == 0)
+	{
+	  error (_("No comp units in .debug_info section ?"));
+	  return 0;
+	}
 
-  while (start < end)
+      /* Then allocate an array to hold the information.  */
+      debug_information = malloc (num_units *
+				  sizeof (*debug_information));
+      if (debug_information == NULL)
+	{
+	  error (_("Not enough memory for a debug info array of %u entries"),
+		 num_units);
+	  return 0;
+	}
+    }
+
+  if (!do_loc)
+    {
+      printf (_("The section %s contains:\n\n"),
+	      SECTION_NAME (section));
+
+      load_debug_str (file);
+      load_debug_loc (file);
+      load_debug_range (file);
+    }
+
+  for (section_begin = start, unit = 0; start < end; unit++)
     {
       DWARF2_Internal_CompUnit compunit;
       unsigned char *hdrptr;
@@ -9333,13 +9474,27 @@ display_debug_info (Elf_Internal_Shdr *s
       compunit.cu_pointer_size = byte_get (hdrptr, 1);
       hdrptr += 1;
 
+      if ((do_loc || do_debug_loc)
+	  && num_debug_info_entries == 0)
+	{
+	  debug_information [unit].cu_offset = cu_offset;
+	  debug_information [unit].pointer_size
+	    = compunit.cu_pointer_size;
+	  debug_information [unit].loc_offsets = NULL;
+	  debug_information [unit].max_loc_offsets = 0;
+	  debug_information [unit].num_loc_offsets = 0;
+	}
+
       tags = hdrptr;
 
-      printf (_("  Compilation Unit @ %lx:\n"), cu_offset);
-      printf (_("   Length:        %ld\n"), compunit.cu_length);
-      printf (_("   Version:       %d\n"), compunit.cu_version);
-      printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
-      printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
+      if (!do_loc)
+	{
+	  printf (_("  Compilation Unit @ %lx:\n"), cu_offset);
+	  printf (_("   Length:        %ld\n"), compunit.cu_length);
+	  printf (_("   Version:       %d\n"), compunit.cu_version);
+	  printf (_("   Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset);
+	  printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
+	}
 
       if (compunit.cu_version != 2 && compunit.cu_version != 3)
 	{
@@ -9405,11 +9560,13 @@ display_debug_info (Elf_Internal_Shdr *s
 	      return 0;
 	    }
 
-	  printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
-		  level,
-		  (unsigned long) (tags - section_begin - bytes_read),
-		  abbrev_number,
-		  get_TAG_name (entry->tag));
+	  if (!do_loc)
+	    printf (_(" <%d><%lx>: Abbrev Number: %lu (%s)\n"),
+		    level,
+		    (unsigned long) (tags - section_begin
+				     - bytes_read),
+		    abbrev_number,
+		    get_TAG_name (entry->tag));
 
 	  for (attr = entry->first_attr; attr; attr = attr->next)
 	    tags = read_and_display_attr (attr->attribute,
@@ -9417,23 +9574,42 @@ display_debug_info (Elf_Internal_Shdr *s
 					  tags, cu_offset,
 					  compunit.cu_pointer_size,
 					  offset_size,
-					  compunit.cu_version);
+					  compunit.cu_version,
+					  &debug_information [unit],
+					  do_loc);
 
 	  if (entry->children)
 	    ++level;
 	}
     }
 
-  free_debug_range ();
-  free_debug_str ();
-  free_debug_loc ();
+  /* 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)
+      && num_debug_info_entries == 0)
+    num_debug_info_entries = num_units;
+      
+  if (!do_loc)
+    {
+      free_debug_range ();
+      free_debug_str ();
+      free_debug_loc (); 
 
-  printf ("\n");
+      printf ("\n");
+    }
 
   return 1;
 }
 
 static int
+display_debug_info (Elf_Internal_Shdr *section,
+		    unsigned char *start,
+		    FILE *file)
+{
+  return process_debug_info (section, start, file, 0);
+}
+
+static int
 display_debug_aranges (Elf_Internal_Shdr *section,
 		       unsigned char *start,
 		       FILE *file ATTRIBUTE_UNUSED)
@@ -11581,6 +11757,9 @@ process_object (char *file_name, FILE *f
 
   if (debug_information)
     {
+      for (i = 0; i < num_debug_info_entries; i++)
+	if (debug_information [i].loc_offsets != NULL)
+	  free (debug_information [i].loc_offsets);
       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]