Add symbol lookup cache.
[deliverable/binutils-gdb.git] / gdb / symtab.c
index 4672ac31eabf2b53fddc6ccd3d3d19be699cdecd..321241beb691d67af2a724abd483368ccab46b77 100644 (file)
@@ -1,6 +1,6 @@
 /* Symbol table lookup for the GNU debugger, GDB.
 
-   Copyright (C) 1986-2014 Free Software Foundation, Inc.
+   Copyright (C) 1986-2015 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -79,11 +79,9 @@ struct symbol *lookup_local_symbol (const char *name,
                                    const domain_enum domain,
                                    enum language language);
 
-static
-struct symbol *lookup_symbol_via_quick_fns (struct objfile *objfile,
-                                           int block_index,
-                                           const char *name,
-                                           const domain_enum domain);
+static struct symbol *
+  lookup_symbol_in_objfile (struct objfile *objfile, int block_index,
+                           const char *name, const domain_enum domain);
 
 extern initialize_file_ftype _initialize_symtab;
 
@@ -104,9 +102,115 @@ struct main_info
   enum language language_of_main;
 };
 
+/* Program space key for finding its symbol cache.  */
+
+static const struct program_space_data *symbol_cache_key;
+
+/* The default symbol cache size.
+   There is no extra cpu cost for large N (except when flushing the cache,
+   which is rare).  The value here is just a first attempt.  A better default
+   value may be higher or lower.  A prime number can make up for a bad hash
+   computation, so that's why the number is what it is.  */
+#define DEFAULT_SYMBOL_CACHE_SIZE 1021
+
+/* The maximum symbol cache size.
+   There's no method to the decision of what value to use here, other than
+   there's no point in allowing a user typo to make gdb consume all memory.  */
+#define MAX_SYMBOL_CACHE_SIZE (1024*1024)
+
+/* symbol_cache_lookup returns this if a previous lookup failed to find the
+   symbol in any objfile.  */
+#define SYMBOL_LOOKUP_FAILED ((struct symbol *) 1)
+
+/* Recording lookups that don't find the symbol is just as important, if not
+   more so, than recording found symbols.  */
+
+enum symbol_cache_slot_state
+{
+  SYMBOL_SLOT_UNUSED,
+  SYMBOL_SLOT_NOT_FOUND,
+  SYMBOL_SLOT_FOUND
+};
+
+/* Symbols don't specify global vs static block.
+   So keep them in separate caches.  */
+
+struct block_symbol_cache
+{
+  unsigned int hits;
+  unsigned int misses;
+  unsigned int collisions;
+
+  /* SYMBOLS is a variable length array of this size.
+     One can imagine that in general one cache (global/static) should be a
+     fraction of the size of the other, but there's no data at the moment
+     on which to decide.  */
+  unsigned int size;
+
+  struct symbol_cache_slot
+  {
+    enum symbol_cache_slot_state state;
+
+    /* The objfile that was current when the symbol was looked up.
+       This is only needed for global blocks, but for simplicity's sake
+       we allocate the space for both.  If data shows the extra space used
+       for static blocks is a problem, we can split things up then.
+
+       Global blocks need cache lookup to include the objfile context because
+       we need to account for gdbarch_iterate_over_objfiles_in_search_order
+       which can traverse objfiles in, effectively, any order, depending on
+       the current objfile, thus affecting which symbol is found.  Normally,
+       only the current objfile is searched first, and then the rest are
+       searched in recorded order; but putting cache lookup inside
+       gdbarch_iterate_over_objfiles_in_search_order would be awkward.
+       Instead we just make the current objfile part of the context of
+       cache lookup.  This means we can record the same symbol multiple times,
+       each with a different "current objfile" that was in effect when the
+       lookup was saved in the cache, but cache space is pretty cheap.  */
+    const struct objfile *objfile_context;
+
+    union
+    {
+      struct symbol *found;
+      struct
+      {
+       char *name;
+       domain_enum domain;
+      } not_found;
+    } value;
+  } symbols[1];
+};
+
+/* The symbol cache.
+
+   Searching for symbols in the static and global blocks over multiple objfiles
+   again and again can be slow, as can searching very big objfiles.  This is a
+   simple cache to improve symbol lookup performance, which is critical to
+   overall gdb performance.
+
+   Symbols are hashed on the name, its domain, and block.
+   They are also hashed on their objfile for objfile-specific lookups.  */
+
+struct symbol_cache
+{
+  struct block_symbol_cache *global_symbols;
+  struct block_symbol_cache *static_symbols;
+};
+
 /* When non-zero, print debugging messages related to symtab creation.  */
 unsigned int symtab_create_debug = 0;
 
+/* When non-zero, print debugging messages related to symbol lookup.  */
+unsigned int symbol_lookup_debug = 0;
+
+/* The size of the cache is staged here.  */
+static unsigned int new_symbol_cache_size = DEFAULT_SYMBOL_CACHE_SIZE;
+
+/* The current value of the symbol cache size.
+   This is saved so that if the user enters a value too big we can restore
+   the original value from here.  */
+static unsigned int symbol_cache_size = DEFAULT_SYMBOL_CACHE_SIZE;
+
 /* Non-zero if a file may be known by two different basenames.
    This is the uncommon case, and significantly slows down gdb.
    Default set to "off" to not slow down the common case.  */
@@ -152,6 +256,7 @@ domain_name (domain_enum e)
     case UNDEF_DOMAIN: return "UNDEF_DOMAIN";
     case VAR_DOMAIN: return "VAR_DOMAIN";
     case STRUCT_DOMAIN: return "STRUCT_DOMAIN";
+    case MODULE_DOMAIN: return "MODULE_DOMAIN";
     case LABEL_DOMAIN: return "LABEL_DOMAIN";
     case COMMON_BLOCK_DOMAIN: return "COMMON_BLOCK_DOMAIN";
     default: gdb_assert_not_reached ("bad domain_enum");
@@ -173,20 +278,27 @@ search_domain_name (enum search_domain e)
     }
 }
 
-/* Set the primary field in SYMTAB.  */
+/* See symtab.h.  */
 
-void
-set_symtab_primary (struct symtab *symtab, int primary)
+struct symtab *
+compunit_primary_filetab (const struct compunit_symtab *cust)
 {
-  symtab->primary = primary;
+  gdb_assert (COMPUNIT_FILETABS (cust) != NULL);
 
-  if (symtab_create_debug && primary)
-    {
-      fprintf_unfiltered (gdb_stdlog,
-                         "Created primary symtab %s for %s.\n",
-                         host_address_to_string (symtab),
-                         symtab_to_filename_for_display (symtab));
-    }
+  /* The primary file symtab is the first one in the list.  */
+  return COMPUNIT_FILETABS (cust);
+}
+
+/* See symtab.h.  */
+
+enum language
+compunit_language (const struct compunit_symtab *cust)
+{
+  struct symtab *symtab = compunit_primary_filetab (cust);
+
+/* The language of the compunit symtab is the language of its primary
+   source file.  */
+  return SYMTAB_LANGUAGE (symtab);
 }
 
 /* See whether FILENAME matches SEARCH_NAME using the rule that we
@@ -237,8 +349,9 @@ compare_filenames_for_search (const char *filename, const char *search_name)
    are identical to the `map_symtabs_matching_filename' method of
    quick_symbol_functions.
 
-   FIRST and AFTER_LAST indicate the range of symtabs to search.
-   AFTER_LAST is one past the last symtab to search; NULL means to
+   FIRST and AFTER_LAST indicate the range of compunit symtabs to search.
+   Each symtab within the specified compunit symtab is also searched.
+   AFTER_LAST is one past the last compunit symtab to search; NULL means to
    search until the end of the list.  */
 
 int
