]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
This commit was manufactured by cvs2svn to create branch
authornobody <>
Tue, 10 Sep 2002 23:45:27 +0000 (23:45 +0000)
committernobody <>
Tue, 10 Sep 2002 23:45:27 +0000 (23:45 +0000)
'carlton_dictionary-branch'.

Cherrypick from gdb_5_3-branch 2002-09-03 22:29:15 UTC nobody 'This commit was manufactured by cvs2svn to create branch 'gdb_5_3-branch'.':
    gdb/jv-lang.c
    gdb/symmisc.c
Cherrypick from master 2002-09-10 23:45:26 UTC Michael Snyder <msnyder@vmware.com> '2002-09-10  Michael Snyder  <msnyder@redhat.com>':
    gdb/buildsym.c

gdb/buildsym.c [new file with mode: 0644]
gdb/jv-lang.c [new file with mode: 0644]
gdb/symmisc.c [new file with mode: 0644]

diff --git a/gdb/buildsym.c b/gdb/buildsym.c
new file mode 100644 (file)
index 0000000..9d9b4f7
--- /dev/null
@@ -0,0 +1,1170 @@
+/* Support routines for building symbol tables in GDB's internal format.
+   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
+   1996, 1997, 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* This module provides subroutines used for creating and adding to
+   the symbol table.  These routines are called from various symbol-
+   file-reading routines.
+
+   Routines to support specific debugging information formats (stabs,
+   DWARF, etc) belong somewhere else. */
+
+#include "defs.h"
+#include "bfd.h"
+#include "gdb_obstack.h"
+#include "symtab.h"
+#include "symfile.h"           /* Needed for "struct complaint" */
+#include "objfiles.h"
+#include "gdbtypes.h"
+#include "complaints.h"
+#include "gdb_string.h"
+#include "expression.h"                /* For "enum exp_opcode" used by... */
+#include "language.h"          /* For "local_hex_string" */
+#include "bcache.h"
+#include "filenames.h"         /* For DOSish file names */
+#include "macrotab.h"
+#include "demangle.h"          /* Needed by SYMBOL_INIT_DEMANGLED_NAME.  */
+/* Ask buildsym.h to define the vars it normally declares `extern'.  */
+#define        EXTERN
+/**/
+#include "buildsym.h"          /* Our own declarations */
+#undef EXTERN
+
+/* For cleanup_undefined_types and finish_global_stabs (somewhat
+   questionable--see comment where we call them).  */
+
+#include "stabsread.h"
+
+/* List of free `struct pending' structures for reuse.  */
+
+static struct pending *free_pendings;
+
+/* Non-zero if symtab has line number info.  This prevents an
+   otherwise empty symtab from being tossed.  */
+
+static int have_line_numbers;
+\f
+static int compare_line_numbers (const void *ln1p, const void *ln2p);
+\f
+
+/* Initial sizes of data structures.  These are realloc'd larger if
+   needed, and realloc'd down to the size actually used, when
+   completed.  */
+
+#define        INITIAL_CONTEXT_STACK_SIZE      10
+#define        INITIAL_LINE_VECTOR_LENGTH      1000
+\f
+
+/* Complaints about the symbols we have encountered.  */
+
+struct complaint block_end_complaint =
+{"block end address less than block start address in %s (patched it)", 0, 0};
+
+struct complaint anon_block_end_complaint =
+{"block end address 0x%lx less than block start address 0x%lx (patched it)", 0, 0};
+
+struct complaint innerblock_complaint =
+{"inner block not inside outer block in %s", 0, 0};
+
+struct complaint innerblock_anon_complaint =
+{"inner block (0x%lx-0x%lx) not inside outer block (0x%lx-0x%lx)", 0, 0};
+
+struct complaint blockvector_complaint =
+{"block at %s out of order", 0, 0};
+\f
+/* maintain the lists of symbols and blocks */
+
+/* Add a pending list to free_pendings. */
+void
+add_free_pendings (struct pending *list)
+{
+  register struct pending *link = list;
+
+  if (list)
+    {
+      while (link->next) link = link->next;
+      link->next = free_pendings;
+      free_pendings = list;
+    }
+}
+      
+/* Add a symbol to one of the lists of symbols.  */
+
+void
+add_symbol_to_list (struct symbol *symbol, struct pending **listhead)
+{
+  register struct pending *link;
+
+  /* If this is an alias for another symbol, don't add it.  */
+  if (symbol->ginfo.name && symbol->ginfo.name[0] == '#')
+    return;
+
+  /* We keep PENDINGSIZE symbols in each link of the list. If we
+     don't have a link with room in it, add a new link.  */
+  if (*listhead == NULL || (*listhead)->nsyms == PENDINGSIZE)
+    {
+      if (free_pendings)
+       {
+         link = free_pendings;
+         free_pendings = link->next;
+       }
+      else
+       {
+         link = (struct pending *) xmalloc (sizeof (struct pending));
+       }
+
+      link->next = *listhead;
+      *listhead = link;
+      link->nsyms = 0;
+    }
+
+  (*listhead)->symbol[(*listhead)->nsyms++] = symbol;
+}
+
+/* Find a symbol named NAME on a LIST.  NAME need not be
+   '\0'-terminated; LENGTH is the length of the name.  */
+
+struct symbol *
+find_symbol_in_list (struct pending *list, char *name, int length)
+{
+  int j;
+  char *pp;
+
+  while (list != NULL)
+    {
+      for (j = list->nsyms; --j >= 0;)
+       {
+         pp = SYMBOL_NAME (list->symbol[j]);
+         if (*pp == *name && strncmp (pp, name, length) == 0 &&
+             pp[length] == '\0')
+           {
+             return (list->symbol[j]);
+           }
+       }
+      list = list->next;
+    }
+  return (NULL);
+}
+
+/* At end of reading syms, or in case of quit, really free as many
+   `struct pending's as we can easily find. */
+
+/* ARGSUSED */
+void
+really_free_pendings (PTR dummy)
+{
+  struct pending *next, *next1;
+
+  for (next = free_pendings; next; next = next1)
+    {
+      next1 = next->next;
+      xfree ((void *) next);
+    }
+  free_pendings = NULL;
+
+  free_pending_blocks ();
+
+  for (next = file_symbols; next != NULL; next = next1)
+    {
+      next1 = next->next;
+      xfree ((void *) next);
+    }
+  file_symbols = NULL;
+
+  for (next = global_symbols; next != NULL; next = next1)
+    {
+      next1 = next->next;
+      xfree ((void *) next);
+    }
+  global_symbols = NULL;
+
+  if (pending_macros)
+    free_macro_table (pending_macros);
+}
+
+/* This function is called to discard any pending blocks. */
+
+void
+free_pending_blocks (void)
+{
+#if 0                          /* Now we make the links in the
+                                  symbol_obstack, so don't free
+                                  them.  */
+  struct pending_block *bnext, *bnext1;
+
+  for (bnext = pending_blocks; bnext; bnext = bnext1)
+    {
+      bnext1 = bnext->next;
+      xfree ((void *) bnext);
+    }
+#endif
+  pending_blocks = NULL;
+}
+
+/* Take one of the lists of symbols and make a block from it.  Keep
+   the order the symbols have in the list (reversed from the input
+   file).  Put the block on the list of pending blocks.  */
+
+void
+finish_block (struct symbol *symbol, struct pending **listhead,
+             struct pending_block *old_blocks,
+             CORE_ADDR start, CORE_ADDR end,
+             struct objfile *objfile)
+{
+  register struct pending *next, *next1;
+  register struct block *block;
+  register struct pending_block *pblock;
+  struct pending_block *opblock;
+  register int i;
+  register int j;
+
+  /* Count the length of the list of symbols.  */
+
+  for (next = *listhead, i = 0;
+       next;
+       i += next->nsyms, next = next->next)
+    {
+      /* EMPTY */ ;
+    }
+
+  /* Copy the symbols into the block.  */
+
+  if (symbol)
+    {
+      block = (struct block *) 
+       obstack_alloc (&objfile->symbol_obstack,
+                      (sizeof (struct block) + 
+                       ((i - 1) * sizeof (struct symbol *))));
+      BLOCK_NSYMS (block) = i;
+      for (next = *listhead; next; next = next->next)
+       for (j = next->nsyms - 1; j >= 0; j--)
+         {
+           BLOCK_SYM (block, --i) = next->symbol[j];
+         }
+    }
+  else
+    {
+      int htab_size = BLOCK_HASHTABLE_SIZE (i);
+
+      block = (struct block *) 
+       obstack_alloc (&objfile->symbol_obstack,
+                      (sizeof (struct block) + 
+                       ((htab_size - 1) * sizeof (struct symbol *))));
+      for (j = 0; j < htab_size; j++)
+       {
+         BLOCK_BUCKET (block, j) = 0;
+       }
+      BLOCK_BUCKETS (block) = htab_size;
+      for (next = *listhead; next; next = next->next)
+       {
+         for (j = next->nsyms - 1; j >= 0; j--)
+           {
+             struct symbol *sym;
+             unsigned int hash_index;
+             const char *name = SYMBOL_DEMANGLED_NAME (next->symbol[j]);
+             if (name == NULL)
+               name = SYMBOL_NAME (next->symbol[j]);
+             hash_index = msymbol_hash_iw (name);
+             hash_index = hash_index % BLOCK_BUCKETS (block);
+             sym = BLOCK_BUCKET (block, hash_index);
+             BLOCK_BUCKET (block, hash_index) = next->symbol[j];
+             next->symbol[j]->hash_next = sym;
+           }
+       }
+    }
+
+  BLOCK_START (block) = start;
+  BLOCK_END (block) = end;
+  /* Superblock filled in when containing block is made */
+  BLOCK_SUPERBLOCK (block) = NULL;
+
+  BLOCK_GCC_COMPILED (block) = processing_gcc_compilation;
+
+  /* Put the block in as the value of the symbol that names it.  */
+
+  if (symbol)
+    {
+      struct type *ftype = SYMBOL_TYPE (symbol);
+      SYMBOL_BLOCK_VALUE (symbol) = block;
+      BLOCK_FUNCTION (block) = symbol;
+      BLOCK_HASHTABLE (block) = 0;
+
+      if (TYPE_NFIELDS (ftype) <= 0)
+       {
+         /* No parameter type information is recorded with the
+            function's type.  Set that from the type of the
+            parameter symbols. */
+         int nparams = 0, iparams;
+         struct symbol *sym;
+         ALL_BLOCK_SYMBOLS (block, i, sym)
+           {
+             switch (SYMBOL_CLASS (sym))
+               {
+               case LOC_ARG:
+               case LOC_REF_ARG:
+               case LOC_REGPARM:
+               case LOC_REGPARM_ADDR:
+               case LOC_BASEREG_ARG:
+               case LOC_LOCAL_ARG:
+                 nparams++;
+                 break;
+               case LOC_UNDEF:
+               case LOC_CONST:
+               case LOC_STATIC:
+               case LOC_INDIRECT:
+               case LOC_REGISTER:
+               case LOC_LOCAL:
+               case LOC_TYPEDEF:
+               case LOC_LABEL:
+               case LOC_BLOCK:
+               case LOC_CONST_BYTES:
+               case LOC_BASEREG:
+               case LOC_UNRESOLVED:
+               case LOC_OPTIMIZED_OUT:
+               default:
+                 break;
+               }
+           }
+         if (nparams > 0)
+           {
+             TYPE_NFIELDS (ftype) = nparams;
+             TYPE_FIELDS (ftype) = (struct field *)
+               TYPE_ALLOC (ftype, nparams * sizeof (struct field));
+
+             for (i = iparams = 0; iparams < nparams; i++)
+               {
+                 sym = BLOCK_SYM (block, i);
+                 switch (SYMBOL_CLASS (sym))
+                   {
+                   case LOC_ARG:
+                   case LOC_REF_ARG:
+                   case LOC_REGPARM:
+                   case LOC_REGPARM_ADDR:
+                   case LOC_BASEREG_ARG:
+                   case LOC_LOCAL_ARG:
+                     TYPE_FIELD_TYPE (ftype, iparams) = SYMBOL_TYPE (sym);
+                     TYPE_FIELD_ARTIFICIAL (ftype, iparams) = 0;
+                     iparams++;
+                     break;
+                   case LOC_UNDEF:
+                   case LOC_CONST:
+                   case LOC_STATIC:
+                   case LOC_INDIRECT:
+                   case LOC_REGISTER:
+                   case LOC_LOCAL:
+                   case LOC_TYPEDEF:
+                   case LOC_LABEL:
+                   case LOC_BLOCK:
+                   case LOC_CONST_BYTES:
+                   case LOC_BASEREG:
+                   case LOC_UNRESOLVED:
+                   case LOC_OPTIMIZED_OUT:
+                   default:
+                     break;
+                   }
+               }
+           }
+       }
+    }
+  else
+    {
+      BLOCK_FUNCTION (block) = NULL;
+      BLOCK_HASHTABLE (block) = 1;
+    }
+
+  /* Now "free" the links of the list, and empty the list.  */
+
+  for (next = *listhead; next; next = next1)
+    {
+      next1 = next->next;
+      next->next = free_pendings;
+      free_pendings = next;
+    }
+  *listhead = NULL;
+
+#if 1
+  /* Check to be sure that the blocks have an end address that is
+     greater than starting address */
+
+  if (BLOCK_END (block) < BLOCK_START (block))
+    {
+      if (symbol)
+       {
+         complain (&block_end_complaint, SYMBOL_SOURCE_NAME (symbol));
+       }
+      else
+       {
+         complain (&anon_block_end_complaint, BLOCK_END (block), BLOCK_START (block));
+       }
+      /* Better than nothing */
+      BLOCK_END (block) = BLOCK_START (block);
+    }
+#endif
+
+  /* Install this block as the superblock of all blocks made since the
+     start of this scope that don't have superblocks yet.  */
+
+  opblock = NULL;
+  for (pblock = pending_blocks; 
+       pblock && pblock != old_blocks; 
+       pblock = pblock->next)
+    {
+      if (BLOCK_SUPERBLOCK (pblock->block) == NULL)
+       {
+#if 1
+         /* Check to be sure the blocks are nested as we receive
+            them. If the compiler/assembler/linker work, this just
+            burns a small amount of time.  */
+         if (BLOCK_START (pblock->block) < BLOCK_START (block) ||
+             BLOCK_END (pblock->block) > BLOCK_END (block))
+           {
+             if (symbol)
+               {
+                 complain (&innerblock_complaint,
+                           SYMBOL_SOURCE_NAME (symbol));
+               }
+             else
+               {
+                 complain (&innerblock_anon_complaint, BLOCK_START (pblock->block),
+                           BLOCK_END (pblock->block), BLOCK_START (block),
+                           BLOCK_END (block));
+               }
+             if (BLOCK_START (pblock->block) < BLOCK_START (block))
+               BLOCK_START (pblock->block) = BLOCK_START (block);
+             if (BLOCK_END (pblock->block) > BLOCK_END (block))
+               BLOCK_END (pblock->block) = BLOCK_END (block);
+           }
+#endif
+         BLOCK_SUPERBLOCK (pblock->block) = block;
+       }
+      opblock = pblock;
+    }
+
+  record_pending_block (objfile, block, opblock);
+}
+
+/* Record BLOCK on the list of all blocks in the file.  Put it after
+   OPBLOCK, or at the beginning if opblock is NULL.  This puts the
+   block in the list after all its subblocks.
+
+   Allocate the pending block struct in the symbol_obstack to save
+   time.  This wastes a little space.  FIXME: Is it worth it?  */
+
+void
+record_pending_block (struct objfile *objfile, struct block *block,
+                     struct pending_block *opblock)
+{
+  register struct pending_block *pblock;
+
+  pblock = (struct pending_block *)
+    obstack_alloc (&objfile->symbol_obstack, sizeof (struct pending_block));
+  pblock->block = block;
+  if (opblock)
+    {
+      pblock->next = opblock->next;
+      opblock->next = pblock;
+    }
+  else
+    {
+      pblock->next = pending_blocks;
+      pending_blocks = pblock;
+    }
+}
+
+/* OBSOLETE Note that this is only used in this file and in dstread.c, which */
+/* OBSOLETE should be fixed to not need direct access to this function.  When */
+/* OBSOLETE that is done, it can be made static again. */
+
+static struct blockvector *
+make_blockvector (struct objfile *objfile)
+{
+  register struct pending_block *next;
+  register struct blockvector *blockvector;
+  register int i;
+
+  /* Count the length of the list of blocks.  */
+
+  for (next = pending_blocks, i = 0; next; next = next->next, i++)
+    {;
+    }
+
+  blockvector = (struct blockvector *)
+    obstack_alloc (&objfile->symbol_obstack,
+                  (sizeof (struct blockvector)
+                   + (i - 1) * sizeof (struct block *)));
+
+  /* Copy the blocks into the blockvector. This is done in reverse
+     order, which happens to put the blocks into the proper order
+     (ascending starting address). finish_block has hair to insert
+     each block into the list after its subblocks in order to make
+     sure this is true.  */
+
+  BLOCKVECTOR_NBLOCKS (blockvector) = i;
+  for (next = pending_blocks; next; next = next->next)
+    {
+      BLOCKVECTOR_BLOCK (blockvector, --i) = next->block;
+    }
+
+#if 0                          /* Now we make the links in the
+                                  obstack, so don't free them.  */
+  /* Now free the links of the list, and empty the list.  */
+
+  for (next = pending_blocks; next; next = next1)
+    {
+      next1 = next->next;
+      xfree (next);
+    }
+#endif
+  pending_blocks = NULL;
+
+#if 1                          /* FIXME, shut this off after a while
+                                  to speed up symbol reading.  */
+  /* Some compilers output blocks in the wrong order, but we depend on
+     their being in the right order so we can binary search. Check the
+     order and moan about it.  FIXME.  */
+  if (BLOCKVECTOR_NBLOCKS (blockvector) > 1)
+    {
+      for (i = 1; i < BLOCKVECTOR_NBLOCKS (blockvector); i++)
+       {
+         if (BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i - 1))
+             > BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i)))
+           {
+             CORE_ADDR start
+               = BLOCK_START (BLOCKVECTOR_BLOCK (blockvector, i));
+
+             complain (&blockvector_complaint,
+                       local_hex_string ((LONGEST) start));
+           }
+       }
+    }
+#endif
+
+  return (blockvector);
+}
+\f
+/* Start recording information about source code that came from an
+   included (or otherwise merged-in) source file with a different
+   name.  NAME is the name of the file (cannot be NULL), DIRNAME is
+   the directory in which it resides (or NULL if not known).  */
+
+void
+start_subfile (char *name, char *dirname)
+{
+  register struct subfile *subfile;
+
+  /* See if this subfile is already known as a subfile of the current
+     main source file.  */
+
+  for (subfile = subfiles; subfile; subfile = subfile->next)
+    {
+      if (FILENAME_CMP (subfile->name, name) == 0)
+       {
+         current_subfile = subfile;
+         return;
+       }
+    }
+
+  /* This subfile is not known.  Add an entry for it. Make an entry
+     for this subfile in the list of all subfiles of the current main
+     source file.  */
+
+  subfile = (struct subfile *) xmalloc (sizeof (struct subfile));
+  memset ((char *) subfile, 0, sizeof (struct subfile));
+  subfile->next = subfiles;
+  subfiles = subfile;
+  current_subfile = subfile;
+
+  /* Save its name and compilation directory name */
+  subfile->name = (name == NULL) ? NULL : savestring (name, strlen (name));
+  subfile->dirname =
+    (dirname == NULL) ? NULL : savestring (dirname, strlen (dirname));
+
+  /* Initialize line-number recording for this subfile.  */
+  subfile->line_vector = NULL;
+
+  /* Default the source language to whatever can be deduced from the
+     filename.  If nothing can be deduced (such as for a C/C++ include
+     file with a ".h" extension), then inherit whatever language the
+     previous subfile had.  This kludgery is necessary because there
+     is no standard way in some object formats to record the source
+     language.  Also, when symtabs are allocated we try to deduce a
+     language then as well, but it is too late for us to use that
+     information while reading symbols, since symtabs aren't allocated
+     until after all the symbols have been processed for a given
+     source file. */
+
+  subfile->language = deduce_language_from_filename (subfile->name);
+  if (subfile->language == language_unknown &&
+      subfile->next != NULL)
+    {
+      subfile->language = subfile->next->language;
+    }
+
+  /* Initialize the debug format string to NULL.  We may supply it
+     later via a call to record_debugformat. */
+  subfile->debugformat = NULL;
+
+  /* cfront output is a C program, so in most ways it looks like a C
+     program.  But to demangle we need to set the language to C++.  We
+     can distinguish cfront code by the fact that it has #line
+     directives which specify a file name ending in .C.
+
+     So if the filename of this subfile ends in .C, then change the
+     language of any pending subfiles from C to C++.  We also accept
+     any other C++ suffixes accepted by deduce_language_from_filename
+     (in particular, some people use .cxx with cfront).  */
+  /* Likewise for f2c.  */
+
+  if (subfile->name)
+    {
+      struct subfile *s;
+      enum language sublang = deduce_language_from_filename (subfile->name);
+
+      if (sublang == language_cplus || sublang == language_fortran)
+       for (s = subfiles; s != NULL; s = s->next)
+         if (s->language == language_c)
+           s->language = sublang;
+    }
+
+  /* And patch up this file if necessary.  */
+  if (subfile->language == language_c
+      && subfile->next != NULL
+      && (subfile->next->language == language_cplus
+         || subfile->next->language == language_fortran))
+    {
+      subfile->language = subfile->next->language;
+    }
+}
+
+/* For stabs readers, the first N_SO symbol is assumed to be the
+   source file name, and the subfile struct is initialized using that
+   assumption.  If another N_SO symbol is later seen, immediately
+   following the first one, then the first one is assumed to be the
+   directory name and the second one is really the source file name.
+
+   So we have to patch up the subfile struct by moving the old name
+   value to dirname and remembering the new name.  Some sanity
+   checking is performed to ensure that the state of the subfile
+   struct is reasonable and that the old name we are assuming to be a
+   directory name actually is (by checking for a trailing '/'). */
+
+void
+patch_subfile_names (struct subfile *subfile, char *name)
+{
+  if (subfile != NULL && subfile->dirname == NULL && subfile->name != NULL
+      && subfile->name[strlen (subfile->name) - 1] == '/')
+    {
+      subfile->dirname = subfile->name;
+      subfile->name = savestring (name, strlen (name));
+      last_source_file = name;
+
+      /* Default the source language to whatever can be deduced from
+         the filename.  If nothing can be deduced (such as for a C/C++
+         include file with a ".h" extension), then inherit whatever
+         language the previous subfile had.  This kludgery is
+         necessary because there is no standard way in some object
+         formats to record the source language.  Also, when symtabs
+         are allocated we try to deduce a language then as well, but
+         it is too late for us to use that information while reading
+         symbols, since symtabs aren't allocated until after all the
+         symbols have been processed for a given source file. */
+
+      subfile->language = deduce_language_from_filename (subfile->name);
+      if (subfile->language == language_unknown &&
+         subfile->next != NULL)
+       {
+         subfile->language = subfile->next->language;
+       }
+    }
+}
+\f
+/* Handle the N_BINCL and N_EINCL symbol types that act like N_SOL for
+   switching source files (different subfiles, as we call them) within
+   one object file, but using a stack rather than in an arbitrary
+   order.  */
+
+void
+push_subfile (void)
+{
+  register struct subfile_stack *tem
+  = (struct subfile_stack *) xmalloc (sizeof (struct subfile_stack));
+
+  tem->next = subfile_stack;
+  subfile_stack = tem;
+  if (current_subfile == NULL || current_subfile->name == NULL)
+    {
+      internal_error (__FILE__, __LINE__, "failed internal consistency check");
+    }
+  tem->name = current_subfile->name;
+}
+
+char *
+pop_subfile (void)
+{
+  register char *name;
+  register struct subfile_stack *link = subfile_stack;
+
+  if (link == NULL)
+    {
+      internal_error (__FILE__, __LINE__, "failed internal consistency check");
+    }
+  name = link->name;
+  subfile_stack = link->next;
+  xfree ((void *) link);
+  return (name);
+}
+\f
+/* Add a linetable entry for line number LINE and address PC to the
+   line vector for SUBFILE.  */
+
+void
+record_line (register struct subfile *subfile, int line, CORE_ADDR pc)
+{
+  struct linetable_entry *e;
+  /* Ignore the dummy line number in libg.o */
+
+  if (line == 0xffff)
+    {
+      return;
+    }
+
+  /* Make sure line vector exists and is big enough.  */
+  if (!subfile->line_vector)
+    {
+      subfile->line_vector_length = INITIAL_LINE_VECTOR_LENGTH;
+      subfile->line_vector = (struct linetable *)
+       xmalloc (sizeof (struct linetable)
+          + subfile->line_vector_length * sizeof (struct linetable_entry));
+      subfile->line_vector->nitems = 0;
+      have_line_numbers = 1;
+    }
+
+  if (subfile->line_vector->nitems + 1 >= subfile->line_vector_length)
+    {
+      subfile->line_vector_length *= 2;
+      subfile->line_vector = (struct linetable *)
+       xrealloc ((char *) subfile->line_vector,
+                 (sizeof (struct linetable)
+                  + (subfile->line_vector_length
+                     * sizeof (struct linetable_entry))));
+    }
+
+  e = subfile->line_vector->item + subfile->line_vector->nitems++;
+  e->line = line;
+  e->pc = ADDR_BITS_REMOVE(pc);
+}
+
+/* Needed in order to sort line tables from IBM xcoff files.  Sigh!  */
+
+static int
+compare_line_numbers (const void *ln1p, const void *ln2p)
+{
+  struct linetable_entry *ln1 = (struct linetable_entry *) ln1p;
+  struct linetable_entry *ln2 = (struct linetable_entry *) ln2p;
+
+  /* Note: this code does not assume that CORE_ADDRs can fit in ints.
+     Please keep it that way.  */
+  if (ln1->pc < ln2->pc)
+    return -1;
+
+  if (ln1->pc > ln2->pc)
+    return 1;
+
+  /* If pc equal, sort by line.  I'm not sure whether this is optimum
+     behavior (see comment at struct linetable in symtab.h).  */
+  return ln1->line - ln2->line;
+}
+\f
+/* Start a new symtab for a new source file.  Called, for example,
+   when a stabs symbol of type N_SO is seen, or when a DWARF
+   TAG_compile_unit DIE is seen.  It indicates the start of data for
+   one original source file.  */
+
+void
+start_symtab (char *name, char *dirname, CORE_ADDR start_addr)
+{
+
+  last_source_file = name;
+  last_source_start_addr = start_addr;
+  file_symbols = NULL;
+  global_symbols = NULL;
+  within_function = 0;
+  have_line_numbers = 0;
+
+  /* Context stack is initially empty.  Allocate first one with room
+     for 10 levels; reuse it forever afterward.  */
+  if (context_stack == NULL)
+    {
+      context_stack_size = INITIAL_CONTEXT_STACK_SIZE;
+      context_stack = (struct context_stack *)
+       xmalloc (context_stack_size * sizeof (struct context_stack));
+    }
+  context_stack_depth = 0;
+
+  /* Initialize the list of sub source files with one entry for this
+     file (the top-level source file).  */
+
+  subfiles = NULL;
+  current_subfile = NULL;
+  start_subfile (name, dirname);
+}
+
+/* Finish the symbol definitions for one main source file, close off
+   all the lexical contexts for that file (creating struct block's for
+   them), then make the struct symtab for that file and put it in the
+   list of all such.
+
+   END_ADDR is the address of the end of the file's text.  SECTION is
+   the section number (in objfile->section_offsets) of the blockvector
+   and linetable.
+
+   Note that it is possible for end_symtab() to return NULL.  In
+   particular, for the DWARF case at least, it will return NULL when
+   it finds a compilation unit that has exactly one DIE, a
+   TAG_compile_unit DIE.  This can happen when we link in an object
+   file that was compiled from an empty source file.  Returning NULL
+   is probably not the correct thing to do, because then gdb will
+   never know about this empty file (FIXME). */
+
+struct symtab *
+end_symtab (CORE_ADDR end_addr, struct objfile *objfile, int section)
+{
+  register struct symtab *symtab = NULL;
+  register struct blockvector *blockvector;
+  register struct subfile *subfile;
+  register struct context_stack *cstk;
+  struct subfile *nextsub;
+
+  /* Finish the lexical context of the last function in the file; pop
+     the context stack.  */
+
+  if (context_stack_depth > 0)
+    {
+      cstk = pop_context ();
+      /* Make a block for the local symbols within.  */
+      finish_block (cstk->name, &local_symbols, cstk->old_blocks,
+                   cstk->start_addr, end_addr, objfile);
+
+      if (context_stack_depth > 0)
+       {
+         /* This is said to happen with SCO.  The old coffread.c
+            code simply emptied the context stack, so we do the
+            same.  FIXME: Find out why it is happening.  This is not
+            believed to happen in most cases (even for coffread.c);
+            it used to be an abort().  */
+         static struct complaint msg =
+         {"Context stack not empty in end_symtab", 0, 0};
+         complain (&msg);
+         context_stack_depth = 0;
+       }
+    }
+
+  /* Reordered executables may have out of order pending blocks; if
+     OBJF_REORDERED is true, then sort the pending blocks.  */
+  if ((objfile->flags & OBJF_REORDERED) && pending_blocks)
+    {
+      /* FIXME!  Remove this horrid bubble sort and use merge sort!!! */
+      int swapped;
+      do
+       {
+         struct pending_block *pb, *pbnext;
+
+         pb = pending_blocks;
+         pbnext = pb->next;
+         swapped = 0;
+
+         while (pbnext)
+           {
+             /* swap blocks if unordered! */
+
+             if (BLOCK_START (pb->block) < BLOCK_START (pbnext->block))
+               {
+                 struct block *tmp = pb->block;
+                 pb->block = pbnext->block;
+                 pbnext->block = tmp;
+                 swapped = 1;
+               }
+             pb = pbnext;
+             pbnext = pbnext->next;
+           }
+       }
+      while (swapped);
+    }
+
+  /* Cleanup any undefined types that have been left hanging around
+     (this needs to be done before the finish_blocks so that
+     file_symbols is still good).
+
+     Both cleanup_undefined_types and finish_global_stabs are stabs
+     specific, but harmless for other symbol readers, since on gdb
+     startup or when finished reading stabs, the state is set so these
+     are no-ops.  FIXME: Is this handled right in case of QUIT?  Can
+     we make this cleaner?  */
+
+  cleanup_undefined_types ();
+  finish_global_stabs (objfile);
+
+  if (pending_blocks == NULL
+      && file_symbols == NULL
+      && global_symbols == NULL
+      && have_line_numbers == 0
+      && pending_macros == NULL)
+    {
+      /* Ignore symtabs that have no functions with real debugging
+         info.  */
+      blockvector = NULL;
+    }
+  else
+    {
+      /* Define the STATIC_BLOCK & GLOBAL_BLOCK, and build the
+         blockvector.  */
+      finish_block (0, &file_symbols, 0, last_source_start_addr, end_addr,
+                   objfile);
+      finish_block (0, &global_symbols, 0, last_source_start_addr, end_addr,
+                   objfile);
+      blockvector = make_blockvector (objfile);
+    }
+
+#ifndef PROCESS_LINENUMBER_HOOK
+#define PROCESS_LINENUMBER_HOOK()
+#endif
+  PROCESS_LINENUMBER_HOOK ();  /* Needed for xcoff. */
+
+  /* Now create the symtab objects proper, one for each subfile.  */
+  /* (The main file is the last one on the chain.)  */
+
+  for (subfile = subfiles; subfile; subfile = nextsub)
+    {
+      int linetablesize = 0;
+      symtab = NULL;
+
+      /* If we have blocks of symbols, make a symtab. Otherwise, just
+         ignore this file and any line number info in it.  */
+      if (blockvector)
+       {
+         if (subfile->line_vector)
+           {
+             linetablesize = sizeof (struct linetable) +
+               subfile->line_vector->nitems * sizeof (struct linetable_entry);
+#if 0
+             /* I think this is artifact from before it went on the
+                obstack. I doubt we'll need the memory between now
+                and when we free it later in this function.  */
+             /* First, shrink the linetable to make more memory.  */
+             subfile->line_vector = (struct linetable *)
+               xrealloc ((char *) subfile->line_vector, linetablesize);
+#endif
+
+             /* Like the pending blocks, the line table may be
+                scrambled in reordered executables.  Sort it if
+                OBJF_REORDERED is true.  */
+             if (objfile->flags & OBJF_REORDERED)
+               qsort (subfile->line_vector->item,
+                      subfile->line_vector->nitems,
+                    sizeof (struct linetable_entry), compare_line_numbers);
+           }
+
+         /* Now, allocate a symbol table.  */
+         symtab = allocate_symtab (subfile->name, objfile);
+
+         /* Fill in its components.  */
+         symtab->blockvector = blockvector;
+          symtab->macro_table = pending_macros;
+         if (subfile->line_vector)
+           {
+             /* Reallocate the line table on the symbol obstack */
+             symtab->linetable = (struct linetable *)
+               obstack_alloc (&objfile->symbol_obstack, linetablesize);
+             memcpy (symtab->linetable, subfile->line_vector, linetablesize);
+           }
+         else
+           {
+             symtab->linetable = NULL;
+           }
+         symtab->block_line_section = section;
+         if (subfile->dirname)
+           {
+             /* Reallocate the dirname on the symbol obstack */
+             symtab->dirname = (char *)
+               obstack_alloc (&objfile->symbol_obstack,
+                              strlen (subfile->dirname) + 1);
+             strcpy (symtab->dirname, subfile->dirname);
+           }
+         else
+           {
+             symtab->dirname = NULL;
+           }
+         symtab->free_code = free_linetable;
+         symtab->free_ptr = NULL;
+
+         /* Use whatever language we have been using for this
+            subfile, not the one that was deduced in allocate_symtab
+            from the filename.  We already did our own deducing when
+            we created the subfile, and we may have altered our
+            opinion of what language it is from things we found in
+            the symbols. */
+         symtab->language = subfile->language;
+
+         /* Save the debug format string (if any) in the symtab */
+         if (subfile->debugformat != NULL)
+           {
+             symtab->debugformat = obsavestring (subfile->debugformat,
+                                             strlen (subfile->debugformat),
+                                                 &objfile->symbol_obstack);
+           }
+
+         /* All symtabs for the main file and the subfiles share a
+            blockvector, so we need to clear primary for everything
+            but the main file.  */
+
+         symtab->primary = 0;
+       }
+      if (subfile->name != NULL)
+       {
+         xfree ((void *) subfile->name);
+       }
+      if (subfile->dirname != NULL)
+       {
+         xfree ((void *) subfile->dirname);
+       }
+      if (subfile->line_vector != NULL)
+       {
+         xfree ((void *) subfile->line_vector);
+       }
+      if (subfile->debugformat != NULL)
+       {
+         xfree ((void *) subfile->debugformat);
+       }
+
+      nextsub = subfile->next;
+      xfree ((void *) subfile);
+    }
+
+  /* Set this for the main source file.  */
+  if (symtab)
+    {
+      symtab->primary = 1;
+    }
+
+  last_source_file = NULL;
+  current_subfile = NULL;
+  pending_macros = NULL;
+
+  return symtab;
+}
+
+/* Push a context block.  Args are an identifying nesting level
+   (checkable when you pop it), and the starting PC address of this
+   context.  */
+
+struct context_stack *
+push_context (int desc, CORE_ADDR valu)
+{
+  register struct context_stack *new;
+
+  if (context_stack_depth == context_stack_size)
+    {
+      context_stack_size *= 2;
+      context_stack = (struct context_stack *)
+       xrealloc ((char *) context_stack,
+                 (context_stack_size * sizeof (struct context_stack)));
+    }
+
+  new = &context_stack[context_stack_depth++];
+  new->depth = desc;
+  new->locals = local_symbols;
+  new->params = param_symbols;
+  new->old_blocks = pending_blocks;
+  new->start_addr = valu;
+  new->name = NULL;
+
+  local_symbols = NULL;
+  param_symbols = NULL;
+
+  return new;
+}
+\f
+
+/* Compute a small integer hash code for the given name. */
+
+int
+hashname (char *name)
+{
+    return (hash(name,strlen(name)) % HASHSIZE);
+}
+\f
+
+void
+record_debugformat (char *format)
+{
+  current_subfile->debugformat = savestring (format, strlen (format));
+}
+
+/* Merge the first symbol list SRCLIST into the second symbol list
+   TARGETLIST by repeated calls to add_symbol_to_list().  This
+   procedure "frees" each link of SRCLIST by adding it to the
+   free_pendings list.  Caller must set SRCLIST to a null list after
+   calling this function.
+
+   Void return. */
+
+void
+merge_symbol_lists (struct pending **srclist, struct pending **targetlist)
+{
+  register int i;
+
+  if (!srclist || !*srclist)
+    return;
+
+  /* Merge in elements from current link.  */
+  for (i = 0; i < (*srclist)->nsyms; i++)
+    add_symbol_to_list ((*srclist)->symbol[i], targetlist);
+
+  /* Recurse on next.  */
+  merge_symbol_lists (&(*srclist)->next, targetlist);
+
+  /* "Free" the current link.  */
+  (*srclist)->next = free_pendings;
+  free_pendings = (*srclist);
+}
+\f
+/* Initialize anything that needs initializing when starting to read a
+   fresh piece of a symbol file, e.g. reading in the stuff
+   corresponding to a psymtab.  */
+
+void
+buildsym_init (void)
+{
+  free_pendings = NULL;
+  file_symbols = NULL;
+  global_symbols = NULL;
+  pending_blocks = NULL;
+  pending_macros = NULL;
+}
+
+/* Initialize anything that needs initializing when a completely new
+   symbol file is specified (not just adding some symbols from another
+   file, e.g. a shared library).  */
+
+void
+buildsym_new_init (void)
+{
+  buildsym_init ();
+}
diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
new file mode 100644 (file)
index 0000000..3afdebd
--- /dev/null
@@ -0,0 +1,1098 @@
+/* Java language support routines for GDB, the GNU debugger.
+   Copyright 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "gdbtypes.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h"
+#include "value.h"
+#include "c-lang.h"
+#include "jv-lang.h"
+#include "gdbcore.h"
+#include <ctype.h>
+
+struct type *java_int_type;
+struct type *java_byte_type;
+struct type *java_short_type;
+struct type *java_long_type;
+struct type *java_boolean_type;
+struct type *java_char_type;
+struct type *java_float_type;
+struct type *java_double_type;
+struct type *java_void_type;
+
+/* Local functions */
+
+extern void _initialize_java_language (void);
+
+static int java_demangled_signature_length (char *);
+static void java_demangled_signature_copy (char *, char *);
+
+static struct symtab *get_java_class_symtab (void);
+static char *get_java_utf8_name (struct obstack *obstack, struct value *name);
+static int java_class_is_primitive (struct value *clas);
+static struct type *java_lookup_type (char *signature);
+static struct value *java_value_string (char *ptr, int len);
+
+static void java_emit_char (int c, struct ui_file * stream, int quoter);
+
+/* This objfile contains symtabs that have been dynamically created
+   to record dynamically loaded Java classes and dynamically
+   compiled java methods. */
+
+static struct objfile *dynamics_objfile = NULL;
+
+static struct type *java_link_class_type (struct type *, struct value *);
+
+static struct objfile *
+get_dynamics_objfile (void)
+{
+  if (dynamics_objfile == NULL)
+    {
+      dynamics_objfile = allocate_objfile (NULL, 0);
+    }
+  return dynamics_objfile;
+}
+
+#if 1
+/* symtab contains classes read from the inferior. */
+
+static struct symtab *class_symtab = NULL;
+
+/* Maximum number of class in class_symtab before relocation is needed. */
+
+static int class_symtab_space;
+
+static struct symtab *
+get_java_class_symtab (void)
+{
+  if (class_symtab == NULL)
+    {
+      struct objfile *objfile = get_dynamics_objfile ();
+      struct blockvector *bv;
+      struct block *bl;
+      class_symtab = allocate_symtab ("<java-classes>", objfile);
+      class_symtab->language = language_java;
+      bv = (struct blockvector *)
+       obstack_alloc (&objfile->symbol_obstack, sizeof (struct blockvector));
+      BLOCKVECTOR_NBLOCKS (bv) = 1;
+      BLOCKVECTOR (class_symtab) = bv;
+
+      /* Allocate dummy STATIC_BLOCK. */
+      bl = (struct block *)
+       obstack_alloc (&objfile->symbol_obstack, sizeof (struct block));
+      BLOCK_NSYMS (bl) = 0;
+      BLOCK_HASHTABLE (bl) = 0;
+      BLOCK_START (bl) = 0;
+      BLOCK_END (bl) = 0;
+      BLOCK_FUNCTION (bl) = NULL;
+      BLOCK_SUPERBLOCK (bl) = NULL;
+      BLOCK_GCC_COMPILED (bl) = 0;
+      BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
+
+      /* Allocate GLOBAL_BLOCK.  This has to be relocatable. */
+      class_symtab_space = 128;
+      bl = xmmalloc (objfile->md,
+                    sizeof (struct block)
+                    + ((class_symtab_space - 1) * sizeof (struct symbol *)));
+      *bl = *BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+      BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+      class_symtab->free_ptr = (char *) bl;
+    }
+  return class_symtab;
+}
+
+static void
+add_class_symtab_symbol (struct symbol *sym)
+{
+  struct symtab *symtab = get_java_class_symtab ();
+  struct blockvector *bv = BLOCKVECTOR (symtab);
+  struct block *bl = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+  if (BLOCK_NSYMS (bl) >= class_symtab_space)
+    {
+      /* Need to re-allocate. */
+      class_symtab_space *= 2;
+      bl = xmrealloc (symtab->objfile->md, bl,
+                     sizeof (struct block)
+                     + ((class_symtab_space - 1) * sizeof (struct symbol *)));
+      class_symtab->free_ptr = (char *) bl;
+      BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+    }
+
+  BLOCK_SYM (bl, BLOCK_NSYMS (bl)) = sym;
+  BLOCK_NSYMS (bl) = BLOCK_NSYMS (bl) + 1;
+}
+
+static struct symbol *add_class_symbol (struct type *type, CORE_ADDR addr);
+
+static struct symbol *
+add_class_symbol (struct type *type, CORE_ADDR addr)
+{
+  struct symbol *sym;
+  sym = (struct symbol *)
+    obstack_alloc (&dynamics_objfile->symbol_obstack, sizeof (struct symbol));
+  memset (sym, 0, sizeof (struct symbol));
+  SYMBOL_LANGUAGE (sym) = language_java;
+  SYMBOL_NAME (sym) = TYPE_TAG_NAME (type);
+  SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+  /*  SYMBOL_VALUE (sym) = valu; */
+  SYMBOL_TYPE (sym) = type;
+  SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+  SYMBOL_VALUE_ADDRESS (sym) = addr;
+  return sym;
+}
+#endif
+
+struct type *
+java_lookup_class (char *name)
+{
+  struct symbol *sym;
+  sym = lookup_symbol (name, expression_context_block, STRUCT_NAMESPACE,
+                      (int *) 0, (struct symtab **) NULL);
+  if (sym != NULL)
+    return SYMBOL_TYPE (sym);
+#if 0
+  CORE_ADDR addr;
+  if (called from parser)
+    {
+      call lookup_class (or similar) in inferior;
+      if not
+      found:
+       return NULL;
+      addr = found in inferior;
+    }
+  else
+    addr = 0;
+  struct type *type;
+  type = alloc_type (objfile);
+  TYPE_CODE (type) = TYPE_CODE_STRUCT;
+  INIT_CPLUS_SPECIFIC (type);
+  TYPE_TAG_NAME (type) = obsavestring (name, strlen (name), &objfile->type_obstack);
+  TYPE_FLAGS (type) |= TYPE_FLAG_STUB;
+  TYPE ? = addr;
+  return type;
+#else
+  /* FIXME - should search inferior's symbol table. */
+  return NULL;
+#endif
+}
+
+/* Return a nul-terminated string (allocated on OBSTACK) for
+   a name given by NAME (which has type Utf8Const*). */
+
+char *
+get_java_utf8_name (struct obstack *obstack, struct value *name)
+{
+  char *chrs;
+  struct value *temp = name;
+  int name_length;
+  CORE_ADDR data_addr;
+  temp = value_struct_elt (&temp, NULL, "length", NULL, "structure");
+  name_length = (int) value_as_long (temp);
+  data_addr = VALUE_ADDRESS (temp) + VALUE_OFFSET (temp)
+    + TYPE_LENGTH (VALUE_TYPE (temp));
+  chrs = obstack_alloc (obstack, name_length + 1);
+  chrs[name_length] = '\0';
+  read_memory (data_addr, chrs, name_length);
+  return chrs;
+}
+
+struct value *
+java_class_from_object (struct value *obj_val)
+{
+  /* This is all rather inefficient, since the offsets of vtable and
+     class are fixed.  FIXME */
+  struct value *vtable_val;
+
+  if (TYPE_CODE (VALUE_TYPE (obj_val)) == TYPE_CODE_PTR
+      && TYPE_LENGTH (TYPE_TARGET_TYPE (VALUE_TYPE (obj_val))) == 0)
+    obj_val = value_at (get_java_object_type (),
+                       value_as_address (obj_val), NULL);
+
+  vtable_val = value_struct_elt (&obj_val, NULL, "vtable", NULL, "structure");
+  return value_struct_elt (&vtable_val, NULL, "class", NULL, "structure");
+}
+
+/* Check if CLASS_IS_PRIMITIVE(value of clas): */
+static int
+java_class_is_primitive (struct value *clas)
+{
+  struct value *vtable = value_struct_elt (&clas, NULL, "vtable", NULL, "struct");
+  CORE_ADDR i = value_as_address (vtable);
+  return (int) (i & 0x7fffffff) == (int) 0x7fffffff;
+}
+
+/* Read a GCJ Class object, and generated a gdb (TYPE_CODE_STRUCT) type. */
+
+struct type *
+type_from_class (struct value *clas)
+{
+  struct type *type;
+  char *name;
+  struct value *temp;
+  struct objfile *objfile;
+  struct value *utf8_name;
+  char *nptr;
+  CORE_ADDR addr;
+  struct block *bl;
+  int i;
+  int is_array = 0;
+
+  type = check_typedef (VALUE_TYPE (clas));
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    {
+      if (value_logical_not (clas))
+       return NULL;
+      clas = value_ind (clas);
+    }
+  addr = VALUE_ADDRESS (clas) + VALUE_OFFSET (clas);
+
+#if 0
+  get_java_class_symtab ();
+  bl = BLOCKVECTOR_BLOCK (BLOCKVECTOR (class_symtab), GLOBAL_BLOCK);
+  for (i = BLOCK_NSYMS (bl); --i >= 0;)
+    {
+      struct symbol *sym = BLOCK_SYM (bl, i);
+      if (SYMBOL_VALUE_ADDRESS (sym) == addr)
+       return SYMBOL_TYPE (sym);
+    }
+#endif
+
+  objfile = get_dynamics_objfile ();
+  if (java_class_is_primitive (clas))
+    {
+      struct value *sig;
+      temp = clas;
+      sig = value_struct_elt (&temp, NULL, "method_count", NULL, "structure");
+      return java_primitive_type (value_as_long (sig));
+    }
+
+  /* Get Class name. */
+  /* if clasloader non-null, prepend loader address. FIXME */
+  temp = clas;
+  utf8_name = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+  name = get_java_utf8_name (&objfile->type_obstack, utf8_name);
+  for (nptr = name; *nptr != 0; nptr++)
+    {
+      if (*nptr == '/')
+       *nptr = '.';
+    }
+
+  type = java_lookup_class (name);
+  if (type != NULL)
+    return type;
+
+  type = alloc_type (objfile);
+  TYPE_CODE (type) = TYPE_CODE_STRUCT;
+  INIT_CPLUS_SPECIFIC (type);
+
+  if (name[0] == '[')
+    {
+      char *signature = name;
+      int namelen = java_demangled_signature_length (signature);
+      if (namelen > strlen (name))
+       name = obstack_alloc (&objfile->type_obstack, namelen + 1);
+      java_demangled_signature_copy (name, signature);
+      name[namelen] = '\0';
+      is_array = 1;
+      temp = clas;
+      /* Set array element type. */
+      temp = value_struct_elt (&temp, NULL, "methods", NULL, "structure");
+      VALUE_TYPE (temp) = lookup_pointer_type (VALUE_TYPE (clas));
+      TYPE_TARGET_TYPE (type) = type_from_class (temp);
+    }
+
+  ALLOCATE_CPLUS_STRUCT_TYPE (type);
+  TYPE_TAG_NAME (type) = name;
+
+  add_class_symtab_symbol (add_class_symbol (type, addr));
+  return java_link_class_type (type, clas);
+}
+
+/* Fill in class TYPE with data from the CLAS value. */
+
+struct type *
+java_link_class_type (struct type *type, struct value *clas)
+{
+  struct value *temp;
+  char *unqualified_name;
+  char *name = TYPE_TAG_NAME (type);
+  int ninterfaces, nfields, nmethods;
+  int type_is_object = 0;
+  struct fn_field *fn_fields;
+  struct fn_fieldlist *fn_fieldlists;
+  struct value *fields;
+  struct value *methods;
+  struct value *method = NULL;
+  struct value *field = NULL;
+  int i, j;
+  struct objfile *objfile = get_dynamics_objfile ();
+  struct type *tsuper;
+
+  unqualified_name = strrchr (name, '.');
+  if (unqualified_name == NULL)
+    unqualified_name = name;
+
+  temp = clas;
+  temp = value_struct_elt (&temp, NULL, "superclass", NULL, "structure");
+  if (name != NULL && strcmp (name, "java.lang.Object") == 0)
+    {
+      tsuper = get_java_object_type ();
+      if (tsuper && TYPE_CODE (tsuper) == TYPE_CODE_PTR)
+       tsuper = TYPE_TARGET_TYPE (tsuper);
+      type_is_object = 1;
+    }
+  else
+    tsuper = type_from_class (temp);
+
+#if 1
+  ninterfaces = 0;
+#else
+  temp = clas;
+  ninterfaces = value_as_long (value_struct_elt (&temp, NULL, "interface_len", NULL, "structure"));
+#endif
+  TYPE_N_BASECLASSES (type) = (tsuper == NULL ? 0 : 1) + ninterfaces;
+  temp = clas;
+  nfields = value_as_long (value_struct_elt (&temp, NULL, "field_count", NULL, "structure"));
+  nfields += TYPE_N_BASECLASSES (type);
+  nfields++;                   /* Add one for dummy "class" field. */
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field *)
+    TYPE_ALLOC (type, sizeof (struct field) * nfields);
+
+  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+
+  TYPE_FIELD_PRIVATE_BITS (type) =
+    (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+
+  TYPE_FIELD_PROTECTED_BITS (type) =
+    (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
+
+  TYPE_FIELD_IGNORE_BITS (type) =
+    (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_IGNORE_BITS (type), nfields);
+
+  TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *)
+    TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type)));
+  B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type));
+
+  if (tsuper != NULL)
+    {
+      TYPE_BASECLASS (type, 0) = tsuper;
+      if (type_is_object)
+       SET_TYPE_FIELD_PRIVATE (type, 0);
+    }
+
+  i = strlen (name);
+  if (i > 2 && name[i - 1] == ']' && tsuper != NULL)
+    {
+      /* FIXME */
+      TYPE_LENGTH (type) = TYPE_LENGTH (tsuper) + 4;   /* size with "length" */
+    }
+  else
+    {
+      temp = clas;
+      temp = value_struct_elt (&temp, NULL, "size_in_bytes", NULL, "structure");
+      TYPE_LENGTH (type) = value_as_long (temp);
+    }
+
+  fields = NULL;
+  nfields--;                   /* First set up dummy "class" field. */
+  SET_FIELD_PHYSADDR (TYPE_FIELD (type, nfields),
+                     VALUE_ADDRESS (clas) + VALUE_OFFSET (clas));
+  TYPE_FIELD_NAME (type, nfields) = "class";
+  TYPE_FIELD_TYPE (type, nfields) = VALUE_TYPE (clas);
+  SET_TYPE_FIELD_PRIVATE (type, nfields);
+
+  for (i = TYPE_N_BASECLASSES (type); i < nfields; i++)
+    {
+      int accflags;
+      int boffset;
+      if (fields == NULL)
+       {
+         temp = clas;
+         fields = value_struct_elt (&temp, NULL, "fields", NULL, "structure");
+         field = value_ind (fields);
+       }
+      else
+       {                       /* Re-use field value for next field. */
+         VALUE_ADDRESS (field) += TYPE_LENGTH (VALUE_TYPE (field));
+         VALUE_LAZY (field) = 1;
+       }
+      temp = field;
+      temp = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+      TYPE_FIELD_NAME (type, i) =
+       get_java_utf8_name (&objfile->type_obstack, temp);
+      temp = field;
+      accflags = value_as_long (value_struct_elt (&temp, NULL, "accflags",
+                                                 NULL, "structure"));
+      temp = field;
+      temp = value_struct_elt (&temp, NULL, "info", NULL, "structure");
+      boffset = value_as_long (value_struct_elt (&temp, NULL, "boffset",
+                                                NULL, "structure"));
+      if (accflags & 0x0001)   /* public access */
+       {
+         /* ??? */
+       }
+      if (accflags & 0x0002)   /* private access */
+       {
+         SET_TYPE_FIELD_PRIVATE (type, i);
+       }
+      if (accflags & 0x0004)   /* protected access */
+       {
+         SET_TYPE_FIELD_PROTECTED (type, i);
+       }
+      if (accflags & 0x0008)   /* ACC_STATIC */
+       SET_FIELD_PHYSADDR (TYPE_FIELD (type, i), boffset);
+      else
+       TYPE_FIELD_BITPOS (type, i) = 8 * boffset;
+      if (accflags & 0x8000)   /* FIELD_UNRESOLVED_FLAG */
+       {
+         TYPE_FIELD_TYPE (type, i) = get_java_object_type ();  /* FIXME */
+       }
+      else
+       {
+         struct type *ftype;
+         temp = field;
+         temp = value_struct_elt (&temp, NULL, "type", NULL, "structure");
+         ftype = type_from_class (temp);
+         if (TYPE_CODE (ftype) == TYPE_CODE_STRUCT)
+           ftype = lookup_pointer_type (ftype);
+         TYPE_FIELD_TYPE (type, i) = ftype;
+       }
+    }
+
+  temp = clas;
+  nmethods = value_as_long (value_struct_elt (&temp, NULL, "method_count",
+                                             NULL, "structure"));
+  TYPE_NFN_FIELDS_TOTAL (type) = nmethods;
+  j = nmethods * sizeof (struct fn_field);
+  fn_fields = (struct fn_field *)
+    obstack_alloc (&dynamics_objfile->symbol_obstack, j);
+  memset (fn_fields, 0, j);
+  fn_fieldlists = (struct fn_fieldlist *)
+    alloca (nmethods * sizeof (struct fn_fieldlist));
+
+  methods = NULL;
+  for (i = 0; i < nmethods; i++)
+    {
+      char *mname;
+      int k;
+      if (methods == NULL)
+       {
+         temp = clas;
+         methods = value_struct_elt (&temp, NULL, "methods", NULL, "structure");
+         method = value_ind (methods);
+       }
+      else
+       {                       /* Re-use method value for next method. */
+         VALUE_ADDRESS (method) += TYPE_LENGTH (VALUE_TYPE (method));
+         VALUE_LAZY (method) = 1;
+       }
+
+      /* Get method name. */
+      temp = method;
+      temp = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+      mname = get_java_utf8_name (&objfile->type_obstack, temp);
+      if (strcmp (mname, "<init>") == 0)
+       mname = unqualified_name;
+
+      /* Check for an existing method with the same name.
+       * This makes building the fn_fieldslists an O(nmethods**2)
+       * operation.  That could be using hashing, but I doubt it
+       * is worth it.  Note that we do maintain the order of methods
+       * in the inferior's Method table (as long as that is grouped
+       * by method name), which I think is desirable.  --PB */
+      for (k = 0, j = TYPE_NFN_FIELDS (type);;)
+       {
+         if (--j < 0)
+           {                   /* No match - new method name. */
+             j = TYPE_NFN_FIELDS (type)++;
+             fn_fieldlists[j].name = mname;
+             fn_fieldlists[j].length = 1;
+             fn_fieldlists[j].fn_fields = &fn_fields[i];
+             k = i;
+             break;
+           }
+         if (strcmp (mname, fn_fieldlists[j].name) == 0)
+           {                   /* Found an existing method with the same name. */
+             int l;
+             if (mname != unqualified_name)
+               obstack_free (&objfile->type_obstack, mname);
+             mname = fn_fieldlists[j].name;
+             fn_fieldlists[j].length++;
+             k = i - k;        /* Index of new slot. */
+             /* Shift intervening fn_fields (between k and i) down. */
+             for (l = i; l > k; l--)
+               fn_fields[l] = fn_fields[l - 1];
+             for (l = TYPE_NFN_FIELDS (type); --l > j;)
+               fn_fieldlists[l].fn_fields++;
+             break;
+           }
+         k += fn_fieldlists[j].length;
+       }
+      fn_fields[k].physname = "";
+      fn_fields[k].is_stub = 1;
+      fn_fields[k].type = make_function_type (java_void_type, NULL);   /* FIXME */
+      TYPE_CODE (fn_fields[k].type) = TYPE_CODE_METHOD;
+    }
+
+  j = TYPE_NFN_FIELDS (type) * sizeof (struct fn_fieldlist);
+  TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist *)
+    obstack_alloc (&dynamics_objfile->symbol_obstack, j);
+  memcpy (TYPE_FN_FIELDLISTS (type), fn_fieldlists, j);
+
+  return type;
+}
+
+static struct type *java_object_type;
+
+struct type *
+get_java_object_type (void)
+{
+  if (java_object_type == NULL)
+    {
+      struct symbol *sym;
+      sym = lookup_symbol ("java.lang.Object", NULL, STRUCT_NAMESPACE,
+                          (int *) 0, (struct symtab **) NULL);
+      if (sym == NULL)
+       error ("cannot find java.lang.Object");
+      java_object_type = SYMBOL_TYPE (sym);
+    }
+  return java_object_type;
+}
+
+int
+get_java_object_header_size (void)
+{
+  struct type *objtype = get_java_object_type ();
+  if (objtype == NULL)
+    return (2 * TARGET_PTR_BIT / TARGET_CHAR_BIT);
+  else
+    return TYPE_LENGTH (objtype);
+}
+
+int
+is_object_type (struct type *type)
+{
+  CHECK_TYPEDEF (type);
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    {
+      struct type *ttype = check_typedef (TYPE_TARGET_TYPE (type));
+      char *name;
+      if (TYPE_CODE (ttype) != TYPE_CODE_STRUCT)
+       return 0;
+      while (TYPE_N_BASECLASSES (ttype) > 0)
+       ttype = TYPE_BASECLASS (ttype, 0);
+      name = TYPE_TAG_NAME (ttype);
+      if (name != NULL && strcmp (name, "java.lang.Object") == 0)
+       return 1;
+      name = TYPE_NFIELDS (ttype) > 0 ? TYPE_FIELD_NAME (ttype, 0) : (char *) 0;
+      if (name != NULL && strcmp (name, "vtable") == 0)
+       {
+         if (java_object_type == NULL)
+           java_object_type = type;
+         return 1;
+       }
+    }
+  return 0;
+}
+
+struct type *
+java_primitive_type (int signature)
+{
+  switch (signature)
+    {
+    case 'B':
+      return java_byte_type;
+    case 'S':
+      return java_short_type;
+    case 'I':
+      return java_int_type;
+    case 'J':
+      return java_long_type;
+    case 'Z':
+      return java_boolean_type;
+    case 'C':
+      return java_char_type;
+    case 'F':
+      return java_float_type;
+    case 'D':
+      return java_double_type;
+    case 'V':
+      return java_void_type;
+    }
+  error ("unknown signature '%c' for primitive type", (char) signature);
+}
+
+/* If name[0 .. namelen-1] is the name of a primitive Java type,
+   return that type.  Otherwise, return NULL. */
+
+struct type *
+java_primitive_type_from_name (char *name, int namelen)
+{
+  switch (name[0])
+    {
+    case 'b':
+      if (namelen == 4 && memcmp (name, "byte", 4) == 0)
+       return java_byte_type;
+      if (namelen == 7 && memcmp (name, "boolean", 7) == 0)
+       return java_boolean_type;
+      break;
+    case 'c':
+      if (namelen == 4 && memcmp (name, "char", 4) == 0)
+       return java_char_type;
+    case 'd':
+      if (namelen == 6 && memcmp (name, "double", 6) == 0)
+       return java_double_type;
+      break;
+    case 'f':
+      if (namelen == 5 && memcmp (name, "float", 5) == 0)
+       return java_float_type;
+      break;
+    case 'i':
+      if (namelen == 3 && memcmp (name, "int", 3) == 0)
+       return java_int_type;
+      break;
+    case 'l':
+      if (namelen == 4 && memcmp (name, "long", 4) == 0)
+       return java_long_type;
+      break;
+    case 's':
+      if (namelen == 5 && memcmp (name, "short", 5) == 0)
+       return java_short_type;
+      break;
+    case 'v':
+      if (namelen == 4 && memcmp (name, "void", 4) == 0)
+       return java_void_type;
+      break;
+    }
+  return NULL;
+}
+
+/* Return the length (in bytes) of demangled name of the Java type
+   signature string SIGNATURE. */
+
+static int
+java_demangled_signature_length (char *signature)
+{
+  int array = 0;
+  for (; *signature == '['; signature++)
+    array += 2;                        /* Two chars for "[]". */
+  switch (signature[0])
+    {
+    case 'L':
+      /* Subtract 2 for 'L' and ';'. */
+      return strlen (signature) - 2 + array;
+    default:
+      return strlen (TYPE_NAME (java_primitive_type (signature[0]))) + array;
+    }
+}
+
+/* Demangle the Java type signature SIGNATURE, leaving the result in RESULT. */
+
+static void
+java_demangled_signature_copy (char *result, char *signature)
+{
+  int array = 0;
+  char *ptr;
+  int i;
+  while (*signature == '[')
+    {
+      array++;
+      signature++;
+    }
+  switch (signature[0])
+    {
+    case 'L':
+      /* Subtract 2 for 'L' and ';', but add 1 for final nul. */
+      signature++;
+      ptr = result;
+      for (; *signature != ';' && *signature != '\0'; signature++)
+       {
+         if (*signature == '/')
+           *ptr++ = '.';
+         else
+           *ptr++ = *signature;
+       }
+      break;
+    default:
+      ptr = TYPE_NAME (java_primitive_type (signature[0]));
+      i = strlen (ptr);
+      strcpy (result, ptr);
+      ptr = result + i;
+      break;
+    }
+  while (--array >= 0)
+    {
+      *ptr++ = '[';
+      *ptr++ = ']';
+    }
+}
+
+/* Return the demangled name of the Java type signature string SIGNATURE,
+   as a freshly allocated copy. */
+
+char *
+java_demangle_type_signature (char *signature)
+{
+  int length = java_demangled_signature_length (signature);
+  char *result = xmalloc (length + 1);
+  java_demangled_signature_copy (result, signature);
+  result[length] = '\0';
+  return result;
+}
+
+struct type *
+java_lookup_type (char *signature)
+{
+  switch (signature[0])
+    {
+    case 'L':
+    case '[':
+      error ("java_lookup_type not fully implemented");
+    default:
+      return java_primitive_type (signature[0]);
+    }
+}
+
+/* Return the type of TYPE followed by DIMS pairs of [ ].
+   If DIMS == 0, TYPE is returned. */
+
+struct type *
+java_array_type (struct type *type, int dims)
+{
+  struct type *range_type;
+
+  while (dims-- > 0)
+    {
+      range_type = create_range_type (NULL, builtin_type_int, 0, 0);
+      /* FIXME  This is bogus!  Java arrays are not gdb arrays! */
+      type = create_array_type (NULL, type, range_type);
+    }
+
+  return type;
+}
+
+/* Create a Java string in the inferior from a (Utf8) literal. */
+
+static struct value *
+java_value_string (char *ptr, int len)
+{
+  error ("not implemented - java_value_string");       /* FIXME */
+}
+
+/* Print the character C on STREAM as part of the contents of a literal
+   string whose delimiter is QUOTER.  Note that that format for printing
+   characters and strings is language specific. */
+
+static void
+java_emit_char (int c, struct ui_file *stream, int quoter)
+{
+  switch (c)
+    {
+    case '\\':
+    case '\'':
+      fprintf_filtered (stream, "\\%c", c);
+      break;
+    case '\b':
+      fputs_filtered ("\\b", stream);
+      break;
+    case '\t':
+      fputs_filtered ("\\t", stream);
+      break;
+    case '\n':
+      fputs_filtered ("\\n", stream);
+      break;
+    case '\f':
+      fputs_filtered ("\\f", stream);
+      break;
+    case '\r':
+      fputs_filtered ("\\r", stream);
+      break;
+    default:
+      if (isprint (c))
+       fputc_filtered (c, stream);
+      else
+       fprintf_filtered (stream, "\\u%.4x", (unsigned int) c);
+      break;
+    }
+}
+
+static struct value *
+evaluate_subexp_java (struct type *expect_type, register struct expression *exp,
+                     register int *pos, enum noside noside)
+{
+  int pc = *pos;
+  int i;
+  char *name;
+  enum exp_opcode op = exp->elts[*pos].opcode;
+  struct value *arg1;
+  struct value *arg2;
+  struct type *type;
+  switch (op)
+    {
+    case UNOP_IND:
+      if (noside == EVAL_SKIP)
+       goto standard;
+      (*pos)++;
+      arg1 = evaluate_subexp_java (NULL_TYPE, exp, pos, EVAL_NORMAL);
+      if (is_object_type (VALUE_TYPE (arg1)))
+       {
+         struct type *type;
+
+         type = type_from_class (java_class_from_object (arg1));
+         arg1 = value_cast (lookup_pointer_type (type), arg1);
+       }
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      return value_ind (arg1);
+
+    case BINOP_SUBSCRIPT:
+      (*pos)++;
+      arg1 = evaluate_subexp_with_coercion (exp, pos, noside);
+      arg2 = evaluate_subexp_with_coercion (exp, pos, noside);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      /* If the user attempts to subscript something that is not an
+         array or pointer type (like a plain int variable for example),
+         then report this as an error. */
+
+      COERCE_REF (arg1);
+      type = check_typedef (VALUE_TYPE (arg1));
+      if (TYPE_CODE (type) == TYPE_CODE_PTR)
+       type = check_typedef (TYPE_TARGET_TYPE (type));
+      name = TYPE_NAME (type);
+      if (name == NULL)
+       name = TYPE_TAG_NAME (type);
+      i = name == NULL ? 0 : strlen (name);
+      if (TYPE_CODE (type) == TYPE_CODE_STRUCT
+         && i > 2 && name[i - 1] == ']')
+       {
+         CORE_ADDR address;
+         long length, index;
+         struct type *el_type;
+         char buf4[4];
+
+         struct value *clas = java_class_from_object (arg1);
+         struct value *temp = clas;
+         /* Get CLASS_ELEMENT_TYPE of the array type. */
+         temp = value_struct_elt (&temp, NULL, "methods",
+                                  NULL, "structure");
+         VALUE_TYPE (temp) = VALUE_TYPE (clas);
+         el_type = type_from_class (temp);
+         if (TYPE_CODE (el_type) == TYPE_CODE_STRUCT)
+           el_type = lookup_pointer_type (el_type);
+
+         if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return value_zero (el_type, VALUE_LVAL (arg1));
+         address = value_as_address (arg1);
+         address += JAVA_OBJECT_SIZE;
+         read_memory (address, buf4, 4);
+         length = (long) extract_signed_integer (buf4, 4);
+         index = (long) value_as_long (arg2);
+         if (index >= length || index < 0)
+           error ("array index (%ld) out of bounds (length: %ld)",
+                  index, length);
+         address = (address + 4) + index * TYPE_LENGTH (el_type);
+         return value_at (el_type, address, NULL);
+       }
+      else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+       {
+         if (noside == EVAL_AVOID_SIDE_EFFECTS)
+           return value_zero (TYPE_TARGET_TYPE (type), VALUE_LVAL (arg1));
+         else
+           return value_subscript (arg1, arg2);
+       }
+      if (name)
+       error ("cannot subscript something of type `%s'", name);
+      else
+       error ("cannot subscript requested type");
+
+    case OP_STRING:
+      (*pos)++;
+      i = longest_to_int (exp->elts[pc + 1].longconst);
+      (*pos) += 3 + BYTES_TO_EXP_ELEM (i + 1);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      return java_value_string (&exp->elts[pc + 2].string, i);
+
+    case STRUCTOP_STRUCT:
+      arg1 = evaluate_subexp_standard (expect_type, exp, pos, noside);
+      /* Convert object field (such as TYPE.class) to reference. */
+      if (TYPE_CODE (VALUE_TYPE (arg1)) == TYPE_CODE_STRUCT)
+       arg1 = value_addr (arg1);
+      return arg1;
+    default:
+      break;
+    }
+standard:
+  return evaluate_subexp_standard (expect_type, exp, pos, noside);
+nosideret:
+  return value_from_longest (builtin_type_long, (LONGEST) 1);
+}
+
+static struct type *
+java_create_fundamental_type (struct objfile *objfile, int typeid)
+{
+  switch (typeid)
+    {
+    case FT_VOID:
+      return java_void_type;
+    case FT_BOOLEAN:
+      return java_boolean_type;
+    case FT_CHAR:
+      return java_char_type;
+    case FT_FLOAT:
+      return java_float_type;
+    case FT_DBL_PREC_FLOAT:
+      return java_double_type;
+    case FT_BYTE:
+    case FT_SIGNED_CHAR:
+      return java_byte_type;
+    case FT_SHORT:
+    case FT_SIGNED_SHORT:
+      return java_short_type;
+    case FT_INTEGER:
+    case FT_SIGNED_INTEGER:
+      return java_int_type;
+    case FT_LONG:
+    case FT_SIGNED_LONG:
+      return java_long_type;
+    }
+  return c_create_fundamental_type (objfile, typeid);
+}
+
+/* Table mapping opcodes into strings for printing operators
+   and precedences of the operators.  */
+
+const struct op_print java_op_print_tab[] =
+{
+  {",", BINOP_COMMA, PREC_COMMA, 0},
+  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
+  {"==", BINOP_EQUAL, PREC_EQUAL, 0},
+  {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+  {"<=", BINOP_LEQ, PREC_ORDER, 0},
+  {">=", BINOP_GEQ, PREC_ORDER, 0},
+  {">", BINOP_GTR, PREC_ORDER, 0},
+  {"<", BINOP_LESS, PREC_ORDER, 0},
+  {">>", BINOP_RSH, PREC_SHIFT, 0},
+  {"<<", BINOP_LSH, PREC_SHIFT, 0},
+#if 0
+  {">>>", BINOP_ ? ? ?, PREC_SHIFT, 0},
+#endif
+  {"+", BINOP_ADD, PREC_ADD, 0},
+  {"-", BINOP_SUB, PREC_ADD, 0},
+  {"*", BINOP_MUL, PREC_MUL, 0},
+  {"/", BINOP_DIV, PREC_MUL, 0},
+  {"%", BINOP_REM, PREC_MUL, 0},
+  {"-", UNOP_NEG, PREC_PREFIX, 0},
+  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+  {"~", UNOP_COMPLEMENT, PREC_PREFIX, 0},
+  {"*", UNOP_IND, PREC_PREFIX, 0},
+#if 0
+  {"instanceof", ? ? ?, ? ? ?, 0},
+#endif
+  {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
+  {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
+  {NULL, 0, 0, 0}
+};
+
+const struct language_defn java_language_defn =
+{
+  "java",                      /* Language name */
+  language_java,
+  c_builtin_types,
+  range_check_off,
+  type_check_off,
+  case_sensitive_on,
+  java_parse,
+  java_error,
+  evaluate_subexp_java,
+  c_printchar,                 /* Print a character constant */
+  c_printstr,                  /* Function to print string constant */
+  java_emit_char,              /* Function to print a single character */
+  java_create_fundamental_type,        /* Create fundamental type in this language */
+  java_print_type,             /* Print a type using appropriate syntax */
+  java_val_print,              /* Print a value using appropriate syntax */
+  java_value_print,            /* Print a top-level value */
+  {"", "", "", ""},            /* Binary format info */
+  {"0%lo", "0", "o", ""},      /* Octal format info */
+  {"%ld", "", "d", ""},                /* Decimal format info */
+  {"0x%lx", "0x", "x", ""},    /* Hex format info */
+  java_op_print_tab,           /* expression operators for printing */
+  0,                           /* not c-style arrays */
+  0,                           /* String lower bound */
+  &builtin_type_char,          /* Type of string elements */
+  LANG_MAGIC
+};
+
+void
+_initialize_java_language (void)
+{
+
+  java_int_type = init_type (TYPE_CODE_INT, 4, 0, "int", NULL);
+  java_short_type = init_type (TYPE_CODE_INT, 2, 0, "short", NULL);
+  java_long_type = init_type (TYPE_CODE_INT, 8, 0, "long", NULL);
+  java_byte_type = init_type (TYPE_CODE_INT, 1, 0, "byte", NULL);
+  java_boolean_type = init_type (TYPE_CODE_BOOL, 1, 0, "boolean", NULL);
+  java_char_type = init_type (TYPE_CODE_CHAR, 2, TYPE_FLAG_UNSIGNED, "char", NULL);
+  java_float_type = init_type (TYPE_CODE_FLT, 4, 0, "float", NULL);
+  java_double_type = init_type (TYPE_CODE_FLT, 8, 0, "double", NULL);
+  java_void_type = init_type (TYPE_CODE_VOID, 1, 0, "void", NULL);
+
+  add_language (&java_language_defn);
+}
+
+/* Cleanup code that should be run on every "run".
+   We should use make_run_cleanup to have this be called.
+   But will that mess up values in value histry?  FIXME */
+
+extern void java_rerun_cleanup (void);
+void
+java_rerun_cleanup (void)
+{
+  if (class_symtab != NULL)
+    {
+      free_symtab (class_symtab);      /* ??? */
+      class_symtab = NULL;
+    }
+  if (dynamics_objfile != NULL)
+    {
+      free_objfile (dynamics_objfile);
+      dynamics_objfile = NULL;
+    }
+
+  java_object_type = NULL;
+}
diff --git a/gdb/symmisc.c b/gdb/symmisc.c
new file mode 100644 (file)
index 0000000..198b2d6
--- /dev/null
@@ -0,0 +1,1087 @@
+/* Do various things to symbol tables (other than lookup), for GDB.
+
+   Copyright 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994,
+   1995, 1996, 1997, 1998, 1999, 2000, 2002 Free Software Foundation,
+   Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "bfd.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "breakpoint.h"
+#include "command.h"
+#include "gdb_obstack.h"
+#include "language.h"
+#include "bcache.h"
+
+#include "gdb_string.h"
+
+#ifndef DEV_TTY
+#define DEV_TTY "/dev/tty"
+#endif
+
+/* Unfortunately for debugging, stderr is usually a macro.  This is painful
+   when calling functions that take FILE *'s from the debugger.
+   So we make a variable which has the same value and which is accessible when
+   debugging GDB with itself.  Because stdin et al need not be constants,
+   we initialize them in the _initialize_symmisc function at the bottom
+   of the file.  */
+FILE *std_in;
+FILE *std_out;
+FILE *std_err;
+
+/* Prototypes for local functions */
+
+static void dump_symtab (struct objfile *, struct symtab *,
+                        struct ui_file *);
+
+static void dump_psymtab (struct objfile *, struct partial_symtab *,
+                         struct ui_file *);
+
+static void dump_msymbols (struct objfile *, struct ui_file *);
+
+static void dump_objfile (struct objfile *);
+
+static int block_depth (struct block *);
+
+static void print_partial_symbols (struct partial_symbol **, int,
+                                  char *, struct ui_file *);
+
+static void free_symtab_block (struct objfile *, struct block *);
+
+void _initialize_symmisc (void);
+
+struct print_symbol_args
+  {
+    struct symbol *symbol;
+    int depth;
+    struct ui_file *outfile;
+  };
+
+static int print_symbol (PTR);
+
+static void free_symtab_block (struct objfile *, struct block *);
+\f
+
+/* Free a struct block <- B and all the symbols defined in that block.  */
+
+static void
+free_symtab_block (struct objfile *objfile, struct block *b)
+{
+  register int i, n;
+  struct symbol *sym, *next_sym;
+
+  n = BLOCK_BUCKETS (b);
+  for (i = 0; i < n; i++)
+    {
+      for (sym = BLOCK_BUCKET (b, i); sym; sym = next_sym)
+       {
+         next_sym = sym->hash_next;
+         xmfree (objfile->md, SYMBOL_NAME (sym));
+         xmfree (objfile->md, (PTR) sym);
+       }
+    }
+  xmfree (objfile->md, (PTR) b);
+}
+
+/* Free all the storage associated with the struct symtab <- S.
+   Note that some symtabs have contents malloc'ed structure by structure,
+   while some have contents that all live inside one big block of memory,
+   and some share the contents of another symbol table and so you should
+   not free the contents on their behalf (except sometimes the linetable,
+   which maybe per symtab even when the rest is not).
+   It is s->free_code that says which alternative to use.  */
+
+void
+free_symtab (register struct symtab *s)
+{
+  register int i, n;
+  register struct blockvector *bv;
+
+  switch (s->free_code)
+    {
+    case free_nothing:
+      /* All the contents are part of a big block of memory (an obstack),
+         and some other symtab is in charge of freeing that block.
+         Therefore, do nothing.  */
+      break;
+
+    case free_contents:
+      /* Here all the contents were malloc'ed structure by structure
+         and must be freed that way.  */
+      /* First free the blocks (and their symbols.  */
+      bv = BLOCKVECTOR (s);
+      n = BLOCKVECTOR_NBLOCKS (bv);
+      for (i = 0; i < n; i++)
+       free_symtab_block (s->objfile, BLOCKVECTOR_BLOCK (bv, i));
+      /* Free the blockvector itself.  */
+      xmfree (s->objfile->md, (PTR) bv);
+      /* Also free the linetable.  */
+
+    case free_linetable:
+      /* Everything will be freed either by our `free_ptr'
+         or by some other symtab, except for our linetable.
+         Free that now.  */
+      if (LINETABLE (s))
+       xmfree (s->objfile->md, (PTR) LINETABLE (s));
+      break;
+    }
+
+  /* If there is a single block of memory to free, free it.  */
+  if (s->free_ptr != NULL)
+    xmfree (s->objfile->md, s->free_ptr);
+
+  /* Free source-related stuff */
+  if (s->line_charpos != NULL)
+    xmfree (s->objfile->md, (PTR) s->line_charpos);
+  if (s->fullname != NULL)
+    xmfree (s->objfile->md, s->fullname);
+  if (s->debugformat != NULL)
+    xmfree (s->objfile->md, s->debugformat);
+  xmfree (s->objfile->md, (PTR) s);
+}
+
+void
+print_symbol_bcache_statistics (void)
+{
+  struct objfile *objfile;
+
+  immediate_quit++;
+  ALL_OBJFILES (objfile)
+  {
+    printf_filtered ("Byte cache statistics for '%s':\n", objfile->name);
+    print_bcache_statistics (objfile->psymbol_cache, "partial symbol cache");
+  }
+  immediate_quit--;
+}
+
+void
+print_objfile_statistics (void)
+{
+  struct objfile *objfile;
+
+  immediate_quit++;
+  ALL_OBJFILES (objfile)
+  {
+    printf_filtered ("Statistics for '%s':\n", objfile->name);
+    if (OBJSTAT (objfile, n_stabs) > 0)
+      printf_filtered ("  Number of \"stab\" symbols read: %d\n",
+                      OBJSTAT (objfile, n_stabs));
+    if (OBJSTAT (objfile, n_minsyms) > 0)
+      printf_filtered ("  Number of \"minimal\" symbols read: %d\n",
+                      OBJSTAT (objfile, n_minsyms));
+    if (OBJSTAT (objfile, n_psyms) > 0)
+      printf_filtered ("  Number of \"partial\" symbols read: %d\n",
+                      OBJSTAT (objfile, n_psyms));
+    if (OBJSTAT (objfile, n_syms) > 0)
+      printf_filtered ("  Number of \"full\" symbols read: %d\n",
+                      OBJSTAT (objfile, n_syms));
+    if (OBJSTAT (objfile, n_types) > 0)
+      printf_filtered ("  Number of \"types\" defined: %d\n",
+                      OBJSTAT (objfile, n_types));
+    if (OBJSTAT (objfile, sz_strtab) > 0)
+      printf_filtered ("  Space used by a.out string tables: %d\n",
+                      OBJSTAT (objfile, sz_strtab));
+    printf_filtered ("  Total memory used for psymbol obstack: %d\n",
+                    obstack_memory_used (&objfile->psymbol_obstack));
+    printf_filtered ("  Total memory used for psymbol cache: %d\n",
+                    bcache_memory_used (objfile->psymbol_cache));
+    printf_filtered ("  Total memory used for macro cache: %d\n",
+                    bcache_memory_used (objfile->macro_cache));
+    printf_filtered ("  Total memory used for symbol obstack: %d\n",
+                    obstack_memory_used (&objfile->symbol_obstack));
+    printf_filtered ("  Total memory used for type obstack: %d\n",
+                    obstack_memory_used (&objfile->type_obstack));
+  }
+  immediate_quit--;
+}
+
+static void
+dump_objfile (struct objfile *objfile)
+{
+  struct symtab *symtab;
+  struct partial_symtab *psymtab;
+
+  printf_filtered ("\nObject file %s:  ", objfile->name);
+  printf_filtered ("Objfile at ");
+  gdb_print_host_address (objfile, gdb_stdout);
+  printf_filtered (", bfd at ");
+  gdb_print_host_address (objfile->obfd, gdb_stdout);
+  printf_filtered (", %d minsyms\n\n",
+                  objfile->minimal_symbol_count);
+
+  if (objfile->psymtabs)
+    {
+      printf_filtered ("Psymtabs:\n");
+      for (psymtab = objfile->psymtabs;
+          psymtab != NULL;
+          psymtab = psymtab->next)
+       {
+         printf_filtered ("%s at ",
+                          psymtab->filename);
+         gdb_print_host_address (psymtab, gdb_stdout);
+         printf_filtered (", ");
+         if (psymtab->objfile != objfile)
+           {
+             printf_filtered ("NOT ON CHAIN!  ");
+           }
+         wrap_here ("  ");
+       }
+      printf_filtered ("\n\n");
+    }
+
+  if (objfile->symtabs)
+    {
+      printf_filtered ("Symtabs:\n");
+      for (symtab = objfile->symtabs;
+          symtab != NULL;
+          symtab = symtab->next)
+       {
+         printf_filtered ("%s at ", symtab->filename);
+         gdb_print_host_address (symtab, gdb_stdout);
+         printf_filtered (", ");
+         if (symtab->objfile != objfile)
+           {
+             printf_filtered ("NOT ON CHAIN!  ");
+           }
+         wrap_here ("  ");
+       }
+      printf_filtered ("\n\n");
+    }
+}
+
+/* Print minimal symbols from this objfile.  */
+
+static void
+dump_msymbols (struct objfile *objfile, struct ui_file *outfile)
+{
+  struct minimal_symbol *msymbol;
+  int index;
+  char ms_type;
+
+  fprintf_filtered (outfile, "\nObject file %s:\n\n", objfile->name);
+  if (objfile->minimal_symbol_count == 0)
+    {
+      fprintf_filtered (outfile, "No minimal symbols found.\n");
+      return;
+    }
+  for (index = 0, msymbol = objfile->msymbols;
+       SYMBOL_NAME (msymbol) != NULL; msymbol++, index++)
+    {
+      switch (msymbol->type)
+       {
+       case mst_unknown:
+         ms_type = 'u';
+         break;
+       case mst_text:
+         ms_type = 'T';
+         break;
+       case mst_solib_trampoline:
+         ms_type = 'S';
+         break;
+       case mst_data:
+         ms_type = 'D';
+         break;
+       case mst_bss:
+         ms_type = 'B';
+         break;
+       case mst_abs:
+         ms_type = 'A';
+         break;
+       case mst_file_text:
+         ms_type = 't';
+         break;
+       case mst_file_data:
+         ms_type = 'd';
+         break;
+       case mst_file_bss:
+         ms_type = 'b';
+         break;
+       default:
+         ms_type = '?';
+         break;
+       }
+      fprintf_filtered (outfile, "[%2d] %c ", index, ms_type);
+      print_address_numeric (SYMBOL_VALUE_ADDRESS (msymbol), 1, outfile);
+      fprintf_filtered (outfile, " %s", SYMBOL_NAME (msymbol));
+      if (SYMBOL_BFD_SECTION (msymbol))
+       fprintf_filtered (outfile, " section %s",
+                         bfd_section_name (objfile->obfd,
+                                           SYMBOL_BFD_SECTION (msymbol)));
+      if (SYMBOL_DEMANGLED_NAME (msymbol) != NULL)
+       {
+         fprintf_filtered (outfile, "  %s", SYMBOL_DEMANGLED_NAME (msymbol));
+       }
+#ifdef SOFUN_ADDRESS_MAYBE_MISSING
+      if (msymbol->filename)
+       fprintf_filtered (outfile, "  %s", msymbol->filename);
+#endif
+      fputs_filtered ("\n", outfile);
+    }
+  if (objfile->minimal_symbol_count != index)
+    {
+      warning ("internal error:  minimal symbol count %d != %d",
+              objfile->minimal_symbol_count, index);
+    }
+  fprintf_filtered (outfile, "\n");
+}
+
+static void
+dump_psymtab (struct objfile *objfile, struct partial_symtab *psymtab,
+             struct ui_file *outfile)
+{
+  int i;
+
+  fprintf_filtered (outfile, "\nPartial symtab for source file %s ",
+                   psymtab->filename);
+  fprintf_filtered (outfile, "(object ");
+  gdb_print_host_address (psymtab, outfile);
+  fprintf_filtered (outfile, ")\n\n");
+  fprintf_unfiltered (outfile, "  Read from object file %s (",
+                     objfile->name);
+  gdb_print_host_address (objfile, outfile);
+  fprintf_unfiltered (outfile, ")\n");
+
+  if (psymtab->readin)
+    {
+      fprintf_filtered (outfile,
+                       "  Full symtab was read (at ");
+      gdb_print_host_address (psymtab->symtab, outfile);
+      fprintf_filtered (outfile, " by function at ");
+      gdb_print_host_address ((PTR) psymtab->read_symtab, outfile);
+      fprintf_filtered (outfile, ")\n");
+    }
+
+  fprintf_filtered (outfile, "  Relocate symbols by ");
+  for (i = 0; i < psymtab->objfile->num_sections; ++i)
+    {
+      if (i != 0)
+       fprintf_filtered (outfile, ", ");
+      wrap_here ("    ");
+      print_address_numeric (ANOFFSET (psymtab->section_offsets, i),
+                            1,
+                            outfile);
+    }
+  fprintf_filtered (outfile, "\n");
+
+  fprintf_filtered (outfile, "  Symbols cover text addresses ");
+  print_address_numeric (psymtab->textlow, 1, outfile);
+  fprintf_filtered (outfile, "-");
+  print_address_numeric (psymtab->texthigh, 1, outfile);
+  fprintf_filtered (outfile, "\n");
+  fprintf_filtered (outfile, "  Depends on %d other partial symtabs.\n",
+                   psymtab->number_of_dependencies);
+  for (i = 0; i < psymtab->number_of_dependencies; i++)
+    {
+      fprintf_filtered (outfile, "    %d ", i);
+      gdb_print_host_address (psymtab->dependencies[i], outfile);
+      fprintf_filtered (outfile, " %s\n",
+                       psymtab->dependencies[i]->filename);
+    }
+  if (psymtab->n_global_syms > 0)
+    {
+      print_partial_symbols (objfile->global_psymbols.list
+                            + psymtab->globals_offset,
+                            psymtab->n_global_syms, "Global", outfile);
+    }
+  if (psymtab->n_static_syms > 0)
+    {
+      print_partial_symbols (objfile->static_psymbols.list
+                            + psymtab->statics_offset,
+                            psymtab->n_static_syms, "Static", outfile);
+    }
+  fprintf_filtered (outfile, "\n");
+}
+
+static void
+dump_symtab (struct objfile *objfile, struct symtab *symtab,
+            struct ui_file *outfile)
+{
+  register int i, j;
+  int len, blen;
+  register struct linetable *l;
+  struct blockvector *bv;
+  struct symbol *sym;
+  register struct block *b;
+  int depth;
+
+  fprintf_filtered (outfile, "\nSymtab for file %s\n", symtab->filename);
+  if (symtab->dirname)
+    fprintf_filtered (outfile, "Compilation directory is %s\n",
+                     symtab->dirname);
+  fprintf_filtered (outfile, "Read from object file %s (", objfile->name);
+  gdb_print_host_address (objfile, outfile);
+  fprintf_filtered (outfile, ")\n");
+  fprintf_filtered (outfile, "Language: %s\n", language_str (symtab->language));
+
+  /* First print the line table.  */
+  l = LINETABLE (symtab);
+  if (l)
+    {
+      fprintf_filtered (outfile, "\nLine table:\n\n");
+      len = l->nitems;
+      for (i = 0; i < len; i++)
+       {
+         fprintf_filtered (outfile, " line %d at ", l->item[i].line);
+         print_address_numeric (l->item[i].pc, 1, outfile);
+         fprintf_filtered (outfile, "\n");
+       }
+    }
+  /* Now print the block info, but only for primary symtabs since we will
+     print lots of duplicate info otherwise. */
+  if (symtab->primary)
+    {
+      fprintf_filtered (outfile, "\nBlockvector:\n\n");
+      bv = BLOCKVECTOR (symtab);
+      len = BLOCKVECTOR_NBLOCKS (bv);
+      for (i = 0; i < len; i++)
+       {
+         b = BLOCKVECTOR_BLOCK (bv, i);
+         depth = block_depth (b) * 2;
+         print_spaces (depth, outfile);
+         fprintf_filtered (outfile, "block #%03d, object at ", i);
+         gdb_print_host_address (b, outfile);
+         if (BLOCK_SUPERBLOCK (b))
+           {
+             fprintf_filtered (outfile, " under ");
+             gdb_print_host_address (BLOCK_SUPERBLOCK (b), outfile);
+           }
+         /* drow/2002-07-10: We could save the total symbols count
+            even if we're using a hashtable, but nothing else but this message
+            wants it.  */
+         blen = BLOCK_BUCKETS (b);
+         if (BLOCK_HASHTABLE (b))
+           fprintf_filtered (outfile, ", %d buckets in ", blen);
+         else
+           fprintf_filtered (outfile, ", %d syms in ", blen);
+         print_address_numeric (BLOCK_START (b), 1, outfile);
+         fprintf_filtered (outfile, "..");
+         print_address_numeric (BLOCK_END (b), 1, outfile);
+         if (BLOCK_FUNCTION (b))
+           {
+             fprintf_filtered (outfile, ", function %s", SYMBOL_NAME (BLOCK_FUNCTION (b)));
+             if (SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)) != NULL)
+               {
+                 fprintf_filtered (outfile, ", %s",
+                               SYMBOL_DEMANGLED_NAME (BLOCK_FUNCTION (b)));
+               }
+           }
+         if (BLOCK_GCC_COMPILED (b))
+           fprintf_filtered (outfile, ", compiled with gcc%d", BLOCK_GCC_COMPILED (b));
+         fprintf_filtered (outfile, "\n");
+         /* Now print each symbol in this block (in no particular order, if
+            we're using a hashtable).  */
+         ALL_BLOCK_SYMBOLS (b, j, sym)
+           {
+             struct print_symbol_args s;
+             s.symbol = sym;
+             s.depth = depth + 1;
+             s.outfile = outfile;
+             catch_errors (print_symbol, &s, "Error printing symbol:\n",
+                           RETURN_MASK_ALL);
+           }
+       }
+      fprintf_filtered (outfile, "\n");
+    }
+  else
+    {
+      fprintf_filtered (outfile, "\nBlockvector same as previous symtab\n\n");
+    }
+}
+
+void
+maintenance_print_symbols (char *args, int from_tty)
+{
+  char **argv;
+  struct ui_file *outfile;
+  struct cleanup *cleanups;
+  char *symname = NULL;
+  char *filename = DEV_TTY;
+  struct objfile *objfile;
+  struct symtab *s;
+
+  dont_repeat ();
+
+  if (args == NULL)
+    {
+      error ("\
+Arguments missing: an output file name and an optional symbol file name");
+    }
+  else if ((argv = buildargv (args)) == NULL)
+    {
+      nomem (0);
+    }
+  cleanups = make_cleanup_freeargv (argv);
+
+  if (argv[0] != NULL)
+    {
+      filename = argv[0];
+      /* If a second arg is supplied, it is a source file name to match on */
+      if (argv[1] != NULL)
+       {
+         symname = argv[1];
+       }
+    }
+
+  filename = tilde_expand (filename);
+  make_cleanup (xfree, filename);
+
+  outfile = gdb_fopen (filename, FOPEN_WT);
+  if (outfile == 0)
+    perror_with_name (filename);
+  make_cleanup_ui_file_delete (outfile);
+
+  immediate_quit++;
+  ALL_SYMTABS (objfile, s)
+    if (symname == NULL || (STREQ (symname, s->filename)))
+    dump_symtab (objfile, s, outfile);
+  immediate_quit--;
+  do_cleanups (cleanups);
+}
+
+/* Print symbol ARGS->SYMBOL on ARGS->OUTFILE.  ARGS->DEPTH says how
+   far to indent.  ARGS is really a struct print_symbol_args *, but is
+   declared as char * to get it past catch_errors.  Returns 0 for error,
+   1 for success.  */
+
+static int
+print_symbol (PTR args)
+{
+  struct symbol *symbol = ((struct print_symbol_args *) args)->symbol;
+  int depth = ((struct print_symbol_args *) args)->depth;
+  struct ui_file *outfile = ((struct print_symbol_args *) args)->outfile;
+
+  print_spaces (depth, outfile);
+  if (SYMBOL_NAMESPACE (symbol) == LABEL_NAMESPACE)
+    {
+      fprintf_filtered (outfile, "label %s at ", SYMBOL_SOURCE_NAME (symbol));
+      print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+      if (SYMBOL_BFD_SECTION (symbol))
+       fprintf_filtered (outfile, " section %s\n",
+                      bfd_section_name (SYMBOL_BFD_SECTION (symbol)->owner,
+                                        SYMBOL_BFD_SECTION (symbol)));
+      else
+       fprintf_filtered (outfile, "\n");
+      return 1;
+    }
+  if (SYMBOL_NAMESPACE (symbol) == STRUCT_NAMESPACE)
+    {
+      if (TYPE_TAG_NAME (SYMBOL_TYPE (symbol)))
+       {
+         LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+       }
+      else
+       {
+         fprintf_filtered (outfile, "%s %s = ",
+                        (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_ENUM
+                         ? "enum"
+                    : (TYPE_CODE (SYMBOL_TYPE (symbol)) == TYPE_CODE_STRUCT
+                       ? "struct" : "union")),
+                           SYMBOL_NAME (symbol));
+         LA_PRINT_TYPE (SYMBOL_TYPE (symbol), "", outfile, 1, depth);
+       }
+      fprintf_filtered (outfile, ";\n");
+    }
+  else
+    {
+      if (SYMBOL_CLASS (symbol) == LOC_TYPEDEF)
+       fprintf_filtered (outfile, "typedef ");
+      if (SYMBOL_TYPE (symbol))
+       {
+         /* Print details of types, except for enums where it's clutter.  */
+         LA_PRINT_TYPE (SYMBOL_TYPE (symbol), SYMBOL_SOURCE_NAME (symbol),
+                        outfile,
+                        TYPE_CODE (SYMBOL_TYPE (symbol)) != TYPE_CODE_ENUM,
+                        depth);
+         fprintf_filtered (outfile, "; ");
+       }
+      else
+       fprintf_filtered (outfile, "%s ", SYMBOL_SOURCE_NAME (symbol));
+
+      switch (SYMBOL_CLASS (symbol))
+       {
+       case LOC_CONST:
+         fprintf_filtered (outfile, "const %ld (0x%lx)",
+                           SYMBOL_VALUE (symbol),
+                           SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_CONST_BYTES:
+         {
+           unsigned i;
+           struct type *type = check_typedef (SYMBOL_TYPE (symbol));
+           fprintf_filtered (outfile, "const %u hex bytes:",
+                             TYPE_LENGTH (type));
+           for (i = 0; i < TYPE_LENGTH (type); i++)
+             fprintf_filtered (outfile, " %02x",
+                               (unsigned) SYMBOL_VALUE_BYTES (symbol)[i]);
+         }
+         break;
+
+       case LOC_STATIC:
+         fprintf_filtered (outfile, "static at ");
+         print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+         if (SYMBOL_BFD_SECTION (symbol))
+           fprintf_filtered (outfile, " section %s",
+                             bfd_section_name
+                             (SYMBOL_BFD_SECTION (symbol)->owner,
+                              SYMBOL_BFD_SECTION (symbol)));
+         break;
+
+       case LOC_INDIRECT:
+         fprintf_filtered (outfile, "extern global at *(");
+         print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+         fprintf_filtered (outfile, "),");
+         break;
+
+       case LOC_REGISTER:
+         fprintf_filtered (outfile, "register %ld", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_ARG:
+         fprintf_filtered (outfile, "arg at offset 0x%lx",
+                           SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_LOCAL_ARG:
+         fprintf_filtered (outfile, "arg at offset 0x%lx from fp",
+                           SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_REF_ARG:
+         fprintf_filtered (outfile, "reference arg at 0x%lx", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_REGPARM:
+         fprintf_filtered (outfile, "parameter register %ld", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_REGPARM_ADDR:
+         fprintf_filtered (outfile, "address parameter register %ld", SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_LOCAL:
+         fprintf_filtered (outfile, "local at offset 0x%lx",
+                           SYMBOL_VALUE (symbol));
+         break;
+
+       case LOC_BASEREG:
+         fprintf_filtered (outfile, "local at 0x%lx from register %d",
+                           SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+         break;
+
+       case LOC_BASEREG_ARG:
+         fprintf_filtered (outfile, "arg at 0x%lx from register %d",
+                           SYMBOL_VALUE (symbol), SYMBOL_BASEREG (symbol));
+         break;
+
+       case LOC_TYPEDEF:
+         break;
+
+       case LOC_LABEL:
+         fprintf_filtered (outfile, "label at ");
+         print_address_numeric (SYMBOL_VALUE_ADDRESS (symbol), 1, outfile);
+         if (SYMBOL_BFD_SECTION (symbol))
+           fprintf_filtered (outfile, " section %s",
+                             bfd_section_name
+                             (SYMBOL_BFD_SECTION (symbol)->owner,
+                              SYMBOL_BFD_SECTION (symbol)));
+         break;
+
+       case LOC_BLOCK:
+         fprintf_filtered (outfile, "block object ");
+         gdb_print_host_address (SYMBOL_BLOCK_VALUE (symbol), outfile);
+         fprintf_filtered (outfile, ", ");
+         print_address_numeric (BLOCK_START (SYMBOL_BLOCK_VALUE (symbol)),
+                                1,
+                                outfile);
+         fprintf_filtered (outfile, "..");
+         print_address_numeric (BLOCK_END (SYMBOL_BLOCK_VALUE (symbol)),
+                                1,
+                                outfile);
+         if (SYMBOL_BFD_SECTION (symbol))
+           fprintf_filtered (outfile, " section %s",
+                             bfd_section_name
+                             (SYMBOL_BFD_SECTION (symbol)->owner,
+                              SYMBOL_BFD_SECTION (symbol)));
+         break;
+
+       case LOC_UNRESOLVED:
+         fprintf_filtered (outfile, "unresolved");
+         break;
+
+       case LOC_OPTIMIZED_OUT:
+         fprintf_filtered (outfile, "optimized out");
+         break;
+
+       default:
+         fprintf_filtered (outfile, "botched symbol class %x",
+                           SYMBOL_CLASS (symbol));
+         break;
+       }
+    }
+  fprintf_filtered (outfile, "\n");
+  return 1;
+}
+
+void
+maintenance_print_psymbols (char *args, int from_tty)
+{
+  char **argv;
+  struct ui_file *outfile;
+  struct cleanup *cleanups;
+  char *symname = NULL;
+  char *filename = DEV_TTY;
+  struct objfile *objfile;
+  struct partial_symtab *ps;
+
+  dont_repeat ();
+
+  if (args == NULL)
+    {
+      error ("print-psymbols takes an output file name and optional symbol file name");
+    }
+  else if ((argv = buildargv (args)) == NULL)
+    {
+      nomem (0);
+    }
+  cleanups = make_cleanup_freeargv (argv);
+
+  if (argv[0] != NULL)
+    {
+      filename = argv[0];
+      /* If a second arg is supplied, it is a source file name to match on */
+      if (argv[1] != NULL)
+       {
+         symname = argv[1];
+       }
+    }
+
+  filename = tilde_expand (filename);
+  make_cleanup (xfree, filename);
+
+  outfile = gdb_fopen (filename, FOPEN_WT);
+  if (outfile == 0)
+    perror_with_name (filename);
+  make_cleanup_ui_file_delete (outfile);
+
+  immediate_quit++;
+  ALL_PSYMTABS (objfile, ps)
+    if (symname == NULL || (STREQ (symname, ps->filename)))
+    dump_psymtab (objfile, ps, outfile);
+  immediate_quit--;
+  do_cleanups (cleanups);
+}
+
+static void
+print_partial_symbols (struct partial_symbol **p, int count, char *what,
+                      struct ui_file *outfile)
+{
+  fprintf_filtered (outfile, "  %s partial symbols:\n", what);
+  while (count-- > 0)
+    {
+      fprintf_filtered (outfile, "    `%s'", SYMBOL_NAME (*p));
+      if (SYMBOL_DEMANGLED_NAME (*p) != NULL)
+       {
+         fprintf_filtered (outfile, "  `%s'", SYMBOL_DEMANGLED_NAME (*p));
+       }
+      fputs_filtered (", ", outfile);
+      switch (SYMBOL_NAMESPACE (*p))
+       {
+       case UNDEF_NAMESPACE:
+         fputs_filtered ("undefined namespace, ", outfile);
+         break;
+       case VAR_NAMESPACE:
+         /* This is the usual thing -- don't print it */
+         break;
+       case STRUCT_NAMESPACE:
+         fputs_filtered ("struct namespace, ", outfile);
+         break;
+       case LABEL_NAMESPACE:
+         fputs_filtered ("label namespace, ", outfile);
+         break;
+       default:
+         fputs_filtered ("<invalid namespace>, ", outfile);
+         break;
+       }
+      switch (SYMBOL_CLASS (*p))
+       {
+       case LOC_UNDEF:
+         fputs_filtered ("undefined", outfile);
+         break;
+       case LOC_CONST:
+         fputs_filtered ("constant int", outfile);
+         break;
+       case LOC_STATIC:
+         fputs_filtered ("static", outfile);
+         break;
+       case LOC_INDIRECT:
+         fputs_filtered ("extern global", outfile);
+         break;
+       case LOC_REGISTER:
+         fputs_filtered ("register", outfile);
+         break;
+       case LOC_ARG:
+         fputs_filtered ("pass by value", outfile);
+         break;
+       case LOC_REF_ARG:
+         fputs_filtered ("pass by reference", outfile);
+         break;
+       case LOC_REGPARM:
+         fputs_filtered ("register parameter", outfile);
+         break;
+       case LOC_REGPARM_ADDR:
+         fputs_filtered ("register address parameter", outfile);
+         break;
+       case LOC_LOCAL:
+         fputs_filtered ("stack parameter", outfile);
+         break;
+       case LOC_TYPEDEF:
+         fputs_filtered ("type", outfile);
+         break;
+       case LOC_LABEL:
+         fputs_filtered ("label", outfile);
+         break;
+       case LOC_BLOCK:
+         fputs_filtered ("function", outfile);
+         break;
+       case LOC_CONST_BYTES:
+         fputs_filtered ("constant bytes", outfile);
+         break;
+       case LOC_LOCAL_ARG:
+         fputs_filtered ("shuffled arg", outfile);
+         break;
+       case LOC_UNRESOLVED:
+         fputs_filtered ("unresolved", outfile);
+         break;
+       case LOC_OPTIMIZED_OUT:
+         fputs_filtered ("optimized out", outfile);
+         break;
+       default:
+         fputs_filtered ("<invalid location>", outfile);
+         break;
+       }
+      fputs_filtered (", ", outfile);
+      print_address_numeric (SYMBOL_VALUE_ADDRESS (*p), 1, outfile);
+      fprintf_filtered (outfile, "\n");
+      p++;
+    }
+}
+
+void
+maintenance_print_msymbols (char *args, int from_tty)
+{
+  char **argv;
+  struct ui_file *outfile;
+  struct cleanup *cleanups;
+  char *filename = DEV_TTY;
+  char *symname = NULL;
+  struct objfile *objfile;
+
+  dont_repeat ();
+
+  if (args == NULL)
+    {
+      error ("print-msymbols takes an output file name and optional symbol file name");
+    }
+  else if ((argv = buildargv (args)) == NULL)
+    {
+      nomem (0);
+    }
+  cleanups = make_cleanup_freeargv (argv);
+
+  if (argv[0] != NULL)
+    {
+      filename = argv[0];
+      /* If a second arg is supplied, it is a source file name to match on */
+      if (argv[1] != NULL)
+       {
+         symname = argv[1];
+       }
+    }
+
+  filename = tilde_expand (filename);
+  make_cleanup (xfree, filename);
+
+  outfile = gdb_fopen (filename, FOPEN_WT);
+  if (outfile == 0)
+    perror_with_name (filename);
+  make_cleanup_ui_file_delete (outfile);
+
+  immediate_quit++;
+  ALL_OBJFILES (objfile)
+    if (symname == NULL || (STREQ (symname, objfile->name)))
+    dump_msymbols (objfile, outfile);
+  immediate_quit--;
+  fprintf_filtered (outfile, "\n\n");
+  do_cleanups (cleanups);
+}
+
+void
+maintenance_print_objfiles (char *ignore, int from_tty)
+{
+  struct objfile *objfile;
+
+  dont_repeat ();
+
+  immediate_quit++;
+  ALL_OBJFILES (objfile)
+    dump_objfile (objfile);
+  immediate_quit--;
+}
+
+/* Check consistency of psymtabs and symtabs.  */
+
+void
+maintenance_check_symtabs (char *ignore, int from_tty)
+{
+  register struct symbol *sym;
+  register struct partial_symbol **psym;
+  register struct symtab *s = NULL;
+  register struct partial_symtab *ps;
+  struct blockvector *bv;
+  register struct objfile *objfile;
+  register struct block *b;
+  int length;
+
+  ALL_PSYMTABS (objfile, ps)
+  {
+    s = PSYMTAB_TO_SYMTAB (ps);
+    if (s == NULL)
+      continue;
+    bv = BLOCKVECTOR (s);
+    b = BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+    psym = ps->objfile->static_psymbols.list + ps->statics_offset;
+    length = ps->n_static_syms;
+    while (length--)
+      {
+       sym = lookup_block_symbol (b, SYMBOL_NAME (*psym),
+                                  NULL, SYMBOL_NAMESPACE (*psym));
+       if (!sym)
+         {
+           printf_filtered ("Static symbol `");
+           puts_filtered (SYMBOL_NAME (*psym));
+           printf_filtered ("' only found in ");
+           puts_filtered (ps->filename);
+           printf_filtered (" psymtab\n");
+         }
+       psym++;
+      }
+    b = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+    psym = ps->objfile->global_psymbols.list + ps->globals_offset;
+    length = ps->n_global_syms;
+    while (length--)
+      {
+       sym = lookup_block_symbol (b, SYMBOL_NAME (*psym),
+                                  NULL, SYMBOL_NAMESPACE (*psym));
+       if (!sym)
+         {
+           printf_filtered ("Global symbol `");
+           puts_filtered (SYMBOL_NAME (*psym));
+           printf_filtered ("' only found in ");
+           puts_filtered (ps->filename);
+           printf_filtered (" psymtab\n");
+         }
+       psym++;
+      }
+    if (ps->texthigh < ps->textlow)
+      {
+       printf_filtered ("Psymtab ");
+       puts_filtered (ps->filename);
+       printf_filtered (" covers bad range ");
+       print_address_numeric (ps->textlow, 1, gdb_stdout);
+       printf_filtered (" - ");
+       print_address_numeric (ps->texthigh, 1, gdb_stdout);
+       printf_filtered ("\n");
+       continue;
+      }
+    if (ps->texthigh == 0)
+      continue;
+    if (ps->textlow < BLOCK_START (b) || ps->texthigh > BLOCK_END (b))
+      {
+       printf_filtered ("Psymtab ");
+       puts_filtered (ps->filename);
+       printf_filtered (" covers ");
+       print_address_numeric (ps->textlow, 1, gdb_stdout);
+       printf_filtered (" - ");
+       print_address_numeric (ps->texthigh, 1, gdb_stdout);
+       printf_filtered (" but symtab covers only ");
+       print_address_numeric (BLOCK_START (b), 1, gdb_stdout);
+       printf_filtered (" - ");
+       print_address_numeric (BLOCK_END (b), 1, gdb_stdout);
+       printf_filtered ("\n");
+      }
+  }
+}
+\f
+
+/* Return the nexting depth of a block within other blocks in its symtab.  */
+
+static int
+block_depth (struct block *block)
+{
+  register int i = 0;
+  while ((block = BLOCK_SUPERBLOCK (block)) != NULL)
+    {
+      i++;
+    }
+  return i;
+}
+\f
+
+/* Increase the space allocated for LISTP, which is probably
+   global_psymbols or static_psymbols. This space will eventually
+   be freed in free_objfile().  */
+
+void
+extend_psymbol_list (register struct psymbol_allocation_list *listp,
+                    struct objfile *objfile)
+{
+  int new_size;
+  if (listp->size == 0)
+    {
+      new_size = 255;
+      listp->list = (struct partial_symbol **)
+       xmmalloc (objfile->md, new_size * sizeof (struct partial_symbol *));
+    }
+  else
+    {
+      new_size = listp->size * 2;
+      listp->list = (struct partial_symbol **)
+       xmrealloc (objfile->md, (char *) listp->list,
+                  new_size * sizeof (struct partial_symbol *));
+    }
+  /* Next assumes we only went one over.  Should be good if
+     program works correctly */
+  listp->next = listp->list + listp->size;
+  listp->size = new_size;
+}
+
+
+/* Do early runtime initializations. */
+void
+_initialize_symmisc (void)
+{
+  std_in = stdin;
+  std_out = stdout;
+  std_err = stderr;
+}