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]

Re: [3/4] RFC: add DWARF index support


>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

>> +@cindex @file{.gnu-index} file

Eli> ".gdb-index", I believe.

Yeah.  I went with the section name instead here in the new patch.

>> +To create an index file, use the @code{maint save-gdb-index} command:

Eli> Why are we putting this command in the "maint" class?  It sounds like
Eli> a first-class user-level feature, not a GDB maintainer's feature.

I moved it.

>> +@item maint save-gdb-index @var{directory}

Eli> Btw, why isn't this argument optional?

I didn't need that.

Here is a new patch.

Tom

b/gdb/ChangeLog:
2010-07-08  Tom Tromey  <tromey@redhat.com>

	* breakpoint.c (save_cmdlist): No longer static.
	* gdbcmd.h (save_cmdlist): Declare.
	* symfile.c (symbol_file_add_with_addrs_or_offsets): Set
	OBJF_READNOW on objfile if readnow_symbol_files.
	* elfread.c (elf_symfile_read): Use dwarf2_initialize_objfile.
	(elf_sym_fns_gdb_index): New global.
	* dwarf2read.c: Include exceptions.h.
	(offset_type): New.
	(struct mapped_index): New.
	(dwarf2_per_cu_data_ptr): New typedef.
	(struct dwarf2_per_objfile) <using_index, index_table, gdb_index>:
	New fields.
	(GDB_INDEX_SECTION): New define.
	(struct dwarf2_per_cu_quick_data): New.
	(struct dwarf2_per_cu_data) <objfile>: New field.
	<psymtab>: Removed.
	<v>: New field.
	(byte_swap): New function.
	(MAYBE_SWAP): New macro.
	(INDEX_SUFFIX): New macro.
	(dw2_do_instantiate_symtab): New function.
	(dw2_instantiate_symtab): Likewise.
	(create_cus_from_index): Likewise.
	(create_addrmap_from_index): Likewise.
	(mapped_index_string_hash): Likewise.
	(find_slot_in_mapped_hash): Likewise.
	(dwarf2_read_index): Likewise.
	(dw2_setup): Likewise.
	(dw2_require_line_header): Likewise.
	(dw2_require_full_path): Likewise.
	(dw2_find_last_source_symtab): Likewise.
	(dw2_forget_cached_source_info): Likewise.
	(dw2_lookup_symtab): Likewise.
	(dw2_lookup_symbol): Likewise.
	(dw2_do_expand_symtabs_matching): Likewise.
	(dw2_pre_expand_symtabs_matching): Likewise.
	(dw2_print_stats): Likewise.
	(dw2_dump): Likewise.
	(dw2_relocate): Likewise.
	(dw2_expand_symtabs_for_function): Likewise.
	(dw2_expand_all_symtabs): Likewise.
	(dw2_expand_symtabs_with_filename): Likewise.
	(dw2_find_symbol_file): Likewise.
	(dw2_map_ada_symtabs): Likewise.
	(dw2_expand_symtabs_matching): Likewise.
	(dw2_find_pc_sect_symtab): Likewise.
	(dw2_map_symbol_names): Likewise.
	(dw2_map_symbol_filenames): Likewise.
	(dw2_has_symbols): Likewise.
	(dwarf2_gdb_index_functions): New global.
	(dwarf2_initialize_objfile): New function.
	(process_psymtab_comp_unit): Update.
	(add_partial_subprogram): Likewise.
	(dwarf2_psymtab_to_symtab): Likewise.
	(psymtab_to_symtab_1): Use dw2_do_instantiate_symtab.
	(process_full_comp_unit): Update.
	(find_file_and_directory): New function.
	(read_file_scope): Use find_file_and_directory.
	(dwarf2_per_cu_objfile): Update.
	(dwarf2_per_cu_addr_size): Update.
	(dwarf2_per_cu_offset_size): Update.
	(dwarf2_free_objfile): Free the index, if needed.
	(dwarf2_per_objfile_free): Unmap the index, if needed.
	(struct strtab_entry): New.
	(hash_strtab_entry): New function.
	(eq_strtab_entry): Likewise.
	(create_strtab): Likewise.
	(add_string): Likewise.
	(struct symtab_index_entry): New.
	(struct mapped_symtab): New.
	(hash_symtab_entry): New function.
	(eq_symtab_entry): Likewise.
	(delete_symtab_entry): Likewise.
	(create_index_table): Likewise.
	(create_mapped_symtab): Likewise.
	(cleanup_mapped_symtab): Likewise.
	(find_slot): Likewise.
	(hash_expand): Likewise.
	(add_index_entry): Likewise.
	(add_indices_to_cpool): Likewise.
	(write_hash_table): Likewise.
	(add_address_entry): Likewise.
	(write_psymbols): Likewise.
	(write_obstack): Likewise.
	(unlink_if_set): Likewise.
	(write_psymtabs_to_index): Likewise.
	(save_gdb_index_command): Likewise.
	(_initialize_dwarf2_read): Install "save gdb-index"
	command.
	(create_all_comp_units): Initialize 'objfile' field of CU.
	(dwarf2_locate_sections): Check for .gdb_index.
	* psymtab.h (dwarf2_gdb_index_functions): Declare.
	* symfile.h (dwarf2_initialize_objfile): Declare.

b/gdb/doc/ChangeLog:
2010-06-30  Tom Tromey  <tromey@redhat.com>

	* gdb.texinfo (Index Files): New node.

>From ca54c7023e780a22f94a3de8c2d6f8ee630d8164 Mon Sep 17 00:00:00 2001
From: Tom Tromey <tromey@redhat.com>
Date: Wed, 30 Jun 2010 14:34:23 -0600
Subject: [PATCH 2/3] add .gdb-index support

---
 gdb/ChangeLog       |   96 +++
 gdb/breakpoint.c    |    2 +-
 gdb/doc/ChangeLog   |    4 +
 gdb/doc/gdb.texinfo |   41 ++
 gdb/dwarf2read.c    | 1695 +++++++++++++++++++++++++++++++++++++++++++++++++--
 gdb/elfread.c       |   29 +-
 gdb/gdbcmd.h        |    4 +
 gdb/psymtab.h       |    4 +-
 gdb/symfile.c       |    5 +-
 gdb/symfile.h       |    1 +
 10 files changed, 1813 insertions(+), 68 deletions(-)

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 77f8b0d..29e1afc 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -425,7 +425,7 @@ static int tracepoint_count;
 
 static struct cmd_list_element *breakpoint_set_cmdlist;
 static struct cmd_list_element *breakpoint_show_cmdlist;
-static struct cmd_list_element *save_cmdlist;
+struct cmd_list_element *save_cmdlist;
 
 /* Return whether a breakpoint is an active enabled breakpoint.  */
 static int
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 14b0092..69141e3 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -14116,6 +14116,7 @@ program.  To debug a core dump of a previous run, you must also tell
 @menu
 * Files::                       Commands to specify files
 * Separate Debug Files::        Debugging information in separate files
+* Index Files::                 Index files speed up GDB
 * Symbol Errors::               Errors reading symbol files
 * Data Files::                  GDB data files
 @end menu
@@ -15005,6 +15006,46 @@ gnu_debuglink_crc32 (unsigned long crc,
 This computation does not apply to the ``build ID'' method.
 
 
+@node Index Files
+@section Index Files Speed Up @value{GDBN}
+@cindex index files
+@cindex @samp{.gdb_index} section
+
+When @value{GDBN} finds a symbol file, it scans the symbols in the
+file in order to construct an internal symbol table.  This lets most
+@value{GDBN} operations work quickly---at the cost of a delay early
+on.  For large programs, this delay can be quite lengthy, so
+@value{GDBN} provides a way to build an index, which speeds up
+startup.
+
+The index is stored as a section in the symbol file.  @value{GDBN} can
+write the index to a file, then you can put it into the symbol file
+using @command{objcopy}.
+
+To create an index file, use the @code{save gdb-index} command:
+
+@table @code
+@item save gdb-index @var{directory}
+@kindex save gdb-index
+Create an index file for each symbol file currently known by
+@value{GDBN}.  Each file is named after its corresponding symbol file,
+with @samp{.gdb-index} appended, and is written into the given
+@var{directory}.
+@end table
+
+Once you have created an index file you can merge it into your symbol
+file, here named @file{symfile}, using @command{objcopy}:
+
+@smallexample
+$ objcopy --add-section .gdb_index=symfile.gdb-index \
+    --set-section-flags .gdb_index=readonly symfile symfile
+@end smallexample
+
+There are currently some limitation on indices.  They only work when
+for DWARF debugging information, not stabs.  And, they do not
+currently work for programs using Ada.
+
+
 @node Symbol Errors
 @section Errors Reading Symbol Files
 
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 858b18e..2c9a886 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -51,6 +51,8 @@
 #include "typeprint.h"
 #include "jv-lang.h"
 #include "psympriv.h"
+#include "exceptions.h"
+#include "gdb_stat.h"
 
 #include <fcntl.h>
 #include "gdb_string.h"
@@ -129,6 +131,33 @@ struct dwarf2_section_info
   int readin;
 };
 
