Fix memory access violations triggered by running objdump compiled with out-of-bounds...
[deliverable/binutils-gdb.git] / binutils / dwarf.c
index 7cfc45f3f1262d1f2a681085e2c9bb684fb9a177..9daf31579a590661384080ae2e1414a012b472b9 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf.c -- display DWARF contents of a BFD binary file
-   Copyright (C) 2005-2014 Free Software Foundation, Inc.
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -38,12 +38,13 @@ static unsigned int last_pointer_size = 0;
 static int warned_about_missing_comp_units = FALSE;
 
 static unsigned int num_debug_info_entries = 0;
+static unsigned int alloc_num_debug_info_entries = 0;
 static debug_info *debug_information = NULL;
 /* Special value for num_debug_info_entries to indicate
    that the .debug_info section could not be loaded/parsed.  */
 #define DEBUG_INFO_UNAVAILABLE  (unsigned int) -1
 
-int eh_addr_size;
+unsigned int eh_addr_size;
 
 int do_debug_info;
 int do_debug_abbrevs;
@@ -104,7 +105,7 @@ static void load_cu_tu_indexes (void *file);
 #define FLAG_DEBUG_LINES_RAW    1
 #define FLAG_DEBUG_LINES_DECODED 2
 
-static int
+static unsigned int
 size_of_encoded_value (int encoding)
 {
   switch (encoding & 0x7)
@@ -162,17 +163,17 @@ get_encoded_value (unsigned char **pdata,
   return val;
 }
 
-#if __STDC_VERSION__ >= 199901L || (defined(__GNUC__) && __GNUC__ >= 2)
-#ifndef __MINGW32__
-#define  DWARF_VMA_FMT       "ll"
-#define  DWARF_VMA_FMT_LONG  "%16.16llx"
+#if defined HAVE_LONG_LONG && SIZEOF_LONG_LONG > SIZEOF_LONG
+# ifndef __MINGW32__
+#  define DWARF_VMA_FMT                "ll"
+#  define DWARF_VMA_FMT_LONG   "%16.16llx"
+# else
+#  define DWARF_VMA_FMT                "I64"
+#  define DWARF_VMA_FMT_LONG   "%016I64x"
+# endif
 #else
-#define  DWARF_VMA_FMT       "I64"
-#define  DWARF_VMA_FMT_LONG  "%016I64x"
-#endif
-#else
-#define  DWARF_VMA_FMT       "l"
-#define  DWARF_VMA_FMT_LONG  "%16.16lx"
+# define DWARF_VMA_FMT         "l"
+# define DWARF_VMA_FMT_LONG    "%16.16lx"
 #endif
 
 /* Convert a dwarf vma value into a string.  Returns a pointer to a static
@@ -280,6 +281,11 @@ read_leb128 (unsigned char *data,
       shift += 7;
       if ((byte & 0x80) == 0)
        break;
+
+      /* PR 17512: file: 0ca183b8.
+        FIXME: Should we signal this error somehow ?  */
+      if (shift >= sizeof (result))
+       break;
     }
 
   if (length_return != NULL)
