* coffread.c, dbxread.c, elfread.c, mipsread.c, nlmread.c,
[binutils-gdb.git] / gdb / symfile.c
index 6a14c248a4e4606d3aacd0f044a5630d836a7116..2850af3c54d6e6b88c06ca78da2ec8559a07681e 100644 (file)
@@ -1,5 +1,6 @@
 /* Generic symbol file reading for the GNU debugger, GDB.
 /* Generic symbol file reading for the GNU debugger, GDB.
-   Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996
+   Free Software Foundation, Inc.
    Contributed by Cygnus Support, using pieces from other GDB modules.
 
 This file is part of GDB.
    Contributed by Cygnus Support, using pieces from other GDB modules.
 
 This file is part of GDB.
@@ -16,7 +17,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 
 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #include "defs.h"
 #include "symtab.h"
 
 #include "defs.h"
 #include "symtab.h"
@@ -33,15 +34,16 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "complaints.h"
 #include "demangle.h"
 #include "inferior.h" /* for write_pc */
 #include "complaints.h"
 #include "demangle.h"
 #include "inferior.h" /* for write_pc */
+#include "gdb-stabs.h"
+#include "obstack.h"
 
 
-#include <obstack.h>
 #include <assert.h>
 #include <assert.h>
-
 #include <sys/types.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <fcntl.h>
-#include <string.h>
-#include <sys/stat.h>
+#include "gdb_string.h"
+#include "gdb_stat.h"
 #include <ctype.h>
 #include <ctype.h>
+#include <time.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -65,34 +67,28 @@ struct complaint empty_symtab_complaint = {
 
 extern int info_verbose;
 
 
 extern int info_verbose;
 
+extern void report_transfer_performance PARAMS ((unsigned long,
+                                                time_t, time_t));
+
 /* Functions this file defines */
 
 /* Functions this file defines */
 
-static void
-set_initial_language PARAMS ((void));
+static void set_initial_language PARAMS ((void));
 
 
-static void
-load_command PARAMS ((char *, int));
+static void load_command PARAMS ((char *, int));
 
 
-static void
-add_symbol_file_command PARAMS ((char *, int));
+static void add_symbol_file_command PARAMS ((char *, int));
 
 
-static void
-add_shared_symbol_files_command PARAMS ((char *, int));
+static void add_shared_symbol_files_command PARAMS ((char *, int));
 
 
-static void
-cashier_psymtab PARAMS ((struct partial_symtab *));
+static void cashier_psymtab PARAMS ((struct partial_symtab *));
 
 
-static int
-compare_psymbols PARAMS ((const void *, const void *));
+static int compare_psymbols PARAMS ((const void *, const void *));
 
 
-static int
-compare_symbols PARAMS ((const void *, const void *));
+static int compare_symbols PARAMS ((const void *, const void *));
 
 
-static bfd *
-symfile_bfd_open PARAMS ((char *));
+static bfd *symfile_bfd_open PARAMS ((char *));
 
 
-static void
-find_sym_fns PARAMS ((struct objfile *));
+static void find_sym_fns PARAMS ((struct objfile *));
 
 /* List of all available sym_fns.  On gdb startup, each object file reader
    calls add_symtab_fns() to register information on each format it is
 
 /* List of all available sym_fns.  On gdb startup, each object file reader
    calls add_symtab_fns() to register information on each format it is
@@ -100,10 +96,6 @@ find_sym_fns PARAMS ((struct objfile *));
 
 static struct sym_fns *symtab_fns = NULL;
 
 
 static struct sym_fns *symtab_fns = NULL;
 
-/* Structures with which to manage partial symbol allocation.  */
-
-struct psymbol_allocation_list global_psymbols = {0}, static_psymbols = {0};
-
 /* Flag for whether user will be reloading symbols multiple times.
    Defaults to ON for VxWorks, otherwise OFF.  */
 
 /* Flag for whether user will be reloading symbols multiple times.
    Defaults to ON for VxWorks, otherwise OFF.  */
 
