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: Add support for decoding .debug_ranges to readelf


Hi Guys,

  I am applying the attached patch to add the ability to decode the
  contents of .debug_ranges sections to readelf.  This takes two
  forms.  The decoding is done automatically for a specific range when
  a DW_AT_range attribute is encountered and the entire contents of a
  .debug_ranges section can be displayed via the --debug-dump=Ranges
  command line switch.  (Short form: -wR).

  I have included code that should work with 64bit ranges but I have
  not test this yet.

  In the course of developing this patch I also encountered a couple
  of bugs.  One was that the dump_sects array was not being correctly
  reinitialised for each object file that was dumped.  There was code
  in main() to reinitialise the array for each object file specified
  on the command line, but this did not take into account the
  possibility that an archive was being dumped.  Since archives can
  contain multiple object file it is necessary to reinitialise the
  dump_sects array before dumping every single binary

  Another bug was the debug_apply_rela_addends() function warning
  about relocations against STT_OBJECT type symbols.  These can occur
  in good code (eg the _clz.o binary in libgcc.a), and so should be
  allowed. 

  I have included fixes for both of these bugs.
  
  I also tidied up the parsing of the --debug-dump switch so that it
  uses a table structure rather than a long switch statement.  I also
  added a streq() and strneq() macro to tidy up string comparison
  expressions.

binutils/ChangeLog
2004-11-03  Nick Clifton  <nickc@redhat.com>

	* readelf.c (do_debug_ranges): New variable.
	(usage): Document new switch: -wR or --debug-dump=Ranges.
	(parse_args): Handle new switch.  Replace switch statement for the
	long options with a more compact table structure.
	(process_section_headers): Allow the dumping of .debug_ranges
	sections if so requested.
	(debug_displays): Likewise.
	(load_debug_range): New function: Grabs the contents of a
	.debug_ranges section.
	(free_debug_range): New function: Releases the grabbed
	.debug_ranges section.
	(decode_64bit_range): New function: Displays a 64-bit range in a
	.debug_ranges section.
	(decode_range): New function: Displays a 32-bit range in a
	.debug_ranges section.
	(read_and_display_attr_value): Record the value of DW_AT_low_pc
	attributes.  Use decode_ranges() to display a DW_AT_ranges
	attribute.
	(display_debug_info): Use load_debug_range() and
	free_debug_range().
	(display_64bit_debug_ranges): New function.  Displays the contents
	of a 64-bit format .debug_ranges section.
	(display_debug_ranges): New function: Displays the contents of a
	32-bit .debug_ranges section.
	
	(main): Move cmdline_dump_sects and num_cmdline_dump_sects into the
	global scope.
	(process_object): Initialise the dump_sects array from the
	cmdline_dump_sects array before processing each object file.

	(streq, strneq): New macros.  Use them to replace occurrences of
	strcmp() and strncmp().

	(debug_information): New structure array to replace
	debug_line_pointer_sizes array.
	(num_debug_info_entries): New variable to replace
	num_debug_line_pointers.
	(get_pointer_size_of_comp_unit): New function: Returns the pointer
	size of a given compilation unit.
	(get_debug_info): New function to replace
	get_debug_line_pointer_sizes.
	(display_debug_lines): Use the new functions.
	(display_debug_loc): Likewise.
	
	(disassemble_section): Change return type to int.
	(display_debug_lines): Move local variables to their
	innermost scope.
	(display_debug_section): Likewise.  Also record the return value
	of functions called and pass this back to the parent.  Also only
	warn about undumped sections when the user explicitly requested
	their dumping.

	(debug_apply_rela_addends): Allow relocations against STT_OBJECT
	types as well.
	
	* NEWS: Mention the support for decoding .debug_ranges sections.
	* doc/binutils.texi: Document the new command line switch to
	readelf.

Index: binutils/NEWS
===================================================================
RCS file: /cvs/src/src/binutils/NEWS,v
retrieving revision 1.44
diff -c -3 -p -r1.44 NEWS
*** binutils/NEWS	8 Oct 2004 14:54:03 -0000	1.44
--- binutils/NEWS	3 Nov 2004 10:13:19 -0000
***************
*** 1,5 ****
--- 1,10 ----
  -*- text -*-
  
+ * readelf can now display address ranges from .debug_range sections.  This
+   happens automatically when a DW_AT_range attribute is encountered.  The
+   command line switch --debug-dump=Ranges (or -wR) can also be used to display
+   the contents of the .debug_range section.
+ 
  * nm and objdump now have a switch "--special-syms" to enable the displaying of
    symbols which the target considers to be special.  By default these symbols
    are no longer displayed.  Currently the only special symbols are the Mapping
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.263
diff -c -3 -p -r1.263 readelf.c
*** binutils/readelf.c	3 Nov 2004 02:21:57 -0000	1.263
--- binutils/readelf.c	3 Nov 2004 10:13:21 -0000
*************** int do_debug_abbrevs;
*** 159,164 ****
--- 159,165 ----
  int do_debug_lines;
  int do_debug_pubnames;
  int do_debug_aranges;
+ int do_debug_ranges;
  int do_debug_frames;
  int do_debug_frames_interp;
  int do_debug_macinfo;