+/* All offsets in the index are of this type.  It must be
+   architecture-independent.  */
+typedef uint32_t offset_type;
+
+DEF_VEC_I (offset_type);
+
+/* A description of the mapped index.  The file format is described in
+   a comment by the code that writes the index.  */
+struct mapped_index
+{
+  /* The total length of the buffer.  */
+  off_t total_size;
+  /* A pointer to the address table data.  */
+  const gdb_byte *address_table;
+  /* Size of the address table data in bytes.  */
+  offset_type address_table_size;
+  /* The hash table.  */
+  const offset_type *index_table;
+  /* Size in slots, each slot is 2 offset_types.  */
+  offset_type index_table_slots;
+  /* A pointer to the constant pool.  */
+  const char *constant_pool;
+};
+
+typedef struct dwarf2_per_cu_data *dwarf2_per_cu_data_ptr;
+DEF_VEC_P (dwarf2_per_cu_data_ptr);
+
 struct dwarf2_per_objfile
 {
   struct dwarf2_section_info info;
@@ -141,6 +170,7 @@ struct dwarf2_per_objfile
   struct dwarf2_section_info types;
   struct dwarf2_section_info frame;
   struct dwarf2_section_info eh_frame;
+  struct dwarf2_section_info gdb_index;
 
   /* Back link.  */
   struct objfile *objfile;
@@ -163,6 +193,12 @@ struct dwarf2_per_objfile
   /* A flag indicating wether this objfile has a section loaded at a
      VMA of 0.  */
   int has_section_at_zero;
+
+  /* True if we are using the mapped index.  */
+  unsigned char using_index;
+
+  /* The mapped index.  */
+  struct mapped_index *index_table;
 };
 
 static struct dwarf2_per_objfile *dwarf2_per_objfile;
@@ -182,6 +218,7 @@ static struct dwarf2_per_objfile *dwarf2_per_objfile;
 #define TYPES_SECTION    "debug_types"
 #define FRAME_SECTION    "debug_frame"
 #define EH_FRAME_SECTION "eh_frame"
+#define GDB_INDEX_SECTION "gdb_index"
 
 /* local data types */
 
@@ -307,6 +344,32 @@ struct dwarf2_cu
   unsigned int has_namespace_info : 1;
 };
 
+/* 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 line table.  This can be NULL if there was no line table.  */
+  struct line_header *lines;
+
+  /* The file names from the line table.  */
+  const char **file_names;
+  /* The file names from the line table after being run through
+     gdb_realpath.  */
+  const char **full_names;
+
+  /* The corresponding symbol table.  This is NULL if symbols for this
+     CU have not yet been read.  */
+  struct symtab *symtab;
+
+  /* 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 line table.  */
+  unsigned int read_lines : 1;
+};
+
 /* Persistent data held for a compilation unit, even when not
    processing it.  We put a pointer to this structure in the
    read_symtab_private field of the psymtab.  If we encounter
@@ -347,10 +410,21 @@ struct dwarf2_per_cu_data
      it.  */
   htab_t type_hash;
 
-  /* The partial symbol table associated with this compilation unit,
-     or NULL for partial units (which do not have an associated
-     symtab).  */
-  struct partial_symtab *psymtab;
+  /* The corresponding objfile.  */
+  struct objfile *objfile;
+
+  /* When using partial symbol tables, the 'psymtab' field is active.
+     Otherwise the 'quick' field is active.  */
+  union
+  {
+    /* The partial symbol table associated with this compilation unit,
+       or NULL for partial units (which do not have an associated
+       symtab).  */
+    struct partial_symtab *psymtab;
+
+    /* Data needed by the "quick" functions.  */
+    struct dwarf2_per_cu_quick_data *quick;
+  } v;
 };
 
 /* Entry in the signatured_types hash table.  */
@@ -1132,6 +1206,53 @@ static void dwarf2_clear_marks (struct dwarf2_per_cu_data *);
 
 static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu);
 
+static void dwarf2_release_queue (void *dummy);
+
+static void queue_comp_unit (struct dwarf2_per_cu_data *per_cu,
+			     struct objfile *objfile);
+
+static void process_queue (struct objfile *objfile);
+
+static void find_file_and_directory (struct die_info *die,
+				     struct dwarf2_cu *cu,
+				     char **name, char **comp_dir);
+
+static char *file_full_name (int file, struct line_header *lh,
+			     const char *comp_dir);
+
+static gdb_byte *partial_read_comp_unit_head (struct comp_unit_head *header,
+					      gdb_byte *info_ptr,
+					      gdb_byte *buffer,
+					      unsigned int buffer_size,
+					      bfd *abfd);
+
+static void init_cu_die_reader (struct die_reader_specs *reader,
+				struct dwarf2_cu *cu);
+
+#if WORDS_BIGENDIAN
+
+/* Convert VALUE between big- and little-endian.  */
+static offset_type
+byte_swap (offset_type value)
+{
+  offset_type result;
+
+  result = (value & 0xff) << 24;
+  result |= (value & 0xff00) << 8;
+  result |= (value & 0xff0000) >> 8;
+  result |= (value & 0xff000000) >> 24;
+  return result;
+}
+
+#define MAYBE_SWAP(V)  byte_swap (V)
+
+#else
+#define MAYBE_SWAP(V) (V)
+#endif /* WORDS_BIGENDIAN */
+
+/* The suffix for an index file.  */
+#define INDEX_SUFFIX ".gdb-index"
+
 /* Try to locate the sections we need for DWARF 2 debugging
    information and return true if we have enough to do something.  */
 
@@ -1230,6 +1351,11 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr)
       dwarf2_per_objfile->types.asection = sectp;
       dwarf2_per_objfile->types.size = bfd_get_section_size (sectp);
     }
+  else if (section_is_p (sectp->name, GDB_INDEX_SECTION))
+    {
+      dwarf2_per_objfile->gdb_index.asection = sectp;
+      dwarf2_per_objfile->gdb_index.size = bfd_get_section_size (sectp);
+    }
 
   if ((bfd_get_section_flags (abfd, sectp) & SEC_LOAD)
       && bfd_section_vma (abfd, sectp) == 0)
@@ -1434,6 +1560,863 @@ dwarf2_get_section_info (struct objfile *objfile, const char *section_name,
   *sizep = info->size;
 }
 