@@ -113,6 +105,18 @@ int symbol_reloading = SYMBOL_RELOADING_DEFAULT;
 int symbol_reloading = 0;
 #endif
 
 int symbol_reloading = 0;
 #endif
 
+/* If true, then shared library symbols will be added automatically
+   when the inferior is created, new libraries are loaded, or when
+   attaching to the inferior.  This is almost always what users
+   will want to have happen; but for very large programs, the startup
+   time will be excessive, and so if this is a problem, the user can
+   clear this flag and then add the shared library symbols as needed.
+   Note that there is a potential for confusion, since if the shared
+   library symbols are not loaded, commands like "info fun" will *not*
+   report all the functions that are actually present.  */
+
+int auto_solib_add = 1;
+
 \f
 /* Since this function is called from within qsort, in an ANSI environment
    it must conform to the prototype for qsort, which specifies that the
 \f
 /* Since this function is called from within qsort, in an ANSI environment
    it must conform to the prototype for qsort, which specifies that the
@@ -139,9 +143,9 @@ LOCAL FUNCTION
 
 DESCRIPTION
 
 
 DESCRIPTION
 
-       Given pointer to two partial symbol table entries, compare
-       them by name and return -N, 0, or +N (ala strcmp).  Typically
-       used by sorting routines like qsort().
+       Given pointers to pointers to two partial symbol table entries,
+       compare them by name and return -N, 0, or +N (ala strcmp).
+       Typically used by sorting routines like qsort().
 
 NOTES
 
 
 NOTES
 
@@ -158,8 +162,8 @@ compare_psymbols (s1p, s2p)
      const PTR s1p;
      const PTR s2p;
 {
      const PTR s1p;
      const PTR s2p;
 {
-  register char *st1 = SYMBOL_NAME ((struct partial_symbol *) s1p);
-  register char *st2 = SYMBOL_NAME ((struct partial_symbol *) s2p);
+  register char *st1 = SYMBOL_NAME (*(struct partial_symbol **) s1p);
+  register char *st2 = SYMBOL_NAME (*(struct partial_symbol **) s2p);
 
   if ((st1[0] - st2[0]) || !st1[0])
     {
 
   if ((st1[0] - st2[0]) || !st1[0])
     {
@@ -182,7 +186,7 @@ sort_pst_symbols (pst)
   /* Sort the global list; don't sort the static list */
 
   qsort (pst -> objfile -> global_psymbols.list + pst -> globals_offset,
   /* Sort the global list; don't sort the static list */
 
   qsort (pst -> objfile -> global_psymbols.list + pst -> globals_offset,
-        pst -> n_global_syms, sizeof (struct partial_symbol),
+        pst -> n_global_syms, sizeof (struct partial_symbol *),
         compare_psymbols);
 }
 
         compare_psymbols);
 }
 
@@ -260,6 +264,17 @@ obconcat (obstackp, s1, s2, s3)
   return val;
 }
 
   return val;
 }
 
+/* True if we are nested inside psymtab_to_symtab. */
+
+int currently_reading_symtab = 0;
+
+static void
+decrement_reading_symtab (dummy)
+     void *dummy;
+{
+  currently_reading_symtab--;
+}
+
 /* Get the symbol table that corresponds to a partial_symtab.
    This is fast after the first time you do it.  In fact, there
    is an even faster macro PSYMTAB_TO_SYMTAB that does the fast
 /* Get the symbol table that corresponds to a partial_symtab.
    This is fast after the first time you do it.  In fact, there
    is an even faster macro PSYMTAB_TO_SYMTAB that does the fast
@@ -276,7 +291,10 @@ psymtab_to_symtab (pst)
   /* If it has not yet been read in, read it.  */
   if (!pst->readin)
     { 
   /* If it has not yet been read in, read it.  */
   if (!pst->readin)
     { 
+      struct cleanup *back_to = make_cleanup (decrement_reading_symtab, NULL);
+      currently_reading_symtab++;
       (*pst->read_symtab) (pst);
       (*pst->read_symtab) (pst);
+      do_cleanups (back_to);
     }
 
   return pst->symtab;
     }
 
   return pst->symtab;
