2007-10-08 Carlos O'Donell <carlos@codesourcery.com>
[deliverable/binutils-gdb.git] / binutils / dwarf.c
index 00422649dd3fb4ee29d6ba7f98d08d5081b3ff7a..9cfb158aa30c95cabb2113a66e77fbb10e2518a3 100644 (file)
@@ -1,12 +1,12 @@
 /* dwarf.c -- display DWARF contents of a BFD binary file
-   Copyright 2005, 2006
+   Copyright 2005, 2006, 2007
    Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
    02110-1301, USA.  */
 
-#include <stdio.h>
-
-#include "dwarf.h"
-
-#include "bucomm.h"
+#include "sysdep.h"
 #include "libiberty.h"
+#include "bfd.h"
+#include "bucomm.h"
+#include "elf/dwarf2.h"
+#include "dwarf.h"
 
 static int have_frame_base;
 static int need_base_address;
@@ -221,7 +221,7 @@ reset_state_machine (int is_stmt)
    Returns the number of bytes read.  */
 
 static int
-process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
+process_extended_line_op (unsigned char *data, int is_stmt)
 {
   unsigned char op_code;
   unsigned int bytes_read;
@@ -251,7 +251,7 @@ process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size)
       break;
 
     case DW_LNE_set_address:
-      adr = byte_get (data, pointer_size);
+      adr = byte_get (data, len - bytes_read - 1);
       printf (_("set Address to 0x%lx\n"), adr);
       state_machine_regs.address = adr;
       break;
