public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Tom Tromey <tom@tromey.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 15/17] Rewrite .debug_names reader
Date: Sun, 10 Dec 2023 09:45:04 -0700	[thread overview]
Message-ID: <20231210-debug-names-fix-v1-15-a8f6d2525018@tromey.com> (raw)
In-Reply-To: <20231210-debug-names-fix-v1-0-a8f6d2525018@tromey.com>

This rewrites the .debug_names reader to follow the spec.

Since it was first written, gdb's .debug_names writer has been
incorrect -- while the form of the section has been ok, the contents
have been very gdb-specific.

This patch fixes the reader side of this equation, rewriting the
reader to create a cooked index internally -- an important detail
because it allows for the deletion of a lot of code, and it means the
various readers will agree more often.

This reader checks for a new augmentation string.  For the time being,
all other producers are ignored -- the old GDB ones because they are
wrong, and clang because it does not emit DW_IDX_parent.  (If there
are any other producers, I'm unaware of them.)

While the new reader mostly runs in a worker thread, it does not try
to distribute its work.  This could be done by partitioning the name
table.  The parent computations could also be done in parallel after
all names have been read.  I haven't attempted this.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25950
---
 gdb/dwarf2/read-debug-names.c | 947 ++++++++++++++++--------------------------
 1 file changed, 368 insertions(+), 579 deletions(-)

diff --git a/gdb/dwarf2/read-debug-names.c b/gdb/dwarf2/read-debug-names.c
index c6b70550f81..1e53c246b91 100644
--- a/gdb/dwarf2/read-debug-names.c
+++ b/gdb/dwarf2/read-debug-names.c
@@ -20,6 +20,7 @@
 #include "defs.h"
 #include "read-debug-names.h"
 #include "dwarf2/aranges.h"
+#include "dwarf2/cooked-index.h"
 
 #include "complaints.h"
 #include "cp-support.h"
@@ -28,22 +29,62 @@
 #include "read.h"
 #include "stringify.h"
 
-/* A description of the mapped .debug_names.
-   Uninitialized map has CU_COUNT 0.  */
+/* This is just like cooked_index_functions, but overrides a single
+   method so the test suite can distinguish the .debug_names case from
+   the ordinary case.  */
+struct dwarf2_debug_names_index : public cooked_index_functions
+{
+  /* This dumps minimal information about .debug_names.  It is called
+     via "mt print objfiles".  The gdb.dwarf2/gdb-index.exp testcase
+     uses this to verify that .debug_names has been loaded.  */
+  void dump (struct objfile *objfile) override
+  {
+    gdb_printf (".debug_names: exists\n");
+    /* This could call the superclass method if that's useful.  */
+  }
+};
+
+/* This is like a cooked index, but as it has been ingested from
+   .debug_names, it can't be used to write out an index.  */
+class debug_names_index : public cooked_index
+{
+public:
+
+  using cooked_index::cooked_index;
+
+  cooked_index *index_for_writing () override
+  { return nullptr; }
+
+  quick_symbol_functions_up make_quick_functions () const override
+  { return quick_symbol_functions_up (new dwarf2_debug_names_index); }
+};
+
+/* A description of the mapped .debug_names.  */
 
-struct mapped_debug_names final : public mapped_index_base
+struct mapped_debug_names_reader
 {
-  bfd_endian dwarf5_byte_order;
-  bool dwarf5_is_dwarf64;
-  bool augmentation_is_gdb;
-  uint8_t offset_size;
+  const gdb_byte *scan_one_entry (const char *name,
+				  const gdb_byte *entry,
+				  cooked_index_entry **result,
+				  std::optional<ULONGEST> &parent);
+  void scan_entries (uint32_t index, const char *name, const gdb_byte *entry);
+  void scan_all_names ();
+
+  dwarf2_per_objfile *per_objfile = nullptr;
+  bfd *abfd = nullptr;
+  bfd_endian dwarf5_byte_order {};
+  bool dwarf5_is_dwarf64 = false;
+  bool augmentation_is_gdb = false;
+  uint8_t offset_size = 0;
   uint32_t cu_count = 0;
-  uint32_t tu_count, bucket_count, name_count;
-  const gdb_byte *cu_table_reordered, *tu_table_reordered;
-  const uint32_t *bucket_table_reordered, *hash_table_reordered;
-  const gdb_byte *name_table_string_offs_reordered;
-  const gdb_byte *name_table_entry_offs_reordered;
-  const gdb_byte *entry_pool;
+  uint32_t tu_count = 0, bucket_count = 0, name_count = 0;
+  const gdb_byte *cu_table_reordered = nullptr;
+  const gdb_byte *tu_table_reordered = nullptr;
+  const uint32_t *bucket_table_reordered = nullptr;
+  const uint32_t *hash_table_reordered = nullptr;
+  const gdb_byte *name_table_string_offs_reordered = nullptr;
+  const gdb_byte *name_table_entry_offs_reordered = nullptr;
+  const gdb_byte *entry_pool = nullptr;
 
   struct index_val
   {
@@ -64,41 +105,250 @@ struct mapped_debug_names final : public mapped_index_base
 
   std::unordered_map<ULONGEST, index_val> abbrev_map;
 
-  const char *namei_to_name
-    (uint32_t namei, dwarf2_per_objfile *per_objfile) const;
+  std::unique_ptr<cooked_index_shard> shard;
+  std::vector<std::pair<cooked_index_entry *, ULONGEST>> needs_parent;
+  std::vector<std::vector<cooked_index_entry *>> all_entries;
+};
 
-  /* Implementation of the mapped_index_base virtual interface, for
-     the name_components cache.  */
+/* Scan a single entry from the entries table.  Set *RESULT and PARENT
+   (if needed) and return the updated pointer on success, or return
+   nullptr on error, or at the end of the table.  */
 
-  const char *symbol_name_at
-    (offset_type idx, dwarf2_per_objfile *per_objfile) const override
-  { return namei_to_name (idx, per_objfile); }
+const gdb_byte *
+mapped_debug_names_reader::scan_one_entry (const char *name,
+					   const gdb_byte *entry,
+					   cooked_index_entry **result,
+					   std::optional<ULONGEST> &parent)
+{
+  unsigned int bytes_read;
+  const ULONGEST abbrev = read_unsigned_leb128 (abfd, entry, &bytes_read);
+  entry += bytes_read;
+  if (abbrev == 0)
+    return nullptr;
 
-  size_t symbol_name_count () const override
-  { return this->name_count; }
+  const auto indexval_it = abbrev_map.find (abbrev);
+  if (indexval_it == abbrev_map.cend ())
+    {
+      complaint (_("Wrong .debug_names undefined abbrev code %s "
+		   "[in module %s]"),
+		 pulongest (abbrev), bfd_get_filename (abfd));
+      return nullptr;
+    }
 
-  quick_symbol_functions_up make_quick_functions () const override;
-};
+  const auto &indexval = indexval_it->second;
+  cooked_index_flag flags = 0;
+  sect_offset die_offset {};
+  enum language lang = language_unknown;
+  dwarf2_per_cu_data *per_cu = nullptr;
+  for (const auto &attr : indexval.attr_vec)
+    {
+      ULONGEST ull;
+      switch (attr.form)
+	{
+	case DW_FORM_implicit_const:
+	  ull = attr.implicit_const;
+	  break;
+	case DW_FORM_flag_present:
+	  ull = 1;
+	  break;
+	case DW_FORM_udata:
+	  ull = read_unsigned_leb128 (abfd, entry, &bytes_read);
+	  entry += bytes_read;
+	  break;
+	case DW_FORM_ref4:
+	  ull = read_4_bytes (abfd, entry);
+	  entry += 4;
+	  break;
+	case DW_FORM_ref8:
+	  ull = read_8_bytes (abfd, entry);
+	  entry += 8;
+	  break;
+	case DW_FORM_ref_sig8:
+	  ull = read_8_bytes (abfd, entry);
+	  entry += 8;
+	  break;
+	default:
+	  complaint (_("Unsupported .debug_names form %s [in module %s]"),
+		     dwarf_form_name (attr.form),
+		     bfd_get_filename (abfd));
+	  return nullptr;
+	}
+      switch (attr.dw_idx)
+	{
+	case DW_IDX_compile_unit:
+	  {
+	    /* Don't crash on bad data.  */
+	    if (ull >= per_objfile->per_bfd->all_comp_units.size ())
+	      {
+		complaint (_(".debug_names entry has bad CU index %s"
+			     " [in module %s]"),
+			   pulongest (ull),
+			   bfd_get_filename (abfd));
+		continue;
+	      }
+	  }
+	  per_cu = per_objfile->per_bfd->get_cu (ull);
+	  break;
+	case DW_IDX_type_unit:
+	  /* Don't crash on bad data.  */
+	  if (ull >= per_objfile->per_bfd->all_type_units.size ())
+	    {
+	      complaint (_(".debug_names entry has bad TU index %s"
+			   " [in module %s]"),
+			 pulongest (ull),
+			 bfd_get_filename (abfd));
+	      continue;
+	    }
+	  {
+	    int nr_cus = per_objfile->per_bfd->all_comp_units.size ();
+	    per_cu = per_objfile->per_bfd->get_cu (nr_cus + ull);
+	  }
+	  break;
+	case DW_IDX_die_offset:
+	  die_offset = sect_offset (ull);
+	  /* In a per-CU index (as opposed to a per-module index), index
+	     entries without CU attribute implicitly refer to the single CU.  */
+	  if (per_cu == NULL)
+	    per_cu = per_objfile->per_bfd->get_cu (0);
+	  break;
+	case DW_IDX_parent:
+	  parent = ull;
+	  break;
+	case DW_IDX_GNU_internal:
+	  if (augmentation_is_gdb && ull != 0)
+	    flags |= IS_STATIC;
+	  break;
+	case DW_IDX_GNU_main:
+	  if (augmentation_is_gdb && ull != 0)
+	    flags |= IS_MAIN;
+	  break;
+	case DW_IDX_GNU_language:
+	  if (augmentation_is_gdb)
+	    lang = dwarf_lang_to_enum_language (ull);
+	  break;
+	case DW_IDX_GNU_linkage_name:
+	  if (augmentation_is_gdb && ull != 0)
+	    flags |= IS_LINKAGE;
+	  break;
+	}
+    }
+
+  *result = shard->add (die_offset, (dwarf_tag) indexval.dwarf_tag, flags,
+			lang, name, nullptr, per_cu);
+  return entry;
+}
+
+/* Scan all the entries for NAME, at name slot INDEX.  */
+
+void
+mapped_debug_names_reader::scan_entries (uint32_t index,
+					 const char *name,
+					 const gdb_byte *entry)
+{
+  std::vector<cooked_index_entry *> these_entries;
+  
+  while (true)
+    {
+      std::optional<ULONGEST> parent;
+      cooked_index_entry *this_entry;
+      entry = scan_one_entry (name, entry, &this_entry, parent);
+
+      if (entry == nullptr)
+	break;
+
+      these_entries.push_back (this_entry);
+      if (parent.has_value ())
+	needs_parent.emplace_back (this_entry, *parent);
+    }
 
-struct dwarf2_debug_names_index : public dwarf2_base_index_functions
+  all_entries[index] = std::move (these_entries);
+}
+
+/* Scan the name table and create all the entries.  */
+
+void
+mapped_debug_names_reader::scan_all_names ()
 {
-  void dump (struct objfile *objfile) override;
-
-  bool expand_symtabs_matching
-    (struct objfile *objfile,
-     gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
-     const lookup_name_info *lookup_name,
-     gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
-     gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
-     block_search_flags search_flags,
-     domain_enum domain,
-     enum search_domain kind) override;
+  all_entries.resize (name_count);
+
+  /* In the first pass, create all the entries.  */
+  for (uint32_t i = 0; i < name_count; ++i)
+    {
+      const ULONGEST namei_string_offs
+	= extract_unsigned_integer ((name_table_string_offs_reordered
+				     + i * offset_size),
+				    offset_size, dwarf5_byte_order);
+      const char *name = read_indirect_string_at_offset (per_objfile,
+							 namei_string_offs);
+
+      const ULONGEST namei_entry_offs
+	= extract_unsigned_integer ((name_table_entry_offs_reordered
+				     + i * offset_size),
+				    offset_size, dwarf5_byte_order);
+      const gdb_byte *entry = entry_pool + namei_entry_offs;
+
+      scan_entries (i, name, entry);
+    }
+
+  /* Now update the parent pointers for all entries.  This has to be
+     done in a funny way because DWARF specifies the parent entry to
+     point to a name -- but we don't know which specific one.  */
+  for (auto [entry, parent_idx] : needs_parent)
+    {
+      /* Name entries are indexed from 1 in DWARF.  */
+      std::vector<cooked_index_entry *> &entries = all_entries[parent_idx - 1];
+      for (const auto &parent : entries)
+	if (parent->lang == entry->lang)
+	  {
+	    entry->parent_entry = parent;
+	    break;
+	  }
+    }
+}
+
+/* A reader for .debug_names.  */
+
+struct cooked_index_debug_names : public cooked_index_worker
+{
+  cooked_index_debug_names (dwarf2_per_objfile *per_objfile,
+			    mapped_debug_names_reader &&map)
+    : cooked_index_worker (per_objfile),
+      m_map (std::move (map))
+  { }
+
+  void do_reading () override;
+
+  mapped_debug_names_reader m_map;
 };
 
-quick_symbol_functions_up
-mapped_debug_names::make_quick_functions () const
+void
+cooked_index_debug_names::do_reading ()
 {
-  return quick_symbol_functions_up (new dwarf2_debug_names_index);
+  complaint_interceptor complaint_handler;
+  std::vector<gdb_exception> exceptions;
+  try
+    {
+      m_map.scan_all_names ();
+    }
+  catch (const gdb_exception &exc)
+    {
+      exceptions.push_back (std::move (exc));
+    }
+
+  dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
+  per_bfd->quick_file_names_table
+    = create_quick_file_names_table (per_bfd->all_units.size ());
+  m_results.emplace_back (nullptr,
+			  complaint_handler.release (),
+			  std::move (exceptions));
+  std::vector<std::unique_ptr<cooked_index_shard>> indexes;
+  indexes.push_back (std::move (m_map.shard));
+  cooked_index *table
+    = (gdb::checked_static_cast<cooked_index *>
+       (per_bfd->index_table.get ()));
+  table->set_contents (std::move (indexes));
+
+  bfd_thread_cleanup ();
 }
 
 /* Check the signatured type hash table from .debug_names.  */
@@ -106,7 +356,7 @@ mapped_debug_names::make_quick_functions () const
 static bool
 check_signatured_type_table_from_debug_names
   (dwarf2_per_objfile *per_objfile,
-   const mapped_debug_names &map,
+   const mapped_debug_names_reader &map,
    struct dwarf2_section_info *section)
 {
   struct objfile *objfile = per_objfile->objfile;
@@ -143,28 +393,18 @@ check_signatured_type_table_from_debug_names
   return true;
 }
 
-/* Read the address map data from DWARF-5 .debug_aranges, and use it to
-   populate the index_addrmap.  */
-
-static void
-create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
-			     struct dwarf2_section_info *section)
-{
-  dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
-
-  addrmap_mutable mutable_map;
-
-  section->read (per_objfile->objfile);
-  if (read_addrmap_from_aranges (per_objfile, section, &mutable_map))
-    per_bfd->index_addrmap
-      = new (&per_bfd->obstack) addrmap_fixed (&per_bfd->obstack,
-					       &mutable_map);
-}
-
 /* DWARF-5 debug_names reader.  */
 