@@ -301,9 +319,13 @@ init_entry_point_info (objfile)
     {
       /* Examination of non-executable.o files.  Short-circuit this stuff.  */
       objfile -> ei.entry_point = INVALID_ENTRY_POINT;
     {
       /* Examination of non-executable.o files.  Short-circuit this stuff.  */
       objfile -> ei.entry_point = INVALID_ENTRY_POINT;
-      objfile -> ei.entry_file_lowpc = INVALID_ENTRY_LOWPC;
-      objfile -> ei.entry_file_highpc = INVALID_ENTRY_HIGHPC;
     }
     }
+  objfile -> ei.entry_file_lowpc = INVALID_ENTRY_LOWPC;
+  objfile -> ei.entry_file_highpc = INVALID_ENTRY_HIGHPC;
+  objfile -> ei.entry_func_lowpc = INVALID_ENTRY_LOWPC;
+  objfile -> ei.entry_func_highpc = INVALID_ENTRY_HIGHPC;
+  objfile -> ei.main_func_lowpc = INVALID_ENTRY_LOWPC;
+  objfile -> ei.main_func_highpc = INVALID_ENTRY_HIGHPC;
 }
 
 /* Get current entry point address.  */
 }
 
 /* Get current entry point address.  */
@@ -323,7 +345,7 @@ entry_point_address()
    If the vmas and sizes are equal, the last section is considered the
    lowest-addressed loadable section.  */
 
    If the vmas and sizes are equal, the last section is considered the
    lowest-addressed loadable section.  */
 
-static void
+void
 find_lowest_section (abfd, sect, obj)
      bfd *abfd;
      asection *sect;
 find_lowest_section (abfd, sect, obj)
      bfd *abfd;
      asection *sect;
@@ -343,6 +365,31 @@ find_lowest_section (abfd, sect, obj)
     *lowest = sect;
 }
 
     *lowest = sect;
 }
 
+/* Parse the user's idea of an offset for dynamic linking, into our idea
+   of how to represent it for fast symbol reading.  This is the default 
+   version of the sym_fns.sym_offsets function for symbol readers that
+   don't need to do anything special.  It allocates a section_offsets table
+   for the objectfile OBJFILE and stuffs ADDR into all of the offsets.  */
+
+struct section_offsets *
+default_symfile_offsets (objfile, addr)
+     struct objfile *objfile;
+     CORE_ADDR addr;
+{
+  struct section_offsets *section_offsets;
+  int i;
+
+  objfile->num_sections = SECT_OFF_MAX;
+  section_offsets = (struct section_offsets *)
+    obstack_alloc (&objfile -> psymbol_obstack, SIZEOF_SECTION_OFFSETS);
+
+  for (i = 0; i < SECT_OFF_MAX; i++)
+    ANOFFSET (section_offsets, i) = addr;
+  
+  return section_offsets;
+}
+
+
 /* Process a symbol file, as either the main file or as a dynamically
    loaded file.
 
 /* Process a symbol file, as either the main file or as a dynamically
    loaded file.
 
@@ -495,6 +542,13 @@ syms_from_objfile (objfile, addr, mainline, verbo)
   /* Discard cleanups as symbol reading was successful.  */
 
   discard_cleanups (old_chain);
   /* Discard cleanups as symbol reading was successful.  */
 
   discard_cleanups (old_chain);
