RFC: lazy partial symbol table reading

Tom Tromey tromey@redhat.com
Tue Mar 24 00:31:00 GMT 2009


This patch implements lazy partial symbol table reading for DWARF.  It
should not affect other debug info readers.  This is based on an idea
from Apple's branch, but it is my own implementation.

The basic idea is simple: don't read partial symbols until they are
needed.  When they are needed, call require_partial_symbols to read
them.

This meant auditing all the places we might look at partial symbols,
and then deciding what to do.  In some spots this just meant an
unconditional call to require_partial_symbols.  In others, in order to
preserve as much laziness as possible, it meant introducing a separate
loop.

This patch also includes code to read the .debug_aranges section.
This lets gdb preserve laziness when doing lookups by address.

The primary benefit of this patch is faster gdb startup when used with
programs that have many objfiles.  For example, attaching to a running
OpenOffice.org Writer instance went from 1 minute 21 seconds before
the patch, to 16 seconds after the patch.

The primary drawback of this patch is that it makes some operations
slower the first time the user does them.  For example, the first
backtrace might pause as it reads partial symbols.  This can be
noticeable at times.

The speed benefit can be seen even in cases other than a plain
"attach".  For example, with an unmodified gdb, attaching to OO.o and
invoking "thread apply all bt full" takes 1:22 on this machine.  The
same operation with this patch takes 1:05 -- the difference comes
because the modified gdb does not need to read all the debuginfo.
However, this case also shows the drawback, as there is a noticeable
pause in one place to read debuginfo while printing the backtrace.

I'd appreciate comments on this.

I'd like to go even further in this direction, having gdb lazily read
most of the dwarf data.  I think this would be a much bigger project,
though.

Built and regtested on x86-64 (compile farm).

Tom

2009-03-23  Tom Tromey  <tromey@redhat.com>

	* symtab.h (require_partial_symbols): Declare.
	* symtab.c (lookup_partial_symtab): Use ALL_PSYMTABS_REQUIRED.
	(find_pc_sect_psymtab): Check the quick address map.  Require
	partial symbols.
	(require_partial_symbols): New function.
	(lookup_global_symbol_from_objfile): Require partial symbols.
	(lookup_symbol_aux_psymtabs): Use ALL_PSYMTABS_REQUIRED.
	(basic_lookup_transparent_type): Likewise.
	(find_main_psymtab): Check for OBJF_MAIN.  Require partial
	symbols.
	* symfile.h (struct sym_fns) <sym_read_psymbols>: New field.
	(dwarf2_create_quick_addrmap): Declare.
	* symfile.c (have_any_debug_symbols): New function.
	(symbol_file_add_with_addrs_or_offsets): Reorder condition.  Set
	OBJF_MAIN when needed.  Require partial symbols when needed.  Use
	have_any_debug_symbols.
	* stack.c (backtrace_command_1): Unconditionally read symbols.
	* somread.c (som_sym_fns): Update.
	* objfiles.h (struct objfile) <quick_addrmap>: New field.
	(OBJF_SYMTABS_READ): New define.
	(OBJF_MAIN): Likewise.
	(ALL_PSYMTABS_REQUIRED): Likewise.
	* objfiles.c (have_partial_symbols): Add second loop which
	requires partial symbols.
	* mipsread.c (ecoff_sym_fns): Update.
	* machoread.c (macho_sym_fns): Update.
	* elfread.c (elf_symfile_read): Don't build psymtabs.  Call
	dwarf2_create_quick_addrmap.
	(read_psyms): New function.
	(elf_sym_fns): Add read_psyms.
	* dwarf2read.c (aranges_header): Fix typo in comment.
	(dwarf2_has_info): Initialize dwarf_aranges_section.  Make
	idempotent.
	(dwarf2_locate_sections): Change 'ignore_ptr' to 'user_data'.
	Only update sizes when requested.
	(dwarf2_create_quick_addrmap): New function.
	(zlib_decompress_section): Add 'obstack' argument.  Allocate on
	obstack if requested.  Fix cleanups.
	(dwarf2_read_section_1): Rename from dwarf2_read_section.  Add
	'obstack' argument.  Allocate on obstack if requested.
	(dwarf2_read_section): New function.
	* dwarf2-frame.c: Include addrmap.h.
	(dwarf2_frame_find_fde): Check the quick address map.  Call
	require_partial_symbols.
	* dbxread.c (aout_sym_fns): Update.
	* coffread.c (coff_sym_fns): Update.
	* xcoffread.c (xcoff_sym_fns): Update.

diff --git a/gdb/coffread.c b/gdb/coffread.c
index 6059d68..be73a8f 100644
--- a/gdb/coffread.c
+++ b/gdb/coffread.c
@@ -2101,6 +2101,7 @@ static struct sym_fns coff_sym_fns =
   coff_new_init,		/* sym_new_init: init anything gbl to entire symtab */
   coff_symfile_init,		/* sym_init: read initial info, setup for sym_read() */
   coff_symfile_read,		/* sym_read: read a symbol file into symtab */
