This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFA 4/4] Improve DWARF Type Unit performance


This patch is the main patch in the series and contains
the changes to dwarf2read.c.

2012-07-09  Doug Evans  <dje@google.com>

	* dwarf2read.c (dwarf2_per_objfile): New members n_type_unit_groups,
	all_type_unit_groups, type_unit_groups, tu_stats.
	(dwarf2_per_cu_data): Move "imported_symtabs" into new union "s".
	All uses updated.  Add type_unit_group to union "s".
	(type_unit_group): New struct.
	(IS_TYPE_UNIT_GROUP): New macro.
	(abbrev_table): Delete unused member "section".
	(dw2_do_instantiate_symtab): Early exit if type_unit_group.
	(dw2_get_cu): Assert not used with type_unit_group.
	(dw2_get_primary_cu): New function.
	(dw2_build_type_unit_groups_reader): New function.
	(dw2_build_type_unit_groups): New function.
	(dw2_get_file_names): Assert not called on type units.
	(dw2_map_symtabs_matching_filename): Call dw2_build_type_unit_groups.
	Redo loop to iterate over type unit groups instead of type units.
	(dw2_expand_symtabs_matching, dw2_map_symbol_filenames): Ditto.
	(read_abbrev_offset): New function.
	(init_cutu_and_read_dies): New arg "abbrev_table".  All callers
	updated.
	(create_partial_symtab): New function.
	(process_psymtab_comp_unit_reader): Assert not used with type units.
	Call create_partial_symtab.
	(process_psymtab_type_unit): Delete.
	(hash_type_unit_group, eq_type_unit_group): New functions.
	(allocate_type_unit_groups_table): New function.
	(NO_STMT_LIST_TYPE_UNIT_PSYMTAB): New macro.
	(NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE): New macro.
	(create_type_unit_group, get_type_unit_group): New functions.
	(tu_abbrev_offset): New struct.
	(sort_tu_by_abbrev_offset): New function.
	(add_type_unit_group_to_table): New function.
	(build_type_unit_groups): New function.
	(build_type_psymtabs_reader): New function.
	(build_type_psymtab_dependencies): New function.
	(build_type_psymtabs): Rewrite.
	(scan_partial_symbols): Flag an error if a DW_TAG_imported_unit
	is seen in a type unit.
	(process_queue): Move symtab expansion debugging printfs here.
	Call process_full_type_unit for type units.
	(compute_symtab_includes): Assert not called for type units.
	(process_cu_includes): Don't call compute_symtab_includes for
	type units.
	(process_full_type_unit): New function.
	(process_imported_unit_die): Flag an error if called for type units.
	(handle_DW_AT_stmt_list): Delete arg "want_line_info".  All callers
	updated.  Assert not called for type units.
	(read_file_scope): Call dwarf2_start_symtab.
	(setup_type_unit_groups): New function.
	(read_type_unit_scope): Rewrite.
	(abbrev_table_read_table): Initialize abbrev_table->offset.
	(abbrev_table_free_cleanup): New function.
	(dwarf2_start_symtab): New function.
	(load_full_type_unit): Assert not called for type unit groups.

Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.683
diff -u -p -r1.683 dwarf2read.c
--- dwarf2read.c	10 Jul 2012 01:05:06 -0000	1.683
+++ dwarf2read.c	10 Jul 2012 06:11:18 -0000
@@ -214,14 +214,34 @@ struct dwarf2_per_objfile
   /* The .debug_types-related CUs (TUs).  */
   struct signatured_type **all_type_units;
 
-  /* A chain of compilation units that are currently read in, so that
-     they can be freed later.  */
-  struct dwarf2_per_cu_data *read_in_chain;
+  /* The number of entries in all_type_unit_groups.  */
+  int n_type_unit_groups;
+
+  /* Table of type unit groups.
+     This exists to make it easy to iterate over all CUs and TU groups.  */
+  struct type_unit_group **all_type_unit_groups;
+
+  /* Table of struct type_unit_group objects.
+     The hash key is the DW_AT_stmt_list value.  */
+  htab_t type_unit_groups;
 
   /* A table mapping .debug_types signatures to its signatured_type entry.
      This is NULL if the .debug_types section hasn't been read in yet.  */
   htab_t signatured_types;
 
+  /* Type unit statistics, to see how well the scaling improvements
+     are doing.  */
+  struct tu_stats {
+    int nr_uniq_abbrev_tables;
+    int nr_symtabs;
+    int nr_symtab_sharers;
+    int nr_stmt_less_type_units;
+  } tu_stats;
+
+  /* A chain of compilation units that are currently read in, so that
+     they can be freed later.  */
+  struct dwarf2_per_cu_data *read_in_chain;
+
   /* A table mapping DW_AT_dwo_name values to struct dwo_file objects.
      This is NULL if the table hasn't been allocated yet.  */
   htab_t dwo_files;
@@ -533,11 +553,19 @@ struct dwarf2_per_cu_data
     struct dwarf2_per_cu_quick_data *quick;
   } v;
 
-  /* The CUs we import using DW_TAG_imported_unit.  This is filled in
-     while reading psymtabs, used to compute the psymtab dependencies,
-     and then cleared.  Then it is filled in again while reading full
-     symbols, and only deleted when the objfile is destroyed.  */
-  VEC (dwarf2_per_cu_ptr) *imported_symtabs;
+  union
+  {
+    /* The CUs we import using DW_TAG_imported_unit.  This is filled in
+       while reading psymtabs, used to compute the psymtab dependencies,
+       and then cleared.  Then it is filled in again while reading full
+       symbols, and only deleted when the objfile is destroyed.  */
+    VEC (dwarf2_per_cu_ptr) *imported_symtabs;
+
+    /* Type units are grouped by their DW_AT_stmt_list entry so that they
+       can share them.  If this is a TU, this points to the containing
+       symtab.  */
+    struct type_unit_group *type_unit_group;
+  } s;
 };
 
 /* Entry in the signatured_types hash table.  */
@@ -564,6 +592,47 @@ struct signatured_type
   sect_offset type_offset_in_section;
 };
 
+/* Each element of dwarf2_per_objfile->type_unit_groups is a pointer to
+   an object of this type.  */
+
+struct type_unit_group
+{
+  /* dwarf2read.c's main "handle" on the symtab.
+     To simplify things we create an artificial CU that "includes" all the
+     type units using this stmt_list so that the rest of the code still has
+     a "per_cu" handle on the symtab.
+     This PER_CU is recognized by having no section.  */
+#define IS_TYPE_UNIT_GROUP(per_cu) ((per_cu)->info_or_types_section == NULL)
+  struct dwarf2_per_cu_data *per_cu;
+
+  /* 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.  */
+  VEC (dwarf2_per_cu_ptr) *tus;
+
+  /* The primary symtab.
+     Type units don't have DW_AT_name so we create an essentially
+     anonymous symtab as the primary symtab.  */
+  struct symtab *primary_symtab;
+
+  /* Offset in .debug_line.  This is the hash key.  */
+  sect_offset line_offset;
+
+  /* The number of symtabs from the line header.
+     The value here must match line_header.num_file_names.  */
+  unsigned int num_symtabs;
+
+  /* The symbol tables for this TU (obtained from the files listed in
+     DW_AT_stmt_list).
+     WARNING: The order of entries here must match the order of entries
+     in the line header.  After the first TU using this type_unit_group, the
+     line header for the subsequent TUs is recreated from this.  This is done
+     because we need to use the same symtabs for each TU using the same
+     DW_AT_stmt_list value.  Also note that symtabs may be repeated here,
+     there's no guarantee the line header doesn't have duplicate entries.  */
+  struct symtab **symtabs;
+};
+
 /* These sections are what may appear in a "dwo" file.  */
 
 struct dwo_sections