-/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  */
-static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 };
+/* The old, no-longer-supported GDB augmentation.  */
+static const gdb_byte old_gdb_augmentation[]
+     = { 'G', 'D', 'B', 0 };
+static_assert (sizeof (old_gdb_augmentation) % 4 == 0);
+
+/* DWARF-5 augmentation string for GDB's DW_IDX_GNU_* extension.  This
+   must have a size that is a multiple of 4.  */
+static const gdb_byte dwarf5_augmentation[]
+     = { 'G', 'D', 'B', '2', 0, 0, 0, 0 };
+static_assert (sizeof (dwarf5_augmentation) % 4 == 0);
 
 /* A helper function that reads the .debug_names section in SECTION
    and fills in MAP.  FILENAME is the name of the file containing the
@@ -173,11 +413,13 @@ static const gdb_byte dwarf5_augmentation[] = { 'G', 'D', 'B', 0 };
    Returns true if all went well, false otherwise.  */
 
 static bool
-read_debug_names_from_section (struct objfile *objfile,
+read_debug_names_from_section (dwarf2_per_objfile *per_objfile,
 			       const char *filename,
 			       struct dwarf2_section_info *section,
-			       mapped_debug_names &map)
+			       mapped_debug_names_reader &map)
 {
+  struct objfile *objfile = per_objfile->objfile;
+
   if (section->empty ())
     return false;
 
@@ -188,11 +430,13 @@ read_debug_names_from_section (struct objfile *objfile,
 
   section->read (objfile);
 
+  map.per_objfile = per_objfile;
   map.dwarf5_byte_order = gdbarch_byte_order (objfile->arch ());
 
   const gdb_byte *addr = section->buffer;
 
-  bfd *const abfd = section->get_bfd_owner ();
+  bfd *abfd = section->get_bfd_owner ();
+  map.abfd = abfd;
 
   unsigned int bytes_read;
   LONGEST length = read_initial_length (abfd, addr, &bytes_read);
@@ -271,11 +515,27 @@ read_debug_names_from_section (struct objfile *objfile,
      string.  This value is rounded up to a multiple of 4.  */
   uint32_t augmentation_string_size = read_4_bytes (abfd, addr);
   addr += 4;
+  augmentation_string_size += (-augmentation_string_size) & 3;
+
+  if (augmentation_string_size == sizeof (old_gdb_augmentation)
+      && memcmp (addr, old_gdb_augmentation,
+		 sizeof (old_gdb_augmentation)) == 0)
+    {
+      warning (_(".debug_names created by an old version of gdb; ignoring"));
+      return false;
+    }
+
   map.augmentation_is_gdb = ((augmentation_string_size
 			      == sizeof (dwarf5_augmentation))
 			     && memcmp (addr, dwarf5_augmentation,
 					sizeof (dwarf5_augmentation)) == 0);
-  augmentation_string_size += (-augmentation_string_size) & 3;
+
+  if (!map.augmentation_is_gdb)
+    {
+      warning (_(".debug_names not created by gdb; ignoring"));
+      return false;
+    }
+
   addr += augmentation_string_size;
 
   /* List of CUs */
@@ -308,7 +568,7 @@ read_debug_names_from_section (struct objfile *objfile,
 	break;
 
       const auto insertpair
-	= map.abbrev_map.emplace (index_num, mapped_debug_names::index_val ());
+	= map.abbrev_map.emplace (index_num, mapped_debug_names_reader::index_val ());
       if (!insertpair.second)
 	{
 	  warning (_("Section .debug_names in %s has duplicate index %s, "
@@ -316,13 +576,13 @@ read_debug_names_from_section (struct objfile *objfile,
 		   filename, pulongest (index_num));
 	  return false;
 	}
-      mapped_debug_names::index_val &indexval = insertpair.first->second;
+      mapped_debug_names_reader::index_val &indexval = insertpair.first->second;
       indexval.dwarf_tag = read_unsigned_leb128 (abfd, addr, &bytes_read);
       addr += bytes_read;
 
       for (;;)
 	{
-	  mapped_debug_names::index_val::attr attr;
+	  mapped_debug_names_reader::index_val::attr attr;
 	  attr.dw_idx = read_unsigned_leb128 (abfd, addr, &bytes_read);
 	  addr += bytes_read;
 	  attr.form = read_unsigned_leb128 (abfd, addr, &bytes_read);
@@ -356,9 +616,9 @@ read_debug_names_from_section (struct objfile *objfile,
 
 static bool
 check_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd,
-				 const mapped_debug_names &map,
-				 dwarf2_section_info &section,
-				 bool is_dwz)
+				  const mapped_debug_names_reader &map,
+				  dwarf2_section_info &section,
+				  bool is_dwz)
 {
   int nr_cus = per_bfd->all_comp_units.size ();
 
@@ -420,8 +680,8 @@ check_cus_from_debug_names_list (dwarf2_per_bfd *per_bfd,
 
 static bool
 check_cus_from_debug_names (dwarf2_per_bfd *per_bfd,
-			    const mapped_debug_names &map,
-			    const mapped_debug_names &dwz_map)
+			     const mapped_debug_names_reader &map,
+			     const mapped_debug_names_reader &dwz_map)
 {
   if (!check_cus_from_debug_names_list (per_bfd, map, per_bfd->info,
 					false /* is_dwz */))
@@ -435,22 +695,23 @@ check_cus_from_debug_names (dwarf2_per_bfd *per_bfd,
 					  true /* is_dwz */);
 }
 
-/* See read-debug-names.h.  */
+/* This does all the work for dwarf2_read_debug_names, but putting it
+   into a separate function makes some cleanup a bit simpler.  */
 
-bool
-dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
+static bool
+do_dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
 {
-  auto map = std::make_unique<mapped_debug_names> ();
-  mapped_debug_names dwz_map;
+  mapped_debug_names_reader map;
+  mapped_debug_names_reader dwz_map;
   struct objfile *objfile = per_objfile->objfile;
   dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
 
-  if (!read_debug_names_from_section (objfile, objfile_name (objfile),
-				      &per_bfd->debug_names, *map))
+  if (!read_debug_names_from_section (per_objfile, objfile_name (objfile),
+				      &per_bfd->debug_names, map))
     return false;
 
   /* Don't use the index if it's empty.  */
-  if (map->name_count == 0)
+  if (map.name_count == 0)
     return false;
 
   /* If there is a .dwz file, read it so we can get its CU list as
@@ -458,7 +719,7 @@ dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
   dwz_file *dwz = dwarf2_get_dwz_file (per_bfd);
   if (dwz != NULL)
     {
-      if (!read_debug_names_from_section (objfile,
+      if (!read_debug_names_from_section (per_objfile,
 					  bfd_get_filename (dwz->dwz_bfd.get ()),
 					  &dwz->debug_names, dwz_map))
 	{
@@ -469,525 +730,53 @@ dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
     }
 
   create_all_units (per_objfile);
-  if (!check_cus_from_debug_names (per_bfd, *map, dwz_map))
-    {
-      per_bfd->all_units.clear ();
-      return false;
-    }
+  if (!check_cus_from_debug_names (per_bfd, map, dwz_map))
+    return false;
 
-  if (map->tu_count != 0)
+  if (map.tu_count != 0)
     {
       /* We can only handle a single .debug_types when we have an
 	 index.  */
       if (per_bfd->types.size () > 1)
-	{
-	  per_bfd->all_units.clear ();
-	  return false;
-	}
+	return false;
 
       dwarf2_section_info *section
 	= (per_bfd->types.size () == 1
 	   ? &per_bfd->types[0]
 	   : &per_bfd->info);
 
-      if (!check_signatured_type_table_from_debug_names
-	     (per_objfile, *map, section))
-	{
-	  per_bfd->all_units.clear ();
-	  return false;
-	}
-    }
-
-  create_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges);
-
-  per_bfd->index_table = std::move (map);
-  per_bfd->quick_file_names_table =
-    create_quick_file_names_table (per_bfd->all_units.size ());
-
-  return true;
-}
-
-/* Type used to manage iterating over all CUs looking for a symbol for
-   .debug_names.  */
-
-class dw2_debug_names_iterator
-{
-public:
-  dw2_debug_names_iterator (const mapped_debug_names &map,
-			    block_search_flags block_index,
-			    domain_enum domain,
-			    const char *name, dwarf2_per_objfile *per_objfile)
-    : m_map (map), m_block_index (block_index), m_domain (domain),
-      m_addr (find_vec_in_debug_names (map, name, per_objfile)),
-      m_per_objfile (per_objfile)
-  {}
-
-  dw2_debug_names_iterator (const mapped_debug_names &map,
-			    search_domain search, uint32_t namei,
-			    dwarf2_per_objfile *per_objfile,
-			    domain_enum domain = UNDEF_DOMAIN)
-    : m_map (map),
-      m_domain (domain),
-      m_search (search),
-      m_addr (find_vec_in_debug_names (map, namei, per_objfile)),
-      m_per_objfile (per_objfile)
-  {}
-
-  dw2_debug_names_iterator (const mapped_debug_names &map,
-			    block_search_flags block_index, domain_enum domain,
-			    uint32_t namei, dwarf2_per_objfile *per_objfile)
-    : m_map (map), m_block_index (block_index), m_domain (domain),
-      m_addr (find_vec_in_debug_names (map, namei, per_objfile)),
-      m_per_objfile (per_objfile)
-  {}
-
-  /* Return the next matching CU or NULL if there are no more.  */
-  dwarf2_per_cu_data *next ();
-
-private:
-  static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map,
-						  const char *name,
-						  dwarf2_per_objfile *per_objfile);
-  static const gdb_byte *find_vec_in_debug_names (const mapped_debug_names &map,
-						  uint32_t namei,
-						  dwarf2_per_objfile *per_objfile);
-
-  /* The internalized form of .debug_names.  */
-  const mapped_debug_names &m_map;
-
-  /* Restrict the search to these blocks.  */
-  block_search_flags m_block_index = (SEARCH_GLOBAL_BLOCK
-				      | SEARCH_STATIC_BLOCK);
-
-  /* The kind of symbol we're looking for.  */
-  const domain_enum m_domain = UNDEF_DOMAIN;
-  const search_domain m_search = ALL_DOMAIN;
-
-  /* The list of CUs from the index entry of the symbol, or NULL if
-     not found.  */
-  const gdb_byte *m_addr;
-
-  dwarf2_per_objfile *m_per_objfile;
-};
-
-const char *
-mapped_debug_names::namei_to_name
-  (uint32_t namei, dwarf2_per_objfile *per_objfile) const
-{
-  const ULONGEST namei_string_offs
-    = extract_unsigned_integer ((name_table_string_offs_reordered
-				 + namei * offset_size),
-				offset_size,
-				dwarf5_byte_order);
-  return read_indirect_string_at_offset (per_objfile, namei_string_offs);
-}
-
-/* Find a slot in .debug_names for the object named NAME.  If NAME is
-   found, return pointer to its pool data.  If NAME cannot be found,
-   return NULL.  */
-
-const gdb_byte *
-dw2_debug_names_iterator::find_vec_in_debug_names
-  (const mapped_debug_names &map, const char *name,
-   dwarf2_per_objfile *per_objfile)
-{
-  int (*cmp) (const char *, const char *);
-
-  gdb::unique_xmalloc_ptr<char> without_params;
-  if (current_language->la_language == language_cplus
-      || current_language->la_language == language_fortran
-      || current_language->la_language == language_d)
-    {
-      /* NAME is already canonical.  Drop any qualifiers as
-	 .debug_names does not contain any.  */
-
-      if (strchr (name, '(') != NULL)
-	{
-	  without_params = cp_remove_params (name);
-	  if (without_params != NULL)
-	    name = without_params.get ();
-	}
-    }
-
-  cmp = (case_sensitivity == case_sensitive_on ? strcmp : strcasecmp);
-
-  const uint32_t full_hash = dwarf5_djb_hash (name);
-  uint32_t namei
-    = extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
-				(map.bucket_table_reordered
-				 + (full_hash % map.bucket_count)), 4,
-				map.dwarf5_byte_order);
-  if (namei == 0)
-    return NULL;
-  --namei;
-  if (namei >= map.name_count)
-    {
-      complaint (_("Wrong .debug_names with name index %u but name_count=%u "
-		   "[in module %s]"),
-		 namei, map.name_count,
-		 objfile_name (per_objfile->objfile));
-      return NULL;
-    }
-
-  for (;;)
-    {
-      const uint32_t namei_full_hash
-	= extract_unsigned_integer (reinterpret_cast<const gdb_byte *>
-				    (map.hash_table_reordered + namei), 4,
-				    map.dwarf5_byte_order);
-      if (full_hash % map.bucket_count != namei_full_hash % map.bucket_count)
-	return NULL;
-
-      if (full_hash == namei_full_hash)
-	{
-	  const char *const namei_string = map.namei_to_name (namei, per_objfile);
-
-#if 0 /* An expensive sanity check.  */
-	  if (namei_full_hash != dwarf5_djb_hash (namei_string))
-	    {
-	      complaint (_("Wrong .debug_names hash for string at index %u "
-			   "[in module %s]"),
-			 namei, objfile_name (dwarf2_per_objfile->objfile));
-	      return NULL;
-	    }
-#endif
-
-	  if (cmp (namei_string, name) == 0)
-	    {
-	      const ULONGEST namei_entry_offs
-		= extract_unsigned_integer ((map.name_table_entry_offs_reordered
-					     + namei * map.offset_size),
-					    map.offset_size, map.dwarf5_byte_order);
-	      return map.entry_pool + namei_entry_offs;
-	    }
-	}
-
-      ++namei;
-      if (namei >= map.name_count)
-	return NULL;
-    }
-}
-
-const gdb_byte *
-dw2_debug_names_iterator::find_vec_in_debug_names
-  (const mapped_debug_names &map, uint32_t namei, dwarf2_per_objfile *per_objfile)
-{
-  if (namei >= map.name_count)
-    {
-      complaint (_("Wrong .debug_names with name index %u but name_count=%u "
-		   "[in module %s]"),
-		 namei, map.name_count,
-		 objfile_name (per_objfile->objfile));
-      return NULL;
-    }
-
-  const ULONGEST namei_entry_offs
-    = extract_unsigned_integer ((map.name_table_entry_offs_reordered
-				 + namei * map.offset_size),
-				map.offset_size, map.dwarf5_byte_order);
-  return map.entry_pool + namei_entry_offs;
-}
-
-/* See dw2_debug_names_iterator.  */
-
-dwarf2_per_cu_data *
-dw2_debug_names_iterator::next ()
-{
-  if (m_addr == NULL)
-    return NULL;
-
-  dwarf2_per_bfd *per_bfd = m_per_objfile->per_bfd;
-  struct objfile *objfile = m_per_objfile->objfile;
-  bfd *const abfd = objfile->obfd.get ();
-
- again:
-
-  unsigned int bytes_read;
-  const ULONGEST abbrev = read_unsigned_leb128 (abfd, m_addr, &bytes_read);
-  m_addr += bytes_read;
-  if (abbrev == 0)
-    return NULL;
-
-  const auto indexval_it = m_map.abbrev_map.find (abbrev);
-  if (indexval_it == m_map.abbrev_map.cend ())
-    {
-      complaint (_("Wrong .debug_names undefined abbrev code %s "
-		   "[in module %s]"),
-		 pulongest (abbrev), objfile_name (objfile));
-      return NULL;
-    }
-  const mapped_debug_names::index_val &indexval = indexval_it->second;
-  enum class symbol_linkage {
-    unknown,
-    static_,
-    extern_,
-  } symbol_linkage_ = symbol_linkage::unknown;
-  dwarf2_per_cu_data *per_cu = NULL;
-  for (const mapped_debug_names::index_val::attr &attr : indexval.attr_vec)
-    {
-      ULONGEST ull;
-      switch (attr.form)
-	{
-	case DW_FORM_implicit_const:
-	  ull = attr.implicit_const;
-	  break;
-	case DW_FORM_flag_present:
-	  ull = 1;
-	  break;
-	case DW_FORM_udata:
-	  ull = read_unsigned_leb128 (abfd, m_addr, &bytes_read);
-	  m_addr += bytes_read;
-	  break;
-	case DW_FORM_ref4:
-	  ull = read_4_bytes (abfd, m_addr);
-	  m_addr += 4;
-	  break;
-	case DW_FORM_ref8:
-	  ull = read_8_bytes (abfd, m_addr);
-	  m_addr += 8;
-	  break;
-	case DW_FORM_ref_sig8:
-	  ull = read_8_bytes (abfd, m_addr);
-	  m_addr += 8;
-	  break;
-	default:
-	  complaint (_("Unsupported .debug_names form %s [in module %s]"),
-		     dwarf_form_name (attr.form),
-		     objfile_name (objfile));
-	  return NULL;
-	}
-      switch (attr.dw_idx)
-	{
-	case DW_IDX_compile_unit:
-	  {
-	    /* Don't crash on bad data.  */
-	    if (ull >= per_bfd->all_comp_units.size ())
-	      {
-		complaint (_(".debug_names entry has bad CU index %s"
-			     " [in module %s]"),
-			   pulongest (ull),
-			   objfile_name (objfile));
-		continue;
-	      }
-	  }
-	  per_cu = per_bfd->get_index_cu (ull);
-	  break;
-	case DW_IDX_type_unit:
-	  /* Don't crash on bad data.  */
-	  if (ull >= per_bfd->all_type_units.size ())
-	    {
-	      complaint (_(".debug_names entry has bad TU index %s"
-			   " [in module %s]"),
-			 pulongest (ull),
-			 objfile_name (objfile));
-	      continue;
-	    }
-	  {
-	    per_cu = per_bfd->get_index_tu (ull);
-	  }
-	  break;
-	case DW_IDX_die_offset:
-	  /* In a per-CU index (as opposed to a per-module index), index
-	     entries without CU attribute implicitly refer to the single CU.  */
-	  if (per_cu == NULL)
-	    per_cu = per_bfd->get_index_cu (0);
-	  break;
-	case DW_IDX_GNU_internal:
-	  if (!m_map.augmentation_is_gdb)
-	    break;
-	  symbol_linkage_ = symbol_linkage::static_;
-	  break;
-	case DW_IDX_GNU_external:
-	  if (!m_map.augmentation_is_gdb)
-	    break;
-	  symbol_linkage_ = symbol_linkage::extern_;
-	  break;
-	}
+      if (!check_signatured_type_table_from_debug_names (per_objfile,
+							 map, section))
+	return false;
     }
 
-  /* Skip if we couldn't find a valid CU/TU index.  */
-  if (per_cu == nullptr)
-    goto again;
+  per_bfd->debug_aranges.read (per_objfile->objfile);
+  addrmap_mutable addrmap;
+  if (!read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges,
+				  &addrmap))
+    return false;
 
-  /* Skip if already read in.  */
-  if (m_per_objfile->symtab_set_p (per_cu))
-    goto again;
+  map.shard = std::make_unique<cooked_index_shard> ();
+  map.shard->install_addrmap (&addrmap);
 
-  /* Check static vs global.  */
-  if (symbol_linkage_ != symbol_linkage::unknown)
-    {
-      if (symbol_linkage_ == symbol_linkage::static_)
-	{
-	  if ((m_block_index & SEARCH_STATIC_BLOCK) == 0)
-	    goto again;
-	}
-      else
-	{
-	  if ((m_block_index & SEARCH_GLOBAL_BLOCK) == 0)
-	    goto again;
-	}
-    }
+  cooked_index *idx
+    = new debug_names_index (per_objfile,
+			     (std::make_unique<cooked_index_debug_names>
+			      (per_objfile, std::move (map))));
+  per_bfd->index_table.reset (idx);
 
-  /* Match dw2_symtab_iter_next, symbol_kind
-     and debug_names::psymbol_tag.  */
-  switch (m_domain)
-    {
-    case VAR_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case DW_TAG_variable:
-	case DW_TAG_subprogram:
-	/* Some types are also in VAR_DOMAIN.  */
-	case DW_TAG_typedef:
-	case DW_TAG_structure_type:
-	  break;
-	default:
-	  goto again;
-	}
-      break;
-    case STRUCT_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case DW_TAG_typedef:
-	case DW_TAG_structure_type:
-	  break;
-	default:
-	  goto again;
-	}
-      break;
-    case LABEL_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case 0:
-	case DW_TAG_variable:
-	  break;
-	default:
-	  goto again;
-	}
-      break;
-    case MODULE_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case DW_TAG_module:
-	  break;
-	default:
-	  goto again;
-	}
-      break;
-    default:
-      break;
-    }
-
-  /* Match dw2_expand_symtabs_matching, symbol_kind and
-     debug_names::psymbol_tag.  */
-  switch (m_search)
-    {
-    case VARIABLES_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case DW_TAG_variable:
-	  break;
-	default:
-	  goto again;
-	}
-      break;
-    case FUNCTIONS_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case DW_TAG_subprogram:
-	  break;
-	default:
-	  goto again;
-	}
-      break;
-    case TYPES_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case DW_TAG_typedef:
-	case DW_TAG_structure_type:
-	  break;
-	default:
-	  goto again;
-	}
-      break;
-    case MODULES_DOMAIN:
-      switch (indexval.dwarf_tag)
-	{
-	case DW_TAG_module:
-	  break;
-	default:
-	  goto again;
-	}
-    default:
-      break;
-    }
+  idx->start_reading ();
 
