Don't use bfd_get_file_size in objdump
[deliverable/binutils-gdb.git] / binutils / dwarf.c
index 6aca9b79942b5593b6ab445795d5b50b8f973bed..9f17af9ff823bc1517118c8d58b9cc42431bcbad 100644 (file)
@@ -1,5 +1,5 @@
 /* dwarf.c -- display DWARF contents of a BFD binary file
-   Copyright (C) 2005-2018 Free Software Foundation, Inc.
+   Copyright (C) 2005-2019 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -48,11 +48,26 @@ static debug_info *debug_information = NULL;
    that the .debug_info section could not be loaded/parsed.  */
 #define DEBUG_INFO_UNAVAILABLE  (unsigned int) -1
 
-static const char *           dwo_name;
-static const char *           dwo_dir;
-static const unsigned char *  dwo_id;
-static bfd_size_type          dwo_id_len;
-static bfd_boolean            need_dwo_info;
+/* A .debug_info section can contain multiple links to separate
+   DWO object files.  We use these structures to record these links.  */
+typedef enum dwo_type
+{
+ DWO_NAME,
+ DWO_DIR,
+ DWO_ID
+} dwo_type;
+
+typedef struct dwo_info
+{
+  dwo_type          type;
+  const char *      value;
+  struct dwo_info * next;
+} dwo_info;
+
+static dwo_info *   first_dwo_info = NULL;
+static bfd_boolean  need_dwo_info;
+
+separate_info * first_separate_info = NULL;
 
 unsigned int eh_addr_size;
 
@@ -96,10 +111,6 @@ static unsigned int *shndx_pool = NULL;
 static unsigned int shndx_pool_size = 0;
 static unsigned int shndx_pool_used = 0;
 