+  NULL,				/* sym_read_psymbols */
   coff_symfile_finish,		/* sym_finish: finished with file, cleanup */
   default_symfile_offsets,	/* sym_offsets:  xlate external to internal form */
   default_symfile_segments,	/* sym_segments: Get segment information from
diff --git a/gdb/dbxread.c b/gdb/dbxread.c
index 115bdef..aaf2edf 100644
--- a/gdb/dbxread.c
+++ b/gdb/dbxread.c
@@ -3547,6 +3547,7 @@ static struct sym_fns aout_sym_fns =
   dbx_new_init,		/* sym_new_init: init anything gbl to entire symtab */
   dbx_symfile_init,	/* sym_init: read initial info, setup for sym_read() */
   dbx_symfile_read,		/* sym_read: read a symbol file into symtab */
+  NULL,				/* sym_read_psymbols */
   dbx_symfile_finish,		/* sym_finish: finished with file, cleanup */
   default_symfile_offsets, /* sym_offsets: parse user's offsets to
 			      internal form */
diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c
index ce11d89..bfea1d1 100644
--- a/gdb/dwarf2-frame.c
+++ b/gdb/dwarf2-frame.c
@@ -38,6 +38,7 @@
 
 #include "complaints.h"
 #include "dwarf2-frame.h"
+#include "addrmap.h"
 
 struct comp_unit;
 
@@ -1499,6 +1500,13 @@ dwarf2_frame_find_fde (CORE_ADDR *pc)
       struct dwarf2_fde *fde;
       CORE_ADDR offset;
 
+      if (objfile->quick_addrmap)
+	{
+	  if (!addrmap_find (objfile->quick_addrmap, *pc))
+	    continue;
+	}
+      require_partial_symbols (objfile);
+
       fde = objfile_data (objfile, dwarf2_frame_objfile_data);
       if (fde == NULL)
 	continue;
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index feb57b0..fbed255 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -103,7 +103,7 @@ typedef struct pubnames_header
 _PUBNAMES_HEADER;
 #define _ACTUAL_PUBNAMES_HEADER_SIZE 13
 
-/* .debug_pubnames header
+/* .debug_aranges header
    Because of alignment constraints, this structure has padding and cannot
    be mapped directly onto the beginning of the .debug_info section.  */
 typedef struct aranges_header