-  return per_cu;
+  return true;
 }
 
-/* This dumps minimal information about .debug_names.  It is called
-   via "mt print objfiles".  The gdb.dwarf2/gdb-index.exp testcase
-   uses this to verify that .debug_names has been loaded.  */
-
-void
-dwarf2_debug_names_index::dump (struct objfile *objfile)
-{
-  gdb_printf (".debug_names: exists\n");
-}
+/* See read-debug-names.h.  */
 
 bool
-dwarf2_debug_names_index::expand_symtabs_matching
-  (struct objfile *objfile,
-   gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
-   const lookup_name_info *lookup_name,
-   gdb::function_view<expand_symtabs_symbol_matcher_ftype> symbol_matcher,
-   gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify,
-   block_search_flags search_flags,
-   domain_enum domain,
-   enum search_domain kind)
+dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
 {
-  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-
-  dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher);
-
-  /* This invariant is documented in quick-functions.h.  */
-  gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr);
-  if (lookup_name == nullptr)
-    {
-      for (dwarf2_per_cu_data *per_cu
-	     : all_units_range (per_objfile->per_bfd))
-	{
-	  QUIT;
-
-	  if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile,
-						file_matcher,
-						expansion_notify))
-	    return false;
-	}
-      return true;
-    }
-
-  mapped_debug_names &map
-    = *(gdb::checked_static_cast<mapped_debug_names *>
-	(per_objfile->per_bfd->index_table.get ()));
-
-  bool result
-    = dw2_expand_symtabs_matching_symbol (map, *lookup_name,
-					  symbol_matcher,
-					  [&] (offset_type namei)
-    {
-      /* The name was matched, now expand corresponding CUs that were
-	 marked.  */
-      dw2_debug_names_iterator iter (map, kind, namei, per_objfile, domain);
-
-      struct dwarf2_per_cu_data *per_cu;
-      while ((per_cu = iter.next ()) != NULL)
-	if (!dw2_expand_symtabs_matching_one (per_cu, per_objfile,
-					      file_matcher,
-					      expansion_notify))
-	  return false;
-      return true;
-    }, per_objfile);
-
+  bool result = do_dwarf2_read_debug_names (per_objfile);
+  if (!result)
+    per_objfile->per_bfd->all_units.clear ();
   return result;
 }

