public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v2 00/32] Rewrite the DWARF "partial" reader
@ 2021-11-04 18:08 Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 01/32] Introduce make_unique_xstrndup Tom Tromey
                   ` (33 more replies)
  0 siblings, 34 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches

Here is v2 of my series to rewrit the DWARF partial symbol reader.

You can find v1 here:

    https://sourceware.org/pipermail/gdb-patches/2021-August/181624.html

This update addresses all the review comments.  I believe it fixes all
the problems that Tom de Vries found.

I regression tested this on x86-64 Fedora 34.

Let me know what you think.

Tom



^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 01/32] Introduce make_unique_xstrndup
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-05 19:20   ` Simon Marchi
  2021-11-04 18:08 ` [PATCH v2 02/32] Split create_addrmap_from_aranges Tom Tromey
                   ` (32 subsequent siblings)
  33 siblings, 1 reply; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds a new make_unique_xstrndup function, which is the "n"
analogue of make_unique_xstrdup.  This is used by later patches.
---
 gdbsupport/gdb_unique_ptr.h | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/gdbsupport/gdb_unique_ptr.h b/gdbsupport/gdb_unique_ptr.h
index df88cea9cf0..77aecb48e62 100644
--- a/gdbsupport/gdb_unique_ptr.h
+++ b/gdbsupport/gdb_unique_ptr.h
@@ -64,4 +64,13 @@ make_unique_xstrdup (const char *str)
   return gdb::unique_xmalloc_ptr<char> (xstrdup (str));
 }
 
+/* Dup the first N characters of STR and return a unique_xmalloc_ptr
+   for the result.  The result is always \0-terminated.  */
+
+static inline gdb::unique_xmalloc_ptr<char>
+make_unique_xstrndup (const char *str, size_t n)
+{
+  return gdb::unique_xmalloc_ptr<char> (xstrndup (str, n));
+}
+
 #endif /* COMMON_GDB_UNIQUE_PTR_H */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 02/32] Split create_addrmap_from_aranges
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 01/32] Introduce make_unique_xstrndup Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 03/32] Add dwarf2_per_cu_data::addresses_seen Tom Tromey
                   ` (31 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This patch splits create_addrmap_from_aranges into a wrapper function
and a worker function.  The worker function is then used in a later
patch.
---
 gdb/dwarf2/read.c | 49 +++++++++++++++++++++++++++++++----------------
 1 file changed, 32 insertions(+), 17 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 48fb55c308c..ffa62b645aa 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2595,12 +2595,14 @@ create_addrmap_from_index (dwarf2_per_objfile *per_objfile,
 						 &per_bfd->obstack);
 }
 
-/* Read the address map data from DWARF-5 .debug_aranges, and use it to
-   populate the psymtabs_addrmap.  */
+/* Read the address map data from DWARF-5 .debug_aranges, and use it
+   to populate given addrmap.  Returns true on success, false on
+   failure.  */
 
-static void
-create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
-			     struct dwarf2_section_info *section)
+static bool
+read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
+			   struct dwarf2_section_info *section,
+			   addrmap *mutable_map)
 {
   struct objfile *objfile = per_objfile->objfile;
   bfd *abfd = objfile->obfd;
@@ -2608,9 +2610,6 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
   const CORE_ADDR baseaddr = objfile->text_section_offset ();
   dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
 
-  auto_obstack temp_obstack;
-  addrmap *mutable_map = addrmap_create_mutable (&temp_obstack);
-
   std::unordered_map<sect_offset,
 		     dwarf2_per_cu_data *,
 		     gdb::hash_enum<sect_offset>>
@@ -2631,7 +2630,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 	  warning (_("Section .debug_aranges in %s has duplicate "
 		     "debug_info_offset %s, ignoring .debug_aranges."),
 		   objfile_name (objfile), sect_offset_str (per_cu->sect_off));
-	  return;
+	  return false;
 	}
     }
 
@@ -2662,7 +2661,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 		   plongest (entry_addr - section->buffer),
 		   plongest (bytes_read + entry_length),
 		   pulongest (section->size));
-	  return;
+	  return false;
 	}
 
       /* The version number.  */
@@ -2674,7 +2673,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 		     "has unsupported version %d, ignoring .debug_aranges."),
 		   objfile_name (objfile),
 		   plongest (entry_addr - section->buffer), version);
-	  return;
+	  return false;
 	}
 
       const uint64_t debug_info_offset
@@ -2690,7 +2689,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 		   objfile_name (objfile),
 		   plongest (entry_addr - section->buffer),
 		   pulongest (debug_info_offset));
-	  return;
+	  return false;
 	}
       dwarf2_per_cu_data *const per_cu = per_cu_it->second;
 
@@ -2701,7 +2700,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 		     "address_size %u is invalid, ignoring .debug_aranges."),
 		   objfile_name (objfile),
 		   plongest (entry_addr - section->buffer), address_size);
-	  return;
+	  return false;
 	}
 
       const uint8_t segment_selector_size = *addr++;
@@ -2713,7 +2712,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 		   objfile_name (objfile),
 		   plongest (entry_addr - section->buffer),
 		   segment_selector_size);
-	  return;
+	  return false;
 	}
 
       /* Must pad to an alignment boundary that is twice the address
@@ -2734,7 +2733,7 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 			 "ignoring .debug_aranges."),
 		       objfile_name (objfile),
 		       plongest (entry_addr - section->buffer));
-	      return;
+	      return false;
 	    }
 	  ULONGEST start = extract_unsigned_integer (addr, address_size,
 						     dwarf5_byte_order);
@@ -2758,8 +2757,24 @@ create_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 	}
     }
 
-  per_bfd->index_addrmap = addrmap_create_fixed (mutable_map,
-						 &per_bfd->obstack);
+  return true;
+}
+
+/* Read the address map data from DWARF-5 .debug_aranges, and use it to
+   populate the psymtabs_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;
+
+  auto_obstack temp_obstack;
+  addrmap *mutable_map = addrmap_create_mutable (&temp_obstack);
+
+  if (read_addrmap_from_aranges (per_objfile, section, mutable_map))
+    per_bfd->index_addrmap = addrmap_create_fixed (mutable_map,
+						   &per_bfd->obstack);
 }
 
 /* A helper function that reads the .gdb_index from BUFFER and fills
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 03/32] Add dwarf2_per_cu_data::addresses_seen
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 01/32] Introduce make_unique_xstrndup Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 02/32] Split create_addrmap_from_aranges Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 04/32] Refactor dwarf2_get_pc_bounds Tom Tromey
                   ` (30 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds a new member to dwarf2_per_cu_data that indicates whether
addresses have been seen for this CU.  This is then set by the
.debug_aranges reader.  The idea here is to detect when a CU does not
have address information, so that the new indexer will know to do
extra scanning in that case.
---
 gdb/dwarf2/read.c | 2 ++
 gdb/dwarf2/read.h | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index ffa62b645aa..88cb70ed1bb 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2755,6 +2755,8 @@ read_addrmap_from_aranges (dwarf2_per_objfile *per_objfile,
 		 - baseaddr);
 	  addrmap_set_empty (mutable_map, start, end - 1, per_cu);
 	}
+
+      per_cu->addresses_seen = true;
     }
 
   return true;
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 1638d8521c0..1a41d2992f7 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -103,6 +103,7 @@ struct dwarf2_per_cu_data
       reading_dwo_directly (false),
       tu_read (false),
       m_header_read_in (false),
+      addresses_seen (false),
       unit_type {},
       lang (language_unknown)
   {
@@ -153,6 +154,10 @@ struct dwarf2_per_cu_data
      it private at the moment.  */
   mutable bool m_header_read_in : 1;
 
+  /* If addresses have been read for this CU (usually from
+     .debug_aranges), then this flag is set.  */
+  bool addresses_seen : 1;
+
   /* The unit type of this CU.  */
   ENUM_BITFIELD (dwarf_unit_type) unit_type : 8;
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 04/32] Refactor dwarf2_get_pc_bounds
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (2 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 03/32] Add dwarf2_per_cu_data::addresses_seen Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-05 19:51   ` Simon Marchi
  2021-11-04 18:08 ` [PATCH v2 05/32] Allow ada_decode not to decode operators Tom Tromey
                   ` (29 subsequent siblings)
  33 siblings, 1 reply; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes dwarf2_get_pc_bounds so that it does not directly access
a psymtab or psymtabs_addrmap.  Instead, both the addrmap and the
desired payload are passed as parameters.  This makes it suitable to
be used by the new indexer.
---
 gdb/dwarf2/read.c | 46 +++++++++++++++++++++++++++-------------------
 1 file changed, 27 insertions(+), 19 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 88cb70ed1bb..19b1e5c1d55 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -1298,7 +1298,8 @@ enum pc_bounds_kind
 static enum pc_bounds_kind dwarf2_get_pc_bounds (struct die_info *,
 						 CORE_ADDR *, CORE_ADDR *,
 						 struct dwarf2_cu *,
-						 dwarf2_psymtab *);
+						 addrmap *,
+						 void *);
 
 static void get_scope_pc_bounds (struct die_info *,
 				 CORE_ADDR *, CORE_ADDR *,
@@ -7038,8 +7039,11 @@ process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
 
   /* Possibly set the default values of LOWPC and HIGHPC from
      `DW_AT_ranges'.  */
-  cu_bounds_kind = dwarf2_get_pc_bounds (comp_unit_die, &best_lowpc,
-					 &best_highpc, cu, pst);
+  cu_bounds_kind
+    = dwarf2_get_pc_bounds (comp_unit_die, &best_lowpc,
+			    &best_highpc, cu,
+			    per_bfd->partial_symtabs->psymtabs_addrmap,
+			    pst);
   if (cu_bounds_kind == PC_BOUNDS_HIGH_LOW && best_lowpc < best_highpc)
     {
       CORE_ADDR low
@@ -8156,9 +8160,9 @@ add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
     scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu);
 }
 
-static int
-dwarf2_ranges_read (unsigned, CORE_ADDR *, CORE_ADDR *, struct dwarf2_cu *,
-		    dwarf2_psymtab *, dwarf_tag);
+static int dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
+			       CORE_ADDR *high_return, struct dwarf2_cu *cu,
+			       addrmap *map, void *datum, dwarf_tag tag);
 
 /* Read a partial die corresponding to a subprogram or an inlined
    subprogram and create a partial symbol for that subprogram.
@@ -8212,6 +8216,9 @@ add_partial_subprogram (struct partial_die_info *pdi,
       if (pdi->has_range_info
 	  && dwarf2_ranges_read (pdi->ranges_offset, &pdi->lowpc, &pdi->highpc,
 				 cu,
+				 (set_addrmap
+				  ? cu->per_objfile->per_bfd->partial_symtabs->psymtabs_addrmap
+				  : nullptr),
 				 set_addrmap ? cu->per_cu->v.psymtab : nullptr,
 				 pdi->tag))
 	{
@@ -13112,7 +13119,7 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
     }
 
   /* Ignore functions with missing or invalid low and high pc attributes.  */
-  if (dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL)
+  if (dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, nullptr, nullptr)
       <= PC_BOUNDS_INVALID)
     {
       attr = dwarf2_attr (die, DW_AT_external, cu);
@@ -13285,7 +13292,7 @@ read_lexical_block_scope (struct die_info *die, struct dwarf2_cu *cu)
      as multiple lexical blocks?  Handling children in a sane way would
      be nasty.  Might be easier to properly extend generic blocks to
      describe ranges.  */
-  switch (dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, NULL))
+  switch (dwarf2_get_pc_bounds (die, &lowpc, &highpc, cu, nullptr, nullptr))
     {
     case PC_BOUNDS_NOT_PRESENT:
       /* DW_TAG_lexical_block has no attributes, process its children as if
@@ -13530,7 +13537,8 @@ read_call_site_scope (struct die_info *die, struct dwarf2_cu *cu)
 	  CORE_ADDR lowpc;
 
 	  /* DW_AT_entry_pc should be preferred.  */
-	  if (dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu, NULL)
+	  if (dwarf2_get_pc_bounds (target_die, &lowpc, NULL, target_cu,
+				    nullptr, nullptr)
 	      <= PC_BOUNDS_INVALID)
 	    complaint (_("DW_AT_call_target target DIE has invalid "
 			 "low pc, for referencing DIE %s [in module %s]"),
@@ -14036,10 +14044,9 @@ dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu, dwarf_tag tag,
 static int
 dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
 		    CORE_ADDR *high_return, struct dwarf2_cu *cu,
-		    dwarf2_psymtab *ranges_pst, dwarf_tag tag)
+		    addrmap *map, void *datum, dwarf_tag tag)
 {
   struct objfile *objfile = cu->per_objfile->objfile;
-  dwarf2_per_bfd *per_bfd = cu->per_objfile->per_bfd;
   struct gdbarch *gdbarch = objfile->arch ();
   const CORE_ADDR baseaddr = objfile->text_section_offset ();
   int low_set = 0;
@@ -14050,7 +14057,7 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
   retval = dwarf2_ranges_process (offset, cu, tag,
     [&] (CORE_ADDR range_beginning, CORE_ADDR range_end)
     {
-      if (ranges_pst != NULL)
+      if (map != nullptr)
 	{
 	  CORE_ADDR lowpc;
 	  CORE_ADDR highpc;
@@ -14061,8 +14068,7 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
 	  highpc = (gdbarch_adjust_dwarf2_addr (gdbarch,
 						range_end + baseaddr)
 		    - baseaddr);
-	  addrmap_set_empty (per_bfd->partial_symtabs->psymtabs_addrmap,
-			     lowpc, highpc - 1, ranges_pst);
+	  addrmap_set_empty (map, lowpc, highpc - 1, datum);
 	}
 
       /* FIXME: This is recording everything as a low-high
@@ -14105,7 +14111,7 @@ dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
 static enum pc_bounds_kind
 dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
 		      CORE_ADDR *highpc, struct dwarf2_cu *cu,
-		      dwarf2_psymtab *pst)
+		      addrmap *map, void *datum)
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct attribute *attr;
@@ -14148,8 +14154,8 @@ dwarf2_get_pc_bounds (struct die_info *die, CORE_ADDR *lowpc,
 
 	  /* Value of the DW_AT_ranges attribute is the offset in the
 	     .debug_ranges section.  */
-	  if (!dwarf2_ranges_read (ranges_offset, &low, &high, cu, pst,
-				   die->tag))
+	  if (!dwarf2_ranges_read (ranges_offset, &low, &high, cu,
+				   map, datum, die->tag))
 	    return PC_BOUNDS_INVALID;
 	  /* Found discontinuous range of addresses.  */
 	  ret = PC_BOUNDS_RANGES;
@@ -14192,7 +14198,8 @@ dwarf2_get_subprogram_pc_bounds (struct die_info *die,
   CORE_ADDR low, high;
   struct die_info *child = die->child;
 
-  if (dwarf2_get_pc_bounds (die, &low, &high, cu, NULL) >= PC_BOUNDS_RANGES)
+  if (dwarf2_get_pc_bounds (die, &low, &high, cu, nullptr, nullptr)
+      >= PC_BOUNDS_RANGES)
     {
       *lowpc = std::min (*lowpc, low);
       *highpc = std::max (*highpc, high);
@@ -14229,7 +14236,8 @@ get_scope_pc_bounds (struct die_info *die,
   CORE_ADDR best_high = (CORE_ADDR) 0;
   CORE_ADDR current_low, current_high;
 
-  if (dwarf2_get_pc_bounds (die, &current_low, &current_high, cu, NULL)
+  if (dwarf2_get_pc_bounds (die, &current_low, &current_high, cu,
+			    nullptr, nullptr)
       >= PC_BOUNDS_RANGES)
     {
       best_low = current_low;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 05/32] Allow ada_decode not to decode operators
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (3 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 04/32] Refactor dwarf2_get_pc_bounds Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 06/32] Let skip_one_die not skip children Tom Tromey
                   ` (28 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The new DWARF scanner records names as they appear in DWARF.  However,
because Ada is unusual, it also decodes the Ada names to synthesize
package components for them.  In order for this to work out properly,
gdb also needs a mode where ada_decode can be instructed not to decode
Ada operator names.  That is what this patch implements.
---
 gdb/ada-lang.c | 13 ++++++++-----
 gdb/ada-lang.h |  6 ++++--
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d964dae42cf..649a1b3f897 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -1002,7 +1002,7 @@ remove_compiler_suffix (const char *encoded, int *len)
 /* See ada-lang.h.  */
 
 std::string
-ada_decode (const char *encoded, bool wrap)
+ada_decode (const char *encoded, bool wrap, bool operators)
 {
   int i, j;
   int len0;
@@ -1096,7 +1096,7 @@ ada_decode (const char *encoded, bool wrap)
   while (i < len0)
     {
       /* Is this a symbol function?  */
-      if (at_start_name && encoded[i] == 'O')
+      if (operators && at_start_name && encoded[i] == 'O')
 	{
 	  int k;
 
@@ -1233,9 +1233,12 @@ ada_decode (const char *encoded, bool wrap)
   /* Decoded names should never contain any uppercase character.
      Double-check this, and abort the decoding if we find one.  */
 
-  for (i = 0; i < decoded.length(); ++i)
-    if (isupper (decoded[i]) || decoded[i] == ' ')
-      goto Suppress;
+  if (operators)
+    {
+      for (i = 0; i < decoded.length(); ++i)
+	if (isupper (decoded[i]) || decoded[i] == ' ')
+	  goto Suppress;
+    }
 
   /* If the compiler added a suffix, append it now.  */
   if (suffix >= 0)
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
index 0f52ba70649..f3cf9343f05 100644
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -218,8 +218,10 @@ extern const char *ada_decode_symbol (const struct general_symbol_info *);
    the name does not appear to be GNAT-encoded, then the result
    depends on WRAP.  If WRAP is true (the default), then the result is
    simply wrapped in <...>.  If WRAP is false, then the empty string
-   will be returned.  */
-extern std::string ada_decode (const char *name, bool wrap = true);
+   will be returned.  Also, when OPERATORS is false, operator names
+   will not be decoded.  */
+extern std::string ada_decode (const char *name, bool wrap = true,
+			       bool operators = true);
 
 extern std::vector<struct block_symbol> ada_lookup_symbol_list
      (const char *, const struct block *, domain_enum);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 06/32] Let skip_one_die not skip children
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (4 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 05/32] Allow ada_decode not to decode operators Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 07/32] Add name splitting Tom Tromey
                   ` (27 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This patch adds an option to skip_one_die that causes it not to skip
child DIEs.  This is needed in the new scanner.
---
 gdb/dwarf2/read.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 19b1e5c1d55..4e44fa2a058 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -1443,7 +1443,8 @@ static void dwarf2_symbol_mark_computed (const struct attribute *attr,
 
 static const gdb_byte *skip_one_die (const struct die_reader_specs *reader,
 				     const gdb_byte *info_ptr,
-				     const struct abbrev_info *abbrev);
+				     const struct abbrev_info *abbrev,
+				     bool do_skip_children = true);
 
 static hashval_t partial_die_hash (const void *item);
 
@@ -8346,12 +8347,15 @@ skip_children (const struct die_reader_specs *reader, const gdb_byte *info_ptr)
 /* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER.
    INFO_PTR should point just after the initial uleb128 of a DIE, and the
    abbrev corresponding to that skipped uleb128 should be passed in
-   ABBREV.  Returns a pointer to this DIE's sibling, skipping any
-   children.  */
+   ABBREV.
+   
+   If DO_SKIP_CHILDREN is true, or if the DIE has no children, this
+   returns a pointer to this DIE's sibling, skipping any children.
+   Otherwise, returns a pointer to the DIE's first child.  */
 
 static const gdb_byte *
 skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
-	      const struct abbrev_info *abbrev)
+	      const struct abbrev_info *abbrev, bool do_skip_children)
 {
   unsigned int bytes_read;
   struct attribute attr;
@@ -8364,7 +8368,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
   for (i = 0; i < abbrev->num_attrs; i++)
     {
       /* The only abbrev we care about is DW_AT_sibling.  */
-      if (abbrev->attrs[i].name == DW_AT_sibling)
+      if (do_skip_children && abbrev->attrs[i].name == DW_AT_sibling)
 	{
 	  read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
 	  if (attr.form == DW_FORM_ref_addr)
@@ -8481,7 +8485,7 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
 	}
     }
 
-  if (abbrev->has_children)
+  if (do_skip_children && abbrev->has_children)
     return skip_children (reader, info_ptr);
   else
     return info_ptr;
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 07/32] Add name splitting
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (5 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 06/32] Let skip_one_die not skip children Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 08/32] Add new overload of dwarf5_djb_hash Tom Tromey
                   ` (26 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The new DWARF index code works by keeping names pre-split.  That is,
rather than storing a symbol name like "a::b::c", the names "a", "b",
and "c" will be stored separately.

This patch introduces some helper code to split a full name into its
components.
---
 gdb/Makefile.in  |  2 ++
 gdb/split-name.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/split-name.h | 45 +++++++++++++++++++++++++++
 gdb/symtab.h     | 37 ++++++++++++++++++++++
 4 files changed, 165 insertions(+)
 create mode 100644 gdb/split-name.c
 create mode 100644 gdb/split-name.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index f71537f6595..73eaf12e339 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1154,6 +1154,7 @@ COMMON_SFILES = \
 	solib-target.c \
 	source.c \
 	source-cache.c \
+	split-name.c \
 	stabsread.c \
 	stack.c \
 	std-regs.c \
@@ -1445,6 +1446,7 @@ HFILES_NO_SRCDIR = \
 	sparc-ravenscar-thread.h \
 	sparc-tdep.h \
 	sparc64-tdep.h \
+	split-name.h \
 	stabsread.h \
 	stack.h \
 	stap-probe.h \
diff --git a/gdb/split-name.c b/gdb/split-name.c
new file mode 100644
index 00000000000..9e2fbd25659
--- /dev/null
+++ b/gdb/split-name.c
@@ -0,0 +1,81 @@
+/* Split a symbol name.
+
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "split-name.h"
+#include "cp-support.h"
+
+/* See split-name.h.  */
+
+std::vector<gdb::string_view>
+split_name (const char *name, split_style style)
+{
+  std::vector<gdb::string_view> result;
+  unsigned int previous_len = 0;
+
+  switch (style)
+    {
+    case split_style::CXX:
+      for (unsigned int current_len = cp_find_first_component (name);
+	   name[current_len] != '\0';
+	   current_len += cp_find_first_component (name + current_len))
+	{
+	  gdb_assert (name[current_len] == ':');
+	  result.emplace_back (&name[previous_len],
+			       current_len - previous_len);
+	  /* Skip the '::'.  */
+	  current_len += 2;
+	  previous_len = current_len;
+	}
+      break;
+
+    case split_style::UNDERSCORE:
+      /* Handle the Ada encoded (aka mangled) form here.  */
+      for (const char *iter = strstr (name, "__");
+	   iter != nullptr;
+	   iter = strstr (iter, "__"))
+	{
+	  result.emplace_back (&name[previous_len],
+			       iter - &name[previous_len]);
+	  iter += 2;
+	  previous_len = iter - name;
+	}
+      break;
+
+    case split_style::DOT:
+      /* D and Go-style names.  */
+      for (const char *iter = strchr (name, '.');
+	   iter != nullptr;
+	   iter = strchr (iter, '.'))
+	{
+	  result.emplace_back (&name[previous_len],
+			       iter - &name[previous_len]);
+	  ++iter;
+	  previous_len = iter - name;
+	}
+      break;
+
+    default:
+      break;
+    }
+
+  result.emplace_back (&name[previous_len]);
+  return result;
+}
+
diff --git a/gdb/split-name.h b/gdb/split-name.h
new file mode 100644
index 00000000000..b602917622e
--- /dev/null
+++ b/gdb/split-name.h
@@ -0,0 +1,45 @@
+/* Split a symbol name.
+
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_SPLIT_NAME_H
+#define GDB_SPLIT_NAME_H
+
+#include "gdbsupport/gdb_string_view.h"
+
+/* The available styles of name splitting.  */
+
+enum class split_style
+{
+  /* No splitting - C style.  */
+  NONE,
+  /* C++ style, with "::" and template parameter intelligence.  */
+  CXX,
+  /* Split at ".".  Used by Ada, Go, D.  */
+  DOT,
+  /* Split at "__".  Used by Ada encoded names.  */
+  UNDERSCORE,
+};
+
+/* Split NAME into components at module boundaries.  STYLE indicates
+   which style of splitting to use.  */
+
+extern std::vector<gdb::string_view> split_name (const char *name,
+						 split_style style);
+
+#endif /* GDB_SPLIT_NAME_H */
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 61f20b25a7b..a7e0669782b 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -36,6 +36,7 @@
 #include "gdbsupport/iterator-range.h"
 #include "completer.h"
 #include "gdb-demangle.h"
+#include "split-name.h"
 
 /* Opaque declarations.  */
 struct ui_file;
@@ -121,6 +122,21 @@ class ada_lookup_name_info final
   bool verbatim_p () const
   { return m_verbatim_p; }
 
+  /* A wrapper for ::split_name that handles some Ada-specific
+     peculiarities.  */
+  std::vector<gdb::string_view> split_name () const
+  {
+    if (m_verbatim_p || m_standard_p)
+      {
+	std::vector<gdb::string_view> result;
+	if (m_standard_p)
+	  result.emplace_back ("standard");
+	result.emplace_back (m_encoded_name);
+	return result;
+      }
+    return ::split_name (m_encoded_name.c_str (), split_style::UNDERSCORE);
+  }
+
 private:
   /* The Ada-encoded lookup name.  */
   std::string m_encoded_name;
@@ -272,6 +288,27 @@ class lookup_name_info final
       }
   }
 
+  /* A wrapper for ::split_name (see split-name.h) that splits this
+     name, and that handles any language-specific peculiarities.  */  
+  std::vector<gdb::string_view> split_name (language lang) const
+  {
+    if (lang == language_ada)
+      return ada ().split_name ();
+    split_style style = split_style::NONE;
+    switch (lang)
+      {
+      case language_cplus:
+      case language_rust:
+	style = split_style::CXX;
+	break;
+      case language_d:
+      case language_go:
+	style = split_style::DOT;
+	break;
+      }
+    return ::split_name (language_lookup_name (lang), style);
+  }
+
   /* Get the Ada-specific lookup info.  */
   const ada_lookup_name_info &ada () const
   {
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 08/32] Add new overload of dwarf5_djb_hash
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (6 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 07/32] Add name splitting Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-05 20:01   ` Simon Marchi
  2021-11-04 18:08 ` [PATCH v2 09/32] Refactor build_type_psymtabs_reader Tom Tromey
                   ` (25 subsequent siblings)
  33 siblings, 1 reply; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds a new overload of dwarf5_djb_hash.  This is used in
subsequent patches.
---
 gdb/dwarf2/index-common.c | 15 +++++++++++++++
 gdb/dwarf2/index-common.h |  4 ++++
 2 files changed, 19 insertions(+)

diff --git a/gdb/dwarf2/index-common.c b/gdb/dwarf2/index-common.c
index 1c02730a3fe..4bad82218c2 100644
--- a/gdb/dwarf2/index-common.c
+++ b/gdb/dwarf2/index-common.c
@@ -54,3 +54,18 @@ dwarf5_djb_hash (const char *str_)
     hash = hash * 33 + tolower (c);
   return hash;
 }
+
+/* See dwarf-index-common.h.  */
+
+uint32_t
+dwarf5_djb_hash (gdb::string_view str)
+{
+  /* Note: tolower here ignores UTF-8, which isn't fully compliant.
+     See http://dwarfstd.org/ShowIssue.php?issue=161027.1.  */
+
+  uint32_t hash = 5381;
+  size_t len = str.length ();
+  for (size_t i = 0; i < len; ++i)
+    hash = hash * 33 + tolower (str[i] & 0xff);
+  return hash;
+}
diff --git a/gdb/dwarf2/index-common.h b/gdb/dwarf2/index-common.h
index 86180747533..c800b3a7dea 100644
--- a/gdb/dwarf2/index-common.h
+++ b/gdb/dwarf2/index-common.h
@@ -52,4 +52,8 @@ hashval_t mapped_index_string_hash (int index_version, const void *p);
 
 uint32_t dwarf5_djb_hash (const char *str_);
 
+/* Symbol name hashing function as specified by DWARF-5.  */
+
+uint32_t dwarf5_djb_hash (gdb::string_view str_);
+
 #endif /* DWARF_INDEX_COMMON_H */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 09/32] Refactor build_type_psymtabs_reader
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (7 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 08/32] Add new overload of dwarf5_djb_hash Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 10/32] Add batching parameter to parallel_for_each Tom Tromey
                   ` (24 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The new DWARF scanner needs to save the entire cutu_reader object, not
just parts of it.  In order to make this possible, this patch
refactors build_type_psymtabs_reader.  This change is done separately
because it is easy to review in isolation and it helps make the later
patches smaller.
---
 gdb/dwarf2/read.c | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 4e44fa2a058..a4b78200c21 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -1104,9 +1104,7 @@ static dwarf2_psymtab *create_partial_symtab
   (dwarf2_per_cu_data *per_cu, dwarf2_per_objfile *per_objfile,
    const char *name);
 
-static void build_type_psymtabs_reader (const struct die_reader_specs *reader,
-					const gdb_byte *info_ptr,
-					struct die_info *type_unit_die);
+static void build_type_psymtabs_reader (cutu_reader *reader);
 
 static void dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile);
 
@@ -7174,8 +7172,7 @@ process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
       /* Nothing.  */
     }
   else if (this_cu->is_debug_types)
-    build_type_psymtabs_reader (&reader, reader.info_ptr,
-				reader.comp_unit_die);
+    build_type_psymtabs_reader (&reader);
   else if (want_partial_unit
 	   || reader.comp_unit_die->tag != DW_TAG_partial_unit)
     process_psymtab_comp_unit_reader (&reader, reader.info_ptr,
@@ -7189,9 +7186,7 @@ process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
 /* Reader function for build_type_psymtabs.  */
 
 static void
-build_type_psymtabs_reader (const struct die_reader_specs *reader,
-			    const gdb_byte *info_ptr,
-			    struct die_info *type_unit_die)
+build_type_psymtabs_reader (cutu_reader *reader)
 {
   dwarf2_per_objfile *per_objfile = reader->cu->per_objfile;
   struct dwarf2_cu *cu = reader->cu;
@@ -7202,6 +7197,8 @@ build_type_psymtabs_reader (const struct die_reader_specs *reader,
   struct partial_die_info *first_die;
   CORE_ADDR lowpc, highpc;
   dwarf2_psymtab *pst;
+  const gdb_byte *info_ptr = reader->info_ptr;
+  struct die_info *type_unit_die = reader->comp_unit_die;
 
   gdb_assert (per_cu->is_debug_types);
   sig_type = (struct signatured_type *) per_cu;
@@ -7334,8 +7331,7 @@ build_type_psymtabs (dwarf2_per_objfile *per_objfile)
       cutu_reader reader (tu.sig_type, per_objfile,
 			  abbrev_table.get (), nullptr, false);
       if (!reader.dummy_p)
-	build_type_psymtabs_reader (&reader, reader.info_ptr,
-				    reader.comp_unit_die);
+	build_type_psymtabs_reader (&reader);
     }
 }
 
@@ -7423,8 +7419,7 @@ process_skeletonless_type_unit (void **slot, void *info)
   /* This does the job that build_type_psymtabs would have done.  */
   cutu_reader reader (entry, per_objfile, nullptr, nullptr, false);
   if (!reader.dummy_p)
-    build_type_psymtabs_reader (&reader, reader.info_ptr,
-				reader.comp_unit_die);
+    build_type_psymtabs_reader (&reader);
 
   return 1;
 }
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 10/32] Add batching parameter to parallel_for_each
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (8 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 09/32] Refactor build_type_psymtabs_reader Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 11/32] Return vector of results from parallel_for_each Tom Tromey
                   ` (23 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

parallel_for_each currently requires each thread to process at least
10 elements.  However, when indexing, it's fine for a thread to handle
just a single CU.  This patch parameterizes this, and updates the one
user.
---
 gdb/minsyms.c                          |  4 ++--
 gdb/unittests/parallel-for-selftests.c |  2 +-
 gdbsupport/parallel-for.h              | 18 ++++++++++++------
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/gdb/minsyms.c b/gdb/minsyms.c
index 5f4cf54c663..7f2f23dd789 100644
--- a/gdb/minsyms.c
+++ b/gdb/minsyms.c
@@ -1462,8 +1462,8 @@ minimal_symbol_reader::install ()
       std::vector<computed_hash_values> hash_values (mcount);
 
       msymbols = m_objfile->per_bfd->msymbols.get ();
-      gdb::parallel_for_each
-	(&msymbols[0], &msymbols[mcount],
+      /* Arbitrarily require at least 10 elements in a thread.  */
+      gdb::parallel_for_each (10, &msymbols[0], &msymbols[mcount],
 	 [&] (minimal_symbol *start, minimal_symbol *end)
 	 {
 	   for (minimal_symbol *msym = start; msym < end; ++msym)
diff --git a/gdb/unittests/parallel-for-selftests.c b/gdb/unittests/parallel-for-selftests.c
index f149e72f0c7..c7a3780c743 100644
--- a/gdb/unittests/parallel-for-selftests.c
+++ b/gdb/unittests/parallel-for-selftests.c
@@ -52,7 +52,7 @@ test (int n_threads)
 #define NUMBER 10000
 
   std::atomic<int> counter (0);
-  gdb::parallel_for_each (0, NUMBER,
+  gdb::parallel_for_each (1, 0, NUMBER,
 			  [&] (int start, int end)
 			  {
 			    counter += end - start;
diff --git a/gdbsupport/parallel-for.h b/gdbsupport/parallel-for.h
index e4fcb4053b2..54027e69402 100644
--- a/gdbsupport/parallel-for.h
+++ b/gdbsupport/parallel-for.h
@@ -35,11 +35,16 @@ namespace gdb
 
    This approach was chosen over having the callback work on single
    items because it makes it simple for the caller to do
-   once-per-subrange initialization and destruction.  */
+   once-per-subrange initialization and destruction.
+
+   The parameter N says how batching ought to be done -- there will be
+   at least N elements processed per thread.  Setting N to 0 is not
+   allowed.  */
 
 template<class RandomIt, class RangeFunction>
 void
-parallel_for_each (RandomIt first, RandomIt last, RangeFunction callback)
+parallel_for_each (unsigned n, RandomIt first, RandomIt last,
+		   RangeFunction callback)
 {
 #if CXX_STD_THREAD
   /* So we can use a local array below.  */
@@ -52,10 +57,11 @@ parallel_for_each (RandomIt first, RandomIt last, RangeFunction callback)
   size_t n_elements = last - first;
   if (n_threads > 1)
     {
-      /* Arbitrarily require that there should be at least 10 elements
-	 in a thread.  */
-      if (n_elements / n_threads < 10)
-	n_threads = std::max (n_elements / 10, (size_t) 1);
+      /* Require that there should be at least N elements in a
+	 thread.  */
+      gdb_assert (n > 0);
+      if (n_elements / n_threads < n)
+	n_threads = std::max (n_elements / n, (size_t) 1);
       size_t elts_per_thread = n_elements / n_threads;
       n_actual_threads = n_threads - 1;
       for (int i = 0; i < n_actual_threads; ++i)
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 11/32] Return vector of results from parallel_for_each
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (9 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 10/32] Add batching parameter to parallel_for_each Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-17 20:37   ` Lancelot SIX
  2021-11-04 18:08 ` [PATCH v2 12/32] Specialize std::hash for gdb_exception Tom Tromey
                   ` (22 subsequent siblings)
  33 siblings, 1 reply; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes gdb::parallel_for_each to return a vector of the results.
However, if the passed-in function returns void, the return type
remains 'void'.  This functionality is used later, to parallelize the
new indexer.
---
 gdbsupport/parallel-for.h | 143 +++++++++++++++++++++++++++++++-------
 gdbsupport/thread-pool.cc |   6 +-
 gdbsupport/thread-pool.h  |  23 +++++-
 3 files changed, 141 insertions(+), 31 deletions(-)

diff --git a/gdbsupport/parallel-for.h b/gdbsupport/parallel-for.h
index 54027e69402..ee1f283a0bd 100644
--- a/gdbsupport/parallel-for.h
+++ b/gdbsupport/parallel-for.h
@@ -21,6 +21,7 @@
 #define GDBSUPPORT_PARALLEL_FOR_H
 
 #include <algorithm>
+#include <type_traits>
 #if CXX_STD_THREAD
 #include <thread>
 #include "gdbsupport/thread-pool.h"
@@ -29,6 +30,89 @@
 namespace gdb
 {
 
+namespace detail
+{
+
+/* This is a helper class that is used to accumulate results for
+   parallel_for.  There is a specialization for 'void', below.  */
+template<typename T>
+struct par_for_accumulator
+{
+public:
+
+  explicit par_for_accumulator (size_t n_threads)
+    : m_futures (n_threads)
+  {
+  }
+
+  /* The result type that is accumulated.  */
+  typedef std::vector<T> result_type;
+
+  /* Post the Ith task to a background thread, and store a future for
+     later.  */
+  void post (size_t i, std::function<T ()> task)
+  {
+    m_futures[i]
+      = gdb::thread_pool::g_thread_pool->post_task (std::move (task));
+  }
+
+  /* Invoke TASK in the current thread, then compute all the results
+     from all background tasks and put them into a result vector,
+     which is returned.  */
+  result_type finish (std::function<T ()> task)
+  {
+    result_type result (m_futures.size () + 1);
+
+    result.back () = task ();
+
+    for (size_t i = 0; i < m_futures.size (); ++i)
+      result[i] = m_futures[i].get ();
+
+    return result;
+  }
+
+private:
+  
+  /* A vector of futures coming from the tasks run in the
+     background.  */
+  std::vector<std::future<T>> m_futures;
+};
+
+/* See the generic template.  */
+template<>
+struct par_for_accumulator<void>
+{
+public:
+
+  explicit par_for_accumulator (size_t n_threads)
+    : m_futures (n_threads)
+  {
+  }
+
+  /* This specialization does not compute results.  */
+  typedef void result_type;
+
+  void post (size_t i, std::function<void ()> task)
+  {
+    m_futures[i]
+      = gdb::thread_pool::g_thread_pool->post_task (std::move (task));
+  }
+
+  result_type finish (std::function<void ()> task)
+  {
+    task ();
+
+    for (auto &future : m_futures)
+      future.wait ();
+  }
+
+private:
+
+  std::vector<std::future<void>> m_futures;
+};
+
+}
+
 /* A very simple "parallel for".  This splits the range of iterators
    into subranges, and then passes each subrange to the callback.  The
    work may or may not be done in separate threads.
@@ -39,22 +123,28 @@ namespace gdb
 
    The parameter N says how batching ought to be done -- there will be
    at least N elements processed per thread.  Setting N to 0 is not
-   allowed.  */
+   allowed.
+
+   If the function returns a non-void type, then a vector of the
+   results is returned.  The size of the resulting vector depends on
+   the number of threads that were used.  */
 
 template<class RandomIt, class RangeFunction>
-void
+typename gdb::detail::par_for_accumulator<
+    std::result_of_t<RangeFunction (RandomIt, RandomIt)>
+  >::result_type
 parallel_for_each (unsigned n, RandomIt first, RandomIt last,
 		   RangeFunction callback)
 {
-#if CXX_STD_THREAD
-  /* So we can use a local array below.  */
-  const size_t local_max = 16;
-  size_t n_threads = std::min (thread_pool::g_thread_pool->thread_count (),
-			       local_max);
-  size_t n_actual_threads = 0;
-  std::future<void> futures[local_max];
+  typedef typename std::result_of_t<RangeFunction (RandomIt, RandomIt)>
+    result_type;
+
+  size_t n_threads = 1;
 
+#if CXX_STD_THREAD
+  n_threads = thread_pool::g_thread_pool->thread_count ();
   size_t n_elements = last - first;
+  size_t elts_per_thread = 0;
   if (n_threads > 1)
     {
       /* Require that there should be at least N elements in a
@@ -62,29 +152,30 @@ parallel_for_each (unsigned n, RandomIt first, RandomIt last,
       gdb_assert (n > 0);
       if (n_elements / n_threads < n)
 	n_threads = std::max (n_elements / n, (size_t) 1);
-      size_t elts_per_thread = n_elements / n_threads;
-      n_actual_threads = n_threads - 1;
-      for (int i = 0; i < n_actual_threads; ++i)
-	{
-	  RandomIt end = first + elts_per_thread;
-	  auto task = [=] ()
-		      {
-			callback (first, end);
-		      };
-
-	  futures[i] = gdb::thread_pool::g_thread_pool->post_task (task);
-	  first = end;
-	}
+      elts_per_thread = n_elements / n_threads;
     }
 #endif /* CXX_STD_THREAD */
 
-  /* Process all the remaining elements in the main thread.  */
-  callback (first, last);
+  size_t count = n_threads == 0 ? 0 : n_threads - 1;
+  gdb::detail::par_for_accumulator<result_type> results (count);
 
 #if CXX_STD_THREAD
-  for (int i = 0; i < n_actual_threads; ++i)
-    futures[i].wait ();
+  for (int i = 0; i < count; ++i)
+    {
+      RandomIt end = first + elts_per_thread;
+      results.post (i, [=] ()
+        {
+	  return callback (first, end);
+	});
+      first = end;
+    }
 #endif /* CXX_STD_THREAD */
+
+  /* Process all the remaining elements in the main thread.  */
+  return results.finish ([=] ()
+    {
+      return callback (first, last);
+    });
 }
 
 }
diff --git a/gdbsupport/thread-pool.cc b/gdbsupport/thread-pool.cc
index 2bb75cc9cef..f2252ffc9fd 100644
--- a/gdbsupport/thread-pool.cc
+++ b/gdbsupport/thread-pool.cc
@@ -129,11 +129,10 @@ thread_pool::set_thread_count (size_t num_threads)
   m_thread_count = num_threads;
 }
 
-std::future<void>
-thread_pool::post_task (std::function<void ()> &&func)
+void
+thread_pool::do_post_task (std::packaged_task<void ()> &&func)
 {
   std::packaged_task<void ()> t (std::move (func));
-  std::future<void> f = t.get_future ();
 
   if (m_thread_count == 0)
     {
@@ -146,7 +145,6 @@ thread_pool::post_task (std::function<void ()> &&func)
       m_tasks.emplace (std::move (t));
       m_tasks_cv.notify_one ();
     }
-  return f;
 }
 
 void
diff --git a/gdbsupport/thread-pool.h b/gdbsupport/thread-pool.h
index 9bddaa9eaae..bf0e03f005a 100644
--- a/gdbsupport/thread-pool.h
+++ b/gdbsupport/thread-pool.h
@@ -58,7 +58,24 @@ class thread_pool
 
   /* Post a task to the thread pool.  A future is returned, which can
      be used to wait for the result.  */
-  std::future<void> post_task (std::function<void ()> &&func);
+  std::future<void> post_task (std::function<void ()> &&func)
+  {
+    std::packaged_task<void ()> task (std::move (func));
+    std::future<void> result = task.get_future ();
+    do_post_task (std::packaged_task<void ()> (std::move (task)));
+    return result;
+  }
+
+  /* Post a task to the thread pool.  A future is returned, which can
+     be used to wait for the result.  */
+  template<typename T>
+  std::future<T> post_task (std::function<T ()> &&func)
+  {
+    std::packaged_task<T ()> task (std::move (func));
+    std::future<T> result = task.get_future ();
+    do_post_task (std::packaged_task<void ()> (std::move (task)));
+    return result;
+  }
 
 private:
 
@@ -67,6 +84,10 @@ class thread_pool
   /* The callback for each worker thread.  */
   void thread_function ();
 
+  /* Post a task to the thread pool.  A future is returned, which can
+     be used to wait for the result.  */
+  void do_post_task (std::packaged_task<void ()> &&func);
+
   /* The current thread count.  */
   size_t m_thread_count = 0;
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 12/32] Specialize std::hash for gdb_exception
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (10 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 11/32] Return vector of results from parallel_for_each Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 13/32] Introduce DWARF abbrev cache Tom Tromey
                   ` (21 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds a std::hash specialization for gdb_exception.  This lets us
store these objects in a hash table, which is used later in this
series to de-duplicate the exception output from multiple threads.
---
 gdbsupport/common-exceptions.h | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/gdbsupport/common-exceptions.h b/gdbsupport/common-exceptions.h
index 5933c7356fe..051379cdb56 100644
--- a/gdbsupport/common-exceptions.h
+++ b/gdbsupport/common-exceptions.h
@@ -24,6 +24,7 @@
 #include <new>
 #include <memory>
 #include <string>
+#include <functional>
 
 /* Reasons for calling throw_exceptions().  NOTE: all reason values
    must be different from zero.  enum value 0 is reserved for internal
@@ -187,6 +188,24 @@ struct gdb_exception
   std::shared_ptr<std::string> message;
 };
 
+namespace std
+{
+
+/* Specialization of std::hash for gdb_exception.  */
+template<>
+struct hash<gdb_exception>
+{
+  size_t operator() (const gdb_exception &exc) const
+  {
+    size_t result = exc.reason + exc.error;
+    if (exc.message != nullptr)
+      result += std::hash<std::string> {} (*exc.message);
+    return result;
+  }
+};
+
+}
+
 /* Functions to drive the sjlj-based exceptions state machine.  Though
    declared here by necessity, these functions should be considered
    internal to the exceptions subsystem and not used other than via
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 13/32] Introduce DWARF abbrev cache
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (11 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 12/32] Specialize std::hash for gdb_exception Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 14/32] Statically examine abbrev properties Tom Tromey
                   ` (20 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The replacement for the DWARF psymbol reader works in a somewhat
different way.  The current reader reads and stores all the DIEs that
might be interesting.  Then, if it is missing a DIE, it re-scans the
CU and reads them all.  This approach is used for both intra- and
inter-CU references.

I instrumented the partial DIE hash to see how frequently it was used:

    [  0] -> 1538165
    [  1] ->    4912
    [  2] ->   96102
    [  3] ->     175
    [  4] ->     244

That is, most DIEs are never used, and some are looked up twice -- but
this is just an artifact of the implementation of
partial_die_info::fixup, which may do two lookups.

Based on this, the new implementation doesn't try to store any DIEs,
but instead just re-scans them on demand.  In order to do this,
though, it is convenient to have a cache of DWARF abbrevs.  This way,
if a second CU is needed to resolve an inter-CU reference, the abbrevs
for that CU need only be computed a single time.
---
 gdb/Makefile.in           |  1 +
 gdb/dwarf2/abbrev-cache.c | 65 +++++++++++++++++++++++++++++++++++++++
 gdb/dwarf2/abbrev-cache.h | 58 ++++++++++++++++++++++++++++++++++
 gdb/dwarf2/abbrev.c       |  5 +--
 gdb/dwarf2/abbrev.h       |  4 ++-
 5 files changed, 130 insertions(+), 3 deletions(-)
 create mode 100644 gdb/dwarf2/abbrev-cache.c
 create mode 100644 gdb/dwarf2/abbrev-cache.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 73eaf12e339..7c0caff29f1 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1035,6 +1035,7 @@ COMMON_SFILES = \
 	displaced-stepping.c \
 	dummy-frame.c \
 	dwarf2/abbrev.c \
+	dwarf2/abbrev-cache.c \
 	dwarf2/attribute.c \
 	dwarf2/comp-unit-head.c \
 	dwarf2/cu.c \
diff --git a/gdb/dwarf2/abbrev-cache.c b/gdb/dwarf2/abbrev-cache.c
new file mode 100644
index 00000000000..f0705065a3c
--- /dev/null
+++ b/gdb/dwarf2/abbrev-cache.c
@@ -0,0 +1,65 @@
+/* DWARF 2 abbrev table cache
+
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "dwarf2/read.h"
+#include "dwarf2/abbrev-cache.h"
+
+/* Hash function for an abbrev table.  */
+
+hashval_t
+abbrev_cache::hash_table (const void *item)
+{
+  const struct abbrev_table *table = (const struct abbrev_table *) item;
+  return to_underlying (table->sect_off);
+}
+
+/* Comparison function for abbrev table.  */
+
+int
+abbrev_cache::eq_table (const void *lhs, const void *rhs)
+{
+  const struct abbrev_table *l_table = (const struct abbrev_table *) lhs;
+  const search_key *key = (const search_key *) rhs;
+  return (l_table->section == key->section
+	  && l_table->sect_off == key->offset);
+}
+
+abbrev_cache::abbrev_cache ()
+  : m_tables (htab_create_alloc (20, hash_table, eq_table,
+				 htab_delete_entry<abbrev_table>,
+				 xcalloc, xfree))
+{
+}
+
+void
+abbrev_cache::add (abbrev_table_up table)
+{
+  /* We allow this as a convenience to the caller.  */
+  if (table == nullptr)
+    return;
+
+  search_key key = { table->section, table->sect_off };
+  void **slot = htab_find_slot_with_hash (m_tables.get (), &key,
+					  to_underlying (table->sect_off),
+					  INSERT);
+  /* If this one already existed, then it should have been reused.  */
+  gdb_assert (*slot == nullptr);
+  *slot = (void *) table.release ();
+}
diff --git a/gdb/dwarf2/abbrev-cache.h b/gdb/dwarf2/abbrev-cache.h
new file mode 100644
index 00000000000..a651fcc0ec0
--- /dev/null
+++ b/gdb/dwarf2/abbrev-cache.h
@@ -0,0 +1,58 @@
+/* DWARF abbrev table cache
+
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_DWARF2_ABBREV_CACHE_H
+#define GDB_DWARF2_ABBREV_CACHE_H
+
+#include "dwarf2/abbrev.h"
+#include <unordered_set>
+#include "gdbtypes.h"
+
+class abbrev_cache
+{
+public:
+  abbrev_cache ();
+  DISABLE_COPY_AND_ASSIGN (abbrev_cache);
+
+  abbrev_table *find (struct dwarf2_section_info *section, sect_offset offset)
+  {
+    search_key key = { section, offset };
+
+    return (abbrev_table *) htab_find_with_hash (m_tables.get (), &key,
+						 to_underlying (offset));
+  }
+
+  void add (abbrev_table_up table);
+
+private:
+
+  static hashval_t hash_table (const void *item);
+  static int eq_table (const void *lhs, const void *rhs);
+
+  struct search_key
+  {
+    struct dwarf2_section_info *section;
+    sect_offset offset;
+  };
+
+  /* Hash table of abbrev tables.  */
+  htab_up m_tables;
+};
+
+#endif /* GDB_DWARF2_ABBREV_CACHE_H */
diff --git a/gdb/dwarf2/abbrev.c b/gdb/dwarf2/abbrev.c
index a8bdf7182de..c84f21256fd 100644
--- a/gdb/dwarf2/abbrev.c
+++ b/gdb/dwarf2/abbrev.c
@@ -58,8 +58,9 @@ eq_abbrev (const void *lhs, const void *rhs)
    dies from a section we read in all abbreviations and install them
    in a hash table.  */
 
-abbrev_table::abbrev_table (sect_offset off)
+abbrev_table::abbrev_table (sect_offset off, struct dwarf2_section_info *sect)
   : sect_off (off),
+    section (sect),
     m_abbrevs (htab_create_alloc (20, hash_abbrev, eq_abbrev,
 				  nullptr, xcalloc, xfree))
 {
@@ -85,7 +86,7 @@ abbrev_table::read (struct dwarf2_section_info *section,
   const gdb_byte *abbrev_ptr;
   struct abbrev_info *cur_abbrev;
 
-  abbrev_table_up abbrev_table (new struct abbrev_table (sect_off));
+  abbrev_table_up abbrev_table (new struct abbrev_table (sect_off, section));
   struct obstack *obstack = &abbrev_table->m_abbrev_obstack;
 
   /* Caller must ensure this.  */
diff --git a/gdb/dwarf2/abbrev.h b/gdb/dwarf2/abbrev.h
index 50f2ed46083..0a1ca4d39b4 100644
--- a/gdb/dwarf2/abbrev.h
+++ b/gdb/dwarf2/abbrev.h
@@ -85,9 +85,11 @@ struct abbrev_table
      This is used as a sanity check when the table is used.  */
   const sect_offset sect_off;
 
+  struct dwarf2_section_info *section;
+
 private:
 
-  explicit abbrev_table (sect_offset off);
+  abbrev_table (sect_offset off, struct dwarf2_section_info *sect);
 
   DISABLE_COPY_AND_ASSIGN (abbrev_table);
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 14/32] Statically examine abbrev properties
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (12 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 13/32] Introduce DWARF abbrev cache Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 15/32] Update skip_one_die for new " Tom Tromey
                   ` (19 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The new DIE scanner works more or less along the lines indicated by
the text for the .debug_names section, disregarding the bugs in the
specification.

While working on this, I noticed that whether a DIE is interesting is
a static property of the DIE's abbrev.  It also turns out that many
abbrevs imply a static size for the DIE data, and additionally that
for many abbrevs, the sibling offset is stored at a constant offset
from the start of the DIE.

This patch changes the abbrev reader to analyze each abbrev and stash
the results on the abbrev.  These combine to speed up the new indexer.
If the "interesting" flag is false, GDB knows to skip the DIE
immediately.  If the sibling offset is statically known, skipping can
be done without reading any attributes; and in some other cases, the
DIE can be skipped using simple arithmetic.
---
 gdb/dwarf2/abbrev.c | 153 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/dwarf2/abbrev.h |   7 +-
 2 files changed, 158 insertions(+), 2 deletions(-)

diff --git a/gdb/dwarf2/abbrev.c b/gdb/dwarf2/abbrev.c
index c84f21256fd..b36a52cd5be 100644
--- a/gdb/dwarf2/abbrev.c
+++ b/gdb/dwarf2/abbrev.c
@@ -76,6 +76,43 @@ abbrev_table::add_abbrev (struct abbrev_info *abbrev)
   *slot = abbrev;
 }
 
+/* Helper function that returns true if a DIE with the given tag might
+   plausibly be indexed.  */
+
+static bool
+tag_interesting_for_index (dwarf_tag tag)
+{
+  switch (tag)
+    {
+    case DW_TAG_array_type:
+    case DW_TAG_base_type:
+    case DW_TAG_class_type:
+    case DW_TAG_constant:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_enumerator:
+    case DW_TAG_imported_declaration:
+    case DW_TAG_imported_unit:
+    case DW_TAG_inlined_subroutine:
+    case DW_TAG_interface_type:
+    case DW_TAG_module:
+    case DW_TAG_namespace:
+    case DW_TAG_ptr_to_member_type:
+    case DW_TAG_set_type:
+    case DW_TAG_string_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_subprogram:
+    case DW_TAG_subrange_type:
+    case DW_TAG_subroutine_type:
+    case DW_TAG_typedef:
+    case DW_TAG_union_type:
+    case DW_TAG_unspecified_type:
+    case DW_TAG_variable:
+      return true;
+    }
+
+  return false;
+}
+
 /* Read in an abbrev table.  */
 
 abbrev_table_up
@@ -116,6 +153,17 @@ abbrev_table::read (struct dwarf2_section_info *section,
       cur_abbrev->has_children = read_1_byte (abfd, abbrev_ptr);
       abbrev_ptr += 1;
 
+      unsigned int size = 0;
+      unsigned int sibling_offset = -1;
+      bool is_csize = true;
+
+      bool has_hardcoded_declaration = false;
+      bool has_specification_or_origin = false;
+      bool has_name = false;
+      bool has_linkage_name = false;
+      bool has_location = false;
+      bool has_external = false;
+
       /* Now read in declarations.  */
       int num_attrs = 0;
       for (;;)
@@ -142,12 +190,117 @@ abbrev_table::read (struct dwarf2_section_info *section,
 	  if (cur_attr.name == 0)
 	    break;
 
+	  switch (cur_attr.name)
+	    {
+	    case DW_AT_declaration:
+	      if (cur_attr.form == DW_FORM_flag_present)
+		has_hardcoded_declaration = true;
+	      break;
+
+	    case DW_AT_external:
+	      has_external = true;
+	      break;
+
+	    case DW_AT_specification:
+	    case DW_AT_abstract_origin:
+	    case DW_AT_extension:
+	      has_specification_or_origin = true;
+	      break;
+
+	    case DW_AT_name:
+	      has_name = true;
+	      break;
+
+	    case DW_AT_MIPS_linkage_name:
+	    case DW_AT_linkage_name:
+	      has_linkage_name = true;
+	      break;
+
+	    case DW_AT_const_value:
+	    case DW_AT_location:
+	      has_location = true;
+	      break;
+
+	    case DW_AT_sibling:
+	      if (is_csize && cur_attr.form == DW_FORM_ref4)
+		sibling_offset = size;
+	      break;
+	    }
+
+	  switch (cur_attr.form)
+	    {
+	    case DW_FORM_data1:
+	    case DW_FORM_ref1:
+	    case DW_FORM_flag:
+	    case DW_FORM_strx1:
+	      size += 1;
+	      break;
+	    case DW_FORM_flag_present:
+	    case DW_FORM_implicit_const:
+	      break;
+	    case DW_FORM_data2:
+	    case DW_FORM_ref2:
+	    case DW_FORM_strx2:
+	      size += 2;
+	      break;
+	    case DW_FORM_strx3:
+	      size += 3;
+	      break;
+	    case DW_FORM_data4:
+	    case DW_FORM_ref4:
+	    case DW_FORM_strx4:
+	      size += 4;
+	      break;
+	    case DW_FORM_data8:
+	    case DW_FORM_ref8:
+	    case DW_FORM_ref_sig8:
+	      size += 8;
+	      break;
+	    case DW_FORM_data16:
+	      size += 16;
+	      break;
+
+	    default:
+	      is_csize = false;
+	      break;
+	    }
+
 	  ++num_attrs;
 	  obstack_grow (obstack, &cur_attr, sizeof (cur_attr));
 	}
 
       cur_abbrev = (struct abbrev_info *) obstack_finish (obstack);
       cur_abbrev->num_attrs = num_attrs;
+
+      if (!has_name && !has_linkage_name && !has_specification_or_origin)
+	{
+	  /* Some anonymous DIEs are worth examining.  */
+	  cur_abbrev->interesting
+	    = (cur_abbrev->tag == DW_TAG_namespace
+	       || cur_abbrev->tag == DW_TAG_enumeration_type);
+	}
+      else if (has_hardcoded_declaration
+	       && (cur_abbrev->tag != DW_TAG_variable || !has_external))
+	cur_abbrev->interesting = false;
+      else if (!tag_interesting_for_index (cur_abbrev->tag))
+	cur_abbrev->interesting = false;
+      else if (!has_location && !has_specification_or_origin && !has_external
+	       && cur_abbrev->tag == DW_TAG_variable)
+	cur_abbrev->interesting = false;
+      else
+	cur_abbrev->interesting = true;
+
+      /* If there are no children, and the abbrev has a constant size,
+	 then we don't care about the sibling offset, because it's
+	 simple to just skip the entire DIE without reading a sibling
+	 offset.  */
+      if ((!cur_abbrev->has_children && is_csize)
+	  /* Overflow.  */
+	  || sibling_offset != (unsigned short) sibling_offset)
+	sibling_offset = -1;
+      cur_abbrev->size_if_constant = is_csize ? size : 0;
+      cur_abbrev->sibling_offset = sibling_offset;
+
       abbrev_table->add_abbrev (cur_abbrev);
     }
 
diff --git a/gdb/dwarf2/abbrev.h b/gdb/dwarf2/abbrev.h
index 0a1ca4d39b4..ae02f76885d 100644
--- a/gdb/dwarf2/abbrev.h
+++ b/gdb/dwarf2/abbrev.h
@@ -44,9 +44,12 @@ struct abbrev_info
   /* Number identifying abbrev.  */
   unsigned int number;
   /* DWARF tag.  */
-  enum dwarf_tag tag;
+  ENUM_BITFIELD (dwarf_tag) tag : 16;
   /* True if the DIE has children.  */
-  unsigned short has_children;
+  bool has_children;
+  bool interesting;
+  unsigned short size_if_constant;
+  unsigned short sibling_offset;
   /* Number of attributes.  */
   unsigned short num_attrs;
   /* An array of attribute descriptions, allocated using the struct
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 15/32] Update skip_one_die for new abbrev properties
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (13 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 14/32] Statically examine abbrev properties Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 16/32] Introduce the new DWARF index class Tom Tromey
                   ` (18 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This updates skip_one_die to speed it up in the cases where either
sibling_offset or size_if_constant are set.
---
 gdb/dwarf2/read.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index a4b78200c21..be0a077ab34 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -8360,6 +8360,24 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
   const gdb_byte *buffer_end = reader->buffer_end;
   unsigned int form, i;
 
+  if (do_skip_children && abbrev->sibling_offset != (unsigned short) -1)
+    {
+      /* We only handle DW_FORM_ref4 here.  */
+      const gdb_byte *sibling_data = info_ptr + abbrev->sibling_offset;
+      unsigned int offset = read_4_bytes (abfd, sibling_data);
+      const gdb_byte *sibling_ptr = buffer + offset;
+      if (sibling_ptr >= info_ptr && sibling_ptr < reader->buffer_end)
+	return sibling_ptr;
+      /* Fall through to the slow way.  */
+    }
+  else if (abbrev->size_if_constant != 0)
+    {
+      info_ptr += abbrev->size_if_constant;
+      if (do_skip_children && abbrev->has_children)
+	return skip_children (reader, info_ptr);
+      return info_ptr;
+    }
+
   for (i = 0; i < abbrev->num_attrs; i++)
     {
       /* The only abbrev we care about is DW_AT_sibling.  */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 16/32] Introduce the new DWARF index class
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (14 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 15/32] Update skip_one_die for new " Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 17/32] The new DWARF indexer Tom Tromey
                   ` (17 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This patch introduces the new DWARF index class.  It is called
"cooked" to contrast against a "raw" index, which is mapped from disk
without extra effort.

Nothing constructs a cooked index yet.  The essential idea here is
that index entries are created via the "add" method; then when all the
entries have been read, they are "finalize"d -- name canonicalization
is performed and the entries are added to a sorted vector.

Entries use the DWARF name (DW_AT_name) or linkage name, not the full
name as is done for partial symbols.

These two facets -- the short name and the deferred canonicalization
-- help improve the performance of this approach.  This will become
clear in later patches, when parallelization is added.

Some special code is needed for Ada, because GNAT only emits mangled
("encoded", in the Ada lingo) names, and so we reconstruct the
hierarchical structure after the fact.  This is also done in the
finalization phase.

One other aspect worth noting is that the way the "main" function is
found is different in the new code.  Currently gdb will notice
DW_AT_main_subprogram, but won't recognize "main" during reading --
this is done later, via explicit symbol lookup.  This is done
differently in the new code so that finalization can be done in the
background without then requiring a synchronization to look up the
symbol.
---
 gdb/Makefile.in           |   2 +
 gdb/dwarf2/cooked-index.c | 273 ++++++++++++++++++++++++++++++++++++++
 gdb/dwarf2/cooked-index.h | 260 ++++++++++++++++++++++++++++++++++++
 3 files changed, 535 insertions(+)
 create mode 100644 gdb/dwarf2/cooked-index.c
 create mode 100644 gdb/dwarf2/cooked-index.h

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 7c0caff29f1..747e2f38211 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -1038,6 +1038,7 @@ COMMON_SFILES = \
 	dwarf2/abbrev-cache.c \
 	dwarf2/attribute.c \
 	dwarf2/comp-unit-head.c \
+	dwarf2/cooked-index.c \
 	dwarf2/cu.c \
 	dwarf2/dwz.c \
 	dwarf2/expr.c \
@@ -1287,6 +1288,7 @@ HFILES_NO_SRCDIR = \
 	dictionary.h \
 	disasm.h \
 	dummy-frame.h \
+	dwarf2/cooked-index.h \
 	dwarf2/cu.h \
 	dwarf2/frame-tailcall.h \
 	dwarf2/frame.h \
diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c
new file mode 100644
index 00000000000..1b89e4c91f3
--- /dev/null
+++ b/gdb/dwarf2/cooked-index.c
@@ -0,0 +1,273 @@
+/* DIE indexing 
+
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "dwarf2/cooked-index.h"
+#include "dwarf2/read.h"
+#include "cp-support.h"
+#include "ada-lang.h"
+#include "split-name.h"
+#include <algorithm>
+
+/* Hash function for cooked_index_entry.  */
+
+static hashval_t
+hash_entry (const void *e)
+{
+  const cooked_index_entry *entry = (const cooked_index_entry *) e;
+  return dwarf5_djb_hash (entry->canonical);
+}
+
+/* Equality function for cooked_index_entry.  */
+
+static int
+eq_entry (const void *a, const void *b)
+{
+  const cooked_index_entry *ae = (const cooked_index_entry *) a;
+  const gdb::string_view *sv = (const gdb::string_view *) b;
+  return (strlen (ae->canonical) == sv->length ()
+	  && strncasecmp (ae->canonical, sv->data (), sv->length ()) == 0);
+}
+
+/* See cooked-index.h.  */
+
+const char *
+cooked_index_entry::full_name (struct obstack *storage) const
+{
+  if ((flags & IS_LINKAGE) != 0)
+    return canonical;
+
+  const char *sep = nullptr;
+  switch (per_cu->lang)
+    {
+    case language_cplus:
+    case language_rust:
+      sep = "::";
+      break;
+
+    case language_go:
+    case language_d:
+      sep = ".";
+      break;
+    }
+
+  if (sep == nullptr)
+    return canonical;
+
+  const cooked_index_entry *parent = parent_entry;
+  if (tag == DW_TAG_enumeration_type && (flags & IS_ENUM_CLASS) == 0)
+    parent = parent->parent_entry;
+
+  if (parent != nullptr)
+    parent->write_scope (storage, sep);
+  obstack_grow0 (storage, canonical, strlen (canonical));
+  return (const char *) obstack_finish (storage);
+}
+
+/* See cooked-index.h.  */
+
+void
+cooked_index_entry::write_scope (struct obstack *storage,
+				 const char *sep) const
+{
+  if (parent_entry != nullptr)
+    parent_entry->write_scope (storage, sep);
+  obstack_grow (storage, canonical, strlen (canonical));
+  obstack_grow (storage, sep, strlen (sep));
+}
+
+/* See cooked-index.h.  */
+
+const cooked_index_entry *
+cooked_index::add (sect_offset die_offset, enum dwarf_tag tag,
+		   cooked_index_flag flags, const char *name,
+		   const cooked_index_entry *parent_entry,
+		   dwarf2_per_cu_data *per_cu)
+{
+  cooked_index_entry *result = create (die_offset, tag, flags, name,
+				       parent_entry, per_cu);
+  m_entries.push_back (result);
+
+  /* An explicitly-tagged main program should always override the
+     implicit "main" discovery.  */
+  if ((flags & IS_MAIN) != 0)
+    m_main = result;
+  else if (per_cu->lang != language_ada
+	   && m_main == nullptr
+	   && strcmp (name, "main") == 0)
+    m_main = result;
+
+  return result;
+}
+
+/* See cooked-index.h.  */
+
+cooked_index::range
+cooked_index::find (gdb::string_view name, bool completing)
+{
+  auto lower = std::lower_bound (m_entries.begin (), m_entries.end (),
+				 name,
+				 [=] (const cooked_index_entry *entry,
+				      const gdb::string_view &n)
+  {
+    int cmp = strncasecmp (entry->canonical, n.data (), n.length ());
+    if (cmp != 0 || completing)
+      return cmp < 0;
+    return strlen (entry->canonical) < n.length ();
+  });
+
+  auto upper = std::upper_bound (m_entries.begin (), m_entries.end (),
+				 name,
+				 [=] (const gdb::string_view &n,
+				      const cooked_index_entry *entry)
+  {
+    int cmp = strncasecmp (n.data (), entry->canonical, n.length ());
+    if (cmp != 0 || completing)
+      return cmp < 0;
+    return n.length () < strlen (entry->canonical);
+  });
+
+  return range (lower, upper);
+}
+
+/* See cooked-index.h.  */
+
+gdb::unique_xmalloc_ptr<char>
+cooked_index::handle_gnat_encoded_entry (cooked_index_entry *entry,
+					 htab_t gnat_entries)
+{
+  std::string canonical = ada_decode (entry->name, false, false);
+  if (canonical.empty ())
+    return {};
+  std::vector<gdb::string_view> names = split_name (canonical.c_str (),
+						    split_style::DOT);
+  gdb::string_view tail = names.back ();
+  names.pop_back ();
+
+  const cooked_index_entry *parent = nullptr;
+  for (const auto &name : names)
+    {
+      uint32_t hashval = dwarf5_djb_hash (name);
+      void **slot = htab_find_slot_with_hash (gnat_entries, &name,
+					      hashval, INSERT);
+      /* CUs are processed in order, so we only need to check the most
+	 recent entry.  */
+      cooked_index_entry *last = (cooked_index_entry *) *slot;
+      if (last == nullptr || last->per_cu != entry->per_cu)
+	{
+	  gdb::unique_xmalloc_ptr<char> new_name
+	    = make_unique_xstrndup (name.data (), name.length ());
+	  last = create (entry->die_offset, DW_TAG_namespace,
+			 0, new_name.get (), parent,
+			 entry->per_cu);
+	  last->canonical = last->name;
+	  m_names.push_back (std::move (new_name));
+	  *slot = last;
+	}
+
+      parent = last;
+    }
+
+  entry->parent_entry = parent;
+  return make_unique_xstrndup (tail.data (), tail.length ());
+}
+
+/* See cooked-index.h.  */
+
+void
+cooked_index::finalize ()
+{
+  auto hash_name_ptr = [] (const void *p)
+    {
+      const cooked_index_entry *entry = (const cooked_index_entry *) p;
+      return htab_hash_pointer (entry->name);
+    };
+
+  auto eq_name_ptr = [] (const void *a, const void *b) -> int
+    {
+      const cooked_index_entry *ea = (const cooked_index_entry *) a;
+      const cooked_index_entry *eb = (const cooked_index_entry *) b;
+      return ea->name == eb->name;
+    };
+
+  /* We can use pointer equality here because names come from
+     .debug_str, which will normally be unique-ified by the linker.
+     Also, duplicates are relatively harmless -- they just mean a bit
+     of extra memory is used.  */
+  htab_up seen_names (htab_create_alloc (10, hash_name_ptr, eq_name_ptr,
+					 nullptr, xcalloc, xfree));
+
+  htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
+					   nullptr, xcalloc, xfree));
+
+  for (cooked_index_entry *entry : m_entries)
+    {
+      gdb_assert (entry->canonical == nullptr);
+      if ((entry->per_cu->lang != language_cplus
+	   && entry->per_cu->lang != language_ada)
+	  || (entry->flags & IS_LINKAGE) != 0)
+	entry->canonical = entry->name;
+      else
+	{
+	  if (entry->per_cu->lang == language_ada)
+	    {
+	      gdb::unique_xmalloc_ptr<char> canon_name
+		= handle_gnat_encoded_entry (entry, gnat_entries.get ());
+	      if (canon_name == nullptr)
+		entry->canonical = entry->name;
+	      else
+		{
+		  entry->canonical = canon_name.get ();
+		  m_names.push_back (std::move (canon_name));
+		}
+	    }
+	  else
+	    {
+	      void **slot = htab_find_slot (seen_names.get (), entry,
+					    INSERT);
+	      if (*slot == nullptr)
+		{
+		  gdb::unique_xmalloc_ptr<char> canon_name
+		    = cp_canonicalize_string (entry->name);
+		  if (canon_name == nullptr)
+		    entry->canonical = entry->name;
+		  else
+		    {
+		      entry->canonical = canon_name.get ();
+		      m_names.push_back (std::move (canon_name));
+		    }
+		}
+	      else
+		{
+		  const cooked_index_entry *other
+		    = (const cooked_index_entry *) *slot;
+		  entry->canonical = other->canonical;
+		}
+	    }
+	}
+    }
+
+  m_names.shrink_to_fit ();
+  m_entries.shrink_to_fit ();
+  std::sort (m_entries.begin (), m_entries.end (),
+	     [] (const cooked_index_entry *a, const cooked_index_entry *b)
+	     {
+	       return *a < *b;
+	     });
+}
diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
new file mode 100644
index 00000000000..746ccfce4e5
--- /dev/null
+++ b/gdb/dwarf2/cooked-index.h
@@ -0,0 +1,260 @@
+/* DIE indexing 
+
+   Copyright (C) 2021 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef GDB_DWARF2_COOKED_INDEX_H
+#define GDB_DWARF2_COOKED_INDEX_H
+
+#include "dwarf2.h"
+#include "gdbtypes.h"
+#include "symtab.h"
+#include "hashtab.h"
+#include "dwarf2/index-common.h"
+#include "gdbsupport/gdb_string_view.h"
+#include "quick-symbol.h"
+#include "gdb_obstack.h"
+#include "addrmap.h"
+#include "gdbsupport/iterator-range.h"
+
+struct dwarf2_per_cu_data;
+
+/* Flags that describe an entry in the index.  */
+enum cooked_index_flag_enum : unsigned char
+{
+  /* True if this entry is the program's "main".  */
+  IS_MAIN = 1,
+  /* True if this entry represents a "static" object.  */
+  IS_STATIC = 2,
+  /* True if this entry is an "enum class".  */
+  IS_ENUM_CLASS = 4,
+  /* True if this entry uses the linkage name.  */
+  IS_LINKAGE = 8,
+};
+DEF_ENUM_FLAGS_TYPE (enum cooked_index_flag_enum, cooked_index_flag);
+
+/* A cooked_index_entry represents a single item in the index.  Note
+   that two entries can be created for the same DIE -- one using the
+   name, and another one using the linkage name, if any.
+
+   This is an "open" class and the members are all directly
+   accessible.  It is read-only after the index has been fully read
+   and processed.  */
+struct cooked_index_entry : public allocate_on_obstack
+{
+  cooked_index_entry (sect_offset die_offset_, enum dwarf_tag tag_,
+		      cooked_index_flag flags_, const char *name_,
+		      const cooked_index_entry *parent_entry_,
+		      dwarf2_per_cu_data *per_cu_)
+    : name (name_),
+      tag (tag_),
+      flags (flags_),
+      die_offset (die_offset_),
+      parent_entry (parent_entry_),
+      per_cu (per_cu_)
+  {
+  }
+
+  /* Return true if this entry matches SEARCH_FLAGS.  */
+  bool matches (block_search_flags search_flags) const
+  {
+    if ((search_flags & SEARCH_STATIC_BLOCK) != 0
+	&& (flags & IS_STATIC) != 0)
+      return true;
+    if ((search_flags & SEARCH_GLOBAL_BLOCK) != 0
+	&& (flags & IS_STATIC) == 0)
+      return true;
+    return false;
+  }
+
+  /* Return true if this entry matches DOMAIN.  */
+  bool matches (domain_enum domain) const
+  {
+    switch (domain)
+      {
+      case LABEL_DOMAIN:
+	return false;
+
+      case MODULE_DOMAIN:
+	return tag == DW_TAG_module;
+
+      case COMMON_BLOCK_DOMAIN:
+	return tag == DW_TAG_common_block;
+      }
+
+    return true;
+  }
+
+  /* Return true if this entry matches KIND.  */
+  bool matches (enum search_domain kind) const
+  {
+    switch (kind)
+      {
+      case VARIABLES_DOMAIN:
+	return tag == DW_TAG_variable;
+      case FUNCTIONS_DOMAIN:
+	return tag == DW_TAG_subprogram;
+      case TYPES_DOMAIN:
+	return tag == DW_TAG_typedef || tag == DW_TAG_structure_type;
+      case MODULES_DOMAIN:
+	return tag == DW_TAG_module;
+      }
+
+    return true;
+  }
+
+  /* Construct the fully-qualified name of this entry and return a
+     pointer to it.  If allocation is needed, it will be done on
+     STORAGE.  */
+  const char *full_name (struct obstack *storage) const;
+
+  /* Entries must be sorted case-insensitively; this compares two
+     entries.  */
+  bool operator< (const cooked_index_entry &other) const
+  {
+    return strcasecmp (canonical, other.canonical) < 0;
+  }
+
+  /* The name as it appears in DWARF.  This always points into one of
+     the mapped DWARF sections.  Note that this may be the name or the
+     linkage name -- two entries are created for DIEs which have both
+     attributes.  */
+  const char *name;
+  /* The canonical name.  For C++ names, this may differ from NAME.
+     In all other cases, this is equal to NAME.  */
+  const char *canonical = nullptr;
+  /* The DWARF tag.  */
+  enum dwarf_tag tag;
+  /* Any flags attached to this entry.  */
+  cooked_index_flag flags;
+  /* The offset of this DIE.  */
+  sect_offset die_offset;
+  /* The parent entry.  This is NULL for top-level entries.
+     Otherwise, it points to the parent entry, such as a namespace or
+     class.  */
+  const cooked_index_entry *parent_entry;
+  /* The CU from which this entry originates.  */
+  dwarf2_per_cu_data *per_cu;
+
+private:
+
+  void write_scope (struct obstack *storage, const char *sep) const;
+};
+
+/* An index of interesting DIEs.  This is "cooked", in contrast to a
+   mapped .debug_names or .gdb_index, which are "raw".  An entry in
+   the index is of type cooked_index_entry.
+
+   Operations on the index are described below.  They are chosen to
+   make it relatively simple to implement the symtab "quick"
+   methods.  */
+class cooked_index
+{
+public:
+  cooked_index () = default;
+  explicit cooked_index (cooked_index &&other) = default;
+  DISABLE_COPY_AND_ASSIGN (cooked_index);
+  cooked_index &operator= (cooked_index &&other) = default;
+
+  /* Create a new cooked_index_entry and register it with this object.
+     Entries are owned by this object.  The new item is returned.  */
+  const cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
+				 cooked_index_flag flags,
+				 const char *name,
+				 const cooked_index_entry *parent_entry,
+				 dwarf2_per_cu_data *per_cu);
+
+  /* Return the entry that is believed to represent the program's
+     "main".  This will return NULL if no such entry is available.  */
+  const cooked_index_entry *get_main () const
+  {
+    return m_main;
+  }
+
+  /* Install a new fixed addrmap from the given mutable addrmap.  */
+  void install_addrmap (addrmap *map)
+  {
+    gdb_assert (m_addrmap == nullptr);
+    m_addrmap = addrmap_create_fixed (map, &m_storage);
+  }
+
+  /* Look up ADDR in the address map, and return either the
+     corresponding CU, or nullptr if the address could not be
+     found.  */
+  dwarf2_per_cu_data *lookup (CORE_ADDR addr)
+  {
+    return (dwarf2_per_cu_data *) addrmap_find (m_addrmap, addr);
+  }
+
+  /* Finalize the index.  This should be called a single time, when
+     the index has been fully populated.  It enters all the entries
+     into the internal hash table.  */
+  void finalize ();
+
+  /* A simple range over part of m_entries.  */
+  typedef iterator_range<std::vector<cooked_index_entry *>::iterator> range;
+
+  /* Look up an entry by name.  Returns a range of all matching
+     results.  If COMPLETING is true, then a larger range, suitable
+     for completion, will be returned.  */
+  range find (gdb::string_view name, bool completing);
+
+  /* Return a range of all the entries.  */
+  range all_entries ()
+  {
+    return { m_entries.begin (), m_entries.end () };
+  }
+
+private:
+
+  /* GNAT only emits mangled ("encoded") names in the DWARF, and does
+     not emit the module structure.  However, we need this structure
+     to do lookups.  This function recreates that structure for an
+     existing entry.  It returns the base name (last element) of the
+     full decoded name.  */
+  gdb::unique_xmalloc_ptr<char> handle_gnat_encoded_entry
+       (cooked_index_entry *entry, htab_t gnat_entries);
+
+  /* Create a new cooked_index_entry and register it with this object.
+     Entries are owned by this object.  The new item is returned.  */
+  cooked_index_entry *create (sect_offset die_offset,
+			      enum dwarf_tag tag,
+			      cooked_index_flag flags,
+			      const char *name,
+			      const cooked_index_entry *parent_entry,
+			      dwarf2_per_cu_data *per_cu)
+  {
+    return new (&m_storage) cooked_index_entry (die_offset, tag, flags,
+						name, parent_entry,
+						per_cu);
+  }
+
+  /* Storage for the entries.  */
+  auto_obstack m_storage;
+  /* List of all entries.  */
+  std::vector<cooked_index_entry *> m_entries;
+  /* If we found "main" or an entry with 'is_main' set, store it
+     here.  */
+  cooked_index_entry *m_main = nullptr;
+  /* Storage for canonical names.  */
+  std::vector<gdb::unique_xmalloc_ptr<char>> m_names;
+  /* The addrmap.  This maps address ranges to dwarf2_per_cu_data
+     objects.  */
+  addrmap *m_addrmap = nullptr;
+};
+
+#endif /* GDB_DWARF2_COOKED_INDEX_H */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 17/32] The new DWARF indexer
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (15 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 16/32] Introduce the new DWARF index class Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 18/32] Implement quick_symbol_functions for cooked DWARF index Tom Tromey
                   ` (16 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This patch adds the code to index DWARF.  This is just the scanner; it
reads the DWARF and constructs the index, but nothing calls it yet.

The indexer is split into two parts: a storage object and an indexer
object.  This is done to support the parallelization of this code -- a
future patch will create a single storage object per thread.
---
 gdb/dwarf2/read.c | 811 +++++++++++++++++++++++++++++++++++++++++++++-
 gdb/dwarf2/read.h |   7 +-
 2 files changed, 816 insertions(+), 2 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index be0a077ab34..fa6160ea58b 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -89,6 +89,8 @@
 #include "gdbsupport/pathstuff.h"
 #include "count-one-bits.h"
 #include <unordered_set>
+#include "dwarf2/abbrev-cache.h"
+#include "cooked-index.h"
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
@@ -800,6 +802,8 @@ class cutu_reader : public die_reader_specs
 
   DISABLE_COPY_AND_ASSIGN (cutu_reader);
 
+  cutu_reader (cutu_reader &&) = default;
+
   const gdb_byte *info_ptr = nullptr;
   struct die_info *comp_unit_die = nullptr;
   bool dummy_p = false;
@@ -808,6 +812,13 @@ class cutu_reader : public die_reader_specs
      for dummy CUs.  */
   void keep ();
 
+  /* Release the abbrev table, transferring ownership to the
+     caller.  */
+  abbrev_table_up release_abbrev_table ()
+  {
+    return std::move (m_abbrev_table_holder);
+  }
+
 private:
   void init_tu_and_read_dwo_dies (dwarf2_per_cu_data *this_cu,
 				  dwarf2_per_objfile *per_objfile,
@@ -6991,6 +7002,238 @@ create_partial_symtab (dwarf2_per_cu_data *per_cu,
 
   return pst;
 }
+\f
+
+/* An instance of this is created when scanning DWARF to create a
+   cooked index.  */
+
+class cooked_index_storage
+{
+public:
+
+  cooked_index_storage ()
+    : m_reader_hash (htab_create_alloc (10, hash_cutu_reader,
+					eq_cutu_reader,
+					htab_delete_entry<cutu_reader>,
+					xcalloc, xfree)),
+      m_index (new cooked_index),
+      m_addrmap_storage (),
+      m_addrmap (addrmap_create_mutable (&m_addrmap_storage))
+  {
+  }
+
+  DISABLE_COPY_AND_ASSIGN (cooked_index_storage);
+
+  /* Return the current abbrev cache.  */
+  abbrev_cache *get_abbrev_cache ()
+  {
+    return &m_abbrev_cache;
+  }
+
+  /* Return the DIE reader corresponding to PER_CU.  If no such reader
+     has been registered, return NULL.  */
+  cutu_reader *get_reader (dwarf2_per_cu_data *per_cu)
+  {
+    int index = per_cu->index;
+    return (cutu_reader *) htab_find_with_hash (m_reader_hash.get (),
+						&index, index);
+  }
+
+  /* Preserve READER by storing it in the local hash table.  */
+  cutu_reader *preserve (std::unique_ptr<cutu_reader> reader)
+  {
+    m_abbrev_cache.add (reader->release_abbrev_table ());
+
+    int index = reader->cu->per_cu->index;
+    void **slot = htab_find_slot_with_hash (m_reader_hash.get (), &index,
+					    index, INSERT);
+    gdb_assert (*slot == nullptr);
+    cutu_reader *result = reader.get ();
+    *slot = reader.release ();
+    return result;
+  }
+
+  /* Add an entry to the index.  The arguments describe the entry; see
+     cooked-index.h.  The new entry is returned.  */
+  const cooked_index_entry *add (sect_offset die_offset, enum dwarf_tag tag,
+				 cooked_index_flag flags,
+				 const char *name,
+				 const cooked_index_entry *parent_entry,
+				 dwarf2_per_cu_data *per_cu)
+  {
+    return m_index->add (die_offset, tag, flags, name, parent_entry, per_cu);
+  }
+
+  /* Install the current addrmap into the index being constructed,
+     then transfer ownership of the index to the caller.  */
+  std::unique_ptr<cooked_index> release ()
+  {
+    m_index->install_addrmap (m_addrmap);
+    return std::move (m_index);
+  }
+
+  /* Return the mutable addrmap that is currently being created.  */
+  addrmap *get_addrmap ()
+  {
+    return m_addrmap;
+  }
+
+private:
+
+  /* Hash function for a cutu_reader.  */
+  static hashval_t hash_cutu_reader (const void *a)
+  {
+    const cutu_reader *reader = (const cutu_reader *) a;
+    return reader->cu->per_cu->index;
+  }
+
+  /* Equality function for cutu_reader.  */
+  static int eq_cutu_reader (const void *a, const void *b)
+  {
+    const cutu_reader *ra = (const cutu_reader *) a;
+    const int *rb = (const int *) b;
+    return ra->cu->per_cu->index == *rb;
+  }
+
+  /* The abbrev cache used by this indexer.  */
+  abbrev_cache m_abbrev_cache;
+  /* A hash table of cutu_reader objects.  */
+  htab_up m_reader_hash;
+  /* The index that is being constructed.  */
+  std::unique_ptr<cooked_index> m_index;
+
+  /* Storage for the writeable addrmap.  */
+  auto_obstack m_addrmap_storage;
+  /* A writeable addrmap being constructed by this scanner.  */
+  addrmap *m_addrmap;
+};
+
+/* An instance of this is created to index a CU.  */
+
+class cooked_indexer
+{
+public:
+
+  cooked_indexer (cooked_index_storage *storage,
+		  dwarf2_per_cu_data *per_cu,
+		  enum language language)
+    : m_index_storage (storage),
+      m_per_cu (per_cu),
+      m_language (language),
+      m_obstack (),
+      m_die_range_map (addrmap_create_mutable (&m_obstack))
+  {
+  }
+
+  DISABLE_COPY_AND_ASSIGN (cooked_indexer);
+
+  /* Index the given CU.  */
+  void make_index (cutu_reader *reader);
+
+private:
+
+  /* A helper function to turn a section offset into an address that
+     can be used in an addrmap.  */
+  CORE_ADDR form_addr (sect_offset offset, bool is_dwz)
+  {
+    CORE_ADDR value = to_underlying (offset);
+    if (is_dwz)
+      value |= ((CORE_ADDR) 1) << (8 * sizeof (CORE_ADDR) - 1);
+    return value;
+  }
+
+  /* A helper function to scan the PC bounds of READER and record them
+     in the storage's addrmap.  */
+  void check_bounds (cutu_reader *reader);
+
+  /* Ensure that the indicated CU exists.  The cutu_reader for it is
+     returned.  FOR_SCANNING is true if the caller intends to scan all
+     the DIEs in the CU; when false, this use is assumed to be to look
+     up just a single DIE.  */
+  cutu_reader *ensure_cu_exists (cutu_reader *reader,
+				 dwarf2_per_objfile *per_objfile,
+				 sect_offset sect_off,
+				 bool is_dwz,
+				 bool for_scanning);
+
+  /* Index DIEs in the READER starting at INFO_PTR.  PARENT_ENTRY is
+     the entry for the enclosing scope (nullptr at top level).  FULLY
+     is true when a full scan must be done -- in some languages,
+     function scopes must be fully explored in order to find nested
+     functions.  This returns a pointer to just after the spot where
+     reading stopped.  */
+  const gdb_byte *index_dies (cutu_reader *reader,
+			      const gdb_byte *info_ptr,
+			      const cooked_index_entry *parent_entry,
+			      bool fully);
+
+  /* Scan the attributes for a given DIE and update the out
+     parameters.  Returns a pointer to the byte after the DIE.  */
+  const gdb_byte *scan_attributes (dwarf2_per_cu_data *scanning_per_cu,
+				   cutu_reader *reader,
+				   const gdb_byte *watermark_ptr,
+				   const gdb_byte *info_ptr,
+				   const abbrev_info *abbrev,
+				   const char **name,
+				   const char **linkage_name,
+				   cooked_index_flag *flags,
+				   sect_offset *sibling_offset,
+				   const cooked_index_entry **parent_entry,
+				   CORE_ADDR *maybe_defer,
+				   bool for_specification);
+
+  /* Handle DW_TAG_imported_unit, by scanning the DIE to find
+     DW_AT_import, and then scanning the referenced CU.  Returns a
+     pointer to the byte after the DIE.  */
+  const gdb_byte *index_imported_unit (cutu_reader *reader,
+				       const gdb_byte *info_ptr,
+				       const abbrev_info *abbrev);
+
+  /* Recursively read DIEs, recording the section offsets in
+     m_die_range_map and then calling index_dies.  */
+  const gdb_byte *recurse (cutu_reader *reader,
+			   const gdb_byte *info_ptr,
+			   const cooked_index_entry *parent_entry,
+			   bool fully);
+
+  /* The storage object, where the results are kept.  */
+  cooked_index_storage *m_index_storage;
+  /* The CU that we are reading on behalf of.  This object might be
+     asked to index one CU but to treat the results as if they come
+     from some including CU; in this case the including CU would be
+     recorded here.  */
+  dwarf2_per_cu_data *m_per_cu;
+  /* The language that we're assuming when reading.  */
+  enum language m_language;
+
+  /* Temporary storage.  */
+  auto_obstack m_obstack;
+  /* An addrmap that maps from section offsets (see the form_addr
+     method) to newly-created entries.  See m_deferred_entries to
+     understand this.  */
+  addrmap *m_die_range_map;
+
+  /* A single deferred entry.  */
+  struct deferred_entry
+  {
+    sect_offset die_offset;
+    const char *name;
+    CORE_ADDR spec_offset;
+    dwarf_tag tag;
+    cooked_index_flag flags;
+  };
+
+  /* The generated DWARF can sometimes have the declaration for a
+     method in a class (or perhaps namespace) scope, with the
+     definition appearing outside this scope... just one of the many
+     bad things about DWARF.  In order to handle this situation, we
+     defer certain entries until the end of scanning, at which point
+     we'll know the containing context of all the DIEs that we might
+     have scanned.  This vector stores these deferred entries.  */
+  std::vector<deferred_entry> m_deferred_entries;
+};
+
+
 
 /* DIE reader function for process_psymtab_comp_unit.  */
 
@@ -8365,7 +8608,8 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
       /* We only handle DW_FORM_ref4 here.  */
       const gdb_byte *sibling_data = info_ptr + abbrev->sibling_offset;
       unsigned int offset = read_4_bytes (abfd, sibling_data);
-      const gdb_byte *sibling_ptr = buffer + offset;
+      const gdb_byte *sibling_ptr
+	= buffer + to_underlying (cu->header.sect_off) + offset;
       if (sibling_ptr >= info_ptr && sibling_ptr < reader->buffer_end)
 	return sibling_ptr;
       /* Fall through to the slow way.  */
@@ -18977,6 +19221,571 @@ read_full_die (const struct die_reader_specs *reader,
 }
 \f
 
+void
+cooked_indexer::check_bounds (cutu_reader *reader)
+{
+  if (reader->cu->per_cu->addresses_seen)
+    return;
+
+  dwarf2_cu *cu = reader->cu;
+
+  CORE_ADDR best_lowpc = 0, best_highpc = 0;
+  /* Possibly set the default values of LOWPC and HIGHPC from
+     `DW_AT_ranges'.  */
+  dwarf2_find_base_address (reader->comp_unit_die, cu);
+  enum pc_bounds_kind cu_bounds_kind
+    = dwarf2_get_pc_bounds (reader->comp_unit_die, &best_lowpc, &best_highpc,
+			    cu, m_index_storage->get_addrmap (), cu->per_cu);
+  if (cu_bounds_kind == PC_BOUNDS_HIGH_LOW && best_lowpc < best_highpc)
+    {
+      struct objfile *objfile = cu->per_objfile->objfile;
+      CORE_ADDR baseaddr = objfile->text_section_offset ();
+      struct gdbarch *gdbarch = objfile->arch ();
+      CORE_ADDR low
+	= (gdbarch_adjust_dwarf2_addr (gdbarch, best_lowpc + baseaddr)
+	   - baseaddr);
+      CORE_ADDR high
+	= (gdbarch_adjust_dwarf2_addr (gdbarch, best_highpc + baseaddr)
+	   - baseaddr - 1);
+      /* Store the contiguous range if it is not empty; it can be
+	 empty for CUs with no code.  */
+      addrmap_set_empty (m_index_storage->get_addrmap (), low, high,
+			 cu->per_cu);
+
+      cu->per_cu->addresses_seen = true;
+    }
+}
+
+/* Helper function that returns true if TAG can have a linkage
+   name.  */
+
+static bool
+tag_can_have_linkage_name (enum dwarf_tag tag)
+{
+  switch (tag)
+    {
+      /* We include types here because an anonymous C++ type might
+	 have a name for linkage purposes.  */
+    case DW_TAG_class_type:
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+    case DW_TAG_variable:
+    case DW_TAG_subprogram:
+      return true;
+
+    default:
+      return false;
+    }
+}
+
+cutu_reader *
+cooked_indexer::ensure_cu_exists (cutu_reader *reader,
+				  dwarf2_per_objfile *per_objfile,
+				  sect_offset sect_off, bool is_dwz,
+				  bool for_scanning)
+{
+  /* Lookups for type unit references are always in the CU, and
+     cross-CU references will crash.  */
+  if (reader->cu->per_cu->is_dwz == is_dwz
+      && reader->cu->header.offset_in_cu_p (sect_off))
+    return reader;
+
+  dwarf2_per_cu_data *per_cu
+    = dwarf2_find_containing_comp_unit (sect_off, is_dwz, per_objfile);
+
+  /* When scanning, we only want to visit a given CU a single time.
+     Doing this check here avoids self-imports as well.  */
+  if (for_scanning)
+    {
+      if (per_cu->scanned)
+	return nullptr;
+      per_cu->scanned = true;
+    }
+  if (per_cu == m_per_cu)
+    return reader;
+
+  cutu_reader *result = m_index_storage->get_reader (per_cu);
+  if (result == nullptr)
+    {
+      cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false);
+
+      prepare_one_comp_unit (new_reader.cu, new_reader.comp_unit_die,
+			     language_minimal);
+      std::unique_ptr<cutu_reader> copy
+	(new cutu_reader (std::move (new_reader)));
+      result = m_index_storage->preserve (std::move (copy));
+    }
+
+  if (result->dummy_p || !result->comp_unit_die->has_children)
+    return nullptr;
+
+  if (for_scanning)
+    check_bounds (result);
+
+  return result;
+}
+
+const gdb_byte *
+cooked_indexer::scan_attributes (dwarf2_per_cu_data *scanning_per_cu,
+				 cutu_reader *reader,
+				 const gdb_byte *watermark_ptr,
+				 const gdb_byte *info_ptr,
+				 const abbrev_info *abbrev,
+				 const char **name,
+				 const char **linkage_name,
+				 cooked_index_flag *flags,
+				 sect_offset *sibling_offset,
+				 const cooked_index_entry **parent_entry,
+				 CORE_ADDR *maybe_defer,
+				 bool for_specification)
+{
+  bool origin_is_dwz = false;
+  bool is_declaration = false;
+  sect_offset origin_offset {};
+
+  gdb::optional<CORE_ADDR> low_pc;
+  gdb::optional<CORE_ADDR> high_pc;
+  bool high_pc_relative = false;
+
+  for (int i = 0; i < abbrev->num_attrs; ++i)
+    {
+      attribute attr;
+      info_ptr = read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
+      if (attr.requires_reprocessing_p ())
+	read_attribute_reprocess (reader, &attr, abbrev->tag);
+
+      /* Store the data if it is of an attribute we want to keep in a
+	 partial symbol table.  */
+      switch (attr.name)
+	{
+	case DW_AT_name:
+	  switch (abbrev->tag)
+	    {
+	    case DW_TAG_compile_unit:
+	    case DW_TAG_partial_unit:
+	    case DW_TAG_type_unit:
+	      /* Compilation units have a DW_AT_name that is a filename, not
+		 a source language identifier.  */
+	      break;
+
+	    default:
+	      if (*name == nullptr)
+		*name = attr.as_string ();
+	      break;
+	    }
+	  break;
+
+	case DW_AT_linkage_name:
+	case DW_AT_MIPS_linkage_name:
+	  /* Note that both forms of linkage name might appear.  We
+	     assume they will be the same, and we only store the last
+	     one we see.  */
+	  if (*linkage_name == nullptr)
+	    *linkage_name = attr.as_string ();
+	  break;
+
+	case DW_AT_main_subprogram:
+	  if (attr.as_boolean ())
+	    *flags |= IS_MAIN;
+	  break;
+
+	case DW_AT_declaration:
+	  is_declaration = attr.as_boolean ();
+	  break;
+
+	case DW_AT_sibling:
+	  if (sibling_offset != nullptr)
+	    *sibling_offset = attr.get_ref_die_offset ();
+	  break;
+
+	case DW_AT_specification:
+	case DW_AT_abstract_origin:
+	case DW_AT_extension:
+	  origin_offset = attr.get_ref_die_offset ();
+	  origin_is_dwz = attr.form == DW_FORM_GNU_ref_alt;
+	  break;
+
+	case DW_AT_external:
+	  if (attr.as_boolean ())
+	    *flags &= ~IS_STATIC;
+	  break;
+
+	case DW_AT_enum_class:
+	  if (attr.as_boolean ())
+	    *flags |= IS_ENUM_CLASS;
+	  break;
+
+	case DW_AT_low_pc:
+	  low_pc = attr.as_address ();
+	  break;
+
+	case DW_AT_high_pc:
+	  high_pc = attr.as_address ();
+	  if (reader->cu->header.version >= 4 && attr.form_is_constant ())
+	    high_pc_relative = true;
+	  break;
+
+	case DW_AT_location:
+	  if (!scanning_per_cu->addresses_seen && attr.form_is_block ())
+	    {
+	      struct dwarf_block *locdesc = attr.as_block ();
+	      CORE_ADDR addr = decode_locdesc (locdesc, reader->cu);
+	      if (addr != 0
+		  || reader->cu->per_objfile->per_bfd->has_section_at_zero)
+		{
+		  low_pc = addr;
+		  /* For variables, we don't want to try decoding the
+		     type just to find the size -- for gdb's purposes
+		     we only need the address of a variable.  */
+		  high_pc = addr + 1;
+		  high_pc_relative = false;
+		}
+	    }
+	  break;
+
+	case DW_AT_ranges:
+	  if (!scanning_per_cu->addresses_seen)
+	    {
+	      /* Offset in the .debug_ranges or .debug_rnglist section
+		 (depending on DWARF version).  */
+	      ULONGEST ranges_offset = attr.as_unsigned ();
+
+	      /* See dwarf2_cu::gnu_ranges_base's doc for why we might
+		 want to add this value.  */
+	      ranges_offset += reader->cu->gnu_ranges_base;
+
+	      CORE_ADDR lowpc, highpc;
+	      dwarf2_ranges_read (ranges_offset, &lowpc, &highpc, reader->cu,
+				  m_index_storage->get_addrmap (),
+				  scanning_per_cu, abbrev->tag);
+	    }
+	  break;
+	}
+    }
+
+  /* We don't want to examine declarations, but if we found a
+     declaration when handling DW_AT_specification or the like, then
+     that is ok.  Similarly, we allow an external variable without a
+     location; those are resolved via minimal symbols.  */
+  if (is_declaration && !for_specification
+      && (abbrev->tag != DW_TAG_variable
+	  || (*flags & IS_STATIC) != 0))
+    {
+      *linkage_name = nullptr;
+      *name = nullptr;
+    }
+  else if ((*name == nullptr
+	    || (*linkage_name == nullptr
+		&& tag_can_have_linkage_name (abbrev->tag))
+	    || (*parent_entry == nullptr && m_language != language_c))
+	   && origin_offset != sect_offset (0))
+    {
+      cutu_reader *new_reader
+	= ensure_cu_exists (reader, reader->cu->per_objfile, origin_offset,
+			    origin_is_dwz, false);
+      if (new_reader != nullptr)
+	{
+	  const gdb_byte *new_info_ptr = (new_reader->buffer
+					  + to_underlying (origin_offset));
+
+	  if (new_reader->cu == reader->cu
+	      && new_info_ptr > watermark_ptr
+	      && maybe_defer != nullptr
+	      && *parent_entry == nullptr)
+	    *maybe_defer = form_addr (origin_offset, origin_is_dwz);
+	  else if (*parent_entry == nullptr)
+	    {
+	      CORE_ADDR lookup = form_addr (origin_offset, origin_is_dwz);
+	      *parent_entry
+		= (cooked_index_entry *) addrmap_find (m_die_range_map,
+						       lookup);
+	    }
+
+	  unsigned int bytes_read;
+	  const abbrev_info *new_abbrev = peek_die_abbrev (*new_reader,
+							   new_info_ptr,
+							   &bytes_read);
+	  new_info_ptr += bytes_read;
+	  scan_attributes (scanning_per_cu, new_reader, new_info_ptr, new_info_ptr,
+			   new_abbrev, name, linkage_name, flags, nullptr,
+			   parent_entry, maybe_defer, true);
+	}
+    }
+
+  if (!for_specification)
+    {
+      if (m_language == language_ada
+	  && *linkage_name == nullptr
+	  /* && (abbrev->tag == DW_TAG_variable */
+	  /* 	  || abbrev->tag == DW_TAG_subprogram) */)
+	*linkage_name = *name;
+
+      if (!scanning_per_cu->addresses_seen
+	  && low_pc.has_value ()
+	  && (reader->cu->per_objfile->per_bfd->has_section_at_zero
+	      || *low_pc != 0)
+	  && high_pc.has_value ())
+	{
+	  if (high_pc_relative)
+	    high_pc = *high_pc + *low_pc;
+
+	  if (*high_pc > *low_pc)
+	    {
+	      struct objfile *objfile = reader->cu->per_objfile->objfile;
+	      CORE_ADDR baseaddr = objfile->text_section_offset ();
+	      struct gdbarch *gdbarch = objfile->arch ();
+	      CORE_ADDR lo
+		= (gdbarch_adjust_dwarf2_addr (gdbarch, *low_pc + baseaddr)
+		   - baseaddr);
+	      CORE_ADDR hi
+		= (gdbarch_adjust_dwarf2_addr (gdbarch, *high_pc + baseaddr)
+		   - baseaddr);
+	      addrmap_set_empty (m_index_storage->get_addrmap (), lo, hi - 1,
+				 scanning_per_cu);
+	    }
+	}
+
+      if (abbrev->tag == DW_TAG_module || abbrev->tag == DW_TAG_namespace)
+	*flags &= ~IS_STATIC;
+
+      if (abbrev->tag == DW_TAG_namespace && *name == nullptr)
+	*name = "(anonymous namespace)";
+
+      if (m_language == language_cplus
+	  && (abbrev->tag == DW_TAG_class_type
+	      || abbrev->tag == DW_TAG_interface_type
+	      || abbrev->tag == DW_TAG_structure_type
+	      || abbrev->tag == DW_TAG_union_type
+	      || abbrev->tag == DW_TAG_enumeration_type
+	      || abbrev->tag == DW_TAG_enumerator))
+	*flags &= ~IS_STATIC;
+    }
+
+  return info_ptr;
+}
+
+const gdb_byte *
+cooked_indexer::index_imported_unit (cutu_reader *reader,
+				     const gdb_byte *info_ptr,
+				     const abbrev_info *abbrev)
+{
+  sect_offset sect_off {};
+  bool is_dwz = false;
+
+  for (int i = 0; i < abbrev->num_attrs; ++i)
+    {
+      /* Note that we never need to reprocess attributes here.  */
+      attribute attr;
+      info_ptr = read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
+
+      if (attr.name == DW_AT_import)
+	{
+	  sect_off = attr.get_ref_die_offset ();
+	  is_dwz = (attr.form == DW_FORM_GNU_ref_alt
+		    || reader->cu->per_cu->is_dwz);
+	}
+    }
+
+  /* Did not find DW_AT_import.  */
+  if (sect_off == sect_offset (0))
+    return info_ptr;
+
+  dwarf2_per_objfile *per_objfile = reader->cu->per_objfile;
+  cutu_reader *new_reader = ensure_cu_exists (reader, per_objfile, sect_off,
+					      is_dwz, true);
+  if (new_reader != nullptr)
+    {
+      index_dies (new_reader, new_reader->info_ptr, nullptr, false);
+
+      reader->cu->add_dependence (new_reader->cu->per_cu);
+    }
+
+  return info_ptr;
+}
+
+const gdb_byte *
+cooked_indexer::recurse (cutu_reader *reader,
+			 const gdb_byte *info_ptr,
+			 const cooked_index_entry *parent_entry,
+			 bool fully)
+{
+  info_ptr = index_dies (reader, info_ptr, parent_entry, fully);
+
+  if (parent_entry != nullptr)
+    {
+      CORE_ADDR start = form_addr (parent_entry->die_offset,
+				   reader->cu->per_cu->is_dwz);
+      CORE_ADDR end = form_addr (sect_offset (info_ptr - 1 - reader->buffer),
+				 reader->cu->per_cu->is_dwz);
+      addrmap_set_empty (m_die_range_map, start, end, (void *) parent_entry);
+    }
+
+  return info_ptr;
+}
+
+const gdb_byte *
+cooked_indexer::index_dies (cutu_reader *reader,
+			    const gdb_byte *info_ptr,
+			    const cooked_index_entry *parent_entry,
+			    bool fully)
+{
+  const gdb_byte *end_ptr = info_ptr + reader->cu->header.get_length ();
+
+  while (info_ptr < end_ptr)
+    {
+      sect_offset this_die = (sect_offset) (info_ptr - reader->buffer);
+      unsigned int bytes_read;
+      const abbrev_info *abbrev = peek_die_abbrev (*reader, info_ptr,
+						   &bytes_read);
+      info_ptr += bytes_read;
+      if (abbrev == nullptr)
+	break;
+
+      if (abbrev->tag == DW_TAG_imported_unit)
+	{
+	  info_ptr = index_imported_unit (reader, info_ptr, abbrev);
+	  continue;
+	}
+
+      if (!abbrev->interesting)
+	{
+	  info_ptr = skip_one_die (reader, info_ptr, abbrev, !fully);
+	  if (fully && abbrev->has_children)
+	    info_ptr = index_dies (reader, info_ptr, parent_entry, fully);
+	  continue;
+	}
+
+      const char *name = nullptr;
+      const char *linkage_name = nullptr;
+      CORE_ADDR defer = 0;
+      cooked_index_flag flags = IS_STATIC;
+      sect_offset sibling {};
+      const cooked_index_entry *this_parent_entry = parent_entry;
+      info_ptr = scan_attributes (reader->cu->per_cu, reader, info_ptr,
+				  info_ptr, abbrev, &name, &linkage_name,
+				  &flags, &sibling, &this_parent_entry,
+				  &defer, false);
+
+      if (abbrev->tag == DW_TAG_namespace
+	  && m_language == language_cplus
+	  && strcmp (name, "::") == 0)
+	{
+	  /* GCC 4.0 and 4.1 had a bug (PR c++/28460) where they
+	     generated bogus DW_TAG_namespace DIEs with a name of "::"
+	     for the global namespace.  Work around this problem
+	     here.  */
+	  name = nullptr;
+	}
+
+      const cooked_index_entry *this_entry = nullptr;
+      if (name != nullptr)
+	{
+	  if (defer != 0)
+	    m_deferred_entries.push_back ({
+		this_die, name, defer, abbrev->tag, flags
+	      });
+	  else
+	    this_entry = m_index_storage->add (this_die, abbrev->tag, flags,
+					       name, this_parent_entry,
+					       m_per_cu);
+	}
+
+      if (linkage_name != nullptr)
+	{
+	  /* We only want this to be "main" if it has a linkage name
+	     but not an ordinary name.  */
+	  if (name != nullptr)
+	    flags = flags & ~IS_MAIN;
+	  m_index_storage->add (this_die, abbrev->tag, flags | IS_LINKAGE,
+				linkage_name, nullptr, m_per_cu);
+	}
+
+      if (abbrev->has_children)
+	{
+	  switch (abbrev->tag)
+	    {
+	    case DW_TAG_class_type:
+	    case DW_TAG_interface_type:
+	    case DW_TAG_structure_type:
+	    case DW_TAG_union_type:
+	      if (m_language != language_c && this_entry != nullptr)
+		{
+		  info_ptr = recurse (reader, info_ptr, this_entry, fully);
+		  continue;
+		}
+	      break;
+
+	    case DW_TAG_enumeration_type:
+	      /* We need to recurse even for an anonymous enumeration.
+		 Which scope we record as the parent scope depends on
+		 whether we're reading an "enum class".  If so, we use
+		 the enum itself as the parent, yielding names like
+		 "enum_class::enumerator"; otherwise we inject the
+		 names into our own parent scope.  */
+	      info_ptr = recurse (reader, info_ptr,
+				  ((flags & IS_ENUM_CLASS) == 0)
+				  ? parent_entry
+				  : this_entry,
+				  fully);
+	      continue;
+
+	    case DW_TAG_module:
+	      if (this_entry == nullptr)
+		break;
+	      /* FALLTHROUGH */
+	    case DW_TAG_namespace:
+	      /* We don't check THIS_ENTRY for a namespace, to handle
+		 the ancient G++ workaround pointed out above.  */
+	      info_ptr = recurse (reader, info_ptr, this_entry, fully);
+	      continue;
+
+	    case DW_TAG_subprogram:
+	      if ((m_language == language_fortran
+		   || m_language == language_ada)
+		  && this_entry != nullptr)
+		{
+		  info_ptr = recurse (reader, info_ptr, this_entry, true);
+		  continue;
+		}
+	      break;
+	    }
+
+	  if (sibling != sect_offset (0))
+	    {
+	      const gdb_byte *sibling_ptr
+		= reader->buffer + to_underlying (sibling);
+
+	      if (sibling_ptr < info_ptr)
+		complaint (_("DW_AT_sibling points backwards"));
+	      else if (sibling_ptr > reader->buffer_end)
+		reader->die_section->overflow_complaint ();
+	      else
+		info_ptr = sibling_ptr;
+	    }
+	  else
+	    info_ptr = skip_children (reader, info_ptr);
+	}
+    }
+
+  return info_ptr;
+}
+
+void
+cooked_indexer::make_index (cutu_reader *reader)
+{
+  check_bounds (reader);
+  index_dies (reader, reader->info_ptr, nullptr, false);
+
+  for (const auto &entry : m_deferred_entries)
+    {
+      CORE_ADDR key = form_addr (entry.die_offset, m_per_cu->is_dwz);
+      cooked_index_entry *parent
+	= (cooked_index_entry *) addrmap_find (m_die_range_map, key);
+      m_index_storage->add (entry.die_offset, entry.tag, entry.flags,
+			    entry.name, parent, m_per_cu);
+    }
+}
+
 /* Returns nonzero if TAG represents a type that we might generate a partial
    symbol for.  */
 
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 1a41d2992f7..626477339f9 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -105,7 +105,8 @@ struct dwarf2_per_cu_data
       m_header_read_in (false),
       addresses_seen (false),
       unit_type {},
-      lang (language_unknown)
+      lang (language_unknown),
+      scanned (false)
   {
   }
 
@@ -164,6 +165,10 @@ struct dwarf2_per_cu_data
   /* The language of this CU.  */
   ENUM_BITFIELD (language) lang : LANGUAGE_BITS;
 
+  /* True if this CU has been scanned by the indexer; false if
+     not.  */
+  bool scanned : 1;
+
   /* Our index in the unshared "symtabs" vector.  */
   unsigned index = 0;
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 18/32] Implement quick_symbol_functions for cooked DWARF index
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (16 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 17/32] The new DWARF indexer Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 19/32] Wire in the new DWARF indexer Tom Tromey
                   ` (15 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This implements quick_symbol_functions for the cooked DWARF index.
This is the code that interfaces between the new index and the rest of
gdb.  Cooked indexes still aren't created by anything.

For the most part this is straightforward.  It shares some concepts
with the existing DWARF indices.  However, because names are stored
pre-split in the cooked index, name lookup here is necessarily
different; see expand_symtabs_matching for the gory details.
---
 gdb/dwarf2/read.c | 274 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/dwarf2/read.h |   4 +
 2 files changed, 278 insertions(+)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index fa6160ea58b..a8f005f854a 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -91,6 +91,7 @@
 #include <unordered_set>
 #include "dwarf2/abbrev-cache.h"
 #include "cooked-index.h"
+#include "split-name.h"
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
@@ -5540,6 +5541,8 @@ get_gdb_index_contents_from_cache_dwz (objfile *obj, dwz_file *dwz)
   return global_index_cache.lookup_gdb_index (build_id, &dwz->index_cache_res);
 }
 
+static quick_symbol_functions_up make_cooked_index_funcs ();
+
 /* See dwarf2/public.h.  */
 
 void
@@ -5617,6 +5620,13 @@ dwarf2_initialize_objfile (struct objfile *objfile)
       return;
     }
 
+  if (per_bfd->cooked_index_table != nullptr)
+    {
+      dwarf_read_debug_printf ("re-using cooked index table");
+      objfile->qf.push_front (make_cooked_index_funcs ());
+      return;
+    }
+
   if (dwarf2_read_debug_names (per_objfile))
     {
       dwarf_read_debug_printf ("found debug names");
@@ -19786,6 +19796,270 @@ cooked_indexer::make_index (cutu_reader *reader)
     }
 }
 
+/* An implementation of quick_symbol_functions for the cooked DWARF
+   index.  */
+
+struct cooked_index_functions : public dwarf2_base_index_functions
+{
+  struct compunit_symtab *find_pc_sect_compunit_symtab
+    (struct objfile *objfile, struct bound_minimal_symbol msymbol,
+     CORE_ADDR pc, struct obj_section *section, int warn_if_readin) override;
+
+  struct compunit_symtab *find_compunit_symtab_by_address
+    (struct objfile *objfile, CORE_ADDR address) override;
+
+  void dump (struct objfile *objfile) override
+  {
+    printf_filtered ("Cooked index in use\n");
+  }
+
+  void expand_matching_symbols
+    (struct objfile *,
+     const lookup_name_info &lookup_name,
+     domain_enum domain,
+     int global,
+     symbol_compare_ftype *ordered_compare) 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;
+
+  bool can_lazily_read_symbols () override
+  {
+    return true;
+  }
+
+  void read_partial_symbols (struct objfile *objfile) override
+  {
+    if (dwarf2_has_info (objfile, nullptr))
+      dwarf2_build_psymtabs (objfile);
+  }
+};
+
+struct compunit_symtab *
+cooked_index_functions::find_pc_sect_compunit_symtab
+     (struct objfile *objfile,
+      struct bound_minimal_symbol msymbol,
+      CORE_ADDR pc,
+      struct obj_section *section,
+      int warn_if_readin)
+{
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    return nullptr;
+
+  CORE_ADDR baseaddr = objfile->text_section_offset ();
+  dwarf2_per_cu_data *per_cu
+    = per_objfile->per_bfd->cooked_index_table->lookup (pc - baseaddr);
+  if (per_cu == nullptr)
+    return nullptr;
+
+  if (warn_if_readin && per_objfile->symtab_set_p (per_cu))
+    warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
+	     paddress (objfile->arch (), pc));
+
+  compunit_symtab *result = (recursively_find_pc_sect_compunit_symtab
+			     (dw2_instantiate_symtab (per_cu, per_objfile,
+						      false),
+			      pc));
+  gdb_assert (result != nullptr);
+  return result;
+}
+
+struct compunit_symtab *
+cooked_index_functions::find_compunit_symtab_by_address
+     (struct objfile *objfile, CORE_ADDR address)
+{
+  if (objfile->sect_index_data == -1)
+    return nullptr;
+
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    return nullptr;
+
+  CORE_ADDR baseaddr = objfile->data_section_offset ();
+  dwarf2_per_cu_data *per_cu
+    = per_objfile->per_bfd->cooked_index_table->lookup (address - baseaddr);
+  if (per_cu == nullptr)
+    return nullptr;
+
+  return dw2_instantiate_symtab (per_cu, per_objfile, false);
+}
+
+void
+cooked_index_functions::expand_matching_symbols
+     (struct objfile *objfile,
+      const lookup_name_info &lookup_name,
+      domain_enum domain,
+      int global,
+      symbol_compare_ftype *ordered_compare)
+{
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    return;
+  const block_search_flags search_flags = (global
+					   ? SEARCH_GLOBAL_BLOCK
+					   : SEARCH_STATIC_BLOCK);
+  const language_defn *lang = language_def (language_ada);
+  symbol_name_matcher_ftype *name_match
+    = lang->get_symbol_name_matcher (lookup_name);
+
+  for (const cooked_index_entry *entry
+	 : per_objfile->per_bfd->cooked_index_table->all_entries ())
+    {
+      if (entry->parent_entry != nullptr)
+	continue;
+
+      if (!entry->matches (search_flags)
+	  || !entry->matches (domain))
+	continue;
+
+      if (name_match (entry->canonical, lookup_name, nullptr))
+	dw2_instantiate_symtab (entry->per_cu, per_objfile, false);
+    }
+}
+
+bool
+cooked_index_functions::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_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    return true;
+
+  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 (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
+	{
+	  QUIT;
+
+	  if (!dw2_expand_symtabs_matching_one (per_cu.get (), per_objfile,
+						file_matcher,
+						expansion_notify))
+	    return false;
+	}
+      return true;
+    }
+
+  lookup_name_info lookup_name_without_params
+    = lookup_name->make_ignore_params ();
+  bool completing = lookup_name->completion_mode ();
+
+  /* Unique styles of language splitting.  */
+  static const enum language unique_styles[] =
+  {
+    /* No splitting is also a style.  */
+    language_c,
+    /* This includes Rust.  */
+    language_cplus,
+    /* This includes Go.  */
+    language_d,
+    language_ada
+  };
+
+  for (enum language lang : unique_styles)
+    {
+      std::vector<gdb::string_view> name_vec
+	= lookup_name_without_params.split_name (lang);
+
+      for (const cooked_index_entry *entry
+	   : per_objfile->per_bfd->cooked_index_table->find (name_vec.back (),
+							     completing))
+	{
+	  /* No need to consider symbols from expanded CUs.  */
+	  if (per_objfile->symtab_set_p (entry->per_cu))
+	    continue;
+
+	  /* If file-matching was done, we don't need to consider
+	     symbols from unmarked CUs.  */
+	  if (file_matcher != nullptr && !entry->per_cu->v.quick->mark)
+	    continue;
+
+	  /* See if the symbol matches the type filter.  */
+	  if (!entry->matches (search_flags)
+	      || !entry->matches (domain)
+	      || !entry->matches (kind))
+	    continue;
+
+	  /* We've found the base name of the symbol; now walk its
+	     parentage chain, ensuring that each component
+	     matches.  */
+	  bool found = true;
+
+	  const cooked_index_entry *parent = entry->parent_entry;
+	  for (int i = name_vec.size () - 1; i > 0; --i)
+	    {
+	      /* If we ran out of entries, or if this segment doesn't
+		 match, this did not match.  */
+	      if (parent == nullptr
+		  || strncmp (parent->name, name_vec[i - 1].data (),
+			      name_vec[i - 1].length ()) != 0)
+		{
+		  found = false;
+		  break;
+		}
+
+	      parent = parent->parent_entry;
+	    }
+
+	  if (!found)
+	    continue;
+
+	  /* Might have been looking for "a::b" and found
+	     "x::a::b".  */
+	  symbol_name_match_type match_type
+	    = lookup_name_without_params.match_type ();
+	  if ((match_type == symbol_name_match_type::FULL
+	       || (lang != language_ada
+		   && match_type == symbol_name_match_type::EXPRESSION))
+	      && parent != nullptr)
+	    continue;
+
+	  if (symbol_matcher != nullptr)
+	    {
+	      auto_obstack temp_storage;
+	      const char *full_name = entry->full_name (&temp_storage);
+	      if (!symbol_matcher (full_name))
+		continue;
+	    }
+
+	  if (!dw2_expand_symtabs_matching_one (entry->per_cu, per_objfile,
+						file_matcher,
+						expansion_notify))
+	    return false;
+	}
+    }
+
+  return true;
+}
+
+/* Return a new cooked_index_functions object.  */
+
+static quick_symbol_functions_up
+make_cooked_index_funcs ()
+{
+  return quick_symbol_functions_up (new cooked_index_functions);
+}
+
+\f
+
 /* Returns nonzero if TAG represents a type that we might generate a partial
    symbol for.  */
 
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 626477339f9..3717d063fb0 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -23,6 +23,7 @@
 #include <queue>
 #include <unordered_map>
 #include "dwarf2/comp-unit-head.h"
+#include "dwarf2/cooked-index.h"
 #include "dwarf2/index-cache.h"
 #include "dwarf2/section.h"
 #include "filename-seen-cache.h"
@@ -444,6 +445,9 @@ struct dwarf2_per_bfd
   /* The mapped index, or NULL if .debug_names is missing or not being used.  */
   std::unique_ptr<mapped_debug_names> debug_names_table;
 
+  /* The cooked index, or NULL if not using one.  */
+  std::unique_ptr<cooked_index> cooked_index_table;
+
   /* When using index_table, this keeps track of all quick_file_names entries.
      TUs typically share line table entries with a CU, so we maintain a
      separate table of all line table entries to support the sharing.
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 19/32] Wire in the new DWARF indexer
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (17 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 18/32] Implement quick_symbol_functions for cooked DWARF index Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 20/32] Introduce thread-safe handling for complaints Tom Tromey
                   ` (14 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This wires the new DWARF indexer into the existing reader code.  That
is, this patch makes the modification necessary to enable the new
indexer.  It is not actually enabled by this patch -- that will be
done later.

I did a bit of performance testing for this patch and a few others.  I
copied my built gdb to /tmp, so that each test would be done on the
same executable.  Then, each time, I did:

    $ ./gdb -nx
    (gdb) maint time 1
    (gdb) file /tmp/gdb

This patch is the baseline and on one machine came in at 1.598869 wall
time.
---
 gdb/dwarf2/read.c | 199 +++++++++++++++++++++++++++++++++-------------
 1 file changed, 142 insertions(+), 57 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index a8f005f854a..f1e389bc5b2 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -794,7 +794,8 @@ class cutu_reader : public die_reader_specs
 	       dwarf2_per_objfile *per_objfile,
 	       struct abbrev_table *abbrev_table,
 	       dwarf2_cu *existing_cu,
-	       bool skip_partial);
+	       bool skip_partial,
+	       abbrev_cache *cache = nullptr);
 
   explicit cutu_reader (struct dwarf2_per_cu_data *this_cu,
 			dwarf2_per_objfile *per_objfile,
@@ -1116,7 +1117,9 @@ static dwarf2_psymtab *create_partial_symtab
   (dwarf2_per_cu_data *per_cu, dwarf2_per_objfile *per_objfile,
    const char *name);
 
-static void build_type_psymtabs_reader (cutu_reader *reader);
+class cooked_index_storage;
+static void build_type_psymtabs_reader (cutu_reader *reader,
+					cooked_index_storage *storage);
 
 static void dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile);
 
@@ -5608,6 +5611,13 @@ dwarf2_initialize_objfile (struct objfile *objfile)
       return;
     }
 
+  if (per_bfd->cooked_index_table != nullptr)
+    {
+      dwarf_read_debug_printf ("re-using cooked index table");
+      objfile->qf.push_front (make_cooked_index_funcs ());
+      return;
+    }
+
   /* There might already be partial symtabs built for this BFD.  This happens
      when loading the same binary twice with the index-cache enabled.  If so,
      don't try to read an index.  The objfile / per_objfile initialization will
@@ -5620,13 +5630,6 @@ dwarf2_initialize_objfile (struct objfile *objfile)
       return;
     }
 
-  if (per_bfd->cooked_index_table != nullptr)
-    {
-      dwarf_read_debug_printf ("re-using cooked index table");
-      objfile->qf.push_front (make_cooked_index_funcs ());
-      return;
-    }
-
   if (dwarf2_read_debug_names (per_objfile))
     {
       dwarf_read_debug_printf ("found debug names");
@@ -6088,7 +6091,9 @@ fill_in_sig_entry_from_dwo_entry (dwarf2_per_objfile *per_objfile,
   else
       gdb_assert (sig_entry->v.psymtab == NULL);
   gdb_assert (sig_entry->signature == dwo_entry->signature);
-  gdb_assert (to_underlying (sig_entry->type_offset_in_section) == 0);
+  gdb_assert (to_underlying (sig_entry->type_offset_in_section) == 0
+	      || (to_underlying (sig_entry->type_offset_in_section)
+		  == to_underlying (dwo_entry->type_offset_in_tu)));
   gdb_assert (sig_entry->type_unit_group == NULL);
   gdb_assert (sig_entry->dwo_unit == NULL);
 
@@ -6572,7 +6577,8 @@ cutu_reader::cutu_reader (dwarf2_per_cu_data *this_cu,
 			  dwarf2_per_objfile *per_objfile,
 			  struct abbrev_table *abbrev_table,
 			  dwarf2_cu *existing_cu,
-			  bool skip_partial)
+			  bool skip_partial,
+			  abbrev_cache *cache)
   : die_reader_specs {},
     m_this_cu (this_cu)
 {
@@ -6696,10 +6702,16 @@ cutu_reader::cutu_reader (dwarf2_per_cu_data *this_cu,
     gdb_assert (cu->header.abbrev_sect_off == abbrev_table->sect_off);
   else
     {
-      abbrev_section->read (objfile);
-      m_abbrev_table_holder
-	= abbrev_table::read (abbrev_section, cu->header.abbrev_sect_off);
-      abbrev_table = m_abbrev_table_holder.get ();
+      if (cache != nullptr)
+	abbrev_table = cache->find (abbrev_section,
+				    cu->header.abbrev_sect_off);
+      if (abbrev_table == nullptr)
+	{
+	  abbrev_section->read (objfile);
+	  m_abbrev_table_holder
+	    = abbrev_table::read (abbrev_section, cu->header.abbrev_sect_off);
+	  abbrev_table = m_abbrev_table_holder.get ();
+	}
     }
 
   /* Read the top level CU/TU die.  */
@@ -7388,16 +7400,21 @@ static void
 process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
 			   dwarf2_per_objfile *per_objfile,
 			   bool want_partial_unit,
-			   enum language pretend_language)
+			   enum language pretend_language,
+			   cooked_index_storage *storage)
 {
   /* If this compilation unit was already read in, free the
      cached copy in order to read it in again.	This is
      necessary because we skipped some symbols when we first
      read in the compilation unit (see load_partial_dies).
      This problem could be avoided, but the benefit is unclear.  */
-  per_objfile->remove_cu (this_cu);
+  if (!per_objfile->per_bfd->using_index)
+    per_objfile->remove_cu (this_cu);
 
-  cutu_reader reader (this_cu, per_objfile, nullptr, nullptr, false);
+  cutu_reader reader (this_cu, per_objfile, nullptr, nullptr, false,
+		      (storage == nullptr
+		       ? nullptr
+		       : storage->get_abbrev_cache ()));
 
   if (reader.comp_unit_die == nullptr)
     return;
@@ -7425,12 +7442,28 @@ process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
       /* Nothing.  */
     }
   else if (this_cu->is_debug_types)
-    build_type_psymtabs_reader (&reader);
+    build_type_psymtabs_reader (&reader, storage);
   else if (want_partial_unit
 	   || reader.comp_unit_die->tag != DW_TAG_partial_unit)
-    process_psymtab_comp_unit_reader (&reader, reader.info_ptr,
-				      reader.comp_unit_die,
-				      pretend_language);
+    {
+      if (per_objfile->per_bfd->using_index)
+	{
+	  if (!this_cu->scanned && reader.comp_unit_die->has_children)
+	    {
+	      this_cu->scanned = true;
+	      prepare_one_comp_unit (reader.cu, reader.comp_unit_die,
+				     pretend_language);
+	      gdb_assert (storage != nullptr);
+	      cooked_indexer indexer (storage, this_cu,
+				      reader.cu->per_cu->lang);
+	      indexer.make_index (&reader);
+	    }
+	}
+      else
+	process_psymtab_comp_unit_reader (&reader, reader.info_ptr,
+					  reader.comp_unit_die,
+					  pretend_language);
+    }
 
   /* Age out any secondary CUs.  */
   per_objfile->age_comp_units ();
@@ -7439,7 +7472,8 @@ process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
 /* Reader function for build_type_psymtabs.  */
 
 static void
-build_type_psymtabs_reader (cutu_reader *reader)
+build_type_psymtabs_reader (cutu_reader *reader,
+			    cooked_index_storage *storage)
 {
   dwarf2_per_objfile *per_objfile = reader->cu->per_objfile;
   struct dwarf2_cu *cu = reader->cu;
@@ -7467,16 +7501,26 @@ build_type_psymtabs_reader (cutu_reader *reader)
   tu_group->tus->push_back (sig_type);
 
   prepare_one_comp_unit (cu, type_unit_die, language_minimal);
-  pst = create_partial_symtab (per_cu, per_objfile, "");
-  pst->anonymous = true;
 
-  first_die = load_partial_dies (reader, info_ptr, 1);
+  if (per_objfile->per_bfd->using_index)
+    {
+      gdb_assert (storage != nullptr);
+      cooked_indexer indexer (storage, per_cu, cu->per_cu->lang);
+      indexer.make_index (reader);
+    }
+  else
+    {
+      pst = create_partial_symtab (per_cu, per_objfile, "");
+      pst->anonymous = true;
 
-  lowpc = (CORE_ADDR) -1;
-  highpc = (CORE_ADDR) 0;
-  scan_partial_symbols (first_die, &lowpc, &highpc, 0, cu);
+      first_die = load_partial_dies (reader, info_ptr, 1);
 
-  pst->end ();
+      lowpc = (CORE_ADDR) -1;
+      highpc = (CORE_ADDR) 0;
+      scan_partial_symbols (first_die, &lowpc, &highpc, 0, cu);
+
+      pst->end ();
+    }
 }
 
 /* Struct used to sort TUs by their abbreviation table offset.  */
@@ -7515,7 +7559,8 @@ struct tu_abbrev_offset
    dwarf2_per_objfile->per_bfd->type_unit_groups.  */
 
 static void
-build_type_psymtabs (dwarf2_per_objfile *per_objfile)
+build_type_psymtabs (dwarf2_per_objfile *per_objfile,
+		     cooked_index_storage *storage)
 {
   struct tu_stats *tu_stats = &per_objfile->per_bfd->tu_stats;
   abbrev_table_up abbrev_table;
@@ -7584,7 +7629,7 @@ build_type_psymtabs (dwarf2_per_objfile *per_objfile)
       cutu_reader reader (tu.sig_type, per_objfile,
 			  abbrev_table.get (), nullptr, false);
       if (!reader.dummy_p)
-	build_type_psymtabs_reader (&reader);
+	build_type_psymtabs_reader (&reader, storage);
     }
 }
 
@@ -7640,6 +7685,12 @@ build_type_psymtab_dependencies (void **slot, void *info)
   return 1;
 }
 
+struct skeleton_data
+{
+  dwarf2_per_objfile *per_objfile;
+  cooked_index_storage *storage;
+};
+
 /* Traversal function for process_skeletonless_type_unit.
    Read a TU in a DWO file and build partial symbols for it.  */
 
@@ -7647,15 +7698,16 @@ static int
 process_skeletonless_type_unit (void **slot, void *info)
 {
   struct dwo_unit *dwo_unit = (struct dwo_unit *) *slot;
-  dwarf2_per_objfile *per_objfile = (dwarf2_per_objfile *) info;
+  skeleton_data *data = (skeleton_data *) info;
 
   /* If this TU doesn't exist in the global table, add it and read it in.  */
 
-  if (per_objfile->per_bfd->signatured_types == NULL)
-    per_objfile->per_bfd->signatured_types = allocate_signatured_type_table ();
+  if (data->per_objfile->per_bfd->signatured_types == NULL)
+    data->per_objfile->per_bfd->signatured_types
+      = allocate_signatured_type_table ();
 
   signatured_type find_entry (dwo_unit->signature);
-  slot = htab_find_slot (per_objfile->per_bfd->signatured_types.get (),
+  slot = htab_find_slot (data->per_objfile->per_bfd->signatured_types.get (),
 			 &find_entry, INSERT);
   /* If we've already seen this type there's nothing to do.  What's happening
      is we're doing our own version of comdat-folding here.  */
@@ -7665,14 +7717,14 @@ process_skeletonless_type_unit (void **slot, void *info)
   /* This does the job that create_all_comp_units would have done for
      this TU.  */
   signatured_type *entry
-    = add_type_unit (per_objfile, dwo_unit->signature, slot);
-  fill_in_sig_entry_from_dwo_entry (per_objfile, entry, dwo_unit);
+    = add_type_unit (data->per_objfile, dwo_unit->signature, slot);
+  fill_in_sig_entry_from_dwo_entry (data->per_objfile, entry, dwo_unit);
   *slot = entry;
 
   /* This does the job that build_type_psymtabs would have done.  */
-  cutu_reader reader (entry, per_objfile, nullptr, nullptr, false);
+  cutu_reader reader (entry, data->per_objfile, nullptr, nullptr, false);
   if (!reader.dummy_p)
-    build_type_psymtabs_reader (&reader);
+    build_type_psymtabs_reader (&reader, data->storage);
 
   return 1;
 }
@@ -7696,15 +7748,18 @@ process_dwo_file_for_skeletonless_type_units (void **slot, void *info)
    Note: This can't be done until we know what all the DWO files are.  */
 
 static void
-process_skeletonless_type_units (dwarf2_per_objfile *per_objfile)
+process_skeletonless_type_units (dwarf2_per_objfile *per_objfile,
+				 cooked_index_storage *storage)
 {
+  skeleton_data data { per_objfile, storage };
+
   /* Skeletonless TUs in DWP files without .gdb_index is not supported yet.  */
   if (get_dwp_file (per_objfile) == NULL
       && per_objfile->per_bfd->dwo_files != NULL)
     {
       htab_traverse_noresize (per_objfile->per_bfd->dwo_files.get (),
 			      process_dwo_file_for_skeletonless_type_units,
-			      per_objfile);
+			      &data);
     }
 }
 
@@ -7750,9 +7805,6 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
      read_in_chain.  Make sure to free them when we're done.  */
   free_cached_comp_units freer (per_objfile);
 
-  create_all_comp_units (per_objfile);
-  build_type_psymtabs (per_objfile);
-
   /* Create a temporary address map on a temporary obstack.  We later
      copy this to the final obstack.  */
   auto_obstack temp_obstack;
@@ -7761,20 +7813,35 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
     = make_scoped_restore (&per_bfd->partial_symtabs->psymtabs_addrmap,
 			   addrmap_create_mutable (&temp_obstack));
 
+  cooked_index_storage index_storage;
+  cooked_index_storage *index_storage_ptr
+    = per_bfd->using_index ? &index_storage : nullptr;
+  create_all_comp_units (per_objfile);
+  build_type_psymtabs (per_objfile, index_storage_ptr);
+  if (per_bfd->using_index)
+    {
+      per_bfd->quick_file_names_table
+	= create_quick_file_names_table (per_bfd->all_comp_units.size ());
+
+      if (!per_bfd->debug_aranges.empty ())
+	read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges,
+				   index_storage.get_addrmap ());
+    }
+
   for (const auto &per_cu : per_bfd->all_comp_units)
     {
-      if (per_cu->v.psymtab != NULL)
+      if (!per_bfd->using_index && per_cu->v.psymtab != NULL)
 	/* In case a forward DW_TAG_imported_unit has read the CU already.  */
 	continue;
       process_psymtab_comp_unit (per_cu.get (), per_objfile, false,
-				 language_minimal);
+				 language_minimal, index_storage_ptr);
     }
 
   /* This has to wait until we read the CUs, we need the list of DWOs.  */
-  process_skeletonless_type_units (per_objfile);
+  process_skeletonless_type_units (per_objfile, &index_storage);
 
   /* Now that all TUs have been processed we can fill in the dependencies.  */
-  if (per_bfd->type_unit_groups != NULL)
+  if (!per_bfd->using_index && per_bfd->type_unit_groups != NULL)
     {
       htab_traverse_noresize (per_bfd->type_unit_groups.get (),
 			      build_type_psymtab_dependencies, per_objfile);
@@ -7783,14 +7850,27 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
   if (dwarf_read_debug > 0)
     print_tu_stats (per_objfile);
 
-  set_partial_user (per_objfile);
+  if (per_bfd->using_index)
+    {
+      per_bfd->cooked_index_table = index_storage.release ();
+      per_bfd->cooked_index_table->finalize ();
 
-  per_bfd->partial_symtabs->psymtabs_addrmap
-    = addrmap_create_fixed (per_bfd->partial_symtabs->psymtabs_addrmap,
-			    per_bfd->partial_symtabs->obstack ());
-  /* At this point we want to keep the address map.  */
-  save_psymtabs_addrmap.release ();
+      const cooked_index_entry *main_entry
+	= per_bfd->cooked_index_table->get_main ();
+      if (main_entry != nullptr)
+	set_objfile_main_name (objfile, main_entry->name,
+			       main_entry->per_cu->lang);
+    }
+  else
+    {
+      set_partial_user (per_objfile);
 
+      per_bfd->partial_symtabs->psymtabs_addrmap
+	= addrmap_create_fixed (per_bfd->partial_symtabs->psymtabs_addrmap,
+				per_bfd->partial_symtabs->obstack ());
+      /* At this point we want to keep the address map.  */
+      save_psymtabs_addrmap.release ();
+    }
   dwarf_read_debug_printf ("Done building psymtabs of %s",
 			   objfile_name (objfile));
 }
@@ -7879,6 +7959,10 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile,
       this_cu->is_dwz = is_dwz;
       this_cu->section = section;
 
+      if (per_objfile->per_bfd->using_index)
+	this_cu->v.quick = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
+					   struct dwarf2_per_cu_quick_data);
+
       info_ptr = info_ptr + this_cu->length;
       per_objfile->per_bfd->all_comp_units.push_back (std::move (this_cu));
     }
@@ -8007,7 +8091,7 @@ scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc,
 		/* Go read the partial unit, if needed.  */
 		if (per_cu->v.psymtab == NULL)
 		  process_psymtab_comp_unit (per_cu, cu->per_objfile, true,
-					     cu->per_cu->lang);
+					     cu->per_cu->lang, nullptr);
 
 		if (pdi->die_parent == nullptr
 		    && per_cu->unit_type == DW_UT_compile
@@ -19317,7 +19401,8 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader,
   cutu_reader *result = m_index_storage->get_reader (per_cu);
   if (result == nullptr)
     {
-      cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false);
+      cutu_reader new_reader (per_cu, per_objfile, nullptr, nullptr, false,
+			      m_index_storage->get_abbrev_cache ());
 
       prepare_one_comp_unit (new_reader.cu, new_reader.comp_unit_die,
 			     language_minimal);
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 20/32] Introduce thread-safe handling for complaints
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (18 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 19/32] Wire in the new DWARF indexer Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 21/32] Pre-read DWARF section data Tom Tromey
                   ` (13 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This introduces a new class that can be used to make the "complaint"
code thread-safe.  Instantiating the class installs a new handler that
collects complaints, and then prints them all when the object is
destroyed.

This approach requires some locks.  I couldn't think of a better way
to handle this, though, because the I/O system is not thread-safe.

It seemed to me that only GDB developers are likely to enable
complaints, and because the complaint macro handle this case already
(before any locks are required), I reasoned that any performance
degradation that would result here would be fine.

As an aside about complaints -- are they useful at all?  I just ignore
them, myself, since mostly they seem to indicate compiler problems
that can't be solved in the GDB world anyway.  I'd personally prefer
them to be in a separate tool, like a hypothetical 'dwarflint'.
---
 gdb/complaints.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++--
 gdb/complaints.h | 33 +++++++++++++++++++++++
 2 files changed, 99 insertions(+), 2 deletions(-)

diff --git a/gdb/complaints.c b/gdb/complaints.c
index a823fcb0020..65fa2afe499 100644
--- a/gdb/complaints.c
+++ b/gdb/complaints.c
@@ -23,6 +23,7 @@
 #include "gdbcmd.h"
 #include "gdbsupport/selftest.h"
 #include <unordered_map>
+#include <mutex>
 
 /* Map format strings to counters.  */
 
@@ -34,6 +35,10 @@ static std::unordered_map<const char *, int> counters;
 
 int stop_whining = 0;
 
+#if CXX_STD_THREAD
+static std::mutex complaint_mutex;
+#endif /* CXX_STD_THREAD */
+
 /* See complaints.h.  */
 
 void
@@ -41,8 +46,13 @@ complaint_internal (const char *fmt, ...)
 {
   va_list args;
 
-  if (++counters[fmt] > stop_whining)
-    return;
+  {
+#if CXX_STD_THREAD
+    std::lock_guard<std::mutex> guard (complaint_mutex);
+#endif
+    if (++counters[fmt] > stop_whining)
+      return;
+  }
 
   va_start (args, fmt);
 
@@ -66,6 +76,60 @@ clear_complaints ()
   counters.clear ();
 }
 
+/* See complaints.h.  */
+
+complaint_interceptor *complaint_interceptor::g_complaint_interceptor;
+
+/* See complaints.h.  */
+
+complaint_interceptor::complaint_interceptor ()
+  : m_saved_warning_hook (deprecated_warning_hook)
+{
+  /* These cannot be stacked.  */
+  gdb_assert (g_complaint_interceptor == nullptr);
+  g_complaint_interceptor = this;
+  deprecated_warning_hook = issue_complaint;
+}
+
+/* A helper that wraps a warning hook.  */
+
+static void
+wrap_warning_hook (void (*hook) (const char *, va_list), ...)
+{
+  va_list args;
+  va_start (args, hook);
+  hook ("%s", args);
+  va_end (args);
+}
+
+/* See complaints.h.  */
+
+complaint_interceptor::~complaint_interceptor ()
+{
+  for (const std::string &str : m_complaints)
+    {
+      if (m_saved_warning_hook)
+	wrap_warning_hook (m_saved_warning_hook, str.c_str ());
+      else
+	fprintf_filtered (gdb_stderr, _("During symbol reading: %s\n"),
+			  str.c_str ());
+    }
+
+  g_complaint_interceptor = nullptr;
+  deprecated_warning_hook = m_saved_warning_hook;
+}
+
+/* See complaints.h.  */
+
+void
+complaint_interceptor::issue_complaint (const char *fmt, va_list args)
+{
+#if CXX_STD_THREAD
+  std::lock_guard<std::mutex> guard (complaint_mutex);
+#endif
+  g_complaint_interceptor->m_complaints.insert (string_vprintf (fmt, args));
+}
+
 static void
 complaints_show_value (struct ui_file *file, int from_tty,
 		       struct cmd_list_element *cmd, const char *value)
diff --git a/gdb/complaints.h b/gdb/complaints.h
index 485dbb15860..144ce09fa5d 100644
--- a/gdb/complaints.h
+++ b/gdb/complaints.h
@@ -21,6 +21,8 @@
 #if !defined (COMPLAINTS_H)
 #define COMPLAINTS_H
 
+#include <unordered_set>
+
 /* Helper for complaint.  */
 extern void complaint_internal (const char *fmt, ...)
   ATTRIBUTE_PRINTF (1, 2);
@@ -46,5 +48,36 @@ extern int stop_whining;
 
 extern void clear_complaints ();
 
+/* A class that can handle calls to complaint from multiple threads.
+   When this is instantiated, it hooks into the complaint mechanism,
+   so the 'complaint' macro can continue to be used.  When it is
+   destroyed, it issues all the complaints that have been stored.  It
+   should only be instantiated in the main thread.  */
+
+class complaint_interceptor
+{
+public:
+
+  complaint_interceptor ();
+  ~complaint_interceptor ();
+
+  DISABLE_COPY_AND_ASSIGN (complaint_interceptor);
+
+private:
+
+  /* The issued complaints.  */
+  std::unordered_set<std::string> m_complaints;
+
+  /* The saved value of deprecated_warning_hook.  */
+  void (*m_saved_warning_hook) (const char *, va_list)
+    ATTRIBUTE_FPTR_PRINTF(1,0);
+
+  /* A helper function that is used by the 'complaint' implementation
+     to issue a complaint.  */
+  static void issue_complaint (const char *, va_list);
+
+  /* This object.  Used by the static callback function.  */
+  static complaint_interceptor *g_complaint_interceptor;
+};
 
 #endif /* !defined (COMPLAINTS_H) */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 21/32] Pre-read DWARF section data
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (19 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 20/32] Introduce thread-safe handling for complaints Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 22/32] Parallelize DWARF indexing Tom Tromey
                   ` (12 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Because BFD is not thread-safe, we need to be sure that any section
data that is needed is read before trying to do any DWARF indexing in
the background.

This patch takes a simple approach to this -- it pre-reads the
"info"-related sections.  This is done for the main file, but also any
auxiliary files as well, such as the DWO file.

This patch could be perhaps enhanced by removing some now-redundant
calls to dwarf2_section_info::read.
---
 gdb/dwarf2/read.c | 209 ++++++++++++++++++++--------------------------
 gdb/dwarf2/read.h |   4 +
 2 files changed, 93 insertions(+), 120 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index f1e389bc5b2..ba804ba5c67 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -2055,6 +2055,25 @@ dwarf2_get_section_info (struct objfile *objfile,
   *sizep = info->size;
 }
 
+/* See dwarf2/read.h.  */
+
+void
+dwarf2_per_bfd::map_info_sections (struct objfile *objfile)
+{
+  info.read (objfile);
+  abbrev.read (objfile);
+  line.read (objfile);
+  str.read (objfile);
+  str_offsets.read (objfile);
+  line_str.read (objfile);
+  ranges.read (objfile);
+  rnglists.read (objfile);
+  addr.read (objfile);
+
+  for (auto &section : types)
+    section.read (objfile);
+}
+
 \f
 /* DWARF quick_symbol_functions support.  */
 
@@ -7799,7 +7818,7 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
   scoped_restore restore_reading_psyms
     = make_scoped_restore (&per_bfd->reading_partial_symbols, true);
 
-  per_bfd->info.read (objfile);
+  per_bfd->map_info_sections (objfile);
 
   /* Any cached compilation units will be linked by the per-objfile
      read_in_chain.  Make sure to free them when we're done.  */
@@ -12605,69 +12624,47 @@ open_dwo_file (dwarf2_per_objfile *per_objfile,
    size of each of the DWO debugging sections we are interested in.  */
 
 static void
-dwarf2_locate_dwo_sections (bfd *abfd, asection *sectp,
-			    dwo_sections *dwo_sections)
+dwarf2_locate_dwo_sections (struct objfile *objfile, bfd *abfd,
+			    asection *sectp, dwo_sections *dwo_sections)
 {
   const struct dwop_section_names *names = &dwop_section_names;
 
+  struct dwarf2_section_info *dw_sect = nullptr;
+
   if (names->abbrev_dwo.matches (sectp->name))
-    {
-      dwo_sections->abbrev.s.section = sectp;
-      dwo_sections->abbrev.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->abbrev;
   else if (names->info_dwo.matches (sectp->name))
-    {
-      dwo_sections->info.s.section = sectp;
-      dwo_sections->info.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->info;
   else if (names->line_dwo.matches (sectp->name))
-    {
-      dwo_sections->line.s.section = sectp;
-      dwo_sections->line.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->line;
   else if (names->loc_dwo.matches (sectp->name))
-    {
-      dwo_sections->loc.s.section = sectp;
-      dwo_sections->loc.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->loc;
   else if (names->loclists_dwo.matches (sectp->name))
-    {
-      dwo_sections->loclists.s.section = sectp;
-      dwo_sections->loclists.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->loclists;
   else if (names->macinfo_dwo.matches (sectp->name))
-    {
-      dwo_sections->macinfo.s.section = sectp;
-      dwo_sections->macinfo.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->macinfo;
   else if (names->macro_dwo.matches (sectp->name))
-    {
-      dwo_sections->macro.s.section = sectp;
-      dwo_sections->macro.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->macro;
   else if (names->rnglists_dwo.matches (sectp->name))
-    {
-      dwo_sections->rnglists.s.section = sectp;
-      dwo_sections->rnglists.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->rnglists;
   else if (names->str_dwo.matches (sectp->name))
-    {
-      dwo_sections->str.s.section = sectp;
-      dwo_sections->str.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->str;
   else if (names->str_offsets_dwo.matches (sectp->name))
-    {
-      dwo_sections->str_offsets.s.section = sectp;
-      dwo_sections->str_offsets.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwo_sections->str_offsets;
   else if (names->types_dwo.matches (sectp->name))
     {
       struct dwarf2_section_info type_section;
 
       memset (&type_section, 0, sizeof (type_section));
-      type_section.s.section = sectp;
-      type_section.size = bfd_section_size (sectp);
       dwo_sections->types.push_back (type_section);
+      dw_sect = &dwo_sections->types.back ();
+    }
+
+  if (dw_sect != nullptr)
+    {
+      dw_sect->s.section = sectp;
+      dw_sect->size = bfd_section_size (sectp);
+      dw_sect->read (objfile);
     }
 }
 
@@ -12695,8 +12692,8 @@ open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name,
   dwo_file->dbfd = std::move (dbfd);
 
   for (asection *sec : gdb_bfd_sections (dwo_file->dbfd))
-    dwarf2_locate_dwo_sections (dwo_file->dbfd.get (), sec,
-				&dwo_file->sections);
+    dwarf2_locate_dwo_sections (per_objfile->objfile, dwo_file->dbfd.get (),
+				sec, &dwo_file->sections);
 
   create_cus_hash_table (per_objfile, cu, *dwo_file, dwo_file->sections.info,
 			 dwo_file->cus);
@@ -12723,8 +12720,8 @@ open_and_init_dwo_file (dwarf2_cu *cu, const char *dwo_name,
    we are interested in.  */
 
 static void
-dwarf2_locate_common_dwp_sections (bfd *abfd, asection *sectp,
-				   dwp_file *dwp_file)
+dwarf2_locate_common_dwp_sections (struct objfile *objfile, bfd *abfd,
+				   asection *sectp, dwp_file *dwp_file)
 {
   const struct dwop_section_names *names = &dwop_section_names;
   unsigned int elf_section_nr = elf_section_data (sectp)->this_idx;
@@ -12735,20 +12732,19 @@ dwarf2_locate_common_dwp_sections (bfd *abfd, asection *sectp,
   dwp_file->elf_sections[elf_section_nr] = sectp;
 
   /* Look for specific sections that we need.  */
+  struct dwarf2_section_info *dw_sect = nullptr;
   if (names->str_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.str.s.section = sectp;
-      dwp_file->sections.str.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.str;
   else if (names->cu_index.matches (sectp->name))
-    {
-      dwp_file->sections.cu_index.s.section = sectp;
-      dwp_file->sections.cu_index.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.cu_index;
   else if (names->tu_index.matches (sectp->name))
+    dw_sect = &dwp_file->sections.tu_index;
+
+  if (dw_sect != nullptr)
     {
-      dwp_file->sections.tu_index.s.section = sectp;
-      dwp_file->sections.tu_index.size = bfd_section_size (sectp);
+      dw_sect->s.section = sectp;
+      dw_sect->size = bfd_section_size (sectp);
+      dw_sect->read (objfile);
     }
 }
 
@@ -12758,7 +12754,8 @@ dwarf2_locate_common_dwp_sections (bfd *abfd, asection *sectp,
    have version 1 or 2 or 5 until we parse the cu_index/tu_index sections.  */
 
 static void
-dwarf2_locate_v2_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr)
+dwarf2_locate_v2_dwp_sections (struct objfile *objfile, bfd *abfd,
+			       asection *sectp, void *dwp_file_ptr)
 {
   struct dwp_file *dwp_file = (struct dwp_file *) dwp_file_ptr;
   const struct dwop_section_names *names = &dwop_section_names;
@@ -12770,45 +12767,29 @@ dwarf2_locate_v2_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr)
   dwp_file->elf_sections[elf_section_nr] = sectp;
 
   /* Look for specific sections that we need.  */
+  struct dwarf2_section_info *dw_sect = nullptr;
   if (names->abbrev_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.abbrev.s.section = sectp;
-      dwp_file->sections.abbrev.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.abbrev;
   else if (names->info_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.info.s.section = sectp;
-      dwp_file->sections.info.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.info;
   else if (names->line_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.line.s.section = sectp;
-      dwp_file->sections.line.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.line;
   else if (names->loc_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.loc.s.section = sectp;
-      dwp_file->sections.loc.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.loc;
   else if (names->macinfo_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.macinfo.s.section = sectp;
-      dwp_file->sections.macinfo.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.macinfo;
   else if (names->macro_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.macro.s.section = sectp;
-      dwp_file->sections.macro.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.macro;
   else if (names->str_offsets_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.str_offsets.s.section = sectp;
-      dwp_file->sections.str_offsets.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.str_offsets;
   else if (names->types_dwo.matches (sectp->name))
+    dw_sect = &dwp_file->sections.types;
+
+  if (dw_sect != nullptr)
     {
-      dwp_file->sections.types.s.section = sectp;
-      dwp_file->sections.types.size = bfd_section_size (sectp);
+      dw_sect->s.section = sectp;
+      dw_sect->size = bfd_section_size (sectp);
+      dw_sect->read (objfile);
     }
 }
 
@@ -12818,7 +12799,8 @@ dwarf2_locate_v2_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr)
    have version 1 or 2 or 5 until we parse the cu_index/tu_index sections.  */
 
 static void
-dwarf2_locate_v5_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr)
+dwarf2_locate_v5_dwp_sections (struct objfile *objfile, bfd *abfd,
+			       asection *sectp, void *dwp_file_ptr)
 {
   struct dwp_file *dwp_file = (struct dwp_file *) dwp_file_ptr;
   const struct dwop_section_names *names = &dwop_section_names;
@@ -12830,40 +12812,27 @@ dwarf2_locate_v5_dwp_sections (bfd *abfd, asection *sectp, void *dwp_file_ptr)
   dwp_file->elf_sections[elf_section_nr] = sectp;
 
   /* Look for specific sections that we need.  */
+  struct dwarf2_section_info *dw_sect = nullptr;
   if (names->abbrev_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.abbrev.s.section = sectp;
-      dwp_file->sections.abbrev.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.abbrev;
   else if (names->info_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.info.s.section = sectp;
-      dwp_file->sections.info.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.info;
   else if (names->line_dwo.matches (sectp->name))
-   {
-     dwp_file->sections.line.s.section = sectp;
-     dwp_file->sections.line.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.line;
   else if (names->loclists_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.loclists.s.section = sectp;
-      dwp_file->sections.loclists.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.loclists;
   else if (names->macro_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.macro.s.section = sectp;
-      dwp_file->sections.macro.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.macro;
   else if (names->rnglists_dwo.matches (sectp->name))
-    {
-      dwp_file->sections.rnglists.s.section = sectp;
-      dwp_file->sections.rnglists.size = bfd_section_size (sectp);
-    }
+    dw_sect = &dwp_file->sections.rnglists;
   else if (names->str_offsets_dwo.matches (sectp->name))
+    dw_sect = &dwp_file->sections.str_offsets;
+
+  if (dw_sect != nullptr)
     {
-      dwp_file->sections.str_offsets.s.section = sectp;
-      dwp_file->sections.str_offsets.size = bfd_section_size (sectp);
+      dw_sect->s.section = sectp;
+      dw_sect->size = bfd_section_size (sectp);
+      dw_sect->read (objfile);
     }
 }
 
@@ -12990,7 +12959,7 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile)
 		    dwp_file->num_sections, asection *);
 
   for (asection *sec : gdb_bfd_sections (dwp_file->dbfd))
-    dwarf2_locate_common_dwp_sections (dwp_file->dbfd.get (), sec,
+    dwarf2_locate_common_dwp_sections (objfile, dwp_file->dbfd.get (), sec,
 				       dwp_file.get ());
 
   dwp_file->cus = create_dwp_hash_table (per_objfile, dwp_file.get (), 0);
@@ -13020,10 +12989,10 @@ open_and_init_dwp_file (dwarf2_per_objfile *per_objfile)
   for (asection *sec : gdb_bfd_sections (dwp_file->dbfd))
     {
       if (dwp_file->version == 2)
-	dwarf2_locate_v2_dwp_sections (dwp_file->dbfd.get (), sec,
+	dwarf2_locate_v2_dwp_sections (objfile, dwp_file->dbfd.get (), sec,
 				       dwp_file.get ());
       else
-	dwarf2_locate_v5_dwp_sections (dwp_file->dbfd.get (), sec,
+	dwarf2_locate_v5_dwp_sections (objfile, dwp_file->dbfd.get (), sec,
 				       dwp_file.get ());
     }
 
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 3717d063fb0..3b29a0a2a73 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -361,6 +361,10 @@ struct dwarf2_per_bfd
      is allocated on the dwarf2_per_bfd obstack.  */
   signatured_type_up allocate_signatured_type (ULONGEST signature);
 
+  /* Map all the DWARF section data needed when scanning
+     .debug_info.  */
+  void map_info_sections (struct objfile *objfile);
+
 private:
   /* This function is mapped across the sections and remembers the
      offset and size of each of the debugging sections we are
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 22/32] Parallelize DWARF indexing
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (20 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 21/32] Pre-read DWARF section data Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 23/32] "Finalize" the DWARF index in the background Tom Tromey
                   ` (11 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This parallelizes the new DWARF indexer.  The indexer's storage was
designed so that each storage object and each indexer is fully
independent.  This setup makes it simple to scan different CUs
independently.

This patch creates a new cooked index storage object per thread, and
then scans a subset of all the CUs in each such thread, using gdb's
existing thread pool.

In the ongoing "gdb gdb" example, this patch reduces the wall time
down to 0.668923, from 0.903534.  (Note that the 0.903534 is the time
for the new index -- that is, when the "enable the new index" patch is
rebased to before this one.  However, in the final series, that patch
appears toward the end.  Hopefully this isn't too confusing.)
---
 gdb/dwarf2/cooked-index.c | 142 ++++++++++++++++++++++++++++----------
 gdb/dwarf2/cooked-index.h | 116 ++++++++++++++++++++++---------
 gdb/dwarf2/read.c         | 114 +++++++++++++++++++++++++-----
 gdb/dwarf2/read.h         |   4 +-
 4 files changed, 288 insertions(+), 88 deletions(-)

diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c
index 1b89e4c91f3..bb10b884a43 100644
--- a/gdb/dwarf2/cooked-index.c
+++ b/gdb/dwarf2/cooked-index.c
@@ -116,10 +116,41 @@ cooked_index::add (sect_offset die_offset, enum dwarf_tag tag,
   return result;
 }
 
+cooked_index_vector::cooked_index_vector (vec_type &&vec)
+  : m_vector (std::move (vec))
+{
+  finalize ();
+}
+
+/* See cooked-index.h.  */
+
+dwarf2_per_cu_data *
+cooked_index_vector::lookup (CORE_ADDR addr)
+{
+  for (const auto &index : m_vector)
+    {
+      dwarf2_per_cu_data *result = index->lookup (addr);
+      if (result != nullptr)
+	return result;
+    }
+  return nullptr;
+}
+
+/* See cooked-index.h.  */
+
+std::vector<addrmap *>
+cooked_index_vector::get_addrmaps ()
+{
+  std::vector<addrmap *> result;
+  for (const auto &index : m_vector)
+    result.push_back (index->m_addrmap);
+  return result;
+}
+
 /* See cooked-index.h.  */
 
-cooked_index::range
-cooked_index::find (gdb::string_view name, bool completing)
+cooked_index_vector::range
+cooked_index_vector::find (gdb::string_view name, bool completing)
 {
   auto lower = std::lower_bound (m_entries.begin (), m_entries.end (),
 				 name,
@@ -149,8 +180,8 @@ cooked_index::find (gdb::string_view name, bool completing)
 /* See cooked-index.h.  */
 
 gdb::unique_xmalloc_ptr<char>
-cooked_index::handle_gnat_encoded_entry (cooked_index_entry *entry,
-					 htab_t gnat_entries)
+cooked_index_vector::handle_gnat_encoded_entry (cooked_index_entry *entry,
+						htab_t gnat_entries)
 {
   std::string canonical = ada_decode (entry->name, false, false);
   if (canonical.empty ())
@@ -173,9 +204,11 @@ cooked_index::handle_gnat_encoded_entry (cooked_index_entry *entry,
 	{
 	  gdb::unique_xmalloc_ptr<char> new_name
 	    = make_unique_xstrndup (name.data (), name.length ());
-	  last = create (entry->die_offset, DW_TAG_namespace,
-			 0, new_name.get (), parent,
-			 entry->per_cu);
+	  /* It doesn't matter which obstack we allocate this on, so
+	     we pick the most convenient one.  */
+	  last = m_vector[0]->create (entry->die_offset, DW_TAG_namespace,
+				      0, new_name.get (), parent,
+				      entry->per_cu);
 	  last->canonical = last->name;
 	  m_names.push_back (std::move (new_name));
 	  *slot = last;
@@ -190,8 +223,28 @@ cooked_index::handle_gnat_encoded_entry (cooked_index_entry *entry,
 
 /* See cooked-index.h.  */
 
+const cooked_index_entry *
+cooked_index_vector::get_main () const
+{
+  const cooked_index_entry *result = nullptr;
+
+  for (const auto &index : m_vector)
+    {
+      const cooked_index_entry *entry = index->get_main ();
+      if (result == nullptr
+	  || ((result->flags & IS_MAIN) == 0
+	      && entry != nullptr
+	      && (entry->flags & IS_MAIN) != 0))
+	result = entry;
+    }
+
+  return result;
+}
+
+/* See cooked-index.h.  */
+
 void
-cooked_index::finalize ()
+cooked_index_vector::finalize ()
 {
   auto hash_name_ptr = [] (const void *p)
     {
@@ -213,38 +266,26 @@ cooked_index::finalize ()
   htab_up seen_names (htab_create_alloc (10, hash_name_ptr, eq_name_ptr,
 					 nullptr, xcalloc, xfree));
 
-  htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
-					   nullptr, xcalloc, xfree));
-
-  for (cooked_index_entry *entry : m_entries)
+  for (auto &index : m_vector)
     {
-      gdb_assert (entry->canonical == nullptr);
-      if ((entry->per_cu->lang != language_cplus
-	   && entry->per_cu->lang != language_ada)
-	  || (entry->flags & IS_LINKAGE) != 0)
-	entry->canonical = entry->name;
-      else
+      htab_up gnat_entries (htab_create_alloc (10, hash_entry, eq_entry,
+					       nullptr, xcalloc, xfree));
+
+      std::vector<cooked_index_entry *> entries
+	= std::move (index->m_entries);
+      for (cooked_index_entry *entry : entries)
 	{
-	  if (entry->per_cu->lang == language_ada)
-	    {
-	      gdb::unique_xmalloc_ptr<char> canon_name
-		= handle_gnat_encoded_entry (entry, gnat_entries.get ());
-	      if (canon_name == nullptr)
-		entry->canonical = entry->name;
-	      else
-		{
-		  entry->canonical = canon_name.get ();
-		  m_names.push_back (std::move (canon_name));
-		}
-	    }
+	  gdb_assert (entry->canonical == nullptr);
+	  if ((entry->per_cu->lang != language_cplus
+	       && entry->per_cu->lang != language_ada)
+	      || (entry->flags & IS_LINKAGE) != 0)
+	    entry->canonical = entry->name;
 	  else
 	    {
-	      void **slot = htab_find_slot (seen_names.get (), entry,
-					    INSERT);
-	      if (*slot == nullptr)
+	      if (entry->per_cu->lang == language_ada)
 		{
 		  gdb::unique_xmalloc_ptr<char> canon_name
-		    = cp_canonicalize_string (entry->name);
+		    = handle_gnat_encoded_entry (entry, gnat_entries.get ());
 		  if (canon_name == nullptr)
 		    entry->canonical = entry->name;
 		  else
@@ -255,12 +296,39 @@ cooked_index::finalize ()
 		}
 	      else
 		{
-		  const cooked_index_entry *other
-		    = (const cooked_index_entry *) *slot;
-		  entry->canonical = other->canonical;
+		  void **slot = htab_find_slot (seen_names.get (), entry,
+						INSERT);
+		  if (*slot == nullptr)
+		    {
+		      gdb::unique_xmalloc_ptr<char> canon_name
+			= cp_canonicalize_string (entry->name);
+		      if (canon_name == nullptr)
+			entry->canonical = entry->name;
+		      else
+			{
+			  entry->canonical = canon_name.get ();
+			  m_names.push_back (std::move (canon_name));
+			}
+		    }
+		  else
+		    {
+		      const cooked_index_entry *other
+			= (const cooked_index_entry *) *slot;
+		      entry->canonical = other->canonical;
+		    }
 		}
 	    }
 	}
+
+      if (m_entries.empty ())
+	m_entries = std::move (entries);
+      else
+	{
+	  size_t old_size = m_entries.size ();
+	  m_entries.resize (m_entries.size () + entries.size ());
+	  memcpy (m_entries.data () + old_size,
+		  entries.data (), entries.size () * sizeof (entries[0]));
+	}
     }
 
   m_names.shrink_to_fit ();
diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
index 746ccfce4e5..a4bfc3eb183 100644
--- a/gdb/dwarf2/cooked-index.h
+++ b/gdb/dwarf2/cooked-index.h
@@ -30,6 +30,7 @@
 #include "gdb_obstack.h"
 #include "addrmap.h"
 #include "gdbsupport/iterator-range.h"
+#include "gdbsupport/thread-pool.h"
 
 struct dwarf2_per_cu_data;
 
@@ -155,6 +156,8 @@ struct cooked_index_entry : public allocate_on_obstack
   void write_scope (struct obstack *storage, const char *sep) const;
 };
 
+class cooked_index_vector;
+
 /* An index of interesting DIEs.  This is "cooked", in contrast to a
    mapped .debug_names or .gdb_index, which are "raw".  An entry in
    the index is of type cooked_index_entry.
@@ -178,13 +181,6 @@ class cooked_index
 				 const cooked_index_entry *parent_entry,
 				 dwarf2_per_cu_data *per_cu);
 
-  /* Return the entry that is believed to represent the program's
-     "main".  This will return NULL if no such entry is available.  */
-  const cooked_index_entry *get_main () const
-  {
-    return m_main;
-  }
-
   /* Install a new fixed addrmap from the given mutable addrmap.  */
   void install_addrmap (addrmap *map)
   {
@@ -192,6 +188,17 @@ class cooked_index
     m_addrmap = addrmap_create_fixed (map, &m_storage);
   }
 
+  friend class cooked_index_vector;
+
+private:
+
+  /* Return the entry that is believed to represent the program's
+     "main".  This will return NULL if no such entry is available.  */
+  const cooked_index_entry *get_main () const
+  {
+    return m_main;
+  }
+
   /* Look up ADDR in the address map, and return either the
      corresponding CU, or nullptr if the address could not be
      found.  */
@@ -200,10 +207,52 @@ class cooked_index
     return (dwarf2_per_cu_data *) addrmap_find (m_addrmap, addr);
   }
 
-  /* Finalize the index.  This should be called a single time, when
-     the index has been fully populated.  It enters all the entries
-     into the internal hash table.  */
-  void finalize ();
+  /* Create a new cooked_index_entry and register it with this object.
+     Entries are owned by this object.  The new item is returned.  */
+  cooked_index_entry *create (sect_offset die_offset,
+			      enum dwarf_tag tag,
+			      cooked_index_flag flags,
+			      const char *name,
+			      const cooked_index_entry *parent_entry,
+			      dwarf2_per_cu_data *per_cu)
+  {
+    return new (&m_storage) cooked_index_entry (die_offset, tag, flags,
+						name, parent_entry,
+						per_cu);
+  }
+
+  /* Storage for the entries.  */
+  auto_obstack m_storage;
+  /* List of all entries.  */
+  std::vector<cooked_index_entry *> m_entries;
+  /* If we found "main" or an entry with 'is_main' set, store it
+     here.  */
+  cooked_index_entry *m_main = nullptr;
+  /* When constructing the index, entries are stored on a linked list.
+     This member points to the head of that list.  Later, they are
+     entered into the hash table, at which point this is no longer
+     used.  */
+  cooked_index_entry *m_start = nullptr;
+  /* The addrmap.  This maps address ranges to dwarf2_per_cu_data
+     objects.  */
+  addrmap *m_addrmap = nullptr;
+};
+
+/* The main index of DIEs.  The parallel DIE indexers create
+   cooked_index objects.  Then, these are all handled to a
+   cooked_index_vector for storage and final indexing.  The index is
+   made by iterating over the entries previously created.  */
+
+class cooked_index_vector
+{
+public:
+
+  /* A convenience typedef for the vector that is contained in this
+     object.  */
+  typedef std::vector<std::unique_ptr<cooked_index>> vec_type;
+
+  explicit cooked_index_vector (vec_type &&vec);
+  DISABLE_COPY_AND_ASSIGN (cooked_index_vector);
 
   /* A simple range over part of m_entries.  */
   typedef iterator_range<std::vector<cooked_index_entry *>::iterator> range;
@@ -219,6 +268,19 @@ class cooked_index
     return { m_entries.begin (), m_entries.end () };
   }
 
+  /* Look up ADDR in the address map, and return either the
+     corresponding CU, or nullptr if the address could not be
+     found.  */
+  dwarf2_per_cu_data *lookup (CORE_ADDR addr);
+
+  /* Return a new vector of all the addrmaps used by all the indexes
+     held by this object.  */
+  std::vector<addrmap *> get_addrmaps ();
+
+  /* Return the entry that is believed to represent the program's
+     "main".  This will return NULL if no such entry is available.  */
+  const cooked_index_entry *get_main () const;
+
 private:
 
   /* GNAT only emits mangled ("encoded") names in the DWARF, and does
@@ -229,32 +291,20 @@ class cooked_index
   gdb::unique_xmalloc_ptr<char> handle_gnat_encoded_entry
        (cooked_index_entry *entry, htab_t gnat_entries);
 
-  /* Create a new cooked_index_entry and register it with this object.
-     Entries are owned by this object.  The new item is returned.  */
-  cooked_index_entry *create (sect_offset die_offset,
-			      enum dwarf_tag tag,
-			      cooked_index_flag flags,
-			      const char *name,
-			      const cooked_index_entry *parent_entry,
-			      dwarf2_per_cu_data *per_cu)
-  {
-    return new (&m_storage) cooked_index_entry (die_offset, tag, flags,
-						name, parent_entry,
-						per_cu);
-  }
+  /* Finalize the index.  This should be called a single time, when
+     the index has been fully populated.  It enters all the entries
+     into the internal hash table.  */
+  void finalize ();
 
-  /* Storage for the entries.  */
-  auto_obstack m_storage;
-  /* List of all entries.  */
+  /* The vector of cooked_index objects.  This is stored because the
+     entries are stored on the obstacks in those objects.  */
+  vec_type m_vector;
+
+  /* List of all entries.  This is sorted during finalization.  */
   std::vector<cooked_index_entry *> m_entries;
-  /* If we found "main" or an entry with 'is_main' set, store it
-     here.  */
-  cooked_index_entry *m_main = nullptr;
+
   /* Storage for canonical names.  */
   std::vector<gdb::unique_xmalloc_ptr<char>> m_names;
-  /* The addrmap.  This maps address ranges to dwarf2_per_cu_data
-     objects.  */
-  addrmap *m_addrmap = nullptr;
 };
 
 #endif /* GDB_DWARF2_COOKED_INDEX_H */
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index ba804ba5c67..01cfa42f45a 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -92,6 +92,8 @@
 #include "dwarf2/abbrev-cache.h"
 #include "cooked-index.h"
 #include "split-name.h"
+#include "gdbsupport/parallel-for.h"
+#include "gdbsupport/thread-pool.h"
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
@@ -6504,6 +6506,12 @@ lookup_dwo_id (struct dwarf2_cu *cu, struct die_info* comp_unit_die)
 static struct dwo_unit *
 lookup_dwo_unit (dwarf2_cu *cu, die_info *comp_unit_die, const char *dwo_name)
 {
+  /* We need a lock here both to handle the DWO hash table, and BFD,
+     which is not thread-safe.  */
+  static std::mutex dwo_lock;
+
+  std::lock_guard<std::mutex> guard (dwo_lock);
+
   dwarf2_per_cu_data *per_cu = cu->per_cu;
   struct dwo_unit *dwo_unit;
   const char *comp_dir;
@@ -6651,9 +6659,14 @@ cutu_reader::cutu_reader (dwarf2_per_cu_data *this_cu,
     }
   else
     {
-      /* If an existing_cu is provided, a dwarf2_cu must not exist for this_cu
-	 in per_objfile yet.  */
-      gdb_assert (per_objfile->get_cu (this_cu) == nullptr);
+      /* If an existing_cu is provided, a dwarf2_cu must not exist for
+	 this_cu in per_objfile yet.  Here, CACHE doubles as a flag to
+	 let us know that the CU is being scanned using the parallel
+	 indexer.  This assert is avoided in this case because (1) it
+	 is irrelevant, and (2) the get_cu method is not
+	 thread-safe.  */
+      gdb_assert (cache != nullptr
+		  || per_objfile->get_cu (this_cu) == nullptr);
       m_new_cu.reset (new dwarf2_cu (this_cu, per_objfile));
       cu = m_new_cu.get ();
     }
@@ -7467,9 +7480,10 @@ process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
     {
       if (per_objfile->per_bfd->using_index)
 	{
-	  if (!this_cu->scanned && reader.comp_unit_die->has_children)
+	  bool nope = false;
+	  if (this_cu->scanned.compare_exchange_strong (nope, true)
+	      && reader.comp_unit_die->has_children)
 	    {
-	      this_cu->scanned = true;
 	      prepare_one_comp_unit (reader.cu, reader.comp_unit_die,
 				     pretend_language);
 	      gdb_assert (storage != nullptr);
@@ -7837,6 +7851,7 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
     = per_bfd->using_index ? &index_storage : nullptr;
   create_all_comp_units (per_objfile);
   build_type_psymtabs (per_objfile, index_storage_ptr);
+  std::vector<std::unique_ptr<cooked_index>> indexes;
   if (per_bfd->using_index)
     {
       per_bfd->quick_file_names_table
@@ -7845,15 +7860,70 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
       if (!per_bfd->debug_aranges.empty ())
 	read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges,
 				   index_storage.get_addrmap ());
-    }
 
-  for (const auto &per_cu : per_bfd->all_comp_units)
+      {
+	/* Ensure that complaints are handled correctly.  */
+	complaint_interceptor complaint_handler;
+
+	using iter_type = typeof (per_bfd->all_comp_units.begin ());
+
+	/* Each thread returns a pair holding a cooked index, and a vector
+	   of errors that should be printed.  The latter is done because
+	   GDB's I/O system is not thread-safe.  run_on_main_thread could be
+	   used, but that would mean the messages are printed after the
+	   prompt, which looks weird.  */
+	using result_type = std::pair<std::unique_ptr<cooked_index>,
+				      std::vector<gdb_exception>>;
+	std::vector<result_type> results
+	  = gdb::parallel_for_each (1, per_bfd->all_comp_units.begin (),
+				    per_bfd->all_comp_units.end (),
+				    [=] (iter_type iter, iter_type end)
+				    {
+				      std::vector<gdb_exception> errors;
+				      cooked_index_storage thread_storage;
+				      for (; iter != end; ++iter)
+					{
+					  dwarf2_per_cu_data *per_cu = iter->get ();
+					  try
+					    {
+					      process_psymtab_comp_unit (per_cu, per_objfile,
+									 false,
+									 language_minimal,
+									 &thread_storage);
+					    }
+					  catch (gdb_exception &except)
+					    {
+					      errors.push_back (std::move (except));
+					    }
+					}
+				      return result_type (thread_storage.release (),
+							  std::move (errors));
+				    });
+
+	/* Only show a given exception a single time.  */
+	std::unordered_set<gdb_exception> seen_exceptions;
+	for (auto &one_result : results)
+	  {
+	    indexes.push_back (std::move (one_result.first));
+	    for (auto &one_exc : one_result.second)
+	      {
+		if (seen_exceptions.insert (one_exc).second)
+		  exception_print (gdb_stderr, one_exc);
+	      }
+	  }
+      }
+    }
+  else
     {
-      if (!per_bfd->using_index && per_cu->v.psymtab != NULL)
-	/* In case a forward DW_TAG_imported_unit has read the CU already.  */
-	continue;
-      process_psymtab_comp_unit (per_cu.get (), per_objfile, false,
-				 language_minimal, index_storage_ptr);
+      for (const auto &per_cu : per_bfd->all_comp_units)
+	{
+	  if (!per_bfd->using_index && per_cu->v.psymtab != NULL)
+	    /* In case a forward DW_TAG_imported_unit has read the CU
+	       already.  */
+	    continue;
+	  process_psymtab_comp_unit (per_cu.get (), per_objfile, false,
+				     language_minimal, nullptr);
+	}
     }
 
   /* This has to wait until we read the CUs, we need the list of DWOs.  */
@@ -7871,8 +7941,20 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
 
   if (per_bfd->using_index)
     {
-      per_bfd->cooked_index_table = index_storage.release ();
-      per_bfd->cooked_index_table->finalize ();
+      indexes.push_back (index_storage.release ());
+      /* Remove any NULL entries.  This might happen if parallel-for
+	 decides to throttle the number of threads that were used.  */
+      indexes.erase
+	(std::remove_if (indexes.begin (),
+			 indexes.end (),
+			 [] (const std::unique_ptr<cooked_index> &entry)
+			 {
+			   return entry == nullptr;
+			 }),
+	 indexes.end ());
+      indexes.shrink_to_fit ();
+      per_bfd->cooked_index_table.reset
+	(new cooked_index_vector (std::move (indexes)));
 
       const cooked_index_entry *main_entry
 	= per_bfd->cooked_index_table->get_main ();
@@ -19360,9 +19442,9 @@ cooked_indexer::ensure_cu_exists (cutu_reader *reader,
      Doing this check here avoids self-imports as well.  */
   if (for_scanning)
     {
-      if (per_cu->scanned)
+      bool nope = false;
+      if (!per_cu->scanned.compare_exchange_strong (nope, true))
 	return nullptr;
-      per_cu->scanned = true;
     }
   if (per_cu == m_per_cu)
     return reader;
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 3b29a0a2a73..45e4739acfd 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -168,7 +168,7 @@ struct dwarf2_per_cu_data
 
   /* True if this CU has been scanned by the indexer; false if
      not.  */
-  bool scanned : 1;
+  std::atomic<bool> scanned;
 
   /* Our index in the unshared "symtabs" vector.  */
   unsigned index = 0;
@@ -450,7 +450,7 @@ struct dwarf2_per_bfd
   std::unique_ptr<mapped_debug_names> debug_names_table;
 
   /* The cooked index, or NULL if not using one.  */
-  std::unique_ptr<cooked_index> cooked_index_table;
+  std::unique_ptr<cooked_index_vector> cooked_index_table;
 
   /* When using index_table, this keeps track of all quick_file_names entries.
      TUs typically share line table entries with a CU, so we maintain a
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 23/32] "Finalize" the DWARF index in the background
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (21 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 22/32] Parallelize DWARF indexing Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:08 ` [PATCH v2 24/32] Rename write_psymtabs_to_index Tom Tromey
                   ` (10 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

After scanning the CUs, the DWARF indexer merges all the data into a
single vector, canonicalizing C++ names as it proceeds.  While not
necessarily single-threaded, this process is currently done in just
one thread, to keep memory costs lower.

However, this work is all done without reference to any data outside
of the indexes.  This patch improves the apparent performance of GDB
by moving it to the background.  All uses of the index are then made
to wait for this process to complete.

In our ongoing example, this reduces the scanning time on gdb itself
to 0.173937 (wall).  Recall that before this patch, the time was
0.668923; and psymbol reader does this in 1.598869.  That is, at the
end of this series, we see about a 10x speedup.
---
 gdb/dwarf2/cooked-index.c | 10 ++++++++--
 gdb/dwarf2/cooked-index.h | 17 +++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/gdb/dwarf2/cooked-index.c b/gdb/dwarf2/cooked-index.c
index bb10b884a43..7e114c4edd2 100644
--- a/gdb/dwarf2/cooked-index.c
+++ b/gdb/dwarf2/cooked-index.c
@@ -117,9 +117,13 @@ cooked_index::add (sect_offset die_offset, enum dwarf_tag tag,
 }
 
 cooked_index_vector::cooked_index_vector (vec_type &&vec)
-  : m_vector (std::move (vec))
+  : m_vector (std::move (vec)),
+    m_future (gdb::thread_pool::g_thread_pool->post_task
+	      ([this] ()
+	      {
+		finalize ();
+	      }))
 {
-  finalize ();
 }
 
 /* See cooked-index.h.  */
@@ -152,6 +156,8 @@ cooked_index_vector::get_addrmaps ()
 cooked_index_vector::range
 cooked_index_vector::find (gdb::string_view name, bool completing)
 {
+  m_future.wait ();
+
   auto lower = std::lower_bound (m_entries.begin (), m_entries.end (),
 				 name,
 				 [=] (const cooked_index_entry *entry,
diff --git a/gdb/dwarf2/cooked-index.h b/gdb/dwarf2/cooked-index.h
index a4bfc3eb183..365150b8692 100644
--- a/gdb/dwarf2/cooked-index.h
+++ b/gdb/dwarf2/cooked-index.h
@@ -254,6 +254,17 @@ class cooked_index_vector
   explicit cooked_index_vector (vec_type &&vec);
   DISABLE_COPY_AND_ASSIGN (cooked_index_vector);
 
+  ~cooked_index_vector ()
+  {
+    /* The 'finalize' method may be run in a different thread.  If
+       this object is destroyed before this completes, then the method
+       will end up writing to freed memory.  Waiting for this to
+       complete avoids this problem; and the cost seems ignorable
+       because creating and immediately destroying the debug info is a
+       relatively rare thing to do.  */
+    m_future.wait ();
+  }
+
   /* A simple range over part of m_entries.  */
   typedef iterator_range<std::vector<cooked_index_entry *>::iterator> range;
 
@@ -265,6 +276,7 @@ class cooked_index_vector
   /* Return a range of all the entries.  */
   range all_entries ()
   {
+    m_future.wait ();
     return { m_entries.begin (), m_entries.end () };
   }
 
@@ -305,6 +317,11 @@ class cooked_index_vector
 
   /* Storage for canonical names.  */
   std::vector<gdb::unique_xmalloc_ptr<char>> m_names;
+
+  /* A future that tracks when the 'finalize' method is done.  Note
+     that the 'get' method is never called on this future, only
+     'wait'.  */
+  std::future<void> m_future;
 };
 
 #endif /* GDB_DWARF2_COOKED_INDEX_H */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 24/32] Rename write_psymtabs_to_index
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (22 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 23/32] "Finalize" the DWARF index in the background Tom Tromey
@ 2021-11-04 18:08 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 25/32] Change the key type in psym_index_map Tom Tromey
                   ` (9 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

We'll be removing all the psymtab code from the DWARF reader.  As a
preparatory step, this renames write_psymtabs_to_index to avoid the
"psymtab" name.
---
 gdb/dwarf2/index-cache.c |  6 +++---
 gdb/dwarf2/index-write.c | 10 +++++-----
 gdb/dwarf2/index-write.h |  2 +-
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdb/dwarf2/index-cache.c b/gdb/dwarf2/index-cache.c
index f439b37db5a..38f8223ed21 100644
--- a/gdb/dwarf2/index-cache.c
+++ b/gdb/dwarf2/index-cache.c
@@ -149,9 +149,9 @@ index_cache::store (dwarf2_per_objfile *per_objfile)
 
       /* Write the index itself to the directory, using the build id as the
 	 filename.  */
-      write_psymtabs_to_index (per_objfile, m_dir.c_str (),
-			       build_id_str.c_str (), dwz_build_id_ptr,
-			       dw_index_kind::GDB_INDEX);
+      write_dwarf_index (per_objfile, m_dir.c_str (),
+			 build_id_str.c_str (), dwz_build_id_ptr,
+			 dw_index_kind::GDB_INDEX);
     }
   catch (const gdb_exception_error &except)
     {
diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index e92def7590b..7fbc52cf05f 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -1577,9 +1577,9 @@ struct index_wip_file
 /* See dwarf-index-write.h.  */
 
 void
-write_psymtabs_to_index (dwarf2_per_objfile *per_objfile, const char *dir,
-			 const char *basename, const char *dwz_basename,
-			 dw_index_kind index_kind)
+write_dwarf_index (dwarf2_per_objfile *per_objfile, const char *dir,
+		   const char *basename, const char *dwz_basename,
+		   dw_index_kind index_kind)
 {
   dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
   struct objfile *objfile = per_objfile->objfile;
@@ -1675,8 +1675,8 @@ save_gdb_index_command (const char *arg, int from_tty)
 	      if (dwz != NULL)
 		dwz_basename = lbasename (dwz->filename ());
 
-	      write_psymtabs_to_index (per_objfile, arg, basename, dwz_basename,
-				       index_kind);
+	      write_dwarf_index (per_objfile, arg, basename, dwz_basename,
+				 index_kind);
 	    }
 	  catch (const gdb_exception_error &except)
 	    {
diff --git a/gdb/dwarf2/index-write.h b/gdb/dwarf2/index-write.h
index 27f1f03cd8b..8fb81dda8be 100644
--- a/gdb/dwarf2/index-write.h
+++ b/gdb/dwarf2/index-write.h
@@ -32,7 +32,7 @@
    derived from INDEX_KIND is added to this base name.  DWZ_BASENAME is the
    same, but for the dwz file's index.  */
 
-extern void write_psymtabs_to_index
+extern void write_dwarf_index
   (dwarf2_per_objfile *per_objfile, const char *dir, const char *basename,
    const char *dwz_basename, dw_index_kind index_kind);
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 25/32] Change the key type in psym_index_map
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (23 preceding siblings ...)
  2021-11-04 18:08 ` [PATCH v2 24/32] Rename write_psymtabs_to_index Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 26/32] Change parameters to write_address_map Tom Tromey
                   ` (8 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

In order to change the DWARF index writer to avoid partial symtabs,
this patch changes the key type in psym_index_map (and renames that
type as well).  Using the dwarf2_per_cu_data as the key makes it
simpler to reuse this code with the new indexer.
---
 gdb/dwarf2/index-write.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index 7fbc52cf05f..28c623a12dd 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -407,17 +407,17 @@ write_hash_table (mapped_symtab *symtab, data_buf &output, data_buf &cpool)
     }
 }
 
-typedef std::unordered_map<partial_symtab *, unsigned int> psym_index_map;
+typedef std::unordered_map<dwarf2_per_cu_data *, unsigned int> cu_index_map;
 
 /* Helper struct for building the address table.  */
 struct addrmap_index_data
 {
-  addrmap_index_data (data_buf &addr_vec_, psym_index_map &cu_index_htab_)
+  addrmap_index_data (data_buf &addr_vec_, cu_index_map &cu_index_htab_)
     : addr_vec (addr_vec_), cu_index_htab (cu_index_htab_)
   {}
 
   data_buf &addr_vec;
-  psym_index_map &cu_index_htab;
+  cu_index_map &cu_index_htab;
 
   int operator() (CORE_ADDR start_addr, void *obj);
 
@@ -447,7 +447,7 @@ add_address_entry (data_buf &addr_vec,
 int
 addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
 {
-  partial_symtab *pst = (partial_symtab *) obj;
+  dwarf2_psymtab *pst = (dwarf2_psymtab *) obj;
 
   if (previous_valid)
     add_address_entry (addr_vec,
@@ -457,7 +457,7 @@ addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
   previous_cu_start = start_addr;
   if (pst != NULL)
     {
-      const auto it = cu_index_htab.find (pst);
+      const auto it = cu_index_htab.find (pst->per_cu_data);
       gdb_assert (it != cu_index_htab.cend ());
       previous_cu_index = it->second;
       previous_valid = true;
@@ -474,7 +474,7 @@ addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
 
 static void
 write_address_map (dwarf2_per_bfd *per_bfd, data_buf &addr_vec,
-		   psym_index_map &cu_index_htab)
+		   cu_index_map &cu_index_htab)
 {
   struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
 
@@ -1317,11 +1317,11 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
   data_buf objfile_cu_list;
   data_buf dwz_cu_list;
 
-  /* While we're scanning CU's create a table that maps a psymtab pointer
+  /* While we're scanning CU's create a table that maps a dwarf2_per_cu_data
      (which is what addrmap records) to its index (which is what is recorded
      in the index file).  This will later be needed to write the address
      table.  */
-  psym_index_map cu_index_htab;
+  cu_index_map cu_index_htab;
   cu_index_htab.reserve (per_objfile->per_bfd->all_comp_units.size ());
 
   /* Store out the .debug_type CUs, if any.  */
@@ -1349,7 +1349,7 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
 	    recursively_write_psymbols (objfile, psymtab, &symtab,
 					psyms_seen, this_counter);
 
-	  const auto insertpair = cu_index_htab.emplace (psymtab,
+	  const auto insertpair = cu_index_htab.emplace (per_cu,
 							 this_counter);
 	  gdb_assert (insertpair.second);
 	}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 26/32] Change parameters to write_address_map
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (24 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 25/32] Change the key type in psym_index_map Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 27/32] Genericize addrmap handling in the DWARF index writer Tom Tromey
                   ` (7 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

To support the removal of partial symtabs from the DWARF index writer,
this makes a small change to have write_address_map accept the address
map as a parameter, rather than assuming it always comes from the
per-BFD object.
---
 gdb/dwarf2/index-write.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index 28c623a12dd..8bf7e8fdd1c 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -473,13 +473,12 @@ addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
    in the index file.  */
 
 static void
-write_address_map (dwarf2_per_bfd *per_bfd, data_buf &addr_vec,
+write_address_map (struct addrmap *addrmap, data_buf &addr_vec,
 		   cu_index_map &cu_index_htab)
 {
   struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
 
-  addrmap_foreach (per_bfd->partial_symtabs->psymtabs_addrmap,
-		   addrmap_index_data);
+  addrmap_foreach (addrmap, addrmap_index_data);
 
   /* It's highly unlikely the last entry (end address = 0xff...ff)
      is valid, but we should still handle it.
@@ -1378,7 +1377,8 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
 
   /* Dump the address map.  */
   data_buf addr_vec;
-  write_address_map (per_objfile->per_bfd, addr_vec, cu_index_htab);
+  write_address_map (per_objfile->per_bfd->partial_symtabs->psymtabs_addrmap,
+		     addr_vec, cu_index_htab);
 
   /* Now that we've processed all symbols we can shrink their cu_indices
      lists.  */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 27/32] Genericize addrmap handling in the DWARF index writer
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (25 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 26/32] Change parameters to write_address_map Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 28/32] Adapt .gdb_index writer to new DWARF scanner Tom Tromey
                   ` (6 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This updates the DWARF index writing code to make the addrmap-writing
a bit more generic.  Now, it can handle multiple maps, and it can work
using the maps generated by the new indexer.

Note that the new addrmap_index_data::using_index field will be
deleted in a future patch, when the rest of the DWARF psymtab code is
removed.
---
 gdb/dwarf2/index-write.c | 37 ++++++++++++++++++++++++++++---------
 1 file changed, 28 insertions(+), 9 deletions(-)

diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index 8bf7e8fdd1c..13b929fea54 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -412,8 +412,11 @@ typedef std::unordered_map<dwarf2_per_cu_data *, unsigned int> cu_index_map;
 /* Helper struct for building the address table.  */
 struct addrmap_index_data
 {
-  addrmap_index_data (data_buf &addr_vec_, cu_index_map &cu_index_htab_)
-    : addr_vec (addr_vec_), cu_index_htab (cu_index_htab_)
+  addrmap_index_data (data_buf &addr_vec_, cu_index_map &cu_index_htab_,
+		      bool using_index_)
+    : addr_vec (addr_vec_),
+      cu_index_htab (cu_index_htab_),
+      using_index (using_index_)
   {}
 
   data_buf &addr_vec;
@@ -421,6 +424,8 @@ struct addrmap_index_data
 
   int operator() (CORE_ADDR start_addr, void *obj);
 
+  /* True if the DWARF reader uses the new DWARF indexer.  */
+  bool using_index;
   /* True if the previous_* fields are valid.
      We can't write an entry until we see the next entry (since it is only then
      that we know the end of the entry).  */
@@ -447,7 +452,11 @@ add_address_entry (data_buf &addr_vec,
 int
 addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
 {
-  dwarf2_psymtab *pst = (dwarf2_psymtab *) obj;
+  dwarf2_per_cu_data *per_cu;
+  if (using_index)
+    per_cu = (dwarf2_per_cu_data *) obj;
+  else
+    per_cu = obj == nullptr ? nullptr : ((dwarf2_psymtab *) obj)->per_cu_data;
 
   if (previous_valid)
     add_address_entry (addr_vec,
@@ -455,9 +464,9 @@ addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
 		       previous_cu_index);
 
   previous_cu_start = start_addr;
-  if (pst != NULL)
+  if (per_cu != NULL)
     {
-      const auto it = cu_index_htab.find (pst->per_cu_data);
+      const auto it = cu_index_htab.find (per_cu);
       gdb_assert (it != cu_index_htab.cend ());
       previous_cu_index = it->second;
       previous_valid = true;
@@ -474,9 +483,10 @@ addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
 
 static void
 write_address_map (struct addrmap *addrmap, data_buf &addr_vec,
-		   cu_index_map &cu_index_htab)
+		   cu_index_map &cu_index_htab, bool using_index)
 {
-  struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
+  struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab,
+						using_index);
 
   addrmap_foreach (addrmap, addrmap_index_data);
 
@@ -1377,8 +1387,17 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
 
   /* Dump the address map.  */
   data_buf addr_vec;
-  write_address_map (per_objfile->per_bfd->partial_symtabs->psymtabs_addrmap,
-		     addr_vec, cu_index_htab);
+  if (per_objfile->per_bfd->using_index)
+    {
+      std::vector<addrmap *> addrmaps
+	= per_objfile->per_bfd->cooked_index_table->get_addrmaps ();
+      for (auto map : addrmaps)
+	write_address_map (map, addr_vec, cu_index_htab, true);
+    }
+  else
+    write_address_map (per_objfile->per_bfd->partial_symtabs->psymtabs_addrmap,
+		       addr_vec, cu_index_htab,
+		       per_objfile->per_bfd->using_index);
 
   /* Now that we've processed all symbols we can shrink their cu_indices
      lists.  */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 28/32] Adapt .gdb_index writer to new DWARF scanner
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (26 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 27/32] Genericize addrmap handling in the DWARF index writer Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 29/32] Adapt .debug_names " Tom Tromey
                   ` (5 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This updates the .gdb_index writer to work with the new DWARF scanner.
The .debug_names writer is deferred to another patch, to make review
simpler.

This introduces a small hack to psyms_seen_size, but is
inconsequential because this function will be deleted in a subsequent
patch.
---
 gdb/dwarf2/index-write.c               | 63 ++++++++++++++++++++++----
 gdb/testsuite/gdb.dwarf2/gdb-index.exp |  5 +-
 2 files changed, 59 insertions(+), 9 deletions(-)

diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index 13b929fea54..0d8127c2898 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -189,7 +189,7 @@ struct mapped_symtab
   offset_type n_elements = 0;
   std::vector<symtab_index_entry> data;
 
-  /* Temporary storage for Ada names.  */
+  /* Temporary storage for names.  */
   auto_obstack m_string_obstack;
 };
 
@@ -1237,6 +1237,9 @@ check_dwarf64_offsets (dwarf2_per_objfile *per_objfile)
 static size_t
 psyms_seen_size (dwarf2_per_objfile *per_objfile)
 {
+  if (per_objfile->per_bfd->using_index)
+    return 0;
+
   size_t psyms_count = 0;
   for (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
     {
@@ -1312,6 +1315,41 @@ write_gdbindex_1 (FILE *out_file,
   assert_file_size (out_file, total_len);
 }
 
+/* Write the contents of the internal "cooked" index.  */
+
+static void
+write_cooked_index (dwarf2_per_objfile *per_objfile,
+		    const cu_index_map &cu_index_htab,
+		    struct mapped_symtab *symtab)
+{
+  gdb_assert (per_objfile->per_bfd->using_index);
+
+  for (const cooked_index_entry *entry
+	 : per_objfile->per_bfd->cooked_index_table->all_entries ())
+    {
+      const auto it = cu_index_htab.find (entry->per_cu);
+      gdb_assert (it != cu_index_htab.cend ());
+
+      const char *name = entry->full_name (&symtab->m_string_obstack);
+
+      gdb_index_symbol_kind kind;
+      if (entry->tag == DW_TAG_subprogram)
+	kind = GDB_INDEX_SYMBOL_KIND_FUNCTION;
+      else if (entry->tag == DW_TAG_variable
+	       || entry->tag == DW_TAG_constant
+	       || entry->tag == DW_TAG_enumerator)
+	kind = GDB_INDEX_SYMBOL_KIND_VARIABLE;
+      else if (entry->tag == DW_TAG_module
+	       || entry->tag == DW_TAG_common_block)
+	kind = GDB_INDEX_SYMBOL_KIND_OTHER;
+      else
+	kind = GDB_INDEX_SYMBOL_KIND_TYPE;
+
+      add_index_entry (symtab, name, (entry->flags & IS_STATIC) != 0,
+		       kind, it->second);
+    }
+}
+
 /* Write contents of a .gdb_index section for OBJFILE into OUT_FILE.
    If OBJFILE has an associated dwz file, write contents of a .gdb_index
    section for that dwz file into DWZ_OUT_FILE.  If OBJFILE does not have an
@@ -1348,7 +1386,9 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
     {
       dwarf2_per_cu_data *per_cu
 	= per_objfile->per_bfd->all_comp_units[i].get ();
-      partial_symtab *psymtab = per_cu->v.psymtab;
+      partial_symtab *psymtab = (per_objfile->per_bfd->using_index
+				 ? nullptr
+				 : per_cu->v.psymtab);
 
       int &this_counter = per_cu->is_debug_types ? types_counter : counter;
 
@@ -1357,7 +1397,10 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
 	  if (psymtab->user == NULL)
 	    recursively_write_psymbols (objfile, psymtab, &symtab,
 					psyms_seen, this_counter);
+	}
 
+      if (psymtab != NULL || per_objfile->per_bfd->using_index)
+	{
 	  const auto insertpair = cu_index_htab.emplace (per_cu,
 							 this_counter);
 	  gdb_assert (insertpair.second);
@@ -1385,6 +1428,9 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
       ++this_counter;
     }
 
+  if (per_objfile->per_bfd->using_index)
+    write_cooked_index (per_objfile, cu_index_htab, &symtab);
+
   /* Dump the address map.  */
   data_buf addr_vec;
   if (per_objfile->per_bfd->using_index)
@@ -1396,8 +1442,7 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
     }
   else
     write_address_map (per_objfile->per_bfd->partial_symtabs->psymtabs_addrmap,
-		       addr_vec, cu_index_htab,
-		       per_objfile->per_bfd->using_index);
+		       addr_vec, cu_index_htab, false);
 
   /* Now that we've processed all symbols we can shrink their cu_indices
      lists.  */
@@ -1603,15 +1648,17 @@ write_dwarf_index (dwarf2_per_objfile *per_objfile, const char *dir,
   dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
   struct objfile *objfile = per_objfile->objfile;
 
-  if (per_objfile->per_bfd->using_index)
+  if (per_objfile->per_bfd->using_index
+      && per_objfile->per_bfd->cooked_index_table == nullptr)
     error (_("Cannot use an index to create the index"));
 
   if (per_objfile->per_bfd->types.size () > 1)
     error (_("Cannot make an index when the file has multiple .debug_types sections"));
 
-  if (per_bfd->partial_symtabs == nullptr
-      || !per_bfd->partial_symtabs->psymtabs
-      || !per_bfd->partial_symtabs->psymtabs_addrmap)
+  if ((per_bfd->partial_symtabs == nullptr
+       || !per_bfd->partial_symtabs->psymtabs
+       || !per_bfd->partial_symtabs->psymtabs_addrmap)
+      && per_bfd->cooked_index_table == nullptr)
     return;
 
   struct stat st;
diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index.exp b/gdb/testsuite/gdb.dwarf2/gdb-index.exp
index 0b7adb5379d..19b47907dee 100644
--- a/gdb/testsuite/gdb.dwarf2/gdb-index.exp
+++ b/gdb/testsuite/gdb.dwarf2/gdb-index.exp
@@ -90,12 +90,15 @@ gdb_test_multiple "mt print objfiles ${testfile}" $test {
     -re "debug_names.*${gdb_prompt} $" {
 	set binfile_with_index $binfile
     }
-    -re "Psymtabs.*${gdb_prompt} $" {
+    -re "(Psymtabs|Cooked).*${gdb_prompt} $" {
 	set binfile_with_index [local_add_gdb_index $binfile]
 	if { ${binfile_with_index} == "" } {
 	    return -1
 	}
     }
+    -re ".*${gdb_prompt} $" {
+	fail "unrecognized symbol reader"
+    }
 }
 
 # Ok, we have a copy of $binfile with an index.
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 29/32] Adapt .debug_names writer to new DWARF scanner
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (27 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 28/32] Adapt .gdb_index writer to new DWARF scanner Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 30/32] Enable the new DWARF indexer Tom Tromey
                   ` (4 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This updates the .debug_names writer to work with the new DWARF
scanner.
---
 gdb/dwarf2/index-write.c | 52 ++++++++++++++++++++++++++++++++--------
 1 file changed, 42 insertions(+), 10 deletions(-)

diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index 0d8127c2898..71cdb394c51 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -664,15 +664,10 @@ class debug_names
   enum class unit_kind { cu, tu };
 
   /* Insert one symbol.  */
-  void insert (const partial_symbol *psym, int cu_index, bool is_static,
-	       unit_kind kind)
+  void insert (int dwarf_tag, const char *name, int cu_index, bool is_static,
+	       unit_kind kind, enum language lang)
   {
-    const int dwarf_tag = psymbol_tag (psym);
-    if (dwarf_tag == 0)
-      return;
-    const char *name = psym->ginfo.search_name ();
-
-    if (psym->ginfo.language () == language_ada)
+    if (lang == language_ada)
       {
 	/* We want to ensure that the Ada main function's name appears
 	   verbatim in the index.  However, this name will be of the
@@ -715,6 +710,28 @@ class debug_names
     value_set.emplace (symbol_value (dwarf_tag, cu_index, is_static, kind));
   }
 
+  void insert (const partial_symbol *psym, int cu_index, bool is_static,
+	       unit_kind kind)
+  {
+    const int dwarf_tag = psymbol_tag (psym);
+    if (dwarf_tag == 0)
+      return;
+    const char *name = psym->ginfo.search_name ();
+
+    insert (dwarf_tag, name, cu_index, is_static, kind,
+	    psym->ginfo.language ());
+  }
+
+  void insert (const cooked_index_entry *entry)
+  {
+    const auto it = m_cu_index_htab.find (entry->per_cu);
+    gdb_assert (it != m_cu_index_htab.cend ());
+    const char *name = entry->full_name (&m_string_obstack);
+    insert (entry->tag, name, it->second, (entry->flags & IS_STATIC) != 0,
+	    entry->per_cu->is_debug_types ? unit_kind::tu : unit_kind::cu,
+	    entry->per_cu->lang);
+  }
+
   /* Build all the tables.  All symbols must be already inserted.
      This function does not call file_write, caller has to do it
      afterwards.  */
@@ -897,6 +914,11 @@ class debug_names
     m_debugstrlookup.file_write (file_str);
   }
 
+  void add_cu (dwarf2_per_cu_data *per_cu, offset_type index)
+  {
+    m_cu_index_htab.emplace (per_cu, index);
+  }
+
 private:
 
   /* Storage for symbol names mapping them to their .debug_str section
@@ -1211,6 +1233,8 @@ class debug_names
 
   /* Temporary storage for Ada names.  */
   auto_obstack m_string_obstack;
+
+  cu_index_map m_cu_index_htab;
 };
 
 /* Return iff any of the needed offsets does not fit into 32-bit
@@ -1491,17 +1515,20 @@ write_debug_names (dwarf2_per_objfile *per_objfile,
   int types_counter = 0;
   for (int i = 0; i < per_objfile->per_bfd->all_comp_units.size (); ++i)
     {
-      const dwarf2_per_cu_data *per_cu
+      dwarf2_per_cu_data *per_cu
 	= per_objfile->per_bfd->all_comp_units[i].get ();
-      partial_symtab *psymtab = per_cu->v.psymtab;
 
       int &this_counter = per_cu->is_debug_types ? types_counter : counter;
       data_buf &this_list = per_cu->is_debug_types ? types_cu_list : cu_list;
+      partial_symtab *psymtab = (per_objfile->per_bfd->using_index
+				 ? nullptr
+				 : per_cu->v.psymtab);
 
       if (psymtab != nullptr && psymtab->user == nullptr)
 	nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen,
 					      this_counter);
 
+      nametable.add_cu (per_cu, this_counter);
       this_list.append_uint (nametable.dwarf5_offset_size (),
 			     dwarf5_byte_order,
 			     to_underlying (per_cu->sect_off));
@@ -1513,6 +1540,11 @@ write_debug_names (dwarf2_per_objfile *per_objfile,
 			  - per_objfile->per_bfd->tu_stats.nr_tus));
   gdb_assert (types_counter == per_objfile->per_bfd->tu_stats.nr_tus);
 
+  if (per_objfile->per_bfd->using_index)
+    for (const cooked_index_entry *entry
+	   : per_objfile->per_bfd->cooked_index_table->all_entries ())
+      nametable.insert (entry);
+
   nametable.build ();
 
   /* No addr_vec - DWARF-5 uses .debug_aranges generated by GCC.  */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 30/32] Enable the new DWARF indexer
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (28 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 29/32] Adapt .debug_names " Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 31/32] Delete DWARF psymtab code Tom Tromey
                   ` (3 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This patch finally enables the new indexer.  It is left until this
point in the series to avoid any regressions; in particular, it has to
come after the changes to the DWARF index writer to avoid this
problem.

However, if you experiment with the series, this patch can be moved
anywhere from the patch to wire in the new reader to this point.
Moving this patch around is how I got separate numbers for the
parallelization and background finalization patches.

In the ongoing performance example, this reduces the time from the
baseline of 1.598869 to 0.903534.
---
 gdb/dwarf2/read.c                               |  3 ++-
 gdb/testsuite/gdb.base/maint.exp                | 14 +++++++++++---
 gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp |  3 +--
 gdb/testsuite/lib/gdb.exp                       |  2 +-
 4 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 01cfa42f45a..49288d72bb2 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -5679,7 +5679,8 @@ dwarf2_initialize_objfile (struct objfile *objfile)
     }
 
   global_index_cache.miss ();
-  objfile->qf.push_front (make_lazy_dwarf_reader ());
+  per_bfd->using_index = true;
+  objfile->qf.push_front (make_cooked_index_funcs ());
 }
 
 \f
diff --git a/gdb/testsuite/gdb.base/maint.exp b/gdb/testsuite/gdb.base/maint.exp
index 0a0cc0f813c..84f203438da 100644
--- a/gdb/testsuite/gdb.base/maint.exp
+++ b/gdb/testsuite/gdb.base/maint.exp
@@ -200,11 +200,11 @@ set re \
 	 "  Number of symbol tables: $decimal" \
 	 "  Number of symbol tables with line tables: $decimal" \
 	 "  Number of symbol tables with blockvectors: $decimal" \
-	 "(  Number of read CUs: $decimal" \
-	 "  Number of unread CUs: $decimal" \
-	 ")?(  Number of \"partial\" symbols read: $decimal" \
+	 "(  Number of \"partial\" symbols read: $decimal" \
 	 ")?(  Number of psym tables \\(not yet expanded\\): $decimal" \
 	 ")?(  Total memory used for psymbol cache: $decimal" \
+	 ")?(  Number of read CUs: $decimal" \
+	 "  Number of unread CUs: $decimal" \
 	 ")?  Total memory used for objfile obstack: $decimal" \
 	 "  Total memory used for BFD obstack: $decimal" \
 	 "  Total memory used for string cache: $decimal" \
@@ -224,12 +224,17 @@ gdb_test_no_output "maint print dummy-frames"
 
 set header 0
 set psymtabs 0
+set cooked_index 0
 set symtabs 0
 gdb_test_multiple "maint print objfiles" "" -lbl {
     -re "\r\nObject file.*maint($EXEEXT)?:  Objfile at ${hex}" {
 	set header 1
 	exp_continue
     }
+    -re "\r\nCooked index" {
+	set cooked_index 1
+	exp_continue
+    }
     -re "\r\nPsymtabs:\[\r\t \]+" {
 	set psymtabs 1
 	exp_continue
@@ -248,6 +253,9 @@ proc maint_pass_if {val name} {
 }
 
 maint_pass_if $header   "maint print objfiles: header"
+if {$cooked_index} {
+    set have_psyms 0
+}
 if { $have_psyms } {
     maint_pass_if $psymtabs "maint print objfiles: psymtabs"
 }
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp b/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp
index 8a11d1d5575..a9922322c38 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-missing-cu-tag.exp
@@ -54,8 +54,7 @@ clean_restart
 set pattern1 \
     [multi_line \
 	 "Reading symbols from \[^\r\n\]+" \
-	 "Dwarf Error: unexpected tag 'DW_TAG_subprogram' at offset $hex \\\[\[^\r\n\]+\\\]" \
-	 "\\(No debugging symbols \[^\r\n\]+\\)"]
+	 "Dwarf Error: unexpected tag 'DW_TAG_subprogram' at offset $hex \\\[\[^\r\n\]+\\\]"]
 
 # This pattern is hit when GDB does use -readnow (e.g. running with
 # --target_board=readnow).
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 97bedd5cb58..3d95397f8e1 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -7939,7 +7939,7 @@ proc ensure_gdb_index { binfile {style ""} } {
 	    set has_index 1
 	    gdb_test_lines "" $gdb_test_name ".*"
 	}
-	-re "\r\nPsymtabs:(?=\r\n)" {
+	-re "\r\n(Cooked index in use|Psymtabs)(?=\r\n)" {
 	    gdb_test_lines "" $gdb_test_name ".*"
 	}
 	-re ".gdb_index: faked for \"readnow\"" {
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 31/32] Delete DWARF psymtab code
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (29 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 30/32] Enable the new DWARF indexer Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-04 18:09 ` [PATCH v2 32/32] Remove dwarf2_per_cu_data::v Tom Tromey
                   ` (2 subsequent siblings)
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This removes the DWARF psymtab reader.
---
 gdb/dwarf2/cu.c                               |    1 +
 gdb/dwarf2/index-write.c                      |  338 +-
 gdb/dwarf2/line-header.h                      |    3 -
 gdb/dwarf2/public.h                           |    2 +-
 gdb/dwarf2/read.c                             | 3253 +++--------------
 gdb/dwarf2/read.h                             |   54 +-
 .../gdb.dwarf2/gdb-index-nodebug.exp          |    8 +
 7 files changed, 454 insertions(+), 3205 deletions(-)

diff --git a/gdb/dwarf2/cu.c b/gdb/dwarf2/cu.c
index e7aed774c25..2f8ec08378a 100644
--- a/gdb/dwarf2/cu.c
+++ b/gdb/dwarf2/cu.c
@@ -20,6 +20,7 @@
 #include "defs.h"
 #include "dwarf2/cu.h"
 #include "dwarf2/read.h"
+#include "objfiles.h"
 
 /* Initialize dwarf2_cu to read PER_CU, in the context of PER_OBJFILE.  */
 
diff --git a/gdb/dwarf2/index-write.c b/gdb/dwarf2/index-write.c
index 71cdb394c51..c5a593606d1 100644
--- a/gdb/dwarf2/index-write.c
+++ b/gdb/dwarf2/index-write.c
@@ -36,7 +36,6 @@
 #include "gdb/gdb-index.h"
 #include "gdbcmd.h"
 #include "objfiles.h"
-#include "psympriv.h"
 #include "ada-lang.h"
 
 #include <algorithm>
@@ -412,11 +411,9 @@ typedef std::unordered_map<dwarf2_per_cu_data *, unsigned int> cu_index_map;
 /* Helper struct for building the address table.  */
 struct addrmap_index_data
 {
-  addrmap_index_data (data_buf &addr_vec_, cu_index_map &cu_index_htab_,
-		      bool using_index_)
+  addrmap_index_data (data_buf &addr_vec_, cu_index_map &cu_index_htab_)
     : addr_vec (addr_vec_),
-      cu_index_htab (cu_index_htab_),
-      using_index (using_index_)
+      cu_index_htab (cu_index_htab_)
   {}
 
   data_buf &addr_vec;
@@ -424,8 +421,6 @@ struct addrmap_index_data
 
   int operator() (CORE_ADDR start_addr, void *obj);
 
-  /* True if the DWARF reader uses the new DWARF indexer.  */
-  bool using_index;
   /* True if the previous_* fields are valid.
      We can't write an entry until we see the next entry (since it is only then
      that we know the end of the entry).  */
@@ -452,11 +447,7 @@ add_address_entry (data_buf &addr_vec,
 int
 addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
 {
-  dwarf2_per_cu_data *per_cu;
-  if (using_index)
-    per_cu = (dwarf2_per_cu_data *) obj;
-  else
-    per_cu = obj == nullptr ? nullptr : ((dwarf2_psymtab *) obj)->per_cu_data;
+  dwarf2_per_cu_data *per_cu = (dwarf2_per_cu_data *) obj;
 
   if (previous_valid)
     add_address_entry (addr_vec,
@@ -483,10 +474,9 @@ addrmap_index_data::operator() (CORE_ADDR start_addr, void *obj)
 
 static void
 write_address_map (struct addrmap *addrmap, data_buf &addr_vec,
-		   cu_index_map &cu_index_htab, bool using_index)
+		   cu_index_map &cu_index_htab)
 {
-  struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab,
-						using_index);
+  struct addrmap_index_data addrmap_index_data (addr_vec, cu_index_htab);
 
   addrmap_foreach (addrmap, addrmap_index_data);
 
@@ -501,142 +491,6 @@ write_address_map (struct addrmap *addrmap, data_buf &addr_vec,
 		       addrmap_index_data.previous_cu_index);
 }
 
-/* Return the symbol kind of PSYM.  */
-
-static gdb_index_symbol_kind
-symbol_kind (struct partial_symbol *psym)
-{
-  domain_enum domain = psym->domain;
-  enum address_class aclass = psym->aclass;
-
-  switch (domain)
-    {
-    case VAR_DOMAIN:
-      switch (aclass)
-	{
-	case LOC_BLOCK:
-	  return GDB_INDEX_SYMBOL_KIND_FUNCTION;
-	case LOC_TYPEDEF:
-	  return GDB_INDEX_SYMBOL_KIND_TYPE;
-	case LOC_COMPUTED:
-	case LOC_CONST_BYTES:
-	case LOC_OPTIMIZED_OUT:
-	case LOC_STATIC:
-	  return GDB_INDEX_SYMBOL_KIND_VARIABLE;
-	case LOC_CONST:
-	  /* Note: It's currently impossible to recognize psyms as enum values
-	     short of reading the type info.  For now punt.  */
-	  return GDB_INDEX_SYMBOL_KIND_VARIABLE;
-	default:
-	  /* There are other LOC_FOO values that one might want to classify
-	     as variables, but dwarf2read.c doesn't currently use them.  */
-	  return GDB_INDEX_SYMBOL_KIND_OTHER;
-	}
-    case STRUCT_DOMAIN:
-      return GDB_INDEX_SYMBOL_KIND_TYPE;
-    default:
-      return GDB_INDEX_SYMBOL_KIND_OTHER;
-    }
-}
-
-/* Add a list of partial symbols to SYMTAB.  */
-
-static void
-write_psymbols (struct mapped_symtab *symtab,
-		std::unordered_set<partial_symbol *> &psyms_seen,
-		const std::vector<partial_symbol *> &symbols,
-		offset_type cu_index,
-		int is_static)
-{
-  for (partial_symbol *psym : symbols)
-    {
-      const char *name = psym->ginfo.search_name ();
-
-      if (psym->ginfo.language () == language_ada)
-	{
-	  /* We want to ensure that the Ada main function's name appears
-	     verbatim in the index.  However, this name will be of the
-	     form "_ada_mumble", and will be rewritten by ada_decode.
-	     So, recognize it specially here and add it to the index by
-	     hand.  */
-	  if (strcmp (main_name (), name) == 0)
-	    {
-	      gdb_index_symbol_kind kind = symbol_kind (psym);
-
-	      add_index_entry (symtab, name, is_static, kind, cu_index);
-	    }
-
-	  /* In order for the index to work when read back into gdb, it
-	     has to supply a funny form of the name: it should be the
-	     encoded name, with any suffixes stripped.  Using the
-	     ordinary encoded name will not work properly with the
-	     searching logic in find_name_components_bounds; nor will
-	     using the decoded name.  Furthermore, an Ada "verbatim"
-	     name (of the form "<MumBle>") must be entered without the
-	     angle brackets.  Note that the current index is unusual,
-	     see PR symtab/24820 for details.  */
-	  std::string decoded = ada_decode (name);
-	  if (decoded[0] == '<')
-	    name = (char *) obstack_copy0 (&symtab->m_string_obstack,
-					   decoded.c_str () + 1,
-					   decoded.length () - 2);
-	  else
-	    name = obstack_strdup (&symtab->m_string_obstack,
-				   ada_encode (decoded.c_str ()));
-	}
-
-      /* Only add a given psymbol once.  */
-      if (psyms_seen.insert (psym).second)
-	{
-	  gdb_index_symbol_kind kind = symbol_kind (psym);
-
-	  add_index_entry (symtab, name, is_static, kind, cu_index);
-	}
-    }
-}
-
-/* Recurse into all "included" dependencies and count their symbols as
-   if they appeared in this psymtab.  */
-
-static void
-recursively_count_psymbols (partial_symtab *psymtab,
-			    size_t &psyms_seen)
-{
-  for (int i = 0; i < psymtab->number_of_dependencies; ++i)
-    if (psymtab->dependencies[i]->user != NULL)
-      recursively_count_psymbols (psymtab->dependencies[i],
-				  psyms_seen);
-
-  psyms_seen += psymtab->global_psymbols.size ();
-  psyms_seen += psymtab->static_psymbols.size ();
-}
-
-/* Recurse into all "included" dependencies and write their symbols as
-   if they appeared in this psymtab.  */
-
-static void
-recursively_write_psymbols (struct objfile *objfile,
-			    partial_symtab *psymtab,
-			    struct mapped_symtab *symtab,
-			    std::unordered_set<partial_symbol *> &psyms_seen,
-			    offset_type cu_index)
-{
-  int i;
-
-  for (i = 0; i < psymtab->number_of_dependencies; ++i)
-    if (psymtab->dependencies[i]->user != NULL)
-      recursively_write_psymbols (objfile,
-				  psymtab->dependencies[i],
-				  symtab, psyms_seen, cu_index);
-
-  write_psymbols (symtab, psyms_seen,
-		  psymtab->global_psymbols, cu_index,
-		  0);
-  write_psymbols (symtab, psyms_seen,
-		  psymtab->static_psymbols, cu_index,
-		  1);
-}
-
 /* DWARF-5 .debug_names builder.  */
 class debug_names
 {
@@ -710,18 +564,6 @@ class debug_names
     value_set.emplace (symbol_value (dwarf_tag, cu_index, is_static, kind));
   }
 
-  void insert (const partial_symbol *psym, int cu_index, bool is_static,
-	       unit_kind kind)
-  {
-    const int dwarf_tag = psymbol_tag (psym);
-    if (dwarf_tag == 0)
-      return;
-    const char *name = psym->ginfo.search_name ();
-
-    insert (dwarf_tag, name, cu_index, is_static, kind,
-	    psym->ginfo.language ());
-  }
-
   void insert (const cooked_index_entry *entry)
   {
     const auto it = m_cu_index_htab.find (entry->per_cu);
@@ -863,25 +705,6 @@ class debug_names
     return m_abbrev_table.size ();
   }
 
-  /* Recurse into all "included" dependencies and store their symbols
-     as if they appeared in this psymtab.  */
-  void recursively_write_psymbols
-    (struct objfile *objfile,
-     partial_symtab *psymtab,
-     std::unordered_set<partial_symbol *> &psyms_seen,
-     int cu_index)
-  {
-    for (int i = 0; i < psymtab->number_of_dependencies; ++i)
-      if (psymtab->dependencies[i]->user != NULL)
-	recursively_write_psymbols
-	  (objfile, psymtab->dependencies[i], psyms_seen, cu_index);
-
-    write_psymbols (psyms_seen, psymtab->global_psymbols,
-		    cu_index, false, unit_kind::cu);
-    write_psymbols (psyms_seen, psymtab->static_psymbols,
-		    cu_index, true, unit_kind::cu);
-  }
-
   /* Return number of bytes the .debug_names section will have.  This
      must be called only after calling the build method.  */
   size_t bytes () const
@@ -1148,59 +971,6 @@ class debug_names
     offset_vec_tmpl<OffsetSize> m_name_table_entry_offs;
   };
 
-  /* Try to reconstruct original DWARF tag for given partial_symbol.
-     This function is not DWARF-5 compliant but it is sufficient for
-     GDB as a DWARF-5 index consumer.  */
-  static int psymbol_tag (const struct partial_symbol *psym)
-  {
-    domain_enum domain = psym->domain;
-    enum address_class aclass = psym->aclass;
-
-    switch (domain)
-      {
-      case VAR_DOMAIN:
-	switch (aclass)
-	  {
-	  case LOC_BLOCK:
-	    return DW_TAG_subprogram;
-	  case LOC_TYPEDEF:
-	    return DW_TAG_typedef;
-	  case LOC_COMPUTED:
-	  case LOC_CONST_BYTES:
-	  case LOC_OPTIMIZED_OUT:
-	  case LOC_STATIC:
-	    return DW_TAG_variable;
-	  case LOC_CONST:
-	    /* Note: It's currently impossible to recognize psyms as enum values
-	       short of reading the type info.  For now punt.  */
-	    return DW_TAG_variable;
-	  default:
-	    /* There are other LOC_FOO values that one might want to classify
-	       as variables, but dwarf2read.c doesn't currently use them.  */
-	    return DW_TAG_variable;
-	  }
-      case STRUCT_DOMAIN:
-	return DW_TAG_structure_type;
-      case MODULE_DOMAIN:
-	return DW_TAG_module;
-      default:
-	return 0;
-      }
-  }
-
-  /* Call insert for all partial symbols and mark them in PSYMS_SEEN.  */
-  void write_psymbols (std::unordered_set<partial_symbol *> &psyms_seen,
-		       const std::vector<partial_symbol *> &symbols,
-		       int cu_index, bool is_static, unit_kind kind)
-  {
-    for (partial_symbol *psym : symbols)
-      {
-	/* Only add a given psymbol once.  */
-	if (psyms_seen.insert (psym).second)
-	  insert (psym, cu_index, is_static, kind);
-      }
-  }
-
   /* Store value of each symbol.  */
   std::unordered_map<c_str_view, std::set<symbol_value>, c_str_view_hasher>
     m_name_to_value_set;
@@ -1252,31 +1022,6 @@ check_dwarf64_offsets (dwarf2_per_objfile *per_objfile)
   return false;
 }
 
-/* The psyms_seen set is potentially going to be largish (~40k
-   elements when indexing a -g3 build of GDB itself).  Estimate the
-   number of elements in order to avoid too many rehashes, which
-   require rebuilding buckets and thus many trips to
-   malloc/free.  */
-
-static size_t
-psyms_seen_size (dwarf2_per_objfile *per_objfile)
-{
-  if (per_objfile->per_bfd->using_index)
-    return 0;
-
-  size_t psyms_count = 0;
-  for (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
-    {
-      partial_symtab *psymtab = per_cu->v.psymtab;
-
-      if (psymtab != NULL && psymtab->user == NULL)
-	recursively_count_psymbols (psymtab, psyms_count);
-    }
-  /* Generating an index for gdb itself shows a ratio of
-     TOTAL_SEEN_SYMS/UNIQUE_SYMS or ~5.  4 seems like a good bet.  */
-  return psyms_count / 4;
-}
-
 /* Assert that FILE's size is EXPECTED_SIZE.  Assumes file's seek
    position is at the end of the file.  */
 
@@ -1346,8 +1091,6 @@ write_cooked_index (dwarf2_per_objfile *per_objfile,
 		    const cu_index_map &cu_index_htab,
 		    struct mapped_symtab *symtab)
 {
-  gdb_assert (per_objfile->per_bfd->using_index);
-
   for (const cooked_index_entry *entry
 	 : per_objfile->per_bfd->cooked_index_table->all_entries ())
     {
@@ -1383,7 +1126,6 @@ static void
 write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
 		FILE *dwz_out_file)
 {
-  struct objfile *objfile = per_objfile->objfile;
   mapped_symtab symtab;
   data_buf objfile_cu_list;
   data_buf dwz_cu_list;
@@ -1402,33 +1144,17 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
      work here.  Also, the debug_types entries do not appear in
      all_comp_units, but only in their own hash table.  */
 
-  std::unordered_set<partial_symbol *> psyms_seen
-    (psyms_seen_size (per_objfile));
   int counter = 0;
   int types_counter = 0;
   for (int i = 0; i < per_objfile->per_bfd->all_comp_units.size (); ++i)
     {
       dwarf2_per_cu_data *per_cu
 	= per_objfile->per_bfd->all_comp_units[i].get ();
-      partial_symtab *psymtab = (per_objfile->per_bfd->using_index
-				 ? nullptr
-				 : per_cu->v.psymtab);
 
       int &this_counter = per_cu->is_debug_types ? types_counter : counter;
 
-      if (psymtab != NULL)
-	{
-	  if (psymtab->user == NULL)
-	    recursively_write_psymbols (objfile, psymtab, &symtab,
-					psyms_seen, this_counter);
-	}
-
-      if (psymtab != NULL || per_objfile->per_bfd->using_index)
-	{
-	  const auto insertpair = cu_index_htab.emplace (per_cu,
-							 this_counter);
-	  gdb_assert (insertpair.second);
-	}
+      const auto insertpair = cu_index_htab.emplace (per_cu, this_counter);
+      gdb_assert (insertpair.second);
 
       /* The all_comp_units list contains CUs read from the objfile as well as
 	 from the eventual dwz file.  We need to place the entry in the
@@ -1452,21 +1178,14 @@ write_gdbindex (dwarf2_per_objfile *per_objfile, FILE *out_file,
       ++this_counter;
     }
 
-  if (per_objfile->per_bfd->using_index)
-    write_cooked_index (per_objfile, cu_index_htab, &symtab);
+  write_cooked_index (per_objfile, cu_index_htab, &symtab);
 
   /* Dump the address map.  */
   data_buf addr_vec;
-  if (per_objfile->per_bfd->using_index)
-    {
-      std::vector<addrmap *> addrmaps
-	= per_objfile->per_bfd->cooked_index_table->get_addrmaps ();
-      for (auto map : addrmaps)
-	write_address_map (map, addr_vec, cu_index_htab, true);
-    }
-  else
-    write_address_map (per_objfile->per_bfd->partial_symtabs->psymtabs_addrmap,
-		       addr_vec, cu_index_htab, false);
+  std::vector<addrmap *> addrmaps
+    = per_objfile->per_bfd->cooked_index_table->get_addrmaps ();
+  for (auto map : addrmaps)
+    write_address_map (map, addr_vec, cu_index_htab);
 
   /* Now that we've processed all symbols we can shrink their cu_indices
      lists.  */
@@ -1509,8 +1228,6 @@ write_debug_names (dwarf2_per_objfile *per_objfile,
   data_buf cu_list;
   data_buf types_cu_list;
   debug_names nametable (per_objfile, dwarf5_is_dwarf64, dwarf5_byte_order);
-  std::unordered_set<partial_symbol *>
-    psyms_seen (psyms_seen_size (per_objfile));
   int counter = 0;
   int types_counter = 0;
   for (int i = 0; i < per_objfile->per_bfd->all_comp_units.size (); ++i)
@@ -1520,13 +1237,6 @@ write_debug_names (dwarf2_per_objfile *per_objfile,
 
       int &this_counter = per_cu->is_debug_types ? types_counter : counter;
       data_buf &this_list = per_cu->is_debug_types ? types_cu_list : cu_list;
-      partial_symtab *psymtab = (per_objfile->per_bfd->using_index
-				 ? nullptr
-				 : per_cu->v.psymtab);
-
-      if (psymtab != nullptr && psymtab->user == nullptr)
-	nametable.recursively_write_psymbols (objfile, psymtab, psyms_seen,
-					      this_counter);
 
       nametable.add_cu (per_cu, this_counter);
       this_list.append_uint (nametable.dwarf5_offset_size (),
@@ -1540,10 +1250,9 @@ write_debug_names (dwarf2_per_objfile *per_objfile,
 			  - per_objfile->per_bfd->tu_stats.nr_tus));
   gdb_assert (types_counter == per_objfile->per_bfd->tu_stats.nr_tus);
 
-  if (per_objfile->per_bfd->using_index)
-    for (const cooked_index_entry *entry
-	   : per_objfile->per_bfd->cooked_index_table->all_entries ())
-      nametable.insert (entry);
+  for (const cooked_index_entry *entry
+	 : per_objfile->per_bfd->cooked_index_table->all_entries ())
+    nametable.insert (entry);
 
   nametable.build ();
 
@@ -1677,22 +1386,19 @@ write_dwarf_index (dwarf2_per_objfile *per_objfile, const char *dir,
 		   const char *basename, const char *dwz_basename,
 		   dw_index_kind index_kind)
 {
-  dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
   struct objfile *objfile = per_objfile->objfile;
 
-  if (per_objfile->per_bfd->using_index
-      && per_objfile->per_bfd->cooked_index_table == nullptr)
-    error (_("Cannot use an index to create the index"));
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    {
+      if (per_objfile->per_bfd->index_table != nullptr
+	  || per_objfile->per_bfd->debug_names_table != nullptr)
+	error (_("Cannot use an index to create the index"));
+      error (_("No debugging symbols"));
+    }
 
   if (per_objfile->per_bfd->types.size () > 1)
     error (_("Cannot make an index when the file has multiple .debug_types sections"));
 
-  if ((per_bfd->partial_symtabs == nullptr
-       || !per_bfd->partial_symtabs->psymtabs
-       || !per_bfd->partial_symtabs->psymtabs_addrmap)
-      && per_bfd->cooked_index_table == nullptr)
-    return;
-
   struct stat st;
   if (stat (objfile_name (objfile), &st) < 0)
     perror_with_name (objfile_name (objfile));
diff --git a/gdb/dwarf2/line-header.h b/gdb/dwarf2/line-header.h
index 4cacb8ca344..c0f8a619f7a 100644
--- a/gdb/dwarf2/line-header.h
+++ b/gdb/dwarf2/line-header.h
@@ -59,9 +59,6 @@ struct file_entry
 
   unsigned int length {};
 
-  /* True if referenced by the Line Number Program.  */
-  bool included_p {};
-
   /* The associated symbol table, if any.  */
   struct symtab *symtab {};
 };
diff --git a/gdb/dwarf2/public.h b/gdb/dwarf2/public.h
index 33bb5d48217..60a99bf4a42 100644
--- a/gdb/dwarf2/public.h
+++ b/gdb/dwarf2/public.h
@@ -40,7 +40,7 @@ extern void dwarf2_initialize_objfile (struct objfile *objfile);
 
 struct psymbol_functions;
 extern void dwarf2_build_psymtabs (struct objfile *,
-				   psymbol_functions *psf = nullptr);
+				   bool already_attached = false);
 extern void dwarf2_build_frame_info (struct objfile *);
 
 #endif /* DWARF2_PUBLIC_H */
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 49288d72bb2..4c5d6f25369 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -64,7 +64,6 @@
 #include "block.h"
 #include "addrmap.h"
 #include "typeprint.h"
-#include "psympriv.h"
 #include "c-lang.h"
 #include "go-lang.h"
 #include "valprint.h"
@@ -482,13 +481,8 @@ struct stmt_list_hash
    that can be shared across objfiles.  The non-shareable parts are in
    type_unit_group_unshareable.  */
 
-struct type_unit_group : public dwarf2_per_cu_data
+struct type_unit_group
 {
-  /* The TUs that share this DW_AT_stmt_list entry.
-     This is added to while parsing type units to build partial symtabs,
-     and is deleted afterwards and not used again.  */
-  std::vector<signatured_type *> *tus = nullptr;
-
   /* The data used to construct the hash key.  */
   struct stmt_list_hash hash {};
 };
@@ -838,164 +832,6 @@ class cutu_reader : public die_reader_specs
   abbrev_table_up m_dwo_abbrev_table;
 };
 
-/* When we construct a partial symbol table entry we only
-   need this much information.  */
-struct partial_die_info : public allocate_on_obstack
-  {
-    partial_die_info (sect_offset sect_off, const struct abbrev_info *abbrev);
-
-    /* Disable assign but still keep copy ctor, which is needed
-       load_partial_dies.   */
-    partial_die_info& operator=(const partial_die_info& rhs) = delete;
-    partial_die_info (const partial_die_info &) = default;
-
-    /* Adjust the partial die before generating a symbol for it.  This
-       function may set the is_external flag or change the DIE's
-       name.  */
-    void fixup (struct dwarf2_cu *cu);
-
-    /* Read a minimal amount of information into the minimal die
-       structure.  */
-    const gdb_byte *read (const struct die_reader_specs *reader,
-			  const struct abbrev_info &abbrev,
-			  const gdb_byte *info_ptr);
-
-    /* Compute the name of this partial DIE.  This memoizes the
-       result, so it is safe to call multiple times.  */
-    const char *name (dwarf2_cu *cu);
-
-    /* Offset of this DIE.  */
-    const sect_offset sect_off;
-
-    /* DWARF-2 tag for this DIE.  */
-    const ENUM_BITFIELD(dwarf_tag) tag : 16;
-
-    /* Assorted flags describing the data found in this DIE.  */
-    const unsigned int has_children : 1;
-
-    unsigned int is_external : 1;
-    unsigned int is_declaration : 1;
-    unsigned int has_type : 1;
-    unsigned int has_specification : 1;
-    unsigned int has_pc_info : 1;
-    unsigned int has_range_info : 1;
-    unsigned int may_be_inlined : 1;
-
-    /* This DIE has been marked DW_AT_main_subprogram.  */
-    unsigned int main_subprogram : 1;
-
-    /* Flag set if the SCOPE field of this structure has been
-       computed.  */
-    unsigned int scope_set : 1;
-
-    /* Flag set if the DIE has a byte_size attribute.  */
-    unsigned int has_byte_size : 1;
-
-    /* Flag set if the DIE has a DW_AT_const_value attribute.  */
-    unsigned int has_const_value : 1;
-
-    /* Flag set if any of the DIE's children are template arguments.  */
-    unsigned int has_template_arguments : 1;
-
-    /* Flag set if fixup has been called on this die.  */
-    unsigned int fixup_called : 1;
-
-    /* Flag set if DW_TAG_imported_unit uses DW_FORM_GNU_ref_alt.  */
-    unsigned int is_dwz : 1;
-
-    /* Flag set if spec_offset uses DW_FORM_GNU_ref_alt.  */
-    unsigned int spec_is_dwz : 1;
-
-    unsigned int canonical_name : 1;
-
-    /* The name of this DIE.  Normally the value of DW_AT_name, but
-       sometimes a default name for unnamed DIEs.  */
-    const char *raw_name = nullptr;
-
-    /* The linkage name, if present.  */
-    const char *linkage_name = nullptr;
-
-    /* The scope to prepend to our children.  This is generally
-       allocated on the comp_unit_obstack, so will disappear
-       when this compilation unit leaves the cache.  */
-    const char *scope = nullptr;
-
-    /* Some data associated with the partial DIE.  The tag determines
-       which field is live.  */
-    union
-    {
-      /* The location description associated with this DIE, if any.  */
-      struct dwarf_block *locdesc;
-      /* The offset of an import, for DW_TAG_imported_unit.  */
-      sect_offset sect_off;
-    } d {};
-
-    union
-    {
-      /* If HAS_PC_INFO, the PC range associated with this DIE.  */
-      struct
-      {
-	CORE_ADDR lowpc;
-	CORE_ADDR highpc;
-      };
-      /* If HAS_RANGE_INFO, the ranges offset associated with this DIE.  */
-      ULONGEST ranges_offset;
-    };
-
-    /* Pointer into the info_buffer (or types_buffer) pointing at the target of
-       DW_AT_sibling, if any.  */
-    /* NOTE: This member isn't strictly necessary, partial_die_info::read
-       could return DW_AT_sibling values to its caller load_partial_dies.  */
-    const gdb_byte *sibling = nullptr;
-
-    /* If HAS_SPECIFICATION, the offset of the DIE referred to by
-       DW_AT_specification (or DW_AT_abstract_origin or
-       DW_AT_extension).  */
-    sect_offset spec_offset {};
-
-    /* Pointers to this DIE's parent, first child, and next sibling,
-       if any.  */
-    struct partial_die_info *die_parent = nullptr;
-    struct partial_die_info *die_child = nullptr;
-    struct partial_die_info *die_sibling = nullptr;
-
-    friend struct partial_die_info *
-    dwarf2_cu::find_partial_die (sect_offset sect_off);
-
-  private:
-    /* Only need to do look up in dwarf2_cu::find_partial_die.  */
-    partial_die_info (sect_offset sect_off)
-      : partial_die_info (sect_off, DW_TAG_padding, 0)
-    {
-    }
-
-    partial_die_info (sect_offset sect_off_, enum dwarf_tag tag_,
-		      int has_children_)
-      : sect_off (sect_off_), tag (tag_), has_children (has_children_)
-    {
-      is_external = 0;
-      is_declaration = 0;
-      has_type = 0;
-      has_specification = 0;
-      has_pc_info = 0;
-      has_range_info = 0;
-      may_be_inlined = 0;
-      main_subprogram = 0;
-      scope_set = 0;
-      has_byte_size = 0;
-      has_const_value = 0;
-      has_template_arguments = 0;
-      fixup_called = 0;
-      is_dwz = 0;
-      spec_is_dwz = 0;
-      canonical_name = 0;
-      /* Don't set these using NSDMI (Non-static data member initialisation),
-	 because g++-4.8 will error out.  */
-      lowpc = 0;
-      highpc = 0;
-    }
-  };
-
 /* FIXME: We might want to set this from BFD via bfd_arch_bits_per_byte,
    but this would require a corresponding change in unpack_field_as_long
    and friends.  */
@@ -1115,63 +951,14 @@ show_dwarf_max_cache_age (struct ui_file *file, int from_tty,
 static void dwarf2_find_base_address (struct die_info *die,
 				      struct dwarf2_cu *cu);
 
-static dwarf2_psymtab *create_partial_symtab
-  (dwarf2_per_cu_data *per_cu, dwarf2_per_objfile *per_objfile,
-   const char *name);
-
 class cooked_index_storage;
 static void build_type_psymtabs_reader (cutu_reader *reader,
 					cooked_index_storage *storage);
 
 static void dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile);
 
-static void scan_partial_symbols (struct partial_die_info *,
-				  CORE_ADDR *, CORE_ADDR *,
-				  int, struct dwarf2_cu *);
-
-static void add_partial_symbol (struct partial_die_info *,
-				struct dwarf2_cu *);
-
-static void add_partial_namespace (struct partial_die_info *pdi,
-				   CORE_ADDR *lowpc, CORE_ADDR *highpc,
-				   int set_addrmap, struct dwarf2_cu *cu);
-
-static void add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
-				CORE_ADDR *highpc, int set_addrmap,
-				struct dwarf2_cu *cu);
-
-static void add_partial_enumeration (struct partial_die_info *enum_pdi,
-				     struct dwarf2_cu *cu);
-
-static void add_partial_subprogram (struct partial_die_info *pdi,
-				    CORE_ADDR *lowpc, CORE_ADDR *highpc,
-				    int need_pc, struct dwarf2_cu *cu);
-
 static unsigned int peek_abbrev_code (bfd *, const gdb_byte *);
 
-static struct partial_die_info *load_partial_dies
-  (const struct die_reader_specs *, const gdb_byte *, int);
-
-/* A pair of partial_die_info and compilation unit.  */
-struct cu_partial_die_info
-{
-  /* The compilation unit of the partial_die_info.  */
-  struct dwarf2_cu *cu;
-  /* A partial_die_info.  */
-  struct partial_die_info *pdi;
-
-  cu_partial_die_info (struct dwarf2_cu *cu, struct partial_die_info *pdi)
-    : cu (cu),
-      pdi (pdi)
-  { /* Nothing.  */ }
-
-private:
-  cu_partial_die_info () = delete;
-};
-
-static const struct cu_partial_die_info find_partial_die (sect_offset, int,
-							  struct dwarf2_cu *);
-
 static const gdb_byte *read_attribute (const struct die_reader_specs *,
 				       struct attribute *,
 				       const struct attr_abbrev *,
@@ -1221,10 +1008,8 @@ 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 *,
+				struct dwarf2_cu *,
 				CORE_ADDR, int decode_mapping);
 
 static void dwarf2_start_subfile (struct dwarf2_cu *, const char *,
@@ -1461,10 +1246,6 @@ static const gdb_byte *skip_one_die (const struct die_reader_specs *reader,
 				     const struct abbrev_info *abbrev,
 				     bool do_skip_children = true);
 
-static hashval_t partial_die_hash (const void *item);
-
-static int partial_die_eq (const void *item_lhs, const void *item_rhs);
-
 static struct dwarf2_per_cu_data *dwarf2_find_containing_comp_unit
   (sect_offset sect_off, unsigned int offset_in_dwz,
    dwarf2_per_objfile *per_objfile);
@@ -2124,30 +1905,6 @@ struct dwarf2_per_cu_quick_data
   bool files_read : 1;
 };
 
-/* A subclass of psymbol_functions that arranges to read the DWARF
-   partial symbols when needed.  */
-struct lazy_dwarf_reader : public psymbol_functions
-{
-  using psymbol_functions::psymbol_functions;
-
-  bool can_lazily_read_symbols () override
-  {
-    return true;
-  }
-
-  void read_partial_symbols (struct objfile *objfile) override
-  {
-    if (dwarf2_has_info (objfile, nullptr))
-      dwarf2_build_psymtabs (objfile, this);
-  }
-};
-
-static quick_symbol_functions_up
-make_lazy_dwarf_reader ()
-{
-  return quick_symbol_functions_up (new lazy_dwarf_reader);
-}
-
 struct dwarf2_base_index_functions : public quick_symbol_functions
 {
   bool has_symbols (struct objfile *objfile) override;
@@ -2331,11 +2088,6 @@ static void
 dw2_do_instantiate_symtab (dwarf2_per_cu_data *per_cu,
 			   dwarf2_per_objfile *per_objfile, bool skip_partial)
 {
-  /* Skip type_unit_groups, reading the type units they contain
-     is handled elsewhere.  */
-  if (per_cu->type_unit_group_p ())
-    return;
-
   {
     /* The destructor of dwarf2_queue_guard frees any entries left on
        the queue.  After this point we're guaranteed to leave this function
@@ -2378,8 +2130,6 @@ dw2_instantiate_symtab (dwarf2_per_cu_data *per_cu,
 			dwarf2_per_objfile *per_objfile,
 			bool skip_partial)
 {
-  gdb_assert (per_objfile->per_bfd->using_index);
-
   if (!per_objfile->symtab_set_p (per_cu))
     {
       free_cached_comp_units freer (per_objfile);
@@ -3017,7 +2767,6 @@ dwarf2_read_gdb_index
   create_addrmap_from_index (per_objfile, map.get ());
 
   per_bfd->index_table = std::move (map);
-  per_bfd->using_index = 1;
   per_bfd->quick_file_names_table =
     create_quick_file_names_table (per_bfd->all_comp_units.size ());
 
@@ -3131,8 +2880,6 @@ dw2_get_file_names (dwarf2_per_cu_data *this_cu,
 {
   /* This should never be called for TUs.  */
   gdb_assert (! this_cu->is_debug_types);
-  /* Nor type unit groups.  */
-  gdb_assert (! this_cu->type_unit_group_p ());
 
   if (this_cu->v.quick->files_read)
     return this_cu->v.quick->file_names;
@@ -3190,7 +2937,7 @@ dwarf2_base_index_functions::find_last_source_symtab (struct objfile *objfile)
 void
 dwarf2_per_cu_data::free_cached_file_names ()
 {
-  if (per_bfd == nullptr || !per_bfd->using_index || v.quick == nullptr)
+  if (per_bfd == nullptr || v.quick == nullptr)
     return;
 
   struct quick_file_names *file_data = v.quick->file_names;
@@ -3394,7 +3141,6 @@ dwarf2_gdb_index::dump (struct objfile *objfile)
 {
   dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
 
-  gdb_assert (per_objfile->per_bfd->using_index);
   printf_filtered (".gdb_index:");
   if (per_objfile->per_bfd->index_table != NULL)
     {
@@ -4976,7 +4722,6 @@ dwarf2_read_debug_names (dwarf2_per_objfile *per_objfile)
   create_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges);
 
   per_bfd->debug_names_table = std::move (map);
-  per_bfd->using_index = 1;
   per_bfd->quick_file_names_table =
     create_quick_file_names_table (per_bfd->all_comp_units.size ());
 
@@ -5402,7 +5147,6 @@ dwarf2_debug_names_index::dump (struct objfile *objfile)
 {
   dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
 
-  gdb_assert (per_objfile->per_bfd->using_index);
   printf_filtered (".debug_names:");
   if (per_objfile->per_bfd->debug_names_table)
     printf_filtered (" exists\n");
@@ -5585,16 +5329,6 @@ dwarf2_initialize_objfile (struct objfile *objfile)
     {
       dwarf_read_debug_printf ("readnow requested");
 
-      /* When using READNOW, the using_index flag (set below) indicates that
-	 PER_BFD was already initialized, when we loaded some other objfile.  */
-      if (per_bfd->using_index)
-	{
-	  dwarf_read_debug_printf ("using_index already set");
-	  objfile->qf.push_front (make_dwarf_gdb_index ());
-	  return;
-	}
-
-      per_bfd->using_index = 1;
       create_all_comp_units (per_objfile);
       per_bfd->quick_file_names_table
 	= create_quick_file_names_table (per_bfd->all_comp_units.size ());
@@ -5639,18 +5373,6 @@ dwarf2_initialize_objfile (struct objfile *objfile)
       return;
     }
 
-  /* There might already be partial symtabs built for this BFD.  This happens
-     when loading the same binary twice with the index-cache enabled.  If so,
-     don't try to read an index.  The objfile / per_objfile initialization will
-     be completed in dwarf2_build_psymtabs, in the standard partial symtabs
-     code path.  */
-  if (per_bfd->partial_symtabs != nullptr)
-    {
-      dwarf_read_debug_printf ("re-using shared partial symtabs");
-      objfile->qf.push_front (make_lazy_dwarf_reader ());
-      return;
-    }
-
   if (dwarf2_read_debug_names (per_objfile))
     {
       dwarf_read_debug_printf ("found debug names");
@@ -5679,7 +5401,6 @@ dwarf2_initialize_objfile (struct objfile *objfile)
     }
 
   global_index_cache.miss ();
-  per_bfd->using_index = true;
   objfile->qf.push_front (make_cooked_index_funcs ());
 }
 
@@ -5688,47 +5409,21 @@ dwarf2_initialize_objfile (struct objfile *objfile)
 /* Build a partial symbol table.  */
 
 void
-dwarf2_build_psymtabs (struct objfile *objfile, psymbol_functions *psf)
+dwarf2_build_psymtabs (struct objfile *objfile, bool already_attached)
 {
   dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-  dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
-
-  if (per_bfd->partial_symtabs != nullptr)
-    {
-      /* Partial symbols were already read, so now we can simply
-	 attach them.  */
-      if (psf == nullptr)
-	{
-	  psf = new psymbol_functions (per_bfd->partial_symtabs);
-	  objfile->qf.emplace_front (psf);
-	}
-      else
-	psf->set_partial_symtabs (per_bfd->partial_symtabs);
-      return;
-    }
 
-  if (psf == nullptr)
+  if (already_attached)
     {
-      psf = new psymbol_functions;
-      objfile->qf.emplace_front (psf);
+      if (per_objfile->per_bfd->cooked_index_table != nullptr)
+	return;
     }
-  const std::shared_ptr<psymtab_storage> &partial_symtabs
-    = psf->get_partial_symtabs ();
-
-  /* Set the local reference to partial symtabs, so that we don't try
-     to read them again if reading another objfile with the same BFD.
-     If we can't in fact share, this won't make a difference anyway as
-     the dwarf2_per_bfd object won't be shared.  */
-  per_bfd->partial_symtabs = partial_symtabs;
+  else
+    objfile->qf.push_front (make_cooked_index_funcs ());
 
   try
     {
-      /* This isn't really ideal: all the data we allocate on the
-	 objfile's obstack is still uselessly kept around.  However,
-	 freeing it seems unsafe.  */
-      psymtab_discarder psymtabs (partial_symtabs.get ());
       dwarf2_build_psymtabs_hard (per_objfile);
-      psymtabs.keep ();
 
       /* (maybe) store an index in the cache.  */
       global_index_cache.store (per_objfile);
@@ -5809,108 +5504,6 @@ read_abbrev_offset (dwarf2_per_objfile *per_objfile,
   return (sect_offset) read_offset (abfd, info_ptr, offset_size);
 }
 
-/* A partial symtab that is used only for include files.  */
-struct dwarf2_include_psymtab : public partial_symtab
-{
-  dwarf2_include_psymtab (const char *filename,
-			  psymtab_storage *partial_symtabs,
-			  objfile_per_bfd_storage *objfile_per_bfd)
-    : partial_symtab (filename, partial_symtabs, objfile_per_bfd)
-  {
-  }
-
-  void read_symtab (struct objfile *objfile) override
-  {
-    /* It's an include file, no symbols to read for it.
-       Everything is in the includer symtab.  */
-
-    /* The expansion of a dwarf2_include_psymtab is just a trigger for
-       expansion of the includer psymtab.  We use the dependencies[0] field to
-       model the includer.  But if we go the regular route of calling
-       expand_psymtab here, and having expand_psymtab call expand_dependencies
-       to expand the includer, we'll only use expand_psymtab on the includer
-       (making it a non-toplevel psymtab), while if we expand the includer via
-       another path, we'll use read_symtab (making it a toplevel psymtab).
-       So, don't pretend a dwarf2_include_psymtab is an actual toplevel
-       psymtab, and trigger read_symtab on the includer here directly.  */
-    includer ()->read_symtab (objfile);
-  }
-
-  void expand_psymtab (struct objfile *objfile) override
-  {
-    /* This is not called by read_symtab, and should not be called by any
-       expand_dependencies.  */
-    gdb_assert (false);
-  }
-
-  bool readin_p (struct objfile *objfile) const override
-  {
-    return includer ()->readin_p (objfile);
-  }
-
-  compunit_symtab *get_compunit_symtab (struct objfile *objfile) const override
-  {
-    return nullptr;
-  }
-
-private:
-  partial_symtab *includer () const
-  {
-    /* An include psymtab has exactly one dependency: the psymtab that
-       includes it.  */
-    gdb_assert (this->number_of_dependencies == 1);
-    return this->dependencies[0];
-  }
-};
-
-/* Allocate a new partial symtab for file named NAME and mark this new
-   partial symtab as being an include of PST.  */
-
-static void
-dwarf2_create_include_psymtab (dwarf2_per_bfd *per_bfd,
-			       const char *name,
-			       dwarf2_psymtab *pst,
-			       psymtab_storage *partial_symtabs,
-			       objfile_per_bfd_storage *objfile_per_bfd)
-{
-  dwarf2_include_psymtab *subpst
-    = new dwarf2_include_psymtab (name, partial_symtabs, objfile_per_bfd);
-
-  if (!IS_ABSOLUTE_PATH (subpst->filename))
-    subpst->dirname = pst->dirname;
-
-  subpst->dependencies = per_bfd->partial_symtabs->allocate_dependencies (1);
-  subpst->dependencies[0] = pst;
-  subpst->number_of_dependencies = 1;
-}
-
-/* Read the Line Number Program data and extract the list of files
-   included by the source file represented by PST.  Build an include
-   partial symtab for each of these included files.  */
-
-static void
-dwarf2_build_include_psymtabs (struct dwarf2_cu *cu,
-			       struct die_info *die,
-			       const file_and_directory &fnd,
-			       dwarf2_psymtab *pst)
-{
-  line_header_up lh;
-  struct attribute *attr;
-
-  attr = dwarf2_attr (die, DW_AT_stmt_list, cu);
-  if (attr != nullptr && attr->form_is_unsigned ())
-    lh = dwarf_decode_line_header ((sect_offset) attr->as_unsigned (), cu);
-  if (lh == NULL)
-    return;  /* No linetable, so no includes.  */
-
-  /* NOTE: pst->dirname is DW_AT_comp_dir (if present).  Also note
-     that we pass in the raw text_low here; that is ok because we're
-     only decoding the line table to make include partial symtabs, and
-     so the addresses aren't really used.  */
-  dwarf_decode_lines (lh.get (), fnd, cu, pst,
-		      pst->raw_text_low (), 1);
-}
-
 static hashval_t
 hash_signatured_type (const void *item)
 {
@@ -6074,12 +5667,8 @@ add_type_unit (dwarf2_per_objfile *per_objfile, ULONGEST sig, void **slot)
 
   per_objfile->per_bfd->all_comp_units.emplace_back
     (sig_type_holder.release ());
-  if (per_objfile->per_bfd->using_index)
-    {
-      sig_type->v.quick =
-	OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
-			struct dwarf2_per_cu_quick_data);
-    }
+  sig_type->v.quick = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
+				      struct dwarf2_per_cu_quick_data);
 
   if (slot == NULL)
     {
@@ -6105,13 +5694,8 @@ fill_in_sig_entry_from_dwo_entry (dwarf2_per_objfile *per_objfile,
   /* Make sure we're not clobbering something we don't expect to.  */
   gdb_assert (! sig_entry->queued);
   gdb_assert (per_objfile->get_cu (sig_entry) == NULL);
-  if (per_bfd->using_index)
-    {
-      gdb_assert (sig_entry->v.quick != NULL);
-      gdb_assert (!per_objfile->symtab_set_p (sig_entry));
-    }
-  else
-      gdb_assert (sig_entry->v.psymtab == NULL);
+  gdb_assert (sig_entry->v.quick != NULL);
+  gdb_assert (!per_objfile->symtab_set_p (sig_entry));
   gdb_assert (sig_entry->signature == dwo_entry->signature);
   gdb_assert (to_underlying (sig_entry->type_offset_in_section) == 0
 	      || (to_underlying (sig_entry->type_offset_in_section)
@@ -6148,7 +5732,7 @@ lookup_dwo_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
   struct dwo_unit find_dwo_entry, *dwo_entry;
   void **slot;
 
-  gdb_assert (cu->dwo_unit && per_objfile->per_bfd->using_index);
+  gdb_assert (cu->dwo_unit);
 
   /* If TU skeletons have been removed then we may not have read in any
      TUs yet.  */
@@ -6213,7 +5797,7 @@ lookup_dwp_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
   struct dwo_unit *dwo_entry;
   void **slot;
 
-  gdb_assert (cu->dwo_unit && per_objfile->per_bfd->using_index);
+  gdb_assert (cu->dwo_unit);
   gdb_assert (dwp_file != NULL);
 
   /* If TU skeletons have been removed then we may not have read in any
@@ -6254,7 +5838,7 @@ lookup_signatured_type (struct dwarf2_cu *cu, ULONGEST sig)
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
 
-  if (cu->dwo_unit && per_objfile->per_bfd->using_index)
+  if (cu->dwo_unit)
     {
       /* We're in a DWO/DWP file, and we're using .gdb_index.
 	 These cases require special processing.  */
@@ -6945,34 +6529,7 @@ allocate_type_unit_groups_table ()
 static std::unique_ptr<type_unit_group>
 create_type_unit_group (struct dwarf2_cu *cu, sect_offset line_offset_struct)
 {
-  dwarf2_per_objfile *per_objfile = cu->per_objfile;
-  dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
-
   std::unique_ptr<type_unit_group> tu_group (new type_unit_group);
-  tu_group->per_bfd = per_bfd;
-
-  if (per_bfd->using_index)
-    {
-      tu_group->v.quick = OBSTACK_ZALLOC (&per_bfd->obstack,
-					  struct dwarf2_per_cu_quick_data);
-    }
-  else
-    {
-      unsigned int line_offset = to_underlying (line_offset_struct);
-      dwarf2_psymtab *pst;
-      std::string name;
-
-      /* Give the symtab a useful name for debug purposes.  */
-      if ((line_offset & NO_STMT_LIST_TYPE_UNIT_PSYMTAB) != 0)
-	name = string_printf ("<type_units_%d>",
-			      (line_offset & ~NO_STMT_LIST_TYPE_UNIT_PSYMTAB));
-      else
-	name = string_printf ("<type_units_at_0x%x>", line_offset);
-
-      pst = create_partial_symtab (tu_group.get (), per_objfile,
-				   name.c_str ());
-      pst->anonymous = true;
-    }
 
   tu_group->hash.dwo_unit = cu->dwo_unit;
   tu_group->hash.line_sect_off = line_offset_struct;
@@ -7034,30 +6591,6 @@ get_type_unit_group (struct dwarf2_cu *cu, const struct attribute *stmt_list)
   return tu_group;
 }
 \f
-/* Partial symbol tables.  */
-
-/* Create a psymtab named NAME and assign it to PER_CU.
-
-   The caller must fill in the following details:
-   dirname, textlow, texthigh.  */
-
-static dwarf2_psymtab *
-create_partial_symtab (dwarf2_per_cu_data *per_cu,
-		       dwarf2_per_objfile *per_objfile,
-		       const char *name)
-{
-  dwarf2_psymtab *pst
-    = new dwarf2_psymtab (name, per_objfile->per_bfd->partial_symtabs.get (),
-			  per_objfile->objfile->per_bfd, per_cu);
-
-  pst->psymtabs_addrmap_supported = true;
-
-  /* This is the glue that links PST into GDB's symbol API.  */
-  per_cu->v.psymtab = pst;
-
-  return pst;
-}
-\f
 
 /* An instance of this is created when scanning DWARF to create a
    cooked index.  */
@@ -7288,166 +6821,16 @@ class cooked_indexer
   std::vector<deferred_entry> m_deferred_entries;
 };
 
-
-
-/* DIE reader function for process_psymtab_comp_unit.  */
-
-static void
-process_psymtab_comp_unit_reader (const struct die_reader_specs *reader,
-				  const gdb_byte *info_ptr,
-				  struct die_info *comp_unit_die,
-				  enum language pretend_language)
-{
-  struct dwarf2_cu *cu = reader->cu;
-  dwarf2_per_objfile *per_objfile = cu->per_objfile;
-  dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
-  struct objfile *objfile = per_objfile->objfile;
-  struct gdbarch *gdbarch = objfile->arch ();
-  struct dwarf2_per_cu_data *per_cu = cu->per_cu;
-  CORE_ADDR baseaddr;
-  CORE_ADDR best_lowpc = 0, best_highpc = 0;
-  dwarf2_psymtab *pst;
-  enum pc_bounds_kind cu_bounds_kind;
-
-  gdb_assert (! per_cu->is_debug_types);
-
-  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)
-    {
-      debug_filename.reset (concat (artificial, "@",
-				    sect_offset_str (per_cu->sect_off),
-				    (char *) NULL));
-      fnd.name = debug_filename.get ();
-    }
-
-  pst = create_partial_symtab (per_cu, per_objfile, fnd.name);
-
-  /* This must be done before calling dwarf2_build_include_psymtabs.  */
-  pst->dirname = dwarf2_string_attr (comp_unit_die, DW_AT_comp_dir, cu);
-
-  baseaddr = objfile->text_section_offset ();
-
-  dwarf2_find_base_address (comp_unit_die, cu);
-
-  /* Possibly set the default values of LOWPC and HIGHPC from
-     `DW_AT_ranges'.  */
-  cu_bounds_kind
-    = dwarf2_get_pc_bounds (comp_unit_die, &best_lowpc,
-			    &best_highpc, cu,
-			    per_bfd->partial_symtabs->psymtabs_addrmap,
-			    pst);
-  if (cu_bounds_kind == PC_BOUNDS_HIGH_LOW && best_lowpc < best_highpc)
-    {
-      CORE_ADDR low
-	= (gdbarch_adjust_dwarf2_addr (gdbarch, best_lowpc + baseaddr)
-	   - baseaddr);
-      CORE_ADDR high
-	= (gdbarch_adjust_dwarf2_addr (gdbarch, best_highpc + baseaddr)
-	   - baseaddr - 1);
-      /* Store the contiguous range if it is not empty; it can be
-	 empty for CUs with no code.  */
-      addrmap_set_empty (per_bfd->partial_symtabs->psymtabs_addrmap,
-			 low, high, pst);
-    }
-
-  /* Check if comp unit has_children.
-     If so, read the rest of the partial symbols from this comp unit.
-     If not, there's no more debug_info for this comp unit.  */
-  if (comp_unit_die->has_children)
-    {
-      struct partial_die_info *first_die;
-      CORE_ADDR lowpc, highpc;
-
-      lowpc = ((CORE_ADDR) -1);
-      highpc = ((CORE_ADDR) 0);
-
-      first_die = load_partial_dies (reader, info_ptr, 1);
-
-      scan_partial_symbols (first_die, &lowpc, &highpc,
-			    cu_bounds_kind <= PC_BOUNDS_INVALID, cu);
-
-      /* If we didn't find a lowpc, set it to highpc to avoid
-	 complaints from `maint check'.	 */
-      if (lowpc == ((CORE_ADDR) -1))
-	lowpc = highpc;
-
-      /* If the compilation unit didn't have an explicit address range,
-	 then use the information extracted from its child dies.  */
-      if (cu_bounds_kind <= PC_BOUNDS_INVALID)
-	{
-	  best_lowpc = lowpc;
-	  best_highpc = highpc;
-	}
-    }
-  pst->set_text_low (gdbarch_adjust_dwarf2_addr (gdbarch,
-						 best_lowpc + baseaddr)
-		     - baseaddr);
-  pst->set_text_high (gdbarch_adjust_dwarf2_addr (gdbarch,
-						  best_highpc + baseaddr)
-		      - baseaddr);
-
-  pst->end ();
-
-  if (!cu->per_cu->imported_symtabs_empty ())
-    {
-      int i;
-      int len = cu->per_cu->imported_symtabs_size ();
-
-      /* Fill in 'dependencies' here; we fill in 'users' in a
-	 post-pass.  */
-      pst->number_of_dependencies = len;
-      pst->dependencies
-	= per_bfd->partial_symtabs->allocate_dependencies (len);
-      for (i = 0; i < len; ++i)
-	{
-	  pst->dependencies[i]
-	    = cu->per_cu->imported_symtabs->at (i)->v.psymtab;
-	}
-
-      cu->per_cu->imported_symtabs_free ();
-    }
-
-  /* Get the list of files included in the current compilation unit,
-     and build a psymtab for each of them.  */
-  dwarf2_build_include_psymtabs (cu, comp_unit_die, fnd, pst);
-
-  dwarf_read_debug_printf ("Psymtab for %s unit @%s: %s - %s"
-			   ", %d global, %d static syms",
-			   per_cu->is_debug_types ? "type" : "comp",
-			   sect_offset_str (per_cu->sect_off),
-			   paddress (gdbarch, pst->text_low (objfile)),
-			   paddress (gdbarch, pst->text_high (objfile)),
-			   (int) pst->global_psymbols.size (),
-			   (int) pst->static_psymbols.size ());
-}
-
 /* Subroutine of dwarf2_build_psymtabs_hard to simplify it.
    Process compilation unit THIS_CU for a psymtab.  */
 
 static void
 process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
 			   dwarf2_per_objfile *per_objfile,
-			   bool want_partial_unit,
-			   enum language pretend_language,
 			   cooked_index_storage *storage)
 {
-  /* If this compilation unit was already read in, free the
-     cached copy in order to read it in again.	This is
-     necessary because we skipped some symbols when we first
-     read in the compilation unit (see load_partial_dies).
-     This problem could be avoided, but the benefit is unclear.  */
-  if (!per_objfile->per_bfd->using_index)
-    per_objfile->remove_cu (this_cu);
-
   cutu_reader reader (this_cu, per_objfile, nullptr, nullptr, false,
-		      (storage == nullptr
-		       ? nullptr
-		       : storage->get_abbrev_cache ()));
+		      storage->get_abbrev_cache ());
 
   if (reader.comp_unit_die == nullptr)
     return;
@@ -7476,31 +6859,19 @@ process_psymtab_comp_unit (dwarf2_per_cu_data *this_cu,
     }
   else if (this_cu->is_debug_types)
     build_type_psymtabs_reader (&reader, storage);
-  else if (want_partial_unit
-	   || reader.comp_unit_die->tag != DW_TAG_partial_unit)
+  else if (reader.comp_unit_die->tag != DW_TAG_partial_unit)
     {
-      if (per_objfile->per_bfd->using_index)
+      bool nope = false;
+      if (this_cu->scanned.compare_exchange_strong (nope, true)
+	  && reader.comp_unit_die->has_children)
 	{
-	  bool nope = false;
-	  if (this_cu->scanned.compare_exchange_strong (nope, true)
-	      && reader.comp_unit_die->has_children)
-	    {
-	      prepare_one_comp_unit (reader.cu, reader.comp_unit_die,
-				     pretend_language);
-	      gdb_assert (storage != nullptr);
-	      cooked_indexer indexer (storage, this_cu,
-				      reader.cu->per_cu->lang);
-	      indexer.make_index (&reader);
-	    }
+	  prepare_one_comp_unit (reader.cu, reader.comp_unit_die,
+				 language_minimal);
+	  gdb_assert (storage != nullptr);
+	  cooked_indexer indexer (storage, this_cu, reader.cu->per_cu->lang);
+	  indexer.make_index (&reader);
 	}
-      else
-	process_psymtab_comp_unit_reader (&reader, reader.info_ptr,
-					  reader.comp_unit_die,
-					  pretend_language);
     }
-
-  /* Age out any secondary CUs.  */
-  per_objfile->age_comp_units ();
 }
 
 /* Reader function for build_type_psymtabs.  */
@@ -7509,52 +6880,20 @@ static void
 build_type_psymtabs_reader (cutu_reader *reader,
 			    cooked_index_storage *storage)
 {
-  dwarf2_per_objfile *per_objfile = reader->cu->per_objfile;
   struct dwarf2_cu *cu = reader->cu;
   struct dwarf2_per_cu_data *per_cu = cu->per_cu;
-  struct signatured_type *sig_type;
-  struct type_unit_group *tu_group;
-  struct attribute *attr;
-  struct partial_die_info *first_die;
-  CORE_ADDR lowpc, highpc;
-  dwarf2_psymtab *pst;
-  const gdb_byte *info_ptr = reader->info_ptr;
   struct die_info *type_unit_die = reader->comp_unit_die;
 
   gdb_assert (per_cu->is_debug_types);
-  sig_type = (struct signatured_type *) per_cu;
 
   if (! type_unit_die->has_children)
     return;
 
-  attr = type_unit_die->attr (DW_AT_stmt_list);
-  tu_group = get_type_unit_group (cu, attr);
-
-  if (tu_group->tus == nullptr)
-    tu_group->tus = new std::vector<signatured_type *>;
-  tu_group->tus->push_back (sig_type);
-
   prepare_one_comp_unit (cu, type_unit_die, language_minimal);
 
-  if (per_objfile->per_bfd->using_index)
-    {
-      gdb_assert (storage != nullptr);
-      cooked_indexer indexer (storage, per_cu, cu->per_cu->lang);
-      indexer.make_index (reader);
-    }
-  else
-    {
-      pst = create_partial_symtab (per_cu, per_objfile, "");
-      pst->anonymous = true;
-
-      first_die = load_partial_dies (reader, info_ptr, 1);
-
-      lowpc = (CORE_ADDR) -1;
-      highpc = (CORE_ADDR) 0;
-      scan_partial_symbols (first_die, &lowpc, &highpc, 0, cu);
-
-      pst->end ();
-    }
+  gdb_assert (storage != nullptr);
+  cooked_indexer indexer (storage, per_cu, cu->per_cu->lang);
+  indexer.make_index (reader);
 }
 
 /* Struct used to sort TUs by their abbreviation table offset.  */
@@ -7688,45 +7027,14 @@ print_tu_stats (dwarf2_per_objfile *per_objfile)
 			   tu_stats->nr_all_type_units_reallocs);
 }
 
-/* Traversal function for build_type_psymtabs.  */
-
-static int
-build_type_psymtab_dependencies (void **slot, void *info)
+struct skeleton_data
 {
-  dwarf2_per_objfile *per_objfile = (dwarf2_per_objfile *) info;
-  dwarf2_per_bfd *per_bfd = per_objfile->per_bfd;
-  struct type_unit_group *tu_group = (struct type_unit_group *) *slot;
-  dwarf2_psymtab *pst = tu_group->v.psymtab;
-  int len = (tu_group->tus == nullptr) ? 0 : tu_group->tus->size ();
-  int i;
+  dwarf2_per_objfile *per_objfile;
+  cooked_index_storage *storage;
+};
 
-  gdb_assert (len > 0);
-  gdb_assert (tu_group->type_unit_group_p ());
-
-  pst->number_of_dependencies = len;
-  pst->dependencies = per_bfd->partial_symtabs->allocate_dependencies (len);
-  for (i = 0; i < len; ++i)
-    {
-      struct signatured_type *iter = tu_group->tus->at (i);
-      gdb_assert (iter->is_debug_types);
-      pst->dependencies[i] = iter->v.psymtab;
-      iter->type_unit_group = tu_group;
-    }
-
-  delete tu_group->tus;
-  tu_group->tus = nullptr;
-
-  return 1;
-}
-
-struct skeleton_data
-{
-  dwarf2_per_objfile *per_objfile;
-  cooked_index_storage *storage;
-};
-
-/* Traversal function for process_skeletonless_type_unit.
-   Read a TU in a DWO file and build partial symbols for it.  */
+/* Traversal function for process_skeletonless_type_unit.
+   Read a TU in a DWO file and build partial symbols for it.  */
 
 static int
 process_skeletonless_type_unit (void **slot, void *info)
@@ -7797,27 +7105,6 @@ process_skeletonless_type_units (dwarf2_per_objfile *per_objfile,
     }
 }
 
-/* Compute the 'user' field for each psymtab in DWARF2_PER_OBJFILE.  */
-
-static void
-set_partial_user (dwarf2_per_objfile *per_objfile)
-{
-  for (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
-    {
-      dwarf2_psymtab *pst = per_cu->v.psymtab;
-
-      if (pst == NULL)
-	continue;
-
-      for (int j = 0; j < pst->number_of_dependencies; ++j)
-	{
-	  /* Set the 'user' field only if it is not already set.  */
-	  if (pst->dependencies[j]->user == NULL)
-	    pst->dependencies[j]->user = pst;
-	}
-    }
-}
-
 /* Build the partial symbol table by doing a quick pass through the
    .debug_info and .debug_abbrev sections.  */
 
@@ -7830,178 +7117,97 @@ dwarf2_build_psymtabs_hard (dwarf2_per_objfile *per_objfile)
   dwarf_read_debug_printf ("Building psymtabs of objfile %s ...",
 			   objfile_name (objfile));
 
-  scoped_restore restore_reading_psyms
-    = make_scoped_restore (&per_bfd->reading_partial_symbols, true);
-
   per_bfd->map_info_sections (objfile);
 
-  /* Any cached compilation units will be linked by the per-objfile
-     read_in_chain.  Make sure to free them when we're done.  */
-  free_cached_comp_units freer (per_objfile);
-
-  /* Create a temporary address map on a temporary obstack.  We later
-     copy this to the final obstack.  */
-  auto_obstack temp_obstack;
-
-  scoped_restore save_psymtabs_addrmap
-    = make_scoped_restore (&per_bfd->partial_symtabs->psymtabs_addrmap,
-			   addrmap_create_mutable (&temp_obstack));
-
   cooked_index_storage index_storage;
-  cooked_index_storage *index_storage_ptr
-    = per_bfd->using_index ? &index_storage : nullptr;
   create_all_comp_units (per_objfile);
-  build_type_psymtabs (per_objfile, index_storage_ptr);
+  build_type_psymtabs (per_objfile, &index_storage);
   std::vector<std::unique_ptr<cooked_index>> indexes;
-  if (per_bfd->using_index)
-    {
-      per_bfd->quick_file_names_table
-	= create_quick_file_names_table (per_bfd->all_comp_units.size ());
 
-      if (!per_bfd->debug_aranges.empty ())
-	read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges,
-				   index_storage.get_addrmap ());
+  per_bfd->quick_file_names_table
+    = create_quick_file_names_table (per_bfd->all_comp_units.size ());
+  if (!per_bfd->debug_aranges.empty ())
+    read_addrmap_from_aranges (per_objfile, &per_bfd->debug_aranges,
+			       index_storage.get_addrmap ());
 
+  {
+    /* Ensure that complaints are handled correctly.  */
+    complaint_interceptor complaint_handler;
+
+    using iter_type = typeof (per_bfd->all_comp_units.begin ());
+
+    /* Each thread returns a pair holding a cooked index, and a vector
+       of errors that should be printed.  The latter is done because
+       GDB's I/O system is not thread-safe.  run_on_main_thread could be
+       used, but that would mean the messages are printed after the
+       prompt, which looks weird.  */
+    using result_type = std::pair<std::unique_ptr<cooked_index>,
+				  std::vector<gdb_exception>>;
+    std::vector<result_type> results
+      = gdb::parallel_for_each (1, per_bfd->all_comp_units.begin (),
+				per_bfd->all_comp_units.end (),
+				[=] (iter_type iter, iter_type end)
       {
-	/* Ensure that complaints are handled correctly.  */
-	complaint_interceptor complaint_handler;
-
-	using iter_type = typeof (per_bfd->all_comp_units.begin ());
-
-	/* Each thread returns a pair holding a cooked index, and a vector
-	   of errors that should be printed.  The latter is done because
-	   GDB's I/O system is not thread-safe.  run_on_main_thread could be
-	   used, but that would mean the messages are printed after the
-	   prompt, which looks weird.  */
-	using result_type = std::pair<std::unique_ptr<cooked_index>,
-				      std::vector<gdb_exception>>;
-	std::vector<result_type> results
-	  = gdb::parallel_for_each (1, per_bfd->all_comp_units.begin (),
-				    per_bfd->all_comp_units.end (),
-				    [=] (iter_type iter, iter_type end)
-				    {
-				      std::vector<gdb_exception> errors;
-				      cooked_index_storage thread_storage;
-				      for (; iter != end; ++iter)
-					{
-					  dwarf2_per_cu_data *per_cu = iter->get ();
-					  try
-					    {
-					      process_psymtab_comp_unit (per_cu, per_objfile,
-									 false,
-									 language_minimal,
-									 &thread_storage);
-					    }
-					  catch (gdb_exception &except)
-					    {
-					      errors.push_back (std::move (except));
-					    }
-					}
-				      return result_type (thread_storage.release (),
-							  std::move (errors));
-				    });
-
-	/* Only show a given exception a single time.  */
-	std::unordered_set<gdb_exception> seen_exceptions;
-	for (auto &one_result : results)
+	std::vector<gdb_exception> errors;
+	cooked_index_storage thread_storage;
+	for (; iter != end; ++iter)
 	  {
-	    indexes.push_back (std::move (one_result.first));
-	    for (auto &one_exc : one_result.second)
+	    dwarf2_per_cu_data *per_cu = iter->get ();
+	    try
+	      {
+		process_psymtab_comp_unit (per_cu, per_objfile,
+					   &thread_storage);
+	      }
+	    catch (gdb_exception &except)
 	      {
-		if (seen_exceptions.insert (one_exc).second)
-		  exception_print (gdb_stderr, one_exc);
+		errors.push_back (std::move (except));
 	      }
 	  }
+	return result_type (thread_storage.release (), std::move (errors));
+      });
+
+    /* Only show a given exception a single time.  */
+    std::unordered_set<gdb_exception> seen_exceptions;
+    for (auto &one_result : results)
+      {
+	indexes.push_back (std::move (one_result.first));
+	for (auto &one_exc : one_result.second)
+	  if (seen_exceptions.insert (one_exc).second)
+	    exception_print (gdb_stderr, one_exc);
       }
-    }
-  else
-    {
-      for (const auto &per_cu : per_bfd->all_comp_units)
-	{
-	  if (!per_bfd->using_index && per_cu->v.psymtab != NULL)
-	    /* In case a forward DW_TAG_imported_unit has read the CU
-	       already.  */
-	    continue;
-	  process_psymtab_comp_unit (per_cu.get (), per_objfile, false,
-				     language_minimal, nullptr);
-	}
-    }
+  }
 
   /* This has to wait until we read the CUs, we need the list of DWOs.  */
   process_skeletonless_type_units (per_objfile, &index_storage);
 
-  /* Now that all TUs have been processed we can fill in the dependencies.  */
-  if (!per_bfd->using_index && per_bfd->type_unit_groups != NULL)
-    {
-      htab_traverse_noresize (per_bfd->type_unit_groups.get (),
-			      build_type_psymtab_dependencies, per_objfile);
-    }
-
   if (dwarf_read_debug > 0)
     print_tu_stats (per_objfile);
 
-  if (per_bfd->using_index)
-    {
-      indexes.push_back (index_storage.release ());
-      /* Remove any NULL entries.  This might happen if parallel-for
-	 decides to throttle the number of threads that were used.  */
-      indexes.erase
-	(std::remove_if (indexes.begin (),
-			 indexes.end (),
-			 [] (const std::unique_ptr<cooked_index> &entry)
-			 {
-			   return entry == nullptr;
-			 }),
-	 indexes.end ());
-      indexes.shrink_to_fit ();
-      per_bfd->cooked_index_table.reset
-	(new cooked_index_vector (std::move (indexes)));
-
-      const cooked_index_entry *main_entry
-	= per_bfd->cooked_index_table->get_main ();
-      if (main_entry != nullptr)
-	set_objfile_main_name (objfile, main_entry->name,
-			       main_entry->per_cu->lang);
-    }
-  else
-    {
-      set_partial_user (per_objfile);
+  indexes.push_back (index_storage.release ());
+  /* Remove any NULL entries.  This might happen if parallel-for
+     decides to throttle the number of threads that were used.  */
+  indexes.erase
+    (std::remove_if (indexes.begin (),
+		     indexes.end (),
+		     [] (const std::unique_ptr<cooked_index> &entry)
+		     {
+		       return entry == nullptr;
+		     }),
+     indexes.end ());
+  indexes.shrink_to_fit ();
+  per_bfd->cooked_index_table.reset
+    (new cooked_index_vector (std::move (indexes)));
+
+  const cooked_index_entry *main_entry
+    = per_bfd->cooked_index_table->get_main ();
+  if (main_entry != nullptr)
+    set_objfile_main_name (objfile, main_entry->name,
+			   main_entry->per_cu->lang);
 
-      per_bfd->partial_symtabs->psymtabs_addrmap
-	= addrmap_create_fixed (per_bfd->partial_symtabs->psymtabs_addrmap,
-				per_bfd->partial_symtabs->obstack ());
-      /* At this point we want to keep the address map.  */
-      save_psymtabs_addrmap.release ();
-    }
   dwarf_read_debug_printf ("Done building psymtabs of %s",
 			   objfile_name (objfile));
 }
 
-/* Load the partial DIEs for a secondary CU into memory.
-   This is also used when rereading a primary CU with load_all_dies.  */
-
-static void
-load_partial_comp_unit (dwarf2_per_cu_data *this_cu,
-			dwarf2_per_objfile *per_objfile,
-			dwarf2_cu *existing_cu)
-{
-  cutu_reader reader (this_cu, per_objfile, nullptr, existing_cu, false);
-
-  if (!reader.dummy_p)
-    {
-      prepare_one_comp_unit (reader.cu, reader.comp_unit_die,
-			     language_minimal);
-
-      /* Check if comp unit has_children.
-	 If so, read the rest of the partial symbols from this comp unit.
-	 If not, there's no more debug_info for this comp unit.  */
-      if (reader.comp_unit_die->has_children)
-	load_partial_dies (&reader, reader.info_ptr, 0);
-
-      reader.keep ();
-    }
-}
-
 static void
 read_comp_units_from_section (dwarf2_per_objfile *per_objfile,
 			      struct dwarf2_section_info *section,
@@ -8061,9 +7267,8 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile,
       this_cu->is_dwz = is_dwz;
       this_cu->section = section;
 
-      if (per_objfile->per_bfd->using_index)
-	this_cu->v.quick = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
-					   struct dwarf2_per_cu_quick_data);
+      this_cu->v.quick = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
+					 struct dwarf2_per_cu_quick_data);
 
       info_ptr = info_ptr + this_cu->length;
       per_objfile->per_bfd->all_comp_units.push_back (std::move (this_cu));
@@ -8094,742 +7299,120 @@ create_all_comp_units (dwarf2_per_objfile *per_objfile)
   per_objfile->per_bfd->signatured_types = std::move (types_htab);
 }
 
-/* Process all loaded DIEs for compilation unit CU, starting at
-   FIRST_DIE.  The caller should pass SET_ADDRMAP == 1 if the compilation
-   unit DIE did not have PC info (DW_AT_low_pc and DW_AT_high_pc, or
-   DW_AT_ranges).  See the comments of add_partial_subprogram on how
-   SET_ADDRMAP is used and how *LOWPC and *HIGHPC are updated.  */
+/* Return the initial uleb128 in the die at INFO_PTR.  */
 
-static void
-scan_partial_symbols (struct partial_die_info *first_die, CORE_ADDR *lowpc,
-		      CORE_ADDR *highpc, int set_addrmap,
-		      struct dwarf2_cu *cu)
+static unsigned int
+peek_abbrev_code (bfd *abfd, const gdb_byte *info_ptr)
 {
-  struct partial_die_info *pdi;
-
-  /* Now, march along the PDI's, descending into ones which have
-     interesting children but skipping the children of the other ones,
-     until we reach the end of the compilation unit.  */
-
-  pdi = first_die;
-
-  while (pdi != NULL)
-    {
-      pdi->fixup (cu);
-
-      /* Anonymous namespaces or modules have no name but have interesting
-	 children, so we need to look at them.  Ditto for anonymous
-	 enums.  */
-
-      if (pdi->raw_name != NULL || pdi->tag == DW_TAG_namespace
-	  || pdi->tag == DW_TAG_module || pdi->tag == DW_TAG_enumeration_type
-	  || pdi->tag == DW_TAG_imported_unit
-	  || pdi->tag == DW_TAG_inlined_subroutine)
-	{
-	  switch (pdi->tag)
-	    {
-	    case DW_TAG_subprogram:
-	    case DW_TAG_inlined_subroutine:
-	      add_partial_subprogram (pdi, lowpc, highpc, set_addrmap, cu);
-	      if (cu->per_cu->lang == language_cplus)
-		scan_partial_symbols (pdi->die_child, lowpc, highpc,
-				      set_addrmap, cu);
-	      break;
-	    case DW_TAG_constant:
-	    case DW_TAG_variable:
-	    case DW_TAG_typedef:
-	    case DW_TAG_union_type:
-	      if (!pdi->is_declaration
-		  || (pdi->tag == DW_TAG_variable && pdi->is_external))
-		{
-		  add_partial_symbol (pdi, cu);
-		}
-	      break;
-	    case DW_TAG_class_type:
-	    case DW_TAG_interface_type:
-	    case DW_TAG_structure_type:
-	      if (!pdi->is_declaration)
-		{
-		  add_partial_symbol (pdi, cu);
-		}
-	      if ((cu->per_cu->lang == language_rust
-		   || cu->per_cu->lang == language_cplus)
-		  && pdi->has_children)
-		scan_partial_symbols (pdi->die_child, lowpc, highpc,
-				      set_addrmap, cu);
-	      break;
-	    case DW_TAG_enumeration_type:
-	      if (!pdi->is_declaration)
-		add_partial_enumeration (pdi, cu);
-	      break;
-	    case DW_TAG_base_type:
-	    case DW_TAG_subrange_type:
-	      /* File scope base type definitions are added to the partial
-		 symbol table.  */
-	      add_partial_symbol (pdi, cu);
-	      break;
-	    case DW_TAG_namespace:
-	      add_partial_namespace (pdi, lowpc, highpc, set_addrmap, cu);
-	      break;
-	    case DW_TAG_module:
-	      if (!pdi->is_declaration)
-		add_partial_module (pdi, lowpc, highpc, set_addrmap, cu);
-	      break;
-	    case DW_TAG_imported_unit:
-	      {
-		struct dwarf2_per_cu_data *per_cu;
-
-		/* For now we don't handle imported units in type units.  */
-		if (cu->per_cu->is_debug_types)
-		  {
-		    error (_("Dwarf Error: DW_TAG_imported_unit is not"
-			     " supported in type units [in module %s]"),
-			   objfile_name (cu->per_objfile->objfile));
-		  }
-
-		per_cu = dwarf2_find_containing_comp_unit
-			   (pdi->d.sect_off, pdi->is_dwz, cu->per_objfile);
-
-		/* Go read the partial unit, if needed.  */
-		if (per_cu->v.psymtab == NULL)
-		  process_psymtab_comp_unit (per_cu, cu->per_objfile, true,
-					     cu->per_cu->lang, nullptr);
-
-		if (pdi->die_parent == nullptr
-		    && per_cu->unit_type == DW_UT_compile
-		    && per_cu->lang == language_cplus)
-		  /* Regard import as hint.  See corresponding code in
-		     process_imported_unit_die.  */
-		  break;
-
-		cu->per_cu->imported_symtabs_push (per_cu);
-	      }
-	      break;
-	    case DW_TAG_imported_declaration:
-	      add_partial_symbol (pdi, cu);
-	      break;
-	    default:
-	      break;
-	    }
-	}
-
-      /* If the die has a sibling, skip to the sibling.  */
+  unsigned int bytes_read;
 
-      pdi = pdi->die_sibling;
-    }
+  return read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
 }
 
-/* Functions used to compute the fully scoped name of a partial DIE.
-
-   Normally, this is simple.  For C++, the parent DIE's fully scoped
-   name is concatenated with "::" and the partial DIE's name.
-   Enumerators are an exception; they use the scope of their parent
-   enumeration type, i.e. the name of the enumeration type is not
-   prepended to the enumerator.
+/* Read the initial uleb128 in the die at INFO_PTR in compilation unit
+   READER::CU.  Use READER::ABBREV_TABLE to lookup any abbreviation.
 
-   There are two complexities.  One is DW_AT_specification; in this
-   case "parent" means the parent of the target of the specification,
-   instead of the direct parent of the DIE.  The other is compilers
-   which do not emit DW_TAG_namespace; in this case we try to guess
-   the fully qualified name of structure types from their members'
-   linkage names.  This must be done using the DIE's children rather
-   than the children of any DW_AT_specification target.  We only need
-   to do this for structures at the top level, i.e. if the target of
-   any DW_AT_specification (if any; otherwise the DIE itself) does not
-   have a parent.  */
+   Return the corresponding abbrev, or NULL if the number is zero (indicating
+   an empty DIE).  In either case *BYTES_READ will be set to the length of
+   the initial number.  */
 
-/* Compute the scope prefix associated with PDI's parent, in
-   compilation unit CU.  The result will be allocated on CU's
-   comp_unit_obstack, or a copy of the already allocated PDI->NAME
-   field.  NULL is returned if no prefix is necessary.  */
-static const char *
-partial_die_parent_scope (struct partial_die_info *pdi,
-			  struct dwarf2_cu *cu)
+static const struct abbrev_info *
+peek_die_abbrev (const die_reader_specs &reader,
+		 const gdb_byte *info_ptr, unsigned int *bytes_read)
 {
-  const char *grandparent_scope;
-  struct partial_die_info *parent, *real_pdi;
+  dwarf2_cu *cu = reader.cu;
+  bfd *abfd = reader.abfd;
+  unsigned int abbrev_number
+    = read_unsigned_leb128 (abfd, info_ptr, bytes_read);
 
-  /* We need to look at our parent DIE; if we have a DW_AT_specification,
-     then this means the parent of the specification DIE.  */
+  if (abbrev_number == 0)
+    return NULL;
 
-  real_pdi = pdi;
-  while (real_pdi->has_specification)
+  const abbrev_info *abbrev
+    = reader.abbrev_table->lookup_abbrev (abbrev_number);
+  if (!abbrev)
     {
-      auto res = find_partial_die (real_pdi->spec_offset,
-				   real_pdi->spec_is_dwz, cu);
-      real_pdi = res.pdi;
-      cu = res.cu;
+      error (_("Dwarf Error: Could not find abbrev number %d in %s"
+	       " at offset %s [in module %s]"),
+	     abbrev_number, cu->per_cu->is_debug_types ? "TU" : "CU",
+	     sect_offset_str (cu->header.sect_off), bfd_get_filename (abfd));
     }
 
-  parent = real_pdi->die_parent;
-  if (parent == NULL)
-    return NULL;
-
-  if (parent->scope_set)
-    return parent->scope;
-
-  parent->fixup (cu);
+  return abbrev;
+}
 
-  grandparent_scope = partial_die_parent_scope (parent, cu);
+/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER.
+   Returns a pointer to the end of a series of DIEs, terminated by an empty
+   DIE.  Any children of the skipped DIEs will also be skipped.  */
 
-  /* GCC 4.0 and 4.1 had a bug (PR c++/28460) where they generated bogus
-     DW_TAG_namespace DIEs with a name of "::" for the global namespace.
-     Work around this problem here.  */
-  if (cu->per_cu->lang == language_cplus
-      && parent->tag == DW_TAG_namespace
-      && strcmp (parent->name (cu), "::") == 0
-      && grandparent_scope == NULL)
+static const gdb_byte *
+skip_children (const struct die_reader_specs *reader, const gdb_byte *info_ptr)
+{
+  while (1)
     {
-      parent->scope = NULL;
-      parent->scope_set = 1;
-      return NULL;
-    }
+      unsigned int bytes_read;
+      const abbrev_info *abbrev = peek_die_abbrev (*reader, info_ptr,
+						   &bytes_read);
 
-  /* Nested subroutines in Fortran get a prefix.  */
-  if (pdi->tag == DW_TAG_enumerator)
-    /* Enumerators should not get the name of the enumeration as a prefix.  */
-    parent->scope = grandparent_scope;
-  else if (parent->tag == DW_TAG_namespace
-      || parent->tag == DW_TAG_module
-      || parent->tag == DW_TAG_structure_type
-      || parent->tag == DW_TAG_class_type
-      || parent->tag == DW_TAG_interface_type
-      || parent->tag == DW_TAG_union_type
-      || parent->tag == DW_TAG_enumeration_type
-      || (cu->per_cu->lang == language_fortran
-	  && parent->tag == DW_TAG_subprogram
-	  && pdi->tag == DW_TAG_subprogram))
-    {
-      if (grandparent_scope == NULL)
-	parent->scope = parent->name (cu);
+      if (abbrev == NULL)
+	return info_ptr + bytes_read;
       else
-	parent->scope = typename_concat (&cu->comp_unit_obstack,
-					 grandparent_scope,
-					 parent->name (cu), 0, cu);
-    }
-  else
-    {
-      /* FIXME drow/2004-04-01: What should we be doing with
-	 function-local names?  For partial symbols, we should probably be
-	 ignoring them.  */
-      complaint (_("unhandled containing DIE tag %s for DIE at %s"),
-		 dwarf_tag_name (parent->tag),
-		 sect_offset_str (pdi->sect_off));
-      parent->scope = grandparent_scope;
+	info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev);
     }
-
-  parent->scope_set = 1;
-  return parent->scope;
 }
 
-/* Return the fully scoped name associated with PDI, from compilation unit
-   CU.  The result will be allocated with malloc.  */
+/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER.
+   INFO_PTR should point just after the initial uleb128 of a DIE, and the
+   abbrev corresponding to that skipped uleb128 should be passed in
+   ABBREV.
+   
+   If DO_SKIP_CHILDREN is true, or if the DIE has no children, this
+   returns a pointer to this DIE's sibling, skipping any children.
+   Otherwise, returns a pointer to the DIE's first child.  */
 
-static gdb::unique_xmalloc_ptr<char>
-partial_die_full_name (struct partial_die_info *pdi,
-		       struct dwarf2_cu *cu)
+static const gdb_byte *
+skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
+	      const struct abbrev_info *abbrev, bool do_skip_children)
 {
-  const char *parent_scope;
+  unsigned int bytes_read;
+  struct attribute attr;
+  bfd *abfd = reader->abfd;
+  struct dwarf2_cu *cu = reader->cu;
+  const gdb_byte *buffer = reader->buffer;
+  const gdb_byte *buffer_end = reader->buffer_end;
+  unsigned int form, i;
 
-  /* If this is a template instantiation, we can not work out the
-     template arguments from partial DIEs.  So, unfortunately, we have
-     to go through the full DIEs.  At least any work we do building
-     types here will be reused if full symbols are loaded later.  */
-  if (pdi->has_template_arguments)
+  if (do_skip_children && abbrev->sibling_offset != (unsigned short) -1)
     {
-      pdi->fixup (cu);
-
-      if (pdi->name (cu) != NULL && strchr (pdi->name (cu), '<') == NULL)
-	{
-	  struct die_info *die;
-	  struct attribute attr;
-	  struct dwarf2_cu *ref_cu = cu;
-
-	  /* DW_FORM_ref_addr is using section offset.  */
-	  attr.name = (enum dwarf_attribute) 0;
-	  attr.form = DW_FORM_ref_addr;
-	  attr.u.unsnd = to_underlying (pdi->sect_off);
-	  die = follow_die_ref (NULL, &attr, &ref_cu);
-
-	  return make_unique_xstrdup (dwarf2_full_name (NULL, die, ref_cu));
-	}
+      /* We only handle DW_FORM_ref4 here.  */
+      const gdb_byte *sibling_data = info_ptr + abbrev->sibling_offset;
+      unsigned int offset = read_4_bytes (abfd, sibling_data);
+      const gdb_byte *sibling_ptr
+	= buffer + to_underlying (cu->header.sect_off) + offset;
+      if (sibling_ptr >= info_ptr && sibling_ptr < reader->buffer_end)
+	return sibling_ptr;
+      /* Fall through to the slow way.  */
     }
-
-  parent_scope = partial_die_parent_scope (pdi, cu);
-  if (parent_scope == NULL)
-    return NULL;
-  else
-    return gdb::unique_xmalloc_ptr<char> (typename_concat (NULL, parent_scope,
-							   pdi->name (cu),
-							   0, cu));
-}
-
-static void
-add_partial_symbol (struct partial_die_info *pdi, struct dwarf2_cu *cu)
-{
-  dwarf2_per_objfile *per_objfile = cu->per_objfile;
-  struct objfile *objfile = per_objfile->objfile;
-  struct gdbarch *gdbarch = objfile->arch ();
-  CORE_ADDR addr = 0;
-  const char *actual_name = NULL;
-  CORE_ADDR baseaddr;
-
-  baseaddr = objfile->text_section_offset ();
-
-  gdb::unique_xmalloc_ptr<char> built_actual_name
-    = partial_die_full_name (pdi, cu);
-  if (built_actual_name != NULL)
-    actual_name = built_actual_name.get ();
-
-  if (actual_name == NULL)
-    actual_name = pdi->name (cu);
-
-  partial_symbol psymbol;
-  memset (&psymbol, 0, sizeof (psymbol));
-  psymbol.ginfo.set_language (cu->per_cu->lang,
-			      &objfile->objfile_obstack);
-  psymbol.ginfo.set_section_index (-1);
-
-  /* The code below indicates that the psymbol should be installed by
-     setting this.  */
-  gdb::optional<psymbol_placement> where;
-
-  switch (pdi->tag)
+  else if (abbrev->size_if_constant != 0)
     {
-    case DW_TAG_inlined_subroutine:
-    case DW_TAG_subprogram:
-      addr = (gdbarch_adjust_dwarf2_addr (gdbarch, pdi->lowpc + baseaddr)
-	      - baseaddr);
-      if (pdi->is_external
-	  || cu->per_cu->lang == language_ada
-	  || (cu->per_cu->lang == language_fortran
-	      && pdi->die_parent != NULL
-	      && pdi->die_parent->tag == DW_TAG_subprogram))
-	{
-	  /* Normally, only "external" DIEs are part of the global scope.
-	     But in Ada and Fortran, we want to be able to access nested
-	     procedures globally.  So all Ada and Fortran subprograms are
-	     stored in the global scope.  */
-	  where = psymbol_placement::GLOBAL;
-	}
-      else
-	where = psymbol_placement::STATIC;
-
-      psymbol.domain = VAR_DOMAIN;
-      psymbol.aclass = LOC_BLOCK;
-      psymbol.ginfo.set_section_index (SECT_OFF_TEXT (objfile));
-      psymbol.ginfo.value.address = addr;
-
-      if (pdi->main_subprogram && actual_name != NULL)
-	set_objfile_main_name (objfile, actual_name, cu->per_cu->lang);
-      break;
-    case DW_TAG_constant:
-      psymbol.domain = VAR_DOMAIN;
-      psymbol.aclass = LOC_STATIC;
-      where = (pdi->is_external
-	       ? psymbol_placement::GLOBAL
-	       : psymbol_placement::STATIC);
-      break;
-    case DW_TAG_variable:
-      if (pdi->d.locdesc)
-	addr = decode_locdesc (pdi->d.locdesc, cu);
+      info_ptr += abbrev->size_if_constant;
+      if (do_skip_children && abbrev->has_children)
+	return skip_children (reader, info_ptr);
+      return info_ptr;
+    }
 
-      if (pdi->d.locdesc
-	  && addr == 0
-	  && !per_objfile->per_bfd->has_section_at_zero)
+  for (i = 0; i < abbrev->num_attrs; i++)
+    {
+      /* The only abbrev we care about is DW_AT_sibling.  */
+      if (do_skip_children && abbrev->attrs[i].name == DW_AT_sibling)
 	{
-	  /* A global or static variable may also have been stripped
-	     out by the linker if unused, in which case its address
-	     will be nullified; do not add such variables into partial
-	     symbol table then.  */
-	}
-      else if (pdi->is_external)
-	{
-	  /* Global Variable.
-	     Don't enter into the minimal symbol tables as there is
-	     a minimal symbol table entry from the ELF symbols already.
-	     Enter into partial symbol table if it has a location
-	     descriptor or a type.
-	     If the location descriptor is missing, new_symbol will create
-	     a LOC_UNRESOLVED symbol, the address of the variable will then
-	     be determined from the minimal symbol table whenever the variable
-	     is referenced.
-	     The address for the partial symbol table entry is not
-	     used by GDB, but it comes in handy for debugging partial symbol
-	     table building.  */
-
-	  if (pdi->d.locdesc || pdi->has_type)
+	  read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
+	  if (attr.form == DW_FORM_ref_addr)
+	    complaint (_("ignoring absolute DW_AT_sibling"));
+	  else
 	    {
-	      psymbol.domain = VAR_DOMAIN;
-	      psymbol.aclass = LOC_STATIC;
-	      psymbol.ginfo.set_section_index (SECT_OFF_TEXT (objfile));
-	      psymbol.ginfo.value.address = addr;
-	      where = psymbol_placement::GLOBAL;
-	    }
-	}
-      else
-	{
-	  int has_loc = pdi->d.locdesc != NULL;
-
-	  /* Static Variable.  Skip symbols whose value we cannot know (those
-	     without location descriptors or constant values).  */
-	  if (!has_loc && !pdi->has_const_value)
-	    return;
-
-	  psymbol.domain = VAR_DOMAIN;
-	  psymbol.aclass = LOC_STATIC;
-	  psymbol.ginfo.set_section_index (SECT_OFF_TEXT (objfile));
-	  if (has_loc)
-	    psymbol.ginfo.value.address = addr;
-	  where = psymbol_placement::STATIC;
-	}
-      break;
-    case DW_TAG_array_type:
-    case DW_TAG_typedef:
-    case DW_TAG_base_type:
-    case DW_TAG_subrange_type:
-      psymbol.domain = VAR_DOMAIN;
-      psymbol.aclass = LOC_TYPEDEF;
-      where = psymbol_placement::STATIC;
-      break;
-    case DW_TAG_imported_declaration:
-    case DW_TAG_namespace:
-      psymbol.domain = VAR_DOMAIN;
-      psymbol.aclass = LOC_TYPEDEF;
-      where = psymbol_placement::GLOBAL;
-      break;
-    case DW_TAG_module:
-      /* With Fortran 77 there might be a "BLOCK DATA" module
-	 available without any name.  If so, we skip the module as it
-	 doesn't bring any value.  */
-      if (actual_name != nullptr)
-	{
-	  psymbol.domain = MODULE_DOMAIN;
-	  psymbol.aclass = LOC_TYPEDEF;
-	  where = psymbol_placement::GLOBAL;
-	}
-      break;
-    case DW_TAG_class_type:
-    case DW_TAG_interface_type:
-    case DW_TAG_structure_type:
-    case DW_TAG_union_type:
-    case DW_TAG_enumeration_type:
-      /* Skip external references.  The DWARF standard says in the section
-	 about "Structure, Union, and Class Type Entries": "An incomplete
-	 structure, union or class type is represented by a structure,
-	 union or class entry that does not have a byte size attribute
-	 and that has a DW_AT_declaration attribute."  */
-      if (!pdi->has_byte_size && pdi->is_declaration)
-	return;
-
-      /* NOTE: carlton/2003-10-07: See comment in new_symbol about
-	 static vs. global.  */
-      psymbol.domain = STRUCT_DOMAIN;
-      psymbol.aclass = LOC_TYPEDEF;
-      where = (cu->per_cu->lang == language_cplus
-	       ? psymbol_placement::GLOBAL
-	       : psymbol_placement::STATIC);
-      break;
-    case DW_TAG_enumerator:
-      psymbol.domain = VAR_DOMAIN;
-      psymbol.aclass = LOC_CONST;
-      where = (cu->per_cu->lang == language_cplus
-	       ? psymbol_placement::GLOBAL
-	       : psymbol_placement::STATIC);
-      break;
-    default:
-      break;
-    }
-
-  if (where.has_value ())
-    {
-      if (built_actual_name != nullptr)
-	actual_name = objfile->intern (actual_name);
-      if (pdi->linkage_name == nullptr
-	  || cu->per_cu->lang == language_ada)
-	psymbol.ginfo.set_linkage_name (actual_name);
-      else
-	{
-	  psymbol.ginfo.set_demangled_name (actual_name,
-					    &objfile->objfile_obstack);
-	  psymbol.ginfo.set_linkage_name (pdi->linkage_name);
-	}
-      cu->per_cu->v.psymtab->add_psymbol
-	(psymbol, *where, per_objfile->per_bfd->partial_symtabs.get (),
-	 objfile);
-    }
-}
-
-/* Read a partial die corresponding to a namespace; also, add a symbol
-   corresponding to that namespace to the symbol table.  NAMESPACE is
-   the name of the enclosing namespace.  */
-
-static void
-add_partial_namespace (struct partial_die_info *pdi,
-		       CORE_ADDR *lowpc, CORE_ADDR *highpc,
-		       int set_addrmap, struct dwarf2_cu *cu)
-{
-  /* Add a symbol for the namespace.  */
-
-  add_partial_symbol (pdi, cu);
-
-  /* Now scan partial symbols in that namespace.  */
-
-  if (pdi->has_children)
-    scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu);
-}
-
-/* Read a partial die corresponding to a Fortran module.  */
-
-static void
-add_partial_module (struct partial_die_info *pdi, CORE_ADDR *lowpc,
-		    CORE_ADDR *highpc, int set_addrmap, struct dwarf2_cu *cu)
-{
-  /* Add a symbol for the namespace.  */
-
-  add_partial_symbol (pdi, cu);
-
-  /* Now scan partial symbols in that module.  */
-
-  if (pdi->has_children)
-    scan_partial_symbols (pdi->die_child, lowpc, highpc, set_addrmap, cu);
-}
-
-static int dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
-			       CORE_ADDR *high_return, struct dwarf2_cu *cu,
-			       addrmap *map, void *datum, dwarf_tag tag);
-
-/* Read a partial die corresponding to a subprogram or an inlined
-   subprogram and create a partial symbol for that subprogram.
-   When the CU language allows it, this routine also defines a partial
-   symbol for each nested subprogram that this subprogram contains.
-   If SET_ADDRMAP is true, record the covered ranges in the addrmap.
-   Set *LOWPC and *HIGHPC to the lowest and highest PC values found in PDI.
-
-   PDI may also be a lexical block, in which case we simply search
-   recursively for subprograms defined inside that lexical block.
-   Again, this is only performed when the CU language allows this
-   type of definitions.  */
-
-static void
-add_partial_subprogram (struct partial_die_info *pdi,
-			CORE_ADDR *lowpc, CORE_ADDR *highpc,
-			int set_addrmap, struct dwarf2_cu *cu)
-{
-  if (pdi->tag == DW_TAG_subprogram || pdi->tag == DW_TAG_inlined_subroutine)
-    {
-      if (pdi->has_pc_info)
-	{
-	  if (pdi->lowpc < *lowpc)
-	    *lowpc = pdi->lowpc;
-	  if (pdi->highpc > *highpc)
-	    *highpc = pdi->highpc;
-	  if (set_addrmap)
-	    {
-	      struct objfile *objfile = cu->per_objfile->objfile;
-	      dwarf2_per_bfd *per_bfd = cu->per_objfile->per_bfd;
-	      struct gdbarch *gdbarch = objfile->arch ();
-	      CORE_ADDR baseaddr;
-	      CORE_ADDR this_highpc;
-	      CORE_ADDR this_lowpc;
-
-	      baseaddr = objfile->text_section_offset ();
-	      this_lowpc
-		= (gdbarch_adjust_dwarf2_addr (gdbarch,
-					       pdi->lowpc + baseaddr)
-		   - baseaddr);
-	      this_highpc
-		= (gdbarch_adjust_dwarf2_addr (gdbarch,
-					       pdi->highpc + baseaddr)
-		   - baseaddr);
-	      addrmap_set_empty (per_bfd->partial_symtabs->psymtabs_addrmap,
-				 this_lowpc, this_highpc - 1,
-				 cu->per_cu->v.psymtab);
-	    }
-	}
-
-      if (pdi->has_range_info
-	  && dwarf2_ranges_read (pdi->ranges_offset, &pdi->lowpc, &pdi->highpc,
-				 cu,
-				 (set_addrmap
-				  ? cu->per_objfile->per_bfd->partial_symtabs->psymtabs_addrmap
-				  : nullptr),
-				 set_addrmap ? cu->per_cu->v.psymtab : nullptr,
-				 pdi->tag))
-	{
-	  if (pdi->lowpc < *lowpc)
-	    *lowpc = pdi->lowpc;
-	  if (pdi->highpc > *highpc)
-	    *highpc = pdi->highpc;
-	}
-
-      if (pdi->has_pc_info || pdi->has_range_info
-	  || (!pdi->is_external && pdi->may_be_inlined))
-	{
-	  if (!pdi->is_declaration)
-	    /* Ignore subprogram DIEs that do not have a name, they are
-	       illegal.  Do not emit a complaint at this point, we will
-	       do so when we convert this psymtab into a symtab.  */
-	    if (pdi->name (cu))
-	      add_partial_symbol (pdi, cu);
-	}
-    }
-
-  if (! pdi->has_children)
-    return;
-
-  if (cu->per_cu->lang == language_ada
-      || cu->per_cu->lang == language_fortran)
-    {
-      pdi = pdi->die_child;
-      while (pdi != NULL)
-	{
-	  pdi->fixup (cu);
-	  if (pdi->tag == DW_TAG_subprogram
-	      || pdi->tag == DW_TAG_inlined_subroutine
-	      || pdi->tag == DW_TAG_lexical_block)
-	    add_partial_subprogram (pdi, lowpc, highpc, set_addrmap, cu);
-	  pdi = pdi->die_sibling;
-	}
-    }
-}
-
-/* Read a partial die corresponding to an enumeration type.  */
-
-static void
-add_partial_enumeration (struct partial_die_info *enum_pdi,
-			 struct dwarf2_cu *cu)
-{
-  struct partial_die_info *pdi;
-
-  if (enum_pdi->name (cu) != NULL)
-    add_partial_symbol (enum_pdi, cu);
-
-  pdi = enum_pdi->die_child;
-  while (pdi)
-    {
-      if (pdi->tag != DW_TAG_enumerator || pdi->raw_name == NULL)
-	complaint (_("malformed enumerator DIE ignored"));
-      else
-	add_partial_symbol (pdi, cu);
-      pdi = pdi->die_sibling;
-    }
-}
-
-/* Return the initial uleb128 in the die at INFO_PTR.  */
-
-static unsigned int
-peek_abbrev_code (bfd *abfd, const gdb_byte *info_ptr)
-{
-  unsigned int bytes_read;
-
-  return read_unsigned_leb128 (abfd, info_ptr, &bytes_read);
-}
-
-/* Read the initial uleb128 in the die at INFO_PTR in compilation unit
-   READER::CU.  Use READER::ABBREV_TABLE to lookup any abbreviation.
-
-   Return the corresponding abbrev, or NULL if the number is zero (indicating
-   an empty DIE).  In either case *BYTES_READ will be set to the length of
-   the initial number.  */
-
-static const struct abbrev_info *
-peek_die_abbrev (const die_reader_specs &reader,
-		 const gdb_byte *info_ptr, unsigned int *bytes_read)
-{
-  dwarf2_cu *cu = reader.cu;
-  bfd *abfd = reader.abfd;
-  unsigned int abbrev_number
-    = read_unsigned_leb128 (abfd, info_ptr, bytes_read);
-
-  if (abbrev_number == 0)
-    return NULL;
-
-  const abbrev_info *abbrev
-    = reader.abbrev_table->lookup_abbrev (abbrev_number);
-  if (!abbrev)
-    {
-      error (_("Dwarf Error: Could not find abbrev number %d in %s"
-	       " at offset %s [in module %s]"),
-	     abbrev_number, cu->per_cu->is_debug_types ? "TU" : "CU",
-	     sect_offset_str (cu->header.sect_off), bfd_get_filename (abfd));
-    }
-
-  return abbrev;
-}
-
-/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER.
-   Returns a pointer to the end of a series of DIEs, terminated by an empty
-   DIE.  Any children of the skipped DIEs will also be skipped.  */
-
-static const gdb_byte *
-skip_children (const struct die_reader_specs *reader, const gdb_byte *info_ptr)
-{
-  while (1)
-    {
-      unsigned int bytes_read;
-      const abbrev_info *abbrev = peek_die_abbrev (*reader, info_ptr,
-						   &bytes_read);
-
-      if (abbrev == NULL)
-	return info_ptr + bytes_read;
-      else
-	info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev);
-    }
-}
-
-/* Scan the debug information for CU starting at INFO_PTR in buffer BUFFER.
-   INFO_PTR should point just after the initial uleb128 of a DIE, and the
-   abbrev corresponding to that skipped uleb128 should be passed in
-   ABBREV.
-   
-   If DO_SKIP_CHILDREN is true, or if the DIE has no children, this
-   returns a pointer to this DIE's sibling, skipping any children.
-   Otherwise, returns a pointer to the DIE's first child.  */
-
-static const gdb_byte *
-skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
-	      const struct abbrev_info *abbrev, bool do_skip_children)
-{
-  unsigned int bytes_read;
-  struct attribute attr;
-  bfd *abfd = reader->abfd;
-  struct dwarf2_cu *cu = reader->cu;
-  const gdb_byte *buffer = reader->buffer;
-  const gdb_byte *buffer_end = reader->buffer_end;
-  unsigned int form, i;
-
-  if (do_skip_children && abbrev->sibling_offset != (unsigned short) -1)
-    {
-      /* We only handle DW_FORM_ref4 here.  */
-      const gdb_byte *sibling_data = info_ptr + abbrev->sibling_offset;
-      unsigned int offset = read_4_bytes (abfd, sibling_data);
-      const gdb_byte *sibling_ptr
-	= buffer + to_underlying (cu->header.sect_off) + offset;
-      if (sibling_ptr >= info_ptr && sibling_ptr < reader->buffer_end)
-	return sibling_ptr;
-      /* Fall through to the slow way.  */
-    }
-  else if (abbrev->size_if_constant != 0)
-    {
-      info_ptr += abbrev->size_if_constant;
-      if (do_skip_children && abbrev->has_children)
-	return skip_children (reader, info_ptr);
-      return info_ptr;
-    }
-
-  for (i = 0; i < abbrev->num_attrs; i++)
-    {
-      /* The only abbrev we care about is DW_AT_sibling.  */
-      if (do_skip_children && abbrev->attrs[i].name == DW_AT_sibling)
-	{
-	  read_attribute (reader, &attr, &abbrev->attrs[i], info_ptr);
-	  if (attr.form == DW_FORM_ref_addr)
-	    complaint (_("ignoring absolute DW_AT_sibling"));
-	  else
-	    {
-	      sect_offset off = attr.get_ref_die_offset ();
-	      const gdb_byte *sibling_ptr = buffer + to_underlying (off);
+	      sect_offset off = attr.get_ref_die_offset ();
+	      const gdb_byte *sibling_ptr = buffer + to_underlying (off);
 
 	      if (sibling_ptr < info_ptr)
 		complaint (_("DW_AT_sibling points backwards"));
@@ -8943,57 +7526,6 @@ skip_one_die (const struct die_reader_specs *reader, const gdb_byte *info_ptr,
   else
     return info_ptr;
 }
-
-/* Locate ORIG_PDI's sibling.
-   INFO_PTR should point to the start of the next DIE after ORIG_PDI.  */
-
-static const gdb_byte *
-locate_pdi_sibling (const struct die_reader_specs *reader,
-		    struct partial_die_info *orig_pdi,
-		    const gdb_byte *info_ptr)
-{
-  /* Do we know the sibling already?  */
-
-  if (orig_pdi->sibling)
-    return orig_pdi->sibling;
-
-  /* Are there any children to deal with?  */
-
-  if (!orig_pdi->has_children)
-    return info_ptr;
-
-  /* Skip the children the long way.  */
-
-  return skip_children (reader, info_ptr);
-}
-
-/* Expand this partial symbol table into a full symbol table.  SELF is
-   not NULL.  */
-
-void
-dwarf2_psymtab::read_symtab (struct objfile *objfile)
-{
-  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-
-  gdb_assert (!per_objfile->symtab_set_p (per_cu_data));
-
-  /* If this psymtab is constructed from a debug-only objfile, the
-     has_section_at_zero flag will not necessarily be correct.  We
-     can get the correct value for this flag by looking at the data
-     associated with the (presumably stripped) associated objfile.  */
-  if (objfile->separate_debug_objfile_backlink)
-    {
-      dwarf2_per_objfile *per_objfile_backlink
-	= get_dwarf2_per_objfile (objfile->separate_debug_objfile_backlink);
-
-      per_objfile->per_bfd->has_section_at_zero
-	= per_objfile_backlink->per_bfd->has_section_at_zero;
-    }
-
-  expand_psymtab (objfile);
-
-  process_cu_includes (per_objfile);
-}
 \f
 /* Reading in full CUs.  */
 
@@ -9041,18 +7573,6 @@ maybe_queue_comp_unit (struct dwarf2_cu *dependent_cu,
 		       dwarf2_per_objfile *per_objfile,
 		       enum language pretend_language)
 {
-  /* We may arrive here during partial symbol reading, if we need full
-     DIEs to process an unusual case (e.g. template arguments).  Do
-     not queue PER_CU, just tell our caller to load its DIEs.  */
-  if (per_cu->per_bfd->reading_partial_symbols)
-    {
-      dwarf2_cu *cu = per_objfile->get_cu (per_cu);
-
-      if (cu == NULL || cu->dies == NULL)
-	return 1;
-      return 0;
-    }
-
   /* Mark the dependence relation so that we don't flush PER_CU
      too early.  */
   if (dependent_cu != NULL)
@@ -9157,39 +7677,6 @@ process_queue (dwarf2_per_objfile *per_objfile)
 			   objfile_name (per_objfile->objfile));
 }
 
-/* Read in full symbols for PST, and anything it depends on.  */
-
-void
-dwarf2_psymtab::expand_psymtab (struct objfile *objfile)
-{
-  gdb_assert (!readin_p (objfile));
-
-  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-  free_cached_comp_units freer (per_objfile);
-  expand_dependencies (objfile);
-
-  dw2_do_instantiate_symtab (per_cu_data, per_objfile, false);
-  gdb_assert (get_compunit_symtab (objfile) != nullptr);
-}
-
-/* See psympriv.h.  */
-
-bool
-dwarf2_psymtab::readin_p (struct objfile *objfile) const
-{
-  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-  return per_objfile->symtab_set_p (per_cu_data);
-}
-
-/* See psympriv.h.  */
-
-compunit_symtab *
-dwarf2_psymtab::get_compunit_symtab (struct objfile *objfile) const
-{
-  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-  return per_objfile->get_symtab (per_cu_data);
-}
-
 /* Trivial hash function for die_info: the hash value of a DIE
    is its offset in .debug_info for this objfile.  */
 
@@ -11008,7 +9495,7 @@ find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu)
 
 static void
 handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu,
-			const file_and_directory &fnd, CORE_ADDR lowpc) /* ARI: editCase function */
+			CORE_ADDR lowpc) /* ARI: editCase function */
 {
   dwarf2_per_objfile *per_objfile = cu->per_objfile;
   struct attribute *attr;
@@ -11096,9 +9583,7 @@ handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu,
       gdb_assert (die->tag != DW_TAG_partial_unit);
     }
   decode_mapping = (die->tag != DW_TAG_partial_unit);
-  dwarf_decode_lines (cu->line_header, fnd, cu, nullptr, lowpc,
-		      decode_mapping);
-
+  dwarf_decode_lines (cu->line_header, cu, lowpc, decode_mapping);
 }
 
 /* Process DW_TAG_compile_unit or DW_TAG_partial_unit.  */
@@ -11137,7 +9622,7 @@ 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);
+  handle_DW_AT_stmt_list (die, cu, lowpc);
 
   /* Process all dies in compilation unit.  */
   if (die->child != NULL)
@@ -19975,7 +18460,7 @@ struct cooked_index_functions : public dwarf2_base_index_functions
   void read_partial_symbols (struct objfile *objfile) override
   {
     if (dwarf2_has_info (objfile, nullptr))
-      dwarf2_build_psymtabs (objfile);
+      dwarf2_build_psymtabs (objfile, true);
   }
 };
 
@@ -19993,1029 +18478,210 @@ cooked_index_functions::find_pc_sect_compunit_symtab
 
   CORE_ADDR baseaddr = objfile->text_section_offset ();
   dwarf2_per_cu_data *per_cu
-    = per_objfile->per_bfd->cooked_index_table->lookup (pc - baseaddr);
-  if (per_cu == nullptr)
-    return nullptr;
-
-  if (warn_if_readin && per_objfile->symtab_set_p (per_cu))
-    warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
-	     paddress (objfile->arch (), pc));
-
-  compunit_symtab *result = (recursively_find_pc_sect_compunit_symtab
-			     (dw2_instantiate_symtab (per_cu, per_objfile,
-						      false),
-			      pc));
-  gdb_assert (result != nullptr);
-  return result;
-}
-
-struct compunit_symtab *
-cooked_index_functions::find_compunit_symtab_by_address
-     (struct objfile *objfile, CORE_ADDR address)
-{
-  if (objfile->sect_index_data == -1)
-    return nullptr;
-
-  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-  if (per_objfile->per_bfd->cooked_index_table == nullptr)
-    return nullptr;
-
-  CORE_ADDR baseaddr = objfile->data_section_offset ();
-  dwarf2_per_cu_data *per_cu
-    = per_objfile->per_bfd->cooked_index_table->lookup (address - baseaddr);
-  if (per_cu == nullptr)
-    return nullptr;
-
-  return dw2_instantiate_symtab (per_cu, per_objfile, false);
-}
-
-void
-cooked_index_functions::expand_matching_symbols
-     (struct objfile *objfile,
-      const lookup_name_info &lookup_name,
-      domain_enum domain,
-      int global,
-      symbol_compare_ftype *ordered_compare)
-{
-  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-  if (per_objfile->per_bfd->cooked_index_table == nullptr)
-    return;
-  const block_search_flags search_flags = (global
-					   ? SEARCH_GLOBAL_BLOCK
-					   : SEARCH_STATIC_BLOCK);
-  const language_defn *lang = language_def (language_ada);
-  symbol_name_matcher_ftype *name_match
-    = lang->get_symbol_name_matcher (lookup_name);
-
-  for (const cooked_index_entry *entry
-	 : per_objfile->per_bfd->cooked_index_table->all_entries ())
-    {
-      if (entry->parent_entry != nullptr)
-	continue;
-
-      if (!entry->matches (search_flags)
-	  || !entry->matches (domain))
-	continue;
-
-      if (name_match (entry->canonical, lookup_name, nullptr))
-	dw2_instantiate_symtab (entry->per_cu, per_objfile, false);
-    }
-}
-
-bool
-cooked_index_functions::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_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
-  if (per_objfile->per_bfd->cooked_index_table == nullptr)
-    return true;
-
-  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 (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
-	{
-	  QUIT;
-
-	  if (!dw2_expand_symtabs_matching_one (per_cu.get (), per_objfile,
-						file_matcher,
-						expansion_notify))
-	    return false;
-	}
-      return true;
-    }
-
-  lookup_name_info lookup_name_without_params
-    = lookup_name->make_ignore_params ();
-  bool completing = lookup_name->completion_mode ();
-
-  /* Unique styles of language splitting.  */
-  static const enum language unique_styles[] =
-  {
-    /* No splitting is also a style.  */
-    language_c,
-    /* This includes Rust.  */
-    language_cplus,
-    /* This includes Go.  */
-    language_d,
-    language_ada
-  };
-
-  for (enum language lang : unique_styles)
-    {
-      std::vector<gdb::string_view> name_vec
-	= lookup_name_without_params.split_name (lang);
-
-      for (const cooked_index_entry *entry
-	   : per_objfile->per_bfd->cooked_index_table->find (name_vec.back (),
-							     completing))
-	{
-	  /* No need to consider symbols from expanded CUs.  */
-	  if (per_objfile->symtab_set_p (entry->per_cu))
-	    continue;
-
-	  /* If file-matching was done, we don't need to consider
-	     symbols from unmarked CUs.  */
-	  if (file_matcher != nullptr && !entry->per_cu->v.quick->mark)
-	    continue;
-
-	  /* See if the symbol matches the type filter.  */
-	  if (!entry->matches (search_flags)
-	      || !entry->matches (domain)
-	      || !entry->matches (kind))
-	    continue;
-
-	  /* We've found the base name of the symbol; now walk its
-	     parentage chain, ensuring that each component
-	     matches.  */
-	  bool found = true;
-
-	  const cooked_index_entry *parent = entry->parent_entry;
-	  for (int i = name_vec.size () - 1; i > 0; --i)
-	    {
-	      /* If we ran out of entries, or if this segment doesn't
-		 match, this did not match.  */
-	      if (parent == nullptr
-		  || strncmp (parent->name, name_vec[i - 1].data (),
-			      name_vec[i - 1].length ()) != 0)
-		{
-		  found = false;
-		  break;
-		}
-
-	      parent = parent->parent_entry;
-	    }
-
-	  if (!found)
-	    continue;
-
-	  /* Might have been looking for "a::b" and found
-	     "x::a::b".  */
-	  symbol_name_match_type match_type
-	    = lookup_name_without_params.match_type ();
-	  if ((match_type == symbol_name_match_type::FULL
-	       || (lang != language_ada
-		   && match_type == symbol_name_match_type::EXPRESSION))
-	      && parent != nullptr)
-	    continue;
-
-	  if (symbol_matcher != nullptr)
-	    {
-	      auto_obstack temp_storage;
-	      const char *full_name = entry->full_name (&temp_storage);
-	      if (!symbol_matcher (full_name))
-		continue;
-	    }
-
-	  if (!dw2_expand_symtabs_matching_one (entry->per_cu, per_objfile,
-						file_matcher,
-						expansion_notify))
-	    return false;
-	}
-    }
-
-  return true;
-}
-
-/* Return a new cooked_index_functions object.  */
-
-static quick_symbol_functions_up
-make_cooked_index_funcs ()
-{
-  return quick_symbol_functions_up (new cooked_index_functions);
-}
-
-\f
-
-/* Returns nonzero if TAG represents a type that we might generate a partial
-   symbol for.  */
-
-static int
-is_type_tag_for_partial (int tag, enum language lang)
-{
-  switch (tag)
-    {
-#if 0
-    /* Some types that would be reasonable to generate partial symbols for,
-       that we don't at present.  Note that normally this does not
-       matter, mainly because C compilers don't give names to these
-       types, but instead emit DW_TAG_typedef.  */
-    case DW_TAG_file_type:
-    case DW_TAG_ptr_to_member_type:
-    case DW_TAG_set_type:
-    case DW_TAG_string_type:
-    case DW_TAG_subroutine_type:
-#endif
-
-      /* GNAT may emit an array with a name, but no typedef, so we
-	 need to make a symbol in this case.  */
-    case DW_TAG_array_type:
-      return lang == language_ada;
-
-    case DW_TAG_base_type:
-    case DW_TAG_class_type:
-    case DW_TAG_interface_type:
-    case DW_TAG_enumeration_type:
-    case DW_TAG_structure_type:
-    case DW_TAG_subrange_type:
-    case DW_TAG_typedef:
-    case DW_TAG_union_type:
-      return 1;
-    default:
-      return 0;
-    }
-}
-
-/* Load all DIEs that are interesting for partial symbols into memory.  */
-
-static struct partial_die_info *
-load_partial_dies (const struct die_reader_specs *reader,
-		   const gdb_byte *info_ptr, int building_psymtab)
-{
-  struct dwarf2_cu *cu = reader->cu;
-  struct objfile *objfile = cu->per_objfile->objfile;
-  struct partial_die_info *parent_die, *last_die, *first_die = NULL;
-  unsigned int bytes_read;
-  unsigned int load_all = 0;
-  int nesting_level = 1;
-
-  parent_die = NULL;
-  last_die = NULL;
-
-  gdb_assert (cu->per_cu != NULL);
-  if (cu->load_all_dies)
-    load_all = 1;
-
-  cu->partial_dies
-    = htab_create_alloc_ex (cu->header.length / 12,
-			    partial_die_hash,
-			    partial_die_eq,
-			    NULL,
-			    &cu->comp_unit_obstack,
-			    hashtab_obstack_allocate,
-			    dummy_obstack_deallocate);
-
-  while (1)
-    {
-      const abbrev_info *abbrev = peek_die_abbrev (*reader, info_ptr,
-						   &bytes_read);
-
-      /* A NULL abbrev means the end of a series of children.  */
-      if (abbrev == NULL)
-	{
-	  if (--nesting_level == 0)
-	    return first_die;
-
-	  info_ptr += bytes_read;
-	  last_die = parent_die;
-	  parent_die = parent_die->die_parent;
-	  continue;
-	}
-
-      /* Check for template arguments.  We never save these; if
-	 they're seen, we just mark the parent, and go on our way.  */
-      if (parent_die != NULL
-	  && cu->per_cu->lang == language_cplus
-	  && (abbrev->tag == DW_TAG_template_type_param
-	      || abbrev->tag == DW_TAG_template_value_param))
-	{
-	  parent_die->has_template_arguments = 1;
-
-	  if (!load_all)
-	    {
-	      /* We don't need a partial DIE for the template argument.  */
-	      info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev);
-	      continue;
-	    }
-	}
-
-      /* We only recurse into c++ subprograms looking for template arguments.
-	 Skip their other children.  */
-      if (!load_all
-	  && cu->per_cu->lang == language_cplus
-	  && parent_die != NULL
-	  && parent_die->tag == DW_TAG_subprogram
-	  && abbrev->tag != DW_TAG_inlined_subroutine)
-	{
-	  info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev);
-	  continue;
-	}
-
-      /* Check whether this DIE is interesting enough to save.  Normally
-	 we would not be interested in members here, but there may be
-	 later variables referencing them via DW_AT_specification (for
-	 static members).  */
-      if (!load_all
-	  && !is_type_tag_for_partial (abbrev->tag, cu->per_cu->lang)
-	  && abbrev->tag != DW_TAG_constant
-	  && abbrev->tag != DW_TAG_enumerator
-	  && abbrev->tag != DW_TAG_subprogram
-	  && abbrev->tag != DW_TAG_inlined_subroutine
-	  && abbrev->tag != DW_TAG_lexical_block
-	  && abbrev->tag != DW_TAG_variable
-	  && abbrev->tag != DW_TAG_namespace
-	  && abbrev->tag != DW_TAG_module
-	  && abbrev->tag != DW_TAG_member
-	  && abbrev->tag != DW_TAG_imported_unit
-	  && abbrev->tag != DW_TAG_imported_declaration)
-	{
-	  /* Otherwise we skip to the next sibling, if any.  */
-	  info_ptr = skip_one_die (reader, info_ptr + bytes_read, abbrev);
-	  continue;
-	}
-
-      struct partial_die_info pdi ((sect_offset) (info_ptr - reader->buffer),
-				   abbrev);
-
-      info_ptr = pdi.read (reader, *abbrev, info_ptr + bytes_read);
-
-      /* This two-pass algorithm for processing partial symbols has a
-	 high cost in cache pressure.  Thus, handle some simple cases
-	 here which cover the majority of C partial symbols.  DIEs
-	 which neither have specification tags in them, nor could have
-	 specification tags elsewhere pointing at them, can simply be
-	 processed and discarded.
-
-	 This segment is also optional; scan_partial_symbols and
-	 add_partial_symbol will handle these DIEs if we chain
-	 them in normally.  When compilers which do not emit large
-	 quantities of duplicate debug information are more common,
-	 this code can probably be removed.  */
-
-      /* Any complete simple types at the top level (pretty much all
-	 of them, for a language without namespaces), can be processed
-	 directly.  */
-      if (parent_die == NULL
-	  && pdi.has_specification == 0
-	  && pdi.is_declaration == 0
-	  && ((pdi.tag == DW_TAG_typedef && !pdi.has_children)
-	      || pdi.tag == DW_TAG_base_type
-	      || pdi.tag == DW_TAG_array_type
-	      || pdi.tag == DW_TAG_subrange_type))
-	{
-	  if (building_psymtab && pdi.raw_name != NULL)
-	    add_partial_symbol (&pdi, cu);
-
-	  info_ptr = locate_pdi_sibling (reader, &pdi, info_ptr);
-	  continue;
-	}
-
-      /* The exception for DW_TAG_typedef with has_children above is
-	 a workaround of GCC PR debug/47510.  In the case of this complaint
-	 type_name_or_error will error on such types later.
-
-	 GDB skipped children of DW_TAG_typedef by the shortcut above and then
-	 it could not find the child DIEs referenced later, this is checked
-	 above.  In correct DWARF DW_TAG_typedef should have no children.  */
-
-      if (pdi.tag == DW_TAG_typedef && pdi.has_children)
-	complaint (_("DW_TAG_typedef has childen - GCC PR debug/47510 bug "
-		     "- DIE at %s [in module %s]"),
-		   sect_offset_str (pdi.sect_off), objfile_name (objfile));
-
-      /* If we're at the second level, and we're an enumerator, and
-	 our parent has no specification (meaning possibly lives in a
-	 namespace elsewhere), then we can add the partial symbol now
-	 instead of queueing it.  */
-      if (pdi.tag == DW_TAG_enumerator
-	  && parent_die != NULL
-	  && parent_die->die_parent == NULL
-	  && parent_die->tag == DW_TAG_enumeration_type
-	  && parent_die->has_specification == 0)
-	{
-	  if (pdi.raw_name == NULL)
-	    complaint (_("malformed enumerator DIE ignored"));
-	  else if (building_psymtab)
-	    add_partial_symbol (&pdi, cu);
-
-	  info_ptr = locate_pdi_sibling (reader, &pdi, info_ptr);
-	  continue;
-	}
-
-      struct partial_die_info *part_die
-	= new (&cu->comp_unit_obstack) partial_die_info (pdi);
-
-      /* We'll save this DIE so link it in.  */
-      part_die->die_parent = parent_die;
-      part_die->die_sibling = NULL;
-      part_die->die_child = NULL;
-
-      if (last_die && last_die == parent_die)
-	last_die->die_child = part_die;
-      else if (last_die)
-	last_die->die_sibling = part_die;
-
-      last_die = part_die;
-
-      if (first_die == NULL)
-	first_die = part_die;
-
-      /* Maybe add the DIE to the hash table.  Not all DIEs that we
-	 find interesting need to be in the hash table, because we
-	 also have the parent/sibling/child chains; only those that we
-	 might refer to by offset later during partial symbol reading.
-
-	 For now this means things that might have be the target of a
-	 DW_AT_specification, DW_AT_abstract_origin, or
-	 DW_AT_extension.  DW_AT_extension will refer only to
-	 namespaces; DW_AT_abstract_origin refers to functions (and
-	 many things under the function DIE, but we do not recurse
-	 into function DIEs during partial symbol reading) and
-	 possibly variables as well; DW_AT_specification refers to
-	 declarations.  Declarations ought to have the DW_AT_declaration
-	 flag.  It happens that GCC forgets to put it in sometimes, but
-	 only for functions, not for types.
-
-	 Adding more things than necessary to the hash table is harmless
-	 except for the performance cost.  Adding too few will result in
-	 wasted time in find_partial_die, when we reread the compilation
-	 unit with load_all_dies set.  */
-
-      if (load_all
-	  || abbrev->tag == DW_TAG_constant
-	  || abbrev->tag == DW_TAG_subprogram
-	  || abbrev->tag == DW_TAG_variable
-	  || abbrev->tag == DW_TAG_namespace
-	  || part_die->is_declaration)
-	{
-	  void **slot;
-
-	  slot = htab_find_slot_with_hash (cu->partial_dies, part_die,
-					   to_underlying (part_die->sect_off),
-					   INSERT);
-	  *slot = part_die;
-	}
-
-      /* For some DIEs we want to follow their children (if any).  For C
-	 we have no reason to follow the children of structures; for other
-	 languages we have to, so that we can get at method physnames
-	 to infer fully qualified class names, for DW_AT_specification,
-	 and for C++ template arguments.  For C++, we also look one level
-	 inside functions to find template arguments (if the name of the
-	 function does not already contain the template arguments).
-
-	 For Ada and Fortran, we need to scan the children of subprograms
-	 and lexical blocks as well because these languages allow the
-	 definition of nested entities that could be interesting for the
-	 debugger, such as nested subprograms for instance.  */
-      if (last_die->has_children
-	  && (load_all
-	      || last_die->tag == DW_TAG_namespace
-	      || last_die->tag == DW_TAG_module
-	      || last_die->tag == DW_TAG_enumeration_type
-	      || (cu->per_cu->lang == language_cplus
-		  && last_die->tag == DW_TAG_subprogram
-		  && (last_die->raw_name == NULL
-		      || strchr (last_die->raw_name, '<') == NULL))
-	      || (cu->per_cu->lang != language_c
-		  && (last_die->tag == DW_TAG_class_type
-		      || last_die->tag == DW_TAG_interface_type
-		      || last_die->tag == DW_TAG_structure_type
-		      || last_die->tag == DW_TAG_union_type))
-	      || ((cu->per_cu->lang == language_ada
-		   || cu->per_cu->lang == language_fortran)
-		  && (last_die->tag == DW_TAG_subprogram
-		      || last_die->tag == DW_TAG_lexical_block))))
-	{
-	  nesting_level++;
-	  parent_die = last_die;
-	  continue;
-	}
-
-      /* Otherwise we skip to the next sibling, if any.  */
-      info_ptr = locate_pdi_sibling (reader, last_die, info_ptr);
-
-      /* Back to the top, do it again.  */
-    }
-}
-
-partial_die_info::partial_die_info (sect_offset sect_off_,
-				    const struct abbrev_info *abbrev)
-  : partial_die_info (sect_off_, abbrev->tag, abbrev->has_children)
-{
-}
-
-/* See class definition.  */
-
-const char *
-partial_die_info::name (dwarf2_cu *cu)
-{
-  if (!canonical_name && raw_name != nullptr)
-    {
-      struct objfile *objfile = cu->per_objfile->objfile;
-      raw_name = dwarf2_canonicalize_name (raw_name, cu, objfile);
-      canonical_name = 1;
-    }
-
-  return raw_name;
-}
-
-/* Read a minimal amount of information into the minimal die structure.
-   INFO_PTR should point just after the initial uleb128 of a DIE.  */
-
-const gdb_byte *
-partial_die_info::read (const struct die_reader_specs *reader,
-			const struct abbrev_info &abbrev, const gdb_byte *info_ptr)
-{
-  struct dwarf2_cu *cu = reader->cu;
-  dwarf2_per_objfile *per_objfile = cu->per_objfile;
-  unsigned int i;
-  int has_low_pc_attr = 0;
-  int has_high_pc_attr = 0;
-  int high_pc_relative = 0;
-
-  for (i = 0; i < abbrev.num_attrs; ++i)
-    {
-      attribute attr;
-      info_ptr = read_attribute (reader, &attr, &abbrev.attrs[i], info_ptr);
-      /* String and address offsets that need to do the reprocessing have
-	 already been read at this point, so there is no need to wait until
-	 the loop terminates to do the reprocessing.  */
-      if (attr.requires_reprocessing_p ())
-	read_attribute_reprocess (reader, &attr, tag);
-      /* Store the data if it is of an attribute we want to keep in a
-	 partial symbol table.  */
-      switch (attr.name)
-	{
-	case DW_AT_name:
-	  switch (tag)
-	    {
-	    case DW_TAG_compile_unit:
-	    case DW_TAG_partial_unit:
-	    case DW_TAG_type_unit:
-	      /* Compilation units have a DW_AT_name that is a filename, not
-		 a source language identifier.  */
-	    case DW_TAG_enumeration_type:
-	    case DW_TAG_enumerator:
-	      /* These tags always have simple identifiers already; no need
-		 to canonicalize them.  */
-	      canonical_name = 1;
-	      raw_name = attr.as_string ();
-	      break;
-	    default:
-	      canonical_name = 0;
-	      raw_name = attr.as_string ();
-	      break;
-	    }
-	  break;
-	case DW_AT_linkage_name:
-	case DW_AT_MIPS_linkage_name:
-	  /* Note that both forms of linkage name might appear.  We
-	     assume they will be the same, and we only store the last
-	     one we see.  */
-	  linkage_name = attr.as_string ();
-	  break;
-	case DW_AT_low_pc:
-	  has_low_pc_attr = 1;
-	  lowpc = attr.as_address ();
-	  break;
-	case DW_AT_high_pc:
-	  has_high_pc_attr = 1;
-	  highpc = attr.as_address ();
-	  if (cu->header.version >= 4 && attr.form_is_constant ())
-		high_pc_relative = 1;
-	  break;
-	case DW_AT_location:
-	  /* Support the .debug_loc offsets.  */
-	  if (attr.form_is_block ())
-	    {
-	      d.locdesc = attr.as_block ();
-	    }
-	  else if (attr.form_is_section_offset ())
-	    {
-	      dwarf2_complex_location_expr_complaint ();
-	    }
-	  else
-	    {
-	      dwarf2_invalid_attrib_class_complaint ("DW_AT_location",
-						     "partial symbol information");
-	    }
-	  break;
-	case DW_AT_external:
-	  is_external = attr.as_boolean ();
-	  break;
-	case DW_AT_declaration:
-	  is_declaration = attr.as_boolean ();
-	  break;
-	case DW_AT_type:
-	  has_type = 1;
-	  break;
-	case DW_AT_abstract_origin:
-	case DW_AT_specification:
-	case DW_AT_extension:
-	  has_specification = 1;
-	  spec_offset = attr.get_ref_die_offset ();
-	  spec_is_dwz = (attr.form == DW_FORM_GNU_ref_alt
-				   || cu->per_cu->is_dwz);
-	  break;
-	case DW_AT_sibling:
-	  /* Ignore absolute siblings, they might point outside of
-	     the current compile unit.  */
-	  if (attr.form == DW_FORM_ref_addr)
-	    complaint (_("ignoring absolute DW_AT_sibling"));
-	  else
-	    {
-	      const gdb_byte *buffer = reader->buffer;
-	      sect_offset off = attr.get_ref_die_offset ();
-	      const gdb_byte *sibling_ptr = buffer + to_underlying (off);
-
-	      if (sibling_ptr < info_ptr)
-		complaint (_("DW_AT_sibling points backwards"));
-	      else if (sibling_ptr > reader->buffer_end)
-		reader->die_section->overflow_complaint ();
-	      else
-		sibling = sibling_ptr;
-	    }
-	  break;
-	case DW_AT_byte_size:
-	  has_byte_size = 1;
-	  break;
-	case DW_AT_const_value:
-	  has_const_value = 1;
-	  break;
-	case DW_AT_calling_convention:
-	  /* DWARF doesn't provide a way to identify a program's source-level
-	     entry point.  DW_AT_calling_convention attributes are only meant
-	     to describe functions' calling conventions.
-
-	     However, because it's a necessary piece of information in
-	     Fortran, and before DWARF 4 DW_CC_program was the only
-	     piece of debugging information whose definition refers to
-	     a 'main program' at all, several compilers marked Fortran
-	     main programs with DW_CC_program --- even when those
-	     functions use the standard calling conventions.
-
-	     Although DWARF now specifies a way to provide this
-	     information, we support this practice for backward
-	     compatibility.  */
-	  if (attr.constant_value (0) == DW_CC_program
-	      && cu->per_cu->lang == language_fortran)
-	    main_subprogram = 1;
-	  break;
-	case DW_AT_inline:
-	  {
-	    LONGEST value = attr.constant_value (-1);
-	    if (value == DW_INL_inlined
-		|| value == DW_INL_declared_inlined)
-	      may_be_inlined = 1;
-	  }
-	  break;
-
-	case DW_AT_import:
-	  if (tag == DW_TAG_imported_unit)
-	    {
-	      d.sect_off = attr.get_ref_die_offset ();
-	      is_dwz = (attr.form == DW_FORM_GNU_ref_alt
-				  || cu->per_cu->is_dwz);
-	    }
-	  break;
-
-	case DW_AT_main_subprogram:
-	  main_subprogram = attr.as_boolean ();
-	  break;
-
-	case DW_AT_ranges:
-	  {
-	    /* Offset in the .debug_ranges or .debug_rnglist section (depending
-	       on DWARF version).  */
-	    ranges_offset = attr.as_unsigned ();
-
-	    /* See dwarf2_cu::gnu_ranges_base's doc for why we might want to add
-	       this value.  */
-	    if (tag != DW_TAG_compile_unit)
-	      ranges_offset += cu->gnu_ranges_base;
-
-	    has_range_info = 1;
-	  }
-	  break;
-
-	default:
-	  break;
-	}
-    }
-
-  /* For Ada, if both the name and the linkage name appear, we prefer
-     the latter.  This lets "catch exception" work better, regardless
-     of the order in which the name and linkage name were emitted.
-     Really, though, this is just a workaround for the fact that gdb
-     doesn't store both the name and the linkage name.  */
-  if (cu->per_cu->lang == language_ada && linkage_name != nullptr)
-    raw_name = linkage_name;
-
-  if (high_pc_relative)
-    highpc += lowpc;
-
-  if (has_low_pc_attr && has_high_pc_attr)
-    {
-      /* When using the GNU linker, .gnu.linkonce. sections are used to
-	 eliminate duplicate copies of functions and vtables and such.
-	 The linker will arbitrarily choose one and discard the others.
-	 The AT_*_pc values for such functions refer to local labels in
-	 these sections.  If the section from that file was discarded, the
-	 labels are not in the output, so the relocs get a value of 0.
-	 If this is a discarded function, mark the pc bounds as invalid,
-	 so that GDB will ignore it.  */
-      if (lowpc == 0 && !per_objfile->per_bfd->has_section_at_zero)
-	{
-	  struct objfile *objfile = per_objfile->objfile;
-	  struct gdbarch *gdbarch = objfile->arch ();
-
-	  complaint (_("DW_AT_low_pc %s is zero "
-		       "for DIE at %s [in module %s]"),
-		     paddress (gdbarch, lowpc),
-		     sect_offset_str (sect_off),
-		     objfile_name (objfile));
-	}
-      /* dwarf2_get_pc_bounds has also the strict low < high requirement.  */
-      else if (lowpc >= highpc)
-	{
-	  struct objfile *objfile = per_objfile->objfile;
-	  struct gdbarch *gdbarch = objfile->arch ();
-
-	  complaint (_("DW_AT_low_pc %s is not < DW_AT_high_pc %s "
-		       "for DIE at %s [in module %s]"),
-		     paddress (gdbarch, lowpc),
-		     paddress (gdbarch, highpc),
-		     sect_offset_str (sect_off),
-		     objfile_name (objfile));
-	}
-      else
-	has_pc_info = 1;
-    }
-
-  return info_ptr;
-}
-
-/* Find a cached partial DIE at OFFSET in CU.  */
-
-struct partial_die_info *
-dwarf2_cu::find_partial_die (sect_offset sect_off)
-{
-  struct partial_die_info *lookup_die = NULL;
-  struct partial_die_info part_die (sect_off);
+    = per_objfile->per_bfd->cooked_index_table->lookup (pc - baseaddr);
+  if (per_cu == nullptr)
+    return nullptr;
 
-  lookup_die = ((struct partial_die_info *)
-		htab_find_with_hash (partial_dies, &part_die,
-				     to_underlying (sect_off)));
+  if (warn_if_readin && per_objfile->symtab_set_p (per_cu))
+    warning (_("(Internal error: pc %s in read in CU, but not in symtab.)"),
+	     paddress (objfile->arch (), pc));
 
-  return lookup_die;
+  compunit_symtab *result = (recursively_find_pc_sect_compunit_symtab
+			     (dw2_instantiate_symtab (per_cu, per_objfile,
+						      false),
+			      pc));
+  gdb_assert (result != nullptr);
+  return result;
 }
 
-/* Find a partial DIE at OFFSET, which may or may not be in CU,
-   except in the case of .debug_types DIEs which do not reference
-   outside their CU (they do however referencing other types via
-   DW_FORM_ref_sig8).  */
-
-static const struct cu_partial_die_info
-find_partial_die (sect_offset sect_off, int offset_in_dwz, struct dwarf2_cu *cu)
+struct compunit_symtab *
+cooked_index_functions::find_compunit_symtab_by_address
+     (struct objfile *objfile, CORE_ADDR address)
 {
-  dwarf2_per_objfile *per_objfile = cu->per_objfile;
-  struct objfile *objfile = per_objfile->objfile;
-  struct partial_die_info *pd = NULL;
-
-  if (offset_in_dwz == cu->per_cu->is_dwz
-      && cu->header.offset_in_cu_p (sect_off))
-    {
-      pd = cu->find_partial_die (sect_off);
-      if (pd != NULL)
-	return { cu, pd };
-      /* We missed recording what we needed.
-	 Load all dies and try again.  */
-    }
-  else
-    {
-      /* TUs don't reference other CUs/TUs (except via type signatures).  */
-      if (cu->per_cu->is_debug_types)
-	{
-	  error (_("Dwarf Error: Type Unit at offset %s contains"
-		   " external reference to offset %s [in module %s].\n"),
-		 sect_offset_str (cu->header.sect_off), sect_offset_str (sect_off),
-		 bfd_get_filename (objfile->obfd));
-	}
-      dwarf2_per_cu_data *per_cu
-	= dwarf2_find_containing_comp_unit (sect_off, offset_in_dwz,
-					    per_objfile);
+  if (objfile->sect_index_data == -1)
+    return nullptr;
 
-      cu = per_objfile->get_cu (per_cu);
-      if (cu == NULL || cu->partial_dies == NULL)
-	load_partial_comp_unit (per_cu, per_objfile, nullptr);
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    return nullptr;
 
-      cu = per_objfile->get_cu (per_cu);
+  CORE_ADDR baseaddr = objfile->data_section_offset ();
+  dwarf2_per_cu_data *per_cu
+    = per_objfile->per_bfd->cooked_index_table->lookup (address - baseaddr);
+  if (per_cu == nullptr)
+    return nullptr;
 
-      cu->last_used = 0;
-      pd = cu->find_partial_die (sect_off);
-    }
+  return dw2_instantiate_symtab (per_cu, per_objfile, false);
+}
 
-  /* If we didn't find it, and not all dies have been loaded,
-     load them all and try again.  */
+void
+cooked_index_functions::expand_matching_symbols
+     (struct objfile *objfile,
+      const lookup_name_info &lookup_name,
+      domain_enum domain,
+      int global,
+      symbol_compare_ftype *ordered_compare)
+{
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    return;
+  const block_search_flags search_flags = (global
+					   ? SEARCH_GLOBAL_BLOCK
+					   : SEARCH_STATIC_BLOCK);
+  const language_defn *lang = language_def (language_ada);
+  symbol_name_matcher_ftype *name_match
+    = lang->get_symbol_name_matcher (lookup_name);
 
-  if (pd == NULL && cu->load_all_dies == 0)
+  for (const cooked_index_entry *entry
+	 : per_objfile->per_bfd->cooked_index_table->all_entries ())
     {
-      cu->load_all_dies = 1;
+      if (entry->parent_entry != nullptr)
+	continue;
 
-      /* This is nasty.  When we reread the DIEs, somewhere up the call chain
-	 THIS_CU->cu may already be in use.  So we can't just free it and
-	 replace its DIEs with the ones we read in.  Instead, we leave those
-	 DIEs alone (which can still be in use, e.g. in scan_partial_symbols),
-	 and clobber THIS_CU->cu->partial_dies with the hash table for the new
-	 set.  */
-      load_partial_comp_unit (cu->per_cu, per_objfile, cu);
+      if (!entry->matches (search_flags)
+	  || !entry->matches (domain))
+	continue;
 
-      pd = cu->find_partial_die (sect_off);
+      if (name_match (entry->canonical, lookup_name, nullptr))
+	dw2_instantiate_symtab (entry->per_cu, per_objfile, false);
     }
-
-  if (pd == NULL)
-    error (_("Dwarf Error: Cannot find DIE at %s [from module %s]\n"),
-		    sect_offset_str (sect_off), bfd_get_filename (objfile->obfd));
-  return { cu, pd };
 }
 
-/* See if we can figure out if the class lives in a namespace.  We do
-   this by looking for a member function; its demangled name will
-   contain namespace info, if there is any.  */
-
-static void
-guess_partial_die_structure_name (struct partial_die_info *struct_pdi,
-				  struct dwarf2_cu *cu)
+bool
+cooked_index_functions::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)
 {
-  /* NOTE: carlton/2003-10-07: Getting the info this way changes
-     what template types look like, because the demangler
-     frequently doesn't give the same name as the debug info.  We
-     could fix this by only using the demangled name to get the
-     prefix (but see comment in read_structure_type).  */
-
-  struct partial_die_info *real_pdi;
-  struct partial_die_info *child_pdi;
-
-  /* If this DIE (this DIE's specification, if any) has a parent, then
-     we should not do this.  We'll prepend the parent's fully qualified
-     name when we create the partial symbol.  */
-
-  real_pdi = struct_pdi;
-  while (real_pdi->has_specification)
-    {
-      auto res = find_partial_die (real_pdi->spec_offset,
-				   real_pdi->spec_is_dwz, cu);
-      real_pdi = res.pdi;
-      cu = res.cu;
-    }
+  dwarf2_per_objfile *per_objfile = get_dwarf2_per_objfile (objfile);
+  if (per_objfile->per_bfd->cooked_index_table == nullptr)
+    return true;
 
-  if (real_pdi->die_parent != NULL)
-    return;
+  dw_expand_symtabs_matching_file_matcher (per_objfile, file_matcher);
 
-  for (child_pdi = struct_pdi->die_child;
-       child_pdi != NULL;
-       child_pdi = child_pdi->die_sibling)
+  /* This invariant is documented in quick-functions.h.  */
+  gdb_assert (lookup_name != nullptr || symbol_matcher == nullptr);
+  if (lookup_name == nullptr)
     {
-      if (child_pdi->tag == DW_TAG_subprogram
-	  && child_pdi->linkage_name != NULL)
+      for (const auto &per_cu : per_objfile->per_bfd->all_comp_units)
 	{
-	  gdb::unique_xmalloc_ptr<char> actual_class_name
-	    (cu->language_defn->class_name_from_physname
-	     (child_pdi->linkage_name));
-	  if (actual_class_name != NULL)
-	    {
-	      struct objfile *objfile = cu->per_objfile->objfile;
-	      struct_pdi->raw_name = objfile->intern (actual_class_name.get ());
-	      struct_pdi->canonical_name = 1;
-	    }
-	  break;
-	}
-    }
-}
-
-/* Return true if a DIE with TAG may have the DW_AT_const_value
-   attribute.  */
+	  QUIT;
 
-static bool
-can_have_DW_AT_const_value_p (enum dwarf_tag tag)
-{
-  switch (tag)
-    {
-    case DW_TAG_constant:
-    case DW_TAG_enumerator:
-    case DW_TAG_formal_parameter:
-    case DW_TAG_template_value_param:
-    case DW_TAG_variable:
+	  if (!dw2_expand_symtabs_matching_one (per_cu.get (), per_objfile,
+						file_matcher,
+						expansion_notify))
+	    return false;
+	}
       return true;
     }
 
-  return false;
-}
-
-void
-partial_die_info::fixup (struct dwarf2_cu *cu)
-{
-  /* Once we've fixed up a die, there's no point in doing so again.
-     This also avoids a memory leak if we were to call
-     guess_partial_die_structure_name multiple times.  */
-  if (fixup_called)
-    return;
+  lookup_name_info lookup_name_without_params
+    = lookup_name->make_ignore_params ();
+  bool completing = lookup_name->completion_mode ();
 
-  /* If we found a reference attribute and the DIE has no name, try
-     to find a name in the referred to DIE.  */
+  /* Unique styles of language splitting.  */
+  static const enum language unique_styles[] =
+  {
+    /* No splitting is also a style.  */
+    language_c,
+    /* This includes Rust.  */
+    language_cplus,
+    /* This includes Go.  */
+    language_d,
+    language_ada
+  };
 
-  if (raw_name == NULL && has_specification)
+  for (enum language lang : unique_styles)
     {
-      struct partial_die_info *spec_die;
-
-      auto res = find_partial_die (spec_offset, spec_is_dwz, cu);
-      spec_die = res.pdi;
-      cu = res.cu;
-
-      spec_die->fixup (cu);
+      std::vector<gdb::string_view> name_vec
+	= lookup_name_without_params.split_name (lang);
 
-      if (spec_die->raw_name)
+      for (const cooked_index_entry *entry
+	   : per_objfile->per_bfd->cooked_index_table->find (name_vec.back (),
+							     completing))
 	{
-	  raw_name = spec_die->raw_name;
-	  canonical_name = spec_die->canonical_name;
+	  /* No need to consider symbols from expanded CUs.  */
+	  if (per_objfile->symtab_set_p (entry->per_cu))
+	    continue;
 
-	  /* Copy DW_AT_external attribute if it is set.  */
-	  if (spec_die->is_external)
-	    is_external = spec_die->is_external;
-	}
-    }
+	  /* If file-matching was done, we don't need to consider
+	     symbols from unmarked CUs.  */
+	  if (file_matcher != nullptr && !entry->per_cu->v.quick->mark)
+	    continue;
 
-  if (!has_const_value && has_specification
-      && can_have_DW_AT_const_value_p (tag))
-    {
-      struct partial_die_info *spec_die;
+	  /* See if the symbol matches the type filter.  */
+	  if (!entry->matches (search_flags)
+	      || !entry->matches (domain)
+	      || !entry->matches (kind))
+	    continue;
 
-      auto res = find_partial_die (spec_offset, spec_is_dwz, cu);
-      spec_die = res.pdi;
-      cu = res.cu;
+	  /* We've found the base name of the symbol; now walk its
+	     parentage chain, ensuring that each component
+	     matches.  */
+	  bool found = true;
 
-      spec_die->fixup (cu);
+	  const cooked_index_entry *parent = entry->parent_entry;
+	  for (int i = name_vec.size () - 1; i > 0; --i)
+	    {
+	      /* If we ran out of entries, or if this segment doesn't
+		 match, this did not match.  */
+	      if (parent == nullptr
+		  || strncmp (parent->name, name_vec[i - 1].data (),
+			      name_vec[i - 1].length ()) != 0)
+		{
+		  found = false;
+		  break;
+		}
 
-      if (spec_die->has_const_value)
-	{
-	  /* Copy DW_AT_const_value attribute if it is set.  */
-	  has_const_value = spec_die->has_const_value;
-	}
-    }
+	      parent = parent->parent_entry;
+	    }
 
-  /* Set default names for some unnamed DIEs.  */
+	  if (!found)
+	    continue;
 
-  if (raw_name == NULL && tag == DW_TAG_namespace)
-    {
-      raw_name = CP_ANONYMOUS_NAMESPACE_STR;
-      canonical_name = 1;
-    }
+	  /* Might have been looking for "a::b" and found
+	     "x::a::b".  */
+	  symbol_name_match_type match_type
+	    = lookup_name_without_params.match_type ();
+	  if ((match_type == symbol_name_match_type::FULL
+	       || (lang != language_ada
+		   && match_type == symbol_name_match_type::EXPRESSION))
+	      && parent != nullptr)
+	    continue;
 
-  /* If there is no parent die to provide a namespace, and there are
-     children, see if we can determine the namespace from their linkage
-     name.  */
-  if (cu->per_cu->lang == language_cplus
-      && !cu->per_objfile->per_bfd->types.empty ()
-      && die_parent == NULL
-      && has_children
-      && (tag == DW_TAG_class_type
-	  || tag == DW_TAG_structure_type
-	  || tag == DW_TAG_union_type))
-    guess_partial_die_structure_name (this, cu);
-
-  /* GCC might emit a nameless struct or union that has a linkage
-     name.  See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47510.  */
-  if (raw_name == NULL
-      && (tag == DW_TAG_class_type
-	  || tag == DW_TAG_interface_type
-	  || tag == DW_TAG_structure_type
-	  || tag == DW_TAG_union_type)
-      && linkage_name != NULL)
-    {
-      gdb::unique_xmalloc_ptr<char> demangled
-	(gdb_demangle (linkage_name, DMGL_TYPES));
-      if (demangled != nullptr)
-	{
-	  const char *base;
-
-	  /* Strip any leading namespaces/classes, keep only the base name.
-	     DW_AT_name for named DIEs does not contain the prefixes.  */
-	  base = strrchr (demangled.get (), ':');
-	  if (base && base > demangled.get () && base[-1] == ':')
-	    base++;
-	  else
-	    base = demangled.get ();
+	  if (symbol_matcher != nullptr)
+	    {
+	      auto_obstack temp_storage;
+	      const char *full_name = entry->full_name (&temp_storage);
+	      if (!symbol_matcher (full_name))
+		continue;
+	    }
 
-	  struct objfile *objfile = cu->per_objfile->objfile;
-	  raw_name = objfile->intern (base);
-	  canonical_name = 1;
+	  if (!dw2_expand_symtabs_matching_one (entry->per_cu, per_objfile,
+						file_matcher,
+						expansion_notify))
+	    return false;
 	}
     }
 
-  fixup_called = 1;
+  return true;
+}
+
+/* Return a new cooked_index_functions object.  */
+
+static quick_symbol_functions_up
+make_cooked_index_funcs ()
+{
+  return quick_symbol_functions_up (new cooked_index_functions);
 }
 
+\f
+
 /* Read the .debug_loclists or .debug_rnglists header (they are the same format)
    contents from the given SECTION in the HEADER.
 
@@ -22072,8 +19738,7 @@ class lnp_state_machine
 public:
   /* Initialize a machine state for the start of a line number
      program.  */
-  lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, line_header *lh,
-		     bool record_lines_p);
+  lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch, line_header *lh);
 
   file_entry *current_file ()
   {
@@ -22164,11 +19829,6 @@ class lnp_state_machine
 
   gdbarch *m_gdbarch;
 
-  /* True if we're recording lines.
-     Otherwise we're building partial symtabs and are just interested in
-     finding include files mentioned by the line number program.  */
-  bool m_record_lines_p;
-
   /* The line number header.  */
   line_header *m_line_header;
 
@@ -22251,7 +19911,7 @@ lnp_state_machine::handle_set_file (file_name_index file)
   const file_entry *fe = current_file ();
   if (fe == NULL)
     dwarf2_debug_line_missing_file_complaint ();
-  else if (m_record_lines_p)
+  else
     {
       const char *dir = fe->include_dir (m_line_header);
 
@@ -22393,54 +20053,50 @@ lnp_state_machine::record_line (bool end_sequence)
      previous version of the code.  */
   else if (m_op_index == 0 || end_sequence)
     {
-      fe->included_p = true;
-      if (m_record_lines_p)
-	{
-	  /* When we switch files we insert an end maker in the first file,
-	     switch to the second file and add a new line entry.  The
-	     problem is that the end marker inserted in the first file will
-	     discard any previous line entries at the same address.  If the
-	     line entries in the first file are marked as is-stmt, while
-	     the new line in the second file is non-stmt, then this means
-	     the end marker will discard is-stmt lines so we can have a
-	     non-stmt line.  This means that there are less addresses at
-	     which the user can insert a breakpoint.
-
-	     To improve this we track the last address in m_last_address,
-	     and whether we have seen an is-stmt at this address.  Then
-	     when switching files, if we have seen a stmt at the current
-	     address, and we are switching to create a non-stmt line, then
-	     discard the new line.  */
-	  bool file_changed
-	    = m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
-	  bool ignore_this_line
-	   = ((file_changed && !end_sequence && m_last_address == m_address
-	       && !m_is_stmt && m_stmt_at_address)
-	      || (!end_sequence && m_line == 0));
-
-	  if ((file_changed && !ignore_this_line) || end_sequence)
-	    {
-	      dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
-				 m_currently_recording_lines ? m_cu : nullptr);
-	    }
-
-	  if (!end_sequence && !ignore_this_line)
+      /* When we switch files we insert an end maker in the first file,
+	 switch to the second file and add a new line entry.  The
+	 problem is that the end marker inserted in the first file will
+	 discard any previous line entries at the same address.  If the
+	 line entries in the first file are marked as is-stmt, while
+	 the new line in the second file is non-stmt, then this means
+	 the end marker will discard is-stmt lines so we can have a
+	 non-stmt line.  This means that there are less addresses at
+	 which the user can insert a breakpoint.
+
+	 To improve this we track the last address in m_last_address,
+	 and whether we have seen an is-stmt at this address.  Then
+	 when switching files, if we have seen a stmt at the current
+	 address, and we are switching to create a non-stmt line, then
+	 discard the new line.  */
+      bool file_changed
+	= m_last_subfile != m_cu->get_builder ()->get_current_subfile ();
+      bool ignore_this_line
+	= ((file_changed && !end_sequence && m_last_address == m_address
+	    && !m_is_stmt && m_stmt_at_address)
+	   || (!end_sequence && m_line == 0));
+
+      if ((file_changed && !ignore_this_line) || end_sequence)
+	{
+	  dwarf_finish_line (m_gdbarch, m_last_subfile, m_address,
+			     m_currently_recording_lines ? m_cu : nullptr);
+	}
+
+      if (!end_sequence && !ignore_this_line)
+	{
+	  bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
+
+	  if (dwarf_record_line_p (m_cu, m_line, m_last_line,
+				   m_line_has_non_zero_discriminator,
+				   m_last_subfile))
 	    {
-	      bool is_stmt = producer_is_codewarrior (m_cu) || m_is_stmt;
-
-	      if (dwarf_record_line_p (m_cu, m_line, m_last_line,
-				       m_line_has_non_zero_discriminator,
-				       m_last_subfile))
-		{
-		  buildsym_compunit *builder = m_cu->get_builder ();
-		  dwarf_record_line_1 (m_gdbarch,
-				       builder->get_current_subfile (),
-				       m_line, m_address, is_stmt,
-				       m_currently_recording_lines ? m_cu : nullptr);
-		}
-	      m_last_subfile = m_cu->get_builder ()->get_current_subfile ();
-	      m_last_line = m_line;
+	      buildsym_compunit *builder = m_cu->get_builder ();
+	      dwarf_record_line_1 (m_gdbarch,
+				   builder->get_current_subfile (),
+				   m_line, m_address, is_stmt,
+				   m_currently_recording_lines ? m_cu : nullptr);
 	    }
+	  m_last_subfile = m_cu->get_builder ()->get_current_subfile ();
+	  m_last_line = m_line;
 	}
     }
 
@@ -22455,11 +20111,10 @@ lnp_state_machine::record_line (bool end_sequence)
 }
 
 lnp_state_machine::lnp_state_machine (struct dwarf2_cu *cu, gdbarch *arch,
-				      line_header *lh, bool record_lines_p)
+				      line_header *lh)
 {
   m_cu = cu;
   m_gdbarch = arch;
-  m_record_lines_p = record_lines_p;
   m_line_header = lh;
 
   m_currently_recording_lines = true;
@@ -22504,13 +20159,11 @@ lnp_state_machine::check_line_address (struct dwarf2_cu *cu,
 }
 
 /* Subroutine of dwarf_decode_lines to simplify it.
-   Process the line number information in LH.
-   If DECODE_FOR_PST_P is non-zero, all we do is process the line number
-   program in order to set included_p for every referenced header.  */
+   Process the line number information in LH.  */
 
 static void
 dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
-		      const int decode_for_pst_p, CORE_ADDR lowpc)
+		      CORE_ADDR lowpc)
 {
   const gdb_byte *line_ptr, *extended_end;
   const gdb_byte *line_end;
@@ -22520,10 +20173,6 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
   struct objfile *objfile = cu->per_objfile->objfile;
   bfd *abfd = objfile->obfd;
   struct gdbarch *gdbarch = objfile->arch ();
-  /* True if we're recording line info (as opposed to building partial
-     symtabs and just interested in finding include files mentioned by
-     the line number program).  */
-  bool record_lines_p = !decode_for_pst_p;
 
   baseaddr = objfile->text_section_offset ();
 
@@ -22535,18 +20184,15 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
     {
       /* The DWARF line number program state machine.  Reset the state
 	 machine at the start of each sequence.  */
-      lnp_state_machine state_machine (cu, gdbarch, lh, record_lines_p);
+      lnp_state_machine state_machine (cu, gdbarch, lh);
       bool end_sequence = false;
 
-      if (record_lines_p)
-	{
-	  /* Start a subfile for the current file of the state
-	     machine.  */
-	  const file_entry *fe = state_machine.current_file ();
+      /* Start a subfile for the current file of the state
+	 machine.  */
+      const file_entry *fe = state_machine.current_file ();
 
-	  if (fe != NULL)
-	    dwarf2_start_subfile (cu, fe->name, fe->include_dir (lh));
-	}
+      if (fe != NULL)
+	dwarf2_start_subfile (cu, fe->name, fe->include_dir (lh));
 
       /* Decode the table.  */
       while (line_ptr < line_end && !end_sequence)
@@ -22724,13 +20370,6 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
    structure and CU.  The actual information extracted and the type
    of structures created from the LNP depends on the value of PST.
 
-   1. If PST is NULL, then this procedure uses the data from the program
-      to create all necessary symbol tables, and their linetables.
-
-   2. If PST is not NULL, this procedure reads the program to determine
-      the list of files included by the unit represented by PST, and
-      builds all the associated partial symbol tables.
-
    FND holds the CU file name and directory, if known.
    It is used for relative paths in the line table.
 
@@ -22748,52 +20387,28 @@ dwarf_decode_lines_1 (struct line_header *lh, struct dwarf2_cu *cu,
    table is read in.  */
 
 static void
-dwarf_decode_lines (struct line_header *lh, const file_and_directory &fnd,
-		    struct dwarf2_cu *cu, dwarf2_psymtab *pst,
+dwarf_decode_lines (struct line_header *lh, struct dwarf2_cu *cu,
 		    CORE_ADDR lowpc, int decode_mapping)
 {
-  struct objfile *objfile = cu->per_objfile->objfile;
-  const int decode_for_pst_p = (pst != NULL);
-
   if (decode_mapping)
-    dwarf_decode_lines_1 (lh, cu, decode_for_pst_p, lowpc);
+    dwarf_decode_lines_1 (lh, cu, lowpc);
 
-  if (decode_for_pst_p)
-    {
-      /* Now that we're done scanning the Line Header Program, we can
-	 create the psymtab of each included file.  */
-      for (auto &file_entry : lh->file_names ())
-	if (file_entry.included_p)
-	  {
-	    gdb::unique_xmalloc_ptr<char> name_holder;
-	    const char *include_name =
-	      compute_include_file_name (lh, file_entry, fnd, &name_holder);
-	    if (include_name != NULL)
-	      dwarf2_create_include_psymtab
-		(cu->per_objfile->per_bfd, include_name, pst,
-		 cu->per_objfile->per_bfd->partial_symtabs.get (),
-		 objfile->per_bfd);
-	  }
-    }
-  else
-    {
-      /* Make sure a symtab is created for every file, even files
-	 which contain only variables (i.e. no code with associated
-	 line numbers).  */
-      buildsym_compunit *builder = cu->get_builder ();
-      struct compunit_symtab *cust = builder->get_compunit_symtab ();
+  /* Make sure a symtab is created for every file, even files
+     which contain only variables (i.e. no code with associated
+     line numbers).  */
+  buildsym_compunit *builder = cu->get_builder ();
+  struct compunit_symtab *cust = builder->get_compunit_symtab ();
 
-      for (auto &fe : lh->file_names ())
+  for (auto &fe : lh->file_names ())
+    {
+      dwarf2_start_subfile (cu, fe.name, fe.include_dir (lh));
+      if (builder->get_current_subfile ()->symtab == NULL)
 	{
-	  dwarf2_start_subfile (cu, fe.name, fe.include_dir (lh));
-	  if (builder->get_current_subfile ()->symtab == NULL)
-	    {
-	      builder->get_current_subfile ()->symtab
-		= allocate_symtab (cust,
-				   builder->get_current_subfile ()->name);
-	    }
-	  fe.symtab = builder->get_current_subfile ()->symtab;
+	  builder->get_current_subfile ()->symtab
+	    = allocate_symtab (cust,
+			       builder->get_current_subfile ()->name);
 	}
+      fe.symtab = builder->get_current_subfile ()->symtab;
     }
 }
 
@@ -24525,7 +22140,6 @@ follow_die_offset (sect_offset sect_off, int offset_in_dwz,
   else if (cu->dies == NULL)
     {
       /* We're loading full DIEs during partial symbol reading.  */
-      gdb_assert (per_objfile->per_bfd->reading_partial_symbols);
       load_full_comp_unit (cu->per_cu, per_objfile, cu, false,
 			   language_minimal);
     }
@@ -25067,9 +22681,6 @@ load_full_type_unit (dwarf2_per_cu_data *per_cu,
 {
   struct signatured_type *sig_type;
 
-  /* Caller is responsible for ensuring type_unit_groups don't get here.  */
-  gdb_assert (! per_cu->type_unit_group_p ());
-
   /* We have the per_cu, but we need the signatured_type.
      Fortunately this is an easy translation.  */
   gdb_assert (per_cu->is_debug_types);
@@ -26109,32 +23720,6 @@ get_die_type (struct die_info *die, struct dwarf2_cu *cu)
   return get_die_type_at_offset (die->sect_off, cu->per_cu, cu->per_objfile);
 }
 
-/* Trivial hash function for partial_die_info: the hash value of a DIE
-   is its offset in .debug_info for this objfile.  */
-
-static hashval_t
-partial_die_hash (const void *item)
-{
-  const struct partial_die_info *part_die
-    = (const struct partial_die_info *) item;
-
-  return to_underlying (part_die->sect_off);
-}
-
-/* Trivial comparison function for partial_die_info structures: two DIEs
-   are equal if they have the same offset.  */
-
-static int
-partial_die_eq (const void *item_lhs, const void *item_rhs)
-{
-  const struct partial_die_info *part_die_lhs
-    = (const struct partial_die_info *) item_lhs;
-  const struct partial_die_info *part_die_rhs
-    = (const struct partial_die_info *) item_rhs;
-
-  return part_die_lhs->sect_off == part_die_rhs->sect_off;
-}
-
 struct cmd_list_element *set_dwarf_cmdlist;
 struct cmd_list_element *show_dwarf_cmdlist;
 
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 45e4739acfd..2e4741234fb 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -30,7 +30,6 @@
 #include "gdb_obstack.h"
 #include "gdbsupport/hash_enum.h"
 #include "gdbsupport/function-view.h"
-#include "psympriv.h"
 
 /* Hold 'maintenance (set|show) dwarf' commands.  */
 extern struct cmd_list_element *set_dwarf_cmdlist;
@@ -50,7 +49,6 @@ struct dwarf2_cu;
 struct dwarf2_debug_sections;
 struct dwarf2_per_bfd;
 struct dwarf2_per_cu_data;
-struct dwarf2_psymtab;
 struct mapped_index;
 struct mapped_debug_names;
 struct signatured_type;
@@ -190,14 +188,8 @@ struct dwarf2_per_cu_data
      should be private, but we can't make it private at the moment.  */
   mutable comp_unit_head m_header {};
 
-  /* When dwarf2_per_bfd::using_index is true, the 'quick' field
-     is active.  Otherwise, the 'psymtab' field is active.  */
   union
   {
-    /* The partial symbol table associated with this compilation unit,
-       or NULL for unread partial units.  */
-    dwarf2_psymtab *psymtab;
-
     /* Data needed by the "quick" functions.  */
     struct dwarf2_per_cu_quick_data *quick;
   } v {};
@@ -280,13 +272,6 @@ struct dwarf2_per_cu_data
     return dwarf_version;
   }
 
-  /* A type unit group has a per_cu object that is recognized by
-     having no section.  */
-  bool type_unit_group_p () const
-  {
-    return section == nullptr;
-  }
-
   /* Free any cached file names.  */
   void free_cached_file_names ();
 };
@@ -376,9 +361,9 @@ struct dwarf2_per_bfd
   /* The corresponding BFD.  */
   bfd *obfd;
 
-  /* Objects that can be shared across objfiles are stored in this
-     obstack or on the psymtab obstack, while objects that are
-     objfile-specific are stored on the objfile obstack.  */
+  /* Objects that can be shared across objfiles may be stored in this
+     obstack, while objects that are objfile-specific are stored on
+     the objfile obstack.  */
   auto_obstack obstack;
 
   dwarf2_section_info info {};
@@ -439,10 +424,6 @@ struct dwarf2_per_bfd
      VMA of 0.  */
   bool has_section_at_zero = false;
 
-  /* True if we are using the mapped index,
-     or we are faking it for OBJF_READNOW's sake.  */
-  bool using_index = false;
-
   /* The mapped index, or NULL if .gdb_index is missing or not being used.  */
   std::unique_ptr<mapped_index> index_table;
 
@@ -461,10 +442,6 @@ struct dwarf2_per_bfd
      CU and its associated TU group if there is one.  */
   htab_up quick_file_names_table;
 
-  /* Set during partial symbol reading, to prevent queueing of full
-     symbols.  */
-  bool reading_partial_symbols = false;
-
   /* The CUs we recently read.  */
   std::vector<dwarf2_per_cu_data *> just_read_cus;
 
@@ -481,11 +458,6 @@ struct dwarf2_per_bfd
   /* CUs that are queued to be read.  */
   gdb::optional<std::queue<dwarf2_queue_item>> queue;
 
-  /* We keep a separate reference to the partial symtabs, in case we
-     are sharing them between objfiles.  This is only set after
-     partial symbols have been read the first time.  */
-  std::shared_ptr<psymtab_storage> partial_symtabs;
-
   /* The address map that is used by the DWARF index code.  */
   struct addrmap *index_addrmap = nullptr;
 };
@@ -615,26 +587,6 @@ struct dwarf2_per_objfile
 
 dwarf2_per_objfile *get_dwarf2_per_objfile (struct objfile *objfile);
 
-/* A partial symtab specialized for DWARF.  */
-struct dwarf2_psymtab : public partial_symtab
-{
-  dwarf2_psymtab (const char *filename,
-		  psymtab_storage *partial_symtabs,
-		  objfile_per_bfd_storage *objfile_per_bfd,
-		  dwarf2_per_cu_data *per_cu)
-    : partial_symtab (filename, partial_symtabs, objfile_per_bfd, 0),
-      per_cu_data (per_cu)
-  {
-  }
-
-  void read_symtab (struct objfile *) override;
-  void expand_psymtab (struct objfile *) override;
-  bool readin_p (struct objfile *) const override;
-  compunit_symtab *get_compunit_symtab (struct objfile *) const override;
-
-  struct dwarf2_per_cu_data *per_cu_data;
-};
-
 /* Return the type of the DIE at DIE_OFFSET in the CU named by
    PER_CU.  */
 
diff --git a/gdb/testsuite/gdb.dwarf2/gdb-index-nodebug.exp b/gdb/testsuite/gdb.dwarf2/gdb-index-nodebug.exp
index 6eb34f9f2c4..c6f7d9bf065 100644
--- a/gdb/testsuite/gdb.dwarf2/gdb-index-nodebug.exp
+++ b/gdb/testsuite/gdb.dwarf2/gdb-index-nodebug.exp
@@ -28,6 +28,11 @@ set have_index_re \
 	 "Error while writing index for \[^\r\n\]*:" \
 	 "Cannot use an index to create the index"]
 set have_index_re [join $have_index_re]
+set no_debug_re \
+    [list \
+	 "Error while writing index for \[^\r\n\]*:" \
+	 "No debugging symbols"]
+set no_debug_re [join $no_debug_re]
 set readnow_p [readnow]
 
 set index_file ${testfile}.gdb-index
@@ -41,6 +46,9 @@ gdb_test_multiple $cmd "try to save gdb index" {
 	    fail $gdb_test_name
 	}
     }
+    -re -wrap $no_debug_re {
+	pass $gdb_test_name
+    }
     -re -wrap "^$cmd" {
 	pass $gdb_test_name
     }
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* [PATCH v2 32/32] Remove dwarf2_per_cu_data::v
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (30 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 31/32] Delete DWARF psymtab code Tom Tromey
@ 2021-11-04 18:09 ` Tom Tromey
  2021-11-06 12:25 ` [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom de Vries
  2021-11-08 17:41 ` Simon Marchi
  33 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-04 18:09 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

Now that the psymtab reader has been removed, the
dwarf2_per_cu_data::v union is no longer needed.  Instead, we can
simply move the members from dwarf2_per_cu_quick_data into
dwarf2_per_cu_data and remove the "quick" object entirely.
---
 gdb/dwarf2/read.c | 75 +++++++++++------------------------------------
 gdb/dwarf2/read.h | 19 ++++++++----
 2 files changed, 31 insertions(+), 63 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index 4c5d6f25369..95cca652eeb 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -1886,25 +1886,6 @@ struct quick_file_names
   const char **real_names;
 };
 
-/* When using the index (and thus not using psymtabs), each CU has an
-   object of this type.  This is used to hold information needed by
-   the various "quick" methods.  */
-struct dwarf2_per_cu_quick_data
-{
-  /* The file table.  This can be NULL if there was no file table
-     or it's currently not read in.
-     NOTE: This points into dwarf2_per_objfile->per_bfd->quick_file_names_table.  */
-  struct quick_file_names *file_names;
-
-  /* A temporary mark bit used when iterating over all CUs in
-     expand_symtabs_matching.  */
-  unsigned int mark : 1;
-
-  /* True if we've tried to read the file table.  There will be no
-     point in trying to read it again next time.  */
-  bool files_read : 1;
-};
-
 struct dwarf2_base_index_functions : public quick_symbol_functions
 {
   bool has_symbols (struct objfile *objfile) override;
@@ -2178,8 +2159,6 @@ create_cu_from_index_list (dwarf2_per_bfd *per_bfd,
   the_cu->sect_off = sect_off;
   the_cu->length = length;
   the_cu->section = section;
-  the_cu->v.quick = OBSTACK_ZALLOC (&per_bfd->obstack,
-				    struct dwarf2_per_cu_quick_data);
   the_cu->is_dwz = is_dwz;
   return the_cu;
 }
@@ -2260,9 +2239,6 @@ create_signatured_type_table_from_index
       sig_type->type_offset_in_tu = type_offset_in_tu;
       sig_type->section = section;
       sig_type->sect_off = sect_off;
-      sig_type->v.quick
-	= OBSTACK_ZALLOC (&per_bfd->obstack,
-			  struct dwarf2_per_cu_quick_data);
 
       slot = htab_find_slot (sig_types_hash.get (), sig_type.get (), INSERT);
       *slot = sig_type.get ();
@@ -2311,9 +2287,6 @@ create_signatured_type_table_from_debug_names
       sig_type->type_offset_in_tu = cu_header.type_cu_offset_in_tu;
       sig_type->section = section;
       sig_type->sect_off = sect_off;
-      sig_type->v.quick
-	= OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
-			  struct dwarf2_per_cu_quick_data);
 
       slot = htab_find_slot (sig_types_hash.get (), sig_type.get (), INSERT);
       *slot = sig_type.get ();
@@ -2789,7 +2762,7 @@ dw2_get_file_names_reader (const struct die_reader_specs *reader,
 
   gdb_assert (! this_cu->is_debug_types);
 
-  this_cu->v.quick->files_read = true;
+  this_cu->files_read = true;
   /* Our callers never want to match partial units -- instead they
      will match the enclosing full CU.  */
   if (comp_unit_die->tag == DW_TAG_partial_unit)
@@ -2816,7 +2789,7 @@ dw2_get_file_names_reader (const struct die_reader_specs *reader,
 			     &find_entry, INSERT);
       if (*slot != NULL)
 	{
-	  lh_cu->v.quick->file_names = (struct quick_file_names *) *slot;
+	  lh_cu->file_names = (struct quick_file_names *) *slot;
 	  return;
 	}
 
@@ -2868,7 +2841,7 @@ dw2_get_file_names_reader (const struct die_reader_specs *reader,
 
   qfn->real_names = NULL;
 
-  lh_cu->v.quick->file_names = qfn;
+  lh_cu->file_names = qfn;
 }
 
 /* A helper for the "quick" functions which attempts to read the line
@@ -2881,14 +2854,14 @@ dw2_get_file_names (dwarf2_per_cu_data *this_cu,
   /* This should never be called for TUs.  */
   gdb_assert (! this_cu->is_debug_types);
 
-  if (this_cu->v.quick->files_read)
-    return this_cu->v.quick->file_names;
+  if (this_cu->files_read)
+    return this_cu->file_names;
 
   cutu_reader reader (this_cu, per_objfile);
   if (!reader.dummy_p)
     dw2_get_file_names_reader (&reader, reader.comp_unit_die);
 
-  return this_cu->v.quick->file_names;
+  return this_cu->file_names;
 }
 
 /* A helper for the "quick" functions which computes and caches the
@@ -2937,10 +2910,10 @@ dwarf2_base_index_functions::find_last_source_symtab (struct objfile *objfile)
 void
 dwarf2_per_cu_data::free_cached_file_names ()
 {
-  if (per_bfd == nullptr || v.quick == nullptr)
+  if (per_bfd == nullptr)
     return;
 
-  struct quick_file_names *file_data = v.quick->file_names;
+  struct quick_file_names *file_data = file_names;
   if (file_data != nullptr && file_data->real_names != nullptr)
     {
       for (int i = 0; i < file_data->num_file_names; ++i)
@@ -4012,7 +3985,7 @@ dw2_expand_symtabs_matching_one
    gdb::function_view<expand_symtabs_file_matcher_ftype> file_matcher,
    gdb::function_view<expand_symtabs_exp_notify_ftype> expansion_notify)
 {
-  if (file_matcher == NULL || per_cu->v.quick->mark)
+  if (file_matcher == NULL || per_cu->mark)
     {
       bool symtab_was_null = !per_objfile->symtab_set_p (per_cu);
 
@@ -4153,7 +4126,7 @@ dw_expand_symtabs_matching_file_matcher
 
       if (per_cu->is_debug_types)
 	continue;
-      per_cu->v.quick->mark = 0;
+      per_cu->mark = 0;
 
       /* We only need to look at symtabs not already expanded.  */
       if (per_objfile->symtab_set_p (per_cu.get ()))
@@ -4168,7 +4141,7 @@ dw_expand_symtabs_matching_file_matcher
 	continue;
       else if (htab_find (visited_found.get (), file_data) != NULL)
 	{
-	  per_cu->v.quick->mark = 1;
+	  per_cu->mark = 1;
 	  continue;
 	}
 
@@ -4178,7 +4151,7 @@ dw_expand_symtabs_matching_file_matcher
 
 	  if (file_matcher (file_data->file_names[j], false))
 	    {
-	      per_cu->v.quick->mark = 1;
+	      per_cu->mark = 1;
 	      break;
 	    }
 
@@ -4192,12 +4165,12 @@ dw_expand_symtabs_matching_file_matcher
 	  this_real_name = dw2_get_real_path (per_objfile, file_data, j);
 	  if (file_matcher (this_real_name, false))
 	    {
-	      per_cu->v.quick->mark = 1;
+	      per_cu->mark = 1;
 	      break;
 	    }
 	}
 
-      void **slot = htab_find_slot (per_cu->v.quick->mark
+      void **slot = htab_find_slot (per_cu->mark
 				    ? visited_found.get ()
 				    : visited_not_found.get (),
 				    file_data, INSERT);
@@ -4341,8 +4314,8 @@ dwarf2_base_index_functions::map_symbol_filenames
       if (!per_cu->is_debug_types
 	  && per_objfile->symtab_set_p (per_cu.get ()))
 	{
-	  if (per_cu->v.quick->file_names != nullptr)
-	    qfn_cache.insert (per_cu->v.quick->file_names);
+	  if (per_cu->file_names != nullptr)
+	    qfn_cache.insert (per_cu->file_names);
 	}
     }
 
@@ -5333,14 +5306,6 @@ dwarf2_initialize_objfile (struct objfile *objfile)
       per_bfd->quick_file_names_table
 	= create_quick_file_names_table (per_bfd->all_comp_units.size ());
 
-      for (int i = 0; i < per_bfd->all_comp_units.size (); ++i)
-	{
-	  dwarf2_per_cu_data *per_cu = per_bfd->get_cu (i);
-
-	  per_cu->v.quick = OBSTACK_ZALLOC (&per_bfd->obstack,
-					    struct dwarf2_per_cu_quick_data);
-	}
-
       /* Arrange for gdb to see the "quick" functions.  However, these
 	 functions will be no-ops because we will have expanded all
 	 symtabs.  */
@@ -5667,8 +5632,6 @@ add_type_unit (dwarf2_per_objfile *per_objfile, ULONGEST sig, void **slot)
 
   per_objfile->per_bfd->all_comp_units.emplace_back
     (sig_type_holder.release ());
-  sig_type->v.quick = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
-				      struct dwarf2_per_cu_quick_data);
 
   if (slot == NULL)
     {
@@ -5694,7 +5657,6 @@ fill_in_sig_entry_from_dwo_entry (dwarf2_per_objfile *per_objfile,
   /* Make sure we're not clobbering something we don't expect to.  */
   gdb_assert (! sig_entry->queued);
   gdb_assert (per_objfile->get_cu (sig_entry) == NULL);
-  gdb_assert (sig_entry->v.quick != NULL);
   gdb_assert (!per_objfile->symtab_set_p (sig_entry));
   gdb_assert (sig_entry->signature == dwo_entry->signature);
   gdb_assert (to_underlying (sig_entry->type_offset_in_section) == 0
@@ -7267,9 +7229,6 @@ read_comp_units_from_section (dwarf2_per_objfile *per_objfile,
       this_cu->is_dwz = is_dwz;
       this_cu->section = section;
 
-      this_cu->v.quick = OBSTACK_ZALLOC (&per_objfile->per_bfd->obstack,
-					 struct dwarf2_per_cu_quick_data);
-
       info_ptr = info_ptr + this_cu->length;
       per_objfile->per_bfd->all_comp_units.push_back (std::move (this_cu));
     }
@@ -18611,7 +18570,7 @@ cooked_index_functions::expand_symtabs_matching
 
 	  /* If file-matching was done, we don't need to consider
 	     symbols from unmarked CUs.  */
-	  if (file_matcher != nullptr && !entry->per_cu->v.quick->mark)
+	  if (file_matcher != nullptr && !entry->per_cu->mark)
 	    continue;
 
 	  /* See if the symbol matches the type filter.  */
diff --git a/gdb/dwarf2/read.h b/gdb/dwarf2/read.h
index 2e4741234fb..50fd3faf782 100644
--- a/gdb/dwarf2/read.h
+++ b/gdb/dwarf2/read.h
@@ -103,6 +103,8 @@ struct dwarf2_per_cu_data
       tu_read (false),
       m_header_read_in (false),
       addresses_seen (false),
+      mark (false),
+      files_read (false),
       unit_type {},
       lang (language_unknown),
       scanned (false)
@@ -158,6 +160,14 @@ struct dwarf2_per_cu_data
      .debug_aranges), then this flag is set.  */
   bool addresses_seen : 1;
 
+  /* A temporary mark bit used when iterating over all CUs in
+     expand_symtabs_matching.  */
+  unsigned int mark : 1;
+
+  /* True if we've tried to read the file table.  There will be no
+     point in trying to read it again next time.  */
+  bool files_read : 1;
+
   /* The unit type of this CU.  */
   ENUM_BITFIELD (dwarf_unit_type) unit_type : 8;
 
@@ -188,11 +198,10 @@ struct dwarf2_per_cu_data
      should be private, but we can't make it private at the moment.  */
   mutable comp_unit_head m_header {};
 
-  union
-  {
-    /* Data needed by the "quick" functions.  */
-    struct dwarf2_per_cu_quick_data *quick;
-  } v {};
+  /* The file table.  This can be NULL if there was no file table
+     or it's currently not read in.
+     NOTE: This points into dwarf2_per_objfile->per_bfd->quick_file_names_table.  */
+  struct quick_file_names *file_names = nullptr;
 
   /* The CUs we import using DW_TAG_imported_unit.  This is filled in
      while reading psymtabs, used to compute the psymtab dependencies,
-- 
2.31.1


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/32] Introduce make_unique_xstrndup
  2021-11-04 18:08 ` [PATCH v2 01/32] Introduce make_unique_xstrndup Tom Tromey
@ 2021-11-05 19:20   ` Simon Marchi
  2021-11-05 20:08     ` Tom Tromey
  0 siblings, 1 reply; 53+ messages in thread
From: Simon Marchi @ 2021-11-05 19:20 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 2021-11-04 2:08 p.m., Tom Tromey wrote:
> This adds a new make_unique_xstrndup function, which is the "n"
> analogue of make_unique_xstrdup.  This is used by later patches.
> ---
>  gdbsupport/gdb_unique_ptr.h | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/gdbsupport/gdb_unique_ptr.h b/gdbsupport/gdb_unique_ptr.h
> index df88cea9cf0..77aecb48e62 100644
> --- a/gdbsupport/gdb_unique_ptr.h
> +++ b/gdbsupport/gdb_unique_ptr.h
> @@ -64,4 +64,13 @@ make_unique_xstrdup (const char *str)
>    return gdb::unique_xmalloc_ptr<char> (xstrdup (str));
>  }
>  
> +/* Dup the first N characters of STR and return a unique_xmalloc_ptr
> +   for the result.  The result is always \0-terminated.  */
> +
> +static inline gdb::unique_xmalloc_ptr<char>
> +make_unique_xstrndup (const char *str, size_t n)
> +{
> +  return gdb::unique_xmalloc_ptr<char> (xstrndup (str, n));
> +}
> +
>  #endif /* COMMON_GDB_UNIQUE_PTR_H */
> -- 
> 2.31.1
> 

I found one spot where you could use this, in cli/cli-setshow.exp.  I think
that if the new function is used, this patch could be pushed right away.

Simon

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 04/32] Refactor dwarf2_get_pc_bounds
  2021-11-04 18:08 ` [PATCH v2 04/32] Refactor dwarf2_get_pc_bounds Tom Tromey
@ 2021-11-05 19:51   ` Simon Marchi
  2021-11-24 15:53     ` Tom Tromey
  0 siblings, 1 reply; 53+ messages in thread
From: Simon Marchi @ 2021-11-05 19:51 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

> @@ -14036,10 +14044,9 @@ dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu, dwarf_tag tag,
>  static int
>  dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
>  		    CORE_ADDR *high_return, struct dwarf2_cu *cu,
> -		    dwarf2_psymtab *ranges_pst, dwarf_tag tag)
> +		    addrmap *map, void *datum, dwarf_tag tag)

Perhaps it's code that is going to be deleted anyway, but the comment
above this would need to be updated.


^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 08/32] Add new overload of dwarf5_djb_hash
  2021-11-04 18:08 ` [PATCH v2 08/32] Add new overload of dwarf5_djb_hash Tom Tromey
@ 2021-11-05 20:01   ` Simon Marchi
  2021-11-07 17:02     ` Tom Tromey
  0 siblings, 1 reply; 53+ messages in thread
From: Simon Marchi @ 2021-11-05 20:01 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 2021-11-04 2:08 p.m., Tom Tromey wrote:
> This adds a new overload of dwarf5_djb_hash.  This is used in
> subsequent patches.
> ---
>  gdb/dwarf2/index-common.c | 15 +++++++++++++++
>  gdb/dwarf2/index-common.h |  4 ++++
>  2 files changed, 19 insertions(+)
> 
> diff --git a/gdb/dwarf2/index-common.c b/gdb/dwarf2/index-common.c
> index 1c02730a3fe..4bad82218c2 100644
> --- a/gdb/dwarf2/index-common.c
> +++ b/gdb/dwarf2/index-common.c
> @@ -54,3 +54,18 @@ dwarf5_djb_hash (const char *str_)
>      hash = hash * 33 + tolower (c);
>    return hash;
>  }
> +
> +/* See dwarf-index-common.h.  */
> +
> +uint32_t
> +dwarf5_djb_hash (gdb::string_view str)
> +{
> +  /* Note: tolower here ignores UTF-8, which isn't fully compliant.
> +     See http://dwarfstd.org/ShowIssue.php?issue=161027.1.  */
> +
> +  uint32_t hash = 5381;
> +  size_t len = str.length ();
> +  for (size_t i = 0; i < len; ++i)
> +    hash = hash * 33 + tolower (str[i] & 0xff);
> +  return hash;
> +}

For bonus points, you could iterate using:

  for (char c : str)

... unless you see a good reason not to.

Simon

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 01/32] Introduce make_unique_xstrndup
  2021-11-05 19:20   ` Simon Marchi
@ 2021-11-05 20:08     ` Tom Tromey
  0 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-05 20:08 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

Simon> I found one spot where you could use this, in cli/cli-setshow.exp.  I think
Simon> that if the new function is used, this patch could be pushed right away.

Thanks.  I found a second spot as well, and I'm going to check in the
appended.

Tom

commit be77dd73c769b3e7ac62bd4c0b98242b62d080e0
Author: Tom Tromey <tom@tromey.com>
Date:   Fri Jun 4 16:00:33 2021 -0600

    Introduce make_unique_xstrndup
    
    This adds a new make_unique_xstrndup function, which is the "n"
    analogue of make_unique_xstrdup.  It also updates a couple existing
    places to use this function.

diff --git a/gdb/cli/cli-setshow.c b/gdb/cli/cli-setshow.c
index dcb50caf5e3..18e2d4ed5c8 100644
--- a/gdb/cli/cli-setshow.c
+++ b/gdb/cli/cli-setshow.c
@@ -375,14 +375,13 @@ do_set_command (const char *arg, int from_tty, struct cmd_list_element *c)
 	  {
 	    /* Clear trailing whitespace of filename.  */
 	    const char *ptr = arg + strlen (arg) - 1;
-	    char *copy;
 
 	    while (ptr >= arg && (*ptr == ' ' || *ptr == '\t'))
 	      ptr--;
-	    copy = xstrndup (arg, ptr + 1 - arg);
+	    gdb::unique_xmalloc_ptr<char> copy
+	      = make_unique_xstrndup (arg, ptr + 1 - arg);
 
-	    val = tilde_expand (copy);
-	    xfree (copy);
+	    val = tilde_expand (copy.get ());
 	  }
 	else
 	  val = xstrdup ("");
diff --git a/gdb/parse.c b/gdb/parse.c
index b2f23eb67bb..a76a6c1afdb 100644
--- a/gdb/parse.c
+++ b/gdb/parse.c
@@ -199,7 +199,8 @@ parser_state::mark_completion_tag (enum type_code tag, const char *ptr,
 	      || tag == TYPE_CODE_STRUCT
 	      || tag == TYPE_CODE_ENUM);
   m_completion_state.expout_tag_completion_type = tag;
-  m_completion_state.expout_completion_name.reset (xstrndup (ptr, length));
+  m_completion_state.expout_completion_name
+    = make_unique_xstrndup (ptr, length);
 }
 
 /* See parser-defs.h.  */
diff --git a/gdbsupport/gdb_unique_ptr.h b/gdbsupport/gdb_unique_ptr.h
index df88cea9cf0..77aecb48e62 100644
--- a/gdbsupport/gdb_unique_ptr.h
+++ b/gdbsupport/gdb_unique_ptr.h
@@ -64,4 +64,13 @@ make_unique_xstrdup (const char *str)
   return gdb::unique_xmalloc_ptr<char> (xstrdup (str));
 }
 
+/* Dup the first N characters of STR and return a unique_xmalloc_ptr
+   for the result.  The result is always \0-terminated.  */
+
+static inline gdb::unique_xmalloc_ptr<char>
+make_unique_xstrndup (const char *str, size_t n)
+{
+  return gdb::unique_xmalloc_ptr<char> (xstrndup (str, n));
+}
+
 #endif /* COMMON_GDB_UNIQUE_PTR_H */

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (31 preceding siblings ...)
  2021-11-04 18:09 ` [PATCH v2 32/32] Remove dwarf2_per_cu_data::v Tom Tromey
@ 2021-11-06 12:25 ` Tom de Vries
  2021-11-11 12:23   ` Tom de Vries
  2021-11-16 23:56   ` Tom Tromey
  2021-11-08 17:41 ` Simon Marchi
  33 siblings, 2 replies; 53+ messages in thread
From: Tom de Vries @ 2021-11-06 12:25 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 11/4/21 7:08 PM, Tom Tromey wrote:
> Here is v2 of my series to rewrit the DWARF partial symbol reader.
> 
> You can find v1 here:
> 
>     https://sourceware.org/pipermail/gdb-patches/2021-August/181624.html
> 
> This update addresses all the review comments.  I believe it fixes all
> the problems that Tom de Vries found.
> 
> I regression tested this on x86-64 Fedora 34.
> 

I regression tested this on openSUSE Leap 15.2 x86_64 and got only known
FAILs:
...
FAIL: gdb.base/step-over-syscall.exp: clone: displaced=off: single step
over clone (timeout)
FAIL: gdb.cp/no-dmgl-verbose.exp: setting breakpoint at 'f(std::string)'
FAIL: gdb.go/package.exp: setting breakpoint at package2.Foo
FAIL: gdb.go/package.exp: going to first breakpoint (the program exited)
...

So that looks great :)

Then I tried an experiment with parsing all .debug files installed on
the system which happens to be 636 files, totaling at 4.8 GB.

More concretely, I ran this command in a file loop:
...
$ for f in $(find /usr/lib/debug/ -name "*.debug" | grep -v build-id);
do echo "Loading $f"; gdb -q -batch $f; done 2>&1 | tee LOG
...

My idea was to compare execution times, but instead I ran into some
trouble (while using master instead, everything worked fine).

This triggered a fair amount of times:
...
$ grep -c "has duplicate debug_info_offset 0x0, ignoring .debug_aranges" LOG
40
...
as well as:
...
$ grep -c "DW_FORM_GNU_strp_alt used without .debug_str" LOG
16
...

I managed to reproduce both with a hello world, like so:
...
$ cat ./hello.c
#include <stdio.h>

int
main (void)
{
  printf
("hello00000000000000000000000000000000000000000000000000000000000000000000\n");
  return 0;
}
$ gcc ./hello.c -g
$ cp a.out b.out
$ dwz -m c.out a.out b.out
$ gdb -q -batch a.out

warning: Section .debug_aranges in /home/vries/gdb_versions/devel/a.out
has duplicate debug_info_offset 0x0, ignoring .debug_aranges.
DW_FORM_GNU_strp_alt used without .debug_str section [in module
/home/vries/gdb_versions/devel/c.out]
...

The latter may or may not trigger, and disappears with "maint set
worker-thread 0".

The exec seems sane.

The .debug_aranges section does not have duplicates, and does not
contain a .debug_info offset 0x0:
...
$ readelf -wr a.out | egrep "debug_aranges|Offset into"
Contents of the .debug_aranges section:
  Offset into .debug_info:  0x1f
  Offset into .debug_info:  0x4d
  Offset into .debug_info:  0x87
  Offset into .debug_info:  0xa9
  Offset into .debug_info:  0xf5
  Offset into .debug_info:  0x1ce
...

The a.out indeed doesn't have a .debug_str, but the .gnu_debuglink file
c.out does:
...
$ readelf -S -W a.out | grep debug_str
$
$ readelf -S -W c.out | grep debug_str
  [ 5] .debug_str        PROGBITS        0000000000000000 0005a1 0005fe
01  MS  0   0  1
$
...

I managed to reproduce both problems using system compiler gcc 7.5.0 and
gcc 11.2.1. [ If you have trouble reproducing this, maybe the target
boards cc-with-dwz and cc-with-dwz-m will help. ]

Thanks,
- Tom

> Let me know what you think.
> 
> Tom
> 
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 08/32] Add new overload of dwarf5_djb_hash
  2021-11-05 20:01   ` Simon Marchi
@ 2021-11-07 17:02     ` Tom Tromey
  0 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-07 17:02 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

Simon> For bonus points, you could iterate using:

Simon>   for (char c : str)

Simon> ... unless you see a good reason not to.

I made this change on my branch.

thanks,
Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
                   ` (32 preceding siblings ...)
  2021-11-06 12:25 ` [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom de Vries
@ 2021-11-08 17:41 ` Simon Marchi
  2021-11-10 19:56   ` Tom Tromey
  33 siblings, 1 reply; 53+ messages in thread
From: Simon Marchi @ 2021-11-08 17:41 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 2021-11-04 2:08 p.m., Tom Tromey wrote:
> Here is v2 of my series to rewrit the DWARF partial symbol reader.
>
> You can find v1 here:
>
>     https://sourceware.org/pipermail/gdb-patches/2021-August/181624.html
>
> This update addresses all the review comments.  I believe it fixes all
> the problems that Tom de Vries found.
>
> I regression tested this on x86-64 Fedora 34.
>
> Let me know what you think.
>
> Tom
>
>

Hi Tom,

I did go through the series, I don't have any objection, and don't have
much constructive comments, because I'm not that aware of how things
work currently with partial symtabs.

What I think I understand is that with the new indexer, we gather
essentially the same information that we gather today with partial
symbols (just the information needed for doing lookups and expanding
symtabs), but store it in a data structure that is better designed,
letting us do more in parallel.  Does that sounds right?  If not, can
you explain what's the main difference?

What sounds nice with partial symtabs is that they are re-used by
different debug formats, so each format doesn't need to implement its
own data structures to manage symtab lookups and expansion.  How much is
that new DWARF indexer really DWARF-specific (the part that parses the
DWARF obviously is, but the part that holds names and stuff)?  Could it
one day be used by other debug formats?

Simon

Simon

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-08 17:41 ` Simon Marchi
@ 2021-11-10 19:56   ` Tom Tromey
  0 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-10 19:56 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

Simon> What I think I understand is that with the new indexer, we gather
Simon> essentially the same information that we gather today with partial
Simon> symbols (just the information needed for doing lookups and expanding
Simon> symtabs), but store it in a data structure that is better designed,
Simon> letting us do more in parallel.  Does that sounds right?  If not, can
Simon> you explain what's the main difference?

Yeah, the biggest gains are due to parallelism.  The single largest
user-visible change comes from pushing the necessary post-processing
into a background thread.

However there are various smaller gains in the series as well:

* Abbrevs are analyzed statically, so we can skip many more DIEs without
  examining their contents.
* The partial DIE cache is eliminated.
* Name canonicalization is done just on the name in the DIE,
  rather than constructing a full name and then canonicalizing the
  entire thing.
* The abbrev cache may also speed up DWARF scanning in some scenarios.

Simon> What sounds nice with partial symtabs is that they are re-used by
Simon> different debug formats, so each format doesn't need to implement its
Simon> own data structures to manage symtab lookups and expansion.

True, but this is also a drawback, because psymtabs weren't really
designed for DWARF.  I tried many times to speed up the existing reader,
and couldn't make it work...

Also, another way to look at this is that the new approach shares more
code with the existing DWARF index readers.  It also provides the
possibility of making the .debug_names writer work correctly (currently
it is far from what the standard requires).

Simon> How much is
Simon> that new DWARF indexer really DWARF-specific (the part that parses the
Simon> DWARF obviously is, but the part that holds names and stuff)?  Could it
Simon> one day be used by other debug formats?

Not readily, because AFAIK the other debug formats aren't hierarchical
in nature.  Except for Ada (which as always works in its own way), the
new reader uses the hierarchical nature of DWARF to simplify the
resulting data structure.  (For Ada, this same thing is done, but in a
post-processing step.)

Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-06 12:25 ` [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom de Vries
@ 2021-11-11 12:23   ` Tom de Vries
  2021-11-16 23:56   ` Tom Tromey
  1 sibling, 0 replies; 53+ messages in thread
From: Tom de Vries @ 2021-11-11 12:23 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 11/6/21 1:25 PM, Tom de Vries via Gdb-patches wrote:
> On 11/4/21 7:08 PM, Tom Tromey wrote:
>> Here is v2 of my series to rewrit the DWARF partial symbol reader.
>>
>> You can find v1 here:
>>
>>     https://sourceware.org/pipermail/gdb-patches/2021-August/181624.html
>>
>> This update addresses all the review comments.  I believe it fixes all
>> the problems that Tom de Vries found.
>>
>> I regression tested this on x86-64 Fedora 34.
>>
> 
> I regression tested this on openSUSE Leap 15.2 x86_64 and got only known
> FAILs:
> ...
> FAIL: gdb.base/step-over-syscall.exp: clone: displaced=off: single step
> over clone (timeout)
> FAIL: gdb.cp/no-dmgl-verbose.exp: setting breakpoint at 'f(std::string)'
> FAIL: gdb.go/package.exp: setting breakpoint at package2.Foo
> FAIL: gdb.go/package.exp: going to first breakpoint (the program exited)
> ...
> 
> So that looks great :)
> 
> Then I tried an experiment with parsing all .debug files installed on
> the system which happens to be 636 files, totaling at 4.8 GB.
> 
> More concretely, I ran this command in a file loop:
> ...
> $ for f in $(find /usr/lib/debug/ -name "*.debug" | grep -v build-id);
> do echo "Loading $f"; gdb -q -batch $f; done 2>&1 | tee LOG
> ...
> 
> My idea was to compare execution times, but instead I ran into some
> trouble (while using master instead, everything worked fine).
> 
> This triggered a fair amount of times:
> ...
> $ grep -c "has duplicate debug_info_offset 0x0, ignoring .debug_aranges" LOG
> 40
> ...
> as well as:
> ...
> $ grep -c "DW_FORM_GNU_strp_alt used without .debug_str" LOG
> 16
> ...
> 
> I managed to reproduce both with a hello world, like so:
> ...
> $ cat ./hello.c
> #include <stdio.h>
> 
> int
> main (void)
> {
>   printf
> ("hello00000000000000000000000000000000000000000000000000000000000000000000\n");
>   return 0;
> }
> $ gcc ./hello.c -g
> $ cp a.out b.out
> $ dwz -m c.out a.out b.out
> $ gdb -q -batch a.out
> 
> warning: Section .debug_aranges in /home/vries/gdb_versions/devel/a.out
> has duplicate debug_info_offset 0x0, ignoring .debug_aranges.
> DW_FORM_GNU_strp_alt used without .debug_str section [in module
> /home/vries/gdb_versions/devel/c.out]
> ...
> 

OK, I see now what is going wrong.

The compilation unit offsets are:
...
$ readelf --dwarf-depth 0 -wi ./a.out | grep @
  Compilation Unit @ offset 0x0:
  Compilation Unit @ offset 0x1f:
  Compilation Unit @ offset 0x4d:
  Compilation Unit @ offset 0x87:
  Compilation Unit @ offset 0xa9:
  Compilation Unit @ offset 0xf5:
  Compilation Unit @ offset 0x1ce:
$ readelf --dwarf-depth 0 -wi ./c.out | grep @
  Compilation Unit @ offset 0x0:
  Compilation Unit @ offset 0x38:
  Compilation Unit @ offset 0x5e:
  Compilation Unit @ offset 0x2aa:
  Compilation Unit @ offset 0x330:
...
and at the moment of the warning we have:
...
(gdb) p (*per_bfd->all_comp_units[0])->sect_off
$42 = 0
(gdb) p (*per_bfd->all_comp_units[1])->sect_off
$43 = (unknown: 0x1f)
(gdb) p (*per_bfd->all_comp_units[7])->sect_off
$44 = 0
(gdb) p (*per_bfd->all_comp_units[8])->sect_off
$45 = (unknown: 0x38)
...

So, the CUs of a.out and c.out end up in the same vector, and that
triggers the duplicate offset warning.

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-06 12:25 ` [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom de Vries
  2021-11-11 12:23   ` Tom de Vries
@ 2021-11-16 23:56   ` Tom Tromey
  2021-11-17  9:22     ` Tom de Vries
                       ` (2 more replies)
  1 sibling, 3 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-16 23:56 UTC (permalink / raw)
  To: Tom de Vries; +Cc: Tom Tromey, gdb-patches

Tom> This triggered a fair amount of times:
Tom> ...
Tom> $ grep -c "has duplicate debug_info_offset 0x0, ignoring .debug_aranges" LOG
Tom> 40

I think this is something of a latent bug, and the fix I applied is to
skip DWZ units in this loop.  I don't think .debug_aranges can refer to
a CU coming from the DWZ file.

Tom> $ grep -c "DW_FORM_GNU_strp_alt used without .debug_str" LOG
Tom> 16
Tom> ...

I think this happens because I failed to consider DWZ files in the
pre-reading patch.  I've applied a fix to pre-read some of the debug
sections from this file.  I couldn't reproduce the bug myself.

I really appreciate the testing you've done.  I'll send v3 of the series
once I do some more testing... I plan to regression test with a few
different approaches (dwz, probably split DWARF too).  Meanwhile the
unpolished version is on the 'submit/no-more-psym' branch in my github.

thanks,
Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-16 23:56   ` Tom Tromey
@ 2021-11-17  9:22     ` Tom de Vries
  2021-11-18 14:43     ` Tom Tromey
  2021-11-22 19:59     ` Tom Tromey
  2 siblings, 0 replies; 53+ messages in thread
From: Tom de Vries @ 2021-11-17  9:22 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 11/17/21 12:56 AM, Tom Tromey wrote:
> Tom> This triggered a fair amount of times:
> Tom> ...
> Tom> $ grep -c "has duplicate debug_info_offset 0x0, ignoring .debug_aranges" LOG
> Tom> 40
> 
> I think this is something of a latent bug, and the fix I applied is to
> skip DWZ units in this loop.  I don't think .debug_aranges can refer to
> a CU coming from the DWZ file.
> 

Ack, that makes sense to me.

> Tom> $ grep -c "DW_FORM_GNU_strp_alt used without .debug_str" LOG
> Tom> 16
> Tom> ...
> 
> I think this happens because I failed to consider DWZ files in the
> pre-reading patch.  I've applied a fix to pre-read some of the debug
> sections from this file.  I couldn't reproduce the bug myself.
> 
Both problems are gone in the latest version, thanks.

> I really appreciate the testing you've done. 

No problem :)

> I'll send v3 of the series
> once I do some more testing... I plan to regression test with a few
> different approaches (dwz, probably split DWARF too).  Meanwhile the
> unpolished version is on the 'submit/no-more-psym' branch in my github.
> 

I've done now the experiment I set out to do: I build with -O2 two
configurations:
- merge-base (git merge-base master no-more-psym)
- no-more-psym
and ran the loop over .debug files, twice (with gdb worker-threads
defaulting to 4 on my dual-core-4-thread CPU).

results merge-base:

real    2m44.899s
user    2m43.299s
sys     0m11.635s

real    2m44.451s
user    2m43.121s
sys     0m11.515s

results no-more-psym:

real    1m47.708s
user    2m0.686s
sys     0m12.500s

real    1m47.426s
user    2m0.960s
sys     0m12.089s

That's 35% real time reduction on average.

Then I picked the largest file:
/usr/lib/debug/usr/lib64/libLLVM.so.10-10.0.1-lp152.35.10.x86_64.debug,
and used just that one.

results merge-base:

real    0m35.661s
user    0m35.654s
sys     0m0.172s

real    0m35.692s
user    0m35.654s
sys     0m0.207s

results no-more-psym:

real    0m13.268s
user    0m18.084s
sys     0m0.620s

real    0m13.362s
user    0m18.181s
sys     0m0.582s

That's a 62% real time reduction.

Interesting to see that in both comparisons we have speedup because of:
- doing less (decrease in user time)
- doing things in parallel (real < user)

Indeed, switching off parallelism using "maint set worker-threads 0"
while redoing the last measurement still gives us a nice speedup:

real    0m15.498s
user    0m15.120s
sys     0m0.380s

real    0m15.540s
user    0m15.152s
sys     0m0.401s

Thanks,
- Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 11/32] Return vector of results from parallel_for_each
  2021-11-04 18:08 ` [PATCH v2 11/32] Return vector of results from parallel_for_each Tom Tromey
@ 2021-11-17 20:37   ` Lancelot SIX
  2021-11-18 14:41     ` Tom Tromey
  0 siblings, 1 reply; 53+ messages in thread
From: Lancelot SIX @ 2021-11-17 20:37 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> +
> +/* See the generic template.  */
> +template<>
> +struct par_for_accumulator<void>
> +{
> +public:
> +
> +  explicit par_for_accumulator (size_t n_threads)
> +    : m_futures (n_threads)
> +  {
> +  }
> +
> +  /* This specialization does not compute results.  */
> +  typedef void result_type;
> +
> +  void post (size_t i, std::function<void ()> task)
> +  {
> +    m_futures[i]
> +      = gdb::thread_pool::g_thread_pool->post_task (std::move (task));
> +  }
> +
> +  result_type finish (std::function<void ()> task)
> +  {
> +    task ();
> +
> +    for (auto &future : m_futures)
> +      future.wait ();

Hi,

There is a point here I missed when I read though the V1 of the series.

I think you also want to use 'get' here instead of 'wait' (as you do in
the non specialized version of the template).

Wait 'just' makes sure the result becomes accessible (in this case,
makes sure the task is executed), while get also accesses it.  Even if
the task returns nothing, if an exception is thrown during execution of
the task, calling wait will just make sure the exception is stored in
the future object.  Calling get will re-throw the exception, which is
probably what we want.

Best,
Lancelot.

> +  }
> +
> +private:
> +
> +  std::vector<std::future<void>> m_futures;
> +};
> +
> +}
> +

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 11/32] Return vector of results from parallel_for_each
  2021-11-17 20:37   ` Lancelot SIX
@ 2021-11-18 14:41     ` Tom Tromey
  0 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-18 14:41 UTC (permalink / raw)
  To: Lancelot SIX via Gdb-patches; +Cc: Tom Tromey, Lancelot SIX

>>>>> "Lancelot" == Lancelot SIX via Gdb-patches <gdb-patches@sourceware.org> writes:

Lancelot> I think you also want to use 'get' here instead of 'wait' (as you do in
Lancelot> the non specialized version of the template).
[...]

Thank you for the review.  I've made this change locally.

Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-16 23:56   ` Tom Tromey
  2021-11-17  9:22     ` Tom de Vries
@ 2021-11-18 14:43     ` Tom Tromey
  2021-11-22 19:59     ` Tom Tromey
  2 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-18 14:43 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Tom de Vries, gdb-patches

Tom> I really appreciate the testing you've done.  I'll send v3 of the series
Tom> once I do some more testing... I plan to regression test with a few
Tom> different approaches (dwz, probably split DWARF too).

Testing with the cc-with-dwz-m board seems ok.
Testing with fission-dwp pointed out some more failures.  I've fixed most
of these, but there are still some in gdb.arch.

Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-16 23:56   ` Tom Tromey
  2021-11-17  9:22     ` Tom de Vries
  2021-11-18 14:43     ` Tom Tromey
@ 2021-11-22 19:59     ` Tom Tromey
  2021-11-22 20:52       ` Tom de Vries
  2 siblings, 1 reply; 53+ messages in thread
From: Tom Tromey @ 2021-11-22 19:59 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Tom de Vries, gdb-patches

Tom> I'll send v3 of the series once I do some more testing... I plan to
Tom> regression test with a few different approaches (dwz, probably
Tom> split DWARF too).

I think the branch is regression free in the normal case and when using
the cc-with-dwz-m board.

I also tried the fission-dwp board, and I have a single regression.  I'm
inclined to ignore this one, but I figured I'd describe it first in case
anyone wants to lobby for it to be fixed.

First, the regression only affects one Ada test case, dgopt.exp, and
only when using fission-dwp.  In this scenario, the executable has a
stub CU that looks like:

     <0><3f>: Abbrev Number: 1 (DW_TAG_compile_unit)
    [...]
        <50>   DW_AT_stmt_list   : 0x24d
    [...]
        <58>   DW_AT_comp_dir    : (indirect string, offset: 0x0): /home/tromey/gdb/build/gdb/testsuite/outputs/gdb.ada/dgopt

Note there is no DW_AT_name.

The corresponding .dwo file says:

     <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
    [...]
        <e>   DW_AT_name        : (indexed string: 0x1): /home/tromey/gdb/binutils-gdb/gdb/testsuite/gdb.ada/dgopt/x.adb
        <f>   DW_AT_comp_dir    : (indexed string: 0x2): /home/tromey/gdb/build/gdb/testsuite/outputs/gdb.ada/dgopt

That is, this has the correct file name in DW_AT_name.  This is why the
psymtab reader works -- the psymtab reader uses the line table, but also
uses this name for file name matches.

The line table does not mention x.adb, but instead:

     The File Name Table (offset 0x26a):
      Entry Dir     Time    Size    Name
      1     0       0       0       x.adb.dg

That is, the file name table here holds the name of a file that's
generated by the Ada compiler when run in a special mode.

So, my inclination is to say that this is probably a compiler bug, or in
any case an obscure oddity that gdb shouldn't bother with.  To my
knowledge, there aren't Ada users who also use Fission anyway.

I do think this could be fixed.  It would require maybe storing a
file_and_directory in the dwarf2_per_cu_data.  So if you think this is
important, I'd probably refactor to take this approach.

TBH I had expected this scenario to make a .gdb_index -- that's what
fission-dwp is supposed to do, I think, via gold -- but this didn't
happen.  So possibly this is another oddity in the Ada toolchain, or
maybe the gdb test suite.  I'm not certain.

Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-22 19:59     ` Tom Tromey
@ 2021-11-22 20:52       ` Tom de Vries
  2021-11-22 22:11         ` Tom Tromey
  0 siblings, 1 reply; 53+ messages in thread
From: Tom de Vries @ 2021-11-22 20:52 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 11/22/21 8:59 PM, Tom Tromey wrote:
> Tom> I'll send v3 of the series once I do some more testing... I plan to
> Tom> regression test with a few different approaches (dwz, probably
> Tom> split DWARF too).
> 
> I think the branch is regression free in the normal case and when using
> the cc-with-dwz-m board.
> 
> I also tried the fission-dwp board, and I have a single regression.  I'm
> inclined to ignore this one, but I figured I'd describe it first in case
> anyone wants to lobby for it to be fixed.
> 
> First, the regression only affects one Ada test case, dgopt.exp, and
> only when using fission-dwp.  In this scenario, the executable has a
> stub CU that looks like:
> 
>      <0><3f>: Abbrev Number: 1 (DW_TAG_compile_unit)
>     [...]
>         <50>   DW_AT_stmt_list   : 0x24d
>     [...]
>         <58>   DW_AT_comp_dir    : (indirect string, offset: 0x0): /home/tromey/gdb/build/gdb/testsuite/outputs/gdb.ada/dgopt
> 
> Note there is no DW_AT_name.
> 
> The corresponding .dwo file says:
> 
>      <0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
>     [...]
>         <e>   DW_AT_name        : (indexed string: 0x1): /home/tromey/gdb/binutils-gdb/gdb/testsuite/gdb.ada/dgopt/x.adb
>         <f>   DW_AT_comp_dir    : (indexed string: 0x2): /home/tromey/gdb/build/gdb/testsuite/outputs/gdb.ada/dgopt
> 
> That is, this has the correct file name in DW_AT_name.  This is why the
> psymtab reader works -- the psymtab reader uses the line table, but also
> uses this name for file name matches.
> 
> The line table does not mention x.adb, but instead:
> 
>      The File Name Table (offset 0x26a):
>       Entry Dir     Time    Size    Name
>       1     0       0       0       x.adb.dg
> 
> That is, the file name table here holds the name of a file that's
> generated by the Ada compiler when run in a special mode.
> 
> So, my inclination is to say that this is probably a compiler bug, or in
> any case an obscure oddity that gdb shouldn't bother with.  To my
> knowledge, there aren't Ada users who also use Fission anyway.
> 

I've looked at the readelf -w output for native, and I see the same,
that is, a CU with:
...
    <14e2>   DW_AT_name        :
/home/vries/gdb_versions/devel/binutils-gdb.git/gdb/testsuite/gdb.ada/dgopt/x.adb
...
and a .debug_line entry with:
...
 The File Name Table (offset 0x361):
  Entry Dir     Time    Size    Name
  1     0       0       0       x.adb.dg
...

At the gnat docs we find:
...
-gnatD[=nn]
  ...
  The debugging information generated by the gcc -g switch will refer to
the generated xxx.dg file.
...

So, I'm inclined to say that it's a compiler bug that we have
"DW_AT_name x.adb" rather than "DW_AT_name x.adb.dg".  I'd file a gcc PR
for this.

Only, it's a compiler bug that the compiler doesn't stick to its own
spec, but AFAIU this is valid DWARF.

I tried a two-file test-case:
...
$ cat test.c
#include "test2.c"
$ cat test2.c
int
main (void)
{
  return 0;
}
$ gcc -g test.c
...
and got the same structure.

FWIW, it could be interesting to create a similar test-case with these
sources and see if the same problem pops up for your branch with
fission-dwp.

Thanks,
- Tom

> I do think this could be fixed.  It would require maybe storing a
> file_and_directory in the dwarf2_per_cu_data.  So if you think this is
> important, I'd probably refactor to take this approach.
> 
> TBH I had expected this scenario to make a .gdb_index -- that's what
> fission-dwp is supposed to do, I think, via gold -- but this didn't
> happen.  So possibly this is another oddity in the Ada toolchain, or
> maybe the gdb test suite.  I'm not certain.
> 
> Tom
> 

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-22 20:52       ` Tom de Vries
@ 2021-11-22 22:11         ` Tom Tromey
  2021-11-23  7:56           ` Tom de Vries
  0 siblings, 1 reply; 53+ messages in thread
From: Tom Tromey @ 2021-11-22 22:11 UTC (permalink / raw)
  To: Tom de Vries; +Cc: Tom Tromey, gdb-patches

Tom> I tried a two-file test-case:
Tom> ...
Tom> $ cat test.c
Tom> #include "test2.c"
Tom> $ cat test2.c
Tom> int
Tom> main (void)
Tom> {
Tom>   return 0;
Tom> }
Tom> $ gcc -g test.c
Tom> ...
Tom> and got the same structure.

For me, with this test, the compiler doesn't mention test.c at all in
its output, so even the unmodified gdb can't find it.

Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-22 22:11         ` Tom Tromey
@ 2021-11-23  7:56           ` Tom de Vries
  2021-11-23 17:00             ` Tom Tromey
  0 siblings, 1 reply; 53+ messages in thread
From: Tom de Vries @ 2021-11-23  7:56 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 11/22/21 11:11 PM, Tom Tromey wrote:
> Tom> I tried a two-file test-case:
> Tom> ...
> Tom> $ cat test.c
> Tom> #include "test2.c"
> Tom> $ cat test2.c
> Tom> int
> Tom> main (void)
> Tom> {
> Tom>   return 0;
> Tom> }
> Tom> $ gcc -g test.c
> Tom> ...
> Tom> and got the same structure.
> 
> For me, with this test, the compiler doesn't mention test.c at all in
> its output, so even the unmodified gdb can't find it.

[ I've sent an off-list message to discuss how to reproduce this. ]

FWIW, I think this is sufficiently cornercase that it's not worth
blocking the trunk commit of the branch.  Filing this in bugzilla to
deal with later and adding a KFAIL in the test should be sufficient.

Thanks,
- Tom



^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 00/32] Rewrite the DWARF "partial" reader
  2021-11-23  7:56           ` Tom de Vries
@ 2021-11-23 17:00             ` Tom Tromey
  0 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-23 17:00 UTC (permalink / raw)
  To: Tom de Vries; +Cc: Tom Tromey, gdb-patches

>> For me, with this test, the compiler doesn't mention test.c at all in
>> its output, so even the unmodified gdb can't find it.

Tom> [ I've sent an off-list message to discuss how to reproduce this. ]

I applied your test case and:

    $ runtest --target_board=fission-dwp gdb.base/include-main.exp
    [...]
    # of expected passes		2

I'm using the Fedora 34 system compiler.

    $ gcc --version
    gcc (GCC) 11.2.1 20210728 (Red Hat 11.2.1-1)

Tom> FWIW, I think this is sufficiently cornercase that it's not worth
Tom> blocking the trunk commit of the branch.  Filing this in bugzilla to
Tom> deal with later and adding a KFAIL in the test should be sufficient.

For me, if it's reproducible with C or C++, then it should be fixed.
For Ada, I think it's less important simply because I think nobody is
using fission/dwp there.

Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

* Re: [PATCH v2 04/32] Refactor dwarf2_get_pc_bounds
  2021-11-05 19:51   ` Simon Marchi
@ 2021-11-24 15:53     ` Tom Tromey
  0 siblings, 0 replies; 53+ messages in thread
From: Tom Tromey @ 2021-11-24 15:53 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:

>> @@ -14036,10 +14044,9 @@ dwarf2_ranges_process (unsigned offset, struct dwarf2_cu *cu, dwarf_tag tag,
>> static int
>> dwarf2_ranges_read (unsigned offset, CORE_ADDR *low_return,
>> CORE_ADDR *high_return, struct dwarf2_cu *cu,
>> -		    dwarf2_psymtab *ranges_pst, dwarf_tag tag)
>> +		    addrmap *map, void *datum, dwarf_tag tag)

Simon> Perhaps it's code that is going to be deleted anyway, but the comment
Simon> above this would need to be updated.

I did this, thanks.

Tom

^ permalink raw reply	[flat|nested] 53+ messages in thread

end of thread, other threads:[~2021-11-24 15:53 UTC | newest]

Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-04 18:08 [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom Tromey
2021-11-04 18:08 ` [PATCH v2 01/32] Introduce make_unique_xstrndup Tom Tromey
2021-11-05 19:20   ` Simon Marchi
2021-11-05 20:08     ` Tom Tromey
2021-11-04 18:08 ` [PATCH v2 02/32] Split create_addrmap_from_aranges Tom Tromey
2021-11-04 18:08 ` [PATCH v2 03/32] Add dwarf2_per_cu_data::addresses_seen Tom Tromey
2021-11-04 18:08 ` [PATCH v2 04/32] Refactor dwarf2_get_pc_bounds Tom Tromey
2021-11-05 19:51   ` Simon Marchi
2021-11-24 15:53     ` Tom Tromey
2021-11-04 18:08 ` [PATCH v2 05/32] Allow ada_decode not to decode operators Tom Tromey
2021-11-04 18:08 ` [PATCH v2 06/32] Let skip_one_die not skip children Tom Tromey
2021-11-04 18:08 ` [PATCH v2 07/32] Add name splitting Tom Tromey
2021-11-04 18:08 ` [PATCH v2 08/32] Add new overload of dwarf5_djb_hash Tom Tromey
2021-11-05 20:01   ` Simon Marchi
2021-11-07 17:02     ` Tom Tromey
2021-11-04 18:08 ` [PATCH v2 09/32] Refactor build_type_psymtabs_reader Tom Tromey
2021-11-04 18:08 ` [PATCH v2 10/32] Add batching parameter to parallel_for_each Tom Tromey
2021-11-04 18:08 ` [PATCH v2 11/32] Return vector of results from parallel_for_each Tom Tromey
2021-11-17 20:37   ` Lancelot SIX
2021-11-18 14:41     ` Tom Tromey
2021-11-04 18:08 ` [PATCH v2 12/32] Specialize std::hash for gdb_exception Tom Tromey
2021-11-04 18:08 ` [PATCH v2 13/32] Introduce DWARF abbrev cache Tom Tromey
2021-11-04 18:08 ` [PATCH v2 14/32] Statically examine abbrev properties Tom Tromey
2021-11-04 18:08 ` [PATCH v2 15/32] Update skip_one_die for new " Tom Tromey
2021-11-04 18:08 ` [PATCH v2 16/32] Introduce the new DWARF index class Tom Tromey
2021-11-04 18:08 ` [PATCH v2 17/32] The new DWARF indexer Tom Tromey
2021-11-04 18:08 ` [PATCH v2 18/32] Implement quick_symbol_functions for cooked DWARF index Tom Tromey
2021-11-04 18:08 ` [PATCH v2 19/32] Wire in the new DWARF indexer Tom Tromey
2021-11-04 18:08 ` [PATCH v2 20/32] Introduce thread-safe handling for complaints Tom Tromey
2021-11-04 18:08 ` [PATCH v2 21/32] Pre-read DWARF section data Tom Tromey
2021-11-04 18:08 ` [PATCH v2 22/32] Parallelize DWARF indexing Tom Tromey
2021-11-04 18:08 ` [PATCH v2 23/32] "Finalize" the DWARF index in the background Tom Tromey
2021-11-04 18:08 ` [PATCH v2 24/32] Rename write_psymtabs_to_index Tom Tromey
2021-11-04 18:09 ` [PATCH v2 25/32] Change the key type in psym_index_map Tom Tromey
2021-11-04 18:09 ` [PATCH v2 26/32] Change parameters to write_address_map Tom Tromey
2021-11-04 18:09 ` [PATCH v2 27/32] Genericize addrmap handling in the DWARF index writer Tom Tromey
2021-11-04 18:09 ` [PATCH v2 28/32] Adapt .gdb_index writer to new DWARF scanner Tom Tromey
2021-11-04 18:09 ` [PATCH v2 29/32] Adapt .debug_names " Tom Tromey
2021-11-04 18:09 ` [PATCH v2 30/32] Enable the new DWARF indexer Tom Tromey
2021-11-04 18:09 ` [PATCH v2 31/32] Delete DWARF psymtab code Tom Tromey
2021-11-04 18:09 ` [PATCH v2 32/32] Remove dwarf2_per_cu_data::v Tom Tromey
2021-11-06 12:25 ` [PATCH v2 00/32] Rewrite the DWARF "partial" reader Tom de Vries
2021-11-11 12:23   ` Tom de Vries
2021-11-16 23:56   ` Tom Tromey
2021-11-17  9:22     ` Tom de Vries
2021-11-18 14:43     ` Tom Tromey
2021-11-22 19:59     ` Tom Tromey
2021-11-22 20:52       ` Tom de Vries
2021-11-22 22:11         ` Tom Tromey
2021-11-23  7:56           ` Tom de Vries
2021-11-23 17:00             ` Tom Tromey
2021-11-08 17:41 ` Simon Marchi
2021-11-10 19:56   ` Tom Tromey

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).