@@ -768,6 +768,9 @@ static void scan_partial_symbols (struct partial_die_info *,
 static void add_partial_symbol (struct partial_die_info *,
 				struct dwarf2_cu *);
 
+static gdb_byte *read_comp_unit_head (struct comp_unit_head *, gdb_byte *,
+				      bfd *);
+
 static int pdi_needs_namespace (enum dwarf_tag tag);
 
 static void add_partial_namespace (struct partial_die_info *pdi,
@@ -794,6 +797,10 @@ static void dwarf2_psymtab_to_symtab (struct partial_symtab *);
 
 static void psymtab_to_symtab_1 (struct partial_symtab *);
 
+static gdb_byte *dwarf2_read_section_1 (struct objfile *objfile,
+					struct obstack *obstack,
+					asection *sectp);
+
 gdb_byte *dwarf2_read_section (struct objfile *, asection *);
 
 static void dwarf2_read_abbrevs (bfd *abfd, struct dwarf2_cu *cu);
@@ -1110,13 +1117,19 @@ static struct type *get_die_type (struct die_info *die, struct dwarf2_cu *cu);
 int
 dwarf2_has_info (struct objfile *objfile)
 {
-  struct dwarf2_per_objfile *data;
+  int update_sizes = 0;
 
   /* Initialize per-objfile state.  */
-  data = obstack_alloc (&objfile->objfile_obstack, sizeof (*data));
-  memset (data, 0, sizeof (*data));
-  set_objfile_data (objfile, dwarf2_objfile_data_key, data);
-  dwarf2_per_objfile = data;
+  dwarf2_per_objfile = objfile_data (objfile, dwarf2_objfile_data_key);
+  if (!dwarf2_per_objfile)
+    {
+      struct dwarf2_per_objfile *data
+	= obstack_alloc (&objfile->objfile_obstack, sizeof (*data));
+      memset (data, 0, sizeof (*data));
+      set_objfile_data (objfile, dwarf2_objfile_data_key, data);
+      dwarf2_per_objfile = data;
+      update_sizes = 1;
+    }
 
   dwarf_info_section = 0;
   dwarf_abbrev_section = 0;
@@ -1127,8 +1140,9 @@ dwarf2_has_info (struct objfile *objfile)
   dwarf_eh_frame_section = 0;
   dwarf_ranges_section = 0;
   dwarf_loc_section = 0;
+  dwarf_aranges_section = 0;
   
-  bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, NULL);
+  bfd_map_over_sections (objfile->obfd, dwarf2_locate_sections, &update_sizes);
   return (dwarf_info_section != NULL && dwarf_abbrev_section != NULL);
 }
 
@@ -1149,51 +1163,61 @@ section_is_p (asection *sectp, const char *name)
    in.  */
 
 static void
-dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr)
+dwarf2_locate_sections (bfd *abfd, asection *sectp, void *user_data)
 {
+  int update_sizes = * (int *) user_data;
   if (section_is_p (sectp, INFO_SECTION))
     {
-      dwarf2_per_objfile->info_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->info_size = bfd_get_section_size (sectp);
       dwarf_info_section = sectp;
     }
   else if (section_is_p (sectp, ABBREV_SECTION))
     {
-      dwarf2_per_objfile->abbrev_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->abbrev_size = bfd_get_section_size (sectp);
       dwarf_abbrev_section = sectp;
     }
   else if (section_is_p (sectp, LINE_SECTION))
     {
-      dwarf2_per_objfile->line_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->line_size = bfd_get_section_size (sectp);
       dwarf_line_section = sectp;
     }
   else if (section_is_p (sectp, PUBNAMES_SECTION))
     {
-      dwarf2_per_objfile->pubnames_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->pubnames_size = bfd_get_section_size (sectp);
       dwarf_pubnames_section = sectp;
     }
   else if (section_is_p (sectp, ARANGES_SECTION))
     {
-      dwarf2_per_objfile->aranges_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->aranges_size = bfd_get_section_size (sectp);
       dwarf_aranges_section = sectp;
     }
   else if (section_is_p (sectp, LOC_SECTION))
     {
-      dwarf2_per_objfile->loc_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->loc_size = bfd_get_section_size (sectp);
       dwarf_loc_section = sectp;
     }
   else if (section_is_p (sectp, MACINFO_SECTION))
     {
-      dwarf2_per_objfile->macinfo_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->macinfo_size = bfd_get_section_size (sectp);
       dwarf_macinfo_section = sectp;
     }
   else if (section_is_p (sectp, STR_SECTION))
     {
-      dwarf2_per_objfile->str_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->str_size = bfd_get_section_size (sectp);
       dwarf_str_section = sectp;
     }
   else if (section_is_p (sectp, FRAME_SECTION))
     {
-      dwarf2_per_objfile->frame_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->frame_size = bfd_get_section_size (sectp);
       dwarf_frame_section = sectp;
     }
   else if (section_is_p (sectp, EH_FRAME_SECTION))
@@ -1201,13 +1225,15 @@ dwarf2_locate_sections (bfd *abfd, asection *sectp, void *ignore_ptr)
       flagword aflag = bfd_get_section_flags (ignore_abfd, sectp);
       if (aflag & SEC_HAS_CONTENTS)
         {
-          dwarf2_per_objfile->eh_frame_size = bfd_get_section_size (sectp);
+	  if (update_sizes)
+	    dwarf2_per_objfile->eh_frame_size = bfd_get_section_size (sectp);
           dwarf_eh_frame_section = sectp;
         }
     }
   else if (section_is_p (sectp, RANGES_SECTION))
     {
-      dwarf2_per_objfile->ranges_size = bfd_get_section_size (sectp);
+      if (update_sizes)
+	dwarf2_per_objfile->ranges_size = bfd_get_section_size (sectp);
       dwarf_ranges_section = sectp;
     }
   
@@ -1250,6 +1276,78 @@ dwarf2_resize_section (asection *sectp, bfd_size_type new_size)
                     sectp->name);
 }
 
+/* Read the .debug_aranges section and construct an address map.  */
+
+void
+dwarf2_create_quick_addrmap (struct objfile *objfile)
+{
+  char *aranges_buffer, *aranges_ptr;
+  bfd *abfd = objfile->obfd;
+  CORE_ADDR baseaddr;
+  struct cleanup *old;
+  struct obstack temp_obstack;
+  struct addrmap *mutable_map;
+
+  if (!dwarf_aranges_section)
+    return;
+
+  baseaddr = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile));
+
+  aranges_buffer = dwarf2_read_section_1 (objfile, NULL, dwarf_aranges_section);
+  aranges_ptr = aranges_buffer;
+  old = make_cleanup (xfree, aranges_buffer);
+
+  obstack_init (&temp_obstack);
+  make_cleanup_obstack_free (&temp_obstack);
+  mutable_map = addrmap_create_mutable (&temp_obstack);
+
+  while ((aranges_ptr - aranges_buffer) < dwarf2_per_objfile->aranges_size)
+    {
+      struct comp_unit_head cu_header;
+      unsigned int bytes_read, segment_size, delta;
+      LONGEST info_offset;
+      struct dwarf2_cu cu;
+
+      cu_header.initial_length_size = 0;
+      aranges_ptr = read_comp_unit_head (&cu_header, aranges_ptr, abfd);
+
+      segment_size = read_1_byte (abfd, aranges_ptr);
+      aranges_ptr += 1;
+
+      /* Align the pointer to twice the pointer size.  I didn't see
+	 this in the spec but it appears to be required.  */
+      delta = (aranges_ptr - aranges_buffer) % (2 * cu_header.addr_size);
+      delta = (2 * cu_header.addr_size - delta) % (2 * cu_header.addr_size);
+      aranges_ptr += delta;
+
+      memset (&cu, 0, sizeof (cu));
+      cu.header.addr_size = cu_header.addr_size;
+
+      while (1)
+	{
+	  CORE_ADDR address, length;
+
+	  address = read_address (abfd, aranges_ptr, &cu, &bytes_read);
+	  aranges_ptr += bytes_read;
+
+	  length = read_address (abfd, aranges_ptr, &cu, &bytes_read);
+	  aranges_ptr += bytes_read;
+
+	  if (address == 0 && length == 0)
+	    break;
+
+	  address += baseaddr;
+
+	  addrmap_set_empty (mutable_map, address, address + length, objfile);
+	}
+    }
+
+  objfile->quick_addrmap = addrmap_create_fixed (mutable_map,
+						 &objfile->objfile_obstack);
+  do_cleanups (old);
+}
+
+
 /* Build a partial symbol table.  */
 
 void
