This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[RFC] Symbol table hashing patch


I've taken the patches Daniel Berlin sent me to implement hashed symtabs and
gone over them thoroughly over the past week, and I have something I would
like to see committed.  This is an RFC instead of an RFA because I have a
few small FIXME comments I'd like feedback on first, though.

The general structure of the patch:
  - First of all, I introduced a macro for looking at all the symbols in a
    given block (ALL_BLOCK_SYMBOLS).  I then changed all sites.  This
    changes the order in which symbols will be seen, but with a few
    exceptions (below), that's fine.  The large change in printcmd.c
    is almost entirely whitespace; do not be alarmed unduly :)
  - I fixed a logic bug in msymtab_hash_iw.
  - I added code to lookup_block_symbol to use the hashtable; nothing
    surprising here.
  - Based on some experimentation, and Daniel's patch, I increased
    MINIMAL_SYMBOL_HASH_SIZE; I went over a set of random binaries
    and objfiles on my system, and this seems like a reasonable change.
    The C library, for instance, has 1933 msyms; gdb has 3670 without
    debug info and 7475 with.  A hash table with 349 buckets, while not
    entirely unreasonable, seemed a little small.  This change is
    unrelated to the others, though, if people disagree with it.
  - I went to the other symbol readers et al. which create blocks on their
    own (dstread.c, jv-lang.c, and mdebugread.c), and made sure that
    they marked the blocks they built as unhashed.  Better would be to
    make them use the normal interface for doing this, but without
    any way to test such changes I'm not going to.  I'm a little
    bit nervous about mdebugread.c in particular, but I'm reasonably
    sure that I'm correct.

Now, for the parts I'd like comments on:
  - coffread.c:patch_opaque_types used to walk the symbol table backwards,
    before it was sorted.  Is this important?  From the comments I could
    not tell.
  - Cosmetically, the output of dump_symtab changed.  I don't think it's
    worth sorting just for this.  It causes one testsuite regression,
    which I'll fix by tweaking the testsuite if no one insists on sorting.
  - Daniel noticed a scary block in search_symbols:
          /* Skip the sort if this block is always sorted.  */
          if (!BLOCK_SHOULD_SORT (b))
            sort_block_syms (b);
    BLOCK_SHOULD_SORT was formerly "if the block has more than 40 symbols
    and is not order-sensitive (list of function arguments, etc)".  Sorting
    such a function block seems like a very bad idea.  OK to remove this?
    search_symbols doesn't even need a sorted block; it searches all entries
    anyway.  The results will no longer be sorted; if it is prefered, we can
    sort the results after searching is complete.

-- 
Daniel Jacobowitz                           Carnegie Mellon University
MontaVista Software                         Debian GNU/Linux Developer

2001-10-01  Daniel Jacobowitz  <drow@mvista.com>

	Based on patch from Daniel Berlin <dan@cgsoftware.com>.
	* buildsym.c: Include "demangle.h" for SYMBOL_INIT_DEMANGLED_NAME.
	(finish_block) For non-function blocks, hash the symbol table.  For
	function blocks, mark the symbol table as unhashed.

	* minsyms.c (msymbol_hash): Use better hash function.
	Return hash value without taking modulus.
	(msymbol_hash_iw): Likewise.  Terminate loop at '(' properly.
	(add_minsym_to_hash_table): Take modulus of msymbol_hash's return
	value.
	(add_minsym_to_demangled_hash_table): Likewise for msymbol_hash_iw.
	(lookup_minimal_symbol): Likewise for both.

	* symtab.h (struct block): Add `hashtable' flag.
	(BLOCK_HASHTABLE): New macro.
	(BLOCK_BUCKETS): New macro.
	(BLOCK_BUCKET): New macro.
	(ALL_BLOCK_SYMBOLS): New macro.
	(BLOCK_SHOULD_SORT): Do not sort hashed blocks.
	(struct symbol): Add `hash_next' pointer.

	* symtab.c (lookup_block_symbol): Search using the hash table when
	possible.
	(find_pc_sect_symtab): Use ALL_BLOCK_SYMBOLS.
	(search_symbols): Do not attempt to sort hashed blocks or function
	blocks.  Use ALL_BLOCK_SYMBOLS.
	(make_symbol_completion_list): Use ALL_BLOCK_SYMBOLS.
	(make_symbol_overload_list): Likewise.

	* objfiles.h: Increase MINIMAL_SYMBOL_HASH_SIZE.

	* dstread.c (process_dst_block): Clear hashtable bit for new block.
	(read_dst_symtab): Likewise.
	* jv-lang.c (get_java_class_symtab): Likewise.
	* mdebugread.c: Include "gdb_assert.h".
	(shrink_block): Assert that the block being modified is not hashed.

	* symmisc.c (free_symtab_block): Walk the hash table when freeing
	symbols.
	(dump_symtab): Recognize hashed blocks.  Use ALL_BLOCK_SYMBOLS.

	* breakpoint.c (get_catch_sals):  Use ALL_BLOCK_SYMBOLS.
	* coffread.c (patch_opaque_types): Likewise.
	* objfiles.c (objfile_relocate): Likewise.
	* stack.c (print_block_frame_locals): Likewise.
	(print_block_frame_labels): Likewise.
	(print_frame_arg_vars): Likewise.
	* tracepoint.c (add_local_symbols): Likewise.
	(scope_info): Likewise.
	* printcmd.c (print_frame_args): Likewise.  Assert that
	function blocks do not have hashed symbol tables.

