Add symbol lookup cache.
[deliverable/binutils-gdb.git] / gdb / symtab.c
index c697b1bcca0bcc391fe8af0d7c9f66cb8c3a1486..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");
@@ -1056,6 +1161,552 @@ expand_symtab_containing_pc (CORE_ADDR pc, struct obj_section *section)
   }
 }
 \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.  */
 
@@ -1148,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_OBJFILE (sym);
+    objfile = symbol_objfile (sym);
 
   if (SYMBOL_OBJ_SECTION (objfile, sym))
     return sym;
@@ -1314,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;
@@ -1321,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;
        }
@@ -1329,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;
 }
 
@@ -1388,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
@@ -1400,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'.  */
@@ -1431,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.
@@ -1523,13 +2242,31 @@ 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;
 }
 
@@ -1546,27 +2283,10 @@ lookup_global_symbol_from_objfile (struct objfile *main_objfile,
        objfile;
        objfile = objfile_separate_debug_iterate (main_objfile, objfile))
     {
-      struct compunit_symtab *cust;
-      struct symbol *sym;
-
-      /* Go through symtabs.  */
-      ALL_OBJFILE_COMPUNITS (objfile, cust)
-       {
-         const struct blockvector *bv;
-         const struct block *block;
-
-         bv = COMPUNIT_BLOCKVECTOR (cust);
-         block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
-         sym = block_lookup_symbol (block, name, domain);
-         if (sym)
-           {
-             block_found = block;
-             return fixup_symbol_section (sym, objfile);
-           }
-       }
+      struct symbol *sym = lookup_symbol_in_objfile (objfile, GLOBAL_BLOCK,
+                                                    name, domain);
 
-      sym = lookup_symbol_via_quick_fns (objfile, GLOBAL_BLOCK, name, domain);
-      if (sym)
+      if (sym != NULL)
        return sym;
     }
 
@@ -1586,6 +2306,16 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile, int block_index,
 
   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_COMPUNITS (objfile, cust)
     {
       const struct blockvector *bv;
@@ -1597,11 +2327,19 @@ lookup_symbol_in_objfile_symtabs (struct objfile *objfile, int block_index,
       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;
 }
 
@@ -1683,15 +2421,42 @@ lookup_symbol_via_quick_fns (struct objfile *objfile, int block_index,
 
   if (!objfile->sf)
     return NULL;
+
+  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)
-    return 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, 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);
 }
@@ -1699,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)
 {
@@ -1741,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);
 }
 
@@ -1752,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:
@@ -1770,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;
 }
 
@@ -1786,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;
 }
 
@@ -1843,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
@@ -2708,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
@@ -2722,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)
@@ -2802,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_OBJFILE (sym);
     }
   else
     {
@@ -2837,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 && COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (SYMBOL_SYMTAB (sym))))
+  if (sym != NULL
+      && COMPUNIT_LOCATIONS_VALID (SYMTAB_COMPUNIT (symbol_symtab (sym))))
     force_skip = 0;
 
   saved_pc = pc;
@@ -2902,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);
     }
@@ -2942,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));
     }
 }
 
@@ -3424,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;
 
@@ -3706,7 +4585,7 @@ search_symbols (const char *regexp, enum search_domain kind,
        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;
 
@@ -3740,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;
@@ -3798,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)
@@ -3824,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)
@@ -3921,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));
        }
     }
 
@@ -4011,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))
@@ -4028,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
        {
@@ -5156,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
@@ -5174,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;
 }
@@ -5188,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
@@ -5203,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)
@@ -5270,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.039938 seconds and 4 git commands to generate.