+
+
+/* Read in the symbols for PER_CU.  OBJFILE is the objfile from which
+   this CU came.  */
+static void
+dw2_do_instantiate_symtab (struct objfile *objfile,
+			   struct dwarf2_per_cu_data *per_cu)
+{
+  struct cleanup *back_to;
+
+  back_to = make_cleanup (dwarf2_release_queue, NULL);
+
+  queue_comp_unit (per_cu, objfile);
+
+  if (per_cu->from_debug_types)
+    read_signatured_type_at_offset (objfile, per_cu->offset);
+  else
+    load_full_comp_unit (per_cu, objfile);
+
+  process_queue (objfile);
+
+  /* Age the cache, releasing compilation units that have not
+     been used recently.  */
+  age_cached_comp_units ();
+
+  do_cleanups (back_to);
+}
+
+/* Ensure that the symbols for PER_CU have been read in.  OBJFILE is
+   the objfile from which this CU came.  Returns the resulting symbol
+   table.  */
+static struct symtab *
+dw2_instantiate_symtab (struct objfile *objfile,
+			struct dwarf2_per_cu_data *per_cu)
+{
+  if (!per_cu->v.quick->symtab)
+    {
+      struct cleanup *back_to = make_cleanup (free_cached_comp_units, NULL);
+      increment_reading_symtab ();
+      dw2_do_instantiate_symtab (objfile, per_cu);
+      do_cleanups (back_to);
+    }
+  return per_cu->v.quick->symtab;
+}
+
+/* A helper function that knows how to read a 64-bit value in a way
+   that doesn't make gdb die.  Returns 1 if the conversion went ok, 0
+   otherwise.  */
+static int
+extract_cu_value (const char *bytes, ULONGEST *result)
+{
+  if (sizeof (ULONGEST) < 8)
+    {
+      int i;
+
+      /* Ignore the upper 4 bytes if they are all zero.  */
+      for (i = 0; i < 4; ++i)
+	if (bytes[i + 4] != 0)
+	  return 0;
+
+      *result = extract_unsigned_integer (bytes, 4, BFD_ENDIAN_LITTLE);
+    }
+  else
+    *result = extract_unsigned_integer (bytes, 8, BFD_ENDIAN_LITTLE);
+  return 1;
+}
+
+/* Read the CU list from the mapped index, and use it to create all
+   the CU objects for this objfile.  Return 0 if something went wrong,
+   1 if everything went ok.  */
+static int
+create_cus_from_index (struct objfile *objfile, struct mapped_index *index,
+		       const gdb_byte *cu_list, offset_type cu_list_elements)
+{
+  offset_type i;
+  const char *entry;
+
+  dwarf2_per_objfile->n_comp_units = cu_list_elements / 2;
+  dwarf2_per_objfile->all_comp_units
+    = obstack_alloc (&objfile->objfile_obstack,
+		     dwarf2_per_objfile->n_comp_units
+		     * sizeof (struct dwarf2_per_cu_data *));
+
+  for (i = 0; i < cu_list_elements; i += 2)
+    {
+      struct dwarf2_per_cu_data *the_cu;
+      ULONGEST offset, length;
+
+      if (!extract_cu_value (cu_list, &offset)
+	  || !extract_cu_value (cu_list + 8, &length))
+	return 0;
+      cu_list += 2 * 8;
+
+      the_cu = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+			       struct dwarf2_per_cu_data);
+      the_cu->offset = offset;
+      the_cu->length = length;
+      the_cu->objfile = objfile;
+      the_cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+					struct dwarf2_per_cu_quick_data);
+      dwarf2_per_objfile->all_comp_units[i / 2] = the_cu;
+    }
+
+  return 1;
+}
+
+/* Read the address map data from the mapped index, and use it to
+   populate the objfile's psymtabs_addrmap.  */
+static void
+create_addrmap_from_index (struct objfile *objfile, struct mapped_index *index)
+{
+  const gdb_byte *iter, *end;
+  struct obstack temp_obstack;
+  struct addrmap *mutable_map;
+  struct cleanup *cleanup;
+  CORE_ADDR baseaddr;
+
+  obstack_init (&temp_obstack);
+  cleanup = make_cleanup_obstack_free (&temp_obstack);
+  mutable_map = addrmap_create_mutable (&temp_obstack);
+
+  iter = index->address_table;
+  end = iter + index->address_table_size;
+
+  baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+  while (iter < end)
+    {
+      ULONGEST hi, lo, cu_index;
+      lo = extract_unsigned_integer (iter, 8, BFD_ENDIAN_LITTLE);
+      iter += 8;
+      hi = extract_unsigned_integer (iter, 8, BFD_ENDIAN_LITTLE);
+      iter += 8;
+      cu_index = extract_unsigned_integer (iter, 4, BFD_ENDIAN_LITTLE);
+      iter += 4;
+      
+      addrmap_set_empty (mutable_map, lo + baseaddr, hi + baseaddr - 1,
+			 dwarf2_per_objfile->all_comp_units[cu_index]);
+    }
+
+  objfile->psymtabs_addrmap = addrmap_create_fixed (mutable_map,
+						    &objfile->objfile_obstack);
+  do_cleanups (cleanup);
+}
+
+/* The hash function for strings in the mapped index.  This is the
+   same as the hashtab.c hash function, but we keep a separate copy to
+   maintain control over the implementation.  This is necessary
+   because the hash function is tied to the format of the mapped index
+   file.  */
+static hashval_t
+mapped_index_string_hash (const void *p)
+{
+  const unsigned char *str = (const unsigned char *) p;
+  hashval_t r = 0;
+  unsigned char c;
+
+  while ((c = *str++) != 0)
+    r = r * 67 + c - 113;
+
+  return r;
+}
+
+/* Find a slot in the mapped index INDEX for the object named NAME.
+   If NAME is found, set *VEC_OUT to point to the CU vector in the
+   constant pool and return 1.  If NAME cannot be found, return 0.  */
+static int
+find_slot_in_mapped_hash (struct mapped_index *index, const char *name,
+			  offset_type **vec_out)
+{
+  offset_type hash = mapped_index_string_hash (name);
+  offset_type slot, step;
+
+  slot = hash & (index->index_table_slots - 1);
+  step = ((hash * 17) & (index->index_table_slots - 1)) | 1;
+
+  for (;;)
+    {
+      /* Convert a slot number to an offset into the table.  */
+      offset_type i = 2 * slot;
+      const char *str;
+      if (index->index_table[i] == 0 && index->index_table[i + 1] == 0)
+	return 0;
+
+      str = index->constant_pool + MAYBE_SWAP (index->index_table[i]);
+      if (!strcmp (name, str))
+	{
+	  *vec_out = (offset_type *) (index->constant_pool
+				      + MAYBE_SWAP (index->index_table[i + 1]));
+	  return 1;
+	}
+
+      slot = (slot + step) & (index->index_table_slots - 1);
+    }
+}
+
+/* Read the index file.  If everything went ok, initialize the "quick"
+   elements of all the CUs and return 1.  Otherwise, return 0.  */
+static int
+dwarf2_read_index (struct objfile *objfile)
+{
+  struct stat st, obstat;
+  int fd;
+  char *addr;
+  struct mapped_index *map;
+  offset_type val, *metadata;
+  char buf1[8], buf2[8];
+  const gdb_byte *cu_list;
+  offset_type cu_list_elements;
+
+  if (dwarf2_per_objfile->gdb_index.asection == NULL
+      || dwarf2_per_objfile->gdb_index.size == 0)
+    return 0;
+  dwarf2_read_section (objfile, &dwarf2_per_objfile->gdb_index);
+
+  addr = dwarf2_per_objfile->gdb_index.buffer;
+  /* Version check.  */
+  if (MAYBE_SWAP (*(offset_type *) addr) != 1)
+    return 0;
+
+  map = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct mapped_index);
+  map->total_size = st.st_size;
+
+  metadata = (offset_type *) (addr + sizeof (offset_type));
+  cu_list = addr + MAYBE_SWAP (metadata[0]);
+  cu_list_elements = ((MAYBE_SWAP (metadata[1]) - MAYBE_SWAP (metadata[0]))
+		      / 8);
+  map->address_table = addr + MAYBE_SWAP (metadata[1]);
+  map->address_table_size = (MAYBE_SWAP (metadata[2])
+			     - MAYBE_SWAP (metadata[1]));
+  map->index_table = (offset_type *) (addr + MAYBE_SWAP (metadata[2]));
+  map->index_table_slots = ((MAYBE_SWAP (metadata[3])
+			     - MAYBE_SWAP (metadata[2]))
+			    / (2 * sizeof (offset_type)));
+  map->constant_pool = addr + MAYBE_SWAP (metadata[3]);
+
+  if (!create_cus_from_index (objfile, map, cu_list, cu_list_elements))
+    return 0;
+
+  create_addrmap_from_index (objfile, map);
+
+  dwarf2_per_objfile->index_table = map;
+  dwarf2_per_objfile->using_index = 1;
+
+  return 1;
+}
+
+/* A helper for the "quick" functions which sets the global
+   dwarf2_per_objfile according to OBJFILE.  */
+static void
+dw2_setup (struct objfile *objfile)
+{
+  dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key);
+  gdb_assert (dwarf2_per_objfile);
+}
+
+/* A helper for the "quick" functions which attempts to read the line
+   table for THIS_CU.  */
+static void
+dw2_require_line_header (struct objfile *objfile,
+			 struct dwarf2_per_cu_data *this_cu)
+{
+  bfd *abfd = objfile->obfd;
+  struct line_header *lh = NULL;
+  struct attribute *attr;
+  struct cleanup *cleanups;
+  struct die_info *comp_unit_die;
+  gdb_byte *beg_of_comp_unit, *info_ptr, *buffer;
+  int has_children, i;
+  struct dwarf2_cu cu;
+  unsigned int bytes_read, buffer_size;
+  struct die_reader_specs reader_specs;
+  char *name, *comp_dir;
+
+  if (this_cu->v.quick->read_lines)
+    return;
+  this_cu->v.quick->read_lines = 1;
+
+  memset (&cu, 0, sizeof (cu));
+  cu.objfile = objfile;
+  obstack_init (&cu.comp_unit_obstack);
+
+  cleanups = make_cleanup (free_stack_comp_unit, &cu);
+
+  dwarf2_read_section (objfile, &dwarf2_per_objfile->info);
+  buffer_size = dwarf2_per_objfile->info.size;
+  buffer = dwarf2_per_objfile->info.buffer;
+  info_ptr = buffer + this_cu->offset;
+  beg_of_comp_unit = info_ptr;
+
+  info_ptr = partial_read_comp_unit_head (&cu.header, info_ptr,
+					  buffer, buffer_size,
+					  abfd);
+
+  /* Complete the cu_header.  */
+  cu.header.offset = beg_of_comp_unit - buffer;
+  cu.header.first_die_offset = info_ptr - beg_of_comp_unit;
+
+  this_cu->cu = &cu;
+  cu.per_cu = this_cu;
+
+  dwarf2_read_abbrevs (abfd, &cu);
+  make_cleanup (dwarf2_free_abbrev_table, &cu);
+
+  if (this_cu->from_debug_types)
+    info_ptr += 8 /*signature*/ + cu.header.offset_size;
+  init_cu_die_reader (&reader_specs, &cu);
+  info_ptr = read_full_die (&reader_specs, &comp_unit_die, info_ptr,
+			    &has_children);
+
+  attr = dwarf2_attr (comp_unit_die, DW_AT_stmt_list, &cu);
+  if (attr)
+    {
+      unsigned int line_offset = DW_UNSND (attr);
+      lh = dwarf_decode_line_header (line_offset, abfd, &cu);
+    }
+  if (lh == NULL)
+    {
+      do_cleanups (cleanups);
+      return;
+    }
+
+  find_file_and_directory (comp_unit_die, &cu, &name, &comp_dir);
+
+  this_cu->v.quick->lines = lh;
+
+  this_cu->v.quick->file_names
+    = obstack_alloc (&objfile->objfile_obstack,
+		     lh->num_file_names * sizeof (char *));
+  for (i = 0; i < lh->num_file_names; ++i)
+    this_cu->v.quick->file_names[i] = file_full_name (i + 1, lh, comp_dir);
+
+  do_cleanups (cleanups);
+}
+
+/* A helper for the "quick" functions which computes and caches the
+   real path for a given file name from the line table.
+   dw2_require_line_header must have been called before this is
+   invoked.  */
+static const char *
+dw2_require_full_path (struct objfile *objfile,
+		       struct dwarf2_per_cu_data *cu,
+		       int index)
+{
+  if (!cu->v.quick->full_names)
+    cu->v.quick->full_names
+      = OBSTACK_CALLOC (&objfile->objfile_obstack,
+			cu->v.quick->lines->num_file_names,
+			sizeof (char *));
+
+  if (!cu->v.quick->full_names[index])
+    cu->v.quick->full_names[index]
+      = gdb_realpath (cu->v.quick->file_names[index]);
+
+  return cu->v.quick->full_names[index];
+}
+
+static struct symtab *
+dw2_find_last_source_symtab (struct objfile *objfile)
+{
+  int index;
+  dw2_setup (objfile);
+  index = dwarf2_per_objfile->n_comp_units - 1;
+  return dw2_instantiate_symtab (objfile,
+				 dwarf2_per_objfile->all_comp_units[index]);
+}
+
+static void
+dw2_forget_cached_source_info (struct objfile *objfile)
+{
+  int i;
+
+  dw2_setup (objfile);
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+      if (cu->v.quick->full_names)
+	{
+	  int j;
+
+	  for (j = 0; j < cu->v.quick->lines->num_file_names; ++j)
+	    xfree ((void *) cu->v.quick->full_names[j]);
+	}
+    }
+}
+
+static int
+dw2_lookup_symtab (struct objfile *objfile, const char *name,
+		   const char *full_path, const char *real_path,
+		   struct symtab **result)
+{
+  int i;
+  int check_basename = lbasename (name) == name;
+  struct dwarf2_per_cu_data *base_cu = NULL;
+
+  dw2_setup (objfile);
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      int j;
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+      if (cu->v.quick->symtab)
+	continue;
+
+      dw2_require_line_header (objfile, cu);
+      if (!cu->v.quick->lines)
+	continue;
+
+      for (j = 0; j < cu->v.quick->lines->num_file_names; ++j)
+	{
+	  const char *this_name = cu->v.quick->file_names[j];
+
+	  if (FILENAME_CMP (name, this_name) == 0)
+	    {
+	      *result = dw2_instantiate_symtab (objfile, cu);
+	      return 1;
+	    }
+
+	  if (check_basename && ! base_cu
+	      && FILENAME_CMP (lbasename (this_name), name) == 0)
+	    base_cu = cu;
+
+	  if (full_path != NULL)
+	    {
+	      const char *this_full_name = dw2_require_full_path (objfile,
+								  cu, j);
+
+	      if (this_full_name
+		  && FILENAME_CMP (full_path, this_full_name) == 0)
+		{
+		  *result = dw2_instantiate_symtab (objfile, cu);
+		  return 1;
+		}
+	    }
+
+	  if (real_path != NULL)
+	    {
+	      const char *this_full_name = dw2_require_full_path (objfile,
+								  cu, j);
+
+	      if (this_full_name != NULL)
+		{
+		  char *rp = gdb_realpath (this_full_name);
+		  if (rp != NULL && FILENAME_CMP (real_path, rp) == 0)
+		    {
+		      xfree (rp);
+		      *result = dw2_instantiate_symtab (objfile, cu);
+		      return 1;
+		    }
+		  xfree (rp);
+		}
+	    }
+	}
+    }
+
+  if (base_cu)
+    {
+      *result = dw2_instantiate_symtab (objfile, base_cu);
+      return 1;
+    }
+
+  return 0;
+}
+
+static struct symtab *
+dw2_lookup_symbol (struct objfile *objfile, int block_index,
+		   const char *name, domain_enum domain)
+{
+  /* We do all the work in the pre_expand_symtabs_matching hook
+     instead.  */
+  return NULL;
+}
+
+/* A helper function that expands all symtabs that hold an object
+   named NAME.  */
+static void
+dw2_do_expand_symtabs_matching (struct objfile *objfile, const char *name)
+{
+  dw2_setup (objfile);
+
+  if (dwarf2_per_objfile->index_table)
+    {
+      offset_type *vec;
+
+      if (find_slot_in_mapped_hash (dwarf2_per_objfile->index_table,
+				    name, &vec))
+	{
+	  offset_type i, len = MAYBE_SWAP (*vec);
+	  for (i = 0; i < len; ++i)
+	    {
+	      offset_type cu_index = MAYBE_SWAP (vec[i + 1]);
+	      struct dwarf2_per_cu_data *cu;
+	      cu = dwarf2_per_objfile->all_comp_units[cu_index];
+	      dw2_instantiate_symtab (objfile, cu);
+	    }
+	}
+    }
+}
+
+static void
+dw2_pre_expand_symtabs_matching (struct objfile *objfile,
+				 int kind, const char *name,
+				 domain_enum domain)
+{
+  dw2_do_expand_symtabs_matching (objfile, name);
+}
+
+static void
+dw2_print_stats (struct objfile *objfile)
+{
+  int i, count;
+
+  dw2_setup (objfile);
+  count = 0;
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+      if (!cu->v.quick->symtab)
+	++count;
+    }
+  printf_filtered (_("  Number of unread CUs: %d\n"), count);
+}
+
+static void
+dw2_dump (struct objfile *objfile)
+{
+  /* Nothing worth printing.  */
+}
+
+static void
+dw2_relocate (struct objfile *objfile, struct section_offsets *new_offsets,
+	      struct section_offsets *delta)
+{
+  /* There's nothing to relocate here.  */
+}
+
+static void
+dw2_expand_symtabs_for_function (struct objfile *objfile,
+				 const char *func_name)
+{
+  dw2_do_expand_symtabs_matching (objfile, func_name);
+}
+
+static void
+dw2_expand_all_symtabs (struct objfile *objfile)
+{
+  int i;
+
+  dw2_setup (objfile);
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+      dw2_instantiate_symtab (objfile, cu);
+    }
+}
+
+static void
+dw2_expand_symtabs_with_filename (struct objfile *objfile,
+				  const char *filename)
+{
+  int i;
+
+  dw2_setup (objfile);
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      int j;
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+      if (cu->v.quick->symtab)
+	continue;
+
+      dw2_require_line_header (objfile, cu);
+      if (!cu->v.quick->lines)
+	continue;
+
+      for (j = 0; j < cu->v.quick->lines->num_file_names; ++j)
+	{
+	  const char *this_name = cu->v.quick->file_names[j];
+	  if (strcmp (this_name, filename) == 0)
+	    {
+	      dw2_instantiate_symtab (objfile, cu);
+	      break;
+	    }
+	}
+    }
+}
+
+static char *
+dw2_find_symbol_file (struct objfile *objfile, const char *name)
+{
+  struct dwarf2_per_cu_data *cu;
+  offset_type *vec;
+
+  dw2_setup (objfile);
+
+  if (!dwarf2_per_objfile->index_table)
+    return NULL;
+
+  if (!find_slot_in_mapped_hash (dwarf2_per_objfile->index_table,
+				 name, &vec))
+    return NULL;
+
+  /* Note that this just looks at the very first one named NAME -- but
+     actually we are looking for a function.  find_main_filename
+     should be rewritten so that it doesn't require a custom hook.  It
+     could just use the ordinary symbol tables.  */
+  /* vec[0] is the length, which must always be >0.  */
+  cu = dwarf2_per_objfile->all_comp_units[MAYBE_SWAP (vec[1])];
+
+  dw2_require_line_header (objfile, cu);
+  if (!cu->v.quick->lines)
+    return NULL;
+
+  return (char *) cu->v.quick->file_names[cu->v.quick->lines->num_file_names
+					  - 1];
+}
+
+static void
+dw2_map_ada_symtabs (struct objfile *objfile,
+		     int (*wild_match) (const char *, int, const char *),
+		     int (*is_name_suffix) (const char *),
+		     void (*callback) (struct objfile *,
+				       struct symtab *, void *),
+		     const char *name, int global,
+		     domain_enum namespace, int wild,
+		     void *data)
+{
+  /* For now, we don't support Ada, so this function can't be
+     reached.  */
+  internal_error (__FILE__, __LINE__,
+		  _("map_ada_symtabs called via index method"));
+}
+
+static void
+dw2_expand_symtabs_matching (struct objfile *objfile,
+			     int (*file_matcher) (const char *, void *),
+			     int (*name_matcher) (const char *, void *),
+			     domain_enum kind,
+			     void *data)
+{
+  int i;
+  offset_type iter;
+
+  dw2_setup (objfile);
+  if (!dwarf2_per_objfile->index_table)
+    return;
+
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      int j;
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+      cu->v.quick->mark = 0;
+      if (cu->v.quick->symtab)
+	continue;
+
+      dw2_require_line_header (objfile, cu);
+      if (!cu->v.quick->lines)
+	continue;
+
+      for (j = 0; j < cu->v.quick->lines->num_file_names; ++j)
+	{
+	  if (file_matcher (cu->v.quick->file_names[j], data))
+	    {
+	      cu->v.quick->mark = 1;
+	      break;
+	    }
+	}
+    }
+
+  for (iter = 0;
+       iter < dwarf2_per_objfile->index_table->index_table_slots;
+       ++iter)
+    {
+      offset_type idx = 2 * iter;
+      const char *name;
+      offset_type *vec, vec_len, vec_idx;
+
+      if (dwarf2_per_objfile->index_table->index_table[idx] == 0
+	  && dwarf2_per_objfile->index_table->index_table[idx + 1] == 0)
+	continue;
+
+      name = (dwarf2_per_objfile->index_table->constant_pool
+	      + dwarf2_per_objfile->index_table->index_table[idx]);
+
+      if (! (*name_matcher) (name, data))
+	continue;
+
+      /* The name was matched, now expand corresponding CUs that were
+	 marked.  */
+      vec = (offset_type *) (dwarf2_per_objfile->index_table->constant_pool
+			     + dwarf2_per_objfile->index_table->index_table[idx + 1]);
+      vec_len = MAYBE_SWAP (vec[0]);
+      for (vec_idx = 0; vec_idx < vec_len; ++vec_idx)
+	{
+	  struct dwarf2_per_cu_data *cu
+	    = dwarf2_per_objfile->all_comp_units[MAYBE_SWAP (vec[vec_idx + 1])];
+	  if (cu->v.quick->mark)
+	    dw2_instantiate_symtab (objfile, cu);
+	}
+    }
+}
+
+static struct symtab *
+dw2_find_pc_sect_symtab (struct objfile *objfile,
+			 struct minimal_symbol *msymbol,
+			 CORE_ADDR pc,
+			 struct obj_section *section,
+			 int warn_if_readin)
+{
+  struct dwarf2_per_cu_data *data;
+
+  dw2_setup (objfile);
+
+  if (!objfile->psymtabs_addrmap)
+    return NULL;
+
+  data = addrmap_find (objfile->psymtabs_addrmap, pc);
+  if (!data)
+    return NULL;
+
+  if (warn_if_readin && data->v.quick->symtab)
+    warning (_("(Internal error: pc %s in read in CU, but not in symtab.)\n"),
+	     paddress (get_objfile_arch (objfile), pc));
+
+  return dw2_instantiate_symtab (objfile, data);
+}
+
+static void
+dw2_map_symbol_names (struct objfile *objfile,
+		      void (*fun) (const char *, void *),
+		      void *data)
+{
+  offset_type iter;
+  dw2_setup (objfile);
+
+  if (!dwarf2_per_objfile->index_table)
+    return;
+
+  for (iter = 0;
+       iter < dwarf2_per_objfile->index_table->index_table_slots;
+       ++iter)
+    {
+      offset_type idx = 2 * iter;
+      const char *name;
+      offset_type *vec, vec_len, vec_idx;
+
+      if (dwarf2_per_objfile->index_table->index_table[idx] == 0
+	  && dwarf2_per_objfile->index_table->index_table[idx + 1] == 0)
+	continue;
+
+      name = (dwarf2_per_objfile->index_table->constant_pool
+	      + dwarf2_per_objfile->index_table->index_table[idx]);
+
+      (*fun) (name, data);
+    }
+}
+
+static void
+dw2_map_symbol_filenames (struct objfile *objfile,
+			  void (*fun) (const char *, const char *, void *),
+			  void *data)
+{
+  int i;
+
+  dw2_setup (objfile);
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      int j;
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+      if (cu->v.quick->symtab)
+	continue;
+
+      dw2_require_line_header (objfile, cu);
+      if (!cu->v.quick->lines)
+	continue;
+
+      for (j = 0; j < cu->v.quick->lines->num_file_names; ++j)
+	{
+	  const char *this_full_name = dw2_require_full_path (objfile, cu, j);
+	  (*fun) (cu->v.quick->file_names[j], this_full_name, data);
+	}
+    }
+}
+
+static int
+dw2_has_symbols (struct objfile *objfile)
+{
+  return 1;
+}
+
+const struct quick_symbol_functions dwarf2_gdb_index_functions =
+{
+  dw2_has_symbols,
+  dw2_find_last_source_symtab,
+  dw2_forget_cached_source_info,
+  dw2_lookup_symtab,
+  dw2_lookup_symbol,
+  dw2_pre_expand_symtabs_matching,
+  dw2_print_stats,
+  dw2_dump,
+  dw2_relocate,
+  dw2_expand_symtabs_for_function,
+  dw2_expand_all_symtabs,
+  dw2_expand_symtabs_with_filename,
+  dw2_find_symbol_file,
+  dw2_map_ada_symtabs,
+  dw2_expand_symtabs_matching,
+  dw2_find_pc_sect_symtab,
+  dw2_map_symbol_names,
+  dw2_map_symbol_filenames
+};
+
+/* Initialize for reading DWARF for this objfile.  Return 0 if this
+   file will use psymtabs, or 1 if using the GNU index.  */
+
+int
+dwarf2_initialize_objfile (struct objfile *objfile)
+{
+  /* If we're about to read full symbols, don't bother with the
+     indices.  In this case we also don't care if some other debug
+     format is making psymtabs, because they are all about to be
+     expanded anyway.  */
+  if ((objfile->flags & OBJF_READNOW))
+    {
+      int i;
+
+      dwarf2_per_objfile->using_index = 1;
+      create_all_comp_units (objfile);
+
+      for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+	{
+	  struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+	  cu->v.quick = OBSTACK_ZALLOC (&objfile->objfile_obstack,
+					struct dwarf2_per_cu_quick_data);
+	}
+
+      /* Return 1 so that gdb sees the "quick" functions.  However,
+	 these functions will be no-ops because we will have expanded
+	 all symtabs.  */
+      return 1;
+    }
+
+  if (dwarf2_read_index (objfile))
+    return 1;
+
+  dwarf2_build_psymtabs (objfile);
+  return 0;
+}
+
+
+
 /* Build a partial symbol table.  */
 
 void