+
+/* Call this after reading in a new symbol table to give target dependant code
+   a crack at the new symbols.  For instance, this could be used to update the
+   values of target-specific symbols GDB needs to keep track of (such as
+   _sigtramp, or whatever).  */
+
+  TARGET_SYMFILE_POSTREAD (objfile);
 }
 
 /* Perform required actions after either reading in the initial
 }
 
 /* Perform required actions after either reading in the initial
@@ -628,6 +682,8 @@ symbol_file_add (name, from_tty, addr, mainline, mapped, readnow)
 
   new_symfile_objfile (objfile, mainline, from_tty);
 
 
   new_symfile_objfile (objfile, mainline, from_tty);
 
+  target_new_objfile (objfile);
+
   return (objfile);
 }
 
   return (objfile);
 }
 
@@ -840,8 +896,9 @@ find_sym_fns (objfile)
   enum bfd_flavour our_flavour = bfd_get_flavour (objfile -> obfd);
   char *our_target = bfd_get_target (objfile -> obfd);
 
   enum bfd_flavour our_flavour = bfd_get_flavour (objfile -> obfd);
   char *our_target = bfd_get_target (objfile -> obfd);
 
-  /* Special kludge for RS/6000.  See xcoffread.c.  */
-  if (STREQ (our_target, "aixcoff-rs6000"))
+  /* Special kludge for RS/6000 and PowerMac.  See xcoffread.c.  */
+  if (STREQ (our_target, "aixcoff-rs6000") ||
+      STREQ (our_target, "xcoff-powermac"))
     our_flavour = (enum bfd_flavour)-1;
 
   /* Special kludge for apollo.  See dstread.c.  */
     our_flavour = (enum bfd_flavour)-1;
 
   /* Special kludge for apollo.  See dstread.c.  */
@@ -888,6 +945,18 @@ generic_load (filename, from_tty)
   struct cleanup *old_cleanups;
   asection *s;
   bfd *loadfile_bfd;
   struct cleanup *old_cleanups;
   asection *s;
   bfd *loadfile_bfd;
+  time_t start_time, end_time; /* Start and end times of download */
+  unsigned long data_count = 0;        /* Number of bytes transferred to memory */
+  int n; 
+  unsigned long load_offset = 0;       /* offset to add to vma for each section */
+  char buf[128];
+
+  /* enable user to specify address for downloading as 2nd arg to load */
+  n = sscanf(filename, "%s 0x%x", buf, &load_offset);
+  if (n > 1 ) 
+    filename = buf;
+  else
+    load_offset = 0;
 
   loadfile_bfd = bfd_openr (filename, gnutarget);
   if (loadfile_bfd == NULL)
 
   loadfile_bfd = bfd_openr (filename, gnutarget);
   if (loadfile_bfd == NULL)
@@ -906,6 +975,8 @@ generic_load (filename, from_tty)
             bfd_errmsg (bfd_get_error ()));
     }
   
             bfd_errmsg (bfd_get_error ()));
     }
   
+  start_time = time (NULL);
+
   for (s = loadfile_bfd->sections; s; s = s->next) 
     {
       if (s->flags & SEC_LOAD) 
   for (s = loadfile_bfd->sections; s; s = s->next) 
     {
       if (s->flags & SEC_LOAD) 
@@ -919,10 +990,13 @@ generic_load (filename, from_tty)
              struct cleanup *old_chain;
              bfd_vma vma;
 
              struct cleanup *old_chain;
              bfd_vma vma;
 
+             data_count += size;
+
              buffer = xmalloc (size);
              old_chain = make_cleanup (free, buffer);
 
              vma = bfd_get_section_vma (loadfile_bfd, s);
              buffer = xmalloc (size);
              old_chain = make_cleanup (free, buffer);
 
              vma = bfd_get_section_vma (loadfile_bfd, s);
+                 vma += load_offset;
 
              /* Is this really necessary?  I guess it gives the user something
                 to look at during a long download.  */
 
              /* Is this really necessary?  I guess it gives the user something
                 to look at during a long download.  */
@@ -941,6 +1015,10 @@ generic_load (filename, from_tty)
        }
     }
 
        }
     }
 
