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 616: Fix dumping .debug_loc section


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.


H.J.
----
2004-12-28  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): Better handle location list.
	(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-28 16:48:30.710090225 -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
 
@@ -7073,6 +7075,11 @@ find_section (const char * name)
 typedef struct
 {
   unsigned int   pointer_size;
+  unsigned int   num_loc_offsets;
+  /* This is an array of offsets to the location list table.  */
+  unsigned long  *loc_offsets;
+  /* Pointer to the one past the last element in the array.  */
+  unsigned long  *last_loc_offset_p;
   unsigned long  cu_offset;
 }
 debug_info;
@@ -7135,11 +7142,6 @@ 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;
 
   /* 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;
-	}
-    }
-
+  num_debug_info_entries = process_debug_info (section, start, file, 1);
   free (start);
-
-  return num_debug_info_entries = num_units;
+  return num_debug_info_entries;
 }
 
 static int
@@ -8525,43 +8454,53 @@ display_debug_loc (Elf_Internal_Shdr *se
       unsigned long offset;
       unsigned int pointer_size;
       unsigned long cu_offset;
-
-      offset = start - section_begin;
+      unsigned long *offset_p;
 
       /* 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);
 
-      comp_unit ++;
-
-      while (1)
-	{
-	  begin = byte_get (start, pointer_size);
-	  start += pointer_size;
-	  end = byte_get (start, pointer_size);
-	  start += pointer_size;
+      for (offset_p = debug_information [comp_unit].loc_offsets;
+	   offset_p < debug_information [comp_unit].last_loc_offset_p;
+	   offset_p++)
+	{
+	  offset = start - section_begin;
+	  
+	  if (offset != *offset_p)
+	    error (_(".debug_loc section doesn't match debug_info section\n"));
+
+	  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;
+	      if (begin == 0 && end == 0)
+		break;
 
-	  /* For now, skip any base address specifiers.  */
-	  if (begin == 0xffffffff)
-	    continue;
+	      /* For now, skip any base address specifiers.  */
+	      if (begin == 0xffffffff)
+		continue;
 
-	  begin += addr;
-	  end += addr;
+	      begin += addr;
+	      end += addr;
 
-	  length = byte_get (start, 2);
-	  start += 2;
+	      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");
+	      printf ("    %8.8lx %8.8lx %8.8lx (",
+		      offset, begin, end);
+	      decode_location_expression (start, pointer_size, length,
+					  cu_offset);
+	      printf (")\n");
 
-	  start += length;
+	      start += length;
+	    }
+	  printf ("\n");
 	}
-      printf ("\n");
+      comp_unit ++;
     }
   return 1;
 }