@@ -1897,7 +2880,7 @@ process_psymtab_comp_unit (struct objfile *objfile,
   /* Store the function that reads in the rest of the symbol table */
   pst->read_symtab = dwarf2_psymtab_to_symtab;
 
-  this_cu->psymtab = pst;
+  this_cu->v.psymtab = pst;
 
   dwarf2_find_base_address (comp_unit_die, &cu);
 
@@ -2182,6 +3165,7 @@ create_all_comp_units (struct objfile *objfile)
       memset (this_cu, 0, sizeof (*this_cu));
       this_cu->offset = offset;
       this_cu->length = length + initial_length_size;
+      this_cu->objfile = objfile;
 
       if (n_comp_units == n_allocated)
 	{
@@ -2613,7 +3597,7 @@ add_partial_subprogram (struct partial_die_info *pdi,
 	      addrmap_set_empty (objfile->psymtabs_addrmap,
 				 pdi->lowpc + baseaddr,
 				 pdi->highpc - 1 + baseaddr,
-				 cu->per_cu->psymtab);
+				 cu->per_cu->v.psymtab);
 	    }
           if (!pdi->is_declaration)
 	    /* Ignore subprogram DIEs that do not have a name, they are
@@ -2885,7 +3869,6 @@ locate_pdi_sibling (struct partial_die_info *orig_pdi,
 static void
 dwarf2_psymtab_to_symtab (struct partial_symtab *pst)
 {
-  /* FIXME: This is barely more than a stub.  */
   if (pst != NULL)
     {
       if (pst->readin)
@@ -2958,7 +3941,9 @@ process_queue (struct objfile *objfile)
      may load a new CU, adding it to the end of the queue.  */
   for (item = dwarf2_queue; item != NULL; dwarf2_queue = item = next_item)
     {
-      if (item->per_cu->psymtab && !item->per_cu->psymtab->readin)
+      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->per_cu->queued = 0;
@@ -3035,22 +4020,7 @@ psymtab_to_symtab_1 (struct partial_symtab *pst)
       return;
     }
 
-  back_to = make_cleanup (dwarf2_release_queue, NULL);
-
-  queue_comp_unit (per_cu, pst->objfile);
-
-  if (per_cu->from_debug_types)
-    read_signatured_type_at_offset (pst->objfile, per_cu->offset);
-  else
-    load_full_comp_unit (per_cu, pst->objfile);
-
-  process_queue (pst->objfile);
-
-  /* Age the cache, releasing compilation units that have not
-     been used recently.  */
-  age_cached_comp_units ();
-
-  do_cleanups (back_to);
+  dw2_do_instantiate_symtab (pst->objfile, per_cu);
 }
 
 /* Load the DIEs associated with PER_CU into memory.  */
@@ -3130,9 +4100,8 @@ load_full_comp_unit (struct dwarf2_per_cu_data *per_cu, struct objfile *objfile)
 static void
 process_full_comp_unit (struct dwarf2_per_cu_data *per_cu)
 {
-  struct partial_symtab *pst = per_cu->psymtab;
   struct dwarf2_cu *cu = per_cu->cu;
-  struct objfile *objfile = pst->objfile;
+  struct objfile *objfile = per_cu->objfile;
   CORE_ADDR lowpc, highpc;
   struct symtab *symtab;
   struct cleanup *back_to;
@@ -3165,8 +4134,15 @@ process_full_comp_unit (struct dwarf2_per_cu_data *per_cu)
     {
       symtab->language = cu->language;
     }
-  pst->symtab = symtab;
-  pst->readin = 1;
+
+  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);
 }