@@ -5386,10 +5484,13 @@ read_die_and_siblings (gdb_byte *info_ptr, bfd *abfd,
 }
 
 /* Decompress a section that was compressed using zlib.  Store the
-   decompressed buffer, and its size, in OUTBUF and OUTSIZE.  */
+   decompressed buffer, and its size, in OUTBUF and OUTSIZE.  The
+   result is allocated on OBSTACK; if OBSTACK is NULL, xmalloc is
+   used.  */
 
 static void
-zlib_decompress_section (struct objfile *objfile, asection *sectp,
+zlib_decompress_section (struct objfile *objfile, struct obstack *obstack,
+			 asection *sectp,
                          gdb_byte **outbuf, bfd_size_type *outsize)
 {
   bfd *abfd = objfile->obfd;
@@ -5405,6 +5506,7 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp,
   z_stream strm;
   int rc;
   int header_size = 12;
+  struct cleanup *cleanups = make_cleanup (xfree, compressed_buffer);
 
   if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
       || bfd_bread (compressed_buffer, compressed_size, abfd) != compressed_size)
@@ -5434,8 +5536,13 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp,
   strm.avail_in = compressed_size - header_size;
   strm.next_in = (Bytef*) compressed_buffer + header_size;
   strm.avail_out = uncompressed_size;
-  uncompressed_buffer = obstack_alloc (&objfile->objfile_obstack,
-                                       uncompressed_size);
+  if (obstack)
+    uncompressed_buffer = obstack_alloc (obstack, uncompressed_size);
+  else
+    {
+      uncompressed_buffer = xmalloc (uncompressed_size);
+      make_cleanup (xfree, uncompressed_buffer);
+    }
   rc = inflateInit (&strm);
   while (strm.avail_in > 0)
     {
@@ -5456,6 +5563,7 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp,
     error (_("Dwarf Error: concluding DWARF uncompression in '%s': %d"),
            bfd_get_filename (abfd), rc);
 
+  discard_cleanups (cleanups);
   xfree (compressed_buffer);
   *outbuf = uncompressed_buffer;
   *outsize = uncompressed_size;
@@ -5463,17 +5571,20 @@ zlib_decompress_section (struct objfile *objfile, asection *sectp,
 }
 
 
-/* Read the contents of the section at OFFSET and of size SIZE from the
-   object file specified by OBJFILE into the objfile_obstack and return it.
-   If the section is compressed, uncompress it before returning.  */
+/* Read the contents of the section at OFFSET and of size SIZE from
+   the object file specified by OBJFILE into OBSTACK and return it.
+   If OBSTACK is NULL, xmalloc is used instead.  If the section is
+   compressed, uncompress it before returning.  */
 
-gdb_byte *
-dwarf2_read_section (struct objfile *objfile, asection *sectp)
+static gdb_byte *
+dwarf2_read_section_1 (struct objfile *objfile, struct obstack *obstack,
+		       asection *sectp)
 {
   bfd *abfd = objfile->obfd;
   gdb_byte *buf, *retbuf;
   bfd_size_type size = bfd_get_section_size (sectp);
   unsigned char header[4];
+  struct cleanup *old = NULL;
 
   if (size == 0)
     return NULL;
@@ -5486,30 +5597,49 @@ dwarf2_read_section (struct objfile *objfile, asection *sectp)
       /* Upon decompression, update the buffer and its size.  */
       if (strncmp (header, "ZLIB", sizeof (header)) == 0)
         {
-          zlib_decompress_section (objfile, sectp, &buf, &size);
+          zlib_decompress_section (objfile, obstack, sectp, &buf, &size);
           dwarf2_resize_section (sectp, size);
           return buf;
         }
     }
 
   /* If we get here, we are a normal, not-compressed section.  */
-  buf = obstack_alloc (&objfile->objfile_obstack, size);
+  if (obstack)
+    buf = obstack_alloc (obstack, size);
+  else
+    {
+      buf = xmalloc (size);
+      old = make_cleanup (xfree, buf);
+    }
   /* When debugging .o files, we may need to apply relocations; see
      http://sourceware.org/ml/gdb-patches/2002-04/msg00136.html .
      We never compress sections in .o files, so we only need to
      try this when the section is not compressed.  */
   retbuf = symfile_relocate_debug_section (abfd, sectp, buf);
   if (retbuf != NULL)
-    return retbuf;
+    {
+      if (old)
+	discard_cleanups (old);
+      return retbuf;
+    }
 
   if (bfd_seek (abfd, sectp->filepos, SEEK_SET) != 0
       || bfd_bread (buf, size, abfd) != size)
     error (_("Dwarf Error: Can't read DWARF data from '%s'"),
 	   bfd_get_filename (abfd));
 
+  if (old)
+    discard_cleanups (old);
+
   return buf;
 }
 
+gdb_byte *
+dwarf2_read_section (struct objfile *objfile, asection *sectp)
+{
+  return dwarf2_read_section_1 (objfile, &objfile->objfile_obstack, sectp);
+}
+
 /* In DWARF version 2, the description of the debugging information is
    stored in a separate .debug_abbrev section.  Before we read any
    dies from a section we read in all abbreviations and install them
diff --git a/gdb/elfread.c b/gdb/elfread.c
index ff220a2..13158f4 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -727,10 +727,18 @@ elf_symfile_read (struct objfile *objfile, int mainline)
 				str_sect->filepos,
 				bfd_section_size (abfd, str_sect));
     }
+
+  if (dwarf2_has_info (objfile))
+    dwarf2_create_quick_addrmap (objfile);
+}
+
+static void
+read_psyms (struct objfile *objfile)
+{
   if (dwarf2_has_info (objfile))
     {
       /* DWARF 2 sections */
-      dwarf2_build_psymtabs (objfile, mainline);
+      dwarf2_build_psymtabs (objfile, 0);
     }
 
   /* FIXME: kettenis/20030504: This still needs to be integrated with
@@ -880,6 +888,7 @@ static struct sym_fns elf_sym_fns =
   elf_new_init,			/* sym_new_init: init anything gbl to entire symtab */
   elf_symfile_init,		/* sym_init: read initial info, setup for sym_read() */
   elf_symfile_read,		/* sym_read: read a symbol file into symtab */