@@ -8822,6 +8761,168 @@ decode_range (unsigned long offset, bfd_
 
 
 static unsigned char *
+read_and_process_attr_value (unsigned long attribute,
+			     unsigned long form,
+			     unsigned char *data,
+			     unsigned long cu_offset,
+			     unsigned long pointer_size,
+			     unsigned long offset_size,
+			     int dwarf_version,
+			     debug_info *debug_info_p)
+{
+  unsigned long uvalue = 0;
+  int bytes_read;
+
+  switch (form)
+    {
+    case DW_FORM_ref8:
+      data += 8;
+      break;
+
+    case DW_FORM_data8:
+      if (sizeof (uvalue) == 8)
+	{
+	  uvalue = byte_get (data, 8);
+	  data += 8;
+	}
+      else
+	error (_("DW_FORM_data8 is unsupported when offset_size (%d) != 8\n"),
+	       offset_size);
+      break;
+
+
+    case DW_FORM_string:
+      data += strlen ((char *) data) + 1;
+      break;
+
+    case DW_FORM_ref_addr:
+      if (dwarf_version == 2)
+	{
+	  data += pointer_size;
+	}
+      else if (dwarf_version == 3)
+	{
+	  data += offset_size;
+	}
+      else
+	{
+	  error (_("Internal error: DWARF version is not 2 or 3.\n"));
+	}
+      break;
+
+    case DW_FORM_addr:
+    case DW_FORM_strp:
+      data += offset_size;
+      break;
+
+    case DW_FORM_ref1:
+    case DW_FORM_flag:
+    case DW_FORM_data1:
+      data++;
+      break;
+
+    case DW_FORM_ref2:
+    case DW_FORM_data2:
+      data += 2;
+      break;
+
+    case DW_FORM_ref4:
+      data += 4;
+      break;
+
+    case DW_FORM_data4:
+      uvalue = byte_get (data, 4);
+      data += 4;
+      break;
+
+    case DW_FORM_sdata:
+      uvalue = read_leb128 (data, & bytes_read, 1);
+      data += bytes_read;
+      break;
+
+    case DW_FORM_ref_udata:
+    case DW_FORM_udata:
+      uvalue = read_leb128 (data, & bytes_read, 0);
+      data += bytes_read;
+      break;
+
+    case DW_FORM_indirect:
+      form = read_leb128 (data, & bytes_read, 0);
+      data += bytes_read;
+      return read_and_process_attr_value (attribute, form, data,
+					  cu_offset, pointer_size,
+					  offset_size, dwarf_version,
+					  debug_info_p);
+      break;
+
+    case DW_FORM_block:
+      uvalue = read_leb128 (data, & bytes_read, 0);
+      data += bytes_read + uvalue;
+      break;
+
+    case DW_FORM_block1:
+      uvalue = byte_get (data, 1);
+      data += 1 + uvalue;
+      break;
+
+    case DW_FORM_block2:
+      uvalue = byte_get (data, 2);
+      data += 2 + uvalue;
+      break;
+
+    case DW_FORM_block4:
+      uvalue = byte_get (data, 4);
+      data += 3 + uvalue;
+      break;
+
+    default:
+      warn (_("Unrecognized form: %d\n"), form);
+      break;
+    }
+
+  /* For some attributes we can display further information.  */
+
+  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->num_loc_offsets;
+	  if (max == 0
+	      || (debug_info_p->last_loc_offset_p
+		  >= &debug_info_p->loc_offsets [max]))
+	    {
+	      max += 1024;
+	      debug_info_p->loc_offsets
+		= xrealloc (debug_info_p->loc_offsets,
+			    max * sizeof (*debug_info_p->loc_offsets));
+	      debug_info_p->last_loc_offset_p
+		= &debug_info_p->loc_offsets [debug_info_p->num_loc_offsets];
+	      debug_info_p->num_loc_offsets = max;
+	    }
+	  *debug_info_p->last_loc_offset_p = uvalue;
+	  debug_info_p->last_loc_offset_p++;
+	}
+      break;
+
+    default:
+      break;
+    }
+
+  return data;
+}
+
+static unsigned char *
 read_and_display_attr_value (unsigned long attribute,
 			     unsigned long form,
 			     unsigned char *data,
@@ -8925,12 +9026,15 @@ read_and_display_attr_value (unsigned lo
     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);
       break;
 
+    case DW_FORM_data4:
+      printf (" %lx", uvalue);
+      break;
+
     case DW_FORM_ref8:
     case DW_FORM_data8:
       uvalue = byte_get (data, 4);
@@ -9273,20 +9377,64 @@ 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)
+    {
+      unsigned long length;
 
-  load_debug_str (file);
-  load_debug_loc (file);
-  load_debug_range (file);
+      /* 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);
 
-  while (start < end)
+	  if (length == 0xffffffff)
+	    {
+	      length = byte_get (section_begin + 4, 8);
+	      section_begin += length + 12;
+	    }
+	  else
+	    section_begin += length + 4;
+	}
+
+      if (num_units == 0)
+	{
+	  error (_("No comp units in .debug_info section ?"));
+	  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);
+	  return 0;
+	}
+    }
+  else
+    {
+      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 +9481,26 @@ display_debug_info (Elf_Internal_Shdr *s
       compunit.cu_pointer_size = byte_get (hdrptr, 1);
       hdrptr += 1;
 
+      if (do_loc)
+	{
+	  debug_information [unit].cu_offset = cu_offset;
+	  debug_information [unit].pointer_size
+	    = compunit.cu_pointer_size;
+	  debug_information [unit].num_loc_offsets = 0;
+	  debug_information [unit].loc_offsets = NULL;
+	  debug_information [unit].last_loc_offset_p = NULL;
+	}
+
       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,32 +9566,60 @@ 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));
-
-	  for (attr = entry->first_attr; attr; attr = attr->next)
-	    tags = read_and_display_attr (attr->attribute,
-					  attr->form,
-					  tags, cu_offset,
-					  compunit.cu_pointer_size,
-					  offset_size,
-					  compunit.cu_version);
+	  if (do_loc)
+	    {
+	      for (attr = entry->first_attr; attr; attr = attr->next)
+		tags = read_and_process_attr_value (attr->attribute,
+						    attr->form,
+						    tags, cu_offset,
+						    compunit.cu_pointer_size,
+						    offset_size,
+						    compunit.cu_version,
+						    &debug_information [unit]);
+	    }
+	  else
+	    {
+	      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,
+					      attr->form,
+					      tags, cu_offset,
+					      compunit.cu_pointer_size,
+					      offset_size,
+					      compunit.cu_version);
+	    }
 
 	  if (entry->children)
 	    ++level;
 	}
     }
 
-  free_debug_range ();
-  free_debug_str ();
-  free_debug_loc ();
+  if (do_loc)
+    return num_units;
+  else
+    {
+      free_debug_range ();
+      free_debug_str ();
+      free_debug_loc (); 
 
-  printf ("\n");
+      printf ("\n");
+      
+      return 1;
+    }
+}
 
-  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
@@ -11581,6 +11770,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]