MIPS/opcodes: Only examine ELF file structures if SYMTAB_AVAILABLE
[deliverable/binutils-gdb.git] / binutils / dwarf.c
index c14049ac8d2aafa9c7fcbd247b0460ede6d6f79e..66ad1fd2659d0c8e693b7d35322bffae2a9e6e4b 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf.c -- display DWARF contents of a BFD binary file
-   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Copyright (C) 2005-2016 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -200,7 +200,7 @@ dwarf_vmatoa_1 (const char *fmtch, dwarf_vma value, unsigned num_bytes)
 
   if (num_bytes)
     {
-      /* Printf does not have a way of specifiying a maximum field width for an
+      /* Printf does not have a way of specifying a maximum field width for an
         integer value, so we print the full value into a buffer and then select
         the precision we need.  */
       snprintf (ret, sizeof (buf[0].place), DWARF_VMA_FMT_LONG, value);
@@ -292,7 +292,7 @@ read_leb128 (unsigned char *data,
     *length_return = num_read;
 
   if (sign && (shift < 8 * sizeof (result)) && (byte & 0x40))
-    result |= (dwarf_vma) -1 << shift;
+    result |= -((dwarf_vma) 1 << shift);
 
   return result;
 }
@@ -317,8 +317,13 @@ read_uleb128 (unsigned char * data,
 #define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END)   \
   do                                           \
     {                                          \
-      int dummy [sizeof (VAL) < (AMOUNT) ? -1 : 1] ATTRIBUTE_UNUSED ; \
       unsigned int amount = (AMOUNT);          \
+      if (sizeof (VAL) < amount)               \
+       {                                       \
+         error (_("internal error: attempt to read %d bytes of data in to %d sized variable"),\
+                amount, (int) sizeof (VAL));   \
+         amount = sizeof (VAL);                \
+       }                                       \
       if (((PTR) + amount) >= (END))           \
        {                                       \
          if ((PTR) < (END))                    \
@@ -1819,6 +1824,7 @@ read_and_display_attr_value (unsigned long attribute,
        {
        case DW_AT_frame_base:
          have_frame_base = 1;
+         /* Fall through.  */
        case DW_AT_location:
        case DW_AT_string_length:
        case DW_AT_return_addr:
@@ -2094,6 +2100,7 @@ read_and_display_attr_value (unsigned long attribute,
 
     case DW_AT_frame_base:
       have_frame_base = 1;
+      /* Fall through.  */
     case DW_AT_location:
     case DW_AT_string_length:
     case DW_AT_return_addr:
@@ -3247,16 +3254,32 @@ display_debug_lines_decoded (struct dwarf_section *section,
 
          /* Traverse the Directory table just to count entries.  */
          data = standard_opcodes + linfo.li_opcode_base - 1;
+         /* PR 20440 */
+         if (data >= end)
+           {
+             warn (_("opcode base of %d extends beyond end of section\n"),
+                   linfo.li_opcode_base);
+             return 0;
+           }
+
          if (*data != 0)
            {
              unsigned char *ptr_directory_table = data;
 
-             while (*data != 0)
+             while (data < end && *data != 0)
                {
                  data += strnlen ((char *) data, end - data) + 1;
                  n_directories++;
                }
 
+             /* PR 20440 */
+             if (data >= end)
+               {
+                 warn (_("directory table ends unexpectedly\n"));
+                 n_directories = 0;
+                 break;
+               }
+
              /* Go through the directory table again to save the directories.  */
              directory_table = (unsigned char **)
                xmalloc (n_directories * sizeof (unsigned char *));
@@ -3274,11 +3297,11 @@ display_debug_lines_decoded (struct dwarf_section *section,
          data++;
 
          /* Traverse the File Name table just to count the entries.  */
-         if (*data != 0)
+         if (data < end && *data != 0)
            {
              unsigned char *ptr_file_name_table = data;
 
-             while (*data != 0)
+             while (data < end && *data != 0)
                {
                  unsigned int bytes_read;
 
@@ -3295,6 +3318,13 @@ display_debug_lines_decoded (struct dwarf_section *section,
                  n_files++;
                }
 
+             if (data >= end)
+               {
+                 warn (_("file table ends unexpectedly\n"));
+                 n_files = 0;
+                 break;
+               }
+
              /* Go through the file table again to save the strings.  */
              file_table = (File_Entry *) xmalloc (n_files * sizeof (File_Entry));
 
@@ -3329,7 +3359,20 @@ display_debug_lines_decoded (struct dwarf_section *section,
              else
                {
                  unsigned int ix = file_table[0].directory_index;
-                 const char *directory = ix ? (char *)directory_table[ix - 1] : ".";
+                 const char *directory;
+
+                 if (ix == 0)
+                   directory = ".";
+                 /* PR 20439 */
+                 else if (n_directories == 0)
+                   directory = _("<unknown>");
+                 else if (ix > n_directories)
+                   {
+                     warn (_("directory index %u > number of directories %u\n"), ix, n_directories);
+                     directory = _("<corrupt>");
+                   }
+                 else
+                   directory = (char *) directory_table[ix - 1];
 
                  if (do_wide || strlen (directory) < 76)
                    printf (_("CU: %s/%s:\n"), directory, file_table[0].name);
@@ -3487,20 +3530,35 @@ display_debug_lines_decoded (struct dwarf_section *section,
                   data += bytes_read;
                   state_machine_regs.file = adv;
 
-                  if (file_table == NULL)
-                    printf (_("\n [Use file table entry %d]\n"), state_machine_regs.file - 1);
-                  else if (file_table[state_machine_regs.file - 1].directory_index == 0)
-                    /* If directory index is 0, that means current directory.  */
-                    printf ("\n./%s:[++]\n",
-                            file_table[state_machine_regs.file - 1].name);
-                  else if (directory_table == NULL)
-                    printf (_("\n [Use directory table entry %d]\n"),
-                            file_table[state_machine_regs.file - 1].directory_index - 1);
-                  else
-                    /* The directory index starts counting at 1.  */
-                    printf ("\n%s/%s:\n",
-                            directory_table[file_table[state_machine_regs.file - 1].directory_index - 1],
-                            file_table[state_machine_regs.file - 1].name);
+                  {
+                    unsigned file = state_machine_regs.file - 1;
+                    unsigned dir;
+
+                    if (file_table == NULL || n_files == 0)
+                      printf (_("\n [Use file table entry %d]\n"), file);
+                    /* PR 20439 */
+                    else if (file >= n_files)
+                      {
+                        warn (_("file index %u > number of files %u\n"), file + 1, n_files);
+                        printf (_("\n <over large file table index %u>"), file);
+                      }
+                    else if ((dir = file_table[file].directory_index) == 0)
+                      /* If directory index is 0, that means current directory.  */
+                      printf ("\n./%s:[++]\n", file_table[file].name);
+                    else if (directory_table == NULL || n_directories == 0)
+                      printf (_("\n [Use file %s in directory table entry %d]\n"),
+                              file_table[file].name, dir);
+                    /* PR 20439 */
+                    else if (dir > n_directories)
+                      {
+                        warn (_("directory index %u > number of directories %u\n"), dir, n_directories);
+                        printf (_("\n <over large directory table entry %u>\n"), dir);
+                      }
+                    else
+                      printf ("\n%s/%s:\n",
+                              /* The directory index starts counting at 1.  */
+                              directory_table[dir - 1], file_table[file].name);
+                  }
                   break;
 
                 case DW_LNS_set_column:
@@ -3582,9 +3640,19 @@ display_debug_lines_decoded (struct dwarf_section *section,
              size_t fileNameLength;
 
              if (file_table)
-               fileName = (char *) file_table[state_machine_regs.file - 1].name;
+               {
+                 unsigned indx = state_machine_regs.file - 1;
+                 /* PR 20439  */
+                 if (indx >= n_files)
+                   {
+                     warn (_("corrupt file index %u encountered\n"), indx);
+                     fileName = _("<corrupt>");
+                   }
+                 else
+                   fileName = (char *) file_table[indx].name;
+               }
              else
-               fileName = "<unknown>";
+               fileName = _("<unknown>");
 
              fileNameLength = strlen (fileName);
 
@@ -4326,6 +4394,16 @@ display_debug_abbrev (struct dwarf_section *section,
   return 1;
 }
 
+/* Return true when ADDR is the maximum address, when addresses are
+   POINTER_SIZE bytes long.  */
+
+static bfd_boolean
+is_max_address (dwarf_vma addr, unsigned int pointer_size)
+{
+  dwarf_vma mask = ~(~(dwarf_vma) 1 << (pointer_size * 8 - 1));
+  return ((addr & mask) == mask);
+}
+
 /* Display a location list from a normal (ie, non-dwo) .debug_loc section.  */
 
 static void
@@ -4380,10 +4458,6 @@ display_loc_list (struct dwarf_section *section,
 
       printf ("    %8.8lx ", off);
 
-      /* Note: we use sign extension here in order to be sure that we can detect
-        the -1 escape value.  Sign extension into the top 32 bits of a 32-bit
-        address will not affect the values that we display since we always show
-        hex values, and always the bottom 32-bits.  */
       SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, section_end);
       SAFE_BYTE_GET_AND_INC (end, start, pointer_size, section_end);
 
@@ -4404,7 +4478,8 @@ display_loc_list (struct dwarf_section *section,
        }
 
       /* Check base address specifiers.  */
-      if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
+      if (is_max_address (begin, pointer_size)
+          && !is_max_address (end, pointer_size))
        {
          base_address = end;
          print_dwarf_vma (begin, pointer_size);
@@ -4898,7 +4973,12 @@ display_debug_aranges (struct dwarf_section *section,
 
       if (arange.ar_version != 2 && arange.ar_version != 3)
        {
-         warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
+         /* PR 19872: A version number of 0 probably means that there is
+            padding at the end of the .debug_aranges section.  Gold puts
+            it there when performing an incremental link, for example.
+            So do not generate a warning in this case.  */
+         if (arange.ar_version)
+           warn (_("Only DWARF 2 and 3 aranges are currently supported.\n"));
          break;
        }
 
@@ -5202,11 +5282,6 @@ display_debug_ranges (struct dwarf_section *section,
          dwarf_vma begin;
          dwarf_vma end;
 
-         /* Note: we use sign extension here in order to be sure that
-            we can detect the -1 escape value.  Sign extension into the
-            top 32 bits of a 32-bit address will not affect the values
-            that we display since we always show hex values, and always
-            the bottom 32-bits.  */
          SAFE_BYTE_GET_AND_INC (begin, start, pointer_size, finish);
          if (start >= finish)
            break;
@@ -5221,7 +5296,8 @@ display_debug_ranges (struct dwarf_section *section,
            }
 
          /* Check base address specifiers.  */
-         if (begin == (dwarf_vma) -1 && end != (dwarf_vma) -1)
+          if (is_max_address (begin, pointer_size)
+              && !is_max_address (end, pointer_size))
            {
              base_address = end;
              print_dwarf_vma (begin, pointer_size);
@@ -5451,6 +5527,30 @@ init_dwarf_regnames_aarch64 (void)
   dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_aarch64);
 }
 
+static const char *const dwarf_regnames_s390[] =
+{
+  /* Avoid saying "r5 (r5)", so omit the names of r0-r15.  */
+  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
+  "f0",  "f2",  "f4",  "f6",  "f1",  "f3",  "f5",  "f7",
+  "f8",  "f10", "f12", "f14", "f9",  "f11", "f13", "f15",
+  "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7",
+  "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",
+  "a0",  "a1",  "a2",  "a3",  "a4",  "a5",  "a6",  "a7",
+  "a8",  "a9",  "a10", "a11", "a12", "a13", "a14", "a15",
+  "pswm", "pswa",
+  NULL, NULL,
+  "v16", "v18", "v20", "v22", "v17", "v19", "v21", "v23",
+  "v24", "v26", "v28", "v30", "v25", "v27", "v29", "v31",
+};
+
+void
+init_dwarf_regnames_s390 (void)
+{
+  dwarf_regnames = dwarf_regnames_s390;
+  dwarf_regnames_count = ARRAY_SIZE (dwarf_regnames_s390);
+}
+
 void
 init_dwarf_regnames (unsigned int e_machine)
 {
@@ -5474,6 +5574,10 @@ init_dwarf_regnames (unsigned int e_machine)
       init_dwarf_regnames_aarch64 ();
       break;
 
+    case EM_S390:
+      init_dwarf_regnames_s390 ();
+      break;
+
     default:
       break;
     }
@@ -5503,7 +5607,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg
   unsigned int r;
   char tmp[100];
 
-  if (*max_regs < fc->ncols)
+  if (*max_regs != fc->ncols)
     *max_regs = fc->ncols;
 
   if (*need_col_headers)
@@ -5518,7 +5622,7 @@ frame_display_row (Frame_Chunk *fc, int *need_col_headers, unsigned int *max_reg
        if (fc->col_type[r] != DW_CFA_unreferenced)
          {
            if (r == fc->ra)
-             printf ("ra      ");
+             printf ("ra    ");
            else
              printf ("%-5s ", regname (r, 1));
          }
@@ -5739,6 +5843,7 @@ display_debug_frames (struct dwarf_section *section,
       unsigned int encoded_ptr_size = saved_eh_addr_size;
       unsigned int offset_size;
       unsigned int initial_length_size;
+      bfd_boolean all_nops;
 
       saved_start = start;
 
@@ -6172,6 +6277,8 @@ display_debug_frames (struct dwarf_section *section,
          start = tmp;
        }
 
+      all_nops = TRUE;
+
       /* Now we know what registers are used, make a second pass over
         the chunk, this time actually printing out the info.  */
 
@@ -6190,6 +6297,10 @@ display_debug_frames (struct dwarf_section *section,
          if (op & 0xc0)
            op &= 0xc0;
 
+         /* Make a note if something other than DW_CFA_nop happens.  */
+         if (op != DW_CFA_nop)
+           all_nops = FALSE;
+
          /* Warning: if you add any more cases to this switch, be
             sure to add them to the corresponding switch above.  */
          switch (op)
@@ -6222,19 +6333,25 @@ display_debug_frames (struct dwarf_section *section,
              break;
 
            case DW_CFA_restore:
-             if (opa >= (unsigned int) cie->ncols
-                 || opa >= (unsigned int) fc->ncols)
+             if (opa >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_restore: %s%s\n",
                        reg_prefix, regname (opa, 0));
-             if (*reg_prefix == '\0')
+             if (*reg_prefix != '\0')
+               break;
+
+             if (opa >= (unsigned int) cie->ncols
+                 || (do_debug_frames_interp
+                     && cie->col_type[opa] == DW_CFA_unreferenced))
+               {
+                 fc->col_type[opa] = DW_CFA_undefined;
+                 fc->col_offset[opa] = 0;
+               }
+             else
                {
                  fc->col_type[opa] = cie->col_type[opa];
                  fc->col_offset[opa] = cie->col_offset[opa];
-                 if (do_debug_frames_interp
-                     && fc->col_type[opa] == DW_CFA_unreferenced)
-                   fc->col_type[opa] = DW_CFA_undefined;
                }
              break;
 
@@ -6309,7 +6426,7 @@ display_debug_frames (struct dwarf_section *section,
              if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
-               printf ("  DW_CFA_val_offset: %s%s at cfa%+ld\n",
+               printf ("  DW_CFA_val_offset: %s%s is cfa%+ld\n",
                        reg_prefix, regname (reg, 0),
                        roffs * fc->data_factor);
              if (*reg_prefix == '\0')
@@ -6321,13 +6438,20 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_restore_extended:
              reg = LEB ();
-             if (reg >= (unsigned int) cie->ncols
-                 || reg >= (unsigned int) fc->ncols)
+             if (reg >= (unsigned int) fc->ncols)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
                printf ("  DW_CFA_restore_extended: %s%s\n",
                        reg_prefix, regname (reg, 0));
-             if (*reg_prefix == '\0')
+             if (*reg_prefix != '\0')
+               break;
+
+             if (reg >= (unsigned int) cie->ncols)
+               {
+                 fc->col_type[reg] = DW_CFA_undefined;
+                 fc->col_offset[reg] = 0;
+               }
+             else
                {
                  fc->col_type[reg] = cie->col_type[reg];
                  fc->col_offset[reg] = cie->col_offset[reg];
@@ -6456,7 +6580,7 @@ display_debug_frames (struct dwarf_section *section,
 
            case DW_CFA_def_cfa_expression:
              ul = LEB ();
-             if (start >= block_end || start + ul > block_end || start + ul < start)
+             if (start >= block_end || ul > (unsigned long) (block_end - start))
                {
                  printf (_("  DW_CFA_def_cfa_expression: <corrupt len %lu>\n"), ul);
                  break;
@@ -6544,7 +6668,7 @@ display_debug_frames (struct dwarf_section *section,
              if (frame_need_space (fc, reg) < 0)
                reg_prefix = bad_reg;
              if (! do_debug_frames_interp || *reg_prefix != '\0')
-               printf ("  DW_CFA_val_offset_sf: %s%s at cfa%+ld\n",
+               printf ("  DW_CFA_val_offset_sf: %s%s is cfa%+ld\n",
                        reg_prefix, regname (reg, 0),
                        (long)(l * fc->data_factor));
              if (*reg_prefix == '\0')
@@ -6620,7 +6744,8 @@ display_debug_frames (struct dwarf_section *section,
            }
        }
 
-      if (do_debug_frames_interp)
+      /* Interpret the CFA - as long as it is not completely full of NOPs.  */
+      if (do_debug_frames_interp && ! all_nops)
        frame_display_row (fc, &need_col_headers, &max_regs);
 
       start = block_end;
@@ -7438,7 +7563,7 @@ dwarf_select_sections_by_names (const char *names)
       { "macro", & do_debug_macinfo, 1 },
       { "pubnames", & do_debug_pubnames, 1 },
       { "pubtypes", & do_debug_pubtypes, 1 },
-      /* This entry is for compatability
+      /* This entry is for compatibility
         with earlier versions of readelf.  */
       { "ranges", & do_debug_aranges, 1 },
       { "rawline", & do_debug_lines, FLAG_DEBUG_LINES_RAW },
@@ -7531,6 +7656,7 @@ dwarf_select_sections_by_letters (const char *letters)
 
       case 'F':
        do_debug_frames_interp = 1;
+       /* Fall through.  */
       case 'f':
        do_debug_frames = 1;
        break;
This page took 0.030192 seconds and 4 git commands to generate.