+  read_psyms,			/* sym_read_psymbols */
   elf_symfile_finish,		/* sym_finish: finished with file, cleanup */
   default_symfile_offsets,	/* sym_offsets:  Translate ext. to int. relocation */
   elf_symfile_segments,		/* sym_segments: Get segment information from
diff --git a/gdb/machoread.c b/gdb/machoread.c
index d8d3bd2..248fae2 100644
--- a/gdb/machoread.c
+++ b/gdb/machoread.c
@@ -681,6 +681,7 @@ static struct sym_fns macho_sym_fns = {
   macho_new_init,               /* sym_new_init: init anything gbl to entire symtab */
   macho_symfile_init,           /* sym_init: read initial info, setup for sym_read() */
   macho_symfile_read,           /* sym_read: read a symbol file into symtab */
+  NULL,				/* sym_read_psymbols */
   macho_symfile_finish,         /* sym_finish: finished with file, cleanup */
   macho_symfile_offsets,        /* sym_offsets:  xlate external to internal form */
   NULL                          /* next: pointer to next struct sym_fns */
diff --git a/gdb/mipsread.c b/gdb/mipsread.c
index a84003f..924c1c5 100644
--- a/gdb/mipsread.c
+++ b/gdb/mipsread.c
@@ -394,6 +394,7 @@ static struct sym_fns ecoff_sym_fns =
   mipscoff_new_init,		/* sym_new_init: init anything gbl to entire symtab */
   mipscoff_symfile_init,	/* sym_init: read initial info, setup for sym_read() */
   mipscoff_symfile_read,	/* sym_read: read a symbol file into symtab */
+  NULL,				/* sym_read_psymbols */
   mipscoff_symfile_finish,	/* sym_finish: finished with file, cleanup */
   default_symfile_offsets,	/* sym_offsets: dummy FIXME til implem sym reloc */
   default_symfile_segments,	/* sym_segments: Get segment information from
diff --git a/gdb/objfiles.c b/gdb/objfiles.c
index 795d53b..e687ae5 100644
--- a/gdb/objfiles.c
+++ b/gdb/objfiles.c
@@ -693,6 +693,20 @@ have_partial_symbols (void)
 	return 1;
       }
   }
+
+  /* Try again, after reading partial symbols.  We do this in two
+     passes because objfiles are always added to the head of the list,
+     and there might be a later objfile for which we've already read
+     partial symbols.  */
+  ALL_OBJFILES (ofp)
+  {
+    require_partial_symbols (ofp);
+    if (ofp->psymtabs != NULL)
+      {
+	return 1;
+      }
+  }
+
   return 0;
 }
 
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
index 60d3143..07a6a3a 100644
--- a/gdb/objfiles.h
+++ b/gdb/objfiles.h
@@ -212,6 +212,11 @@ struct objfile
 
     struct partial_symtab *psymtabs;
 
