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]

[RFA]: Massive C++ fixes and enhancements


This patch does the following:

1. Removes the remaining use of linear search through symbol tables
when there was a C++ symbol in the symtab. This means that rather than
search through 1,000,000 symbols to find out we don't have a
particular C++ symbol, we now search 20.  Trust me when i tell you
this is a significant speedup.
2. Fixes a bad problem with respect to STABS debugging in C++. This
was causing massive testsuite failures, as well as the inability to
call operator functions.
3. Speed up symbol searching even more by makeing sure we don't check
the same block twice in a given global lookup (before we would check
the same block, over and over again, for the same symbol, inside one
particular loop. Now i just make sure we only check a given block once
inside that loop).
4. Fix completion of C++ names. Now you can properly complete without
quotes, even when you have space in the name, assuming the space is in
a template or function argument list.
Like so:
(
(gdb) b bas<tab>
displays:
(gdb) b basic_string<char,

(gdb) b basic_string<char,<tab>
(displays a list of completions too long to print here, but all
correct)
(gdb) b basic_string<char, <tab>
(note the space i added after char,)

displays:
(gdb) b basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >

(gdb) b basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> ><tab>

displays:

::length(void) const
::max_size(void) const
::nilRep
::npos
::operator=(basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> > const &)
::operator[](unsigned int)
::rep(void) const

(etc)

(gdb) b basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::rep
rep(void) const
replace(unsigned int, unsigned int, char const *, unsigned int)
repup(basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::Rep *)
(gdb) b basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::rep<enter>

(gdb) b basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::rep       
Breakpoint 2 at 0x804b082: file /usr/include/g++-3/std/bastring.h, line 152.

Now, this isn't perfect, because the parsing of the name isn't
perfect.

In particular, if you have a function named:
'basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::rep(void) const'

You need to either not complete all the way (up to the rep is okay),
or quote it.

This is because the actual name has const, but when it goes to
breakpoint it, it ends up stripping the const, and you get
(gdb) b basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::rep(void) const 
Function "basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::rep(void)" not defined.



This should make a *lot* of people happy.



Changelog to follow in a few minutes.

I need approval from some people to commit all this.

It causes no regressions.

Trust me when i tell you that if the new binary search only wasn't
working, every single C++ test would fail. I checked this to make sure
it was the case.


--Dan
? config.log
? config.h
? config.status
? Makefile
? .gdbinit
? stamp-h
? version.c
? c-exp.tab.c
? jv-exp.tab.c
? f-exp.tab.c
? m2-exp.tab.c
? init.c
? gdb
? gdbcppfixes
? doc/config.log
? doc/config.status
? doc/Makefile
? gdbserver/config.log
? gdbserver/config.status
? gdbserver/Makefile
? testsuite/config.log
? testsuite/testrun.sum
? testsuite/config.status
? testsuite/testrun.log
? testsuite/Makefile
? testsuite/gdb.asm/config.log
? testsuite/gdb.asm/config.status
? testsuite/gdb.asm/Makefile
? testsuite/gdb.base/config.log
? testsuite/gdb.base/config.status
? testsuite/gdb.base/Makefile
? testsuite/gdb.c++/config.log
? testsuite/gdb.c++/misc.ci
? testsuite/gdb.c++/config.status
? testsuite/gdb.c++/misc
? testsuite/gdb.c++/Makefile
? testsuite/gdb.chill/config.log
? testsuite/gdb.chill/config.status
? testsuite/gdb.chill/Makefile
? testsuite/gdb.disasm/config.log
? testsuite/gdb.disasm/config.status
? testsuite/gdb.disasm/Makefile
? testsuite/gdb.gdbtk/config.log
? testsuite/gdb.gdbtk/config.status
? testsuite/gdb.gdbtk/Makefile
? testsuite/gdb.java/config.log
? testsuite/gdb.java/config.status
? testsuite/gdb.java/Makefile
? testsuite/gdb.mi/config.log
? testsuite/gdb.mi/config.status
? testsuite/gdb.mi/Makefile
? testsuite/gdb.stabs/config.log
? testsuite/gdb.stabs/config.status
? testsuite/gdb.stabs/Makefile
? testsuite/gdb.threads/config.log
? testsuite/gdb.threads/config.h
? testsuite/gdb.threads/config.status
? testsuite/gdb.threads/Makefile
? testsuite/gdb.trace/config.log
? testsuite/gdb.trace/config.status
? testsuite/gdb.trace/Makefile
Index: symfile.c
===================================================================
RCS file: /cvs/src/src/gdb/symfile.c,v
retrieving revision 1.17
diff -c -3 -p -r1.17 symfile.c
*** symfile.c	2000/08/07 15:02:48	1.17
--- symfile.c	2000/08/10 14:12:52
*************** compare_symbols (const PTR s1p, const PT
*** 212,219 ****
  
    s1 = (struct symbol **) s1p;
    s2 = (struct symbol **) s2p;
! 
!   return (STRCMP (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2)));
  }
  
  /*
--- 212,218 ----
  
    s1 = (struct symbol **) s1p;
    s2 = (struct symbol **) s2p;
!   return (STRCMP (SYMBOL_SOURCE_NAME (*s1), SYMBOL_SOURCE_NAME (*s2)));
  }
  
  /*
*************** compare_symbols (const PTR s1p, const PT
*** 241,248 ****
  static int
  compare_psymbols (const PTR s1p, const PTR s2p)
  {
!   register char *st1 = SYMBOL_NAME (*(struct partial_symbol **) s1p);
!   register char *st2 = SYMBOL_NAME (*(struct partial_symbol **) s2p);
  
    if ((st1[0] - st2[0]) || !st1[0])
      {
--- 240,253 ----
  static int
  compare_psymbols (const PTR s1p, const PTR s2p)
  {
!  register struct partial_symbol **s1, **s2;
!  register char *st1, *st2;
! 
!   s1 = (struct partial_symbol **) s1p;
!   s2 = (struct partial_symbol **) s2p;
!   st1 = SYMBOL_SOURCE_NAME(*s1);
!   st2 = SYMBOL_SOURCE_NAME(*s2);
! 
  
    if ((st1[0] - st2[0]) || !st1[0])
      {
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.11
diff -c -3 -p -r1.11 symtab.c
*** symtab.c	2000/08/04 23:13:50	1.11
--- symtab.c	2000/08/10 14:12:57
*************** gdb_mangle_name (struct type *type, int 
*** 296,301 ****
--- 296,303 ----
    char buf[20];
    int len = (newname == NULL ? 0 : strlen (newname));
  
+   if (OPNAME_PREFIX_P (field_name))
+ 	  return physname;
    is_full_physname_constructor =
      ((physname[0] == '_' && physname[1] == '_' &&
        (isdigit (physname[2]) || physname[2] == 'Q' || physname[2] == 't'))
*************** gdb_mangle_name (struct type *type, int 
*** 335,357 ****
  		      + strlen (physname)
  		      + 1);
  
-   /* Only needed for GNU-mangled names.  ANSI-mangled names
-      work with the normal mechanisms.  */
-   if (OPNAME_PREFIX_P (field_name))
      {
-       const char *opname = cplus_mangle_opname (field_name + 3, 0);
-       if (opname == NULL)
- 	error ("No mangling for \"%s\"", field_name);
-       mangled_name_len += strlen (opname);
        mangled_name = (char *) xmalloc (mangled_name_len);
- 
-       strncpy (mangled_name, field_name, 3);
-       mangled_name[3] = '\0';
-       strcat (mangled_name, opname);
-     }
-   else
-     {
-       mangled_name = (char *) xmalloc (mangled_name_len);
        if (is_constructor)
  	mangled_name[0] = '\0';
        else
--- 337,344 ----
*************** fixup_psymbol_section (struct partial_sy
*** 549,555 ****
--- 536,549 ----
  
    return psym;
  }
+ /* We seem to be looking things up in the same block >1 times, because
+    of the global search.*/
+ 
+ #define BLOCK_LOOKUP_HASH_SIZE 16
+ static const struct block *checked_blocks[BLOCK_LOOKUP_HASH_SIZE];
+ 
  
+ 
  /* Find the definition for a specified symbol name NAME
     in namespace NAMESPACE, visible from lexical block BLOCK.
     Returns the struct symbol pointer, or zero if no symbol is found.
*************** fixup_psymbol_section (struct partial_sy
*** 572,589 ****
     can probably assume it will never hit the C++ code).  */
  
  struct symbol *
! lookup_symbol (const char *name, register const struct block *block,
  	       const namespace_enum namespace, int *is_a_field_of_this,
  	       struct symtab **symtab)
  {
    register struct symbol *sym;
    register struct symtab *s = NULL;
    register struct partial_symtab *ps;
!   struct blockvector *bv;
    register struct objfile *objfile = NULL;
    register struct block *b;
    register struct minimal_symbol *msymbol;
  
    /* Search specified block and its superiors.  */
  
    while (block != 0)
--- 566,598 ----
     can probably assume it will never hit the C++ code).  */
  
  struct symbol *
! lookup_symbol (const char *beforename, register const struct block *block,
  	       const namespace_enum namespace, int *is_a_field_of_this,
  	       struct symtab **symtab)
  {
    register struct symbol *sym;
    register struct symtab *s = NULL;
    register struct partial_symtab *ps;
!   register struct blockvector *bv;
    register struct objfile *objfile = NULL;
    register struct block *b;
    register struct minimal_symbol *msymbol;
+   const char *name;
  
+   /* First, reset the checked_blocks */
+   memset(&checked_blocks, 0, sizeof(checked_blocks));
+   
+   /* Demangle the name before doing a lookup, so we can always binary
+      search. */
+   name=cplus_demangle(beforename, DMGL_ANSI | DMGL_PARAMS);
+ 
+   /* Couldn't demangle, might be a C name. If it's really C++, we have
+      barely have a prayer of finding it anyway, or it being useful, if
+      we can't demangle it, so ....
+   */
+   if (!name)
+     name=beforename;
+   
    /* Search specified block and its superiors.  */
  
    while (block != 0)
*************** lookup_symbol (const char *name, registe
*** 677,684 ****
--- 686,707 ----
  
    ALL_SYMTABS (objfile, s)
    {
+     register unsigned long hashval;
      bv = BLOCKVECTOR (s);
      block = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+     /* Check if we already tried here */
+     hashval = hash((unsigned int *)&block, sizeof (struct block *)) %
+       BLOCK_LOOKUP_HASH_SIZE;
+     
+     if ((checked_blocks[hashval] != NULL) && checked_blocks[hashval]
+ 	== block )
+       {
+ 	continue;
+       }
+     else
+       {
+ 	checked_blocks[hashval]=block;
+       }
      sym = lookup_block_symbol (block, name, namespace);
      if (sym)
        {
*************** lookup_partial_symbol (struct partial_sy
*** 969,980 ****
  	  center = bottom + (top - bottom) / 2;
  	  if (!(center < top))
  	    abort ();
! 	  if (!do_linear_search
! 	      && (SYMBOL_LANGUAGE (*center) == language_java))
  	    {
  	      do_linear_search = 1;
  	    }
! 	  if (STRCMP (SYMBOL_NAME (*center), name) >= 0)
  	    {
  	      top = center;
  	    }
--- 992,1002 ----
  	  center = bottom + (top - bottom) / 2;
  	  if (!(center < top))
  	    abort ();
! 	  if (!do_linear_search && ( SYMBOL_LANGUAGE (*center) == language_java))
  	    {
  	      do_linear_search = 1;
  	    }
! 	  if (STRCMP (SYMBOL_SOURCE_NAME (*center), name) >= 0)
  	    {
  	      top = center;
  	    }
*************** lookup_block_symbol (register const stru
*** 1177,1185 ****
      {
        /* Reset the linear search flag so if the binary search fails, we
           won't do the linear search once unless we find some reason to
!          do so, such as finding a C++ symbol during the binary search.
!          Note that for C++ modules, ALL the symbols in a block should
!          end up marked as C++ symbols. */
  
        do_linear_search = 0;
        top = BLOCK_NSYMS (block);
--- 1199,1205 ----
      {
        /* Reset the linear search flag so if the binary search fails, we
           won't do the linear search once unless we find some reason to
!          do so */
  
        do_linear_search = 0;
        top = BLOCK_NSYMS (block);
*************** lookup_block_symbol (register const stru
*** 1197,1218 ****
  	    }
  	  inc = (inc >> 1) + bot;
  	  sym = BLOCK_SYM (block, inc);
! 	  if (!do_linear_search
! 	      && (SYMBOL_LANGUAGE (sym) == language_cplus
! 		  || SYMBOL_LANGUAGE (sym) == language_java
! 	      ))
  	    {
  	      do_linear_search = 1;
  	    }
! 	  if (SYMBOL_NAME (sym)[0] < name[0])
  	    {
  	      bot = inc;
  	    }
! 	  else if (SYMBOL_NAME (sym)[0] > name[0])
  	    {
  	      top = inc;
  	    }
! 	  else if (STRCMP (SYMBOL_NAME (sym), name) < 0)
  	    {
  	      bot = inc;
  	    }
--- 1217,1235 ----
  	    }
  	  inc = (inc >> 1) + bot;
  	  sym = BLOCK_SYM (block, inc);
! 	  if (!do_linear_search && (SYMBOL_LANGUAGE (sym) == language_java))
  	    {
  	      do_linear_search = 1;
  	    }
! 	  if (SYMBOL_SOURCE_NAME (sym)[0] < name[0])
  	    {
  	      bot = inc;
  	    }
! 	  else if (SYMBOL_SOURCE_NAME (sym)[0] > name[0])
  	    {
  	      top = inc;
  	    }
! 	  else if (STRCMP (SYMBOL_SOURCE_NAME (sym), name) < 0)
  	    {
  	      bot = inc;
  	    }
*************** lookup_block_symbol (register const stru
*** 1234,1252 ****
        while (bot < top)
  	{
  	  sym = BLOCK_SYM (block, bot);
! 	  inc = SYMBOL_NAME (sym)[0] - name[0];
! 	  if (inc == 0)
! 	    {
! 	      inc = STRCMP (SYMBOL_NAME (sym), name);
! 	    }
! 	  if (inc == 0 && SYMBOL_NAMESPACE (sym) == namespace)
! 	    {
! 	      return (sym);
! 	    }
! 	  if (inc > 0)
! 	    {
! 	      break;
! 	    }
  	  bot++;
  	}
      }
--- 1251,1258 ----
        while (bot < top)
  	{
  	  sym = BLOCK_SYM (block, bot);
! 	  if (SYMBOL_MATCHES_NAME(sym, name))
! 	    return sym;	  	  
  	  bot++;
  	}
      }
*************** decode_line_1 (char **argptr, int funfir
*** 2460,2465 ****
--- 2466,2472 ----
    register struct minimal_symbol *msymbol;
    char *copy;
    struct symbol *sym_class;
+   int triedonce=0;
    int i1;
    int is_quoted;
    int is_quote_enclosed;
*************** decode_line_1 (char **argptr, int funfir
*** 2570,2582 ****
      }
    else
      is_quote_enclosed = 0;
    for (; *p; p++)
      {
        if (p[0] == '<')
  	{
  	  char *temp_end = find_template_name_end (p);
! 	  if (!temp_end)
  	    error ("malformed template specification in command");
  	  p = temp_end;
  	}
        /* Check for the end of the first half of the linespec.  End of line,
--- 2577,2602 ----
      }
    else
      is_quote_enclosed = 0;
+ tryagain:
    for (; *p; p++)
      {
        if (p[0] == '<')
  	{
  	  char *temp_end = find_template_name_end (p);
! 	  if (!temp_end && !triedonce)
! 	  {
! 		  triedonce=1;
! 		  is_quote_enclosed=1;
! 		  p=*argptr;
! 		  if (has_comma)
! 			  *ii=',';
! 		  s=NULL;
! 		  goto tryagain;
! 	   }
! 	  else if (!temp_end && triedonce)
! 	  {
  	    error ("malformed template specification in command");
+ 	  }
  	  p = temp_end;
  	}
        /* Check for the end of the first half of the linespec.  End of line,
*************** decode_line_1 (char **argptr, int funfir
*** 2784,2792 ****
  
  		      if (OPNAME_PREFIX_P (copy))
  			{
! 			  tmp = (char *) alloca (strlen (copy + 3) + 9);
  			  strcpy (tmp, "operator ");
! 			  strcat (tmp, copy + 3);
  			}
  		      else
  			tmp = copy;
--- 2804,2812 ----
  
  		      if (OPNAME_PREFIX_P (copy))
  			{
! 			  tmp = (char *) alloca (strlen (copy + 8) + 9);
  			  strcpy (tmp, "operator ");
! 			  strcat (tmp, copy + 8);
  			}
  		      else
  			tmp = copy;
*************** make_symbol_completion_list (char *text,
*** 4163,4178 ****
        return NULL;
      else
        {
! 	/* It is not a quoted string.  Break it based on the characters
! 	   which are in symbols.  */
! 	while (p > text)
  	  {
! 	    if (isalnum (p[-1]) || p[-1] == '_' || p[-1] == '\0')
! 	      --p;
! 	    else
  	      break;
  	  }
  	sym_text = p;
        }
    }
  
--- 4183,4201 ----
        return NULL;
      else
        {
! 	      for (p = text; *p != '\0'; ++p)
  	  {
! 		      if (!isprint(*p))
  	      break;
  	  }
+ 	      if (*p!='\0')
+ 	      {
  	sym_text = p;
+ 	      }
+ 	      else
+ 	      {
+ 		     sym_text=text;
+ 	      } 
        }
    }
  
Index: symtab.h
===================================================================
RCS file: /cvs/src/src/gdb/symtab.h,v
retrieving revision 1.13
diff -c -3 -p -r1.13 symtab.h
*** symtab.h	2000/08/07 15:02:48	1.13
--- symtab.h	2000/08/10 14:12:59
*************** extern CORE_ADDR symbol_overlayed_addres
*** 168,175 ****
     specified obstack. */
  
  #define SYMBOL_INIT_DEMANGLED_NAME(symbol,obstack)			\
!   do {									\
      char *demangled = NULL;						\
      if (SYMBOL_LANGUAGE (symbol) == language_cplus			\
  	|| SYMBOL_LANGUAGE (symbol) == language_auto)			\
        {									\
--- 168,177 ----
     specified obstack. */
  
  #define SYMBOL_INIT_DEMANGLED_NAME(symbol,obstack)			\
!   {									\
      char *demangled = NULL;						\
+     if (SYMBOL_LANGUAGE (symbol) == language_unknown)			\
+ 	    SYMBOL_LANGUAGE(symbol) = language_auto;			\
      if (SYMBOL_LANGUAGE (symbol) == language_cplus			\
  	|| SYMBOL_LANGUAGE (symbol) == language_auto)			\
        {									\
*************** extern CORE_ADDR symbol_overlayed_addres
*** 222,232 ****
  	    SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL;		\
  	  }								\
        }									\
!     if (SYMBOL_LANGUAGE (symbol) == language_auto)			\
!       {									\
! 	SYMBOL_LANGUAGE (symbol) = language_unknown;			\
!       }									\
!   } while (0)
  
  /* Macro that returns the demangled name for a symbol based on the language
     for that symbol.  If no demangled name exists, returns NULL. */
--- 224,230 ----
  	    SYMBOL_CHILL_DEMANGLED_NAME (symbol) = NULL;		\
  	  }								\
        }									\
!   } 
  
  /* Macro that returns the demangled name for a symbol based on the language
     for that symbol.  If no demangled name exists, returns NULL. */
*************** struct partial_symtab
*** 1053,1059 ****
     Note that this macro is g++ specific (FIXME). */
  
  #define OPNAME_PREFIX_P(NAME) \
!   ((NAME)[0] == 'o' && (NAME)[1] == 'p' && is_cplus_marker ((NAME)[2]))
  
  /* Macro that yields non-zero value iff NAME is the prefix for C++ vtbl
     names.  Note that this macro is g++ specific (FIXME).
--- 1051,1057 ----
     Note that this macro is g++ specific (FIXME). */
  
  #define OPNAME_PREFIX_P(NAME) \
!   (!strncmp(NAME,"operator",8))
  
  /* Macro that yields non-zero value iff NAME is the prefix for C++ vtbl
     names.  Note that this macro is g++ specific (FIXME).

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