@@ -895,6 +895,9 @@ decode_location_expression (unsigned char * data,
        case DW_OP_call_ref:
          printf ("DW_OP_call_ref");
          break;
+       case DW_OP_form_tls_address:
+         printf ("DW_OP_form_tls_address");
+         break;
 
          /* GNU extensions.  */
        case DW_OP_GNU_push_tls_address:
@@ -1213,26 +1216,37 @@ read_and_display_attr_value (unsigned long attribute,
     case DW_AT_language:
       switch (uvalue)
        {
-       case DW_LANG_C:                 printf ("(non-ANSI C)"); break;
+         /* Ordered by the numeric value of these constants.  */
        case DW_LANG_C89:               printf ("(ANSI C)"); break;
+       case DW_LANG_C:                 printf ("(non-ANSI C)"); break;
+       case DW_LANG_Ada83:             printf ("(Ada)"); break;
        case DW_LANG_C_plus_plus:       printf ("(C++)"); break;
+       case DW_LANG_Cobol74:           printf ("(Cobol 74)"); break;
+       case DW_LANG_Cobol85:           printf ("(Cobol 85)"); break;
        case DW_LANG_Fortran77:         printf ("(FORTRAN 77)"); break;
        case DW_LANG_Fortran90:         printf ("(Fortran 90)"); break;
-       case DW_LANG_Modula2:           printf ("(Modula 2)"); break;
        case DW_LANG_Pascal83:          printf ("(ANSI Pascal)"); break;
-       case DW_LANG_Ada83:             printf ("(Ada)"); break;
-       case DW_LANG_Cobol74:           printf ("(Cobol 74)"); break;
-       case DW_LANG_Cobol85:           printf ("(Cobol 85)"); break;
+       case DW_LANG_Modula2:           printf ("(Modula 2)"); break;
          /* DWARF 2.1 values.  */
+       case DW_LANG_Java:              printf ("(Java)"); break;
        case DW_LANG_C99:               printf ("(ANSI C99)"); break;
        case DW_LANG_Ada95:             printf ("(ADA 95)"); break;
        case DW_LANG_Fortran95:         printf ("(Fortran 95)"); break;
+         /* DWARF 3 values.  */
+       case DW_LANG_PLI:               printf ("(PLI)"); break;
+       case DW_LANG_ObjC:              printf ("(Objective C)"); break;
+       case DW_LANG_ObjC_plus_plus:    printf ("(Objective C++)"); break;
+       case DW_LANG_UPC:               printf ("(Unified Parallel C)"); break;
+       case DW_LANG_D:                 printf ("(D)"); break;
          /* MIPS extension.  */
        case DW_LANG_Mips_Assembler:    printf ("(MIPS assembler)"); break;
          /* UPC extension.  */
        case DW_LANG_Upc:               printf ("(Unified Parallel C)"); break;
        default:
-         printf ("(Unknown: %lx)", uvalue);
+         if (uvalue >= DW_LANG_lo_user && uvalue <= DW_LANG_hi_user)
+           printf ("(implementation defined: %lx)", uvalue);
+         else
+           printf ("(Unknown: %lx)", uvalue);
          break;
        }
       break;
@@ -1604,7 +1618,6 @@ process_debug_info (struct dwarf_section *section, void *file,
       hdrptr += 2;
 
       cu_offset = start - section_begin;
-      start += compunit.cu_length + initial_length_size;
 
       cu_abbrev_offset_ptr = hdrptr;
       compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
@@ -1628,8 +1641,6 @@ process_debug_info (struct dwarf_section *section, void *file,
          debug_information [unit].num_range_lists = 0;
        }
 
-      tags = hdrptr;
-
       if (!do_loc)
        {
          printf (_("  Compilation Unit @ offset 0x%lx:\n"), cu_offset);
@@ -1639,6 +1650,16 @@ process_debug_info (struct dwarf_section *section, void *file,
          printf (_("   Pointer Size:  %d\n"), compunit.cu_pointer_size);
        }
 
+      if (cu_offset + compunit.cu_length + initial_length_size
+         > section->size)
+       {
+         warn (_("Debug info is corrupted, length is invalid (section is %lu bytes)\n"),
+               (unsigned long)section->size);
+         break;
+       }
+      tags = hdrptr;
+      start += compunit.cu_length + initial_length_size;
+
       if (compunit.cu_version != 2 && compunit.cu_version != 3)
        {
          warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n"));
@@ -1649,11 +1670,15 @@ process_debug_info (struct dwarf_section *section, void *file,
 
       /* Process the abbrevs used by this compilation unit. DWARF
         sections under Mach-O have non-zero addresses.  */
-      process_abbrev_section
-       ((unsigned char *) debug_displays [abbrev].section.start
-        + compunit.cu_abbrev_offset - debug_displays [abbrev].section.address,
-        (unsigned char *) debug_displays [abbrev].section.start
-        + debug_displays [abbrev].section.size);
+      if (compunit.cu_abbrev_offset >= debug_displays [abbrev].section.size)
+       warn (_("Debug info is corrupted, abbrev offset is invalid (section is %lu bytes)\n"),
+             (unsigned long)debug_displays [abbrev].section.size);
+      else
+       process_abbrev_section
+         ((unsigned char *) debug_displays [abbrev].section.start
+          + compunit.cu_abbrev_offset - debug_displays [abbrev].section.address,
+          (unsigned char *) debug_displays [abbrev].section.start
+          + debug_displays [abbrev].section.size);
 
       level = 0;
       while (tags < start)
@@ -1673,6 +1698,13 @@ process_debug_info (struct dwarf_section *section, void *file,
              continue;
            }
 
+         if (!do_loc)
+           printf (_(" <%d><%lx>: Abbrev Number: %lu"),
+                   level,
+                   (unsigned long) (tags - section_begin
+                                    - bytes_read),
+                   abbrev_number);
          /* Scan through the abbreviation list until we reach the
             correct entry.  */
          for (entry = first_abbrev;
@@ -1682,18 +1714,18 @@ process_debug_info (struct dwarf_section *section, void *file,
 
          if (entry == NULL)
            {
+             if (!do_loc)
+               {
+                 printf ("\n");
+                 fflush (stdout);
+               }
              warn (_("Unable to locate entry %lu in the abbreviation table\n"),
                    abbrev_number);
              return 0;
            }
 
          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));
+           printf (_(" (%s)\n"), get_TAG_name (entry->tag));
  
          switch (entry->tag)
            {
@@ -1704,7 +1736,6 @@ process_debug_info (struct dwarf_section *section, void *file,
              need_base_address = 1;
              break;
            case DW_TAG_entry_point:
-           case DW_TAG_inlined_subroutine:
            case DW_TAG_subprogram:
              need_base_address = 0;
              /* Assuming that there is no DW_AT_frame_base.  */
@@ -1713,14 +1744,20 @@ process_debug_info (struct dwarf_section *section, void *file,
            }
 
          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,
-                                         &debug_information [unit],
-                                         do_loc);
+           {
+             if (! do_loc)
+               /* Show the offset from where the tag was extracted.  */
+               printf ("  <%2lx>", (unsigned long)(tags - section_begin));
+
+             tags = read_and_display_attr (attr->attribute,
+                                           attr->form,
+                                           tags, cu_offset,
+                                           compunit.cu_pointer_size,
+                                           offset_size,
+                                           compunit.cu_version,
+                                           &debug_information [unit],
+                                           do_loc);
+           }
  
          if (entry->children)
            ++level;
@@ -1766,55 +1803,12 @@ load_debug_info (void * file)
     return 0;
 }
 
-/* Retrieve the pointer size associated with the given compilation unit.
-   Optionally the offset of this unit into the .debug_info section is
-   also retutned.  If there is no .debug_info section then an error
-   message is issued and 0 is returned.  If the requested comp unit has
-   not been defined in the .debug_info section then a warning message
-   is issued and the last know pointer size is returned.  This message
-   is only issued once per section dumped per file dumped.  */
-
-static unsigned int
-get_pointer_size_and_offset_of_comp_unit (unsigned int comp_unit,
-                                         const char * section_name,
-                                         unsigned long * offset_return)
-{
-  unsigned long offset = 0;
-
-  if (num_debug_info_entries == 0)
-    error (_("%s section needs a populated .debug_info section\n"),
-          section_name);
-
-  else if (comp_unit >= num_debug_info_entries)
-    {
-      if (!warned_about_missing_comp_units)
-       {
-         warn (_("%s section has more comp units than .debug_info section\n"),
-               section_name);
-         warn (_("assuming that the pointer size is %d, from the last comp unit in .debug_info\n\n"),
-               last_pointer_size);
-         warned_about_missing_comp_units = TRUE;
-       }
-    }
-  else
-    {
-      last_pointer_size = debug_information [comp_unit].pointer_size;
-      offset = debug_information [comp_unit].cu_offset;
-    }
-
-  if (offset_return != NULL)
-    * offset_return = offset;
-
-  return last_pointer_size;
-}
-
 static int
 display_debug_lines (struct dwarf_section *section, void *file)
 {
   unsigned char *start = section->start;
   unsigned char *data = start;
   unsigned char *end = start + section->size;
-  unsigned int comp_unit = 0;
 
   printf (_("\nDump of debug contents of section %s:\n\n"),
          section->name);
@@ -1827,7 +1821,6 @@ display_debug_lines (struct dwarf_section *section, void *file)
       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;
@@ -1885,12 +1878,6 @@ display_debug_lines (struct dwarf_section *section, void *file)
       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.  */
-      pointer_size = get_pointer_size_and_offset_of_comp_unit
-       (comp_unit, ".debug_line", NULL);
-      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);
@@ -1899,9 +1886,6 @@ display_debug_lines (struct dwarf_section *section, void *file)
       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)%s\n"),
-             pointer_size,
-             warned_about_missing_comp_units ? " [assumed]" : "" );
 
       end_of_sequence = data + info.li_length + initial_length_size;
 
@@ -1993,14 +1977,7 @@ display_debug_lines (struct dwarf_section *section, void *file)
          else switch (op_code)
            {
            case DW_LNS_extended_op:
-             if (pointer_size == 0)
-               {
-                 warn (_("Extend line ops need a valid pointer size, guessing at 4\n"));
-                 pointer_size = 4;
-               }
-
-             data += process_extended_line_op (data, info.li_default_is_stmt,
-                                               pointer_size);
+             data += process_extended_line_op (data, info.li_default_is_stmt);
              break;
 
            case DW_LNS_copy:
@@ -2375,7 +2352,8 @@ display_debug_loc (struct dwarf_section *section, void *file)
     error (_("No location lists in .debug_info section!\n"));
 
   /* DWARF sections under Mach-O have non-zero addresses.  */
-  if (debug_information [first].loc_offsets [0] != section->address)
+  if (debug_information [first].num_loc_offsets > 0
+      && debug_information [first].loc_offsets [0] != section->address)
     warn (_("Location lists in %s section start at 0x%lx\n"),
          section->name, debug_information [first].loc_offsets [0]);
 
@@ -2555,7 +2533,6 @@ display_debug_str (struct dwarf_section *section,
   return 1;
 }
 
-
 static int
 display_debug_info (struct dwarf_section *section, void *file)
 {
@@ -2579,6 +2556,7 @@ display_debug_aranges (struct dwarf_section *section,
       unsigned char *ranges;
       unsigned long length;
       unsigned long address;
+      unsigned char address_size;
       int excess;
       int offset_size;
       int initial_length_size;
@@ -2625,33 +2603,46 @@ display_debug_aranges (struct dwarf_section *section,
       printf (_("  Pointer Size:             %d\n"), arange.ar_pointer_size);
       printf (_("  Segment Size:             %d\n"), arange.ar_segment_size);
 
-      printf (_("\n    Address  Length\n"));
+      address_size = arange.ar_pointer_size + arange.ar_segment_size;
+
+      /* The DWARF spec does not require that the address size be a power
+        of two, but we do.  This will have to change if we ever encounter
+        an uneven architecture.  */
+      if ((address_size & (address_size - 1)) != 0)
+       {
+         warn (_("Pointer size + Segment size is not a power of two.\n"));
+         break;
+       }
+      
+      if (address_size > 4)
+       printf (_("\n    Address            Length\n"));
+      else
+       printf (_("\n    Address    Length\n"));
 
       ranges = hdrptr;
 
-      /* Must pad to an alignment boundary that is twice the pointer size.  */
-      excess = (hdrptr - start) % (2 * arange.ar_pointer_size);
+      /* Must pad to an alignment boundary that is twice the address size.  */
+      excess = (hdrptr - start) % (2 * address_size);
       if (excess)
-       ranges += (2 * arange.ar_pointer_size) - excess;
+       ranges += (2 * address_size) - excess;
 
-      for (;;)
-       {
-         address = byte_get (ranges, arange.ar_pointer_size);
+      start += arange.ar_length + initial_length_size;
 
-         ranges += arange.ar_pointer_size;
+      while (ranges + 2 * address_size <= start)
+       {
+         address = byte_get (ranges, address_size);
 
-         length  = byte_get (ranges, arange.ar_pointer_size);
+         ranges += address_size;
 
-         ranges += arange.ar_pointer_size;
+         length  = byte_get (ranges, address_size);
 
-         /* A pair of zeros marks the end of the list.  */
-         if (address == 0 && length == 0)
-           break;
+         ranges += address_size;
 
-         printf ("    %8.8lx %lu\n", address, length);
+         if (address_size > 4)
+           printf ("    0x%16.16lx 0x%lx\n", address, length);
+         else
+           printf ("    0x%8.8lx 0x%lx\n", address, length);       
        }
-
-      start += arange.ar_length + initial_length_size;
     }
 
   printf ("\n");
@@ -2732,7 +2723,8 @@ display_debug_ranges (struct dwarf_section *section,
     error (_("No range lists in .debug_info section!\n"));
 
   /* DWARF sections under Mach-O have non-zero addresses.  */
-  if (debug_information [first].range_lists [0] != section->address)
+  if (debug_information [first].num_range_lists > 0
+      && debug_information [first].range_lists [0] != section->address)
     warn (_("Range lists in %s section start at 0x%lx\n"),
          section->name, debug_information [first].range_lists [0]);
 
@@ -2943,6 +2935,7 @@ static dwarf_vma
 get_encoded_value (unsigned char *data, int encoding)
 {
   int size = size_of_encoded_value (encoding);
+
   if (encoding & DW_EH_PE_signed)
     return byte_get_signed (data, size);
   else
@@ -2991,7 +2984,7 @@ display_debug_frames (struct dwarf_section *section,
        {
          printf ("\n%08lx ZERO terminator\n\n",
                    (unsigned long)(saved_start - section_start));
-         return 1;
+         continue;
        }
 
       if (length == 0xffffffff)
@@ -3008,6 +3001,12 @@ display_debug_frames (struct dwarf_section *section,
        }
 
       block_end = saved_start + length + initial_length_size;
+      if (block_end > end)
+       {
+         warn ("Invalid length %#08lx in FDE at %#08lx\n",
+               length, (unsigned long)(saved_start - section_start));
+         block_end = end;
+       }
       cie_id = byte_get (start, offset_size); start += offset_size;
 
       if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
@@ -3142,9 +3141,8 @@ display_debug_frames (struct dwarf_section *section,
 
          if (!cie)
            {
-             warn ("Invalid CIE pointer %08lx in FDE at %p\n",
-                   cie_id, saved_start);
-             start = block_end;
+             warn ("Invalid CIE pointer %#08lx in FDE at %#08lx\n",
+                   cie_id, (unsigned long)(saved_start - section_start));
              fc->ncols = 0;
              fc->col_type = xmalloc (sizeof (short int));
              fc->col_offset = xmalloc (sizeof (int));
@@ -3648,7 +3646,10 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            default:
-             warn (_("unsupported or unknown DW_CFA_%d\n"), op);
+             if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
+               printf (_("  DW_CFA_??? (User defined call frame op: %#x)\n"), op);
+             else
+               warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);              
              start = block_end;
            }
        }
This page took 0.040668 seconds and 4 git commands to generate.