@@ -445,9 +451,13 @@ process_extended_line_op (unsigned char * data,
     case DW_LNE_set_address:
       /* PR 17512: file: 002-100480-0.004.  */
       if (len - bytes_read - 1 > 8)
-       warn (_("Length (%d) of DW_LNE_set_address op is too long\n"),
-             len - bytes_read - 1);
-      SAFE_BYTE_GET (adr, data, len - bytes_read - 1, end);
+       {
+         warn (_("Length (%d) of DW_LNE_set_address op is too long\n"),
+               len - bytes_read - 1);
+         adr = 0;
+       }
+      else
+       SAFE_BYTE_GET (adr, data, len - bytes_read - 1, end);
       printf (_("set Address to 0x%s\n"), dwarf_vmatoa ("x", adr));
       state_machine_regs.address = adr;
       state_machine_regs.op_index = 0;
@@ -1303,6 +1313,9 @@ decode_location_expression (unsigned char * data,
        case DW_OP_GNU_entry_value:
          uvalue = read_uleb128 (data, &bytes_read, end);
          data += bytes_read;
+         /* PR 17531: file: 0cc9cd00.  */
+         if (uvalue > (dwarf_vma) (end - data))
+           uvalue = end - data;
          printf ("DW_OP_GNU_entry_value: (");
          if (decode_location_expression (data, pointer_size, offset_size,
                                          dwarf_version, uvalue,
@@ -1662,8 +1675,12 @@ read_and_display_attr_value (unsigned long attribute,
          uvalue = 0;
          block_start = end;
        }
+      /* FIXME: Testing "(block_start + uvalue) < block_start" miscompiles with
+        gcc 4.8.3 running on an x86_64 host in 32-bit mode.  So we pre-compute
+        block_start + uvalue here.  */
+      data = block_start + uvalue;
       /* PR 17512: file: 008-103549-0.001:0.1.  */
-      if (block_start + uvalue > end)
+      if (block_start + uvalue > end || data < block_start)
        {
          warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
          uvalue = end - block_start;
@@ -1683,7 +1700,8 @@ read_and_display_attr_value (unsigned long attribute,
          uvalue = 0;
          block_start = end;
        }
-      if (block_start + uvalue > end)
+      data = block_start + uvalue;
+      if (block_start + uvalue > end || data < block_start)
        {
          warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
          uvalue = end - block_start;
@@ -1703,7 +1721,8 @@ read_and_display_attr_value (unsigned long attribute,
          uvalue = 0;
          block_start = end;
        }
-      if (block_start + uvalue > end)
+      data = block_start + uvalue;
+      if (block_start + uvalue > end || data < block_start)
        {
          warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
          uvalue = end - block_start;
@@ -1724,7 +1743,10 @@ read_and_display_attr_value (unsigned long attribute,
          uvalue = 0;
          block_start = end;
        }
-      if (block_start + uvalue > end)
+      data = block_start + uvalue;
+      if (block_start + uvalue > end
+         /* PR 17531: file: 5b5f0592.  */ 
+         || data < block_start)
        {
          warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
          uvalue = end - block_start;
@@ -1936,8 +1958,10 @@ read_and_display_attr_value (unsigned long attribute,
          /* DWARF 5 values.  */
        case DW_LANG_Go:                printf ("(Go)"); break;
        case DW_LANG_C_plus_plus_11:    printf ("(C++11)"); break;
-       case DW_LANG_C11:               printf ("(ANSI C11)"); break;
+       case DW_LANG_C11:               printf ("(C11)"); break;
        case DW_LANG_C_plus_plus_14:    printf ("(C++14)"); break;
+       case DW_LANG_Fortran03:         printf ("(Fortran 03)"); break;
+       case DW_LANG_Fortran08:         printf ("(Fortran 08)"); break;
          /* MIPS extension.  */
        case DW_LANG_Mips_Assembler:    printf ("(MIPS assembler)"); break;
          /* UPC extension.  */
@@ -2121,7 +2145,7 @@ read_and_display_attr_value (unsigned long attribute,
          uvalue += cu_offset;
 
        if (uvalue >= section->size)
-         warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset %lx is too big.\n"),
+         warn (_("Offset %s used as value for DW_AT_import attribute of DIE at offset 0x%lx is too big.\n"),
                dwarf_vmatoa ("x", uvalue),
                (unsigned long) (orig_data - section->start));
        else
@@ -2255,8 +2279,8 @@ process_debug_info (struct dwarf_section *section,
 
          /* Negative values are illegal, they may even cause infinite
             looping.  This can happen if we can't accurately apply
-            relocations to an object file.  */
-         if ((signed long) length <= 0)
+            relocations to an object file, or if the file is corrupt.  */
+         if ((signed long) length <= 0 || section_begin < start)
            {
              warn (_("Corrupt unit length (0x%s) found in section %s\n"),
                    dwarf_vmatoa ("x", length), section->name);
@@ -2272,13 +2296,15 @@ process_debug_info (struct dwarf_section *section,
 
       /* Then allocate an array to hold the information.  */
       debug_information = (debug_info *) cmalloc (num_units,
-                                                  sizeof (* debug_information));
+                                                 sizeof (* debug_information));
       if (debug_information == NULL)
        {
          error (_("Not enough memory for a debug info array of %u entries\n"),
                 num_units);
+         alloc_num_debug_info_entries = num_debug_info_entries = 0;
          return 0;
        }
+      alloc_num_debug_info_entries = num_units;
     }
 
   if (!do_loc)
@@ -2438,11 +2464,19 @@ process_debug_info (struct dwarf_section *section,
                  " extends beyond end of section (length = %s)\n"),
                dwarf_vmatoa ("x", cu_offset),
                dwarf_vmatoa ("x", compunit.cu_length));
+         num_units = unit;
          break;
        }
       tags = hdrptr;
       start += compunit.cu_length + initial_length_size;
 
+      if (start > end)
+       {
+         warn (_("Debug info is corrupt.  CU at %s extends beyond end of section"),
+               dwarf_vmatoa ("x", cu_offset));
+         start = end;
+       }
+
       if (compunit.cu_version != 2
          && compunit.cu_version != 3
          && compunit.cu_version != 4)
@@ -2460,6 +2494,12 @@ process_debug_info (struct dwarf_section *section,
        warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than abbrev section size (%lx)\n"),
              (unsigned long) compunit.cu_abbrev_offset,
              (unsigned long) abbrev_size);
+      /* PR 17531: file:4bcd9ce9.  */ 
+      else if ((abbrev_base + abbrev_size)
+              > debug_displays [abbrev_sec].section.size)
+       warn (_("Debug info is corrupted, abbrev size (%lx) is larger than abbrev section size (%lx)\n"),
+             (unsigned long) abbrev_base + abbrev_size,
+             (unsigned long) debug_displays [abbrev_sec].section.size);
       else
        process_abbrev_section
          (((unsigned char *) debug_displays [abbrev_sec].section.start
@@ -2559,7 +2599,7 @@ process_debug_info (struct dwarf_section *section,
                  printf ("\n");
                  fflush (stdout);
                }
-             warn (_("DIE at offset %lx refers to abbreviation number %lu which does not exist\n"),
+             warn (_("DIE at offset 0x%lx refers to abbreviation number %lu which does not exist\n"),
                    die_offset, abbrev_number);
              return 0;
            }
@@ -2593,9 +2633,10 @@ process_debug_info (struct dwarf_section *section,
                /* Show the offset from where the tag was extracted.  */
                printf ("    <%lx>", (unsigned long)(tags - section_begin));
 
-             arg = debug_information;
-             if (debug_information)
-               arg += unit;
+             if (debug_information && unit < alloc_num_debug_info_entries)
+               arg = debug_information + unit;
+             else
+               arg = NULL;
 
              tags = read_and_display_attr (attr->attribute,
                                            attr->form,
@@ -2621,7 +2662,12 @@ process_debug_info (struct dwarf_section *section,
   if ((do_loc || do_debug_loc || do_debug_ranges)
       && num_debug_info_entries == 0
       && ! do_types)
-    num_debug_info_entries = num_units;
+    {
+      if (num_units > alloc_num_debug_info_entries)    
+       num_debug_info_entries = alloc_num_debug_info_entries;
+      else
+       num_debug_info_entries = num_units;
+    }
 
   if (!do_loc)
     printf ("\n");
@@ -2658,9 +2704,10 @@ load_debug_info (void * file)
   if (load_debug_section (info, file)
       && process_debug_info (&debug_displays [info].section, file, abbrev, 1, 0))
     return num_debug_info_entries;
-  else if (load_debug_section (info_dwo, file)
-           && process_debug_info (&debug_displays [info_dwo].section, file,
-                                  abbrev_dwo, 1, 0))
+
+  if (load_debug_section (info_dwo, file)
+      && process_debug_info (&debug_displays [info_dwo].section, file,
+                            abbrev_dwo, 1, 0))
     return num_debug_info_entries;
 
   num_debug_info_entries = DEBUG_INFO_UNAVAILABLE;
@@ -2757,7 +2804,8 @@ read_debug_line_header (struct dwarf_section * section,
   /* PR 17512: file:002-117414-0.004.  */ 
   if (* end_of_sequence > end)
     {
-      warn (_("Line length %lld extends beyond end of section\n"), linfo->li_length);
+      warn (_("Line length %s extends beyond end of section\n"),
+           dwarf_vmatoa ("u", linfo->li_length));
       * end_of_sequence = end;
       return NULL;
     }
@@ -2802,6 +2850,12 @@ display_debug_lines_raw (struct dwarf_section *section,
          end_of_sequence = end;
          standard_opcodes = NULL;
          linfo = saved_linfo;
+         /* PR 17531: file: 0522b371.  */
+         if (linfo.li_line_range == 0)
+           {
+             warn (_("Partial .debug_line. section encountered without a prior full .debug_line section\n"));
+             return 0;
+           }
          reset_state_machine (linfo.li_default_is_stmt);
        }
       else
@@ -2815,7 +2869,7 @@ display_debug_lines_raw (struct dwarf_section *section,
          printf (_("  Offset:                      0x%lx\n"), (long)(data - start));
          printf (_("  Length:                      %ld\n"), (long) linfo.li_length);
          printf (_("  DWARF Version:               %d\n"), linfo.li_version);
-         printf (_("  Prologue Length:             %d\n"), linfo.li_prologue_length);
+         printf (_("  Prologue Length:             %d\n"), (int) linfo.li_prologue_length);
          printf (_("  Minimum Instruction Length:  %d\n"), linfo.li_min_insn_length);
          if (linfo.li_version >= 4)
            printf (_("  Maximum Ops per Instruction: %d\n"), linfo.li_max_ops_per_insn);
@@ -3153,6 +3207,12 @@ display_debug_lines_decoded (struct dwarf_section *section,
          end_of_sequence = end;
          standard_opcodes = NULL;
          linfo = saved_linfo;
+         /* PR 17531: file: 0522b371.  */
+         if (linfo.li_line_range == 0)
+           {
+             warn (_("Partial .debug_line. section encountered without a prior full .debug_line section\n"));
+             return 0;
+           }
          reset_state_machine (linfo.li_default_is_stmt);
         }
       else
@@ -3163,6 +3223,12 @@ display_debug_lines_decoded (struct dwarf_section *section,
                                                & end_of_sequence)) == NULL)
              return 0;
 
+         /* PR 17531: file: 0522b371.  */
+         if (linfo.li_line_range == 0)
+           {
+             warn (_("Line range of 0 is invalid, using 1 instead\n"));
+             linfo.li_line_range = 1;
+           }
          reset_state_machine (linfo.li_default_is_stmt);
 
          /* Save a pointer to the contents of the Opcodes table.  */
@@ -3681,7 +3747,25 @@ display_debug_pubnames_worker (struct dwarf_section *section,
 
       SAFE_BYTE_GET_AND_INC (names.pn_size, data, offset_size, end);
 
-      start += names.pn_length + initial_length_size;
+      /* PR 17531: file: 7615b6b2.  */
+      if ((dwarf_signed_vma) names.pn_length < 0
+         /* PR 17531: file: a5dbeaa7. */
+         || start + names.pn_length + initial_length_size < start)
+       {
+         warn (_("Negative length for public name: 0x%lx\n"), (long) names.pn_length);
+         start = end;
+       }
+      else
+       start += names.pn_length + initial_length_size;
+
+      printf (_("  Length:                              %ld\n"),
+             (long) names.pn_length);
+      printf (_("  Version:                             %d\n"),
+             names.pn_version);
+      printf (_("  Offset into .debug_info section:     0x%lx\n"),
+             (unsigned long) names.pn_offset);
+      printf (_("  Size of area in .debug_info section: %ld\n"),
+             (long) names.pn_size);
 
       if (names.pn_version != 2 && names.pn_version != 3)
        {
@@ -3696,15 +3780,6 @@ display_debug_pubnames_worker (struct dwarf_section *section,
          continue;
        }
 
-      printf (_("  Length:                              %ld\n"),
-             (long) names.pn_length);
-      printf (_("  Version:                             %d\n"),
-             names.pn_version);
-      printf (_("  Offset into .debug_info section:     0x%lx\n"),
-             (unsigned long) names.pn_offset);
-      printf (_("  Size of area in .debug_info section: %ld\n"),
-             (long) names.pn_size);
-
       if (is_gnu)
        printf (_("\n    Offset  Kind          Name\n"));
       else
@@ -4242,23 +4317,35 @@ display_debug_abbrev (struct dwarf_section *section,
 static void
 display_loc_list (struct dwarf_section *section,
                   unsigned char **start_ptr,
-                  int debug_info_entry,
+                  unsigned int debug_info_entry,
                   unsigned long offset,
                   unsigned long base_address,
                   int has_frame_base)
 {
   unsigned char *start = *start_ptr;
   unsigned char *section_end = section->start + section->size;
-  unsigned long cu_offset = debug_information [debug_info_entry].cu_offset;
-  unsigned int pointer_size = debug_information [debug_info_entry].pointer_size;
-  unsigned int offset_size = debug_information [debug_info_entry].offset_size;
-  int dwarf_version = debug_information [debug_info_entry].dwarf_version;
+  unsigned long cu_offset;
+  unsigned int pointer_size;
+  unsigned int offset_size;
+  int dwarf_version;
 
   dwarf_vma begin;
   dwarf_vma end;
   unsigned short length;
   int need_frame_base;
 
+  if (debug_info_entry >= num_debug_info_entries)
+    {
+      warn (_("No debug information available for loc lists of entry: %u\n"),
+           debug_info_entry);
+      return;
+    }
+  
+  cu_offset = debug_information [debug_info_entry].cu_offset;
+  pointer_size = debug_information [debug_info_entry].pointer_size;
+  offset_size = debug_information [debug_info_entry].offset_size;
+  dwarf_version = debug_information [debug_info_entry].dwarf_version;
+  
   if (pointer_size < 2 || pointer_size > 8)
     {
       warn (_("Invalid pointer size (%d) in debug info for entry %d\n"),
@@ -4362,22 +4449,34 @@ print_addr_index (unsigned int idx, unsigned int len)
 static void
 display_loc_list_dwo (struct dwarf_section *section,
                       unsigned char **start_ptr,
-                      int debug_info_entry,
+                      unsigned int debug_info_entry,
                       unsigned long offset,
                       int has_frame_base)
 {
   unsigned char *start = *start_ptr;
   unsigned char *section_end = section->start + section->size;
-  unsigned long cu_offset = debug_information [debug_info_entry].cu_offset;
-  unsigned int pointer_size = debug_information [debug_info_entry].pointer_size;
-  unsigned int offset_size = debug_information [debug_info_entry].offset_size;
-  int dwarf_version = debug_information [debug_info_entry].dwarf_version;
+  unsigned long cu_offset;
+  unsigned int pointer_size;
+  unsigned int offset_size;
+  int dwarf_version;
   int entry_type;
   unsigned short length;
   int need_frame_base;
   unsigned int idx;
   unsigned int bytes_read;
 
+  if (debug_info_entry >= num_debug_info_entries)
+    {
+      warn (_("No debug information for loc lists of entry: %u\n"),
+           debug_info_entry);
+      return;
+    }
+
+  cu_offset = debug_information [debug_info_entry].cu_offset;
+  pointer_size = debug_information [debug_info_entry].pointer_size;
+  offset_size = debug_information [debug_info_entry].offset_size;
+  dwarf_version = debug_information [debug_info_entry].dwarf_version;
+
   if (pointer_size < 2 || pointer_size > 8)
     {
       warn (_("Invalid pointer size (%d) in debug info for entry %d\n"),
@@ -4868,21 +4967,30 @@ display_debug_addr (struct dwarf_section *section,
 
   printf (_("Contents of the %s section:\n\n"), section->name);
 
-  debug_addr_info = (debug_info **) xmalloc ((num_debug_info_entries + 1)
-                                             * sizeof (debug_info *));
+  /* PR  17531: file: cf38d01b.
+     We use xcalloc because a corrupt file may not have initialised all of the
+     fields in the debug_info structure, which means that the sort below might
+     try to move uninitialised data.  */
+  debug_addr_info = (debug_info **) xcalloc ((num_debug_info_entries + 1),
+                                             sizeof (debug_info *));
 
   count = 0;
   for (i = 0; i < num_debug_info_entries; i++)
-    {
-      if (debug_information [i].addr_base != DEBUG_INFO_UNAVAILABLE)
-        debug_addr_info [count++] = &debug_information [i];
-    }
+    if (debug_information [i].addr_base != DEBUG_INFO_UNAVAILABLE)
+      {
+       /* PR 17531: file: cf38d01b.  */
+       if (debug_information[i].addr_base >= section->size)
+         warn (_("Corrupt address base (%lx) found in debug section %u\n"),
+               (unsigned long) debug_information[i].addr_base, i);
+       else
+         debug_addr_info [count++] = debug_information + i;
+      }
 
   /* Add a sentinel to make iteration convenient.  */
   debug_addr_info [count] = (debug_info *) xmalloc (sizeof (debug_info));
   debug_addr_info [count]->addr_base = section->size;
-
   qsort (debug_addr_info, count, sizeof (debug_info *), comp_addr_base);
+
   for (i = 0; i < count; i++)
     {
       unsigned int idx;
@@ -5443,7 +5551,20 @@ read_cie (unsigned char *start, unsigned char *end,
   if (version >= 4)
     {
       GET (fc->ptr_size, 1);
+      if (fc->ptr_size < 1 || fc->ptr_size > 8)
+       {
+         warn (_("Invalid pointer size (%d) in CIE data\n"), fc->ptr_size);
+         return end;
+       }
+
       GET (fc->segment_size, 1);
+      /* PR 17512: file: e99d2804.  */
+      if (fc->segment_size > 8 || fc->segment_size + fc->ptr_size > 8)
+       {
+         warn (_("Invalid segment size (%d) in CIE data\n"), fc->segment_size);
+         return end;
+       }
+
       eh_addr_size = fc->ptr_size;
     }
   else
@@ -5470,16 +5591,27 @@ read_cie (unsigned char *start, unsigned char *end,
       /* PR 17512: file: 11042-2589-0.004.  */
       if (start > end)
        {
-         warn (_("Augmentation data too long: 0x%lx"), augmentation_data_len);
+         warn (_("Augmentation data too long: 0x%lx\n"), augmentation_data_len);
          return end;
        }
     }
 
   if (augmentation_data_len)
     {
-      unsigned char *p, *q;
+      unsigned char *p;
+      unsigned char *q;
+      unsigned char *qend;
+      
       p = (unsigned char *) fc->augmentation + 1;
       q = augmentation_data;
+      qend = q + augmentation_data_len;
+
+      /* PR 17531: file: 015adfaa.  */
+      if (qend < q)
+       {
+         warn (_("Negative augmentation data length: 0x%lx"), augmentation_data_len);
+         augmentation_data_len = 0;
+       }
 
       while (p < end && q < augmentation_data + augmentation_data_len)
        {
@@ -5495,6 +5627,8 @@ read_cie (unsigned char *start, unsigned char *end,
            break;
          p++;
        }
+      /* Note - it is OK if this loop terminates with q < qend.
+        Padding may have been inserted to align the end of the CIE.  */
     }
 
   *p_cie = fc;
@@ -5522,7 +5656,7 @@ display_debug_frames (struct dwarf_section *section,
   unsigned int length_return;
   unsigned int max_regs = 0;
   const char *bad_reg = _("bad register: ");
-  int saved_eh_addr_size = eh_addr_size;
+  unsigned int saved_eh_addr_size = eh_addr_size;
 
   printf (_("Contents of the %s section:\n"), section->name);
 
@@ -5787,7 +5921,7 @@ display_debug_frames (struct dwarf_section *section,
              augmentation_data = start;
              start += augmentation_data_len;
              /* PR 17512: file: 722-8446-0.004.  */
-             if (start >= end)
+             if (start >= end || ((signed long) augmentation_data_len) < 0)
                {
                  warn (_("Corrupt augmentation data length: %lx\n"),
                        augmentation_data_len);
@@ -5839,6 +5973,7 @@ display_debug_frames (struct dwarf_section *section,
            {
              unsigned int reg, op, opa;
              unsigned long temp;
+             unsigned char * new_start;
 
              op = *start++;
              opa = op & 0x3f;
@@ -5909,26 +6044,28 @@ display_debug_frames (struct dwarf_section *section,
                  break;
                case DW_CFA_def_cfa_expression:
                  temp = LEB ();
-                 if (start + temp < start)
+                 new_start = start + temp;
+                 if (new_start < start)
                    {
                      warn (_("Corrupt CFA_def expression value: %lu\n"), temp);
                      start = block_end;
                    }
                  else
-                   start += temp;
+                   start = new_start;
                  break;
                case DW_CFA_expression:
                case DW_CFA_val_expression:
                  reg = LEB ();
                  temp = LEB ();
-                 if (start + temp < start)
+                 new_start = start + temp;
+                 if (new_start < start)
                    {
                      /* PR 17512: file:306-192417-0.005.  */ 
                      warn (_("Corrupt CFA expression value: %lu\n"), temp);
                      start = block_end;
                    }
                  else
-                   start += temp;
+                   start = new_start;
                  if (frame_need_space (fc, reg) >= 0)
                    fc->col_type[reg] = DW_CFA_undefined;
                  break;
@@ -6200,7 +6337,7 @@ display_debug_frames (struct dwarf_section *section,
                  fc->cfa_exp = rs->cfa_exp;
                  if (frame_need_space (fc, rs->ncols - 1) < 0)
                    {
-                     warn (_("Invalid column number in saved frame state"));
+                     warn (_("Invalid column number in saved frame state\n"));
                      fc->ncols = 0;
                      break;
                    }
@@ -6486,9 +6623,42 @@ display_gdb_index (struct dwarf_section *section,
       return 0;
     }
 
+  /* PR 17531: file: 418d0a8a.  */
+  if (tu_list_offset < cu_list_offset)
+    {
+      warn (_("TU offset (%x) is less than CU offset (%x)\n"),
+           tu_list_offset, cu_list_offset);
+      return 0;
+    }
+
   cu_list_elements = (tu_list_offset - cu_list_offset) / 8;
+
+  if (address_table_offset < tu_list_offset)
+    {
+      warn (_("Address table offset (%x) is less than TU offset (%x)\n"),
+           address_table_offset, tu_list_offset);
+      return 0;
+    }
+
   tu_list_elements = (address_table_offset - tu_list_offset) / 8;
+
+  /* PR 17531: file: 18a47d3d.  */
+  if (symbol_table_offset < address_table_offset)
+    {
+      warn (_("Symbol table offset (%xl) is less then Address table offset (%x)\n"),
+           symbol_table_offset, address_table_offset);
+      return 0;
+    }
+
   address_table_size = symbol_table_offset - address_table_offset;
+
+  if (constant_pool_offset < symbol_table_offset)
+    {
+      warn (_("Constant pool offset (%x) is less than symbol table offset (%x)\n"),
+           constant_pool_offset, symbol_table_offset);
+      return 0;
+    }
+
   symbol_table_slots = (constant_pool_offset - symbol_table_offset) / 8;
 
   cu_list = start + cu_list_offset;
@@ -6497,6 +6667,12 @@ display_gdb_index (struct dwarf_section *section,
   symbol_table = start + symbol_table_offset;
   constant_pool = start + constant_pool_offset;
 
+  if (address_table + address_table_size * (2 + 8 + 4) > section->start + section->size)
+    {
+      warn (_("Address table extends beyond end of section.\n"));
+      return 0;
+    }
+  
   printf (_("\nCU table:\n"));
   for (i = 0; i < cu_list_elements; i += 2)
     {
@@ -6523,7 +6699,8 @@ display_gdb_index (struct dwarf_section *section,
     }
 
   printf (_("\nAddress table:\n"));
-  for (i = 0; i < address_table_size; i += 2 * 8 + 4)
+  for (i = 0; i < address_table_size && i <= address_table_size - (2 * 8 + 4);
+       i += 2 * 8 + 4)
     {
       uint64_t low = byte_get_little_endian (address_table + i, 8);
       uint64_t high = byte_get_little_endian (address_table + i + 8, 8);
@@ -6546,10 +6723,44 @@ display_gdb_index (struct dwarf_section *section,
        {
          unsigned int j;
 
-         printf ("[%3u] %s:", i, constant_pool + name_offset);
+         /* PR 17531: file: 5b7b07ad.  */
+         if (constant_pool + name_offset < constant_pool
+             || constant_pool + name_offset >= section->start + section->size)
+           {
+             printf (_("[%3u] <corrupt offset: %x>"), i, name_offset);
+             warn (_("Corrupt name offset of 0x%x found for symbol table slot %d\n"),
+                   name_offset, i);
+           }
+         else
+           printf ("[%3u] %.*s:", i,
+                   (int) (section->size - (constant_pool_offset + name_offset)),
+                   constant_pool + name_offset);
+
+         if (constant_pool + cu_vector_offset < constant_pool
+             || constant_pool + cu_vector_offset >= section->start + section->size - 3)
+           {
+             printf (_("<invalid CU vector offset: %x>\n"), cu_vector_offset);
+             warn (_("Corrupt CU vector offset of 0x%x found for symbol table slot %d\n"),
+                   cu_vector_offset, i);
+             continue;
+           }
+
          num_cus = byte_get_little_endian (constant_pool + cu_vector_offset, 4);
+
+         if (num_cus * 4 < num_cus
+             || constant_pool + cu_vector_offset + 4 + num_cus * 4
+             >= section->start + section->size
+             || (constant_pool + cu_vector_offset + 4 + num_cus * 4) < constant_pool)
+           {
+             printf ("<invalid number of CUs: %d>\n", num_cus);
+             warn (_("Invalid number of CUs (0x%x) for symbol table slot %d\n"),
+                   num_cus, i);
+             continue;
+           }
+
          if (num_cus > 1)
            printf ("\n");
+
          for (j = 0; j < num_cus; ++j)
            {
              int is_static;
@@ -6686,7 +6897,7 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
   /* PR 17512: file: 002-376-0.004.  */
   if (section->size < 24)
     {
-      warn (_("Section %s is too small to contain a CU/TU header"),
+      warn (_("Section %s is too small to contain a CU/TU header\n"),
            section->name);
       return 0;
     }
@@ -6701,6 +6912,14 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
   pindex = phash + nslots * 8;
   ppool = pindex + nslots * 4;
 
+  /* PR 17531: file: 45d69832.  */
+  if (pindex < phash || ppool < phdr)
+    {
+      warn (_("Section %s is too small for %d slots\n"),
+           section->name, nslots);
+      return 0;
+    }
+
   if (do_display)
     {
       printf (_("Contents of the %s section:\n\n"), section->name);
@@ -6732,6 +6951,13 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
            {
              SAFE_BYTE_GET (j, pindex, 4, limit);
              shndx_list = ppool + j * 4;
+             /* PR 17531: file: 705e010d.  */
+             if (shndx_list < ppool)
+               {
+                 warn (_("Section index pool located before start of section\n"));
+                 return 0;
+               }
+
              if (do_display)
                printf (_("  [%3d] Signature:  0x%s  Sections: "),
                        i, dwarf_vmatoa64 (signature_high, signature_low,
@@ -6796,13 +7022,13 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
          if (is_tu_index)
            {
              tu_count = nused;
-             tu_sets = xcmalloc (nused, sizeof (struct cu_tu_set));
+             tu_sets = xcalloc2 (nused, sizeof (struct cu_tu_set));
              this_set = tu_sets;
            }
          else
            {
              cu_count = nused;
-             cu_sets = xcmalloc (nused, sizeof (struct cu_tu_set));
+             cu_sets = xcalloc2 (nused, sizeof (struct cu_tu_set));
              this_set = cu_sets;
            }
        }
@@ -6849,7 +7075,12 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
                  else
                    {
                      SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
-                     this_set [row - 1].section_offsets [dw_sect] = val;
+
+                     /* PR 17531: file: 10796eb3.  */
+                     if (dw_sect >= DW_SECT_MAX)
+                       warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect);
+                     else
+                       this_set [row - 1].section_offsets [dw_sect] = val;
                    }
                }
 
@@ -6902,6 +7133,9 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
                  else
                    {
                      SAFE_BYTE_GET (dw_sect, ppool + j * 4, 4, limit);
+                     if (dw_sect >= DW_SECT_MAX)
+                       warn (_("Overlarge Dwarf section index detected: %u\n"), dw_sect);
+                     else
                      this_set [row - 1].section_sizes [dw_sect] = val;
                    }
                }
@@ -6986,34 +7220,69 @@ display_debug_not_supported (struct dwarf_section *section,
   return 1;
 }
 
+/* Like malloc, but takes two parameters like calloc.
+   Verifies that the first parameter is not too large.
+   Note: does *not* initialise the allocated memory to zero.  */
 void *
 cmalloc (size_t nmemb, size_t size)
 {
   /* Check for overflow.  */
   if (nmemb >= ~(size_t) 0 / size)
     return NULL;
-  else
-    return malloc (nmemb * size);
+
+  return xmalloc (nmemb * size);
 }
 
+/* Like xmalloc, but takes two parameters like calloc.
+   Verifies that the first parameter is not too large.
+   Note: does *not* initialise the allocated memory to zero.  */
 void *
 xcmalloc (size_t nmemb, size_t size)
 {
   /* Check for overflow.  */
   if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return xmalloc (nmemb * size);
+    {
+      fprintf (stderr,
+              _("Attempt to allocate an array with an excessive number of elements: 0x%lx\n"),
+              (long) nmemb);
+      xexit (1);
+    }
+
+  return xmalloc (nmemb * size);
 }
 
+/* Like xrealloc, but takes three parameters.
+   Verifies that the second parameter is not too large.
+   Note: does *not* initialise any new memory to zero.  */
 void *
 xcrealloc (void *ptr, size_t nmemb, size_t size)
 {
   /* Check for overflow.  */
   if (nmemb >= ~(size_t) 0 / size)
-    return NULL;
-  else
-    return xrealloc (ptr, nmemb * size);
+    {
+      fprintf (stderr,
+              _("Attempt to re-allocate an array with an excessive number of elements: 0x%lx\n"),
+              (long) nmemb);
+      xexit (1);
+    }
+
+  return xrealloc (ptr, nmemb * size);
+}
+
+/* Like xcalloc, but verifies that the first parameter is not too large.  */
+void *
+xcalloc2 (size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    {
+      fprintf (stderr,
+              _("Attempt to allocate a zero'ed array with an excessive number of elements: 0x%lx\n"),
+              (long) nmemb);
+      xexit (1);
+    }
+
+  return xcalloc (nmemb, size);
 }
 
 void
@@ -7041,10 +7310,9 @@ free_debug_memory (void)
                free (debug_information [i].range_lists);
            }
        }
-
       free (debug_information);
       debug_information = NULL;
-      num_debug_info_entries = 0;
+      alloc_num_debug_info_entries = num_debug_info_entries = 0;
     }
 }
 
@@ -7188,7 +7456,7 @@ dwarf_select_sections_by_letters (const char *letters)
        break;
 
       default:
-       warn (_("Unrecognized debug option '%s'\n"), optarg);
+       warn (_("Unrecognized debug option '%s'\n"), letters);
        break;
       }
 }
This page took 0.036124 seconds and 4 git commands to generate.