*************** size_t group_count = 0;
*** 185,191 ****
  
  struct group **section_headers_groups;
  
! /* A dynamic array of flags indicating which sections require dumping.  */
  char *dump_sects = NULL;
  unsigned int num_dump_sects = 0;
  
--- 186,201 ----
  
  struct group **section_headers_groups;
  
! /* A dynamic array of flags indicating for which sections a hex dump
!    has been requested (via the -x switch) and/or a disassembly dump
!    (via the -i switch).  */
! char *cmdline_dump_sects = NULL;
! unsigned num_cmdline_dump_sects = 0;
! 
! /* A dynamic array of flags indicating for which sections a dump of
!    some kind has been requested.  It is reset on a per-object file
!    basis and then initialised from the cmdline_dump_sects array and
!    the results of interpreting the -w switch.  */
  char *dump_sects = NULL;
  unsigned int num_dump_sects = 0;
  
*************** static void (*byte_put) (unsigned char *
*** 259,264 ****
--- 269,278 ----
  /* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has
     already been called and verified that the string exists.  */
  #define GET_DYNAMIC_NAME(offset)	(dynamic_strings + offset)
+ 
+ /* This is just a bit of syntatic sugar.  */
+ #define streq(a,b)	(strcmp ((a), (b)) == 0)
+ #define strneq(a,b,n)	(strncmp ((a), (b), (n)) == 0)
  
  static void
  error (const char *message, ...)
*************** usage (void)
*** 2576,2583 ****
    -A --arch-specific     Display architecture specific information (if any).\n\
    -D --use-dynamic       Use the dynamic section info when displaying symbols\n\
    -x --hex-dump=<number> Dump the contents of section <number>\n\
!   -w[liaprmfFso] or\n\
!   --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=str,=loc]\n\
                           Display the contents of DWARF2 debug sections\n"));
  #ifdef SUPPORT_DISASSEMBLY
    fprintf (stdout, _("\
--- 2591,2598 ----
    -A --arch-specific     Display architecture specific information (if any).\n\
    -D --use-dynamic       Use the dynamic section info when displaying symbols\n\
    -x --hex-dump=<number> Dump the contents of section <number>\n\
!   -w[liaprmfFsoR] or\n\
!   --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\
                           Display the contents of DWARF2 debug sections\n"));
  #ifdef SUPPORT_DISASSEMBLY
    fprintf (stdout, _("\
*************** usage (void)
*** 2594,2599 ****
--- 2609,2619 ----
    exit (0);
  }
  
+ /* Record the fact that the user wants the contents of section number
+    SECTION to be displayed using the method(s) encoded as flags bits
+    in TYPE.  Note, TYPE can be zero if we are creating the array for
+    the first time.  */
+ 
  static void
  request_dump (unsigned int section, int type)
  {
*************** parse_args (int argc, char **argv)
*** 2744,2753 ****
  		    break;
  
  		  case 'r':
- 		  case 'R':
  		    do_debug_aranges = 1;
  		    break;
  
  		  case 'F':
  		    do_debug_frames_interp = 1;
  		  case 'f':
--- 2764,2776 ----
  		    break;
  
  		  case 'r':
  		    do_debug_aranges = 1;
  		    break;
  
+ 		  case 'R':
+ 		    do_debug_ranges = 1;
+ 		    break;
+ 
  		  case 'F':
  		    do_debug_frames_interp = 1;
  		  case 'f':
*************** parse_args (int argc, char **argv)
*** 2781,2790 ****
  	    do_debugging = 1;
  	  else
  	    {
! 	      static const char *debug_dump_opt[]
! 		= { "line", "info", "abbrev", "pubnames", "ranges",
! 		    "macro", "frames", "frames-interp", "str", "loc", NULL };
! 	      unsigned int index;
  	      const char *p;
  
  	      do_debugging = 0;
--- 2804,2836 ----
  	    do_debugging = 1;
  	  else
  	    {
! 	      typedef struct
! 	      {
! 		const char * option;
! 		int *        variable;
! 	      }
! 	      debug_dump_long_opts;
! 
! 	      debug_dump_long_opts opts_table [] =
! 		{
! 		  /* Please keep this table alpha- sorted.  */
! 		  { "Ranges", & do_debug_ranges },
! 		  { "abbrev", & do_debug_abbrevs },
! 		  { "aranges", & do_debug_aranges },
! 		  { "frames", & do_debug_frames },
! 		  { "frames-interp", & do_debug_frames_interp },
! 		  { "info", & do_debug_info },
! 		  { "line", & do_debug_lines },
! 		  { "loc",  & do_debug_loc },
! 		  { "macro", & do_debug_macinfo },
! 		  { "pubnames", & do_debug_pubnames },
! 		  /* This entry is for compatability
! 		     with earlier versions of readelf.  */
! 		  { "ranges", & do_debug_aranges },
! 		  { "str", & do_debug_str },
! 		  { NULL, NULL }
! 		};
! 
  	      const char *p;
  
  	      do_debugging = 0;
*************** parse_args (int argc, char **argv)
*** 2792,2850 ****
  	      p = optarg;
  	      while (*p)
  		{
! 		  for (index = 0; debug_dump_opt[index]; index++)
  		    {
! 		      size_t len = strlen (debug_dump_opt[index]);
  
! 		      if (strncmp (p, debug_dump_opt[index], len) == 0
  			  && (p[len] == ',' || p[len] == '\0'))
  			{
! 			  switch (p[0])
! 			    {
! 			    case 'i':
! 			      do_debug_info = 1;
! 			      break;
! 
! 			    case 'a':
! 			      do_debug_abbrevs = 1;
! 			      break;
! 
! 			    case 'l':
! 			      if (p[1] == 'i')
! 				do_debug_lines = 1;
! 			      else
! 				do_debug_loc = 1;
! 			      break;
! 
! 			    case 'p':
! 			      do_debug_pubnames = 1;
! 			      break;
! 
! 			    case 'r':
! 			      do_debug_aranges = 1;
! 			      break;
! 
! 			    case 'f':
! 			      if (len > 6)
! 				do_debug_frames_interp = 1;
! 			      do_debug_frames = 1;
! 			      break;
! 
! 			    case 'm':
! 			      do_debug_macinfo = 1;
! 			      break;
! 
! 			    case 's':
! 			      do_debug_str = 1;
! 			      break;
! 			    }
  
  			  p += len;
  			  break;
  			}
  		    }
  
! 		  if (debug_dump_opt[index] == NULL)
  		    {
  		      warn (_("Unrecognized debug option '%s'\n"), p);
  		      p = strchr (p, ',');
--- 2838,2865 ----
  	      p = optarg;
  	      while (*p)
  		{
! 		  debug_dump_long_opts * entry;
! 
! 		  for (entry = opts_table; entry->option; entry++)
  		    {
! 		      size_t len = strlen (entry->option);
  
! 		      if (strneq (p, entry->option, len)
  			  && (p[len] == ',' || p[len] == '\0'))
  			{
! 			  * entry->variable = 1;
! 
! 			  /* The --debug-dump=frames-interp option also
! 			     enables the --debug-dump=frames option.  */
! 			  if (do_debug_frames_interp)
! 			    do_debug_frames = 1;
  
  			  p += len;
  			  break;
  			}
  		    }
  
! 		  if (entry->option == NULL)
  		    {
  		      warn (_("Unrecognized debug option '%s'\n"), p);
  		      p = strchr (p, ',');
*************** process_section_headers (FILE *file)
*** 3740,3768 ****
        else if ((do_debugging || do_debug_info || do_debug_abbrevs
  		|| do_debug_lines || do_debug_pubnames || do_debug_aranges
  		|| do_debug_frames || do_debug_macinfo || do_debug_str
! 		|| do_debug_loc)
! 	       && strncmp (name, ".debug_", 7) == 0)
  	{
  	  name += 7;
  
  	  if (do_debugging
! 	      || (do_debug_info     && (strcmp (name, "info") == 0))
! 	      || (do_debug_abbrevs  && (strcmp (name, "abbrev") == 0))
! 	      || (do_debug_lines    && (strcmp (name, "line") == 0))
! 	      || (do_debug_pubnames && (strcmp (name, "pubnames") == 0))
! 	      || (do_debug_aranges  && (strcmp (name, "aranges") == 0))
! 	      || (do_debug_frames   && (strcmp (name, "frame") == 0))
! 	      || (do_debug_macinfo  && (strcmp (name, "macinfo") == 0))
! 	      || (do_debug_str      && (strcmp (name, "str") == 0))
! 	      || (do_debug_loc      && (strcmp (name, "loc") == 0))
  	      )
  	    request_dump (i, DEBUG_DUMP);
  	}
        /* linkonce section to be combined with .debug_info at link time.  */
        else if ((do_debugging || do_debug_info)
! 	       && strncmp (name, ".gnu.linkonce.wi.", 17) == 0)
  	request_dump (i, DEBUG_DUMP);
!       else if (do_debug_frames && strcmp (name, ".eh_frame") == 0)
  	request_dump (i, DEBUG_DUMP);
      }
  
--- 3755,3784 ----
        else if ((do_debugging || do_debug_info || do_debug_abbrevs
  		|| do_debug_lines || do_debug_pubnames || do_debug_aranges
  		|| do_debug_frames || do_debug_macinfo || do_debug_str
! 		|| do_debug_loc || do_debug_ranges)
! 	       && strneq (name, ".debug_", 7))
  	{
  	  name += 7;
  
  	  if (do_debugging
! 	      || (do_debug_info     && streq (name, "info"))
! 	      || (do_debug_abbrevs  && streq (name, "abbrev"))
! 	      || (do_debug_lines    && streq (name, "line"))
! 	      || (do_debug_pubnames && streq (name, "pubnames"))
! 	      || (do_debug_aranges  && streq (name, "aranges"))
! 	      || (do_debug_ranges   && streq (name, "ranges"))
! 	      || (do_debug_frames   && streq (name, "frame"))
! 	      || (do_debug_macinfo  && streq (name, "macinfo"))
! 	      || (do_debug_str      && streq (name, "str"))
! 	      || (do_debug_loc      && streq (name, "loc"))
  	      )
  	    request_dump (i, DEBUG_DUMP);
  	}
        /* linkonce section to be combined with .debug_info at link time.  */
        else if ((do_debugging || do_debug_info)
! 	       && strneq (name, ".gnu.linkonce.wi.", 17))
  	request_dump (i, DEBUG_DUMP);
!       else if (do_debug_frames && streq (name, ".eh_frame"))
  	request_dump (i, DEBUG_DUMP);
      }
  
*************** process_syminfo (FILE *file ATTRIBUTE_UN
*** 6811,6817 ****
  }
  
  #ifdef SUPPORT_DISASSEMBLY
! static void
  disassemble_section (Elf_Internal_Shdr *section, FILE *file)
  {
    printf (_("\nAssembly dump of section %s\n"),
--- 6824,6830 ----
  }
  
  #ifdef SUPPORT_DISASSEMBLY
! static int
  disassemble_section (Elf_Internal_Shdr *section, FILE *file)
  {
    printf (_("\nAssembly dump of section %s\n"),
*************** find_section (const char * name)
*** 7051,7061 ****
    return NULL;
  }
  
! /* Size of pointers in the .debug_line section.  This information is not
!    really present in that section.  It's obtained before dumping the debug
!    sections by doing some pre-scan of the .debug_info section.  */
! static unsigned int * debug_line_pointer_sizes = NULL;
! static unsigned int   num_debug_line_pointer_sizes = 0;
  
  /* Locate and scan the .debug_info section in the file and record the pointer
     sizes for the compilation units in it.  Usually an executable will have
--- 7065,7091 ----
    return NULL;
  }
  
! /* This could just be an array of unsigned integers, but I expect
!    that we will want to extend the structure to contain other
!    information.  */
! typedef struct
! {
!   unsigned int pointer_size;
! }
! debug_info;
! 
! static debug_info *   debug_information = NULL;
! static unsigned int   num_debug_info_entries = 0;
! 
! static unsigned int
! get_pointer_size_of_comp_unit (unsigned int comp_unit)
! {
!   if (num_debug_info_entries == 0
!       || comp_unit >= num_debug_info_entries)
!     return 0;
! 
!   return debug_information [comp_unit].pointer_size;
! }
  
  /* Locate and scan the .debug_info section in the file and record the pointer
     sizes for the compilation units in it.  Usually an executable will have
*************** static unsigned int   num_debug_line_poi
*** 7064,7070 ****
     compilation units upon success.  */
  
  static unsigned int
! get_debug_line_pointer_sizes (FILE * file)
  {
    Elf_Internal_Shdr * section;
    unsigned char *     start;
--- 7094,7100 ----
     compilation units upon success.  */
  
  static unsigned int
! get_debug_info (FILE * file)
  {
    Elf_Internal_Shdr * section;
    unsigned char *     start;
*************** get_debug_line_pointer_sizes (FILE * fil
*** 7074,7086 ****
    unsigned int        num_units;
    unsigned int        unit;
  
    section = find_section (".debug_info");
    if (section == NULL)
      return 0;
  
    length = section->sh_size;
    start = get_data (NULL, file, section->sh_offset, section->sh_size,
! 		    _("extracting pointer sizes from .debug_info section"));
    if (start == NULL)
      return 0;
  
--- 7104,7120 ----
    unsigned int        num_units;
    unsigned int        unit;
  
+   /* If we already have the information there is nothing else to do.  */
+   if (num_debug_info_entries > 0)
+     return num_debug_info_entries;
+ 
    section = find_section (".debug_info");
    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;
  
*************** get_debug_line_pointer_sizes (FILE * fil
*** 7109,7119 ****
        return 0;
      }
  
!   /* Then allocate an array to hold the pointer sizes.  */
!   debug_line_pointer_sizes = malloc (num_units * sizeof * debug_line_pointer_sizes);
!   if (debug_line_pointer_sizes == NULL)
      {
!       error (_("Not enough memory for a pointer size array of %u entries"),
  	     num_units);
        free (start);
        return 0;
--- 7143,7153 ----
        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;
*************** get_debug_line_pointer_sizes (FILE * fil
*** 7134,7140 ****
  	     -----------------------------
  	     Total:               22 bytes  */
  
! 	  debug_line_pointer_sizes [unit] = byte_get (begin + 22, 1);
  	  length = byte_get (begin + 4, 8);
  	  begin += length + 12;
  	}
--- 7168,7174 ----
  	     -----------------------------
  	     Total:               22 bytes  */
  
! 	  debug_information [unit].pointer_size = byte_get (begin + 22, 1);
  	  length = byte_get (begin + 4, 8);
  	  begin += length + 12;
  	}
*************** get_debug_line_pointer_sizes (FILE * fil
*** 7149,7188 ****
  	     -----------------------------
  	     Total:               10 bytes  */
  
! 	  debug_line_pointer_sizes [unit] = byte_get (begin + 10, 1);
  	  begin += length + 4;
  	}
      }
  
    free (start);
!   num_debug_line_pointer_sizes = num_units;
!   return num_units;
  }
  
  static int
  display_debug_lines (Elf_Internal_Shdr *section,
  		     unsigned char *start, FILE *file)
  {
-   unsigned char *hdrptr;
-   DWARF2_Internal_LineInfo info;
-   unsigned char *standard_opcodes;
    unsigned char *data = start;
    unsigned char *end = start + section->sh_size;
-   unsigned char *end_of_sequence;
-   int i;
-   int offset_size;
-   int initial_length_size;
    unsigned int comp_unit = 0;
  
    printf (_("\nDump of debug contents of section %s:\n\n"),
  	  SECTION_NAME (section));
  
!   if (num_debug_line_pointer_sizes == 0)
!     get_debug_line_pointer_sizes (file);
  
    while (data < end)
      {
        unsigned int pointer_size;
  
        hdrptr = data;
  
--- 7183,7221 ----
  	     -----------------------------
  	     Total:               10 bytes  */
  
! 	  debug_information [unit].pointer_size = byte_get (begin + 10, 1);
  	  begin += length + 4;
  	}
      }
  
    free (start);
! 
!   return num_debug_info_entries = num_units;
  }
  
  static int
  display_debug_lines (Elf_Internal_Shdr *section,
  		     unsigned char *start, FILE *file)
  {
    unsigned char *data = start;
    unsigned char *end = start + section->sh_size;
    unsigned int comp_unit = 0;
  
    printf (_("\nDump of debug contents of section %s:\n\n"),
  	  SECTION_NAME (section));
  
!   get_debug_info (file);
  
    while (data < end)
      {
+       DWARF2_Internal_LineInfo info;
+       unsigned char *standard_opcodes;
+       unsigned char *end_of_sequence;
+       unsigned char *hdrptr;
        unsigned int pointer_size;
+       int initial_length_size;
+       int offset_size;
+       int i;
  
        hdrptr = data;
  
*************** display_debug_lines (Elf_Internal_Shdr *
*** 7239,7254 ****
  
        /* Get the pointer size from the comp unit associated
  	 with this block of line number information.  */
!       if (comp_unit >= num_debug_line_pointer_sizes)
  	{
  	  error (_("Not enough comp units for .debug_line section\n"));
  	  return 0;
  	}
!       else
! 	{
! 	  pointer_size = debug_line_pointer_sizes [comp_unit];
! 	  comp_unit ++;
! 	}
  
        printf (_("  Length:                      %ld\n"), info.li_length);
        printf (_("  DWARF Version:               %d\n"), info.li_version);
--- 7272,7284 ----
  
        /* Get the pointer size from the comp unit associated
  	 with this block of line number information.  */
!       pointer_size = get_pointer_size_of_comp_unit (comp_unit);
!       if (pointer_size == 0)
  	{
  	  error (_("Not enough comp units for .debug_line section\n"));
  	  return 0;
  	}
!       comp_unit ++;
  
        printf (_("  Length:                      %ld\n"), info.li_length);
        printf (_("  DWARF Version:               %d\n"), info.li_version);
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 8438,8445 ****
        return 0;
      }
  
!   if (num_debug_line_pointer_sizes == 0)
!     get_debug_line_pointer_sizes (file);
  
    printf (_("Contents of the .debug_loc section:\n\n"));
    printf (_("\n    Offset   Begin    End      Expression\n"));
--- 8467,8473 ----
        return 0;
      }
  
!   get_debug_info (file);
  
    printf (_("Contents of the .debug_loc section:\n\n"));
    printf (_("\n    Offset   Begin    End      Expression\n"));
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 8456,8471 ****
  
        /* Get the pointer size from the comp unit associated
  	 with this block of location information.  */
!       if (comp_unit >= num_debug_line_pointer_sizes)
  	{
  	  error (_("Not enough comp units for .debug_loc section\n"));
  	  return 0;
  	}
!       else
! 	{
! 	  pointer_size = debug_line_pointer_sizes [comp_unit];
! 	  comp_unit ++;
! 	}
  
        while (1)
  	{
--- 8484,8496 ----
  
        /* Get the pointer size from the comp unit associated
  	 with this block of location information.  */
!       pointer_size = get_pointer_size_of_comp_unit (comp_unit);
!       if (pointer_size == 0)
  	{
  	  error (_("Not enough comp units for .debug_loc section\n"));
  	  return 0;
  	}
!       comp_unit ++;
  
        while (1)
  	{
*************** display_debug_str (Elf_Internal_Shdr *se
*** 8603,8608 ****
--- 8628,8783 ----
    return 1;
  }
  
+ static const char *   debug_range_contents;
+ static unsigned long  debug_range_size;
+ 
+ static void
+ load_debug_range (FILE *file)
+ {
+   Elf_Internal_Shdr *sec;
+ 
+   /* If it is already loaded, do nothing.  */
+   if (debug_range_contents != NULL)
+     return;
+ 
+   /* Locate the .debug_str section.  */
+   sec = find_section (".debug_ranges");
+   if (sec == NULL)
+     return;
+ 
+   debug_range_size = sec->sh_size;
+ 
+   debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+ 				   _("debug_range section data"));
+ }
+ 
+ static void
+ free_debug_range (void)
+ {
+   if (debug_range_contents == NULL)
+     return;
+ 
+   free ((char *) debug_range_contents);
+   debug_range_contents = NULL;
+   debug_range_size = 0;
+ }
+ 
+ 
+ /* 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 (")");
+ }
+ 
+ 
  static unsigned char *
  read_and_display_attr_value (unsigned long attribute,
  			     unsigned long form,
*************** read_and_display_attr_value (unsigned lo
*** 8612,8617 ****
--- 8787,8793 ----
  			     unsigned long offset_size,
  			     int dwarf_version)
  {
+   static unsigned long saved_DW_AT_low_pc = 0;
    unsigned long uvalue = 0;
    unsigned char *block_start = NULL;
    int bytes_read;
*************** read_and_display_attr_value (unsigned lo
*** 8925,8935 ****
  	  printf (")");
  	}
        else if (form == DW_FORM_data4 || form == DW_FORM_data8)
! 	{
! 	  printf ("(");
! 	  printf ("location list");
! 	  printf (")");
! 	}
        break;
  
      default:
--- 9101,9120 ----
  	  printf (")");
  	}
        else if (form == DW_FORM_data4 || form == DW_FORM_data8)
! 	printf (_("(location list)"));
! 
!       break;
! 
!     case DW_AT_low_pc:
!       /* This is a hack.  We keep track of the DW_AT_low_pc attributes
! 	 and use them when decoding DW_AT_ranges attributes.  The
! 	 assumption here is that we are decoding the attributes in order
! 	 and so the correct base address for the range is the low_pc.  */
!       saved_DW_AT_low_pc = uvalue;
!       break;
! 
!     case DW_AT_ranges:
!       decode_range (uvalue, saved_DW_AT_low_pc);
        break;
  
      default:
*************** debug_apply_rela_addends (FILE *file,
*** 9007,9016 ****
  	      sym = symtab + ELF32_R_SYM (rp->r_info);
  
  	      if (ELF32_R_SYM (rp->r_info) != 0
! 		  && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
  		{
! 		  warn (_("Skipping unexpected symbol type %u\n"),
! 			ELF32_ST_TYPE (sym->st_info));
  		  continue;
  		}
  	    }
--- 9192,9206 ----
  	      sym = symtab + ELF32_R_SYM (rp->r_info);
  
  	      if (ELF32_R_SYM (rp->r_info) != 0
! 		  && ELF32_ST_TYPE (sym->st_info) != STT_SECTION
! 		  /* Relocations against object symbols can happen,
! 		     eg when referencing a global array.  For an
! 		     example of this see the _clz.o binary in libgcc.a.  */
! 		  && ELF32_ST_TYPE (sym->st_info) != STT_OBJECT)
  		{
! 		  warn (_("%s: skipping unexpected symbol type %s in relocation in section .rela%s\n"),
! 			get_symbol_type (ELF32_ST_TYPE (sym->st_info)),
! 			SECTION_NAME (section));
  		  continue;
  		}
  	    }
*************** debug_apply_rela_addends (FILE *file,
*** 9019,9028 ****
  	      sym = symtab + ELF64_R_SYM (rp->r_info);
  
  	      if (ELF64_R_SYM (rp->r_info) != 0
! 		  && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
  		{
! 		  warn (_("Skipping unexpected symbol type %u\n"),
! 			ELF64_ST_TYPE (sym->st_info));
  		  continue;
  		}
  	    }
--- 9209,9220 ----
  	      sym = symtab + ELF64_R_SYM (rp->r_info);
  
  	      if (ELF64_R_SYM (rp->r_info) != 0
! 		  && ELF64_ST_TYPE (sym->st_info) != STT_SECTION
! 		  && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT)
  		{
! 		  warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"),
! 			get_symbol_type (ELF64_ST_TYPE (sym->st_info)),
! 			SECTION_NAME (section));
  		  continue;
  		}
  	    }
*************** display_debug_info (Elf_Internal_Shdr *s
*** 9049,9054 ****
--- 9241,9247 ----
  
    load_debug_str (file);
    load_debug_loc (file);
+   load_debug_range (file);
  
    while (start < end)
      {
*************** display_debug_info (Elf_Internal_Shdr *s
*** 9188,9193 ****
--- 9381,9387 ----
  	}
      }
  
+   free_debug_range ();
    free_debug_str ();
    free_debug_loc ();
  
*************** display_debug_aranges (Elf_Internal_Shdr
*** 9292,9297 ****
--- 9486,9580 ----
    return 1;
  }
  
+ static int
+ display_64bit_debug_ranges (unsigned char * start, unsigned char * end)
+ {
+   bfd_vma base_address = 0;
+ 
+   while (start < end)
+     {
+       bfd_vma a, b;
+ 
+       a = byte_get (start, 8);
+       b = byte_get (start + 8, 8);
+ 
+       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
+ 	{
+ 	  printf ("range from ");
+ 	  print_vma (base_address + a, PREFIX_HEX);
+ 	  printf (" to ");
+ 	  print_vma (base_address + b, PREFIX_HEX);
+ 	}
+ 
+       start += 16;
+       printf ("\n");
+     }
+ 
+   return 1;
+ }
+ 
+ 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;
+ 
+   printf (_("The section %s contains:\n\n"), SECTION_NAME (section));
+ 
+   while (start < end)
+     {
+       unsigned long a;
+       unsigned long b;
+ 
+       a = byte_get (start, 4);
+       b = byte_get (start + 4, 4);
+ 
+       if (a == 0xffffffff)
+ 	{
+ 	  /* 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);
+ 
+       start += 8;
+     }
+ 
+   return 1;
+ }
+ 
  typedef struct Frame_Chunk
  {
    struct Frame_Chunk *next;
*************** debug_displays[] =
*** 10140,10146 ****
    { ".debug_str",		display_debug_str },
    { ".debug_loc",		display_debug_loc },
    { ".debug_pubtypes",		display_debug_pubnames },
!   { ".debug_ranges",		display_debug_not_supported },
    { ".debug_static_func",	display_debug_not_supported },
    { ".debug_static_vars",	display_debug_not_supported },
    { ".debug_types",		display_debug_not_supported },
--- 10423,10429 ----
    { ".debug_str",		display_debug_str },
    { ".debug_loc",		display_debug_loc },
    { ".debug_pubtypes",		display_debug_pubnames },
!   { ".debug_ranges",		display_debug_ranges },
    { ".debug_static_func",	display_debug_not_supported },
    { ".debug_static_vars",	display_debug_not_supported },
    { ".debug_types",		display_debug_not_supported },
*************** display_debug_section (Elf_Internal_Shdr
*** 10152,10158 ****
  {
    char *name = SECTION_NAME (section);
    bfd_size_type length;
!   unsigned char *start;
    int i;
  
    length = section->sh_size;
--- 10435,10441 ----
  {
    char *name = SECTION_NAME (section);
    bfd_size_type length;
!   int result = 1;
    int i;
  
    length = section->sh_size;
*************** display_debug_section (Elf_Internal_Shdr
*** 10162,10203 ****
        return 0;
      }
  
!   start = get_data (NULL, file, section->sh_offset, length,
! 		    _("debug section data"));
!   if (!start)
!     return 0;
! 
!   /* See if we know how to display the contents of this section.  */
!   if (strncmp (name, ".gnu.linkonce.wi.", 17) == 0)
      name = ".debug_info";
  
    for (i = NUM_ELEM (debug_displays); i--;)
!     if (strcmp (debug_displays[i].name, name) == 0)
        {
! 	debug_displays[i].display (section, start, file);
  	break;
        }
  
    if (i == -1)
!     printf (_("Unrecognized debug section: %s\n"), name);
! 
!   free (start);
! 
!   /* If we loaded in the abbrev section at some point,
!      we must release it here.  */
!   free_abbrevs ();
  
!   return 1;
  }
  
! static int
  process_section_contents (FILE *file)
  {
    Elf_Internal_Shdr *section;
    unsigned int i;
  
    if (! do_dump)
!     return 1;
  
    for (i = 0, section = section_headers;
         i < elf_header.e_shnum && i < num_dump_sects;
--- 10445,10494 ----
        return 0;
      }
  
!   if (strneq (name, ".gnu.linkonce.wi.", 17))
      name = ".debug_info";
  
+   /* See if we know how to display the contents of this section.  */
    for (i = NUM_ELEM (debug_displays); i--;)
!     if (streq (debug_displays[i].name, name))
        {
! 	unsigned char *start;
! 
! 	start = get_data (NULL, file, section->sh_offset, length,
! 			  _("debug section data"));
! 	if (start == NULL)
! 	  {
! 	    result = 0;
! 	    break;
! 	  }
! 
! 	result &= debug_displays[i].display (section, start, file);
! 	free (start);
! 
! 	/* If we loaded in the abbrev section
! 	   at some point, we must release it here.  */
! 	free_abbrevs ();
! 
  	break;
        }
  
    if (i == -1)
!     {
!       printf (_("Unrecognized debug section: %s\n"), name);
!       result = 0;
!     }
  
!   return result;
  }
  
! static void
  process_section_contents (FILE *file)
  {
    Elf_Internal_Shdr *section;
    unsigned int i;
  
    if (! do_dump)
!     return;
  
    for (i = 0, section = section_headers;
         i < elf_header.e_shnum && i < num_dump_sects;
*************** process_section_contents (FILE *file)
*** 10214,10223 ****
  	display_debug_section (section, file);
      }
  
!   if (i < num_dump_sects)
!     warn (_("Some sections were not dumped because they do not exist!\n"));
! 
!   return 1;
  }
  
  static void
--- 10505,10515 ----
  	display_debug_section (section, file);
      }
  
!   /* Check to see if the user requested a
!      dump of a section that does not exist.  */
!   while (i++ < num_dump_sects)
!     if (dump_sects[i])
!       warn (_("Section %d was not dumped because it does not exist!\n"), i);
  }
  
  static void
*************** process_object (char *file_name, FILE *f
*** 11129,11134 ****
--- 11421,11443 ----
    if (show_name)
      printf (_("\nFile: %s\n"), file_name);
  
+   /* Initialise the dump_sects array from the cmdline_dump_sects array.
+      Note we do this even if cmdline_dump_sects is empty because we
+      must make sure that the dump_sets array is zeroed out before each
+      object file is processed.  */
+   if (num_dump_sects > num_cmdline_dump_sects)
+     memset (dump_sects, 0, num_dump_sects);
+ 
+   if (num_cmdline_dump_sects > 0)
+     {
+       if (num_dump_sects == 0)
+ 	/* A sneaky way of allocating the dump_sects array.  */
+ 	request_dump (num_cmdline_dump_sects, 0);
+ 
+       assert (num_dump_sects >= num_cmdline_dump_sects);
+       memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects);
+     }
+   
    if (! process_file_header ())
      return 1;
  
*************** process_object (char *file_name, FILE *f
*** 11226,11231 ****
--- 11535,11547 ----
        section_groups = NULL;
      }
  
+   if (debug_information)
+     {
+       free (debug_information);
+       debug_information = NULL;
+       num_debug_info_entries = 0;
+     }
+ 
    return 0;
  }
  
*************** int
*** 11476,11483 ****
  main (int argc, char **argv)
  {
    int err;
-   char *cmdline_dump_sects = NULL;
-   unsigned num_cmdline_dump_sects = 0;
  
  #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
    setlocale (LC_MESSAGES, "");
--- 11792,11797 ----
*************** main (int argc, char **argv)
*** 11490,11502 ****
  
    parse_args (argc, argv);
  
!   if (optind < (argc - 1))
!     show_name = 1;
! 
!   /* When processing more than one file remember the dump requests
!      issued on command line to reset them after each file.  */
!   if (optind + 1 < argc && dump_sects != NULL)
      {
        cmdline_dump_sects = malloc (num_dump_sects);
        if (cmdline_dump_sects == NULL)
  	error (_("Out of memory allocating dump request table."));
--- 11804,11812 ----
  
    parse_args (argc, argv);
  
!   if (num_dump_sects > 0)
      {
+       /* Make a copy of the dump_sects array.  */
        cmdline_dump_sects = malloc (num_dump_sects);
        if (cmdline_dump_sects == NULL)
  	error (_("Out of memory allocating dump request table."));
*************** main (int argc, char **argv)
*** 11507,11525 ****
  	}
      }
  
    err = 0;
    while (optind < argc)
!     {
!       err |= process_file (argv[optind++]);
! 
!       /* Reset dump requests.  */
!       if (optind < argc && dump_sects != NULL)
! 	{
! 	  num_dump_sects = num_cmdline_dump_sects;
! 	  if (num_cmdline_dump_sects > 0)
! 	    memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects);
! 	}
!     }
  
    if (dump_sects != NULL)
      free (dump_sects);
--- 11817,11828 ----
  	}
      }
  
+   if (optind < (argc - 1))
+     show_name = 1;
+ 
    err = 0;
    while (optind < argc)
!     err |= process_file (argv[optind++]);
  
    if (dump_sects != NULL)
      free (dump_sects);
Index: binutils/doc/binutils.texi
===================================================================
RCS file: /cvs/src/src/binutils/doc/binutils.texi,v
retrieving revision 1.59
diff -c -3 -p -r1.59 binutils.texi
*** binutils/doc/binutils.texi	26 Oct 2004 16:05:42 -0000	1.59
--- binutils/doc/binutils.texi	3 Nov 2004 10:13:22 -0000
*************** readelf [@option{-a}|@option{--all}] 
*** 3153,3160 ****
          [@option{-A}|@option{--arch-specific}]
          [@option{-D}|@option{--use-dynamic}]
          [@option{-x} <number>|@option{--hex-dump=}<number>]
!         [@option{-w[liaprmfFso]}|
!          @option{--debug-dump}[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=frames-interp,=str,=loc]]
          [@option{-I}|@option{-histogram}]
          [@option{-v}|@option{--version}]
          [@option{-W}|@option{--wide}]
--- 3153,3160 ----
          [@option{-A}|@option{--arch-specific}]
          [@option{-D}|@option{--use-dynamic}]
          [@option{-x} <number>|@option{--hex-dump=}<number>]
!         [@option{-w[liaprmfFsoR]}|
!          @option{--debug-dump}[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]]
          [@option{-I}|@option{-histogram}]
          [@option{-v}|@option{--version}]
          [@option{-W}|@option{--wide}]
*************** symbols section.
*** 3271,3278 ****
  @itemx --hex-dump=<number>
  Displays the contents of the indicated section as a hexadecimal dump.
  
! @item -w[liaprmfFso]
! @itemx --debug-dump[=line,=info,=abbrev,=pubnames,=ranges,=macro,=frames,=frames-interp,=str,=loc]
  Displays the contents of the debug sections in the file, if any are
  present.  If one of the optional letters or words follows the switch
  then only data found in those specific sections will be dumped.
--- 3271,3278 ----
  @itemx --hex-dump=<number>
  Displays the contents of the indicated section as a hexadecimal dump.
  
! @item -w[liaprmfFsoR]
! @itemx --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=frames-interp,=str,=loc,=Ranges]
  Displays the contents of the debug sections in the file, if any are
  present.  If one of the optional letters or words follows the switch
  then only data found in those specific sections will be dumped.

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