+    /* An address map that can be used to quickly determine if an
+       address comes from this objfile.  This can be NULL.  */
+
+    struct addrmap *quick_addrmap;
+
     /* Map addresses to the entries of PSYMTABS.  It would be more efficient to
        have a map per the whole process but ADDRMAP cannot selectively remove
        its items during FREE_OBJFILE.  This mapping is already present even for
@@ -419,6 +424,14 @@ struct objfile
 
 #define OBJF_KEEPBFD	(1 << 4)	/* Do not delete bfd */
 
+/* Set if we have tried to read partial symtabs for this objfile.
+   This is used to allow lazy reading of partial symtabs.  */
+
+#define OBJF_SYMTABS_READ (1 << 5)
+
+/* This flag is set for the main objfile.  */
+
+#define OBJF_MAIN (1 << 6)
 
 /* The object file that the main symbol table was loaded from (e.g. the
    argument to the "symbol-file" or "file" command).  */
@@ -556,6 +569,13 @@ extern void *objfile_data (struct objfile *objfile,
   ALL_OBJFILES (objfile)	 \
     ALL_OBJFILE_PSYMTABS (objfile, p)
 
+/* Like ALL_PSYMTABS, but ensure that partial symbols have been read
+   before examining the objfile.  */
+
+#define ALL_PSYMTABS_REQUIRED(objfile, p)			\
+  ALL_OBJFILES (objfile)					\
+    ALL_OBJFILE_PSYMTABS (require_partial_symbols (objfile), p)
+
 /* Traverse all minimal symbols in all objfiles.  */
 
 #define	ALL_MSYMBOLS(objfile, m) \
diff --git a/gdb/somread.c b/gdb/somread.c
index 36a2b28..4d5bda9 100644
--- a/gdb/somread.c
+++ b/gdb/somread.c
@@ -435,6 +435,7 @@ static struct sym_fns som_sym_fns =
   som_new_init,			/* sym_new_init: init anything gbl to entire symtab */
   som_symfile_init,		/* sym_init: read initial info, setup for sym_read() */
   som_symfile_read,		/* sym_read: read a symbol file into symtab */
+  NULL,				/* sym_read_psymbols */
   som_symfile_finish,		/* sym_finish: finished with file, cleanup */
   som_symfile_offsets,		/* sym_offsets:  Translate ext. to int. relocation */
   default_symfile_segments,	/* sym_segments: Get segment information from
diff --git a/gdb/stack.c b/gdb/stack.c
index f185841..d7434c2 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1273,24 +1273,24 @@ backtrace_command_1 (char *count_exp, int show_locals, int from_tty)
   else
     count = -1;
 
-  if (info_verbose)
-    {
-      struct partial_symtab *ps;
-
-      /* Read in symbols for all of the frames.  Need to do this in a
-         separate pass so that "Reading in symbols for xxx" messages
-         don't screw up the appearance of the backtrace.  Also if
-         people have strong opinions against reading symbols for
-         backtrace this may have to be an option.  */
-      i = count;
-      for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi))
-	{
-	  QUIT;
-	  ps = find_pc_psymtab (get_frame_address_in_block (fi));
-	  if (ps)
-	    PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in.  */
-	}
-    }
+  {
+    struct partial_symtab *ps;
+
+    /* Read in symbols for all of the frames.  Need to do this
+       unconditionally to ensure that psymbols are read.  Also need to
+       do this in a separate pass so that "Reading in symbols for xxx"
+       messages don't screw up the appearance of the backtrace.  Also
+       if people have strong opinions against reading symbols for
+       backtrace this may have to be an option.  */
+    i = count;
+    for (fi = trailing; fi != NULL && i--; fi = get_prev_frame (fi))
+      {
+	QUIT;
+	ps = find_pc_psymtab (get_frame_address_in_block (fi));
+	if (info_verbose && ps)
+	  PSYMTAB_TO_SYMTAB (ps); /* Force syms to come in.  */
+      }
+  }
 
   for (i = 0, fi = trailing; fi && count--; i++, fi = get_prev_frame (fi))
     {
diff --git a/gdb/symfile.c b/gdb/symfile.c
index 63b5c1d..8490bfd 100644
--- a/gdb/symfile.c
+++ b/gdb/symfile.c
@@ -929,6 +929,17 @@ new_symfile_objfile (struct objfile *objfile, int mainline, int verbo)
   clear_complaints (&symfile_complaints, 0, verbo);
 }
 
+/* A helper function which returns true if OBJFILE has any debug
+   symbols, and false otherwise.  */
+static int
+have_any_debug_symbols (struct objfile *objfile)
+{
+  return (objfile->psymtabs || objfile->quick_addrmap
+	  || (objfile->separate_debug_objfile
+	      && (objfile->separate_debug_objfile->psymtabs
+		  || objfile->separate_debug_objfile->quick_addrmap)));
+}
+
 /* Process a symbol file, as either the main file or as a dynamically
    loaded file.
 
@@ -965,13 +976,15 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty,
   /* Give user a chance to burp if we'd be
      interactively wiping out any existing symbols.  */
 