@@ -247,48 +360,52 @@ iterate_over_some_symtabs (const char *name,
                           int (*callback) (struct symtab *symtab,
                                            void *data),
                           void *data,
-                          struct symtab *first,
-                          struct symtab *after_last)
+                          struct compunit_symtab *first,
+                          struct compunit_symtab *after_last)
 {
-  struct symtab *s = NULL;
+  struct compunit_symtab *cust;
+  struct symtab *s;
   const char* base_name = lbasename (name);
 
-  for (s = first; s != NULL && s != after_last; s = s->next)
+  for (cust = first; cust != NULL && cust != after_last; cust = cust->next)
     {
-      if (compare_filenames_for_search (s->filename, name))
-       {
-         if (callback (s, data))
-           return 1;
-         continue;
-       }
-
-      /* Before we invoke realpath, which can get expensive when many
-        files are involved, do a quick comparison of the basenames.  */
-      if (! basenames_may_differ
-         && FILENAME_CMP (base_name, lbasename (s->filename)) != 0)
-       continue;
-
-      if (compare_filenames_for_search (symtab_to_fullname (s), name))
+      ALL_COMPUNIT_FILETABS (cust, s)
        {
-         if (callback (s, data))
-           return 1;
-         continue;
-       }
+         if (compare_filenames_for_search (s->filename, name))
+           {
+             if (callback (s, data))
+               return 1;
+             continue;
+           }
 
-      /* If the user gave us an absolute path, try to find the file in
-        this symtab and use its absolute path.  */
-      if (real_path != NULL)
-       {
-         const char *fullname = symtab_to_fullname (s);
+         /* Before we invoke realpath, which can get expensive when many
+            files are involved, do a quick comparison of the basenames.  */
+         if (! basenames_may_differ
+             && FILENAME_CMP (base_name, lbasename (s->filename)) != 0)
+           continue;
 
-         gdb_assert (IS_ABSOLUTE_PATH (real_path));
-         gdb_assert (IS_ABSOLUTE_PATH (name));
-         if (FILENAME_CMP (real_path, fullname) == 0)
+         if (compare_filenames_for_search (symtab_to_fullname (s), name))
            {
              if (callback (s, data))
                return 1;
              continue;
            }
+
+         /* If the user gave us an absolute path, try to find the file in
+            this symtab and use its absolute path.  */
+         if (real_path != NULL)
+           {
+             const char *fullname = symtab_to_fullname (s);
+
+             gdb_assert (IS_ABSOLUTE_PATH (real_path));
+             gdb_assert (IS_ABSOLUTE_PATH (name));
+             if (FILENAME_CMP (real_path, fullname) == 0)
+               {
+                 if (callback (s, data))
+                   return 1;
+                 continue;
+               }
+           }
        }
     }
 
@@ -324,7 +441,7 @@ iterate_over_symtabs (const char *name,
   ALL_OBJFILES (objfile)
   {
     if (iterate_over_some_symtabs (name, real_path, callback, data,
-                                  objfile->symtabs, NULL))
+                                  objfile->compunit_symtabs, NULL))
       {
        do_cleanups (cleanups);
        return;
@@ -461,40 +578,15 @@ gdb_mangle_name (struct type *type, int method_id, int signature_id)
   return (mangled_name);
 }
 
-/* Initialize the cplus_specific structure.  'cplus_specific' should
-   only be allocated for use with cplus symbols.  */
-
-static void
-symbol_init_cplus_specific (struct general_symbol_info *gsymbol,
-                           struct obstack *obstack)
-{
-  /* A language_specific structure should not have been previously
-     initialized.  */
-  gdb_assert (gsymbol->language_specific.cplus_specific == NULL);
-  gdb_assert (obstack != NULL);
-
-  gsymbol->language_specific.cplus_specific =
-    OBSTACK_ZALLOC (obstack, struct cplus_specific);
-}
-
 /* Set the demangled name of GSYMBOL to NAME.  NAME must be already
-   correctly allocated.  For C++ symbols a cplus_specific struct is
-   allocated so OBJFILE must not be NULL.  If this is a non C++ symbol
-   OBJFILE can be NULL.  */
+   correctly allocated.  */
 
 void
 symbol_set_demangled_name (struct general_symbol_info *gsymbol,
                            const char *name,
                            struct obstack *obstack)
 {
-  if (gsymbol->language == language_cplus)
-    {
-      if (gsymbol->language_specific.cplus_specific == NULL)
-       symbol_init_cplus_specific (gsymbol, obstack);
-
-      gsymbol->language_specific.cplus_specific->demangled_name = name;
-    }
-  else if (gsymbol->language == language_ada)
+  if (gsymbol->language == language_ada)
     {
       if (name == NULL)
        {
@@ -516,14 +608,7 @@ symbol_set_demangled_name (struct general_symbol_info *gsymbol,
 const char *
 symbol_get_demangled_name (const struct general_symbol_info *gsymbol)
 {
-  if (gsymbol->language == language_cplus)
-    {
-      if (gsymbol->language_specific.cplus_specific != NULL)
-       return gsymbol->language_specific.cplus_specific->demangled_name;
-      else
-       return NULL;
-    }
-  else if (gsymbol->language == language_ada)
+  if (gsymbol->language == language_ada)
     {
       if (!gsymbol->ada_mangled)
        return NULL;
@@ -543,7 +628,8 @@ symbol_set_language (struct general_symbol_info *gsymbol,
                     struct obstack *obstack)
 {
   gsymbol->language = language;
-  if (gsymbol->language == language_d
+  if (gsymbol->language == language_cplus
+      || gsymbol->language == language_d
       || gsymbol->language == language_go
       || gsymbol->language == language_java
       || gsymbol->language == language_objc
@@ -556,8 +642,6 @@ symbol_set_language (struct general_symbol_info *gsymbol,
       gdb_assert (gsymbol->ada_mangled == 0);
       gsymbol->language_specific.obstack = obstack;
     }
-  else if (gsymbol->language == language_cplus)
-    gsymbol->language_specific.cplus_specific = NULL;
   else
     {
       memset (&gsymbol->language_specific, 0,
@@ -1067,16 +1151,562 @@ expand_symtab_containing_pc (CORE_ADDR pc, struct obj_section *section)
 
   ALL_OBJFILES (objfile)
   {
-    struct symtab *s = NULL;
+    struct compunit_symtab *cust = NULL;
 
     if (objfile->sf)
-      s = objfile->sf->qf->find_pc_sect_symtab (objfile, msymbol,
-                                               pc, section, 0);
-    if (s != NULL)
+      cust = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile, msymbol,
+                                                           pc, section, 0);
+    if (cust)
       return;
   }
 }
 \f
+/* Hash function for the symbol cache.  */
+
+static unsigned int
+hash_symbol_entry (const struct objfile *objfile_context,
+                  const char *name, domain_enum domain)
+{
+  unsigned int hash = (uintptr_t) objfile_context;
+
+  if (name != NULL)
+    hash += htab_hash_string (name);
+
+  hash += domain;
+
+  return hash;
+}
+
+/* Equality function for the symbol cache.  */
+
+static int
+eq_symbol_entry (const struct symbol_cache_slot *slot,
+                const struct objfile *objfile_context,
+                const char *name, domain_enum domain)
+{
+  const char *slot_name;
+  domain_enum slot_domain;
+
+  if (slot->state == SYMBOL_SLOT_UNUSED)
+    return 0;
+
+  if (slot->objfile_context != objfile_context)
+    return 0;
+
+  if (slot->state == SYMBOL_SLOT_NOT_FOUND)
+    {
+      slot_name = slot->value.not_found.name;
+      slot_domain = slot->value.not_found.domain;
+    }
+  else
+    {
+      slot_name = SYMBOL_SEARCH_NAME (slot->value.found);
+      slot_domain = SYMBOL_DOMAIN (slot->value.found);
+    }
+
+  /* NULL names match.  */
+  if (slot_name == NULL && name == NULL)
+    {
+      /* But there's no point in calling symbol_matches_domain in the
+        SYMBOL_SLOT_FOUND case.  */
+      if (slot_domain != domain)
+       return 0;
+    }
+  else if (slot_name != NULL && name != NULL)
+    {
+      /* It's important that we use the same comparison that was done the
+        first time through.  If the slot records a found symbol, then this
+        means using strcmp_iw on SYMBOL_SEARCH_NAME.  See dictionary.c.
+        It also means using symbol_matches_domain for found symbols.
+        See block.c.
+
+        If the slot records a not-found symbol, then require a precise match.
+        We could still be lax with whitespace like strcmp_iw though.  */
+
+      if (slot->state == SYMBOL_SLOT_NOT_FOUND)
+       {
+         if (strcmp (slot_name, name) != 0)
+           return 0;
+         if (slot_domain != domain)
+           return 0;
+       }
+      else
+       {
+         struct symbol *sym = slot->value.found;
+
+         if (strcmp_iw (slot_name, name) != 0)
+           return 0;
+         if (!symbol_matches_domain (SYMBOL_LANGUAGE (sym),
+                                     slot_domain, domain))
+           return 0;
+       }
+    }
+  else
+    {
+      /* Only one name is NULL.  */
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Given a cache of size SIZE, return the size of the struct (with variable
+   length array) in bytes.  */
+
+static size_t
+symbol_cache_byte_size (unsigned int size)
+{
+  return (sizeof (struct block_symbol_cache)
+         + ((size - 1) * sizeof (struct symbol_cache_slot)));
+}
+
+/* Resize CACHE.  */
+
+static void
+resize_symbol_cache (struct symbol_cache *cache, unsigned int new_size)
+{
+  /* If there's no change in size, don't do anything.
+     All caches have the same size, so we can just compare with the size
+     of the global symbols cache.  */
+  if ((cache->global_symbols != NULL
+       && cache->global_symbols->size == new_size)
+      || (cache->global_symbols == NULL
+         && new_size == 0))
+    return;
+
+  xfree (cache->global_symbols);
+  xfree (cache->static_symbols);
+
+  if (new_size == 0)
+    {
+      cache->global_symbols = NULL;
+      cache->static_symbols = NULL;
+    }
+  else
+    {
+      size_t total_size = symbol_cache_byte_size (new_size);
+
+      cache->global_symbols = xcalloc (1, total_size);
+      cache->static_symbols = xcalloc (1, total_size);
+      cache->global_symbols->size = new_size;
+      cache->static_symbols->size = new_size;
+    }
+}
+
+/* Make a symbol cache of size SIZE.  */
+
+static struct symbol_cache *
+make_symbol_cache (unsigned int size)
+{
+  struct symbol_cache *cache;
+
+  cache = XCNEW (struct symbol_cache);
+  resize_symbol_cache (cache, symbol_cache_size);
+  return cache;
+}
+
+/* Free the space used by CACHE.  */
+
+static void
+free_symbol_cache (struct symbol_cache *cache)
+{
+  xfree (cache->global_symbols);
+  xfree (cache->static_symbols);
+  xfree (cache);
+}
+
+/* Return the symbol cache of PSPACE.
+   Create one if it doesn't exist yet.  */
+
+static struct symbol_cache *
+get_symbol_cache (struct program_space *pspace)
+{
+  struct symbol_cache *cache = program_space_data (pspace, symbol_cache_key);
+
+  if (cache == NULL)
+    {
+      cache = make_symbol_cache (symbol_cache_size);
+      set_program_space_data (pspace, symbol_cache_key, cache);
+    }
+
+  return cache;
+}
+
+/* Delete the symbol cache of PSPACE.
+   Called when PSPACE is destroyed.  */
+
+static void
+symbol_cache_cleanup (struct program_space *pspace, void *data)
+{
+  struct symbol_cache *cache = data;
+
+  free_symbol_cache (cache);
+}
+
+/* Set the size of the symbol cache in all program spaces.  */
+
+static void
+set_symbol_cache_size (unsigned int new_size)
+{
+  struct program_space *pspace;
+
+  ALL_PSPACES (pspace)
+    {
+      struct symbol_cache *cache
+       = program_space_data (pspace, symbol_cache_key);
+
+      /* The pspace could have been created but not have a cache yet.  */
+      if (cache != NULL)
+       resize_symbol_cache (cache, new_size);
+    }
+}
+
+/* Called when symbol-cache-size is set.  */
+
+static void
+set_symbol_cache_size_handler (char *args, int from_tty,
+                              struct cmd_list_element *c)
+{
+  if (new_symbol_cache_size > MAX_SYMBOL_CACHE_SIZE)
+    {
+      /* Restore the previous value.
+        This is the value the "show" command prints.  */
+      new_symbol_cache_size = symbol_cache_size;
+
+      error (_("Symbol cache size is too large, max is %u."),
+            MAX_SYMBOL_CACHE_SIZE);
+    }
+  symbol_cache_size = new_symbol_cache_size;
+
+  set_symbol_cache_size (symbol_cache_size);
+}
+
+/* Lookup symbol NAME,DOMAIN in BLOCK in the symbol cache of PSPACE.
+   OBJFILE_CONTEXT is the current objfile, which may be NULL.
+   The result is the symbol if found, SYMBOL_LOOKUP_FAILED if a previous lookup
+   failed (and thus this one will too), or NULL if the symbol is not present
+   in the cache.
+   *BSC_PTR, *SLOT_PTR are set to the cache and slot of the symbol, whether
+   found or not found.  */
+
+static struct symbol *
+symbol_cache_lookup (struct symbol_cache *cache,
+                    struct objfile *objfile_context, int block,
+                    const char *name, domain_enum domain,
+                    struct block_symbol_cache **bsc_ptr,
+                    struct symbol_cache_slot **slot_ptr)
+{
+  struct block_symbol_cache *bsc;
+  unsigned int hash;
+  struct symbol_cache_slot *slot;
+
+  if (block == GLOBAL_BLOCK)
+    bsc = cache->global_symbols;
+  else
+    bsc = cache->static_symbols;
+  if (bsc == NULL)
+    {
+      *bsc_ptr = NULL;
+      *slot_ptr = NULL;
+      return NULL;
+    }
+
+  hash = hash_symbol_entry (objfile_context, name, domain);
+  slot = bsc->symbols + hash % bsc->size;
+  *bsc_ptr = bsc;
+  *slot_ptr = slot;
+
+  if (eq_symbol_entry (slot, objfile_context, name, domain))
+    {
+      if (symbol_lookup_debug)
+       fprintf_unfiltered (gdb_stdlog,
+                           "%s block symbol cache hit%s for %s, %s\n",
+                           block == GLOBAL_BLOCK ? "Global" : "Static",
+                           slot->state == SYMBOL_SLOT_NOT_FOUND
+                           ? " (not found)" : "",
+                           name, domain_name (domain));
+      ++bsc->hits;
+      if (slot->state == SYMBOL_SLOT_NOT_FOUND)
+       return SYMBOL_LOOKUP_FAILED;
+      return slot->value.found;
+    }
+
+  if (symbol_lookup_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "%s block symbol cache miss for %s, %s\n",
+                         block == GLOBAL_BLOCK ? "Global" : "Static",
+                         name, domain_name (domain));
+    }
+  ++bsc->misses;
+  return NULL;
+}
+
+/* Clear out SLOT.  */
+
+static void
+symbol_cache_clear_slot (struct symbol_cache_slot *slot)
+{
+  if (slot->state == SYMBOL_SLOT_NOT_FOUND)
+    xfree (slot->value.not_found.name);
+  slot->state = SYMBOL_SLOT_UNUSED;
+}
+
+/* Mark SYMBOL as found in SLOT.
+   OBJFILE_CONTEXT is the current objfile when the lookup was done, or NULL
+   if it's not needed to distinguish lookups (STATIC_BLOCK).  It is *not*
+   necessarily the objfile the symbol was found in.  */
+
+static void
+symbol_cache_mark_found (struct block_symbol_cache *bsc,
+                        struct symbol_cache_slot *slot,
+                        struct objfile *objfile_context,
+                        struct symbol *symbol)
+{
+  if (bsc == NULL)
+    return;
+  if (slot->state != SYMBOL_SLOT_UNUSED)
+    {
+      ++bsc->collisions;
+      symbol_cache_clear_slot (slot);
+    }
+  slot->state = SYMBOL_SLOT_FOUND;
+  slot->objfile_context = objfile_context;
+  slot->value.found = symbol;
+}
+
+/* Mark symbol NAME, DOMAIN as not found in SLOT.
+   OBJFILE_CONTEXT is the current objfile when the lookup was done, or NULL
+   if it's not needed to distinguish lookups (STATIC_BLOCK).  */
+
+static void
+symbol_cache_mark_not_found (struct block_symbol_cache *bsc,
+                            struct symbol_cache_slot *slot,
+                            struct objfile *objfile_context,
+                            const char *name, domain_enum domain)
+{
+  if (bsc == NULL)
+    return;
+  if (slot->state != SYMBOL_SLOT_UNUSED)
+    {
+      ++bsc->collisions;
+      symbol_cache_clear_slot (slot);
+    }
+  slot->state = SYMBOL_SLOT_NOT_FOUND;
+  slot->objfile_context = objfile_context;
+  slot->value.not_found.name = xstrdup (name);
+  slot->value.not_found.domain = domain;
+}
+
+/* Flush the symbol cache of PSPACE.  */
+
+static void
+symbol_cache_flush (struct program_space *pspace)
+{
+  struct symbol_cache *cache = program_space_data (pspace, symbol_cache_key);
+  int pass;
+  size_t total_size;
+
+  if (cache == NULL)
+    return;
+  if (cache->global_symbols == NULL)
+    {
+      gdb_assert (symbol_cache_size == 0);
+      gdb_assert (cache->static_symbols == NULL);
+      return;
+    }
+
+  /* If the cache is untouched since the last flush, early exit.
+     This is important for performance during the startup of a program linked
+     with 100s (or 1000s) of shared libraries.  */
+  if (cache->global_symbols->misses == 0
+      && cache->static_symbols->misses == 0)
+    return;
+
+  gdb_assert (cache->global_symbols->size == symbol_cache_size);
+  gdb_assert (cache->static_symbols->size == symbol_cache_size);
+
+  for (pass = 0; pass < 2; ++pass)
+    {
+      struct block_symbol_cache *bsc
+       = pass == 0 ? cache->global_symbols : cache->static_symbols;
+      unsigned int i;
+
+      for (i = 0; i < bsc->size; ++i)
+       symbol_cache_clear_slot (&bsc->symbols[i]);
+    }
+
+  cache->global_symbols->hits = 0;
+  cache->global_symbols->misses = 0;
+  cache->global_symbols->collisions = 0;
+  cache->static_symbols->hits = 0;
+  cache->static_symbols->misses = 0;
+  cache->static_symbols->collisions = 0;
+}
+
+/* Dump CACHE.  */
+
+static void
+symbol_cache_dump (const struct symbol_cache *cache)
+{
+  int pass;
+
+  if (cache->global_symbols == NULL)
+    {
+      printf_filtered ("  <disabled>\n");
+      return;
+    }
+
+  for (pass = 0; pass < 2; ++pass)
+    {
+      const struct block_symbol_cache *bsc
+       = pass == 0 ? cache->global_symbols : cache->static_symbols;
+      unsigned int i;
+
+      if (pass == 0)
+       printf_filtered ("Global symbols:\n");
+      else
+       printf_filtered ("Static symbols:\n");
+
+      for (i = 0; i < bsc->size; ++i)
+       {
+         const struct symbol_cache_slot *slot = &bsc->symbols[i];
+
+         QUIT;
+
+         switch (slot->state)
+           {
+           case SYMBOL_SLOT_UNUSED:
+             break;
+           case SYMBOL_SLOT_NOT_FOUND:
+             printf_filtered ("  [%-4u] = %s, %s (not found)\n", i,
+                              host_address_to_string (slot->objfile_context),
+                              slot->value.not_found.name);
+             break;
+           case SYMBOL_SLOT_FOUND:
+             printf_filtered ("  [%-4u] = %s, %s\n", i,
+                              host_address_to_string (slot->objfile_context),
+                              SYMBOL_PRINT_NAME (slot->value.found));
+             break;
+           }
+       }
+    }
+}
+
+/* The "mt print symbol-cache" command.  */
+
+static void
+maintenance_print_symbol_cache (char *args, int from_tty)
+{
+  struct program_space *pspace;
+
+  ALL_PSPACES (pspace)
+    {
+      struct symbol_cache *cache;
+
+      printf_filtered (_("Symbol cache for pspace %d\n%s:\n"),
+                      pspace->num,
+                      pspace->symfile_object_file != NULL
+                      ? objfile_name (pspace->symfile_object_file)
+                      : "(no object file)");
+
+      /* If the cache hasn't been created yet, avoid creating one.  */
+      cache = program_space_data (pspace, symbol_cache_key);
+      if (cache == NULL)
+       printf_filtered ("  <empty>\n");
+      else
+       symbol_cache_dump (cache);
+    }
+}
+
+/* The "mt flush-symbol-cache" command.  */
+
+static void
+maintenance_flush_symbol_cache (char *args, int from_tty)
+{
+  struct program_space *pspace;
+
+  ALL_PSPACES (pspace)
+    {
+      symbol_cache_flush (pspace);
+    }
+}
+
+/* Print usage statistics of CACHE.  */
+
+static void
+symbol_cache_stats (struct symbol_cache *cache)
+{
+  int pass;
+
+  if (cache->global_symbols == NULL)
+    {
+      printf_filtered ("  <disabled>\n");
+      return;
+    }
+
+  for (pass = 0; pass < 2; ++pass)
+    {
+      const struct block_symbol_cache *bsc
+       = pass == 0 ? cache->global_symbols : cache->static_symbols;
+
+      QUIT;
+
+      if (pass == 0)
+       printf_filtered ("Global block cache stats:\n");
+      else
+       printf_filtered ("Static block cache stats:\n");
+
+      printf_filtered ("  size:       %u\n", bsc->size);
+      printf_filtered ("  hits:       %u\n", bsc->hits);
+      printf_filtered ("  misses:     %u\n", bsc->misses);
+      printf_filtered ("  collisions: %u\n", bsc->collisions);
+    }
+}
+
+/* The "mt print symbol-cache-statistics" command.  */
+
+static void
+maintenance_print_symbol_cache_statistics (char *args, int from_tty)
+{
+  struct program_space *pspace;
+
+  ALL_PSPACES (pspace)
+    {
+      struct symbol_cache *cache;
+
+      printf_filtered (_("Symbol cache statistics for pspace %d\n%s:\n"),
+                      pspace->num,
+                      pspace->symfile_object_file != NULL
+                      ? objfile_name (pspace->symfile_object_file)
+                      : "(no object file)");
+
+      /* If the cache hasn't been created yet, avoid creating one.  */
+      cache = program_space_data (pspace, symbol_cache_key);
+      if (cache == NULL)
+       printf_filtered ("  empty, no stats available\n");
+      else
+       symbol_cache_stats (cache);
+    }
+}
+
+/* This module's 'new_objfile' observer.  */
+
+static void
+symtab_new_objfile_observer (struct objfile *objfile)
+{
+  /* Ideally we'd use OBJFILE->pspace, but OBJFILE may be NULL.  */
+  symbol_cache_flush (current_program_space);
+}
+
+/* This module's 'free_objfile' observer.  */
+
+static void
+symtab_free_objfile_observer (struct objfile *objfile)
+{
+  symbol_cache_flush (objfile->pspace);
+}
+\f
 /* Debug symbols usually don't have section information.  We need to dig that
    out of the minimal symbols and stash that in the debug symbol.  */
 
@@ -1169,12 +1799,15 @@ fixup_symbol_section (struct symbol *sym, struct objfile *objfile)
   if (!sym)
     return NULL;
 
+  if (!SYMBOL_OBJFILE_OWNED (sym))
+    return sym;
+
   /* We either have an OBJFILE, or we can get at it from the sym's
      symtab.  Anything else is a bug.  */
-  gdb_assert (objfile || SYMBOL_SYMTAB (sym));
+  gdb_assert (objfile || symbol_symtab (sym));
 
   if (objfile == NULL)
-    objfile = SYMBOL_SYMTAB (sym)->objfile;
+    objfile = symbol_objfile (sym);
 
   if (SYMBOL_OBJ_SECTION (objfile, sym))
     return sym;
@@ -1335,6 +1968,16 @@ lookup_language_this (const struct language_defn *lang,
   if (lang->la_name_of_this == NULL || block == NULL)
     return NULL;
 
+  if (symbol_lookup_debug > 1)
+    {
+      struct objfile *objfile = lookup_objfile_from_block (block);
+
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_language_this (%s, %s (objfile %s))",
+                         lang->la_name, host_address_to_string (block),
+                         objfile_debug_name (objfile));
+    }
+
   while (block)
     {
       struct symbol *sym;
@@ -1342,6 +1985,13 @@ lookup_language_this (const struct language_defn *lang,
       sym = block_lookup_symbol (block, lang->la_name_of_this, VAR_DOMAIN);
       if (sym != NULL)
        {
+         if (symbol_lookup_debug > 1)
+           {
+             fprintf_unfiltered (gdb_stdlog, " = %s (%s, block %s)\n",
+                                 SYMBOL_PRINT_NAME (sym),
+                                 host_address_to_string (sym),
+                                 host_address_to_string (block));
+           }
          block_found = block;
          return sym;
        }
@@ -1350,6 +2000,8 @@ lookup_language_this (const struct language_defn *lang,
       block = BLOCK_SUPERBLOCK (block);
     }
 
+  if (symbol_lookup_debug > 1)
+    fprintf_unfiltered (gdb_stdlog, " = NULL\n");
   return NULL;
 }
 
@@ -1409,6 +2061,25 @@ lookup_symbol_aux (const char *name, const struct block *block,
   struct symbol *sym;
   const struct language_defn *langdef;
 
+  if (symbol_lookup_debug)
+    {
+      struct objfile *objfile = lookup_objfile_from_block (block);
+
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_aux (%s, %s (objfile %s), %s, %s)\n",
+                         name, host_address_to_string (block),
+                         objfile != NULL
+                         ? objfile_debug_name (objfile) : "NULL",
+                         domain_name (domain), language_str (language));
+    }
+
+  /* Initialize block_found so that the language la_lookup_symbol_nonlocal
+     routines don't have to set it (to NULL) if a primitive type is found.
+     We do this early so that block_found is also NULL if no symbol is
+     found (though this is not part of the API, and callers cannot assume
+     this).  */
+  block_found = NULL;
+
   /* Make sure we do something sensible with is_a_field_of_this, since
      the callers that set this parameter to some non-null value will
      certainly use it later.  If we don't set it, the contents of
@@ -1421,7 +2092,14 @@ lookup_symbol_aux (const char *name, const struct block *block,
 
   sym = lookup_local_symbol (name, block, domain, language);
   if (sym != NULL)
-    return sym;
+    {
+      if (symbol_lookup_debug)
+       {
+         fprintf_unfiltered (gdb_stdlog, "lookup_symbol_aux (...) = %s\n",
+                             host_address_to_string (sym));
+       }
+      return sym;
+    }
 
   /* If requested to do so by the caller and if appropriate for LANGUAGE,
      check to see if NAME is a field of `this'.  */
@@ -1452,21 +2130,41 @@ lookup_symbol_aux (const char *name, const struct block *block,
                   langdef->la_name_of_this);
 
          if (check_field (t, name, is_a_field_of_this))
-           return NULL;
+           {
+             if (symbol_lookup_debug)
+               {
+                 fprintf_unfiltered (gdb_stdlog,
+                                     "lookup_symbol_aux (...) = NULL\n");
+               }
+             return NULL;
+           }
        }
     }
 
   /* Now do whatever is appropriate for LANGUAGE to look
      up static and global variables.  */
 
-  sym = langdef->la_lookup_symbol_nonlocal (name, block, domain);
+  sym = langdef->la_lookup_symbol_nonlocal (langdef, name, block, domain);
   if (sym != NULL)
-    return sym;
+    {
+      if (symbol_lookup_debug)
+       {
+         fprintf_unfiltered (gdb_stdlog, "lookup_symbol_aux (...) = %s\n",
+                             host_address_to_string (sym));
+       }
+      return sym;
+    }
 
   /* Now search all static file-level symbols.  Not strictly correct,
      but more useful than an error.  */
 
-  return lookup_static_symbol (name, domain);
+  sym = lookup_static_symbol (name, domain);
+  if (symbol_lookup_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog, "lookup_symbol_aux (...) = %s\n",
+                         sym != NULL ? host_address_to_string (sym) : "NULL");
+    }
+  return sym;
 }
 
 /* Check to see if the symbol is defined in BLOCK or its superiors.
@@ -1516,17 +2214,16 @@ struct objfile *
 lookup_objfile_from_block (const struct block *block)
 {
   struct objfile *obj;
-  struct symtab *s;
+  struct compunit_symtab *cust;
 
   if (block == NULL)
     return NULL;
 
   block = block_global_block (block);
-  /* Go through SYMTABS.
-     Non-primary symtabs share the block vector with their primary symtabs
-     so we use ALL_PRIMARY_SYMTABS here instead of ALL_SYMTABS.  */
-  ALL_PRIMARY_SYMTABS (obj, s)
-    if (block == BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK))
+  /* Look through all blockvectors.  */
+  ALL_COMPUNITS (obj, cust)
+    if (block == BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust),
+                                   GLOBAL_BLOCK))
       {
        if (obj->separate_debug_objfile_backlink)
          obj = obj->separate_debug_objfile_backlink;
@@ -1545,49 +2242,51 @@ lookup_symbol_in_block (const char *name, const struct block *block,
 {
   struct symbol *sym;
 
+  if (symbol_lookup_debug > 1)
+    {
+      struct objfile *objfile = lookup_objfile_from_block (block);
+
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_in_block (%s, %s (objfile %s), %s)",
+                         name, host_address_to_string (block),
+                         objfile_debug_name (objfile),
+                         domain_name (domain));
+    }
+
   sym = block_lookup_symbol (block, name, domain);
   if (sym)
     {
+      if (symbol_lookup_debug > 1)
+       {
+         fprintf_unfiltered (gdb_stdlog, " = %s\n",
+                             host_address_to_string (sym));
+       }
       block_found = block;
       return fixup_symbol_section (sym, NULL);
     }
 
+  if (symbol_lookup_debug > 1)
+    fprintf_unfiltered (gdb_stdlog, " = NULL\n");
   return NULL;
 }
 
 /* See symtab.h.  */
 
 struct symbol *
-lookup_global_symbol_from_objfile (const struct objfile *main_objfile,
+lookup_global_symbol_from_objfile (struct objfile *main_objfile,
                                   const char *name,
                                   const domain_enum domain)
 {
-  const struct objfile *objfile;
-  struct symbol *sym;
-  const struct blockvector *bv;
-  const struct block *block;
-  struct symtab *s;
+  struct objfile *objfile;
 
   for (objfile = main_objfile;
        objfile;
        objfile = objfile_separate_debug_iterate (main_objfile, objfile))
     {
-      /* Go through symtabs.  */
-      ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s)
-       {
-         bv = BLOCKVECTOR (s);
-         block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
-         sym = block_lookup_symbol (block, name, domain);
-         if (sym)
-           {
-             block_found = block;
-             return fixup_symbol_section (sym, (struct objfile *)objfile);
-           }
-       }
+      struct symbol *sym = lookup_symbol_in_objfile (objfile, GLOBAL_BLOCK,
+                                                    name, domain);
 
-      sym = lookup_symbol_via_quick_fns ((struct objfile *) objfile,
-                                        GLOBAL_BLOCK, name, domain);
-      if (sym)
+      if (sym != NULL)
        return sym;
     }
 
@@ -1603,29 +2302,55 @@ static struct symbol *
 lookup_symbol_in_objfile_symtabs (struct objfile *objfile, int block_index,
                                  const char *name, const domain_enum domain)
 {
-  struct symbol *sym = NULL;
-  const struct blockvector *bv;
-  const struct block *block;
-  struct symtab *s;
+  struct compunit_symtab *cust;
+
+  gdb_assert (block_index == GLOBAL_BLOCK || block_index == STATIC_BLOCK);
+
+  if (symbol_lookup_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_in_objfile_symtabs (%s, %s, %s, %s)",
+                         objfile_debug_name (objfile),
+                         block_index == GLOBAL_BLOCK
+                         ? "GLOBAL_BLOCK" : "STATIC_BLOCK",
+                         name, domain_name (domain));
+    }
 
-  ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s)
+  ALL_OBJFILE_COMPUNITS (objfile, cust)
     {
-      bv = BLOCKVECTOR (s);
+      const struct blockvector *bv;
+      const struct block *block;
+      struct symbol *sym;
+
+      bv = COMPUNIT_BLOCKVECTOR (cust);
       block = BLOCKVECTOR_BLOCK (bv, block_index);
-      sym = block_lookup_symbol (block, name, domain);
+      sym = block_lookup_symbol_primary (block, name, domain);
       if (sym)
        {
+         if (symbol_lookup_debug > 1)
+           {
+             fprintf_unfiltered (gdb_stdlog, " = %s (block %s)\n",
+                                 host_address_to_string (sym),
+                                 host_address_to_string (block));
+           }
          block_found = block;
          return fixup_symbol_section (sym, objfile);
        }
     }
 
+  if (symbol_lookup_debug > 1)
+    fprintf_unfiltered (gdb_stdlog, " = NULL\n");
   return NULL;
 }
 
 /* Wrapper around lookup_symbol_in_objfile_symtabs for search_symbols.
    Look up LINKAGE_NAME in DOMAIN in the global and static blocks of OBJFILE
-   and all related objfiles.  */
+   and all associated separate debug objfiles.
+
+   Normally we only look in OBJFILE, and not any separate debug objfiles
+   because the outer loop will cause them to be searched too.  This case is
+   different.  Here we're called from search_symbols where it will only
+   call us for the the objfile that contains a matching minsym.  */
 
 static struct symbol *
 lookup_symbol_in_objfile_from_linkage_name (struct objfile *objfile,
@@ -1670,14 +2395,16 @@ lookup_symbol_in_objfile_from_linkage_name (struct objfile *objfile,
 
 static void ATTRIBUTE_NORETURN
 error_in_psymtab_expansion (int block_index, const char *name,
-                           struct symtab *symtab)
+                           struct compunit_symtab *cust)
 {
   error (_("\
 Internal: %s symbol `%s' found in %s psymtab but not in symtab.\n\
 %s may be an inlined function, or may be a template function\n  \
 (if a template, try specifying an instantiation: %s<type>)."),
         block_index == GLOBAL_BLOCK ? "global" : "static",
-        name, symtab_to_filename_for_display (symtab), name, name);
+        name,
+        symtab_to_filename_for_display (compunit_primary_filetab (cust)),
+        name, name);
 }
 
 /* A helper function for various lookup routines that interfaces with
@@ -1687,22 +2414,49 @@ static struct symbol *
 lookup_symbol_via_quick_fns (struct objfile *objfile, int block_index,
                             const char *name, const domain_enum domain)
 {
-  struct symtab *symtab;
+  struct compunit_symtab *cust;
   const struct blockvector *bv;
   const struct block *block;
   struct symbol *sym;
 
   if (!objfile->sf)
     return NULL;
-  symtab = objfile->sf->qf->lookup_symbol (objfile, block_index, name, domain);
-  if (!symtab)
-    return NULL;
 
-  bv = BLOCKVECTOR (symtab);
+  if (symbol_lookup_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_via_quick_fns (%s, %s, %s, %s)\n",
+                         objfile_debug_name (objfile),
+                         block_index == GLOBAL_BLOCK
+                         ? "GLOBAL_BLOCK" : "STATIC_BLOCK",
+                         name, domain_name (domain));
+    }
+
+  cust = objfile->sf->qf->lookup_symbol (objfile, block_index, name, domain);
+  if (cust == NULL)
+    {
+      if (symbol_lookup_debug > 1)
+       {
+         fprintf_unfiltered (gdb_stdlog,
+                             "lookup_symbol_via_quick_fns (...) = NULL\n");
+       }
+      return NULL;
+    }
+
+  bv = COMPUNIT_BLOCKVECTOR (cust);
   block = BLOCKVECTOR_BLOCK (bv, block_index);
   sym = block_lookup_symbol (block, name, domain);
   if (!sym)
-    error_in_psymtab_expansion (block_index, name, symtab);
+    error_in_psymtab_expansion (block_index, name, cust);
+
+  if (symbol_lookup_debug > 1)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_via_quick_fns (...) = %s (block %s)\n",
+                         host_address_to_string (sym),
+                         host_address_to_string (block));
+    }
+
   block_found = block;
   return fixup_symbol_section (sym, objfile);
 }
@@ -1710,7 +2464,8 @@ lookup_symbol_via_quick_fns (struct objfile *objfile, int block_index,
 /* See symtab.h.  */
 
 struct symbol *
-basic_lookup_symbol_nonlocal (const char *name,
+basic_lookup_symbol_nonlocal (const struct language_defn *langdef,
+                             const char *name,
                              const struct block *block,
                              const domain_enum domain)
 {
@@ -1752,6 +2507,25 @@ basic_lookup_symbol_nonlocal (const char *name,
   if (sym != NULL)
     return sym;
 
+  /* If we didn't find a definition for a builtin type in the static block,
+     search for it now.  This is actually the right thing to do and can be
+     a massive performance win.  E.g., when debugging a program with lots of
+     shared libraries we could search all of them only to find out the
+     builtin type isn't defined in any of them.  This is common for types
+     like "void".  */
+  if (domain == VAR_DOMAIN)
+    {
+      struct gdbarch *gdbarch;
+
+      if (block == NULL)
+       gdbarch = target_gdbarch ();
+      else
+       gdbarch = block_gdbarch (block);
+      sym = language_lookup_primitive_type_as_symbol (langdef, gdbarch, name);
+      if (sym != NULL)
+       return sym;
+    }
+
   return lookup_global_symbol (name, block, domain);
 }
 
@@ -1763,11 +2537,32 @@ lookup_symbol_in_static_block (const char *name,
                               const domain_enum domain)
 {
   const struct block *static_block = block_static_block (block);
+  struct symbol *sym;
 
-  if (static_block != NULL)
-    return lookup_symbol_in_block (name, static_block, domain);
-  else
+  if (static_block == NULL)
     return NULL;
+
+  if (symbol_lookup_debug)
+    {
+      struct objfile *objfile = lookup_objfile_from_block (static_block);
+
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_in_static_block (%s, %s (objfile %s),"
+                         " %s)\n",
+                         name,
+                         host_address_to_string (block),
+                         objfile_debug_name (objfile),
+                         domain_name (domain));
+    }
+
+  sym = lookup_symbol_in_block (name, static_block, domain);
+  if (symbol_lookup_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_in_static_block (...) = %s\n",
+                         sym != NULL ? host_address_to_string (sym) : "NULL");
+    }
+  return sym;
 }
 
 /* Perform the standard symbol lookup of NAME in OBJFILE:
@@ -1781,14 +2576,41 @@ lookup_symbol_in_objfile (struct objfile *objfile, int block_index,
 {
   struct symbol *result;
 
+  if (symbol_lookup_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_in_objfile (%s, %s, %s, %s)\n",
+                         objfile_debug_name (objfile),
+                         block_index == GLOBAL_BLOCK
+                         ? "GLOBAL_BLOCK" : "STATIC_BLOCK",
+                         name, domain_name (domain));
+    }
+
   result = lookup_symbol_in_objfile_symtabs (objfile, block_index,
                                             name, domain);
-  if (result == NULL)
+  if (result != NULL)
     {
-      result = lookup_symbol_via_quick_fns (objfile, block_index,
-                                           name, domain);
+      if (symbol_lookup_debug)
+       {
+         fprintf_unfiltered (gdb_stdlog,
+                             "lookup_symbol_in_objfile (...) = %s"
+                             " (in symtabs)\n",
+                             host_address_to_string (result));
+       }
+      return result;
     }
 
+  result = lookup_symbol_via_quick_fns (objfile, block_index,
+                                       name, domain);
+  if (symbol_lookup_debug)
+    {
+      fprintf_unfiltered (gdb_stdlog,
+                         "lookup_symbol_in_objfile (...) = %s%s\n",
+                         result != NULL
+                         ? host_address_to_string (result)
+                         : "NULL",
+                         result != NULL ? " (via quick fns)" : "");
+    }
   return result;
 }
 
@@ -1797,16 +2619,36 @@ lookup_symbol_in_objfile (struct objfile *objfile, int block_index,
 struct symbol *
 lookup_static_symbol (const char *name, const domain_enum domain)
 {
+  struct symbol_cache *cache = get_symbol_cache (current_program_space);
   struct objfile *objfile;
   struct symbol *result;
+  struct block_symbol_cache *bsc;
+  struct symbol_cache_slot *slot;
+
+  /* Lookup in STATIC_BLOCK is not current-objfile-dependent, so just pass
+     NULL for OBJFILE_CONTEXT.  */
+  result = symbol_cache_lookup (cache, NULL, STATIC_BLOCK, name, domain,
+                               &bsc, &slot);
+  if (result != NULL)
+    {
+      if (result == SYMBOL_LOOKUP_FAILED)
+       return NULL;
+      return result;
+    }
 
   ALL_OBJFILES (objfile)
     {
       result = lookup_symbol_in_objfile (objfile, STATIC_BLOCK, name, domain);
       if (result != NULL)
-       return result;
+       {
+         /* Still pass NULL for OBJFILE_CONTEXT here.  */
+         symbol_cache_mark_found (bsc, slot, NULL, result);
+         return result;
+       }
     }
 
+  /* Still pass NULL for OBJFILE_CONTEXT here.  */
+  symbol_cache_mark_not_found (bsc, slot, NULL, name, domain);
   return NULL;
 }
 
@@ -1854,25 +2696,48 @@ lookup_global_symbol (const char *name,
                      const struct block *block,
                      const domain_enum domain)
 {
-  struct symbol *sym = NULL;
-  struct objfile *objfile = NULL;
+  struct symbol_cache *cache = get_symbol_cache (current_program_space);
+  struct symbol *sym;
+  struct objfile *objfile;
   struct global_sym_lookup_data lookup_data;
+  struct block_symbol_cache *bsc;
+  struct symbol_cache_slot *slot;
 
-  /* Call library-specific lookup procedure.  */
   objfile = lookup_objfile_from_block (block);
+
+  /* First see if we can find the symbol in the cache.
+     This works because we use the current objfile to qualify the lookup.  */
+  sym = symbol_cache_lookup (cache, objfile, GLOBAL_BLOCK, name, domain,
+                            &bsc, &slot);
+  if (sym != NULL)
+    {
+      if (sym == SYMBOL_LOOKUP_FAILED)
+       return NULL;
+      return sym;
+    }
+
+  /* Call library-specific lookup procedure.  */
   if (objfile != NULL)
     sym = solib_global_lookup (objfile, name, domain);
-  if (sym != NULL)
-    return sym;
 
-  memset (&lookup_data, 0, sizeof (lookup_data));
-  lookup_data.name = name;
-  lookup_data.domain = domain;
-  gdbarch_iterate_over_objfiles_in_search_order
-    (objfile != NULL ? get_objfile_arch (objfile) : target_gdbarch (),
-     lookup_symbol_global_iterator_cb, &lookup_data, objfile);
+  /* If that didn't work go a global search (of global blocks, heh).  */
+  if (sym == NULL)
+    {
+      memset (&lookup_data, 0, sizeof (lookup_data));
+      lookup_data.name = name;
+      lookup_data.domain = domain;
+      gdbarch_iterate_over_objfiles_in_search_order
+       (objfile != NULL ? get_objfile_arch (objfile) : target_gdbarch (),
+        lookup_symbol_global_iterator_cb, &lookup_data, objfile);
+      sym = lookup_data.result;
+    }
+
+  if (sym != NULL)
+    symbol_cache_mark_found (bsc, slot, objfile, sym);
+  else
+    symbol_cache_mark_not_found (bsc, slot, objfile, name, domain);
 
-  return lookup_data.result;
+  return sym;
 }
 
 int
@@ -1911,23 +2776,23 @@ static struct type *
 basic_lookup_transparent_type_quick (struct objfile *objfile, int block_index,
                                     const char *name)
 {
-  struct symtab *symtab;
+  struct compunit_symtab *cust;
   const struct blockvector *bv;
   struct block *block;
   struct symbol *sym;
 
   if (!objfile->sf)
     return NULL;
-  symtab = objfile->sf->qf->lookup_symbol (objfile, block_index, name,
-                                          STRUCT_DOMAIN);
-  if (!symtab)
+  cust = objfile->sf->qf->lookup_symbol (objfile, block_index, name,
+                                        STRUCT_DOMAIN);
+  if (cust == NULL)
     return NULL;
 
-  bv = BLOCKVECTOR (symtab);
+  bv = COMPUNIT_BLOCKVECTOR (cust);
   block = BLOCKVECTOR_BLOCK (bv, block_index);
   sym = block_lookup_symbol (block, name, STRUCT_DOMAIN);
   if (!sym)
-    error_in_psymtab_expansion (block_index, name, symtab);
+    error_in_psymtab_expansion (block_index, name, cust);
 
   if (!TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
     return SYMBOL_TYPE (sym);
@@ -1945,7 +2810,7 @@ struct type *
 basic_lookup_transparent_type (const char *name)
 {
   struct symbol *sym;
-  struct symtab *s = NULL;
+  struct compunit_symtab *cust;
   const struct blockvector *bv;
   struct objfile *objfile;
   struct block *block;
@@ -1958,9 +2823,9 @@ basic_lookup_transparent_type (const char *name)
 
   ALL_OBJFILES (objfile)
   {
-    ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s)
+    ALL_OBJFILE_COMPUNITS (objfile, cust)
       {
-       bv = BLOCKVECTOR (s);
+       bv = COMPUNIT_BLOCKVECTOR (cust);
        block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
        sym = block_lookup_symbol (block, name, STRUCT_DOMAIN);
        if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
@@ -1986,9 +2851,9 @@ basic_lookup_transparent_type (const char *name)
 
   ALL_OBJFILES (objfile)
   {
-    ALL_OBJFILE_PRIMARY_SYMTABS (objfile, s)
+    ALL_OBJFILE_COMPUNITS (objfile, cust)
       {
-       bv = BLOCKVECTOR (s);
+       bv = COMPUNIT_BLOCKVECTOR (cust);
        block = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
        sym = block_lookup_symbol (block, name, STRUCT_DOMAIN);
        if (sym && !TYPE_IS_OPAQUE (SYMBOL_TYPE (sym)))
@@ -2036,16 +2901,14 @@ iterate_over_symbols (const struct block *block, const char *name,
     }
 }
 
-/* Find the symtab associated with PC and SECTION.  Look through the
-   psymtabs and read in another symtab if necessary.  */
+/* Find the compunit symtab associated with PC and SECTION.
+   This will read in debug info as necessary.  */
 
-struct symtab *
-find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
+struct compunit_symtab *
+find_pc_sect_compunit_symtab (CORE_ADDR pc, struct obj_section *section)
 {
-  struct block *b;
-  const struct blockvector *bv;
-  struct symtab *s = NULL;
-  struct symtab *best_s = NULL;
+  struct compunit_symtab *cust;
+  struct compunit_symtab *best_cust = NULL;
   struct objfile *objfile;
   CORE_ADDR distance = 0;
   struct bound_minimal_symbol msymbol;
@@ -2079,9 +2942,12 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
      It also happens for objfiles that have their functions reordered.
      For these, the symtab we are looking for is not necessarily read in.  */
 
-  ALL_PRIMARY_SYMTABS (objfile, s)
+  ALL_COMPUNITS (objfile, cust)
   {
-    bv = BLOCKVECTOR (s);
+    struct block *b;
+    const struct blockvector *bv;
+
+    bv = COMPUNIT_BLOCKVECTOR (cust);
     b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
 
     if (BLOCK_START (b) <= pc
@@ -2097,14 +2963,14 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
           can't be found.  */
        if ((objfile->flags & OBJF_REORDERED) && objfile->sf)
          {
-           struct symtab *result;
+           struct compunit_symtab *result;
 
            result
-             = objfile->sf->qf->find_pc_sect_symtab (objfile,
-                                                     msymbol,
-                                                     pc, section,
-                                                     0);
-           if (result)
+             = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile,
+                                                              msymbol,
+                                                              pc, section,
+                                                              0);
+           if (result != NULL)
              return result;
          }
        if (section != 0)
@@ -2124,39 +2990,40 @@ find_pc_sect_symtab (CORE_ADDR pc, struct obj_section *section)
                                   section.  */
          }
        distance = BLOCK_END (b) - BLOCK_START (b);
-       best_s = s;
+       best_cust = cust;
       }
   }
 
-  if (best_s != NULL)
-    return (best_s);
+  if (best_cust != NULL)
+    return best_cust;
 
   /* Not found in symtabs, search the "quick" symtabs (e.g. psymtabs).  */
 
   ALL_OBJFILES (objfile)
   {
-    struct symtab *result;
+    struct compunit_symtab *result;
 
     if (!objfile->sf)
       continue;
-    result = objfile->sf->qf->find_pc_sect_symtab (objfile,
-                                                  msymbol,
-                                                  pc, section,
-                                                  1);
-    if (result)
+    result = objfile->sf->qf->find_pc_sect_compunit_symtab (objfile,
+                                                           msymbol,
+                                                           pc, section,
+                                                           1);
+    if (result != NULL)
       return result;
   }
 
   return NULL;
 }
 
-/* Find the symtab associated with PC.  Look through the psymtabs and read
-   in another symtab if necessary.  Backward compatibility, no section.  */
+/* Find the compunit symtab associated with PC.
+   This will read in debug info as necessary.
+   Backward compatibility, no section.  */
 
-struct symtab *
-find_pc_symtab (CORE_ADDR pc)
+struct compunit_symtab *
+find_pc_compunit_symtab (CORE_ADDR pc)
 {
-  return find_pc_sect_symtab (pc, find_pc_mapped_section (pc));
+  return find_pc_sect_compunit_symtab (pc, find_pc_mapped_section (pc));
 }
 \f
 
@@ -2180,7 +3047,8 @@ find_pc_symtab (CORE_ADDR pc)
 struct symtab_and_line
 find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
 {
-  struct symtab *s;
+  struct compunit_symtab *cust;
+  struct symtab *iter_s;
   struct linetable *l;
   int len;
   int i;
@@ -2188,7 +3056,6 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
   struct symtab_and_line val;
   const struct blockvector *bv;
   struct bound_minimal_symbol msymbol;
-  struct objfile *objfile;
 
   /* Info on best line seen so far, and where it starts, and its file.  */
 
@@ -2306,8 +3173,8 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
       }
 
 
-  s = find_pc_sect_symtab (pc, section);
-  if (!s)
+  cust = find_pc_sect_compunit_symtab (pc, section);
+  if (cust == NULL)
     {
       /* If no symbol information, return previous pc.  */
       if (notcurrent)
@@ -2316,20 +3183,16 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
       return val;
     }
 
-  bv = BLOCKVECTOR (s);
-  objfile = s->objfile;
+  bv = COMPUNIT_BLOCKVECTOR (cust);
 
   /* Look at all the symtabs that share this blockvector.
      They all have the same apriori range, that we found was right;
      but they have different line tables.  */
 
-  ALL_OBJFILE_SYMTABS (objfile, s)
+  ALL_COMPUNIT_FILETABS (cust, iter_s)
     {
-      if (BLOCKVECTOR (s) != bv)
-       continue;
-
       /* Find the best line in this symtab.  */
-      l = LINETABLE (s);
+      l = SYMTAB_LINETABLE (iter_s);
       if (!l)
        continue;
       len = l->nitems;
@@ -2373,7 +3236,7 @@ find_pc_sect_line (CORE_ADDR pc, struct obj_section *section, int notcurrent)
       if (prev && prev->line && (!best || prev->pc > best->pc))
        {
          best = prev;
-         best_symtab = s;
+         best_symtab = iter_s;
 
          /* Discard BEST_END if it's before the PC of the current BEST.  */
          if (best_end <= best->pc)
@@ -2431,6 +3294,19 @@ find_pc_line (CORE_ADDR pc, int notcurrent)
     pc = overlay_mapped_address (pc, section);
   return find_pc_sect_line (pc, section, notcurrent);
 }
+
+/* See symtab.h.  */
+
+struct symtab *
+find_pc_line_symtab (CORE_ADDR pc)
+{
+  struct symtab_and_line sal;
+
+  /* This always passes zero for NOTCURRENT to find_pc_line.
+     There are currently no callers that ever pass non-zero.  */
+  sal = find_pc_line (pc, 0);
+  return sal.symtab;
+}
 \f
 /* Find line number LINE in any symtab whose name is the same as
    SYMTAB.
@@ -2456,7 +3332,7 @@ find_line_symtab (struct symtab *symtab, int line,
   struct symtab *best_symtab;
 
   /* First try looking it up in the given symtab.  */
-  best_linetable = LINETABLE (symtab);
+  best_linetable = SYMTAB_LINETABLE (symtab);
   best_symtab = symtab;
   best_index = find_line_common (best_linetable, line, &exact, 0);
   if (best_index < 0 || !exact)
@@ -2474,6 +3350,7 @@ find_line_symtab (struct symtab *symtab, int line,
       int best;
 
       struct objfile *objfile;
+      struct compunit_symtab *cu;
       struct symtab *s;
 
       if (best_index >= 0)
@@ -2488,7 +3365,7 @@ find_line_symtab (struct symtab *symtab, int line,
                                                   symtab_to_fullname (symtab));
       }
 
-      ALL_SYMTABS (objfile, s)
+      ALL_FILETABS (objfile, cu, s)
       {
        struct linetable *l;
        int ind;
@@ -2498,7 +3375,7 @@ find_line_symtab (struct symtab *symtab, int line,
        if (FILENAME_CMP (symtab_to_fullname (symtab),
                          symtab_to_fullname (s)) != 0)
          continue;     
-       l = LINETABLE (s);
+       l = SYMTAB_LINETABLE (s);
        ind = find_line_common (l, line, &exact, 0);
        if (ind >= 0)
          {
@@ -2548,13 +3425,14 @@ find_pcs_for_symtab_line (struct symtab *symtab, int line,
       int was_exact;
       int idx;
 
-      idx = find_line_common (LINETABLE (symtab), line, &was_exact, start);
+      idx = find_line_common (SYMTAB_LINETABLE (symtab), line, &was_exact,
+                             start);
       if (idx < 0)
        break;
 
       if (!was_exact)
        {
-         struct linetable_entry *item = &LINETABLE (symtab)->item[idx];
+         struct linetable_entry *item = &SYMTAB_LINETABLE (symtab)->item[idx];
 
          if (*best_item == NULL || item->line < (*best_item)->line)
            *best_item = item;
@@ -2562,7 +3440,8 @@ find_pcs_for_symtab_line (struct symtab *symtab, int line,
          break;
        }
 
-      VEC_safe_push (CORE_ADDR, result, LINETABLE (symtab)->item[idx].pc);
+      VEC_safe_push (CORE_ADDR, result,
+                    SYMTAB_LINETABLE (symtab)->item[idx].pc);
       start = idx + 1;
     }
 
@@ -2587,7 +3466,7 @@ find_line_pc (struct symtab *symtab, int line, CORE_ADDR *pc)
   symtab = find_line_symtab (symtab, line, &ind, NULL);
   if (symtab != NULL)
     {
-      l = LINETABLE (symtab);
+      l = SYMTAB_LINETABLE (symtab);
       *pc = l->item[ind].pc;
       return 1;
     }
@@ -2705,10 +3584,11 @@ struct symtab_and_line
 find_function_start_sal (struct symbol *sym, int funfirstline)
 {
   struct symtab_and_line sal;
+  struct obj_section *section;
 
   fixup_symbol_section (sym, NULL);
-  sal = find_pc_sect_line (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)),
-                          SYMBOL_OBJ_SECTION (SYMBOL_OBJFILE (sym), sym), 0);
+  section = SYMBOL_OBJ_SECTION (symbol_objfile (sym), sym);
+  sal = find_pc_sect_line (BLOCK_START (SYMBOL_BLOCK_VALUE (sym)), section, 0);
 
   /* We always should have a line for the function start address.
      If we don't, something is odd.  Create a plain SAL refering
@@ -2719,7 +3599,7 @@ find_function_start_sal (struct symbol *sym, int funfirstline)
       init_sal (&sal);
       sal.pspace = current_program_space;
       sal.pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
-      sal.section = SYMBOL_OBJ_SECTION (SYMBOL_OBJFILE (sym), sym);
+      sal.section = section;
     }
 
   if (funfirstline)
@@ -2741,7 +3621,7 @@ skip_prologue_using_lineinfo (CORE_ADDR func_addr, struct symtab *symtab)
   int i;
 
   /* Give up if this symbol has no lineinfo table.  */
-  l = LINETABLE (symtab);
+  l = SYMTAB_LINETABLE (symtab);
   if (l == NULL)
     return func_addr;
 
@@ -2799,10 +3679,10 @@ skip_prologue_sal (struct symtab_and_line *sal)
     {
       fixup_symbol_section (sym, NULL);
 
+      objfile = symbol_objfile (sym);
       pc = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
-      section = SYMBOL_OBJ_SECTION (SYMBOL_OBJFILE (sym), sym);
+      section = SYMBOL_OBJ_SECTION (objfile, sym);
       name = SYMBOL_LINKAGE_NAME (sym);
-      objfile = SYMBOL_SYMTAB (sym)->objfile;
     }
   else
     {
@@ -2834,7 +3714,8 @@ skip_prologue_sal (struct symtab_and_line *sal)
   /* Be conservative - allow direct PC (without skipping prologue) only if we
      have proven the CU (Compilation Unit) supports it.  sal->SYMTAB does not
      have to be set by the caller so we use SYM instead.  */
-  if (sym && SYMBOL_SYMTAB (sym)->locations_valid)
+  if (sym != NULL
+      && COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (symbol_symtab (sym))))
     force_skip = 0;
 
   saved_pc = pc;
@@ -2899,7 +3780,7 @@ skip_prologue_sal (struct symtab_and_line *sal)
      is aligned.  */
   if (!force_skip && sym && start_sal.symtab == NULL)
     {
-      pc = skip_prologue_using_lineinfo (pc, SYMBOL_SYMTAB (sym));
+      pc = skip_prologue_using_lineinfo (pc, symbol_symtab (sym));
       /* Recalculate the line number.  */
       start_sal = find_pc_sect_line (pc, section, 0);
     }
@@ -2939,7 +3820,7 @@ skip_prologue_sal (struct symtab_and_line *sal)
       && SYMBOL_LINE (BLOCK_FUNCTION (function_block)) != 0)
     {
       sal->line = SYMBOL_LINE (BLOCK_FUNCTION (function_block));
-      sal->symtab = SYMBOL_SYMTAB (BLOCK_FUNCTION (function_block));
+      sal->symtab = symbol_symtab (BLOCK_FUNCTION (function_block));
     }
 }
 
@@ -2982,7 +3863,7 @@ skip_prologue_using_sal (struct gdbarch *gdbarch, CORE_ADDR func_addr)
         do this.  */
       if (prologue_sal.symtab->language != language_asm)
        {
-         struct linetable *linetable = LINETABLE (prologue_sal.symtab);
+         struct linetable *linetable = SYMTAB_LINETABLE (prologue_sal.symtab);
          int idx = 0;
 
          /* Skip any earlier lines, and any end-of-sequence marker
@@ -3321,6 +4202,7 @@ output_partial_symbol_filename (const char *filename, const char *fullname,
 static void
 sources_info (char *ignore, int from_tty)
 {
+  struct compunit_symtab *cu;
   struct symtab *s;
   struct objfile *objfile;
   struct output_source_filename_data data;
@@ -3338,7 +4220,7 @@ sources_info (char *ignore, int from_tty)
   printf_filtered ("Source files for which symbols have been read in:\n\n");
 
   data.first = 1;
-  ALL_SYMTABS (objfile, s)
+  ALL_FILETABS (objfile, cu, s)
   {
     const char *fullname = symtab_to_fullname (s);
 
@@ -3420,7 +4302,8 @@ compare_search_syms (const void *sa, const void *sb)
   struct symbol_search *sym_b = *(struct symbol_search **) sb;
   int c;
 
-  c = FILENAME_CMP (sym_a->symtab->filename, sym_b->symtab->filename);
+  c = FILENAME_CMP (symbol_symtab (sym_a->symbol)->filename,
+                   symbol_symtab (sym_b->symbol)->filename);
   if (c != 0)
     return c;
 
@@ -3536,7 +4419,7 @@ search_symbols (const char *regexp, enum search_domain kind,
                int nfiles, const char *files[],
                struct symbol_search **matches)
 {
-  struct symtab *s;
+  struct compunit_symtab *cust;
   const struct blockvector *bv;
   struct block *b;
   int i = 0;
@@ -3676,10 +4559,10 @@ search_symbols (const char *regexp, enum search_domain kind,
              {
                /* Note: An important side-effect of these lookup functions
                   is to expand the symbol table if msymbol is found, for the
-                  benefit of the next loop on ALL_PRIMARY_SYMTABS.  */
+                  benefit of the next loop on ALL_COMPUNITS.  */
                if (kind == FUNCTIONS_DOMAIN
-                   ? find_pc_symtab (MSYMBOL_VALUE_ADDRESS (objfile,
-                                                            msymbol)) == NULL
+                   ? (find_pc_compunit_symtab
+                      (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) == NULL)
                    : (lookup_symbol_in_objfile_from_linkage_name
                       (objfile, MSYMBOL_LINKAGE_NAME (msymbol), VAR_DOMAIN)
                       == NULL))
@@ -3694,15 +4577,15 @@ search_symbols (const char *regexp, enum search_domain kind,
   nfound = 0;
   retval_chain = make_cleanup_free_search_symbols (&found);
 
-  ALL_PRIMARY_SYMTABS (objfile, s)
+  ALL_COMPUNITS (objfile, cust)
   {
-    bv = BLOCKVECTOR (s);
+    bv = COMPUNIT_BLOCKVECTOR (cust);
     for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
       {
        b = BLOCKVECTOR_BLOCK (bv, i);
        ALL_BLOCK_SYMBOLS (b, iter, sym)
          {
-           struct symtab *real_symtab = SYMBOL_SYMTAB (sym);
+           struct symtab *real_symtab = symbol_symtab (sym);
 
            QUIT;
 
@@ -3725,8 +4608,8 @@ search_symbols (const char *regexp, enum search_domain kind,
                            e.g., c++ static const members.
                            We only want to skip enums here.  */
                         && !(SYMBOL_CLASS (sym) == LOC_CONST
-                             && TYPE_CODE (SYMBOL_TYPE (sym))
-                             == TYPE_CODE_ENUM))
+                             && (TYPE_CODE (SYMBOL_TYPE (sym))
+                                 == TYPE_CODE_ENUM)))
                        || (kind == FUNCTIONS_DOMAIN 
                            && SYMBOL_CLASS (sym) == LOC_BLOCK)
                        || (kind == TYPES_DOMAIN
@@ -3736,7 +4619,6 @@ search_symbols (const char *regexp, enum search_domain kind,
                struct symbol_search *psr = (struct symbol_search *)
                  xmalloc (sizeof (struct symbol_search));
                psr->block = i;
-               psr->symtab = real_symtab;
                psr->symbol = sym;
                memset (&psr->msymbol, 0, sizeof (psr->msymbol));
                psr->next = NULL;
@@ -3758,7 +4640,7 @@ search_symbols (const char *regexp, enum search_domain kind,
     }
 
   /* If there are no eyes, avoid all contact.  I mean, if there are
-     no debug symbols, then print directly from the msymbol_vector.  */
+     no debug symbols, then add matching minsyms.  */
 
   if (found_misc || (nfiles == 0 && kind != FUNCTIONS_DOMAIN))
     {
@@ -3781,8 +4663,8 @@ search_symbols (const char *regexp, enum search_domain kind,
                /* For functions we can do a quick check of whether the
                   symbol might be found via find_pc_symtab.  */
                if (kind != FUNCTIONS_DOMAIN
-                   || find_pc_symtab (MSYMBOL_VALUE_ADDRESS (objfile,
-                                                             msymbol)) == NULL)
+                   || (find_pc_compunit_symtab
+                       (MSYMBOL_VALUE_ADDRESS (objfile, msymbol)) == NULL))
                  {
                    if (lookup_symbol_in_objfile_from_linkage_name
                        (objfile, MSYMBOL_LINKAGE_NAME (msymbol), VAR_DOMAIN)
@@ -3794,7 +4676,6 @@ search_symbols (const char *regexp, enum search_domain kind,
                        psr->block = i;
                        psr->msymbol.minsym = msymbol;
                        psr->msymbol.objfile = objfile;
-                       psr->symtab = NULL;
                        psr->symbol = NULL;
                        psr->next = NULL;
                        if (tail == NULL)
@@ -3820,9 +4701,10 @@ search_symbols (const char *regexp, enum search_domain kind,
 
 static void
 print_symbol_info (enum search_domain kind,
-                  struct symtab *s, struct symbol *sym,
+                  struct symbol *sym,
                   int block, const char *last)
 {
+  struct symtab *s = symbol_symtab (sym);
   const char *s_filename = symtab_to_filename_for_display (s);
 
   if (last == NULL || filename_cmp (last, s_filename) != 0)
@@ -3917,11 +4799,11 @@ symtab_symbol_info (char *regexp, enum search_domain kind, int from_tty)
       else
        {
          print_symbol_info (kind,
-                            p->symtab,
                             p->symbol,
                             p->block,
                             last_filename);
-         last_filename = symtab_to_filename_for_display (p->symtab);
+         last_filename
+           = symtab_to_filename_for_display (symbol_symtab (p->symbol));
        }
     }
 
@@ -4007,7 +4889,8 @@ rbreak_command (char *regexp, int from_tty)
     {
       if (p->msymbol.minsym == NULL)
        {
-         const char *fullname = symtab_to_fullname (p->symtab);
+         struct symtab *symtab = symbol_symtab (p->symbol);
+         const char *fullname = symtab_to_fullname (symtab);
 
          int newlen = (strlen (fullname)
                        + strlen (SYMBOL_LINKAGE_NAME (p->symbol))
@@ -4024,10 +4907,9 @@ rbreak_command (char *regexp, int from_tty)
          strcat (string, "'");
          break_command (string, from_tty);
          print_symbol_info (FUNCTIONS_DOMAIN,
-                            p->symtab,
                             p->symbol,
                             p->block,
-                            symtab_to_filename_for_display (p->symtab));
+                            symtab_to_filename_for_display (symtab));
        }
       else
        {
@@ -4334,7 +5216,7 @@ default_make_symbol_completion_list_break_on (const char *text,
      won't be that many.  */
 
   struct symbol *sym;
-  struct symtab *s;
+  struct compunit_symtab *cust;
   struct minimal_symbol *msymbol;
   struct objfile *objfile;
   const struct block *b;
@@ -4500,10 +5382,10 @@ default_make_symbol_completion_list_break_on (const char *text,
   /* Go through the symtabs and check the externs and statics for
      symbols which match.  */
 
-  ALL_PRIMARY_SYMTABS (objfile, s)
+  ALL_COMPUNITS (objfile, cust)
   {
     QUIT;
-    b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+    b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), GLOBAL_BLOCK);
     ALL_BLOCK_SYMBOLS (b, iter, sym)
       {
        if (code == TYPE_CODE_UNDEF
@@ -4513,10 +5395,10 @@ default_make_symbol_completion_list_break_on (const char *text,
       }
   }
 
-  ALL_PRIMARY_SYMTABS (objfile, s)
+  ALL_COMPUNITS (objfile, cust)
   {
     QUIT;
-    b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+    b = BLOCKVECTOR_BLOCK (COMPUNIT_BLOCKVECTOR (cust), STATIC_BLOCK);
     ALL_BLOCK_SYMBOLS (b, iter, sym)
       {
        if (code == TYPE_CODE_UNDEF
@@ -4680,13 +5562,13 @@ make_file_symbol_completion_list (const char *text, const char *word,
   /* Go through this symtab and check the externs and statics for
      symbols which match.  */
 
-  b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
+  b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), GLOBAL_BLOCK);
   ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
       COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
     }
 
-  b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
+  b = BLOCKVECTOR_BLOCK (SYMTAB_BLOCKVECTOR (s), STATIC_BLOCK);
   ALL_BLOCK_SYMBOLS (b, iter, sym)
     {
       COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
@@ -4793,6 +5675,7 @@ maybe_add_partial_symtab_filename (const char *filename, const char *fullname,
 VEC (char_ptr) *
 make_source_files_completion_list (const char *text, const char *word)
 {
+  struct compunit_symtab *cu;
   struct symtab *s;
   struct objfile *objfile;
   size_t text_len = strlen (text);
@@ -4811,7 +5694,7 @@ make_source_files_completion_list (const char *text, const char *word)
   cache_cleanup = make_cleanup (delete_filename_seen_cache,
                                filename_seen_cache);
 
-  ALL_SYMTABS (objfile, s)
+  ALL_FILETABS (objfile, cu, s)
     {
       if (not_interesting_fname (s->filename))
        continue;
@@ -5151,13 +6034,23 @@ initialize_ordinary_address_classes (void)
 
 \f
 
-/* Initialize the symbol SYM.  */
+/* Helper function to initialize the fields of an objfile-owned symbol.
+   It assumed that *SYM is already all zeroes.  */
+
+static void
+initialize_objfile_symbol_1 (struct symbol *sym)
+{
+  SYMBOL_OBJFILE_OWNED (sym) = 1;
+  SYMBOL_SECTION (sym) = -1;
+}
+
+/* Initialize the symbol SYM, and mark it as being owned by an objfile.  */
 
 void
-initialize_symbol (struct symbol *sym)
+initialize_objfile_symbol (struct symbol *sym)
 {
   memset (sym, 0, sizeof (*sym));
-  SYMBOL_SECTION (sym) = -1;
+  initialize_objfile_symbol_1 (sym);
 }
 
 /* Allocate and initialize a new 'struct symbol' on OBJFILE's
@@ -5169,7 +6062,7 @@ allocate_symbol (struct objfile *objfile)
   struct symbol *result;
 
   result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol);
-  SYMBOL_SECTION (result) = -1;
+  initialize_objfile_symbol_1 (result);
 
   return result;
 }
@@ -5183,11 +6076,48 @@ allocate_template_symbol (struct objfile *objfile)
   struct template_symbol *result;
 
   result = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct template_symbol);
-  SYMBOL_SECTION (&result->base) = -1;
+  initialize_objfile_symbol_1 (&result->base);
 
   return result;
 }
 
+/* See symtab.h.  */
+
+struct objfile *
+symbol_objfile (const struct symbol *symbol)
+{
+  gdb_assert (SYMBOL_OBJFILE_OWNED (symbol));
+  return SYMTAB_OBJFILE (symbol->owner.symtab);
+}
+
+/* See symtab.h.  */
+
+struct gdbarch *
+symbol_arch (const struct symbol *symbol)
+{
+  if (!SYMBOL_OBJFILE_OWNED (symbol))
+    return symbol->owner.arch;
+  return get_objfile_arch (SYMTAB_OBJFILE (symbol->owner.symtab));
+}
+
+/* See symtab.h.  */
+
+struct symtab *
+symbol_symtab (const struct symbol *symbol)
+{
+  gdb_assert (SYMBOL_OBJFILE_OWNED (symbol));
+  return symbol->owner.symtab;
+}
+
+/* See symtab.h.  */
+
+void
+symbol_set_symtab (struct symbol *symbol, struct symtab *symtab)
+{
+  gdb_assert (SYMBOL_OBJFILE_OWNED (symbol));
+  symbol->owner.symtab = symtab;
+}
+
 \f
 
 void
@@ -5198,6 +6128,9 @@ _initialize_symtab (void)
   main_progspace_key
     = register_program_space_data_with_cleanup (NULL, main_info_cleanup);
 
+  symbol_cache_key
+    = register_program_space_data_with_cleanup (NULL, symbol_cache_cleanup);
+
   add_info ("variables", variables_info, _("\
 All global and static variable names, or those matching REGEXP."));
   if (dbx_commands)
@@ -5265,5 +6198,39 @@ A value greater than 1 provides more verbose information."),
                             NULL,
                             &setdebuglist, &showdebuglist);
 
+  add_setshow_zuinteger_cmd ("symbol-lookup", no_class, &symbol_lookup_debug,
+                          _("\
+Set debugging of symbol lookup."), _("\
+Show debugging of symbol lookup."), _("\
+When enabled (non-zero), symbol lookups are logged."),
+                          NULL, NULL,
+                          &setdebuglist, &showdebuglist);
+
+  add_setshow_zuinteger_cmd ("symbol-cache-size", no_class,
+                            &new_symbol_cache_size,
+                            _("Set the size of the symbol cache."),
+                            _("Show the size of the symbol cache."), _("\
+The size of the symbol cache.\n\
+If zero then the symbol cache is disabled."),
+                            set_symbol_cache_size_handler, NULL,
+                            &maintenance_set_cmdlist,
+                            &maintenance_show_cmdlist);
+
+  add_cmd ("symbol-cache", class_maintenance, maintenance_print_symbol_cache,
+          _("Dump the symbol cache for each program space."),
+          &maintenanceprintlist);
+
+  add_cmd ("symbol-cache-statistics", class_maintenance,
+          maintenance_print_symbol_cache_statistics,
+          _("Print symbol cache statistics for each program space."),
+          &maintenanceprintlist);
+
+  add_cmd ("flush-symbol-cache", class_maintenance,
+          maintenance_flush_symbol_cache,
+          _("Flush the symbol cache for each program space."),
+          &maintenancelist);
+
   observer_attach_executable_changed (symtab_observer_executable_changed);
+  observer_attach_new_objfile (symtab_new_objfile_observer);
+  observer_attach_free_objfile (symtab_free_objfile_observer);
 }
This page took 0.052086 seconds and 4 git commands to generate.