+  end_time = time (NULL);
+
+  printf_filtered ("Start address 0x%lx\n", loadfile_bfd->start_address);
+
   /* We were doing this in remote-mips.c, I suspect it is right
      for other targets too.  */
   write_pc (loadfile_bfd->start_address);
   /* We were doing this in remote-mips.c, I suspect it is right
      for other targets too.  */
   write_pc (loadfile_bfd->start_address);
@@ -951,9 +1029,27 @@ generic_load (filename, from_tty)
      loaded in.  remote-nindy.c had no call to symbol_file_add, but remote-vx.c
      does.  */
 
      loaded in.  remote-nindy.c had no call to symbol_file_add, but remote-vx.c
      does.  */
 
+  report_transfer_performance (data_count, start_time, end_time);
+
   do_cleanups (old_cleanups);
 }
 
   do_cleanups (old_cleanups);
 }
 
+/* Report how fast the transfer went. */
+
+void
+report_transfer_performance (data_count, start_time, end_time)
+unsigned long data_count;
+time_t start_time, end_time;
+{
+  printf_filtered ("Transfer rate: ");
+  if (end_time != start_time)
+    printf_filtered ("%d bits/sec",
+                    (data_count * 8) / (end_time - start_time));
+  else
+    printf_filtered ("%d bits in <1 sec", (data_count * 8));
+  printf_filtered (".\n");
+}
+
 /* This function allows the addition of incrementally linked object files.
    It does not modify any state in the target, only in the debugger.  */
 
 /* This function allows the addition of incrementally linked object files.
    It does not modify any state in the target, only in the debugger.  */
 
@@ -1147,16 +1243,17 @@ reread_symbols ()
             enough?  */
          if (objfile->global_psymbols.list)
            mfree (objfile->md, objfile->global_psymbols.list);
             enough?  */
          if (objfile->global_psymbols.list)
            mfree (objfile->md, objfile->global_psymbols.list);
-         objfile->global_psymbols.list = NULL;
-         objfile->global_psymbols.next = NULL;
-         objfile->global_psymbols.size = 0;
+         memset (&objfile -> global_psymbols, 0,
+                 sizeof (objfile -> global_psymbols));
          if (objfile->static_psymbols.list)
            mfree (objfile->md, objfile->static_psymbols.list);
          if (objfile->static_psymbols.list)
            mfree (objfile->md, objfile->static_psymbols.list);
-         objfile->static_psymbols.list = NULL;
-         objfile->static_psymbols.next = NULL;
-         objfile->static_psymbols.size = 0;
+         memset (&objfile -> static_psymbols, 0,
+                 sizeof (objfile -> static_psymbols));
 
          /* Free the obstacks for non-reusable objfiles */
 
          /* Free the obstacks for non-reusable objfiles */
+         obstack_free (&objfile -> psymbol_cache.cache, 0);
+         memset (&objfile -> psymbol_cache, 0,
+                 sizeof (objfile -> psymbol_cache));
          obstack_free (&objfile -> psymbol_obstack, 0);
          obstack_free (&objfile -> symbol_obstack, 0);
          obstack_free (&objfile -> type_obstack, 0);
          obstack_free (&objfile -> psymbol_obstack, 0);
          obstack_free (&objfile -> symbol_obstack, 0);
          obstack_free (&objfile -> type_obstack, 0);
@@ -1176,6 +1273,8 @@ reread_symbols ()
          objfile -> md = NULL;
          /* obstack_specify_allocation also initializes the obstack so
             it is empty.  */
          objfile -> md = NULL;
          /* obstack_specify_allocation also initializes the obstack so
             it is empty.  */
+         obstack_specify_allocation (&objfile -> psymbol_cache.cache, 0, 0,
+                                     xmalloc, free);
          obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0,
                                      xmalloc, free);
          obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0,
          obstack_specify_allocation (&objfile -> psymbol_obstack, 0, 0,
                                      xmalloc, free);
          obstack_specify_allocation (&objfile -> symbol_obstack, 0, 0,
@@ -1231,6 +1330,13 @@ reread_symbols ()
             again now.  */
          objfile->mtime = new_modtime;
          reread_one = 1;
             again now.  */
          objfile->mtime = new_modtime;
          reread_one = 1;
+
+         /* Call this after reading in a new symbol table to give target
+            dependant code a crack at the new symbols.  For instance, this
+            could be used to update the values of target-specific symbols GDB
+            needs to keep track of (such as _sigtramp, or whatever).  */
+
+         TARGET_SYMFILE_POSTREAD (objfile);
        }
     }
   }
        }
     }
   }
