gdb: work around negative DW_AT_data_member_location GCC 11 bug
[binutils-gdb.git] / gdb / dwarf2 / read.c
index 00856b86483f4fbde07a17ef2f39f7ea28c02840..1a749eac334fe6a25a511d2268722f1089441500 100644 (file)
@@ -1,6 +1,6 @@
 /* DWARF 2 debugging format support for GDB.
 
-   Copyright (C) 1994-2021 Free Software Foundation, Inc.
+   Copyright (C) 1994-2022 Free Software Foundation, Inc.
 
    Adapted by Gary Funck (gary@intrepid.com), Intrepid Technology,
    Inc.  with support from Florida State University (under contract
@@ -1206,7 +1206,6 @@ static struct die_info *die_specification (struct die_info *die,
 static line_header_up dwarf_decode_line_header (sect_offset sect_off,
                                                struct dwarf2_cu *cu);
 
-struct file_and_directory;
 static void dwarf_decode_lines (struct line_header *,
                                const file_and_directory &,
                                struct dwarf2_cu *, dwarf2_psymtab *,
@@ -1538,23 +1537,8 @@ dwarf2_per_cu_data_deleter::operator() (dwarf2_per_cu_data *data)
     delete data;
 }
 
-/* The return type of find_file_and_directory.  Note, the enclosed
-   string pointers are only valid while this object is valid.  */
-
-struct file_and_directory
-{
-  /* The filename.  This is never NULL.  */
-  const char *name;
-
-  /* The compilation directory.  NULL if not known.  If we needed to
-     compute a new string, it will be stored in the per-BFD string
-     bcache; otherwise, points directly to the DW_AT_comp_dir string
-     attribute owned by the obstack that owns the DIE.  */
-  const char *comp_dir;
-};
-
-static file_and_directory find_file_and_directory (struct die_info *die,
-                                                  struct dwarf2_cu *cu);
+static file_and_directory &find_file_and_directory
+     (struct die_info *die, struct dwarf2_cu *cu);
 
 static const char *compute_include_file_name
      (const struct line_header *lh,
@@ -3021,10 +3005,10 @@ dw2_get_file_names_reader (const struct die_reader_specs *reader,
       lh = dwarf_decode_line_header (line_offset, cu);
     }
 
-  file_and_directory fnd = find_file_and_directory (comp_unit_die, cu);
+  file_and_directory &fnd = find_file_and_directory (comp_unit_die, cu);
 
   int offset = 0;
-  if (strcmp (fnd.name, "<unknown>") != 0)
+  if (!fnd.is_unknown ())
     ++offset;
   else if (lh == nullptr)
     return;
@@ -3053,12 +3037,12 @@ dw2_get_file_names_reader (const struct die_reader_specs *reader,
     }
 
   qfn->num_file_names = offset + include_names.size ();
-  qfn->comp_dir = fnd.comp_dir;
+  qfn->comp_dir = fnd.intern_comp_dir (per_objfile->objfile);
   qfn->file_names =
     XOBNEWVEC (&per_objfile->per_bfd->obstack, const char *,
               qfn->num_file_names);
   if (offset != 0)
-    qfn->file_names[0] = xstrdup (fnd.name);
+    qfn->file_names[0] = xstrdup (fnd.get_name ());
 
   if (!include_names.empty ())
     memcpy (&qfn->file_names[offset], include_names.data (),
@@ -5787,7 +5771,10 @@ struct dwarf2_include_psymtab : public partial_symtab
 
   compunit_symtab *get_compunit_symtab (struct objfile *objfile) const override
   {
-    return nullptr;
+    compunit_symtab *cust = includer ()->get_compunit_symtab (objfile);
+    while (cust != nullptr && cust->user != nullptr)
+      cust = cust->user;
+    return cust;
   }
 
 private:
@@ -6999,18 +6986,18 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
   prepare_one_comp_unit (cu, comp_unit_die, pretend_language);
 
   /* Allocate a new partial symbol table structure.  */
-  gdb::unique_xmalloc_ptr<char> debug_filename;
   static const char artificial[] = "<artificial>";
-  file_and_directory fnd = find_file_and_directory (comp_unit_die, cu);
-  if (strcmp (fnd.name, artificial) == 0)
+  file_and_directory &fnd = find_file_and_directory (comp_unit_die, cu);
+  if (strcmp (fnd.get_name (), artificial) == 0)
     {
-      debug_filename.reset (concat (artificial, "@",
-                                   sect_offset_str (per_cu->sect_off),
-                                   (char *) NULL));
-      fnd.name = debug_filename.get ();
+      gdb::unique_xmalloc_ptr<char> debug_filename
+       (concat (artificial, "@",
+                sect_offset_str (per_cu->sect_off),
+                (char *) NULL));
+      fnd.set_name (std::move (debug_filename));
     }
 
-  pst = create_partial_symtab (per_cu, per_objfile, fnd.name);
+  pst = create_partial_symtab (per_cu, per_objfile, fnd.get_name ());
 
   /* This must be done before calling dwarf2_build_include_psymtabs.  */
   pst->dirname = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
@@ -10487,39 +10474,25 @@ producer_is_gcc_lt_4_3 (struct dwarf2_cu *cu)
   return cu->producer_is_gcc_lt_4_3;
 }
 
-static file_and_directory
+static file_and_directory &
 find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu)
 {
-  file_and_directory res;
+  if (cu->per_cu->fnd != nullptr)
+    return *cu->per_cu->fnd;
 
   /* Find the filename.  Do not use dwarf2_name here, since the filename
      is not a source language identifier.  */
-  res.name = dwarf2_string_attr (die, DW_AT_name, cu);
-  res.comp_dir = dwarf2_string_attr (die, DW_AT_comp_dir, cu);
+  file_and_directory res (dwarf2_string_attr (die, DW_AT_name, cu),
+                         dwarf2_string_attr (die, DW_AT_comp_dir, cu));
 
-  if (res.comp_dir == NULL
-      && producer_is_gcc_lt_4_3 (cu) && res.name != NULL
-      && IS_ABSOLUTE_PATH (res.name))
-    {
-      std::string comp_dir_storage = ldirname (res.name);
-      if (!comp_dir_storage.empty ())
-       res.comp_dir
-         = cu->per_objfile->objfile->intern (comp_dir_storage.c_str ());
-    }
-  if (res.comp_dir != NULL)
-    {
-      /* Irix 6.2 native cc prepends <machine>.: to the compilation
-        directory, get rid of it.  */
-      const char *cp = strchr (res.comp_dir, ':');
-
-      if (cp && cp != res.comp_dir && cp[-1] == '.' && cp[1] == '/')
-       res.comp_dir = cp + 1;
-    }
+  if (res.get_comp_dir () == nullptr
+      && producer_is_gcc_lt_4_3 (cu)
+      && res.get_name () != nullptr
+      && IS_ABSOLUTE_PATH (res.get_name ()))
+    res.set_comp_dir (ldirname (res.get_name ()));
 
-  if (res.name == NULL)
-    res.name = "<unknown>";
-
-  return res;
+  cu->per_cu->fnd.reset (new file_and_directory (std::move (res)));
+  return *cu->per_cu->fnd;
 }
 
 /* Handle DW_AT_stmt_list for a compilation unit.
@@ -10647,9 +10620,9 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
     lowpc = highpc;
   lowpc = gdbarch_adjust_dwarf2_addr (gdbarch, lowpc + baseaddr);
 
-  file_and_directory fnd = find_file_and_directory (die, cu);
+  file_and_directory &fnd = find_file_and_directory (die, cu);
 
-  cu->start_symtab (fnd.name, fnd.comp_dir, lowpc);
+  cu->start_symtab (fnd.get_name (), fnd.intern_comp_dir (objfile), lowpc);
 
   gdb_assert (per_objfile->sym_cu == nullptr);
   scoped_restore restore_sym_cu
@@ -10657,8 +10630,13 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
 
   /* Decode line number information if present.  We do this before
      processing child DIEs, so that the line header table is available
-     for DW_AT_decl_file.  */
-  handle_DW_AT_stmt_list (die, cu, fnd, lowpc);
+     for DW_AT_decl_file.  The PC check is here because, if LOWPC and
+     HIGHPC are both 0x0, then there won't be any interesting code in
+     the CU, but a check later on (in
+     lnp_state_machine::check_line_address) will fail to properly
+     exclude an entry that was removed via --gc-sections.  */
+  if (lowpc != highpc)
+    handle_DW_AT_stmt_list (die, cu, fnd, lowpc);
 
   /* Process all dies in compilation unit.  */
   if (die->child != NULL)