@@ -3559,6 +4535,46 @@ free_cu_line_header (void *arg)
 }
 
 static void
+find_file_and_directory (struct die_info *die, struct dwarf2_cu *cu,
+			 char **name, char **comp_dir)
+{
+  struct attribute *attr;
+
+  *name = NULL;
+  *comp_dir = NULL;
+
+  /* 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_comp_dir, cu);
+  if (attr)
+    *comp_dir = DW_STRING (attr);
+  else if (*name != NULL && IS_ABSOLUTE_PATH (*name))
+    {
+      *comp_dir = ldirname (*name);
+      if (*comp_dir != NULL)
+	make_cleanup (xfree, *comp_dir);
+    }
+  if (*comp_dir != NULL)
+    {
+      /* Irix 6.2 native cc prepends <machine>.: to the compilation
+	 directory, get rid of it.  */
+      char *cp = strchr (*comp_dir, ':');
+
+      if (cp && cp != *comp_dir && cp[-1] == '.' && cp[1] == '/')
+	*comp_dir = cp + 1;
+    }
+
+  if (*name == NULL)
+    *name = "<unknown>";
+}
+
+static void
 read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
 {
   struct objfile *objfile = cu->objfile;
@@ -3584,35 +4600,7 @@ read_file_scope (struct die_info *die, struct dwarf2_cu *cu)
   lowpc += baseaddr;
   highpc += baseaddr;
 
-  /* 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_comp_dir, cu);
-  if (attr)
-    comp_dir = DW_STRING (attr);
-  else if (name != NULL && IS_ABSOLUTE_PATH (name))
-    {
-      comp_dir = ldirname (name);
-      if (comp_dir != NULL)
-	make_cleanup (xfree, comp_dir);
-    }
-  if (comp_dir != NULL)
-    {
-      /* Irix 6.2 native cc prepends <machine>.: to the compilation
-	 directory, get rid of it.  */
-      char *cp = strchr (comp_dir, ':');
-
-      if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/')
-	comp_dir = cp + 1;
-    }
-
-  if (name == NULL)
-    name = "<unknown>";
+  find_file_and_directory (die, cu, &name, &comp_dir);
 
   attr = dwarf2_attr (die, DW_AT_language, cu);
   if (attr)
