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]: readelf: Per comp-unit pointer sizes


Hi Guys,

  Currently readelf assumes that the pointer size in the DWARF debug
  information for a given executable is fixed.  This does not have to
  be the case, and indeed some toolchains (eg mipsisa64-elf) can
  produce executables with multiple pointer sizes.

  The patch below fixes readelf so that it computes an array of
  pointer sizes from the contents of the .debug.info sections and then
  uses these sizes when displaying the .debug.line and .debug.loc
  sections.

Cheers
        Nick

binutils/ChangeLog
2003-12-29  Nick Clifton  <nickc@redhat.com>

	* readelf.c (debug_line_pointer_size): Replace with an array
        called 'debug_line_pointer_sizes'.
        (num_debug_line_pointer_sizes): New variable.
        (display_debug_lines): Extract pointer size from the
        debug_line_pointer_sizes array.
        (display_debug_loc): Likewise.
        (prescan_debug_info): Fill in the debug_line_pointer_sizes
        array.

Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.227
diff -c -3 -p -r1.227 readelf.c
*** binutils/readelf.c	19 Dec 2003 11:43:47 -0000	1.227
--- binutils/readelf.c	29 Dec 2003 11:52:14 -0000
*************** process_extended_line_op (unsigned char 
*** 6274,6280 ****
  /* 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 int debug_line_pointer_size = 4;
  
  static int
  display_debug_lines (Elf_Internal_Shdr *section,
--- 6274,6281 ----
  /* 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;
  
  static int
  display_debug_lines (Elf_Internal_Shdr *section,
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6290,6301 ****
--- 6291,6305 ----
    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));
  
    while (data < end)
      {
+       unsigned int pointer_size;
+ 
        hdrptr = data;
  
        /* Check the length of the block.  */
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6349,6354 ****
--- 6353,6371 ----
        info.li_line_base <<= 24;
        info.li_line_base >>= 24;
  
+       /* 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_lines 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);
        printf (_("  Prologue Length:             %d\n"), info.li_prologue_length);
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6357,6362 ****
--- 6374,6380 ----
        printf (_("  Line Base:                   %d\n"), info.li_line_base);
        printf (_("  Line Range:                  %d\n"), info.li_line_range);
        printf (_("  Opcode Base:                 %d\n"), info.li_opcode_base);
+       printf (_("  (Pointer size:               %u)\n"), pointer_size);
  
        end_of_sequence = data + info.li_length + initial_length_size;
  
*************** display_debug_lines (Elf_Internal_Shdr *
*** 6449,6455 ****
  	    {
  	    case DW_LNS_extended_op:
  	      data += process_extended_line_op (data, info.li_default_is_stmt,
! 						debug_line_pointer_size);
  	      break;
  
  	    case DW_LNS_copy:
--- 6467,6473 ----
  	    {
  	    case DW_LNS_extended_op:
  	      data += process_extended_line_op (data, info.li_default_is_stmt,
! 						pointer_size);
  	      break;
  
  	    case DW_LNS_copy:
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 7531,7536 ****
--- 7549,7555 ----
    unsigned long bytes;
    unsigned char *section_begin = start;
    bfd_vma addr;
+   unsigned int comp_unit = 0;
  
    addr = section->sh_addr;
    bytes = section->sh_size;
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 7551,7571 ****
        unsigned long end;
        unsigned short length;
        unsigned long offset;
  
        offset = start - section_begin;
  
        while (1)
  	{
! 	  /* Normally, the lists in the debug_loc section are related to a
! 	     given compilation unit, and thus, we would use the pointer size
! 	     of that compilation unit.  However, since we are displaying it
! 	     separately here, we either have to store pointer sizes of all
! 	     compilation units, or assume they don't change.   We assume,
! 	     like the debug_line display, that it doesn't change.  */
! 	  begin = byte_get (start, debug_line_pointer_size);
! 	  start += debug_line_pointer_size;
! 	  end = byte_get (start, debug_line_pointer_size);
! 	  start += debug_line_pointer_size;
  
  	  if (begin == 0 && end == 0)
  	    break;
--- 7570,7598 ----
        unsigned long end;
        unsigned short length;
        unsigned long offset;
+       unsigned int pointer_size;
  
        offset = start - section_begin;
  
+       /* 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)
  	{
! 	  begin = byte_get (start, pointer_size);
! 	  start += pointer_size;
! 	  end = byte_get (start, pointer_size);
! 	  start += pointer_size;
  
  	  if (begin == 0 && end == 0)
  	    break;
*************** display_debug_loc (Elf_Internal_Shdr *se
*** 7581,7587 ****
  	  start += 2;
  
  	  printf ("    %8.8lx %8.8lx %8.8lx (", offset, begin, end);
! 	  decode_location_expression (start, debug_line_pointer_size, length);
  	  printf (")\n");
  
  	  start += length;
--- 7608,7614 ----
  	  start += 2;
  
  	  printf ("    %8.8lx %8.8lx %8.8lx (", offset, begin, end);
! 	  decode_location_expression (start, pointer_size, length);
  	  printf (")\n");
  
  	  start += length;
*************** display_debug_not_supported (Elf_Interna
*** 9167,9222 ****
    return 1;
  }
  
! /* Pre-scan the .debug_info section to record the size of address.
!    When dumping the .debug_line, we use that size information, assuming
!    that all compilation units have the same address size.  */
! static int
! prescan_debug_info (Elf_Internal_Shdr *section ATTRIBUTE_UNUSED,
! 		    unsigned char *start,
  		    FILE *file ATTRIBUTE_UNUSED)
  {
!   unsigned long length;
  
!   /* 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.  For the purposes
!      of this prescan, we don't care about the actual length, but the
!      presence of the escape bytes does affect the location of the byte
!      which describes the address size.  */
!   length = byte_get (start, 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_line_pointer_size = byte_get (start + 22, 1);
      }
!   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_line_pointer_size = byte_get (start + 10, 1);
!     }
!   return 0;
! }
! 
!   /* A structure containing the name of a debug section and a pointer
!      to a function that can decode it.  The third field is a prescan
!      function to be run over the section before displaying any of the
!      sections.  */
  struct
  {
    const char *const name;
--- 9194,9290 ----
    return 1;
  }
  
! /* Pre-scan the .debug_info section to record the pointer sizes for the
!    compilation units.  Usually an executable will have just one pointer
!    size, but this is not guaranteed, and so we try not to make any
!    assumptions.  Returns zero upon failure, or the number of compilation
!    units upon success.  */
! 
! static unsigned int
! prescan_debug_info (Elf_Internal_Shdr *section, unsigned char *start,
  		    FILE *file ATTRIBUTE_UNUSED)
  {
!   unsigned char *begin;
!   unsigned char *end = start + section->sh_size;
!   unsigned long  length;
!   unsigned int   num_units;
!   unsigned int   unit;
!     
!   /* First scan the section to compute 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 ?"));
!       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);
!       return 0;
      }
! 
!   /* Populate the array.  */
!   for (begin = start, unit = 0; begin < end; unit++)
      {
!       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_line_pointer_sizes [unit] = 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_line_pointer_sizes [unit] = byte_get (begin + 10, 1);
! 	  begin += length + 4;
! 	}
!     }
! 
!   num_debug_line_pointer_sizes = num_units;
!   return num_units;
! }
! 
! /* A structure containing the name of a debug section and a pointer
!    to a function that can decode it.  The third field is a prescan
!    function to be run over the section before displaying any of the
!    sections.  */
  struct
  {
    const char *const name;
        


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