@@ -804,8 +873,8 @@ struct attr_abbrev
 
 struct abbrev_table
 {
-  /* Where the abbrev table came from.  */
-  struct dwarf2_section_info *section;
+  /* Where the abbrev table came from.
+     This is used as a sanity check when the table is used.  */
   sect_offset offset;
 
   /* Storage for the abbrev table.  */
@@ -1105,6 +1174,8 @@ static struct abbrev_table *abbrev_table
 
 static void abbrev_table_free (struct abbrev_table *);
 
+static void abbrev_table_free_cleanup (void *);
+
 static void dwarf2_read_abbrevs (struct dwarf2_cu *,
 				 struct dwarf2_section_info *);
 
@@ -1155,6 +1226,9 @@ static LONGEST read_offset (bfd *, gdb_b
 
 static LONGEST read_offset_1 (bfd *, gdb_byte *, unsigned int);
 
+static sect_offset read_abbrev_offset (struct dwarf2_section_info *,
+				       sect_offset);
+
 static gdb_byte *read_n_bytes (bfd *, gdb_byte *, unsigned int);
 
 static char *read_direct_string (bfd *, gdb_byte *, unsigned int *);
@@ -1203,6 +1277,9 @@ static void dwarf_decode_lines (struct l
 
 static void dwarf2_start_subfile (char *, const char *, const char *);
 
+static void dwarf2_start_symtab (struct dwarf2_cu *,
+				 char *, char *, CORE_ADDR);
+
 static struct symbol *new_symbol (struct die_info *, struct type *,
 				  struct dwarf2_cu *);
 
@@ -1387,6 +1464,11 @@ static void load_full_type_unit (struct 
 
 static void read_signatured_type (struct signatured_type *);
 
+static struct type_unit_group *get_type_unit_group
+    (struct dwarf2_per_cu_data *, struct attribute *);
+
+static void build_type_unit_groups (die_reader_func_ftype *, void *);
+
 /* memory allocation interface */
 
 static struct dwarf_block *dwarf_alloc_block (struct dwarf2_cu *);
@@ -1451,6 +1533,9 @@ static void load_full_comp_unit (struct 
 static void process_full_comp_unit (struct dwarf2_per_cu_data *,
 				    enum language);
 
+static void process_full_type_unit (struct dwarf2_per_cu_data *,
+				    enum language);
+
 static void dwarf2_add_dependence (struct dwarf2_cu *,
 				   struct dwarf2_per_cu_data *);
 
@@ -1482,7 +1567,8 @@ static char *file_full_name (int file, s
 			     const char *comp_dir);
 
 static void init_cutu_and_read_dies
-  (struct dwarf2_per_cu_data *this_cu, int use_existing_cu, int keep,
+  (struct dwarf2_per_cu_data *this_cu, struct abbrev_table *abbrev_table,
+   int use_existing_cu, int keep,
    die_reader_func_ftype *die_reader_func, void *data);
 
 static void init_cutu_and_read_dies_simple
@@ -1491,8 +1577,6 @@ static void init_cutu_and_read_dies_simp
 
 static htab_t allocate_signatured_type_table (struct objfile *objfile);
 
-static void process_psymtab_comp_unit (struct dwarf2_per_cu_data *, int);
-
 static htab_t allocate_dwo_unit_table (struct objfile *objfile);
 
 static struct dwo_unit *lookup_dwo_comp_unit
@@ -2026,6 +2110,11 @@ dw2_do_instantiate_symtab (struct dwarf2
 {
   struct cleanup *back_to;
 
+  /* Skip type_unit_groups, reading the type units they contain
+     is handled elsewhere.  */
+  if (IS_TYPE_UNIT_GROUP (per_cu))
+    return;
+
   back_to = make_cleanup (dwarf2_release_queue, NULL);
 
   if (dwarf2_per_objfile->using_index
@@ -2064,16 +2153,63 @@ dw2_instantiate_symtab (struct dwarf2_pe
   return per_cu->v.quick->symtab;
 }
 
-/* Return the CU given its index.  */
+/* Return the CU given its index.
+
+   This is intended for loops like:
+
+   for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+		    + dwarf2_per_objfile->n_type_units); ++i)
+     {
+       struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+
+       ...;
+     }
+*/
 
 static struct dwarf2_per_cu_data *
 dw2_get_cu (int index)
 {
   if (index >= dwarf2_per_objfile->n_comp_units)
     {
+      struct dwarf2_per_cu_data *per_cu;
+
       index -= dwarf2_per_objfile->n_comp_units;
-      return &dwarf2_per_objfile->all_type_units[index]->per_cu;
+      per_cu = &dwarf2_per_objfile->all_type_units[index]->per_cu;
+      gdb_assert (! IS_TYPE_UNIT_GROUP (per_cu));
+      return per_cu;
     }
+
+  return dwarf2_per_objfile->all_comp_units[index];
+}
+
+/* Return the primary CU given its index.
+   The difference between this function and dw2_get_cu is in the handling
+   of type units (TUs).  Here we return the type_unit_group object.
+
+   This is intended for loops like:
+
+   for (i = 0; i < (dwarf2_per_objfile->n_comp_units
+		    + dwarf2_per_objfile->n_type_unit_groups); ++i)
+     {
+       struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i);
+
+       ...;
+     }
+*/
+
+static struct dwarf2_per_cu_data *
+dw2_get_primary_cu (int index)
+{
+  if (index >= dwarf2_per_objfile->n_comp_units)
+    {
+      struct dwarf2_per_cu_data *per_cu;
+
+      index -= dwarf2_per_objfile->n_comp_units;
+      per_cu = dwarf2_per_objfile->all_type_unit_groups[index]->per_cu;
+      gdb_assert (IS_TYPE_UNIT_GROUP (per_cu));
+      return per_cu;
+    }
+
   return dwarf2_per_objfile->all_comp_units[index];
 }
 
@@ -2474,6 +2610,41 @@ dw2_setup (struct objfile *objfile)
   gdb_assert (dwarf2_per_objfile);
 }
 
+/* Reader function for dw2_build_type_unit_groups.  */
+
+static void
+dw2_build_type_unit_groups_reader (const struct die_reader_specs *reader,
+				   gdb_byte *info_ptr,
+				   struct die_info *type_unit_die,
+				   int has_children,
+				   void *data)
+{
+  struct dwarf2_cu *cu = reader->cu;
+  struct dwarf2_per_cu_data *per_cu = cu->per_cu;
+  struct attribute *attr;
+  struct type_unit_group *tu_group;
+
+  gdb_assert (data == NULL);
+
+  if (! has_children)
+    return;
+
+  attr = dwarf2_attr_no_follow (type_unit_die, DW_AT_stmt_list);
+  /* Call this for its side-effect of creating the associated
+     struct type_unit_group if it doesn't already exist.  */
+  tu_group = get_type_unit_group (per_cu, attr);
+}
+
+/* Build dwarf2_per_objfile->type_unit_groups.
+   This function may be called multiple times.  */
+
+static void
+dw2_build_type_unit_groups (void)
+{
+  if (dwarf2_per_objfile->type_unit_groups == NULL)
+    build_type_unit_groups (dw2_build_type_unit_groups_reader, NULL);
+}
+
 /* die_reader_func for dw2_get_file_names.  */
 
 static void
@@ -2558,6 +2729,10 @@ static struct quick_file_names *
 dw2_get_file_names (struct objfile *objfile,
 		    struct dwarf2_per_cu_data *this_cu)
 {
+  /* For TUs this should only be called on the parent group.  */
+  if (this_cu->is_debug_types)
+    gdb_assert (IS_TYPE_UNIT_GROUP (this_cu));
+
   if (this_cu->v.quick->file_names != NULL)
     return this_cu->v.quick->file_names;
   /* If we know there is no line data, no point in looking again.  */
@@ -2569,7 +2744,8 @@ dw2_get_file_names (struct objfile *objf
      However, that's not the case for TUs where DW_AT_stmt_list lives in the
      DWO file.  */
   if (this_cu->is_debug_types)
-    init_cutu_and_read_dies (this_cu, 0, 0, dw2_get_file_names_reader, NULL);
+    init_cutu_and_read_dies (this_cu, NULL, 0, 0,
+			     dw2_get_file_names_reader, NULL);
   else
     init_cutu_and_read_dies_simple (this_cu, dw2_get_file_names_reader, NULL);
 
@@ -2675,11 +2851,13 @@ dw2_map_symtabs_matching_filename (struc
 
   dw2_setup (objfile);
 
+  dw2_build_type_unit_groups ();
+
   for (i = 0; i < (dwarf2_per_objfile->n_comp_units
-		   + dwarf2_per_objfile->n_type_units); ++i)
+		   + dwarf2_per_objfile->n_type_unit_groups); ++i)
     {
       int j;
-      struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+      struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i);
       struct quick_file_names *file_data;
 
       /* We only need to look at symtabs not already expanded.  */
@@ -2997,8 +3175,8 @@ dw2_find_symbol_file (struct objfile *ob
   if (per_cu->v.quick->symtab != NULL)
     return per_cu->v.quick->symtab->filename;
 
-  init_cutu_and_read_dies (per_cu, 0, 0, dw2_get_primary_filename_reader,
-			   &filename);
+  init_cutu_and_read_dies (per_cu, NULL, 0, 0,
+			   dw2_get_primary_filename_reader, &filename);
 
   return filename;
 }
@@ -3040,6 +3218,8 @@ dw2_expand_symtabs_matching
       struct cleanup *cleanup;
       htab_t visited_found, visited_not_found;
 
+      dw2_build_type_unit_groups ();
+
       visited_found = htab_create_alloc (10,
 					 htab_hash_pointer, htab_eq_pointer,
 					 NULL, xcalloc, xfree);
@@ -3050,10 +3230,10 @@ dw2_expand_symtabs_matching
       make_cleanup_htab_delete (visited_not_found);
 
       for (i = 0; i < (dwarf2_per_objfile->n_comp_units
-		       + dwarf2_per_objfile->n_type_units); ++i)
+		       + dwarf2_per_objfile->n_type_unit_groups); ++i)
 	{
 	  int j;
-	  struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+	  struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i);
 	  struct quick_file_names *file_data;
 	  void **slot;
 
@@ -3223,6 +3403,8 @@ dw2_map_symbol_filenames (struct objfile
   cleanup = make_cleanup_htab_delete (visited);
   dw2_setup (objfile);
 
+  dw2_build_type_unit_groups ();
+
   /* We can ignore file names coming from already-expanded CUs.  */
   for (i = 0; i < (dwarf2_per_objfile->n_comp_units
 		   + dwarf2_per_objfile->n_type_units); ++i)
@@ -3239,10 +3421,10 @@ dw2_map_symbol_filenames (struct objfile
     }
 
   for (i = 0; i < (dwarf2_per_objfile->n_comp_units
-		   + dwarf2_per_objfile->n_type_units); ++i)
+		   + dwarf2_per_objfile->n_type_unit_groups); ++i)
     {
       int j;
-      struct dwarf2_per_cu_data *per_cu = dw2_get_cu (i);
+      struct dwarf2_per_cu_data *per_cu = dw2_get_primary_cu (i);
       struct quick_file_names *file_data;
       void **slot;
 
@@ -3541,6 +3723,26 @@ read_and_check_type_unit_head (struct co
   return info_ptr;
 }
 
+/* Fetch the abbreviation table offset from a comp or type unit header.  */
+
+static sect_offset
+read_abbrev_offset (struct dwarf2_section_info *section,
+		    sect_offset offset)
+{
+  bfd *abfd = section->asection->owner;
+  gdb_byte *info_ptr;
+  unsigned int length, initial_length_size, offset_size;
+  sect_offset abbrev_offset;
+
+  dwarf2_read_section (dwarf2_per_objfile->objfile, section);
+  info_ptr = section->buffer + offset.sect_off;
+  length = read_initial_length (abfd, info_ptr, &initial_length_size);
+  offset_size = initial_length_size == 4 ? 4 : 8;
+  info_ptr += initial_length_size + 2 /*version*/;
+  abbrev_offset.sect_off = read_offset_1 (abfd, info_ptr, offset_size);
+  return abbrev_offset;
+}
+
 /* Allocate a new partial symtab for file named NAME and mark this new
    partial symtab as being an include of PST.  */
 
@@ -3876,6 +4078,10 @@ init_cu_die_reader (struct die_reader_sp
 /* Initialize a CU (or TU) and read its DIEs.
    If the CU defers to a DWO file, read the DWO file as well.
 
+   ABBREV_TABLE, if non-NULL, is the abbreviation table to use.
+   Otherwise the table specified in the comp unit header is read in and used.
+   This is an optimization for when we already have the abbrev table.
+
    If USE_EXISTING_CU is non-zero, and THIS_CU->cu is non-NULL, then use it.
    Otherwise, a new CU is allocated with xmalloc.
 
@@ -3887,6 +4093,7 @@ init_cu_die_reader (struct die_reader_sp
 
 static void
 init_cutu_and_read_dies (struct dwarf2_per_cu_data *this_cu,
+			 struct abbrev_table *abbrev_table,
 			 int use_existing_cu, int keep,
 			 die_reader_func_ftype *die_reader_func,
 			 void *data)
@@ -4006,7 +4213,14 @@ init_cutu_and_read_dies (struct dwarf2_p
      done.  Note that it's important that if the CU had an abbrev table
      on entry we don't free it when we're done: Somewhere up the call stack
      it may be in use.  */
-  if (cu->abbrev_table == NULL)
+  if (abbrev_table != NULL)
+    {
+      gdb_assert (cu->abbrev_table == NULL);
+      gdb_assert (cu->header.abbrev_offset.sect_off
+		  == abbrev_table->offset.sect_off);
+      cu->abbrev_table = abbrev_table;
+    }
+  else if (cu->abbrev_table == NULL)
     {
       dwarf2_read_abbrevs (cu, abbrev_section);
       make_cleanup (dwarf2_free_abbrev_table, cu);
@@ -4138,8 +4352,16 @@ init_cutu_and_read_dies (struct dwarf2_p
 	}
 
       /* Discard the original CU's abbrev table, and read the DWO's.  */
-      dwarf2_free_abbrev_table (cu);
-      dwarf2_read_abbrevs (cu, dwo_abbrev_section);
+      if (abbrev_table == NULL)
+	{
+	  dwarf2_free_abbrev_table (cu);
+	  dwarf2_read_abbrevs (cu, dwo_abbrev_section);
+	}
+      else
+	{
+	  dwarf2_read_abbrevs (cu, dwo_abbrev_section);
+	  make_cleanup (dwarf2_free_abbrev_table, cu);
+	}
 
       /* Read in the die, but leave space to copy over the attributes
 	 from the stub.  This has the benefit of simplifying the rest of
@@ -4294,6 +4516,32 @@ init_cutu_and_read_dies_simple (struct d
 				     die_reader_func, data);
 }
 
+/* Create a psymtab named NAME and assign it to PER_CU.
+
+   The caller must fill in the following details:
+   dirname, textlow, texthigh.  */
+
+static struct partial_symtab *
+create_partial_symtab (struct dwarf2_per_cu_data *per_cu, const char *name)
+{
+  struct objfile *objfile = per_cu->objfile;
+  struct partial_symtab *pst;
+
+  pst = start_psymtab_common (objfile, objfile->section_offsets,
+			      name, 0,
+			      objfile->global_psymbols.next,
+			      objfile->static_psymbols.next);
+
+  pst->psymtabs_addrmap_supported = 1;
+
+  /* This is the glue that links PST into GDB's symbol API.  */
+  pst->read_symtab_private = per_cu;
+  pst->read_symtab = dwarf2_psymtab_to_symtab;
+  per_cu->v.psymtab = pst;
+
+  return pst;
+}
+
 /* die_reader_func for process_psymtab_comp_unit.  */
 
 static void
@@ -4319,6 +4567,8 @@ process_psymtab_comp_unit_reader (const 
 	  || !*want_partial_unit_ptr))
     return;
 
+  gdb_assert (! per_cu->is_debug_types);
+
   prepare_one_comp_unit (cu, comp_unit_die, language_minimal);
 
   cu->list_in_scope = &file_symbols;
@@ -4329,27 +4579,16 @@ process_psymtab_comp_unit_reader (const 
     filename = "";
   else
     filename = DW_STRING (attr);
-  pst = start_psymtab_common (objfile, objfile->section_offsets,
-			      filename,
-			      /* TEXTLOW and TEXTHIGH are set below.  */
-			      0,
-			      objfile->global_psymbols.next,
-			      objfile->static_psymbols.next);
-  pst->psymtabs_addrmap_supported = 1;
 
+  pst = create_partial_symtab (per_cu, filename);
+
+  /* This must be done before calling dwarf2_build_include_psymtabs.  */
   attr = dwarf2_attr (comp_unit_die, DW_AT_comp_dir, cu);
   if (attr != NULL)
     pst->dirname = DW_STRING (attr);
 
-  pst->read_symtab_private = per_cu;
-
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
-  /* Store the function that reads in the rest of the symbol table.  */
-  pst->read_symtab = dwarf2_psymtab_to_symtab;
-
-  per_cu->v.psymtab = pst;
-
   dwarf2_find_base_address (comp_unit_die, cu);
 
   /* Possibly set the default values of LOWPC and HIGHPC from
@@ -4401,10 +4640,10 @@ process_psymtab_comp_unit_reader (const 
     (objfile->static_psymbols.list + pst->statics_offset);
   sort_pst_symbols (pst);
 
-  if (!VEC_empty (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs))
+  if (!VEC_empty (dwarf2_per_cu_ptr, cu->per_cu->s.imported_symtabs))
     {
       int i;
-      int len = VEC_length (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs);
+      int len = VEC_length (dwarf2_per_cu_ptr, cu->per_cu->s.imported_symtabs);
       struct dwarf2_per_cu_data *iter;
 
       /* Fill in 'dependencies' here; we fill in 'users' in a
@@ -4413,25 +4652,17 @@ process_psymtab_comp_unit_reader (const 
       pst->dependencies = obstack_alloc (&objfile->objfile_obstack,
 					 len * sizeof (struct symtab *));
       for (i = 0;
-	   VEC_iterate (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs,
+	   VEC_iterate (dwarf2_per_cu_ptr, cu->per_cu->s.imported_symtabs,
 			i, iter);
 	   ++i)
 	pst->dependencies[i] = iter->v.psymtab;
 
-      VEC_free (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs);
+      VEC_free (dwarf2_per_cu_ptr, cu->per_cu->s.imported_symtabs);
     }
 
-  if (per_cu->is_debug_types)
-    {
-      /* It's not clear we want to do anything with stmt lists here.
-	 Waiting to see what gcc ultimately does.  */
-    }
-  else
-    {
-      /* 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, pst);
-    }
+  /* 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, pst);
 
   if (dwarf2_read_debug)
     {
@@ -4464,38 +4695,399 @@ process_psymtab_comp_unit (struct dwarf2
     free_one_cached_comp_unit (this_cu);
 
   gdb_assert (! this_cu->is_debug_types);
-  init_cutu_and_read_dies (this_cu, 0, 0, process_psymtab_comp_unit_reader,
+  init_cutu_and_read_dies (this_cu, NULL, 0, 0,
+			   process_psymtab_comp_unit_reader,
 			   &want_partial_unit);
 
   /* Age out any secondary CUs.  */
   age_cached_comp_units ();
 }
 
-/* Traversal function for htab_traverse_noresize.
-   Process one .debug_types comp-unit.	*/
+static hashval_t
+hash_type_unit_group (const void *item)
+{
+  const struct type_unit_group *symtab = item;
+
+  return symtab->line_offset.sect_off;
+}
 
 static int
-process_psymtab_type_unit (void **slot, void *info)
+eq_type_unit_group (const void *item_lhs, const void *item_rhs)
 {
-  struct signatured_type *sig_type = (struct signatured_type *) *slot;
-  struct dwarf2_per_cu_data *per_cu = &sig_type->per_cu;
+  const struct type_unit_group *lhs = item_lhs;
+  const struct type_unit_group *rhs = item_rhs;
 
-  gdb_assert (per_cu->is_debug_types);
-  gdb_assert (info == NULL);
+  return lhs->line_offset.sect_off == rhs->line_offset.sect_off;
+}
 
-  /* 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_cu->cu != NULL)
-    free_one_cached_comp_unit (per_cu);
+/* Allocate a hash table for type unit groups.  */
+
+static htab_t
+allocate_type_unit_groups_table (void)
+{
+  return htab_create_alloc_ex (3,
+			       hash_type_unit_group,
+			       eq_type_unit_group,
+			       NULL,
+			       &dwarf2_per_objfile->objfile->objfile_obstack,
+			       hashtab_obstack_allocate,
+			       dummy_obstack_deallocate);
+}
+
+/* Type units that don't have DW_AT_stmt_list are grouped into their own
+   partial symtabs.  We combine several TUs per psymtab to not let the size
+   of any one psymtab grow too big.  */
+#define NO_STMT_LIST_TYPE_UNIT_PSYMTAB (1 << 31)
+#define NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE 10
+
+/* Helper routine for build_type_psymtabs_reader.
+   Create the type_unit_group object used to hold one or more TUs.  */
+
+static struct type_unit_group *
+create_type_unit_group (struct dwarf2_per_cu_data *per_cu,
+			sect_offset line_offset_struct)
+{
+  struct objfile *objfile = dwarf2_per_objfile->objfile;
+  struct type_unit_group *tu_group;
+  struct partial_symtab *pst;
+  unsigned int line_offset;
+  char *name;
 
-  init_cutu_and_read_dies (per_cu, 0, 0, process_psymtab_comp_unit_reader,
-			   NULL);
+  line_offset = line_offset_struct.sect_off;
 
-  /* Age out any secondary CUs.  */
-  age_cached_comp_units ();
+  /* Give the symtab a useful name for debug purposes.  */
+  if ((line_offset & NO_STMT_LIST_TYPE_UNIT_PSYMTAB) != 0)
+    name = xstrprintf ("<type_units_%d>",
+		       (line_offset & ~NO_STMT_LIST_TYPE_UNIT_PSYMTAB));
+  else
+    name = xstrprintf ("<type_units_at_0x%x>", line_offset);
+
+  tu_group = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+			     struct type_unit_group);
+
+  per_cu = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+			   struct dwarf2_per_cu_data);
+  per_cu->objfile = objfile;
+  per_cu->is_debug_types = 1;
+  per_cu->s.type_unit_group = tu_group;
+
+  pst = create_partial_symtab (per_cu, name);
+  pst->anonymous = 1;
+
+  xfree (name);
+
+  tu_group->per_cu = per_cu;
+  tu_group->line_offset.sect_off = line_offset;
+
+  return tu_group;
+}
+
+/* Look up the type_unit_group for PER_CU, and create it if necessary.
+   STMT_LIST is an DW_AT_stmt_list attribute.  */
+
+static struct type_unit_group *
+get_type_unit_group (struct dwarf2_per_cu_data *per_cu,
+		     struct attribute *stmt_list)
+{
+  struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats;
+  struct type_unit_group *tu_group;
+  void **slot;
+  unsigned int line_offset;
+  struct type_unit_group type_unit_group_for_lookup;
+
+  if (dwarf2_per_objfile->type_unit_groups == NULL)
+    {
+      dwarf2_per_objfile->type_unit_groups =
+	allocate_type_unit_groups_table ();
+    }
+
+  /* Do we need to create a new group, or can we use an existing one?  */
+
+  if (stmt_list)
+    {
+      line_offset = DW_UNSND (stmt_list);
+      ++tu_stats->nr_symtab_sharers;
+    }
+  else
+    {
+      /* Ugh, no stmt_list.  Rare, but we have to handle it.
+	 We can do various things here like create one group per TU or
+	 spread them over multiple groups to split up the expansion work.
+	 To avoid worst case scenarios (too many groups or too large groups)
+	 we, umm, group them in bunches.  */
+      line_offset = (NO_STMT_LIST_TYPE_UNIT_PSYMTAB
+		     | (tu_stats->nr_stmt_less_type_units
+			/ NO_STMT_LIST_TYPE_UNIT_PSYMTAB_SIZE));
+      ++tu_stats->nr_stmt_less_type_units;
+    }
+
+  type_unit_group_for_lookup.line_offset.sect_off = line_offset;
+  slot = htab_find_slot (dwarf2_per_objfile->type_unit_groups,
+			 &type_unit_group_for_lookup, INSERT);
+  if (*slot != NULL)
+    {
+      tu_group = *slot;
+      gdb_assert (tu_group != NULL);
+    }
+  else
+    {
+      sect_offset line_offset_struct;
+
+      line_offset_struct.sect_off = line_offset;
+      tu_group = create_type_unit_group (per_cu, line_offset_struct);
+      *slot = tu_group;
+      ++tu_stats->nr_symtabs;
+    }
+
+  return tu_group;
+}
+
+/* Struct used to sort TUs by their abbreviation table offset.  */
+
+struct tu_abbrev_offset
+{
+  struct signatured_type *sig_type;
+  sect_offset abbrev_offset;
+};
+
+/* Helper routine for build_type_unit_groups, passed to qsort.  */
+
+static int
+sort_tu_by_abbrev_offset (const void *ap, const void *bp)
+{
+  const struct tu_abbrev_offset * const *a = ap;
+  const struct tu_abbrev_offset * const *b = bp;
+  unsigned int aoff = (*a)->abbrev_offset.sect_off;
+  unsigned int boff = (*b)->abbrev_offset.sect_off;
+
+  return (aoff > boff) - (aoff < boff);
+}
+
+/* A helper function to add a type_unit_group to a table.  */
+
+static int
+add_type_unit_group_to_table (void **slot, void *datum)
+{
+  struct type_unit_group *tu_group = *slot;
+  struct type_unit_group ***datap = datum;
+
+  **datap = tu_group;
+  ++*datap;
+
+  return 1;
+}
+
+/* Efficiently read all the type units, calling init_cutu_and_read_dies on
+   each one passing FUNC,DATA.
+
+   The efficiency is because we sort TUs by the abbrev table they use and
+   only read each abbrev table once.  In one program there are 200K TUs
+   sharing 8K abbrev tables.
+
+   The main purpose of this function is to support building the
+   dwarf2_per_objfile->type_unit_groups table.
+   TUs typically share the DW_AT_stmt_list of the CU they came from, so we
+   can collapse the search space by grouping them by stmt_list.
+   The savings can be significant, in the same program from above the 200K TUs
+   share 8K stmt_list tables.
+
+   FUNC is expected to call get_type_unit_group, which will create the
+   struct type_unit_group if necessary and add it to
+   dwarf2_per_objfile->type_unit_groups.  */
+
+static void
+build_type_unit_groups (die_reader_func_ftype *func, void *data)
+{
+  struct objfile *objfile = dwarf2_per_objfile->objfile;
+  struct tu_stats *tu_stats = &dwarf2_per_objfile->tu_stats;
+  struct cleanup *cleanups;
+  struct abbrev_table *abbrev_table;
+  sect_offset abbrev_offset;
+  struct tu_abbrev_offset *sorted_by_abbrev;
+  struct type_unit_group **iter;
+  int i;
+
+  /* It's up to the caller to not call us multiple times.  */
+  gdb_assert (dwarf2_per_objfile->type_unit_groups == NULL);
+
+  if (dwarf2_per_objfile->n_type_units == 0)
+    return;
+
+  /* TUs typically share abbrev tables, and there can be way more TUs than
+     abbrev tables.  Sort by abbrev table to reduce the number of times we
+     read each abbrev table in.
+     Alternatives are to punt or to maintain a cache of abbrev tables.
+     This is simpler and efficient enough for now.
+
+     Later we group TUs by their DW_AT_stmt_list value (as this defines the
+     symtab to use).  Typically TUs with the same abbrev offset have the same
+     stmt_list value too so in practice this should work well.
+
+     The basic algorithm here is:
+
+      sort TUs by abbrev table
+      for each TU with same abbrev table:
+	read abbrev table if first user
+	read TU top level DIE
+	  [IWBN if DWO skeletons had DW_AT_stmt_list]
+	call FUNC  */
+
+  if (dwarf2_read_debug)
+    fprintf_unfiltered (gdb_stdlog, "Building type unit groups ...\n");
+
+  /* Sort in a separate table to maintain the order of all_type_units
+     for .gdb_index: TU indices directly index all_type_units.  */
+  sorted_by_abbrev = XNEWVEC (struct tu_abbrev_offset,
+			      dwarf2_per_objfile->n_type_units);
+  for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+    {
+      struct signatured_type *sig_type = dwarf2_per_objfile->all_type_units[i];
+
+      sorted_by_abbrev[i].sig_type = sig_type;
+      sorted_by_abbrev[i].abbrev_offset =
+	read_abbrev_offset (sig_type->per_cu.info_or_types_section,
+			    sig_type->per_cu.offset);
+    }
+  cleanups = make_cleanup (xfree, sorted_by_abbrev);
+  qsort (sorted_by_abbrev, dwarf2_per_objfile->n_type_units,
+	 sizeof (struct tu_abbrev_offset), sort_tu_by_abbrev_offset);
+
+  memset (tu_stats, 0, sizeof (*tu_stats));
+  abbrev_offset.sect_off = ~(unsigned) 0;
+  abbrev_table = NULL;
+  make_cleanup (abbrev_table_free_cleanup, &abbrev_table);
+
+  for (i = 0; i < dwarf2_per_objfile->n_type_units; ++i)
+    {
+      const struct tu_abbrev_offset *tu = &sorted_by_abbrev[i];
+
+      /* Switch to the next abbrev table if necessary.  */
+      if (abbrev_table == NULL
+	  || tu->abbrev_offset.sect_off != abbrev_offset.sect_off)
+	{
+	  if (abbrev_table != NULL)
+	    {
+	      abbrev_table_free (abbrev_table);
+	      /* Reset to NULL in case abbrev_table_read_table throws
+		 an error: abbrev_table_free_cleanup will get called.  */
+	      abbrev_table = NULL;
+	    }
+	  abbrev_offset = tu->abbrev_offset;
+	  abbrev_table =
+	    abbrev_table_read_table (&dwarf2_per_objfile->abbrev,
+				     abbrev_offset);
+	  ++tu_stats->nr_uniq_abbrev_tables;
+	}
+
+      init_cutu_and_read_dies (&tu->sig_type->per_cu, abbrev_table, 0, 0,
+			       func, data);
+    }
+
+  /* Create a vector of pointers to primary type units to make it easy to
+     iterate over them and CUs.  See dw2_get_primary_cu.  */
+  dwarf2_per_objfile->n_type_unit_groups =
+    htab_elements (dwarf2_per_objfile->type_unit_groups);
+  dwarf2_per_objfile->all_type_unit_groups =
+    obstack_alloc (&objfile->objfile_obstack,
+		   dwarf2_per_objfile->n_type_unit_groups
+		   * sizeof (struct type_unit_group *));
+  iter = &dwarf2_per_objfile->all_type_unit_groups[0];
+  htab_traverse_noresize (dwarf2_per_objfile->type_unit_groups,
+			  add_type_unit_group_to_table, &iter);
+  gdb_assert (iter - &dwarf2_per_objfile->all_type_unit_groups[0]
+	      == dwarf2_per_objfile->n_type_unit_groups);
+
+  do_cleanups (cleanups);
+
+  if (dwarf2_read_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "Done building type unit groups:\n");
+      fprintf_unfiltered (gdb_stdlog, "  %d TUs\n",
+			  dwarf2_per_objfile->n_type_units);
+      fprintf_unfiltered (gdb_stdlog, "  %d uniq abbrev tables\n",
+			  tu_stats->nr_uniq_abbrev_tables);
+      fprintf_unfiltered (gdb_stdlog, "  %d symtabs from stmt_list entries\n",
+			  tu_stats->nr_symtabs);
+      fprintf_unfiltered (gdb_stdlog, "  %d symtab sharers\n",
+			  tu_stats->nr_symtab_sharers);
+      fprintf_unfiltered (gdb_stdlog, "  %d type units without a stmt_list\n",
+			  tu_stats->nr_stmt_less_type_units);
+    }
+}
+
+/* Reader function for build_type_psymtabs.  */
+
+static void
+build_type_psymtabs_reader (const struct die_reader_specs *reader,
+			    gdb_byte *info_ptr,
+			    struct die_info *type_unit_die,
+			    int has_children,
+			    void *data)
+{
+  struct objfile *objfile = dwarf2_per_objfile->objfile;
+  struct dwarf2_cu *cu = reader->cu;
+  struct dwarf2_per_cu_data *per_cu = cu->per_cu;
+  struct type_unit_group *tu_group;
+  struct attribute *attr;
+  struct partial_die_info *first_die;
+  CORE_ADDR lowpc, highpc;
+  struct partial_symtab *pst;
+
+  gdb_assert (data == NULL);
+
+  if (! has_children)
+    return;
+
+  attr = dwarf2_attr_no_follow (type_unit_die, DW_AT_stmt_list);
+  tu_group = get_type_unit_group (per_cu, attr);
+
+  VEC_safe_push (dwarf2_per_cu_ptr, tu_group->tus, per_cu);
+
+  prepare_one_comp_unit (cu, type_unit_die, language_minimal);
+  cu->list_in_scope = &file_symbols;
+  pst = create_partial_symtab (per_cu, "");
+  pst->anonymous = 1;
+
+  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->n_global_syms = objfile->global_psymbols.next -
+    (objfile->global_psymbols.list + pst->globals_offset);
+  pst->n_static_syms = objfile->static_psymbols.next -
+    (objfile->static_psymbols.list + pst->statics_offset);
+  sort_pst_symbols (pst);
+}
+
+/* Traversal function for build_type_psymtabs.  */
+
+static int
+build_type_psymtab_dependencies (void **slot, void *info)
+{
+  struct objfile *objfile = dwarf2_per_objfile->objfile;
+  struct type_unit_group *tu_group = (struct type_unit_group *) *slot;
+  struct dwarf2_per_cu_data *per_cu = tu_group->per_cu;
+  struct partial_symtab *pst = per_cu->v.psymtab;
+  int len = VEC_length (dwarf2_per_cu_ptr, tu_group->tus);
+  struct dwarf2_per_cu_data *iter;
+  int i;
+
+  gdb_assert (len > 0);
+
+  pst->number_of_dependencies = len;
+  pst->dependencies = obstack_alloc (&objfile->objfile_obstack,
+				     len * sizeof (struct psymtab *));
+  for (i = 0;
+       VEC_iterate (dwarf2_per_cu_ptr, tu_group->tus, i, iter);
+       ++i)
+    {
+      pst->dependencies[i] = iter->v.psymtab;
+      iter->s.type_unit_group = tu_group;
+    }
+
+  VEC_free (dwarf2_per_cu_ptr, tu_group->tus);
 
   return 1;
 }
@@ -4509,8 +5101,11 @@ build_type_psymtabs (struct objfile *obj
   if (! create_all_type_units (objfile))
     return;
 
-  htab_traverse_noresize (dwarf2_per_objfile->signatured_types,
-			  process_psymtab_type_unit, NULL);
+  build_type_unit_groups (build_type_psymtabs_reader, NULL);
+
+  /* Now that all TUs have been processed we can fill in the dependencies.  */
+  htab_traverse_noresize (dwarf2_per_objfile->type_unit_groups,
+			  build_type_psymtab_dependencies, NULL);
 }
 
 /* A cleanup function that clears objfile's psymtabs_addrmap field.  */
@@ -4626,7 +5221,8 @@ load_partial_comp_unit_reader (const str
 static void
 load_partial_comp_unit (struct dwarf2_per_cu_data *this_cu)
 {
-  init_cutu_and_read_dies (this_cu, 1, 1, load_partial_comp_unit_reader, NULL);
+  init_cutu_and_read_dies (this_cu, NULL, 1, 1,
+			   load_partial_comp_unit_reader, NULL);
 }
 
 /* Create a list of all compilation units in OBJFILE.
@@ -4765,6 +5361,14 @@ scan_partial_symbols (struct partial_die
 	      {
 		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]"),
+			   cu->objfile->name);
+		  }
+
 		per_cu = dwarf2_find_containing_comp_unit (pdi->d.offset,
 							   cu->objfile);
 
@@ -4772,8 +5376,8 @@ scan_partial_symbols (struct partial_die
 		if (per_cu->v.psymtab == NULL)
 		  process_psymtab_comp_unit (per_cu, 1);
 
-		VEC_safe_push (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs,
-			       per_cu);
+		VEC_safe_push (dwarf2_per_cu_ptr,
+			       cu->per_cu->s.imported_symtabs, per_cu);
 	      }
 	      break;
 	    default:
@@ -5558,7 +6162,30 @@ process_queue (void)
       if (dwarf2_per_objfile->using_index
 	  ? !item->per_cu->v.quick->symtab
 	  : (item->per_cu->v.psymtab && !item->per_cu->v.psymtab->readin))
-	process_full_comp_unit (item->per_cu, item->pretend_language);
+	{
+	  struct dwarf2_per_cu_data *per_cu = item->per_cu;
+
+	  if (dwarf2_read_debug)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "Expanding symtab of %s at offset 0x%x\n",
+				  per_cu->is_debug_types ? "TU" : "CU",
+				  per_cu->offset.sect_off);
+	    }
+
+	  if (per_cu->is_debug_types)
+	    process_full_type_unit (per_cu, item->pretend_language);
+	  else
+	    process_full_comp_unit (per_cu, item->pretend_language);
+
+	  if (dwarf2_read_debug)
+	    {
+	      fprintf_unfiltered (gdb_stdlog,
+				  "Done expanding %s at offset 0x%x\n",
+				  per_cu->is_debug_types ? "TU" : "CU",
+				  per_cu->offset.sect_off);
+	    }
+	}
 
       item->per_cu->queued = 0;
       next_item = item->next;
@@ -5716,8 +6343,8 @@ load_full_comp_unit (struct dwarf2_per_c
 {
   gdb_assert (! this_cu->is_debug_types);
 
-  init_cutu_and_read_dies (this_cu, 1, 1, load_full_comp_unit_reader,
-			   &pretend_language);
+  init_cutu_and_read_dies (this_cu, NULL, 1, 1,
+			   load_full_comp_unit_reader, &pretend_language);
 }
 
 /* Add a DIE to the delayed physname list.  */
@@ -5880,7 +6507,7 @@ recursively_compute_inclusions (VEC (dwa
     VEC_safe_push (dwarf2_per_cu_ptr, *result, per_cu);
 
   for (ix = 0;
-       VEC_iterate (dwarf2_per_cu_ptr, per_cu->imported_symtabs, ix, iter);
+       VEC_iterate (dwarf2_per_cu_ptr, per_cu->s.imported_symtabs, ix, iter);
        ++ix)
     recursively_compute_inclusions (result, all_children, iter);
 }
@@ -5891,7 +6518,9 @@ recursively_compute_inclusions (VEC (dwa
 static void
 compute_symtab_includes (struct dwarf2_per_cu_data *per_cu)
 {
-  if (!VEC_empty (dwarf2_per_cu_ptr, per_cu->imported_symtabs))
+  gdb_assert (! per_cu->is_debug_types);
+
+  if (!VEC_empty (dwarf2_per_cu_ptr, per_cu->s.imported_symtabs))
     {
       int ix, len;
       struct dwarf2_per_cu_data *iter;
@@ -5907,7 +6536,7 @@ compute_symtab_includes (struct dwarf2_p
 					NULL, xcalloc, xfree);
 
       for (ix = 0;
-	   VEC_iterate (dwarf2_per_cu_ptr, per_cu->imported_symtabs,
+	   VEC_iterate (dwarf2_per_cu_ptr, per_cu->s.imported_symtabs,
 			ix, iter);
 	   ++ix)
 	recursively_compute_inclusions (&result_children, all_children, iter);
@@ -5942,7 +6571,10 @@ process_cu_includes (void)
        VEC_iterate (dwarf2_per_cu_ptr, dwarf2_per_objfile->just_read_cus,
 		    ix, iter);
        ++ix)
-    compute_symtab_includes (iter);
+    {
+      if (! iter->is_debug_types)
+	compute_symtab_includes (iter);
+    }
 
   VEC_free (dwarf2_per_cu_ptr, dwarf2_per_objfile->just_read_cus);
 }
@@ -5961,14 +6593,6 @@ process_full_comp_unit (struct dwarf2_pe
   struct cleanup *back_to, *delayed_list_cleanup;
   CORE_ADDR baseaddr;
 
-  if (dwarf2_read_debug)
-    {
-      fprintf_unfiltered (gdb_stdlog,
-			  "Expanding symtab of %s at offset 0x%x\n",
-			  per_cu->is_debug_types ? "TU" : "CU",
-			  per_cu->offset.sect_off);
-    }
-
   baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
 
   buildsym_init ();
@@ -6044,14 +6668,78 @@ process_full_comp_unit (struct dwarf2_pe
   VEC_safe_push (dwarf2_per_cu_ptr, dwarf2_per_objfile->just_read_cus, per_cu);
 
   do_cleanups (back_to);
+}
 
-  if (dwarf2_read_debug)
+/* Generate full symbol information for type unit PER_CU, whose DIEs have
+   already been loaded into memory.  */
+
+static void
+process_full_type_unit (struct dwarf2_per_cu_data *per_cu,
+			enum language pretend_language)
+{
+  struct dwarf2_cu *cu = per_cu->cu;
+  struct objfile *objfile = per_cu->objfile;
+  struct symtab *symtab;
+  struct cleanup *back_to, *delayed_list_cleanup;
+
+  buildsym_init ();
+  back_to = make_cleanup (really_free_pendings, NULL);
+  delayed_list_cleanup = make_cleanup (free_delayed_list, cu);
+
+  cu->list_in_scope = &file_symbols;
+
+  cu->language = pretend_language;
+  cu->language_defn = language_def (cu->language);
+
+  /* The symbol tables are set up in read_type_unit_scope.  */
+  process_die (cu->dies, cu);
+
+  /* For now fudge the Go package.  */
+  if (cu->language == language_go)
+    fixup_go_packaging (cu);
+
+  /* Now that we have processed all the DIEs in the CU, all the types 
+     should be complete, and it should now be safe to compute all of the
+     physnames.  */
+  compute_delayed_physnames (cu);
+  do_cleanups (delayed_list_cleanup);
+
+  /* TUs share symbol tables.
+     If this is the first TU to use this symtab, complete the construction
+     of it with end_symtab.  Otherwise, complete the addition of this TU's
+     symbols to the existing symtab.  */
+  if (per_cu->s.type_unit_group->primary_symtab == NULL)
+    {
+      symtab = end_expandable_symtab (0, objfile, SECT_OFF_TEXT (objfile));
+      per_cu->s.type_unit_group->primary_symtab = symtab;
+
+      if (symtab != NULL)
+	{
+	  /* Set symtab language to language from DW_AT_language.  If the
+	     compilation is from a C file generated by language preprocessors,
+	     do not set the language if it was already deduced by
+	     start_subfile.  */
+	  if (!(cu->language == language_c && symtab->language != language_c))
+	    symtab->language = cu->language;
+	}
+    }
+  else
     {
-      fprintf_unfiltered (gdb_stdlog,
-			  "Done expanding symtab of %s at offset 0x%x\n",
-			  per_cu->is_debug_types ? "TU" : "CU",
-			  per_cu->offset.sect_off);
+      augment_type_symtab (objfile,
+			   per_cu->s.type_unit_group->primary_symtab);
+      symtab = per_cu->s.type_unit_group->primary_symtab;
     }
+
+  if (dwarf2_per_objfile->using_index)
+    per_cu->v.quick->symtab = symtab;
+  else
+    {
+      struct partial_symtab *pst = per_cu->v.psymtab;
+      pst->symtab = symtab;
+      pst->readin = 1;
+    }
+
+  do_cleanups (back_to);
 }
 
 /* Process an imported unit DIE.  */
@@ -6061,6 +6749,14 @@ process_imported_unit_die (struct die_in
 {
   struct attribute *attr;
 
+  /* 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]"),
+	     cu->objfile->name);
+    }
+
   attr = dwarf2_attr (die, DW_AT_import, cu);
   if (attr != NULL)
     {
@@ -6075,7 +6771,7 @@ process_imported_unit_die (struct die_in
       if (maybe_queue_comp_unit (cu, per_cu, cu->language))
 	load_full_comp_unit (per_cu, cu->language);
 
-      VEC_safe_push (dwarf2_per_cu_ptr, cu->per_cu->imported_symtabs,
+      VEC_safe_push (dwarf2_per_cu_ptr, cu->per_cu->s.imported_symtabs,
 		     per_cu);
     }
 }
@@ -6760,7 +7456,7 @@ read_import_statement (struct die_info *
   do_cleanups (cleanups);
 }
 
-/* Cleanup function for read_file_scope.  */
+/* Cleanup function for handle_DW_AT_stmt_list.  */
 
 static void
 free_cu_line_header (void *arg)
@@ -6811,17 +7507,19 @@ find_file_and_directory (struct die_info
     *name = "<unknown>";
 }
 
-/* Handle DW_AT_stmt_list for a compilation unit or type unit.
-   DIE is the DW_TAG_compile_unit or DW_TAG_type_unit die for CU.
+/* Handle DW_AT_stmt_list for a compilation unit.
+   DIE is the DW_TAG_compile_unit die for CU.
    COMP_DIR is the compilation directory.
    WANT_LINE_INFO is non-zero if the pc/line-number mapping is needed.  */
 
 static void
 handle_DW_AT_stmt_list (struct die_info *die, struct dwarf2_cu *cu,
-			const char *comp_dir, int want_line_info)
+			const char *comp_dir)
 {
   struct attribute *attr;
 
+  gdb_assert (! cu->per_cu->is_debug_types);
+
   attr = dwarf2_attr (die, DW_AT_stmt_list, cu);
   if (attr)
     {
@@ -6833,7 +7531,7 @@ handle_DW_AT_stmt_list (struct die_info 
 	{
 	  cu->line_header = line_header;
 	  make_cleanup (free_cu_line_header, cu);
-	  dwarf_decode_lines (line_header, comp_dir, cu, NULL, want_line_info);
+	  dwarf_decode_lines (line_header, comp_dir, cu, NULL, 1);
 	}
     }
 }
@@ -6879,19 +7577,12 @@ read_file_scope (struct die_info *die, s
   if (cu->producer && strstr (cu->producer, "GNU Go ") != NULL)
     set_cu_language (DW_LANG_Go, cu);
 
-  /* We assume that we're processing GCC output.  */
-  processing_gcc_compilation = 2;
-
-  processing_has_namespace_info = 0;
-
-  start_symtab (name, comp_dir, lowpc);
-  record_debugformat ("DWARF 2");
-  record_producer (cu->producer);
+  dwarf2_start_symtab (cu, name, comp_dir, lowpc);
 
   /* 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, comp_dir, 1);
+  handle_DW_AT_stmt_list (die, cu, comp_dir);
 
   /* Process all dies in compilation unit.  */
   if (die->child != NULL)
@@ -6931,81 +7622,141 @@ read_file_scope (struct die_info *die, s
   do_cleanups (back_to);
 }
 
-/* Process DW_TAG_type_unit.
-   For TUs we want to skip the first top level sibling if it's not the
-   actual type being defined by this TU.  In this case the first top
-   level sibling is there to provide context only.  */
+/* TU version of handle_DW_AT_stmt_list for read_type_unit_scope.
+   Create the set of symtabs used by this TU, or if this TU is sharing
+   symtabs with another TU and the symtabs have already been created
+   then restore those symtabs in the line header.
+   We don't need the pc/line-number mapping for type units.  */
 
 static void
-read_type_unit_scope (struct die_info *die, struct dwarf2_cu *cu)
+setup_type_unit_groups (struct die_info *die, struct dwarf2_cu *cu)
 {
-  struct objfile *objfile = cu->objfile;
-  struct cleanup *back_to = make_cleanup (null_cleanup, 0);
-  CORE_ADDR lowpc;
+  struct objfile *objfile = dwarf2_per_objfile->objfile;
+  struct dwarf2_per_cu_data *per_cu = cu->per_cu;
+  struct type_unit_group *tu_group;
+  int first_time;
+  struct line_header *lh;
   struct attribute *attr;
-  char *name = NULL;
-  char *comp_dir = NULL;
-  struct die_info *child_die;
-  bfd *abfd = objfile->obfd;
+  unsigned int i, line_offset;
 
-  /* start_symtab needs a low pc, but we don't really have one.
-     Do what read_file_scope would do in the absence of such info.  */
-  lowpc = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+  gdb_assert (per_cu->is_debug_types);
 
-  /* Find the filename.  Do not use dwarf2_name here, since the filename
-     is not a source language identifier.  */
-  attr = dwarf2_attr (die, DW_AT_name, cu);
-  if (attr)
-    name = DW_STRING (attr);
+  attr = dwarf2_attr (die, DW_AT_stmt_list, cu);
 
-  attr = dwarf2_attr (die, DW_AT_comp_dir, cu);
-  if (attr)
-    comp_dir = DW_STRING (attr);
-  else if (name != NULL && IS_ABSOLUTE_PATH (name))
+  /* If we're using .gdb_index (includes -readnow) then
+     per_cu->s.type_unit_group may not have been set up yet.  */
+  if (per_cu->s.type_unit_group == NULL)
+    per_cu->s.type_unit_group = get_type_unit_group (per_cu, attr);
+  tu_group = per_cu->s.type_unit_group;
+
+  /* If we've already processed this stmt_list there's no real need to
+     do it again, we could fake it and just recreate the part we need
+     (file name,index -> symtab mapping).  If data shows this optimization
+     is useful we can do it then.  */
+  first_time = tu_group->primary_symtab == NULL;
+
+  /* We have to handle the case of both a missing DW_AT_stmt_list or bad
+     debug info.  */
+  lh = NULL;
+  if (attr != NULL)
     {
-      comp_dir = ldirname (name);
-      if (comp_dir != NULL)
-	make_cleanup (xfree, comp_dir);
+      line_offset = DW_UNSND (attr);
+      lh = dwarf_decode_line_header (line_offset, cu);
+    }
+  if (lh == NULL)
+    {
+      if (first_time)
+	dwarf2_start_symtab (cu, "", NULL, 0);
+      else
+	{
+	  gdb_assert (tu_group->symtabs == NULL);
+	  restart_symtab (0);
+	}
+      /* Note: The primary symtab will get allocated at the end.  */
+      return;
     }
 
-  if (name == NULL)
-    name = "<unknown>";
+  cu->line_header = lh;
+  make_cleanup (free_cu_line_header, cu);
 
-  prepare_one_comp_unit (cu, die, language_minimal);
+  if (first_time)
+    {
+      dwarf2_start_symtab (cu, "", NULL, 0);
 
-  /* We assume that we're processing GCC output.  */
-  processing_gcc_compilation = 2;
+      tu_group->num_symtabs = lh->num_file_names;
+      tu_group->symtabs = XNEWVEC (struct symtab *, lh->num_file_names);
 
-  processing_has_namespace_info = 0;
+      for (i = 0; i < lh->num_file_names; ++i)
+	{
+	  char *dir = NULL;
+	  struct file_entry *fe = &lh->file_names[i];
 
-  start_symtab (name, comp_dir, lowpc);
-  record_debugformat ("DWARF 2");
-  record_producer (cu->producer);
+	  if (fe->dir_index)
+	    dir = lh->include_dirs[fe->dir_index - 1];
+	  dwarf2_start_subfile (fe->name, dir, NULL);
 
-  /* 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.
-     We don't need the pc/line-number mapping for type units.  */
-  handle_DW_AT_stmt_list (die, cu, comp_dir, 0);
+	  /* Note: We don't have to watch for the main subfile here, type units
+	     don't have DW_AT_name.  */
 
-  /* Process the dies in the type unit.  */
-  if (die->child == NULL)
+	  if (current_subfile->symtab == NULL)
+	    {
+	      /* NOTE: start_subfile will recognize when it's been passed
+		 a file it has already seen.  So we can't assume there's a
+		 simple mapping from lh->file_names to subfiles,
+		 lh->file_names may contain dups.  */
+	      current_subfile->symtab = allocate_symtab (current_subfile->name,
+							 objfile);
+	    }
+
+	  fe->symtab = current_subfile->symtab;
+	  tu_group->symtabs[i] = fe->symtab;
+	}
+    }
+  else
     {
-      dump_die_for_error (die);
-      error (_("Dwarf Error: Missing children for type unit [in module %s]"),
-	     bfd_get_filename (abfd));
+      restart_symtab (0);
+
+      for (i = 0; i < lh->num_file_names; ++i)
+	{
+	  struct file_entry *fe = &lh->file_names[i];
+
+	  fe->symtab = tu_group->symtabs[i];
+	}
     }
 
-  child_die = die->child;
+  /* The main symtab is allocated last.  Type units don't have DW_AT_name
+     so they don't have a "real" (so to speak) symtab anyway.
+     There is later code that will assign the main symtab to all symbols
+     that don't have one.  We need to handle the case of a symbol with a
+     missing symtab (DW_AT_decl_file) anyway.  */
+}
 
-  while (child_die && child_die->tag)
-    {
-      process_die (child_die, cu);
+/* Process DW_TAG_type_unit.
+   For TUs we want to skip the first top level sibling if it's not the
+   actual type being defined by this TU.  In this case the first top
+   level sibling is there to provide context only.  */
 
-      child_die = sibling_die (child_die);
-    }
+static void
+read_type_unit_scope (struct die_info *die, struct dwarf2_cu *cu)
+{
+  struct die_info *child_die;
 
-  do_cleanups (back_to);
+  prepare_one_comp_unit (cu, die, language_minimal);
+
+  /* Initialize (or reinitialize) the machinery for building symtabs.
+     We do this before processing child DIEs, so that the line header table
+     is available for DW_AT_decl_file.  */
+  setup_type_unit_groups (die, cu);
+
+  if (die->child != NULL)
+    {
+      child_die = die->child;
+      while (child_die && child_die->tag)
+	{
+	  process_die (child_die, cu);
+	  child_die = sibling_die (child_die);
+	}
+    }
 }
 
 /* DWO files.  */
@@ -11155,6 +11906,7 @@ abbrev_table_read_table (struct dwarf2_s
   unsigned int allocated_attrs;
 
   abbrev_table = XMALLOC (struct abbrev_table);
+  abbrev_table->offset = offset;
   obstack_init (&abbrev_table->abbrev_obstack);
   abbrev_table->abbrevs = obstack_alloc (&abbrev_table->abbrev_obstack,
 					 (ABBREV_HASH_SIZE
@@ -11241,6 +11993,21 @@ abbrev_table_free (struct abbrev_table *
   xfree (abbrev_table);
 }
 
+/* Same as abbrev_table_free but as a cleanup.
+   We pass in a pointer to the pointer to the table so that we can
+   set the pointer to NULL when we're done.  It also simplifies
+   build_type_unit_groups.  */
+
+static void
+abbrev_table_free_cleanup (void *table_ptr)
+{
+  struct abbrev_table **abbrev_table_ptr = table_ptr;
+
+  if (*abbrev_table_ptr != NULL)
+    abbrev_table_free (*abbrev_table_ptr);
+  *abbrev_table_ptr = NULL;
+}
+
 /* Read the abbrev table for CU from ABBREV_SECTION.  */
 
 static void
@@ -13600,6 +14367,23 @@ dwarf2_start_subfile (char *filename, co
     xfree (fullname);
 }
 
+/* Start a symtab for DWARF.
+   NAME, COMP_DIR, LOW_PC are passed to start_symtab.  */
+
+static void
+dwarf2_start_symtab (struct dwarf2_cu *cu,
+		     char *name, char *comp_dir, CORE_ADDR low_pc)
+{
+  start_symtab (name, comp_dir, low_pc);
+  record_debugformat ("DWARF 2");
+  record_producer (cu->producer);
+
+  /* We assume that we're processing GCC output.  */
+  processing_gcc_compilation = 2;
+
+  processing_has_namespace_info = 0;
+}
+
 static void
 var_decode_location (struct attribute *attr, struct symbol *sym,
 		     struct dwarf2_cu *cu)
@@ -15515,6 +16299,9 @@ load_full_type_unit (struct dwarf2_per_c
 {
   struct signatured_type *sig_type;
 
+  /* Caller is responsible for ensuring type_unit_groups don't get here.  */
+  gdb_assert (! IS_TYPE_UNIT_GROUP (per_cu));
+
   /* We have the per_cu, but we need the signatured_type.
      Fortunately this is an easy translation.  */
   gdb_assert (per_cu->is_debug_types);
@@ -15577,7 +16364,8 @@ read_signatured_type (struct signatured_
   gdb_assert (per_cu->is_debug_types);
   gdb_assert (per_cu->cu == NULL);
 
-  init_cutu_and_read_dies (per_cu, 0, 1, read_signatured_type_reader, NULL);
+  init_cutu_and_read_dies (per_cu, NULL, 0, 1,
+			   read_signatured_type_reader, NULL);
 }
 
 /* Decode simple location descriptions.
@@ -17510,7 +18298,7 @@ dwarf2_per_objfile_free (struct objfile 
 
   for (ix = 0; ix < dwarf2_per_objfile->n_comp_units; ++ix)
     VEC_free (dwarf2_per_cu_ptr,
-	      dwarf2_per_objfile->all_comp_units[ix]->imported_symtabs);
+	      dwarf2_per_objfile->all_comp_units[ix]->s.imported_symtabs);
 
   VEC_free (dwarf2_section_info_def, data->types);
 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]