@@ -12034,7 +13022,7 @@ dwarf2_symbol_mark_computed (struct attribute *attr, struct symbol *sym,
 struct objfile *
 dwarf2_per_cu_objfile (struct dwarf2_per_cu_data *per_cu)
 {
-  struct objfile *objfile = per_cu->psymtab->objfile;
+  struct objfile *objfile = per_cu->objfile;
 
   /* Return the master objfile, so that we can report and look up the
      correct file containing this variable.  */
@@ -12054,7 +13042,7 @@ dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *per_cu)
   else
     {
       /* If the CU is not currently read in, we re-read its header.  */
-      struct objfile *objfile = per_cu->psymtab->objfile;
+      struct objfile *objfile = per_cu->objfile;
       struct dwarf2_per_objfile *per_objfile
 	= objfile_data (objfile, dwarf2_objfile_data_key);
       gdb_byte *info_ptr = per_objfile->info.buffer + per_cu->offset;
@@ -12076,7 +13064,7 @@ dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *per_cu)
   else
     {
       /* If the CU is not currently read in, we re-read its header.  */
-      struct objfile *objfile = per_cu->psymtab->objfile;
+      struct objfile *objfile = per_cu->objfile;
       struct dwarf2_per_objfile *per_objfile
 	= objfile_data (objfile, dwarf2_objfile_data_key);
       gdb_byte *info_ptr = per_objfile->info.buffer + per_cu->offset;
@@ -12305,6 +13293,30 @@ dwarf2_free_objfile (struct objfile *objfile)
   /* Cached DIE trees use xmalloc and the comp_unit_obstack.  */
   free_cached_comp_units (NULL);
 
+  if (dwarf2_per_objfile->using_index)
+    {
+      int i;
+
+      for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+	{
+	  int j;
+	  struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+
+	  if (!cu->v.quick->lines)
+	    continue;
+
+	  for (j = 0; j < cu->v.quick->lines->num_file_names; ++j)
+	    {
+	      if (cu->v.quick->file_names)
+		xfree ((void *) cu->v.quick->file_names[j]);
+	      if (cu->v.quick->full_names)
+		xfree ((void *) cu->v.quick->full_names[j]);
+	    }
+
+	  free_line_header (cu->v.quick->lines);
+	}
+    }
+
   /* Everything else should be on the objfile obstack.  */
 }
 
@@ -12559,8 +13571,567 @@ dwarf2_per_objfile_free (struct objfile *objfile, void *d)
   munmap_section_buffer (&data->loc);
   munmap_section_buffer (&data->frame);
   munmap_section_buffer (&data->eh_frame);
+  munmap_section_buffer (&data->gdb_index);
+}
+
+
+
+/* The contents of the hash table we create when building the string
+   table.  */
+struct strtab_entry
+{
+  offset_type offset;
+  const char *str;
+};
+
+/* Hash function for a strtab_entry.  */
+static hashval_t
+hash_strtab_entry (const void *e)
+{
+  const struct strtab_entry *entry = e;
+  return mapped_index_string_hash (entry->str);
+}
+
+/* Equality function for a strtab_entry.  */
+static int
+eq_strtab_entry (const void *a, const void *b)
+{
+  const struct strtab_entry *ea = a;
+  const struct strtab_entry *eb = b;
+  return !strcmp (ea->str, eb->str);
+}
+
+/* Create a strtab_entry hash table.  */
+static htab_t
+create_strtab (void)
+{
+  return htab_create_alloc (100, hash_strtab_entry, eq_strtab_entry,
+			    xfree, xcalloc, xfree);
+}
+
+/* Add a string to the constant pool.  Return the string's offset in
+   host order.  */
+static offset_type
+add_string (htab_t table, struct obstack *cpool, const char *str)
+{
+  void **slot;
+  struct strtab_entry entry;
+  struct strtab_entry *result;
+
+  entry.str = str;
+  slot = htab_find_slot (table, &entry, INSERT);
+  if (*slot)
+    result = *slot;
+  else
+    {
+      result = XNEW (struct strtab_entry);
+      result->offset = obstack_object_size (cpool);
+      result->str = str;
+      obstack_grow_str0 (cpool, str);
+      *slot = result;
+    }
+  return result->offset;
+}
+
+/* An entry in the symbol table.  */
+struct symtab_index_entry
+{
+  /* The name of the symbol.  */
+  const char *name;
+  /* The offset of the name in the constant pool.  */
+  offset_type index_offset;
+  /* A sorted vector of the indices of all the CUs that hold an object
+     of this name.  */
+  VEC (offset_type) *cu_indices;
+};
+
+/* The symbol table.  This is a power-of-2-sized hash table.  */
+struct mapped_symtab
+{
+  offset_type n_elements;
+  offset_type size;
+  struct symtab_index_entry **data;
+};
+
+/* Hash function for a symtab_index_entry.  */
+static hashval_t
+hash_symtab_entry (const void *e)
+{
+  const struct symtab_index_entry *entry = e;
+  return iterative_hash (VEC_address (offset_type, entry->cu_indices),
+			 sizeof (offset_type) * VEC_length (offset_type,
+							    entry->cu_indices),
+			 0);
+}
+
+/* Equality function for a symtab_index_entry.  */
+static int
+eq_symtab_entry (const void *a, const void *b)
+{
+  const struct symtab_index_entry *ea = a;
+  const struct symtab_index_entry *eb = b;
+  int len = VEC_length (offset_type, ea->cu_indices);
+  if (len != VEC_length (offset_type, eb->cu_indices))
+    return 0;
+  return !memcmp (VEC_address (offset_type, ea->cu_indices),
+		  VEC_address (offset_type, eb->cu_indices),
+		  sizeof (offset_type) * len);
+}
+
+/* Destroy a symtab_index_entry.  */
+static void
+delete_symtab_entry (void *p)
+{
+  struct symtab_index_entry *entry = p;
+  VEC_free (offset_type, entry->cu_indices);
+  xfree (entry);
+}
+
+/* Create a hash table holding symtab_index_entry objects.  */
+static htab_t
+create_index_table (void)
+{
+  return htab_create_alloc (100, hash_symtab_entry, eq_symtab_entry,
+			    delete_symtab_entry, xcalloc, xfree);
+}
+
+/* Create a new mapped symtab object.  */
+static struct mapped_symtab *
+create_mapped_symtab (void)
+{
+  struct mapped_symtab *symtab = XNEW (struct mapped_symtab);
+  symtab->n_elements = 0;
+  symtab->size = 1024;
+  symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
+  return symtab;
+}
+
+/* Destroy a mapped_symtab.  */
+static void
+cleanup_mapped_symtab (void *p)
+{
+  struct mapped_symtab *symtab = p;
+  /* The contents of the array are freed when the other hash table is
+     destroyed.  */
+  xfree (symtab->data);
+  xfree (symtab);
+}
+
+/* Find a slot in SYMTAB for the symbol NAME.  Returns a pointer to
+   the slot.  */
+static struct symtab_index_entry **
+find_slot (struct mapped_symtab *symtab, const char *name)
+{
+  offset_type index, step, hash = mapped_index_string_hash (name);
+
+  index = hash & (symtab->size - 1);
+  step = ((hash * 17) & (symtab->size - 1)) | 1;
+
+  for (;;)
+    {
+      if (!symtab->data[index] || !strcmp (name, symtab->data[index]->name))
+	return &symtab->data[index];
+      index = (index + step) & (symtab->size - 1);
+    }
+}
+
+/* Expand SYMTAB's hash table.  */
+static void
+hash_expand (struct mapped_symtab *symtab)
+{
+  offset_type old_size = symtab->size;
+  offset_type i;
+  struct symtab_index_entry **old_entries = symtab->data;
+
+  symtab->size *= 2;
+  symtab->data = XCNEWVEC (struct symtab_index_entry *, symtab->size);
+
+  for (i = 0; i < old_size; ++i)
+    {
+      if (old_entries[i])
+	{
+	  struct symtab_index_entry **slot = find_slot (symtab,
+							old_entries[i]->name);
+	  *slot = old_entries[i];
+	}
+    }
+
+  xfree (old_entries);
+}
+
+/* Add an entry to SYMTAB.  NAME is the name of the symbol.  CU_INDEX
+   is the index of the CU in which the symbol appears.  */
+static void
+add_index_entry (struct mapped_symtab *symtab, const char *name,
+		 offset_type cu_index)
+{
+  struct symtab_index_entry **slot;
+
+  ++symtab->n_elements;
+  if (4 * symtab->n_elements / 3 >= symtab->size)
+    hash_expand (symtab);
+
+  slot = find_slot (symtab, name);
+  if (!*slot)
+    {
+      *slot = XNEW (struct symtab_index_entry);
+      (*slot)->name = name;
+      (*slot)->cu_indices = NULL;
+    }
+  /* Don't push an index twice.  Due to how we add entries we only
+     have to check the last one.  */ 
+  if (VEC_empty (offset_type, (*slot)->cu_indices)
+      || VEC_length (offset_type, (*slot)->cu_indices) != cu_index)
+    VEC_safe_push (offset_type, (*slot)->cu_indices, cu_index);
+}
+
+/* Add a vector of indices to the constant pool.  */
+static offset_type
+add_indices_to_cpool (htab_t index_table, struct obstack *cpool,
+		      struct symtab_index_entry *entry)
+{
+  void **slot;
+
+  slot = htab_find_slot (index_table, entry, INSERT);
+  if (!*slot)
+    {
+      offset_type len = VEC_length (offset_type, entry->cu_indices);
+      offset_type val = MAYBE_SWAP (len);
+      offset_type iter;
+      int i;
+
+      *slot = entry;
+      entry->index_offset = obstack_object_size (cpool);
+
+      obstack_grow (cpool, &val, sizeof (val));
+      for (i = 0;
+	   VEC_iterate (offset_type, entry->cu_indices, i, iter);
+	   ++i)
+	{
+	  val = MAYBE_SWAP (iter);
+	  obstack_grow (cpool, &val, sizeof (val));
+	}
+    }
+  else
+    {
+      struct symtab_index_entry *old_entry = *slot;
+      entry->index_offset = old_entry->index_offset;
+      entry = old_entry;
+    }
+  return entry->index_offset;
+}
+
+/* Write the mapped hash table SYMTAB to the obstack OUTPUT, with
+   constant pool entries going into the obstack CPOOL.  */
+static void
+write_hash_table (struct mapped_symtab *symtab,
+		  struct obstack *output, struct obstack *cpool)
+{
+  offset_type i;
+  htab_t index_table;
+  htab_t str_table;
+
+  index_table = create_index_table ();
+  str_table = create_strtab ();
+  /* We add all the index vectors to the constant pool first, to
+     ensure alignment is ok.  */
+  for (i = 0; i < symtab->size; ++i)
+    {
+      if (symtab->data[i])
+	add_indices_to_cpool (index_table, cpool, symtab->data[i]);
+    }
+
+  /* Now write out the hash table.  */
+  for (i = 0; i < symtab->size; ++i)
+    {
+      offset_type str_off, vec_off;
+
+      if (symtab->data[i])
+	{
+	  str_off = add_string (str_table, cpool, symtab->data[i]->name);
+	  vec_off = symtab->data[i]->index_offset;
+	}
+      else
+	{
+	  /* While 0 is a valid constant pool index, it is not valid
+	     to have 0 for both offsets.  */
+	  str_off = 0;
+	  vec_off = 0;
+	}
+
+      str_off = MAYBE_SWAP (str_off);
+      vec_off = MAYBE_SWAP (vec_off);
+
+      obstack_grow (output, &str_off, sizeof (str_off));
+      obstack_grow (output, &vec_off, sizeof (vec_off));
+    }
+
+  htab_delete (str_table);
+  htab_delete (index_table);
+}
+
+/* Write an address entry to ADDR_OBSTACK.  The addresses are taken
+   from PST; CU_INDEX is the index of the CU in the vector of all
+   CUs.  */
+static void
+add_address_entry (struct objfile *objfile,
+		   struct obstack *addr_obstack, struct partial_symtab *pst,
+		   unsigned int cu_index)
+{
+  offset_type offset;
+  char addr[8];
+  CORE_ADDR baseaddr;
+
+  baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+  store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, pst->textlow - baseaddr);
+  obstack_grow (addr_obstack, addr, 8);
+  store_unsigned_integer (addr, 8, BFD_ENDIAN_LITTLE, pst->texthigh - baseaddr);
+  obstack_grow (addr_obstack, addr, 8);
+  offset = MAYBE_SWAP (cu_index);
+  obstack_grow (addr_obstack, &offset, sizeof (offset_type));
+}
+
+/* Add a list of partial symbols to SYMTAB.  */
+static void
+write_psymbols (struct mapped_symtab *symtab,
+		struct partial_symbol **psymp,
+		int count,
+		offset_type cu_index)
+{
+  for (; count-- > 0; ++psymp)
+    {
+      if (SYMBOL_LANGUAGE (*psymp) == language_ada)
+	error (_("Ada is not currently supported by the index"));
+      add_index_entry (symtab, SYMBOL_NATURAL_NAME (*psymp), cu_index);
+    }
+}
+
+/* Write the contents of an ("unfinished") obstack to FILE.  Throw an
+   exception if there is an error.  */
+static void
+write_obstack (FILE *file, struct obstack *obstack)
+{
+  if (fwrite (obstack_base (obstack), 1, obstack_object_size (obstack),
+	      file)
+      != obstack_object_size (obstack))
+    error (_("couldn't data write to file"));
+}
+
+/* Unlink a file if the argument is not NULL.  */
+static void
+unlink_if_set (void *p)
+{
+  char **filename = p;
+  if (*filename)
+    unlink (*filename);
 }
 