-/* Pointer to a separate file containing extra debug information.  */
-static void * separate_debug_file = NULL;
-static const char * separate_debug_filename = NULL;
-
 /* For version 2 package files, each set contains an array of section offsets
    and an array of section sizes, giving the offset and size of the
    contribution from a CU or TU within one of the debug sections.
@@ -387,6 +398,9 @@ read_uleb128 (unsigned char * data,
     }                                                          \
   while (0)
 
+/* Read AMOUNT bytes from PTR and store them in VAL as an unsigned value.
+   Checks to make sure that the read will not reach or pass END
+   and that VAL is big enough to hold AMOUNT bytes.  */
 #define SAFE_BYTE_GET(VAL, PTR, AMOUNT, END)   \
   do                                           \
     {                                          \
@@ -415,6 +429,7 @@ read_uleb128 (unsigned char * data,
     }                                          \
   while (0)
 
+/* Like SAFE_BYTE_GET, but also increments PTR by AMOUNT.  */
 #define SAFE_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END)   \
   do                                                   \
     {                                                  \
@@ -423,6 +438,7 @@ read_uleb128 (unsigned char * data,
     }                                                  \
   while (0)
 
+/* Like SAFE_BYTE_GET, but reads a signed value.  */
 #define SAFE_SIGNED_BYTE_GET(VAL, PTR, AMOUNT, END)    \
   do                                                   \
     {                                                  \
@@ -441,6 +457,7 @@ read_uleb128 (unsigned char * data,
     }                                                  \
   while (0)
 
+/* Like SAFE_SIGNED_BYTE_GET, but also increments PTR by AMOUNT.  */
 #define SAFE_SIGNED_BYTE_GET_AND_INC(VAL, PTR, AMOUNT, END)    \
   do                                                           \
     {                                                          \
@@ -1569,6 +1586,25 @@ decode_location_expression (unsigned char * data,
          data += bytes_read;
          printf ("DW_OP_GNU_const_index <0x%s>", dwarf_vmatoa ("x", uvalue));
          break;
+       case DW_OP_GNU_variable_value:
+         /* FIXME: Strictly speaking for 64-bit DWARF3 files
+            this ought to be an 8-byte wide computation.  */
+         if (dwarf_version == -1)
+           {
+             printf (_("(DW_OP_GNU_variable_value in frame info)"));
+             /* No way to tell where the next op is, so just bail.  */
+             return need_frame_base;
+           }
+         if (dwarf_version == 2)
+           {
+             SAFE_BYTE_GET_AND_INC (uvalue, data, pointer_size, end);
+           }
+         else
+           {
+             SAFE_BYTE_GET_AND_INC (uvalue, data, offset_size, end);
+           }
+         printf ("DW_OP_GNU_variable_value: <0x%s>", dwarf_vmatoa ("x", uvalue));
+         break;
 
          /* HP extensions.  */
        case DW_OP_HP_is_value:
@@ -1686,37 +1722,44 @@ add64 (dwarf_vma * high_bits, dwarf_vma * low_bits, dwarf_vma inc)
 static const char *
 fetch_alt_indirect_string (dwarf_vma offset)
 {
-  struct dwarf_section * section;
-  const char *           ret;
+  separate_info * i;
 
   if (! do_follow_links)
     return "";
 
-  if (separate_debug_file == NULL)
-    return _("<following link not possible>");
+  if (first_separate_info == NULL)
+    return _("<no links available>");
 
-  if (! load_debug_section (separate_debug_str, separate_debug_file))
-    return _("<could not load separate string section>");
+  for (i = first_separate_info; i != NULL; i = i->next)
+    {
+      struct dwarf_section * section;
+      const char *           ret;
 
-  section = &debug_displays [separate_debug_str].section;
-  if (section->start == NULL)
-    return  _("<no .debug_str section>");
+      if (! load_debug_section (separate_debug_str, i->handle))
+       continue;
 
-  if (offset >= section->size)
-    {
-      warn (_("DW_FORM_GNU_strp_alt offset too big: %s\n"), dwarf_vmatoa ("x", offset));
-      return _("<offset is too big>");
-    }
+      section = &debug_displays [separate_debug_str].section;
 
-  ret = (const char *) (section->start + offset);
-  /* Unfortunately we cannot rely upon the .debug_str section ending with a
-     NUL byte.  Since our caller is expecting to receive a well formed C
-     string we test for the lack of a terminating byte here.  */
-  if (strnlen ((const char *) ret, section->size - offset)
-      == section->size - offset)
-    return _("<no NUL byte at end of .debug_str section>");
+      if (section->start == NULL)
+       continue;
 
-  return ret;
+      if (offset >= section->size)
+       continue;
+
+      ret = (const char *) (section->start + offset);
+      /* Unfortunately we cannot rely upon the .debug_str section ending with a
+        NUL byte.  Since our caller is expecting to receive a well formed C
+        string we test for the lack of a terminating byte here.  */
+      if (strnlen ((const char *) ret, section->size - offset)
+         == section->size - offset)
+       return _("<no NUL byte at end of alt .debug_str section>");
+
+      return ret;
+    }
+  
+  warn (_("DW_FORM_GNU_strp_alt offset (%s) too big or no string sections available\n"),
+       dwarf_vmatoa ("x", offset));
+  return _("<offset is too big>");
 }
        
 static const char *
@@ -1745,6 +1788,49 @@ get_AT_name (unsigned long attribute)
   return name;
 }
 
+static void
+add_dwo_info (const char * field, dwo_type type)
+{
+  dwo_info * dwinfo = xmalloc (sizeof * dwinfo);
+
+  dwinfo->type = type;
+  dwinfo->value = field;
+  dwinfo->next = first_dwo_info;
+  first_dwo_info = dwinfo;
+}
+
+static void
+add_dwo_name (const char * name)
+{
+  add_dwo_info (name, DWO_NAME);
+}
+
+static void
+add_dwo_dir (const char * dir)
+{
+  add_dwo_info (dir, DWO_DIR);
+}
+
+static void
+add_dwo_id (const char * id)
+{
+  add_dwo_info (id, DWO_ID);
+}
+
+static void
+free_dwo_info (void)
+{
+  dwo_info * dwinfo;
+  dwo_info * next;
+
+  for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = next)
+    {
+      next = dwinfo->next;
+      free (dwinfo);
+    }
+  first_dwo_info = NULL;
+}
+
 static unsigned char *
 read_and_display_attr_value (unsigned long           attribute,
                             unsigned long           form,
@@ -2168,19 +2254,28 @@ read_and_display_attr_value (unsigned long           attribute,
              debug_info_p->have_frame_base [num] = have_frame_base;
              if (attribute != DW_AT_GNU_locviews)
                {
-                 debug_info_p->loc_offsets [num] = uvalue;
-                 debug_info_p->num_loc_offsets++;
-                 assert (debug_info_p->num_loc_offsets
-                         - debug_info_p->num_loc_views <= 1);
+                 /* Corrupt DWARF info can produce more offsets than views.
+                    See PR 23062 for an example.  */
+                 if (debug_info_p->num_loc_offsets
+                     > debug_info_p->num_loc_views)
+                   warn (_("More location offset attributes than DW_AT_GNU_locview attributes\n"));
+                 else
+                   {
+                     debug_info_p->loc_offsets [num] = uvalue;
+                     debug_info_p->num_loc_offsets++;
+                   }
                }
              else
                {
                  assert (debug_info_p->num_loc_views <= num);
                  num = debug_info_p->num_loc_views;
-                 debug_info_p->loc_views [num] = uvalue;
-                 debug_info_p->num_loc_views++;
-                 assert (debug_info_p->num_loc_views
-                         - debug_info_p->num_loc_offsets <= 1);
+                 if (num > debug_info_p->num_loc_offsets)
+                   warn (_("More DW_AT_GNU_locview attributes than location offset attributes\n"));
+                 else
+                   {
+                     debug_info_p->loc_views [num] = uvalue;
+                     debug_info_p->num_loc_views++;
+                   }
                }
            }
          break;
@@ -2226,18 +2321,17 @@ read_and_display_attr_value (unsigned long           attribute,
            switch (form)
              {
              case DW_FORM_strp:
-               dwo_name = (const char *) fetch_indirect_string (uvalue);
+               add_dwo_name ((const char *) fetch_indirect_string (uvalue));
                break;
              case DW_FORM_GNU_str_index:
-               dwo_name = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+               add_dwo_name (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
                break;
              case DW_FORM_string:
-               dwo_name = (const char *) orig_data;
+               add_dwo_name ((const char *) orig_data);
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
                      get_FORM_name (form), get_AT_name (attribute));
-               dwo_name = _("<unknown>");
                break;
              }
          break;
@@ -2248,21 +2342,20 @@ read_and_display_attr_value (unsigned long           attribute,
            switch (form)
              {
              case DW_FORM_strp:
-               dwo_dir = (const char *) fetch_indirect_string (uvalue);
+               add_dwo_dir ((const char *) fetch_indirect_string (uvalue));
                break;
              case DW_FORM_line_strp:
-               dwo_dir = (const char *) fetch_indirect_line_string (uvalue);
+               add_dwo_dir ((const char *) fetch_indirect_line_string (uvalue));
                break;
              case DW_FORM_GNU_str_index:
-               dwo_dir = fetch_indexed_string (uvalue, this_set, offset_size, FALSE);
+               add_dwo_dir (fetch_indexed_string (uvalue, this_set, offset_size, FALSE));
                break;
              case DW_FORM_string:
-               dwo_dir = (const char *) orig_data;
+               add_dwo_dir ((const char *) orig_data);
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
                      get_FORM_name (form), get_AT_name (attribute));
-               dwo_dir = _("<unknown>");
                break;
              }
          break;
@@ -2272,13 +2365,12 @@ read_and_display_attr_value (unsigned long           attribute,
            switch (form)
              {
              case DW_FORM_data8:
-               dwo_id = data - 8;
-               dwo_id_len = 8;
+               /* FIXME: Record the length of the ID as well ?  */
+               add_dwo_id ((const char *) (data - 8));
                break;
              default:
                warn (_("Unsupported form (%s) for attribute %s\n"),
                      get_FORM_name (form), get_AT_name (attribute));
-               dwo_id = NULL;
                break;
              }
          break;
@@ -2346,12 +2438,22 @@ read_and_display_attr_value (unsigned long           attribute,
          /* DWARF 4 values.  */
        case DW_LANG_Python:            printf ("(Python)"); break;
          /* DWARF 5 values.  */
+       case DW_LANG_OpenCL:            printf ("(OpenCL)"); break;
        case DW_LANG_Go:                printf ("(Go)"); break;
+       case DW_LANG_Modula3:           printf ("(Modula 3)"); break;
+       case DW_LANG_Haskell:           printf ("(Haskell)"); break;
+       case DW_LANG_C_plus_plus_03:    printf ("(C++03)"); break;
        case DW_LANG_C_plus_plus_11:    printf ("(C++11)"); break;
+       case DW_LANG_OCaml:             printf ("(OCaml)"); break;
+       case DW_LANG_Rust:              printf ("(Rust)"); break;
        case DW_LANG_C11:               printf ("(C11)"); break;
+       case DW_LANG_Swift:             printf ("(Swift)"); break;
+       case DW_LANG_Julia:             printf ("(Julia)"); break;
+       case DW_LANG_Dylan:             printf ("(Dylan)"); 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;
+       case DW_LANG_RenderScript:      printf ("(RenderScript)"); break;
          /* MIPS extension.  */
        case DW_LANG_Mips_Assembler:    printf ("(MIPS assembler)"); break;
          /* UPC extension.  */
@@ -2678,30 +2780,47 @@ read_and_display_attr (unsigned long           attribute,
 }
 
 /* Like load_debug_section, but if the ordinary call fails, and we are
-   following debug links, and we have been able to load a separate debug
-   info file, then attempt to load the requested section from the separate
-   file.  */
+   following debug links, then attempt to load the requested section
+   from one of the separate debug info files.  */
 
 static bfd_boolean
 load_debug_section_with_follow (enum dwarf_section_display_enum sec_enum,
-                               void * data)
+                               void * handle)
 {
-  if (load_debug_section (sec_enum, data))
+  if (load_debug_section (sec_enum, handle))
     {
-      if (data == separate_debug_file)
-       debug_displays[sec_enum].section.filename = separate_debug_filename;
-       
-      /* FIXME: We should check to see if there is a separate debug info file
-        that also contains this section, and if so, issue a warning.  */
+      if (debug_displays[sec_enum].section.filename == NULL)
+       {
+         /* See if we can associate a filename with this section.  */
+         separate_info * i;
+
+         for (i = first_separate_info; i != NULL; i = i->next)
+           if (i->handle == handle)
+             {
+               debug_displays[sec_enum].section.filename = i->filename;
+               break;
+             }
+       }
+
       return TRUE;
     }
 
-  if (do_follow_links && separate_debug_file != NULL)
-    if (load_debug_section (sec_enum, separate_debug_file))
-      {
-       debug_displays[sec_enum].section.filename = separate_debug_filename;
-       return TRUE;
-      }
+  if (do_follow_links)
+    {
+      separate_info * i;
+
+      for (i = first_separate_info; i != NULL; i = i->next)
+       {
+         if (load_debug_section (sec_enum, i->handle))
+           {
+             debug_displays[sec_enum].section.filename = i->filename;
+
+             /* FIXME: We should check to see if any of the remaining debug info
+                files also contain this section, and, umm, do something about it.  */
+             return TRUE;
+           }
+       }
+    }
 
   return FALSE;
 }
@@ -3399,7 +3518,7 @@ display_formatted_table (unsigned char *                   data,
                         unsigned char *                   end,
                         const DWARF2_Internal_LineInfo *  linfo,
                         struct dwarf_section *            section,
-                        const char *                      what)
+                        bfd_boolean                       is_dir)
 {
   unsigned char *format_start, format_count, *format, formati;
   dwarf_vma data_count, datai;
@@ -3415,7 +3534,10 @@ display_formatted_table (unsigned char *                   data,
       data += bytes_read;
       if (data == end)
        {
-         warn (_("Corrupt %s format table entry\n"), what);
+         if (is_dir)
+           warn (_("Corrupt directory format table entry\n"));
+         else
+           warn (_("Corrupt file name format table entry\n"));
          return data;
        }
     }
@@ -3424,18 +3546,28 @@ display_formatted_table (unsigned char *                   data,
   data += bytes_read;
   if (data == end)
     {
-      warn (_("Corrupt %s list\n"), what);
+      if (is_dir)
+       warn (_("Corrupt directory list\n"));
+      else
+       warn (_("Corrupt file name list\n"));
       return data;
     }
 
   if (data_count == 0)
     {
-      printf (_("\n The %s Table is empty.\n"), what);
+      if (is_dir)
+       printf (_("\n The Directory Table is empty.\n"));
+      else
+       printf (_("\n The File Name Table is empty.\n"));
       return data;
     }
 
-  printf (_("\n The %s Table (offset 0x%lx):\n"), what,
-         (long)(data - start));
+  if (is_dir)
+    printf (_("\n The Directory Table (offset 0x%lx):\n"),
+           (long) (data - start));
+  else
+    printf (_("\n The File Name Table (offset 0x%lx):\n"),
+           (long) (data - start));
 
   printf (_("  Entry"));
   /* Delay displaying name as the last entry for better screen layout.  */ 
@@ -3503,7 +3635,10 @@ display_formatted_table (unsigned char *                   data,
        }
       if (data == end)
        {
-         warn (_("Corrupt %s entries list\n"), what);
+         if (is_dir)
+           warn (_("Corrupt directory entries list\n"));
+         else
+           warn (_("Corrupt file name entries list\n"));
          return data;
        }
       putchar ('\n');
@@ -3611,9 +3746,9 @@ display_debug_lines_raw (struct dwarf_section *  section,
              load_debug_section_with_follow (line_str, file);
 
              data = display_formatted_table (data, start, end, &linfo, section,
-                                             _("Directory"));
+                                             TRUE);
              data = display_formatted_table (data, start, end, &linfo, section,
-                                             _("File name"));
+                                             FALSE);
            }
          else
            {
@@ -4297,7 +4432,7 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                printf ("%s:\n", file_table[0].name);
            }
 
-         printf (_("File name                            Line number    Starting address    View\n"));
+         printf (_("File name                            Line number    Starting address    View    Stmt\n"));
          saved_linfo = linfo;
        }
 
@@ -4635,9 +4770,14 @@ display_debug_lines_decoded (struct dwarf_section *  section,
                }
 
              if (state_machine_regs.view)
-               printf ("  %6u\n", state_machine_regs.view);
+               printf ("  %6u", state_machine_regs.view);
              else
-               putchar ('\n');
+               printf ("        ");
+
+             if (state_machine_regs.is_stmt)
+               printf ("       x");
+
+             putchar ('\n');
              state_machine_regs.view++;
 
              if (xop == -DW_LNE_end_sequence)
@@ -5938,12 +6078,12 @@ display_debug_loc (struct dwarf_section *section, void *file)
   unsigned char *next = start, *vnext = vstart;
   unsigned int *array = NULL;
   const char *suffix = strrchr (section->name, '.');
-  int is_dwo = 0;
+  bfd_boolean is_dwo = FALSE;
   int is_loclists = strstr (section->name, "debug_loclists") != NULL;
   dwarf_vma expected_start = 0;
 
   if (suffix && strcmp (suffix, ".dwo") == 0)
-    is_dwo = 1;
+    is_dwo = TRUE;
 
   bytes = section->size;
 
@@ -6489,6 +6629,7 @@ display_debug_addr (struct dwarf_section *section,
 }
 
 /* Display the .debug_str_offsets and .debug_str_offsets.dwo sections.  */
+
 static int
 display_debug_str_offsets (struct dwarf_section *section,
                           void *file ATTRIBUTE_UNUSED)
@@ -6543,6 +6684,7 @@ display_debug_ranges_list (unsigned char *start, unsigned char *finish,
        break;
       SAFE_SIGNED_BYTE_GET_AND_INC (end, start, pointer_size, finish);
 
+      
       printf ("    %8.8lx ", offset);
 
       if (begin == 0 && end == 0)
@@ -6810,6 +6952,13 @@ display_debug_ranges (struct dwarf_section *section,
          continue;
        }
 
+      if (next < section_begin || next >= finish)
+       {
+         warn (_("Corrupt offset (%#8.8lx) in range entry %u\n"),
+               (unsigned long) offset, i);
+         continue;
+       }
+
       if (dwarf_check != 0 && i > 0)
        {
          if (start < next)
@@ -6825,6 +6974,7 @@ display_debug_ranges (struct dwarf_section *section,
                    (unsigned long) (next - section_begin), section->name);
            }
        }
+
       start = next;
       last_start = next;
 
@@ -7249,7 +7399,7 @@ read_cie (unsigned char *start, unsigned char *end,
   if (start == end)
     {
       warn (_("No terminator for augmentation name\n"));
-      return start;
+      goto fail;
     }
 
   if (strcmp (fc->augmentation, "eh") == 0)
@@ -7261,7 +7411,7 @@ read_cie (unsigned char *start, unsigned char *end,
       if (fc->ptr_size < 1 || fc->ptr_size > 8)
        {
          warn (_("Invalid pointer size (%d) in CIE data\n"), fc->ptr_size);
-         return end;
+         goto fail;
        }
 
       GET (fc->segment_size, 1);
@@ -7269,7 +7419,7 @@ read_cie (unsigned char *start, unsigned char *end,
       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;
+         goto fail;
        }
 
       eh_addr_size = fc->ptr_size;
@@ -7279,8 +7429,10 @@ read_cie (unsigned char *start, unsigned char *end,
       fc->ptr_size = eh_addr_size;
       fc->segment_size = 0;
     }
+
   READ_ULEB (fc->code_factor);
   READ_SLEB (fc->data_factor);
+
   if (version == 1)
     {
       GET (fc->ra, 1);
@@ -7300,7 +7452,7 @@ read_cie (unsigned char *start, unsigned char *end,
          warn (_("Augmentation data too long: 0x%s, expected at most %#lx\n"),
                dwarf_vmatoa ("x", augmentation_data_len),
                (unsigned long) (end - start));
-         return end;
+         goto fail;
        }
       start += augmentation_data_len;
     }
@@ -7325,6 +7477,8 @@ read_cie (unsigned char *start, unsigned char *end,
            fc->fde_encoding = *q++;
          else if (*p == 'S')
            ;
+         else if (*p == 'B')
+           ;
          else
            break;
          p++;
@@ -7342,6 +7496,12 @@ read_cie (unsigned char *start, unsigned char *end,
       *p_aug = augmentation_data;
     }
   return start;
+
+ fail:
+  free (fc->col_offset);
+  free (fc->col_type);
+  free (fc);
+  return end;
 }
 
 /* Prints out the contents on the DATA array formatted as unsigned bytes.
@@ -7387,10 +7547,10 @@ display_debug_frames (struct dwarf_section *section,
   unsigned char *start = section->start;
   unsigned char *end = start + section->size;
   unsigned char *section_start = start;
-  Frame_Chunk *chunks = 0, *forward_refs = 0;
-  Frame_Chunk *remembered_state = 0;
+  Frame_Chunk *chunks = NULL, *forward_refs = NULL;
+  Frame_Chunk *remembered_state = NULL;
   Frame_Chunk *rs;
-  int is_eh = strcmp (section->name, ".eh_frame") == 0;
+  bfd_boolean is_eh = strcmp (section->name, ".eh_frame") == 0;
   unsigned int length_return;
   unsigned int max_regs = 0;
   const char *bad_reg = _("bad register: ");
@@ -8323,6 +8483,36 @@ display_debug_frames (struct dwarf_section *section,
 
   printf ("\n");
 
+  while (remembered_state != NULL)
+    {
+      rs = remembered_state;
+      remembered_state = rs->next;
+      free (rs->col_type);
+      free (rs->col_offset);
+      rs->next = NULL; /* Paranoia.  */
+      free (rs);
+    }
+
+  while (chunks != NULL)
+    {
+      rs = chunks;
+      chunks = rs->next;
+      free (rs->col_type);
+      free (rs->col_offset);
+      rs->next = NULL; /* Paranoia.  */
+      free (rs);
+    }
+
+  while (forward_refs != NULL)
+    {
+      rs = forward_refs;
+      forward_refs = rs->next;
+      free (rs->col_type);
+      free (rs->col_offset);
+      rs->next = NULL; /* Paranoia.  */
+      free (rs);
+    }
+
   return 1;
 }
 
@@ -9262,7 +9452,18 @@ process_cu_tu_index (struct dwarf_section *section, int do_display)
                }
 
              if (!do_display)
-               memcpy (&this_set[row - 1].signature, ph, sizeof (uint64_t));
+               {
+                 size_t num_copy = sizeof (uint64_t);
+
+                 /* PR 23064: Beware of buffer overflow.  */
+                 if (ph + num_copy < limit)
+                   memcpy (&this_set[row - 1].signature, ph, num_copy);
+                 else
+                   {
+                     warn (_("Signature (%p) extends beyond end of space in section\n"), ph);
+                     return 0;
+                   }
+               }
 
              prow = poffsets + (row - 1) * ncols * 4;
              /* PR 17531: file: b8ce60a8.  */
@@ -9625,6 +9826,7 @@ parse_gnu_debuglink (struct dwarf_section * section, void * data)
      The CRC value is stored after the filename, aligned up to 4 bytes.  */
   name = (const char *) section->start;
 
+  
   crc_offset = strnlen (name, section->size) + 1;
   crc_offset = (crc_offset + 3) & ~3;
   if (crc_offset + 4 > section->size)
@@ -9686,6 +9888,17 @@ parse_gnu_debugaltlink (struct dwarf_section * section, void * data)
   return name;
 }
 
+static void
+add_separate_debug_file (const char * filename, void * handle)
+{
+  separate_info * i = xmalloc (sizeof * i);
+
+  i->filename = filename;
+  i->handle   = handle;
+  i->next     = first_separate_info;
+  first_separate_info = i;
+}
+
 static void *
 load_separate_debug_info (const char *            main_filename,
                          struct dwarf_section *  xlink,
@@ -9694,7 +9907,7 @@ load_separate_debug_info (const char *            main_filename,
                          void *                  func_data)
 {
   const char *   separate_filename;
-  char *         debugfile;
+  char *         debug_filename;
   char *         canon_dir;
   size_t         canon_dirlen;
   size_t         dirlen;
@@ -9726,189 +9939,226 @@ load_separate_debug_info (const char *            main_filename,
 #define EXTRA_DEBUG_ROOT2 "/usr/lib/debug/usr"
 #endif
 
-  debugfile = (char *) malloc (strlen (DEBUGDIR) + 1
-                              + canon_dirlen
-                              + strlen (".debug/")
+  debug_filename = (char *) malloc (strlen (DEBUGDIR) + 1
+                                   + canon_dirlen
+                                   + strlen (".debug/")
 #ifdef EXTRA_DEBUG_ROOT1
-                              + strlen (EXTRA_DEBUG_ROOT1)
+                                   + strlen (EXTRA_DEBUG_ROOT1)
 #endif
 #ifdef EXTRA_DEBUG_ROOT2
-                              + strlen (EXTRA_DEBUG_ROOT2)
+                                   + strlen (EXTRA_DEBUG_ROOT2)
 #endif
-                              + strlen (separate_filename)
-                              + 1);
-  if (debugfile == NULL)
+                                   + strlen (separate_filename)
+                                   + 1);
+  if (debug_filename == NULL)
     {
       warn (_("Out of memory"));
+      free (canon_dir);
       return NULL;
     }
 
   /* First try in the current directory.  */
-  sprintf (debugfile, "%s", separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s", separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* Then try in a subdirectory called .debug.  */
-  sprintf (debugfile, ".debug/%s", separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, ".debug/%s", separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* Then try in the same directory as the original file.  */
-  sprintf (debugfile, "%s%s", canon_dir, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* And the .debug subdirectory of that directory.  */
-  sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 
 #ifdef EXTRA_DEBUG_ROOT1
   /* Try the first extra debug file root.  */
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
+  if (check_func (debug_filename, func_data))
+    goto found;
+
+  /* Try the first extra debug file root.  */
+  sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 #endif
 
 #ifdef EXTRA_DEBUG_ROOT2
   /* Try the second extra debug file root.  */
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
-  if (check_func (debugfile, func_data))
+  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
+  if (check_func (debug_filename, func_data))
     goto found;
 #endif
 
-  /* Then try in the global debugfile directory.  */
-  strcpy (debugfile, DEBUGDIR);
+  /* Then try in the global debug_filename directory.  */
+  strcpy (debug_filename, DEBUGDIR);
   dirlen = strlen (DEBUGDIR) - 1;
   if (dirlen > 0 && DEBUGDIR[dirlen] != '/')
-    strcat (debugfile, "/");
-  strcat (debugfile, (const char *) separate_filename);
+    strcat (debug_filename, "/");
+  strcat (debug_filename, (const char *) separate_filename);
 
-  if (check_func (debugfile, func_data))
+  if (check_func (debug_filename, func_data))
     goto found;
 
   /* Failed to find the file.  */
   warn (_("could not find separate debug file '%s'\n"), separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  warn (_("tried: %s\n"), debug_filename);
 
 #ifdef EXTRA_DEBUG_ROOT2
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT2, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 #endif
 
 #ifdef EXTRA_DEBUG_ROOT1
-  sprintf (debugfile, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s/%s/%s", EXTRA_DEBUG_ROOT1, canon_dir, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
+
+  sprintf (debug_filename, "%s/%s", EXTRA_DEBUG_ROOT1, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 #endif
 
-  sprintf (debugfile, "%s.debug/%s", canon_dir, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s.debug/%s", canon_dir, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debugfile, "%s%s", canon_dir, separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s%s", canon_dir, separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debugfile, ".debug/%s", separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, ".debug/%s", separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
-  sprintf (debugfile, "%s", separate_filename);
-  warn (_("tried: %s\n"), debugfile);
+  sprintf (debug_filename, "%s", separate_filename);
+  warn (_("tried: %s\n"), debug_filename);
 
   free (canon_dir);
-  free (debugfile);
+  free (debug_filename);
   return NULL;
 
  found:
   free (canon_dir);
 
+  void * debug_handle;
+
   /* Now open the file.... */
-  if ((separate_debug_file = open_debug_file (debugfile)) == NULL)
+  if ((debug_handle = open_debug_file (debug_filename)) == NULL)
     {
-      warn (_("failed to open separate debug file: %s\n"), debugfile);
-      free (debugfile);
+      warn (_("failed to open separate debug file: %s\n"), debug_filename);
+      free (debug_filename);
       return FALSE;
     }
 
   /* FIXME: We do not check to see if there are any other separate debug info
      files that would also match.  */
 
-  printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debugfile);
-  separate_debug_filename = debugfile;
+  printf (_("%s: Found separate debug info file: %s\n\n"), main_filename, debug_filename);
+  add_separate_debug_file (debug_filename, debug_handle);
 
-  /* Do not free debugfile - it might be referenced inside
+  /* Do not free debug_filename - it might be referenced inside
      the structure returned by open_debug_file().  */
-  return separate_debug_file;
+  return debug_handle;
 }
 
 /* Attempt to load a separate dwarf object file.  */
 
 static void *
-load_dwo_file (const char * main_filename)
+load_dwo_file (const char * main_filename, const char * name, const char * dir, const char * id ATTRIBUTE_UNUSED)
 {
-  char * filename;
+  char * separate_filename;
+  void * separate_handle;
 
   /* FIXME: Skip adding / if dwo_dir ends in /.  */
-  filename = concat (dwo_dir, "/", dwo_name, NULL);
-  if (filename == NULL)
+  separate_filename = concat (dir, "/", name, NULL);
+  if (separate_filename == NULL)
     {
       warn (_("Out of memory allocating dwo filename\n"));
       return NULL;
     }
 
-  if ((separate_debug_file = open_debug_file (filename)) == NULL)
+  if ((separate_handle = open_debug_file (separate_filename)) == NULL)
     {
-      warn (_("Unable to load dwo file: %s\n"), filename);
-      free (filename);
+      warn (_("Unable to load dwo file: %s\n"), separate_filename);
+      free (separate_filename);
       return NULL;
     }
 
   /* FIXME: We should check the dwo_id.  */
 
-  printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, filename);
-  separate_debug_filename = filename;
-  return separate_debug_file;
+  printf (_("%s: Found separate debug object file: %s\n\n"), main_filename, separate_filename);
+  add_separate_debug_file (separate_filename, separate_handle);
+  /* Note - separate_filename will be freed in free_debug_memory().  */
+  return separate_handle;
 }
 
-/* Load a separate debug info file, if it exists.
-   Returns the data pointer that is the result of calling open_debug_file
-   on the separate debug info file, or NULL if there were problems or there
-   is no such file.  */
+/* Load the separate debug info file(s) attached to FILE, if any exist.
+   Returns TRUE if any were found, FALSE otherwise.
+   If TRUE is returned then the linked list starting at first_separate_info
+   will be populated with open file handles.  */
 
-void *
-load_separate_debug_file (void * file, const char * filename)
+bfd_boolean
+load_separate_debug_files (void * file, const char * filename)
 {
   /* Skip this operation if we are not interested in debug links.  */
   if (! do_follow_links && ! do_debug_links)
-    return NULL;
+    return FALSE;
 
-  /* See if there is a dwo link.  */
+  /* See if there are any dwo links.  */
   if (load_debug_section (str, file)
       && load_debug_section (abbrev, file)
       && load_debug_section (info, file))
     {
-      dwo_name = dwo_dir = NULL;
-      dwo_id = NULL;
-      dwo_id_len = 0;
+      free_dwo_info ();
 
       if (process_debug_info (& debug_displays[info].section, file, abbrev, TRUE, FALSE))
        {
-         if (dwo_name != NULL)
+         bfd_boolean introduced = FALSE;
+         dwo_info *   dwinfo;
+         const char * dir = NULL;
+         const char * id = NULL;
+
+         for (dwinfo = first_dwo_info; dwinfo != NULL; dwinfo = dwinfo->next)
            {
-             if (do_debug_links)
+             switch (dwinfo->type)
                {
-                 printf (_("The %s section contains a link to a dwo file:\n"),
-                         debug_displays [info].section.uncompressed_name);
-                 printf (_("  Name:      %s\n"), dwo_name);
-                 printf (_("  Directory: %s\n"), dwo_dir ? dwo_dir : _("<not-found>"));
-                 if (dwo_id != NULL)
-                   display_data (printf (_("  ID:       ")), dwo_id, dwo_id_len);
-                 else
-                   printf (_("  ID: <unknown>\n"));
-                 printf ("\n\n");
-               }
+               case DWO_NAME:
+                 if (do_debug_links)
+                   {
+                     if (! introduced)
+                       {
+                         printf (_("The %s section contains link(s) to dwo file(s):\n\n"),
+                                 debug_displays [info].section.uncompressed_name);
+                         introduced = TRUE;
+                       }
 
-             /* FIXME: We do not check to see if there are any more dwo links in the file...  */
-             if (do_follow_links)
-               return load_dwo_file (filename);
+                     printf (_("  Name:      %s\n"), dwinfo->value);
+                     printf (_("  Directory: %s\n"), dir ? dir : _("<not-found>"));
+                     if (id != NULL)
+                       display_data (printf (_("  ID:       ")), (unsigned char *) id, 8);
+                     else
+                       printf (_("  ID: <unknown>\n"));
+                     printf ("\n\n");
+                   }
+
+                 if (do_follow_links)
+                   load_dwo_file (filename, dwinfo->value, dir, id);
+                 break;
+
+               case DWO_DIR:
+                 dir = dwinfo->value;
+                 break;
+
+               case DWO_ID:
+                 id = dwinfo->value;
+                 break;
+
+               default:
+                 error (_("Unexpected DWO INFO type"));
+                 break;
+               }
            }
        }
     }
@@ -9916,7 +10166,7 @@ load_separate_debug_file (void * file, const char * filename)
   if (! do_follow_links)
     /* The other debug links will be displayed by display_debug_links()
        so we do not need to do any further processing here.  */
-    return NULL;
+    return FALSE;
 
   /* FIXME: We do not check for the presence of both link sections in the same file.  */
   /* FIXME: We do not check the separate debug info file to see if it too contains debuglinks.  */
@@ -9927,26 +10177,29 @@ load_separate_debug_file (void * file, const char * filename)
     {
       Build_id_data * build_id_data;
 
-      return load_separate_debug_info (filename,
-                                      & debug_displays[gnu_debugaltlink].section,
-                                      parse_gnu_debugaltlink,
-                                      check_gnu_debugaltlink,
-                                      & build_id_data);
+      load_separate_debug_info (filename,
+                               & debug_displays[gnu_debugaltlink].section,
+                               parse_gnu_debugaltlink,
+                               check_gnu_debugaltlink,
+                               & build_id_data);
     }
 
   if (load_debug_section (gnu_debuglink, file))
     {
       unsigned long crc32;
 
-      return load_separate_debug_info (filename,
-                                      & debug_displays[gnu_debuglink].section,
-                                      parse_gnu_debuglink,
-                                      check_gnu_debuglink,
-                                      & crc32);
+      load_separate_debug_info (filename,
+                               & debug_displays[gnu_debuglink].section,
+                               parse_gnu_debuglink,
+                               check_gnu_debuglink,
+                               & crc32);
     }
 
+  if (first_separate_info != NULL)
+    return TRUE;
+
   do_follow_links = 0;
-  return NULL;
+  return FALSE;
 }  
 
 void
@@ -9979,14 +10232,19 @@ free_debug_memory (void)
       alloc_num_debug_info_entries = num_debug_info_entries = 0;
     }
 
-  if (separate_debug_file != NULL)
-    {
-      close_debug_file (separate_debug_file);
-      separate_debug_file = NULL;
+  separate_info * d;
+  separate_info * next;
 
-      free ((void *) separate_debug_filename);
-      separate_debug_filename = NULL;
+  for (d = first_separate_info; d != NULL; d = next)
+    {
+      close_debug_file (d->handle);
+      free ((void *) d->filename);
+      next = d->next;
+      free ((void *) d);
     }
+  first_separate_info = NULL;
+  
+  free_dwo_info ();
 }
 
 void
This page took 0.041607 seconds and 4 git commands to generate.