-  if ((have_full_symbols () || have_partial_symbols ())
-      && mainline
+  if (mainline
       && from_tty
+      && (have_full_symbols () || have_partial_symbols ())
       && !query (_("Load new symbol table from \"%s\"? "), name))
     error (_("Not confirmed."));
 
   objfile = allocate_objfile (abfd, flags);
+  if (mainline)
+    objfile->flags |= OBJF_MAIN;
   discard_cleanups (my_cleanups);
 
   if (addrs)
@@ -1007,6 +1020,8 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty,
 
   if ((flags & OBJF_READNOW) || readnow_symbol_files)
     {
+      require_partial_symbols (objfile);
+
       if ((from_tty || info_verbose) && print_symbol_loading)
 	{
 	  printf_unfiltered (_("expanding to full symbols..."));
@@ -1025,7 +1040,7 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty,
   /* 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.
      `.gnu_debuglink' may no longer be present with `.note.gnu.build-id'.  */
-  if (objfile->psymtabs == NULL)
+  if (!have_any_debug_symbols (objfile))
     debugfile = find_separate_debug_file (objfile);
   if (debugfile)
     {
@@ -1049,8 +1064,8 @@ symbol_file_add_with_addrs_or_offsets (bfd *abfd, int from_tty,
       xfree (debugfile);
     }
 
-  if (!have_partial_symbols () && !have_full_symbols ()
-      && print_symbol_loading)
+  if ((from_tty || info_verbose) && print_symbol_loading && mainline
+      && !have_any_debug_symbols (objfile))
     {
       wrap_here ("");
       printf_unfiltered (_("(no debugging symbols found)"));
@@ -2423,13 +2438,15 @@ reread_symbols (void)
 	         zero is OK since dbxread.c also does what it needs to do if
 	         objfile->global_psymbols.size is 0.  */
 	      (*objfile->sf->sym_read) (objfile, 0);
-	      if (!have_partial_symbols () && !have_full_symbols ())
+	      if (!have_any_debug_symbols (objfile))
 		{
 		  wrap_here ("");
 		  printf_unfiltered (_("(no debugging symbols found)\n"));
 		  wrap_here ("");
 		}
 
+	      objfile->flags &= ~OBJF_SYMTABS_READ;
+
 	      /* We're done reading the symbol file; finish off complaints.  */
 	      clear_complaints (&symfile_complaints, 0, 1);
 
diff --git a/gdb/symfile.h b/gdb/symfile.h
index 88f8326..51b26e0 100644
--- a/gdb/symfile.h
+++ b/gdb/symfile.h
@@ -140,6 +140,12 @@ struct sym_fns
 
   void (*sym_read) (struct objfile *, int);
 
+  /* Read the partial symbols for an objfile.  This may be NULL, in
+     which case gdb assumes that sym_read already read the partial
+     symbols.  */
+
+  void (*sym_read_psymbols) (struct objfile *);
+
   /* Called when we are finished with an objfile.  Should do all
      cleanup that is specific to the object file format for the
      particular objfile.  */
@@ -370,6 +376,7 @@ void free_symfile_segment_data (struct symfile_segment_data *data);
 
 extern int dwarf2_has_info (struct objfile *);
 
+extern void dwarf2_create_quick_addrmap (struct objfile *);
 extern void dwarf2_build_psymtabs (struct objfile *, int);
 extern void dwarf2_build_frame_info (struct objfile *);
 
diff --git a/gdb/symtab.c b/gdb/symtab.c
index 7fff68a..4f1bf66 100644
--- a/gdb/symtab.c
+++ b/gdb/symtab.c
@@ -273,7 +273,7 @@ lookup_partial_symtab (const char *name)
       make_cleanup (xfree, real_path);
     }
 
-  ALL_PSYMTABS (objfile, pst)
+  ALL_PSYMTABS_REQUIRED (objfile, pst)
   {
     if (FILENAME_CMP (name, pst->filename) == 0)
       {
@@ -870,7 +870,13 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section)
      than the later used TEXTLOW/TEXTHIGH one.  */
 
   ALL_OBJFILES (objfile)
-    if (objfile->psymtabs_addrmap != NULL)
+  {
+    if (objfile->quick_addrmap)
+      {
+	if (!addrmap_find (objfile->quick_addrmap, pc))
+	  continue;
+      }
+    if (require_partial_symbols (objfile)->psymtabs_addrmap != NULL)
       {
 	struct partial_symtab *pst;
 
@@ -903,6 +909,7 @@ find_pc_sect_psymtab (CORE_ADDR pc, struct obj_section *section)
 	    return pst;
 	  }
       }
+  }
 
   /* Existing PSYMTABS_ADDRMAP mapping is present even for PARTIAL_SYMTABs
      which still have no corresponding full SYMTABs read.  But it is not
@@ -1170,6 +1177,22 @@ fixup_psymbol_section (struct partial_symbol *psym, struct objfile *objfile)
   return psym;
 }
 
+/* Ensure that the partial symbols for OBJFILE have been loaded.  This
+   function always returns its argument, as a convenience.  */
+
+struct objfile *
+require_partial_symbols (struct objfile *objfile)
+{
+  if ((objfile->flags & OBJF_SYMTABS_READ) == 0)
+    {
+      objfile->flags |= OBJF_SYMTABS_READ;
+
+      if (objfile->sf->sym_read_psymbols)
+	(*objfile->sf->sym_read_psymbols) (objfile);
+    }
+  return objfile;
+}
+
 /* Find the definition for a specified symbol name NAME
    in domain DOMAIN, visible from lexical block BLOCK.
    Returns the struct symbol pointer, or zero if no symbol is found.
@@ -1449,6 +1472,7 @@ lookup_global_symbol_from_objfile (const struct objfile *objfile,
   }
 
   /* Now go through psymtabs.  */
+  require_partial_symbols ((struct objfile *) objfile);
   ALL_OBJFILE_PSYMTABS (objfile, ps)
   {
     if (!ps->readin
@@ -1519,7 +1543,7 @@ lookup_symbol_aux_psymtabs (int block_index, const char *name,
   struct symtab *s;
   const int psymtab_index = (block_index == GLOBAL_BLOCK ? 1 : 0);
 
-  ALL_PSYMTABS (objfile, ps)
+  ALL_PSYMTABS_REQUIRED (objfile, ps)
   {
     if (!ps->readin
 	&& lookup_partial_symbol (ps, name, linkage_name,
@@ -1804,7 +1828,11 @@ basic_lookup_transparent_type (const char *name)
       }
   }
 
-  ALL_PSYMTABS (objfile, ps)
+  /* FIXME: .debug_pubnames should be read in.
+     
+     One may also try to the first pass without the require_partial_symbols
+     call but that would behave nondeterministically.  */
+  ALL_PSYMTABS_REQUIRED (objfile, ps)
   {
     if (!ps->readin && lookup_partial_symbol (ps, name, NULL,
 					      1, STRUCT_DOMAIN))
@@ -1852,7 +1880,12 @@ basic_lookup_transparent_type (const char *name)
       }
   }
 
-  ALL_PSYMTABS (objfile, ps)
+  /* FIXME: Something like .debug_pubnames containing also static symbols
+     should be read in.  Compiler needs to be taught to generate it first.
+     
+     One may also try to the first pass without the require_partial_symbols
+     call but that would behave nondeterministically.  */
+  ALL_PSYMTABS_REQUIRED (objfile, ps)
   {
     if (!ps->readin && lookup_partial_symbol (ps, name, NULL, 0, STRUCT_DOMAIN))
       {
@@ -1893,7 +1926,21 @@ find_main_psymtab (void)
   struct partial_symtab *pst;
   struct objfile *objfile;
 
-  ALL_PSYMTABS (objfile, pst)
+  ALL_OBJFILES (objfile)
+  {
+    if ((objfile->flags & OBJF_MAIN) == 0)
+      continue;
+    require_partial_symbols (objfile);
+    ALL_OBJFILE_PSYMTABS (objfile, pst)
+    {
+      if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN))
+	{
+	  return pst;
+	}
+    }
+  }
+
+  ALL_PSYMTABS_REQUIRED (objfile, pst)
   {
     if (lookup_partial_symbol (pst, main_name (), NULL, 1, VAR_DOMAIN))
       {
@@ -3084,7 +3131,7 @@ search_symbols (char *regexp, domain_enum kind, int nfiles, char *files[],
      matching the regexp.  That way we don't have to reproduce all of
      the machinery below. */
 
-  ALL_PSYMTABS (objfile, ps)
+  ALL_PSYMTABS_REQUIRED (objfile, ps)
   {
     struct partial_symbol **bound, **gbound, **sbound;
     int keep_going = 1;
diff --git a/gdb/symtab.h b/gdb/symtab.h
index 8b086f3..cbfbd50 100644
--- a/gdb/symtab.h
+++ b/gdb/symtab.h
@@ -1027,6 +1027,8 @@ extern void clear_pc_function_cache (void);
 
 /* from symtab.c: */
 
+struct objfile *require_partial_symbols (struct objfile *);
+
 /* lookup partial symbol table by filename */
 
 extern struct partial_symtab *lookup_partial_symtab (const char *);
diff --git a/gdb/xcoffread.c b/gdb/xcoffread.c
index 9ae929f..63b6818 100644
--- a/gdb/xcoffread.c
+++ b/gdb/xcoffread.c
@@ -3037,6 +3037,7 @@ static struct sym_fns xcoff_sym_fns =
   xcoff_new_init,		/* sym_new_init: init anything gbl to entire symtab */
   xcoff_symfile_init,		/* sym_init: read initial info, setup for sym_read() */
   xcoff_initial_scan,		/* sym_read: read a symbol file into symtab */
+  NULL,				/* sym_read_psymbols */
   xcoff_symfile_finish,		/* sym_finish: finished with file, cleanup */
   xcoff_symfile_offsets,	/* sym_offsets: xlate offsets ext->int form */
   default_symfile_segments,	/* sym_segments: Get segment information from



More information about the Gdb-patches mailing list