+/* Create an index file for OBJFILE in the directory DIR.  */
+static void
+write_psymtabs_to_index (struct objfile *objfile, const char *dir)
+{
+  struct cleanup *cleanup;
+  char *filename, *cleanup_filename;
+  struct obstack contents, addr_obstack, constant_pool, symtab_obstack, cu_list;
+  int i;
+  FILE *out_file;
+  struct mapped_symtab *symtab;
+  offset_type val, size_of_contents, total_len;
+  struct stat st;
+  char buf[8];
+
+  if (!objfile->psymtabs)
+    return;
+  if (dwarf2_per_objfile->using_index)
+    error (_("Cannot use an index to create the index"));
+
+  if (stat (objfile->name, &st) < 0)
+    perror_with_name (_("Could not stat"));
+
+  filename = concat (dir, SLASH_STRING, lbasename (objfile->name),
+		     INDEX_SUFFIX, (char *) NULL);
+  cleanup = make_cleanup (xfree, filename);
+
+  out_file = fopen (filename, "wb");
+  if (!out_file)
+    error (_("Can't open `%s' for writing"), filename);
+
+  cleanup_filename = filename;
+  make_cleanup (unlink_if_set, &cleanup_filename);
+
+  symtab = create_mapped_symtab ();
+  make_cleanup (cleanup_mapped_symtab, symtab);
+
+  obstack_init (&addr_obstack);
+  make_cleanup_obstack_free (&addr_obstack);
+
+  obstack_init (&cu_list);
+  make_cleanup_obstack_free (&cu_list);
+
+  for (i = 0; i < dwarf2_per_objfile->n_comp_units; ++i)
+    {
+      struct dwarf2_per_cu_data *cu = dwarf2_per_objfile->all_comp_units[i];
+      struct partial_symtab *psymtab = cu->v.psymtab;
+      gdb_byte val[8];
+
+      write_psymbols (symtab,
+		      objfile->global_psymbols.list + psymtab->globals_offset,
+		      psymtab->n_global_syms, i);
+      write_psymbols (symtab,
+		      objfile->static_psymbols.list + psymtab->statics_offset,
+		      psymtab->n_static_syms, i);
+
+      add_address_entry (objfile, &addr_obstack, psymtab, i);
+
+      store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, cu->offset);
+      obstack_grow (&cu_list, val, 8);
+      store_unsigned_integer (val, 8, BFD_ENDIAN_LITTLE, cu->length);
+      obstack_grow (&cu_list, val, 8);
+    }
+
+  obstack_init (&constant_pool);
+  make_cleanup_obstack_free (&constant_pool);
+  obstack_init (&symtab_obstack);
+  make_cleanup_obstack_free (&symtab_obstack);
+  write_hash_table (symtab, &symtab_obstack, &constant_pool);
+
+  obstack_init (&contents);
+  make_cleanup_obstack_free (&contents);
+  size_of_contents = 5 * sizeof (offset_type);
+  total_len = size_of_contents;
+
+  /* The version number.  */
+  val = MAYBE_SWAP (1);
+  obstack_grow (&contents, &val, sizeof (val));
+
+  /* The offset of the CU list from the start of the file.  */
+  val = MAYBE_SWAP (total_len);
+  obstack_grow (&contents, &val, sizeof (val));
+  total_len += obstack_object_size (&cu_list);
+
+  /* The offset of the address table from the start of the file.  */
+  val = MAYBE_SWAP (total_len);
+  obstack_grow (&contents, &val, sizeof (val));
+  total_len += obstack_object_size (&addr_obstack);
+
+  /* The offset of the symbol table from the start of the file.  */
+  val = MAYBE_SWAP (total_len);
+  obstack_grow (&contents, &val, sizeof (val));
+  total_len += obstack_object_size (&symtab_obstack);
+
+  /* The offset of the constant pool from the start of the file.  */
+  val = MAYBE_SWAP (total_len);
+  obstack_grow (&contents, &val, sizeof (val));
+  total_len += obstack_object_size (&constant_pool);
+
+  gdb_assert (obstack_object_size (&contents) == size_of_contents);
+
+  write_obstack (out_file, &contents);
+  write_obstack (out_file, &cu_list);
+  write_obstack (out_file, &addr_obstack);
+  write_obstack (out_file, &symtab_obstack);
+  write_obstack (out_file, &constant_pool);
+
+  fclose (out_file);
+
+  /* We want to keep the file, so we set cleanup_filename to NULL
+     here.  See unlink_if_set.  */
+  cleanup_filename = NULL;
+
+  do_cleanups (cleanup);
+}
+
+/* The mapped index file format is designed to be directly mmap()able
+   on any architecture.  In most cases, a datum is represented using a
+   little-endian 32-bit integer value, called an offset_type.  Big
+   endian machines must byte-swap the values before using them.
+   Exceptions to this rule are noted.  The data is laid out such that
+   alignment is always respected.
+
+   A mapped index consists of several sections.
+
+   1. The file header.  This is a sequence of values, of offset_type
+   unless otherwise noted:
+   [0] The version number.  Currently 1.
+   [1] The offset, from the start of the file, of the CU list.
+   [2] The offset, from the start of the file, of the address section.
+   [3] The offset, from the start of the file, of the symbol table.
+   [4] The offset, from the start of the file, of the constant pool.
+
+   2. The CU list.  This is a sequence of pairs of 64-bit
+   little-endian values.  The first element in each pair is the offset
+   of a CU in the .debug_info section.  The second element in each
+   pair is the length of that CU.  References to a CU elsewhere in the
+   map are done using a CU index, which is just the 0-based index into
+   this table.
+
+   3. The address section.  The address section consists of a sequence
+   of address entries.  Each address entry has three elements.
+   [0] The low address.  This is a 64-bit little-endian value.
+   [1] The high address.  This is a 64-bit little-endian value.
+   [2] The CU index.  This is an offset_type value.
+
+   4. The symbol table.  This is a hash table.  The size of the hash
+   table is always a power of 2.  The initial hash and the step are
+   currently defined by the `find_slot' function.
+
+   Each slot in the hash table consists of a pair of offset_type
+   values.  The first value is the offset of the symbol's name in the
+   constant pool.  The second value is the offset of the CU vector in
+   the constant pool.
+
+   If both values are 0, then this slot in the hash table is empty.
+   This is ok because while 0 is a valid constant pool index, it
+   cannot be a valid index for both a string and a CU vector.
+
+   A string in the constant pool is stored as a \0-terminated string,
+   as you'd expect.
+
+   A CU vector in the constant pool is a sequence of offset_type
+   values.  The first value is the number of CU indices in the vector.
+   Each subsequent value is the index of a CU in the CU list.  This
+   element in the hash table is used to indicate which CUs define the
+   symbol.
+
+   5. The constant pool.  This is simply a bunch of bytes.  It is
+   organized so that alignment is correct: CU vectors are stored
+   first, followed by strings.  */
+static void
+save_gdb_index_command (char *arg, int from_tty)
+{
+  struct objfile *objfile;
+
+  if (!arg || !*arg)
+    error (_("usage: maintenance save-gdb-index DIRECTORY"));
+
+  ALL_OBJFILES (objfile)
+  {
+    struct stat st;
+
+    /* If the objfile does not correspond to an actual file, skip it.  */
+    if (stat (objfile->name, &st) < 0)
+      continue;
+
+    dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key);
+    if (dwarf2_per_objfile)
+      {
+	volatile struct gdb_exception except;
+
+	TRY_CATCH (except, RETURN_MASK_ERROR)
+	  {
+	    write_psymtabs_to_index (objfile, arg);
+	  }
+	if (except.reason < 0)
+	  exception_fprintf (gdb_stderr, except,
+			     _("Error while writing index for `%s': "),
+			     objfile->name);
+      }
+  }
+}
+
+
+
 int dwarf2_always_disassemble;
 
 static void