@@ -14342,6 +14320,7 @@ check_producer (struct dwarf2_cu *cu)
     {
       cu->producer_is_gxx_lt_4_6 = major < 4 || (major == 4 && minor < 6);
       cu->producer_is_gcc_lt_4_3 = major < 4 || (major == 4 && minor < 3);
+      cu->producer_is_gcc_11 = major == 11;
     }
   else if (producer_is_icc (cu->producer, &major, &minor))
     {
@@ -14486,6 +14465,19 @@ handle_member_location (struct die_info *die, struct dwarf2_cu *cu,
       if (attr->form_is_constant ())
        {
          LONGEST offset = attr->constant_value (0);
+
+         /* Work around this GCC 11 bug, where it would erroneously use -1
+            data member locations, instead of 0:
+
+              Negative DW_AT_data_member_location
+              https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101378
+            */
+         if (offset == -1 && cu->producer_is_gcc_11)
+           {
+             complaint (_("DW_AT_data_member_location value of -1, assuming 0"));
+             offset = 0;
+           }
+
          field->set_loc_bitpos (offset * bits_per_byte);
        }
       else if (attr->form_is_section_offset ())
@@ -14936,7 +14928,7 @@ add_variant_property (struct field_info *fip, struct type *type,
     offset_map[fip->fields[i].offset] = i;
 
   struct objfile *objfile = cu->per_objfile->objfile;
-  gdb::array_view<variant_part> parts
+  gdb::array_view<const variant_part> parts
     = create_variant_parts (&objfile->objfile_obstack, offset_map, fip,
                            fip->variant_parts);
 
@@ -18258,16 +18250,7 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
        break;
       case DW_ATE_UTF:
        {
-         if (bits == 16)
-           type = builtin_type (arch)->builtin_char16;
-         else if (bits == 32)
-           type = builtin_type (arch)->builtin_char32;
-         else
-           {
-             complaint (_("unsupported DW_ATE_UTF bit size: '%d'"),
-                        bits);
-             type = dwarf2_init_integer_type (cu, objfile, bits, 1, name);
-           }
+         type = init_character_type (objfile, bits, 1, name);
          return set_die_type (die, type, cu);
        }
        break;
@@ -18287,7 +18270,9 @@ read_base_type (struct die_info *die, struct dwarf2_cu *cu)
        break;
     }
 
-  if (name && strcmp (name, "char") == 0)
+  if (type->code () == TYPE_CODE_INT
+      && name != nullptr
+      && strcmp (name, "char") == 0)
     type->set_has_no_signedness (true);
 
   maybe_set_alignment (cu, die, type);
@@ -19979,7 +19964,7 @@ read_attribute_reprocess (const struct die_reader_specs *reader,
          break;
        }
       default:
-       gdb_assert_not_reached (_("Unexpected DWARF form."));
+       gdb_assert_not_reached ("Unexpected DWARF form.");
     }
 }
 