-- 
2.43.0


  parent reply	other threads:[~2023-12-10 16:45 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-12-10 16:44 [PATCH 00/17] Rewrite .debug_names reader and writer Tom Tromey
2023-12-10 16:44 ` [PATCH 01/17] Refactor 'maint set dwarf synchronous' handling Tom Tromey
2023-12-10 16:44 ` [PATCH 02/17] Refactor quick-function installation in DWARF reader Tom Tromey
2023-12-10 16:44 ` [PATCH 03/17] Remove IS_ENUM_CLASS from cooked_index_flag Tom Tromey
2023-12-10 16:44 ` [PATCH 04/17] Add some new DW_IDX_* values Tom Tromey
2024-01-09 15:08   ` Tom Tromey
2024-01-09 19:02     ` Tom Tromey
2023-12-10 16:44 ` [PATCH 05/17] Document GDB extensions to DWARF .debug_names Tom Tromey
2023-12-10 17:37   ` Eli Zaretskii
2024-01-17 16:24     ` Tom Tromey
2023-12-10 16:44 ` [PATCH 06/17] Add language to cooked_index_entry Tom Tromey
2023-12-10 16:44 ` [PATCH 07/17] Move cooked_index_functions to cooked-index.h Tom Tromey
2023-12-10 16:44 ` [PATCH 08/17] Do not write the index cache from an index Tom Tromey
2023-12-10 16:44 ` [PATCH 09/17] Change cooked_index_worker to abstract base class Tom Tromey
2023-12-10 16:44 ` [PATCH 10/17] Remove cooked_index_worker::start_reading Tom Tromey
2023-12-10 16:45 ` [PATCH 11/17] Empty hash table fix in .debug_names reader Tom Tromey
2023-12-10 16:45 ` [PATCH 12/17] Fix dw2-zero-range.exp when an index is in use Tom Tromey
2023-12-10 16:45 ` [PATCH 13/17] Explicitly expand CUs in dw2-inline-with-lexical-scope.exp Tom Tromey
2023-12-10 16:45 ` [PATCH 14/17] Remove some .debug_names tests Tom Tromey
2023-12-10 16:45 ` Tom Tromey [this message]
2023-12-10 16:45 ` [PATCH 16/17] Export dwarf5_augmentation Tom Tromey
2023-12-10 16:45 ` [PATCH 17/17] Rewrite .debug_names writer Tom Tromey

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231210-debug-names-fix-v1-15-a8f6d2525018@tromey.com \
    --to=tom@tromey.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).