Index: gdb/breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.53
diff -u -p -r1.53 breakpoint.c
--- breakpoint.c	2001/09/18 05:00:48	1.53
+++ breakpoint.c	2001/10/01 22:20:38
@@ -5871,15 +5871,11 @@ get_catch_sals (int this_level_only)
 	  if (blocks_searched[index] == 0)
 	    {
 	      struct block *b = BLOCKVECTOR_BLOCK (bl, index);
-	      int nsyms;
 	      register int i;
 	      register struct symbol *sym;
 
-	      nsyms = BLOCK_NSYMS (b);
-
-	      for (i = 0; i < nsyms; i++)
+	      ALL_BLOCK_SYMBOLS (b, i, sym)
 		{
-		  sym = BLOCK_SYM (b, i);
 		  if (STREQ (SYMBOL_NAME (sym), "default"))
 		    {
 		      if (have_default)
Index: gdb/buildsym.c
===================================================================
RCS file: /cvs/src/src/gdb/buildsym.c,v
retrieving revision 1.11
diff -u -p -r1.11 buildsym.c
--- buildsym.c	2001/04/30 10:30:27	1.11
+++ buildsym.c	2001/10/01 22:20:39
@@ -39,6 +39,7 @@
 #include "language.h"		/* For "longest_local_hex_string_custom" */
 #include "bcache.h"
 #include "filenames.h"		/* For DOSish file names */
+#include "demangle.h"		/* Needed by SYMBOL_INIT_DEMANGLED_NAME */
 /* Ask buildsym.h to define the vars it normally declares `extern'.  */
 #define	EXTERN
 /**/
@@ -239,17 +240,45 @@ finish_block (struct symbol *symbol, str
       /* EMPTY */ ;
     }
 
-  block = (struct block *) obstack_alloc (&objfile->symbol_obstack,
-	    (sizeof (struct block) + ((i - 1) * sizeof (struct symbol *))));
-
   /* Copy the symbols into the block.  */
 
-  BLOCK_NSYMS (block) = i;
-  for (next = *listhead; next; next = next->next)
+  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
     {
-      for (j = next->nsyms - 1; j >= 0; j--)
+      block = (struct block *) 
+	obstack_alloc (&objfile->symbol_obstack,
+		       (sizeof (struct block) + 
+			((i / 5) * sizeof (struct symbol *))));
+      for (j = 0; j < ((i / 5) + 1); j++)
 	{
-	  BLOCK_SYM (block, --i) = next->symbol[j];
+	  BLOCK_BUCKET (block, j) = 0;
+	}
+      BLOCK_BUCKETS (block) = (i / 5) + 1;
+      for (next = *listhead; next; next = next->next)
+	{
+	  for (j = next->nsyms - 1; j >= 0; j--)
+	    {
+	      struct symbol *sym;
+	      unsigned int hash_index;
+	      SYMBOL_INIT_DEMANGLED_NAME (next->symbol[j], &objfile->symbol_obstack);
+	      hash_index = msymbol_hash_iw (SYMBOL_SOURCE_NAME (next->symbol[j]));
+	      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;
+	    }
 	}
     }
 
@@ -267,6 +296,7 @@ finish_block (struct symbol *symbol, str
       struct type *ftype = SYMBOL_TYPE (symbol);
       SYMBOL_BLOCK_VALUE (symbol) = block;
       BLOCK_FUNCTION (block) = symbol;
+      BLOCK_HASHTABLE (block) = 0;
 
       if (TYPE_NFIELDS (ftype) <= 0)
 	{
@@ -348,6 +378,7 @@ finish_block (struct symbol *symbol, str
   else
     {
       BLOCK_FUNCTION (block) = NULL;
+      BLOCK_HASHTABLE (block) = 1;
     }
 
   /* Now "free" the links of the list, and empty the list.  */
Index: gdb/coffread.c
===================================================================
RCS file: /cvs/src/src/gdb/coffread.c,v
retrieving revision 1.20
diff -u -p -r1.20 coffread.c
--- coffread.c	2001/09/20 03:03:39	1.20
+++ coffread.c	2001/10/01 22:20:40
@@ -1446,13 +1446,13 @@ patch_opaque_types (struct symtab *s)
 
   /* Go through the per-file symbols only */
   b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
-  for (i = BLOCK_NSYMS (b) - 1; i >= 0; i--)
+  /* FIXMED: Originally all symbols, in reverse order, before they are sorted.  */
+  ALL_BLOCK_SYMBOLS (b, i, real_sym)
     {
       /* Find completed typedefs to use to fix opaque ones.
          Remove syms from the chain when their types are stored,
          but search the whole chain, as there may be several syms
          from different files with the same name.  */
-      real_sym = BLOCK_SYM (b, i);
       if (SYMBOL_CLASS (real_sym) == LOC_TYPEDEF &&
 	  SYMBOL_NAMESPACE (real_sym) == VAR_NAMESPACE &&
 	  TYPE_CODE (SYMBOL_TYPE (real_sym)) == TYPE_CODE_PTR &&
Index: gdb/dstread.c
===================================================================
RCS file: /cvs/src/src/gdb/dstread.c,v
retrieving revision 1.7
diff -u -p -r1.7 dstread.c
--- dstread.c	2001/03/06 08:21:06	1.7
+++ dstread.c	2001/10/01 22:20:41
@@ -1407,6 +1407,7 @@ process_dst_block (struct objfile *objfi
       symnum++;
     }
   BLOCK_NSYMS (block) = total_symbols;
+  BLOCK_HASHTABLE (block) = 0;
   BLOCK_START (block) = address;
   BLOCK_END (block) = address + size;
   BLOCK_SUPERBLOCK (block) = 0;
@@ -1491,6 +1492,7 @@ read_dst_symtab (struct objfile *objfile
 			     (total_globals - 1) *
 			   sizeof (struct symbol *));
 	  BLOCK_NSYMS (global_block) = total_globals;
+	  BLOCK_HASHTABLE (global_block) = 0;
 	  for (symnum = 0; symnum < total_globals; symnum++)
 	    {
 	      nextsym = dst_global_symbols->next;
Index: gdb/jv-lang.c
===================================================================
RCS file: /cvs/src/src/gdb/jv-lang.c,v
retrieving revision 1.7
diff -u -p -r1.7 jv-lang.c
--- jv-lang.c	2001/03/23 22:48:44	1.7
+++ jv-lang.c	2001/10/01 22:20:42
@@ -106,6 +106,7 @@ get_java_class_symtab (void)
       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;
Index: gdb/mdebugread.c
===================================================================
RCS file: /cvs/src/src/gdb/mdebugread.c,v
retrieving revision 1.15
diff -u -p -r1.15 mdebugread.c
--- mdebugread.c	2001/09/05 02:54:15	1.15
+++ mdebugread.c	2001/10/01 22:20:46
@@ -52,6 +52,7 @@
 #include "stabsread.h"
 #include "complaints.h"
 #include "demangle.h"
+#include "gdb_assert.h"
 
 /* These are needed if the tm.h file does not contain the necessary
    mips specific definitions.  */
@@ -4154,6 +4155,11 @@ shrink_block (struct block *b, struct sy
 				   (sizeof (struct block)
 				    + ((BLOCK_NSYMS (b) - 1)
 				       * sizeof (struct symbol *))));
+
+  /* FIXME: Not worth hashing this block as it's built.  */
+  /* All callers should have created the block with new_block (), which
+     would mean it was not previously hashed.  Make sure.  */
+  gdb_assert (BLOCK_HASHTABLE (new) == 0);
 
   /* Should chase pointers to old one.  Fortunately, that`s just
      the block`s function and inferior blocks */
Index: gdb/minsyms.c
===================================================================
RCS file: /cvs/src/src/gdb/minsyms.c,v
retrieving revision 1.17
diff -u -p -r1.17 minsyms.c
--- minsyms.c	2001/05/29 10:45:10	1.17
+++ minsyms.c	2001/10/01 22:20:47
@@ -96,10 +96,12 @@ msymbol_hash_iw (const char *string)
       while (isspace (*string))
 	++string;
       if (*string && *string != '(')
-	hash = (31 * hash) + *string;
-      ++string;
+        {
+	  hash = hash * 67 + *string - 113;
+	  ++string;
+	}
     }
-  return hash % MINIMAL_SYMBOL_HASH_SIZE;
+  return hash;
 }
 
 /* Compute a hash code for a string.  */
@@ -109,8 +111,8 @@ msymbol_hash (const char *string)
 {
   unsigned int hash = 0;
   for (; *string; ++string)
-    hash = (31 * hash) + *string;
-  return hash % MINIMAL_SYMBOL_HASH_SIZE;
+    hash = hash * 67 + *string - 113;
+  return hash;
 }
 
 /* Add the minimal symbol SYM to an objfile's minsym hash table, TABLE.  */
@@ -120,7 +122,7 @@ add_minsym_to_hash_table (struct minimal
 {
   if (sym->hash_next == NULL)
     {
-      unsigned int hash = msymbol_hash (SYMBOL_NAME (sym));
+      unsigned int hash = msymbol_hash (SYMBOL_NAME (sym)) % MINIMAL_SYMBOL_HASH_SIZE;
       sym->hash_next = table[hash];
       table[hash] = sym;
     }
@@ -134,7 +136,7 @@ add_minsym_to_demangled_hash_table (stru
 {
   if (sym->demangled_hash_next == NULL)
     {
-      unsigned int hash = msymbol_hash_iw (SYMBOL_DEMANGLED_NAME (sym));
+      unsigned int hash = msymbol_hash_iw (SYMBOL_DEMANGLED_NAME (sym)) % MINIMAL_SYMBOL_HASH_SIZE;
       sym->demangled_hash_next = table[hash];
       table[hash] = sym;
     }
@@ -162,8 +164,8 @@ lookup_minimal_symbol (register const ch
   struct minimal_symbol *found_file_symbol = NULL;
   struct minimal_symbol *trampoline_symbol = NULL;
 
-  unsigned int hash = msymbol_hash (name);
-  unsigned int dem_hash = msymbol_hash_iw (name);
+  unsigned int hash = msymbol_hash (name) % MINIMAL_SYMBOL_HASH_SIZE;
+  unsigned int dem_hash = msymbol_hash_iw (name) % MINIMAL_SYMBOL_HASH_SIZE;
 
 #ifdef SOFUN_ADDRESS_MAYBE_MISSING
   if (sfile != NULL)
Index: gdb/objfiles.c
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.c,v
retrieving revision 1.16
diff -u -p -r1.16 objfiles.c
--- objfiles.c	2001/07/05 21:32:39	1.16
+++ objfiles.c	2001/10/01 22:20:53
@@ -557,16 +557,15 @@ objfile_relocate (struct objfile *objfil
       for (i = 0; i < BLOCKVECTOR_NBLOCKS (bv); ++i)
 	{
 	  struct block *b;
+	  struct symbol *sym;
 	  int j;
 
 	  b = BLOCKVECTOR_BLOCK (bv, i);
 	  BLOCK_START (b) += ANOFFSET (delta, s->block_line_section);
 	  BLOCK_END (b) += ANOFFSET (delta, s->block_line_section);
 
-	  for (j = 0; j < BLOCK_NSYMS (b); ++j)
+	  ALL_BLOCK_SYMBOLS (b, j, sym)
 	    {
-	      struct symbol *sym = BLOCK_SYM (b, j);
-
 	      fixup_symbol_section (sym, objfile);
 
 	      /* The RS6000 code from which this was taken skipped
Index: gdb/objfiles.h
===================================================================
RCS file: /cvs/src/src/gdb/objfiles.h,v
retrieving revision 1.8
diff -u -p -r1.8 objfiles.h
--- objfiles.h	2001/03/06 08:21:11	1.8
+++ objfiles.h	2001/10/01 22:20:53
@@ -202,7 +202,7 @@ extern void print_objfile_statistics (vo
 extern void print_symbol_bcache_statistics (void);
 
 /* Number of entries in the minimal symbol hash table.  */
-#define MINIMAL_SYMBOL_HASH_SIZE 349
+#define MINIMAL_SYMBOL_HASH_SIZE 2039
 
 /* Master structure for keeping track of each file from which
    gdb reads symbols.  There are several ways these get allocated: 1.
Index: gdb/printcmd.c
===================================================================
RCS file: /cvs/src/src/gdb/printcmd.c,v
retrieving revision 1.27
diff -u -p -r1.27 printcmd.c
--- printcmd.c	2001/09/12 04:18:08	1.27
+++ printcmd.c	2001/10/01 22:20:54
@@ -38,6 +38,7 @@
 #include "symfile.h"		/* for overlay functions */
 #include "objfiles.h"		/* ditto */
 #include "completer.h"		/* for completion functions */
+#include "gdb_assert.h"
 #ifdef UI_OUT
 #include "ui-out.h"
 #endif
@@ -1806,168 +1807,171 @@ print_frame_args (struct symbol *func, s
   if (func)
     {
       b = SYMBOL_BLOCK_VALUE (func);
+      /* Function blocks are order sensitive, and thus should not be
+	 hashed.  */
+      gdb_assert (BLOCK_HASHTABLE (b) == 0);
       nsyms = BLOCK_NSYMS (b);
-    }
 
-  for (i = 0; i < nsyms; i++)
-    {
-      QUIT;
-      sym = BLOCK_SYM (b, i);
+      ALL_BLOCK_SYMBOLS (b, i, sym);
+        {
+	  QUIT;
+	  sym = BLOCK_SYM (b, i);
 
-      /* Keep track of the highest stack argument offset seen, and
-         skip over any kinds of symbols we don't care about.  */
+	  /* Keep track of the highest stack argument offset seen, and
+	     skip over any kinds of symbols we don't care about.  */
 
-      switch (SYMBOL_CLASS (sym))
-	{
-	case LOC_ARG:
-	case LOC_REF_ARG:
-	  {
-	    long current_offset = SYMBOL_VALUE (sym);
-	    arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
+	  switch (SYMBOL_CLASS (sym))
+	    {
+	    case LOC_ARG:
+	    case LOC_REF_ARG:
+	      {
+		long current_offset = SYMBOL_VALUE (sym);
+		arg_size = TYPE_LENGTH (SYMBOL_TYPE (sym));
 
-	    /* Compute address of next argument by adding the size of
-	       this argument and rounding to an int boundary.  */
-	    current_offset =
-	      ((current_offset + arg_size + sizeof (int) - 1)
-		 & ~(sizeof (int) - 1));
-
-	    /* If this is the highest offset seen yet, set highest_offset.  */
-	    if (highest_offset == -1
-		|| (current_offset > highest_offset))
-	      highest_offset = current_offset;
+		/* Compute address of next argument by adding the size of
+		   this argument and rounding to an int boundary.  */
+		current_offset =
+		  ((current_offset + arg_size + sizeof (int) - 1)
+		   & ~(sizeof (int) - 1));
+
+		/* If this is the highest offset seen yet, set highest_offset.  */
+		if (highest_offset == -1
+		    || (current_offset > highest_offset))
+		  highest_offset = current_offset;
 
-	    /* Add the number of ints we're about to print to args_printed.  */
-	    args_printed += (arg_size + sizeof (int) - 1) / sizeof (int);
-	  }
+		/* Add the number of ints we're about to print to args_printed.  */
+		args_printed += (arg_size + sizeof (int) - 1) / sizeof (int);
+	      }
 
-	  /* We care about types of symbols, but don't need to keep track of
-	     stack offsets in them.  */
-	case LOC_REGPARM:
-	case LOC_REGPARM_ADDR:
-	case LOC_LOCAL_ARG:
-	case LOC_BASEREG_ARG:
-	  break;
-
-	  /* Other types of symbols we just skip over.  */
-	default:
-	  continue;
-	}
+	      /* We care about types of symbols, but don't need to keep track of
+		 stack offsets in them.  */
+	    case LOC_REGPARM:
+	    case LOC_REGPARM_ADDR:
+	    case LOC_LOCAL_ARG:
+	    case LOC_BASEREG_ARG:
+	      break;
+
+	    /* Other types of symbols we just skip over.  */
+	    default:
+	      continue;
+	    }
 
-      /* We have to look up the symbol because arguments can have
-         two entries (one a parameter, one a local) and the one we
-         want is the local, which lookup_symbol will find for us.
-         This includes gcc1 (not gcc2) on the sparc when passing a
-         small structure and gcc2 when the argument type is float
-         and it is passed as a double and converted to float by
-         the prologue (in the latter case the type of the LOC_ARG
-         symbol is double and the type of the LOC_LOCAL symbol is
-         float).  */
-      /* But if the parameter name is null, don't try it.
-         Null parameter names occur on the RS/6000, for traceback tables.
-         FIXME, should we even print them?  */
+	  /* We have to look up the symbol because arguments can have
+	     two entries (one a parameter, one a local) and the one we
+	     want is the local, which lookup_symbol will find for us.
+	     This includes gcc1 (not gcc2) on the sparc when passing a
+	     small structure and gcc2 when the argument type is float
+	     and it is passed as a double and converted to float by
+	     the prologue (in the latter case the type of the LOC_ARG
+	     symbol is double and the type of the LOC_LOCAL symbol is
+	     float).  */
+	  /* But if the parameter name is null, don't try it.
+	     Null parameter names occur on the RS/6000, for traceback tables.
+	     FIXME, should we even print them?  */
 
-      if (*SYMBOL_NAME (sym))
-	{
-	  struct symbol *nsym;
-	  nsym = lookup_symbol
-	    (SYMBOL_NAME (sym),
-	     b, VAR_NAMESPACE, (int *) NULL, (struct symtab **) NULL);
-	  if (SYMBOL_CLASS (nsym) == LOC_REGISTER)
+	  if (*SYMBOL_NAME (sym))
 	    {
-	      /* There is a LOC_ARG/LOC_REGISTER pair.  This means that
-	         it was passed on the stack and loaded into a register,
-	         or passed in a register and stored in a stack slot.
-	         GDB 3.x used the LOC_ARG; GDB 4.0-4.11 used the LOC_REGISTER.
-
-	         Reasons for using the LOC_ARG:
-	         (1) because find_saved_registers may be slow for remote
-	         debugging,
-	         (2) because registers are often re-used and stack slots
-	         rarely (never?) are.  Therefore using the stack slot is
-	         much less likely to print garbage.
-
-	         Reasons why we might want to use the LOC_REGISTER:
-	         (1) So that the backtrace prints the same value as
-	         "print foo".  I see no compelling reason why this needs
-	         to be the case; having the backtrace print the value which
-	         was passed in, and "print foo" print the value as modified
-	         within the called function, makes perfect sense to me.
-
-	         Additional note:  It might be nice if "info args" displayed
-	         both values.
-	         One more note:  There is a case with sparc structure passing
-	         where we need to use the LOC_REGISTER, but this is dealt with
-	         by creating a single LOC_REGPARM in symbol reading.  */
-
-	      /* Leave sym (the LOC_ARG) alone.  */
-	      ;
+	      struct symbol *nsym;
+	      nsym = lookup_symbol
+		(SYMBOL_NAME (sym),
+		 b, VAR_NAMESPACE, (int *) NULL, (struct symtab **) NULL);
+	      if (SYMBOL_CLASS (nsym) == LOC_REGISTER)
+		{
+		  /* There is a LOC_ARG/LOC_REGISTER pair.  This means that
+		     it was passed on the stack and loaded into a register,
+		     or passed in a register and stored in a stack slot.
+		     GDB 3.x used the LOC_ARG; GDB 4.0-4.11 used the LOC_REGISTER.
+
+		     Reasons for using the LOC_ARG:
+		     (1) because find_saved_registers may be slow for remote
+		     debugging,
+		     (2) because registers are often re-used and stack slots
+		     rarely (never?) are.  Therefore using the stack slot is
+		     much less likely to print garbage.
+
+		     Reasons why we might want to use the LOC_REGISTER:
+		     (1) So that the backtrace prints the same value as
+		     "print foo".  I see no compelling reason why this needs
+		     to be the case; having the backtrace print the value which
+		     was passed in, and "print foo" print the value as modified
+		     within the called function, makes perfect sense to me.
+
+		     Additional note:  It might be nice if "info args" displayed
+		     both values.
+		     One more note:  There is a case with sparc structure passing
+		     where we need to use the LOC_REGISTER, but this is dealt with
+		     by creating a single LOC_REGPARM in symbol reading.  */
+
+		  /* Leave sym (the LOC_ARG) alone.  */
+		  ;
+		}
+	      else
+		sym = nsym;
 	    }
-	  else
-	    sym = nsym;
-	}
 
 #ifdef UI_OUT
-      /* Print the current arg.  */
-      if (!first)
-	ui_out_text (uiout, ", ");
-      ui_out_wrap_hint (uiout, "    ");
-
-      annotate_arg_begin ();
-
-      list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
-      fprintf_symbol_filtered (stb->stream, SYMBOL_SOURCE_NAME (sym),
-			    SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
-      ui_out_field_stream (uiout, "name", stb);
-      annotate_arg_name_end ();
-      ui_out_text (uiout, "=");
+	  /* Print the current arg.  */
+	  if (!first)
+	    ui_out_text (uiout, ", ");
+	  ui_out_wrap_hint (uiout, "    ");
+
+	  annotate_arg_begin ();
+
+	  list_chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
+	  fprintf_symbol_filtered (stb->stream, SYMBOL_SOURCE_NAME (sym),
+				   SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
+	  ui_out_field_stream (uiout, "name", stb);
+	  annotate_arg_name_end ();
+	  ui_out_text (uiout, "=");
 #else
-      /* Print the current arg.  */
-      if (!first)
-	fprintf_filtered (stream, ", ");
-      wrap_here ("    ");
-
-      annotate_arg_begin ();
-
-      fprintf_symbol_filtered (stream, SYMBOL_SOURCE_NAME (sym),
-			    SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
-      annotate_arg_name_end ();
-      fputs_filtered ("=", stream);
+	  /* Print the current arg.  */
+	  if (!first)
+	    fprintf_filtered (stream, ", ");
+	  wrap_here ("    ");
+
+	  annotate_arg_begin ();
+
+	  fprintf_symbol_filtered (stream, SYMBOL_SOURCE_NAME (sym),
+				   SYMBOL_LANGUAGE (sym), DMGL_PARAMS | DMGL_ANSI);
+	  annotate_arg_name_end ();
+	  fputs_filtered ("=", stream);
 #endif
 
-      /* Avoid value_print because it will deref ref parameters.  We just
-         want to print their addresses.  Print ??? for args whose address
-         we do not know.  We pass 2 as "recurse" to val_print because our
-         standard indentation here is 4 spaces, and val_print indents
-         2 for each recurse.  */
-      val = read_var_value (sym, fi);
+	  /* Avoid value_print because it will deref ref parameters.  We just
+	     want to print their addresses.  Print ??? for args whose address
+	     we do not know.  We pass 2 as "recurse" to val_print because our
+	     standard indentation here is 4 spaces, and val_print indents
+	     2 for each recurse.  */
+	  val = read_var_value (sym, fi);
 
-      annotate_arg_value (val == NULL ? NULL : VALUE_TYPE (val));
+	  annotate_arg_value (val == NULL ? NULL : VALUE_TYPE (val));
 
-      if (val)
-	{
+	  if (val)
+	    {
 #ifdef UI_OUT
-	  val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
-		     VALUE_ADDRESS (val),
-		     stb->stream, 0, 0, 2, Val_no_prettyprint);
-	  ui_out_field_stream (uiout, "value", stb);
-	}
-      else
-	ui_out_text (uiout, "???");
+	      val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
+			 VALUE_ADDRESS (val),
+			 stb->stream, 0, 0, 2, Val_no_prettyprint);
+	      ui_out_field_stream (uiout, "value", stb);
+	    }
+	  else
+	    ui_out_text (uiout, "???");
 
-      /* Invoke ui_out_tuple_end.  */
-      do_cleanups (list_chain);
+	  /* Invoke ui_out_tuple_end.  */
+	  do_cleanups (list_chain);
 #else
-	  val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
-		     VALUE_ADDRESS (val),
-		     stream, 0, 0, 2, Val_no_prettyprint);
-	}
-      else
-	fputs_filtered ("???", stream);
+	      val_print (VALUE_TYPE (val), VALUE_CONTENTS (val), 0,
+			 VALUE_ADDRESS (val),
+			 stream, 0, 0, 2, Val_no_prettyprint);
+	    }
+	  else
+	    fputs_filtered ("???", stream);
 #endif
 
-      annotate_arg_end ();
+	  annotate_arg_end ();
 
-      first = 0;
+	  first = 0;
+	}
     }
 
   /* Don't print nameless args in situations where we don't know
Index: gdb/stack.c
===================================================================
RCS file: /cvs/src/src/gdb/stack.c,v
retrieving revision 1.22
diff -u -p -r1.22 stack.c
--- stack.c	2001/07/14 18:59:07	1.22
+++ stack.c	2001/10/01 22:20:55
@@ -1207,16 +1207,12 @@ static int
 print_block_frame_locals (struct block *b, register struct frame_info *fi,
 			  int num_tabs, register struct ui_file *stream)
 {
-  int nsyms;
   register int i, j;
   register struct symbol *sym;
   register int values_printed = 0;
 
-  nsyms = BLOCK_NSYMS (b);
-
-  for (i = 0; i < nsyms; i++)
+  ALL_BLOCK_SYMBOLS (b, i, sym)
     {
-      sym = BLOCK_SYM (b, i);
       switch (SYMBOL_CLASS (sym))
 	{
 	case LOC_LOCAL:
@@ -1246,16 +1242,12 @@ static int
 print_block_frame_labels (struct block *b, int *have_default,
 			  register struct ui_file *stream)
 {
-  int nsyms;
   register int i;
   register struct symbol *sym;
   register int values_printed = 0;
-
-  nsyms = BLOCK_NSYMS (b);
 
-  for (i = 0; i < nsyms; i++)
+  ALL_BLOCK_SYMBOLS (b, i, sym)
     {
-      sym = BLOCK_SYM (b, i);
       if (STREQ (SYMBOL_NAME (sym), "default"))
 	{
 	  if (*have_default)
@@ -1432,7 +1424,6 @@ print_frame_arg_vars (register struct fr
 {
   struct symbol *func = get_frame_function (fi);
   register struct block *b;
-  int nsyms;
   register int i;
   register struct symbol *sym, *sym2;
   register int values_printed = 0;
@@ -1444,11 +1435,8 @@ print_frame_arg_vars (register struct fr
     }
 
   b = SYMBOL_BLOCK_VALUE (func);
-  nsyms = BLOCK_NSYMS (b);
-
-  for (i = 0; i < nsyms; i++)
+  ALL_BLOCK_SYMBOLS (b, i, sym)
     {
-      sym = BLOCK_SYM (b, i);
       switch (SYMBOL_CLASS (sym))
 	{
 	case LOC_ARG:
@@ -1483,7 +1471,6 @@ print_frame_arg_vars (register struct fr
 	  break;
 	}
     }
-
   if (!values_printed)
     {
       fprintf_filtered (stream, "No arguments.\n");
Index: gdb/symmisc.c
===================================================================
RCS file: /cvs/src/src/gdb/symmisc.c,v
retrieving revision 1.5
diff -u -p -r1.5 symmisc.c
--- symmisc.c	2001/03/06 08:21:17	1.5
+++ symmisc.c	2001/10/01 22:20:56
@@ -86,11 +86,17 @@ static void
 free_symtab_block (struct objfile *objfile, struct block *b)
 {
   register int i, n;
-  n = BLOCK_NSYMS (b);
+  struct symbol *sym, *next_sym;
+
+  n = BLOCK_BUCKETS (b);
   for (i = 0; i < n; i++)
     {
-      mfree (objfile->md, SYMBOL_NAME (BLOCK_SYM (b, i)));
-      mfree (objfile->md, (PTR) BLOCK_SYM (b, i));
+      for (sym = BLOCK_BUCKET (b, i); sym; sym = next_sym)
+	{
+	  next_sym = sym->hash_next;
+	  mfree (objfile->md, SYMBOL_NAME (sym));
+	  mfree (objfile->md, (PTR) sym);
+	}
     }
   mfree (objfile->md, (PTR) b);
 }
@@ -410,6 +416,7 @@ dump_symtab (struct objfile *objfile, st
   int len, blen;
   register struct linetable *l;
   struct blockvector *bv;
+  struct symbol *sym;
   register struct block *b;
   int depth;
 
@@ -454,8 +461,12 @@ dump_symtab (struct objfile *objfile, st
 	      fprintf_filtered (outfile, " under ");
 	      gdb_print_host_address (BLOCK_SUPERBLOCK (b), outfile);
 	    }
-	  blen = BLOCK_NSYMS (b);
-	  fprintf_filtered (outfile, ", %d syms in ", blen);
+	  /* FIXMED: Save total syms count even if hashed?  */
+	  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);
@@ -471,11 +482,12 @@ dump_symtab (struct objfile *objfile, st
 	  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 */
-	  for (j = 0; j < blen; j++)
+	  /* Now print each symbol in this block.  */
+	  /* FIXMED: Sort?  */
+	  ALL_BLOCK_SYMBOLS (b, j, sym)
 	    {
 	      struct print_symbol_args s;
-	      s.symbol = BLOCK_SYM (b, j);
+	      s.symbol = sym;
 	      s.depth = depth + 1;
 	      s.outfile = outfile;
 	      catch_errors (print_symbol, &s, "Error printing symbol:\n",
Index: gdb/symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.42
diff -u -p -r1.42 symtab.c
--- symtab.c	2001/07/07 17:19:50	1.42
+++ symtab.c	2001/10/01 22:20:57
@@ -1186,6 +1186,20 @@ lookup_block_symbol (register const stru
   register struct symbol *sym_found = NULL;
   register int do_linear_search = 1;
 
+  if (BLOCK_HASHTABLE (block))
+    {
+      unsigned int hash_index;
+      hash_index = msymbol_hash_iw (name);
+      hash_index = hash_index % BLOCK_BUCKETS (block);
+      for (sym = BLOCK_BUCKET (block, hash_index); sym; sym = sym->hash_next)
+	{
+	  if (SYMBOL_NAMESPACE (sym) == namespace 
+	      && SYMBOL_MATCHES_NAME (sym, name))
+	    return sym;
+	}
+      return NULL;
+    }
+
   /* If the blocks's symbols were sorted, start with a binary search.  */
 
   if (BLOCK_SHOULD_SORT (block))
@@ -1414,14 +1428,15 @@ find_pc_sect_symtab (CORE_ADDR pc, asect
 	if (section != 0)
 	  {
 	    int i;
+	    struct symbol *sym = NULL;
 
-	    for (i = 0; i < b->nsyms; i++)
+	    ALL_BLOCK_SYMBOLS (b, i, sym)
 	      {
-		fixup_symbol_section (b->sym[i], objfile);
-		if (section == SYMBOL_BFD_SECTION (b->sym[i]))
+		fixup_symbol_section (sym, objfile);
+		if (section == SYMBOL_BFD_SECTION (sym))
 		  break;
 	      }
-	    if (i >= b->nsyms)
+	    if ((i >= BLOCK_BUCKETS (b)) && (sym == NULL))
 	      continue;		/* no symbol in this symtab matches section */
 	  }
 	distance = BLOCK_END (b) - BLOCK_START (b);
@@ -2513,13 +2528,18 @@ search_symbols (char *regexp, namespace_
       for (i = GLOBAL_BLOCK; i <= STATIC_BLOCK; i++)
 	{
 	  b = BLOCKVECTOR_BLOCK (bv, i);
+	  /* FIXMED: The #if 0'd code seems *very* wrong. It'll sort blocks 
+	     that we specifically are supposed to avoid sorting.  */
+#if 0
+	  
 	  /* Skip the sort if this block is always sorted.  */
 	  if (!BLOCK_SHOULD_SORT (b))
 	    sort_block_syms (b);
-	  for (j = 0; j < BLOCK_NSYMS (b); j++)
+#endif
+	  ALL_BLOCK_SYMBOLS (b, j, sym)
 	    {
 	      QUIT;
-	      sym = BLOCK_SYM (b, j);
+	      /* FIXME: Hoist file_matches out of this loop.  */
 	      if (file_matches (s->filename, files, nfiles)
 		  && ((regexp == NULL || SYMBOL_MATCHES_REGEXP (sym))
 		      && ((kind == VARIABLES_NAMESPACE && SYMBOL_CLASS (sym) != LOC_TYPEDEF
@@ -2546,6 +2566,7 @@ search_symbols (char *regexp, namespace_
 		  tail = psr;
 		}
 	    }
+	  /* FIXMED: Sort the results?  */
 	}
     prev_bv = bv;
   }
@@ -3030,9 +3051,8 @@ make_symbol_completion_list (char *text,
       /* Also catch fields of types defined in this places which match our
          text string.  Only complete on types visible from current context. */
 
-      for (i = 0; i < BLOCK_NSYMS (b); i++)
+      ALL_BLOCK_SYMBOLS (b, i, sym)
 	{
-	  sym = BLOCK_SYM (b, i);
 	  COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
 	  if (SYMBOL_CLASS (sym) == LOC_TYPEDEF)
 	    {
@@ -3061,23 +3081,22 @@ make_symbol_completion_list (char *text,
   {
     QUIT;
     b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
-    for (i = 0; i < BLOCK_NSYMS (b); i++)
+    ALL_BLOCK_SYMBOLS (b, i, sym)
       {
-	sym = BLOCK_SYM (b, i);
 	COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
       }
   }
 
   ALL_SYMTABS (objfile, s)
   {
+    struct symbol *sym;
     QUIT;
     b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
     /* Don't do this block twice.  */
     if (b == surrounding_static_block)
       continue;
-    for (i = 0; i < BLOCK_NSYMS (b); i++)
+    ALL_BLOCK_SYMBOLS (b, i, sym)
       {
-	sym = BLOCK_SYM (b, i);
 	COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
       }
   }
@@ -3181,16 +3200,14 @@ make_file_symbol_completion_list (char *
      symbols which match.  */
 
   b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
-  for (i = 0; i < BLOCK_NSYMS (b); i++)
+  ALL_BLOCK_SYMBOLS (b, i, sym)
     {
-      sym = BLOCK_SYM (b, i);
       COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
     }
 
   b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), STATIC_BLOCK);
-  for (i = 0; i < BLOCK_NSYMS (b); i++)
+  ALL_BLOCK_SYMBOLS (b, i, sym)
     {
-      sym = BLOCK_SYM (b, i);
       COMPLETION_LIST_ADD_SYMBOL (sym, sym_text, sym_text_len, text, word);
     }
 
@@ -3568,9 +3585,8 @@ make_symbol_overload_list (struct symbol
       /* Also catch fields of types defined in this places which match our
          text string.  Only complete on types visible from current context. */
 
-      for (i = 0; i < BLOCK_NSYMS (b); i++)
+      ALL_BLOCK_SYMBOLS (b, i, sym)
 	{
-	  sym = BLOCK_SYM (b, i);
 	  overload_list_add_symbol (sym, oload_name);
 	}
     }
@@ -3582,9 +3598,8 @@ make_symbol_overload_list (struct symbol
   {
     QUIT;
     b = BLOCKVECTOR_BLOCK (BLOCKVECTOR (s), GLOBAL_BLOCK);
-    for (i = 0; i < BLOCK_NSYMS (b); i++)
+    ALL_BLOCK_SYMBOLS (b, i, sym)
       {
-	sym = BLOCK_SYM (b, i);
 	overload_list_add_symbol (sym, oload_name);
       }
   }
@@ -3596,9 +3611,8 @@ make_symbol_overload_list (struct symbol
     /* Don't do this block twice.  */
     if (b == surrounding_static_block)
       continue;
-    for (i = 0; i < BLOCK_NSYMS (b); i++)
+    ALL_BLOCK_SYMBOLS (b, i, sym)
       {
-	sym = BLOCK_SYM (b, i);
 	overload_list_add_symbol (sym, oload_name);
       }
   }
Index: gdb/symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.24
diff -u -p -r1.24 symtab.h
--- symtab.h	2001/07/07 17:19:50	1.24
+++ symtab.h	2001/10/01 22:20:58
@@ -449,6 +449,10 @@ struct block
 
     unsigned char gcc_compile_flag;
 
+    /* If this is really a hashtable of the symbols, this flag is 1.  */
+
+    unsigned char hashtable;
+
     /* Number of local symbols.  */
 
     int nsyms;
@@ -461,18 +465,34 @@ struct block
 
 #define BLOCK_START(bl)		(bl)->startaddr
 #define BLOCK_END(bl)		(bl)->endaddr
-#define BLOCK_NSYMS(bl)		(bl)->nsyms
-#define BLOCK_SYM(bl, n)	(bl)->sym[n]
 #define BLOCK_FUNCTION(bl)	(bl)->function
 #define BLOCK_SUPERBLOCK(bl)	(bl)->superblock
 #define BLOCK_GCC_COMPILED(bl)	(bl)->gcc_compile_flag
+#define BLOCK_HASHTABLE(bl)     (bl)->hashtable
 
+/* For BLOCK_HASHTABLE (bl) == 0 blocks only.  */
+#define BLOCK_NSYMS(bl)		(bl)->nsyms
+#define BLOCK_SYM(bl, n)	(bl)->sym[n]
+
+/* For BLOCK_HASHTABLE (bl) == 1 blocks, but these are valid
+   for non-hashed blocks as well - each symbol will appear to be
+   one bucket by itself.  */
+#define BLOCK_BUCKETS(bl)	(bl)->nsyms
+#define BLOCK_BUCKET(bl, n)	(bl)->sym[n]
+
+/* Macro to loop through all symbols in a block BL, in no particular order.
+   i counts which bucket we are in, and sym points to the current symbol.  */
+#define ALL_BLOCK_SYMBOLS(bl, i, sym)   \
+	for ((i) = 0; (i) < BLOCK_BUCKETS ((bl)); (i)++)        \
+	  for ((sym) = BLOCK_BUCKET ((bl), (i)); (sym);         \
+	       (sym) = (sym)->hash_next)
+
 /* Nonzero if symbols of block BL should be sorted alphabetically.
    Don't sort a block which corresponds to a function.  If we did the
    sorting would have to preserve the order of the symbols for the
    arguments.  */
 
-#define BLOCK_SHOULD_SORT(bl) ((bl)->nsyms >= 40 && BLOCK_FUNCTION (bl) == NULL)
+#define BLOCK_SHOULD_SORT(bl) (!BLOCK_HASHTABLE (bl) && BLOCK_FUNCTION (bl) == NULL)
 
 
 /* Represent one symbol name; a variable, constant, function or typedef.  */
@@ -722,6 +742,8 @@ struct symbol
     /* List of ranges where this symbol is active.  This is only
        used by alias symbols at the current time.  */
     struct range_list *ranges;
+
+    struct symbol *hash_next;
   };
 
 
Index: gdb/tracepoint.c
===================================================================
RCS file: /cvs/src/src/gdb/tracepoint.c,v
retrieving revision 1.26
diff -u -p -r1.26 tracepoint.c
--- tracepoint.c	2001/08/23 20:31:36	1.26
+++ tracepoint.c	2001/10/01 22:20:59
@@ -1296,16 +1296,14 @@ add_local_symbols (struct collection_lis
 {
   struct symbol *sym;
   struct block *block;
-  int i, nsyms, count = 0;
+  int i, count = 0;
 
   block = block_for_pc (pc);
   while (block != 0)
     {
       QUIT;			/* allow user to bail out with ^C */
-      nsyms = BLOCK_NSYMS (block);
-      for (i = 0; i < nsyms; i++)
+      ALL_BLOCK_SYMBOLS (block, i, sym)
 	{
-	  sym = BLOCK_SYM (block, i);
 	  switch (SYMBOL_CLASS (sym))
 	    {
 	    default:
@@ -2335,7 +2333,7 @@ scope_info (char *args, int from_tty)
   struct minimal_symbol *msym;
   struct block *block;
   char **canonical, *symname, *save_args = args;
-  int i, j, nsyms, count = 0;
+  int i, j, count = 0;
 
   if (args == 0 || *args == 0)
     error ("requires an argument (function, line or *addr) to define a scope");
@@ -2351,14 +2349,13 @@ scope_info (char *args, int from_tty)
   while (block != 0)
     {
       QUIT;			/* allow user to bail out with ^C */
-      nsyms = BLOCK_NSYMS (block);
-      for (i = 0; i < nsyms; i++)
+      ALL_BLOCK_SYMBOLS (block, i, sym)
 	{
 	  QUIT;			/* allow user to bail out with ^C */
 	  if (count == 0)
 	    printf_filtered ("Scope for %s:\n", save_args);
 	  count++;
-	  sym = BLOCK_SYM (block, i);
+
 	  symname = SYMBOL_NAME (sym);
 	  if (symname == NULL || *symname == '\0')
 	    continue;		/* probably botched, certainly useless */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]