@@ -20304,6 +20289,18 @@ read_indirect_string (dwarf2_per_objfile *per_objfile, bfd *abfd,
 
 /* See read.h.  */
 
+const char *
+dwarf2_per_objfile::read_line_string (const gdb_byte *buf,
+                                     unsigned int offset_size)
+{
+  bfd *abfd = objfile->obfd;
+  ULONGEST str_offset = read_offset (abfd, buf, offset_size);
+
+  return per_bfd->line_str.read_string (objfile, str_offset, "DW_FORM_line_strp");
+}
+
+/* See read.h.  */
+
 const char *
 dwarf2_per_objfile::read_line_string (const gdb_byte *buf,
                                      const struct comp_unit_head *cu_header,
@@ -20753,7 +20750,7 @@ compute_include_file_name (const struct line_header *lh, const file_entry &fe,
 
   gdb::unique_xmalloc_ptr<char> hold_compare;
   if (!IS_ABSOLUTE_PATH (include_name)
-      && (dir_name != NULL || cu_info.comp_dir != NULL))
+      && (dir_name != nullptr || cu_info.get_comp_dir () != nullptr))
     {
       /* Avoid creating a duplicate name for CU_INFO.
         We do this by comparing INCLUDE_NAME and CU_INFO.
@@ -20783,19 +20780,20 @@ compute_include_file_name (const struct line_header *lh, const file_entry &fe,
          include_name = name_holder->get ();
          include_name_to_compare = include_name;
        }
-      if (!IS_ABSOLUTE_PATH (include_name) && cu_info.comp_dir != nullptr)
+      if (!IS_ABSOLUTE_PATH (include_name)
+         && cu_info.get_comp_dir () != nullptr)
        {
-         hold_compare.reset (concat (cu_info.comp_dir, SLASH_STRING,
+         hold_compare.reset (concat (cu_info.get_comp_dir (), SLASH_STRING,
                                      include_name, (char *) NULL));
          include_name_to_compare = hold_compare.get ();
        }
     }
 
   gdb::unique_xmalloc_ptr<char> copied_name;
-  const char *cu_filename = cu_info.name;
-  if (!IS_ABSOLUTE_PATH (cu_filename) && cu_info.comp_dir != nullptr)
+  const char *cu_filename = cu_info.get_name ();
+  if (!IS_ABSOLUTE_PATH (cu_filename) && cu_info.get_comp_dir () != nullptr)
     {
-      copied_name.reset (concat (cu_info.comp_dir, SLASH_STRING,
+      copied_name.reset (concat (cu_info.get_comp_dir (), SLASH_STRING,
                                 cu_filename, (char *) NULL));
       cu_filename = copied_name.get ();
     }
@@ -23001,31 +22999,28 @@ dump_die_shallow (struct ui_file *f, int indent, struct die_info *die)
 {
   unsigned int i;
 
-  print_spaces (indent, f);
-  fprintf_unfiltered (f, "Die: %s (abbrev %d, offset %s)\n",
+  fprintf_unfiltered (f, "%*sDie: %s (abbrev %d, offset %s)\n",
+                     indent, "",
                      dwarf_tag_name (die->tag), die->abbrev,
                      sect_offset_str (die->sect_off));
 
   if (die->parent != NULL)
-    {
-      print_spaces (indent, f);
-      fprintf_unfiltered (f, "  parent at offset: %s\n",
-                         sect_offset_str (die->parent->sect_off));
-    }
+    fprintf_unfiltered (f, "%*s  parent at offset: %s\n",
+                       indent, "",
+                       sect_offset_str (die->parent->sect_off));
 
-  print_spaces (indent, f);
-  fprintf_unfiltered (f, "  has children: %s\n",
-          dwarf_bool_name (die->child != NULL));
+  fprintf_unfiltered (f, "%*s  has children: %s\n",
+                     indent, "",
+                     dwarf_bool_name (die->child != NULL));
 
-  print_spaces (indent, f);
-  fprintf_unfiltered (f, "  attributes:\n");
+  fprintf_unfiltered (f, "%*s  attributes:\n", indent, "");
 
   for (i = 0; i < die->num_attrs; ++i)
     {
-      print_spaces (indent, f);
-      fprintf_unfiltered (f, "    %s (%s) ",
-              dwarf_attr_name (die->attrs[i].name),
-              dwarf_form_name (die->attrs[i].form));
+      fprintf_unfiltered (f, "%*s    %s (%s) ",
+                         indent, "",
+                         dwarf_attr_name (die->attrs[i].name),
+                         dwarf_form_name (die->attrs[i].form));
 
       switch (die->attrs[i].form)
        {
@@ -23141,8 +23136,7 @@ dump_die_1 (struct ui_file *f, int level, int max_level, struct die_info *die)
 
   if (die->child != NULL)
     {
-      print_spaces (indent, f);
-      fprintf_unfiltered (f, "  Children:");
+      fprintf_unfiltered (f, "%*s  Children:", indent, "");
       if (level + 1 < max_level)
        {
          fprintf_unfiltered (f, "\n");