@@ -1358,6 +1464,7 @@ clear_symtab_users ()
   current_source_symtab = 0;
   current_source_line = 0;
   clear_pc_function_cache ();
   current_source_symtab = 0;
   current_source_line = 0;
   clear_pc_function_cache ();
+  target_new_objfile (NULL);
 }
 
 /* clear_symtab_users_once:
 }
 
 /* clear_symtab_users_once:
@@ -1574,8 +1681,8 @@ start_psymtab_common (objfile, section_offsets,
      struct section_offsets *section_offsets;
      char *filename;
      CORE_ADDR textlow;
      struct section_offsets *section_offsets;
      char *filename;
      CORE_ADDR textlow;
-     struct partial_symbol *global_syms;
-     struct partial_symbol *static_syms;
+     struct partial_symbol **global_syms;
+     struct partial_symbol **static_syms;
 {
   struct partial_symtab *psymtab;
 
 {
   struct partial_symtab *psymtab;
 
@@ -1588,82 +1695,60 @@ start_psymtab_common (objfile, section_offsets,
   return (psymtab);
 }
 \f
   return (psymtab);
 }
 \f
-/* Debugging versions of functions that are usually inline macros
-   (see symfile.h).  */
-
-#if !INLINE_ADD_PSYMBOL
-
 /* Add a symbol with a long value to a psymtab.
    Since one arg is a struct, we pass in a ptr and deref it (sigh).  */
 
 void
 /* Add a symbol with a long value to a psymtab.
    Since one arg is a struct, we pass in a ptr and deref it (sigh).  */
 
 void
-add_psymbol_to_list (name, namelength, namespace, class, list, val, language,
-                    objfile)
+add_psymbol_to_list (name, namelength, namespace, class, list, val, coreaddr,
+                    language, objfile)
      char *name;
      int namelength;
      char *name;
      int namelength;
-     enum namespace namespace;
+     namespace_enum namespace;
      enum address_class class;
      struct psymbol_allocation_list *list;
      enum address_class class;
      struct psymbol_allocation_list *list;