@@ -12624,4 +14195,8 @@ The value is the maximum depth to print."),
 			    NULL,
 			    NULL,
 			    &setdebuglist, &showdebuglist);
+
+  add_cmd ("gdb-index", class_files, save_gdb_index_command,
+	   _("Save a .gdb-index file"),
+	   &save_cmdlist);
 }
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 8c00938..ae92ff6 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -40,6 +40,9 @@
 
 extern void _initialize_elfread (void);
 
+/* Forward declaration.  */
+static struct sym_fns elf_sym_fns_gdb_index;
+
 /* The struct elfinfo is available only during ELF symbol table and
    psymtab reading.  It is destroyed at the completion of psymtab-reading.
    It's local to elf_symfile_read.  */
@@ -869,11 +872,9 @@ elf_symfile_read (struct objfile *objfile, int symfile_flags)
 				str_sect->filepos,
 				bfd_section_size (abfd, str_sect));
     }
-  if (dwarf2_has_info (objfile))
-    {
-      /* DWARF 2 sections */
-      dwarf2_build_psymtabs (objfile);
-    }
+
+  if (dwarf2_has_info (objfile) && dwarf2_initialize_objfile (objfile))
+    objfile->sf = &elf_sym_fns_gdb_index;
 
   /* If the file has its own symbol tables it has no separate debug info.
      `.dynsym'/`.symtab' go to MSYMBOLS, `.debug_info' goes to SYMTABS/PSYMTABS.
@@ -1049,6 +1050,24 @@ static struct sym_fns elf_sym_fns =
   NULL				/* next: pointer to next struct sym_fns */
 };
 
+/* The same as elf_sym_fns, but not registered and uses the
+   DWARF-specific GNU index rather than psymtab.  */
+static struct sym_fns elf_sym_fns_gdb_index =
+{
+  bfd_target_elf_flavour,
+  elf_new_init,			/* sym_new_init: init anything gbl to entire symab */
+  elf_symfile_init,		/* sym_init: read initial info, setup for sym_red() */
+  elf_symfile_read,		/* sym_read: read a symbol file into symtab */
+  elf_symfile_finish,		/* sym_finish: finished with file, cleanup */
+  default_symfile_offsets,	/* sym_offsets:  Translate ext. to int. relocatin */
+  elf_symfile_segments,		/* sym_segments: Get segment information from
+				   a file.  */
+  NULL,                         /* sym_read_linetable */
+  default_symfile_relocate,	/* sym_relocate: Relocate a debug section.  */
+  &dwarf2_gdb_index_functions,
+  NULL				/* next: pointer to next struct sym_fns */
+};
+
 void
 _initialize_elfread (void)
 {
diff --git a/gdb/gdbcmd.h b/gdb/gdbcmd.h
index 6a230c0..d87a813 100644
--- a/gdb/gdbcmd.h
+++ b/gdb/gdbcmd.h
@@ -124,6 +124,10 @@ extern struct cmd_list_element *setchecklist;
 
 extern struct cmd_list_element *showchecklist;
 
+/* Chain containing all defined "save" subcommands.  */
+
+extern struct cmd_list_element *save_cmdlist;
+
 extern void execute_command (char *, int);
 
 enum command_control_type execute_control_command (struct command_line *);
diff --git a/gdb/psymtab.h b/gdb/psymtab.h
index 9b8c8df..de8b67e 100644
--- a/gdb/psymtab.h
+++ b/gdb/psymtab.h
@@ -1,6 +1,6 @@
 /* Public partial symbol table definitions.
 
-   Copyright (C) 2009 Free Software Foundation, Inc.
+   Copyright (C) 2009, 2010 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -28,4 +28,6 @@ void map_partial_symbol_filenames (void (*) (const char *, const char *,
 
 extern const struct quick_symbol_functions psym_functions;
 
+extern const struct quick_symbol_functions dwarf2_gdb_index_functions;
+
 #endif /* PSYMTAB_H */
diff --git a/gdb/symfile.c b/gdb/symfile.c
index ab51fa4..af1b42c 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -1059,6 +1059,9 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd,
   const char *name = bfd_get_filename (abfd);
   const int from_tty = add_flags & SYMFILE_VERBOSE;
 
+  if (readnow_symbol_files)
+    flags |= OBJF_READNOW;
+
   my_cleanups = make_cleanup_bfd_close (abfd);
 
   /* Give user a chance to burp if we'd be
@@ -1095,7 +1098,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd,
      the gdb startup command line or on a per symbol file basis.  Expand
      all partial symbol tables for this objfile if so. */
 
-  if ((flags & OBJF_READNOW) || readnow_symbol_files)
+  if ((flags & OBJF_READNOW))
     {
       if (from_tty || info_verbose)
 	{
diff --git a/gdb/symfile.h b/gdb/symfile.h
index a869fa3..d0fbb65 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -575,6 +575,7 @@ extern struct cleanup *increment_reading_symtab (void);
 
 extern int dwarf2_has_info (struct objfile *);
 
+extern int dwarf2_initialize_objfile (struct objfile *);
 extern void dwarf2_build_psymtabs (struct objfile *);
 extern void dwarf2_build_frame_info (struct objfile *);
 
-- 
1.6.2.5


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