-     long val;
+     long val;                                 /* Value as a long */
+     CORE_ADDR coreaddr;                       /* Value as a CORE_ADDR */
      enum language language;
      struct objfile *objfile;
 {
   register struct partial_symbol *psym;
      enum language language;
      struct objfile *objfile;
 {
   register struct partial_symbol *psym;
-  register char *demangled_name;
-
-  if (list->next >= list->list + list->size)
+  char *buf = alloca (namelength + 1);
+  /* psymbol is static so that there will be no uninitialized gaps in the
+     structure which might contain random data, causing cache misses in
+     bcache. */
+  static struct partial_symbol psymbol;
+
+  /* Create local copy of the partial symbol */
+  memcpy (buf, name, namelength);
+  buf[namelength] = '\0';
+  SYMBOL_NAME (&psymbol) = bcache (buf, namelength + 1, &objfile->psymbol_cache);
+  /* val and coreaddr are mutually exclusive, one of them *will* be zero */
+  if (val != 0)
     {
     {
-      extend_psymbol_list (list,objfile);
+      SYMBOL_VALUE (&psymbol) = val;
     }
     }
-  psym = list->next++;
-  
-  SYMBOL_NAME (psym) =
-    (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1);
-  memcpy (SYMBOL_NAME (psym), name, namelength);
-  SYMBOL_NAME (psym)[namelength] = '\0';
-  SYMBOL_VALUE (psym) = val;
-  SYMBOL_LANGUAGE (psym) = language;
-  PSYMBOL_NAMESPACE (psym) = namespace;
-  PSYMBOL_CLASS (psym) = class;
-  SYMBOL_INIT_LANGUAGE_SPECIFIC (psym, language);
-}
-
-/* Add a symbol with a CORE_ADDR value to a psymtab. */
+  else
+    {
+      SYMBOL_VALUE_ADDRESS (&psymbol) = coreaddr;
+    }
+  SYMBOL_SECTION (&psymbol) = 0;
+  SYMBOL_LANGUAGE (&psymbol) = language;
+  PSYMBOL_NAMESPACE (&psymbol) = namespace;
+  PSYMBOL_CLASS (&psymbol) = class;
+  SYMBOL_INIT_LANGUAGE_SPECIFIC (&psymbol, language);
 
 
-void
-add_psymbol_addr_to_list (name, namelength, namespace, class, list, val,
-                         language, objfile)
-     char *name;
-     int namelength;
-     enum namespace namespace;
-     enum address_class class;
-     struct psymbol_allocation_list *list;
-     CORE_ADDR val;
-     enum language language;
-     struct objfile *objfile;
-{
-  register struct partial_symbol *psym;
-  register char *demangled_name;
+  /* Stash the partial symbol away in the cache */
+  psym = bcache (&psymbol, sizeof (struct partial_symbol), &objfile->psymbol_cache);
 
 
+  /* Save pointer to partial symbol in psymtab, growing symtab if needed. */
   if (list->next >= list->list + list->size)
     {
   if (list->next >= list->list + list->size)
     {
-      extend_psymbol_list (list,objfile);
+      extend_psymbol_list (list, objfile);
     }
     }
-  psym = list->next++;
-  
-  SYMBOL_NAME (psym) =
-    (char *) obstack_alloc (&objfile->psymbol_obstack, namelength + 1);
-  memcpy (SYMBOL_NAME (psym), name, namelength);
-  SYMBOL_NAME (psym)[namelength] = '\0';
-  SYMBOL_VALUE_ADDRESS (psym) = val;
-  SYMBOL_LANGUAGE (psym) = language;
-  PSYMBOL_NAMESPACE (psym) = namespace;
-  PSYMBOL_CLASS (psym) = class;
-  SYMBOL_INIT_LANGUAGE_SPECIFIC (psym, language);
+  *list->next++ = psym;
+  OBJSTAT (objfile, n_psyms++);
 }
 
 }
 
-#endif /* !INLINE_ADD_PSYMBOL */
-
 /* Initialize storage for partial symbols.  */
 
 void
 /* Initialize storage for partial symbols.  */
 
 void
@@ -1689,13 +1774,13 @@ init_psymbol_list (objfile, total_symbols)
   objfile -> global_psymbols.size = total_symbols / 10;
   objfile -> static_psymbols.size = total_symbols / 10;
   objfile -> global_psymbols.next =
   objfile -> global_psymbols.size = total_symbols / 10;
   objfile -> static_psymbols.size = total_symbols / 10;
   objfile -> global_psymbols.next =
-    objfile -> global_psymbols.list = (struct partial_symbol *)
+    objfile -> global_psymbols.list = (struct partial_symbol **)
       xmmalloc (objfile -> md, objfile -> global_psymbols.size
       xmmalloc (objfile -> md, objfile -> global_psymbols.size
-                            * sizeof (struct partial_symbol));
+                            * sizeof (struct partial_symbol *));
   objfile -> static_psymbols.next =
   objfile -> static_psymbols.next =
-    objfile -> static_psymbols.list = (struct partial_symbol *)
+    objfile -> static_psymbols.list = (struct partial_symbol **)
       xmmalloc (objfile -> md, objfile -> static_psymbols.size
       xmmalloc (objfile -> md, objfile -> static_psymbols.size
-                            * sizeof (struct partial_symbol));
+                            * sizeof (struct partial_symbol *));
 }
 \f
 void
 }
 \f
 void